@xirang-ai/dsh-teamflow 0.1.0 → 0.1.2
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.en.md +18 -14
- package/README.md +18 -14
- package/RELEASE.md +9 -9
- package/cordis.patch.yml +2 -0
- package/lib/client.js +494 -153
- package/lib/index.d.ts +7 -1
- package/lib/index.js +10 -4
- package/lib/remote/contract.d.ts +34 -1
- package/lib/remote/contract.js +16 -0
- package/lib/remote/service.d.ts +15 -2
- package/lib/remote/service.js +49 -6
- package/lib/requirement-discussion.d.ts +23 -0
- package/lib/requirement-discussion.js +26 -0
- package/lib/store/db.d.ts +8 -3
- package/lib/store/db.js +34 -2
- package/lib/store/docs.d.ts +9 -11
- package/lib/store/docs.js +25 -52
- package/lib/store/model.d.ts +23 -0
- package/lib/store/model.js +4 -0
- package/lib/store/paths.d.ts +20 -0
- package/lib/store/paths.js +54 -1
- package/lib/store/schema.js +71 -14
- package/lib/store/workflow.d.ts +50 -25
- package/lib/store/workflow.js +210 -97
- package/lib/tools/get-bug.js +1 -1
- package/lib/tools/get-design-doc.js +1 -1
- package/lib/tools/get-requirement.js +1 -1
- package/lib/tools/get-story.js +1 -1
- package/lib/tools/index.js +7 -0
- package/lib/tools/link-session.d.ts +3 -0
- package/lib/tools/link-session.js +87 -0
- package/locale/en.json +5 -1
- package/locale/zh.json +5 -1
- package/package.json +4 -4
package/lib/client.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* @xirang-ai/dsh-teamflow 0.1.
|
|
1
|
+
/* @xirang-ai/dsh-teamflow 0.1.2 — generated by scripts/build.mjs, do not edit. */
|
|
2
2
|
window.__ModuleLoader__.load({
|
|
3
3
|
id: "@xirang-ai/dsh-teamflow",
|
|
4
4
|
factory: (require) => {
|
|
@@ -234,10 +234,12 @@ window.__ModuleLoader__.load({
|
|
|
234
234
|
"composer.locked": "The conversation has started; create a new one to switch agents.",
|
|
235
235
|
"composer.noPreset": "The preset agent is not loaded, so the switch was not applied.",
|
|
236
236
|
"composer.other": "Other (default)",
|
|
237
|
-
"create.attachment.add": "Add
|
|
237
|
+
"create.attachment.add": "Add attachments",
|
|
238
238
|
"create.attachment.blocked": "Attachments are still uploading; wait for them to finish before sending.",
|
|
239
239
|
"create.attachment.busy": "The conversation is busy, so the attachments were not sent. Try again.",
|
|
240
240
|
"create.attachment.cancelled": "Upload cancelled; nothing was sent.",
|
|
241
|
+
"create.attachment.dropActive": "Release to attach these files.",
|
|
242
|
+
"create.attachment.dropHint": "Click to choose files, or drop them here.",
|
|
241
243
|
"create.attachment.failed": "Upload failed",
|
|
242
244
|
"create.attachment.failed.network": "The upload failed. Check the network and try again.",
|
|
243
245
|
"create.attachment.failed.rejected": "The host rejected the file (damaged content or wrong type).",
|
|
@@ -339,6 +341,7 @@ window.__ModuleLoader__.load({
|
|
|
339
341
|
"delete.statusMissing": "—",
|
|
340
342
|
"delete.summary": "{total} record(s), {deletable} deletable",
|
|
341
343
|
"detail.branch": "Branch",
|
|
344
|
+
"detail.bugDiscussion": "Discuss this bug in a new session",
|
|
342
345
|
"detail.bugBody": "What happened",
|
|
343
346
|
"detail.completedAt": "Completed",
|
|
344
347
|
"detail.description": "Description",
|
|
@@ -354,6 +357,7 @@ window.__ModuleLoader__.load({
|
|
|
354
357
|
"detail.discussionNewDetail": "Discuss the detailed design in a new conversation",
|
|
355
358
|
"detail.discussionNewSplit": "Split Stories in a new conversation",
|
|
356
359
|
"detail.discussionOpen": "Open",
|
|
360
|
+
"detail.storyDiscussion": "Discuss this story in a new session",
|
|
357
361
|
"detail.discussionStarting": "Creating conversation…",
|
|
358
362
|
"detail.docs": "Detailed design",
|
|
359
363
|
"detail.docsEmpty": "No detailed design written yet.",
|
|
@@ -570,10 +574,12 @@ window.__ModuleLoader__.load({
|
|
|
570
574
|
"composer.locked": "会话已开始,无法再切换 Agent;请新建会话。",
|
|
571
575
|
"composer.noPreset": "预设 Agent 未加载,无法切换。",
|
|
572
576
|
"composer.other": "其他(默认)",
|
|
573
|
-
"create.attachment.add": "
|
|
577
|
+
"create.attachment.add": "添加附件",
|
|
574
578
|
"create.attachment.blocked": "附件正在上传,上传完成后再提交。",
|
|
575
579
|
"create.attachment.busy": "会话正忙,附件未发送,请稍后重试。",
|
|
576
580
|
"create.attachment.cancelled": "已取消上传,附件未发送。",
|
|
581
|
+
"create.attachment.dropActive": "松手即可添加附件。",
|
|
582
|
+
"create.attachment.dropHint": "点击选择文件,或把文件拖到这里。",
|
|
577
583
|
"create.attachment.failed": "上传失败",
|
|
578
584
|
"create.attachment.failed.network": "上传暂时失败,请检查网络后重试。",
|
|
579
585
|
"create.attachment.failed.rejected": "宿主拒绝了该文件(内容损坏或类型不符)。",
|
|
@@ -675,6 +681,7 @@ window.__ModuleLoader__.load({
|
|
|
675
681
|
"delete.statusMissing": "—",
|
|
676
682
|
"delete.summary": "共 {total} 条,可删除 {deletable} 条",
|
|
677
683
|
"detail.branch": "分支",
|
|
684
|
+
"detail.bugDiscussion": "在新会话中进行缺陷讨论",
|
|
678
685
|
"detail.bugBody": "缺陷说明",
|
|
679
686
|
"detail.completedAt": "完成时间",
|
|
680
687
|
"detail.description": "故事说明",
|
|
@@ -690,6 +697,7 @@ window.__ModuleLoader__.load({
|
|
|
690
697
|
"detail.discussionNewDetail": "在新会话中进行详细设计讨论",
|
|
691
698
|
"detail.discussionNewSplit": "在新会话中进行故事拆分",
|
|
692
699
|
"detail.discussionOpen": "打开",
|
|
700
|
+
"detail.storyDiscussion": "在新会话中进行故事讨论",
|
|
693
701
|
"detail.discussionStarting": "正在创建会话…",
|
|
694
702
|
"detail.docs": "详细设计",
|
|
695
703
|
"detail.docsEmpty": "还没有写详细设计。",
|
|
@@ -893,6 +901,7 @@ window.__ModuleLoader__.load({
|
|
|
893
901
|
cancelStory: "cancelStory",
|
|
894
902
|
completeBug: "completeBug",
|
|
895
903
|
prepareRequirementSession: "prepareRequirementSession",
|
|
904
|
+
prepareDiscussionSession: "prepareDiscussionSession",
|
|
896
905
|
sessionPermissionTier: "sessionPermissionTier",
|
|
897
906
|
previewDelete: "previewDelete",
|
|
898
907
|
deleteRecords: "deleteRecords",
|
|
@@ -1030,6 +1039,21 @@ window.__ModuleLoader__.load({
|
|
|
1030
1039
|
]),
|
|
1031
1040
|
result: JSON_CODEC
|
|
1032
1041
|
}),
|
|
1042
|
+
Object.freeze({
|
|
1043
|
+
id: `${PACKAGE_NAME}#${METHODS.prepareDiscussionSession}`,
|
|
1044
|
+
service: SERVICE_KEY,
|
|
1045
|
+
namespace: NAMESPACE,
|
|
1046
|
+
method: METHODS.prepareDiscussionSession,
|
|
1047
|
+
invocation: { kind: "direct" },
|
|
1048
|
+
parameters: Object.freeze([
|
|
1049
|
+
parameter("subjectType", "Discussion subject: requirement, story or bug"),
|
|
1050
|
+
parameter("subjectId", "Requirement, story or defect the discussion belongs to"),
|
|
1051
|
+
parameter("sessionId", "Newly created conversation to link"),
|
|
1052
|
+
parameter("kind", "Discussion kind: discuss for stories and defects, the requirement kinds otherwise"),
|
|
1053
|
+
LOCALE_PARAMETER
|
|
1054
|
+
]),
|
|
1055
|
+
result: JSON_CODEC
|
|
1056
|
+
}),
|
|
1033
1057
|
Object.freeze({
|
|
1034
1058
|
id: `${PACKAGE_NAME}#${METHODS.sessionPermissionTier}`,
|
|
1035
1059
|
service: SERVICE_KEY,
|
|
@@ -1093,6 +1117,7 @@ window.__ModuleLoader__.load({
|
|
|
1093
1117
|
});
|
|
1094
1118
|
|
|
1095
1119
|
// src/client/composer.tsx
|
|
1120
|
+
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
1096
1121
|
var import_react = require("react");
|
|
1097
1122
|
|
|
1098
1123
|
// src/create.ts
|
|
@@ -1146,6 +1171,15 @@ window.__ModuleLoader__.load({
|
|
|
1146
1171
|
}
|
|
1147
1172
|
return ["【继续讨论需求与概要设计】", "", "我的补充:"].join("\n");
|
|
1148
1173
|
}
|
|
1174
|
+
var STORY_DISCUSSION_PRESET = "xirang-story";
|
|
1175
|
+
var BUG_DISCUSSION_PRESET = "xirang-bug";
|
|
1176
|
+
function presetForRecordDiscussion(kind) {
|
|
1177
|
+
return kind === "bug" ? BUG_DISCUSSION_PRESET : STORY_DISCUSSION_PRESET;
|
|
1178
|
+
}
|
|
1179
|
+
function buildRecordDiscussionPrompt(kind, title) {
|
|
1180
|
+
const heading = kind === "bug" ? "【继续讨论缺陷】" : "【继续讨论故事】";
|
|
1181
|
+
return [heading, title, "", "我的补充:"].join("\n");
|
|
1182
|
+
}
|
|
1149
1183
|
|
|
1150
1184
|
// src/client/composer-kind.ts
|
|
1151
1185
|
var COMPOSER_KINDS = [...CREATE_KINDS, "design", "detail", "split"];
|
|
@@ -2281,8 +2315,82 @@ window.__ModuleLoader__.load({
|
|
|
2281
2315
|
* Attachment block. The picker is the Host's own file input, so it keeps the
|
|
2282
2316
|
* Host rules for what can be selected; it is only hidden because the visible
|
|
2283
2317
|
* control is the card's button and native inputs cannot be styled consistently.
|
|
2318
|
+
* The whole card body is one picker: a large plus, the action, and what a drop
|
|
2319
|
+
* will do. It stays a real <button>, so the drop target always keeps a
|
|
2320
|
+
* keyboard and single-pointer equivalent for the drag gesture.
|
|
2321
|
+
*/
|
|
2322
|
+
.tf-attachment-pick {
|
|
2323
|
+
display: flex;
|
|
2324
|
+
flex-direction: column;
|
|
2325
|
+
align-items: center;
|
|
2326
|
+
justify-content: center;
|
|
2327
|
+
gap: 6px;
|
|
2328
|
+
width: 100%;
|
|
2329
|
+
min-height: 150px;
|
|
2330
|
+
margin-top: 10px;
|
|
2331
|
+
padding: 20px 16px;
|
|
2332
|
+
border: 1px dashed var(--dsw-alias-border-l3, currentColor);
|
|
2333
|
+
border-radius: 12px;
|
|
2334
|
+
background: var(--dsw-alias-bg-l2, transparent);
|
|
2335
|
+
color: var(--dsw-alias-label-secondary, inherit);
|
|
2336
|
+
font: inherit;
|
|
2337
|
+
text-align: center;
|
|
2338
|
+
cursor: pointer;
|
|
2339
|
+
transition: border-color .12s ease, background-color .12s ease;
|
|
2340
|
+
}
|
|
2341
|
+
.tf-attachment-pick:hover:not(:disabled) {
|
|
2342
|
+
border-color: var(--dsw-alias-state-business-primary, #4176e6);
|
|
2343
|
+
background: var(--dsw-alias-interactive-bg-hover, transparent);
|
|
2344
|
+
}
|
|
2345
|
+
.tf-attachment-pick:focus-visible {
|
|
2346
|
+
outline: 2px solid var(--dsw-alias-link, #4176e6);
|
|
2347
|
+
outline-offset: 2px;
|
|
2348
|
+
}
|
|
2349
|
+
.tf-attachment-pick:disabled { opacity: .5; cursor: default; }
|
|
2350
|
+
.tf-attachment-plus {
|
|
2351
|
+
display: grid;
|
|
2352
|
+
place-items: center;
|
|
2353
|
+
width: 40px;
|
|
2354
|
+
height: 40px;
|
|
2355
|
+
border-radius: 50%;
|
|
2356
|
+
background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .04));
|
|
2357
|
+
color: var(--dsw-alias-state-business-primary, #4176e6);
|
|
2358
|
+
font-size: 24px;
|
|
2359
|
+
font-weight: 300;
|
|
2360
|
+
line-height: 1;
|
|
2361
|
+
}
|
|
2362
|
+
.tf-attachment-pick-title {
|
|
2363
|
+
font-size: 13px;
|
|
2364
|
+
font-weight: 600;
|
|
2365
|
+
color: var(--dsw-alias-label-primary, inherit);
|
|
2366
|
+
}
|
|
2367
|
+
.tf-attachment-pick-sub {
|
|
2368
|
+
font-size: 11.5px;
|
|
2369
|
+
line-height: 1.5;
|
|
2370
|
+
color: var(--dsw-alias-label-tertiary, inherit);
|
|
2371
|
+
}
|
|
2372
|
+
.tf-attachment-limits {
|
|
2373
|
+
margin: 8px 0 0;
|
|
2374
|
+
font-size: 11.5px;
|
|
2375
|
+
line-height: 1.5;
|
|
2376
|
+
text-align: center;
|
|
2377
|
+
color: var(--dsw-alias-label-caption, inherit);
|
|
2378
|
+
}
|
|
2379
|
+
/*
|
|
2380
|
+
* The attachment card doubles as the drop target, so a file dropped anywhere
|
|
2381
|
+
* the user reads as "the attachment area" lands on the picker's own intake path.
|
|
2382
|
+
* Only the picker itself lights up while a file drag is inside the card, and its
|
|
2383
|
+
* subtitle says what releasing will do.
|
|
2284
2384
|
*/
|
|
2285
|
-
.tf-attachment-
|
|
2385
|
+
.tf-attachment-dropzone[data-drag='active'] .tf-attachment-pick {
|
|
2386
|
+
border-style: solid;
|
|
2387
|
+
border-color: var(--dsw-alias-state-business-primary, #4176e6);
|
|
2388
|
+
background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #4176e6) 7%, transparent);
|
|
2389
|
+
}
|
|
2390
|
+
.tf-attachment-dropzone[data-drag='active'] .tf-attachment-pick-sub {
|
|
2391
|
+
color: var(--dsw-alias-state-business-primary, #4176e6);
|
|
2392
|
+
font-weight: 600;
|
|
2393
|
+
}
|
|
2286
2394
|
.tf-attachment-input {
|
|
2287
2395
|
position: absolute;
|
|
2288
2396
|
width: 1px;
|
|
@@ -2472,23 +2580,37 @@ window.__ModuleLoader__.load({
|
|
|
2472
2580
|
`;
|
|
2473
2581
|
var COMPOSER_STYLES = `
|
|
2474
2582
|
.tf-composer { display: inline-flex; align-items: center; gap: 6px; min-width: 0; max-width: 100%; }
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
.tf-composer-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2583
|
+
/* Trigger matches the Host's composer selects (permission, model): same height,
|
|
2584
|
+
radius, spacing, type scale and interaction colors, all from theme tokens. */
|
|
2585
|
+
.tf-composer-trigger {
|
|
2586
|
+
display: inline-flex;
|
|
2587
|
+
align-items: center;
|
|
2588
|
+
gap: 4px;
|
|
2589
|
+
min-width: 0;
|
|
2590
|
+
max-width: 220px;
|
|
2591
|
+
height: 28px;
|
|
2592
|
+
padding: 0 4px 0 8px;
|
|
2593
|
+
border: none;
|
|
2594
|
+
border-radius: var(--dsw-radius-sm, 7px);
|
|
2595
|
+
background: none;
|
|
2484
2596
|
color: var(--dsw-alias-label-secondary, inherit);
|
|
2485
2597
|
font: inherit;
|
|
2486
|
-
font-size:
|
|
2598
|
+
font-size: 13px;
|
|
2599
|
+
font-weight: 500;
|
|
2600
|
+
line-height: 20px;
|
|
2487
2601
|
cursor: pointer;
|
|
2488
2602
|
outline: none;
|
|
2489
2603
|
}
|
|
2490
|
-
|
|
2491
|
-
|
|
2604
|
+
@media (hover: hover) {
|
|
2605
|
+
.tf-composer-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, transparent); }
|
|
2606
|
+
}
|
|
2607
|
+
.tf-composer-trigger:focus-visible {
|
|
2608
|
+
box-shadow: 0 0 0 2px var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
|
|
2609
|
+
}
|
|
2610
|
+
.tf-composer-trigger:disabled { color: var(--dsw-alias-label-dimmed, inherit); cursor: default; }
|
|
2611
|
+
.tf-composer-value { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2612
|
+
.tf-composer-chevron { display: inline-flex; flex: none; color: var(--dsw-alias-label-caption, inherit); transition: transform .12s; }
|
|
2613
|
+
.tf-composer-chevron-open { transform: rotate(180deg); }
|
|
2492
2614
|
.tf-composer-note {
|
|
2493
2615
|
font-size: 11px;
|
|
2494
2616
|
color: var(--dsw-alias-label-caption, inherit);
|
|
@@ -2516,6 +2638,7 @@ window.__ModuleLoader__.load({
|
|
|
2516
2638
|
const kinds = discussionSession ? COMPOSER_KINDS : CREATE_KINDS;
|
|
2517
2639
|
const [pending, setPending] = (0, import_react.useState)(false);
|
|
2518
2640
|
const [error, setError] = (0, import_react.useState)(null);
|
|
2641
|
+
const [open, setOpen] = (0, import_react.useState)(false);
|
|
2519
2642
|
const change = (0, import_react.useCallback)(
|
|
2520
2643
|
(next) => {
|
|
2521
2644
|
setError(null);
|
|
@@ -2569,26 +2692,55 @@ window.__ModuleLoader__.load({
|
|
|
2569
2692
|
},
|
|
2570
2693
|
[agentPresets, blank, mode, sessionId, t]
|
|
2571
2694
|
);
|
|
2695
|
+
const locked = !blank;
|
|
2696
|
+
const currentLabel = mode === "" ? t("composer.other") : t(COMPOSER_KIND_LABEL[mode]);
|
|
2697
|
+
const items = [
|
|
2698
|
+
{ id: "", label: t("composer.other") },
|
|
2699
|
+
...kinds.map((kind) => ({ id: kind, label: t(COMPOSER_KIND_LABEL[kind]) }))
|
|
2700
|
+
];
|
|
2572
2701
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2573
2702
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: COMPOSER_STYLES }),
|
|
2574
2703
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "tf-composer", children: [
|
|
2575
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2704
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2705
|
+
import_dsh_client_ui_primitives.Menu,
|
|
2706
|
+
{
|
|
2707
|
+
open,
|
|
2708
|
+
items,
|
|
2709
|
+
selectedId: mode,
|
|
2710
|
+
onSelect: (id2) => {
|
|
2711
|
+
setOpen(false);
|
|
2712
|
+
change(id2);
|
|
2713
|
+
},
|
|
2714
|
+
onClose: () => setOpen(false),
|
|
2715
|
+
side: "top",
|
|
2716
|
+
portal: true,
|
|
2717
|
+
anchor: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
2718
|
+
"button",
|
|
2719
|
+
{
|
|
2720
|
+
type: "button",
|
|
2721
|
+
className: "tf-composer-trigger",
|
|
2722
|
+
"aria-label": `${t("composer.label")}: ${currentLabel}`,
|
|
2723
|
+
"aria-haspopup": "menu",
|
|
2724
|
+
"aria-expanded": open,
|
|
2725
|
+
"aria-busy": pending,
|
|
2726
|
+
title: blank ? t("composer.hint") : t("composer.locked"),
|
|
2727
|
+
disabled: pending || locked,
|
|
2728
|
+
onClick: () => setOpen((value2) => !value2),
|
|
2729
|
+
children: [
|
|
2730
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tf-composer-value", children: currentLabel }),
|
|
2731
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2732
|
+
"span",
|
|
2733
|
+
{
|
|
2734
|
+
className: open ? "tf-composer-chevron tf-composer-chevron-open" : "tf-composer-chevron",
|
|
2735
|
+
"aria-hidden": "true",
|
|
2736
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {})
|
|
2737
|
+
}
|
|
2738
|
+
)
|
|
2739
|
+
]
|
|
2740
|
+
}
|
|
2741
|
+
)
|
|
2742
|
+
}
|
|
2743
|
+
),
|
|
2592
2744
|
error !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tf-composer-note", role: "status", children: error }) : null
|
|
2593
2745
|
] })
|
|
2594
2746
|
] });
|
|
@@ -2700,6 +2852,12 @@ window.__ModuleLoader__.load({
|
|
|
2700
2852
|
}
|
|
2701
2853
|
return { accepted: kept, rejections };
|
|
2702
2854
|
}
|
|
2855
|
+
function carriesFiles(types) {
|
|
2856
|
+
return types !== void 0 && types.includes("Files");
|
|
2857
|
+
}
|
|
2858
|
+
function droppedFiles(files) {
|
|
2859
|
+
return files === void 0 ? [] : Array.from(files);
|
|
2860
|
+
}
|
|
2703
2861
|
|
|
2704
2862
|
// src/client/icon.tsx
|
|
2705
2863
|
var import_react2 = require("react");
|
|
@@ -2747,7 +2905,7 @@ window.__ModuleLoader__.load({
|
|
|
2747
2905
|
}
|
|
2748
2906
|
|
|
2749
2907
|
// src/client/page.tsx
|
|
2750
|
-
var
|
|
2908
|
+
var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
2751
2909
|
var import_react10 = require("react");
|
|
2752
2910
|
|
|
2753
2911
|
// src/client/board.ts
|
|
@@ -2757,6 +2915,13 @@ window.__ModuleLoader__.load({
|
|
|
2757
2915
|
const pad = (value2) => String(value2).padStart(2, "0");
|
|
2758
2916
|
return `${pad(at.getMonth() + 1)}-${pad(at.getDate())} ${pad(at.getHours())}:${pad(at.getMinutes())}`;
|
|
2759
2917
|
}
|
|
2918
|
+
function discussionNodes(sessions) {
|
|
2919
|
+
return sessions.map((session) => ({
|
|
2920
|
+
sessionId: session.sessionId,
|
|
2921
|
+
kind: session.kind,
|
|
2922
|
+
at: session.linkedAt ?? session.preparedAt ?? session.createdAt
|
|
2923
|
+
}));
|
|
2924
|
+
}
|
|
2760
2925
|
var EMPTY_BOARD = { requirements: [], standalone: [], bugs: [] };
|
|
2761
2926
|
var STORY_RUNNING = ["developing", "self_testing"];
|
|
2762
2927
|
var STORY_DONE = ["done", "completed", "cancelled"];
|
|
@@ -2887,7 +3052,8 @@ window.__ModuleLoader__.load({
|
|
|
2887
3052
|
acceptance: parsed.acceptance,
|
|
2888
3053
|
bodyMissing: story.bodyMissing,
|
|
2889
3054
|
...last === void 0 ? {} : { lastRun: { status: last.status, at: last.at } },
|
|
2890
|
-
runs
|
|
3055
|
+
runs,
|
|
3056
|
+
sessions: discussionNodes(story.sessions)
|
|
2891
3057
|
};
|
|
2892
3058
|
if (story.requirementId === null) {
|
|
2893
3059
|
standalone.push({ kind: "story", id: story.id, workspaceId: node.workspaceId, story: node });
|
|
@@ -2908,12 +3074,8 @@ window.__ModuleLoader__.load({
|
|
|
2908
3074
|
const finished = stories.length > 0 && stories.every((story) => story.status === "completed");
|
|
2909
3075
|
const state = requirement.status === "archived" ? "done" : running ? "running" : requirement.status === "completed" || finished ? "done" : "ready";
|
|
2910
3076
|
const branch = runs.find((run) => run.branch.length > 0)?.branch;
|
|
2911
|
-
const sessions =
|
|
2912
|
-
(session) =>
|
|
2913
|
-
sessionId: session.sessionId,
|
|
2914
|
-
kind: session.kind,
|
|
2915
|
-
at: session.linkedAt ?? session.preparedAt ?? session.createdAt
|
|
2916
|
-
})
|
|
3077
|
+
const sessions = discussionNodes(
|
|
3078
|
+
snapshot.requirementSessions.filter((session) => session.requirementId === requirement.id)
|
|
2917
3079
|
);
|
|
2918
3080
|
const latestDesign = sessions.find((session) => session.kind === "design");
|
|
2919
3081
|
return {
|
|
@@ -2952,7 +3114,8 @@ window.__ModuleLoader__.load({
|
|
|
2952
3114
|
updatedAt: bug.updatedAt,
|
|
2953
3115
|
...last?.sessionId === void 0 ? {} : { sessionId: last.sessionId },
|
|
2954
3116
|
...bug.createSessionId === null ? {} : { createSessionId: bug.createSessionId },
|
|
2955
|
-
runs
|
|
3117
|
+
runs,
|
|
3118
|
+
sessions: discussionNodes(bug.sessions)
|
|
2956
3119
|
};
|
|
2957
3120
|
});
|
|
2958
3121
|
return { requirements, standalone, bugs };
|
|
@@ -3449,6 +3612,8 @@ window.__ModuleLoader__.load({
|
|
|
3449
3612
|
const [files, setFiles] = (0, import_react4.useState)([]);
|
|
3450
3613
|
const [rejections, setRejections] = (0, import_react4.useState)([]);
|
|
3451
3614
|
const picker = (0, import_react4.useRef)(null);
|
|
3615
|
+
const [dragActive, setDragActive] = (0, import_react4.useState)(false);
|
|
3616
|
+
const dragDepth = (0, import_react4.useRef)(0);
|
|
3452
3617
|
const previews = (0, import_react4.useRef)(/* @__PURE__ */ new Map());
|
|
3453
3618
|
const [, bumpPreviews] = (0, import_react4.useState)(0);
|
|
3454
3619
|
const [broken, setBroken] = (0, import_react4.useState)([]);
|
|
@@ -3501,18 +3666,75 @@ window.__ModuleLoader__.load({
|
|
|
3501
3666
|
},
|
|
3502
3667
|
[]
|
|
3503
3668
|
);
|
|
3504
|
-
const
|
|
3505
|
-
const picked = Array.from(event.target.files ?? []);
|
|
3506
|
-
event.target.value = "";
|
|
3669
|
+
const addFiles = (picked) => {
|
|
3507
3670
|
if (picked.length === 0) return;
|
|
3508
3671
|
const intake = intakeAttachments(picked, files, attachmentPolicy ?? null);
|
|
3509
3672
|
if (intake.accepted.length > 0) setFiles((current) => [...current, ...intake.accepted]);
|
|
3510
3673
|
setRejections(intake.rejections);
|
|
3511
3674
|
};
|
|
3675
|
+
const pick = (event) => {
|
|
3676
|
+
const picked = Array.from(event.target.files ?? []);
|
|
3677
|
+
event.target.value = "";
|
|
3678
|
+
addFiles(picked);
|
|
3679
|
+
};
|
|
3680
|
+
const dropRefused = busy || attachmentAvailable === false;
|
|
3681
|
+
const dragEnter = (event) => {
|
|
3682
|
+
if (!carriesFiles(event.dataTransfer?.types) || dropRefused) return;
|
|
3683
|
+
event.preventDefault();
|
|
3684
|
+
dragDepth.current += 1;
|
|
3685
|
+
setDragActive(true);
|
|
3686
|
+
};
|
|
3687
|
+
const dragOver = (event) => {
|
|
3688
|
+
if (!carriesFiles(event.dataTransfer?.types)) return;
|
|
3689
|
+
event.preventDefault();
|
|
3690
|
+
event.dataTransfer.dropEffect = dropRefused ? "none" : "copy";
|
|
3691
|
+
};
|
|
3692
|
+
const dragLeave = (event) => {
|
|
3693
|
+
if (!carriesFiles(event.dataTransfer?.types)) return;
|
|
3694
|
+
dragDepth.current = Math.max(0, dragDepth.current - 1);
|
|
3695
|
+
if (dragDepth.current === 0) setDragActive(false);
|
|
3696
|
+
};
|
|
3697
|
+
const drop = (event) => {
|
|
3698
|
+
if (!carriesFiles(event.dataTransfer?.types)) return;
|
|
3699
|
+
event.preventDefault();
|
|
3700
|
+
dragDepth.current = 0;
|
|
3701
|
+
setDragActive(false);
|
|
3702
|
+
if (dropRefused) return;
|
|
3703
|
+
addFiles(droppedFiles(event.dataTransfer?.files));
|
|
3704
|
+
};
|
|
3705
|
+
(0, import_react4.useEffect)(() => {
|
|
3706
|
+
if (!dragActive) return;
|
|
3707
|
+
const reset = () => {
|
|
3708
|
+
dragDepth.current = 0;
|
|
3709
|
+
setDragActive(false);
|
|
3710
|
+
};
|
|
3711
|
+
const onKeyDown = (event) => {
|
|
3712
|
+
if (event.key === "Escape") reset();
|
|
3713
|
+
};
|
|
3714
|
+
window.addEventListener("keydown", onKeyDown);
|
|
3715
|
+
window.addEventListener("dragend", reset);
|
|
3716
|
+
window.addEventListener("drop", reset);
|
|
3717
|
+
window.addEventListener("blur", reset);
|
|
3718
|
+
return () => {
|
|
3719
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
3720
|
+
window.removeEventListener("dragend", reset);
|
|
3721
|
+
window.removeEventListener("drop", reset);
|
|
3722
|
+
window.removeEventListener("blur", reset);
|
|
3723
|
+
};
|
|
3724
|
+
}, [dragActive]);
|
|
3512
3725
|
const remove2 = (index2) => {
|
|
3513
3726
|
setFiles((current) => current.filter((_, position) => position !== index2));
|
|
3514
3727
|
setRejections([]);
|
|
3515
3728
|
};
|
|
3729
|
+
const pageDragOver = (event) => {
|
|
3730
|
+
if (carriesFiles(event.dataTransfer?.types)) event.preventDefault();
|
|
3731
|
+
};
|
|
3732
|
+
const pageDrop = (event) => {
|
|
3733
|
+
if (!carriesFiles(event.dataTransfer?.types)) return;
|
|
3734
|
+
event.preventDefault();
|
|
3735
|
+
dragDepth.current = 0;
|
|
3736
|
+
setDragActive(false);
|
|
3737
|
+
};
|
|
3516
3738
|
const submit = (event) => {
|
|
3517
3739
|
event.preventDefault();
|
|
3518
3740
|
if (busy) return;
|
|
@@ -3543,7 +3765,7 @@ window.__ModuleLoader__.load({
|
|
|
3543
3765
|
size: formatBytes(attachmentPolicy.maxImageBytes),
|
|
3544
3766
|
count: attachmentPolicy.maxImagesPerMessage
|
|
3545
3767
|
});
|
|
3546
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "tf-create", children: [
|
|
3768
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "tf-create", onDragOver: pageDragOver, onDrop: pageDrop, children: [
|
|
3547
3769
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("header", { className: "tf-detail-head", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "tf-detail-heading", children: [
|
|
3548
3770
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h1", { className: "tf-title", children: t("create.title") }),
|
|
3549
3771
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "tf-sub", children: t("create.subtitle") })
|
|
@@ -3606,88 +3828,100 @@ window.__ModuleLoader__.load({
|
|
|
3606
3828
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-field-hint", children: t("create.descriptionHint") })
|
|
3607
3829
|
] })
|
|
3608
3830
|
] }),
|
|
3609
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
onClick: () => picker.current?.click(),
|
|
3623
|
-
children: t("create.attachment.add")
|
|
3624
|
-
}
|
|
3625
|
-
),
|
|
3626
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-field-hint tf-grow", children: attachmentHint })
|
|
3627
|
-
] }),
|
|
3628
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3629
|
-
"input",
|
|
3630
|
-
{
|
|
3631
|
-
ref: picker,
|
|
3632
|
-
className: "tf-attachment-input",
|
|
3633
|
-
type: "file",
|
|
3634
|
-
multiple: true,
|
|
3635
|
-
tabIndex: -1,
|
|
3636
|
-
"aria-hidden": true,
|
|
3637
|
-
onChange: pick
|
|
3638
|
-
}
|
|
3639
|
-
),
|
|
3640
|
-
files.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "tf-attachment-list", children: files.map((file, index2) => {
|
|
3641
|
-
const state = uploads[fileKey(file)];
|
|
3642
|
-
const label = state === void 0 ? null : state.status === "uploaded" ? t("create.attachment.uploaded") : state.status === "failed" ? t("create.attachment.failed") : state.status === "uploading" ? state.percent === void 0 ? t("create.attachment.uploading") : t("create.attachment.uploadingPercent", { percent: state.percent }) : t("create.attachment.queued");
|
|
3643
|
-
const key = fileKey(file);
|
|
3644
|
-
const preview = broken.includes(key) ? void 0 : previews.current.get(key);
|
|
3645
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("li", { className: "tf-attachment-item", "data-state": state?.status, children: [
|
|
3646
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-thumb", "data-kind": isImageFile(file) ? "image" : "file", children: preview === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-ext", children: fileExtension(file.name) }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3647
|
-
"img",
|
|
3648
|
-
{
|
|
3649
|
-
className: "tf-attachment-thumb-img",
|
|
3650
|
-
src: preview,
|
|
3651
|
-
alt: file.name,
|
|
3652
|
-
onError: () => setBroken((current) => current.includes(key) ? current : [...current, key])
|
|
3653
|
-
}
|
|
3654
|
-
) }),
|
|
3655
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "tf-attachment-body", children: [
|
|
3656
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-name", title: file.name, children: file.name }),
|
|
3657
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "tf-attachment-meta", children: [
|
|
3658
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-size", children: formatBytes(file.size) }),
|
|
3659
|
-
label === null ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
3660
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-sep", "aria-hidden": true, children: t("create.attachment.metaSep") }),
|
|
3661
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-status", children: label })
|
|
3662
|
-
] })
|
|
3663
|
-
] }),
|
|
3664
|
-
state?.status === "failed" && state.reason !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-error", children: t(FAILURE_KEY[state.reason]) }) : null,
|
|
3665
|
-
state?.status === "uploading" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-track", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3666
|
-
"span",
|
|
3667
|
-
{
|
|
3668
|
-
className: "tf-attachment-fill",
|
|
3669
|
-
style: { width: `${Math.max(4, Math.min(100, state.percent ?? 0))}%` }
|
|
3670
|
-
}
|
|
3671
|
-
) }) : null
|
|
3831
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3832
|
+
"section",
|
|
3833
|
+
{
|
|
3834
|
+
className: "tf-card tf-attachment-dropzone",
|
|
3835
|
+
"data-drag": dragActive ? "active" : void 0,
|
|
3836
|
+
onDragEnter: dragEnter,
|
|
3837
|
+
onDragOver: dragOver,
|
|
3838
|
+
onDragLeave: dragLeave,
|
|
3839
|
+
onDrop: drop,
|
|
3840
|
+
children: [
|
|
3841
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "tf-card-head", children: [
|
|
3842
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "tf-card-title", children: t("create.attachment.label") }),
|
|
3843
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-card-hint", children: t("create.attachment.optional") })
|
|
3672
3844
|
] }),
|
|
3673
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.
|
|
3845
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3674
3846
|
"button",
|
|
3675
3847
|
{
|
|
3676
|
-
className: "tf-attachment-
|
|
3848
|
+
className: "tf-attachment-pick",
|
|
3677
3849
|
type: "button",
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3850
|
+
disabled: busy || attachmentAvailable === false,
|
|
3851
|
+
onClick: () => picker.current?.click(),
|
|
3852
|
+
children: [
|
|
3853
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-plus", "aria-hidden": "true", children: "+" }),
|
|
3854
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-pick-title", children: t("create.attachment.add") }),
|
|
3855
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-pick-sub", children: dragActive ? t("create.attachment.dropActive") : t("create.attachment.dropHint") })
|
|
3856
|
+
]
|
|
3682
3857
|
}
|
|
3683
|
-
)
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3858
|
+
),
|
|
3859
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "tf-attachment-limits", children: attachmentHint }),
|
|
3860
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3861
|
+
"input",
|
|
3862
|
+
{
|
|
3863
|
+
ref: picker,
|
|
3864
|
+
className: "tf-attachment-input",
|
|
3865
|
+
type: "file",
|
|
3866
|
+
multiple: true,
|
|
3867
|
+
tabIndex: -1,
|
|
3868
|
+
"aria-hidden": true,
|
|
3869
|
+
onChange: pick
|
|
3870
|
+
}
|
|
3871
|
+
),
|
|
3872
|
+
files.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "tf-attachment-list", children: files.map((file, index2) => {
|
|
3873
|
+
const state = uploads[fileKey(file)];
|
|
3874
|
+
const label = state === void 0 ? null : state.status === "uploaded" ? t("create.attachment.uploaded") : state.status === "failed" ? t("create.attachment.failed") : state.status === "uploading" ? state.percent === void 0 ? t("create.attachment.uploading") : t("create.attachment.uploadingPercent", { percent: state.percent }) : t("create.attachment.queued");
|
|
3875
|
+
const key = fileKey(file);
|
|
3876
|
+
const preview = broken.includes(key) ? void 0 : previews.current.get(key);
|
|
3877
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("li", { className: "tf-attachment-item", "data-state": state?.status, children: [
|
|
3878
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-thumb", "data-kind": isImageFile(file) ? "image" : "file", children: preview === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-ext", children: fileExtension(file.name) }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3879
|
+
"img",
|
|
3880
|
+
{
|
|
3881
|
+
className: "tf-attachment-thumb-img",
|
|
3882
|
+
src: preview,
|
|
3883
|
+
alt: file.name,
|
|
3884
|
+
onError: () => setBroken((current) => current.includes(key) ? current : [...current, key])
|
|
3885
|
+
}
|
|
3886
|
+
) }),
|
|
3887
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "tf-attachment-body", children: [
|
|
3888
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-name", title: file.name, children: file.name }),
|
|
3889
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "tf-attachment-meta", children: [
|
|
3890
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-size", children: formatBytes(file.size) }),
|
|
3891
|
+
label === null ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
3892
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-sep", "aria-hidden": true, children: t("create.attachment.metaSep") }),
|
|
3893
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-status", children: label })
|
|
3894
|
+
] })
|
|
3895
|
+
] }),
|
|
3896
|
+
state?.status === "failed" && state.reason !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-error", children: t(FAILURE_KEY[state.reason]) }) : null,
|
|
3897
|
+
state?.status === "uploading" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tf-attachment-track", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3898
|
+
"span",
|
|
3899
|
+
{
|
|
3900
|
+
className: "tf-attachment-fill",
|
|
3901
|
+
style: { width: `${Math.max(4, Math.min(100, state.percent ?? 0))}%` }
|
|
3902
|
+
}
|
|
3903
|
+
) }) : null
|
|
3904
|
+
] }),
|
|
3905
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3906
|
+
"button",
|
|
3907
|
+
{
|
|
3908
|
+
className: "tf-attachment-remove",
|
|
3909
|
+
type: "button",
|
|
3910
|
+
"aria-label": `${t("create.attachment.remove")} ${file.name}`,
|
|
3911
|
+
disabled: busy,
|
|
3912
|
+
onClick: () => remove2(index2),
|
|
3913
|
+
children: "×"
|
|
3914
|
+
}
|
|
3915
|
+
)
|
|
3916
|
+
] }, `${fileKey(file)}-${index2}`);
|
|
3917
|
+
}) }) : null,
|
|
3918
|
+
rejections.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "tf-attachment-rejected", role: "alert", children: rejections.map((rejection, index2) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: t(REJECTION_KEY[rejection.reason], {
|
|
3919
|
+
name: rejection.file.name,
|
|
3920
|
+
...rejection.params
|
|
3921
|
+
}) }, `${rejection.file.name}-${index2}`)) }) : null
|
|
3922
|
+
]
|
|
3923
|
+
}
|
|
3924
|
+
),
|
|
3691
3925
|
invalid !== null || error !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "tf-error", role: "alert", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AlertText, { text: invalid?.message ?? error ?? "" }) }) : null,
|
|
3692
3926
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "tf-create-actions", children: [
|
|
3693
3927
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "tf-btn", "data-tone": "primary", type: "submit", disabled: !canSubmit, children: staging ? t("create.attachment.submitUploading") : busy ? t("create.submitting") : t("create.submit") }),
|
|
@@ -13852,7 +14086,7 @@ window.__ModuleLoader__.load({
|
|
|
13852
14086
|
},
|
|
13853
14087
|
[basePath, onMissing, onOpenPath]
|
|
13854
14088
|
);
|
|
13855
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
14089
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dsh_client_ui_primitives2.MarkdownDelegateProvider, { openFile: basePath === void 0 ? void 0 : openFile, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dsh_client_ui_primitives2.MarkdownText, { text, labels }) });
|
|
13856
14090
|
}
|
|
13857
14091
|
function SectionHead({
|
|
13858
14092
|
title,
|
|
@@ -13908,6 +14142,7 @@ window.__ModuleLoader__.load({
|
|
|
13908
14142
|
const [createBusy, setCreateBusy] = (0, import_react10.useState)(false);
|
|
13909
14143
|
const [createError, setCreateError] = (0, import_react10.useState)(null);
|
|
13910
14144
|
const [discussionBusy, setDiscussionBusy] = (0, import_react10.useState)(null);
|
|
14145
|
+
const [recordDiscussionBusy, setRecordDiscussionBusy] = (0, import_react10.useState)(null);
|
|
13911
14146
|
const [cleanup, setCleanup] = (0, import_react10.useState)(false);
|
|
13912
14147
|
const [selected2, setSelected] = (0, import_react10.useState)(/* @__PURE__ */ new Set());
|
|
13913
14148
|
const [confirm, setConfirm] = (0, import_react10.useState)(null);
|
|
@@ -14411,14 +14646,59 @@ window.__ModuleLoader__.load({
|
|
|
14411
14646
|
},
|
|
14412
14647
|
[data, openConversation2, showToast, t]
|
|
14413
14648
|
);
|
|
14649
|
+
const startRecordDiscussion = (0, import_react10.useCallback)(
|
|
14650
|
+
(subject) => {
|
|
14651
|
+
const open = openConversation2;
|
|
14652
|
+
if (open === void 0) {
|
|
14653
|
+
showToast(t("toast.startUnavailable"));
|
|
14654
|
+
return;
|
|
14655
|
+
}
|
|
14656
|
+
setRecordDiscussionBusy(subject.kind);
|
|
14657
|
+
open(subject.workspaceId, buildRecordDiscussionPrompt(subject.kind, subject.title), {
|
|
14658
|
+
agentPreset: presetForRecordDiscussion(subject.kind),
|
|
14659
|
+
autoSend: false,
|
|
14660
|
+
composerKind: subject.kind
|
|
14661
|
+
}).then(async (outcome) => {
|
|
14662
|
+
if (outcome.status === "unavailable") {
|
|
14663
|
+
if (mounted.current) {
|
|
14664
|
+
showToast(outcome.message ?? t("toast.discussionFailed", { title: subject.title }));
|
|
14665
|
+
}
|
|
14666
|
+
return;
|
|
14667
|
+
}
|
|
14668
|
+
if (outcome.sessionId === void 0) {
|
|
14669
|
+
if (mounted.current) {
|
|
14670
|
+
showToast(t("toast.discussionDrafted", { title: subject.title }));
|
|
14671
|
+
}
|
|
14672
|
+
return;
|
|
14673
|
+
}
|
|
14674
|
+
try {
|
|
14675
|
+
await data.prepareDiscussionSession(subject.kind, subject.id, outcome.sessionId, "discuss");
|
|
14676
|
+
if (!mounted.current) return;
|
|
14677
|
+
showToast(
|
|
14678
|
+
outcome.status === "drafted" ? t("toast.discussionDrafted", { title: subject.title }) : t("toast.discussionStarted", { title: subject.title })
|
|
14679
|
+
);
|
|
14680
|
+
} catch (failure) {
|
|
14681
|
+
if (!mounted.current) return;
|
|
14682
|
+
showToast(
|
|
14683
|
+
t("toast.discussionLinkFailed", {
|
|
14684
|
+
title: subject.title,
|
|
14685
|
+
message: failureMessage(failure)
|
|
14686
|
+
})
|
|
14687
|
+
);
|
|
14688
|
+
}
|
|
14689
|
+
}).catch(() => {
|
|
14690
|
+
if (mounted.current) showToast(t("toast.discussionFailed", { title: subject.title }));
|
|
14691
|
+
}).finally(() => {
|
|
14692
|
+
if (mounted.current) setRecordDiscussionBusy(null);
|
|
14693
|
+
});
|
|
14694
|
+
},
|
|
14695
|
+
[data, openConversation2, showToast, t]
|
|
14696
|
+
);
|
|
14414
14697
|
const requirementAction = (0, import_react10.useCallback)(
|
|
14415
14698
|
(requirement) => {
|
|
14416
14699
|
if (requirement.state === "running") {
|
|
14417
14700
|
return { label: t("row.open"), tone: "live", icon: ICONS.live };
|
|
14418
14701
|
}
|
|
14419
|
-
if (requirement.state === "done") {
|
|
14420
|
-
return { label: t("row.history"), tone: "ghost", icon: ICONS.ghost };
|
|
14421
|
-
}
|
|
14422
14702
|
const lone = loneReadyStory(requirement);
|
|
14423
14703
|
return lone === void 0 ? null : { label: t("row.start"), tone: "soft", icon: ICONS.soft };
|
|
14424
14704
|
},
|
|
@@ -14513,11 +14793,7 @@ window.__ModuleLoader__.load({
|
|
|
14513
14793
|
}
|
|
14514
14794
|
};
|
|
14515
14795
|
const storyAction = (0, import_react10.useCallback)(
|
|
14516
|
-
(story) => {
|
|
14517
|
-
if (story.state === "running") return { label: t("row.open"), tone: "live", icon: ICONS.live };
|
|
14518
|
-
if (story.state === "done") return { label: t("row.history"), tone: "ghost", icon: ICONS.ghost };
|
|
14519
|
-
return { label: t("row.start"), tone: "soft", icon: ICONS.soft };
|
|
14520
|
-
},
|
|
14796
|
+
(story) => story.state === "ready" ? { label: t("row.start"), tone: "soft", icon: ICONS.soft } : null,
|
|
14521
14797
|
[t]
|
|
14522
14798
|
);
|
|
14523
14799
|
const runStoryAction = (0, import_react10.useCallback)(
|
|
@@ -15043,7 +15319,14 @@ window.__ModuleLoader__.load({
|
|
|
15043
15319
|
onDelete: () => openDelete([{ kind: "bug", id: activeBug.id }]),
|
|
15044
15320
|
onComplete: () => setDecision({ kind: "complete-bug", bug: activeBug, busy: false, error: null }),
|
|
15045
15321
|
onStartFix: (tier) => startBugFix(activeBug, tier),
|
|
15046
|
-
onCancelFix: () => cancelBugFix(activeBug)
|
|
15322
|
+
onCancelFix: () => cancelBugFix(activeBug),
|
|
15323
|
+
onNewDiscussion: () => startRecordDiscussion({
|
|
15324
|
+
kind: "bug",
|
|
15325
|
+
id: activeBug.id,
|
|
15326
|
+
title: activeBug.title,
|
|
15327
|
+
workspaceId: activeBug.workspaceId
|
|
15328
|
+
}),
|
|
15329
|
+
discussionBusy: recordDiscussionBusy === "bug"
|
|
15047
15330
|
}
|
|
15048
15331
|
) : null,
|
|
15049
15332
|
view.kind === "story" && activeStory !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
@@ -15063,7 +15346,14 @@ window.__ModuleLoader__.load({
|
|
|
15063
15346
|
onCancelRun: () => setDecision({ kind: "cancel-run", story: activeStory, busy: false, error: null }),
|
|
15064
15347
|
onOpenSession: (sessionId) => openSession(sessionId),
|
|
15065
15348
|
onOpenPath: openFile,
|
|
15066
|
-
onMissing: (path) => showToast(t("doc.linkMissing", { path }))
|
|
15349
|
+
onMissing: (path) => showToast(t("doc.linkMissing", { path })),
|
|
15350
|
+
onNewDiscussion: () => startRecordDiscussion({
|
|
15351
|
+
kind: "story",
|
|
15352
|
+
id: activeStory.id,
|
|
15353
|
+
title: activeStory.title,
|
|
15354
|
+
workspaceId: activeStory.workspaceId
|
|
15355
|
+
}),
|
|
15356
|
+
discussionBusy: recordDiscussionBusy === "story"
|
|
15067
15357
|
}
|
|
15068
15358
|
) : null
|
|
15069
15359
|
] }) }),
|
|
@@ -15940,6 +16230,8 @@ window.__ModuleLoader__.load({
|
|
|
15940
16230
|
onComplete,
|
|
15941
16231
|
onStartFix,
|
|
15942
16232
|
onCancelFix,
|
|
16233
|
+
onNewDiscussion,
|
|
16234
|
+
discussionBusy = false,
|
|
15943
16235
|
readOnly = false
|
|
15944
16236
|
}) {
|
|
15945
16237
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
@@ -15966,27 +16258,42 @@ window.__ModuleLoader__.load({
|
|
|
15966
16258
|
readOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("button", { className: "tf-btn tf-danger", "data-tone": "ghost", type: "button", onClick: onDelete, style: { flex: "0 0 auto" }, children: [
|
|
15967
16259
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TrashGlyph, {}),
|
|
15968
16260
|
t("delete.action")
|
|
15969
|
-
] })
|
|
15970
|
-
readOnly || bug.sessionId === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
15971
|
-
"button",
|
|
15972
|
-
{
|
|
15973
|
-
className: "tf-btn",
|
|
15974
|
-
"data-tone": "live",
|
|
15975
|
-
type: "button",
|
|
15976
|
-
onClick: () => onOpenSession(bug.sessionId),
|
|
15977
|
-
style: { flex: "0 0 auto" },
|
|
15978
|
-
children: [
|
|
15979
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChatGlyph, {}),
|
|
15980
|
-
t("row.open")
|
|
15981
|
-
]
|
|
15982
|
-
}
|
|
15983
|
-
)
|
|
16261
|
+
] })
|
|
15984
16262
|
] }),
|
|
15985
16263
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "tf-grid", children: [
|
|
15986
16264
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
|
|
15987
16265
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { className: "tf-card", children: [
|
|
15988
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
15989
|
-
|
|
16266
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
16267
|
+
SectionHead,
|
|
16268
|
+
{
|
|
16269
|
+
title: t("detail.bugBody"),
|
|
16270
|
+
action: readOnly || onNewDiscussion === void 0 ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
16271
|
+
"button",
|
|
16272
|
+
{
|
|
16273
|
+
className: "tf-btn tf-btn-sm",
|
|
16274
|
+
"data-tone": "soft",
|
|
16275
|
+
type: "button",
|
|
16276
|
+
disabled: discussionBusy,
|
|
16277
|
+
onClick: onNewDiscussion,
|
|
16278
|
+
children: [
|
|
16279
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PlusGlyph, {}),
|
|
16280
|
+
discussionBusy ? t("detail.discussionStarting") : t("detail.bugDiscussion")
|
|
16281
|
+
]
|
|
16282
|
+
}
|
|
16283
|
+
)
|
|
16284
|
+
}
|
|
16285
|
+
),
|
|
16286
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "tf-doc-body", children: bug.bodyMissing ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "tf-card-hint", children: t("body.missingGeneric") }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MarkdownBody, { text: bug.content.join("\n"), t }) }),
|
|
16287
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
16288
|
+
DiscussionSessions,
|
|
16289
|
+
{
|
|
16290
|
+
t,
|
|
16291
|
+
sessions: bug.sessions,
|
|
16292
|
+
sessionTitle,
|
|
16293
|
+
onOpenSession,
|
|
16294
|
+
readOnly
|
|
16295
|
+
}
|
|
16296
|
+
)
|
|
15990
16297
|
] }),
|
|
15991
16298
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { className: "tf-card", children: [
|
|
15992
16299
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
@@ -16062,6 +16369,8 @@ window.__ModuleLoader__.load({
|
|
|
16062
16369
|
onOpenSession,
|
|
16063
16370
|
onOpenPath,
|
|
16064
16371
|
onMissing,
|
|
16372
|
+
onNewDiscussion,
|
|
16373
|
+
discussionBusy = false,
|
|
16065
16374
|
readOnly = false
|
|
16066
16375
|
}) {
|
|
16067
16376
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
@@ -16111,7 +16420,26 @@ window.__ModuleLoader__.load({
|
|
|
16111
16420
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "tf-grid", children: [
|
|
16112
16421
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
|
|
16113
16422
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { className: "tf-card", children: [
|
|
16114
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
16423
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
16424
|
+
SectionHead,
|
|
16425
|
+
{
|
|
16426
|
+
title: t("detail.storyBody"),
|
|
16427
|
+
action: readOnly || onNewDiscussion === void 0 ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
16428
|
+
"button",
|
|
16429
|
+
{
|
|
16430
|
+
className: "tf-btn tf-btn-sm",
|
|
16431
|
+
"data-tone": "soft",
|
|
16432
|
+
type: "button",
|
|
16433
|
+
disabled: discussionBusy,
|
|
16434
|
+
onClick: onNewDiscussion,
|
|
16435
|
+
children: [
|
|
16436
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PlusGlyph, {}),
|
|
16437
|
+
discussionBusy ? t("detail.discussionStarting") : t("detail.storyDiscussion")
|
|
16438
|
+
]
|
|
16439
|
+
}
|
|
16440
|
+
)
|
|
16441
|
+
}
|
|
16442
|
+
),
|
|
16115
16443
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "tf-doc-body", children: story.bodyMissing ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "tf-card-hint", style: { margin: 0 }, children: t("body.missing", { path: story.path }) }) : story.body.trim() === "" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "tf-card-hint", style: { margin: 0 }, children: t("detail.noDescription") }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
16116
16444
|
MarkdownBody,
|
|
16117
16445
|
{
|
|
@@ -16121,7 +16449,17 @@ window.__ModuleLoader__.load({
|
|
|
16121
16449
|
onOpenPath,
|
|
16122
16450
|
onMissing
|
|
16123
16451
|
}
|
|
16124
|
-
) })
|
|
16452
|
+
) }),
|
|
16453
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
16454
|
+
DiscussionSessions,
|
|
16455
|
+
{
|
|
16456
|
+
t,
|
|
16457
|
+
sessions: story.sessions,
|
|
16458
|
+
sessionTitle,
|
|
16459
|
+
onOpenSession,
|
|
16460
|
+
readOnly
|
|
16461
|
+
}
|
|
16462
|
+
)
|
|
16125
16463
|
] }),
|
|
16126
16464
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { className: "tf-card", children: [
|
|
16127
16465
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
@@ -16891,6 +17229,9 @@ window.__ModuleLoader__.load({
|
|
|
16891
17229
|
prepareRequirementSession: async (requirementId, sessionId, kind) => callRemote(
|
|
16892
17230
|
(await ready.promise).prepareRequirementSession(requirementId, sessionId, kind, locale())
|
|
16893
17231
|
),
|
|
17232
|
+
prepareDiscussionSession: async (subjectType, subjectId, sessionId, kind) => callRemote(
|
|
17233
|
+
(await ready.promise).prepareDiscussionSession(subjectType, subjectId, sessionId, kind, locale())
|
|
17234
|
+
),
|
|
16894
17235
|
sessionPermissionTier: async (sessionId) => callRemote((await ready.promise).sessionPermissionTier(sessionId, locale())),
|
|
16895
17236
|
previewDelete: async (targets) => callRemote((await ready.promise).previewDelete(targets, locale())),
|
|
16896
17237
|
deleteRecords: async (targets) => callRemote((await ready.promise).deleteRecords(targets, locale())),
|