@deepseek-ai/dsh-client-ui-workflow-run 0.1.0-rc.7 → 0.1.0-rc.8
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 +1 -1
- package/README.zh.md +1 -1
- package/lib/client.js +261 -86
- package/package.json +21 -25
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/client/ui-workflow-run/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 5093050ac7bd7e5d8a8779c4fe9848ee4f7da28b
|
|
6
|
+
README.zh.md: f7b652d87dc01e5161eac8ea3fc9025136feca90
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Phase groups come only from members that actually started. Exact phase strings s
|
|
|
12
12
|
|
|
13
13
|
## Presentation and navigation
|
|
14
14
|
|
|
15
|
-
The run and each phase
|
|
15
|
+
The run and each phase are controlled disclosures in every status. A mount opens running, failed, cancelled, and interrupted levels and closes fully completed levels; users can then toggle either level with the full row, Enter, or Space. Ordinary running updates preserve the current choice, the first abnormal edge opens once, normal completion closes once, and a completed phase plus the outer run open again when a new running member starts under the same phase key. If an entire new clean cycle arrives in one render while the run remains active, the phase finishes folded but the outer run opens once to expose its updated summary. Completion updates the visible status immediately but delays its automatic close while focus remains inside the content. `WorkflowRunPanel` owns the phase choices, so closing and reopening the outer run does not reset them; a renderer remount reconstructs every initial choice from durable facts. The run uses a 32-pixel `--dsw-alias-bg-module-platform` row with persistent right/down chevrons and an inline state dot plus status text, without a badge. Phases use 32-pixel disclosure rows with title and member count in the flexible main area and a fixed precise aggregate-status tail, without another dot. Members use a 16-pixel dot slot, a truncating name area, and a fixed 64-pixel status column.
|
|
16
16
|
|
|
17
17
|
A member opens a child Session only while every current fact agrees: the member is running, the child id is in the ordinary Session list, the row has `origin: 'subagent'`, its `parentId` is the current Session, and the list row is still running. Underlined member text is the only visible navigation affordance; keyboard focus draws a two-pixel business-primary ring around the name area, while status copy remains `Running`. The component calls only the injected ordinary `sessions.open(id)` action; remote, addressed-only, wrong-parent, or terminal rows remain non-interactive.
|
|
18
18
|
|
package/README.zh.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
## 展示与导航
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
运行和每个阶段在所有状态下都是受控 disclosure。挂载时,运行中、失败、已取消和已中断层级默认展开,全部完成的层级默认折叠;此后用户可以点击整行,或按 Enter、Space 切换任一层级。普通运行更新保留当前选择,首次异常边沿只自动展开一次,正常完成只自动折叠一次;已完成阶段在同一 phase key 下开始新的运行成员时,该 Phase 与外层运行会再次自动展开。若一个完整的新干净周期在同一次渲染中送达,且运行仍处于活动状态,Phase 保持折叠,但外层运行会自动展开一次以展示更新后的摘要。完成状态会立即更新,但只要焦点仍位于展开内容内,自动折叠就会等待焦点离开。Phase 选择由 `WorkflowRunPanel` 持有,因此关闭并重新打开外层运行不会重置它们;renderer remount 会从持久事实重建每层的初始选择。运行使用 32 像素 `--dsw-alias-bg-module-platform` 背景行,常驻向右/向下 chevron,并以内联状态点加状态文字表达结局,不使用胶囊。阶段使用 32 像素 disclosure 行,在可伸缩主区显示标题与成员数,在固定尾部精确显示聚合状态且不重复状态点。成员使用 16 像素状态点槽、可省略名称区和固定 64 像素状态列。
|
|
16
16
|
|
|
17
17
|
只有所有实时事实同时成立时,成员才可打开子 Session:成员仍在运行、子 id 位于普通 Session 列表、列表行为 `origin: 'subagent'`、`parentId` 等于当前 Session,且列表行仍标记运行。带下划线的成员文字是唯一可见导航提示;键盘聚焦时,名称区显示 2 像素 business-primary 焦点环,右侧状态仍只显示“运行中”。组件只调用注入的普通 `sessions.open(id)`;远程、仅地址化、父级不符或终态的行都不可交互。
|
|
18
18
|
|
package/lib/client.js
CHANGED
|
@@ -19,28 +19,28 @@ window.__ModuleLoader__.load({
|
|
|
19
19
|
document.head.appendChild(tag);
|
|
20
20
|
}
|
|
21
21
|
var WorkflowRunPanel_module_css_default = {
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"members": "DBuyfa_members",
|
|
22
|
+
"dotSlot": "DBuyfa_dotSlot",
|
|
23
|
+
"empty": "DBuyfa_empty",
|
|
24
|
+
"memberButton": "DBuyfa_memberButton",
|
|
26
25
|
"memberLabel": "DBuyfa_memberLabel",
|
|
27
|
-
"phaseTitle": "DBuyfa_phaseTitle",
|
|
28
|
-
"runLeading": "DBuyfa_runLeading",
|
|
29
26
|
"memberLabelWrap": "DBuyfa_memberLabelWrap",
|
|
30
|
-
"phase": "DBuyfa_phase",
|
|
31
|
-
"phaseList": "DBuyfa_phaseList",
|
|
32
|
-
"empty": "DBuyfa_empty",
|
|
33
27
|
"memberRow": "DBuyfa_memberRow",
|
|
28
|
+
"memberStatus": "DBuyfa_memberStatus",
|
|
29
|
+
"members": "DBuyfa_members",
|
|
30
|
+
"phase": "DBuyfa_phase",
|
|
31
|
+
"phaseCount": "DBuyfa_phaseCount",
|
|
32
|
+
"phaseHeader": "DBuyfa_phaseHeader",
|
|
34
33
|
"phaseLeading": "DBuyfa_phaseLeading",
|
|
35
|
-
"
|
|
36
|
-
"statusTail": "DBuyfa_statusTail",
|
|
34
|
+
"phaseList": "DBuyfa_phaseList",
|
|
37
35
|
"phaseStatus": "DBuyfa_phaseStatus",
|
|
38
|
-
"
|
|
36
|
+
"phaseTitle": "DBuyfa_phaseTitle",
|
|
37
|
+
"root": "DBuyfa_root",
|
|
39
38
|
"runHeader": "DBuyfa_runHeader",
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
39
|
+
"runLeading": "DBuyfa_runLeading",
|
|
40
|
+
"runSummary": "DBuyfa_runSummary",
|
|
41
|
+
"runTitle": "DBuyfa_runTitle",
|
|
42
|
+
"separator": "DBuyfa_separator",
|
|
43
|
+
"statusTail": "DBuyfa_statusTail"
|
|
44
44
|
};
|
|
45
45
|
//#endregion
|
|
46
46
|
//#region lib/types/client/WorkflowRunPanel.js
|
|
@@ -75,30 +75,85 @@ window.__ModuleLoader__.load({
|
|
|
75
75
|
function memberCount(count, t) {
|
|
76
76
|
return t(count === 1 ? "run.members.one" : "run.members.other", { count });
|
|
77
77
|
}
|
|
78
|
-
function
|
|
79
|
-
return phase.members.some((member) => member.status !== "completed");
|
|
80
|
-
}
|
|
81
|
-
/* v8 ignore next -- DisclosureRow requires the callback but cannot invoke it when expandable is false. */
|
|
82
|
-
const forcedOpenToggle = () => {};
|
|
83
|
-
function ManualDisclosure(props) {
|
|
84
|
-
const [open, setOpen] = (0, react.useState)(false);
|
|
78
|
+
function StatusDisclosure(props) {
|
|
85
79
|
return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.DisclosureRow, {
|
|
86
80
|
...props,
|
|
87
|
-
|
|
88
|
-
expandable: true,
|
|
89
|
-
onToggle: () => {
|
|
90
|
-
setOpen((value) => !value);
|
|
91
|
-
}
|
|
81
|
+
expandable: true
|
|
92
82
|
});
|
|
93
83
|
}
|
|
94
|
-
function
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
84
|
+
function abnormal(status) {
|
|
85
|
+
return status === "failed" || status === "cancelled" || status === "interrupted";
|
|
86
|
+
}
|
|
87
|
+
function phaseDisclosureFacts(phase) {
|
|
88
|
+
return {
|
|
89
|
+
mode: phase.members.some((member) => abnormal(member.status)) ? "abnormal" : phase.members.some((member) => member.status === "running") ? "running" : "clean",
|
|
90
|
+
activityCount: phase.members.length
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function runDisclosureFacts(status, phases) {
|
|
94
|
+
return {
|
|
95
|
+
mode: abnormal(status) || phases.some(([, facts]) => facts.mode === "abnormal") ? "abnormal" : status === "running" || phases.some(([, facts]) => facts.mode === "running") ? "running" : "clean",
|
|
96
|
+
activityCount: phases.reduce((count, [, facts]) => count + facts.activityCount, 0)
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function initialDisclosureState(facts) {
|
|
100
|
+
return {
|
|
101
|
+
...facts,
|
|
102
|
+
open: facts.mode !== "clean",
|
|
103
|
+
pendingCleanCollapse: false
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function advanceDisclosureState(current, facts, focusWithin) {
|
|
107
|
+
if (current.mode === facts.mode && current.activityCount === facts.activityCount) {
|
|
108
|
+
if (!current.pendingCleanCollapse || focusWithin) return current;
|
|
109
|
+
return {
|
|
110
|
+
...current,
|
|
111
|
+
open: false,
|
|
112
|
+
pendingCleanCollapse: false
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (facts.mode === "clean") {
|
|
116
|
+
const deferCollapse = current.open && focusWithin;
|
|
117
|
+
return {
|
|
118
|
+
...facts,
|
|
119
|
+
open: deferCollapse,
|
|
120
|
+
pendingCleanCollapse: deferCollapse
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (current.mode === "clean" || facts.mode === "abnormal" && current.mode !== "abnormal") return {
|
|
124
|
+
...facts,
|
|
98
125
|
open: true,
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
126
|
+
pendingCleanCollapse: false
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
...facts,
|
|
130
|
+
open: current.open,
|
|
131
|
+
pendingCleanCollapse: false
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function focusIsWithin(element) {
|
|
135
|
+
if (element === null || element === void 0) return false;
|
|
136
|
+
return element.contains(element.ownerDocument.activeElement);
|
|
137
|
+
}
|
|
138
|
+
function collapsePending(state) {
|
|
139
|
+
if (!state.pendingCleanCollapse) return state;
|
|
140
|
+
return {
|
|
141
|
+
...state,
|
|
142
|
+
open: false,
|
|
143
|
+
pendingCleanCollapse: false
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function existingPhaseState(phases, key) {
|
|
147
|
+
const phase = phases.get(key);
|
|
148
|
+
/* v8 ignore next -- mounted phase callbacks are created from this owner map. */
|
|
149
|
+
if (phase === void 0) throw new Error(`Missing disclosure state for phase ${key}`);
|
|
150
|
+
return phase;
|
|
151
|
+
}
|
|
152
|
+
function preventPendingHeaderFocus(event) {
|
|
153
|
+
const header = event.currentTarget.querySelector("[data-disclosure-row]");
|
|
154
|
+
/* v8 ignore next -- DisclosureRow always renders its header before the content. */
|
|
155
|
+
if (header === null) throw new Error("Missing disclosure header");
|
|
156
|
+
if (header.contains(event.target)) event.preventDefault();
|
|
102
157
|
}
|
|
103
158
|
function phaseStatusSummary(members, t) {
|
|
104
159
|
const counts = /* @__PURE__ */ new Map();
|
|
@@ -122,11 +177,12 @@ window.__ModuleLoader__.load({
|
|
|
122
177
|
}
|
|
123
178
|
return result;
|
|
124
179
|
}
|
|
125
|
-
function RunHeader({ children, count, name,
|
|
180
|
+
function RunHeader({ children, count, name, onToggle, open, status, t }) {
|
|
126
181
|
return (0, react_jsx_runtime.jsx)(StatusDisclosure, {
|
|
127
182
|
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {}),
|
|
128
183
|
title: t("run.title", { name }),
|
|
129
|
-
|
|
184
|
+
open,
|
|
185
|
+
onToggle,
|
|
130
186
|
expandOnRowClick: true,
|
|
131
187
|
previewChevron: false,
|
|
132
188
|
keepContentWhenOpen: true,
|
|
@@ -153,6 +209,8 @@ window.__ModuleLoader__.load({
|
|
|
153
209
|
}
|
|
154
210
|
function MemberRow({ member, navigable, openSession, t }) {
|
|
155
211
|
const name = readableMember(member.label, t);
|
|
212
|
+
const [focused, setFocused] = (0, react.useState)(false);
|
|
213
|
+
const renderButton = navigable || focused;
|
|
156
214
|
const content = (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
157
215
|
(0, react_jsx_runtime.jsx)("span", {
|
|
158
216
|
className: WorkflowRunPanel_module_css_default.dotSlot,
|
|
@@ -173,88 +231,205 @@ window.__ModuleLoader__.load({
|
|
|
173
231
|
children: t(STATUS_KEYS[member.status])
|
|
174
232
|
})
|
|
175
233
|
] });
|
|
176
|
-
if (!
|
|
234
|
+
if (!renderButton) return (0, react_jsx_runtime.jsx)("div", {
|
|
177
235
|
className: WorkflowRunPanel_module_css_default.memberRow,
|
|
178
236
|
"data-member-status": member.status,
|
|
179
237
|
children: content
|
|
180
238
|
});
|
|
181
239
|
return (0, react_jsx_runtime.jsx)("button", {
|
|
182
240
|
type: "button",
|
|
183
|
-
className: WorkflowRunPanel_module_css_default.memberButton,
|
|
241
|
+
className: navigable ? WorkflowRunPanel_module_css_default.memberButton : WorkflowRunPanel_module_css_default.memberRow,
|
|
184
242
|
"data-member-status": member.status,
|
|
185
|
-
"aria-
|
|
186
|
-
|
|
187
|
-
|
|
243
|
+
"aria-disabled": navigable ? void 0 : true,
|
|
244
|
+
"aria-label": navigable ? t("member.open", { name }) : name,
|
|
245
|
+
tabIndex: navigable ? void 0 : -1,
|
|
246
|
+
onFocus: () => {
|
|
247
|
+
setFocused(true);
|
|
248
|
+
},
|
|
249
|
+
onBlur: () => {
|
|
250
|
+
setFocused(false);
|
|
188
251
|
},
|
|
252
|
+
onClick: navigable ? () => {
|
|
253
|
+
openSession(member.childId);
|
|
254
|
+
} : void 0,
|
|
189
255
|
children: content
|
|
190
256
|
});
|
|
191
257
|
}
|
|
192
|
-
function PhaseSection({ phase, navigable, openSession, t }) {
|
|
193
|
-
return (0, react_jsx_runtime.jsx)(
|
|
194
|
-
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {}),
|
|
195
|
-
title: readablePhase(phase.phase, t),
|
|
196
|
-
cleanCycleKey: phase.members.length,
|
|
197
|
-
requiresExpansion: phaseRequiresExpansion(phase),
|
|
198
|
-
expandOnRowClick: true,
|
|
199
|
-
previewChevron: false,
|
|
200
|
-
keepContentWhenOpen: true,
|
|
258
|
+
function PhaseSection({ contentRef, onContentBlur, onToggle, open, pendingCleanCollapse, phase, navigable, openSession, t }) {
|
|
259
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
201
260
|
className: WorkflowRunPanel_module_css_default.phase,
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
261
|
+
onMouseDownCapture: pendingCleanCollapse ? preventPendingHeaderFocus : void 0,
|
|
262
|
+
children: (0, react_jsx_runtime.jsx)(StatusDisclosure, {
|
|
263
|
+
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {}),
|
|
264
|
+
title: readablePhase(phase.phase, t),
|
|
265
|
+
open,
|
|
266
|
+
onToggle,
|
|
267
|
+
expandOnRowClick: true,
|
|
268
|
+
previewChevron: false,
|
|
269
|
+
keepContentWhenOpen: true,
|
|
270
|
+
rowClassName: WorkflowRunPanel_module_css_default.phaseHeader,
|
|
271
|
+
leadingClassName: WorkflowRunPanel_module_css_default.phaseLeading,
|
|
272
|
+
titleClassName: WorkflowRunPanel_module_css_default.phaseTitle,
|
|
273
|
+
collapsedContent: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
274
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
275
|
+
className: WorkflowRunPanel_module_css_default.separator,
|
|
276
|
+
"aria-hidden": true
|
|
277
|
+
}),
|
|
278
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
279
|
+
className: WorkflowRunPanel_module_css_default.phaseCount,
|
|
280
|
+
"data-phase-count": true,
|
|
281
|
+
children: memberCount(phase.members.length, t)
|
|
282
|
+
}),
|
|
283
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
284
|
+
className: WorkflowRunPanel_module_css_default.phaseStatus,
|
|
285
|
+
"data-phase-status-text": true,
|
|
286
|
+
children: phaseStatusSummary(phase.members, t)
|
|
287
|
+
})
|
|
288
|
+
] }),
|
|
289
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
290
|
+
ref: contentRef,
|
|
291
|
+
className: WorkflowRunPanel_module_css_default.members,
|
|
292
|
+
onBlur: onContentBlur,
|
|
293
|
+
children: phase.members.map((member) => (0, react_jsx_runtime.jsx)(MemberRow, {
|
|
294
|
+
member,
|
|
295
|
+
navigable: navigable.includes(member.childId),
|
|
296
|
+
openSession,
|
|
297
|
+
t
|
|
298
|
+
}, member.seq))
|
|
219
299
|
})
|
|
220
|
-
] }),
|
|
221
|
-
children: (0, react_jsx_runtime.jsx)("div", {
|
|
222
|
-
className: WorkflowRunPanel_module_css_default.members,
|
|
223
|
-
children: phase.members.map((member) => (0, react_jsx_runtime.jsx)(MemberRow, {
|
|
224
|
-
member,
|
|
225
|
-
navigable: navigable.includes(member.childId),
|
|
226
|
-
openSession,
|
|
227
|
-
t
|
|
228
|
-
}, member.seq))
|
|
229
300
|
})
|
|
230
301
|
});
|
|
231
302
|
}
|
|
232
303
|
/** Render one durable workflow run with status-driven run and phase disclosure. */
|
|
233
304
|
function WorkflowRunPanel({ node, sessionId, useSessions, openSession, t }) {
|
|
234
|
-
const
|
|
235
|
-
const
|
|
305
|
+
const phaseFacts = (0, react.useMemo)(() => node.data.phases.map((phase) => [phase.key, phaseDisclosureFacts(phase)]), [node.data.phases]);
|
|
306
|
+
const runFacts = (0, react.useMemo)(() => runDisclosureFacts(node.data.status, phaseFacts), [node.data.status, phaseFacts]);
|
|
307
|
+
const totalMembers = runFacts.activityCount;
|
|
308
|
+
const [disclosures, setDisclosures] = (0, react.useState)(() => ({
|
|
309
|
+
run: initialDisclosureState(runFacts),
|
|
310
|
+
phases: new Map(phaseFacts.map(([key, facts]) => [key, initialDisclosureState(facts)]))
|
|
311
|
+
}));
|
|
312
|
+
const runContentRef = (0, react.useRef)(null);
|
|
313
|
+
const phaseContentRefs = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
236
314
|
const navigable = useSessions((sessions) => navigableMembers(sessions, node.data.phases, sessionId), _deepseek_ai_dsh_client_runtime_client.shallowEqual);
|
|
315
|
+
(0, react.useLayoutEffect)(() => {
|
|
316
|
+
setDisclosures((current) => {
|
|
317
|
+
const phases = /* @__PURE__ */ new Map();
|
|
318
|
+
let phasesChanged = current.phases.size !== phaseFacts.length;
|
|
319
|
+
let phaseStartedCycle = false;
|
|
320
|
+
for (const [key, facts] of phaseFacts) {
|
|
321
|
+
const previous = current.phases.get(key);
|
|
322
|
+
const next = previous === void 0 ? initialDisclosureState(facts) : advanceDisclosureState(previous, facts, focusIsWithin(phaseContentRefs.current.get(key)));
|
|
323
|
+
phases.set(key, next);
|
|
324
|
+
if (next !== previous) phasesChanged = true;
|
|
325
|
+
if (previous?.mode === "clean" && (facts.mode !== "clean" || facts.activityCount !== previous.activityCount)) phaseStartedCycle = true;
|
|
326
|
+
}
|
|
327
|
+
const advancedRun = advanceDisclosureState(current.run, runFacts, focusIsWithin(runContentRef.current));
|
|
328
|
+
const run = phaseStartedCycle && runFacts.mode !== "clean" && !advancedRun.open ? {
|
|
329
|
+
...advancedRun,
|
|
330
|
+
open: true,
|
|
331
|
+
pendingCleanCollapse: false
|
|
332
|
+
} : advancedRun;
|
|
333
|
+
return run !== current.run || phasesChanged ? {
|
|
334
|
+
run,
|
|
335
|
+
phases
|
|
336
|
+
} : current;
|
|
337
|
+
});
|
|
338
|
+
}, [
|
|
339
|
+
disclosures.run.open,
|
|
340
|
+
phaseFacts,
|
|
341
|
+
runFacts
|
|
342
|
+
]);
|
|
343
|
+
const toggleRun = () => {
|
|
344
|
+
setDisclosures((current) => ({
|
|
345
|
+
...current,
|
|
346
|
+
run: {
|
|
347
|
+
...current.run,
|
|
348
|
+
open: !current.run.open,
|
|
349
|
+
pendingCleanCollapse: false
|
|
350
|
+
}
|
|
351
|
+
}));
|
|
352
|
+
};
|
|
353
|
+
const togglePhase = (key) => {
|
|
354
|
+
setDisclosures((current) => {
|
|
355
|
+
const phases = new Map(current.phases);
|
|
356
|
+
const phase = existingPhaseState(phases, key);
|
|
357
|
+
phases.set(key, {
|
|
358
|
+
...phase,
|
|
359
|
+
open: !phase.open,
|
|
360
|
+
pendingCleanCollapse: false
|
|
361
|
+
});
|
|
362
|
+
return {
|
|
363
|
+
...current,
|
|
364
|
+
phases
|
|
365
|
+
};
|
|
366
|
+
});
|
|
367
|
+
};
|
|
368
|
+
const settleRunBlur = (event) => {
|
|
369
|
+
if (event.currentTarget.contains(event.relatedTarget)) return;
|
|
370
|
+
setDisclosures((current) => {
|
|
371
|
+
const run = collapsePending(current.run);
|
|
372
|
+
return run === current.run ? current : {
|
|
373
|
+
...current,
|
|
374
|
+
run
|
|
375
|
+
};
|
|
376
|
+
});
|
|
377
|
+
};
|
|
378
|
+
const settlePhaseBlur = (key, event) => {
|
|
379
|
+
if (event.currentTarget.contains(event.relatedTarget)) return;
|
|
380
|
+
setDisclosures((current) => {
|
|
381
|
+
const phase = existingPhaseState(current.phases, key);
|
|
382
|
+
const next = collapsePending(phase);
|
|
383
|
+
if (next === phase) return current;
|
|
384
|
+
const phases = new Map(current.phases);
|
|
385
|
+
phases.set(key, next);
|
|
386
|
+
return {
|
|
387
|
+
...current,
|
|
388
|
+
phases
|
|
389
|
+
};
|
|
390
|
+
});
|
|
391
|
+
};
|
|
237
392
|
return (0, react_jsx_runtime.jsx)("section", {
|
|
238
393
|
className: WorkflowRunPanel_module_css_default.root,
|
|
239
394
|
"data-workflow-run": true,
|
|
240
395
|
"data-run-status": node.data.status,
|
|
396
|
+
onMouseDownCapture: disclosures.run.pendingCleanCollapse ? preventPendingHeaderFocus : void 0,
|
|
241
397
|
children: (0, react_jsx_runtime.jsx)(RunHeader, {
|
|
242
398
|
count: totalMembers,
|
|
243
399
|
name: node.data.name,
|
|
244
|
-
|
|
400
|
+
open: disclosures.run.open,
|
|
401
|
+
onToggle: toggleRun,
|
|
245
402
|
status: node.data.status,
|
|
246
403
|
t,
|
|
247
404
|
children: (0, react_jsx_runtime.jsx)("div", {
|
|
405
|
+
ref: runContentRef,
|
|
248
406
|
className: WorkflowRunPanel_module_css_default.phaseList,
|
|
407
|
+
onBlur: settleRunBlur,
|
|
249
408
|
children: node.data.phases.length === 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
250
409
|
className: WorkflowRunPanel_module_css_default.empty,
|
|
251
410
|
children: t("run.empty")
|
|
252
|
-
}) : node.data.phases.map((phase) =>
|
|
253
|
-
phase
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
411
|
+
}) : node.data.phases.map((phase) => {
|
|
412
|
+
const facts = phaseDisclosureFacts(phase);
|
|
413
|
+
const disclosure = disclosures.phases.get(phase.key) ?? initialDisclosureState(facts);
|
|
414
|
+
return (0, react_jsx_runtime.jsx)(PhaseSection, {
|
|
415
|
+
contentRef: (element) => {
|
|
416
|
+
if (element === null) phaseContentRefs.current.delete(phase.key);
|
|
417
|
+
else phaseContentRefs.current.set(phase.key, element);
|
|
418
|
+
},
|
|
419
|
+
onContentBlur: (event) => {
|
|
420
|
+
settlePhaseBlur(phase.key, event);
|
|
421
|
+
},
|
|
422
|
+
onToggle: () => {
|
|
423
|
+
togglePhase(phase.key);
|
|
424
|
+
},
|
|
425
|
+
open: disclosure.open,
|
|
426
|
+
pendingCleanCollapse: disclosure.pendingCleanCollapse,
|
|
427
|
+
phase,
|
|
428
|
+
navigable,
|
|
429
|
+
openSession,
|
|
430
|
+
t
|
|
431
|
+
}, phase.key);
|
|
432
|
+
})
|
|
258
433
|
})
|
|
259
434
|
})
|
|
260
435
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-ui-workflow-run",
|
|
3
3
|
"description": "Durable workflow-run Conversation Node and nested member disclosure for dsh web",
|
|
4
|
-
"version": "0.1.0-rc.
|
|
4
|
+
"version": "0.1.0-rc.8",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -46,34 +46,30 @@
|
|
|
46
46
|
"lib/types/**/*.d.ts"
|
|
47
47
|
],
|
|
48
48
|
"license": "MIT",
|
|
49
|
-
"dependencies": {
|
|
50
|
-
"react": "^18.2.0"
|
|
51
|
-
},
|
|
52
49
|
"peerDependencies": {
|
|
53
|
-
"@deepseek-ai/dsh-client-
|
|
54
|
-
"@deepseek-ai/dsh-client-
|
|
55
|
-
"@deepseek-ai/dsh-
|
|
56
|
-
"@deepseek-ai/dsh-
|
|
57
|
-
"@deepseek-ai/dsh-
|
|
58
|
-
"@deepseek-ai/dsh-
|
|
59
|
-
"@deepseek-ai/
|
|
60
|
-
"@deepseek-ai/dsh-workflow": "^0.1.0-rc.
|
|
61
|
-
"@deepseek-ai/dsh-session": "^0.1.0-rc.7",
|
|
62
|
-
"@deepseek-ai/cordis": "^4.0.1"
|
|
50
|
+
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8",
|
|
51
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8",
|
|
52
|
+
"@deepseek-ai/dsh-invariants": "^0.1.0-rc.8",
|
|
53
|
+
"@deepseek-ai/dsh-session": "^0.1.0-rc.8",
|
|
54
|
+
"@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.8",
|
|
55
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8",
|
|
56
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
57
|
+
"@deepseek-ai/dsh-workflow": "^0.1.0-rc.8"
|
|
63
58
|
},
|
|
64
59
|
"devDependencies": {
|
|
65
60
|
"@types/react": "~18.3.1",
|
|
66
|
-
"
|
|
67
|
-
"@deepseek-ai/dsh-client-
|
|
68
|
-
"@deepseek-ai/dsh-client-
|
|
69
|
-
"@deepseek-ai/dsh-client-
|
|
70
|
-
"@deepseek-ai/dsh-client-ui-
|
|
71
|
-
"@deepseek-ai/dsh-client-ui-
|
|
72
|
-
"@deepseek-ai/dsh-
|
|
73
|
-
"@deepseek-ai/dsh-
|
|
74
|
-
"@deepseek-ai/dsh-
|
|
75
|
-
"@deepseek-ai/
|
|
76
|
-
"@deepseek-ai/dsh-
|
|
61
|
+
"react": "^18.2.0",
|
|
62
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8",
|
|
63
|
+
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8",
|
|
64
|
+
"@deepseek-ai/dsh-client-test-runtime": "^0.1.0-rc.8",
|
|
65
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8",
|
|
66
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.8",
|
|
67
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.8",
|
|
68
|
+
"@deepseek-ai/dsh-invariants": "^0.1.0-rc.8",
|
|
69
|
+
"@deepseek-ai/dsh-session": "^0.1.0-rc.8",
|
|
70
|
+
"@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.8",
|
|
71
|
+
"@deepseek-ai/dsh-workflow": "^0.1.0-rc.8",
|
|
72
|
+
"@deepseek-ai/cordis": "^4.0.1"
|
|
77
73
|
},
|
|
78
74
|
"scripts": {
|
|
79
75
|
"bundle": "tsdown",
|