@syncended/dsh-automations 0.2.1 → 0.3.0
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/README.md +2 -2
- package/docs/architecture.md +4 -2
- package/lib/client.js +578 -228
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ A DeepSeek Harness plugin for durable, configurable cron jobs. Each occurrence s
|
|
|
8
8
|
|
|
9
9
|
- Standard five-field cron expressions with `UTC` or IANA timezones.
|
|
10
10
|
- Per-job project directory, provider/model, reasoning effort, agent preset, permission preset, and timeout.
|
|
11
|
-
- Enable/disable, Run now, edit, delete, cancel, and recent run history from the main **Automations** sidebar action or **Settings → Automations**.
|
|
11
|
+
- Enable/disable, Run now, edit, delete, cancel, and recent run history from a full center workspace opened by the main **Automations** sidebar action, or from **Settings → Automations**.
|
|
12
12
|
- Overlap policies:
|
|
13
13
|
- `skip` — record and skip an occurrence while the job has queued/running work.
|
|
14
14
|
- `queue` — serialize occurrences for the same job.
|
|
@@ -42,7 +42,7 @@ pnpm build
|
|
|
42
42
|
dsh plugin --profile web add .
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
The package declares a DSH bundle, so `dsh plugin` appends it to the Web profile automatically. Restart the running Web Harness after the initial install, then refresh the page. Open **Automations** from the main sidebar, or use **Settings → Automations**.
|
|
45
|
+
The package declares a DSH bundle, so `dsh plugin` appends it to the Web profile automatically. Restart the running Web Harness after the initial install, then refresh the page. Open the full **Automations** workspace from the main sidebar, or use **Settings → Automations**.
|
|
46
46
|
|
|
47
47
|
To remove it:
|
|
48
48
|
|
package/docs/architecture.md
CHANGED
|
@@ -15,7 +15,7 @@ Non-goals for the first release:
|
|
|
15
15
|
## Components
|
|
16
16
|
|
|
17
17
|
```text
|
|
18
|
-
Sidebar / Settings UI / HTTP API
|
|
18
|
+
Sidebar / Center workspace / Settings UI / HTTP API
|
|
19
19
|
│
|
|
20
20
|
▼
|
|
21
21
|
AutomationService ─── ProjectPolicy
|
|
@@ -30,7 +30,9 @@ Sidebar / Settings UI / HTTP API
|
|
|
30
30
|
|
|
31
31
|
### Browser surfaces
|
|
32
32
|
|
|
33
|
-
The same automation page is available through
|
|
33
|
+
The same automation page is available through Settings and a dedicated center workspace. `settings.section` keeps configuration available inside Settings; `sidebar.footer.action` activates a temporary, higher-priority `conversation` entry that replaces the current center occupant. This provides a split-screen-like full-center experience while using the single-slot election directly rather than Split Screen's internal view contributions. Closing Automations disposes its entry immediately, revealing whichever center surface was previously active. A small client-only disclosure store coordinates the sidebar trigger and dynamic registration; neither surface owns scheduler state, and both read the same package HTTP API.
|
|
34
|
+
|
|
35
|
+
Interactive chrome uses the ambient `@deepseek-ai/dsh-client-ui-primitives` `Button`, `Menu`, and icon components. Package CSS is limited to the automation-specific layout and composes only public DSH semantic tokens, so theme, menu, focus, and button behavior stay aligned with the host UI.
|
|
34
36
|
|
|
35
37
|
### AutomationService
|
|
36
38
|
|
package/lib/client.js
CHANGED
|
@@ -13,6 +13,23 @@ window.__ModuleLoader__.load({
|
|
|
13
13
|
const React = require("react");
|
|
14
14
|
const h = React.createElement;
|
|
15
15
|
const { useCallback, useEffect, useId, useRef, useState, useSyncExternalStore } = React;
|
|
16
|
+
const {
|
|
17
|
+
Button,
|
|
18
|
+
Menu,
|
|
19
|
+
RiskConfirmation,
|
|
20
|
+
IconAgentPresetOutline16,
|
|
21
|
+
IconBrowseOutline16,
|
|
22
|
+
IconCheckOutline16,
|
|
23
|
+
IconChevronDownOutline14,
|
|
24
|
+
IconChevronLeftOutline14,
|
|
25
|
+
IconEditOutline16,
|
|
26
|
+
IconPlayOutline16,
|
|
27
|
+
IconPlusOutline16,
|
|
28
|
+
IconRefreshOutline16,
|
|
29
|
+
IconSettingsOutline16,
|
|
30
|
+
IconTrashOutline16,
|
|
31
|
+
IconWarningOutline16,
|
|
32
|
+
} = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
16
33
|
const inject = ["slots"];
|
|
17
34
|
|
|
18
35
|
const API_PREFIX = "/api/automations";
|
|
@@ -73,6 +90,26 @@ window.__ModuleLoader__.load({
|
|
|
73
90
|
minimal: "Minimal mode",
|
|
74
91
|
cordis: "Creator mode",
|
|
75
92
|
};
|
|
93
|
+
const PERMISSION_PRESET_PRESENTATION = {
|
|
94
|
+
"read-only": {
|
|
95
|
+
label: "Read Only",
|
|
96
|
+
detail: "Read files without modifying the workspace.",
|
|
97
|
+
icon: IconBrowseOutline16,
|
|
98
|
+
tone: "read",
|
|
99
|
+
},
|
|
100
|
+
"workspace-write": {
|
|
101
|
+
label: "Workspace Write",
|
|
102
|
+
detail: "Write inside the workspace; wider retries require approval.",
|
|
103
|
+
icon: IconEditOutline16,
|
|
104
|
+
tone: "write",
|
|
105
|
+
},
|
|
106
|
+
"danger-full-access": {
|
|
107
|
+
label: "Full access",
|
|
108
|
+
detail: "Full file access without approval prompts.",
|
|
109
|
+
icon: IconWarningOutline16,
|
|
110
|
+
tone: "danger",
|
|
111
|
+
},
|
|
112
|
+
};
|
|
76
113
|
|
|
77
114
|
function humanizePresetId(id) {
|
|
78
115
|
return id
|
|
@@ -91,6 +128,24 @@ window.__ModuleLoader__.load({
|
|
|
91
128
|
return readableId === id ? id : readableId + " (" + id + ")";
|
|
92
129
|
}
|
|
93
130
|
|
|
131
|
+
function permissionPresetPresentation(value) {
|
|
132
|
+
const known = PERMISSION_PRESET_PRESENTATION[value];
|
|
133
|
+
if (known) return known;
|
|
134
|
+
return {
|
|
135
|
+
label: humanizePresetId(value) || value || "Unknown permission",
|
|
136
|
+
detail: "Host-provided permission preset.",
|
|
137
|
+
icon: IconSettingsOutline16,
|
|
138
|
+
tone: "custom",
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function PermissionPresetIcon({ value, className }) {
|
|
143
|
+
const presentation = permissionPresetPresentation(value);
|
|
144
|
+
return h(presentation.icon, {
|
|
145
|
+
className: (className ? className + " " : "") + "dsh-auto-permission-glyph dsh-auto-permission-glyph-" + presentation.tone,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
94
149
|
function browserTimezone() {
|
|
95
150
|
return BROWSER_TIMEZONE;
|
|
96
151
|
}
|
|
@@ -258,6 +313,289 @@ window.__ModuleLoader__.load({
|
|
|
258
313
|
);
|
|
259
314
|
}
|
|
260
315
|
|
|
316
|
+
function pickerMenuFor(ownerId) {
|
|
317
|
+
return Array.from(document.querySelectorAll('[role="menu"]')).find((menu) =>
|
|
318
|
+
Array.from(menu.querySelectorAll("[data-dsh-auto-picker-owner]")).some((item) =>
|
|
319
|
+
item.getAttribute("data-dsh-auto-picker-owner") === ownerId,
|
|
320
|
+
),
|
|
321
|
+
) || null;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function focusPickerTrigger(triggerRef) {
|
|
325
|
+
requestAnimationFrame(() => triggerRef.current?.focus());
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function focusAfterPickerTab(trigger, backwards) {
|
|
329
|
+
requestAnimationFrame(() => {
|
|
330
|
+
const focusBoundary = trigger?.closest(".dsh-auto-form") || trigger?.closest('[role="dialog"]');
|
|
331
|
+
if (!focusBoundary) {
|
|
332
|
+
trigger?.focus();
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const focusables = visibleFocusables(focusBoundary);
|
|
336
|
+
const index = focusables.indexOf(trigger);
|
|
337
|
+
const target = index < 0 ? trigger : focusables[index + (backwards ? -1 : 1)];
|
|
338
|
+
(target || trigger)?.focus();
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function usePickerMenuNavigation({ open, setOpen, ownerId, selectedId, triggerRef }) {
|
|
343
|
+
useEffect(() => {
|
|
344
|
+
if (!open) return;
|
|
345
|
+
const focusSelected = () => {
|
|
346
|
+
const menu = pickerMenuFor(ownerId);
|
|
347
|
+
if (!menu) return;
|
|
348
|
+
const buttons = Array.from(menu.querySelectorAll('button[role="menuitem"]:not(:disabled)'));
|
|
349
|
+
const selected = buttons.find((button) =>
|
|
350
|
+
button.querySelector("[data-dsh-auto-picker-item]")?.getAttribute("data-dsh-auto-picker-item") === selectedId,
|
|
351
|
+
);
|
|
352
|
+
(selected || buttons[0])?.focus();
|
|
353
|
+
};
|
|
354
|
+
const frame = requestAnimationFrame(focusSelected);
|
|
355
|
+
const onKeyDown = (event) => {
|
|
356
|
+
const menu = pickerMenuFor(ownerId);
|
|
357
|
+
if (!menu || !(event.target instanceof Node) || !menu.contains(event.target)) return;
|
|
358
|
+
const buttons = Array.from(menu.querySelectorAll('button[role="menuitem"]:not(:disabled)'));
|
|
359
|
+
const index = buttons.indexOf(event.target.closest('button[role="menuitem"]'));
|
|
360
|
+
let target;
|
|
361
|
+
if (event.key === "ArrowDown") target = buttons[(Math.max(index, -1) + 1) % buttons.length];
|
|
362
|
+
else if (event.key === "ArrowUp") target = buttons[(index <= 0 ? buttons.length : index) - 1];
|
|
363
|
+
else if (event.key === "Home") target = buttons[0];
|
|
364
|
+
else if (event.key === "End") target = buttons[buttons.length - 1];
|
|
365
|
+
else if (event.key === "Escape") {
|
|
366
|
+
event.preventDefault();
|
|
367
|
+
event.stopImmediatePropagation();
|
|
368
|
+
setOpen(false);
|
|
369
|
+
focusPickerTrigger(triggerRef);
|
|
370
|
+
return;
|
|
371
|
+
} else if (event.key === "Tab") {
|
|
372
|
+
event.preventDefault();
|
|
373
|
+
event.stopImmediatePropagation();
|
|
374
|
+
setOpen(false);
|
|
375
|
+
focusAfterPickerTab(triggerRef.current, event.shiftKey);
|
|
376
|
+
return;
|
|
377
|
+
} else return;
|
|
378
|
+
if (!target) return;
|
|
379
|
+
event.preventDefault();
|
|
380
|
+
target.focus();
|
|
381
|
+
};
|
|
382
|
+
document.addEventListener("keydown", onKeyDown, true);
|
|
383
|
+
return () => {
|
|
384
|
+
cancelAnimationFrame(frame);
|
|
385
|
+
document.removeEventListener("keydown", onKeyDown, true);
|
|
386
|
+
};
|
|
387
|
+
}, [open, ownerId, selectedId, setOpen, triggerRef]);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function openPickerFromKeyboard(event, setOpen) {
|
|
391
|
+
if (event.key !== "ArrowDown" && event.key !== "ArrowUp") return;
|
|
392
|
+
event.preventDefault();
|
|
393
|
+
setOpen(true);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function useRiskConfirmationFocus(open) {
|
|
397
|
+
useEffect(() => {
|
|
398
|
+
if (!open) return;
|
|
399
|
+
const riskDialog = () => Array.from(document.querySelectorAll('[role="dialog"]')).find((dialog) =>
|
|
400
|
+
dialog.getAttribute("aria-label") === "Enable Full access?",
|
|
401
|
+
) || null;
|
|
402
|
+
let innerFrame;
|
|
403
|
+
const frame = requestAnimationFrame(() => {
|
|
404
|
+
innerFrame = requestAnimationFrame(() => {
|
|
405
|
+
riskDialog()?.querySelector('input[type="checkbox"]')?.focus();
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
const onKeyDown = (event) => {
|
|
409
|
+
const dialog = riskDialog();
|
|
410
|
+
if (!dialog) return;
|
|
411
|
+
if (event.key === "Escape" && dialog.contains(event.target)) {
|
|
412
|
+
event.__dshAutomationsNested = true;
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
if (event.key !== "Tab") return;
|
|
416
|
+
const focusables = visibleFocusables(dialog);
|
|
417
|
+
if (focusables.length === 0) return;
|
|
418
|
+
const index = focusables.indexOf(event.target);
|
|
419
|
+
const next = event.shiftKey
|
|
420
|
+
? focusables[index <= 0 ? focusables.length - 1 : index - 1]
|
|
421
|
+
: focusables[index < 0 || index === focusables.length - 1 ? 0 : index + 1];
|
|
422
|
+
event.preventDefault();
|
|
423
|
+
event.stopImmediatePropagation();
|
|
424
|
+
next.focus();
|
|
425
|
+
};
|
|
426
|
+
document.addEventListener("keydown", onKeyDown, true);
|
|
427
|
+
return () => {
|
|
428
|
+
cancelAnimationFrame(frame);
|
|
429
|
+
if (innerFrame !== undefined) cancelAnimationFrame(innerFrame);
|
|
430
|
+
document.removeEventListener("keydown", onKeyDown, true);
|
|
431
|
+
};
|
|
432
|
+
}, [open]);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function PickerItemCopy({ label, detail, ownerId, itemId }) {
|
|
436
|
+
return h(
|
|
437
|
+
"span",
|
|
438
|
+
{
|
|
439
|
+
className: "dsh-auto-picker-item-copy",
|
|
440
|
+
"data-dsh-auto-picker-owner": ownerId,
|
|
441
|
+
"data-dsh-auto-picker-item": itemId,
|
|
442
|
+
},
|
|
443
|
+
h("span", { className: "dsh-auto-picker-item-label" }, label),
|
|
444
|
+
detail ? h("span", { className: "dsh-auto-picker-item-detail" }, detail) : null,
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function AgentPresetPicker({ id, value, presets, onChange }) {
|
|
449
|
+
const [open, setOpen] = useState(false);
|
|
450
|
+
const ownerId = useId();
|
|
451
|
+
const triggerRef = useRef(null);
|
|
452
|
+
usePickerMenuNavigation({ open, setOpen, ownerId, selectedId: value, triggerRef });
|
|
453
|
+
const selected = presets.find((preset) => preset.id === value);
|
|
454
|
+
const label = value === ""
|
|
455
|
+
? "Harness default"
|
|
456
|
+
: agentPresetDisplayLabel(selected || { id: value, name: value });
|
|
457
|
+
const items = [
|
|
458
|
+
{
|
|
459
|
+
id: "",
|
|
460
|
+
label: h(PickerItemCopy, {
|
|
461
|
+
label: "Harness default",
|
|
462
|
+
detail: "Use the current Harness agent preset.",
|
|
463
|
+
ownerId,
|
|
464
|
+
itemId: "",
|
|
465
|
+
}),
|
|
466
|
+
icon: h(IconAgentPresetOutline16),
|
|
467
|
+
},
|
|
468
|
+
...presets.map((preset) => ({
|
|
469
|
+
id: preset.id,
|
|
470
|
+
label: h(PickerItemCopy, {
|
|
471
|
+
label: agentPresetDisplayLabel(preset),
|
|
472
|
+
detail: preset.broken ? "Failed to load: " + preset.broken : null,
|
|
473
|
+
ownerId,
|
|
474
|
+
itemId: preset.id,
|
|
475
|
+
}),
|
|
476
|
+
icon: h(IconAgentPresetOutline16),
|
|
477
|
+
disabled: Boolean(preset.broken),
|
|
478
|
+
})),
|
|
479
|
+
];
|
|
480
|
+
return h(Menu, {
|
|
481
|
+
open,
|
|
482
|
+
onClose: () => setOpen(false),
|
|
483
|
+
items,
|
|
484
|
+
selectedId: value,
|
|
485
|
+
onSelect: (next) => {
|
|
486
|
+
setOpen(false);
|
|
487
|
+
onChange(next);
|
|
488
|
+
focusPickerTrigger(triggerRef);
|
|
489
|
+
},
|
|
490
|
+
side: "top",
|
|
491
|
+
portal: true,
|
|
492
|
+
className: "dsh-auto-picker-root",
|
|
493
|
+
anchor: h(
|
|
494
|
+
"button",
|
|
495
|
+
{
|
|
496
|
+
ref: triggerRef,
|
|
497
|
+
id,
|
|
498
|
+
type: "button",
|
|
499
|
+
className: "dsh-auto-picker-trigger",
|
|
500
|
+
"aria-haspopup": "menu",
|
|
501
|
+
"aria-expanded": open,
|
|
502
|
+
onKeyDown: (event) => openPickerFromKeyboard(event, setOpen),
|
|
503
|
+
onClick: () => setOpen((current) => !current),
|
|
504
|
+
},
|
|
505
|
+
h(IconAgentPresetOutline16, { className: "dsh-auto-picker-trigger-icon" }),
|
|
506
|
+
h("span", { className: "dsh-auto-picker-trigger-label" }, label),
|
|
507
|
+
h(IconChevronDownOutline14, { className: "dsh-auto-picker-chevron" + (open ? " dsh-auto-picker-chevron-open" : "") }),
|
|
508
|
+
),
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function PermissionPresetPicker({ id, value, presets, onChange }) {
|
|
513
|
+
const [open, setOpen] = useState(false);
|
|
514
|
+
const [confirmingFullAccess, setConfirmingFullAccess] = useState(false);
|
|
515
|
+
const [acknowledged, setAcknowledged] = useState(false);
|
|
516
|
+
const ownerId = useId();
|
|
517
|
+
const triggerRef = useRef(null);
|
|
518
|
+
usePickerMenuNavigation({ open, setOpen, ownerId, selectedId: value, triggerRef });
|
|
519
|
+
useRiskConfirmationFocus(confirmingFullAccess);
|
|
520
|
+
const selected = permissionPresetPresentation(value);
|
|
521
|
+
const items = presets.map((preset) => {
|
|
522
|
+
const presentation = permissionPresetPresentation(preset);
|
|
523
|
+
return {
|
|
524
|
+
id: preset,
|
|
525
|
+
label: h(PickerItemCopy, {
|
|
526
|
+
label: presentation.label,
|
|
527
|
+
detail: presentation.detail,
|
|
528
|
+
ownerId,
|
|
529
|
+
itemId: preset,
|
|
530
|
+
}),
|
|
531
|
+
icon: h(PermissionPresetIcon, { value: preset }),
|
|
532
|
+
danger: preset === "danger-full-access",
|
|
533
|
+
};
|
|
534
|
+
});
|
|
535
|
+
const closeConfirmation = () => {
|
|
536
|
+
setConfirmingFullAccess(false);
|
|
537
|
+
setAcknowledged(false);
|
|
538
|
+
focusPickerTrigger(triggerRef);
|
|
539
|
+
};
|
|
540
|
+
return h(
|
|
541
|
+
React.Fragment,
|
|
542
|
+
null,
|
|
543
|
+
h(Menu, {
|
|
544
|
+
open,
|
|
545
|
+
onClose: () => setOpen(false),
|
|
546
|
+
items,
|
|
547
|
+
selectedId: value,
|
|
548
|
+
onSelect: (next) => {
|
|
549
|
+
setOpen(false);
|
|
550
|
+
if (next === "danger-full-access" && value !== "danger-full-access") {
|
|
551
|
+
setAcknowledged(false);
|
|
552
|
+
setConfirmingFullAccess(true);
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
onChange(next);
|
|
556
|
+
focusPickerTrigger(triggerRef);
|
|
557
|
+
},
|
|
558
|
+
side: "top",
|
|
559
|
+
portal: true,
|
|
560
|
+
className: "dsh-auto-picker-root",
|
|
561
|
+
anchor: h(
|
|
562
|
+
"button",
|
|
563
|
+
{
|
|
564
|
+
ref: triggerRef,
|
|
565
|
+
id,
|
|
566
|
+
type: "button",
|
|
567
|
+
className: "dsh-auto-picker-trigger",
|
|
568
|
+
"data-permission-preset": value,
|
|
569
|
+
"aria-haspopup": "menu",
|
|
570
|
+
"aria-expanded": open,
|
|
571
|
+
onKeyDown: (event) => openPickerFromKeyboard(event, setOpen),
|
|
572
|
+
onClick: () => setOpen((current) => !current),
|
|
573
|
+
},
|
|
574
|
+
h(PermissionPresetIcon, { value, className: "dsh-auto-picker-trigger-icon" }),
|
|
575
|
+
h("span", { className: "dsh-auto-picker-trigger-label" }, selected.label),
|
|
576
|
+
h(IconChevronDownOutline14, { className: "dsh-auto-picker-chevron" + (open ? " dsh-auto-picker-chevron-open" : "") }),
|
|
577
|
+
),
|
|
578
|
+
}),
|
|
579
|
+
h(RiskConfirmation, {
|
|
580
|
+
open: confirmingFullAccess,
|
|
581
|
+
title: "Enable Full access?",
|
|
582
|
+
description: "Full access lets scheduled agents perform sensitive actions, file changes, and external commands without approval prompts. Only use it for automations you trust.",
|
|
583
|
+
acknowledgeLabel: "I understand the risks and want to continue",
|
|
584
|
+
cancelLabel: "Cancel",
|
|
585
|
+
confirmLabel: "Enable Full access",
|
|
586
|
+
acknowledged,
|
|
587
|
+
onAcknowledgedChange: setAcknowledged,
|
|
588
|
+
onCancel: closeConfirmation,
|
|
589
|
+
onConfirm: () => {
|
|
590
|
+
setConfirmingFullAccess(false);
|
|
591
|
+
setAcknowledged(false);
|
|
592
|
+
onChange("danger-full-access");
|
|
593
|
+
focusPickerTrigger(triggerRef);
|
|
594
|
+
},
|
|
595
|
+
}),
|
|
596
|
+
);
|
|
597
|
+
}
|
|
598
|
+
|
|
261
599
|
function StatusPill(props) {
|
|
262
600
|
return h("span", { className: "dsh-auto-status dsh-auto-status-" + props.status }, props.status);
|
|
263
601
|
}
|
|
@@ -273,6 +611,8 @@ window.__ModuleLoader__.load({
|
|
|
273
611
|
: ["workspace-write"];
|
|
274
612
|
const agentPresets = meta && Array.isArray(meta.agentPresets) ? meta.agentPresets : [];
|
|
275
613
|
const creating = editing === null;
|
|
614
|
+
const formPrefix = "dsh-auto-form-" + String(useId()).replace(/[^A-Za-z0-9_-]/g, "");
|
|
615
|
+
const fieldId = (name) => formPrefix + "-" + name;
|
|
276
616
|
|
|
277
617
|
return h(
|
|
278
618
|
"form",
|
|
@@ -288,9 +628,9 @@ window.__ModuleLoader__.load({
|
|
|
288
628
|
{ className: "dsh-auto-formgrid" },
|
|
289
629
|
h(
|
|
290
630
|
Field,
|
|
291
|
-
{ label: "Name", htmlFor: "
|
|
631
|
+
{ label: "Name", htmlFor: fieldId("name"), required: true },
|
|
292
632
|
h("input", {
|
|
293
|
-
id: "
|
|
633
|
+
id: fieldId("name"),
|
|
294
634
|
className: "dsh-auto-input",
|
|
295
635
|
type: "text",
|
|
296
636
|
value: draft.name,
|
|
@@ -302,9 +642,9 @@ window.__ModuleLoader__.load({
|
|
|
302
642
|
creating
|
|
303
643
|
? h(
|
|
304
644
|
Field,
|
|
305
|
-
{ label: "Job id", htmlFor: "
|
|
645
|
+
{ label: "Job id", htmlFor: fieldId("id"), hint: "Lowercase letters, digits and hyphens; auto-derived from the name. Leave blank to let the server generate one." },
|
|
306
646
|
h("input", {
|
|
307
|
-
id: "
|
|
647
|
+
id: fieldId("id"),
|
|
308
648
|
className: "dsh-auto-input",
|
|
309
649
|
type: "text",
|
|
310
650
|
value: draft.id,
|
|
@@ -318,9 +658,9 @@ window.__ModuleLoader__.load({
|
|
|
318
658
|
)
|
|
319
659
|
: h(
|
|
320
660
|
Field,
|
|
321
|
-
{ label: "Job id", htmlFor: "
|
|
661
|
+
{ label: "Job id", htmlFor: fieldId("id"), hint: "Fixed after creation." },
|
|
322
662
|
h("input", {
|
|
323
|
-
id: "
|
|
663
|
+
id: fieldId("id"),
|
|
324
664
|
className: "dsh-auto-input",
|
|
325
665
|
type: "text",
|
|
326
666
|
value: draft.id,
|
|
@@ -330,9 +670,9 @@ window.__ModuleLoader__.load({
|
|
|
330
670
|
),
|
|
331
671
|
h(
|
|
332
672
|
Field,
|
|
333
|
-
{ label: "Cron", htmlFor: "
|
|
673
|
+
{ label: "Cron", htmlFor: fieldId("cron"), required: true, hint: "Five-field cron (minute hour day-of-month month day-of-week)." },
|
|
334
674
|
h("input", {
|
|
335
|
-
id: "
|
|
675
|
+
id: fieldId("cron"),
|
|
336
676
|
className: "dsh-auto-input",
|
|
337
677
|
type: "text",
|
|
338
678
|
value: draft.cron,
|
|
@@ -342,30 +682,30 @@ window.__ModuleLoader__.load({
|
|
|
342
682
|
),
|
|
343
683
|
h(
|
|
344
684
|
Field,
|
|
345
|
-
{ label: "Timezone", htmlFor: "
|
|
685
|
+
{ label: "Timezone", htmlFor: fieldId("timezone"), required: true },
|
|
346
686
|
h("input", {
|
|
347
|
-
id: "
|
|
687
|
+
id: fieldId("timezone"),
|
|
348
688
|
className: "dsh-auto-input",
|
|
349
689
|
type: "text",
|
|
350
|
-
list: "
|
|
690
|
+
list: fieldId("timezone-list"),
|
|
351
691
|
value: draft.timezone,
|
|
352
692
|
spellCheck: false,
|
|
353
693
|
onChange: (event) => onChange("timezone", event.target.value),
|
|
354
694
|
}),
|
|
355
695
|
h(
|
|
356
696
|
"datalist",
|
|
357
|
-
{ id: "
|
|
697
|
+
{ id: fieldId("timezone-list") },
|
|
358
698
|
TIMEZONES.map((zone) => h("option", { key: zone, value: zone })),
|
|
359
699
|
),
|
|
360
700
|
),
|
|
361
701
|
h(
|
|
362
702
|
Field,
|
|
363
|
-
{ label: "Enabled", htmlFor: "
|
|
703
|
+
{ label: "Enabled", htmlFor: fieldId("enabled") },
|
|
364
704
|
h(
|
|
365
705
|
"label",
|
|
366
706
|
{ className: "dsh-auto-check" },
|
|
367
707
|
h("input", {
|
|
368
|
-
id: "
|
|
708
|
+
id: fieldId("enabled"),
|
|
369
709
|
type: "checkbox",
|
|
370
710
|
checked: draft.enabled,
|
|
371
711
|
onChange: (event) => onChange("enabled", event.target.checked),
|
|
@@ -375,9 +715,9 @@ window.__ModuleLoader__.load({
|
|
|
375
715
|
),
|
|
376
716
|
h(
|
|
377
717
|
Field,
|
|
378
|
-
{ label: "Timeout (ms)", htmlFor: "
|
|
718
|
+
{ label: "Timeout (ms)", htmlFor: fieldId("timeout"), required: true, hint: "Wall-clock limit for each run (1s to 24h)." },
|
|
379
719
|
h("input", {
|
|
380
|
-
id: "
|
|
720
|
+
id: fieldId("timeout"),
|
|
381
721
|
className: "dsh-auto-input",
|
|
382
722
|
type: "number",
|
|
383
723
|
min: MIN_TIMEOUT_MS,
|
|
@@ -389,12 +729,12 @@ window.__ModuleLoader__.load({
|
|
|
389
729
|
),
|
|
390
730
|
h(
|
|
391
731
|
Field,
|
|
392
|
-
{ label: "Provider", htmlFor: "
|
|
732
|
+
{ label: "Provider", htmlFor: fieldId("provider"), hint: "Blank uses the current Harness default. You may type an unlisted provider route." },
|
|
393
733
|
h("input", {
|
|
394
|
-
id: "
|
|
734
|
+
id: fieldId("provider"),
|
|
395
735
|
className: "dsh-auto-input",
|
|
396
736
|
type: "text",
|
|
397
|
-
list: "
|
|
737
|
+
list: fieldId("provider-list"),
|
|
398
738
|
value: draft.provider,
|
|
399
739
|
spellCheck: false,
|
|
400
740
|
placeholder: "Harness default",
|
|
@@ -402,7 +742,7 @@ window.__ModuleLoader__.load({
|
|
|
402
742
|
}),
|
|
403
743
|
h(
|
|
404
744
|
"datalist",
|
|
405
|
-
{ id: "
|
|
745
|
+
{ id: fieldId("provider-list") },
|
|
406
746
|
providers.map((provider) => h("option", { key: provider.id, value: provider.id })),
|
|
407
747
|
),
|
|
408
748
|
),
|
|
@@ -410,17 +750,17 @@ window.__ModuleLoader__.load({
|
|
|
410
750
|
Field,
|
|
411
751
|
{
|
|
412
752
|
label: "Model",
|
|
413
|
-
htmlFor: "
|
|
753
|
+
htmlFor: fieldId("model"),
|
|
414
754
|
required: draft.provider !== "",
|
|
415
755
|
hint: draft.provider === ""
|
|
416
756
|
? "Set a provider first, or leave both blank for the Harness default."
|
|
417
757
|
: "Choose a discovered model or type an adapter-supported model id.",
|
|
418
758
|
},
|
|
419
759
|
h("input", {
|
|
420
|
-
id: "
|
|
760
|
+
id: fieldId("model"),
|
|
421
761
|
className: "dsh-auto-input",
|
|
422
762
|
type: "text",
|
|
423
|
-
list: "
|
|
763
|
+
list: fieldId("model-list"),
|
|
424
764
|
value: draft.model,
|
|
425
765
|
spellCheck: false,
|
|
426
766
|
placeholder: draft.provider === "" ? "Harness default" : "Model id",
|
|
@@ -429,18 +769,18 @@ window.__ModuleLoader__.load({
|
|
|
429
769
|
}),
|
|
430
770
|
h(
|
|
431
771
|
"datalist",
|
|
432
|
-
{ id: "
|
|
772
|
+
{ id: fieldId("model-list") },
|
|
433
773
|
models.map((model) => h("option", { key: model, value: model })),
|
|
434
774
|
),
|
|
435
775
|
),
|
|
436
776
|
h(
|
|
437
777
|
Field,
|
|
438
|
-
{ label: "Reasoning effort", htmlFor: "
|
|
778
|
+
{ label: "Reasoning effort", htmlFor: fieldId("effort"), hint: "Blank uses the provider default." },
|
|
439
779
|
h("input", {
|
|
440
|
-
id: "
|
|
780
|
+
id: fieldId("effort"),
|
|
441
781
|
className: "dsh-auto-input",
|
|
442
782
|
type: "text",
|
|
443
|
-
list: "
|
|
783
|
+
list: fieldId("effort-list"),
|
|
444
784
|
value: draft.reasoningEffort,
|
|
445
785
|
spellCheck: false,
|
|
446
786
|
placeholder: "e.g. medium",
|
|
@@ -448,52 +788,42 @@ window.__ModuleLoader__.load({
|
|
|
448
788
|
}),
|
|
449
789
|
h(
|
|
450
790
|
"datalist",
|
|
451
|
-
{ id: "
|
|
791
|
+
{ id: fieldId("effort-list") },
|
|
452
792
|
REASONING_EFFORTS.map((effort) => h("option", { key: effort, value: effort })),
|
|
453
793
|
),
|
|
454
794
|
),
|
|
455
795
|
h(
|
|
456
796
|
Field,
|
|
457
|
-
{ label: "Agent preset", htmlFor: "
|
|
458
|
-
h(
|
|
459
|
-
"
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
onChange: (event) => onChange("agentPreset", event.target.value),
|
|
465
|
-
},
|
|
466
|
-
h("option", { value: "" }, "Harness default"),
|
|
467
|
-
agentPresets.map((preset) =>
|
|
468
|
-
h(
|
|
469
|
-
"option",
|
|
470
|
-
{ key: preset.id, value: preset.id },
|
|
471
|
-
agentPresetDisplayLabel(preset) + (preset.broken ? " (broken: " + preset.broken + ")" : ""),
|
|
472
|
-
),
|
|
473
|
-
),
|
|
474
|
-
),
|
|
797
|
+
{ label: "Agent preset", htmlFor: fieldId("preset"), hint: "Uses the current Harness default when not explicitly selected." },
|
|
798
|
+
h(AgentPresetPicker, {
|
|
799
|
+
id: fieldId("preset"),
|
|
800
|
+
value: draft.agentPreset,
|
|
801
|
+
presets: agentPresets,
|
|
802
|
+
onChange: (value) => onChange("agentPreset", value),
|
|
803
|
+
}),
|
|
475
804
|
),
|
|
476
805
|
h(
|
|
477
806
|
Field,
|
|
478
|
-
{
|
|
479
|
-
|
|
480
|
-
"
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
807
|
+
{
|
|
808
|
+
label: "Permission preset",
|
|
809
|
+
htmlFor: fieldId("permission"),
|
|
810
|
+
required: true,
|
|
811
|
+
hint: permissionPresetPresentation(draft.permissionPreset).detail,
|
|
812
|
+
},
|
|
813
|
+
h(PermissionPresetPicker, {
|
|
814
|
+
id: fieldId("permission"),
|
|
815
|
+
value: draft.permissionPreset,
|
|
816
|
+
presets: permissionPresets,
|
|
817
|
+
onChange: (value) => onChange("permissionPreset", value),
|
|
818
|
+
}),
|
|
489
819
|
),
|
|
490
820
|
h(
|
|
491
821
|
Field,
|
|
492
|
-
{ label: "Overlap policy", htmlFor: "
|
|
822
|
+
{ label: "Overlap policy", htmlFor: fieldId("overlap"), full: true, hint: "What happens when a scheduled run fires while another run for the same job is still active." },
|
|
493
823
|
h(
|
|
494
824
|
"select",
|
|
495
825
|
{
|
|
496
|
-
id: "
|
|
826
|
+
id: fieldId("overlap"),
|
|
497
827
|
className: "dsh-auto-select",
|
|
498
828
|
value: draft.overlap,
|
|
499
829
|
onChange: (event) => onChange("overlap", event.target.value),
|
|
@@ -503,11 +833,11 @@ window.__ModuleLoader__.load({
|
|
|
503
833
|
),
|
|
504
834
|
h(
|
|
505
835
|
Field,
|
|
506
|
-
{ label: "Misfire policy", htmlFor: "
|
|
836
|
+
{ label: "Misfire policy", htmlFor: fieldId("misfire"), hint: "How a missed occurrence is handled after the scheduler is back." },
|
|
507
837
|
h(
|
|
508
838
|
"select",
|
|
509
839
|
{
|
|
510
|
-
id: "
|
|
840
|
+
id: fieldId("misfire"),
|
|
511
841
|
className: "dsh-auto-select",
|
|
512
842
|
value: draft.misfire,
|
|
513
843
|
onChange: (event) => onChange("misfire", event.target.value),
|
|
@@ -517,9 +847,9 @@ window.__ModuleLoader__.load({
|
|
|
517
847
|
),
|
|
518
848
|
h(
|
|
519
849
|
Field,
|
|
520
|
-
{ label: "Working directory", htmlFor: "
|
|
850
|
+
{ label: "Working directory", htmlFor: fieldId("cwd"), required: true, full: true, hint: "Absolute project directory the agent runs in." },
|
|
521
851
|
h("input", {
|
|
522
|
-
id: "
|
|
852
|
+
id: fieldId("cwd"),
|
|
523
853
|
className: "dsh-auto-input",
|
|
524
854
|
type: "text",
|
|
525
855
|
value: draft.cwd,
|
|
@@ -530,9 +860,9 @@ window.__ModuleLoader__.load({
|
|
|
530
860
|
),
|
|
531
861
|
h(
|
|
532
862
|
Field,
|
|
533
|
-
{ label: "Prompt", htmlFor: "
|
|
863
|
+
{ label: "Prompt", htmlFor: fieldId("prompt"), required: true, full: true, hint: "Instructions for the agent run. Prompts are never shown in run history." },
|
|
534
864
|
h("textarea", {
|
|
535
|
-
id: "
|
|
865
|
+
id: fieldId("prompt"),
|
|
536
866
|
className: "dsh-auto-textarea",
|
|
537
867
|
value: draft.prompt,
|
|
538
868
|
placeholder: "Summarize yesterday's progress and list today's priorities\u2026",
|
|
@@ -547,13 +877,18 @@ window.__ModuleLoader__.load({
|
|
|
547
877
|
"div",
|
|
548
878
|
{ className: "dsh-auto-formactions" },
|
|
549
879
|
h(
|
|
550
|
-
|
|
551
|
-
{
|
|
880
|
+
Button,
|
|
881
|
+
{
|
|
882
|
+
type: "submit",
|
|
883
|
+
variant: "primary",
|
|
884
|
+
icon: saving ? null : h(IconCheckOutline16),
|
|
885
|
+
disabled: saving,
|
|
886
|
+
},
|
|
552
887
|
saving ? "Saving\u2026" : creating ? "Create automation" : "Save changes",
|
|
553
888
|
),
|
|
554
889
|
h(
|
|
555
|
-
|
|
556
|
-
{ type: "button",
|
|
890
|
+
Button,
|
|
891
|
+
{ type: "button", variant: "outline", onClick: onCancel, disabled: saving },
|
|
557
892
|
"Cancel",
|
|
558
893
|
),
|
|
559
894
|
),
|
|
@@ -589,6 +924,7 @@ window.__ModuleLoader__.load({
|
|
|
589
924
|
name: job.execution.agentPreset,
|
|
590
925
|
})
|
|
591
926
|
: "";
|
|
927
|
+
const permission = permissionPresetPresentation(job.execution.permissionPreset);
|
|
592
928
|
|
|
593
929
|
return h(
|
|
594
930
|
"article",
|
|
@@ -634,7 +970,12 @@ window.__ModuleLoader__.load({
|
|
|
634
970
|
presetLabel !== ""
|
|
635
971
|
? h("span", { title: "Agent preset" }, presetLabel)
|
|
636
972
|
: null,
|
|
637
|
-
h(
|
|
973
|
+
h(
|
|
974
|
+
"span",
|
|
975
|
+
{ className: "dsh-auto-card-permission", title: "Permission preset: " + job.execution.permissionPreset },
|
|
976
|
+
h(PermissionPresetIcon, { value: job.execution.permissionPreset }),
|
|
977
|
+
permission.label,
|
|
978
|
+
),
|
|
638
979
|
h("span", { title: "Timeout" }, formatTimeout(job.execution.timeoutMs)),
|
|
639
980
|
h("span", { className: "dsh-auto-muted", title: "Version" }, "v" + job.version),
|
|
640
981
|
),
|
|
@@ -642,15 +983,24 @@ window.__ModuleLoader__.load({
|
|
|
642
983
|
"div",
|
|
643
984
|
{ className: "dsh-auto-card-actions" },
|
|
644
985
|
h(
|
|
645
|
-
|
|
646
|
-
{
|
|
986
|
+
Button,
|
|
987
|
+
{
|
|
988
|
+
type: "button",
|
|
989
|
+
variant: "ghost",
|
|
990
|
+
size: "sm",
|
|
991
|
+
icon: h(IconEditOutline16),
|
|
992
|
+
onClick: onEdit,
|
|
993
|
+
disabled: busyForJob || running,
|
|
994
|
+
},
|
|
647
995
|
"Edit",
|
|
648
996
|
),
|
|
649
997
|
h(
|
|
650
|
-
|
|
998
|
+
Button,
|
|
651
999
|
{
|
|
652
1000
|
type: "button",
|
|
653
|
-
|
|
1001
|
+
variant: "primary",
|
|
1002
|
+
size: "sm",
|
|
1003
|
+
icon: running ? null : h(IconPlayOutline16),
|
|
654
1004
|
onClick: onRun,
|
|
655
1005
|
disabled: busyForJob,
|
|
656
1006
|
},
|
|
@@ -661,26 +1011,32 @@ window.__ModuleLoader__.load({
|
|
|
661
1011
|
"span",
|
|
662
1012
|
{ className: "dsh-auto-confirm" },
|
|
663
1013
|
h(
|
|
664
|
-
|
|
1014
|
+
Button,
|
|
665
1015
|
{
|
|
666
1016
|
type: "button",
|
|
667
|
-
|
|
1017
|
+
variant: "ghost",
|
|
1018
|
+
size: "sm",
|
|
1019
|
+
className: "dsh-auto-danger-button",
|
|
1020
|
+
icon: deleting ? null : h(IconTrashOutline16),
|
|
668
1021
|
onClick: onDeleteConfirm,
|
|
669
1022
|
disabled: deleting,
|
|
670
1023
|
},
|
|
671
1024
|
deleting ? "Deleting\u2026" : "Confirm delete",
|
|
672
1025
|
),
|
|
673
1026
|
h(
|
|
674
|
-
|
|
675
|
-
{ type: "button",
|
|
1027
|
+
Button,
|
|
1028
|
+
{ type: "button", variant: "outline", size: "sm", onClick: onDeleteCancel, disabled: deleting },
|
|
676
1029
|
"Keep",
|
|
677
1030
|
),
|
|
678
1031
|
)
|
|
679
1032
|
: h(
|
|
680
|
-
|
|
1033
|
+
Button,
|
|
681
1034
|
{
|
|
682
1035
|
type: "button",
|
|
683
|
-
|
|
1036
|
+
variant: "ghost",
|
|
1037
|
+
size: "sm",
|
|
1038
|
+
className: "dsh-auto-danger-button",
|
|
1039
|
+
icon: h(IconTrashOutline16),
|
|
684
1040
|
onClick: onDelete,
|
|
685
1041
|
disabled: busyForJob,
|
|
686
1042
|
},
|
|
@@ -750,26 +1106,29 @@ window.__ModuleLoader__.load({
|
|
|
750
1106
|
"span",
|
|
751
1107
|
{ className: "dsh-auto-confirm" },
|
|
752
1108
|
h(
|
|
753
|
-
|
|
1109
|
+
Button,
|
|
754
1110
|
{
|
|
755
1111
|
type: "button",
|
|
756
|
-
|
|
1112
|
+
variant: "ghost",
|
|
1113
|
+
size: "sm",
|
|
1114
|
+
className: "dsh-auto-danger-button",
|
|
757
1115
|
onClick: () => onCancelConfirm(run),
|
|
758
1116
|
disabled: cancelling,
|
|
759
1117
|
},
|
|
760
1118
|
cancelling ? "Cancelling\u2026" : "Confirm",
|
|
761
1119
|
),
|
|
762
1120
|
h(
|
|
763
|
-
|
|
764
|
-
{ type: "button",
|
|
1121
|
+
Button,
|
|
1122
|
+
{ type: "button", variant: "outline", size: "sm", onClick: onCancelReset, disabled: cancelling },
|
|
765
1123
|
"Back",
|
|
766
1124
|
),
|
|
767
1125
|
)
|
|
768
1126
|
: h(
|
|
769
|
-
|
|
1127
|
+
Button,
|
|
770
1128
|
{
|
|
771
1129
|
type: "button",
|
|
772
|
-
|
|
1130
|
+
variant: "ghost",
|
|
1131
|
+
size: "sm",
|
|
773
1132
|
onClick: () => onCancel(run),
|
|
774
1133
|
},
|
|
775
1134
|
"Cancel",
|
|
@@ -788,7 +1147,7 @@ window.__ModuleLoader__.load({
|
|
|
788
1147
|
);
|
|
789
1148
|
}
|
|
790
1149
|
|
|
791
|
-
function AutomationsSection() {
|
|
1150
|
+
function AutomationsSection({ centerMode = false } = {}) {
|
|
792
1151
|
const [meta, setMeta] = useState(null);
|
|
793
1152
|
const [snapshot, setSnapshot] = useState(null);
|
|
794
1153
|
const [loading, setLoading] = useState(true);
|
|
@@ -1065,14 +1424,17 @@ window.__ModuleLoader__.load({
|
|
|
1065
1424
|
|
|
1066
1425
|
return h(
|
|
1067
1426
|
"section",
|
|
1068
|
-
{
|
|
1427
|
+
{
|
|
1428
|
+
className: "dsh-auto-root" + (centerMode ? " dsh-auto-root-workspace" : ""),
|
|
1429
|
+
"aria-busy": loading ? "true" : null,
|
|
1430
|
+
},
|
|
1069
1431
|
h(
|
|
1070
1432
|
"div",
|
|
1071
1433
|
{ className: "dsh-auto-head" },
|
|
1072
1434
|
h(
|
|
1073
1435
|
"div",
|
|
1074
1436
|
null,
|
|
1075
|
-
h("h2",
|
|
1437
|
+
h("h2", { className: centerMode ? "dsh-auto-sr-only" : undefined }, "Automations"),
|
|
1076
1438
|
h(
|
|
1077
1439
|
"p",
|
|
1078
1440
|
{ className: "dsh-auto-sub" },
|
|
@@ -1083,8 +1445,8 @@ window.__ModuleLoader__.load({
|
|
|
1083
1445
|
),
|
|
1084
1446
|
!formOpen
|
|
1085
1447
|
? h(
|
|
1086
|
-
|
|
1087
|
-
{ type: "button",
|
|
1448
|
+
Button,
|
|
1449
|
+
{ type: "button", variant: "primary", icon: h(IconPlusOutline16), onClick: openCreate },
|
|
1088
1450
|
"New automation",
|
|
1089
1451
|
)
|
|
1090
1452
|
: null,
|
|
@@ -1121,8 +1483,8 @@ window.__ModuleLoader__.load({
|
|
|
1121
1483
|
{ className: "dsh-auto-error", role: "alert" },
|
|
1122
1484
|
h("p", null, "Could not load automations: ", loadError),
|
|
1123
1485
|
h(
|
|
1124
|
-
|
|
1125
|
-
{ type: "button",
|
|
1486
|
+
Button,
|
|
1487
|
+
{ type: "button", variant: "primary", size: "sm", icon: h(IconRefreshOutline16), onClick: () => loadSnapshot(true) },
|
|
1126
1488
|
"Retry",
|
|
1127
1489
|
),
|
|
1128
1490
|
)
|
|
@@ -1194,7 +1556,7 @@ window.__ModuleLoader__.load({
|
|
|
1194
1556
|
};
|
|
1195
1557
|
}
|
|
1196
1558
|
|
|
1197
|
-
const
|
|
1559
|
+
const FOCUSABLE_SELECTOR = [
|
|
1198
1560
|
"a[href]",
|
|
1199
1561
|
"button:not([disabled])",
|
|
1200
1562
|
"input:not([disabled])",
|
|
@@ -1204,45 +1566,15 @@ window.__ModuleLoader__.load({
|
|
|
1204
1566
|
"[tabindex]:not([tabindex=\"-1\"])",
|
|
1205
1567
|
].join(",");
|
|
1206
1568
|
|
|
1207
|
-
function
|
|
1569
|
+
function visibleFocusables(panel) {
|
|
1208
1570
|
if (!panel) return [];
|
|
1209
|
-
return Array.from(panel.querySelectorAll(
|
|
1571
|
+
return Array.from(panel.querySelectorAll(FOCUSABLE_SELECTOR)).filter((element) =>
|
|
1210
1572
|
!element.hasAttribute("hidden") &&
|
|
1211
1573
|
element.getAttribute("aria-hidden") !== "true" &&
|
|
1212
1574
|
element.getClientRects().length > 0,
|
|
1213
1575
|
);
|
|
1214
1576
|
}
|
|
1215
1577
|
|
|
1216
|
-
function trapModalTab(event, panel) {
|
|
1217
|
-
if (
|
|
1218
|
-
event.key !== "Tab" ||
|
|
1219
|
-
event.defaultPrevented ||
|
|
1220
|
-
event.altKey ||
|
|
1221
|
-
event.ctrlKey ||
|
|
1222
|
-
event.metaKey
|
|
1223
|
-
) return;
|
|
1224
|
-
const focusables = modalFocusables(panel);
|
|
1225
|
-
if (focusables.length === 0) {
|
|
1226
|
-
event.preventDefault();
|
|
1227
|
-
panel?.focus();
|
|
1228
|
-
return;
|
|
1229
|
-
}
|
|
1230
|
-
const first = focusables[0];
|
|
1231
|
-
const last = focusables[focusables.length - 1];
|
|
1232
|
-
const active = panel.ownerDocument.activeElement;
|
|
1233
|
-
if (event.shiftKey) {
|
|
1234
|
-
if (active === first || !panel.contains(active)) {
|
|
1235
|
-
event.preventDefault();
|
|
1236
|
-
last.focus();
|
|
1237
|
-
}
|
|
1238
|
-
return;
|
|
1239
|
-
}
|
|
1240
|
-
if (active === last || !panel.contains(active)) {
|
|
1241
|
-
event.preventDefault();
|
|
1242
|
-
first.focus();
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
1578
|
function AutomationGlyph({ size = 18 }) {
|
|
1247
1579
|
return h(
|
|
1248
1580
|
"svg",
|
|
@@ -1265,24 +1597,6 @@ window.__ModuleLoader__.load({
|
|
|
1265
1597
|
);
|
|
1266
1598
|
}
|
|
1267
1599
|
|
|
1268
|
-
function CloseGlyph() {
|
|
1269
|
-
return h(
|
|
1270
|
-
"svg",
|
|
1271
|
-
{
|
|
1272
|
-
width: "16",
|
|
1273
|
-
height: "16",
|
|
1274
|
-
viewBox: "0 0 16 16",
|
|
1275
|
-
fill: "none",
|
|
1276
|
-
stroke: "currentColor",
|
|
1277
|
-
strokeWidth: "1.5",
|
|
1278
|
-
strokeLinecap: "round",
|
|
1279
|
-
"aria-hidden": "true",
|
|
1280
|
-
focusable: "false",
|
|
1281
|
-
},
|
|
1282
|
-
h("path", { d: "M3.5 3.5l9 9M12.5 3.5l-9 9" }),
|
|
1283
|
-
);
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
1600
|
function AutomationsSidebarAction({ wide, disclosure }) {
|
|
1287
1601
|
const open = useSyncExternalStore(
|
|
1288
1602
|
disclosure.subscribe,
|
|
@@ -1309,10 +1623,9 @@ window.__ModuleLoader__.load({
|
|
|
1309
1623
|
ref: triggerRef,
|
|
1310
1624
|
type: "button",
|
|
1311
1625
|
className: "dsh-auto-sidebar-trigger",
|
|
1312
|
-
title: wide ? undefined : "Automations",
|
|
1313
|
-
"aria-label": "Automations",
|
|
1314
|
-
"aria-
|
|
1315
|
-
"aria-expanded": open,
|
|
1626
|
+
title: wide ? undefined : open ? "Exit Automations" : "Automations",
|
|
1627
|
+
"aria-label": open ? "Exit Automations" : "Open Automations",
|
|
1628
|
+
"aria-pressed": open,
|
|
1316
1629
|
"data-active": open ? "true" : undefined,
|
|
1317
1630
|
"data-dsh-automations-trigger": "true",
|
|
1318
1631
|
onClick: disclosure.toggle,
|
|
@@ -1323,87 +1636,76 @@ window.__ModuleLoader__.load({
|
|
|
1323
1636
|
);
|
|
1324
1637
|
}
|
|
1325
1638
|
|
|
1326
|
-
function
|
|
1327
|
-
const
|
|
1328
|
-
disclosure.subscribe,
|
|
1329
|
-
disclosure.getSnapshot,
|
|
1330
|
-
disclosure.getSnapshot,
|
|
1331
|
-
);
|
|
1332
|
-
const closeRef = useRef(null);
|
|
1333
|
-
const panelRef = useRef(null);
|
|
1639
|
+
function AutomationsWorkspace({ disclosure }) {
|
|
1640
|
+
const workspaceRef = useRef(null);
|
|
1334
1641
|
const titleId = useId();
|
|
1335
1642
|
|
|
1336
1643
|
useEffect(() => {
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1644
|
+
const frame = window.requestAnimationFrame(() =>
|
|
1645
|
+
workspaceRef.current?.querySelector('[data-dsh-automations-exit="true"]')?.focus(),
|
|
1646
|
+
);
|
|
1647
|
+
const onKeyDown = (event) => {
|
|
1648
|
+
if (event.key !== "Escape" || event.defaultPrevented || event.__dshAutomationsNested) return;
|
|
1649
|
+
if (event.target?.closest?.('[role="dialog"],[role="menu"]')) return;
|
|
1650
|
+
if (document.querySelector('.dsh-auto-picker-trigger[aria-expanded="true"]')) return;
|
|
1651
|
+
event.preventDefault();
|
|
1652
|
+
disclosure.close();
|
|
1653
|
+
};
|
|
1654
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1655
|
+
return () => {
|
|
1656
|
+
window.cancelAnimationFrame(frame);
|
|
1657
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
1658
|
+
};
|
|
1659
|
+
}, [disclosure]);
|
|
1341
1660
|
|
|
1342
|
-
if (!open) return null;
|
|
1343
1661
|
return h(
|
|
1344
|
-
"
|
|
1345
|
-
{
|
|
1346
|
-
|
|
1662
|
+
"section",
|
|
1663
|
+
{
|
|
1664
|
+
ref: workspaceRef,
|
|
1665
|
+
className: "dsh-auto-workspace",
|
|
1666
|
+
"data-dsh-automations-workspace": "true",
|
|
1667
|
+
"aria-labelledby": titleId,
|
|
1668
|
+
},
|
|
1347
1669
|
h(
|
|
1348
|
-
"
|
|
1349
|
-
{
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
role: "dialog",
|
|
1353
|
-
tabIndex: -1,
|
|
1354
|
-
"aria-modal": "true",
|
|
1355
|
-
"aria-labelledby": titleId,
|
|
1356
|
-
onKeyDownCapture: (event) => {
|
|
1357
|
-
if (event.key === "Escape") {
|
|
1358
|
-
event.preventDefault();
|
|
1359
|
-
disclosure.close();
|
|
1360
|
-
return;
|
|
1361
|
-
}
|
|
1362
|
-
trapModalTab(event, panelRef.current);
|
|
1363
|
-
},
|
|
1364
|
-
},
|
|
1670
|
+
"header",
|
|
1671
|
+
{ className: "dsh-auto-workspace-toolbar" },
|
|
1672
|
+
h("span", { className: "dsh-auto-workspace-icon", "aria-hidden": "true" }, h(AutomationGlyph, { size: 16 })),
|
|
1673
|
+
h("strong", { id: titleId, className: "dsh-auto-workspace-title" }, "Automations"),
|
|
1365
1674
|
h(
|
|
1366
|
-
|
|
1367
|
-
{
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
"
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
title: "Close",
|
|
1377
|
-
onClick: disclosure.close,
|
|
1378
|
-
},
|
|
1379
|
-
h(CloseGlyph),
|
|
1380
|
-
),
|
|
1675
|
+
Button,
|
|
1676
|
+
{
|
|
1677
|
+
type: "button",
|
|
1678
|
+
variant: "toolbar",
|
|
1679
|
+
size: "sm",
|
|
1680
|
+
icon: h(IconChevronLeftOutline14),
|
|
1681
|
+
onClick: disclosure.close,
|
|
1682
|
+
"data-dsh-automations-exit": "true",
|
|
1683
|
+
},
|
|
1684
|
+
"Exit Automations",
|
|
1381
1685
|
),
|
|
1382
|
-
h("div", { className: "dsh-auto-overlay-body" }, h(AutomationsSection)),
|
|
1383
1686
|
),
|
|
1687
|
+
h("div", { className: "dsh-auto-workspace-scroll" }, h(AutomationsSection, { centerMode: true })),
|
|
1384
1688
|
);
|
|
1385
1689
|
}
|
|
1386
1690
|
|
|
1387
1691
|
const STYLE_CSS = [
|
|
1388
1692
|
".dsh-auto-sidebar-action{box-sizing:border-box;width:100%;height:42px;flex:none;display:flex;align-items:center;margin:4px 0 0;}",
|
|
1389
|
-
".dsh-auto-sidebar-trigger{box-sizing:border-box;appearance:none;width:calc(100% + 4px);height:42px;margin:0 -2px;padding:0 10px 0 8px;border:0;border-radius:12px;background:transparent;color:var(--dsw-alias-label-primary,#0f1115);display:flex;align-items:center;gap:8px;overflow:hidden;font:14px
|
|
1693
|
+
".dsh-auto-sidebar-trigger{box-sizing:border-box;appearance:none;width:calc(100% + 4px);height:42px;margin:0 -2px;padding:0 10px 0 8px;border:0;border-radius:12px;background:transparent;color:var(--dsw-alias-label-primary,#0f1115);display:flex;align-items:center;gap:8px;overflow:hidden;font-family:inherit;font-size:14px;line-height:22px;cursor:pointer;}",
|
|
1390
1694
|
".dsh-auto-sidebar-trigger:hover,.dsh-auto-sidebar-trigger[data-active=\"true\"]{background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06));}",
|
|
1391
1695
|
".dsh-auto-sidebar-trigger:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#4176e6);outline-offset:-2px;}",
|
|
1392
1696
|
".dsh-auto-sidebar-trigger svg{flex:none;}",
|
|
1393
1697
|
".dsh-auto-sidebar-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
|
|
1394
1698
|
".dsh-auto-sidebar-action-rail{width:36px;height:36px;margin:0;}",
|
|
1395
1699
|
".dsh-auto-sidebar-action-rail .dsh-auto-sidebar-trigger{width:36px;height:36px;margin:0;padding:0;justify-content:center;gap:0;border-radius:50%;}",
|
|
1396
|
-
".dsh-auto-
|
|
1397
|
-
".dsh-auto-
|
|
1398
|
-
".dsh-auto-
|
|
1399
|
-
".dsh-auto-
|
|
1400
|
-
".dsh-auto-
|
|
1401
|
-
".dsh-auto-
|
|
1402
|
-
".dsh-auto-overlay-close:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#4176e6);outline-offset:1px;}",
|
|
1403
|
-
".dsh-auto-overlay-body{box-sizing:border-box;min-height:0;flex:1;padding:0 28px 28px;overflow-y:auto;overscroll-behavior:contain;--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);}",
|
|
1404
|
-
".dsh-auto-overlay-body>.dsh-auto-root{width:100%;margin:0 auto;padding-top:0;}",
|
|
1700
|
+
".dsh-auto-workspace{box-sizing:border-box;width:100%;height:100%;min-width:0;min-height:0;display:flex;flex-direction:column;overflow:hidden;color:var(--dsw-alias-label-primary,#0f1115);background:var(--dsw-alias-bg-base,#fff);font-family:inherit;}",
|
|
1701
|
+
".dsh-auto-workspace-toolbar{box-sizing:border-box;width:100%;height:44px;flex:none;display:flex;align-items:center;gap:8px;padding:6px 10px 6px 12px;border-bottom:1px solid var(--dsw-alias-border-l2,rgba(15,17,21,.14));background:var(--dsw-alias-bg-base,#fff);}",
|
|
1702
|
+
".dsh-auto-workspace-icon{width:28px;height:28px;flex:none;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;color:var(--dsw-alias-state-business-primary,#4176e6);background:color-mix(in srgb,var(--dsw-alias-state-business-primary,#4176e6) 10%,transparent);}",
|
|
1703
|
+
".dsh-auto-workspace-title{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;line-height:20px;}",
|
|
1704
|
+
".dsh-auto-workspace-scroll{container:dsh-auto-workspace / inline-size;box-sizing:border-box;min-height:0;flex:1;padding:24px clamp(20px,4vw,48px) 40px;overflow-y:auto;overscroll-behavior:contain;--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);}",
|
|
1705
|
+
".dsh-auto-workspace-scroll>.dsh-auto-root{width:100%;margin:0 auto;padding-top:0;}",
|
|
1405
1706
|
".dsh-auto-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important;}",
|
|
1406
|
-
".dsh-auto-root{--dsh-auto-border:var(--dsw-alias-border-l2,rgba(15,17,21,.14));--dsh-auto-
|
|
1707
|
+
".dsh-auto-root{--dsh-auto-border:var(--dsw-alias-border-l2,rgba(15,17,21,.14));--dsh-auto-surface:var(--dsw-alias-bg-layer-3,#fff);--dsh-auto-surface-active:var(--dsw-alias-bg-layer-2,#fff);--dsh-auto-input-bg:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1,#fff));--dsh-auto-text:var(--dsw-alias-label-primary,#0f1115);--dsh-auto-text-secondary:var(--dsw-alias-label-secondary,#4f5661);--dsh-auto-muted:var(--dsw-alias-label-tertiary,#81858c);--dsh-auto-caption:var(--dsw-alias-label-caption,#adb2b8);--dsh-auto-accent:var(--dsw-alias-state-business-primary,#4176e6);--dsh-auto-danger:var(--dsw-alias-state-error-primary,#ec1313);--dsh-auto-success:var(--dsw-alias-state-success-primary,#22c55e);--dsh-auto-warning:var(--dsw-alias-state-warn-primary,#f59e0b);box-sizing:border-box;max-width:820px;padding-top:12px;display:flex;flex-direction:column;gap:16px;font-family:inherit;color:var(--dsh-auto-text);}",
|
|
1708
|
+
".dsh-auto-root-workspace{max-width:960px;}",
|
|
1407
1709
|
"body:not([data-ds-dark-theme]) .dsh-auto-root{color-scheme:light;}",
|
|
1408
1710
|
"body[data-ds-dark-theme] .dsh-auto-root{color-scheme:dark;}",
|
|
1409
1711
|
".dsh-auto-root *,.dsh-auto-root *::before,.dsh-auto-root *::after{box-sizing:border-box;}",
|
|
@@ -1415,21 +1717,30 @@ window.__ModuleLoader__.load({
|
|
|
1415
1717
|
".dsh-auto-flash-success{background:color-mix(in srgb,var(--dsh-auto-success) 12%,transparent);color:var(--dsh-auto-success);}",
|
|
1416
1718
|
".dsh-auto-flash-warn{background:color-mix(in srgb,var(--dsh-auto-warning) 12%,transparent);color:var(--dsh-auto-warning);}",
|
|
1417
1719
|
".dsh-auto-linkbtn{appearance:none;font:inherit;font-size:inherit;color:inherit;text-decoration:underline;cursor:pointer;background:none;border:none;padding:0;}",
|
|
1418
|
-
".dsh-auto-
|
|
1419
|
-
".dsh-auto-
|
|
1420
|
-
".dsh-auto-btn:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsh-auto-border-strong);}",
|
|
1421
|
-
".dsh-auto-btn:disabled{opacity:.4;cursor:default;}",
|
|
1422
|
-
".dsh-auto-btn-primary{background:var(--dsh-auto-primary-fill);border-color:transparent;color:var(--dsh-auto-on-primary);}",
|
|
1423
|
-
".dsh-auto-btn-primary:hover:not(:disabled){background:var(--dsh-auto-primary-hover);}",
|
|
1424
|
-
".dsh-auto-btn-danger,.dsh-auto-btn-danger-ghost{background:transparent;border-color:transparent;color:var(--dsh-auto-danger);}",
|
|
1425
|
-
".dsh-auto-btn-danger:hover:not(:disabled),.dsh-auto-btn-danger-ghost:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger,color-mix(in srgb,var(--dsh-auto-danger) 10%,transparent));}",
|
|
1426
|
-
".dsh-auto-btn-ghost{border-color:transparent;color:var(--dsh-auto-text-secondary);}",
|
|
1720
|
+
".dsh-auto-danger-button{color:var(--dsh-auto-danger);}",
|
|
1721
|
+
".dsh-auto-danger-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger,color-mix(in srgb,var(--dsh-auto-danger) 10%,transparent));}",
|
|
1427
1722
|
".dsh-auto-input,.dsh-auto-select,.dsh-auto-textarea{width:100%;min-height:34px;padding:6px 10px;border:1px solid var(--dsh-auto-border);border-radius:8px;background:var(--dsh-auto-input-bg);color:var(--dsh-auto-text);font-family:inherit;font-size:13px;line-height:1.5;}",
|
|
1428
1723
|
".dsh-auto-input,.dsh-auto-textarea{appearance:none;}",
|
|
1429
1724
|
".dsh-auto-input::placeholder,.dsh-auto-textarea::placeholder{color:var(--dsh-auto-caption);}",
|
|
1430
1725
|
".dsh-auto-select option{background:var(--dsh-auto-input-bg);color:var(--dsh-auto-text);}",
|
|
1431
1726
|
".dsh-auto-input:focus-visible,.dsh-auto-select:focus-visible,.dsh-auto-textarea:focus-visible{outline:none;border-color:var(--dsh-auto-accent);box-shadow:0 0 0 2px color-mix(in srgb,var(--dsh-auto-accent) 18%,transparent);}",
|
|
1432
1727
|
".dsh-auto-input:disabled,.dsh-auto-select:disabled,.dsh-auto-textarea:disabled{opacity:1;color:var(--dsh-auto-muted);background:var(--dsh-auto-surface-active);cursor:default;}",
|
|
1728
|
+
".dsh-auto-picker-root{width:100%;display:flex;}",
|
|
1729
|
+
".dsh-auto-picker-trigger{appearance:none;width:100%;height:34px;padding:0 9px;border:1px solid var(--dsh-auto-border);border-radius:8px;background:var(--dsh-auto-input-bg);color:var(--dsh-auto-text);display:flex;align-items:center;gap:8px;font-family:inherit;font-size:13px;line-height:20px;text-align:left;cursor:pointer;}",
|
|
1730
|
+
".dsh-auto-picker-trigger:hover{background:var(--dsw-alias-interactive-bg-hover,var(--dsh-auto-input-bg));}",
|
|
1731
|
+
".dsh-auto-picker-trigger:focus-visible{outline:none;border-color:var(--dsh-auto-accent);box-shadow:0 0 0 2px color-mix(in srgb,var(--dsh-auto-accent) 18%,transparent);}",
|
|
1732
|
+
".dsh-auto-picker-trigger-icon{flex:none;color:var(--dsh-auto-muted);}",
|
|
1733
|
+
".dsh-auto-picker-trigger-label{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
|
|
1734
|
+
".dsh-auto-picker-chevron{flex:none;color:var(--dsh-auto-muted);transition:transform .12s ease;}",
|
|
1735
|
+
".dsh-auto-picker-chevron-open{transform:rotate(180deg);}",
|
|
1736
|
+
".dsh-auto-picker-item-copy{min-width:0;display:flex;flex-direction:column;white-space:normal;}",
|
|
1737
|
+
".dsh-auto-picker-item-label{color:inherit;font-size:14px;line-height:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
|
|
1738
|
+
".dsh-auto-picker-item-detail{color:var(--dsh-auto-muted);font-size:12px;line-height:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
|
|
1739
|
+
".dsh-auto-permission-glyph{flex:none;}",
|
|
1740
|
+
".dsh-auto-permission-glyph-read{color:var(--dsh-auto-muted);}",
|
|
1741
|
+
".dsh-auto-permission-glyph-write{color:var(--dsh-auto-accent);}",
|
|
1742
|
+
".dsh-auto-permission-glyph-danger{color:var(--dsh-auto-danger);}",
|
|
1743
|
+
".dsh-auto-permission-glyph-custom{color:var(--dsh-auto-muted);}",
|
|
1433
1744
|
".dsh-auto-textarea{resize:vertical;min-height:110px;}",
|
|
1434
1745
|
".dsh-auto-check{display:inline-flex;align-items:center;gap:8px;font-size:13px;cursor:pointer;min-height:34px;}",
|
|
1435
1746
|
".dsh-auto-check input{width:16px;height:16px;margin:0;accent-color:var(--dsh-auto-accent);cursor:pointer;}",
|
|
@@ -1452,6 +1763,8 @@ window.__ModuleLoader__.load({
|
|
|
1452
1763
|
".dsh-auto-card-id{font-size:11px;color:var(--dsh-auto-muted);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;}",
|
|
1453
1764
|
".dsh-auto-card-meta{display:flex;flex-wrap:wrap;gap:4px 14px;font-size:12px;color:var(--dsh-auto-text-secondary);line-height:1.5;}",
|
|
1454
1765
|
".dsh-auto-card-meta span{white-space:nowrap;}",
|
|
1766
|
+
".dsh-auto-card-permission{display:inline-flex;align-items:center;gap:4px;}",
|
|
1767
|
+
".dsh-auto-card-permission svg{width:14px;height:14px;}",
|
|
1455
1768
|
".dsh-auto-next{font-variant-numeric:tabular-nums;}",
|
|
1456
1769
|
".dsh-auto-muted{color:var(--dsh-auto-muted);}",
|
|
1457
1770
|
".dsh-auto-card-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap;}",
|
|
@@ -1488,13 +1801,34 @@ window.__ModuleLoader__.load({
|
|
|
1488
1801
|
"@keyframes dsh-auto-pulse{0%,100%{opacity:1}50%{opacity:.35}}",
|
|
1489
1802
|
".dsh-auto-empty,.dsh-auto-loading,.dsh-auto-error{padding:22px 16px;text-align:center;border:1px dashed var(--dsh-auto-border);border-radius:12px;font-size:13px;color:var(--dsh-auto-text-secondary);}",
|
|
1490
1803
|
".dsh-auto-error{color:var(--dsh-auto-danger);display:flex;flex-direction:column;gap:10px;align-items:center;}",
|
|
1491
|
-
"@
|
|
1804
|
+
"@container dsh-auto-workspace (max-width:680px){.dsh-auto-formgrid{grid-template-columns:1fr;}.dsh-auto-card-head{flex-direction:column;align-items:flex-start;}.dsh-auto-run-name{max-width:150px;}}",
|
|
1805
|
+
"@media (max-width:640px){.dsh-auto-workspace-toolbar{padding-inline:8px;}.dsh-auto-workspace-scroll{padding:16px 14px 28px;}.dsh-auto-formgrid{grid-template-columns:1fr;}.dsh-auto-card-head{flex-direction:column;align-items:flex-start;}.dsh-auto-run-name{max-width:150px;}}",
|
|
1492
1806
|
].join("\n");
|
|
1493
1807
|
|
|
1494
1808
|
function apply(ctx) {
|
|
1495
1809
|
const disclosure = createDisclosureStore();
|
|
1496
|
-
|
|
1497
|
-
|
|
1810
|
+
let centerDeclared = false;
|
|
1811
|
+
let disposeCenter = null;
|
|
1812
|
+
const unmountCenter = () => {
|
|
1813
|
+
if (!disposeCenter) return;
|
|
1814
|
+
const dispose = disposeCenter;
|
|
1815
|
+
disposeCenter = null;
|
|
1816
|
+
dispose();
|
|
1817
|
+
};
|
|
1818
|
+
const mountCenter = () => {
|
|
1819
|
+
if (!centerDeclared || !disclosure.getSnapshot() || disposeCenter) return;
|
|
1820
|
+
try {
|
|
1821
|
+
disposeCenter = ctx.slots.register({
|
|
1822
|
+
name: "conversation",
|
|
1823
|
+
priority: -200,
|
|
1824
|
+
inject: () => ({ disclosure }),
|
|
1825
|
+
}, AutomationsWorkspace);
|
|
1826
|
+
} catch (error) {
|
|
1827
|
+
console.error("dsh automations: could not mount center workspace", error);
|
|
1828
|
+
disclosure.close();
|
|
1829
|
+
}
|
|
1830
|
+
};
|
|
1831
|
+
|
|
1498
1832
|
ctx.effect(() => {
|
|
1499
1833
|
const tag = document.createElement("style");
|
|
1500
1834
|
tag.setAttribute("data-plugin", "@syncended/dsh-automations");
|
|
@@ -1504,7 +1838,28 @@ window.__ModuleLoader__.load({
|
|
|
1504
1838
|
tag.remove();
|
|
1505
1839
|
};
|
|
1506
1840
|
}, "@syncended/dsh-automations: client styles");
|
|
1507
|
-
ctx.effect(
|
|
1841
|
+
ctx.effect(
|
|
1842
|
+
() => ctx.slots.inject("conversation", () => {
|
|
1843
|
+
centerDeclared = true;
|
|
1844
|
+
mountCenter();
|
|
1845
|
+
return () => {
|
|
1846
|
+
centerDeclared = false;
|
|
1847
|
+
unmountCenter();
|
|
1848
|
+
};
|
|
1849
|
+
}),
|
|
1850
|
+
"@syncended/dsh-automations: center workspace",
|
|
1851
|
+
);
|
|
1852
|
+
ctx.effect(() => {
|
|
1853
|
+
const unsubscribe = disclosure.subscribe(() => {
|
|
1854
|
+
if (disclosure.getSnapshot()) mountCenter();
|
|
1855
|
+
else unmountCenter();
|
|
1856
|
+
});
|
|
1857
|
+
return () => {
|
|
1858
|
+
unsubscribe();
|
|
1859
|
+
unmountCenter();
|
|
1860
|
+
disclosure.dispose();
|
|
1861
|
+
};
|
|
1862
|
+
}, "@syncended/dsh-automations: workspace state");
|
|
1508
1863
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
1509
1864
|
name: "settings.section",
|
|
1510
1865
|
id: "automations",
|
|
@@ -1518,16 +1873,11 @@ window.__ModuleLoader__.load({
|
|
|
1518
1873
|
label: "Automations",
|
|
1519
1874
|
inject: () => ({ disclosure }),
|
|
1520
1875
|
}, AutomationsSidebarAction));
|
|
1521
|
-
ctx.slots.inject("shell.overlay", () => ctx.slots.register({
|
|
1522
|
-
name: "shell.overlay",
|
|
1523
|
-
id: "automations",
|
|
1524
|
-
order: 50,
|
|
1525
|
-
label: "Automations",
|
|
1526
|
-
inject: () => ({ disclosure }),
|
|
1527
|
-
}, AutomationsOverlay));
|
|
1528
1876
|
}
|
|
1529
1877
|
|
|
1530
1878
|
exports.agentPresetDisplayLabel = agentPresetDisplayLabel;
|
|
1879
|
+
exports.permissionPresetPresentation = permissionPresetPresentation;
|
|
1880
|
+
exports.PermissionPresetPicker = PermissionPresetPicker;
|
|
1531
1881
|
exports.inject = inject;
|
|
1532
1882
|
exports.apply = apply;
|
|
1533
1883
|
return module.exports;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncended/dsh-automations",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Durable cron automations for DeepSeek Harness",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"inject": [
|
|
31
31
|
"@deepseek-ai/dsh-client-runtime",
|
|
32
32
|
"@deepseek-ai/dsh-client-ui-layout",
|
|
33
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
33
34
|
"@deepseek-ai/dsh-client-ui-sidebar",
|
|
34
35
|
"@deepseek-ai/dsh-client-ui-settings"
|
|
35
36
|
],
|
|
@@ -82,6 +83,7 @@
|
|
|
82
83
|
"@deepseek-ai/dsh-agent-default-model": "^0.1.1-rc.2",
|
|
83
84
|
"@deepseek-ai/dsh-agent-presets": "^0.1.1-rc.2",
|
|
84
85
|
"@deepseek-ai/dsh-client-runtime": "^0.1.1-rc.2",
|
|
86
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.1-rc.2",
|
|
85
87
|
"@deepseek-ai/dsh-client-ui-layout": "^0.1.1-rc.2",
|
|
86
88
|
"@deepseek-ai/dsh-client-ui-settings": "^0.1.1-rc.2",
|
|
87
89
|
"@deepseek-ai/dsh-client-ui-sidebar": "^0.1.1-rc.2",
|
|
@@ -97,7 +99,9 @@
|
|
|
97
99
|
"@deepseek-ai/dsh-agent-default-model": "0.1.1-rc.2",
|
|
98
100
|
"@deepseek-ai/dsh-agent-presets": "0.1.1-rc.2",
|
|
99
101
|
"@deepseek-ai/dsh-client-runtime": "0.1.1-rc.2",
|
|
102
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.1-rc.2",
|
|
100
103
|
"@deepseek-ai/dsh-client-ui-layout": "0.1.1-rc.2",
|
|
104
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.1-rc.2",
|
|
101
105
|
"@deepseek-ai/dsh-client-ui-settings": "0.1.1-rc.2",
|
|
102
106
|
"@deepseek-ai/dsh-client-ui-sidebar": "0.1.1-rc.2",
|
|
103
107
|
"@deepseek-ai/dsh-host-webserver": "0.1.1-rc.2",
|