@michengai/dsh-automation 0.1.19 → 0.1.21

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/lib/client.js CHANGED
@@ -27,10 +27,10 @@ __export(index_exports, {
27
27
  name: () => name
28
28
  });
29
29
  module.exports = __toCommonJS(index_exports);
30
- var import_react8 = require("react");
30
+ var import_react11 = require("react");
31
31
 
32
32
  // src/client/AutomationView.tsx
33
- var import_react4 = require("react");
33
+ var import_react6 = require("react");
34
34
 
35
35
  // src/client/helpers.ts
36
36
  var AutomationFormError = class extends Error {
@@ -227,6 +227,24 @@ function sortAutomations(items, key, direction) {
227
227
  return left.id.localeCompare(right.id);
228
228
  });
229
229
  }
230
+ var SETTINGS_SORT_DEFAULT_KEY = "dsh-automation.sort-default.settings";
231
+ var OVERVIEW_SORT_DEFAULT_KEY = "dsh-automation.sort-default.overview";
232
+ function readSortDefault(storage, storageKey) {
233
+ if (storage === void 0) return void 0;
234
+ try {
235
+ const raw = storage.getItem(storageKey);
236
+ if (raw === null) return void 0;
237
+ const parsed = JSON.parse(raw);
238
+ if (parsed.key !== "created" && parsed.key !== "planned") return void 0;
239
+ if (parsed.direction !== "asc" && parsed.direction !== "desc") return void 0;
240
+ return { key: parsed.key, direction: parsed.direction };
241
+ } catch {
242
+ return void 0;
243
+ }
244
+ }
245
+ function writeSortDefault(storage, storageKey, key, direction) {
246
+ storage.setItem(storageKey, JSON.stringify({ key, direction }));
247
+ }
230
248
  function groupHistory(runs, range, now, t) {
231
249
  const buckets = /* @__PURE__ */ new Map();
232
250
  for (const run of runs) {
@@ -322,6 +340,9 @@ function RefreshIcon(props) {
322
340
  function PlayIcon(props) {
323
341
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 16 16", width: 16, height: 16, fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4.6 3.4 11.7 8l-7.1 4.6V3.4Z", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.6", strokeLinejoin: "round" }) });
324
342
  }
343
+ function PauseIcon(props) {
344
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFrame, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 7v10M15 7v10" }) });
345
+ }
325
346
  function TrashIcon(props) {
326
347
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FillIcon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M14.478 4.841 14.214 10.115c-.104 2.072-.147 2.896-.827 3.846a3.53 3.53 0 0 1-1.044.993c-.519.333-1.101.478-1.784.546-.671.067-1.509.066-2.559.066s-1.887.001-2.558-.066c-.683-.068-1.266-.213-1.784-.546a3.53 3.53 0 0 1-1.044-.993c-.681-.95-.724-1.774-.828-3.846L1.522 4.841l1.368-.068.263 5.273c.109 2.176.171 2.556.573 3.117a2.16 2.16 0 0 0 .673.64c.263.169.603.277 1.179.334.587.059 1.345.06 2.422.06s1.834-.001 2.422-.06c.575-.057.916-.165 1.179-.335.262-.168.49-.386.672-.64.402-.56.464-.94.573-3.116l.263-5.273 1.369.068ZM5.43 6.228h1.37v5.163H5.43V6.228Zm3.77 0h1.37v5.163H9.2V6.228ZM8.536.434c.644 0 1.116-.007 1.56.137.14.045.276.101.406.168.416.212.745.552 1.2 1.007l.796.795h2.876v1.37H.626V2.541h2.876l.796-.795c.456-.455.784-.795 1.2-1.007.13-.067.266-.123.405-.168C6.348.427 6.82.434 7.464.434h1.072Zm-1.072 1.37c-.732 0-.948.008-1.138.07a2.2 2.2 0 0 0-.206.085c-.156.08-.296.204-.678.583h5.117c-.382-.379-.522-.503-.679-.583a2.2 2.2 0 0 0-.205-.085c-.191-.062-.406-.07-1.138-.07H7.464Z" }) });
327
348
  }
@@ -331,6 +352,15 @@ function ShieldIcon(props) {
331
352
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m9.4 12 1.7 1.7 3.7-4" })
332
353
  ] });
333
354
  }
355
+ function CalendarIcon(props) {
356
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(IconFrame, { ...props, children: [
357
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "4", y: "5.5", width: "16", height: "14", rx: "2" }),
358
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 3.8v3.4M16 3.8v3.4M4 9.5h16" })
359
+ ] });
360
+ }
361
+ function CheckIcon(props) {
362
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFrame, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m5.5 12.5 4 4 9-9" }) });
363
+ }
334
364
  function MoreIcon(props) {
335
365
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(IconFrame, { ...props, children: [
336
366
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "6", cy: "12", r: "1.2", fill: "currentColor" }),
@@ -1167,6 +1197,131 @@ function DeleteConfirmation({
1167
1197
  ) });
1168
1198
  }
1169
1199
 
1200
+ // src/client/dropdown-menu.tsx
1201
+ var import_react4 = require("react");
1202
+ var import_react_dom2 = require("react-dom");
1203
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1204
+ function DropdownMenu({
1205
+ ariaLabel,
1206
+ className,
1207
+ buttonClassName,
1208
+ menuClassName,
1209
+ options,
1210
+ trigger
1211
+ }) {
1212
+ const [open, setOpen] = (0, import_react4.useState)(false);
1213
+ const root = (0, import_react4.useRef)(null);
1214
+ const menuRef = (0, import_react4.useRef)(null);
1215
+ const [menuStyle, setMenuStyle] = (0, import_react4.useState)({});
1216
+ const selectedLabel = options.find((option) => option.selected)?.label ?? options[0]?.label ?? ariaLabel;
1217
+ (0, import_react4.useEffect)(() => {
1218
+ if (!open) return;
1219
+ const close = (event) => {
1220
+ if (root.current !== null && root.current.contains(event.target)) return;
1221
+ if (menuRef.current?.contains(event.target) === true) return;
1222
+ setOpen(false);
1223
+ };
1224
+ const closeOnEscape = (event) => {
1225
+ if (event.key === "Escape") setOpen(false);
1226
+ };
1227
+ document.addEventListener("mousedown", close);
1228
+ document.addEventListener("keydown", closeOnEscape);
1229
+ return () => {
1230
+ document.removeEventListener("mousedown", close);
1231
+ document.removeEventListener("keydown", closeOnEscape);
1232
+ };
1233
+ }, [open]);
1234
+ (0, import_react4.useLayoutEffect)(() => {
1235
+ if (!open) return;
1236
+ const update = () => {
1237
+ const button = root.current?.querySelector(".dsh-st-dropdown-btn");
1238
+ const rect = button?.getBoundingClientRect();
1239
+ if (rect === void 0) return;
1240
+ const height = menuRef.current?.offsetHeight ?? 220;
1241
+ const margin = 8;
1242
+ let top = rect.bottom + 6;
1243
+ if (top + height > window.innerHeight - margin) top = Math.max(margin, rect.top - height - 6);
1244
+ const right = Math.max(margin, window.innerWidth - rect.right);
1245
+ setMenuStyle((current) => current.top === top && current.right === right ? current : { position: "fixed", top, right });
1246
+ };
1247
+ const onScroll = (event) => {
1248
+ if (event.target instanceof Node && menuRef.current?.contains(event.target)) return;
1249
+ update();
1250
+ };
1251
+ update();
1252
+ window.addEventListener("resize", update);
1253
+ document.addEventListener("scroll", onScroll, true);
1254
+ return () => {
1255
+ window.removeEventListener("resize", update);
1256
+ document.removeEventListener("scroll", onScroll, true);
1257
+ };
1258
+ }, [open, selectedLabel]);
1259
+ const menu = open && typeof document !== "undefined" ? (0, import_react_dom2.createPortal)(
1260
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: menuRef, className: `dsh-st-dropdown-menu is-float${menuClassName === void 0 ? "" : ` ${menuClassName}`}`, style: menuStyle, children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1261
+ DropdownRow,
1262
+ {
1263
+ label: option.label,
1264
+ selected: option.selected,
1265
+ trailing: option.trailing,
1266
+ onSelect: () => {
1267
+ if (option.keepOpen !== true) setOpen(false);
1268
+ option.onSelect();
1269
+ }
1270
+ },
1271
+ option.key
1272
+ )) }),
1273
+ document.body
1274
+ ) : null;
1275
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `dsh-st-dropdown${className === void 0 ? "" : ` ${className}`}`, ref: root, children: [
1276
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: `dsh-st-dropdown-btn${buttonClassName === void 0 ? "" : ` ${buttonClassName}`}${open ? " is-open" : ""}`, "aria-label": ariaLabel, "aria-expanded": open, onClick: () => setOpen((value) => !value), children: trigger ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1277
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-dropdown-label", children: selectedLabel }),
1278
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronIcon, { width: 10, height: 10, className: "dsh-st-dropdown-chevron" })
1279
+ ] }) }),
1280
+ menu
1281
+ ] });
1282
+ }
1283
+ function DropdownRow({
1284
+ label,
1285
+ selected,
1286
+ trailing,
1287
+ onSelect
1288
+ }) {
1289
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1290
+ "div",
1291
+ {
1292
+ className: `dsh-st-dropdown-row${selected ? " is-selected" : ""}${trailing === void 0 ? "" : " has-trailing"}`,
1293
+ role: "menuitemradio",
1294
+ "aria-checked": selected,
1295
+ tabIndex: 0,
1296
+ onClick: onSelect,
1297
+ onKeyDown: (event) => {
1298
+ if (event.key === "Enter" || event.key === " ") {
1299
+ event.preventDefault();
1300
+ onSelect();
1301
+ }
1302
+ },
1303
+ children: [
1304
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-dropdown-label-cell", children: label }),
1305
+ trailing !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1306
+ "button",
1307
+ {
1308
+ type: "button",
1309
+ className: `dsh-st-dropdown-default${trailing.active ? " is-on" : ""}`,
1310
+ disabled: trailing.active,
1311
+ onClick: (event) => {
1312
+ event.stopPropagation();
1313
+ trailing.onSelect();
1314
+ },
1315
+ children: trailing.label
1316
+ }
1317
+ ),
1318
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-dropdown-spacer" }),
1319
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-dropdown-check", children: selected ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CheckOutlineIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-sort-tick" }) })
1320
+ ]
1321
+ }
1322
+ );
1323
+ }
1324
+
1170
1325
  // src/client/prefill.ts
1171
1326
  var pending = null;
1172
1327
  var listeners = /* @__PURE__ */ new Set();
@@ -1349,29 +1504,139 @@ function createAutomationRuntime(rpc) {
1349
1504
  };
1350
1505
  }
1351
1506
 
1507
+ // src/client/sort-menu.tsx
1508
+ var import_react5 = require("react");
1509
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1510
+ var SORT_OPTIONS = [
1511
+ ["created", "desc"],
1512
+ ["created", "asc"],
1513
+ ["planned", "asc"],
1514
+ ["planned", "desc"]
1515
+ ];
1516
+ function SortMenu({
1517
+ t,
1518
+ storage,
1519
+ storageKey,
1520
+ sortKey,
1521
+ sortDirection,
1522
+ onSelect,
1523
+ compact = false,
1524
+ iconOnly = false,
1525
+ className
1526
+ }) {
1527
+ const [saved, setSaved] = (0, import_react5.useState)(() => readSortDefault(storage, storageKey));
1528
+ const options = SORT_OPTIONS.map(([key, direction]) => {
1529
+ const selected = sortKey === key && sortDirection === direction;
1530
+ const isDefault = saved?.key === key && saved.direction === direction;
1531
+ return {
1532
+ key: `${key}-${direction}`,
1533
+ label: t(key === "planned" ? `sort.planned.${direction}` : `sort.created.${direction}`),
1534
+ selected,
1535
+ keepOpen: true,
1536
+ onSelect: () => onSelect(key, direction),
1537
+ ...selected && storage !== void 0 ? {
1538
+ trailing: {
1539
+ label: t("sort.default.saved"),
1540
+ active: isDefault,
1541
+ onSelect: () => {
1542
+ writeSortDefault(storage, storageKey, key, direction);
1543
+ setSaved({ key, direction });
1544
+ }
1545
+ }
1546
+ } : {}
1547
+ };
1548
+ });
1549
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1550
+ DropdownMenu,
1551
+ {
1552
+ ariaLabel: t("sort.by"),
1553
+ ...compact || className !== void 0 ? { className: [compact ? "dsh-st-dropdown-compact" : "", className ?? ""].filter(Boolean).join(" ") } : {},
1554
+ ...iconOnly ? { buttonClassName: "dsh-st-n-head-btn", trigger: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SlidersIcon, { width: 16, height: 16 }) } : {},
1555
+ menuClassName: compact ? "dsh-st-dropdown-sort dsh-st-dropdown-compact" : "dsh-st-dropdown-sort",
1556
+ options
1557
+ }
1558
+ );
1559
+ }
1560
+
1561
+ // src/client/task-settings-request.ts
1562
+ var AUTOMATION_TASK_SETTINGS_EVENT = "dsh-automation:open-task-settings";
1563
+ var AUTOMATION_TASK_SETTINGS_STORAGE_KEY = "dsh-automation:pending-task-settings";
1564
+ function parseAutomationTaskSettingsRequest(value) {
1565
+ if (typeof value !== "object" || value === null) return void 0;
1566
+ const record = value;
1567
+ if (typeof record.name !== "string" || record.name.trim() === "" || !Array.isArray(record.sessionIds) || record.sessionIds.some((id) => typeof id !== "string")) return void 0;
1568
+ if (record.automationId !== void 0 && (typeof record.automationId !== "string" || record.automationId.trim() === "")) return void 0;
1569
+ return {
1570
+ ...typeof record.automationId === "string" ? { automationId: record.automationId } : {},
1571
+ name: record.name,
1572
+ sessionIds: [...record.sessionIds]
1573
+ };
1574
+ }
1575
+ function writeAutomationTaskSettingsRequest(storage, request) {
1576
+ try {
1577
+ storage?.setItem(AUTOMATION_TASK_SETTINGS_STORAGE_KEY, JSON.stringify(request));
1578
+ } catch {
1579
+ }
1580
+ }
1581
+ function requestAutomationTaskSettings(request) {
1582
+ if (typeof window === "undefined") return;
1583
+ writeAutomationTaskSettingsRequest(window.sessionStorage, request);
1584
+ window.dispatchEvent(new CustomEvent(AUTOMATION_TASK_SETTINGS_EVENT, { detail: request }));
1585
+ }
1586
+ function readAutomationTaskSettingsRequest(storage) {
1587
+ if (storage === void 0) return void 0;
1588
+ try {
1589
+ const raw = storage.getItem(AUTOMATION_TASK_SETTINGS_STORAGE_KEY);
1590
+ return raw === null ? void 0 : parseAutomationTaskSettingsRequest(JSON.parse(raw));
1591
+ } catch {
1592
+ return void 0;
1593
+ }
1594
+ }
1595
+ function clearAutomationTaskSettingsRequest(storage) {
1596
+ try {
1597
+ storage?.removeItem(AUTOMATION_TASK_SETTINGS_STORAGE_KEY);
1598
+ } catch {
1599
+ }
1600
+ }
1601
+ function resolveAutomationTaskSettings(request, automations, runs) {
1602
+ if (request.automationId !== void 0) {
1603
+ const exact = automations.find((item) => item.id === request.automationId);
1604
+ if (exact !== void 0) return exact;
1605
+ }
1606
+ const sessionIds = new Set(request.sessionIds);
1607
+ const automationId = runs.find((run) => run.sessionId !== void 0 && sessionIds.has(run.sessionId))?.automationId;
1608
+ const mapped = automations.find((item) => item.id === automationId);
1609
+ if (mapped !== void 0) return mapped;
1610
+ const named = automations.filter((item) => item.name === request.name);
1611
+ return named.length === 1 ? named[0] : void 0;
1612
+ }
1613
+
1352
1614
  // src/client/AutomationView.tsx
1353
- var import_jsx_runtime5 = require("react/jsx-runtime");
1615
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1616
+ var SORT_STORAGE = typeof window === "undefined" ? void 0 : window.localStorage;
1617
+ var TASK_SETTINGS_STORAGE = typeof window === "undefined" ? void 0 : window.sessionStorage;
1354
1618
  var EXAMPLES = [
1355
1619
  { name: "\u6BCF\u65E5\u56DE\u5F52\u68C0\u67E5", scheduleKind: "daily", time: "09:00", weekdays: [1, 2, 3, 4, 5] },
1356
1620
  { name: "\u6BCF\u5468\u4F9D\u8D56\u5DE1\u68C0", scheduleKind: "weekly", time: "10:00", weekdays: [1] },
1357
1621
  { name: "\u5DE5\u4F5C\u65E5\u65E9\u62A5", scheduleKind: "weekly", time: "08:00", weekdays: [1, 2, 3, 4, 5] }
1358
1622
  ];
1359
1623
  function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1360
- const state = (0, import_react4.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
1361
- const [tab, setTab] = (0, import_react4.useState)("mine");
1362
- const [query, setQuery] = (0, import_react4.useState)("");
1363
- const [creating, setCreating] = (0, import_react4.useState)(false);
1364
- const [editingId, setEditingId] = (0, import_react4.useState)();
1365
- const [deleteTarget, setDeleteTarget] = (0, import_react4.useState)();
1366
- const [draft, setDraft] = (0, import_react4.useState)();
1367
- const [busy, setBusy] = (0, import_react4.useState)(false);
1368
- const [error, setError] = (0, import_react4.useState)();
1369
- const [historyRange, setHistoryRange] = (0, import_react4.useState)("day");
1370
- const [historyTask, setHistoryTask] = (0, import_react4.useState)("all");
1371
- const [historyStatus, setHistoryStatus] = (0, import_react4.useState)("all");
1372
- const [sortKey, setSortKey] = (0, import_react4.useState)("created");
1373
- const [sortDirection, setSortDirection] = (0, import_react4.useState)("desc");
1374
- const now = (0, import_react4.useMemo)(() => new Date(state.snapshot?.serverNow ?? Date.now()), [state.snapshot?.serverNow, state.refreshedAt]);
1624
+ const state = (0, import_react6.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
1625
+ const [tab, setTab] = (0, import_react6.useState)("mine");
1626
+ const [query, setQuery] = (0, import_react6.useState)("");
1627
+ const [creating, setCreating] = (0, import_react6.useState)(false);
1628
+ const [editingId, setEditingId] = (0, import_react6.useState)();
1629
+ const [deleteTarget, setDeleteTarget] = (0, import_react6.useState)();
1630
+ const [draft, setDraft] = (0, import_react6.useState)();
1631
+ const [busy, setBusy] = (0, import_react6.useState)(false);
1632
+ const [error, setError] = (0, import_react6.useState)();
1633
+ const [historyRange, setHistoryRange] = (0, import_react6.useState)("day");
1634
+ const [historyTask, setHistoryTask] = (0, import_react6.useState)("all");
1635
+ const [historyStatus, setHistoryStatus] = (0, import_react6.useState)("all");
1636
+ const [sortKey, setSortKey] = (0, import_react6.useState)(() => readSortDefault(SORT_STORAGE, SETTINGS_SORT_DEFAULT_KEY)?.key ?? "created");
1637
+ const [sortDirection, setSortDirection] = (0, import_react6.useState)(() => readSortDefault(SORT_STORAGE, SETTINGS_SORT_DEFAULT_KEY)?.direction ?? "desc");
1638
+ const [taskSettingsRequest, setTaskSettingsRequest] = (0, import_react6.useState)(() => readAutomationTaskSettingsRequest(TASK_SETTINGS_STORAGE));
1639
+ const now = (0, import_react6.useMemo)(() => new Date(state.snapshot?.serverNow ?? Date.now()), [state.snapshot?.serverNow, state.refreshedAt]);
1375
1640
  const snapshot = state.snapshot;
1376
1641
  const workspaces = snapshot?.workspaces ?? [];
1377
1642
  const models = snapshot?.models ?? [];
@@ -1415,37 +1680,61 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1415
1680
  setDraft(formFromAutomation(item, workspaces, snapshot?.defaultModel ?? null, snapshot?.defaultPermission ?? item.permission));
1416
1681
  setCreating(true);
1417
1682
  };
1418
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-shell", children: [
1419
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("header", { className: "dsh-st-top", children: [
1420
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-heading", children: [
1421
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h1", { children: t("tab") }),
1422
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: t("header.lead") })
1683
+ (0, import_react6.useEffect)(() => {
1684
+ if (typeof window === "undefined") return;
1685
+ const onTaskSettings = (event) => {
1686
+ const request = parseAutomationTaskSettingsRequest(event.detail);
1687
+ if (request !== void 0) setTaskSettingsRequest(request);
1688
+ };
1689
+ window.addEventListener(AUTOMATION_TASK_SETTINGS_EVENT, onTaskSettings);
1690
+ return () => {
1691
+ window.removeEventListener(AUTOMATION_TASK_SETTINGS_EVENT, onTaskSettings);
1692
+ };
1693
+ }, []);
1694
+ (0, import_react6.useEffect)(() => {
1695
+ if (taskSettingsRequest === void 0 || snapshot === void 0) return;
1696
+ const item = resolveAutomationTaskSettings(taskSettingsRequest, snapshot.automations, snapshot.runs);
1697
+ clearAutomationTaskSettingsRequest(TASK_SETTINGS_STORAGE);
1698
+ setTaskSettingsRequest(void 0);
1699
+ setTab("mine");
1700
+ setQuery("");
1701
+ if (item === void 0) {
1702
+ setError(t("error.taskMissing"));
1703
+ return;
1704
+ }
1705
+ openEdit(item);
1706
+ }, [snapshot, taskSettingsRequest, t]);
1707
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-shell", children: [
1708
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("header", { className: "dsh-st-top", children: [
1709
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-heading", children: [
1710
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { children: t("tab") }),
1711
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: t("header.lead") })
1423
1712
  ] }),
1424
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-toolbar", children: [
1425
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { className: "dsh-st-search", value: query, placeholder: t("search.placeholder"), onChange: (event) => setQuery(event.target.value) }),
1426
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", className: "dsh-st-btn", onClick: () => {
1713
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-toolbar", children: [
1714
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { className: "dsh-st-search", value: query, placeholder: t("search.placeholder"), onChange: (event) => setQuery(event.target.value) }),
1715
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", className: "dsh-st-btn", onClick: () => {
1427
1716
  setChatPrefill(t("chat.prompt"));
1428
1717
  closeSettings?.();
1429
1718
  }, children: [
1430
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChatIcon, {}),
1719
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChatIcon, {}),
1431
1720
  t("action.chatCreate")
1432
1721
  ] }),
1433
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", className: "dsh-st-btn dsh-st-btn--primary", disabled: defaultPermission === "" || permissions.length === 0, onClick: () => openCreate(), children: [
1434
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PlusIcon, {}),
1722
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", className: "dsh-st-btn dsh-st-btn--primary", disabled: defaultPermission === "" || permissions.length === 0, onClick: () => openCreate(), children: [
1723
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PlusIcon, {}),
1435
1724
  t("action.create")
1436
1725
  ] }),
1437
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "dsh-st-icon", onClick: () => {
1726
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "dsh-st-icon", onClick: () => {
1438
1727
  void runtime.refresh();
1439
- }, "aria-label": t("section.refresh"), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RefreshIcon, {}) })
1728
+ }, "aria-label": t("section.refresh"), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RefreshIcon, {}) })
1440
1729
  ] })
1441
1730
  ] }),
1442
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-banner", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
1443
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(InfoIcon, {}),
1731
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-banner", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
1732
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(InfoIcon, {}),
1444
1733
  t("banner.wake")
1445
1734
  ] }) }),
1446
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "dsh-st-examples", children: [
1447
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-examples-head", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h2", { children: t("examples.title") }) }),
1448
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-example-row", children: EXAMPLES.map((example, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1735
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "dsh-st-examples", children: [
1736
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-examples-head", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { children: t("examples.title") }) }),
1737
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-example-row", children: EXAMPLES.map((example, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1449
1738
  "button",
1450
1739
  {
1451
1740
  type: "button",
@@ -1459,10 +1748,10 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1459
1748
  weekdays: example.weekdays
1460
1749
  }),
1461
1750
  children: [
1462
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: t(`examples.${index + 1}.title`) }),
1463
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: t(`examples.${index + 1}.body`) }),
1464
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "dsh-st-chip", children: [
1465
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ClockIcon, {}),
1751
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: t(`examples.${index + 1}.title`) }),
1752
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: t(`examples.${index + 1}.body`) }),
1753
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "dsh-st-chip", children: [
1754
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ClockIcon, {}),
1466
1755
  t(`examples.${index + 1}.chip`)
1467
1756
  ] })
1468
1757
  ]
@@ -1470,22 +1759,24 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1470
1759
  example.name
1471
1760
  )) })
1472
1761
  ] }),
1473
- error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dsh-st-error", children: error }),
1474
- (state.phase === "idle" || state.phase === "loading" && snapshot === void 0) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dsh-st-muted", children: t("loading") }),
1475
- state.phase === "error" && snapshot === void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-empty", children: [
1476
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { children: t("error.title") }),
1477
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: state.error }),
1478
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "dsh-st-btn dsh-st-btn--primary", onClick: () => {
1762
+ error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "dsh-st-error", children: error }),
1763
+ (state.phase === "idle" || state.phase === "loading" && snapshot === void 0) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "dsh-st-muted", children: t("loading") }),
1764
+ state.phase === "error" && snapshot === void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-empty", children: [
1765
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { children: t("error.title") }),
1766
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: state.error }),
1767
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "dsh-st-btn dsh-st-btn--primary", onClick: () => {
1479
1768
  void runtime.refresh();
1480
1769
  }, children: t("error.retry") })
1481
1770
  ] }),
1482
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-tabs", children: [
1483
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: tab === "mine" ? "is-on" : "", onClick: () => setTab("mine"), children: t("tabs.mine") }),
1484
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: tab === "runs" ? "is-on" : "", onClick: () => setTab("runs"), children: t("tabs.runs") }),
1485
- tab === "mine" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1771
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-tabs", children: [
1772
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: tab === "mine" ? "is-on" : "", onClick: () => setTab("mine"), children: t("tabs.mine") }),
1773
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: tab === "runs" ? "is-on" : "", onClick: () => setTab("runs"), children: t("tabs.runs") }),
1774
+ tab === "mine" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-sort-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1486
1775
  SortMenu,
1487
1776
  {
1488
1777
  t,
1778
+ ...SORT_STORAGE === void 0 ? {} : { storage: SORT_STORAGE },
1779
+ storageKey: SETTINGS_SORT_DEFAULT_KEY,
1489
1780
  sortKey,
1490
1781
  sortDirection,
1491
1782
  onSelect: (key, direction) => {
@@ -1493,10 +1784,10 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1493
1784
  setSortDirection(direction);
1494
1785
  }
1495
1786
  }
1496
- ),
1497
- tab === "runs" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-filters", children: [
1498
- ["day", "week", "month"].map((range) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: historyRange === range ? "is-on" : "", onClick: () => setHistoryRange(range), children: t(`history.range.${range}`) }, range)),
1499
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1787
+ ) }),
1788
+ tab === "runs" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-filters", children: [
1789
+ ["day", "week", "month"].map((range) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: historyRange === range ? "is-on" : "", onClick: () => setHistoryRange(range), children: t(`history.range.${range}`) }, range)),
1790
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1500
1791
  DropdownMenu,
1501
1792
  {
1502
1793
  ariaLabel: t("history.allTasks"),
@@ -1511,7 +1802,7 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1511
1802
  ]
1512
1803
  }
1513
1804
  ),
1514
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1805
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1515
1806
  DropdownMenu,
1516
1807
  {
1517
1808
  ariaLabel: t("history.allStatus"),
@@ -1528,10 +1819,10 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1528
1819
  )
1529
1820
  ] })
1530
1821
  ] }),
1531
- tab === "mine" && (automations.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-empty", children: [
1532
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { children: t("empty.title") }),
1533
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: t("empty.body") })
1534
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-grid", children: automations.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1822
+ tab === "mine" && (automations.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-empty", children: [
1823
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { children: t("empty.title") }),
1824
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: t("empty.body") })
1825
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-grid", children: automations.map((item) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1535
1826
  TaskCard,
1536
1827
  {
1537
1828
  item,
@@ -1549,11 +1840,11 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1549
1840
  },
1550
1841
  item.id
1551
1842
  )) })),
1552
- tab === "runs" && (groups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-empty", children: t("runs.empty") }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-timeline", children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "dsh-st-group", children: [
1553
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { children: group.label }),
1554
- group.items.map((run) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RunRow, { run, t }, run.id))
1843
+ tab === "runs" && (groups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-empty", children: t("runs.empty") }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-timeline", children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "dsh-st-group", children: [
1844
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { children: group.label }),
1845
+ group.items.map((run) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RunRow, { run, t }, run.id))
1555
1846
  ] }, group.key)) })),
1556
- creating && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1847
+ creating && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1557
1848
  CreateModal,
1558
1849
  {
1559
1850
  t,
@@ -1583,7 +1874,7 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1583
1874
  },
1584
1875
  editingId ?? "create"
1585
1876
  ),
1586
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1877
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1587
1878
  DeleteConfirmation,
1588
1879
  {
1589
1880
  target: deleteTarget,
@@ -1612,9 +1903,9 @@ function TaskCard({
1612
1903
  onRun,
1613
1904
  onDelete
1614
1905
  }) {
1615
- const [menu, setMenu] = (0, import_react4.useState)(false);
1616
- const root = (0, import_react4.useRef)(null);
1617
- (0, import_react4.useEffect)(() => {
1906
+ const [menu, setMenu] = (0, import_react6.useState)(false);
1907
+ const root = (0, import_react6.useRef)(null);
1908
+ (0, import_react6.useEffect)(() => {
1618
1909
  if (!menu) return;
1619
1910
  const close = (event) => {
1620
1911
  if (root.current !== null && !root.current.contains(event.target)) setMenu(false);
@@ -1624,131 +1915,59 @@ function TaskCard({
1624
1915
  document.removeEventListener("mousedown", close);
1625
1916
  };
1626
1917
  }, [menu]);
1627
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("article", { className: "dsh-st-card", ref: root, onClick: onEdit, children: [
1628
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-card-head", children: [
1629
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: `dsh-st-switch ${item.status === "active" ? "is-on" : ""}`, role: "switch", "aria-checked": item.status === "active", disabled: busy, onClick: (event) => {
1918
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("article", { className: "dsh-st-card", ref: root, onClick: onEdit, children: [
1919
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-card-head", children: [
1920
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: `dsh-st-switch ${item.status === "active" ? "is-on" : ""}`, role: "switch", "aria-checked": item.status === "active", disabled: busy, onClick: (event) => {
1630
1921
  event.stopPropagation();
1631
1922
  onToggle();
1632
1923
  } }),
1633
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "dsh-st-more", onClick: (event) => {
1924
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "dsh-st-more", onClick: (event) => {
1634
1925
  event.stopPropagation();
1635
1926
  setMenu((value) => !value);
1636
- }, "aria-label": t("card.more"), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MoreIcon, {}) }),
1637
- menu && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-menu", onClick: (event) => event.stopPropagation(), children: [
1638
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", disabled: busy, onClick: () => {
1927
+ }, "aria-label": t("card.more"), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MoreIcon, {}) }),
1928
+ menu && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-menu", onClick: (event) => event.stopPropagation(), children: [
1929
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", disabled: busy, onClick: () => {
1639
1930
  setMenu(false);
1640
1931
  onRun();
1641
1932
  }, children: [
1642
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PlayIcon, { width: 16, height: 16 }),
1933
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PlayIcon, { width: 16, height: 16 }),
1643
1934
  t("menu.run")
1644
1935
  ] }),
1645
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", disabled: busy, onClick: () => {
1936
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", disabled: busy, onClick: () => {
1646
1937
  setMenu(false);
1647
1938
  onEdit();
1648
1939
  }, children: [
1649
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PencilIcon, { width: 16, height: 16 }),
1940
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PencilIcon, { width: 16, height: 16 }),
1650
1941
  t("menu.edit")
1651
1942
  ] }),
1652
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", className: "is-danger", disabled: busy, onClick: () => {
1943
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", className: "is-danger", disabled: busy, onClick: () => {
1653
1944
  setMenu(false);
1654
1945
  onDelete();
1655
1946
  }, children: [
1656
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TrashIcon, { width: 16, height: 16 }),
1947
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TrashIcon, { width: 16, height: 16 }),
1657
1948
  t("menu.delete")
1658
1949
  ] })
1659
1950
  ] })
1660
1951
  ] }),
1661
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { children: item.name }),
1662
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: item.prompt }),
1663
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-card-foot", children: [
1664
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "dsh-st-chip", children: [
1665
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ClockIcon, {}),
1952
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { children: item.name }),
1953
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: item.prompt }),
1954
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-card-foot", children: [
1955
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "dsh-st-chip", children: [
1956
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ClockIcon, {}),
1666
1957
  formatSchedule(item.schedule, t)
1667
1958
  ] }),
1668
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: item.nextRunAt === void 0 ? t("stats.noneScheduled") : t("history.nextApprox", { when: formatWithin(item.nextRunAt, now, t) }) })
1959
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: item.nextRunAt === void 0 ? t("stats.noneScheduled") : t("history.nextApprox", { when: formatWithin(item.nextRunAt, now, t) }) })
1669
1960
  ] })
1670
1961
  ] });
1671
1962
  }
1672
- function SortMenu({
1673
- t,
1674
- sortKey,
1675
- sortDirection,
1676
- onSelect
1677
- }) {
1678
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1679
- DropdownMenu,
1680
- {
1681
- className: "dsh-st-sort",
1682
- ariaLabel: t("sort.by"),
1683
- options: [
1684
- { key: "created-desc", label: t("sort.created.desc"), selected: sortKey === "created" && sortDirection === "desc", onSelect: () => onSelect("created", "desc") },
1685
- { key: "created-asc", label: t("sort.created.asc"), selected: sortKey === "created" && sortDirection === "asc", onSelect: () => onSelect("created", "asc") },
1686
- { key: "planned-asc", label: t("sort.planned.asc"), selected: sortKey === "planned" && sortDirection === "asc", onSelect: () => onSelect("planned", "asc") },
1687
- { key: "planned-desc", label: t("sort.planned.desc"), selected: sortKey === "planned" && sortDirection === "desc", onSelect: () => onSelect("planned", "desc") }
1688
- ]
1689
- }
1690
- );
1691
- }
1692
- function DropdownMenu({
1693
- ariaLabel,
1694
- className,
1695
- options
1696
- }) {
1697
- const [open, setOpen] = (0, import_react4.useState)(false);
1698
- const root = (0, import_react4.useRef)(null);
1699
- (0, import_react4.useEffect)(() => {
1700
- if (!open) return;
1701
- const close = (event) => {
1702
- if (root.current !== null && !root.current.contains(event.target)) setOpen(false);
1703
- };
1704
- const closeOnEscape = (event) => {
1705
- if (event.key === "Escape") setOpen(false);
1706
- };
1707
- document.addEventListener("mousedown", close);
1708
- document.addEventListener("keydown", closeOnEscape);
1709
- return () => {
1710
- document.removeEventListener("mousedown", close);
1711
- document.removeEventListener("keydown", closeOnEscape);
1712
- };
1713
- }, [open]);
1714
- const selectedLabel = options.find((option) => option.selected)?.label ?? options[0]?.label ?? ariaLabel;
1715
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `dsh-st-dropdown${className === void 0 ? "" : ` ${className}`}`, ref: root, children: [
1716
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", className: `dsh-st-dropdown-btn${open ? " is-open" : ""}`, "aria-label": ariaLabel, "aria-expanded": open, onClick: () => setOpen((value) => !value), children: [
1717
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-dropdown-label", children: selectedLabel }),
1718
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronIcon, { width: 10, height: 10, className: "dsh-st-dropdown-chevron" })
1719
- ] }),
1720
- open && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-dropdown-menu", children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1721
- DropdownRow,
1722
- {
1723
- label: option.label,
1724
- selected: option.selected,
1725
- onSelect: () => {
1726
- setOpen(false);
1727
- option.onSelect();
1728
- }
1729
- },
1730
- option.key
1731
- )) })
1732
- ] });
1733
- }
1734
- function DropdownRow({
1735
- label,
1736
- selected,
1737
- onSelect
1738
- }) {
1739
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", "aria-pressed": selected, className: selected ? "is-selected" : void 0, onClick: onSelect, children: [
1740
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: label }),
1741
- selected ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CheckOutlineIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-sort-tick" })
1742
- ] });
1743
- }
1744
1963
  function RunRow({ run, t }) {
1745
1964
  const duration = formatDuration(run.startedAt, run.finishedAt);
1746
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("article", { className: `dsh-st-run is-${run.status}`, children: [
1747
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: run.automationName }),
1748
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { children: [
1749
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: clockTime(run.startedAt ?? run.scheduledFor) }),
1750
- duration !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: duration }),
1751
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: t("history.trigger") })
1965
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("article", { className: `dsh-st-run is-${run.status}`, children: [
1966
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: run.automationName }),
1967
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { children: [
1968
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: clockTime(run.startedAt ?? run.scheduledFor) }),
1969
+ duration !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: duration }),
1970
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: t("history.trigger") })
1752
1971
  ] })
1753
1972
  ] });
1754
1973
  }
@@ -1761,6 +1980,8 @@ var en = {
1761
1980
  "sidebar.tabs": "Workspace views",
1762
1981
  "sidebar.tasksTab": "Tasks",
1763
1982
  "sidebar.channelsTab": "Channels",
1983
+ "sidebar.views": "Scheduled views",
1984
+ "sidebar.viewOverview": "Task overview",
1764
1985
  "sidebar.empty": "No scheduled runs yet.",
1765
1986
  "sidebar.tasksEmpty": "No web tasks yet.",
1766
1987
  "sidebar.ungrouped": "Ungrouped",
@@ -1795,6 +2016,16 @@ var en = {
1795
2016
  "session.rename": "Rename",
1796
2017
  "session.fork": "Fork session",
1797
2018
  "session.archive": "Archive session",
2019
+ "session.moreActions": "More actions for {title}",
2020
+ "session.groupActions": "Actions for {name}",
2021
+ "session.taskSettings": "Task settings",
2022
+ "session.archiveGroup": "Archive all conversations",
2023
+ "session.archiveGroupConfirm": "Archive all",
2024
+ "session.archiveGroupDescription": "Archive all {count} conversations for \u201C{name}\u201D. You can restore them later in Settings \u2192 Archived.",
2025
+ "session.archiveGroupPending": "Archiving conversations\u2026",
2026
+ "session.archiveGroupFailed": "Some conversations could not be archived: {message}",
2027
+ "session.archiveGroupClose": "Close",
2028
+ "session.archiveGroupCancel": "Cancel",
1798
2029
  "session.idle": "Idle",
1799
2030
  "session.runningStatus": "Running",
1800
2031
  "session.delete": "Remove from Scheduled",
@@ -1828,6 +2059,7 @@ var en = {
1828
2059
  "sort.created.desc": "Created time descending",
1829
2060
  "sort.planned.asc": "Planned time ascending",
1830
2061
  "sort.planned.desc": "Planned time descending",
2062
+ "sort.default.saved": "Default",
1831
2063
  "form.workspace": "Workspace",
1832
2064
  "form.workspacePath": "Folder path",
1833
2065
  "form.workspacePathPlaceholder": "D:\\work\\project",
@@ -1864,6 +2096,7 @@ var en = {
1864
2096
  "empty.body": "Save a self-contained task, a schedule, and a permission boundary. Every run starts in a new Session.",
1865
2097
  "empty.action": "Create the first automation",
1866
2098
  "runs.empty": "No runs yet. Run one now, or wait for the next scheduled occurrence.",
2099
+ "overview.empty": "No scheduled tasks yet. Create one in Settings.",
1867
2100
  "form.title": "Create automation",
1868
2101
  "form.subtitle": "Write a complete, standalone task. Scheduled runs do not inherit this conversation.",
1869
2102
  "form.name": "Name",
@@ -1946,6 +2179,7 @@ var en = {
1946
2179
  "error.title": "Automations could not be loaded",
1947
2180
  "error.retry": "Try again",
1948
2181
  "error.action": "The action failed. Please try again.",
2182
+ "error.taskMissing": "This scheduled task no longer exists.",
1949
2183
  "error.offline": "Could not reach the local automation service. Check that DSH is still running and try again.",
1950
2184
  "time.now": "now",
1951
2185
  "time.minuteAgo": "{count}m ago",
@@ -1961,6 +2195,8 @@ var zh = {
1961
2195
  "sidebar.tabs": "\u5DE5\u4F5C\u533A\u5206\u7C7B",
1962
2196
  "sidebar.tasksTab": "\u4EFB\u52A1",
1963
2197
  "sidebar.channelsTab": "\u9891\u9053",
2198
+ "sidebar.views": "\u5B9A\u65F6\u9875\u89C6\u56FE",
2199
+ "sidebar.viewOverview": "\u4EFB\u52A1\u603B\u89C8",
1964
2200
  "sidebar.empty": "\u8FD8\u6CA1\u6709\u5B9A\u65F6\u4EFB\u52A1\u6267\u884C\u8BB0\u5F55\u3002",
1965
2201
  "sidebar.tasksEmpty": "\u6682\u65E0\u7F51\u9875\u4EFB\u52A1",
1966
2202
  "sidebar.ungrouped": "\u672A\u5206\u7EC4",
@@ -1995,6 +2231,16 @@ var zh = {
1995
2231
  "session.rename": "\u91CD\u547D\u540D",
1996
2232
  "session.fork": "\u5206\u53C9\u4F1A\u8BDD",
1997
2233
  "session.archive": "\u5F52\u6863\u4F1A\u8BDD",
2234
+ "session.moreActions": "\u201C{title}\u201D\u7684\u66F4\u591A\u64CD\u4F5C",
2235
+ "session.groupActions": "\u201C{name}\u201D\u7684\u4EFB\u52A1\u64CD\u4F5C",
2236
+ "session.taskSettings": "\u4EFB\u52A1\u8BBE\u7F6E",
2237
+ "session.archiveGroup": "\u5F52\u6863\u6574\u7EC4\u4F1A\u8BDD",
2238
+ "session.archiveGroupConfirm": "\u786E\u8BA4\u5F52\u6863",
2239
+ "session.archiveGroupDescription": "\u5C06\u5F52\u6863\u201C{name}\u201D\u4E0B\u7684 {count} \u4E2A\u4F1A\u8BDD\u3002\u5F52\u6863\u540E\u53EF\u4EE5\u5728\u201C\u8BBE\u7F6E \u2192 \u5DF2\u5F52\u6863\u201D\u4E2D\u6062\u590D\u3002",
2240
+ "session.archiveGroupPending": "\u6B63\u5728\u5F52\u6863\u6574\u7EC4\u4F1A\u8BDD\u2026",
2241
+ "session.archiveGroupFailed": "\u90E8\u5206\u4F1A\u8BDD\u5F52\u6863\u5931\u8D25\uFF1A{message}",
2242
+ "session.archiveGroupClose": "\u5173\u95ED",
2243
+ "session.archiveGroupCancel": "\u53D6\u6D88",
1998
2244
  "session.idle": "\u7A7A\u95F2",
1999
2245
  "session.runningStatus": "\u8FD0\u884C\u4E2D",
2000
2246
  "session.delete": "\u4ECE\u5B9A\u65F6\u9875\u79FB\u9664",
@@ -2028,6 +2274,7 @@ var zh = {
2028
2274
  "sort.created.desc": "\u6309\u521B\u5EFA\u65F6\u95F4\u5012\u5E8F",
2029
2275
  "sort.planned.asc": "\u6309\u8BA1\u5212\u65F6\u95F4\u5347\u5E8F",
2030
2276
  "sort.planned.desc": "\u6309\u8BA1\u5212\u65F6\u95F4\u5012\u5E8F",
2277
+ "sort.default.saved": "\u9ED8\u8BA4",
2031
2278
  "form.workspace": "\u5DE5\u4F5C\u76EE\u5F55",
2032
2279
  "form.workspacePath": "\u76EE\u5F55\u8DEF\u5F84",
2033
2280
  "form.workspacePathPlaceholder": "D:\\work\\project",
@@ -2064,6 +2311,7 @@ var zh = {
2064
2311
  "empty.body": "\u8BBE\u7F6E\u4E00\u4E2A\u76EE\u6807\u660E\u786E\u7684\u4EFB\u52A1\u3001\u8FD0\u884C\u65F6\u95F4\u548C\u6743\u9650\u8FB9\u754C\u3002\u6BCF\u6B21\u8FD0\u884C\u90FD\u4ECE\u5168\u65B0 Session \u5F00\u59CB\u3002",
2065
2312
  "empty.action": "\u521B\u5EFA\u7B2C\u4E00\u4E2A\u81EA\u52A8\u5316",
2066
2313
  "runs.empty": "\u8FD8\u6CA1\u6709\u8FD0\u884C\u8BB0\u5F55\u3002\u4F60\u53EF\u4EE5\u7ACB\u5373\u8FD0\u884C\u4E00\u6B21\uFF0C\u6216\u7B49\u5F85\u8BA1\u5212\u89E6\u53D1\u3002",
2314
+ "overview.empty": "\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\uFF0C\u53EF\u5230\u8BBE\u7F6E\u9875\u521B\u5EFA\u3002",
2067
2315
  "form.title": "\u521B\u5EFA\u81EA\u52A8\u5316",
2068
2316
  "form.subtitle": "\u8BF7\u5199\u5B8C\u6574\u3001\u72EC\u7ACB\u7684\u4EFB\u52A1\u8BF4\u660E\uFF1A\u5B9A\u65F6\u8FD0\u884C\u4E0D\u4F1A\u7EE7\u627F\u5F53\u524D\u5BF9\u8BDD\u3002",
2069
2317
  "form.name": "\u540D\u79F0",
@@ -2146,6 +2394,7 @@ var zh = {
2146
2394
  "error.title": "\u65E0\u6CD5\u52A0\u8F7D\u81EA\u52A8\u5316",
2147
2395
  "error.retry": "\u91CD\u8BD5",
2148
2396
  "error.action": "\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
2397
+ "error.taskMissing": "\u8BE5\u5B9A\u65F6\u4EFB\u52A1\u5DF2\u4E0D\u5B58\u5728\u3002",
2149
2398
  "error.offline": "\u65E0\u6CD5\u8FDE\u63A5\u672C\u673A\u81EA\u52A8\u5316\u670D\u52A1\uFF0C\u8BF7\u786E\u8BA4 DSH \u4ECD\u5728\u8FD0\u884C\u540E\u91CD\u8BD5\u3002",
2150
2399
  "time.now": "\u521A\u521A",
2151
2400
  "time.minuteAgo": "{count} \u5206\u949F\u524D",
@@ -2233,8 +2482,9 @@ function isForeignSidebarHost(component) {
2233
2482
  }
2234
2483
 
2235
2484
  // src/client/native-session-list.tsx
2236
- var import_react6 = require("react");
2237
- var import_react_dom2 = require("react-dom");
2485
+ var import_react9 = require("react");
2486
+ var import_react_dom3 = require("react-dom");
2487
+ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
2238
2488
 
2239
2489
  // src/client/native-session-menu.ts
2240
2490
  function resolveEventElement(target) {
@@ -2308,6 +2558,18 @@ function relativeTime(value, t, now = Date.now()) {
2308
2558
  return t("time.dayAgo", { count: Math.floor(hour / 24) });
2309
2559
  }
2310
2560
 
2561
+ // src/client/native-group-actions.ts
2562
+ var ARCHIVE_MANAGER_PLUGIN = "@michengai/dsh-archive-manager";
2563
+ function hasArchiveManagerPlugin(root) {
2564
+ return root?.querySelector(`[data-plugin="${ARCHIVE_MANAGER_PLUGIN}"]`) != null;
2565
+ }
2566
+ function scheduledGroupShowsActiveFolder(expanded, sessionIds, selectedId) {
2567
+ return expanded && selectedId !== null && sessionIds.includes(selectedId);
2568
+ }
2569
+ async function archiveScheduledGroup(sessionIds, archiveSession) {
2570
+ for (const sessionId of sessionIds) await archiveSession(sessionId);
2571
+ }
2572
+
2311
2573
  // src/run-title.ts
2312
2574
  function formatRunStamp(iso) {
2313
2575
  const value = new Date(iso);
@@ -2354,6 +2616,26 @@ function groupScheduledSessions(automations, runs) {
2354
2616
  };
2355
2617
  }).filter((group) => group.sessions.length > 0);
2356
2618
  }
2619
+ function deriveTaskOverviewRows(automations, runs) {
2620
+ const lastByAutomation = /* @__PURE__ */ new Map();
2621
+ for (const run of runs) {
2622
+ if (run.sessionId === void 0 || run.sessionId === "") continue;
2623
+ const current = lastByAutomation.get(run.automationId);
2624
+ const stamp = Date.parse(run.startedAt ?? run.scheduledFor);
2625
+ const currentStamp = current === void 0 ? Number.NaN : Date.parse(current.startedAt ?? current.scheduledFor);
2626
+ if (current === void 0 || stamp >= currentStamp) lastByAutomation.set(run.automationId, run);
2627
+ }
2628
+ return automations.map((item) => {
2629
+ const last = lastByAutomation.get(item.id);
2630
+ return {
2631
+ id: item.id,
2632
+ name: item.name,
2633
+ status: item.status,
2634
+ ...item.nextRunAt === void 0 ? {} : { nextRunAt: item.nextRunAt },
2635
+ ...last === void 0 ? {} : { lastSessionId: last.sessionId }
2636
+ };
2637
+ });
2638
+ }
2357
2639
  function keepScheduledSessionLink(sessionId, archived, presentIds) {
2358
2640
  if (sessionId === void 0 || sessionId === "") return false;
2359
2641
  if (archived.has(sessionId)) return false;
@@ -2585,9 +2867,116 @@ function latestSessionTime(group) {
2585
2867
  return latest;
2586
2868
  }
2587
2869
 
2870
+ // src/client/schedule-overview.tsx
2871
+ var import_react7 = require("react");
2872
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2873
+ var EMPTY_SET = /* @__PURE__ */ new Set();
2874
+ var SORT_STORAGE2 = typeof window === "undefined" ? void 0 : window.localStorage;
2875
+ function ScheduleViewSwitch({
2876
+ t,
2877
+ view,
2878
+ onChange
2879
+ }) {
2880
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dsh-st-rail-views", role: "tablist", "aria-label": t("sidebar.views"), children: [
2881
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", role: "tab", "aria-selected": view === "runs", className: view === "runs" ? "is-on" : void 0, onClick: () => onChange("runs"), children: t("tabs.runs") }),
2882
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", role: "tab", "aria-selected": view === "overview", className: view === "overview" ? "is-on" : void 0, onClick: () => onChange("overview"), children: t("sidebar.viewOverview") })
2883
+ ] });
2884
+ }
2885
+ function ScheduleOverview({
2886
+ t,
2887
+ automations,
2888
+ runs,
2889
+ openSession,
2890
+ serverNow,
2891
+ archived,
2892
+ presentIds
2893
+ }) {
2894
+ const [sortKey, setSortKey] = (0, import_react7.useState)(() => readSortDefault(SORT_STORAGE2, OVERVIEW_SORT_DEFAULT_KEY)?.key ?? "planned");
2895
+ const [sortDirection, setSortDirection] = (0, import_react7.useState)(() => readSortDefault(SORT_STORAGE2, OVERVIEW_SORT_DEFAULT_KEY)?.direction ?? "asc");
2896
+ const now = (0, import_react7.useMemo)(() => new Date(serverNow ?? Date.now()), [serverNow]);
2897
+ const rows = (0, import_react7.useMemo)(() => {
2898
+ const sorted = sortAutomations(automations, sortKey, sortDirection);
2899
+ return deriveTaskOverviewRows(sorted, runs).map((row) => {
2900
+ if (row.lastSessionId === void 0 || !keepScheduledSessionLink(row.lastSessionId, archived ?? EMPTY_SET, presentIds)) {
2901
+ const { lastSessionId: _dropped, ...rest } = row;
2902
+ return rest;
2903
+ }
2904
+ return row;
2905
+ });
2906
+ }, [archived, automations, presentIds, runs, sortDirection, sortKey]);
2907
+ const scheduleSummaries = (0, import_react7.useMemo)(() => new Map(automations.map((item) => [item.id, formatSchedule(item.schedule, t)])), [automations, t]);
2908
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dsh-st-overview", children: [
2909
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dsh-st-overview-head", children: [
2910
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dsh-st-overview-title", children: [
2911
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { children: t("sidebar.viewOverview") }),
2912
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "aria-label": `${rows.length}`, children: rows.length })
2913
+ ] }),
2914
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2915
+ SortMenu,
2916
+ {
2917
+ t,
2918
+ compact: true,
2919
+ iconOnly: true,
2920
+ className: "dsh-st-overview-sort",
2921
+ ...SORT_STORAGE2 === void 0 ? {} : { storage: SORT_STORAGE2 },
2922
+ storageKey: OVERVIEW_SORT_DEFAULT_KEY,
2923
+ sortKey,
2924
+ sortDirection,
2925
+ onSelect: (key, direction) => {
2926
+ setSortKey(key);
2927
+ setSortDirection(direction);
2928
+ }
2929
+ }
2930
+ )
2931
+ ] }),
2932
+ rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "dsh-st-rail-empty", children: t("overview.empty") }) : rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(OverviewRow, { t, row, now, scheduleSummary: scheduleSummaries.get(row.id) ?? "", ...openSession === void 0 ? {} : { openSession } }, row.id))
2933
+ ] });
2934
+ }
2935
+ function OverviewRow({
2936
+ t,
2937
+ row,
2938
+ now,
2939
+ scheduleSummary,
2940
+ openSession
2941
+ }) {
2942
+ const paused = row.status !== "active";
2943
+ const nextRun = row.nextRunAt === void 0 ? t("stats.noneScheduled") : formatWithin(row.nextRunAt, now, t);
2944
+ const status = paused ? t("status.paused") : t("status.active");
2945
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2946
+ "button",
2947
+ {
2948
+ type: "button",
2949
+ className: `dsh-st-overview-row${paused ? " is-paused" : ""}`,
2950
+ disabled: row.lastSessionId === void 0,
2951
+ title: paused ? t("status.paused") : t("status.active"),
2952
+ onClick: () => {
2953
+ if (row.lastSessionId !== void 0) openSession?.(row.lastSessionId);
2954
+ },
2955
+ children: [
2956
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-copy", children: [
2957
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-status", children: [
2958
+ paused ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PauseIcon, { width: 14, height: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CheckIcon, { width: 14, height: 14 }),
2959
+ status
2960
+ ] }),
2961
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dsh-st-overview-name", children: row.name }),
2962
+ scheduleSummary !== "" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-schedule", children: [
2963
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CalendarIcon, { width: 14, height: 14 }),
2964
+ scheduleSummary
2965
+ ] })
2966
+ ] }),
2967
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-next", children: [
2968
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: t("stats.next") }),
2969
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { children: nextRun })
2970
+ ] }),
2971
+ row.lastSessionId !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ChevronIcon, { width: 12, height: 12, className: "dsh-st-overview-chevron" })
2972
+ ]
2973
+ }
2974
+ );
2975
+ }
2976
+
2588
2977
  // src/client/workspace-toolbar.tsx
2589
- var import_react5 = require("react");
2590
- var import_jsx_runtime6 = require("react/jsx-runtime");
2978
+ var import_react8 = require("react");
2979
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2591
2980
  function officialSearchIconSize(expanded) {
2592
2981
  return expanded ? 11 : 14;
2593
2982
  }
@@ -2600,15 +2989,15 @@ function WorkspaceToolbar({
2600
2989
  onSortChange,
2601
2990
  onGroupModeChange
2602
2991
  }) {
2603
- const [searching, setSearching] = (0, import_react5.useState)(query.trim() !== "");
2604
- const [filterOpen, setFilterOpen] = (0, import_react5.useState)(false);
2605
- const inputRef = (0, import_react5.useRef)(null);
2606
- const rootRef = (0, import_react5.useRef)(null);
2992
+ const [searching, setSearching] = (0, import_react8.useState)(query.trim() !== "");
2993
+ const [filterOpen, setFilterOpen] = (0, import_react8.useState)(false);
2994
+ const inputRef = (0, import_react8.useRef)(null);
2995
+ const rootRef = (0, import_react8.useRef)(null);
2607
2996
  const searchSize = officialSearchIconSize(searching);
2608
- (0, import_react5.useEffect)(() => {
2997
+ (0, import_react8.useEffect)(() => {
2609
2998
  if (searching) inputRef.current?.focus();
2610
2999
  }, [searching]);
2611
- (0, import_react5.useEffect)(() => {
3000
+ (0, import_react8.useEffect)(() => {
2612
3001
  if (!filterOpen) return;
2613
3002
  const close = (event) => {
2614
3003
  const target = event.target;
@@ -2626,37 +3015,37 @@ function WorkspaceToolbar({
2626
3015
  onQueryChange("");
2627
3016
  setSearching(false);
2628
3017
  };
2629
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: searching ? "dsh-st-n-toolbar is-search" : "dsh-st-n-toolbar", ref: rootRef, children: [
2630
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-st-n-head-label", children: t("sidebar.workspaces") }),
2631
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-n-search-slot", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-st-n-search", onClick: openSearch, children: [
2632
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "dsh-st-n-search-btn", "aria-label": t("sidebar.search"), "aria-expanded": searching, onClick: openSearch, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SearchOutlineIcon, { width: searchSize, height: searchSize }) }),
2633
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { ref: inputRef, className: "dsh-st-n-search-input", value: query, placeholder: t("sidebar.searchSessions"), "aria-label": t("sidebar.searchSessions"), tabIndex: searching ? 0 : -1, "aria-hidden": !searching, onChange: (event) => onQueryChange(event.target.value), onKeyDown: (event) => {
3018
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: searching ? "dsh-st-n-toolbar is-search" : "dsh-st-n-toolbar", ref: rootRef, children: [
3019
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dsh-st-n-head-label", children: t("sidebar.workspaces") }),
3020
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-st-n-search-slot", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dsh-st-n-search", onClick: openSearch, children: [
3021
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "dsh-st-n-search-btn", "aria-label": t("sidebar.search"), "aria-expanded": searching, onClick: openSearch, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SearchOutlineIcon, { width: searchSize, height: searchSize }) }),
3022
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { ref: inputRef, className: "dsh-st-n-search-input", value: query, placeholder: t("sidebar.searchSessions"), "aria-label": t("sidebar.searchSessions"), tabIndex: searching ? 0 : -1, "aria-hidden": !searching, onChange: (event) => onQueryChange(event.target.value), onKeyDown: (event) => {
2634
3023
  if (event.key === "Escape") closeSearch();
2635
3024
  } }),
2636
- searching && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "dsh-st-n-search-clear", "aria-label": t("sidebar.clearSearch"), onClick: (event) => {
3025
+ searching && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "dsh-st-n-search-clear", "aria-label": t("sidebar.clearSearch"), onClick: (event) => {
2637
3026
  event.stopPropagation();
2638
3027
  closeSearch();
2639
- }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CloseOutlineIcon, { width: 14, height: 14 }) })
3028
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CloseOutlineIcon, { width: 14, height: 14 }) })
2640
3029
  ] }) }),
2641
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-n-head-acts", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-st-n-head-filter", children: [
2642
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: filterOpen ? "dsh-st-n-head-btn is-on" : "dsh-st-n-head-btn", "aria-label": t("sidebar.filter"), "aria-expanded": filterOpen, onClick: () => setFilterOpen((open) => !open), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SlidersIcon, { width: 16, height: 16 }) }),
2643
- filterOpen && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-st-n-filter-menu", role: "menu", children: [
2644
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-n-filter-label", children: t("sidebar.groupBy") }),
2645
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FilterRow, { label: t("sidebar.groupWorkspace"), selected: groupMode === "workspace", onSelect: () => {
3030
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-st-n-head-acts", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dsh-st-n-head-filter", children: [
3031
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: filterOpen ? "dsh-st-n-head-btn is-on" : "dsh-st-n-head-btn", "aria-label": t("sidebar.filter"), "aria-expanded": filterOpen, onClick: () => setFilterOpen((open) => !open), children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SlidersIcon, { width: 16, height: 16 }) }),
3032
+ filterOpen && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dsh-st-n-filter-menu", role: "menu", children: [
3033
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-st-n-filter-label", children: t("sidebar.groupBy") }),
3034
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FilterRow, { label: t("sidebar.groupWorkspace"), selected: groupMode === "workspace", onSelect: () => {
2646
3035
  onGroupModeChange("workspace");
2647
3036
  setFilterOpen(false);
2648
3037
  } }),
2649
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FilterRow, { label: t("sidebar.groupList"), selected: groupMode === "list", onSelect: () => {
3038
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FilterRow, { label: t("sidebar.groupList"), selected: groupMode === "list", onSelect: () => {
2650
3039
  onGroupModeChange("list");
2651
3040
  setFilterOpen(false);
2652
3041
  } }),
2653
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-n-filter-split" }),
2654
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-n-filter-label", children: t("sidebar.sortBy") }),
2655
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FilterRow, { label: t("sidebar.sortManual"), selected: sort === "manual", onSelect: () => {
3042
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-st-n-filter-split" }),
3043
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-st-n-filter-label", children: t("sidebar.sortBy") }),
3044
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FilterRow, { label: t("sidebar.sortManual"), selected: sort === "manual", onSelect: () => {
2656
3045
  onSortChange("manual");
2657
3046
  setFilterOpen(false);
2658
3047
  } }),
2659
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FilterRow, { label: t("sidebar.sortTime"), selected: sort === "time", onSelect: () => {
3048
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FilterRow, { label: t("sidebar.sortTime"), selected: sort === "time", onSelect: () => {
2660
3049
  onSortChange("time");
2661
3050
  setFilterOpen(false);
2662
3051
  } })
@@ -2669,34 +3058,40 @@ function FilterRow({
2669
3058
  selected,
2670
3059
  onSelect
2671
3060
  }) {
2672
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("button", { type: "button", role: "menuitemradio", "aria-checked": selected, className: selected ? "is-on" : void 0, onClick: onSelect, children: [
2673
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: label }),
2674
- selected ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckOutlineIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-st-n-filter-tick" })
3061
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("button", { type: "button", role: "menuitemradio", "aria-checked": selected, className: selected ? "is-on" : void 0, onClick: onSelect, children: [
3062
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: label }),
3063
+ selected ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CheckOutlineIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dsh-st-n-filter-tick" })
2675
3064
  ] });
2676
3065
  }
2677
3066
 
2678
3067
  // src/client/native-session-list.tsx
2679
- var import_jsx_runtime7 = require("react/jsx-runtime");
3068
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2680
3069
  var EMPTY_SESSION_BY_ID = {};
2681
3070
  function NativeScheduleSessionList(props) {
2682
- const { t, runtime, openSession, useSessions, useWorkspaces, renameSession, archiveSession, forkSession } = props;
2683
- const state = (0, import_react6.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
2684
- const selectedId = useSessions ? useSessions((snap) => snap?.current ?? null) : null;
2685
- const sessionById = useSessions ? useSessions((snap) => snap?.byId ?? EMPTY_SESSION_BY_ID) : EMPTY_SESSION_BY_ID;
2686
- const archivedIds = useWorkspaces ? useWorkspaces((snap) => snap?.archivedSessionIds ?? []) : [];
2687
- const [folded, setFolded] = (0, import_react6.useState)({});
2688
- const [openMenu, setOpenMenu] = (0, import_react6.useState)(null);
2689
- const [query, setQuery] = (0, import_react6.useState)("");
2690
- const [sort, setSort] = (0, import_react6.useState)("time");
2691
- const [groupMode, setGroupMode] = (0, import_react6.useState)("workspace");
2692
- const archived = (0, import_react6.useMemo)(() => new Set(archivedIds), [archivedIds]);
2693
- const listedIds = useSessions ? useSessions((snap) => Array.isArray(snap?.ids) ? snap.ids : void 0) : void 0;
2694
- const presentIds = (0, import_react6.useMemo)(() => {
3071
+ const { t, runtime, openSession, useSessions, useWorkspaces, renameSession, archiveSession, forkSession, openTaskSettings } = props;
3072
+ const state = (0, import_react9.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
3073
+ const selectedId = useSessions ? useSessions((snap) => snap.current ?? null) : null;
3074
+ const sessionById = useSessions ? useSessions((snap) => snap.byId ?? EMPTY_SESSION_BY_ID) : EMPTY_SESSION_BY_ID;
3075
+ const archivedIds = useWorkspaces ? useWorkspaces((snap) => snap.archivedSessionIds ?? []) : [];
3076
+ const [folded, setFolded] = (0, import_react9.useState)({});
3077
+ const [openMenu, setOpenMenu] = (0, import_react9.useState)(null);
3078
+ const [openGroupMenu, setOpenGroupMenu] = (0, import_react9.useState)();
3079
+ const [archiveGroupTarget, setArchiveGroupTarget] = (0, import_react9.useState)();
3080
+ const [archiveGroupBusy, setArchiveGroupBusy] = (0, import_react9.useState)(false);
3081
+ const [archiveGroupError, setArchiveGroupError] = (0, import_react9.useState)();
3082
+ const [archiveManagerInstalled, setArchiveManagerInstalled] = (0, import_react9.useState)(() => typeof document !== "undefined" && hasArchiveManagerPlugin(document));
3083
+ const [query, setQuery] = (0, import_react9.useState)("");
3084
+ const [sort, setSort] = (0, import_react9.useState)("time");
3085
+ const [groupMode, setGroupMode] = (0, import_react9.useState)("workspace");
3086
+ const [view, setView] = (0, import_react9.useState)("runs");
3087
+ const archived = (0, import_react9.useMemo)(() => new Set(archivedIds), [archivedIds]);
3088
+ const listedIds = useSessions ? useSessions((snap) => Array.isArray(snap.ids) ? snap.ids : void 0) : void 0;
3089
+ const presentIds = (0, import_react9.useMemo)(() => {
2695
3090
  if (listedIds !== void 0) return new Set(listedIds);
2696
3091
  const keys = Object.keys(sessionById);
2697
3092
  return keys.length > 0 ? new Set(keys) : void 0;
2698
3093
  }, [listedIds, sessionById]);
2699
- const groups = (0, import_react6.useMemo)(() => {
3094
+ const groups = (0, import_react9.useMemo)(() => {
2700
3095
  const snapshot = state.snapshot;
2701
3096
  if (snapshot === void 0) return [];
2702
3097
  return groupScheduledSessions(snapshot.automations, snapshot.runs).map((group) => ({
@@ -2712,63 +3107,212 @@ function NativeScheduleSessionList(props) {
2712
3107
  })
2713
3108
  })).filter((group) => group.sessions.length > 0);
2714
3109
  }, [archived, presentIds, sessionById, state.snapshot]);
2715
- const visibleGroups = (0, import_react6.useMemo)(() => applyWorkspaceBrowserQuery(groups.map((group) => ({ ...group, name: group.name })), query, sort, groupMode), [groups, query, sort, groupMode]);
2716
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-n", children: [
2717
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(WorkspaceToolbar, { t, query, sort, groupMode, onQueryChange: setQuery, onSortChange: setSort, onGroupModeChange: setGroupMode }),
2718
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-n-tree", role: "tree", children: [
2719
- state.phase === "loading" && visibleGroups.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-n-empty", children: t("loading") }),
2720
- visibleGroups.length === 0 && state.phase !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-n-empty", children: t("sidebar.empty") }),
2721
- visibleGroups.map((group) => {
2722
- const expanded = folded[group.id] !== true;
2723
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-n-group", children: [
2724
- groupMode === "workspace" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-n-row", role: "treeitem", "aria-expanded": expanded, onClick: () => setFolded((current) => ({ ...current, [group.id]: expanded })), children: [
2725
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-st-n-slot dsh-st-n-folder", children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FolderOpenIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FolderClosedIcon, { width: 16, height: 16 }) }),
2726
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-st-n-title", children: group.name })
2727
- ] }),
2728
- (groupMode === "list" || expanded) && group.sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2729
- NativeSessionRow,
2730
- {
2731
- t,
2732
- id: session.id,
2733
- title: session.title,
2734
- hoverTitle: String(sessionById[session.id]?.displayTitle ?? sessionById[session.id]?.title ?? group.name),
2735
- updatedAt: session.updatedAt,
2736
- running: session.running,
2737
- selected: selectedId === session.id,
2738
- menuOpen: openMenu?.id === session.id,
2739
- menuPoint: openMenu === null || openMenu.id !== session.id ? { x: 8, y: 8 } : { x: openMenu.x, y: openMenu.y },
2740
- onToggleMenu: (event) => setOpenMenu((current) => nextOpenSessionMenu(current, session.id, pointerPoint(event))),
2741
- onCloseMenu: () => setOpenMenu((current) => current?.id === session.id ? null : current),
2742
- onOpen: () => {
2743
- setOpenMenu(null);
2744
- openSession?.(session.id);
3110
+ const visibleGroups = (0, import_react9.useMemo)(() => applyWorkspaceBrowserQuery(groups.map((group) => ({ ...group, name: group.name })), query, sort, groupMode), [groups, query, sort, groupMode]);
3111
+ (0, import_react9.useEffect)(() => {
3112
+ if (typeof document === "undefined" || typeof MutationObserver === "undefined") return;
3113
+ const refresh = () => {
3114
+ setArchiveManagerInstalled(hasArchiveManagerPlugin(document));
3115
+ };
3116
+ refresh();
3117
+ const observer = new MutationObserver(refresh);
3118
+ observer.observe(document.documentElement, { childList: true, subtree: true });
3119
+ return () => {
3120
+ observer.disconnect();
3121
+ };
3122
+ }, []);
3123
+ const canArchiveGroup = archiveManagerInstalled && archiveSession !== void 0;
3124
+ const confirmArchiveGroup = () => {
3125
+ if (archiveGroupTarget === void 0 || archiveSession === void 0 || archiveGroupBusy) return;
3126
+ const target = archiveGroupTarget;
3127
+ setArchiveGroupBusy(true);
3128
+ setArchiveGroupError(void 0);
3129
+ void archiveScheduledGroup(target.sessionIds, archiveSession).then(() => {
3130
+ setArchiveGroupTarget(void 0);
3131
+ }).catch((caught) => {
3132
+ setArchiveGroupError(caught instanceof Error ? caught.message : t("error.action"));
3133
+ }).finally(() => {
3134
+ setArchiveGroupBusy(false);
3135
+ });
3136
+ };
3137
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-st-n", children: [
3138
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ScheduleViewSwitch, { t, view, onChange: setView }),
3139
+ view === "overview" ? state.snapshot === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-st-n-empty", children: state.phase === "loading" ? t("loading") : t("overview.empty") }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3140
+ ScheduleOverview,
3141
+ {
3142
+ t,
3143
+ automations: state.snapshot.automations,
3144
+ runs: state.snapshot.runs,
3145
+ ...openSession === void 0 ? {} : { openSession },
3146
+ ...state.snapshot.serverNow === void 0 ? {} : { serverNow: state.snapshot.serverNow },
3147
+ archived,
3148
+ ...presentIds === void 0 ? {} : { presentIds }
3149
+ }
3150
+ ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
3151
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(WorkspaceToolbar, { t, query, sort, groupMode, onQueryChange: setQuery, onSortChange: setSort, onGroupModeChange: setGroupMode }),
3152
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-st-n-tree", role: "tree", children: [
3153
+ state.phase === "loading" && visibleGroups.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-st-n-empty", children: t("loading") }),
3154
+ visibleGroups.length === 0 && state.phase !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-st-n-empty", children: t("sidebar.empty") }),
3155
+ visibleGroups.map((group) => {
3156
+ const expanded = folded[group.id] !== true;
3157
+ const hasCurrentSession = scheduledGroupShowsActiveFolder(expanded, group.sessions.map((session) => session.id), selectedId);
3158
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-st-n-group", children: [
3159
+ groupMode === "workspace" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3160
+ NativeScheduleGroupRow,
3161
+ {
3162
+ t,
3163
+ id: group.id,
3164
+ name: group.name,
3165
+ sessionIds: group.sessions.map((session) => session.id),
3166
+ expanded,
3167
+ hasCurrentSession,
3168
+ menuOpen: openGroupMenu === group.id,
3169
+ canArchiveGroup,
3170
+ onToggle: () => setFolded((current) => ({ ...current, [group.id]: expanded })),
3171
+ onMenuChange: (open) => {
3172
+ setOpenMenu(null);
3173
+ setOpenGroupMenu(open ? group.id : void 0);
3174
+ },
3175
+ onTaskSettings: () => {
3176
+ openTaskSettings?.({ automationId: group.id, name: group.name, sessionIds: group.sessions.map((session) => session.id) });
3177
+ },
3178
+ onArchiveGroup: () => {
3179
+ setArchiveGroupError(void 0);
3180
+ setArchiveGroupTarget({ id: group.id, name: group.name, sessionIds: group.sessions.map((session) => session.id) });
3181
+ }
3182
+ }
3183
+ ),
3184
+ (groupMode === "list" || expanded) && group.sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3185
+ NativeSessionRow,
3186
+ {
3187
+ t,
3188
+ id: session.id,
3189
+ title: session.title,
3190
+ hoverTitle: String(sessionById[session.id]?.displayTitle ?? sessionById[session.id]?.title ?? group.name),
3191
+ updatedAt: session.updatedAt,
3192
+ running: session.running,
3193
+ selected: selectedId === session.id,
3194
+ menuOpen: openMenu?.id === session.id,
3195
+ menuPoint: openMenu === null || openMenu.id !== session.id ? { x: 8, y: 8 } : { x: openMenu.x, y: openMenu.y },
3196
+ onToggleMenu: (event) => {
3197
+ setOpenGroupMenu(void 0);
3198
+ setOpenMenu((current) => nextOpenSessionMenu(current, session.id, pointerPoint(event)));
3199
+ },
3200
+ onCloseMenu: () => setOpenMenu((current) => current?.id === session.id ? null : current),
3201
+ onOpen: () => {
3202
+ setOpenMenu(null);
3203
+ openSession?.(session.id);
3204
+ },
3205
+ ...renameSession === void 0 ? {} : { renameSession },
3206
+ ...archiveSession === void 0 ? {} : { archiveSession },
3207
+ ...forkSession === void 0 ? {} : { forkSession }
2745
3208
  },
2746
- ...renameSession === void 0 ? {} : { renameSession },
2747
- ...archiveSession === void 0 ? {} : { archiveSession },
2748
- ...forkSession === void 0 ? {} : { forkSession }
2749
- },
2750
- session.id
2751
- ))
2752
- ] }, group.id);
2753
- })
2754
- ] })
3209
+ session.id
3210
+ ))
3211
+ ] }, group.id);
3212
+ })
3213
+ ] })
3214
+ ] }),
3215
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
3216
+ import_dsh_client_ui_primitives2.Modal,
3217
+ {
3218
+ open: archiveGroupTarget !== void 0,
3219
+ onClose: () => {
3220
+ if (archiveGroupBusy) return;
3221
+ setArchiveGroupTarget(void 0);
3222
+ setArchiveGroupError(void 0);
3223
+ },
3224
+ closeLabel: t("session.archiveGroupClose"),
3225
+ title: t("session.archiveGroup"),
3226
+ footer: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-st-n-dialog-actions", children: [
3227
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "outline", disabled: archiveGroupBusy, onClick: () => {
3228
+ setArchiveGroupTarget(void 0);
3229
+ setArchiveGroupError(void 0);
3230
+ }, children: t("session.archiveGroupCancel") }),
3231
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "outline", className: "dsh-st-n-danger-button", disabled: archiveGroupBusy, onClick: confirmArchiveGroup, children: t("session.archiveGroupConfirm") })
3232
+ ] }),
3233
+ children: [
3234
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "dsh-st-n-dialog-copy", children: archiveGroupTarget === void 0 ? "" : t("session.archiveGroupDescription", { name: archiveGroupTarget.name, count: archiveGroupTarget.sessionIds.length }) }),
3235
+ archiveGroupBusy && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-st-n-dialog-status", role: "status", children: t("session.archiveGroupPending") }),
3236
+ archiveGroupError !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-st-n-dialog-error", role: "alert", children: t("session.archiveGroupFailed", { message: archiveGroupError }) })
3237
+ ]
3238
+ }
3239
+ )
2755
3240
  ] });
2756
3241
  }
3242
+ function NativeScheduleGroupRow(props) {
3243
+ const { t, id, name: name2, expanded, hasCurrentSession, menuOpen, canArchiveGroup, onToggle, onMenuChange, onTaskSettings, onArchiveGroup } = props;
3244
+ const items = [
3245
+ { id: "task-settings", label: t("session.taskSettings"), icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dsh_client_ui_primitives2.IconSettingsOutline16, { size: 16 }) },
3246
+ ...canArchiveGroup ? [
3247
+ { type: "separator", id: "archive-separator" },
3248
+ { id: "archive-group", label: t("session.archiveGroup"), icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dsh_client_ui_primitives2.IconArchiveOutline20, { size: 16 }), danger: true }
3249
+ ] : []
3250
+ ];
3251
+ const rowClass = "dsh-st-n-row" + (hasCurrentSession ? " has-current-session" : "") + (menuOpen ? " is-menu" : "");
3252
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
3253
+ "div",
3254
+ {
3255
+ className: rowClass,
3256
+ role: "treeitem",
3257
+ "aria-expanded": expanded,
3258
+ "data-n-group": id,
3259
+ onClick: onToggle,
3260
+ children: [
3261
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-slot dsh-st-n-folder", children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FolderOpenIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FolderClosedIcon, { width: 16, height: 16 }) }),
3262
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-title", children: name2 }),
3263
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-acts", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3264
+ import_dsh_client_ui_primitives2.Menu,
3265
+ {
3266
+ open: menuOpen,
3267
+ onClose: () => {
3268
+ onMenuChange(false);
3269
+ },
3270
+ items,
3271
+ onSelect: (action) => {
3272
+ onMenuChange(false);
3273
+ if (action === "task-settings") onTaskSettings();
3274
+ if (action === "archive-group") onArchiveGroup();
3275
+ },
3276
+ portal: true,
3277
+ dense: true,
3278
+ compact: true,
3279
+ anchor: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3280
+ "button",
3281
+ {
3282
+ type: "button",
3283
+ className: "dsh-st-n-ico",
3284
+ "aria-label": t("session.groupActions", { name: name2 }),
3285
+ onMouseDown: (event) => {
3286
+ event.stopPropagation();
3287
+ },
3288
+ onClick: (event) => {
3289
+ event.stopPropagation();
3290
+ onMenuChange(!menuOpen);
3291
+ },
3292
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dsh_client_ui_primitives2.IconEllipsisOutline16, { size: 16 })
3293
+ }
3294
+ )
3295
+ }
3296
+ ) })
3297
+ ]
3298
+ }
3299
+ );
3300
+ }
2757
3301
  function NativeSessionRow(props) {
2758
3302
  const { t, id, title, hoverTitle, updatedAt, running, selected, menuOpen, menuPoint, onToggleMenu, onCloseMenu, onOpen, renameSession, archiveSession, forkSession } = props;
2759
- const rowRef = (0, import_react6.useRef)(null);
2760
- const menuRef = (0, import_react6.useRef)(null);
2761
- const hoverRef = (0, import_react6.useRef)(null);
2762
- const [hoverOpen, setHoverOpen] = (0, import_react6.useState)(false);
2763
- const [hoverStyle, setHoverStyle] = (0, import_react6.useState)({});
2764
- const hoverTimer = (0, import_react6.useRef)(void 0);
2765
- const [renaming, setRenaming] = (0, import_react6.useState)(false);
2766
- const [draft, setDraft] = (0, import_react6.useState)(title);
2767
- const [menuStyle, setMenuStyle] = (0, import_react6.useState)({});
2768
- (0, import_react6.useEffect)(() => {
3303
+ const rowRef = (0, import_react9.useRef)(null);
3304
+ const menuRef = (0, import_react9.useRef)(null);
3305
+ const hoverRef = (0, import_react9.useRef)(null);
3306
+ const [hoverOpen, setHoverOpen] = (0, import_react9.useState)(false);
3307
+ const [hoverStyle, setHoverStyle] = (0, import_react9.useState)({});
3308
+ const hoverTimer = (0, import_react9.useRef)(void 0);
3309
+ const [renaming, setRenaming] = (0, import_react9.useState)(false);
3310
+ const [draft, setDraft] = (0, import_react9.useState)(title);
3311
+ const [menuStyle, setMenuStyle] = (0, import_react9.useState)({});
3312
+ (0, import_react9.useEffect)(() => {
2769
3313
  setDraft(title);
2770
3314
  }, [title]);
2771
- (0, import_react6.useEffect)(() => {
3315
+ (0, import_react9.useEffect)(() => {
2772
3316
  if (!menuOpen) return;
2773
3317
  const close = (event) => {
2774
3318
  if (!shouldCloseNativeSessionMenu(event.target, [rowRef.current, menuRef.current])) return;
@@ -2784,7 +3328,7 @@ function NativeSessionRow(props) {
2784
3328
  document.removeEventListener("keydown", onKey);
2785
3329
  };
2786
3330
  }, [menuOpen, onCloseMenu]);
2787
- (0, import_react6.useLayoutEffect)(() => {
3331
+ (0, import_react9.useLayoutEffect)(() => {
2788
3332
  if (!menuOpen) return;
2789
3333
  const update = () => {
2790
3334
  const el = menuRef.current;
@@ -2799,7 +3343,7 @@ function NativeSessionRow(props) {
2799
3343
  document.removeEventListener("scroll", update, true);
2800
3344
  };
2801
3345
  }, [menuOpen, menuPoint]);
2802
- (0, import_react6.useEffect)(() => {
3346
+ (0, import_react9.useEffect)(() => {
2803
3347
  if (!hoverOpen || menuOpen) return;
2804
3348
  const update = () => {
2805
3349
  const row = rowRef.current?.getBoundingClientRect();
@@ -2816,7 +3360,7 @@ function NativeSessionRow(props) {
2816
3360
  document.removeEventListener("scroll", update, true);
2817
3361
  };
2818
3362
  }, [hoverOpen, menuOpen, title, updatedAt, running]);
2819
- (0, import_react6.useEffect)(() => () => {
3363
+ (0, import_react9.useEffect)(() => () => {
2820
3364
  if (hoverTimer.current !== void 0) window.clearTimeout(hoverTimer.current);
2821
3365
  }, []);
2822
3366
  const run = (action) => {
@@ -2833,7 +3377,7 @@ function NativeSessionRow(props) {
2833
3377
  };
2834
3378
  const rowClass = "dsh-st-n-sess" + (selected ? " is-on" : "") + (menuOpen ? " is-menu" : "");
2835
3379
  if (renaming) {
2836
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: rowClass, ref: rowRef, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { className: "dsh-st-n-rename", value: draft, autoFocus: true, "aria-label": t("session.rename"), onChange: (event) => setDraft(event.target.value), onClick: (event) => event.stopPropagation(), onKeyDown: (event) => {
3380
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: rowClass, ref: rowRef, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { className: "dsh-st-n-rename", value: draft, autoFocus: true, "aria-label": t("session.rename"), onChange: (event) => setDraft(event.target.value), onClick: (event) => event.stopPropagation(), onKeyDown: (event) => {
2837
3381
  if (event.key === "Enter") {
2838
3382
  event.preventDefault();
2839
3383
  setRenaming(false);
@@ -2850,23 +3394,23 @@ function NativeSessionRow(props) {
2850
3394
  } }) });
2851
3395
  }
2852
3396
  const menuItems = [
2853
- { id: "rename", label: t("session.rename"), icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PencilIcon, { width: 16, height: 16 }), go: () => {
3397
+ { id: "rename", label: t("session.rename"), icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PencilIcon, { width: 16, height: 16 }), go: () => {
2854
3398
  setRenaming(true);
2855
3399
  } },
2856
- { id: "fork", label: t("session.fork"), icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(BranchIcon, { width: 16, height: 16 }), go: () => run(() => forkSession?.(id)) },
2857
- { id: "archive", label: t("session.archive"), icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ArchiveIcon, { width: 16, height: 16 }), go: () => run(() => archiveSession?.(id)) }
3400
+ { id: "fork", label: t("session.fork"), icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(BranchIcon, { width: 16, height: 16 }), go: () => run(() => forkSession?.(id)) },
3401
+ { id: "archive", label: t("session.archive"), icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ArchiveIcon, { width: 16, height: 16 }), go: () => run(() => archiveSession?.(id)) }
2858
3402
  ];
2859
- const menu = menuOpen && typeof document !== "undefined" ? (0, import_react_dom2.createPortal)(
2860
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: menuRef, className: "dsh-st-n-menu is-float", "data-n-menu": id, style: menuStyle, onMouseDown: (event) => event.stopPropagation(), onClick: (event) => event.stopPropagation(), children: menuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", className: void 0, onClick: () => {
3403
+ const menu = menuOpen && typeof document !== "undefined" ? (0, import_react_dom3.createPortal)(
3404
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: menuRef, className: "dsh-st-n-menu is-float", "data-n-menu": id, style: menuStyle, onMouseDown: (event) => event.stopPropagation(), onClick: (event) => event.stopPropagation(), children: menuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("button", { type: "button", className: void 0, onClick: () => {
2861
3405
  onCloseMenu();
2862
3406
  item.go();
2863
3407
  }, children: [
2864
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-st-n-mi", children: item.icon }),
3408
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-mi", children: item.icon }),
2865
3409
  item.label
2866
3410
  ] }, item.id)) }),
2867
3411
  document.body
2868
3412
  ) : null;
2869
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: rowClass, ref: rowRef, role: "treeitem", tabIndex: 0, "aria-selected": selected, "data-n-menu-root": id, onClick: onOpen, onMouseEnter: showHover, onMouseLeave: hideHover, onKeyDown: (event) => {
3413
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: rowClass, ref: rowRef, role: "treeitem", tabIndex: 0, "aria-selected": selected, "data-n-menu-root": id, onClick: onOpen, onMouseEnter: showHover, onMouseLeave: hideHover, onKeyDown: (event) => {
2870
3414
  if (event.key === "Enter" || event.key === " ") {
2871
3415
  event.preventDefault();
2872
3416
  onOpen();
@@ -2876,21 +3420,21 @@ function NativeSessionRow(props) {
2876
3420
  event.stopPropagation();
2877
3421
  onToggleMenu(event);
2878
3422
  }, children: [
2879
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-st-n-slot", children: running ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RunningStateDot, {}) : null }),
2880
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-st-n-title", children: title }),
2881
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-st-n-time", children: relativeTime(updatedAt, t) }),
2882
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-st-n-acts", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "dsh-st-n-ico", "aria-label": title + " \u66F4\u591A", onMouseDown: (event) => event.stopPropagation(), onClick: (event) => {
3423
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-slot", children: running ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(RunningStateDot, {}) : null }),
3424
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-title", children: title }),
3425
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-time", children: relativeTime(updatedAt, t) }),
3426
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-acts", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "dsh-st-n-ico", "aria-label": t("session.moreActions", { title }), onMouseDown: (event) => event.stopPropagation(), onClick: (event) => {
2883
3427
  event.stopPropagation();
2884
3428
  hideHover();
2885
3429
  onToggleMenu(event);
2886
- }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(EllipsisIcon, { width: 16, height: 16 }) }) }),
3430
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(EllipsisIcon, { width: 16, height: 16 }) }) }),
2887
3431
  menu,
2888
- hoverOpen && !menuOpen && typeof document !== "undefined" && (0, import_react_dom2.createPortal)(
2889
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { ref: hoverRef, className: "dsh-st-n-hover", style: hoverStyle, onMouseEnter: showHover, onMouseLeave: hideHover, children: [
2890
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-n-hover-title", children: (hoverTitle ?? title).trim() || title }),
2891
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-n-hover-time", children: relativeTime(updatedAt, t) }),
2892
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-n-hover-state", children: [
2893
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: running ? "dsh-st-n-hover-dot is-run" : "dsh-st-n-hover-dot" }),
3432
+ hoverOpen && !menuOpen && typeof document !== "undefined" && (0, import_react_dom3.createPortal)(
3433
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref: hoverRef, className: "dsh-st-n-hover", style: hoverStyle, onMouseEnter: showHover, onMouseLeave: hideHover, children: [
3434
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-st-n-hover-title", children: (hoverTitle ?? title).trim() || title }),
3435
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-st-n-hover-time", children: relativeTime(updatedAt, t) }),
3436
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-st-n-hover-state", children: [
3437
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: running ? "dsh-st-n-hover-dot is-run" : "dsh-st-n-hover-dot" }),
2894
3438
  running ? t("session.runningStatus") : t("session.idle")
2895
3439
  ] })
2896
3440
  ] }),
@@ -2900,11 +3444,11 @@ function NativeSessionRow(props) {
2900
3444
  }
2901
3445
 
2902
3446
  // src/client/ScheduleRail.tsx
2903
- var import_react7 = require("react");
2904
- var import_jsx_runtime8 = require("react/jsx-runtime");
3447
+ var import_react10 = require("react");
3448
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2905
3449
  var EMPTY_EXTRA_TABS = [];
2906
3450
  var noopSubscribe = (_listener) => () => void 0;
2907
- var OfficialTreeGuard = class extends import_react7.Component {
3451
+ var OfficialTreeGuard = class extends import_react10.Component {
2908
3452
  state = { failed: false };
2909
3453
  static getDerivedStateFromError() {
2910
3454
  return { failed: true };
@@ -2919,45 +3463,61 @@ var OfficialTreeGuard = class extends import_react7.Component {
2919
3463
  function ScheduleRail({
2920
3464
  t,
2921
3465
  runtime,
2922
- openSession
3466
+ openSession,
3467
+ view: controlledView,
3468
+ showViewSwitch = true
2923
3469
  }) {
2924
- const state = (0, import_react7.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
2925
- const [folded, setFolded] = (0, import_react7.useState)({});
2926
- const groups = (0, import_react7.useMemo)(() => {
2927
- const snapshot = state.snapshot;
3470
+ const state = (0, import_react10.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
3471
+ const [folded, setFolded] = (0, import_react10.useState)({});
3472
+ const [localView, setLocalView] = (0, import_react10.useState)("runs");
3473
+ const view = controlledView ?? localView;
3474
+ const snapshot = state.snapshot;
3475
+ const groups = (0, import_react10.useMemo)(() => {
2928
3476
  if (snapshot === void 0) return [];
2929
3477
  return groupScheduledSessions(snapshot.automations, snapshot.runs);
2930
- }, [state.snapshot]);
2931
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dsh-st-rail", children: [
2932
- state.phase === "loading" && groups.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "dsh-st-rail-empty", children: t("loading") }),
2933
- groups.length === 0 && state.phase !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "dsh-st-rail-empty", children: t("sidebar.empty") }),
2934
- groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "dsh-st-rail-group", children: [
2935
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2936
- "button",
2937
- {
2938
- type: "button",
2939
- className: "dsh-st-rail-head",
2940
- onClick: () => setFolded((current) => ({ ...current, [group.id]: !current[group.id] })),
2941
- children: [
2942
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dsh-st-rail-folder", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ClockIcon, { width: 16, height: 16 }) }),
2943
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dsh-st-rail-title", children: group.name })
2944
- ]
2945
- }
2946
- ),
2947
- folded[group.id] !== true && group.sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2948
- "button",
2949
- {
2950
- type: "button",
2951
- className: "dsh-st-rail-session",
2952
- onClick: () => openSession?.(session.id),
2953
- children: [
2954
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: session.label }),
2955
- session.running && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(RunningStateDot, {})
2956
- ]
2957
- },
2958
- session.id
2959
- ))
2960
- ] }, group.id))
3478
+ }, [snapshot]);
3479
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "dsh-st-rail", children: [
3480
+ showViewSwitch && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScheduleViewSwitch, { t, view, onChange: setLocalView }),
3481
+ view === "overview" ? snapshot === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-rail-empty", children: state.phase === "loading" ? t("loading") : t("overview.empty") }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3482
+ ScheduleOverview,
3483
+ {
3484
+ t,
3485
+ automations: snapshot.automations,
3486
+ runs: snapshot.runs,
3487
+ ...openSession === void 0 ? {} : { openSession },
3488
+ ...snapshot.serverNow === void 0 ? {} : { serverNow: snapshot.serverNow }
3489
+ }
3490
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
3491
+ state.phase === "loading" && groups.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-rail-empty", children: t("loading") }),
3492
+ groups.length === 0 && state.phase !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-rail-empty", children: t("sidebar.empty") }),
3493
+ groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("section", { className: "dsh-st-rail-group", children: [
3494
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3495
+ "button",
3496
+ {
3497
+ type: "button",
3498
+ className: "dsh-st-rail-head",
3499
+ onClick: () => setFolded((current) => ({ ...current, [group.id]: !current[group.id] })),
3500
+ children: [
3501
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "dsh-st-rail-folder", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ClockIcon, { width: 16, height: 16 }) }),
3502
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "dsh-st-rail-title", children: group.name })
3503
+ ]
3504
+ }
3505
+ ),
3506
+ folded[group.id] !== true && group.sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3507
+ "button",
3508
+ {
3509
+ type: "button",
3510
+ className: "dsh-st-rail-session",
3511
+ onClick: () => openSession?.(session.id),
3512
+ children: [
3513
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: session.label }),
3514
+ session.running && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(RunningStateDot, {})
3515
+ ]
3516
+ },
3517
+ session.id
3518
+ ))
3519
+ ] }, group.id))
3520
+ ] })
2961
3521
  ] });
2962
3522
  }
2963
3523
  function NativeScheduleShell({
@@ -2975,19 +3535,19 @@ function NativeScheduleShell({
2975
3535
  wide
2976
3536
  }) {
2977
3537
  const Official = officialTree;
2978
- const [tab, setTab] = (0, import_react7.useState)(() => {
3538
+ const [tab, setTab] = (0, import_react10.useState)(() => {
2979
3539
  try {
2980
3540
  return readNativeSidebarTab(window.localStorage.getItem(NATIVE_SIDEBAR_TAB_KEY));
2981
3541
  } catch {
2982
3542
  return "tasks";
2983
3543
  }
2984
3544
  });
2985
- const extraTabs = (0, import_react7.useSyncExternalStore)(
3545
+ const extraTabs = (0, import_react10.useSyncExternalStore)(
2986
3546
  tabRegistry?.subscribe ?? noopSubscribe,
2987
3547
  () => tabRegistry?.getTabs() ?? EMPTY_EXTRA_TABS,
2988
3548
  () => EMPTY_EXTRA_TABS
2989
3549
  );
2990
- const channelsReady = (0, import_react7.useSyncExternalStore)(
3550
+ const channelsReady = (0, import_react10.useSyncExternalStore)(
2991
3551
  subscribeChannels ?? noopSubscribe,
2992
3552
  () => {
2993
3553
  try {
@@ -2999,25 +3559,25 @@ function NativeScheduleShell({
2999
3559
  () => false
3000
3560
  );
3001
3561
  const currentId = useSessions?.((state) => state?.current ?? null);
3002
- const automationState = (0, import_react7.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
3003
- const scheduledIds = (0, import_react7.useMemo)(() => collectScheduledSessionIds(automationState.snapshot?.runs), [automationState.snapshot]);
3004
- const useFilteredSessions = (0, import_react7.useCallback)((selector, eq) => {
3562
+ const automationState = (0, import_react10.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
3563
+ const scheduledIds = (0, import_react10.useMemo)(() => collectScheduledSessionIds(automationState.snapshot?.runs), [automationState.snapshot]);
3564
+ const useFilteredSessions = (0, import_react10.useCallback)((selector, eq) => {
3005
3565
  if (useSessions === void 0) return selector({ ids: [], byId: {}, current: null });
3006
3566
  return useSessions((state) => selector(filterTaskSessionState(state, scheduledIds)), eq);
3007
3567
  }, [useSessions, scheduledIds]);
3008
- const useFilteredWorkspaces = (0, import_react7.useCallback)((selector, eq) => {
3568
+ const useFilteredWorkspaces = (0, import_react10.useCallback)((selector, eq) => {
3009
3569
  if (useWorkspaces === void 0) return selector({ items: [], archivedSessionIds: [] });
3010
3570
  return useWorkspaces((state) => selector(filterWorkspaceListState(state, scheduledIds)), eq);
3011
3571
  }, [useWorkspaces, scheduledIds]);
3012
- (0, import_react7.useEffect)(() => {
3572
+ (0, import_react10.useEffect)(() => {
3013
3573
  try {
3014
3574
  window.localStorage.setItem(NATIVE_SIDEBAR_TAB_KEY, tab);
3015
3575
  } catch {
3016
3576
  }
3017
3577
  }, [tab]);
3018
- const previousCurrentId = (0, import_react7.useRef)(currentId);
3019
- const tabFollowReady = (0, import_react7.useRef)(false);
3020
- (0, import_react7.useEffect)(() => {
3578
+ const previousCurrentId = (0, import_react10.useRef)(currentId);
3579
+ const tabFollowReady = (0, import_react10.useRef)(false);
3580
+ (0, import_react10.useEffect)(() => {
3021
3581
  if (!tabFollowReady.current) {
3022
3582
  tabFollowReady.current = true;
3023
3583
  previousCurrentId.current = currentId;
@@ -3040,11 +3600,11 @@ function NativeScheduleShell({
3040
3600
  };
3041
3601
  const renderOfficial = (props) => {
3042
3602
  if (Official === void 0) {
3043
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(NativeTaskRail, { t, ...openSession === void 0 ? {} : { openSession }, ...useSessions === void 0 ? {} : { useSessions: useFilteredSessions }, ...useWorkspaces === void 0 ? {} : { useWorkspaces } });
3603
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NativeTaskRail, { t, ...openSession === void 0 ? {} : { openSession }, ...useSessions === void 0 ? {} : { useSessions: useFilteredSessions }, ...useWorkspaces === void 0 ? {} : { useWorkspaces } });
3044
3604
  }
3045
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(OfficialTreeGuard, { fallback: (0, import_react7.createElement)(Official, rawOfficialProps), children: (0, import_react7.createElement)(Official, props) });
3605
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(OfficialTreeGuard, { fallback: (0, import_react10.createElement)(Official, rawOfficialProps), children: (0, import_react10.createElement)(Official, props) });
3046
3606
  };
3047
- if (wide === false) return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: renderOfficial(filteredOfficialProps) });
3607
+ if (wide === false) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: renderOfficial(filteredOfficialProps) });
3048
3608
  const foreignTabs = extraTabs.filter((item) => item.id !== "schedule");
3049
3609
  const visibleTab = resolveVisibleSidebarTab({
3050
3610
  tab,
@@ -3052,15 +3612,15 @@ function NativeScheduleShell({
3052
3612
  extraTabIds: ownedSidebarTabIds({ extraTabIds: foreignTabs.map((item) => item.id), channelsReady })
3053
3613
  });
3054
3614
  const hostedSchedule = extraTabs.find((item) => item.id === "schedule");
3055
- const scheduleBody = hostedSchedule === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(NativeScheduleSessionList, { t, runtime, ...openSession === void 0 ? {} : { openSession }, ...useSessions === void 0 ? {} : { useSessions }, ...useWorkspaces === void 0 ? {} : { useWorkspaces } }) : hostedSchedule.render({ ...hostProps ?? {}, openSession, open: openSession, useSessions, wide: true });
3056
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dsh-st-shell-rail", children: [
3057
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dsh-st-shell-tabs", role: "tablist", "aria-label": t("sidebar.tabs"), children: [
3058
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === "tasks", className: visibleTab === "tasks" ? "is-on" : void 0, onClick: () => setTab("tasks"), children: t("sidebar.tasksTab") }),
3059
- foreignTabs.map((item) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === item.id, className: visibleTab === item.id ? "is-on" : void 0, onClick: () => setTab(item.id), children: item.label }, item.id)),
3060
- channelsReady && foreignTabs.every((item) => item.id !== "channels") && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === "channels", className: visibleTab === "channels" ? "is-on" : void 0, onClick: () => setTab("channels"), children: t("sidebar.channelsTab") }),
3061
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === "schedule", className: visibleTab === "schedule" ? "is-on" : void 0, onClick: () => setTab("schedule"), children: t("sidebar.tab") })
3615
+ const scheduleBody = hostedSchedule === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NativeScheduleSessionList, { t, runtime, ...openSession === void 0 ? {} : { openSession }, ...useSessions === void 0 ? {} : { useSessions }, ...useWorkspaces === void 0 ? {} : { useWorkspaces } }) : hostedSchedule.render({ ...hostProps ?? {}, openSession, open: openSession, useSessions, wide: true });
3616
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "dsh-st-shell-rail", children: [
3617
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "dsh-st-shell-tabs", role: "tablist", "aria-label": t("sidebar.tabs"), children: [
3618
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === "tasks", className: visibleTab === "tasks" ? "is-on" : void 0, onClick: () => setTab("tasks"), children: t("sidebar.tasksTab") }),
3619
+ foreignTabs.map((item) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === item.id, className: visibleTab === item.id ? "is-on" : void 0, onClick: () => setTab(item.id), children: item.label }, item.id)),
3620
+ channelsReady && foreignTabs.every((item) => item.id !== "channels") && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === "channels", className: visibleTab === "channels" ? "is-on" : void 0, onClick: () => setTab("channels"), children: t("sidebar.channelsTab") }),
3621
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === "schedule", className: visibleTab === "schedule" ? "is-on" : void 0, onClick: () => setTab("schedule"), children: t("sidebar.tab") })
3062
3622
  ] }),
3063
- visibleTab === "schedule" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "dsh-st-shell-body", children: scheduleBody }) : foreignTabs.find((item) => item.id === visibleTab) !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "dsh-st-shell-body", children: foreignTabs.find((item) => item.id === visibleTab)?.render({ ...hostProps ?? {}, openSession, open: openSession, useSessions, wide: true }) }) : visibleTab === "channels" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "dsh-st-shell-body", children: renderSlot?.("sidebar.channels", { ...hostProps ?? {}, openSession, open: openSession, useSessions, wide: true, skin: "native" }) }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "dsh-st-official-tree", children: renderOfficial(filteredOfficialProps) })
3623
+ visibleTab === "schedule" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-shell-body", children: scheduleBody }) : foreignTabs.find((item) => item.id === visibleTab) !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-shell-body", children: foreignTabs.find((item) => item.id === visibleTab)?.render({ ...hostProps ?? {}, openSession, open: openSession, useSessions, wide: true }) }) : visibleTab === "channels" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-shell-body", children: renderSlot?.("sidebar.channels", { ...hostProps ?? {}, openSession, open: openSession, useSessions, wide: true, skin: "native" }) }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-official-tree", children: renderOfficial(filteredOfficialProps) })
3064
3624
  ] });
3065
3625
  }
3066
3626
  function NativeTaskRail({
@@ -3072,10 +3632,10 @@ function NativeTaskRail({
3072
3632
  const snap = useSessions === void 0 ? { ids: [], byId: {}, current: null } : useSessions((state) => state ?? { ids: [], byId: {}, current: null });
3073
3633
  const workspaces = useWorkspaces === void 0 ? void 0 : useWorkspaces((state) => state ?? { items: [], archivedSessionIds: [] });
3074
3634
  const groups = groupNativeTaskSessions(snap, workspaces, t("sidebar.ungrouped"));
3075
- if (groups.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "dsh-st-rail-empty", children: t("sidebar.tasksEmpty") });
3076
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "dsh-st-rail", children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "dsh-st-rail-group", children: [
3077
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "dsh-st-rail-head is-static", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dsh-st-rail-title", children: group.label }) }),
3078
- group.sessions.map((item) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3635
+ if (groups.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-rail-empty", children: t("sidebar.tasksEmpty") });
3636
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-rail", children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("section", { className: "dsh-st-rail-group", children: [
3637
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-rail-head is-static", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "dsh-st-rail-title", children: group.label }) }),
3638
+ group.sessions.map((item) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3079
3639
  "button",
3080
3640
  {
3081
3641
  type: "button",
@@ -3083,7 +3643,7 @@ function NativeTaskRail({
3083
3643
  onClick: () => {
3084
3644
  if (item.id !== void 0) openSession?.(item.id);
3085
3645
  },
3086
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: item.title || item.id })
3646
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: item.title || item.id })
3087
3647
  },
3088
3648
  item.id
3089
3649
  ))
@@ -3121,16 +3681,33 @@ var CSS_TEXT = `
3121
3681
  .dsh-st-tabs>button{padding:8px 0;border:0;border-bottom:2px solid transparent;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer}
3122
3682
  .dsh-st-tabs>button.is-on{border-bottom-color:currentColor;color:var(--dsw-alias-label-primary);font-weight:650}
3123
3683
  .dsh-st-dropdown{position:relative;min-width:0}
3124
- .dsh-st-sort{margin-left:auto}
3125
- .dsh-st-dropdown-btn{display:inline-flex;align-items:center;gap:4px;max-width:220px;height:28px;padding:0 10px;border:0;border-radius:999px;background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.14));color:var(--dsw-alias-label-primary,inherit);font:13px/20px inherit;cursor:pointer;white-space:nowrap}
3684
+ .dsh-st-sort-wrap{display:flex;align-items:center;gap:6px;margin-left:auto}
3685
+ .dsh-st-dropdown-btn{display:inline-flex;align-items:center;gap:4px;max-width:220px;height:28px;padding:0 10px;border:0;border-radius:999px;background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.14));color:var(--dsw-alias-label-primary,inherit);font-family:inherit;font-size:13px;line-height:20px;cursor:pointer;white-space:nowrap}
3126
3686
  .dsh-st-dropdown-btn:hover,.dsh-st-dropdown-btn.is-open{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.18))}
3127
3687
  .dsh-st-dropdown-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
3128
3688
  .dsh-st-dropdown-chevron{flex:none;transition:transform .16s ease;transform:rotate(90deg)}
3129
3689
  .dsh-st-dropdown-btn.is-open .dsh-st-dropdown-chevron{transform:rotate(-90deg)}
3130
- .dsh-st-dropdown-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:30;width:180px;max-height:260px;overflow:auto;padding:6px;border:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.12));border-radius:12px;background:var(--dsw-alias-bg-layer-3,#303033);box-shadow:var(--dsw-shadow-lv3,0 8px 24px rgba(0,0,0,.32))}
3131
- .dsh-st-dropdown-menu button{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;min-height:36px;padding:6px 10px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary,inherit);font:13px/20px inherit;cursor:pointer;text-align:left}
3132
- .dsh-st-dropdown-menu button>span:first-child{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
3133
- .dsh-st-dropdown-menu button:hover,.dsh-st-dropdown-menu button.is-selected{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.08));color:var(--dsw-alias-label-primary,inherit)}
3690
+ .dsh-st-dropdown-menu{box-sizing:border-box;position:absolute;right:0;top:calc(100% + 6px);z-index:30;width:max-content;min-width:180px;max-width:calc(100vw - 16px);max-height:260px;overflow-x:hidden;overflow-y:auto;padding:6px;border:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.12));border-radius:12px;background:var(--dsw-alias-bg-layer-3,#303033);box-shadow:var(--dsw-shadow-lv3,0 8px 24px rgba(0,0,0,.32))}
3691
+ .dsh-st-dropdown-menu.is-float{position:fixed;right:auto;top:auto;z-index:1200}
3692
+ .dsh-st-dropdown-menu.dsh-st-dropdown-sort{min-width:0;transition:width .12s ease}
3693
+ .dsh-st-dropdown-row{box-sizing:border-box;display:flex;align-items:center;justify-content:flex-start;gap:8px;width:100%;min-height:36px;padding:6px 10px;border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary,inherit);font-family:inherit;font-size:13px;line-height:20px;cursor:pointer;text-align:left}
3694
+ .dsh-st-dropdown-label-cell{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
3695
+ .dsh-st-dropdown-row:not(.has-trailing) .dsh-st-dropdown-label-cell{flex:1}
3696
+ .dsh-st-dropdown-row.has-trailing .dsh-st-dropdown-label-cell{flex:none}
3697
+ .dsh-st-dropdown-spacer{min-width:0}
3698
+ .dsh-st-dropdown-row:not(.has-trailing) .dsh-st-dropdown-spacer{flex:0 0 0}
3699
+ .dsh-st-dropdown-row.has-trailing .dsh-st-dropdown-spacer{flex:1 1 auto}
3700
+ .dsh-st-dropdown-row.has-trailing{gap:0}
3701
+ .dsh-st-dropdown-row.has-trailing .dsh-st-dropdown-label-cell{margin-right:8px}
3702
+ .dsh-st-dropdown-row.has-trailing .dsh-st-dropdown-default{margin-right:4px}
3703
+ .dsh-st-dropdown-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex:none}
3704
+ .dsh-st-dropdown-row:hover,.dsh-st-dropdown-row.is-selected{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.08));color:var(--dsw-alias-label-primary,inherit)}
3705
+ .dsh-st-dropdown-default{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;width:auto;min-width:0;height:22px;padding:0 6px;border:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.14));border-radius:999px;background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.14));color:var(--dsw-alias-label-primary,inherit);font-family:inherit;font-size:12px;line-height:18px;cursor:pointer;white-space:nowrap;overflow:hidden}
3706
+ .dsh-st-dropdown-default:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.2))}
3707
+ .dsh-st-dropdown-default:disabled,.dsh-st-dropdown-default.is-on{background:rgba(255,255,255,.05);border-color:rgba(255,255,255,.08);color:var(--dsw-alias-label-tertiary,#8b8f98);cursor:default}
3708
+ .dsh-st-dropdown.dsh-st-dropdown-compact .dsh-st-dropdown-btn{font-size:12px;line-height:18px}
3709
+ .dsh-st-dropdown-menu.dsh-st-dropdown-compact .dsh-st-dropdown-row{font-size:12px;line-height:18px}
3710
+ .dsh-st-dropdown-menu.dsh-st-dropdown-compact .dsh-st-dropdown-default{font-size:11px;line-height:16px}
3134
3711
  .dsh-st-sort-tick{width:16px;height:16px;flex:none}
3135
3712
  .dsh-st-filters{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-left:auto}
3136
3713
  .dsh-st-filters>button{height:28px;padding:0 10px;border:0;border-radius:999px;background:rgba(255,255,255,.06);color:inherit;font-size:12px}
@@ -3226,6 +3803,29 @@ var CSS_TEXT = `
3226
3803
  .dsh-st-menu-split{height:1px;margin:6px 8px;background:rgba(255,255,255,.08)}
3227
3804
  .dsh-st-subdialog{margin:0 0 12px;padding:12px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:rgba(255,255,255,.03)}
3228
3805
  .dsh-st-subdialog>strong{display:block;margin:0 0 8px;font-size:13px}
3806
+ .dsh-st-rail-views{display:flex;flex:none;gap:3px;margin:16px 8px 10px;padding:2px;border:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.1));border-radius:9px;background:var(--dsw-alias-bg-layer-2,rgba(255,255,255,.035))}
3807
+ .dsh-st-rail-views button{flex:1;appearance:none;border:1px solid transparent;border-radius:6px;background:transparent;color:var(--dsw-alias-label-secondary,#9ca3af);padding:3px 7px;font-size:12px;line-height:18px;cursor:pointer;transition:background .16s ease,border-color .16s ease,color .16s ease,box-shadow .16s ease}
3808
+ .dsh-st-rail-views button:hover{color:var(--dsw-alias-label-primary,inherit)}
3809
+ .dsh-st-rail-views button.is-on{border-color:var(--dsw-alias-border-l2,rgba(255,255,255,.18));background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.15));color:var(--dsw-alias-label-primary,#fff);font-weight:650;box-shadow:0 1px 3px rgba(0,0,0,.34),inset 0 1px rgba(255,255,255,.06)}
3810
+ .dsh-st-overview{display:flex;flex-direction:column;flex:1;min-height:0;overflow-y:auto;padding:2px 8px 14px}
3811
+ .dsh-st-overview-head{display:flex;flex:none;align-items:center;justify-content:space-between;gap:8px;height:36px;min-height:36px;margin-bottom:4px;padding:6px 0}
3812
+ .dsh-st-overview-title{display:flex;align-items:baseline;min-width:0;gap:6px;color:var(--dsw-alias-label-tertiary,#81858C)}
3813
+ .dsh-st-overview-title strong{font-size:14px;font-weight:400;line-height:20px}
3814
+ .dsh-st-overview-title span{display:inline-grid;place-items:center;min-width:18px;height:18px;padding:0 5px;border-radius:999px;background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.1));color:var(--dsw-alias-label-tertiary,#8b8f98);font-size:11px;line-height:18px}
3815
+ .dsh-st-overview-sort{display:flex;align-items:center}
3816
+ .dsh-st-overview-row{position:relative;display:grid;grid-template-columns:minmax(0,1fr) auto 12px;align-items:center;gap:8px;width:100%;min-height:88px;margin:0 0 8px;padding:9px 10px;border:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.1));border-radius:9px;background:var(--dsw-alias-bg-layer-2,rgba(255,255,255,.035));color:var(--dsw-alias-label-primary,inherit);text-align:left;cursor:pointer;box-shadow:inset 0 1px rgba(255,255,255,.025);transition:background .14s ease,border-color .14s ease}
3817
+ .dsh-st-overview-row:hover:not(:disabled){border-color:var(--dsw-alias-border-inverted,rgba(255,255,255,.18));background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.06))}
3818
+ .dsh-st-overview-row:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#4c8dff);outline-offset:2px}
3819
+ .dsh-st-overview-row:disabled{cursor:default}
3820
+ .dsh-st-overview-copy{display:flex;flex:1;min-width:0;flex-direction:column;gap:4px}
3821
+ .dsh-st-overview-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;line-height:18px;font-weight:580}
3822
+ .dsh-st-overview-status{display:inline-flex;align-self:flex-start;align-items:center;gap:4px;padding:2px 6px;border-radius:999px;background:rgba(50,205,143,.12);color:#45d483;font-size:11px;line-height:16px}
3823
+ .dsh-st-overview-row.is-paused .dsh-st-overview-status{background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.08));color:var(--dsw-alias-label-secondary,#aeb3bd)}
3824
+ .dsh-st-overview-schedule{display:inline-flex;align-items:center;gap:5px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary,#8b8f98);font-size:12px;line-height:16px}
3825
+ .dsh-st-overview-next{display:flex;flex:none;min-width:50px;flex-direction:column;align-items:flex-end;gap:2px;color:var(--dsw-alias-label-tertiary,#8b8f98);font-size:10px;line-height:14px}
3826
+ .dsh-st-overview-next strong{color:var(--dsw-alias-label-secondary,#b6bac2);font-size:12px;font-weight:600;line-height:16px;white-space:nowrap}
3827
+ .dsh-st-overview-row:not(.is-paused) .dsh-st-overview-next strong{color:#45d483}
3828
+ .dsh-st-overview-chevron{flex:none;color:var(--dsw-alias-label-tertiary,#8b8f98)}
3229
3829
  .dsh-st-rail{box-sizing:border-box;height:100%;overflow:auto;padding:4px var(--dsh-sidebar-inline-padding,12px) 18px 8px;color:inherit;scrollbar-gutter:stable}
3230
3830
  .dsh-st-rail-empty{padding:16px 10px;color:var(--dsw-alias-label-tertiary,#8b8f98);font-size:12px}
3231
3831
  .dsh-st-rail-group{margin:0 0 8px}
@@ -3238,14 +3838,26 @@ var CSS_TEXT = `
3238
3838
  .dsh-st-rail-session span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
3239
3839
  .dsh-st-rail-dot{width:6px;height:6px;margin-left:auto;border-radius:50%;background:#34c759;flex:none}.dsh-st-run-dot{flex:none;color:var(--dsw-static-deepseek-450,#4c8dff)}.dsh-st-run-dot-cell{fill:currentColor;opacity:.15;animation:dsh-st-run-chase 1s infinite}@keyframes dsh-st-run-chase{0%,12.4%{opacity:1}12.5%,24.9%{opacity:.6}25%,37.4%{opacity:.35}37.5%,100%{opacity:.15}}
3240
3840
  .dsh-st-shell-rail{display:flex;flex-direction:column;min-height:0;flex:1;height:100%;overflow:hidden}
3241
- .dsh-st-shell-tabs{display:flex;flex:none;gap:18px;padding:4px 12px 0;border-bottom:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.08))}
3242
- .dsh-st-shell-tabs button{appearance:none;border:0;background:transparent;color:var(--dsw-alias-label-secondary,#8b8f98);padding:8px 0;font-size:13px;cursor:pointer}
3841
+ .dsh-st-shell-tabs{display:flex;flex:none;gap:18px;padding:6px 12px 0;border-bottom:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.08))}
3842
+ .dsh-st-shell-tabs button{appearance:none;border:0;background:transparent;color:var(--dsw-alias-label-secondary,#8b8f98);padding:8px 0 9px;font-size:13px;cursor:pointer}
3243
3843
  .dsh-st-shell-tabs button.is-on{color:var(--dsw-alias-label-primary,inherit);box-shadow:inset 0 -2px 0 currentColor}
3244
3844
  .dsh-st-shell-body{display:flex;min-height:0;flex:1;overflow:hidden}
3245
3845
  .dsh-st-shell-body>*{min-width:0;flex:1}.dsh-st-official-tree{display:flex;min-height:0;flex:1;overflow:hidden}.dsh-st-official-tree>*{min-width:0;flex:1}
3246
3846
  .dsh-st-rail-head.is-static{cursor:default;font-weight:600}
3247
3847
  .dsh-st-rail-session.is-on{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}
3248
3848
  .dsh-st-n,.dsh-st-n *{box-sizing:border-box}.dsh-st-n{box-sizing:border-box;display:flex;flex:1;min-width:0;max-width:100%;min-height:0;flex-direction:column;padding:0;padding-right:var(--dsh-sidebar-inline-padding,12px);color:var(--dsw-alias-label-primary,inherit);font:14px/20px inherit;overflow:hidden}.dsh-st-n-toolbar{box-sizing:border-box;flex:none;height:36px;margin:2px -4px 4px 0;padding-left:4px;display:flex;justify-content:flex-end;align-items:center;gap:4px;overflow:visible;position:relative;z-index:2;color:var(--dsw-alias-label-tertiary,#81858C);border-radius:12px}.dsh-st-n-head-label{white-space:nowrap;min-width:0;max-width:45%;flex:none;line-height:20px;font-size:14px;overflow:hidden;transition:max-width .18s var(--ds-ease-in-out,ease),margin-right .18s var(--ds-ease-in-out,ease),opacity .12s var(--ds-ease-in-out,ease),transform .18s var(--ds-ease-in-out,ease),visibility 0s linear}.dsh-st-n-toolbar.is-search .dsh-st-n-head-label{opacity:0;visibility:hidden;max-width:0;margin-right:-4px;transform:translate(-4px);transition-delay:0s,0s,0s,0s,.18s}.dsh-st-n-search-slot{box-sizing:border-box;min-width:28px;max-width:28px;transition:max-width .18s var(--ds-ease-in-out,ease);flex:none;align-items:center;margin-left:auto;display:flex;position:relative;z-index:2}.dsh-st-n-toolbar.is-search .dsh-st-n-search-slot{flex:1;min-width:0;max-width:100%}.dsh-st-n-search{box-sizing:border-box;cursor:text;width:100%;height:28px;color:var(--dsw-alias-label-secondary);transition:width .18s var(--ds-ease-in-out,ease),padding .18s var(--ds-ease-in-out,ease),border-color .18s var(--ds-ease-in-out,ease);background:transparent;border:none;border-radius:50%;flex:none;align-items:center;margin:0;padding:0;display:flex;overflow:hidden}.dsh-st-n-toolbar.is-search .dsh-st-n-search{border:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.10));width:calc(100% + 4px);height:30px;border-radius:10px;margin-inline:-2px;padding:0 4px 0 0}.dsh-st-n-search-btn,.dsh-st-n-head-btn{cursor:pointer;width:28px;height:28px;min-width:28px;min-height:28px;position:relative;z-index:1;color:var(--dsw-alias-label-secondary);background:transparent;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.dsh-st-n-toolbar.is-search .dsh-st-n-search-btn{width:28px;height:30px}.dsh-st-n-search-btn:hover,.dsh-st-n-head-btn:hover,.dsh-st-n-head-btn.is-on{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06));color:var(--dsw-alias-label-primary,inherit)}.dsh-st-n-toolbar.is-search .dsh-st-n-search-btn:hover{background:transparent}.dsh-st-n-head-acts{opacity:1;visibility:visible;max-width:32px;transition:max-width .18s var(--ds-ease-in-out,ease),opacity .12s var(--ds-ease-in-out,ease),transform .18s var(--ds-ease-in-out,ease),visibility 0s linear;flex:none;align-items:center;gap:4px;display:flex;overflow:visible;position:relative}.dsh-st-n-toolbar.is-search .dsh-st-n-head-acts{opacity:0;visibility:hidden;pointer-events:none;max-width:0;transform:translate(4px);transition-delay:0s,0s,0s,.18s}.dsh-st-n-head-filter{position:relative}.dsh-st-n-search-input{display:none;opacity:0;pointer-events:none;width:0;min-width:0;flex:none;color:var(--dsw-alias-label-primary,inherit);transition:opacity .12s var(--ds-ease-in-out,ease);background:transparent;border:none;outline:none;flex:1;font-size:13px;line-height:18px}.dsh-st-n-toolbar.is-search .dsh-st-n-search-input{display:block;opacity:1;pointer-events:auto;margin-left:-2px;width:auto;flex:1;min-width:0}.dsh-st-n-search-input::placeholder{color:var(--dsw-alias-label-tertiary,#81858C)}.dsh-st-n-search-clear{cursor:pointer;width:24px;height:24px;color:var(--dsw-alias-label-secondary);background:transparent;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.dsh-st-n-search-clear:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}@media (prefers-reduced-motion:reduce){.dsh-st-n-head-label,.dsh-st-n-search-slot,.dsh-st-n-search,.dsh-st-n-head-acts,.dsh-st-n-search-input{transition:none}}.dsh-st-n-filter-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:30;min-width:196px;padding:8px 6px;border:1px solid var(--dsw-alias-border-inverted,rgba(255,255,255,.12));border-radius:12px;background:var(--dsw-specific-menu,#1c2128);box-shadow:var(--dsw-shadow-lv3,0 8px 24px rgba(0,0,0,.36))}.dsh-st-n-filter-label{padding:6px 10px 4px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary,#81858C)}.dsh-st-n-filter-split{height:1px;margin:6px 8px;background:var(--dsw-alias-border-l2,rgba(255,255,255,.1))}.dsh-st-n-filter-menu button{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;min-height:36px;padding:6px 10px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary,inherit);font:14px/20px inherit;cursor:pointer;text-align:left}.dsh-st-n-filter-menu button:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}.dsh-st-n-filter-tick{width:16px;height:16px;flex:none}.dsh-st-n-tree{flex:1;min-width:0;max-width:100%;min-height:0;overflow-x:hidden;overflow-y:auto;padding:0 0 16px;user-select:none}.dsh-st-n-empty{padding:14px 8px;color:var(--dsw-alias-label-tertiary,#8b8f98);font-size:12px}.dsh-st-n-group{min-width:0;max-width:100%}.dsh-st-n-row,.dsh-st-n-sess{display:flex;align-items:center;max-width:100%;border-radius:8px;padding:0 8px 0 12px;cursor:pointer;border:0;background:transparent;color:var(--dsw-alias-label-primary,inherit);text-align:left;font:14px/20px inherit}.dsh-st-n-row{height:34px;gap:6px}.dsh-st-n-sess{height:32px;gap:0;position:relative;width:100%;appearance:none}.dsh-st-n-row:hover,.dsh-st-n-sess:hover,.dsh-st-n-sess.is-on,.dsh-st-n-sess.is-menu{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}.dsh-st-n-slot{flex:none;width:16px;height:20px;display:inline-flex;align-items:center;justify-content:center}.dsh-st-n-folder{color:var(--dsw-alias-label-secondary,#9ca39f)}.dsh-st-n-lead{color:var(--dsw-alias-label-tertiary,#81858C)}.dsh-st-n-corner{color:var(--dsw-alias-label-caption,#ADB2B8);width:8px}.dsh-st-n-title{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;line-height:20px}.dsh-st-n-sess .dsh-st-n-title{margin:0 6px 0 4px}.dsh-st-n-time{flex:none;font-size:12px;line-height:20px;color:var(--dsw-alias-label-tertiary,#81858C);white-space:nowrap}.dsh-st-n-acts{flex:none;display:none;align-items:center;gap:12px}.dsh-st-n-row:hover .dsh-st-n-acts,.dsh-st-n-sess:hover .dsh-st-n-acts,.dsh-st-n-row.is-menu .dsh-st-n-acts,.dsh-st-n-sess.is-menu .dsh-st-n-acts{display:inline-flex}.dsh-st-n-sess:hover .dsh-st-n-time,.dsh-st-n-sess.is-menu .dsh-st-n-time{display:none}.dsh-st-n-ico{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border:0;border-radius:4px;background:transparent;color:var(--dsw-alias-label-tertiary,#81858C);padding:0;cursor:pointer}.dsh-st-n-ico:hover{color:var(--dsw-alias-label-primary,inherit)}.dsh-st-n-menu.is-float{position:fixed;z-index:4000;right:auto;top:auto}.dsh-st-n-menu{position:absolute;right:8px;top:calc(100% + 4px);z-index:1100;min-width:218px;max-width:360px;box-sizing:border-box;padding:4px;display:flex;flex-direction:column;border:1px solid var(--dsw-alias-border-inverted,rgba(255,255,255,.12));border-radius:12px;background:var(--dsw-specific-menu,#1c2128);box-shadow:var(--dsw-shadow-lv3,0 8px 24px rgba(0,0,0,.36))}.dsh-st-n-menu button{display:flex;align-items:center;gap:8px;width:100%;min-height:40px;padding:8px 10px;border:0;border-radius:10px;background:transparent;cursor:pointer;font-size:14px;line-height:22px;color:var(--dsw-alias-label-primary,inherit);text-align:left}.dsh-st-n-menu button:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}.dsh-st-n-mi{display:inline-flex;flex:none;width:16px;height:16px;align-items:center;justify-content:center;color:var(--dsw-alias-label-tertiary,#81858C)}.dsh-st-n-menu button.danger{color:var(--dsw-alias-state-error-primary,#f85149)}.dsh-st-n-menu button.danger .dsh-st-n-mi{color:inherit}.dsh-st-n-menu button.danger:hover{background:var(--dsw-alias-interactive-bg-hover-danger,rgba(248,81,73,.12))}.dsh-st-n-hover{position:fixed;z-index:4100;min-width:188px;max-width:280px;padding:12px 14px;border:1px solid var(--dsw-alias-border-inverted,rgba(255,255,255,.12));border-radius:12px;background:var(--dsw-specific-menu,#1c2128);box-shadow:var(--dsw-shadow-lv3,0 8px 24px rgba(0,0,0,.36));color:var(--dsw-alias-label-primary,inherit)}.dsh-st-n-hover-title{font-size:14px;line-height:20px;font-weight:500}.dsh-st-n-hover-time{margin-top:4px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary,#81858C)}.dsh-st-n-hover-state{display:flex;align-items:center;gap:6px;margin-top:8px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary,#9ca39f)}.dsh-st-n-hover-dot{width:8px;height:8px;border-radius:50%;background:#34c759;flex:none}.dsh-st-n-hover-dot.is-run{background:#4c8dff}.dsh-st-n-rename{flex:1;min-width:0;margin:0 6px 0 4px;border:1px solid var(--dsw-alias-border-l2);border-radius:4px;background:var(--dsw-alias-button-elevated-fill,rgba(255,255,255,.04));color:inherit;font:inherit;padding:0 2px}
3849
+ .dsh-st-n-row.is-menu{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}
3850
+ .dsh-st-overview-sort .dsh-st-n-head-btn.is-open{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06));color:var(--dsw-alias-label-primary,inherit)}
3851
+ .dsh-st-n-row[aria-expanded="true"].has-current-session .dsh-st-n-folder{color:var(--dsw-static-deepseek-450,#4c8dff)}
3852
+ .dsh-st-n-sess:focus{outline:none}.dsh-st-n-sess:focus-visible:not(.is-on){box-shadow:inset 0 0 0 2px var(--dsw-alias-state-business-primary,#4c8dff)}
3853
+ .dsh-st-n-row>.dsh-st-n-acts{display:inline-flex;opacity:0;visibility:hidden;pointer-events:none}
3854
+ .dsh-st-n-row:hover>.dsh-st-n-acts,.dsh-st-n-row:focus-within>.dsh-st-n-acts,.dsh-st-n-row.is-menu>.dsh-st-n-acts{opacity:1;visibility:visible;pointer-events:auto}
3855
+ .dsh-st-n-dialog-actions{display:flex;justify-content:flex-end;gap:8px}
3856
+ .dsh-st-n-dialog-copy{margin:0;color:var(--dsw-alias-label-secondary);font-size:14px;line-height:22px}
3857
+ .dsh-st-n-dialog-status{margin-top:12px;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px}
3858
+ .dsh-st-n-dialog-error{margin-top:12px;color:var(--dsw-alias-state-error-primary,#f85149);font-size:13px;line-height:20px}
3859
+ .dsh-st-n-danger-button{color:var(--dsw-alias-state-error-primary,#f85149)!important}
3860
+ .dsh-st-n-danger-button:hover{background:var(--dsw-alias-interactive-bg-hover-danger,rgba(248,81,73,.12))!important}
3249
3861
  `;
3250
3862
  function installStyles() {
3251
3863
  const existing = document.getElementById(STYLE_ID);
@@ -3262,10 +3874,87 @@ function installStyles() {
3262
3874
  };
3263
3875
  }
3264
3876
 
3877
+ // src/client/settings-navigation.ts
3878
+ function pickSettingsSectionButton(buttons, labels) {
3879
+ for (const label of labels) {
3880
+ const target = label.trim();
3881
+ if (target === "") continue;
3882
+ const match = buttons.find((button) => button.textContent?.replace(/\s+/g, " ").trim() === target);
3883
+ if (match !== void 0) return match;
3884
+ }
3885
+ return void 0;
3886
+ }
3887
+ function pickSettingsLauncher(buttons) {
3888
+ const named = buttons.find((button) => {
3889
+ const label = `${button.textContent ?? ""} ${button.getAttribute("aria-label") ?? ""}`.trim();
3890
+ return /(^|\s)(设置|settings)(\s|$)/i.test(label);
3891
+ });
3892
+ return named ?? (buttons.length === 1 ? buttons[0] : void 0);
3893
+ }
3894
+ var cancelPendingNavigation;
3895
+ function openSettingsSection(labels, onSelected, onMissing) {
3896
+ if (typeof document === "undefined" || typeof window === "undefined") {
3897
+ onMissing?.();
3898
+ return;
3899
+ }
3900
+ const launchers = [...document.querySelectorAll('button[aria-haspopup="dialog"]')];
3901
+ const launcher = pickSettingsLauncher(launchers);
3902
+ const dialogOpen = document.querySelector('[role="dialog"]') !== null;
3903
+ if (!dialogOpen && launcher === void 0) {
3904
+ onMissing?.();
3905
+ return;
3906
+ }
3907
+ cancelPendingNavigation?.();
3908
+ if (!dialogOpen) launcher?.click();
3909
+ let frame;
3910
+ let finished = false;
3911
+ const observer = new MutationObserver(() => {
3912
+ schedule();
3913
+ });
3914
+ const cleanup = () => {
3915
+ if (finished) return;
3916
+ finished = true;
3917
+ observer.disconnect();
3918
+ window.clearTimeout(timeout);
3919
+ if (frame !== void 0) window.cancelAnimationFrame(frame);
3920
+ if (cancelPendingNavigation === cleanup) cancelPendingNavigation = void 0;
3921
+ };
3922
+ const select = () => {
3923
+ const buttons = [...document.querySelectorAll('[role="dialog"] nav button')];
3924
+ const target = pickSettingsSectionButton(buttons, labels);
3925
+ if (target === void 0) return false;
3926
+ cleanup();
3927
+ target.click();
3928
+ onSelected?.();
3929
+ return true;
3930
+ };
3931
+ const schedule = () => {
3932
+ if (finished || frame !== void 0) return;
3933
+ frame = window.requestAnimationFrame(() => {
3934
+ frame = void 0;
3935
+ select();
3936
+ });
3937
+ };
3938
+ const timeout = window.setTimeout(() => {
3939
+ if (select()) return;
3940
+ cleanup();
3941
+ onMissing?.();
3942
+ }, 1500);
3943
+ observer.observe(document.body, { childList: true, subtree: true });
3944
+ cancelPendingNavigation = cleanup;
3945
+ schedule();
3946
+ }
3947
+
3265
3948
  // src/client/index.ts
3266
3949
  var name = "dsh-automation-client";
3267
3950
  var inject = ["slots", "locale", "connection", "sessions"];
3268
3951
  var SETTINGS_CLOCK_SVG = '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" aria-hidden="true" data-dsh-schedule-icon="1"><path fill="currentColor" d="M8 1.15A6.85 6.85 0 1 0 8 14.85 6.85 6.85 0 0 0 8 1.15Zm0 1.4a5.45 5.45 0 1 1 0 10.9 5.45 5.45 0 0 1 0-10.9Z"/><path fill="currentColor" d="M8.62 4.35H7.28v4.2l3.02 1.78.67-1.13-2.35-1.39V4.35Z"/></svg>';
3952
+ function isSessionSelector(value) {
3953
+ return typeof value === "function";
3954
+ }
3955
+ function isWorkspaceSelector(value) {
3956
+ return typeof value === "function";
3957
+ }
3269
3958
  function installSettingsNavIcon(labels) {
3270
3959
  const wanted = new Set(labels().map((item) => item.trim()).filter((item) => item !== ""));
3271
3960
  const applyButton = (button) => {
@@ -3311,7 +4000,7 @@ function apply(ctx) {
3311
4000
  label: () => t("tab"),
3312
4001
  icon: "schedule"
3313
4002
  }, function ScheduledTasksSettings(props) {
3314
- return (0, import_react8.createElement)(AutomationView, { t, permissionT, modelT, runtime, ...props.close === void 0 ? {} : { closeSettings: props.close } });
4003
+ return (0, import_react11.createElement)(AutomationView, { t, permissionT, modelT, runtime, ...props.close === void 0 ? {} : { closeSettings: props.close } });
3315
4004
  }));
3316
4005
  ctx.slots.inject("sidebar.schedule", () => ctx.slots.register({
3317
4006
  name: "sidebar.schedule",
@@ -3320,10 +4009,12 @@ function apply(ctx) {
3320
4009
  locale: NS,
3321
4010
  label: () => t("sidebar.tab")
3322
4011
  }, function AutomationScheduleRail(props) {
3323
- return (0, import_react8.createElement)(ScheduleRail, {
4012
+ return (0, import_react11.createElement)(ScheduleRail, {
3324
4013
  t,
3325
4014
  runtime,
3326
- openSession: createScheduledSessionOpener(ctx, runtime, props.openSession)
4015
+ openSession: createScheduledSessionOpener(ctx, runtime, props.openSession),
4016
+ ...props.view === void 0 ? {} : { view: props.view },
4017
+ ...props.showViewSwitch === void 0 ? {} : { showViewSwitch: props.showViewSwitch }
3327
4018
  });
3328
4019
  }));
3329
4020
  ctx.slots.inject("sidebar.workspaces", () => {
@@ -3366,16 +4057,25 @@ function apply(ctx) {
3366
4057
  render: (props) => {
3367
4058
  const hostOpen = typeof props.openSession === "function" ? props.openSession : typeof props.open === "function" ? props.open : openSession;
3368
4059
  const opener = createScheduledSessionOpener(ctx, runtime, hostOpen);
3369
- return (0, import_react8.createElement)(NativeScheduleSessionList, {
4060
+ return (0, import_react11.createElement)(NativeScheduleSessionList, {
3370
4061
  t,
3371
4062
  runtime,
3372
4063
  openSession: opener,
3373
- ...typeof props.useSessions === "function" ? { useSessions: props.useSessions } : {},
3374
- ...typeof props.useWorkspaces === "function" ? { useWorkspaces: props.useWorkspaces } : {},
4064
+ ...isSessionSelector(props.useSessions) ? { useSessions: props.useSessions } : {},
4065
+ ...isWorkspaceSelector(props.useWorkspaces) ? { useWorkspaces: props.useWorkspaces } : {},
3375
4066
  ...typeof props.renameSession === "function" ? { renameSession: props.renameSession } : {},
3376
4067
  ...typeof props.archiveSession === "function" ? { archiveSession: props.archiveSession } : {},
3377
4068
  ...typeof props.deleteSession === "function" ? { deleteSession: props.deleteSession } : {},
3378
- ...typeof props.forkSession === "function" ? { forkSession: props.forkSession } : {}
4069
+ ...typeof props.forkSession === "function" ? { forkSession: props.forkSession } : {},
4070
+ openTaskSettings: (request) => {
4071
+ requestAutomationTaskSettings(request);
4072
+ openSettingsSection(
4073
+ [t("tab"), "Scheduled tasks", "\u5B9A\u65F6\u4EFB\u52A1"],
4074
+ () => {
4075
+ requestAutomationTaskSettings(request);
4076
+ }
4077
+ );
4078
+ }
3379
4079
  });
3380
4080
  }
3381
4081
  });
@@ -3407,7 +4107,7 @@ function apply(ctx) {
3407
4107
  try {
3408
4108
  let AutomationNativeWorkspaceShell2 = function(innerProps) {
3409
4109
  const openSession = createScheduledSessionOpener(ctx, runtime, innerProps.openSession ?? innerProps.open);
3410
- return (0, import_react8.createElement)(NativeScheduleShell, {
4110
+ return (0, import_react11.createElement)(NativeScheduleShell, {
3411
4111
  t,
3412
4112
  runtime,
3413
4113
  hostProps: innerProps,
@@ -3493,7 +4193,7 @@ function createScheduledSessionOpener(ctx, runtime, hostOpen) {
3493
4193
  };
3494
4194
  }
3495
4195
  function PrefillBridge(props) {
3496
- (0, import_react8.useEffect)(() => {
4196
+ (0, import_react11.useEffect)(() => {
3497
4197
  const applyPrefill = (text) => {
3498
4198
  if (text === null || text === "") return;
3499
4199
  if (props.inputActions !== void 0) {