bosun 0.36.0 → 0.36.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +98 -16
- package/README.md +27 -0
- package/agent-event-bus.mjs +5 -5
- package/agent-pool.mjs +129 -12
- package/agent-prompts.mjs +7 -1
- package/agent-sdk.mjs +13 -2
- package/agent-supervisor.mjs +2 -2
- package/agent-work-report.mjs +1 -1
- package/anomaly-detector.mjs +6 -6
- package/autofix.mjs +15 -15
- package/bosun-skills.mjs +4 -4
- package/bosun.schema.json +160 -4
- package/claude-shell.mjs +11 -11
- package/cli.mjs +21 -21
- package/codex-config.mjs +19 -19
- package/codex-shell.mjs +180 -29
- package/config-doctor.mjs +27 -2
- package/config.mjs +60 -7
- package/copilot-shell.mjs +4 -4
- package/error-detector.mjs +1 -1
- package/fleet-coordinator.mjs +2 -2
- package/gemini-shell.mjs +692 -0
- package/github-oauth-portal.mjs +1 -1
- package/github-reconciler.mjs +2 -2
- package/kanban-adapter.mjs +741 -168
- package/merge-strategy.mjs +25 -25
- package/monitor.mjs +123 -105
- package/opencode-shell.mjs +22 -22
- package/package.json +7 -1
- package/postinstall.mjs +22 -22
- package/pr-cleanup-daemon.mjs +6 -6
- package/prepublish-check.mjs +4 -4
- package/presence.mjs +2 -2
- package/primary-agent.mjs +85 -7
- package/publish.mjs +1 -1
- package/review-agent.mjs +1 -1
- package/session-tracker.mjs +11 -0
- package/setup-web-server.mjs +429 -21
- package/setup.mjs +367 -12
- package/shared-knowledge.mjs +1 -1
- package/startup-service.mjs +9 -9
- package/stream-resilience.mjs +58 -4
- package/sync-engine.mjs +2 -2
- package/task-assessment.mjs +9 -9
- package/task-cli.mjs +1 -1
- package/task-complexity.mjs +71 -2
- package/task-context.mjs +1 -2
- package/task-executor.mjs +104 -41
- package/telegram-bot.mjs +825 -494
- package/telegram-sentinel.mjs +28 -28
- package/ui/app.js +256 -23
- package/ui/app.monolith.js +1 -1
- package/ui/components/agent-selector.js +4 -3
- package/ui/components/chat-view.js +101 -28
- package/ui/components/diff-viewer.js +3 -3
- package/ui/components/kanban-board.js +3 -3
- package/ui/components/session-list.js +255 -35
- package/ui/components/workspace-switcher.js +3 -3
- package/ui/demo.html +209 -194
- package/ui/index.html +3 -3
- package/ui/modules/icon-utils.js +206 -142
- package/ui/modules/icons.js +2 -27
- package/ui/modules/settings-schema.js +29 -5
- package/ui/modules/streaming.js +30 -2
- package/ui/modules/vision-stream.js +275 -0
- package/ui/modules/voice-client.js +102 -9
- package/ui/modules/voice-fallback.js +62 -6
- package/ui/modules/voice-overlay.js +594 -59
- package/ui/modules/voice.js +31 -38
- package/ui/setup.html +284 -34
- package/ui/styles/components.css +47 -0
- package/ui/styles/sessions.css +75 -0
- package/ui/tabs/agents.js +73 -43
- package/ui/tabs/chat.js +37 -40
- package/ui/tabs/control.js +2 -2
- package/ui/tabs/dashboard.js +1 -1
- package/ui/tabs/infra.js +10 -10
- package/ui/tabs/library.js +8 -8
- package/ui/tabs/logs.js +10 -10
- package/ui/tabs/settings.js +20 -20
- package/ui/tabs/tasks.js +76 -47
- package/ui-server.mjs +1761 -124
- package/update-check.mjs +13 -13
- package/ve-kanban.mjs +1 -1
- package/whatsapp-channel.mjs +5 -5
- package/workflow-engine.mjs +20 -1
- package/workflow-nodes.mjs +904 -4
- package/workflow-templates/agents.mjs +321 -7
- package/workflow-templates/ci-cd.mjs +6 -6
- package/workflow-templates/github.mjs +156 -84
- package/workflow-templates/planning.mjs +8 -8
- package/workflow-templates/reliability.mjs +8 -8
- package/workflow-templates/security.mjs +3 -3
- package/workflow-templates.mjs +15 -9
- package/workspace-manager.mjs +85 -1
- package/workspace-monitor.mjs +2 -2
- package/workspace-registry.mjs +2 -2
- package/worktree-manager.mjs +1 -1
package/ui/tabs/tasks.js
CHANGED
|
@@ -366,7 +366,7 @@ export function StartTaskModal({
|
|
|
366
366
|
onClick=${handleStart}
|
|
367
367
|
disabled=${starting || !resolvedTaskId}
|
|
368
368
|
>
|
|
369
|
-
${starting ? "Starting…" : "
|
|
369
|
+
${starting ? "Starting…" : ":play: Start Task"}
|
|
370
370
|
</button>
|
|
371
371
|
</div>
|
|
372
372
|
</div>
|
|
@@ -875,7 +875,7 @@ export function TaskProgressModal({ task, onClose }) {
|
|
|
875
875
|
<div class="tp-hero">
|
|
876
876
|
<div class="tp-pulse-dot"></div>
|
|
877
877
|
<div class="tp-hero-title">
|
|
878
|
-
<div class="tp-hero-status-label">${iconText("
|
|
878
|
+
<div class="tp-hero-status-label">${iconText(":zap: Active — Agent Working")}</div>
|
|
879
879
|
</div>
|
|
880
880
|
<${Badge} status="inprogress" text="running" />
|
|
881
881
|
</div>
|
|
@@ -924,7 +924,7 @@ export function TaskProgressModal({ task, onClose }) {
|
|
|
924
924
|
font-weight:${active ? "600" : "400"};"
|
|
925
925
|
>
|
|
926
926
|
<span style="font-size:14px;flex-shrink:0;">
|
|
927
|
-
${done ? resolveIcon("
|
|
927
|
+
${done ? resolveIcon(":check:") : active ? resolveIcon(":refresh:") : ICONS.dot}
|
|
928
928
|
</span>
|
|
929
929
|
<span>${step.label}</span>
|
|
930
930
|
${active && html`
|
|
@@ -956,11 +956,11 @@ export function TaskProgressModal({ task, onClose }) {
|
|
|
956
956
|
class="btn btn-ghost btn-sm"
|
|
957
957
|
onClick=${() => { haptic(); sendCommandToChat("/steer " + task.id); onClose(); }}
|
|
958
958
|
title="Guide the agent mid-task"
|
|
959
|
-
>${iconText("
|
|
959
|
+
>${iconText(":chat: Steer")}</button>
|
|
960
960
|
<button
|
|
961
961
|
class="btn btn-ghost btn-sm"
|
|
962
962
|
onClick=${() => { haptic(); sendCommandToChat("/logs " + task.id); onClose(); }}
|
|
963
|
-
>${iconText("
|
|
963
|
+
>${iconText(":file: Logs")}</button>
|
|
964
964
|
<button class="btn btn-secondary btn-sm" onClick=${handleMarkReview}>
|
|
965
965
|
→ Move to Review
|
|
966
966
|
</button>
|
|
@@ -1085,7 +1085,7 @@ export function TaskReviewModal({ task, onClose, onStart }) {
|
|
|
1085
1085
|
>
|
|
1086
1086
|
|
|
1087
1087
|
<div class="tr-hero">
|
|
1088
|
-
<span class="tr-review-icon">${resolveIcon("
|
|
1088
|
+
<span class="tr-review-icon">${resolveIcon(":search:")}</span>
|
|
1089
1089
|
<div class="tr-hero-title">
|
|
1090
1090
|
<div class="tr-hero-status-label">In Review</div>
|
|
1091
1091
|
${prNumber && html`
|
|
@@ -1094,7 +1094,7 @@ export function TaskReviewModal({ task, onClose, onStart }) {
|
|
|
1094
1094
|
href="#"
|
|
1095
1095
|
onClick=${(e) => { e.preventDefault(); haptic(); sendCommandToChat("/diff " + branchLabel); onClose(); }}
|
|
1096
1096
|
>
|
|
1097
|
-
PR #${prNumber} · View diff
|
|
1097
|
+
PR #${prNumber} · View diff :arrowRight:
|
|
1098
1098
|
</a>
|
|
1099
1099
|
`}
|
|
1100
1100
|
${!prNumber && html`<span style="font-size:12px;color:var(--text-hint);">No PR yet</span>`}
|
|
@@ -1141,12 +1141,12 @@ export function TaskReviewModal({ task, onClose, onStart }) {
|
|
|
1141
1141
|
|
|
1142
1142
|
<div class="tr-section">
|
|
1143
1143
|
<div class="tr-section-title">
|
|
1144
|
-
Checks ${allPass ? iconText("—
|
|
1144
|
+
Checks ${allPass ? iconText("— :check: All passing") : ""}
|
|
1145
1145
|
</div>
|
|
1146
1146
|
<div class="tr-checks-row">
|
|
1147
1147
|
${checks.map((c) => html`
|
|
1148
1148
|
<div class="tr-check-item ${c.status}" key=${c.label}>
|
|
1149
|
-
${resolveIcon(c.status === "pass" ? "
|
|
1149
|
+
${resolveIcon(c.status === "pass" ? ":check:" : c.status === "fail" ? ":close:" : ":clock:")}
|
|
1150
1150
|
${c.label}
|
|
1151
1151
|
</div>
|
|
1152
1152
|
`)}
|
|
@@ -1175,7 +1175,7 @@ export function TaskReviewModal({ task, onClose, onStart }) {
|
|
|
1175
1175
|
<div class="task-attachment-item" key=${att.id || `${name}-${index}`}>
|
|
1176
1176
|
${isImage && url
|
|
1177
1177
|
? html`<img class="task-attachment-thumb" src=${url} alt=${name} />`
|
|
1178
|
-
: html`<span class="task-attachment-icon">${resolveIcon("
|
|
1178
|
+
: html`<span class="task-attachment-icon">${resolveIcon(":link:")}</span>`}
|
|
1179
1179
|
<div class="task-attachment-meta">
|
|
1180
1180
|
${url
|
|
1181
1181
|
? html`<a class="task-attachment-name" href=${url} target="_blank" rel="noopener">${name}</a>`
|
|
@@ -1200,17 +1200,17 @@ export function TaskReviewModal({ task, onClose, onStart }) {
|
|
|
1200
1200
|
title="Mark as merged / done"
|
|
1201
1201
|
>${iconText("✓ Mark Done")}</button>
|
|
1202
1202
|
<button class="btn btn-secondary btn-sm" onClick=${handleReopen}>
|
|
1203
|
-
|
|
1203
|
+
:workflow: Reopen as Active
|
|
1204
1204
|
</button>
|
|
1205
1205
|
<button
|
|
1206
1206
|
class="btn btn-ghost btn-sm"
|
|
1207
1207
|
onClick=${() => { haptic(); sendCommandToChat("/logs " + task.id); onClose(); }}
|
|
1208
|
-
>${iconText("
|
|
1208
|
+
>${iconText(":file: Logs")}</button>
|
|
1209
1209
|
${prNumber && html`
|
|
1210
1210
|
<button
|
|
1211
1211
|
class="btn btn-ghost btn-sm"
|
|
1212
1212
|
onClick=${() => { haptic(); sendCommandToChat("/diff " + branchLabel); onClose(); }}
|
|
1213
|
-
>${iconText("
|
|
1213
|
+
>${iconText(":search: Diff")}</button>
|
|
1214
1214
|
`}
|
|
1215
1215
|
<button
|
|
1216
1216
|
class="btn btn-ghost btn-sm"
|
|
@@ -1540,7 +1540,7 @@ export function TaskDetailModal({ task, onClose, onStart }) {
|
|
|
1540
1540
|
html`
|
|
1541
1541
|
<div class="task-modal-actions">
|
|
1542
1542
|
<button class="btn btn-primary btn-sm" onClick=${handleStart}>
|
|
1543
|
-
|
|
1543
|
+
:play: Dispatch Task
|
|
1544
1544
|
</button>
|
|
1545
1545
|
</div>
|
|
1546
1546
|
`}
|
|
@@ -1616,7 +1616,7 @@ export function TaskDetailModal({ task, onClose, onStart }) {
|
|
|
1616
1616
|
<div class="task-attachment-item" key=${att.id || `${name}-${index}`}>
|
|
1617
1617
|
${isImage && url
|
|
1618
1618
|
? html`<img class="task-attachment-thumb" src=${url} alt=${name} />`
|
|
1619
|
-
: html`<span class="task-attachment-icon">${resolveIcon("
|
|
1619
|
+
: html`<span class="task-attachment-icon">${resolveIcon(":link:")}</span>`}
|
|
1620
1620
|
<div class="task-attachment-meta">
|
|
1621
1621
|
${url
|
|
1622
1622
|
? html`<a class="task-attachment-name" href=${url} target="_blank" rel="noopener">${name}</a>`
|
|
@@ -1673,8 +1673,8 @@ export function TaskDetailModal({ task, onClose, onStart }) {
|
|
|
1673
1673
|
title="Use AI to expand and improve this task description"
|
|
1674
1674
|
>
|
|
1675
1675
|
${rewriting
|
|
1676
|
-
? html`<span style="display:inline-block;animation:spin 0.8s linear infinite">${resolveIcon("
|
|
1677
|
-
: html`${iconText("
|
|
1676
|
+
? html`<span style="display:inline-block;animation:spin 0.8s linear infinite">${resolveIcon(":clock:")}</span> Improving…`
|
|
1677
|
+
: html`${iconText(":star: Improve with AI")}`
|
|
1678
1678
|
}
|
|
1679
1679
|
</button>
|
|
1680
1680
|
<input
|
|
@@ -1836,7 +1836,7 @@ export function TaskDetailModal({ task, onClose, onStart }) {
|
|
|
1836
1836
|
onClick=${handleSave}
|
|
1837
1837
|
disabled=${saving}
|
|
1838
1838
|
>
|
|
1839
|
-
${saving ? "Saving…" : iconText("
|
|
1839
|
+
${saving ? "Saving…" : iconText(":save: Save")}
|
|
1840
1840
|
</button>
|
|
1841
1841
|
<button
|
|
1842
1842
|
class="btn btn-ghost btn-sm"
|
|
@@ -1871,7 +1871,7 @@ export function TaskDetailModal({ task, onClose, onStart }) {
|
|
|
1871
1871
|
sendCommandToChat("/logs " + task.id);
|
|
1872
1872
|
}}
|
|
1873
1873
|
>
|
|
1874
|
-
${iconText("
|
|
1874
|
+
${iconText(":file: View Agent Logs")}
|
|
1875
1875
|
</button>
|
|
1876
1876
|
`}
|
|
1877
1877
|
</div>
|
|
@@ -2436,7 +2436,7 @@ export function TasksTab() {
|
|
|
2436
2436
|
return html`
|
|
2437
2437
|
<div class="flex-between mb-sm" style="padding:0 4px">
|
|
2438
2438
|
<div class="view-toggle">
|
|
2439
|
-
<button class="view-toggle-btn ${!isKanban ? 'active' : ''}" onClick=${() => { viewMode.value = 'list'; haptic(); }}>${iconText("
|
|
2439
|
+
<button class="view-toggle-btn ${!isKanban ? 'active' : ''}" onClick=${() => { viewMode.value = 'list'; haptic(); }}>${iconText(":menu: List")}</button>
|
|
2440
2440
|
<button class="view-toggle-btn ${isKanban ? 'active' : ''}" onClick=${() => { viewMode.value = 'kanban'; haptic(); }}>▦ Board</button>
|
|
2441
2441
|
</div>
|
|
2442
2442
|
<div style="display:flex;gap:8px;align-items:center;">
|
|
@@ -2446,7 +2446,7 @@ export function TasksTab() {
|
|
|
2446
2446
|
haptic();
|
|
2447
2447
|
setShowTemplates(true);
|
|
2448
2448
|
}}
|
|
2449
|
-
>${iconText("
|
|
2449
|
+
>${iconText(":zap: Templates")}</button>
|
|
2450
2450
|
<button
|
|
2451
2451
|
class="btn btn-ghost btn-sm"
|
|
2452
2452
|
onClick=${toggleCompletedFilter}
|
|
@@ -2510,7 +2510,7 @@ export function TasksTab() {
|
|
|
2510
2510
|
|
|
2511
2511
|
const viewToggle = html`
|
|
2512
2512
|
<div class="view-toggle">
|
|
2513
|
-
<button class="view-toggle-btn ${!isKanban ? 'active' : ''}" onClick=${() => { viewMode.value = 'list'; haptic(); }}>${iconText("
|
|
2513
|
+
<button class="view-toggle-btn ${!isKanban ? 'active' : ''}" onClick=${() => { viewMode.value = 'list'; haptic(); }}>${iconText(":menu: List")}</button>
|
|
2514
2514
|
<button class="view-toggle-btn ${isKanban ? 'active' : ''}" onClick=${() => { viewMode.value = 'kanban'; haptic(); }}>▦ Board</button>
|
|
2515
2515
|
</div>
|
|
2516
2516
|
`;
|
|
@@ -2547,16 +2547,16 @@ export function TasksTab() {
|
|
|
2547
2547
|
class="actions-dropdown-item"
|
|
2548
2548
|
onClick=${() => { setActionsOpen(false); setStartAnyOpen(true); }}
|
|
2549
2549
|
>
|
|
2550
|
-
${iconText("
|
|
2550
|
+
${iconText(":play: Start Task")}
|
|
2551
2551
|
</button>
|
|
2552
2552
|
<button
|
|
2553
2553
|
class="actions-dropdown-item"
|
|
2554
2554
|
onClick=${() => { setActionsOpen(false); setShowTemplates(true); }}
|
|
2555
2555
|
>
|
|
2556
|
-
${iconText("
|
|
2556
|
+
${iconText(":zap: Trigger Templates")}
|
|
2557
2557
|
</button>
|
|
2558
|
-
<button class="actions-dropdown-item" onClick=${handleExportCSV}>${iconText("
|
|
2559
|
-
<button class="actions-dropdown-item" onClick=${handleExportJSON}>${iconText("
|
|
2558
|
+
<button class="actions-dropdown-item" onClick=${handleExportCSV}>${iconText(":chart: Export CSV")}</button>
|
|
2559
|
+
<button class="actions-dropdown-item" onClick=${handleExportJSON}>${iconText(":clipboard: Export JSON")}</button>
|
|
2560
2560
|
</div>
|
|
2561
2561
|
`}
|
|
2562
2562
|
</div>
|
|
@@ -2601,7 +2601,7 @@ export function TasksTab() {
|
|
|
2601
2601
|
setStartAnyOpen(true);
|
|
2602
2602
|
}}
|
|
2603
2603
|
>
|
|
2604
|
-
|
|
2604
|
+
:play: Start Task
|
|
2605
2605
|
</button>
|
|
2606
2606
|
${actionsMenu}
|
|
2607
2607
|
`}
|
|
@@ -2778,7 +2778,7 @@ export function TasksTab() {
|
|
|
2778
2778
|
<span class="snapshot-lbl">${m.label}</span>
|
|
2779
2779
|
</button>
|
|
2780
2780
|
`)}
|
|
2781
|
-
<span class="snapshot-view-tag">${iconText(isKanban ? "
|
|
2781
|
+
<span class="snapshot-view-tag">${iconText(isKanban ? ":dot: Board" : ":menu: List")}</span>
|
|
2782
2782
|
</div>
|
|
2783
2783
|
|
|
2784
2784
|
<style>
|
|
@@ -3006,6 +3006,7 @@ function CreateTaskModalInline({ onClose }) {
|
|
|
3006
3006
|
const [rewriting, setRewriting] = useState(false);
|
|
3007
3007
|
const [workspaceId, setWorkspaceId] = useState(activeWorkspaceId.value || "");
|
|
3008
3008
|
const [repository, setRepository] = useState("");
|
|
3009
|
+
const [repositories, setRepositories] = useState([]);
|
|
3009
3010
|
const [showAdvanced, setShowAdvanced] = useState(false);
|
|
3010
3011
|
|
|
3011
3012
|
const handleRewrite = async () => {
|
|
@@ -3051,14 +3052,31 @@ function CreateTaskModalInline({ onClose }) {
|
|
|
3051
3052
|
useEffect(() => {
|
|
3052
3053
|
if (!repositoryOptions.length) {
|
|
3053
3054
|
if (repository) setRepository("");
|
|
3055
|
+
if (repositories.length) setRepositories([]);
|
|
3054
3056
|
return;
|
|
3055
3057
|
}
|
|
3056
3058
|
if (!repositoryOptions.some((repo) => repo?.slug === repository)) {
|
|
3057
3059
|
const primary = repositoryOptions.find((repo) => repo?.primary);
|
|
3058
|
-
|
|
3060
|
+
const defaultSlug = primary?.slug || repositoryOptions[0]?.slug || "";
|
|
3061
|
+
setRepository(defaultSlug);
|
|
3062
|
+
setRepositories(defaultSlug ? [defaultSlug] : []);
|
|
3059
3063
|
}
|
|
3060
3064
|
}, [workspaceId, repositoryOptions.length]);
|
|
3061
3065
|
|
|
3066
|
+
const toggleRepo = (slug) => {
|
|
3067
|
+
setRepositories((prev) =>
|
|
3068
|
+
prev.includes(slug) ? prev.filter((s) => s !== slug) : [...prev, slug],
|
|
3069
|
+
);
|
|
3070
|
+
// Keep single-repo compat: repository = first selected
|
|
3071
|
+
setRepository((prev) => {
|
|
3072
|
+
if (repositories.includes(slug)) {
|
|
3073
|
+
const next = repositories.filter((s) => s !== slug);
|
|
3074
|
+
return next[0] || "";
|
|
3075
|
+
}
|
|
3076
|
+
return prev || slug;
|
|
3077
|
+
});
|
|
3078
|
+
};
|
|
3079
|
+
|
|
3062
3080
|
const handleSubmit = async () => {
|
|
3063
3081
|
if (!title.trim()) {
|
|
3064
3082
|
showToast("Title is required", "error");
|
|
@@ -3067,6 +3085,7 @@ function CreateTaskModalInline({ onClose }) {
|
|
|
3067
3085
|
setSubmitting(true);
|
|
3068
3086
|
haptic("medium");
|
|
3069
3087
|
const tags = normalizeTagInput(tagsInput);
|
|
3088
|
+
const effectiveRepos = repositories.length > 0 ? repositories : (repository ? [repository] : []);
|
|
3070
3089
|
try {
|
|
3071
3090
|
await apiFetch("/api/tasks/create", {
|
|
3072
3091
|
method: "POST",
|
|
@@ -3079,7 +3098,8 @@ function CreateTaskModalInline({ onClose }) {
|
|
|
3079
3098
|
draft,
|
|
3080
3099
|
status: draft ? "draft" : "todo",
|
|
3081
3100
|
workspace: workspaceId || undefined,
|
|
3082
|
-
repository:
|
|
3101
|
+
repository: effectiveRepos[0] || undefined,
|
|
3102
|
+
repositories: effectiveRepos.length > 1 ? effectiveRepos : undefined,
|
|
3083
3103
|
}),
|
|
3084
3104
|
});
|
|
3085
3105
|
showToast("Task created", "success");
|
|
@@ -3185,8 +3205,8 @@ function CreateTaskModalInline({ onClose }) {
|
|
|
3185
3205
|
title="Use AI to expand and improve this task description"
|
|
3186
3206
|
>
|
|
3187
3207
|
${rewriting
|
|
3188
|
-
? html`<span class="spin-icon" style="display:inline-block;animation:spin 0.8s linear infinite">${resolveIcon("
|
|
3189
|
-
: html`${iconText("
|
|
3208
|
+
? html`<span class="spin-icon" style="display:inline-block;animation:spin 0.8s linear infinite">${resolveIcon(":clock:")}</span> Improving…`
|
|
3209
|
+
: html`${iconText(":star: Improve with AI")}`
|
|
3190
3210
|
}
|
|
3191
3211
|
</button>
|
|
3192
3212
|
|
|
@@ -3215,21 +3235,30 @@ function CreateTaskModalInline({ onClose }) {
|
|
|
3215
3235
|
(ws) => html`<option value=${ws.id}>${ws.name || ws.id}</option>`,
|
|
3216
3236
|
)}
|
|
3217
3237
|
</select>
|
|
3218
|
-
<select
|
|
3219
|
-
class="input"
|
|
3220
|
-
value=${repository}
|
|
3221
|
-
onChange=${(e) => setRepository(e.target.value)}
|
|
3222
|
-
disabled=${!repositoryOptions.length}
|
|
3223
|
-
>
|
|
3224
|
-
<option value="">
|
|
3225
|
-
${repositoryOptions.length ? "Auto repo" : "No repos"}
|
|
3226
|
-
</option>
|
|
3227
|
-
${repositoryOptions.map(
|
|
3228
|
-
(repo) =>
|
|
3229
|
-
html`<option value=${repo.slug}>${repo.name}${repo.primary ? " (Primary)" : ""}</option>`,
|
|
3230
|
-
)}
|
|
3231
|
-
</select>
|
|
3232
3238
|
</div>
|
|
3239
|
+
${repositoryOptions.length > 0 && html`
|
|
3240
|
+
<div class="repo-select-group">
|
|
3241
|
+
${repositoryOptions.length === 1
|
|
3242
|
+
? html`<div class="repo-auto-label">
|
|
3243
|
+
Repo: <strong>${repositoryOptions[0].name}</strong>
|
|
3244
|
+
${repositoryOptions[0].primary ? " (Primary)" : ""}
|
|
3245
|
+
</div>`
|
|
3246
|
+
: html`<div class="repo-checkboxes">
|
|
3247
|
+
<span class="repo-checkboxes-label">Repositories</span>
|
|
3248
|
+
${repositoryOptions.map((repo) => html`
|
|
3249
|
+
<label class="repo-checkbox-item">
|
|
3250
|
+
<input
|
|
3251
|
+
type="checkbox"
|
|
3252
|
+
checked=${repositories.includes(repo.slug)}
|
|
3253
|
+
onChange=${() => toggleRepo(repo.slug)}
|
|
3254
|
+
/>
|
|
3255
|
+
${repo.name}${repo.primary ? " (Primary)" : ""}
|
|
3256
|
+
</label>
|
|
3257
|
+
`)}
|
|
3258
|
+
</div>`
|
|
3259
|
+
}
|
|
3260
|
+
</div>
|
|
3261
|
+
`}
|
|
3233
3262
|
`}
|
|
3234
3263
|
|
|
3235
3264
|
<!-- Tags -->
|
|
@@ -3252,7 +3281,7 @@ function CreateTaskModalInline({ onClose }) {
|
|
|
3252
3281
|
onClick=${() => setShowAdvanced(!showAdvanced)}
|
|
3253
3282
|
type="button"
|
|
3254
3283
|
>
|
|
3255
|
-
<span style="display:inline-block;transition:transform 0.15s;transform:rotate(${showAdvanced ? 90 : 0}deg)"
|
|
3284
|
+
<span style="display:inline-block;transition:transform 0.15s;transform:rotate(${showAdvanced ? 90 : 0}deg)">:play:</span>
|
|
3256
3285
|
Advanced${hasAdvanced && !showAdvanced ? " •" : ""}
|
|
3257
3286
|
</button>
|
|
3258
3287
|
|