@linxin666/dsh-client-ui-task-board 0.3.22 → 0.3.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +2 -0
- package/README.zh.md +2 -0
- package/lib/client.js +726 -71
- package/lib/client.js.map +1 -1
- package/lib/index.js +2619 -175
- package/lib/types/client/board/EditTaskModal.d.ts +6 -0
- package/lib/types/client/board/NewTaskModal.d.ts +6 -1
- package/lib/types/client/board/TaskBoard.d.ts +2 -0
- package/lib/types/client/board/TaskForm.d.ts +8 -3
- package/lib/types/client/board/parse-model-pref.d.ts +4 -0
- package/lib/types/client/host-api.d.ts +23 -1
- package/lib/types/client/locales.d.ts +26 -0
- package/lib/types/client/plugin-card-seat.d.ts +96 -0
- package/lib/types/client/sidebar-entry-core.d.ts +32 -0
- package/lib/types/core/controller.d.ts +35 -1
- package/lib/types/core/session-reuse.d.ts +4 -2
- package/lib/types/host-ai.d.ts +51 -0
- package/lib/types/host-ledger.d.ts +15 -0
- package/lib/types/host-routes.d.ts +11 -1
- package/lib/types/index.d.ts +9 -0
- package/lib/types/protocol.d.ts +19 -0
- package/package.json +2 -1
- package/src/client/board/EditTaskModal.tsx +36 -0
- package/src/client/board/NewTaskModal.tsx +119 -5
- package/src/client/board/TaskBoard.tsx +89 -0
- package/src/client/board/TaskDetail.tsx +38 -2
- package/src/client/board/TaskForm.tsx +17 -11
- package/src/client/board/parse-model-pref.ts +35 -0
- package/src/client/board.module.css +61 -0
- package/src/client/host-api.ts +124 -5
- package/src/client/index.ts +18 -17
- package/src/client/locales.ts +52 -0
- package/src/client/plugin-card-seat.ts +185 -0
- package/src/client/sidebar-entry-core.ts +96 -12
- package/src/core/controller.ts +57 -1
- package/src/core/session-reuse.ts +14 -5
- package/src/host-ai.ts +152 -0
- package/src/host-ledger.ts +84 -14
- package/src/host-routes.ts +68 -3
- package/src/index.ts +26 -1
- package/src/protocol.ts +34 -0
package/lib/client.js
CHANGED
|
@@ -644,6 +644,7 @@ window.__ModuleLoader__.load({
|
|
|
644
644
|
presets: [],
|
|
645
645
|
models: []
|
|
646
646
|
};
|
|
647
|
+
workspaceCreator;
|
|
647
648
|
listeners = /* @__PURE__ */ new Set();
|
|
648
649
|
disposers = [];
|
|
649
650
|
now;
|
|
@@ -687,6 +688,8 @@ window.__ModuleLoader__.load({
|
|
|
687
688
|
selectedTaskId: this.selectedTaskId,
|
|
688
689
|
executionOptions: this.executionOptions,
|
|
689
690
|
pendingTaskIds: [...this.pendingTaskIds],
|
|
691
|
+
...this.workspaceCreator === void 0 ? {} : { canCreateWorkspace: true },
|
|
692
|
+
...typeof this.deps.transport?.parseDraft === "function" ? { canParseTask: true } : {},
|
|
690
693
|
...this.transportError === void 0 ? {} : { transportError: this.transportError },
|
|
691
694
|
...this.hostState === void 0 ? {} : { host: this.hostState }
|
|
692
695
|
};
|
|
@@ -789,6 +792,33 @@ window.__ModuleLoader__.load({
|
|
|
789
792
|
};
|
|
790
793
|
this.notify();
|
|
791
794
|
}
|
|
795
|
+
/** Wire (or clear) the runtime's project registration face (issue #1536). */
|
|
796
|
+
setWorkspaceCreator(creator) {
|
|
797
|
+
this.workspaceCreator = creator;
|
|
798
|
+
this.notify();
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Register an existing host directory as a DSH project, exactly as the GUI's
|
|
802
|
+
* own "add project" does; the runtime's failure message surfaces unchanged.
|
|
803
|
+
*/
|
|
804
|
+
async createWorkspace(path) {
|
|
805
|
+
if (this.workspaceCreator === void 0) throw new Error("workspace creation is unavailable");
|
|
806
|
+
return await this.workspaceCreator(path);
|
|
807
|
+
}
|
|
808
|
+
/** Whether this deployment can parse pasted text into task fields (issue #1540). */
|
|
809
|
+
canParseTask() {
|
|
810
|
+
return typeof this.deps.transport?.parseDraft === "function";
|
|
811
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* Parse pasted text into task fields through the Host. The transport already
|
|
814
|
+
* phrases every failure for the user, so its message surfaces unchanged.
|
|
815
|
+
*/
|
|
816
|
+
async parseTaskDraft(request, signal) {
|
|
817
|
+
const transport = this.deps.transport;
|
|
818
|
+
const parse = transport?.parseDraft;
|
|
819
|
+
if (transport === void 0 || parse === void 0) throw new Error("task parsing is unavailable");
|
|
820
|
+
return await parse.call(transport, request, signal);
|
|
821
|
+
}
|
|
792
822
|
moveTask(id, status) {
|
|
793
823
|
if (this.deps.transport !== void 0) {
|
|
794
824
|
this.commitRemote({
|
|
@@ -1573,6 +1603,30 @@ window.__ModuleLoader__.load({
|
|
|
1573
1603
|
"board.updated": "更新于",
|
|
1574
1604
|
"board.created": "创建于",
|
|
1575
1605
|
"board.hostError": "Host 操作失败:{error}",
|
|
1606
|
+
"board.hostError.notMounted": "任务看板的后台接口没有挂载:宿主可能没有加载该插件,也可能后台数据正被另一个 DSH 实例占用。重启 DSH 服务后再试",
|
|
1607
|
+
"board.hostError.unauthorized": "登录状态已失效,请刷新页面后重试",
|
|
1608
|
+
"board.hostError.locked": "任务看板的后台数据被占用:{detail}",
|
|
1609
|
+
"board.hostError.timeout": "后台 {seconds} 秒内没有响应,请稍后重试",
|
|
1610
|
+
"board.hostError.unreachable": "连接不上本机 DSH 服务,请确认它仍在运行",
|
|
1611
|
+
"board.hostError.unexpected": "后台返回了无法识别的响应(HTTP {status})",
|
|
1612
|
+
"board.project": "项目",
|
|
1613
|
+
"board.projectAll": "全部项目",
|
|
1614
|
+
"board.projectNew": "新建项目…",
|
|
1615
|
+
"board.projectNewPath": "项目目录(宿主上的绝对路径)",
|
|
1616
|
+
"board.projectNewPathPlaceholder": "例如 C:\\work\\my-project 或 /home/me/project",
|
|
1617
|
+
"board.projectCreate": "创建项目",
|
|
1618
|
+
"board.projectCreateFailed": "创建项目失败:{error}",
|
|
1619
|
+
"new.aiParse": "AI 解析",
|
|
1620
|
+
"new.aiParseHint": "把从别处复制的一段话粘进来,让模型整理成标题、描述和执行 Prompt;解析结果只填进下面的表单,你可以先改再创建。",
|
|
1621
|
+
"new.aiParsePlaceholder": "粘贴要变成任务的内容…",
|
|
1622
|
+
"new.aiParseModel": "解析用模型",
|
|
1623
|
+
"new.aiParseRun": "解析并填入",
|
|
1624
|
+
"new.aiParseCancel": "取消解析",
|
|
1625
|
+
"new.aiParseEmpty": "先粘贴一段内容再解析",
|
|
1626
|
+
"new.aiParseNoModel": "这个部署还没有可用的模型,请先在 DSH 里配置模型提供商,或换一个模型再试",
|
|
1627
|
+
"new.aiParseUnavailable": "后台没有解析接口可用,重启 DSH 服务后再试",
|
|
1628
|
+
"new.aiParseTimeout": "模型 {seconds} 秒内没有返回结果,请重试或换一个更快的模型",
|
|
1629
|
+
"new.aiParseFailed": "解析失败:{error}",
|
|
1576
1630
|
"board.retryHost": "重试连接 Host",
|
|
1577
1631
|
"board.hostMeta": "Host 时区 {timeZone} · revision {revision}",
|
|
1578
1632
|
"new.title": "标题",
|
|
@@ -1582,6 +1636,7 @@ window.__ModuleLoader__.load({
|
|
|
1582
1636
|
"new.prompt": "执行 Prompt",
|
|
1583
1637
|
"new.promptPlaceholder": "发给 agent 的完整指令(留空则使用标题)",
|
|
1584
1638
|
"new.submit": "创建",
|
|
1639
|
+
"new.createAndRun": "创建并执行",
|
|
1585
1640
|
"new.cancel": "取消",
|
|
1586
1641
|
"new.required": "标题不能为空",
|
|
1587
1642
|
"new.freeze": "冻结快照(可选)",
|
|
@@ -1615,6 +1670,7 @@ window.__ModuleLoader__.load({
|
|
|
1615
1670
|
"detail.permissionConfirmed": "已确认权限绑定 · {time}",
|
|
1616
1671
|
"detail.title": "任务详情",
|
|
1617
1672
|
"detail.edit": "编辑",
|
|
1673
|
+
"detail.editTags": "编辑标签",
|
|
1618
1674
|
"detail.duplicate": "复制为新任务",
|
|
1619
1675
|
"detail.duplicateAndEdit": "修改并新建副本",
|
|
1620
1676
|
"detail.close": "关闭",
|
|
@@ -1736,6 +1792,30 @@ window.__ModuleLoader__.load({
|
|
|
1736
1792
|
"board.updated": "Updated",
|
|
1737
1793
|
"board.created": "Created",
|
|
1738
1794
|
"board.hostError": "Host action failed: {error}",
|
|
1795
|
+
"board.hostError.notMounted": "The task board Host API is not mounted: the Host may not have loaded the plugin, or another DSH instance holds the ledger. Restart the DSH service and try again",
|
|
1796
|
+
"board.hostError.unauthorized": "This session is no longer signed in; reload the page and try again",
|
|
1797
|
+
"board.hostError.locked": "The task board ledger is locked: {detail}",
|
|
1798
|
+
"board.hostError.timeout": "The Host did not answer within {seconds}s; try again shortly",
|
|
1799
|
+
"board.hostError.unreachable": "Cannot reach the local DSH service; make sure it is still running",
|
|
1800
|
+
"board.hostError.unexpected": "The Host returned an unrecognized response (HTTP {status})",
|
|
1801
|
+
"board.project": "Project",
|
|
1802
|
+
"board.projectAll": "All projects",
|
|
1803
|
+
"board.projectNew": "New project…",
|
|
1804
|
+
"board.projectNewPath": "Project directory (absolute path on the Host)",
|
|
1805
|
+
"board.projectNewPathPlaceholder": "e.g. C:\\work\\my-project or /home/me/project",
|
|
1806
|
+
"board.projectCreate": "Create project",
|
|
1807
|
+
"board.projectCreateFailed": "Could not create the project: {error}",
|
|
1808
|
+
"new.aiParse": "Parse with AI",
|
|
1809
|
+
"new.aiParseHint": "Paste text copied from somewhere else and let a model turn it into a title, description, and run prompt; the result only fills the form below, so you can edit it before creating the task.",
|
|
1810
|
+
"new.aiParsePlaceholder": "Paste the content to turn into a task…",
|
|
1811
|
+
"new.aiParseModel": "Model used for parsing",
|
|
1812
|
+
"new.aiParseRun": "Parse and fill",
|
|
1813
|
+
"new.aiParseCancel": "Cancel parsing",
|
|
1814
|
+
"new.aiParseEmpty": "Paste something to parse first",
|
|
1815
|
+
"new.aiParseNoModel": "This deployment has no model available; configure a model provider in DSH or pick another model",
|
|
1816
|
+
"new.aiParseUnavailable": "The Host has no parse endpoint; restart the DSH service and try again",
|
|
1817
|
+
"new.aiParseTimeout": "The model did not answer within {seconds}s; try again or pick a faster model",
|
|
1818
|
+
"new.aiParseFailed": "Parsing failed: {error}",
|
|
1739
1819
|
"board.retryHost": "Retry Host connection",
|
|
1740
1820
|
"board.hostMeta": "Host time zone {timeZone} · revision {revision}",
|
|
1741
1821
|
"new.title": "Title",
|
|
@@ -1745,6 +1825,7 @@ window.__ModuleLoader__.load({
|
|
|
1745
1825
|
"new.prompt": "Run Prompt",
|
|
1746
1826
|
"new.promptPlaceholder": "The full instruction sent to the agent (title is used when blank)",
|
|
1747
1827
|
"new.submit": "Create",
|
|
1828
|
+
"new.createAndRun": "Create and run",
|
|
1748
1829
|
"new.cancel": "Cancel",
|
|
1749
1830
|
"new.required": "Title is required",
|
|
1750
1831
|
"new.freeze": "Frozen snapshot (optional)",
|
|
@@ -1778,6 +1859,7 @@ window.__ModuleLoader__.load({
|
|
|
1778
1859
|
"detail.permissionConfirmed": "Permission confirmed · {time}",
|
|
1779
1860
|
"detail.title": "Task Detail",
|
|
1780
1861
|
"detail.edit": "Edit",
|
|
1862
|
+
"detail.editTags": "Edit tags",
|
|
1781
1863
|
"detail.duplicate": "Duplicate Task",
|
|
1782
1864
|
"detail.duplicateAndEdit": "Edit as New Copy",
|
|
1783
1865
|
"detail.close": "Close",
|
|
@@ -1900,7 +1982,7 @@ window.__ModuleLoader__.load({
|
|
|
1900
1982
|
}
|
|
1901
1983
|
//#endregion
|
|
1902
1984
|
//#region \0dsh-css:packages/dsh-task-board/src/client/board.module.css.mjs
|
|
1903
|
-
const css$1 = "[data-pane=conversation],[class*=centerCol]{position:relative}[data-dsh-taskboard-view]{z-index:60;background:var(--dsw-alias-bg-base);display:none;position:absolute;inset:0;container:_7D6uKa_task-board-view/inline-size}html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [data-dsh-taskboard-view]{display:block}html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [data-pane=conversation]>:not([data-dsh-taskboard-view]),html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [class*=centerCol]>:not([data-dsh-taskboard-view]){display:none!important}._7D6uKa_entry{box-sizing:border-box;width:100%;height:36px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:8px;align-items:center;gap:8px;padding:0 10px;font-size:13px;display:flex}._7D6uKa_entry:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_entry[data-active]{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary);font-weight:600}._7D6uKa_entryIcon{flex:none;justify-content:center;align-items:center;width:24px;height:24px;display:inline-flex}._7D6uKa_entryIcon svg{width:18px;height:18px;display:block}._7D6uKa_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entry,[data-sidebar-collapsed] ._7D6uKa_entry{border-radius:50%;justify-content:center;width:36px;height:36px;margin:0 auto 12px;padding:0}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entryLabel,[data-sidebar-collapsed] ._7D6uKa_entryLabel{display:none}._7D6uKa_board{box-sizing:border-box;background:var(--dsw-alias-bg-base);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:12px;padding:14px 16px 16px;display:flex}._7D6uKa_boardHeader{flex:none;align-items:center;gap:10px;display:flex}._7D6uKa_boardTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;margin:0;font-size:16px;font-weight:700}._7D6uKa_backButton{align-items:center;gap:4px;display:inline-flex}._7D6uKa_search{min-width:120px;color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:0 260px;padding:6px 10px;font-size:13px}._7D6uKa_search::placeholder{color:var(--dsw-alias-label-tertiary)}._7D6uKa_columns{overscroll-behavior-inline:contain;scrollbar-color:var(--dsw-alias-border-l3) var(--dsw-alias-interactive-bg-hover);scrollbar-width:thin;flex:1;grid-auto-columns:minmax(220px,1fr);grid-auto-flow:column;gap:12px;min-height:0;padding-bottom:6px;display:grid;overflow:auto hidden}._7D6uKa_columns::-webkit-scrollbar{height:10px}._7D6uKa_columns::-webkit-scrollbar-track{background:var(--dsw-alias-interactive-bg-hover);border-radius:999px}._7D6uKa_columns::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3);background-clip:content-box;border:2px solid #0000;border-radius:999px}._7D6uKa_columns::-webkit-scrollbar-thumb:hover{background:var(--dsw-alias-border-l4);background-clip:content-box}._7D6uKa_column{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;min-height:0;display:flex;overflow:hidden}._7D6uKa_columnHeader{flex:none;align-items:center;gap:6px;padding:10px 12px;display:flex}._7D6uKa_columnTitle{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:13px;font-weight:700;overflow:hidden}._7D6uKa_columnCount{min-width:0;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;flex:none;padding:1px 8px;font-size:12px}._7D6uKa_statusDot{border-radius:50%;flex:none;width:8px;height:8px}._7D6uKa_statusDot[data-status=backlog]{background:var(--dsw-alias-label-tertiary)}._7D6uKa_statusDot[data-status=todo]{background:var(--dsw-alias-state-business-primary)}._7D6uKa_statusDot[data-status=running]{background:var(--dsw-alias-state-warn-primary)}._7D6uKa_statusDot[data-status=done]{background:var(--dsw-alias-state-success-primary)}._7D6uKa_statusDot[data-status=failed]{background:var(--dsw-alias-state-error-primary)}._7D6uKa_cards{flex-direction:column;flex:1;gap:8px;min-height:0;padding:2px 8px 10px;display:flex;overflow-y:auto}._7D6uKa_columnEmpty{text-align:center;color:var(--dsw-alias-label-tertiary);padding:24px 8px;font-size:12px}._7D6uKa_card{text-align:left;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;color:var(--dsw-alias-label-primary);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;font-family:inherit;transition:box-shadow .12s,border-color .12s,transform .12s;display:flex}._7D6uKa_card:hover{box-shadow:var(--dsw-shadow-lv2);border-color:var(--dsw-alias-border-l3);transform:translateY(-1px)}._7D6uKa_card[data-status=running]{border-color:var(--dsw-alias-state-warn-primary)}._7D6uKa_cardTitle{-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:13px;font-weight:600;line-height:1.35;display:-webkit-box;overflow:hidden}._7D6uKa_cardExcerpt{color:var(--dsw-alias-label-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;line-height:1.4;display:-webkit-box;overflow:hidden}._7D6uKa_cardMeta{color:var(--dsw-alias-label-tertiary);align-items:center;gap:8px;font-size:11px;display:flex}._7D6uKa_cardTime{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}._7D6uKa_cardSchedule{white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;flex:none;padding:2px 6px;font-size:12px;line-height:1}._7D6uKa_cardRun{flex:none}._7D6uKa_cardRun[data-result=failed]{color:var(--dsw-alias-state-error-primary)}._7D6uKa_cardRun[data-result=succeeded]{color:var(--dsw-alias-state-success-primary)}._7D6uKa_cardSession{color:var(--dsw-alias-state-business-primary);flex:none}._7D6uKa_cardRunningLabel{color:var(--dsw-alias-state-warn-primary);font-size:11px}._7D6uKa_cardSpinner{border:2px solid var(--dsw-alias-state-warn-primary);border-top-color:#0000;border-radius:50%;flex:none;width:10px;height:10px;animation:.8s linear infinite _7D6uKa_dshTbSpin}@keyframes _7D6uKa_dshTbSpin{to{transform:rotate(360deg)}}._7D6uKa_primaryButton{color:var(--dsw-alias-label-primary-foreground);background:var(--dsw-alias-button-info-fill);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600}._7D6uKa_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-info-hover)}._7D6uKa_primaryButton:disabled{opacity:.5;cursor:default}._7D6uKa_ghostButton{color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;white-space:nowrap;background:0 0;border-radius:8px;padding:5px 12px;font-size:12px}._7D6uKa_ghostButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}._7D6uKa_ghostButton:disabled{opacity:.45;cursor:default}._7D6uKa_dangerButton{color:#fff;background:var(--dsw-alias-state-error-primary);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600}._7D6uKa_dangerButton:hover:not(:disabled){filter:brightness(1.08)}._7D6uKa_dangerButton:active:not(:disabled){filter:brightness(.94)}._7D6uKa_dangerButton:disabled{opacity:.5;cursor:default}._7D6uKa_iconButton{width:26px;height:26px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0;font-size:13px;display:inline-flex}._7D6uKa_iconButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_linkButton{color:var(--dsw-alias-state-business-primary);cursor:pointer;white-space:nowrap;background:0 0;border:none;padding:0;font-size:12px}._7D6uKa_linkButton:hover{text-decoration:underline}._7D6uKa_modalBackdrop{z-index:1300;background:var(--dsw-alias-bg-mask-1);justify-content:center;align-items:center;display:flex;position:fixed;inset:0}._7D6uKa_modal{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);width:min(520px,100vw - 48px);max-height:calc(100vh - 96px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;gap:12px;padding:18px;display:flex;overflow-y:auto}._7D6uKa_modalTitle{margin:0;font-size:15px;font-weight:700}._7D6uKa_confirmMessage{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:13px;line-height:1.5}._7D6uKa_modalFooter{justify-content:flex-end;gap:10px;margin-top:4px;display:flex}._7D6uKa_field{flex-direction:column;gap:5px;display:flex}._7D6uKa_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}._7D6uKa_input{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);resize:vertical;border-radius:8px;outline:none;padding:7px 10px;font-family:inherit;font-size:13px}._7D6uKa_input:focus{border-color:var(--dsw-alias-state-business-primary)}._7D6uKa_select{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;max-width:100%;padding:7px 10px;font-family:inherit;font-size:13px}._7D6uKa_input::placeholder{color:var(--dsw-alias-label-tertiary)}._7D6uKa_formError{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px}._7D6uKa_detail{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);width:min(640px,100vw - 48px);max-height:calc(100vh - 80px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;display:flex;overflow:hidden}._7D6uKa_detailHeader{border-bottom:1px solid var(--dsw-alias-separator-primary);flex:none;align-items:center;gap:10px;padding:14px 18px;display:flex}._7D6uKa_detailTitle{overflow-wrap:anywhere;flex:1;margin:0;font-size:15px;font-weight:700}._7D6uKa_statusBadge{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:2px 10px;font-size:12px}._7D6uKa_statusBadge[data-status=running]{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}._7D6uKa_statusBadge[data-status=done]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}._7D6uKa_statusBadge[data-status=failed]{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}._7D6uKa_detailBody{flex-direction:column;flex:1;gap:16px;padding:14px 18px;display:flex;overflow-y:auto}._7D6uKa_detailSection{flex-direction:column;gap:6px;display:flex}._7D6uKa_detailSection h4{color:var(--dsw-alias-label-tertiary);text-transform:none;margin:0;font-size:12px;font-weight:700}._7D6uKa_detailText{color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:13px;line-height:1.55}._7D6uKa_scheduleToggle{color:var(--dsw-alias-label-primary);cursor:pointer;user-select:none;align-items:center;gap:8px;font-size:13px;display:flex}._7D6uKa_scheduleToggle input{accent-color:var(--dsw-alias-state-business-primary)}._7D6uKa_scheduleRow{align-items:center;gap:8px;display:flex}._7D6uKa_scheduleInput{min-width:0;font-family:var(--dsw-font-markdown-code-block-small);flex:1;font-size:12.5px}._7D6uKa_scheduleInputInvalid,._7D6uKa_scheduleInputInvalid:focus{border-color:var(--dsw-alias-state-error-primary)}._7D6uKa_schedulePreset{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:none;padding:7px 8px;font-size:12.5px}._7D6uKa_scheduleMeta{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font-size:12px}._7D6uKa_promptBlock{font-size:12.5px;line-height:1.5;font-family:var(--dsw-font-markdown-code-block-small);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-markdown-code-block);border:1px solid var(--dsw-alias-border-l1);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;max-height:240px;margin:0;padding:10px 12px;overflow-y:auto}._7D6uKa_executionList{flex-direction:column;gap:8px;margin:0;padding:0;list-style:none;display:flex}._7D6uKa_executionRow{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-wrap:wrap;align-items:center;gap:10px;padding:8px 10px;display:flex}._7D6uKa_executionBadge{color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-state-warn-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:600}._7D6uKa_executionBadge[data-result=succeeded]{color:var(--dsw-alias-state-success-primary);background:0 0}._7D6uKa_executionBadge[data-result=failed]{color:var(--dsw-alias-state-error-primary);background:0 0}._7D6uKa_executionBadge[data-result=cancelled]{color:var(--dsw-alias-label-tertiary);background:0 0}._7D6uKa_executionTimes{color:var(--dsw-alias-label-secondary);font-size:12px}._7D6uKa_executionError{width:100%;color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;font-size:12px}._7D6uKa_moveRow{flex-wrap:wrap;gap:8px;display:flex}._7D6uKa_detailFooter{border-top:1px solid var(--dsw-alias-separator-primary);flex:none;align-items:center;gap:10px;padding:12px 18px;display:flex}._7D6uKa_detailMeta{color:var(--dsw-alias-label-tertiary);margin-left:auto;font-size:11px}@container _7D6uKa_task-board-view (width<=768px){._7D6uKa_board{gap:10px;padding:10px}._7D6uKa_boardHeader{flex-wrap:wrap;align-items:center;gap:8px}._7D6uKa_backButton{flex:none;order:1}._7D6uKa_boardTitle{flex:auto;order:2}._7D6uKa_boardHeader>._7D6uKa_detailMeta{flex:1 0 100%;order:3;margin-left:0}._7D6uKa_search{flex:1 0 100%;order:4;min-width:0}._7D6uKa_boardHeader>button:not(._7D6uKa_backButton){flex:1 1 0;order:5;min-width:0}._7D6uKa_columns{scroll-snap-type:inline mandatory;scrollbar-width:none;-webkit-overflow-scrolling:touch;grid-auto-columns:86cqw;gap:10px;padding-inline:2px 14cqw;scroll-padding-inline:2px}._7D6uKa_columns::-webkit-scrollbar{display:none}._7D6uKa_column{scroll-snap-align:start;scroll-snap-stop:always}}@container _7D6uKa_task-board-view (width<=720px){._7D6uKa_boardHeader>._7D6uKa_detailMeta{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}}@container _7D6uKa_task-board-view (width<=600px){._7D6uKa_board{padding-inline:8px}}@media (width<=768px){[data-dsh-taskboard-view]{height:100dvh}._7D6uKa_entry,._7D6uKa_card,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle{min-height:44px}._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset{box-sizing:border-box;font-size:16px}._7D6uKa_modalBackdrop{justify-content:stretch;align-items:stretch;width:100vw;height:100dvh}._7D6uKa_modal,._7D6uKa_detail{box-sizing:border-box;border:0;border-radius:0;width:100vw;height:100dvh;max-height:none}._7D6uKa_modal{padding-top:max(16px, env(safe-area-inset-top));padding-right:max(16px, env(safe-area-inset-right));padding-bottom:max(16px, env(safe-area-inset-bottom));padding-left:max(16px, env(safe-area-inset-left))}._7D6uKa_modalFooter{z-index:1;background:var(--dsw-alias-bg-base);flex-wrap:wrap;padding-top:8px;position:sticky;bottom:0}._7D6uKa_modalFooter>button{flex:120px}._7D6uKa_detailHeader{padding-top:max(12px, env(safe-area-inset-top));padding-right:max(14px, env(safe-area-inset-right));padding-left:max(14px, env(safe-area-inset-left));flex-wrap:wrap}._7D6uKa_detailTitle{min-width:0}._7D6uKa_detailBody{overscroll-behavior-y:contain;padding-right:max(14px, env(safe-area-inset-right));padding-left:max(14px, env(safe-area-inset-left))}._7D6uKa_detailFooter{padding-right:max(14px, env(safe-area-inset-right));padding-bottom:max(12px, env(safe-area-inset-bottom));padding-left:max(14px, env(safe-area-inset-left));flex-wrap:wrap}._7D6uKa_detailFooter>button{flex:96px}._7D6uKa_detailFooter>._7D6uKa_detailMeta{text-align:end;flex:1 0 100%;margin-left:0}._7D6uKa_scheduleRow{flex-direction:column;align-items:stretch}._7D6uKa_schedulePreset{width:100%}}._7D6uKa_entry:focus-visible,._7D6uKa_card:focus-visible,._7D6uKa_primaryButton:focus-visible,._7D6uKa_ghostButton:focus-visible,._7D6uKa_dangerButton:focus-visible,._7D6uKa_iconButton:focus-visible,._7D6uKa_linkButton:focus-visible,._7D6uKa_search:focus-visible,._7D6uKa_input:focus-visible,._7D6uKa_select:focus-visible,._7D6uKa_schedulePreset:focus-visible,._7D6uKa_scheduleToggle input:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}._7D6uKa_entry,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle input{transition:background-color .12s,color .12s,border-color .12s,outline-color .12s,box-shadow .12s,transform .12s}._7D6uKa_card:active{box-shadow:var(--dsw-shadow-lv1);transform:translateY(0)}._7D6uKa_entry:active,._7D6uKa_primaryButton:active:not(:disabled),._7D6uKa_ghostButton:active:not(:disabled),._7D6uKa_dangerButton:active:not(:disabled),._7D6uKa_iconButton:active:not(:disabled),._7D6uKa_linkButton:active:not(:disabled){transform:translateY(1px)}._7D6uKa_entry[data-active]:hover{background:var(--dsw-specific-sidebar-nav-item-active)}._7D6uKa_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_linkButton:hover:not(:disabled){text-decoration:underline}._7D6uKa_iconButton:disabled,._7D6uKa_linkButton:disabled{opacity:.45;cursor:default}._7D6uKa_search:focus,._7D6uKa_select:focus,._7D6uKa_schedulePreset:focus{border-color:var(--dsw-alias-state-business-primary)}._7D6uKa_scheduleToggle input{margin:0}@media (prefers-reduced-motion:reduce){._7D6uKa_entry,._7D6uKa_card,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle input{transition:none}._7D6uKa_cardSpinner{animation:none}}._7D6uKa_cardTags{flex-wrap:wrap;gap:4px;display:flex}._7D6uKa_cardTag{border:1px solid var(--dsh-task-tag-border);background:var(--dsh-task-tag-fill);max-width:100%;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;border-radius:999px;padding:0 7px;font-size:10px;line-height:16px;overflow:hidden}._7D6uKa_tagFilter{flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 10px;display:flex}._7D6uKa_tagFilterLabel{color:var(--dsw-alias-label-tertiary);font-size:11px}._7D6uKa_tagChip{border:1px solid var(--dsh-task-tag-border);color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border-radius:999px;padding:1px 9px;font-family:inherit;font-size:11px;line-height:18px}._7D6uKa_tagChip[data-active=true]{background:var(--dsh-task-tag-fill);color:var(--dsw-alias-label-primary)}._7D6uKa_cardTag[data-tag-tone=\"0\"],._7D6uKa_tagChip[data-tag-tone=\"0\"]{--dsh-task-tag-fill:#4e93e82e;--dsh-task-tag-border:#4e93e866}._7D6uKa_cardTag[data-tag-tone=\"1\"],._7D6uKa_tagChip[data-tag-tone=\"1\"]{--dsh-task-tag-fill:#2ea36a2e;--dsh-task-tag-border:#2ea36a66}._7D6uKa_cardTag[data-tag-tone=\"2\"],._7D6uKa_tagChip[data-tag-tone=\"2\"]{--dsh-task-tag-fill:#d08a2a2e;--dsh-task-tag-border:#d08a2a66}._7D6uKa_cardTag[data-tag-tone=\"3\"],._7D6uKa_tagChip[data-tag-tone=\"3\"]{--dsh-task-tag-fill:#b456c82e;--dsh-task-tag-border:#b456c866}._7D6uKa_cardTag[data-tag-tone=\"4\"],._7D6uKa_tagChip[data-tag-tone=\"4\"]{--dsh-task-tag-fill:#cf5f7a2e;--dsh-task-tag-border:#cf5f7a66}._7D6uKa_cardTag[data-tag-tone=\"5\"],._7D6uKa_tagChip[data-tag-tone=\"5\"]{--dsh-task-tag-fill:#4a9fb52e;--dsh-task-tag-border:#4a9fb566}._7D6uKa_fieldHint{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.4}._7D6uKa_tagRow{align-items:center;gap:6px;display:flex}._7D6uKa_tagRow ._7D6uKa_input{flex:1 1 0;min-width:0}._7D6uKa_tagRow ._7D6uKa_ghostButton{flex:none}._7D6uKa_tagAddButton{align-self:flex-start}";
|
|
1985
|
+
const css$1 = "[data-pane=conversation],[class*=centerCol]{position:relative}[data-dsh-taskboard-view]{z-index:60;background:var(--dsw-alias-bg-base);display:none;position:absolute;inset:0;container:_7D6uKa_task-board-view/inline-size}html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [data-dsh-taskboard-view]{display:block}html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [data-pane=conversation]>:not([data-dsh-taskboard-view]),html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [class*=centerCol]>:not([data-dsh-taskboard-view]){display:none!important}._7D6uKa_entry{box-sizing:border-box;width:100%;height:36px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:8px;align-items:center;gap:8px;padding:0 10px;font-size:13px;display:flex}._7D6uKa_entry:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_entry[data-active]{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary);font-weight:600}._7D6uKa_entryIcon{flex:none;justify-content:center;align-items:center;width:24px;height:24px;display:inline-flex}._7D6uKa_entryIcon svg{width:18px;height:18px;display:block}._7D6uKa_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entry,[data-sidebar-collapsed] ._7D6uKa_entry{border-radius:50%;justify-content:center;width:36px;height:36px;margin:0 auto 12px;padding:0}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entryLabel,[data-sidebar-collapsed] ._7D6uKa_entryLabel{display:none}._7D6uKa_board{box-sizing:border-box;background:var(--dsw-alias-bg-base);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:12px;padding:14px 16px 16px;display:flex}._7D6uKa_boardHeader{flex:none;align-items:center;gap:10px;display:flex}._7D6uKa_boardTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;margin:0;font-size:16px;font-weight:700}._7D6uKa_backButton{align-items:center;gap:4px;display:inline-flex}._7D6uKa_search{min-width:120px;color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:0 260px;padding:6px 10px;font-size:13px}._7D6uKa_search::placeholder{color:var(--dsw-alias-label-tertiary)}._7D6uKa_columns{overscroll-behavior-inline:contain;scrollbar-color:var(--dsw-alias-border-l3) var(--dsw-alias-interactive-bg-hover);scrollbar-width:thin;flex:1;grid-auto-columns:minmax(220px,1fr);grid-auto-flow:column;gap:12px;min-height:0;padding-bottom:6px;display:grid;overflow:auto hidden}._7D6uKa_columns::-webkit-scrollbar{height:10px}._7D6uKa_columns::-webkit-scrollbar-track{background:var(--dsw-alias-interactive-bg-hover);border-radius:999px}._7D6uKa_columns::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3);background-clip:content-box;border:2px solid #0000;border-radius:999px}._7D6uKa_columns::-webkit-scrollbar-thumb:hover{background:var(--dsw-alias-border-l4);background-clip:content-box}._7D6uKa_column{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;min-height:0;display:flex;overflow:hidden}._7D6uKa_columnHeader{flex:none;align-items:center;gap:6px;padding:10px 12px;display:flex}._7D6uKa_columnTitle{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:13px;font-weight:700;overflow:hidden}._7D6uKa_columnCount{min-width:0;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;flex:none;padding:1px 8px;font-size:12px}._7D6uKa_statusDot{border-radius:50%;flex:none;width:8px;height:8px}._7D6uKa_statusDot[data-status=backlog]{background:var(--dsw-alias-label-tertiary)}._7D6uKa_statusDot[data-status=todo]{background:var(--dsw-alias-state-business-primary)}._7D6uKa_statusDot[data-status=running]{background:var(--dsw-alias-state-warn-primary)}._7D6uKa_statusDot[data-status=done]{background:var(--dsw-alias-state-success-primary)}._7D6uKa_statusDot[data-status=failed]{background:var(--dsw-alias-state-error-primary)}._7D6uKa_cards{flex-direction:column;flex:1;gap:8px;min-height:0;padding:2px 8px 10px;display:flex;overflow-y:auto}._7D6uKa_columnEmpty{text-align:center;color:var(--dsw-alias-label-tertiary);padding:24px 8px;font-size:12px}._7D6uKa_card{text-align:left;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;color:var(--dsw-alias-label-primary);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;font-family:inherit;transition:box-shadow .12s,border-color .12s,transform .12s;display:flex}._7D6uKa_card:hover{box-shadow:var(--dsw-shadow-lv2);border-color:var(--dsw-alias-border-l3);transform:translateY(-1px)}._7D6uKa_card[data-status=running]{border-color:var(--dsw-alias-state-warn-primary)}._7D6uKa_cardTitle{-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:13px;font-weight:600;line-height:1.35;display:-webkit-box;overflow:hidden}._7D6uKa_cardExcerpt{color:var(--dsw-alias-label-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;line-height:1.4;display:-webkit-box;overflow:hidden}._7D6uKa_cardMeta{color:var(--dsw-alias-label-tertiary);align-items:center;gap:8px;font-size:11px;display:flex}._7D6uKa_cardTime{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}._7D6uKa_cardSchedule{white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;flex:none;padding:2px 6px;font-size:12px;line-height:1}._7D6uKa_cardRun{flex:none}._7D6uKa_cardRun[data-result=failed]{color:var(--dsw-alias-state-error-primary)}._7D6uKa_cardRun[data-result=succeeded]{color:var(--dsw-alias-state-success-primary)}._7D6uKa_cardSession{color:var(--dsw-alias-state-business-primary);flex:none}._7D6uKa_cardRunningLabel{color:var(--dsw-alias-state-warn-primary);font-size:11px}._7D6uKa_cardSpinner{border:2px solid var(--dsw-alias-state-warn-primary);border-top-color:#0000;border-radius:50%;flex:none;width:10px;height:10px;animation:.8s linear infinite _7D6uKa_dshTbSpin}@keyframes _7D6uKa_dshTbSpin{to{transform:rotate(360deg)}}._7D6uKa_primaryButton{color:var(--dsw-alias-label-primary-foreground);background:var(--dsw-alias-button-info-fill);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600}._7D6uKa_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-info-hover)}._7D6uKa_primaryButton:disabled{opacity:.5;cursor:default}._7D6uKa_ghostButton{color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;white-space:nowrap;background:0 0;border-radius:8px;padding:5px 12px;font-size:12px}._7D6uKa_ghostButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}._7D6uKa_ghostButton:disabled{opacity:.45;cursor:default}._7D6uKa_dangerButton{color:#fff;background:var(--dsw-alias-state-error-primary);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600}._7D6uKa_dangerButton:hover:not(:disabled){filter:brightness(1.08)}._7D6uKa_dangerButton:active:not(:disabled){filter:brightness(.94)}._7D6uKa_dangerButton:disabled{opacity:.5;cursor:default}._7D6uKa_iconButton{width:26px;height:26px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0;font-size:13px;display:inline-flex}._7D6uKa_iconButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_linkButton{color:var(--dsw-alias-state-business-primary);cursor:pointer;white-space:nowrap;background:0 0;border:none;padding:0;font-size:12px}._7D6uKa_linkButton:hover{text-decoration:underline}._7D6uKa_modalBackdrop{z-index:1300;background:var(--dsw-alias-bg-mask-1);justify-content:center;align-items:center;display:flex;position:fixed;inset:0}._7D6uKa_modal{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);width:min(520px,100vw - 48px);max-height:calc(100vh - 96px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;gap:12px;padding:18px;display:flex;overflow-y:auto}._7D6uKa_modalTitle{margin:0;font-size:15px;font-weight:700}._7D6uKa_confirmMessage{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:13px;line-height:1.5}._7D6uKa_modalFooter{justify-content:flex-end;gap:10px;margin-top:4px;display:flex}._7D6uKa_field{flex-direction:column;gap:5px;display:flex}._7D6uKa_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}._7D6uKa_input{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);resize:vertical;border-radius:8px;outline:none;padding:7px 10px;font-family:inherit;font-size:13px}._7D6uKa_input:focus{border-color:var(--dsw-alias-state-business-primary)}._7D6uKa_select{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;max-width:100%;padding:7px 10px;font-family:inherit;font-size:13px}._7D6uKa_input::placeholder{color:var(--dsw-alias-label-tertiary)}._7D6uKa_formError{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px}._7D6uKa_detail{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);width:min(640px,100vw - 48px);max-height:calc(100vh - 80px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;display:flex;overflow:hidden}._7D6uKa_detailHeader{border-bottom:1px solid var(--dsw-alias-separator-primary);flex:none;align-items:center;gap:10px;padding:14px 18px;display:flex}._7D6uKa_detailTitle{overflow-wrap:anywhere;flex:1;margin:0;font-size:15px;font-weight:700}._7D6uKa_statusBadge{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:2px 10px;font-size:12px}._7D6uKa_statusBadge[data-status=running]{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}._7D6uKa_statusBadge[data-status=done]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}._7D6uKa_statusBadge[data-status=failed]{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}._7D6uKa_detailBody{flex-direction:column;flex:1;gap:16px;padding:14px 18px;display:flex;overflow-y:auto}._7D6uKa_detailSection{flex-direction:column;gap:6px;display:flex}._7D6uKa_detailSection h4{color:var(--dsw-alias-label-tertiary);text-transform:none;margin:0;font-size:12px;font-weight:700}._7D6uKa_detailText{color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:13px;line-height:1.55}._7D6uKa_scheduleToggle{color:var(--dsw-alias-label-primary);cursor:pointer;user-select:none;align-items:center;gap:8px;font-size:13px;display:flex}._7D6uKa_scheduleToggle input{accent-color:var(--dsw-alias-state-business-primary)}._7D6uKa_scheduleRow{align-items:center;gap:8px;display:flex}._7D6uKa_scheduleInput{min-width:0;font-family:var(--dsw-font-markdown-code-block-small);flex:1;font-size:12.5px}._7D6uKa_scheduleInputInvalid,._7D6uKa_scheduleInputInvalid:focus{border-color:var(--dsw-alias-state-error-primary)}._7D6uKa_schedulePreset{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:none;padding:7px 8px;font-size:12.5px}._7D6uKa_scheduleMeta{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font-size:12px}._7D6uKa_promptBlock{font-size:12.5px;line-height:1.5;font-family:var(--dsw-font-markdown-code-block-small);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-markdown-code-block);border:1px solid var(--dsw-alias-border-l1);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;max-height:240px;margin:0;padding:10px 12px;overflow-y:auto}._7D6uKa_executionList{flex-direction:column;gap:8px;margin:0;padding:0;list-style:none;display:flex}._7D6uKa_executionRow{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-wrap:wrap;align-items:center;gap:10px;padding:8px 10px;display:flex}._7D6uKa_executionBadge{color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-state-warn-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:600}._7D6uKa_executionBadge[data-result=succeeded]{color:var(--dsw-alias-state-success-primary);background:0 0}._7D6uKa_executionBadge[data-result=failed]{color:var(--dsw-alias-state-error-primary);background:0 0}._7D6uKa_executionBadge[data-result=cancelled]{color:var(--dsw-alias-label-tertiary);background:0 0}._7D6uKa_executionTimes{color:var(--dsw-alias-label-secondary);font-size:12px}._7D6uKa_executionError{width:100%;color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;font-size:12px}._7D6uKa_moveRow{flex-wrap:wrap;gap:8px;display:flex}._7D6uKa_detailFooter{border-top:1px solid var(--dsw-alias-separator-primary);flex:none;align-items:center;gap:10px;padding:12px 18px;display:flex}._7D6uKa_detailMeta{color:var(--dsw-alias-label-tertiary);margin-left:auto;font-size:11px}@container _7D6uKa_task-board-view (width<=768px){._7D6uKa_board{gap:10px;padding:10px}._7D6uKa_boardHeader{flex-wrap:wrap;align-items:center;gap:8px}._7D6uKa_backButton{flex:none;order:1}._7D6uKa_boardTitle{flex:auto;order:2}._7D6uKa_boardHeader>._7D6uKa_detailMeta{flex:1 0 100%;order:3;margin-left:0}._7D6uKa_search{flex:1 0 100%;order:4;min-width:0}._7D6uKa_boardHeader>button:not(._7D6uKa_backButton){flex:1 1 0;order:5;min-width:0}._7D6uKa_columns{scroll-snap-type:inline mandatory;scrollbar-width:none;-webkit-overflow-scrolling:touch;grid-auto-columns:86cqw;gap:10px;padding-inline:2px 14cqw;scroll-padding-inline:2px}._7D6uKa_columns::-webkit-scrollbar{display:none}._7D6uKa_column{scroll-snap-align:start;scroll-snap-stop:always}}@container _7D6uKa_task-board-view (width<=720px){._7D6uKa_boardHeader>._7D6uKa_detailMeta{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}}@container _7D6uKa_task-board-view (width<=600px){._7D6uKa_board{padding-inline:8px}}@media (width<=768px){[data-dsh-taskboard-view]{height:100dvh}._7D6uKa_entry,._7D6uKa_card,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle{min-height:44px}._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset{box-sizing:border-box;font-size:16px}._7D6uKa_modalBackdrop{justify-content:stretch;align-items:stretch;width:100vw;height:100dvh}._7D6uKa_modal,._7D6uKa_detail{box-sizing:border-box;border:0;border-radius:0;width:100vw;height:100dvh;max-height:none}._7D6uKa_modal{padding-top:max(16px, env(safe-area-inset-top));padding-right:max(16px, env(safe-area-inset-right));padding-bottom:max(16px, env(safe-area-inset-bottom));padding-left:max(16px, env(safe-area-inset-left))}._7D6uKa_modalFooter{z-index:1;background:var(--dsw-alias-bg-base);flex-wrap:wrap;padding-top:8px;position:sticky;bottom:0}._7D6uKa_modalFooter>button{flex:120px}._7D6uKa_detailHeader{padding-top:max(12px, env(safe-area-inset-top));padding-right:max(14px, env(safe-area-inset-right));padding-left:max(14px, env(safe-area-inset-left));flex-wrap:wrap}._7D6uKa_detailTitle{min-width:0}._7D6uKa_detailBody{overscroll-behavior-y:contain;padding-right:max(14px, env(safe-area-inset-right));padding-left:max(14px, env(safe-area-inset-left))}._7D6uKa_detailFooter{padding-right:max(14px, env(safe-area-inset-right));padding-bottom:max(12px, env(safe-area-inset-bottom));padding-left:max(14px, env(safe-area-inset-left));flex-wrap:wrap}._7D6uKa_detailFooter>button{flex:96px}._7D6uKa_detailFooter>._7D6uKa_detailMeta{text-align:end;flex:1 0 100%;margin-left:0}._7D6uKa_scheduleRow{flex-direction:column;align-items:stretch}._7D6uKa_schedulePreset{width:100%}}._7D6uKa_entry:focus-visible,._7D6uKa_card:focus-visible,._7D6uKa_primaryButton:focus-visible,._7D6uKa_ghostButton:focus-visible,._7D6uKa_dangerButton:focus-visible,._7D6uKa_iconButton:focus-visible,._7D6uKa_linkButton:focus-visible,._7D6uKa_search:focus-visible,._7D6uKa_input:focus-visible,._7D6uKa_select:focus-visible,._7D6uKa_schedulePreset:focus-visible,._7D6uKa_scheduleToggle input:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}._7D6uKa_entry,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle input{transition:background-color .12s,color .12s,border-color .12s,outline-color .12s,box-shadow .12s,transform .12s}._7D6uKa_card:active{box-shadow:var(--dsw-shadow-lv1);transform:translateY(0)}._7D6uKa_entry:active,._7D6uKa_primaryButton:active:not(:disabled),._7D6uKa_ghostButton:active:not(:disabled),._7D6uKa_dangerButton:active:not(:disabled),._7D6uKa_iconButton:active:not(:disabled),._7D6uKa_linkButton:active:not(:disabled){transform:translateY(1px)}._7D6uKa_entry[data-active]:hover{background:var(--dsw-specific-sidebar-nav-item-active)}._7D6uKa_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_linkButton:hover:not(:disabled){text-decoration:underline}._7D6uKa_iconButton:disabled,._7D6uKa_linkButton:disabled{opacity:.45;cursor:default}._7D6uKa_search:focus,._7D6uKa_select:focus,._7D6uKa_schedulePreset:focus{border-color:var(--dsw-alias-state-business-primary)}._7D6uKa_scheduleToggle input{margin:0}@media (prefers-reduced-motion:reduce){._7D6uKa_entry,._7D6uKa_card,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle input{transition:none}._7D6uKa_cardSpinner{animation:none}}._7D6uKa_cardTags{flex-wrap:wrap;gap:4px;display:flex}._7D6uKa_cardTag{border:1px solid var(--dsh-task-tag-border);background:var(--dsh-task-tag-fill);max-width:100%;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;border-radius:999px;padding:0 7px;font-size:10px;line-height:16px;overflow:hidden}._7D6uKa_tagFilter{flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 10px;display:flex}._7D6uKa_tagFilterLabel{color:var(--dsw-alias-label-tertiary);font-size:11px}._7D6uKa_tagChip{border:1px solid var(--dsh-task-tag-border);color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border-radius:999px;padding:1px 9px;font-family:inherit;font-size:11px;line-height:18px}._7D6uKa_tagChip[data-active=true]{background:var(--dsh-task-tag-fill);color:var(--dsw-alias-label-primary)}._7D6uKa_cardTag[data-tag-tone=\"0\"],._7D6uKa_tagChip[data-tag-tone=\"0\"]{--dsh-task-tag-fill:#4e93e82e;--dsh-task-tag-border:#4e93e866}._7D6uKa_cardTag[data-tag-tone=\"1\"],._7D6uKa_tagChip[data-tag-tone=\"1\"]{--dsh-task-tag-fill:#2ea36a2e;--dsh-task-tag-border:#2ea36a66}._7D6uKa_cardTag[data-tag-tone=\"2\"],._7D6uKa_tagChip[data-tag-tone=\"2\"]{--dsh-task-tag-fill:#d08a2a2e;--dsh-task-tag-border:#d08a2a66}._7D6uKa_cardTag[data-tag-tone=\"3\"],._7D6uKa_tagChip[data-tag-tone=\"3\"]{--dsh-task-tag-fill:#b456c82e;--dsh-task-tag-border:#b456c866}._7D6uKa_cardTag[data-tag-tone=\"4\"],._7D6uKa_tagChip[data-tag-tone=\"4\"]{--dsh-task-tag-fill:#cf5f7a2e;--dsh-task-tag-border:#cf5f7a66}._7D6uKa_cardTag[data-tag-tone=\"5\"],._7D6uKa_tagChip[data-tag-tone=\"5\"]{--dsh-task-tag-fill:#4a9fb52e;--dsh-task-tag-border:#4a9fb566}._7D6uKa_fieldHint{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.4}._7D6uKa_tagRow{align-items:center;gap:6px;display:flex}._7D6uKa_tagRow ._7D6uKa_input{flex:1 1 0;min-width:0}._7D6uKa_tagRow ._7D6uKa_ghostButton{flex:none}._7D6uKa_tagAddButton{align-self:flex-start}._7D6uKa_projectFilter{flex:none;align-items:center;gap:6px;display:flex}._7D6uKa_projectFilterLabel{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:12px}._7D6uKa_projectDialog{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;flex-direction:column;flex:none;gap:8px;margin-bottom:8px;padding:10px 12px;display:flex}._7D6uKa_projectDialogActions{justify-content:flex-end;gap:8px;display:flex}._7D6uKa_aiParse{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}._7D6uKa_aiParseRow{align-items:center;gap:8px;display:flex}._7D6uKa_aiParseRow ._7D6uKa_select{flex:1 1 0;min-width:0}._7D6uKa_aiParseRow ._7D6uKa_ghostButton,._7D6uKa_aiParseRow ._7D6uKa_primaryButton{flex:none}";
|
|
1904
1986
|
const tagId$1 = "@linxin666/dsh-client-ui-task-board/packages/dsh-task-board/src/client/board.module.css";
|
|
1905
1987
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
1906
1988
|
const tag = document.createElement("style");
|
|
@@ -1910,6 +1992,8 @@ window.__ModuleLoader__.load({
|
|
|
1910
1992
|
document.head.appendChild(tag);
|
|
1911
1993
|
}
|
|
1912
1994
|
var board_module_css_default = {
|
|
1995
|
+
"aiParse": "_7D6uKa_aiParse",
|
|
1996
|
+
"aiParseRow": "_7D6uKa_aiParseRow",
|
|
1913
1997
|
"backButton": "_7D6uKa_backButton",
|
|
1914
1998
|
"board": "_7D6uKa_board",
|
|
1915
1999
|
"boardHeader": "_7D6uKa_boardHeader",
|
|
@@ -1966,6 +2050,10 @@ window.__ModuleLoader__.load({
|
|
|
1966
2050
|
"modalTitle": "_7D6uKa_modalTitle",
|
|
1967
2051
|
"moveRow": "_7D6uKa_moveRow",
|
|
1968
2052
|
"primaryButton": "_7D6uKa_primaryButton",
|
|
2053
|
+
"projectDialog": "_7D6uKa_projectDialog",
|
|
2054
|
+
"projectDialogActions": "_7D6uKa_projectDialogActions",
|
|
2055
|
+
"projectFilter": "_7D6uKa_projectFilter",
|
|
2056
|
+
"projectFilterLabel": "_7D6uKa_projectFilterLabel",
|
|
1969
2057
|
"promptBlock": "_7D6uKa_promptBlock",
|
|
1970
2058
|
"scheduleInput": "_7D6uKa_scheduleInput",
|
|
1971
2059
|
"scheduleInputInvalid": "_7D6uKa_scheduleInputInvalid",
|
|
@@ -2010,7 +2098,7 @@ window.__ModuleLoader__.load({
|
|
|
2010
2098
|
/** DOM id shared by the tag-name inputs and their datalist (one board at a time). */
|
|
2011
2099
|
const TAG_NAME_LIST_ID = "dsh-task-board-tag-names";
|
|
2012
2100
|
/** Modal overlay: closes on backdrop press, submits through the form. */
|
|
2013
|
-
function ModalShell({ ariaLabel, title, error, pending, submitLabel, onSubmit, onClose, children }) {
|
|
2101
|
+
function ModalShell({ ariaLabel, title, error, pending, submitLabel, onSubmit, onClose, secondaryAction, children }) {
|
|
2014
2102
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2015
2103
|
className: board_module_css_default.modalBackdrop,
|
|
2016
2104
|
onMouseDown: (event) => {
|
|
@@ -2036,17 +2124,27 @@ window.__ModuleLoader__.load({
|
|
|
2036
2124
|
}),
|
|
2037
2125
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
|
|
2038
2126
|
className: board_module_css_default.modalFooter,
|
|
2039
|
-
children: [
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2127
|
+
children: [
|
|
2128
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2129
|
+
type: "button",
|
|
2130
|
+
className: board_module_css_default.ghostButton,
|
|
2131
|
+
onClick: onClose,
|
|
2132
|
+
children: t("new.cancel")
|
|
2133
|
+
}),
|
|
2134
|
+
secondaryAction !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2135
|
+
type: "button",
|
|
2136
|
+
className: board_module_css_default.ghostButton,
|
|
2137
|
+
disabled: pending,
|
|
2138
|
+
onClick: secondaryAction.onSubmit,
|
|
2139
|
+
children: secondaryAction.label
|
|
2140
|
+
}),
|
|
2141
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2142
|
+
type: "submit",
|
|
2143
|
+
className: board_module_css_default.primaryButton,
|
|
2144
|
+
disabled: pending,
|
|
2145
|
+
children: submitLabel
|
|
2146
|
+
})
|
|
2147
|
+
]
|
|
2050
2148
|
})
|
|
2051
2149
|
]
|
|
2052
2150
|
})
|
|
@@ -2178,21 +2276,42 @@ window.__ModuleLoader__.load({
|
|
|
2178
2276
|
});
|
|
2179
2277
|
}
|
|
2180
2278
|
/**
|
|
2181
|
-
*
|
|
2182
|
-
*
|
|
2279
|
+
* Clean a tag list via normalizeTags: trim, drop blanks and duplicates, cap
|
|
2280
|
+
* lengths and count, so the wire always carries a valid tag list.
|
|
2183
2281
|
*/
|
|
2184
2282
|
function cleanTags(tags) {
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2283
|
+
return normalizeTags(tags) ?? [];
|
|
2284
|
+
}
|
|
2285
|
+
//#endregion
|
|
2286
|
+
//#region src/client/board/parse-model-pref.ts
|
|
2287
|
+
/**
|
|
2288
|
+
* The model the user last picked for AI parsing, remembered per browser so the
|
|
2289
|
+
* next new-task modal starts from it instead of the roster's first entry
|
|
2290
|
+
* (issue #1621). An empty value is a real choice — "let the Host use its
|
|
2291
|
+
* default model" — and is remembered as such.
|
|
2292
|
+
*/
|
|
2293
|
+
const PARSE_MODEL_KEY = "dsh-task-board.parse-model";
|
|
2294
|
+
/** The nearest browser storage, or undefined when the global itself throws. */
|
|
2295
|
+
function defaultStorage() {
|
|
2296
|
+
try {
|
|
2297
|
+
return globalThis.localStorage;
|
|
2298
|
+
} catch {
|
|
2299
|
+
return;
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
/** The remembered parse model; '' means the Host default (or no preference). */
|
|
2303
|
+
function readParseModelPreference(storage = defaultStorage()) {
|
|
2304
|
+
try {
|
|
2305
|
+
return storage?.getItem(PARSE_MODEL_KEY) ?? "";
|
|
2306
|
+
} catch {
|
|
2307
|
+
return "";
|
|
2194
2308
|
}
|
|
2195
|
-
|
|
2309
|
+
}
|
|
2310
|
+
/** Remember the picked parse model; '' records the Host-default choice. */
|
|
2311
|
+
function writeParseModelPreference(model, storage = defaultStorage()) {
|
|
2312
|
+
try {
|
|
2313
|
+
storage?.setItem(PARSE_MODEL_KEY, model);
|
|
2314
|
+
} catch {}
|
|
2196
2315
|
}
|
|
2197
2316
|
//#endregion
|
|
2198
2317
|
//#region src/client/board/NewTaskModal.tsx
|
|
@@ -2201,12 +2320,12 @@ window.__ModuleLoader__.load({
|
|
|
2201
2320
|
* Creates through the Host and closes only after the Host confirms it.
|
|
2202
2321
|
*/
|
|
2203
2322
|
/** New-task form overlay. */
|
|
2204
|
-
function NewTaskModal({ controller, onClose, initialTask, onDuplicateSuccess }) {
|
|
2323
|
+
function NewTaskModal({ controller, onClose, initialTask, defaultWorkspaceId, onDuplicateSuccess }) {
|
|
2205
2324
|
const isDuplicate = initialTask !== void 0;
|
|
2206
2325
|
const [title, setTitle] = (0, react.useState)(initialTask?.title ?? "");
|
|
2207
2326
|
const [description, setDescription] = (0, react.useState)(initialTask?.description ?? "");
|
|
2208
2327
|
const [prompt, setPrompt] = (0, react.useState)(initialTask?.prompt ?? "");
|
|
2209
|
-
const [workspaceId, setWorkspaceId] = (0, react.useState)(initialTask?.workspaceId ?? "");
|
|
2328
|
+
const [workspaceId, setWorkspaceId] = (0, react.useState)(initialTask?.workspaceId ?? defaultWorkspaceId ?? "");
|
|
2210
2329
|
const [mode, setMode] = (0, react.useState)(initialTask?.mode ?? "");
|
|
2211
2330
|
const [permission, setPermission] = (0, react.useState)(initialTask?.permission ?? "");
|
|
2212
2331
|
const [model, setModel] = (0, react.useState)(initialTask?.model ?? "");
|
|
@@ -2222,8 +2341,52 @@ window.__ModuleLoader__.load({
|
|
|
2222
2341
|
const [error, setError] = (0, react.useState)(void 0);
|
|
2223
2342
|
const [pending, setPending] = (0, react.useState)(false);
|
|
2224
2343
|
const [options, setOptions] = (0, react.useState)(controller.getSnapshot().executionOptions);
|
|
2344
|
+
const [canParse] = (0, react.useState)(controller.getSnapshot().canParseTask === true);
|
|
2345
|
+
const [parseText, setParseText] = (0, react.useState)("");
|
|
2346
|
+
const [parseModel, setParseModel] = (0, react.useState)(() => readParseModelPreference());
|
|
2347
|
+
const [parsePending, setParsePending] = (0, react.useState)(false);
|
|
2348
|
+
const [parseError, setParseError] = (0, react.useState)(void 0);
|
|
2349
|
+
const parseAbort = (0, react.useRef)(void 0);
|
|
2350
|
+
const parseModels = options.models ?? [];
|
|
2225
2351
|
(0, react.useEffect)(() => controller.subscribe(() => setOptions(controller.getSnapshot().executionOptions)), [controller]);
|
|
2226
|
-
|
|
2352
|
+
(0, react.useEffect)(() => {
|
|
2353
|
+
if (parseModel === "" || parseModels.length === 0) return;
|
|
2354
|
+
if (parseModels.some((option) => option.id === parseModel)) return;
|
|
2355
|
+
setParseModel("");
|
|
2356
|
+
writeParseModelPreference("");
|
|
2357
|
+
}, [parseModel, options.models]);
|
|
2358
|
+
const runParse = async () => {
|
|
2359
|
+
const text = parseText.trim();
|
|
2360
|
+
if (text === "") {
|
|
2361
|
+
setParseError(t("new.aiParseEmpty"));
|
|
2362
|
+
return;
|
|
2363
|
+
}
|
|
2364
|
+
const abort = new AbortController();
|
|
2365
|
+
parseAbort.current = abort;
|
|
2366
|
+
setParsePending(true);
|
|
2367
|
+
setParseError(void 0);
|
|
2368
|
+
try {
|
|
2369
|
+
const draft = await controller.parseTaskDraft({
|
|
2370
|
+
text,
|
|
2371
|
+
...parseModel === "" ? {} : { model: parseModel }
|
|
2372
|
+
}, abort.signal);
|
|
2373
|
+
setTitle(draft.title);
|
|
2374
|
+
setDescription(draft.description);
|
|
2375
|
+
setPrompt(draft.prompt);
|
|
2376
|
+
} catch (parseFailure) {
|
|
2377
|
+
if (!abort.signal.aborted) setParseError(parseFailure instanceof Error ? parseFailure.message : String(parseFailure));
|
|
2378
|
+
} finally {
|
|
2379
|
+
parseAbort.current = void 0;
|
|
2380
|
+
setParsePending(false);
|
|
2381
|
+
}
|
|
2382
|
+
};
|
|
2383
|
+
/**
|
|
2384
|
+
* Create the task through the Host, then optionally start it.
|
|
2385
|
+
* @param runAfterCreate - true for the "create and run" action: the task is
|
|
2386
|
+
* committed either way, and a refused start opens the task instead of
|
|
2387
|
+
* reporting the creation as failed.
|
|
2388
|
+
*/
|
|
2389
|
+
const submit = async (runAfterCreate) => {
|
|
2227
2390
|
if (scheduleEnabled) {
|
|
2228
2391
|
const cron = scheduleCron.trim();
|
|
2229
2392
|
if (cron === "" || !isValidCron(cron)) {
|
|
@@ -2252,7 +2415,7 @@ window.__ModuleLoader__.load({
|
|
|
2252
2415
|
};
|
|
2253
2416
|
const tagList = cleanTags(tags);
|
|
2254
2417
|
setPending(true);
|
|
2255
|
-
|
|
2418
|
+
const task = await controller.createTaskConfirmed({
|
|
2256
2419
|
title,
|
|
2257
2420
|
description,
|
|
2258
2421
|
prompt,
|
|
@@ -2268,13 +2431,17 @@ window.__ModuleLoader__.load({
|
|
|
2268
2431
|
enabled: true,
|
|
2269
2432
|
cron: scheduleCron.trim()
|
|
2270
2433
|
} : void 0
|
|
2271
|
-
})
|
|
2434
|
+
});
|
|
2435
|
+
if (task === void 0) {
|
|
2272
2436
|
setPending(false);
|
|
2273
2437
|
setError(controller.getSnapshot().transportError ?? t("new.required"));
|
|
2274
2438
|
return;
|
|
2275
2439
|
}
|
|
2276
2440
|
if (isDuplicate && archiveOriginal && initialTask !== void 0) if (onDuplicateSuccess !== void 0) await onDuplicateSuccess(initialTask.id);
|
|
2277
2441
|
else await controller.archiveTask(initialTask.id);
|
|
2442
|
+
if (runAfterCreate) {
|
|
2443
|
+
if (!await controller.runTask(task.id)) controller.openTask(task.id);
|
|
2444
|
+
}
|
|
2278
2445
|
onClose();
|
|
2279
2446
|
};
|
|
2280
2447
|
/** Next-run preview for a valid armed cron (creation-time only). */
|
|
@@ -2287,10 +2454,79 @@ window.__ModuleLoader__.load({
|
|
|
2287
2454
|
pending,
|
|
2288
2455
|
submitLabel: t("new.submit"),
|
|
2289
2456
|
onSubmit: () => {
|
|
2290
|
-
submit();
|
|
2457
|
+
submit(false);
|
|
2291
2458
|
},
|
|
2292
2459
|
onClose,
|
|
2460
|
+
secondaryAction: {
|
|
2461
|
+
label: t("new.createAndRun"),
|
|
2462
|
+
onSubmit: () => {
|
|
2463
|
+
submit(true);
|
|
2464
|
+
}
|
|
2465
|
+
},
|
|
2293
2466
|
children: [
|
|
2467
|
+
canParse && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2468
|
+
className: board_module_css_default.aiParse,
|
|
2469
|
+
"data-dsh-part": "ai-parse",
|
|
2470
|
+
children: [
|
|
2471
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2472
|
+
className: board_module_css_default.fieldLabel,
|
|
2473
|
+
children: t("new.aiParse")
|
|
2474
|
+
}),
|
|
2475
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2476
|
+
className: board_module_css_default.fieldHint,
|
|
2477
|
+
children: t("new.aiParseHint")
|
|
2478
|
+
}),
|
|
2479
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
2480
|
+
className: board_module_css_default.input,
|
|
2481
|
+
rows: 3,
|
|
2482
|
+
value: parseText,
|
|
2483
|
+
placeholder: t("new.aiParsePlaceholder"),
|
|
2484
|
+
spellCheck: false,
|
|
2485
|
+
onChange: (event) => {
|
|
2486
|
+
setParseText(event.target.value);
|
|
2487
|
+
setParseError(void 0);
|
|
2488
|
+
}
|
|
2489
|
+
}),
|
|
2490
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2491
|
+
className: board_module_css_default.aiParseRow,
|
|
2492
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
2493
|
+
className: board_module_css_default.select,
|
|
2494
|
+
value: parseModel,
|
|
2495
|
+
"aria-label": t("new.aiParseModel"),
|
|
2496
|
+
onChange: (event) => {
|
|
2497
|
+
setParseModel(event.target.value);
|
|
2498
|
+
writeParseModelPreference(event.target.value);
|
|
2499
|
+
},
|
|
2500
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2501
|
+
value: "",
|
|
2502
|
+
children: t("exec.model.default")
|
|
2503
|
+
}), parseModels.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2504
|
+
value: option.id,
|
|
2505
|
+
children: option.name ?? option.id
|
|
2506
|
+
}, option.id))]
|
|
2507
|
+
}), parsePending ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2508
|
+
type: "button",
|
|
2509
|
+
className: board_module_css_default.ghostButton,
|
|
2510
|
+
onClick: () => {
|
|
2511
|
+
parseAbort.current?.abort();
|
|
2512
|
+
},
|
|
2513
|
+
children: t("new.aiParseCancel")
|
|
2514
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2515
|
+
type: "button",
|
|
2516
|
+
className: board_module_css_default.primaryButton,
|
|
2517
|
+
disabled: parseText.trim() === "",
|
|
2518
|
+
onClick: () => {
|
|
2519
|
+
runParse();
|
|
2520
|
+
},
|
|
2521
|
+
children: t("new.aiParseRun")
|
|
2522
|
+
})]
|
|
2523
|
+
}),
|
|
2524
|
+
parseError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2525
|
+
className: board_module_css_default.formError,
|
|
2526
|
+
children: parseError
|
|
2527
|
+
})
|
|
2528
|
+
]
|
|
2529
|
+
}),
|
|
2294
2530
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaskContentFields, {
|
|
2295
2531
|
title,
|
|
2296
2532
|
description,
|
|
@@ -2759,6 +2995,39 @@ window.__ModuleLoader__.load({
|
|
|
2759
2995
|
})]
|
|
2760
2996
|
});
|
|
2761
2997
|
}
|
|
2998
|
+
/** Edit-tags modal: edit labels only, shown for tasks after first execution. */
|
|
2999
|
+
function EditTagsModal({ controller, task, onClose }) {
|
|
3000
|
+
const [tags, setTags] = (0, react.useState)(task.tags ?? []);
|
|
3001
|
+
const [error, setError] = (0, react.useState)(void 0);
|
|
3002
|
+
const [pending, setPending] = (0, react.useState)(false);
|
|
3003
|
+
const submit = async () => {
|
|
3004
|
+
setPending(true);
|
|
3005
|
+
const tagList = cleanTags(tags);
|
|
3006
|
+
const patch = { tags: tagList.length > 0 ? tagList : null };
|
|
3007
|
+
if (await controller.updateTask(task.id, patch)) {
|
|
3008
|
+
onClose();
|
|
3009
|
+
return;
|
|
3010
|
+
}
|
|
3011
|
+
setPending(false);
|
|
3012
|
+
setError(controller.getSnapshot().transportError ?? t("new.required"));
|
|
3013
|
+
};
|
|
3014
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModalShell, {
|
|
3015
|
+
ariaLabel: t("detail.editTags"),
|
|
3016
|
+
title: t("detail.editTags"),
|
|
3017
|
+
error,
|
|
3018
|
+
pending,
|
|
3019
|
+
submitLabel: t("edit.save"),
|
|
3020
|
+
onSubmit: () => {
|
|
3021
|
+
submit();
|
|
3022
|
+
},
|
|
3023
|
+
onClose,
|
|
3024
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaskTagFields, {
|
|
3025
|
+
tags,
|
|
3026
|
+
knownTags: collectKnownTags(controller.getSnapshot().tasks),
|
|
3027
|
+
onChange: setTags
|
|
3028
|
+
})
|
|
3029
|
+
});
|
|
3030
|
+
}
|
|
2762
3031
|
//#endregion
|
|
2763
3032
|
//#region src/client/board/TaskDetail.tsx
|
|
2764
3033
|
/**
|
|
@@ -3090,6 +3359,7 @@ window.__ModuleLoader__.load({
|
|
|
3090
3359
|
function TaskDetail({ controller, task }) {
|
|
3091
3360
|
const [confirmDelete, setConfirmDelete] = (0, react.useState)(false);
|
|
3092
3361
|
const [showEdit, setShowEdit] = (0, react.useState)(false);
|
|
3362
|
+
const [showEditTags, setShowEditTags] = (0, react.useState)(false);
|
|
3093
3363
|
const [showDuplicate, setShowDuplicate] = (0, react.useState)(false);
|
|
3094
3364
|
const [latest, setLatest] = (0, react.useState)(task);
|
|
3095
3365
|
(0, react.useEffect)(() => {
|
|
@@ -3097,6 +3367,7 @@ window.__ModuleLoader__.load({
|
|
|
3097
3367
|
}, [task]);
|
|
3098
3368
|
(0, react.useEffect)(() => {
|
|
3099
3369
|
setShowEdit(false);
|
|
3370
|
+
setShowEditTags(false);
|
|
3100
3371
|
setShowDuplicate(false);
|
|
3101
3372
|
}, [task.id]);
|
|
3102
3373
|
const current = latest;
|
|
@@ -3166,6 +3437,21 @@ window.__ModuleLoader__.load({
|
|
|
3166
3437
|
children: current.description !== "" ? current.description : "—"
|
|
3167
3438
|
})]
|
|
3168
3439
|
}),
|
|
3440
|
+
current.tags !== void 0 && current.tags.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3441
|
+
className: board_module_css_default.detailSection,
|
|
3442
|
+
"data-dsh-part": "tags",
|
|
3443
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: t("new.tags") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3444
|
+
className: board_module_css_default.cardTags,
|
|
3445
|
+
children: current.tags.map((tag) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3446
|
+
className: board_module_css_default.cardTag,
|
|
3447
|
+
"data-tag-tone": tagTone(tag.name),
|
|
3448
|
+
"data-dsh-part": "tag-badge",
|
|
3449
|
+
"data-tag-hint": tag.promptPrefix === void 0 ? void 0 : tag.promptPrefix,
|
|
3450
|
+
title: tag.promptPrefix === void 0 ? tag.name : tag.promptPrefix,
|
|
3451
|
+
children: tag.name
|
|
3452
|
+
}, tag.name))
|
|
3453
|
+
})]
|
|
3454
|
+
}),
|
|
3169
3455
|
current.freeze !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3170
3456
|
className: board_module_css_default.detailSection,
|
|
3171
3457
|
"data-dsh-part": "freeze",
|
|
@@ -3332,6 +3618,15 @@ window.__ModuleLoader__.load({
|
|
|
3332
3618
|
},
|
|
3333
3619
|
children: t("detail.edit")
|
|
3334
3620
|
}),
|
|
3621
|
+
!archived && !canEditTaskContent(current) && current.status !== "running" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3622
|
+
type: "button",
|
|
3623
|
+
className: board_module_css_default.ghostButton,
|
|
3624
|
+
disabled: pending,
|
|
3625
|
+
onClick: () => {
|
|
3626
|
+
setShowEditTags(true);
|
|
3627
|
+
},
|
|
3628
|
+
children: t("detail.editTags")
|
|
3629
|
+
}),
|
|
3335
3630
|
!archived && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3336
3631
|
type: "button",
|
|
3337
3632
|
className: board_module_css_default.ghostButton,
|
|
@@ -3412,6 +3707,13 @@ window.__ModuleLoader__.load({
|
|
|
3412
3707
|
setShowEdit(false);
|
|
3413
3708
|
}
|
|
3414
3709
|
}),
|
|
3710
|
+
showEditTags && !archived && current.status !== "running" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EditTagsModal, {
|
|
3711
|
+
controller,
|
|
3712
|
+
task: current,
|
|
3713
|
+
onClose: () => {
|
|
3714
|
+
setShowEditTags(false);
|
|
3715
|
+
}
|
|
3716
|
+
}),
|
|
3415
3717
|
showDuplicate && !archived && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NewTaskModal, {
|
|
3416
3718
|
controller,
|
|
3417
3719
|
initialTask: current,
|
|
@@ -3426,13 +3728,6 @@ window.__ModuleLoader__.load({
|
|
|
3426
3728
|
]
|
|
3427
3729
|
});
|
|
3428
3730
|
}
|
|
3429
|
-
//#endregion
|
|
3430
|
-
//#region src/client/board/TaskBoard.tsx
|
|
3431
|
-
/**
|
|
3432
|
-
* Board view: the multi-column kanban that replaces the middle column while
|
|
3433
|
-
* active. Cards open the task detail (never execute directly); the header
|
|
3434
|
-
* offers filter, new-task, and a back-to-chat escape.
|
|
3435
|
-
*/
|
|
3436
3731
|
/** Case-insensitive title/description/tag/freeze-snapshot match. */
|
|
3437
3732
|
function matchesFilter(task, filter) {
|
|
3438
3733
|
if (filter.trim() === "") return true;
|
|
@@ -3479,10 +3774,33 @@ window.__ModuleLoader__.load({
|
|
|
3479
3774
|
const [filter, setFilter] = (0, react.useState)("");
|
|
3480
3775
|
const [tagFilter, setTagFilter] = (0, react.useState)([]);
|
|
3481
3776
|
const [showNew, setShowNew] = (0, react.useState)(false);
|
|
3777
|
+
const [projectId, setProjectId] = (0, react.useState)("");
|
|
3778
|
+
const [showNewProject, setShowNewProject] = (0, react.useState)(false);
|
|
3779
|
+
const [newProjectPath, setNewProjectPath] = (0, react.useState)("");
|
|
3780
|
+
const [newProjectError, setNewProjectError] = (0, react.useState)(void 0);
|
|
3781
|
+
const [newProjectPending, setNewProjectPending] = (0, react.useState)(false);
|
|
3482
3782
|
const selected = selectedTaskOf(snapshot);
|
|
3483
3783
|
const archiveView = snapshot.archiveView;
|
|
3484
3784
|
const knownTags = collectKnownTags(snapshot.tasks);
|
|
3485
|
-
const visible = snapshot.tasks.filter((task) => (archiveView ? task.archivedAt !== void 0 : task.archivedAt === void 0) && matchesFilter(task, filter) && matchesTagFilter(task, tagFilter));
|
|
3785
|
+
const visible = snapshot.tasks.filter((task) => (archiveView ? task.archivedAt !== void 0 : task.archivedAt === void 0) && (projectId === "" || task.workspaceId === projectId) && matchesFilter(task, filter) && matchesTagFilter(task, tagFilter));
|
|
3786
|
+
const projects = snapshot.executionOptions.workspaces;
|
|
3787
|
+
const canCreateProject = snapshot.canCreateWorkspace === true;
|
|
3788
|
+
const submitNewProject = async () => {
|
|
3789
|
+
const path = newProjectPath.trim();
|
|
3790
|
+
if (path === "") return;
|
|
3791
|
+
setNewProjectPending(true);
|
|
3792
|
+
setNewProjectError(void 0);
|
|
3793
|
+
try {
|
|
3794
|
+
const created = await controller.createWorkspace(path);
|
|
3795
|
+
setProjectId(created.workspaceId);
|
|
3796
|
+
setShowNewProject(false);
|
|
3797
|
+
setNewProjectPath("");
|
|
3798
|
+
} catch (error) {
|
|
3799
|
+
setNewProjectError(error instanceof Error ? error.message : String(error));
|
|
3800
|
+
} finally {
|
|
3801
|
+
setNewProjectPending(false);
|
|
3802
|
+
}
|
|
3803
|
+
};
|
|
3486
3804
|
const toggleTag = (0, react.useCallback)((name) => {
|
|
3487
3805
|
setTagFilter((current) => current.includes(name) ? current.filter((entry) => entry !== name) : [...current, name]);
|
|
3488
3806
|
}, []);
|
|
@@ -3521,6 +3839,41 @@ window.__ModuleLoader__.load({
|
|
|
3521
3839
|
timeZone: snapshot.host.scheduler.timeZone
|
|
3522
3840
|
})
|
|
3523
3841
|
}),
|
|
3842
|
+
(projects.length > 0 || canCreateProject) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
3843
|
+
className: board_module_css_default.projectFilter,
|
|
3844
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3845
|
+
className: board_module_css_default.projectFilterLabel,
|
|
3846
|
+
children: t("board.project")
|
|
3847
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
3848
|
+
className: board_module_css_default.select,
|
|
3849
|
+
"data-dsh-part": "project-filter",
|
|
3850
|
+
value: projectId,
|
|
3851
|
+
"aria-label": t("board.project"),
|
|
3852
|
+
onChange: (event) => {
|
|
3853
|
+
const value = event.target.value;
|
|
3854
|
+
if (value === "__dsh_new_project__") {
|
|
3855
|
+
setNewProjectError(void 0);
|
|
3856
|
+
setShowNewProject(true);
|
|
3857
|
+
return;
|
|
3858
|
+
}
|
|
3859
|
+
setProjectId(value);
|
|
3860
|
+
},
|
|
3861
|
+
children: [
|
|
3862
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3863
|
+
value: "",
|
|
3864
|
+
children: t("board.projectAll")
|
|
3865
|
+
}),
|
|
3866
|
+
projects.map((project) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3867
|
+
value: project.workspaceId,
|
|
3868
|
+
children: project.title
|
|
3869
|
+
}, project.workspaceId)),
|
|
3870
|
+
canCreateProject && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3871
|
+
value: "__dsh_new_project__",
|
|
3872
|
+
children: t("board.projectNew")
|
|
3873
|
+
})
|
|
3874
|
+
]
|
|
3875
|
+
})]
|
|
3876
|
+
}),
|
|
3524
3877
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3525
3878
|
className: board_module_css_default.search,
|
|
3526
3879
|
type: "search",
|
|
@@ -3549,6 +3902,52 @@ window.__ModuleLoader__.load({
|
|
|
3549
3902
|
})
|
|
3550
3903
|
]
|
|
3551
3904
|
}),
|
|
3905
|
+
showNewProject && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3906
|
+
className: board_module_css_default.projectDialog,
|
|
3907
|
+
"data-dsh-part": "project-dialog",
|
|
3908
|
+
children: [
|
|
3909
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
3910
|
+
className: board_module_css_default.field,
|
|
3911
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3912
|
+
className: board_module_css_default.fieldLabel,
|
|
3913
|
+
children: t("board.projectNewPath")
|
|
3914
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3915
|
+
className: board_module_css_default.input,
|
|
3916
|
+
value: newProjectPath,
|
|
3917
|
+
placeholder: t("board.projectNewPathPlaceholder"),
|
|
3918
|
+
spellCheck: false,
|
|
3919
|
+
onChange: (event) => {
|
|
3920
|
+
setNewProjectPath(event.target.value);
|
|
3921
|
+
setNewProjectError(void 0);
|
|
3922
|
+
}
|
|
3923
|
+
})]
|
|
3924
|
+
}),
|
|
3925
|
+
newProjectError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3926
|
+
className: board_module_css_default.formError,
|
|
3927
|
+
children: t("board.projectCreateFailed", { error: newProjectError })
|
|
3928
|
+
}),
|
|
3929
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3930
|
+
className: board_module_css_default.projectDialogActions,
|
|
3931
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3932
|
+
type: "button",
|
|
3933
|
+
className: board_module_css_default.ghostButton,
|
|
3934
|
+
onClick: () => {
|
|
3935
|
+
setShowNewProject(false);
|
|
3936
|
+
setNewProjectError(void 0);
|
|
3937
|
+
},
|
|
3938
|
+
children: t("new.cancel")
|
|
3939
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3940
|
+
type: "button",
|
|
3941
|
+
className: board_module_css_default.primaryButton,
|
|
3942
|
+
disabled: newProjectPending || newProjectPath.trim() === "",
|
|
3943
|
+
onClick: () => {
|
|
3944
|
+
submitNewProject();
|
|
3945
|
+
},
|
|
3946
|
+
children: t("board.projectCreate")
|
|
3947
|
+
})]
|
|
3948
|
+
})
|
|
3949
|
+
]
|
|
3950
|
+
}),
|
|
3552
3951
|
!archiveView && knownTags.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3553
3952
|
className: board_module_css_default.tagFilter,
|
|
3554
3953
|
"data-dsh-part": "tag-filter",
|
|
@@ -3681,6 +4080,7 @@ window.__ModuleLoader__.load({
|
|
|
3681
4080
|
}),
|
|
3682
4081
|
showNew && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NewTaskModal, {
|
|
3683
4082
|
controller,
|
|
4083
|
+
...projectId === "" ? {} : { defaultWorkspaceId: projectId },
|
|
3684
4084
|
onClose: () => {
|
|
3685
4085
|
setShowNew(false);
|
|
3686
4086
|
}
|
|
@@ -3933,10 +4333,12 @@ window.__ModuleLoader__.load({
|
|
|
3933
4333
|
if (nested !== null) return nested;
|
|
3934
4334
|
for (const child of root.children) if (child.tagName === "BUTTON") return child;
|
|
3935
4335
|
}
|
|
3936
|
-
/** Build the entry row (
|
|
4336
|
+
/** Build the entry row (detached; inserted once the shell is up). */
|
|
3937
4337
|
function createEntry(options) {
|
|
3938
|
-
const
|
|
3939
|
-
|
|
4338
|
+
const actions = options.actions ?? [];
|
|
4339
|
+
const composite = actions.length > 0;
|
|
4340
|
+
const entry = document.createElement(composite ? "div" : "button");
|
|
4341
|
+
if (!composite) entry.type = "button";
|
|
3940
4342
|
entry.setAttribute(options.rowAttribute, "");
|
|
3941
4343
|
if (options.plugin !== void 0) {
|
|
3942
4344
|
entry.setAttribute("data-dsh-plugin", options.plugin);
|
|
@@ -3948,17 +4350,57 @@ window.__ModuleLoader__.load({
|
|
|
3948
4350
|
const iconSpan = document.createElement("span");
|
|
3949
4351
|
iconSpan.className = options.css["entryIcon"] ?? "";
|
|
3950
4352
|
iconSpan.innerHTML = options.icon;
|
|
3951
|
-
|
|
4353
|
+
const main = composite ? document.createElement("button") : entry;
|
|
4354
|
+
if (composite) {
|
|
4355
|
+
main.type = "button";
|
|
4356
|
+
main.className = options.css["entryMain"] ?? "";
|
|
4357
|
+
main.append(iconSpan, labelSpan);
|
|
4358
|
+
entry.append(main);
|
|
4359
|
+
} else entry.append(iconSpan, labelSpan);
|
|
4360
|
+
const actionButtons = [];
|
|
4361
|
+
for (const action of actions) {
|
|
4362
|
+
const button = document.createElement("button");
|
|
4363
|
+
button.type = "button";
|
|
4364
|
+
button.className = options.css["entryAction"] ?? "";
|
|
4365
|
+
button.setAttribute("data-dsh-entry-action", action.id);
|
|
4366
|
+
button.innerHTML = action.icon;
|
|
4367
|
+
button.addEventListener("click", () => {
|
|
4368
|
+
action.onClick(button);
|
|
4369
|
+
});
|
|
4370
|
+
entry.append(button);
|
|
4371
|
+
actionButtons.push({
|
|
4372
|
+
action,
|
|
4373
|
+
button
|
|
4374
|
+
});
|
|
4375
|
+
}
|
|
4376
|
+
let open = false;
|
|
4377
|
+
const applyActions = () => {
|
|
4378
|
+
for (const { action, button } of actionButtons) {
|
|
4379
|
+
button.innerHTML = open || action.inactiveIcon === void 0 ? action.icon : action.inactiveIcon;
|
|
4380
|
+
const text = action.label(open);
|
|
4381
|
+
button.setAttribute("aria-label", text);
|
|
4382
|
+
button.setAttribute("title", text);
|
|
4383
|
+
if (action.inactiveIcon !== void 0) button.setAttribute("aria-expanded", String(open));
|
|
4384
|
+
}
|
|
4385
|
+
};
|
|
3952
4386
|
const applyLabel = () => {
|
|
3953
|
-
|
|
3954
|
-
if (options.tooltip !== void 0)
|
|
4387
|
+
main.setAttribute("aria-label", options.label());
|
|
4388
|
+
if (options.tooltip !== void 0) main.setAttribute("title", options.tooltip());
|
|
3955
4389
|
labelSpan.textContent = options.label();
|
|
4390
|
+
applyActions();
|
|
3956
4391
|
};
|
|
3957
4392
|
applyLabel();
|
|
3958
|
-
|
|
4393
|
+
main.addEventListener("click", options.onToggle);
|
|
4394
|
+
if (composite) entry.addEventListener("click", (event) => {
|
|
4395
|
+
if (event.target === entry) options.onToggle();
|
|
4396
|
+
});
|
|
3959
4397
|
return {
|
|
3960
4398
|
entry,
|
|
3961
|
-
applyLabel
|
|
4399
|
+
applyLabel,
|
|
4400
|
+
setOpen: (next) => {
|
|
4401
|
+
open = next;
|
|
4402
|
+
applyActions();
|
|
4403
|
+
}
|
|
3962
4404
|
};
|
|
3963
4405
|
}
|
|
3964
4406
|
/** Re-insert the entry after the New Session row (before the browser region). */
|
|
@@ -3982,7 +4424,7 @@ window.__ModuleLoader__.load({
|
|
|
3982
4424
|
*/
|
|
3983
4425
|
function mountSidebarEntry$1(options) {
|
|
3984
4426
|
if (typeof document !== "undefined" && document.querySelector(options.rowSelector) !== null) return () => {};
|
|
3985
|
-
const { entry, applyLabel } = createEntry(options);
|
|
4427
|
+
const { entry, applyLabel, setOpen } = createEntry(options);
|
|
3986
4428
|
let root;
|
|
3987
4429
|
let placed = false;
|
|
3988
4430
|
let unsubscribeRefresh;
|
|
@@ -4022,8 +4464,10 @@ window.__ModuleLoader__.load({
|
|
|
4022
4464
|
});
|
|
4023
4465
|
const unsubscribeActive = options.active === void 0 ? void 0 : (() => {
|
|
4024
4466
|
const syncActive = () => {
|
|
4025
|
-
|
|
4467
|
+
const open = options.active.isOpen();
|
|
4468
|
+
if (open) entry.dataset.active = "true";
|
|
4026
4469
|
else delete entry.dataset.active;
|
|
4470
|
+
setOpen(open);
|
|
4027
4471
|
};
|
|
4028
4472
|
const unsubscribe = options.active.subscribe(syncActive);
|
|
4029
4473
|
syncActive();
|
|
@@ -4902,19 +5346,64 @@ window.__ModuleLoader__.load({
|
|
|
4902
5346
|
//#endregion
|
|
4903
5347
|
//#region src/protocol.ts
|
|
4904
5348
|
const TASK_BOARD_API_PREFIX = "/api/task-board";
|
|
5349
|
+
/** Whether a decoded reply carries the three draft strings the form accepts. */
|
|
5350
|
+
function isTaskParseDraft(value) {
|
|
5351
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5352
|
+
const record = value;
|
|
5353
|
+
return typeof record.title === "string" && typeof record.description === "string" && typeof record.prompt === "string";
|
|
5354
|
+
}
|
|
4905
5355
|
//#endregion
|
|
4906
5356
|
//#region src/client/host-api.ts
|
|
4907
5357
|
const IMPORT_MARKER = "dsh.taskBoard.v2.hostImported";
|
|
4908
5358
|
const SOURCE_KEY = "dsh.taskBoard.v2.sourceId";
|
|
4909
5359
|
const IMPORT_REQUEST_KEY = "dsh.taskBoard.v2.importRequestId";
|
|
4910
5360
|
const REQUEST_TIMEOUT_MS = 15e3;
|
|
5361
|
+
/** Re-notify the panel at most this often while the event stream stays broken. */
|
|
5362
|
+
const STREAM_ERROR_NOTIFY_MS = 15e3;
|
|
5363
|
+
/** Mirrors the Host's own parse budget; only used to phrase the timeout. */
|
|
5364
|
+
const TASK_PARSE_TIMEOUT_SECONDS = 45;
|
|
5365
|
+
/** Transport failure carrying a stable class next to its user-facing message. */
|
|
5366
|
+
var HostApiError = class extends Error {
|
|
5367
|
+
failure;
|
|
5368
|
+
status;
|
|
5369
|
+
constructor(failure, message, status) {
|
|
5370
|
+
super(message);
|
|
5371
|
+
this.failure = failure;
|
|
5372
|
+
this.status = status;
|
|
5373
|
+
this.name = "HostApiError";
|
|
5374
|
+
}
|
|
5375
|
+
};
|
|
4911
5376
|
function uuid() {
|
|
4912
5377
|
return globalThis.crypto?.randomUUID?.() ?? `browser-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
4913
5378
|
}
|
|
5379
|
+
/**
|
|
5380
|
+
* Read one Host response without ever handing a non-JSON body to JSON.parse:
|
|
5381
|
+
* the core webserver answers an unmounted `/api/*` path with the plain text
|
|
5382
|
+
* "not found", which used to surface as a JavaScript parse error in the panel.
|
|
5383
|
+
*/
|
|
4914
5384
|
async function readJson(response) {
|
|
4915
|
-
const
|
|
4916
|
-
|
|
4917
|
-
|
|
5385
|
+
const text = await response.text();
|
|
5386
|
+
let parsed;
|
|
5387
|
+
let readable = false;
|
|
5388
|
+
if (text.trim() !== "") try {
|
|
5389
|
+
parsed = JSON.parse(text);
|
|
5390
|
+
readable = true;
|
|
5391
|
+
} catch {
|
|
5392
|
+
readable = false;
|
|
5393
|
+
}
|
|
5394
|
+
const hostError = readable && typeof parsed === "object" && parsed !== null && typeof parsed.error === "string" ? parsed.error : void 0;
|
|
5395
|
+
if (response.ok) {
|
|
5396
|
+
if (!readable) throw new HostApiError("unexpected", t("board.hostError.unexpected", { status: String(response.status) }), response.status);
|
|
5397
|
+
return parsed;
|
|
5398
|
+
}
|
|
5399
|
+
if (hostError !== void 0) {
|
|
5400
|
+
if (hostError === "forbidden") throw new HostApiError("unauthorized", t("board.hostError.unauthorized"), response.status);
|
|
5401
|
+
if (response.status === 503 || /lock/i.test(hostError)) throw new HostApiError("locked", t("board.hostError.locked", { detail: hostError }), response.status);
|
|
5402
|
+
throw new HostApiError("rejected", hostError, response.status);
|
|
5403
|
+
}
|
|
5404
|
+
if (response.status === 404) throw new HostApiError("not-mounted", t("board.hostError.notMounted"), 404);
|
|
5405
|
+
if (response.status === 401 || response.status === 403) throw new HostApiError("unauthorized", t("board.hostError.unauthorized"), response.status);
|
|
5406
|
+
throw new HostApiError("unexpected", t("board.hostError.unexpected", { status: String(response.status) }), response.status);
|
|
4918
5407
|
}
|
|
4919
5408
|
var HttpTaskBoardHostTransport = class {
|
|
4920
5409
|
storage;
|
|
@@ -4974,14 +5463,54 @@ window.__ModuleLoader__.load({
|
|
|
4974
5463
|
signal: controller.signal
|
|
4975
5464
|
}));
|
|
4976
5465
|
} catch (error) {
|
|
4977
|
-
if (
|
|
4978
|
-
throw
|
|
5466
|
+
if (error instanceof HostApiError) throw error;
|
|
5467
|
+
if (controller.signal.aborted) throw new HostApiError("timeout", t("board.hostError.timeout", { seconds: String(REQUEST_TIMEOUT_MS / 1e3) }));
|
|
5468
|
+
throw new HostApiError("unreachable", t("board.hostError.unreachable"));
|
|
4979
5469
|
} finally {
|
|
4980
5470
|
globalThis.clearTimeout(timeout);
|
|
4981
5471
|
}
|
|
4982
5472
|
}
|
|
5473
|
+
/**
|
|
5474
|
+
* Ask the Host to turn pasted text into task fields. The route answers a
|
|
5475
|
+
* typed failure (no model, timeout, unparseable reply) already phrased for
|
|
5476
|
+
* the form, so the UI never renders a raw status code (issue #1540).
|
|
5477
|
+
*/
|
|
5478
|
+
async parseDraft(request, signal) {
|
|
5479
|
+
let response;
|
|
5480
|
+
try {
|
|
5481
|
+
response = await fetch(`${TASK_BOARD_API_PREFIX}/parse`, {
|
|
5482
|
+
method: "POST",
|
|
5483
|
+
headers: { "content-type": "application/json" },
|
|
5484
|
+
body: JSON.stringify(request),
|
|
5485
|
+
...signal === void 0 ? {} : { signal }
|
|
5486
|
+
});
|
|
5487
|
+
} catch {
|
|
5488
|
+
throw new HostApiError("unreachable", t("board.hostError.unreachable"));
|
|
5489
|
+
}
|
|
5490
|
+
const text = await response.text();
|
|
5491
|
+
let parsed;
|
|
5492
|
+
let readable = false;
|
|
5493
|
+
if (text.trim() !== "") try {
|
|
5494
|
+
parsed = JSON.parse(text);
|
|
5495
|
+
readable = true;
|
|
5496
|
+
} catch {
|
|
5497
|
+
readable = false;
|
|
5498
|
+
}
|
|
5499
|
+
const record = readable && typeof parsed === "object" && parsed !== null ? parsed : void 0;
|
|
5500
|
+
if (response.ok) {
|
|
5501
|
+
if (record !== void 0 && isTaskParseDraft(record.draft)) return record.draft;
|
|
5502
|
+
throw new HostApiError("unexpected", t("new.aiParseFailed", { error: t("board.hostError.unexpected", { status: String(response.status) }) }), response.status);
|
|
5503
|
+
}
|
|
5504
|
+
if (response.status === 404) throw new HostApiError("not-mounted", t("new.aiParseUnavailable"), 404);
|
|
5505
|
+
if (response.status === 401 || response.status === 403) throw new HostApiError("unauthorized", t("board.hostError.unauthorized"), response.status);
|
|
5506
|
+
const code = typeof record?.code === "string" ? record.code : void 0;
|
|
5507
|
+
if (code === "no-model") throw new HostApiError("rejected", t("new.aiParseNoModel"), response.status);
|
|
5508
|
+
if (code === "timeout") throw new HostApiError("timeout", t("new.aiParseTimeout", { seconds: String(TASK_PARSE_TIMEOUT_SECONDS) }), response.status);
|
|
5509
|
+
throw new HostApiError("rejected", t("new.aiParseFailed", { error: typeof record?.error === "string" && record.error !== "" ? record.error : String(response.status) }), response.status);
|
|
5510
|
+
}
|
|
4983
5511
|
subscribe(listener) {
|
|
4984
5512
|
const events = new EventSource(`${TASK_BOARD_API_PREFIX}/events`);
|
|
5513
|
+
let lastStreamErrorNotify = 0;
|
|
4985
5514
|
events.onmessage = (message) => {
|
|
4986
5515
|
try {
|
|
4987
5516
|
const parsed = JSON.parse(message.data);
|
|
@@ -4991,6 +5520,12 @@ window.__ModuleLoader__.load({
|
|
|
4991
5520
|
listener();
|
|
4992
5521
|
}
|
|
4993
5522
|
};
|
|
5523
|
+
events.onerror = () => {
|
|
5524
|
+
const now = Date.now();
|
|
5525
|
+
if (now - lastStreamErrorNotify < STREAM_ERROR_NOTIFY_MS) return;
|
|
5526
|
+
lastStreamErrorNotify = now;
|
|
5527
|
+
listener();
|
|
5528
|
+
};
|
|
4994
5529
|
const onVisible = () => {
|
|
4995
5530
|
if (document.visibilityState === "visible") listener();
|
|
4996
5531
|
};
|
|
@@ -5009,7 +5544,7 @@ window.__ModuleLoader__.load({
|
|
|
5009
5544
|
/** The building package's version, when the bundle carries it. */
|
|
5010
5545
|
function bakedVersion() {
|
|
5011
5546
|
try {
|
|
5012
|
-
return "0.3.
|
|
5547
|
+
return "0.3.24";
|
|
5013
5548
|
} catch {
|
|
5014
5549
|
return;
|
|
5015
5550
|
}
|
|
@@ -5072,6 +5607,129 @@ window.__ModuleLoader__.load({
|
|
|
5072
5607
|
} catch {}
|
|
5073
5608
|
}
|
|
5074
5609
|
//#endregion
|
|
5610
|
+
//#region src/client/plugin-card-seat.ts
|
|
5611
|
+
/**
|
|
5612
|
+
* Family plugin-card seat.
|
|
5613
|
+
*
|
|
5614
|
+
* A family plugin contributes its settings card to whichever plugin-card seat
|
|
5615
|
+
* the running host actually renders:
|
|
5616
|
+
*
|
|
5617
|
+
* - `web-ui.plugin.item` — the list seat declared by the dsh-web-settings
|
|
5618
|
+
* group section (this family's own first-level "Web UI plugins" section);
|
|
5619
|
+
* - `settings.plugin.item` — the official keyed seat of the harness's
|
|
5620
|
+
* `ui-settings-plugins` tab, keyed by the settings namespace the card edits.
|
|
5621
|
+
*
|
|
5622
|
+
* SEAT SELECTION IS NOT A DECLARATION PROBE. The official `ui-settings-plugins`
|
|
5623
|
+
* row belongs to the harness bundle and its `configurable` tab always declares
|
|
5624
|
+
* `settings.plugin.item` before any external plugin's `apply()` runs, so
|
|
5625
|
+
* "is the official seat declared?" answers yes even in the deployment whose
|
|
5626
|
+
* whole point is the family group. Choosing on that probe sends every family
|
|
5627
|
+
* card to the official Plugins tab and leaves the group's own section
|
|
5628
|
+
* permanently empty — the family of reports where the section renders its
|
|
5629
|
+
* heading and zero cards.
|
|
5630
|
+
*
|
|
5631
|
+
* The signal that actually distinguishes the two deployments is whether
|
|
5632
|
+
* dsh-web-settings is loaded: it is the package that owns the group section and
|
|
5633
|
+
* it publishes the `webUiSettings` service during `apply()`, which every
|
|
5634
|
+
* family plugin already reads for its settings scope. Group loaded -> the family
|
|
5635
|
+
* seat; group absent -> the official seat.
|
|
5636
|
+
*
|
|
5637
|
+
* The decision is re-evaluated on every `slots/changed` because the group may
|
|
5638
|
+
* apply after this plugin (the family aggregate orders it first, a profile that
|
|
5639
|
+
* installs the group separately need not): the initial contribution goes to the
|
|
5640
|
+
* official seat, then moves to the family seat the moment the group's section
|
|
5641
|
+
* registers. The entry is disposed before the replacement is registered, so a
|
|
5642
|
+
* card is never in two seats at once.
|
|
5643
|
+
*
|
|
5644
|
+
* The shared tree has no client-SDK dependency, so this module reads its
|
|
5645
|
+
* context through the structural shape below; callers pass the plugin's own
|
|
5646
|
+
* `ctx`.
|
|
5647
|
+
*/
|
|
5648
|
+
/** The family list seat key. */
|
|
5649
|
+
const FAMILY_PLUGIN_CARD_SEAT = "web-ui.plugin.item";
|
|
5650
|
+
/** The official keyed plugin-card seat key. */
|
|
5651
|
+
const OFFICIAL_PLUGIN_CARD_SEAT = "settings.plugin.item";
|
|
5652
|
+
/** The service dsh-web-settings publishes while it is loaded. */
|
|
5653
|
+
const FAMILY_GROUP_SERVICE = "webUiSettings";
|
|
5654
|
+
/**
|
|
5655
|
+
* Whether the family group (dsh-web-settings) is loaded in this page. The
|
|
5656
|
+
* service is the group package's own contract, so the probe cannot be fooled
|
|
5657
|
+
* by a harness release that starts declaring the official seat differently.
|
|
5658
|
+
*/
|
|
5659
|
+
function familyGroupLoaded(ctx) {
|
|
5660
|
+
const get = ctx.get;
|
|
5661
|
+
if (typeof get !== "function") return false;
|
|
5662
|
+
try {
|
|
5663
|
+
return get.call(ctx, FAMILY_GROUP_SERVICE) !== void 0;
|
|
5664
|
+
} catch {
|
|
5665
|
+
return false;
|
|
5666
|
+
}
|
|
5667
|
+
}
|
|
5668
|
+
/** Report a refused registration instead of leaving the user with no card. */
|
|
5669
|
+
function warnRefusedSeat(seat, error) {
|
|
5670
|
+
try {
|
|
5671
|
+
console.warn(`[dsh-web] plugin card registration into "${seat}" was refused; the card will not render`, error);
|
|
5672
|
+
} catch {}
|
|
5673
|
+
}
|
|
5674
|
+
/**
|
|
5675
|
+
* Contribute one family plugin card to the seat this host renders, following
|
|
5676
|
+
* the group if it loads later. The entry is disposed and re-registered on a
|
|
5677
|
+
* seat change, never duplicated.
|
|
5678
|
+
* @param ctx - client context (its slot registry decides the seat).
|
|
5679
|
+
* @param seat - the card contribution.
|
|
5680
|
+
*/
|
|
5681
|
+
function installPluginCard(ctx, seat) {
|
|
5682
|
+
const slots = ctx.slots;
|
|
5683
|
+
const component = seat.component;
|
|
5684
|
+
const inject = seat.inject;
|
|
5685
|
+
let dispose;
|
|
5686
|
+
let current;
|
|
5687
|
+
/**
|
|
5688
|
+
* Re-entrancy latch. The registry emits a change event synchronously from
|
|
5689
|
+
* inside both `register` and the previous entry's disposer, so an unguarded
|
|
5690
|
+
* reconcile would re-enter itself mid-move and register the card twice into
|
|
5691
|
+
* the seat it is leaving ("already has an entry for key ...").
|
|
5692
|
+
*/
|
|
5693
|
+
let reconciling = false;
|
|
5694
|
+
/** Reconcile the contribution with the currently live seat (no-op when unchanged). */
|
|
5695
|
+
const reconcile = () => {
|
|
5696
|
+
if (reconciling) return;
|
|
5697
|
+
const target = familyGroupLoaded(ctx) ? FAMILY_PLUGIN_CARD_SEAT : OFFICIAL_PLUGIN_CARD_SEAT;
|
|
5698
|
+
if (current === target) return;
|
|
5699
|
+
reconciling = true;
|
|
5700
|
+
const previous = dispose;
|
|
5701
|
+
dispose = void 0;
|
|
5702
|
+
current = void 0;
|
|
5703
|
+
previous?.();
|
|
5704
|
+
try {
|
|
5705
|
+
dispose = slots.register(target === "web-ui.plugin.item" ? {
|
|
5706
|
+
name: FAMILY_PLUGIN_CARD_SEAT,
|
|
5707
|
+
id: seat.id,
|
|
5708
|
+
...seat.order === void 0 ? {} : { order: seat.order },
|
|
5709
|
+
...seat.label === void 0 ? {} : { label: seat.label },
|
|
5710
|
+
locale: seat.locale,
|
|
5711
|
+
...seat.inject === void 0 ? {} : { inject }
|
|
5712
|
+
} : {
|
|
5713
|
+
name: OFFICIAL_PLUGIN_CARD_SEAT,
|
|
5714
|
+
key: seat.namespace,
|
|
5715
|
+
locale: seat.locale,
|
|
5716
|
+
...seat.inject === void 0 ? {} : { inject }
|
|
5717
|
+
}, component);
|
|
5718
|
+
current = target;
|
|
5719
|
+
} catch (error) {
|
|
5720
|
+
warnRefusedSeat(target, error);
|
|
5721
|
+
} finally {
|
|
5722
|
+
reconciling = false;
|
|
5723
|
+
}
|
|
5724
|
+
};
|
|
5725
|
+
if (typeof ctx.on === "function") try {
|
|
5726
|
+
ctx.on("slots/changed", () => {
|
|
5727
|
+
reconcile();
|
|
5728
|
+
});
|
|
5729
|
+
} catch {}
|
|
5730
|
+
reconcile();
|
|
5731
|
+
}
|
|
5732
|
+
//#endregion
|
|
5075
5733
|
//#region src/client/index.ts
|
|
5076
5734
|
/** Locale namespace this plugin owns. */
|
|
5077
5735
|
const NS = "task-board";
|
|
@@ -5118,23 +5776,17 @@ window.__ModuleLoader__.load({
|
|
|
5118
5776
|
} catch {}
|
|
5119
5777
|
const settingsScope = (ctx.get("webUiSettings") ?? ctx.settingsScope).bind({ namespace: TASK_BOARD_NS });
|
|
5120
5778
|
const settingsCard = new TaskBoardSettingsCardController(settingsScope);
|
|
5121
|
-
ctx
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
inject: () => settingsCard.inject()
|
|
5129
|
-
}, TaskBoardSettingsCard);
|
|
5130
|
-
return () => {
|
|
5131
|
-
settingsCard.dispose();
|
|
5132
|
-
unregister();
|
|
5133
|
-
};
|
|
5134
|
-
} catch {
|
|
5135
|
-
return () => {};
|
|
5136
|
-
}
|
|
5779
|
+
installPluginCard(ctx, {
|
|
5780
|
+
namespace: TASK_BOARD_NS,
|
|
5781
|
+
id: "task-board",
|
|
5782
|
+
order: 110,
|
|
5783
|
+
locale: NS,
|
|
5784
|
+
inject: () => settingsCard.inject(),
|
|
5785
|
+
component: TaskBoardSettingsCard
|
|
5137
5786
|
});
|
|
5787
|
+
ctx.effect(() => () => {
|
|
5788
|
+
settingsCard.dispose();
|
|
5789
|
+
}, "task-board: settings card");
|
|
5138
5790
|
let uiDisposer;
|
|
5139
5791
|
const mountUi = () => {
|
|
5140
5792
|
if (uiDisposer !== void 0) return;
|
|
@@ -5160,6 +5812,9 @@ window.__ModuleLoader__.load({
|
|
|
5160
5812
|
};
|
|
5161
5813
|
pushWorkspaceOptions();
|
|
5162
5814
|
disposers.push(workspaces.list.subscribe(pushWorkspaceOptions));
|
|
5815
|
+
controller.setWorkspaceCreator(async (path) => {
|
|
5816
|
+
return { workspaceId: (await workspaces.create({ path })).workspaceId };
|
|
5817
|
+
});
|
|
5163
5818
|
const pushModelOptions = async () => {
|
|
5164
5819
|
try {
|
|
5165
5820
|
let models = [];
|