@linxin666/dsh-client-ui-task-board 0.3.2 → 0.3.4
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 +6 -2
- package/README.zh.md +6 -2
- package/lib/client.js +437 -187
- package/lib/client.js.map +1 -1
- package/lib/index.js +45 -9
- package/lib/types/client/PluginSettingsCard.d.ts +2 -0
- package/lib/types/client/board/EditTaskModal.d.ts +8 -0
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/client/locales.d.ts +3 -0
- package/lib/types/client/settings-form.d.ts +1 -1
- package/lib/types/client/telemetry.d.ts +26 -0
- package/lib/types/core/controller.d.ts +9 -1
- package/lib/types/core/use-cases/task-update.d.ts +19 -3
- package/lib/types/http.d.ts +1 -1
- package/lib/types/index.d.ts +1 -1
- package/lib/types/loopback.d.ts +1 -1
- package/lib/types/mount-once.d.ts +1 -1
- package/package.json +2 -4
- package/src/client/PluginSettingsCard.tsx +4 -2
- package/src/client/board/EditTaskModal.tsx +94 -0
- package/src/client/board/TaskBoard.tsx +1 -1
- package/src/client/board/TaskDetail.tsx +19 -0
- package/src/client/index.ts +6 -1
- package/src/client/locales.ts +6 -0
- package/src/client/settings-card.module.css +5 -0
- package/src/client/settings-form.ts +1 -1
- package/src/client/telemetry.ts +105 -0
- package/src/core/controller.ts +11 -3
- package/src/core/use-cases/task-update.ts +33 -3
- package/src/dsh-home.ts +9 -3
- package/src/host-ledger.ts +9 -1
- package/src/http.ts +1 -1
- package/src/index.ts +1 -1
- package/src/loopback.ts +1 -1
- package/src/mount-once.ts +2 -2
package/lib/client.js
CHANGED
|
@@ -451,10 +451,30 @@ window.__ModuleLoader__.load({
|
|
|
451
451
|
* fresh updatedAt. Pure ledger transition (no persistence or notify — the
|
|
452
452
|
* controller orchestrates those).
|
|
453
453
|
*
|
|
454
|
-
* An explicit `undefined` in the patch clears
|
|
455
|
-
* back to the runtime default);
|
|
456
|
-
*
|
|
454
|
+
* An explicit `undefined` in the patch clears an execution-target field
|
|
455
|
+
* (the task falls back to the runtime default); content fields are trimmed
|
|
456
|
+
* and never cleared. An unknown permission string is ignored so stale UI
|
|
457
|
+
* can never persist a value the execution service rejects.
|
|
457
458
|
*/
|
|
459
|
+
/**
|
|
460
|
+
* The fields that edit the task's content (what the user reads and what the
|
|
461
|
+
* next execution sends). Unlike the execution targets they stay editable only
|
|
462
|
+
* while the task has never started executing — after the first run the
|
|
463
|
+
* recorded prompt is the record of what actually ran, so it becomes read-only.
|
|
464
|
+
*/
|
|
465
|
+
const TASK_CONTENT_FIELDS = [
|
|
466
|
+
"title",
|
|
467
|
+
"description",
|
|
468
|
+
"prompt"
|
|
469
|
+
];
|
|
470
|
+
/**
|
|
471
|
+
* Whether a task's content may still be edited: the task must be on-board
|
|
472
|
+
* (not archived) and must never have started executing. Fail-closed: a
|
|
473
|
+
* running, settled, or cancelled-before-launch task keeps its content fixed.
|
|
474
|
+
*/
|
|
475
|
+
function canEditTaskContent(task) {
|
|
476
|
+
return task.archivedAt === void 0 && task.status !== "running" && task.executions.length === 0;
|
|
477
|
+
}
|
|
458
478
|
/** Keep an unknown permission string from entering the ledger. */
|
|
459
479
|
function normalizePermission(current, value) {
|
|
460
480
|
if (value === void 0) return void 0;
|
|
@@ -479,6 +499,11 @@ window.__ModuleLoader__.load({
|
|
|
479
499
|
...patch,
|
|
480
500
|
updatedAt: now
|
|
481
501
|
};
|
|
502
|
+
for (const field of TASK_CONTENT_FIELDS) {
|
|
503
|
+
if (!(field in patch)) continue;
|
|
504
|
+
const value = patch[field];
|
|
505
|
+
next[field] = value === void 0 ? task[field] : value.trim();
|
|
506
|
+
}
|
|
482
507
|
if (workspaceId !== void 0 || "workspaceId" in patch) next.workspaceId = workspaceId;
|
|
483
508
|
if (mode !== void 0 || "mode" in patch) next.mode = mode;
|
|
484
509
|
if (permission !== void 0 || "permission" in patch) next.permission = permission;
|
|
@@ -641,17 +666,23 @@ window.__ModuleLoader__.load({
|
|
|
641
666
|
input
|
|
642
667
|
}, id) ? this.tasks.find((task) => task.id === id) : void 0;
|
|
643
668
|
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
669
|
+
/**
|
|
670
|
+
* Apply an editable-field patch (task content + execution targets).
|
|
671
|
+
* Host-backed: the Host ledger owns the fail-closed checks (the content of
|
|
672
|
+
* an executed task is read-only) and confirms the mutation, so the resolved
|
|
673
|
+
* value reflects whether the Host accepted it; the legacy in-memory path
|
|
674
|
+
* applies and persists synchronously.
|
|
675
|
+
* @returns true when the patch was accepted by the authority.
|
|
676
|
+
*/
|
|
677
|
+
async updateTask(id, patch) {
|
|
678
|
+
if (this.deps.transport !== void 0) return await this.commitRemote({
|
|
679
|
+
kind: "update",
|
|
680
|
+
taskId: id,
|
|
681
|
+
patch
|
|
682
|
+
}, id);
|
|
653
683
|
this.tasks = [...applyUpdateTask(this.tasks, id, patch, this.now())];
|
|
654
684
|
this.persistAndNotify();
|
|
685
|
+
return true;
|
|
655
686
|
}
|
|
656
687
|
/**
|
|
657
688
|
* Replace (a part of) the picker option sets the UI feeds (workspace list
|
|
@@ -1143,7 +1174,10 @@ window.__ModuleLoader__.load({
|
|
|
1143
1174
|
"new.cancel": "取消",
|
|
1144
1175
|
"new.required": "标题不能为空",
|
|
1145
1176
|
"detail.title": "任务详情",
|
|
1177
|
+
"detail.edit": "编辑",
|
|
1146
1178
|
"detail.close": "关闭",
|
|
1179
|
+
"edit.title": "编辑任务",
|
|
1180
|
+
"edit.save": "保存",
|
|
1147
1181
|
"detail.prompt": "执行 Prompt",
|
|
1148
1182
|
"detail.description": "描述",
|
|
1149
1183
|
"detail.execution": "执行记录",
|
|
@@ -1264,7 +1298,10 @@ window.__ModuleLoader__.load({
|
|
|
1264
1298
|
"new.cancel": "Cancel",
|
|
1265
1299
|
"new.required": "Title is required",
|
|
1266
1300
|
"detail.title": "Task Detail",
|
|
1301
|
+
"detail.edit": "Edit",
|
|
1267
1302
|
"detail.close": "Close",
|
|
1303
|
+
"edit.title": "Edit Task",
|
|
1304
|
+
"edit.save": "Save",
|
|
1268
1305
|
"detail.prompt": "Run Prompt",
|
|
1269
1306
|
"detail.description": "Description",
|
|
1270
1307
|
"detail.execution": "Execution History",
|
|
@@ -1877,6 +1914,125 @@ window.__ModuleLoader__.load({
|
|
|
1877
1914
|
});
|
|
1878
1915
|
}
|
|
1879
1916
|
//#endregion
|
|
1917
|
+
//#region src/client/board/EditTaskModal.tsx
|
|
1918
|
+
/**
|
|
1919
|
+
* Edit-task modal: title + description + the prompt the next execution will
|
|
1920
|
+
* send, pre-filled from the task. Shown only for tasks that have never
|
|
1921
|
+
* started executing (the detail view gates on canEditTaskContent); the Host
|
|
1922
|
+
* still re-checks at submit, so a task that started running while the modal
|
|
1923
|
+
* was open fails closed and the error surfaces here.
|
|
1924
|
+
*/
|
|
1925
|
+
/** Edit-task form overlay. */
|
|
1926
|
+
function EditTaskModal({ controller, task, onClose }) {
|
|
1927
|
+
const [title, setTitle] = (0, react.useState)(task.title);
|
|
1928
|
+
const [description, setDescription] = (0, react.useState)(task.description);
|
|
1929
|
+
const [prompt, setPrompt] = (0, react.useState)(task.prompt);
|
|
1930
|
+
const [error, setError] = (0, react.useState)(void 0);
|
|
1931
|
+
const [pending, setPending] = (0, react.useState)(false);
|
|
1932
|
+
const submit = async () => {
|
|
1933
|
+
if (title.trim() === "") {
|
|
1934
|
+
setError(t("new.required"));
|
|
1935
|
+
return;
|
|
1936
|
+
}
|
|
1937
|
+
setPending(true);
|
|
1938
|
+
if (await controller.updateTask(task.id, {
|
|
1939
|
+
title,
|
|
1940
|
+
description,
|
|
1941
|
+
prompt
|
|
1942
|
+
})) {
|
|
1943
|
+
onClose();
|
|
1944
|
+
return;
|
|
1945
|
+
}
|
|
1946
|
+
setPending(false);
|
|
1947
|
+
setError(controller.getSnapshot().transportError ?? t("new.required"));
|
|
1948
|
+
};
|
|
1949
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1950
|
+
className: board_module_css_default.modalBackdrop,
|
|
1951
|
+
onMouseDown: (event) => {
|
|
1952
|
+
if (event.target === event.currentTarget) onClose();
|
|
1953
|
+
},
|
|
1954
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
1955
|
+
className: board_module_css_default.modal,
|
|
1956
|
+
role: "dialog",
|
|
1957
|
+
"aria-label": t("edit.title"),
|
|
1958
|
+
onSubmit: (event) => {
|
|
1959
|
+
event.preventDefault();
|
|
1960
|
+
submit();
|
|
1961
|
+
},
|
|
1962
|
+
children: [
|
|
1963
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
1964
|
+
className: board_module_css_default.modalTitle,
|
|
1965
|
+
children: t("edit.title")
|
|
1966
|
+
}),
|
|
1967
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1968
|
+
className: board_module_css_default.field,
|
|
1969
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1970
|
+
className: board_module_css_default.fieldLabel,
|
|
1971
|
+
children: t("new.title")
|
|
1972
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1973
|
+
className: board_module_css_default.input,
|
|
1974
|
+
value: title,
|
|
1975
|
+
autoFocus: true,
|
|
1976
|
+
placeholder: t("new.titlePlaceholder"),
|
|
1977
|
+
onChange: (event) => {
|
|
1978
|
+
setTitle(event.target.value);
|
|
1979
|
+
setError(void 0);
|
|
1980
|
+
}
|
|
1981
|
+
})]
|
|
1982
|
+
}),
|
|
1983
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1984
|
+
className: board_module_css_default.field,
|
|
1985
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1986
|
+
className: board_module_css_default.fieldLabel,
|
|
1987
|
+
children: t("new.description")
|
|
1988
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
1989
|
+
className: board_module_css_default.input,
|
|
1990
|
+
rows: 3,
|
|
1991
|
+
value: description,
|
|
1992
|
+
placeholder: t("new.descriptionPlaceholder"),
|
|
1993
|
+
onChange: (event) => {
|
|
1994
|
+
setDescription(event.target.value);
|
|
1995
|
+
}
|
|
1996
|
+
})]
|
|
1997
|
+
}),
|
|
1998
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1999
|
+
className: board_module_css_default.field,
|
|
2000
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2001
|
+
className: board_module_css_default.fieldLabel,
|
|
2002
|
+
children: t("new.prompt")
|
|
2003
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
2004
|
+
className: board_module_css_default.input,
|
|
2005
|
+
rows: 4,
|
|
2006
|
+
value: prompt,
|
|
2007
|
+
placeholder: t("new.promptPlaceholder"),
|
|
2008
|
+
onChange: (event) => {
|
|
2009
|
+
setPrompt(event.target.value);
|
|
2010
|
+
}
|
|
2011
|
+
})]
|
|
2012
|
+
}),
|
|
2013
|
+
error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2014
|
+
className: board_module_css_default.formError,
|
|
2015
|
+
children: error
|
|
2016
|
+
}),
|
|
2017
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
|
|
2018
|
+
className: board_module_css_default.modalFooter,
|
|
2019
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2020
|
+
type: "button",
|
|
2021
|
+
className: board_module_css_default.ghostButton,
|
|
2022
|
+
onClick: onClose,
|
|
2023
|
+
children: t("new.cancel")
|
|
2024
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2025
|
+
type: "submit",
|
|
2026
|
+
className: board_module_css_default.primaryButton,
|
|
2027
|
+
disabled: pending,
|
|
2028
|
+
children: t("edit.save")
|
|
2029
|
+
})]
|
|
2030
|
+
})
|
|
2031
|
+
]
|
|
2032
|
+
})
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
//#endregion
|
|
1880
2036
|
//#region src/client/board/TaskDetail.tsx
|
|
1881
2037
|
/**
|
|
1882
2038
|
* Task detail: the full view of one task — content, prompt, execution
|
|
@@ -2156,10 +2312,14 @@ window.__ModuleLoader__.load({
|
|
|
2156
2312
|
/** Task detail overlay. */
|
|
2157
2313
|
function TaskDetail({ controller, task }) {
|
|
2158
2314
|
const [confirmDelete, setConfirmDelete] = (0, react.useState)(false);
|
|
2315
|
+
const [showEdit, setShowEdit] = (0, react.useState)(false);
|
|
2159
2316
|
const [latest, setLatest] = (0, react.useState)(task);
|
|
2160
2317
|
(0, react.useEffect)(() => {
|
|
2161
2318
|
setLatest(task);
|
|
2162
2319
|
}, [task]);
|
|
2320
|
+
(0, react.useEffect)(() => {
|
|
2321
|
+
setShowEdit(false);
|
|
2322
|
+
}, [task.id]);
|
|
2163
2323
|
const current = latest;
|
|
2164
2324
|
const snapshot = controller.getSnapshot();
|
|
2165
2325
|
const running = current.status === "running";
|
|
@@ -2172,177 +2332,196 @@ window.__ModuleLoader__.load({
|
|
|
2172
2332
|
onMouseDown: (event) => {
|
|
2173
2333
|
if (event.target === event.currentTarget) controller.closeTask();
|
|
2174
2334
|
},
|
|
2175
|
-
children: [
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
execution,
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
}
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2335
|
+
children: [
|
|
2336
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2337
|
+
className: board_module_css_default.detail,
|
|
2338
|
+
role: "dialog",
|
|
2339
|
+
"aria-label": t("detail.title"),
|
|
2340
|
+
children: [
|
|
2341
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
2342
|
+
className: board_module_css_default.detailHeader,
|
|
2343
|
+
children: [
|
|
2344
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
2345
|
+
className: board_module_css_default.detailTitle,
|
|
2346
|
+
children: current.title
|
|
2347
|
+
}),
|
|
2348
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2349
|
+
className: board_module_css_default.statusBadge,
|
|
2350
|
+
"data-status": archived ? "archived" : current.status,
|
|
2351
|
+
children: archived ? t("board.archive") : t(STATUS_KEY[current.status])
|
|
2352
|
+
}),
|
|
2353
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2354
|
+
type: "button",
|
|
2355
|
+
className: board_module_css_default.iconButton,
|
|
2356
|
+
"aria-label": t("detail.close"),
|
|
2357
|
+
onClick: () => {
|
|
2358
|
+
controller.closeTask();
|
|
2359
|
+
},
|
|
2360
|
+
children: "×"
|
|
2361
|
+
})
|
|
2362
|
+
]
|
|
2363
|
+
}),
|
|
2364
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2365
|
+
className: board_module_css_default.detailBody,
|
|
2366
|
+
children: [
|
|
2367
|
+
transportError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2368
|
+
className: board_module_css_default.formError,
|
|
2369
|
+
children: [
|
|
2370
|
+
t("board.hostError", { error: transportError }),
|
|
2371
|
+
" ",
|
|
2372
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2373
|
+
type: "button",
|
|
2374
|
+
className: board_module_css_default.linkButton,
|
|
2375
|
+
onClick: () => {
|
|
2376
|
+
controller.retryHostSync();
|
|
2377
|
+
},
|
|
2378
|
+
children: t("board.retryHost")
|
|
2379
|
+
})
|
|
2380
|
+
]
|
|
2381
|
+
}),
|
|
2382
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2383
|
+
className: board_module_css_default.detailSection,
|
|
2384
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: t("detail.description") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2385
|
+
className: board_module_css_default.detailText,
|
|
2386
|
+
children: current.description !== "" ? current.description : "—"
|
|
2387
|
+
})]
|
|
2388
|
+
}),
|
|
2389
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2390
|
+
className: board_module_css_default.detailSection,
|
|
2391
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: t("detail.prompt") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
2392
|
+
className: board_module_css_default.promptBlock,
|
|
2393
|
+
children: current.prompt !== "" ? current.prompt : current.title
|
|
2394
|
+
})]
|
|
2395
|
+
}),
|
|
2396
|
+
!archived && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExecutionSettingsSection, {
|
|
2397
|
+
controller,
|
|
2398
|
+
task: current,
|
|
2399
|
+
pending
|
|
2400
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScheduleSection, {
|
|
2401
|
+
controller,
|
|
2402
|
+
task: current,
|
|
2403
|
+
pending
|
|
2404
|
+
})] }),
|
|
2405
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2406
|
+
className: board_module_css_default.detailSection,
|
|
2407
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: t("detail.execution") }), current.executions.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2408
|
+
className: board_module_css_default.detailText,
|
|
2409
|
+
children: t("detail.noExecution")
|
|
2410
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
2411
|
+
className: board_module_css_default.executionList,
|
|
2412
|
+
children: [...current.executions].reverse().map((execution) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExecutionRow, {
|
|
2413
|
+
execution,
|
|
2414
|
+
timeZone,
|
|
2415
|
+
onOpen: (sessionId) => {
|
|
2416
|
+
controller.openSession(sessionId);
|
|
2417
|
+
}
|
|
2418
|
+
}, execution.id))
|
|
2419
|
+
})]
|
|
2420
|
+
}),
|
|
2421
|
+
!archived && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2422
|
+
className: board_module_css_default.detailSection,
|
|
2423
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: t("board.status") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2424
|
+
className: board_module_css_default.moveRow,
|
|
2425
|
+
children: MANUAL_STATUSES.map((status) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2426
|
+
type: "button",
|
|
2427
|
+
className: board_module_css_default.ghostButton,
|
|
2428
|
+
disabled: current.status === status || running || pending,
|
|
2429
|
+
onClick: () => {
|
|
2430
|
+
controller.moveTask(current.id, status);
|
|
2431
|
+
},
|
|
2432
|
+
children: t(`status.move.${status}`)
|
|
2433
|
+
}, status))
|
|
2434
|
+
})]
|
|
2435
|
+
})
|
|
2436
|
+
]
|
|
2437
|
+
}),
|
|
2438
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
|
|
2439
|
+
className: board_module_css_default.detailFooter,
|
|
2440
|
+
children: [
|
|
2441
|
+
!archived && pending && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2442
|
+
className: board_module_css_default.detailMeta,
|
|
2443
|
+
children: [t("board.pending"), "…"]
|
|
2444
|
+
}),
|
|
2445
|
+
!archived && canEditTaskContent(current) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2446
|
+
type: "button",
|
|
2447
|
+
className: board_module_css_default.ghostButton,
|
|
2448
|
+
disabled: pending,
|
|
2449
|
+
onClick: () => {
|
|
2450
|
+
setShowEdit(true);
|
|
2451
|
+
},
|
|
2452
|
+
children: t("detail.edit")
|
|
2453
|
+
}),
|
|
2454
|
+
!archived && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2455
|
+
type: "button",
|
|
2456
|
+
className: board_module_css_default.primaryButton,
|
|
2457
|
+
disabled: running || pending,
|
|
2458
|
+
onClick: () => {
|
|
2459
|
+
controller.rerunTask(current.id).then(() => {
|
|
2460
|
+
if (controller.getSnapshot().transportError === void 0) controller.closeTask();
|
|
2461
|
+
});
|
|
2462
|
+
},
|
|
2463
|
+
children: current.executions.length === 0 ? t("detail.run") : t("detail.rerun")
|
|
2464
|
+
}),
|
|
2465
|
+
archived ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2466
|
+
type: "button",
|
|
2467
|
+
className: board_module_css_default.primaryButton,
|
|
2468
|
+
disabled: pending,
|
|
2469
|
+
onClick: () => {
|
|
2470
|
+
controller.restoreTask(current.id);
|
|
2471
|
+
},
|
|
2472
|
+
children: t("detail.restore")
|
|
2473
|
+
}) : (current.status === "done" || current.status === "failed") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2474
|
+
type: "button",
|
|
2475
|
+
className: board_module_css_default.ghostButton,
|
|
2476
|
+
disabled: pending,
|
|
2477
|
+
onClick: () => {
|
|
2478
|
+
controller.archiveTask(current.id);
|
|
2479
|
+
},
|
|
2480
|
+
children: t("detail.archive")
|
|
2481
|
+
}),
|
|
2482
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2483
|
+
type: "button",
|
|
2484
|
+
className: board_module_css_default.dangerButton,
|
|
2485
|
+
disabled: pending,
|
|
2486
|
+
onClick: () => {
|
|
2487
|
+
setConfirmDelete(true);
|
|
2488
|
+
},
|
|
2489
|
+
children: t("detail.delete")
|
|
2490
|
+
}),
|
|
2491
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2492
|
+
className: board_module_css_default.detailMeta,
|
|
2493
|
+
children: [
|
|
2494
|
+
t("board.created"),
|
|
2495
|
+
" ",
|
|
2496
|
+
formatTime(current.createdAt, timeZone),
|
|
2497
|
+
archived && ` · ${t("detail.archivedAt", { time: formatTime(current.archivedAt, timeZone) })}`
|
|
2498
|
+
]
|
|
2499
|
+
})
|
|
2500
|
+
]
|
|
2501
|
+
})
|
|
2502
|
+
]
|
|
2503
|
+
}),
|
|
2504
|
+
confirmDelete && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfirmDialog, {
|
|
2505
|
+
title: t("delete.title"),
|
|
2506
|
+
message: t("delete.confirm", { name: current.title }),
|
|
2507
|
+
confirmLabel: t("delete.ok"),
|
|
2508
|
+
danger: true,
|
|
2509
|
+
onCancel: () => {
|
|
2510
|
+
setConfirmDelete(false);
|
|
2511
|
+
},
|
|
2512
|
+
onConfirm: () => {
|
|
2513
|
+
setConfirmDelete(false);
|
|
2514
|
+
controller.deleteTask(current.id);
|
|
2515
|
+
}
|
|
2516
|
+
}),
|
|
2517
|
+
showEdit && !archived && canEditTaskContent(current) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EditTaskModal, {
|
|
2518
|
+
controller,
|
|
2519
|
+
task: current,
|
|
2520
|
+
onClose: () => {
|
|
2521
|
+
setShowEdit(false);
|
|
2522
|
+
}
|
|
2523
|
+
})
|
|
2524
|
+
]
|
|
2346
2525
|
});
|
|
2347
2526
|
}
|
|
2348
2527
|
//#endregion
|
|
@@ -2767,7 +2946,7 @@ window.__ModuleLoader__.load({
|
|
|
2767
2946
|
}
|
|
2768
2947
|
//#endregion
|
|
2769
2948
|
//#region \0dsh-css:packages/dsh-task-board/src/client/settings-card.module.css.mjs
|
|
2770
|
-
const css = ".Jh0q7G_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.Jh0q7G_card:hover{border-color:var(--dsw-alias-label-dimmed)}.Jh0q7G_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.Jh0q7G_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.Jh0q7G_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.Jh0q7G_headerStatic{border-radius:12px;align-items:center;gap:12px;width:100%;padding:14px 16px;display:flex}.Jh0q7G_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.Jh0q7G_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.Jh0q7G_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.Jh0q7G_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Jh0q7G_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.Jh0q7G_chevronOpen{transform:rotate(180deg)}.Jh0q7G_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.Jh0q7G_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.Jh0q7G_notExposed{color:var(--dsw-alias-state-warn-primary);margin:12px 0 0;font-size:12px;line-height:1.5}.Jh0q7G_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.Jh0q7G_failed{min-width:0;color:var(--dsw-alias-label-error);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:12px;line-height:1.5;overflow:hidden}.Jh0q7G_discard,.Jh0q7G_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.Jh0q7G_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.Jh0q7G_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.Jh0q7G_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.Jh0q7G_discard:disabled,.Jh0q7G_save:disabled{opacity:.4;cursor:default}.Jh0q7G_discard:focus-visible,.Jh0q7G_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Jh0q7G_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.Jh0q7G_field+.Jh0q7G_field{border-top:1px solid var(--dsw-alias-border-l2)}.Jh0q7G_head{align-items:center;gap:8px;display:flex}.Jh0q7G_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.Jh0q7G_badges{align-items:center;gap:8px;display:inline-flex}.Jh0q7G_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Jh0q7G_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.Jh0q7G_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.Jh0q7G_reset:disabled{cursor:default}.Jh0q7G_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.Jh0q7G_input,.Jh0q7G_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Jh0q7G_input:focus-visible,.Jh0q7G_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.Jh0q7G_input:disabled,.Jh0q7G_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.Jh0q7G_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Jh0q7G_inputInvalid:focus-visible{outline:2px solid var(--dsw-alias-label-error);outline-offset:1px;border-color:var(--dsw-alias-label-error)}.Jh0q7G_selectWrap{position:relative}.Jh0q7G_selectButton{appearance:none;text-align:left;cursor:pointer;justify-content:space-between;align-items:center;gap:8px;width:100%;display:flex}.Jh0q7G_selectLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.Jh0q7G_selectChevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.Jh0q7G_selectChevronOpen{transform:rotate(180deg)}.Jh0q7G_selectPopup{z-index:40;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);max-height:240px;box-shadow:0 8px 24px var(--dsw-alias-bg-mask-2);opacity:0;border-radius:8px;flex-direction:column;padding:4px;transition:opacity .1s,transform .1s;display:flex;position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto;transform:translateY(-4px)}.Jh0q7G_selectPopupOpen{opacity:1;transform:none}.Jh0q7G_selectPopupClose{opacity:0;pointer-events:none;transform:translateY(-4px)}.Jh0q7G_selectOption{color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;text-overflow:ellipsis;border-radius:6px;flex-shrink:0;padding:6px 10px;font-size:13px;line-height:1.5;overflow:hidden}.Jh0q7G_selectOption:hover,.Jh0q7G_selectOptionActive{background:var(--dsw-alias-interactive-bg-hover)}.Jh0q7G_selectOptionSelected{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 10%, transparent);font-weight:500}.Jh0q7G_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.Jh0q7G_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}@media (prefers-reduced-motion:reduce){.Jh0q7G_card,.Jh0q7G_header,.Jh0q7G_chevron,.Jh0q7G_chevronOpen,.Jh0q7G_discard,.Jh0q7G_save,.Jh0q7G_selectChevron,.Jh0q7G_selectChevronOpen,.Jh0q7G_selectPopup{transition:none}}";
|
|
2949
|
+
const css = ".Jh0q7G_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.Jh0q7G_card:hover{border-color:var(--dsw-alias-label-dimmed)}.Jh0q7G_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.Jh0q7G_header{appearance:none;box-sizing:border-box;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.Jh0q7G_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.Jh0q7G_headerStatic{box-sizing:border-box;border-radius:12px;align-items:center;gap:12px;width:100%;padding:14px 16px;display:flex}.Jh0q7G_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.Jh0q7G_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.Jh0q7G_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.Jh0q7G_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Jh0q7G_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.Jh0q7G_chevronOpen{transform:rotate(180deg)}.Jh0q7G_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.Jh0q7G_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.Jh0q7G_notExposed{color:var(--dsw-alias-state-warn-primary);margin:12px 0 0;font-size:12px;line-height:1.5}.Jh0q7G_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.Jh0q7G_failed{min-width:0;color:var(--dsw-alias-label-error);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:12px;line-height:1.5;overflow:hidden}.Jh0q7G_discard,.Jh0q7G_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.Jh0q7G_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.Jh0q7G_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.Jh0q7G_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.Jh0q7G_discard:disabled,.Jh0q7G_save:disabled{opacity:.4;cursor:default}.Jh0q7G_discard:focus-visible,.Jh0q7G_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Jh0q7G_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.Jh0q7G_field+.Jh0q7G_field{border-top:1px solid var(--dsw-alias-border-l2)}.Jh0q7G_head{align-items:center;gap:8px;display:flex}.Jh0q7G_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.Jh0q7G_badges{align-items:center;gap:8px;display:inline-flex}.Jh0q7G_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Jh0q7G_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.Jh0q7G_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.Jh0q7G_reset:disabled{cursor:default}.Jh0q7G_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.Jh0q7G_input,.Jh0q7G_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Jh0q7G_input:focus-visible,.Jh0q7G_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.Jh0q7G_input:disabled,.Jh0q7G_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.Jh0q7G_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Jh0q7G_inputInvalid:focus-visible{outline:2px solid var(--dsw-alias-label-error);outline-offset:1px;border-color:var(--dsw-alias-label-error)}.Jh0q7G_selectWrap{position:relative}.Jh0q7G_selectButton{appearance:none;text-align:left;cursor:pointer;justify-content:space-between;align-items:center;gap:8px;width:100%;display:flex}.Jh0q7G_selectLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.Jh0q7G_selectChevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.Jh0q7G_selectChevronOpen{transform:rotate(180deg)}.Jh0q7G_selectPopup{z-index:40;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);max-height:240px;box-shadow:0 8px 24px var(--dsw-alias-bg-mask-2);opacity:0;border-radius:8px;flex-direction:column;padding:4px;transition:opacity .1s,transform .1s;display:flex;position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto;transform:translateY(-4px)}.Jh0q7G_selectPopupOpen{opacity:1;transform:none}.Jh0q7G_selectPopupClose{opacity:0;pointer-events:none;transform:translateY(-4px)}.Jh0q7G_selectOption{color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;text-overflow:ellipsis;border-radius:6px;flex-shrink:0;padding:6px 10px;font-size:13px;line-height:1.5;overflow:hidden}.Jh0q7G_selectOption:hover,.Jh0q7G_selectOptionActive{background:var(--dsw-alias-interactive-bg-hover)}.Jh0q7G_selectOptionSelected{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 10%, transparent);font-weight:500}.Jh0q7G_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.Jh0q7G_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}@media (prefers-reduced-motion:reduce){.Jh0q7G_card,.Jh0q7G_header,.Jh0q7G_chevron,.Jh0q7G_chevronOpen,.Jh0q7G_discard,.Jh0q7G_save,.Jh0q7G_selectChevron,.Jh0q7G_selectChevronOpen,.Jh0q7G_selectPopup{transition:none}}";
|
|
2771
2950
|
const tagId = "@linxin666/dsh-client-ui-task-board/settings-card.module.css";
|
|
2772
2951
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
2773
2952
|
const tag = document.createElement("style");
|
|
@@ -2852,7 +3031,7 @@ window.__ModuleLoader__.load({
|
|
|
2852
3031
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2853
3032
|
className: settings_card_module_css_default.description,
|
|
2854
3033
|
title: description,
|
|
2855
|
-
children: description
|
|
3034
|
+
children: props.descriptionNode ?? description
|
|
2856
3035
|
})]
|
|
2857
3036
|
}), state.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2858
3037
|
className: settings_card_module_css_default.pending,
|
|
@@ -2877,7 +3056,7 @@ window.__ModuleLoader__.load({
|
|
|
2877
3056
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2878
3057
|
className: settings_card_module_css_default.description,
|
|
2879
3058
|
title: description,
|
|
2880
|
-
children: description
|
|
3059
|
+
children: props.descriptionNode ?? description
|
|
2881
3060
|
})]
|
|
2882
3061
|
}),
|
|
2883
3062
|
state.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -3298,7 +3477,7 @@ window.__ModuleLoader__.load({
|
|
|
3298
3477
|
/**
|
|
3299
3478
|
* Write every staged edit, then re-seed from what the Host accepted.
|
|
3300
3479
|
*
|
|
3301
|
-
* When the scope carries the optional batch surface (the dsh-web
|
|
3480
|
+
* When the scope carries the optional batch surface (the dsh-web
|
|
3302
3481
|
* bridge scope), every planned write rides one mutation so cross-field
|
|
3303
3482
|
* validate hooks (baseURL+model) judge the batch as a unit instead of
|
|
3304
3483
|
* deadlocking on per-field writes. Otherwise the per-field loop runs.
|
|
@@ -3668,6 +3847,76 @@ window.__ModuleLoader__.load({
|
|
|
3668
3847
|
}
|
|
3669
3848
|
};
|
|
3670
3849
|
//#endregion
|
|
3850
|
+
//#region src/client/telemetry.ts
|
|
3851
|
+
const VISITOR_KEY = "dsh-web-ui-telemetry-visitor";
|
|
3852
|
+
const DAY_KEY_PREFIX = "dsh-web-ui-telemetry-day:";
|
|
3853
|
+
const ENDPOINT = "https://dsh-market.com/api/telemetry/event";
|
|
3854
|
+
/** The building package's version, when the bundle carries it. */
|
|
3855
|
+
function bakedVersion() {
|
|
3856
|
+
try {
|
|
3857
|
+
return "0.3.4";
|
|
3858
|
+
} catch {
|
|
3859
|
+
return;
|
|
3860
|
+
}
|
|
3861
|
+
}
|
|
3862
|
+
/** Read or lazily create the anonymous visitor id; null when storage is unavailable. */
|
|
3863
|
+
function visitorId() {
|
|
3864
|
+
try {
|
|
3865
|
+
const existing = localStorage.getItem(VISITOR_KEY);
|
|
3866
|
+
if (existing && /^[A-Za-z0-9_-]{16,64}$/.test(existing)) return existing;
|
|
3867
|
+
const fresh = crypto.randomUUID().replaceAll("-", "");
|
|
3868
|
+
localStorage.setItem(VISITOR_KEY, fresh);
|
|
3869
|
+
return fresh;
|
|
3870
|
+
} catch {
|
|
3871
|
+
return null;
|
|
3872
|
+
}
|
|
3873
|
+
}
|
|
3874
|
+
/** Drop stale per-day dedup keys so localStorage does not grow forever. */
|
|
3875
|
+
function pruneDayKeys(today) {
|
|
3876
|
+
try {
|
|
3877
|
+
for (let index = localStorage.length - 1; index >= 0; index -= 1) {
|
|
3878
|
+
const key = localStorage.key(index);
|
|
3879
|
+
if (key !== null && key.startsWith(DAY_KEY_PREFIX) && key !== DAY_KEY_PREFIX + today) localStorage.removeItem(key);
|
|
3880
|
+
}
|
|
3881
|
+
} catch {}
|
|
3882
|
+
}
|
|
3883
|
+
/**
|
|
3884
|
+
* Fire the daily heartbeat for the given items at most once per UTC day per
|
|
3885
|
+
* browser. Never throws and never blocks the caller. Items without an explicit
|
|
3886
|
+
* version inherit the bundle's baked build version.
|
|
3887
|
+
*/
|
|
3888
|
+
function reportDailyHeartbeat(items) {
|
|
3889
|
+
try {
|
|
3890
|
+
if (items.length === 0) return;
|
|
3891
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3892
|
+
if (navigator.webdriver) return;
|
|
3893
|
+
if (localStorage.getItem(DAY_KEY_PREFIX + today) !== null) return;
|
|
3894
|
+
const visitor = visitorId();
|
|
3895
|
+
if (visitor === null) return;
|
|
3896
|
+
pruneDayKeys(today);
|
|
3897
|
+
const payloadItems = items.map((item) => {
|
|
3898
|
+
const out = { name: item.name };
|
|
3899
|
+
const version = item.version ?? bakedVersion();
|
|
3900
|
+
if (version !== void 0) out.version = version;
|
|
3901
|
+
if (item.channel !== void 0) out.channel = item.channel;
|
|
3902
|
+
return out;
|
|
3903
|
+
});
|
|
3904
|
+
const body = JSON.stringify({
|
|
3905
|
+
kind: "heartbeat",
|
|
3906
|
+
visitor,
|
|
3907
|
+
items: payloadItems
|
|
3908
|
+
});
|
|
3909
|
+
fetch(ENDPOINT, {
|
|
3910
|
+
method: "POST",
|
|
3911
|
+
headers: { "content-type": "application/json" },
|
|
3912
|
+
body,
|
|
3913
|
+
keepalive: true
|
|
3914
|
+
}).then((response) => {
|
|
3915
|
+
if (response.ok) localStorage.setItem(DAY_KEY_PREFIX + today, "1");
|
|
3916
|
+
}).catch(() => {});
|
|
3917
|
+
} catch {}
|
|
3918
|
+
}
|
|
3919
|
+
//#endregion
|
|
3671
3920
|
//#region src/client/index.ts
|
|
3672
3921
|
/** Locale namespace this plugin owns. */
|
|
3673
3922
|
const NS = "task-board";
|
|
@@ -3688,6 +3937,7 @@ window.__ModuleLoader__.load({
|
|
|
3688
3937
|
* @param ctx - client root context (services: sessions, workspaces).
|
|
3689
3938
|
*/
|
|
3690
3939
|
function apply(ctx) {
|
|
3940
|
+
reportDailyHeartbeat([{ name: "@linxin666/dsh-client-ui-task-board" }]);
|
|
3691
3941
|
if (!claimTaskboardApply()) return;
|
|
3692
3942
|
ctx.effect(() => releaseTaskboardApply, "task-board: apply claim");
|
|
3693
3943
|
ctx.effect(() => {
|