@sparkelf/dsh-task-bus 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +671 -208
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +12 -1
- package/lib/index.js +241 -99
- package/package.json +6 -6
package/lib/client.js
CHANGED
|
@@ -7,6 +7,498 @@ window.__ModuleLoader__.load({
|
|
|
7
7
|
let react = require("react");
|
|
8
8
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
9
9
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
|
+
//#region src/client/theme.ts
|
|
11
|
+
/** Palette aliases the Task Center draws with; the shell owns the values. */
|
|
12
|
+
const colors = {
|
|
13
|
+
panel: "var(--dsw-alias-bg-layer-1, #ffffff)",
|
|
14
|
+
panelAlt: "var(--dsw-alias-bg-layer-2, #f7f8fa)",
|
|
15
|
+
text: "var(--dsw-alias-label-primary, #111827)",
|
|
16
|
+
muted: "var(--dsw-alias-label-secondary, #6b7280)",
|
|
17
|
+
line: "var(--dsw-alias-border-l1, #e5e7eb)",
|
|
18
|
+
accent: "var(--dsw-alias-brand-primary, #2563eb)",
|
|
19
|
+
accentSoft: "var(--dsw-alias-brand-primary-alpha, #eff6ff)",
|
|
20
|
+
warning: "var(--dsw-alias-state-warning, #b45309)",
|
|
21
|
+
success: "var(--dsw-alias-state-success, #047857)",
|
|
22
|
+
danger: "var(--dsw-alias-state-danger, #b91c1c)"
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/client/connector-state.ts
|
|
26
|
+
/**
|
|
27
|
+
* Client state adapter for the Task Center's one connector.
|
|
28
|
+
*
|
|
29
|
+
* The Host owns the authoritative enabled/capability state and the tool
|
|
30
|
+
* disclosure that follows it. This module only reads that state, sends the two
|
|
31
|
+
* writes the panel offers, and projects the task rows a capability filter
|
|
32
|
+
* selects. It never decides permissions: a capability absent from the Host's
|
|
33
|
+
* answer is one this account may not use, so it is never rendered.
|
|
34
|
+
*
|
|
35
|
+
* @module @sparkelf/dsh-task-bus/client/connector-state
|
|
36
|
+
*/
|
|
37
|
+
/** Route the Host serves the connector state from. */
|
|
38
|
+
const CONNECTOR_ROUTE = "/dsh-task-bus/api/connector";
|
|
39
|
+
/** Connector id carried by DataOps approval tasks. */
|
|
40
|
+
const CONNECTOR_ID = "wanxiang-ai";
|
|
41
|
+
/** Display name shared by the card and its empty state. */
|
|
42
|
+
const CONNECTOR_NAME = "万相AI中台连接器";
|
|
43
|
+
/** Copy for the capability ids the Host currently ships. */
|
|
44
|
+
const CAPABILITY_COPY = {
|
|
45
|
+
"approval.push": {
|
|
46
|
+
label: "接收审批任务",
|
|
47
|
+
description: "从万相AI中台接收待办理的审批任务"
|
|
48
|
+
},
|
|
49
|
+
"approval.writeback": {
|
|
50
|
+
label: "回写审批结果",
|
|
51
|
+
description: "把办理结果回写到万相AI中台"
|
|
52
|
+
},
|
|
53
|
+
"task.push": {
|
|
54
|
+
label: "接收通用任务",
|
|
55
|
+
description: "接收万相AI中台下发的通用任务"
|
|
56
|
+
},
|
|
57
|
+
"task.writeback": {
|
|
58
|
+
label: "回写任务状态",
|
|
59
|
+
description: "把任务处理状态回写到万相AI中台"
|
|
60
|
+
},
|
|
61
|
+
"ai.accept": {
|
|
62
|
+
label: "AI 受理",
|
|
63
|
+
description: "由助手创建受理会话处理任务"
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
/** Humanize an id the client has no display copy for. */
|
|
67
|
+
function humanizeCapability(id) {
|
|
68
|
+
return id.replace(/[._-]+/gu, " ").trim();
|
|
69
|
+
}
|
|
70
|
+
/** Parse one unknown wire value into connector state. */
|
|
71
|
+
function parseConnectorState(value) {
|
|
72
|
+
if (typeof value !== "object" || value === null) return {
|
|
73
|
+
enabled: false,
|
|
74
|
+
capabilities: {}
|
|
75
|
+
};
|
|
76
|
+
const row = value;
|
|
77
|
+
const capabilities = {};
|
|
78
|
+
const reasons = {};
|
|
79
|
+
const raw = typeof row.capabilities === "object" && row.capabilities !== null ? row.capabilities : {};
|
|
80
|
+
for (const [id, entry] of Object.entries(raw)) {
|
|
81
|
+
if (typeof entry === "boolean") {
|
|
82
|
+
capabilities[id] = entry;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
86
|
+
const detail = entry;
|
|
87
|
+
if (detail.permitted === false) continue;
|
|
88
|
+
capabilities[id] = detail.enabled === true;
|
|
89
|
+
if (typeof detail.reason === "string" && detail.reason !== "") reasons[id] = detail.reason;
|
|
90
|
+
}
|
|
91
|
+
const rawReasons = typeof row.reasons === "object" && row.reasons !== null ? row.reasons : {};
|
|
92
|
+
for (const [id, reason] of Object.entries(rawReasons)) if (typeof reason === "string" && reason !== "") reasons[id] = reason;
|
|
93
|
+
return {
|
|
94
|
+
enabled: row.enabled === true,
|
|
95
|
+
capabilities,
|
|
96
|
+
...Object.keys(reasons).length === 0 ? {} : { reasons }
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Read the Host's connector state.
|
|
101
|
+
* @param route - connector route; overridable for tests.
|
|
102
|
+
* @returns the parsed state.
|
|
103
|
+
* @throws when the Host rejects the request.
|
|
104
|
+
*/
|
|
105
|
+
async function fetchConnectorState(route = CONNECTOR_ROUTE) {
|
|
106
|
+
const response = await fetch(route, { headers: { accept: "application/json" } });
|
|
107
|
+
if (!response.ok) throw new Error("连接器状态读取失败(" + String(response.status) + ")");
|
|
108
|
+
return parseConnectorState(await response.json());
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Write connector state through the Host.
|
|
112
|
+
* @param patch - the enabled flag and optional capability changes to merge.
|
|
113
|
+
* @param route - connector route; overridable for tests.
|
|
114
|
+
* @returns the state the Host persisted.
|
|
115
|
+
* @throws when the Host rejects the request.
|
|
116
|
+
*/
|
|
117
|
+
async function saveConnectorState(patch, route = CONNECTOR_ROUTE) {
|
|
118
|
+
const response = await fetch(route, {
|
|
119
|
+
method: "POST",
|
|
120
|
+
headers: {
|
|
121
|
+
accept: "application/json",
|
|
122
|
+
"content-type": "application/json"
|
|
123
|
+
},
|
|
124
|
+
body: JSON.stringify(patch)
|
|
125
|
+
});
|
|
126
|
+
if (!response.ok) throw new Error("连接器状态保存失败(" + String(response.status) + ")");
|
|
127
|
+
return parseConnectorState(await response.json());
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Project the capability rows the card renders.
|
|
131
|
+
* @param state - Host state.
|
|
132
|
+
* @returns one row per capability the account may use, in the Host's order.
|
|
133
|
+
*/
|
|
134
|
+
function visibleCapabilities(state) {
|
|
135
|
+
if (state === null) return [];
|
|
136
|
+
return Object.entries(state.capabilities).map(([id, enabled]) => {
|
|
137
|
+
const copy = CAPABILITY_COPY[id];
|
|
138
|
+
return {
|
|
139
|
+
id,
|
|
140
|
+
label: copy?.label ?? humanizeCapability(id),
|
|
141
|
+
...copy === void 0 ? {} : { description: copy.description },
|
|
142
|
+
enabled,
|
|
143
|
+
...state.reasons?.[id] === void 0 ? {} : { unavailableReason: state.reasons[id] }
|
|
144
|
+
};
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The connector that produced a task row. MVP DataOps approval rows predate
|
|
149
|
+
* explicit ids, so their source type still identifies the built-in connector.
|
|
150
|
+
* @param task - one task row.
|
|
151
|
+
* @returns the connector id, or undefined for a generic Task Bus row.
|
|
152
|
+
*/
|
|
153
|
+
function taskConnectorId(task) {
|
|
154
|
+
if (task.connectorId !== void 0 && task.connectorId !== "") return task.connectorId;
|
|
155
|
+
return task.sourceType === "dataops_approval" ? CONNECTOR_ID : void 0;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The capability that produced a task row; an id-less DataOps approval row
|
|
159
|
+
* belongs to `approval.push`.
|
|
160
|
+
* @param task - one task row.
|
|
161
|
+
* @returns the capability id, or undefined for a generic Task Bus row.
|
|
162
|
+
*/
|
|
163
|
+
function taskCapabilityId(task) {
|
|
164
|
+
if (task.capabilityId !== void 0 && task.capabilityId !== "") return task.capabilityId;
|
|
165
|
+
return task.sourceType === "dataops_approval" ? "approval.push" : void 0;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Filter rows for the connector tab.
|
|
169
|
+
* @param tasks - every loaded row.
|
|
170
|
+
* @param capabilityId - `all`, or the capability whose rows should remain.
|
|
171
|
+
* @returns rows produced by the built-in connector, narrowed to the capability.
|
|
172
|
+
*/
|
|
173
|
+
function filterConnectorTasks(tasks, capabilityId) {
|
|
174
|
+
return tasks.filter((task) => taskConnectorId(task) === "wanxiang-ai" && (capabilityId === "all" || taskCapabilityId(task) === capabilityId));
|
|
175
|
+
}
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region src/client/ConnectorCard.tsx
|
|
178
|
+
/** Status label and tone for the card header. */
|
|
179
|
+
function statusOf(state, loading, error) {
|
|
180
|
+
if (loading && state === null) return {
|
|
181
|
+
label: "同步中",
|
|
182
|
+
tone: "neutral"
|
|
183
|
+
};
|
|
184
|
+
if (error !== null) return {
|
|
185
|
+
label: "连接异常",
|
|
186
|
+
tone: "danger"
|
|
187
|
+
};
|
|
188
|
+
if (state?.enabled !== true) return {
|
|
189
|
+
label: "未启用",
|
|
190
|
+
tone: "neutral"
|
|
191
|
+
};
|
|
192
|
+
return {
|
|
193
|
+
label: "已连接",
|
|
194
|
+
tone: "success"
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/** Draw the connector glyph the card header carries. */
|
|
198
|
+
function ConnectorGlyph() {
|
|
199
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
200
|
+
width: "18",
|
|
201
|
+
height: "18",
|
|
202
|
+
viewBox: "0 0 24 24",
|
|
203
|
+
fill: "none",
|
|
204
|
+
stroke: "currentColor",
|
|
205
|
+
strokeWidth: "1.8",
|
|
206
|
+
strokeLinecap: "round",
|
|
207
|
+
strokeLinejoin: "round",
|
|
208
|
+
"aria-hidden": "true",
|
|
209
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M10 13a5 5 0 0 0 7.54.54l2-2a5 5 0 0 0-7.07-7.07l-1.15 1.15" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-2 2a5 5 0 0 0 7.07 7.07l1.15-1.15" })]
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Render the connector card.
|
|
214
|
+
* @param props - server state, write handlers, and the current task count.
|
|
215
|
+
* @returns the card.
|
|
216
|
+
*/
|
|
217
|
+
function ConnectorCard({ state, loading, error, busy, taskCount, onSetEnabled, onToggleCapability, onReload }) {
|
|
218
|
+
const status = statusOf(state, loading, error);
|
|
219
|
+
const enabled = state?.enabled === true;
|
|
220
|
+
const capabilities = visibleCapabilities(state);
|
|
221
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
222
|
+
"data-connector-card": CONNECTOR_NAME,
|
|
223
|
+
"data-connector-enabled": enabled,
|
|
224
|
+
style: {
|
|
225
|
+
width: "100%",
|
|
226
|
+
minWidth: 0,
|
|
227
|
+
border: "1px solid " + colors.line,
|
|
228
|
+
borderRadius: 12,
|
|
229
|
+
background: colors.panelAlt,
|
|
230
|
+
padding: 14,
|
|
231
|
+
display: "flex",
|
|
232
|
+
flexDirection: "column",
|
|
233
|
+
gap: 10
|
|
234
|
+
},
|
|
235
|
+
children: [
|
|
236
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
237
|
+
style: {
|
|
238
|
+
display: "flex",
|
|
239
|
+
alignItems: "center",
|
|
240
|
+
gap: 9
|
|
241
|
+
},
|
|
242
|
+
children: [
|
|
243
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
244
|
+
"aria-hidden": "true",
|
|
245
|
+
style: {
|
|
246
|
+
width: 32,
|
|
247
|
+
height: 32,
|
|
248
|
+
flex: "none",
|
|
249
|
+
borderRadius: 9,
|
|
250
|
+
background: "#2563eb",
|
|
251
|
+
color: "#fff",
|
|
252
|
+
display: "inline-flex",
|
|
253
|
+
alignItems: "center",
|
|
254
|
+
justifyContent: "center"
|
|
255
|
+
},
|
|
256
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConnectorGlyph, {})
|
|
257
|
+
}),
|
|
258
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
259
|
+
style: {
|
|
260
|
+
flex: 1,
|
|
261
|
+
minWidth: 0
|
|
262
|
+
},
|
|
263
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
264
|
+
style: {
|
|
265
|
+
fontSize: 13,
|
|
266
|
+
fontWeight: 700,
|
|
267
|
+
color: colors.text
|
|
268
|
+
},
|
|
269
|
+
children: CONNECTOR_NAME
|
|
270
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
271
|
+
style: {
|
|
272
|
+
marginTop: 2,
|
|
273
|
+
fontSize: 10,
|
|
274
|
+
color: colors.muted
|
|
275
|
+
},
|
|
276
|
+
children: "DataOps"
|
|
277
|
+
})]
|
|
278
|
+
}),
|
|
279
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
|
|
280
|
+
tone: status.tone,
|
|
281
|
+
children: status.label
|
|
282
|
+
})
|
|
283
|
+
]
|
|
284
|
+
}),
|
|
285
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
286
|
+
style: {
|
|
287
|
+
fontSize: 11,
|
|
288
|
+
lineHeight: 1.55,
|
|
289
|
+
color: colors.muted
|
|
290
|
+
},
|
|
291
|
+
children: "接收万相AI中台的审批任务"
|
|
292
|
+
}),
|
|
293
|
+
loading && state === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
294
|
+
style: {
|
|
295
|
+
fontSize: 11,
|
|
296
|
+
color: colors.muted
|
|
297
|
+
},
|
|
298
|
+
children: "正在读取连接器状态…"
|
|
299
|
+
}) : null,
|
|
300
|
+
error === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
301
|
+
role: "alert",
|
|
302
|
+
style: {
|
|
303
|
+
display: "flex",
|
|
304
|
+
alignItems: "center",
|
|
305
|
+
gap: 8,
|
|
306
|
+
fontSize: 11,
|
|
307
|
+
color: colors.danger
|
|
308
|
+
},
|
|
309
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
310
|
+
style: {
|
|
311
|
+
flex: 1,
|
|
312
|
+
minWidth: 0
|
|
313
|
+
},
|
|
314
|
+
children: error
|
|
315
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
316
|
+
size: "sm",
|
|
317
|
+
variant: "ghost",
|
|
318
|
+
disabled: loading,
|
|
319
|
+
onClick: onReload,
|
|
320
|
+
children: "重试"
|
|
321
|
+
})]
|
|
322
|
+
}),
|
|
323
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
324
|
+
style: {
|
|
325
|
+
display: "flex",
|
|
326
|
+
alignItems: "center",
|
|
327
|
+
justifyContent: "space-between",
|
|
328
|
+
gap: 10,
|
|
329
|
+
minHeight: 28
|
|
330
|
+
},
|
|
331
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
332
|
+
style: {
|
|
333
|
+
fontSize: 12,
|
|
334
|
+
color: colors.muted
|
|
335
|
+
},
|
|
336
|
+
children: enabled ? "已启用,任务中心只读取该连接器的任务" : "未启用,任务中心不读取外部任务"
|
|
337
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
|
|
338
|
+
checked: enabled,
|
|
339
|
+
disabled: busy || loading,
|
|
340
|
+
label: (enabled ? "停用 " : "启用 ") + CONNECTOR_NAME,
|
|
341
|
+
onChange: (next) => {
|
|
342
|
+
onSetEnabled(next);
|
|
343
|
+
}
|
|
344
|
+
})]
|
|
345
|
+
}),
|
|
346
|
+
enabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
347
|
+
"data-connector-capabilities": true,
|
|
348
|
+
style: {
|
|
349
|
+
borderTop: "1px solid " + colors.line,
|
|
350
|
+
paddingTop: 8,
|
|
351
|
+
display: "grid",
|
|
352
|
+
gap: 2
|
|
353
|
+
},
|
|
354
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
355
|
+
style: {
|
|
356
|
+
fontSize: 10,
|
|
357
|
+
color: colors.muted
|
|
358
|
+
},
|
|
359
|
+
children: "能力"
|
|
360
|
+
}), capabilities.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
361
|
+
style: {
|
|
362
|
+
fontSize: 11,
|
|
363
|
+
color: colors.muted,
|
|
364
|
+
padding: "6px 0"
|
|
365
|
+
},
|
|
366
|
+
children: "当前账号没有可用的连接器能力,请联系管理员开通"
|
|
367
|
+
}) : capabilities.map((capability) => {
|
|
368
|
+
const unavailable = capability.unavailableReason !== void 0;
|
|
369
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
370
|
+
"data-capability-id": capability.id,
|
|
371
|
+
"data-capability-enabled": capability.enabled,
|
|
372
|
+
style: {
|
|
373
|
+
display: "flex",
|
|
374
|
+
alignItems: "center",
|
|
375
|
+
gap: 10,
|
|
376
|
+
minHeight: 40,
|
|
377
|
+
padding: "4px 0",
|
|
378
|
+
borderTop: "1px solid " + colors.line
|
|
379
|
+
},
|
|
380
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
381
|
+
style: {
|
|
382
|
+
flex: 1,
|
|
383
|
+
minWidth: 0
|
|
384
|
+
},
|
|
385
|
+
children: [
|
|
386
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
387
|
+
style: {
|
|
388
|
+
fontSize: 12,
|
|
389
|
+
color: colors.text
|
|
390
|
+
},
|
|
391
|
+
children: capability.label
|
|
392
|
+
}),
|
|
393
|
+
capability.description === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
394
|
+
style: {
|
|
395
|
+
marginTop: 1,
|
|
396
|
+
fontSize: 10,
|
|
397
|
+
color: colors.muted
|
|
398
|
+
},
|
|
399
|
+
children: capability.description
|
|
400
|
+
}),
|
|
401
|
+
capability.unavailableReason === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
402
|
+
style: {
|
|
403
|
+
marginTop: 2,
|
|
404
|
+
fontSize: 10,
|
|
405
|
+
color: colors.warning
|
|
406
|
+
},
|
|
407
|
+
children: ["暂不可用 · ", capability.unavailableReason]
|
|
408
|
+
})
|
|
409
|
+
]
|
|
410
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
|
|
411
|
+
checked: capability.enabled,
|
|
412
|
+
disabled: busy || unavailable,
|
|
413
|
+
label: (capability.enabled ? "停用 " : "启用 ") + capability.label,
|
|
414
|
+
onChange: (next) => {
|
|
415
|
+
onToggleCapability(capability.id, next);
|
|
416
|
+
}
|
|
417
|
+
})]
|
|
418
|
+
}, capability.id);
|
|
419
|
+
})]
|
|
420
|
+
}) : null,
|
|
421
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
422
|
+
style: {
|
|
423
|
+
display: "flex",
|
|
424
|
+
alignItems: "center",
|
|
425
|
+
justifyContent: "space-between",
|
|
426
|
+
gap: 8,
|
|
427
|
+
marginTop: "auto",
|
|
428
|
+
fontSize: 10,
|
|
429
|
+
color: colors.muted
|
|
430
|
+
},
|
|
431
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: enabled ? "该连接器任务 " + String(taskCount) + " 条" : "启用后在此查看连接器任务" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
432
|
+
size: "sm",
|
|
433
|
+
variant: "ghost",
|
|
434
|
+
disabled: loading,
|
|
435
|
+
onClick: onReload,
|
|
436
|
+
children: "刷新状态"
|
|
437
|
+
})]
|
|
438
|
+
})
|
|
439
|
+
]
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* The disabled connector's empty state, with the one path that can enable it.
|
|
444
|
+
* @param props.onOpenSkillCenter - select the skill center's connector tab.
|
|
445
|
+
* @returns the empty state.
|
|
446
|
+
*/
|
|
447
|
+
function ConnectorDisabledState({ onOpenSkillCenter }) {
|
|
448
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
449
|
+
"data-connector-disabled-state": true,
|
|
450
|
+
style: {
|
|
451
|
+
display: "grid",
|
|
452
|
+
justifyItems: "center",
|
|
453
|
+
gap: 8,
|
|
454
|
+
padding: "36px 20px 40px",
|
|
455
|
+
color: colors.muted,
|
|
456
|
+
textAlign: "center"
|
|
457
|
+
},
|
|
458
|
+
children: [
|
|
459
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
460
|
+
style: {
|
|
461
|
+
display: "inline-flex",
|
|
462
|
+
width: 36,
|
|
463
|
+
height: 36,
|
|
464
|
+
alignItems: "center",
|
|
465
|
+
justifyContent: "center",
|
|
466
|
+
borderRadius: 18,
|
|
467
|
+
background: colors.panelAlt,
|
|
468
|
+
color: colors.muted
|
|
469
|
+
},
|
|
470
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConnectorGlyph, {})
|
|
471
|
+
}),
|
|
472
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
473
|
+
style: {
|
|
474
|
+
fontSize: 13,
|
|
475
|
+
fontWeight: 600,
|
|
476
|
+
color: colors.text
|
|
477
|
+
},
|
|
478
|
+
children: "连接器未启用"
|
|
479
|
+
}),
|
|
480
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
481
|
+
style: {
|
|
482
|
+
maxWidth: 380,
|
|
483
|
+
fontSize: 12,
|
|
484
|
+
lineHeight: 1.6
|
|
485
|
+
},
|
|
486
|
+
children: [
|
|
487
|
+
"在技能中心的连接器页面启用「",
|
|
488
|
+
CONNECTOR_NAME,
|
|
489
|
+
"」后,这里会显示它接收的审批任务。"
|
|
490
|
+
]
|
|
491
|
+
}),
|
|
492
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
493
|
+
size: "sm",
|
|
494
|
+
variant: "outline",
|
|
495
|
+
onClick: onOpenSkillCenter,
|
|
496
|
+
children: "前往技能中心启用"
|
|
497
|
+
})
|
|
498
|
+
]
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
//#endregion
|
|
10
502
|
//#region src/client/index.tsx
|
|
11
503
|
/**
|
|
12
504
|
* The Task Center surface in the frame-wide overlay.
|
|
@@ -20,21 +512,10 @@ window.__ModuleLoader__.load({
|
|
|
20
512
|
"locale",
|
|
21
513
|
"uiWorkspace",
|
|
22
514
|
"sessions",
|
|
23
|
-
"sidebarRight"
|
|
515
|
+
"sidebarRight",
|
|
516
|
+
"layout"
|
|
24
517
|
];
|
|
25
518
|
const ROUTE = "/dsh-task-bus/api";
|
|
26
|
-
const colors = {
|
|
27
|
-
panel: "var(--dsw-alias-bg-layer-1, #ffffff)",
|
|
28
|
-
panelAlt: "var(--dsw-alias-bg-layer-2, #f7f8fa)",
|
|
29
|
-
text: "var(--dsw-alias-label-primary, #111827)",
|
|
30
|
-
muted: "var(--dsw-alias-label-secondary, #6b7280)",
|
|
31
|
-
line: "var(--dsw-alias-border-l1, #e5e7eb)",
|
|
32
|
-
accent: "var(--dsw-alias-brand-primary, #2563eb)",
|
|
33
|
-
accentSoft: "var(--dsw-alias-brand-primary-alpha, #eff6ff)",
|
|
34
|
-
warning: "var(--dsw-alias-state-warning, #b45309)",
|
|
35
|
-
success: "var(--dsw-alias-state-success, #047857)",
|
|
36
|
-
danger: "var(--dsw-alias-state-danger, #b91c1c)"
|
|
37
|
-
};
|
|
38
519
|
const TASK_BUS_MODAL_CLASS = "task-bus-center-modal";
|
|
39
520
|
const TASK_BUS_HISTORY_CLASS = "task-bus-history-modal";
|
|
40
521
|
const TASK_BUS_STYLE_ID = "task-bus-center-modal-style";
|
|
@@ -113,6 +594,17 @@ window.__ModuleLoader__.load({
|
|
|
113
594
|
fontSize: 12,
|
|
114
595
|
cursor: "pointer"
|
|
115
596
|
};
|
|
597
|
+
/** Capability filter chip; the active chip keeps the accent fill and stroke. */
|
|
598
|
+
const filterChipStyle = (active) => ({
|
|
599
|
+
padding: "4px 10px",
|
|
600
|
+
borderRadius: 999,
|
|
601
|
+
border: "1px solid " + (active ? colors.accent : colors.line),
|
|
602
|
+
background: active ? colors.accentSoft : "transparent",
|
|
603
|
+
color: active ? colors.accent : colors.muted,
|
|
604
|
+
fontSize: 11,
|
|
605
|
+
lineHeight: 1.6,
|
|
606
|
+
cursor: "pointer"
|
|
607
|
+
});
|
|
116
608
|
const statusTagTone = (status) => {
|
|
117
609
|
if (status === "completed") return "success";
|
|
118
610
|
if (status === "cancelled") return "neutral";
|
|
@@ -131,8 +623,18 @@ window.__ModuleLoader__.load({
|
|
|
131
623
|
return String(Math.round(hours / 24)) + " 天前";
|
|
132
624
|
};
|
|
133
625
|
const fetchJson = async (path) => {
|
|
134
|
-
const
|
|
135
|
-
|
|
626
|
+
const attempt = async () => {
|
|
627
|
+
const response = await fetch(ROUTE + path, { headers: { accept: "application/json" } });
|
|
628
|
+
return {
|
|
629
|
+
response,
|
|
630
|
+
payload: await response.json()
|
|
631
|
+
};
|
|
632
|
+
};
|
|
633
|
+
let { response, payload } = await attempt();
|
|
634
|
+
if (response.status === 401) {
|
|
635
|
+
await new Promise((resolve) => setTimeout(resolve, 900));
|
|
636
|
+
({response, payload} = await attempt());
|
|
637
|
+
}
|
|
136
638
|
if (!response.ok) {
|
|
137
639
|
const message = payload !== null && typeof payload === "object" && "error" in payload ? String(payload.error) : "任务中心请求失败(" + response.status + ")";
|
|
138
640
|
throw new Error(message);
|
|
@@ -694,169 +1196,7 @@ window.__ModuleLoader__.load({
|
|
|
694
1196
|
]
|
|
695
1197
|
});
|
|
696
1198
|
};
|
|
697
|
-
const
|
|
698
|
-
const DataOpsConnectorCard = ({ approvalCount, connected, enabled, onEnable }) => {
|
|
699
|
-
const [detailOpen, setDetailOpen] = (0, react.useState)(false);
|
|
700
|
-
const status = !enabled ? "未启用" : connected ? "已连接" : "连接异常";
|
|
701
|
-
const tone = !enabled ? "neutral" : connected ? "success" : "danger";
|
|
702
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
703
|
-
style: {
|
|
704
|
-
width: "100%",
|
|
705
|
-
minWidth: 0,
|
|
706
|
-
border: "1px solid " + colors.line,
|
|
707
|
-
borderRadius: 12,
|
|
708
|
-
background: colors.panelAlt,
|
|
709
|
-
padding: 14,
|
|
710
|
-
display: "flex",
|
|
711
|
-
flexDirection: "column",
|
|
712
|
-
gap: 10
|
|
713
|
-
},
|
|
714
|
-
children: [
|
|
715
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
716
|
-
style: {
|
|
717
|
-
display: "flex",
|
|
718
|
-
alignItems: "center",
|
|
719
|
-
gap: 9
|
|
720
|
-
},
|
|
721
|
-
children: [
|
|
722
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
723
|
-
"aria-hidden": "true",
|
|
724
|
-
style: {
|
|
725
|
-
width: 32,
|
|
726
|
-
height: 32,
|
|
727
|
-
flex: "none",
|
|
728
|
-
borderRadius: 9,
|
|
729
|
-
background: "#2563eb",
|
|
730
|
-
color: "#fff",
|
|
731
|
-
display: "inline-flex",
|
|
732
|
-
alignItems: "center",
|
|
733
|
-
justifyContent: "center"
|
|
734
|
-
},
|
|
735
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
736
|
-
width: "18",
|
|
737
|
-
height: "18",
|
|
738
|
-
viewBox: "0 0 24 24",
|
|
739
|
-
fill: "none",
|
|
740
|
-
stroke: "currentColor",
|
|
741
|
-
strokeWidth: "1.8",
|
|
742
|
-
strokeLinecap: "round",
|
|
743
|
-
strokeLinejoin: "round",
|
|
744
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M10 13a5 5 0 0 0 7.54.54l2-2a5 5 0 0 0-7.07-7.07l-1.15 1.15" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-2 2a5 5 0 0 0 7.07 7.07l1.15-1.15" })]
|
|
745
|
-
})
|
|
746
|
-
}),
|
|
747
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
748
|
-
style: {
|
|
749
|
-
flex: 1,
|
|
750
|
-
minWidth: 0
|
|
751
|
-
},
|
|
752
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
753
|
-
style: {
|
|
754
|
-
fontSize: 13,
|
|
755
|
-
fontWeight: 700,
|
|
756
|
-
color: colors.text
|
|
757
|
-
},
|
|
758
|
-
children: "万相 AI 中台"
|
|
759
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
760
|
-
style: {
|
|
761
|
-
marginTop: 2,
|
|
762
|
-
fontSize: 10,
|
|
763
|
-
color: colors.muted
|
|
764
|
-
},
|
|
765
|
-
children: "DataOps 连接器"
|
|
766
|
-
})]
|
|
767
|
-
}),
|
|
768
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
|
|
769
|
-
tone,
|
|
770
|
-
children: status
|
|
771
|
-
})
|
|
772
|
-
]
|
|
773
|
-
}),
|
|
774
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
775
|
-
style: {
|
|
776
|
-
fontSize: 11,
|
|
777
|
-
lineHeight: 1.55,
|
|
778
|
-
color: colors.muted
|
|
779
|
-
},
|
|
780
|
-
children: "接收万相 AI 中台的审批任务"
|
|
781
|
-
}),
|
|
782
|
-
detailOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
783
|
-
style: {
|
|
784
|
-
borderTop: "1px solid " + colors.line,
|
|
785
|
-
paddingTop: 8,
|
|
786
|
-
display: "grid",
|
|
787
|
-
gap: 6
|
|
788
|
-
},
|
|
789
|
-
children: [
|
|
790
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
791
|
-
style: {
|
|
792
|
-
display: "grid",
|
|
793
|
-
gridTemplateColumns: "68px minmax(0,1fr)",
|
|
794
|
-
gap: 8,
|
|
795
|
-
fontSize: 10
|
|
796
|
-
},
|
|
797
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
798
|
-
style: { color: colors.muted },
|
|
799
|
-
children: "协议"
|
|
800
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
801
|
-
style: { color: colors.text },
|
|
802
|
-
children: "DataOps Task Center API"
|
|
803
|
-
})]
|
|
804
|
-
}),
|
|
805
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
806
|
-
style: {
|
|
807
|
-
display: "grid",
|
|
808
|
-
gridTemplateColumns: "68px minmax(0,1fr)",
|
|
809
|
-
gap: 8,
|
|
810
|
-
fontSize: 10
|
|
811
|
-
},
|
|
812
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
813
|
-
style: { color: colors.muted },
|
|
814
|
-
children: "审批任务"
|
|
815
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
816
|
-
style: { color: colors.text },
|
|
817
|
-
children: approvalCount
|
|
818
|
-
})]
|
|
819
|
-
}),
|
|
820
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
821
|
-
style: {
|
|
822
|
-
display: "grid",
|
|
823
|
-
gridTemplateColumns: "68px minmax(0,1fr)",
|
|
824
|
-
gap: 8,
|
|
825
|
-
fontSize: 10
|
|
826
|
-
},
|
|
827
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
828
|
-
style: { color: colors.muted },
|
|
829
|
-
children: "能力"
|
|
830
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
831
|
-
style: { color: colors.text },
|
|
832
|
-
children: "审批 / 通用任务 / AI 受理"
|
|
833
|
-
})]
|
|
834
|
-
})
|
|
835
|
-
]
|
|
836
|
-
}) : null,
|
|
837
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
838
|
-
style: {
|
|
839
|
-
display: "flex",
|
|
840
|
-
gap: 6,
|
|
841
|
-
marginTop: "auto"
|
|
842
|
-
},
|
|
843
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
844
|
-
size: "sm",
|
|
845
|
-
variant: "ghost",
|
|
846
|
-
onClick: () => setDetailOpen((value) => !value),
|
|
847
|
-
children: detailOpen ? "收起" : "详情"
|
|
848
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
849
|
-
size: "sm",
|
|
850
|
-
variant: enabled ? "outline" : "primary",
|
|
851
|
-
disabled: enabled,
|
|
852
|
-
onClick: onEnable,
|
|
853
|
-
children: enabled ? "已启用" : "启用"
|
|
854
|
-
})]
|
|
855
|
-
})
|
|
856
|
-
]
|
|
857
|
-
});
|
|
858
|
-
};
|
|
859
|
-
const TaskCenterButton = ({ openSession }) => {
|
|
1199
|
+
const TaskCenterButton = ({ openSession, openSkillCenter }) => {
|
|
860
1200
|
const [open, setOpen] = (0, react.useState)(false);
|
|
861
1201
|
const [tasks, setTasks] = (0, react.useState)([]);
|
|
862
1202
|
const [loading, setLoading] = (0, react.useState)(false);
|
|
@@ -870,14 +1210,14 @@ window.__ModuleLoader__.load({
|
|
|
870
1210
|
const [createBusy, setCreateBusy] = (0, react.useState)(false);
|
|
871
1211
|
const [selected, setSelected] = (0, react.useState)(null);
|
|
872
1212
|
const [anchor, setAnchor] = (0, react.useState)(null);
|
|
873
|
-
const [
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
});
|
|
1213
|
+
const [connector, setConnector] = (0, react.useState)(null);
|
|
1214
|
+
const [connectorLoading, setConnectorLoading] = (0, react.useState)(true);
|
|
1215
|
+
const [connectorError, setConnectorError] = (0, react.useState)(null);
|
|
1216
|
+
const [connectorBusy, setConnectorBusy] = (0, react.useState)(false);
|
|
1217
|
+
const [capabilityFilter, setCapabilityFilter] = (0, react.useState)("all");
|
|
1218
|
+
const [skillCenterError, setSkillCenterError] = (0, react.useState)(null);
|
|
880
1219
|
const [pendingCount, setPendingCount] = (0, react.useState)(0);
|
|
1220
|
+
const connectorEnabled = connector?.enabled === true;
|
|
881
1221
|
(0, react.useEffect)(() => {
|
|
882
1222
|
if (document.getElementById(TASK_BUS_STYLE_ID) !== null) return;
|
|
883
1223
|
const style = document.createElement("style");
|
|
@@ -920,6 +1260,32 @@ window.__ModuleLoader__.load({
|
|
|
920
1260
|
window.removeEventListener("resize", update);
|
|
921
1261
|
};
|
|
922
1262
|
}, []);
|
|
1263
|
+
const readConnector = async () => {
|
|
1264
|
+
setConnectorLoading(true);
|
|
1265
|
+
setConnectorError(null);
|
|
1266
|
+
try {
|
|
1267
|
+
setConnector(await fetchConnectorState());
|
|
1268
|
+
} catch (cause) {
|
|
1269
|
+
setConnectorError(cause instanceof Error ? cause.message : String(cause));
|
|
1270
|
+
} finally {
|
|
1271
|
+
setConnectorLoading(false);
|
|
1272
|
+
}
|
|
1273
|
+
};
|
|
1274
|
+
(0, react.useEffect)(() => {
|
|
1275
|
+
let alive = true;
|
|
1276
|
+
setConnectorLoading(true);
|
|
1277
|
+
setConnectorError(null);
|
|
1278
|
+
fetchConnectorState().then((next) => {
|
|
1279
|
+
if (alive) setConnector(next);
|
|
1280
|
+
}).catch((cause) => {
|
|
1281
|
+
if (alive) setConnectorError(cause instanceof Error ? cause.message : String(cause));
|
|
1282
|
+
}).finally(() => {
|
|
1283
|
+
if (alive) setConnectorLoading(false);
|
|
1284
|
+
});
|
|
1285
|
+
return () => {
|
|
1286
|
+
alive = false;
|
|
1287
|
+
};
|
|
1288
|
+
}, []);
|
|
923
1289
|
const load = async (silent = false) => {
|
|
924
1290
|
if (!connectorEnabled) {
|
|
925
1291
|
setTasks([]);
|
|
@@ -938,11 +1304,43 @@ window.__ModuleLoader__.load({
|
|
|
938
1304
|
if (!silent) setLoading(false);
|
|
939
1305
|
}
|
|
940
1306
|
};
|
|
941
|
-
const
|
|
942
|
-
|
|
1307
|
+
const setConnectorEnabled = async (enabled) => {
|
|
1308
|
+
setConnectorBusy(true);
|
|
1309
|
+
setConnectorError(null);
|
|
943
1310
|
try {
|
|
944
|
-
|
|
945
|
-
|
|
1311
|
+
setConnector(await saveConnectorState({ enabled }));
|
|
1312
|
+
if (!enabled) {
|
|
1313
|
+
setTasks([]);
|
|
1314
|
+
setCapabilityFilter("all");
|
|
1315
|
+
}
|
|
1316
|
+
} catch (cause) {
|
|
1317
|
+
setConnectorError(cause instanceof Error ? cause.message : String(cause));
|
|
1318
|
+
} finally {
|
|
1319
|
+
setConnectorBusy(false);
|
|
1320
|
+
}
|
|
1321
|
+
};
|
|
1322
|
+
const toggleCapability = async (capabilityId, enabled) => {
|
|
1323
|
+
if (connector === null) return;
|
|
1324
|
+
setConnectorBusy(true);
|
|
1325
|
+
setConnectorError(null);
|
|
1326
|
+
try {
|
|
1327
|
+
setConnector(await saveConnectorState({
|
|
1328
|
+
enabled: connector.enabled,
|
|
1329
|
+
capabilities: { [capabilityId]: enabled }
|
|
1330
|
+
}));
|
|
1331
|
+
} catch (cause) {
|
|
1332
|
+
setConnectorError(cause instanceof Error ? cause.message : String(cause));
|
|
1333
|
+
} finally {
|
|
1334
|
+
setConnectorBusy(false);
|
|
1335
|
+
}
|
|
1336
|
+
};
|
|
1337
|
+
const openSkillCenterFromPanel = () => {
|
|
1338
|
+
if (openSkillCenter()) {
|
|
1339
|
+
setSkillCenterError(null);
|
|
1340
|
+
setOpen(false);
|
|
1341
|
+
return;
|
|
1342
|
+
}
|
|
1343
|
+
setSkillCenterError("技能中心未安装,无法打开连接器页面");
|
|
946
1344
|
};
|
|
947
1345
|
(0, react.useEffect)(() => {
|
|
948
1346
|
if (!open) return;
|
|
@@ -982,13 +1380,18 @@ window.__ModuleLoader__.load({
|
|
|
982
1380
|
window.clearInterval(timer);
|
|
983
1381
|
};
|
|
984
1382
|
}, [connectorEnabled]);
|
|
985
|
-
const filtered = (0, react.useMemo)(() =>
|
|
986
|
-
if (tab === "connectors") return
|
|
987
|
-
if (tab === "group") return task.sourceType === "task_bus" && task.source.type.includes("group");
|
|
988
|
-
if (tab === "mine") return task.status !== "completed" && task.status !== "cancelled";
|
|
989
|
-
if (tab === "personal") return task.sourceType === "task_bus" && !task.source.type.includes("group");
|
|
990
|
-
return
|
|
991
|
-
}
|
|
1383
|
+
const filtered = (0, react.useMemo)(() => {
|
|
1384
|
+
if (tab === "connectors") return connectorEnabled ? filterConnectorTasks(tasks, capabilityFilter) : [];
|
|
1385
|
+
if (tab === "group") return tasks.filter((task) => task.sourceType === "task_bus" && task.source.type.includes("group"));
|
|
1386
|
+
if (tab === "mine") return tasks.filter((task) => task.status !== "completed" && task.status !== "cancelled");
|
|
1387
|
+
if (tab === "personal") return tasks.filter((task) => task.sourceType === "task_bus" && !task.source.type.includes("group"));
|
|
1388
|
+
return tasks;
|
|
1389
|
+
}, [
|
|
1390
|
+
tasks,
|
|
1391
|
+
tab,
|
|
1392
|
+
connectorEnabled,
|
|
1393
|
+
capabilityFilter
|
|
1394
|
+
]);
|
|
992
1395
|
const actionable = tasks.filter((task) => task.status !== "completed" && task.status !== "cancelled").length;
|
|
993
1396
|
const tabItems = [
|
|
994
1397
|
{
|
|
@@ -1033,7 +1436,7 @@ window.__ModuleLoader__.load({
|
|
|
1033
1436
|
panelId: "task-bus-panel-connectors",
|
|
1034
1437
|
label: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["连接器 ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1035
1438
|
style: { opacity: .55 },
|
|
1036
|
-
children:
|
|
1439
|
+
children: connector === null ? 0 : 1
|
|
1037
1440
|
})] })
|
|
1038
1441
|
}
|
|
1039
1442
|
];
|
|
@@ -1322,19 +1725,59 @@ window.__ModuleLoader__.load({
|
|
|
1322
1725
|
task: selected,
|
|
1323
1726
|
onBack: () => setSelected(null)
|
|
1324
1727
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1325
|
-
tab === "connectors" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1728
|
+
tab === "connectors" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1326
1729
|
style: {
|
|
1327
1730
|
display: "grid",
|
|
1328
|
-
gridTemplateColumns: "repeat(auto-fill, minmax(
|
|
1731
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(320px, 1fr))",
|
|
1329
1732
|
gap: 10
|
|
1330
1733
|
},
|
|
1331
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1734
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConnectorCard, {
|
|
1735
|
+
state: connector,
|
|
1736
|
+
loading: connectorLoading,
|
|
1737
|
+
error: connectorError,
|
|
1738
|
+
busy: connectorBusy,
|
|
1739
|
+
taskCount: filtered.length,
|
|
1740
|
+
onSetEnabled: (enabled) => {
|
|
1741
|
+
setConnectorEnabled(enabled);
|
|
1742
|
+
},
|
|
1743
|
+
onToggleCapability: (capabilityId, enabled) => {
|
|
1744
|
+
toggleCapability(capabilityId, enabled);
|
|
1745
|
+
},
|
|
1746
|
+
onReload: () => {
|
|
1747
|
+
readConnector();
|
|
1748
|
+
}
|
|
1336
1749
|
})
|
|
1337
|
-
})
|
|
1750
|
+
}), connectorEnabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1751
|
+
role: "group",
|
|
1752
|
+
"aria-label": "连接器能力筛选",
|
|
1753
|
+
style: {
|
|
1754
|
+
display: "flex",
|
|
1755
|
+
flexWrap: "wrap",
|
|
1756
|
+
gap: 6
|
|
1757
|
+
},
|
|
1758
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1759
|
+
type: "button",
|
|
1760
|
+
"aria-pressed": capabilityFilter === "all",
|
|
1761
|
+
onClick: () => setCapabilityFilter("all"),
|
|
1762
|
+
style: filterChipStyle(capabilityFilter === "all"),
|
|
1763
|
+
children: "全部"
|
|
1764
|
+
}), visibleCapabilities(connector).map((capability) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1765
|
+
type: "button",
|
|
1766
|
+
"data-capability-filter": capability.id,
|
|
1767
|
+
"aria-pressed": capabilityFilter === capability.id,
|
|
1768
|
+
onClick: () => setCapabilityFilter(capability.id),
|
|
1769
|
+
style: filterChipStyle(capabilityFilter === capability.id),
|
|
1770
|
+
children: capability.label
|
|
1771
|
+
}, capability.id))]
|
|
1772
|
+
}) : connectorLoading ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConnectorDisabledState, { onOpenSkillCenter: openSkillCenterFromPanel }), skillCenterError === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1773
|
+
role: "alert",
|
|
1774
|
+
style: {
|
|
1775
|
+
textAlign: "center",
|
|
1776
|
+
color: colors.danger,
|
|
1777
|
+
fontSize: 11
|
|
1778
|
+
},
|
|
1779
|
+
children: skillCenterError
|
|
1780
|
+
})] })] }) : null,
|
|
1338
1781
|
loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1339
1782
|
style: {
|
|
1340
1783
|
padding: 18,
|
|
@@ -1344,14 +1787,23 @@ window.__ModuleLoader__.load({
|
|
|
1344
1787
|
},
|
|
1345
1788
|
children: "正在加载…"
|
|
1346
1789
|
}) : null,
|
|
1347
|
-
!loading && filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1790
|
+
!loading && tab !== "connectors" && filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1348
1791
|
style: {
|
|
1349
1792
|
padding: 18,
|
|
1350
1793
|
textAlign: "center",
|
|
1351
1794
|
color: colors.muted,
|
|
1352
1795
|
fontSize: 12
|
|
1353
1796
|
},
|
|
1354
|
-
children:
|
|
1797
|
+
children: "暂无任务"
|
|
1798
|
+
}) : null,
|
|
1799
|
+
!loading && tab === "connectors" && connectorEnabled && filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1800
|
+
style: {
|
|
1801
|
+
padding: 18,
|
|
1802
|
+
textAlign: "center",
|
|
1803
|
+
color: colors.muted,
|
|
1804
|
+
fontSize: 12
|
|
1805
|
+
},
|
|
1806
|
+
children: capabilityFilter === "all" ? "暂无来自该连接器的任务" : "该能力下暂无任务"
|
|
1355
1807
|
}) : null,
|
|
1356
1808
|
!loading && tab === "connectors" && filtered.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1357
1809
|
style: {
|
|
@@ -1834,7 +2286,18 @@ window.__ModuleLoader__.load({
|
|
|
1834
2286
|
document.removeEventListener("click", onFileClick, true);
|
|
1835
2287
|
};
|
|
1836
2288
|
}, "task-bus: native file card preview");
|
|
1837
|
-
const
|
|
2289
|
+
const openSkillCenter = () => {
|
|
2290
|
+
try {
|
|
2291
|
+
surface.layout.selectPanel("skill-center");
|
|
2292
|
+
return true;
|
|
2293
|
+
} catch {
|
|
2294
|
+
return false;
|
|
2295
|
+
}
|
|
2296
|
+
};
|
|
2297
|
+
const Surface = () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaskCenterButton, {
|
|
2298
|
+
openSession: (sessionId) => surface.uiWorkspace.openSession(sessionId),
|
|
2299
|
+
openSkillCenter
|
|
2300
|
+
});
|
|
1838
2301
|
ctx.effect(() => surface.slots.inject("shell.overlay", () => surface.slots.register({
|
|
1839
2302
|
name: "shell.overlay",
|
|
1840
2303
|
id: "task-bus.center"
|