@syncended/dsh-automations 0.3.1 → 0.4.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 +1 -1
- package/lib/client.js +521 -32
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ dsh plugin --profile web remove @syncended/dsh-automations
|
|
|
56
56
|
|---|---|
|
|
57
57
|
| Name | Human-readable job name. |
|
|
58
58
|
| Cron | Five fields: `minute hour day-of-month month day-of-week`. Example: `0 9 * * 1-5`. |
|
|
59
|
-
|
|
|
59
|
+
| Time zone | Search by city or region in the picker, or enter `UTC` / an IANA name such as `Europe/Berlin`. Current UTC offsets are shown; DST is handled by `cron-parser`. |
|
|
60
60
|
| Project | Existing absolute directory. Its canonical filesystem identity becomes the Session cwd and `workspace-write` root. |
|
|
61
61
|
| Prompt | The user message sent to a fresh Harness Agent. |
|
|
62
62
|
| Provider / model | Leave both blank to resolve the current Harness default at dispatch time. Set both to pin a route. |
|
package/lib/client.js
CHANGED
|
@@ -11,6 +11,7 @@ window.__ModuleLoader__.load({
|
|
|
11
11
|
// the same-origin HTTP API at /api/automations; every mutation carries the
|
|
12
12
|
// x-dsh-automation-client fence header plus an application/json body.
|
|
13
13
|
const React = require("react");
|
|
14
|
+
const { createPortal } = require("react-dom");
|
|
14
15
|
const h = React.createElement;
|
|
15
16
|
const { useCallback, useEffect, useId, useRef, useState, useSyncExternalStore } = React;
|
|
16
17
|
const {
|
|
@@ -23,9 +24,11 @@ window.__ModuleLoader__.load({
|
|
|
23
24
|
IconChevronDownOutline14,
|
|
24
25
|
IconChevronLeftOutline14,
|
|
25
26
|
IconEditOutline16,
|
|
27
|
+
IconGlobeOutline14,
|
|
26
28
|
IconPlayOutline16,
|
|
27
29
|
IconPlusOutline16,
|
|
28
30
|
IconRefreshOutline16,
|
|
31
|
+
IconSearchOutline16,
|
|
29
32
|
IconSettingsOutline16,
|
|
30
33
|
IconTrashOutline16,
|
|
31
34
|
IconWarningOutline16,
|
|
@@ -50,24 +53,75 @@ window.__ModuleLoader__.load({
|
|
|
50
53
|
}
|
|
51
54
|
})();
|
|
52
55
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
56
|
+
const POPULAR_TIMEZONE_CANDIDATES = [
|
|
57
|
+
BROWSER_TIMEZONE,
|
|
58
|
+
"UTC",
|
|
59
|
+
"America/New_York",
|
|
60
|
+
"America/Los_Angeles",
|
|
61
|
+
"America/Sao_Paulo",
|
|
62
|
+
"Europe/London",
|
|
63
|
+
"Europe/Berlin",
|
|
64
|
+
"Europe/Moscow",
|
|
65
|
+
"Asia/Dubai",
|
|
66
|
+
"Asia/Kolkata",
|
|
67
|
+
"Asia/Shanghai",
|
|
68
|
+
"Asia/Tokyo",
|
|
69
|
+
"Australia/Sydney",
|
|
70
|
+
];
|
|
71
|
+
const PREFERRED_TIMEZONE_ALIASES = [
|
|
72
|
+
"Africa/Asmara",
|
|
73
|
+
"America/Argentina/Buenos_Aires",
|
|
74
|
+
"America/Atikokan",
|
|
75
|
+
"America/Indiana/Indianapolis",
|
|
76
|
+
"America/Kentucky/Louisville",
|
|
77
|
+
"America/Nuuk",
|
|
78
|
+
"Asia/Ho_Chi_Minh",
|
|
79
|
+
"Asia/Kathmandu",
|
|
80
|
+
"Asia/Kolkata",
|
|
81
|
+
"Asia/Yangon",
|
|
82
|
+
"Atlantic/Faroe",
|
|
83
|
+
"Europe/Kyiv",
|
|
84
|
+
"Pacific/Chuuk",
|
|
85
|
+
"Pacific/Kanton",
|
|
86
|
+
"Pacific/Pohnpei",
|
|
87
|
+
];
|
|
88
|
+
const TIMEZONE_ALIASES_BY_ZONE = new Map();
|
|
89
|
+
for (const alias of PREFERRED_TIMEZONE_ALIASES) {
|
|
90
|
+
const zone = canonicalTimezone(alias);
|
|
91
|
+
if (!zone || zone === alias) continue;
|
|
92
|
+
const aliases = TIMEZONE_ALIASES_BY_ZONE.get(zone) || [];
|
|
93
|
+
aliases.push(alias);
|
|
94
|
+
TIMEZONE_ALIASES_BY_ZONE.set(zone, aliases);
|
|
95
|
+
}
|
|
96
|
+
const POPULAR_TIMEZONES = Array.from(
|
|
97
|
+
new Set(POPULAR_TIMEZONE_CANDIDATES.map(canonicalTimezone).filter(Boolean)),
|
|
70
98
|
);
|
|
99
|
+
const SUPPORTED_TIMEZONES = (() => {
|
|
100
|
+
let discovered = [];
|
|
101
|
+
try {
|
|
102
|
+
discovered = typeof Intl.supportedValuesOf === "function"
|
|
103
|
+
? Intl.supportedValuesOf("timeZone")
|
|
104
|
+
: [];
|
|
105
|
+
} catch {
|
|
106
|
+
discovered = [];
|
|
107
|
+
}
|
|
108
|
+
return Array.from(
|
|
109
|
+
new Set([
|
|
110
|
+
...POPULAR_TIMEZONES,
|
|
111
|
+
...TIMEZONE_ALIASES_BY_ZONE.keys(),
|
|
112
|
+
...discovered.filter((zone) => typeof zone === "string" && zone !== ""),
|
|
113
|
+
]),
|
|
114
|
+
).sort((left, right) => left.localeCompare(right));
|
|
115
|
+
})();
|
|
116
|
+
const TIMEZONE_SEARCH_INDEX = SUPPORTED_TIMEZONES.map((zone) => {
|
|
117
|
+
const aliases = TIMEZONE_ALIASES_BY_ZONE.get(zone) || [];
|
|
118
|
+
const preferred = aliases[0] || zone;
|
|
119
|
+
return {
|
|
120
|
+
zone,
|
|
121
|
+
city: timezoneCityLabel(preferred),
|
|
122
|
+
search: timezoneSearchKey([zone, ...aliases].join(" ")),
|
|
123
|
+
};
|
|
124
|
+
});
|
|
71
125
|
|
|
72
126
|
const REASONING_EFFORTS = ["low", "medium", "high"];
|
|
73
127
|
const OVERLAP_OPTIONS = [
|
|
@@ -147,6 +201,110 @@ window.__ModuleLoader__.load({
|
|
|
147
201
|
});
|
|
148
202
|
}
|
|
149
203
|
|
|
204
|
+
function canonicalTimezone(value) {
|
|
205
|
+
const timezone = String(value || "").trim();
|
|
206
|
+
if (timezone === "") return null;
|
|
207
|
+
try {
|
|
208
|
+
return new Intl.DateTimeFormat("en-US", { timeZone: timezone }).resolvedOptions().timeZone;
|
|
209
|
+
} catch {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function timezoneCityLabel(zone) {
|
|
215
|
+
if (zone === "UTC") return "UTC";
|
|
216
|
+
const segments = zone.split("/");
|
|
217
|
+
return (segments[segments.length - 1] || zone).replace(/_/g, " ");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function timezonePreferredValue(zone) {
|
|
221
|
+
return TIMEZONE_ALIASES_BY_ZONE.get(zone)?.[0] || zone;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function timezoneSearchKey(zone) {
|
|
225
|
+
const literal = zone.toLowerCase();
|
|
226
|
+
const expanded = literal
|
|
227
|
+
.normalize("NFKD")
|
|
228
|
+
.replace(/[\u0300-\u036f]/g, "")
|
|
229
|
+
.replace(/[\/_\-.]+/g, " ")
|
|
230
|
+
.replace(/\s+/g, " ")
|
|
231
|
+
.trim();
|
|
232
|
+
return expanded;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function timezoneOffsetLabel(zone, at = new Date()) {
|
|
236
|
+
try {
|
|
237
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
238
|
+
timeZone: zone,
|
|
239
|
+
timeZoneName: "longOffset",
|
|
240
|
+
hour: "2-digit",
|
|
241
|
+
});
|
|
242
|
+
const value = formatter.formatToParts(at).find((part) => part.type === "timeZoneName")?.value;
|
|
243
|
+
if (!value) return "UTC offset unavailable";
|
|
244
|
+
if (value === "GMT") return "UTC+00:00";
|
|
245
|
+
return value.replace(/^GMT/, "UTC");
|
|
246
|
+
} catch {
|
|
247
|
+
return "UTC offset unavailable";
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function timezoneSearchResults(query, currentValue, limit = 30) {
|
|
252
|
+
const rawQuery = String(query || "").trim().toLowerCase();
|
|
253
|
+
const current = canonicalTimezone(currentValue);
|
|
254
|
+
if (rawQuery === "") {
|
|
255
|
+
return Array.from(
|
|
256
|
+
new Set([current, BROWSER_TIMEZONE, ...POPULAR_TIMEZONES].filter(Boolean)),
|
|
257
|
+
).slice(0, 12);
|
|
258
|
+
}
|
|
259
|
+
const normalizedQuery = timezoneSearchKey(rawQuery);
|
|
260
|
+
if (normalizedQuery === "") return [];
|
|
261
|
+
const terms = normalizedQuery.split(" ").filter(Boolean);
|
|
262
|
+
return TIMEZONE_SEARCH_INDEX
|
|
263
|
+
.filter((entry) => terms.every((term) => entry.search.includes(term)))
|
|
264
|
+
.map((entry) => {
|
|
265
|
+
const canonical = entry.zone.toLowerCase();
|
|
266
|
+
const preferred = timezonePreferredValue(entry.zone).toLowerCase();
|
|
267
|
+
const city = timezoneSearchKey(entry.city);
|
|
268
|
+
let score = 5;
|
|
269
|
+
if (canonical === rawQuery || preferred === rawQuery) score = 0;
|
|
270
|
+
else if (city === normalizedQuery) score = 1;
|
|
271
|
+
else if (city.startsWith(normalizedQuery)) score = 2;
|
|
272
|
+
else if (canonical.split("/").some((segment) => timezoneSearchKey(segment).startsWith(normalizedQuery))) score = 3;
|
|
273
|
+
else if (entry.search.startsWith(normalizedQuery)) score = 4;
|
|
274
|
+
return { ...entry, score };
|
|
275
|
+
})
|
|
276
|
+
.sort((left, right) => left.score - right.score || left.city.localeCompare(right.city) || left.zone.localeCompare(right.zone))
|
|
277
|
+
.slice(0, limit)
|
|
278
|
+
.map((entry) => entry.zone);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function timezoneNavigationIndex(key, current, resultCount, reopening) {
|
|
282
|
+
if (resultCount === 0) return -1;
|
|
283
|
+
if (reopening) return key === "ArrowDown" ? 0 : resultCount - 1;
|
|
284
|
+
if (key === "ArrowDown") return current < 0 || current >= resultCount - 1 ? 0 : current + 1;
|
|
285
|
+
return current <= 0 ? resultCount - 1 : current - 1;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function timezoneOptionPresentation(zone, offsetCache) {
|
|
289
|
+
let offset = offsetCache?.get(zone);
|
|
290
|
+
if (!offset) {
|
|
291
|
+
offset = timezoneOffsetLabel(zone);
|
|
292
|
+
offsetCache?.set(zone, offset);
|
|
293
|
+
}
|
|
294
|
+
const current = BROWSER_TIMEZONE === zone;
|
|
295
|
+
const preferred = timezonePreferredValue(zone);
|
|
296
|
+
if (zone === "UTC") {
|
|
297
|
+
return {
|
|
298
|
+
label: "UTC",
|
|
299
|
+
detail: offset + " now · Coordinated Universal Time" + (current ? " · Your browser time zone" : ""),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
label: timezoneCityLabel(preferred),
|
|
304
|
+
detail: preferred + " · " + offset + " now" + (current ? " · Your browser time zone" : ""),
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
150
308
|
function browserTimezone() {
|
|
151
309
|
return BROWSER_TIMEZONE;
|
|
152
310
|
}
|
|
@@ -446,6 +604,310 @@ window.__ModuleLoader__.load({
|
|
|
446
604
|
);
|
|
447
605
|
}
|
|
448
606
|
|
|
607
|
+
function useTimeZonePopoverLayout(open, anchorRef, panelRef) {
|
|
608
|
+
const [layout, setLayout] = useState(null);
|
|
609
|
+
useEffect(() => {
|
|
610
|
+
if (!open) {
|
|
611
|
+
setLayout(null);
|
|
612
|
+
return undefined;
|
|
613
|
+
}
|
|
614
|
+
const place = () => {
|
|
615
|
+
const anchor = anchorRef.current;
|
|
616
|
+
if (!anchor) return;
|
|
617
|
+
const rect = anchor.getBoundingClientRect();
|
|
618
|
+
const panel = panelRef.current;
|
|
619
|
+
const margin = 12;
|
|
620
|
+
const gap = 4;
|
|
621
|
+
const width = Math.min(Math.max(rect.width, 280), window.innerWidth - margin * 2);
|
|
622
|
+
const left = Math.min(Math.max(rect.left, margin), window.innerWidth - width - margin);
|
|
623
|
+
const desiredHeight = Math.min(360, panel?.scrollHeight || 360);
|
|
624
|
+
const below = window.innerHeight - rect.bottom - gap - margin;
|
|
625
|
+
const above = rect.top - gap - margin;
|
|
626
|
+
const side = below >= Math.min(desiredHeight, 220) || below >= above ? "bottom" : "top";
|
|
627
|
+
const available = Math.max(80, side === "bottom" ? below : above);
|
|
628
|
+
const maxHeight = Math.min(360, available);
|
|
629
|
+
const renderedHeight = Math.min(panel?.offsetHeight || desiredHeight, maxHeight);
|
|
630
|
+
const top = side === "bottom"
|
|
631
|
+
? rect.bottom + gap
|
|
632
|
+
: Math.max(margin, rect.top - gap - renderedHeight);
|
|
633
|
+
setLayout((current) => {
|
|
634
|
+
const next = { left, top, width, maxHeight, side };
|
|
635
|
+
return current
|
|
636
|
+
&& current.left === next.left
|
|
637
|
+
&& current.top === next.top
|
|
638
|
+
&& current.width === next.width
|
|
639
|
+
&& current.maxHeight === next.maxHeight
|
|
640
|
+
&& current.side === next.side
|
|
641
|
+
? current
|
|
642
|
+
: next;
|
|
643
|
+
});
|
|
644
|
+
};
|
|
645
|
+
const frame = requestAnimationFrame(place);
|
|
646
|
+
window.addEventListener("scroll", place, true);
|
|
647
|
+
window.addEventListener("resize", place);
|
|
648
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(place);
|
|
649
|
+
if (anchorRef.current) observer?.observe(anchorRef.current);
|
|
650
|
+
if (panelRef.current) observer?.observe(panelRef.current);
|
|
651
|
+
return () => {
|
|
652
|
+
cancelAnimationFrame(frame);
|
|
653
|
+
observer?.disconnect();
|
|
654
|
+
window.removeEventListener("scroll", place, true);
|
|
655
|
+
window.removeEventListener("resize", place);
|
|
656
|
+
};
|
|
657
|
+
}, [open, anchorRef, panelRef]);
|
|
658
|
+
return layout;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function TimeZonePicker({ id, value, onChange }) {
|
|
662
|
+
const [open, setOpen] = useState(false);
|
|
663
|
+
const [searching, setSearching] = useState(false);
|
|
664
|
+
const [activeIndex, setActiveIndex] = useState(-1);
|
|
665
|
+
const [announcement, setAnnouncement] = useState("");
|
|
666
|
+
const anchorRef = useRef(null);
|
|
667
|
+
const inputRef = useRef(null);
|
|
668
|
+
const panelRef = useRef(null);
|
|
669
|
+
const offsetCacheRef = useRef(new Map());
|
|
670
|
+
const listboxId = id + "-options";
|
|
671
|
+
const query = searching ? value : "";
|
|
672
|
+
const results = timezoneSearchResults(query, value);
|
|
673
|
+
const active = activeIndex >= 0 && activeIndex < results.length ? activeIndex : -1;
|
|
674
|
+
const selected = canonicalTimezone(value);
|
|
675
|
+
const resumeSearch = value.trim() !== "" && selected === null;
|
|
676
|
+
const popoverLayout = useTimeZonePopoverLayout(open, anchorRef, panelRef);
|
|
677
|
+
const close = () => {
|
|
678
|
+
setOpen(false);
|
|
679
|
+
setSearching(false);
|
|
680
|
+
setActiveIndex(-1);
|
|
681
|
+
setAnnouncement("");
|
|
682
|
+
};
|
|
683
|
+
const show = () => {
|
|
684
|
+
offsetCacheRef.current.clear();
|
|
685
|
+
setAnnouncement("");
|
|
686
|
+
setOpen(true);
|
|
687
|
+
};
|
|
688
|
+
const choose = (zone) => {
|
|
689
|
+
onChange(timezonePreferredValue(zone));
|
|
690
|
+
close();
|
|
691
|
+
requestAnimationFrame(() => inputRef.current?.focus());
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
useEffect(() => {
|
|
695
|
+
if (!open) return undefined;
|
|
696
|
+
const dismiss = (event) => {
|
|
697
|
+
const target = event.target;
|
|
698
|
+
if (!(target instanceof Node)) return;
|
|
699
|
+
if (anchorRef.current?.contains(target) || panelRef.current?.contains(target)) return;
|
|
700
|
+
close();
|
|
701
|
+
};
|
|
702
|
+
document.addEventListener("pointerdown", dismiss, true);
|
|
703
|
+
return () => document.removeEventListener("pointerdown", dismiss, true);
|
|
704
|
+
}, [open]);
|
|
705
|
+
|
|
706
|
+
useEffect(() => {
|
|
707
|
+
if (!open) return undefined;
|
|
708
|
+
const timer = window.setTimeout(() => {
|
|
709
|
+
setAnnouncement(
|
|
710
|
+
results.length === 0
|
|
711
|
+
? "No matching time zones."
|
|
712
|
+
: results.length + (results.length === 1 ? " time zone suggestion available." : " time zone suggestions available."),
|
|
713
|
+
);
|
|
714
|
+
}, 250);
|
|
715
|
+
return () => window.clearTimeout(timer);
|
|
716
|
+
}, [open, query, results.length]);
|
|
717
|
+
|
|
718
|
+
useEffect(() => {
|
|
719
|
+
if (!open || active < 0) return;
|
|
720
|
+
document.getElementById(listboxId + "-option-" + active)?.scrollIntoView({ block: "nearest" });
|
|
721
|
+
}, [open, active, listboxId]);
|
|
722
|
+
|
|
723
|
+
const onInputKeyDown = (event) => {
|
|
724
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
725
|
+
event.preventDefault();
|
|
726
|
+
const navigationResults = !open && resumeSearch
|
|
727
|
+
? timezoneSearchResults(value, value)
|
|
728
|
+
: results;
|
|
729
|
+
if (!open) {
|
|
730
|
+
setSearching(resumeSearch);
|
|
731
|
+
show();
|
|
732
|
+
}
|
|
733
|
+
if (navigationResults.length === 0) {
|
|
734
|
+
setActiveIndex(-1);
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
setActiveIndex((current) =>
|
|
738
|
+
timezoneNavigationIndex(event.key, current, navigationResults.length, !open),
|
|
739
|
+
);
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
if (event.key === "Enter" && open) {
|
|
743
|
+
event.preventDefault();
|
|
744
|
+
if (active >= 0) {
|
|
745
|
+
choose(results[active]);
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
const canonical = canonicalTimezone(value);
|
|
749
|
+
if (canonical) choose(canonical);
|
|
750
|
+
else setAnnouncement("Enter a valid IANA time zone, such as Europe/Berlin.");
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
if (event.key === "Escape" && open) {
|
|
754
|
+
event.preventDefault();
|
|
755
|
+
event.stopPropagation();
|
|
756
|
+
(event.nativeEvent || event).__dshAutomationsNested = true;
|
|
757
|
+
close();
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
if (event.key === "Tab" && open) close();
|
|
761
|
+
};
|
|
762
|
+
|
|
763
|
+
const panel = open
|
|
764
|
+
? h(
|
|
765
|
+
"div",
|
|
766
|
+
{
|
|
767
|
+
ref: panelRef,
|
|
768
|
+
className: "dsh-auto-timezone-popover",
|
|
769
|
+
style: popoverLayout
|
|
770
|
+
? {
|
|
771
|
+
left: popoverLayout.left,
|
|
772
|
+
top: popoverLayout.top,
|
|
773
|
+
width: popoverLayout.width,
|
|
774
|
+
maxHeight: popoverLayout.maxHeight,
|
|
775
|
+
}
|
|
776
|
+
: { left: 12, top: 12, width: 320, visibility: "hidden" },
|
|
777
|
+
"data-side": popoverLayout?.side,
|
|
778
|
+
"data-dsh-auto-timezone-popover": "true",
|
|
779
|
+
},
|
|
780
|
+
h(
|
|
781
|
+
"div",
|
|
782
|
+
{ className: "dsh-auto-timezone-popover-title" },
|
|
783
|
+
searching && query.trim() !== "" ? "Matching time zones" : "Suggested time zones",
|
|
784
|
+
),
|
|
785
|
+
h(
|
|
786
|
+
"div",
|
|
787
|
+
{
|
|
788
|
+
id: listboxId,
|
|
789
|
+
className: "dsh-auto-timezone-list",
|
|
790
|
+
role: "listbox",
|
|
791
|
+
"aria-label": "Time zones",
|
|
792
|
+
},
|
|
793
|
+
results.length > 0
|
|
794
|
+
? results.map((zone, index) => {
|
|
795
|
+
const copy = timezoneOptionPresentation(zone, offsetCacheRef.current);
|
|
796
|
+
const optionId = listboxId + "-option-" + index;
|
|
797
|
+
return h(
|
|
798
|
+
"div",
|
|
799
|
+
{
|
|
800
|
+
key: zone,
|
|
801
|
+
id: optionId,
|
|
802
|
+
className: "dsh-auto-timezone-option",
|
|
803
|
+
role: "option",
|
|
804
|
+
"aria-selected": selected === zone,
|
|
805
|
+
"data-active": active === index ? "true" : undefined,
|
|
806
|
+
onPointerMove: () => setActiveIndex(index),
|
|
807
|
+
onPointerDown: (event) => event.preventDefault(),
|
|
808
|
+
onClick: () => choose(zone),
|
|
809
|
+
},
|
|
810
|
+
h("span", { className: "dsh-auto-timezone-option-icon", "aria-hidden": "true" }, h(IconGlobeOutline14)),
|
|
811
|
+
h(
|
|
812
|
+
"span",
|
|
813
|
+
{ className: "dsh-auto-picker-item-copy" },
|
|
814
|
+
h("span", { className: "dsh-auto-picker-item-label" }, copy.label),
|
|
815
|
+
h("span", { className: "dsh-auto-picker-item-detail" }, copy.detail),
|
|
816
|
+
),
|
|
817
|
+
selected === zone
|
|
818
|
+
? h("span", { className: "dsh-auto-timezone-option-check", "aria-hidden": "true" }, h(IconCheckOutline16))
|
|
819
|
+
: null,
|
|
820
|
+
);
|
|
821
|
+
})
|
|
822
|
+
: h(
|
|
823
|
+
"div",
|
|
824
|
+
{
|
|
825
|
+
className: "dsh-auto-timezone-empty",
|
|
826
|
+
role: "option",
|
|
827
|
+
"aria-disabled": "true",
|
|
828
|
+
"aria-selected": false,
|
|
829
|
+
},
|
|
830
|
+
"No matching time zones. You can still enter a recognized IANA time zone, such as Europe/Berlin.",
|
|
831
|
+
),
|
|
832
|
+
),
|
|
833
|
+
h("p", { className: "dsh-auto-timezone-popover-hint" }, "Type a city, region, or IANA time zone."),
|
|
834
|
+
)
|
|
835
|
+
: null;
|
|
836
|
+
|
|
837
|
+
return h(
|
|
838
|
+
React.Fragment,
|
|
839
|
+
null,
|
|
840
|
+
h(
|
|
841
|
+
"span",
|
|
842
|
+
{
|
|
843
|
+
ref: anchorRef,
|
|
844
|
+
className: "dsh-auto-timezone-control",
|
|
845
|
+
"data-open": open ? "true" : undefined,
|
|
846
|
+
onPointerDown: (event) => {
|
|
847
|
+
if (event.target === inputRef.current) return;
|
|
848
|
+
event.preventDefault();
|
|
849
|
+
if (open) close();
|
|
850
|
+
else {
|
|
851
|
+
setSearching(resumeSearch);
|
|
852
|
+
show();
|
|
853
|
+
requestAnimationFrame(() => {
|
|
854
|
+
inputRef.current?.focus();
|
|
855
|
+
inputRef.current?.select();
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
},
|
|
859
|
+
},
|
|
860
|
+
h("span", { className: "dsh-auto-timezone-control-icon", "aria-hidden": "true" }, h(IconGlobeOutline14)),
|
|
861
|
+
h("input", {
|
|
862
|
+
ref: inputRef,
|
|
863
|
+
id,
|
|
864
|
+
className: "dsh-auto-timezone-input",
|
|
865
|
+
type: "text",
|
|
866
|
+
role: "combobox",
|
|
867
|
+
value,
|
|
868
|
+
placeholder: "Search city or time zone",
|
|
869
|
+
autoComplete: "off",
|
|
870
|
+
spellCheck: false,
|
|
871
|
+
"aria-autocomplete": "list",
|
|
872
|
+
"aria-haspopup": "listbox",
|
|
873
|
+
"aria-expanded": open,
|
|
874
|
+
"aria-controls": open ? listboxId : undefined,
|
|
875
|
+
"aria-activedescendant": open && active >= 0 ? listboxId + "-option-" + active : undefined,
|
|
876
|
+
"aria-invalid": !open && value.trim() !== "" && selected === null ? "true" : undefined,
|
|
877
|
+
onFocus: (event) => {
|
|
878
|
+
setSearching(resumeSearch);
|
|
879
|
+
setActiveIndex(-1);
|
|
880
|
+
show();
|
|
881
|
+
event.currentTarget.select();
|
|
882
|
+
},
|
|
883
|
+
onClick: () => {
|
|
884
|
+
if (open) return;
|
|
885
|
+
setSearching(resumeSearch);
|
|
886
|
+
setActiveIndex(-1);
|
|
887
|
+
show();
|
|
888
|
+
},
|
|
889
|
+
onChange: (event) => {
|
|
890
|
+
setSearching(true);
|
|
891
|
+
setActiveIndex(0);
|
|
892
|
+
show();
|
|
893
|
+
onChange(event.target.value);
|
|
894
|
+
},
|
|
895
|
+
onKeyDown: onInputKeyDown,
|
|
896
|
+
}),
|
|
897
|
+
h(
|
|
898
|
+
"span",
|
|
899
|
+
{
|
|
900
|
+
className: "dsh-auto-timezone-chevron" + (open ? " dsh-auto-timezone-chevron-open" : ""),
|
|
901
|
+
"aria-hidden": "true",
|
|
902
|
+
},
|
|
903
|
+
h(IconChevronDownOutline14),
|
|
904
|
+
),
|
|
905
|
+
),
|
|
906
|
+
open && typeof document !== "undefined" ? createPortal(panel, document.body) : null,
|
|
907
|
+
h("span", { className: "dsh-auto-sr-only", role: "status", "aria-live": "polite" }, announcement),
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
|
|
449
911
|
function AgentPresetPicker({ id, value, presets, onChange }) {
|
|
450
912
|
const [open, setOpen] = useState(false);
|
|
451
913
|
const ownerId = useId();
|
|
@@ -692,21 +1154,17 @@ window.__ModuleLoader__.load({
|
|
|
692
1154
|
),
|
|
693
1155
|
h(
|
|
694
1156
|
Field,
|
|
695
|
-
{
|
|
696
|
-
|
|
1157
|
+
{
|
|
1158
|
+
label: "Time zone",
|
|
1159
|
+
htmlFor: fieldId("timezone"),
|
|
1160
|
+
required: true,
|
|
1161
|
+
hint: "Enter an IANA time zone. Current UTC offsets may change with daylight saving time.",
|
|
1162
|
+
},
|
|
1163
|
+
h(TimeZonePicker, {
|
|
697
1164
|
id: fieldId("timezone"),
|
|
698
|
-
className: "dsh-auto-input",
|
|
699
|
-
type: "text",
|
|
700
|
-
list: fieldId("timezone-list"),
|
|
701
1165
|
value: draft.timezone,
|
|
702
|
-
|
|
703
|
-
onChange: (event) => onChange("timezone", event.target.value),
|
|
1166
|
+
onChange: (value) => onChange("timezone", value),
|
|
704
1167
|
}),
|
|
705
|
-
h(
|
|
706
|
-
"datalist",
|
|
707
|
-
{ id: fieldId("timezone-list") },
|
|
708
|
-
TIMEZONES.map((zone) => h("option", { key: zone, value: zone })),
|
|
709
|
-
),
|
|
710
1168
|
),
|
|
711
1169
|
h(
|
|
712
1170
|
Field,
|
|
@@ -1657,7 +2115,7 @@ window.__ModuleLoader__.load({
|
|
|
1657
2115
|
const onKeyDown = (event) => {
|
|
1658
2116
|
if (event.key !== "Escape" || event.defaultPrevented || event.__dshAutomationsNested) return;
|
|
1659
2117
|
if (event.target?.closest?.('[role="dialog"],[role="menu"]')) return;
|
|
1660
|
-
if (document.querySelector('.dsh-auto-picker-trigger[aria-expanded="true"]')) return;
|
|
2118
|
+
if (document.querySelector('.dsh-auto-picker-trigger[aria-expanded="true"],.dsh-auto-timezone-input[aria-expanded="true"]')) return;
|
|
1661
2119
|
event.preventDefault();
|
|
1662
2120
|
disclosure.close();
|
|
1663
2121
|
};
|
|
@@ -1745,7 +2203,29 @@ window.__ModuleLoader__.load({
|
|
|
1745
2203
|
".dsh-auto-picker-chevron-open{transform:rotate(180deg);}",
|
|
1746
2204
|
".dsh-auto-picker-item-copy{min-width:0;display:flex;flex-direction:column;white-space:normal;}",
|
|
1747
2205
|
".dsh-auto-picker-item-label{color:inherit;font-size:14px;line-height:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
|
|
1748
|
-
".dsh-auto-picker-item-detail{color:var(--dsh-auto-muted);font-size:12px;line-height:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
|
|
2206
|
+
".dsh-auto-picker-item-detail{color:var(--dsh-auto-muted,var(--dsw-alias-label-tertiary,#81858c));font-size:12px;line-height:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
|
|
2207
|
+
".dsh-auto-timezone-control{width:100%;height:34px;padding:0 8px;display:flex;align-items:center;gap:7px;border:1px solid var(--dsh-auto-border);border-radius:8px;background:var(--dsh-auto-input-bg);color:var(--dsh-auto-text);cursor:text;}",
|
|
2208
|
+
".dsh-auto-timezone-control:hover{background:var(--dsw-alias-interactive-bg-hover,var(--dsh-auto-input-bg));}",
|
|
2209
|
+
".dsh-auto-timezone-control:focus-within,.dsh-auto-timezone-control[data-open=\"true\"]{border-color:var(--dsh-auto-accent);box-shadow:0 0 0 2px color-mix(in srgb,var(--dsh-auto-accent) 18%,transparent);}",
|
|
2210
|
+
".dsh-auto-timezone-control:has(.dsh-auto-timezone-input[aria-invalid=\"true\"]){border-color:var(--dsh-auto-danger);}",
|
|
2211
|
+
".dsh-auto-timezone-control-icon,.dsh-auto-timezone-chevron{width:16px;height:16px;flex:none;display:inline-flex;align-items:center;justify-content:center;color:var(--dsh-auto-muted);pointer-events:none;}",
|
|
2212
|
+
".dsh-auto-timezone-input{appearance:none;min-width:0;height:100%;flex:1;padding:0;border:0;outline:0;background:transparent;color:inherit;font:inherit;font-size:13px;line-height:20px;}",
|
|
2213
|
+
".dsh-auto-timezone-input::placeholder{color:var(--dsh-auto-caption);}",
|
|
2214
|
+
".dsh-auto-timezone-chevron{transition:transform .12s ease;}",
|
|
2215
|
+
".dsh-auto-timezone-chevron-open{transform:rotate(180deg);}",
|
|
2216
|
+
".dsh-auto-timezone-popover{box-sizing:border-box;position:fixed;z-index:1100;max-height:min(360px,calc(100vh - 24px));padding:4px;display:flex;flex-direction:column;border:1px solid var(--dsw-alias-border-inverted,var(--dsw-alias-border-l2,rgba(15,17,21,.16)));border-radius:12px;background:var(--dsw-specific-menu,var(--dsw-alias-bg-layer-2,#fff));box-shadow:var(--dsw-shadow-lv3,0 12px 32px rgba(15,17,21,.16));color:var(--dsw-alias-label-primary,#0f1115);font-family:inherit;}",
|
|
2217
|
+
".dsh-auto-timezone-popover *,.dsh-auto-timezone-popover *::before,.dsh-auto-timezone-popover *::after{box-sizing:border-box;}",
|
|
2218
|
+
".dsh-auto-timezone-popover-title{flex:none;padding:7px 10px 5px;color:var(--dsw-alias-label-tertiary,#81858c);font-size:11px;font-weight:600;line-height:16px;text-transform:uppercase;letter-spacing:.04em;}",
|
|
2219
|
+
".dsh-auto-timezone-list{min-height:0;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);}",
|
|
2220
|
+
".dsh-auto-timezone-option{width:100%;min-height:48px;padding:6px 9px;display:flex;align-items:center;gap:8px;border-radius:9px;cursor:pointer;user-select:none;}",
|
|
2221
|
+
".dsh-auto-timezone-option:hover,.dsh-auto-timezone-option[data-active=\"true\"]{background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06));}",
|
|
2222
|
+
".dsh-auto-timezone-option[aria-selected=\"true\"]{color:var(--dsw-alias-state-business-primary,#4176e6);}",
|
|
2223
|
+
".dsh-auto-timezone-option-icon,.dsh-auto-timezone-option-check{width:16px;height:16px;flex:none;display:inline-flex;align-items:center;justify-content:center;color:var(--dsw-alias-label-tertiary,#81858c);}",
|
|
2224
|
+
".dsh-auto-timezone-option>.dsh-auto-picker-item-copy{min-width:0;flex:1;}",
|
|
2225
|
+
".dsh-auto-timezone-option .dsh-auto-picker-item-detail{color:var(--dsw-alias-label-tertiary,#81858c);}",
|
|
2226
|
+
".dsh-auto-timezone-option-check{color:var(--dsw-alias-state-business-primary,#4176e6);}",
|
|
2227
|
+
".dsh-auto-timezone-empty{margin:0;padding:16px 12px;color:var(--dsw-alias-label-secondary,#4f5661);font-size:12px;line-height:18px;text-align:center;}",
|
|
2228
|
+
".dsh-auto-timezone-popover-hint{flex:none;margin:4px 0 0;padding:7px 10px 5px;border-top:1px solid var(--dsw-alias-border-l2,rgba(15,17,21,.12));color:var(--dsw-alias-label-tertiary,#81858c);font-size:11px;line-height:16px;}",
|
|
1749
2229
|
".dsh-auto-permission-glyph{flex:none;}",
|
|
1750
2230
|
".dsh-auto-permission-glyph-read{color:var(--dsh-auto-muted);}",
|
|
1751
2231
|
".dsh-auto-permission-glyph-write{color:var(--dsh-auto-accent);}",
|
|
@@ -1888,7 +2368,16 @@ window.__ModuleLoader__.load({
|
|
|
1888
2368
|
exports.agentPresetDisplayLabel = agentPresetDisplayLabel;
|
|
1889
2369
|
exports.permissionPresetPresentation = permissionPresetPresentation;
|
|
1890
2370
|
exports.PermissionPresetPicker = PermissionPresetPicker;
|
|
1891
|
-
exports.
|
|
2371
|
+
exports.TimeZonePicker = TimeZonePicker;
|
|
2372
|
+
exports.__testing = Object.freeze({
|
|
2373
|
+
nextFormInstancePrefix,
|
|
2374
|
+
canonicalTimezone,
|
|
2375
|
+
timezoneOffsetLabel,
|
|
2376
|
+
timezoneNavigationIndex,
|
|
2377
|
+
timezoneOptionPresentation,
|
|
2378
|
+
timezonePreferredValue,
|
|
2379
|
+
timezoneSearchResults,
|
|
2380
|
+
});
|
|
1892
2381
|
exports.inject = inject;
|
|
1893
2382
|
exports.apply = apply;
|
|
1894
2383
|
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.4.0",
|
|
4
4
|
"description": "Durable cron automations for DeepSeek Harness",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -91,7 +91,8 @@
|
|
|
91
91
|
"@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
|
|
92
92
|
"@deepseek-ai/dsh-permission-presets": "^0.1.1-rc.2",
|
|
93
93
|
"@deepseek-ai/dsh-session": "^0.1.1-rc.2",
|
|
94
|
-
"react": "^18.2.0"
|
|
94
|
+
"react": "^18.2.0",
|
|
95
|
+
"react-dom": "^18.2.0"
|
|
95
96
|
},
|
|
96
97
|
"devDependencies": {
|
|
97
98
|
"@deepseek-ai/cordis": "4.0.1",
|
|
@@ -110,6 +111,7 @@
|
|
|
110
111
|
"@deepseek-ai/dsh-session": "0.1.1-rc.2",
|
|
111
112
|
"@types/node": "^22.0.0",
|
|
112
113
|
"react": "^18.2.0",
|
|
114
|
+
"react-dom": "^18.2.0",
|
|
113
115
|
"typescript": "^5.9.3"
|
|
114
116
|
}
|
|
115
117
|
}
|