@dsh-workbench/core 0.3.3 → 0.3.5
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/client.js +1749 -114
- package/cordis.patch.yml +32 -0
- package/dist/client/client.body.js +1749 -114
- package/dist/client/index.js +1749 -114
- package/dist/host/index.js +3101 -1156
- package/dist/types/app/client.d.ts +306 -60
- package/dist/types/app/layouts/approval-detail.d.ts +13 -0
- package/dist/types/app/layouts/sidebar/RecordFooterAction.d.ts +16 -0
- package/dist/types/app/layouts/sidebar/record-footer.d.ts +4 -0
- package/dist/types/modules/panels/client.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-components.d.ts +3 -0
- package/dist/types/modules/panels/model/diy-components.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-context.d.ts +4 -5
- package/dist/types/modules/panels/model/diy-observers.d.ts +2 -2
- package/dist/types/modules/panels/model/diy-page.d.ts +1 -1
- package/dist/types/modules/panels/model/diy-record-bar.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-record-capture.d.ts +27 -0
- package/dist/types/modules/panels/model/diy-record-capture.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-record-failure.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-record-routes.d.ts +2 -0
- package/dist/types/modules/panels/model/diy-record-routes.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-record-scripts.d.ts +6 -0
- package/dist/types/modules/panels/model/diy-record-text.d.ts +89 -0
- package/dist/types/modules/panels/model/diy-record-text.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-record-tools.d.ts +2 -0
- package/dist/types/modules/panels/model/diy-record.d.ts +76 -0
- package/dist/types/modules/panels/model/diy-record.test.d.ts +1 -0
- package/dist/types/modules/panels/model/handoff.d.ts +1 -0
- package/dist/types/modules/panels/unit.d.ts +10 -5
- package/dist/types/shared/api/context-chips.d.ts +20 -0
- package/dist/types/shared/api/host/diy-acts.d.ts +4 -0
- package/dist/types/shared/api/host/diy-components.d.ts +65 -0
- package/dist/types/shared/api/host/diy-debug-act.d.ts +24 -7
- package/dist/types/shared/api/host/diy-record-act.d.ts +19 -0
- package/dist/types/shared/api/host/diy-workshop.d.ts +1 -3
- package/dist/types/shared/api/host/mount-units.d.ts +4 -0
- package/dist/types/shared/api/host/preset-scope.d.ts +16 -0
- package/dist/types/shared/api/host/tool-scope.d.ts +6 -2
- package/dist/types/shared/api/host/workshop-root.d.ts +7 -0
- package/dist/types/shared/components/BlockerState.d.ts +12 -0
- package/dist/types/shared/components/PanelFoot.d.ts +9 -0
- package/dist/types/shared/components/Tip.d.ts +8 -0
- package/dist/types/shared/hooks/bundle-queries.d.ts +12 -0
- package/dist/types/shared/hooks/fact-transports.d.ts +4 -0
- package/dist/types/shared/hooks/panel-state-report.d.ts +12 -0
- package/dist/types/shared/hooks/use-api-resource.d.ts +22 -0
- package/dist/types/shared/hooks/use-blocker-actions.d.ts +8 -0
- package/dist/types/shared/hooks/use-capabilities.d.ts +55 -0
- package/dist/types/shared/hooks/use-capability-gate.d.ts +16 -0
- package/dist/types/shared/hooks/use-card-summary.d.ts +7 -0
- package/dist/types/shared/hooks/use-diy-debug.d.ts +13 -0
- package/dist/types/shared/hooks/use-diy-record.d.ts +21 -0
- package/dist/types/shared/hooks/use-facts.d.ts +10 -0
- package/dist/types/shared/hooks/use-host-write.d.ts +12 -0
- package/dist/types/shared/hooks/use-long-task.d.ts +8 -0
- package/dist/types/shared/hooks/use-unit-board.d.ts +17 -0
- package/dist/types/shared/hooks/use-visible-busy.d.ts +17 -0
- package/package.json +2 -2
- package/scripts/seed-workshop.sh +42 -2
- package/skills/workbench-module-diy/BUILD.md +4 -3
- package/skills/workbench-module-diy/DATASOURCE.md +2 -2
- package/skills/workbench-module-diy/DESIGN.md +26 -1
- package/skills/workbench-module-diy/FAMILY.md +56 -0
- package/skills/workbench-module-diy/KIT.md +111 -96
- package/skills/workbench-module-diy/PANEL.md +24 -13
- package/skills/workbench-module-diy/REVIEW.md +9 -8
- package/skills/workbench-module-diy/SKILL.md +16 -6
- package/skills/workbench-module-diy/TOOLING.md +5 -2
- package/skills/workbench-module-diy/TOOLS.md +7 -41
- package/skills/workbench-module-diy/WIRING.md +14 -6
- package/skills/workbench-module-diy/WRITES.md +47 -6
|
@@ -13,6 +13,11 @@ var __exportAll = (all, no_symbols) => {
|
|
|
13
13
|
//#endregion
|
|
14
14
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
15
15
|
//#region ../shared/dist/lib/ui.js
|
|
16
|
+
/**
|
|
17
|
+
* 拼类名:只留真值、用空格连接(`false` / `null` / `undefined` / 空串都丢掉)。
|
|
18
|
+
* @param parts - 若干类名或条件值。
|
|
19
|
+
* @returns 拼好的类字符串;一个真值都没有给空串。
|
|
20
|
+
*/
|
|
16
21
|
function cx(...parts) {
|
|
17
22
|
return parts.filter(Boolean).join(" ");
|
|
18
23
|
}
|
|
@@ -21,6 +26,12 @@ var HOUR = 60 * MINUTE;
|
|
|
21
26
|
var DAY = 24 * HOUR;
|
|
22
27
|
var MONTH = 30 * DAY;
|
|
23
28
|
var YEAR = 365 * DAY;
|
|
29
|
+
/**
|
|
30
|
+
* 把时间戳按 dsh 的分档切成「刚刚 / N 分钟 / N 小时 / N 天 / N 月 / N 年」—— 30 天进月、365 天进年。
|
|
31
|
+
* @param epochMs - 要换算的时间戳(毫秒)。
|
|
32
|
+
* @param now - 基准时间,默认 `Date.now()`。
|
|
33
|
+
* @returns 档位与数量;时间戳或基准不是有限数给 `null`,未来时间钳到「刚刚」(`now` / 0)。
|
|
34
|
+
*/
|
|
24
35
|
function relativeTimeBucket(epochMs, now = Date.now()) {
|
|
25
36
|
if (!Number.isFinite(epochMs) || !Number.isFinite(now)) return null;
|
|
26
37
|
const diff = Math.max(0, now - epochMs);
|
|
@@ -52,16 +63,36 @@ function relativeTimeBucket(epochMs, now = Date.now()) {
|
|
|
52
63
|
function bucketLabel(bucket, t) {
|
|
53
64
|
return bucket.unit === "now" ? t("time.now") : t(`time.short.${bucket.unit}`, { n: bucket.n });
|
|
54
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* 行内用的紧凑相对时间(「3 分钟」这种,不带「前」)。
|
|
68
|
+
* @param epochMs - 要换算的时间戳(毫秒)。
|
|
69
|
+
* @param t - 词表取词函数。
|
|
70
|
+
* @param now - 基准时间,默认 `Date.now()`。
|
|
71
|
+
* @returns 紧凑文案;时间戳非法给空串。
|
|
72
|
+
*/
|
|
55
73
|
function relativeTimeCompact(epochMs, t, now) {
|
|
56
74
|
const bucket = relativeTimeBucket(epochMs, now);
|
|
57
75
|
return bucket === null ? "" : bucketLabel(bucket, t);
|
|
58
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* 悬停卡里用的相对时间(「3 分钟前」);「刚刚」那一档不加「前」。
|
|
79
|
+
* @param epochMs - 要换算的时间戳(毫秒)。
|
|
80
|
+
* @param t - 词表取词函数。
|
|
81
|
+
* @param now - 基准时间,默认 `Date.now()`。
|
|
82
|
+
* @returns 带「前」的文案;时间戳非法给空串。
|
|
83
|
+
*/
|
|
59
84
|
function relativeTimeAgo(epochMs, t, now) {
|
|
60
85
|
const bucket = relativeTimeBucket(epochMs, now);
|
|
61
86
|
if (bucket === null) return "";
|
|
62
87
|
const label = bucketLabel(bucket, t);
|
|
63
88
|
return bucket.unit === "now" ? label : t("time.ago", { t: label });
|
|
64
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* 会话行那一版相对时间:一小时内按分钟、一天内按小时、七天内按天,再久直接给绝对时间(到秒)。
|
|
92
|
+
* @param epochMs - 要换算的时间戳(毫秒)。
|
|
93
|
+
* @param t - 词表取词函数。
|
|
94
|
+
* @returns 文案;时间戳不是有限数给空串,未来时间落「刚刚」,七天及以上给本地化的年月日时分秒。
|
|
95
|
+
*/
|
|
65
96
|
function relativeTime(epochMs, t) {
|
|
66
97
|
if (!Number.isFinite(epochMs)) return "";
|
|
67
98
|
const diff = Date.now() - epochMs;
|
|
@@ -78,12 +109,22 @@ function relativeTime(epochMs, t) {
|
|
|
78
109
|
second: "2-digit"
|
|
79
110
|
});
|
|
80
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* 把 `/Users/<用户名>/…` 缩成 `~/…`,免得会话行里全是一样的长前缀。
|
|
114
|
+
* @param path - 任意值。
|
|
115
|
+
* @returns 缩好的路径;不在用户主目录下原样返回,不是字符串给空串。
|
|
116
|
+
*/
|
|
81
117
|
function shortenPath(path) {
|
|
82
118
|
if (typeof path !== "string") return "";
|
|
83
119
|
const hit = path.match(/^\/Users\/[^/]+/);
|
|
84
120
|
return hit === null ? path : path.replace(hit[0], "~");
|
|
85
121
|
}
|
|
86
122
|
var LOCAL_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2}):(\d{2})$/;
|
|
123
|
+
/**
|
|
124
|
+
* 解析不带时区的本地时间戳(`YYYY-MM-DD HH:mm:ss`,也接受 `T` 分隔),按本机时区换算。
|
|
125
|
+
* @param text - 原文;`null` / `undefined` 当空串;首尾空白容忍。
|
|
126
|
+
* @returns 毫秒时间戳;形态不认识给 `NaN`(调用方据此回退到原始字符串,宁可不换算也不显示错时间)。
|
|
127
|
+
*/
|
|
87
128
|
function parseLocalTimestamp(text) {
|
|
88
129
|
const raw = String(text ?? "").trim();
|
|
89
130
|
if (!LOCAL_TIMESTAMP.test(raw)) return NaN;
|
|
@@ -104,6 +145,13 @@ function copyAction(t, text) {
|
|
|
104
145
|
text
|
|
105
146
|
};
|
|
106
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* 把一次读失败翻成一张卡住态,交给卡片直接渲染。
|
|
150
|
+
* @param error 读口回的错误;undefined 表示连错误都没拿到(多半是网络断,回「原因未知」)。
|
|
151
|
+
* @param t 文案函数,只取 blocker.* 命名空间的键。
|
|
152
|
+
* @param context 判定现场;platform 缺省时标题不带平台名。
|
|
153
|
+
* @returns 一定有一张卡,actions 至少一颗「重试」。
|
|
154
|
+
*/
|
|
107
155
|
function blockerOfError(error, t, context = {}) {
|
|
108
156
|
if (error === void 0) return {
|
|
109
157
|
id: "unknown",
|
|
@@ -173,6 +221,12 @@ function blockerOfError(error, t, context = {}) {
|
|
|
173
221
|
};
|
|
174
222
|
}
|
|
175
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* 把宿主回的环境读数翻成卡住态:探针没查过(unchecked)只算提示,不挡卡片。
|
|
226
|
+
* @param capability 宿主回的单元环境读数。
|
|
227
|
+
* @param t 文案函数,键都在 env.unit.* / blocker.* 下。
|
|
228
|
+
* @returns status 为 'ok' 时给 undefined(没有卡住态),其余状态一律给一张。
|
|
229
|
+
*/
|
|
176
230
|
function blockerOfCapability(capability, t) {
|
|
177
231
|
if (capability.status === "ok") return void 0;
|
|
178
232
|
const fixAction = capability.fix === void 0 ? void 0 : {
|
|
@@ -226,12 +280,25 @@ function blockerOfCapability(capability, t) {
|
|
|
226
280
|
}
|
|
227
281
|
//#endregion
|
|
228
282
|
//#region ../shared/dist/api/context-ref.js
|
|
283
|
+
/**
|
|
284
|
+
* 引用标记的固定名字;完整标记是 @<这个名字>:<编码文本>,改它等于作废历史会话里已写下的引用。
|
|
285
|
+
*/
|
|
229
286
|
var CONTEXT_MARKER_NAME = "工作台";
|
|
230
287
|
var MARKER = new RegExp(`@${CONTEXT_MARKER_NAME}:([a-z][a-z0-9-]*:[A-Za-z0-9._~%#/-]+)`, "g");
|
|
231
288
|
var TRAILING_PUNCTUATION = /[.,;:!?]+$/;
|
|
289
|
+
/**
|
|
290
|
+
* 把引用拼回标记体里的那一段文本(不含 @ 与标记名)。
|
|
291
|
+
* @param ref 要拼的引用。
|
|
292
|
+
* @returns 形如 kind:part/part;分段里的 / 不转义,所以分段名本身不能含 /。
|
|
293
|
+
*/
|
|
232
294
|
function encodeRef(ref) {
|
|
233
295
|
return `${ref.kind}:${ref.parts.join("/")}`;
|
|
234
296
|
}
|
|
297
|
+
/**
|
|
298
|
+
* 把 kind:part/part 文本读回引用。
|
|
299
|
+
* @param text 待解析文本。
|
|
300
|
+
* @returns 没冒号、冒号在首尾、种类不是小写字母开头、或冒号后为空时给 undefined;不抛异常。
|
|
301
|
+
*/
|
|
235
302
|
function decodeRef(text) {
|
|
236
303
|
const at = text.indexOf(":");
|
|
237
304
|
if (at <= 0 || at === text.length - 1) return void 0;
|
|
@@ -244,12 +311,27 @@ function decodeRef(text) {
|
|
|
244
311
|
parts
|
|
245
312
|
};
|
|
246
313
|
}
|
|
314
|
+
/**
|
|
315
|
+
* 拼出 @ 后面那半截(标记名加已编码文本),比较与拼接都用它。
|
|
316
|
+
* @param encoded encodeRef 的结果。
|
|
317
|
+
* @returns 形如 工作台:file:src/a.ts。
|
|
318
|
+
*/
|
|
247
319
|
function markerBody(encoded) {
|
|
248
320
|
return `${CONTEXT_MARKER_NAME}:${encoded}`;
|
|
249
321
|
}
|
|
322
|
+
/**
|
|
323
|
+
* 把一条引用拼成能写进对话文本的完整标记。
|
|
324
|
+
* @param ref 要标记的引用。
|
|
325
|
+
* @returns 形如 @工作台:file:src/a.ts 的一段文本。
|
|
326
|
+
*/
|
|
250
327
|
function buildMarker(ref) {
|
|
251
328
|
return `@${markerBody(encodeRef(ref))}`;
|
|
252
329
|
}
|
|
330
|
+
/**
|
|
331
|
+
* 从一段文本里按出现顺序捞出所有标记引用,同一个引用只留第一次。
|
|
332
|
+
* @param text 任意文本;null / undefined 当空串。
|
|
333
|
+
* @returns 解析不出来的标记会被丢掉,所以结果只含合法引用,可能为空数组。
|
|
334
|
+
*/
|
|
253
335
|
function parseMarkers(text) {
|
|
254
336
|
const seen = /* @__PURE__ */ new Set();
|
|
255
337
|
const refs = [];
|
|
@@ -263,15 +345,35 @@ function parseMarkers(text) {
|
|
|
263
345
|
}
|
|
264
346
|
return refs;
|
|
265
347
|
}
|
|
348
|
+
/**
|
|
349
|
+
* 由单元 id 拼出它那一族事实的范围名。
|
|
350
|
+
* @param unit 单元 id,不带后缀。
|
|
351
|
+
* @returns <unit>* —— 永远是范围名,不是某一条事实。
|
|
352
|
+
*/
|
|
266
353
|
function unitFactScope(unit) {
|
|
267
354
|
return `${unit}*`;
|
|
268
355
|
}
|
|
356
|
+
/**
|
|
357
|
+
* 判一个名字是不是范围查法,不是问这条事实存不存在。
|
|
358
|
+
* @param name 事实名或范围名。
|
|
359
|
+
* @returns 单字符 * 不算范围;只有「至少一个字符加 *」才算。
|
|
360
|
+
*/
|
|
269
361
|
function isFactScope(name) {
|
|
270
362
|
return name.length > 1 && name.endsWith("*");
|
|
271
363
|
}
|
|
364
|
+
/**
|
|
365
|
+
* 取范围名对应的前缀,普通事实名原样返回。
|
|
366
|
+
* @param name 事实名或范围名。
|
|
367
|
+
* @returns 去掉末尾 * 的前缀;本来不是范围就给原值。
|
|
368
|
+
*/
|
|
272
369
|
function scopePrefixOf(name) {
|
|
273
370
|
return isFactScope(name) ? name.slice(0, -1) : name;
|
|
274
371
|
}
|
|
372
|
+
/**
|
|
373
|
+
* 造一条事实通道:第一次订阅时才连传输层,最后一个订阅者走掉就断开。
|
|
374
|
+
* @param options 传输层,用来连宿主。
|
|
375
|
+
* @returns 通道句柄;没记录过的事实版本给 0,refresh() 不带事实名时刷新全部并逐个通知。
|
|
376
|
+
*/
|
|
275
377
|
function createFactChannel(options) {
|
|
276
378
|
const entries = /* @__PURE__ */ new Map();
|
|
277
379
|
let epoch = null;
|
|
@@ -371,6 +473,11 @@ function createFactChannel(options) {
|
|
|
371
473
|
};
|
|
372
474
|
return channel;
|
|
373
475
|
}
|
|
476
|
+
/**
|
|
477
|
+
* 把传输层收到的原始数据读成一帧;坏数据当没收到。
|
|
478
|
+
* @param data 帧的原始数据,期望是 JSON 字符串。
|
|
479
|
+
* @returns 合法帧;不是字符串、JSON 坏了、或 rev 不是数字都给 null。
|
|
480
|
+
*/
|
|
374
481
|
function parseFactFrame(data) {
|
|
375
482
|
if (typeof data !== "string") return null;
|
|
376
483
|
try {
|
|
@@ -385,15 +492,32 @@ function parseFactFrame(data) {
|
|
|
385
492
|
return null;
|
|
386
493
|
}
|
|
387
494
|
}
|
|
495
|
+
/**
|
|
496
|
+
* 读口路由到事实名的映射,当前一对一。
|
|
497
|
+
* @param route 读口路由。
|
|
498
|
+
* @returns 该路由对应的事实名(就是路由本身)。
|
|
499
|
+
*/
|
|
388
500
|
function factOfRoute(route) {
|
|
389
501
|
return route;
|
|
390
502
|
}
|
|
391
503
|
//#endregion
|
|
392
504
|
//#region ../shared/dist/api/host-write.js
|
|
505
|
+
/**
|
|
506
|
+
* 由通道与资源拼出写路由。
|
|
507
|
+
* @param channel 写通道。
|
|
508
|
+
* @param resource 该通道下的资源名。
|
|
509
|
+
* @returns 路由字符串;provision 只有一段,其余是 channel/resource。
|
|
510
|
+
*/
|
|
393
511
|
function writeRoute(channel, resource) {
|
|
394
512
|
if (channel === "provision") return "provision";
|
|
395
513
|
return `${channel}/${resource}`;
|
|
396
514
|
}
|
|
515
|
+
/**
|
|
516
|
+
* 把写通道的响应翻成 WriteOutcome。
|
|
517
|
+
* @param response 写口回的响应;null 表示请求本身没成(网络断了,宿主没答)。
|
|
518
|
+
* @param networkText 拿不到任何服务端文案时兜底的那句。
|
|
519
|
+
* @returns 失败时 message 优先用服务端自己的话,没有才用响应正文或 networkText。
|
|
520
|
+
*/
|
|
397
521
|
function writeOutcomeOf(response, networkText) {
|
|
398
522
|
if (response === null) return {
|
|
399
523
|
ok: false,
|
|
@@ -419,18 +543,45 @@ function writeOutcomeOf(response, networkText) {
|
|
|
419
543
|
}
|
|
420
544
|
//#endregion
|
|
421
545
|
//#region ../shared/dist/api/long-task.js
|
|
546
|
+
/**
|
|
547
|
+
* 单元的长任务读口路由。
|
|
548
|
+
* @param unit 单元 id。
|
|
549
|
+
* @returns <unit>/runs。
|
|
550
|
+
*/
|
|
422
551
|
function runsRouteOf(unit) {
|
|
423
552
|
return `${unit}/runs`;
|
|
424
553
|
}
|
|
554
|
+
/**
|
|
555
|
+
* 有长任务在跑时的轮询间隔(毫秒)。
|
|
556
|
+
*/
|
|
425
557
|
var LONG_TASK_POLL_MS = 1500;
|
|
558
|
+
/**
|
|
559
|
+
* 没有长任务时的轮询间隔(毫秒),比在跑那一档大一个量级。
|
|
560
|
+
*/
|
|
426
561
|
var LONG_TASK_IDLE_MS = 1e4;
|
|
562
|
+
/**
|
|
563
|
+
* 算这次该隔多久再问一次长任务。
|
|
564
|
+
* @param live 是否有在跑的长任务。
|
|
565
|
+
* @param override 调用点指定的间隔;给了就用它,不再看 live。
|
|
566
|
+
* @returns 毫秒:有活 1500,没活 10000。
|
|
567
|
+
*/
|
|
427
568
|
function longTaskPollMs(live, override) {
|
|
428
569
|
if (override !== void 0) return override;
|
|
429
570
|
return live ? LONG_TASK_POLL_MS : LONG_TASK_IDLE_MS;
|
|
430
571
|
}
|
|
572
|
+
/**
|
|
573
|
+
* 从读口状态里取 run 列表。
|
|
574
|
+
* @param state 读口状态;value 还没到就按空算。
|
|
575
|
+
* @returns 一串 run(形状由调用点自己判),没有就给空数组。
|
|
576
|
+
*/
|
|
431
577
|
function longTaskRunsOf(state) {
|
|
432
578
|
return state.value?.runs ?? [];
|
|
433
579
|
}
|
|
580
|
+
/**
|
|
581
|
+
* 把长任务态折成状态点的那一档。
|
|
582
|
+
* @param status 长任务的四种态。
|
|
583
|
+
* @returns ongoing / done / error / idle;needs-login 也算进行中。
|
|
584
|
+
*/
|
|
434
585
|
function longTaskDot(status) {
|
|
435
586
|
if (status === "ok") return "done";
|
|
436
587
|
if (status === "failed") return "error";
|
|
@@ -439,11 +590,22 @@ function longTaskDot(status) {
|
|
|
439
590
|
}
|
|
440
591
|
//#endregion
|
|
441
592
|
//#region ../shared/dist/api/unit-board.js
|
|
593
|
+
/**
|
|
594
|
+
* 判这张卡现在能不能画。
|
|
595
|
+
* @param capability 环境读数;还没读到给 null。
|
|
596
|
+
* @param mode 闸档。
|
|
597
|
+
* @returns mode 为 none 或读数还没到都放行(先放行让它读);读到明确不通过(ok 与 unchecked 之外)才拦。
|
|
598
|
+
*/
|
|
442
599
|
function gateOf(capability, mode) {
|
|
443
600
|
if (mode === "none") return { gated: true };
|
|
444
601
|
if (capability === null) return { gated: true };
|
|
445
602
|
return { gated: capability.status === "ok" || capability.status === "unchecked" };
|
|
446
603
|
}
|
|
604
|
+
/**
|
|
605
|
+
* 把候选卡住态分档,每档只留第一个。
|
|
606
|
+
* @param candidates 候选(可能含 undefined),按优先级从高到低给。
|
|
607
|
+
* @returns 分出的 blocker 与 notice;已经有 blocker 时不带 notice(挡住就不必再提示)。
|
|
608
|
+
*/
|
|
447
609
|
function splitBlocker(candidates) {
|
|
448
610
|
let blocker;
|
|
449
611
|
let notice;
|
|
@@ -460,11 +622,22 @@ function splitBlocker(candidates) {
|
|
|
460
622
|
...blocker !== void 0 || notice === void 0 ? {} : { notice }
|
|
461
623
|
};
|
|
462
624
|
}
|
|
625
|
+
/**
|
|
626
|
+
* 由读口错误算出「出错搭车强探」的防抖键:同一个键只自动重探一次。
|
|
627
|
+
* @param error 读口错误;undefined 表示这次没有错误。
|
|
628
|
+
* @returns 键字符串;空 code 归一到 unknown。
|
|
629
|
+
*/
|
|
463
630
|
function probeKeyOf(error) {
|
|
464
631
|
if (error === void 0) return null;
|
|
465
632
|
return error.code === "" ? "unknown" : error.code;
|
|
466
633
|
}
|
|
634
|
+
/**
|
|
635
|
+
* 外壳愿意认的协议版本;不在表里的模块当场被拒,不猜语义。
|
|
636
|
+
*/
|
|
467
637
|
var SUPPORTED_API_VERSIONS = [1];
|
|
638
|
+
/**
|
|
639
|
+
* 协议认得的全部键;写了别的键不会被采纳(外壳静默忽略),所以字段名拼错不会有提示。
|
|
640
|
+
*/
|
|
468
641
|
var DECLARATION_KEYS = [
|
|
469
642
|
"apiVersion",
|
|
470
643
|
"unit",
|
|
@@ -473,6 +646,9 @@ var DECLARATION_KEYS = [
|
|
|
473
646
|
"host",
|
|
474
647
|
"env"
|
|
475
648
|
];
|
|
649
|
+
/**
|
|
650
|
+
* 协议要求必写的键;env 不在其中(没有环境需要就不写)。
|
|
651
|
+
*/
|
|
476
652
|
var DECLARATION_REQUIRED_KEYS = [
|
|
477
653
|
"apiVersion",
|
|
478
654
|
"unit",
|
|
@@ -504,6 +680,12 @@ function stringArrayProblems(at, value) {
|
|
|
504
680
|
if (!Array.isArray(value)) return [`${at} 要是一串字符串,现在是 ${JSON.stringify(value)}`];
|
|
505
681
|
return value.flatMap((item, index) => text(item) === "" ? [`${at}[${index}] 不是非空字符串:${JSON.stringify(item)}`] : []);
|
|
506
682
|
}
|
|
683
|
+
/**
|
|
684
|
+
* 查清单里 dsh.workbench 那一段的形状,回一串给人看的问题(中文,带字段路径)。
|
|
685
|
+
* @param subject 报错时用的主语,一般是包名。
|
|
686
|
+
* @param raw 清单里那段原始值,可能什么都不是。
|
|
687
|
+
* @returns 空数组表示形状过得去;版本不对就当场返回(后面的字段无从判起)。
|
|
688
|
+
*/
|
|
507
689
|
function declarationProblemsOf(subject, raw) {
|
|
508
690
|
if (!isRecord(raw)) return [`${subject}: dsh.workbench 不是一个对象 —— ${JSON.stringify(raw)}`];
|
|
509
691
|
const version = raw.apiVersion;
|
|
@@ -565,6 +747,12 @@ function declarationProblemsOf(subject, raw) {
|
|
|
565
747
|
if (raw.env !== void 0 && !isRecord(raw.env)) problems.push(`${subject}: dsh.workbench.env 要是对象(command / plugins / libs)—— 语义由门禁的 env 判据查,这里只查形状`);
|
|
566
748
|
return problems;
|
|
567
749
|
}
|
|
750
|
+
/**
|
|
751
|
+
* 读一份清单:先查形状,过了再把声明规整成 manifest。
|
|
752
|
+
* @param subject 报错时用的主语。
|
|
753
|
+
* @param raw 清单里 dsh.workbench 那段原始值。
|
|
754
|
+
* @returns 有问题时只有 problems;没问题时 declaration 与 manifest 都给,manifest 里的字符串已 trim。
|
|
755
|
+
*/
|
|
568
756
|
function readDeclaration(subject, raw) {
|
|
569
757
|
const problems = declarationProblemsOf(subject, raw);
|
|
570
758
|
if (problems.length > 0) return { problems };
|
|
@@ -593,46 +781,99 @@ function readDeclaration(subject, raw) {
|
|
|
593
781
|
}
|
|
594
782
|
//#endregion
|
|
595
783
|
//#region ../shared/dist/api/unit.js
|
|
784
|
+
/**
|
|
785
|
+
* 判这个模块要不要往外装东西。
|
|
786
|
+
* @param manifest 模块清单。
|
|
787
|
+
* @returns 插件与共用库两张表都空时给 false。
|
|
788
|
+
*/
|
|
596
789
|
function hasEnvSupply(manifest) {
|
|
597
790
|
return (manifest.env?.plugins ?? []).length > 0 || (manifest.env?.libs ?? []).length > 0;
|
|
598
791
|
}
|
|
599
792
|
//#endregion
|
|
600
793
|
//#region ../shared/dist/config/constants.js
|
|
794
|
+
/** 外壳插件的包名:浏览器模块表与宿主按它注册、认领这枚插件。 */
|
|
601
795
|
var PLUGIN_ID = "@dsh-workbench/core";
|
|
796
|
+
/** 与外壳同批发布的兄弟包名:`release.ts` 用它判一版三包是否都已在源上。 */
|
|
602
797
|
var RELEASE_SIBLINGS = ["@dsh-workbench/shared", "@dsh-workbench/module-tools"];
|
|
798
|
+
/** 外壳宿主 HTTP API 的根前缀;prefs / actions / provision 等路由都挂在它下面。 */
|
|
603
799
|
var API_PREFIX = "/workbench/api";
|
|
800
|
+
/** 模块偏好读写的路由前缀,挂在外壳 API 下:走写通道,拒写回 write-refused。 */
|
|
604
801
|
var PREFS_PREFIX = `${API_PREFIX}/prefs`;
|
|
802
|
+
/** 事实(facts)SSE 事件流的端点路径;前端 `EventSource` 按它带 `since` 游标续传。 */
|
|
605
803
|
var EVENTS_PATH = "/workbench/events";
|
|
804
|
+
/** 写动作的路由前缀,挂在外壳 API 下:模块的写通道 POST 到这里。 */
|
|
606
805
|
var ACTIONS_PREFIX = `${API_PREFIX}/actions`;
|
|
806
|
+
/** 机器供给(provision)的路由前缀:只收 POST,装机时用它铺一份运行环境。 */
|
|
607
807
|
var PROVISION_PREFIX = `${API_PREFIX}/provision`;
|
|
808
|
+
/** 面板运行态上报的路径段:崩溃与卡片收尾分别 POST 到 `panel-state/crash`、`panel-state/cards`。 */
|
|
608
809
|
var PANEL_STATE_PATH = "panel-state";
|
|
810
|
+
/** DIY 调试动作的路径段;宿主按它登记 `/workbench/api/diy-debug` 前缀。 */
|
|
609
811
|
var DIY_DEBUG_PATH = "diy-debug";
|
|
812
|
+
/** 调试动作的子路径(`diy-debug/act`);仓内暂无调用点,动作现走 `DIY_DEBUG_SERVICE`。 */
|
|
610
813
|
var DIY_DEBUG_ACT_PATH = `${DIY_DEBUG_PATH}/act`;
|
|
814
|
+
/** DIY 录制交接的路径段;宿主按它登记 `/workbench/api/diy-record` 前缀。 */
|
|
815
|
+
var DIY_RECORD_PATH = "diy-record";
|
|
816
|
+
/** 录制动作的子路径(`diy-record/act`);仓内暂无调用点,录制现走 `DIY_RECORD_SERVICE`。 */
|
|
817
|
+
var DIY_RECORD_ACT_PATH = `${DIY_RECORD_PATH}/act`;
|
|
818
|
+
/** 面板运行态的路由前缀,挂在外壳 API 下:上报口用它,拒报回 report-refused。 */
|
|
611
819
|
var PANEL_STATE_PREFIX = `${API_PREFIX}/${PANEL_STATE_PATH}`;
|
|
820
|
+
/** 钉住的 opencli 插件版本:`opencli-runtime` 按它校验、取那一份。 */
|
|
612
821
|
var OPENCLI_PIN = "1.8.8";
|
|
822
|
+
/** 缺陷看板套件的 dsh 服务名(`workbenchCodingIssues`):套件照它登记自己那份服务。 */
|
|
613
823
|
var CODING_ISSUES_SERVICE = "workbenchCodingIssues";
|
|
824
|
+
/** 面板套件的 dsh 服务名(`workbenchPanels`):宿主经它取套件公布的清单与订阅。 */
|
|
614
825
|
var PANELS_SERVICE = "workbenchPanels";
|
|
826
|
+
/** 单元花名册服务的 dsh 服务名(`workbenchUnits`):模块经它认领自己的单元。 */
|
|
615
827
|
var UNITS_SERVICE = "workbenchUnits";
|
|
828
|
+
/** 面板运行态服务的 dsh 服务名(`workbenchPanelState`):宿主注册,读口按它取。 */
|
|
616
829
|
var PANEL_STATE_SERVICE = "workbenchPanelState";
|
|
830
|
+
/** DIY 调试约定服务的 dsh 服务名(`workbenchDiyDebug`):调试动作走它,不走 HTTP。 */
|
|
617
831
|
var DIY_DEBUG_SERVICE = "workbenchDiyDebug";
|
|
832
|
+
/** DIY 录制交接服务的 dsh 服务名(`workbenchDiyRecord`):`diy-acts.ts` 经它收发录制三拍。 */
|
|
833
|
+
var DIY_RECORD_SERVICE = "workbenchDiyRecord";
|
|
834
|
+
/** 会话投影服务的 dsh 服务名(`sessionProjections`):宿主经 `stateOf(session, 'agentPreset')` 读那一档。 */
|
|
835
|
+
var SESSION_PROJECTIONS_SERVICE = "sessionProjections";
|
|
836
|
+
/** 单次 opencli 调用的默认超时(毫秒);调用点没传 `timeoutMs` 时按它算。 */
|
|
618
837
|
var OPENCLI_TIMEOUT_MS = 12e4;
|
|
838
|
+
/** 启动预热站点那一跳的超时(毫秒);超时按未热对待,不挡面板。 */
|
|
619
839
|
var WARM_TIMEOUT_MS = 2e4;
|
|
840
|
+
/** 装 / 卸模块包的超时(毫秒):pnpm 与取包内容都按它算。 */
|
|
620
841
|
var INSTALL_TIMEOUT_MS = 3e5;
|
|
842
|
+
/** 查 registry 版本那一次请求的超时(毫秒)。 */
|
|
621
843
|
var VERSION_CHECK_TIMEOUT_MS = 1e4;
|
|
844
|
+
/** 版本查询结果的缓存有效期(毫秒):期内不发第二次请求。 */
|
|
622
845
|
var VERSION_CHECK_TTL_MS = 6e5;
|
|
846
|
+
/** 单元探测结果的缓存有效期(毫秒)。 */
|
|
623
847
|
var PROBE_TTL_MS = 3e4;
|
|
848
|
+
/** 工具读出来的值交给面板后的保留时长(毫秒):过期就不再算这一拍。 */
|
|
624
849
|
var HANDOFF_TTL_MS = 15e3;
|
|
850
|
+
/** 跑本地 git 命令的超时(毫秒);短于对外的 `OPENCLI_TIMEOUT_MS`。 */
|
|
625
851
|
var GIT_TIMEOUT_MS = 1e4;
|
|
852
|
+
/** 面板轮询事实的间隔(毫秒):SSE 断了走这条兜底轮询。 */
|
|
626
853
|
var PANEL_POLL_MS = 2e3;
|
|
854
|
+
/** 没起中文名的工作区默认标题:左栏按它分组、显示。 */
|
|
627
855
|
var DEFAULT_WORKSPACE_TITLE = "default-workspace";
|
|
856
|
+
/** 记住当前项目的 localStorage 键。 */
|
|
628
857
|
var STORAGE_KEY_PROJECT = "dsh-workbench.project";
|
|
858
|
+
/** 记住右栏展开与否的 localStorage 键。 */
|
|
629
859
|
var STORAGE_KEY_RIGHTBAR = "dsh-workbench.rightbar.expanded";
|
|
860
|
+
/** 记住右栏当前列的 localStorage 键。 */
|
|
630
861
|
var STORAGE_KEY_RIGHTBAR_COLUMN = "dsh-workbench.rightbar.column";
|
|
862
|
+
/** 记住右栏宽度(像素数字的字符串)的 localStorage 键。 */
|
|
631
863
|
var STORAGE_KEY_RIGHTBAR_WIDTH = "dsh-workbench.rightbar.width";
|
|
864
|
+
/** dsh i18n 的命名空间:词表都注册在它下面,`ctx.locale.register` / `bind` 按它取。 */
|
|
632
865
|
var LOCALE_NS = "workbench";
|
|
866
|
+
/** 外壳支持的语言标识,顺序即回退顺序:首项是基准,其余词表必须与它逐键同构。 */
|
|
633
867
|
var LOCALES = ["zh", "en"];
|
|
634
868
|
//#endregion
|
|
635
869
|
//#region ../shared/dist/api/workbench-client.js
|
|
870
|
+
/**
|
|
871
|
+
* 打一条宿主读口。
|
|
872
|
+
* @param route 路由,相对 API_PREFIX,不带前导斜杠。
|
|
873
|
+
* @param query 查询参数,undefined 的值不序列化。
|
|
874
|
+
* @param options 中止信号等。
|
|
875
|
+
* @returns HTTP 不是 2xx 时给 ok: false(code 为 http);响应体不是 JSON 会当场抛,调用点要接住。
|
|
876
|
+
*/
|
|
636
877
|
async function apiGet(route, query = {}, options = {}) {
|
|
637
878
|
const { signal } = options;
|
|
638
879
|
const search = new URLSearchParams();
|
|
@@ -652,6 +893,12 @@ async function apiGet(route, query = {}, options = {}) {
|
|
|
652
893
|
};
|
|
653
894
|
return await response.json();
|
|
654
895
|
}
|
|
896
|
+
/**
|
|
897
|
+
* 打一条宿主写口。
|
|
898
|
+
* @param route 路由,相对 API_PREFIX,不带前导斜杠。
|
|
899
|
+
* @param body 请求体,按 JSON 序列化。
|
|
900
|
+
* @returns HTTP 不是 2xx 时给 ok: false(code 为 http);响应体不是 JSON 会当场抛。
|
|
901
|
+
*/
|
|
655
902
|
async function apiPost(route, body) {
|
|
656
903
|
const response = await fetch(`${API_PREFIX}/${route}`, {
|
|
657
904
|
method: "POST",
|
|
@@ -673,26 +920,86 @@ async function apiPost(route, body) {
|
|
|
673
920
|
//#endregion
|
|
674
921
|
//#region ../shared/dist/lib/react.js
|
|
675
922
|
var react = require("react");
|
|
923
|
+
/**
|
|
924
|
+
* React 的 `createElement` 换个短名字再导出 —— 这套代码用 `h(...)` 写元素。
|
|
925
|
+
*/
|
|
676
926
|
var h = react.createElement;
|
|
927
|
+
/**
|
|
928
|
+
* React 的 `Fragment` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
929
|
+
*/
|
|
677
930
|
var Fragment = react.Fragment;
|
|
931
|
+
/**
|
|
932
|
+
* React 的 `Component` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
933
|
+
*/
|
|
678
934
|
var Component = react.Component;
|
|
935
|
+
/**
|
|
936
|
+
* React 的 `createContext` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
937
|
+
*/
|
|
679
938
|
var createContext = react.createContext;
|
|
939
|
+
/**
|
|
940
|
+
* React 的 `useContext` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
941
|
+
*/
|
|
680
942
|
var useContext = react.useContext;
|
|
943
|
+
/**
|
|
944
|
+
* React 的 `useState` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
945
|
+
*/
|
|
681
946
|
var useState = react.useState;
|
|
947
|
+
/**
|
|
948
|
+
* React 的 `useEffect` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
949
|
+
*/
|
|
682
950
|
var useEffect = react.useEffect;
|
|
951
|
+
/**
|
|
952
|
+
* React 的 `useLayoutEffect` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
953
|
+
*/
|
|
683
954
|
var useLayoutEffect = react.useLayoutEffect;
|
|
955
|
+
/**
|
|
956
|
+
* React 的 `useMemo` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
957
|
+
*/
|
|
684
958
|
var useMemo = react.useMemo;
|
|
959
|
+
/**
|
|
960
|
+
* React 的 `useCallback` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
961
|
+
*/
|
|
685
962
|
var useCallback = react.useCallback;
|
|
963
|
+
/**
|
|
964
|
+
* React 的 `useRef` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
965
|
+
*/
|
|
686
966
|
var useRef = react.useRef;
|
|
967
|
+
/**
|
|
968
|
+
* React 的 `useSyncExternalStore` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
969
|
+
*/
|
|
687
970
|
var useSyncExternalStore = react.useSyncExternalStore;
|
|
688
971
|
//#endregion
|
|
689
972
|
//#region ../shared/dist/components/Activity.js
|
|
973
|
+
/**
|
|
974
|
+
* "它做过什么"那一块:上面一行块头、下面一列活动行,卡里放时间线就用它。
|
|
975
|
+
* @param props.head - 块头(如"最近 10 次");不给不画那一行。
|
|
976
|
+
* @param props.children - 块内容,通常是一串 `ActivityLine`。
|
|
977
|
+
* @returns 一个 div。
|
|
978
|
+
*/
|
|
690
979
|
function ActivityBlock({ head, children }) {
|
|
691
980
|
return h("div", { className: "wb-activityBlock" }, head === void 0 ? null : h("div", { className: "wb-activityBlockHead" }, head), children);
|
|
692
981
|
}
|
|
982
|
+
/**
|
|
983
|
+
* 一条活动:状态点 + 正文 + 时间,行尾可挂动作;时间一律用它,别自己拼。
|
|
984
|
+
* @param props.dot - 行首那枚状态点;不给就只留正文。
|
|
985
|
+
* @param props.text - 这一条干了什么。
|
|
986
|
+
* @param props.at - 时间那一格(相对时间文本);不给不画。
|
|
987
|
+
* @param props.actions - 行尾动作,通常是一两颗 `ActivityAction`;不给不画。
|
|
988
|
+
* @returns 一行。
|
|
989
|
+
*/
|
|
693
990
|
function ActivityLine({ dot, text, at, actions }) {
|
|
694
991
|
return h("div", { className: "wb-activityLine" }, dot, h("span", { className: "wb-activityLineText" }, text), at === void 0 ? null : h("span", { className: "wb-activityLineAt" }, at), actions === void 0 ? null : h("span", { className: "wb-activityLineActions" }, actions));
|
|
695
992
|
}
|
|
993
|
+
/**
|
|
994
|
+
* 活动行尾那颗动作:给 `href` 就是外链,否则是图标钮并带上 tooltip。
|
|
995
|
+
* @param props.label - 读屏名,也是 `hint` 不给时的 tooltip 文案。
|
|
996
|
+
* @param props.hint - tooltip 上那句更细的说明;不给退化成 `label`。
|
|
997
|
+
* @param props.icon - 那颗图标。
|
|
998
|
+
* @param props.href - 给了就渲染成新窗口外链;与 `onClick` 同时给时以它为准。
|
|
999
|
+
* @param props.onClick - 图标钮的点击回调。
|
|
1000
|
+
* @param props.failed - 上一次动作失败了:钮换成危险色(默认 false)。
|
|
1001
|
+
* @returns 一个 `<a>` 或一颗 `Button`。
|
|
1002
|
+
*/
|
|
696
1003
|
function ActivityAction({ label, hint, icon, href, onClick, failed }) {
|
|
697
1004
|
const tip = hint ?? label;
|
|
698
1005
|
if (href !== void 0) return h("a", {
|
|
@@ -721,6 +1028,14 @@ function ActivityAction({ label, hint, icon, href, onClick, failed }) {
|
|
|
721
1028
|
}
|
|
722
1029
|
//#endregion
|
|
723
1030
|
//#region ../shared/dist/components/Note.js
|
|
1031
|
+
/**
|
|
1032
|
+
* 一句话说明或一句报错:卡片里的提示条用它,不承载交互。
|
|
1033
|
+
* @param props.tone - `problem` 是报错色;默认 `muted`,普通说明色。
|
|
1034
|
+
* @param props.as - `span` 是跟在别的行里,`p`(默认)独占一段。
|
|
1035
|
+
* @param props.role - 读屏角色:变化中的提示给 `status`、报错给 `alert`;不给不设。
|
|
1036
|
+
* @param props.children - 那句话本身。
|
|
1037
|
+
* @returns 一个 `span` 或 `p`。
|
|
1038
|
+
*/
|
|
724
1039
|
function Note({ tone = "muted", as, role, children }) {
|
|
725
1040
|
const className = tone === "problem" ? "wb-problem" : "wb-note";
|
|
726
1041
|
return as === "span" ? h("span", {
|
|
@@ -733,10 +1048,24 @@ function Note({ tone = "muted", as, role, children }) {
|
|
|
733
1048
|
}
|
|
734
1049
|
//#endregion
|
|
735
1050
|
//#region ../shared/dist/components/CardBoundary.js
|
|
1051
|
+
/**
|
|
1052
|
+
* 把抛出来的任何东西收成一句人能看的失败原因,上报与展示都用它。
|
|
1053
|
+
* @param error - 抛出来的值:`Error` 取 `message`,字符串原样,其余走 JSON。
|
|
1054
|
+
* @returns 一句原因文本;`Error('')` 这种没带 message 的会回空串(调用点别把它当"一定有话")。
|
|
1055
|
+
*/
|
|
736
1056
|
function errorReasonOf(error) {
|
|
737
1057
|
if (error instanceof Error) return error.message;
|
|
738
1058
|
return typeof error === "string" ? error : JSON.stringify(error) ?? String(error);
|
|
739
1059
|
}
|
|
1060
|
+
/**
|
|
1061
|
+
* 卡片级错误边界:一张卡渲染炸了只画一条报错 + 重试,不让整块面板跟着塌。
|
|
1062
|
+
* @param props.unit - 出事的 unit id,写进报错文案并作为上报标识。
|
|
1063
|
+
* @param props.resetKey - 重来键:它一变(如切了工作区)就自动清掉报错,把卡片重新渲染一遍。
|
|
1064
|
+
* @param props.t - 报错那句与重试钮文案的翻译函数。
|
|
1065
|
+
* @param props.onFailure - 失败时把原因报给宿主(面板状态要用);不给就只打一条 console。
|
|
1066
|
+
* @param props.children - 正常时要渲染的卡片内容。
|
|
1067
|
+
* @returns 正常时是 `children`,炸过且还没重来之前是一条报错。
|
|
1068
|
+
*/
|
|
740
1069
|
var CardBoundary = class extends Component {
|
|
741
1070
|
state = { reason: null };
|
|
742
1071
|
static getDerivedStateFromError(error) {
|
|
@@ -788,6 +1117,15 @@ function parseArgs(raw) {
|
|
|
788
1117
|
return {};
|
|
789
1118
|
}
|
|
790
1119
|
}
|
|
1120
|
+
/**
|
|
1121
|
+
* 审批屏的详情格:按工具名找到认领它的模块交给它渲染,没有模块认领就退回外壳那张表或一段原始命令。
|
|
1122
|
+
* @param props.callId - 这次工具调用的 id;不给就直接走兜底(连调用都找不到)。
|
|
1123
|
+
* @param props.useChat - 读会话快照的钩子(dsh 注入);不给就当作读不到调用。
|
|
1124
|
+
* @param props.units - 已装模块的面,按各自的 `approval.tools` 认领这次调用。
|
|
1125
|
+
* @param props.t - 翻译函数;不给就用返回 key 的直通实现。
|
|
1126
|
+
* @param props.renderShell - 没有模块认领时外壳自己的渲染(那张表);不给且这次调用没带 `command` 时整格返回 `null`。
|
|
1127
|
+
* @returns 认领方的渲染、外壳那张表,或一段可复制的命令。
|
|
1128
|
+
*/
|
|
791
1129
|
function ApprovalDetail(props) {
|
|
792
1130
|
const call = (props.useChat ?? (() => void 0))((snapshot) => callOf(snapshot, props.callId));
|
|
793
1131
|
const t = props.t ?? ((key) => key);
|
|
@@ -809,6 +1147,8 @@ function ApprovalDetail(props) {
|
|
|
809
1147
|
t
|
|
810
1148
|
}));
|
|
811
1149
|
}
|
|
1150
|
+
const shell = props.renderShell?.(input, t);
|
|
1151
|
+
if (shell !== void 0 && shell !== null) return h(Fragment, null, shell);
|
|
812
1152
|
if (command === "") return null;
|
|
813
1153
|
return h(_deepseek_ai_dsh_client_ui_primitives.CodeBlock, {
|
|
814
1154
|
code: command,
|
|
@@ -819,6 +1159,14 @@ function ApprovalDetail(props) {
|
|
|
819
1159
|
}
|
|
820
1160
|
//#endregion
|
|
821
1161
|
//#region ../shared/dist/components/ApprovalPlan.js
|
|
1162
|
+
/**
|
|
1163
|
+
* 审批屏那张"这次要做什么"的表:一行一项,上面可给一句附注、下面可给一句警告。
|
|
1164
|
+
* @param props.rows - 详情行,按给的顺序渲染;空数组时只剩附注与警告。
|
|
1165
|
+
* @param props.hint - 表上面那句说明;不给不画。
|
|
1166
|
+
* @param props.warn - 表下面那句警告;不给不画。
|
|
1167
|
+
* @param props.children - 插在表与 `warn` 之间的补充内容。
|
|
1168
|
+
* @returns 一个 div。
|
|
1169
|
+
*/
|
|
822
1170
|
function ApprovalPlan({ rows, hint, warn, children }) {
|
|
823
1171
|
return h("div", { className: "wb-approvalPlan" }, hint === void 0 ? null : h("p", { className: "wb-approvalHint" }, hint), h("dl", { className: "wb-approvalRows" }, rows.map((row, index) => h("div", {
|
|
824
1172
|
className: "wb-approvalRow",
|
|
@@ -827,6 +1175,16 @@ function ApprovalPlan({ rows, hint, warn, children }) {
|
|
|
827
1175
|
}
|
|
828
1176
|
//#endregion
|
|
829
1177
|
//#region ../shared/dist/components/CardHead.js
|
|
1178
|
+
/**
|
|
1179
|
+
* 卡头:标题 + 补充 + 刷新钮(`Card` 内部就是它),要自己拼卡头或加齿轮 / 平台跳转时直接用。
|
|
1180
|
+
* @param props.t - 刷新那两句文案(刷新 / 刷新中)的翻译函数。
|
|
1181
|
+
* @param props.title - 卡标题;`props.meta` 是它右侧那一小段补充,不给不占位。
|
|
1182
|
+
* @param props.refreshing - 正在刷新:刷新钮禁用并转圈。
|
|
1183
|
+
* @param props.onRefresh - 点刷新钮做什么。
|
|
1184
|
+
* @param props.gear - 齿轮钮的读屏名;`gearOpen` 控制它高亮、`onToggleGear` 是点击回调,三者一起给才画。
|
|
1185
|
+
* @param props.platformHref - 整张卡对应系统的地址:给了就画那颗 ↗(新窗口),tooltip 用 `platformTitle`,缺了退化用 `platform`。
|
|
1186
|
+
* @returns 一个 `<header>`。
|
|
1187
|
+
*/
|
|
830
1188
|
function CardHead({ t, title, meta, refreshing, onRefresh, gear, gearOpen, onToggleGear, platformHref, platform, platformTitle }) {
|
|
831
1189
|
const refreshLabel = refreshing ? t("rightbar.refreshing") : t("rightbar.refresh");
|
|
832
1190
|
const platformLabel = platformTitle ?? platform ?? t("rightbar.openPlatform");
|
|
@@ -876,6 +1234,16 @@ function CardHead({ t, title, meta, refreshing, onRefresh, gear, gearOpen, onTog
|
|
|
876
1234
|
}
|
|
877
1235
|
//#endregion
|
|
878
1236
|
//#region ../shared/dist/components/Card.js
|
|
1237
|
+
/**
|
|
1238
|
+
* 一张卡的壳:卡头(标题 + 刷新钮)+ 卡片体,面板上每一格都是它。
|
|
1239
|
+
* @param props.t - 卡头那两句文案(刷新 / 刷新中)的翻译函数。
|
|
1240
|
+
* @param props.refreshing - 正在刷新:刷新钮随之禁用并转圈;接 `resource.phase === 'loading'`。
|
|
1241
|
+
* @param props.onRefresh - 点刷新钮做什么,异步由调用点自己管。
|
|
1242
|
+
* @param props.meta - 标题右侧那一小段补充(条数、时间);不给不占位。
|
|
1243
|
+
* @param props.head - 整块替换卡头时给(如自带齿轮的 `CardHead`);不给用默认卡头。
|
|
1244
|
+
* @param props.children - 卡片体。
|
|
1245
|
+
* @returns 一个 `<section>`。
|
|
1246
|
+
*/
|
|
879
1247
|
function Card({ t, title, refreshing, onRefresh, meta, head, children }) {
|
|
880
1248
|
return h("section", { className: "wb-card" }, head === void 0 ? h(CardHead, {
|
|
881
1249
|
t,
|
|
@@ -888,9 +1256,20 @@ function Card({ t, title, refreshing, onRefresh, meta, head, children }) {
|
|
|
888
1256
|
var CardAnchor_module_default = { anchor: "_anchor_yq4s2_1" };
|
|
889
1257
|
//#endregion
|
|
890
1258
|
//#region ../shared/dist/components/CardAnchor.js
|
|
1259
|
+
/**
|
|
1260
|
+
* 由 unit id 拼出卡片锚点 id,外壳的截图、滚动与页面探针都按它找卡。
|
|
1261
|
+
* @param unit - unit id;`null` 或空串(没有 unit 的卡)时返回 undefined,不生成锚点。
|
|
1262
|
+
* @returns `wb-card-<unit>`,或 undefined。
|
|
1263
|
+
*/
|
|
891
1264
|
function cardIdOf(unit) {
|
|
892
1265
|
return unit === null || unit === "" ? void 0 : `wb-card-${unit}`;
|
|
893
1266
|
}
|
|
1267
|
+
/**
|
|
1268
|
+
* 外壳自己盖的卡片锚点:套在卡外面给出 `id="wb-card-<unit>"`;模块别自己写,也别删。
|
|
1269
|
+
* @param props.unit - 卡的 unit id,用来算锚点 id。
|
|
1270
|
+
* @param props.children - 被锚住的卡片本体;锚点自己 `display: contents`,不占布局。
|
|
1271
|
+
* @returns 带 id 的占位 div。
|
|
1272
|
+
*/
|
|
894
1273
|
function CardAnchor({ unit, children }) {
|
|
895
1274
|
return h("div", {
|
|
896
1275
|
id: cardIdOf(unit),
|
|
@@ -899,6 +1278,12 @@ function CardAnchor({ unit, children }) {
|
|
|
899
1278
|
}
|
|
900
1279
|
//#endregion
|
|
901
1280
|
//#region ../shared/dist/components/Spinner.js
|
|
1281
|
+
/**
|
|
1282
|
+
* 转圈:加载态一律用它(`FormActions` 与 `ChoiceGroup` 内部也是它),别自己写动画。
|
|
1283
|
+
* @param props.size - 直径像素(默认 14,与 dsh 紧凑控件同高)。
|
|
1284
|
+
* @param props.label - 给了才读屏可见(`role="status"`);不给整颗 `aria-hidden`,此时旁边必须有文字。
|
|
1285
|
+
* @returns 一枚 `StateDot state="ongoing"`,自身不带文字。
|
|
1286
|
+
*/
|
|
902
1287
|
function Spinner({ size = 14, label }) {
|
|
903
1288
|
return h("span", {
|
|
904
1289
|
className: "wb-spinner",
|
|
@@ -939,6 +1324,18 @@ function ChoiceMenu(input) {
|
|
|
939
1324
|
"aria-busy": input.loading ? true : void 0
|
|
940
1325
|
}, body);
|
|
941
1326
|
}
|
|
1327
|
+
/**
|
|
1328
|
+
* 一组单选或多选:候选少、要一眼看全时用它;候选多或要搜索就用 `SelectField`。
|
|
1329
|
+
* @param props.multi - true 走多选那支(`values` / `onChange(string[])`);默认单选(`value` / `onChange(string)`)。
|
|
1330
|
+
* @param props.label - 只给读屏的组名(`aria-label`)。
|
|
1331
|
+
* @param props.name - 这一组 `input` 的共用 name。
|
|
1332
|
+
* @param props.options - 候选项,按给的顺序排;空数组时画 `emptyText`(没给就什么都不画)。
|
|
1333
|
+
* @param props.disabled - 禁掉整组(默认 false),不是单颗。
|
|
1334
|
+
* @param props.variant - `boxed`(默认,带边框的选项格)或 `ghost`(无边框,跟着父容器走)。
|
|
1335
|
+
* @param props.loading - 正在读候选:整组换成转圈,文案取 `loadingText`(不给是 `…`);默认 false。
|
|
1336
|
+
* @param props.emptyText - 读到了但一个候选都没有时那句话;不给不画。
|
|
1337
|
+
* @returns 一组 `radio` / `checkbox` 选项。
|
|
1338
|
+
*/
|
|
942
1339
|
function ChoiceGroup(props) {
|
|
943
1340
|
const common = {
|
|
944
1341
|
label: props.label,
|
|
@@ -993,6 +1390,13 @@ function ChoiceGroup(props) {
|
|
|
993
1390
|
}
|
|
994
1391
|
//#endregion
|
|
995
1392
|
//#region ../shared/dist/components/Field.js
|
|
1393
|
+
/**
|
|
1394
|
+
* 标签 + 控件的排布:没进 `FormRow` 时用它兜住一个字段的标签与说明。
|
|
1395
|
+
* @param props.label - 左侧标签,必给。
|
|
1396
|
+
* @param props.hint - 控件下面那行说明;不给不画。
|
|
1397
|
+
* @param props.children - 控件本体,落在标签与说明之间。
|
|
1398
|
+
* @returns 一个 `<label>`,点标签会聚焦里面的控件。
|
|
1399
|
+
*/
|
|
996
1400
|
function Field({ label, hint, children }) {
|
|
997
1401
|
return h("label", { className: "wb-field" }, h("span", { className: "wb-fieldLabel" }, label), children, hint === void 0 ? null : h("span", { className: "wb-fieldHint" }, hint));
|
|
998
1402
|
}
|
|
@@ -1023,6 +1427,11 @@ function variantOf(kind) {
|
|
|
1023
1427
|
if (kind === "danger") return "outline";
|
|
1024
1428
|
return "ghost";
|
|
1025
1429
|
}
|
|
1430
|
+
/**
|
|
1431
|
+
* 操作区:把一组动作按"primary 永远在右、danger 紧挨它左侧"排好,窄了自动折行。
|
|
1432
|
+
* @param props.actions - 动作清单;调用点给的顺序只在同语气内部生效,空数组时整块不渲染。
|
|
1433
|
+
* @returns 一排按钮,或 `null`(没有动作时)。
|
|
1434
|
+
*/
|
|
1026
1435
|
function FormActions({ actions }) {
|
|
1027
1436
|
if (actions.length === 0) return null;
|
|
1028
1437
|
reportExtraPrimaries(actions);
|
|
@@ -1043,9 +1452,23 @@ function FormActions({ actions }) {
|
|
|
1043
1452
|
}
|
|
1044
1453
|
//#endregion
|
|
1045
1454
|
//#region ../shared/dist/components/FormRows.js
|
|
1455
|
+
/**
|
|
1456
|
+
* 表单行的容器:同一份 `FormRows` 共用一个标签列(列宽由最长的标签定),行距也归它。
|
|
1457
|
+
* @param props.children - 一串 `FormRow`;非行的孩子(如分组标题)自动通栏。
|
|
1458
|
+
* @returns 竖排的 div。
|
|
1459
|
+
*/
|
|
1046
1460
|
function FormRows({ children }) {
|
|
1047
1461
|
return h("div", { className: "wb-formRows" }, children);
|
|
1048
1462
|
}
|
|
1463
|
+
/**
|
|
1464
|
+
* 表单一行:左边标签、右边控件,提示与错误占控件下面那一格。
|
|
1465
|
+
* @param props.label - 这一行的标签;进了这一行,控件自己就别再给 `label`,否则会多一个标签。
|
|
1466
|
+
* @param props.hint - 控件下的说明;给了 `problem` 就不画它 —— 同一格不叠两段话。
|
|
1467
|
+
* @param props.problem - 校验失败那句话;给了就顶掉 `hint` 并给整行加上出错标记。
|
|
1468
|
+
* @param props.layout - `stacked` 才是标签在上、控件在下(默认 `inline`:标签在左)。
|
|
1469
|
+
* @param props.children - 控件本体。
|
|
1470
|
+
* @returns 一个 `<label>`。
|
|
1471
|
+
*/
|
|
1049
1472
|
function FormRow({ label, hint, problem, layout = "inline", children }) {
|
|
1050
1473
|
return h("label", {
|
|
1051
1474
|
className: "wb-formRow",
|
|
@@ -1054,7 +1477,269 @@ function FormRow({ label, hint, problem, layout = "inline", children }) {
|
|
|
1054
1477
|
}, h("span", { className: "wb-formLabel" }, label), h("span", { className: "wb-formControl" }, children), problem === void 0 ? hint === void 0 ? null : h("span", { className: "wb-formHint" }, hint) : h("span", { className: "wb-formProblem" }, problem));
|
|
1055
1478
|
}
|
|
1056
1479
|
//#endregion
|
|
1480
|
+
//#region ../shared/dist/components/FormNodes.js
|
|
1481
|
+
/**
|
|
1482
|
+
* 只剩要显示的那些格子 —— `visible: false` 的当它不存在:不渲染、不校验、不进 `values`,也不参与找第一处错误。
|
|
1483
|
+
* @param fields - 表单的字段清单。
|
|
1484
|
+
* @returns 保序的新数组,`visible` 不给或为 `true` 的都在;全不可见时给空数组。
|
|
1485
|
+
*/
|
|
1486
|
+
function visibleFieldsOf(fields) {
|
|
1487
|
+
return fields.filter((field) => field.visible !== false);
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* 找出装配错的键:**假值**的键(空串 / `undefined` / `null`,运行期真漏给 `key` 就是这条)每次出现都算一处,
|
|
1491
|
+
* 以及同一张表单里出现两次的键 —— 这两样都会让 `id` 撞车、`values` 少一格。
|
|
1492
|
+
* @param fields - 表单的字段清单(通常是已经过滤过可见性的那份)。
|
|
1493
|
+
* @returns 出问题的键的清单、按首次出现顺序去重;缺失的键一律记成空串(报的时候印成 `(空 key)`),空表给空数组。
|
|
1494
|
+
*/
|
|
1495
|
+
function duplicateKeysOf(fields) {
|
|
1496
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1497
|
+
const duplicated = /* @__PURE__ */ new Set();
|
|
1498
|
+
for (const field of fields) {
|
|
1499
|
+
const key = field.key;
|
|
1500
|
+
if (!key) {
|
|
1501
|
+
duplicated.add("");
|
|
1502
|
+
continue;
|
|
1503
|
+
}
|
|
1504
|
+
if (seen.has(key)) duplicated.add(key);
|
|
1505
|
+
seen.add(key);
|
|
1506
|
+
}
|
|
1507
|
+
return [...duplicated];
|
|
1508
|
+
}
|
|
1509
|
+
/**
|
|
1510
|
+
* 装配错了要当场诊断:`key` 缺失或重复时给 `console.error` —— 但照渲不误,不 throw。
|
|
1511
|
+
* 形式与理由同 `FormActions` 里那颗多出来的 `primary`:装配的小错不该让 `CardBoundary` 把用户的整张卡变空白。
|
|
1512
|
+
* @param fields - 表单的字段清单(通常是已经过滤过可见性的那份)。
|
|
1513
|
+
*/
|
|
1514
|
+
function reportDuplicateKeys(fields) {
|
|
1515
|
+
const duplicated = duplicateKeysOf(fields);
|
|
1516
|
+
if (duplicated.length === 0) return;
|
|
1517
|
+
const named = duplicated.map((key) => key === "" ? "(空 key)" : key);
|
|
1518
|
+
console.error(`[dsh-workbench] Form 里有重复或缺失的字段 key:${named.join("、")} —— 同一张表单里 key 必须唯一且非空(它决定 id 与 values 的键),否则 id 会撞车、values 会少一格`);
|
|
1519
|
+
}
|
|
1520
|
+
/**
|
|
1521
|
+
* 把每格的 `value` 收成一张键值表交给 `onSubmit` —— `Form` 自己一个值都不存,这张表就是从 `fields` 现取的快照。
|
|
1522
|
+
* @param fields - 表单的字段清单;取的就是它们的 `value`,`value` 是数组的那格(多选)原样带出、不复制。
|
|
1523
|
+
* @returns 键为字段 `key`、值为该格 `value` 的表;`fields` 为空时给空表,不是 `undefined`。
|
|
1524
|
+
*/
|
|
1525
|
+
function formValuesOf(fields) {
|
|
1526
|
+
const values = {};
|
|
1527
|
+
for (const field of fields) values[field.key] = field.value;
|
|
1528
|
+
return values;
|
|
1529
|
+
}
|
|
1530
|
+
/**
|
|
1531
|
+
* 算每格现在该不该报错:还没提交过(`show` 为 false)时一格都不报 —— 不边打字边骂人。
|
|
1532
|
+
* `validate` 返回**真值**才算错,假值(`undefined` / `null` / `false` / 空串)一律当"这格没错" ——
|
|
1533
|
+
* 所以 `v.trim() === '' && '必填'` 这种用 `&&` 算文案的写法是对的。
|
|
1534
|
+
* @param fields - 表单的字段清单(通常是已经过滤过可见性的那份)。
|
|
1535
|
+
* @param show - 提交过没有;false 时全给 `undefined`,true 时逐格调 `field.validate` 并按真值收。
|
|
1536
|
+
* @returns 键为 `key`、值为那句文案或 `undefined` 的表;没给 `validate` 的格子也是 `undefined`。
|
|
1537
|
+
*/
|
|
1538
|
+
function formProblemsOf(fields, show) {
|
|
1539
|
+
const values = formValuesOf(fields);
|
|
1540
|
+
const problems = {};
|
|
1541
|
+
for (const field of fields) {
|
|
1542
|
+
const found = show ? field.validate?.(field.value, values) : void 0;
|
|
1543
|
+
problems[field.key] = found ? found : void 0;
|
|
1544
|
+
}
|
|
1545
|
+
return problems;
|
|
1546
|
+
}
|
|
1547
|
+
/**
|
|
1548
|
+
* 按字段顺序取第一处错误 —— 提交被挡住时要带进视口的就是这一格。
|
|
1549
|
+
* 判的是**真值**(与 `formProblemsOf` 同一口径):假值那种"错误文案"渲染出来本来就是空的,不算错。
|
|
1550
|
+
* @param fields - 表单的字段清单,顺序就是「第一处」的判据。
|
|
1551
|
+
* @param problems - `formProblemsOf` 那张表,也可以是调用点自己拼的(同样按真值判)。
|
|
1552
|
+
* @returns 第一格有错的字段;一格都没错时给 `undefined`。
|
|
1553
|
+
*/
|
|
1554
|
+
function formFirstProblemOf(fields, problems) {
|
|
1555
|
+
return fields.find((field) => Boolean(problems[field.key]));
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* 算提交那一拍该干什么 —— `Form` 的提交钮点下去、以及 `<form>` 的 Enter 提交,走的都是它。
|
|
1559
|
+
* 错的判据只有一份(`formProblemsOf` + `formFirstProblemOf`),这里不重算第二遍。
|
|
1560
|
+
* @param fields - 要提交的那些格子(通常是调用点先 `visibleFieldsOf` 过滤过的,不可见那格不进 `values` 也不算错)。
|
|
1561
|
+
* @returns `blocked: true` 时带上是按字段顺序数第一格有错的字段(拿它去 `revealFirstProblem`);
|
|
1562
|
+
* `blocked: false` 时带上从 `fields` 现取的键值表。空表一定给 `blocked: false` 与空 values。
|
|
1563
|
+
*/
|
|
1564
|
+
function formSubmitOf(fields) {
|
|
1565
|
+
const first = formFirstProblemOf(fields, formProblemsOf(fields, true));
|
|
1566
|
+
if (first !== void 0) return {
|
|
1567
|
+
blocked: true,
|
|
1568
|
+
first
|
|
1569
|
+
};
|
|
1570
|
+
return {
|
|
1571
|
+
blocked: false,
|
|
1572
|
+
values: formValuesOf(fields)
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1575
|
+
/**
|
|
1576
|
+
* 组表单的操作区:调用点给的其余动作在最左,取消在中间,提交永远是最右那颗 `primary`。
|
|
1577
|
+
* @param args.extra - 其余动作(default / danger),保持调用点给的顺序;不给就是没有。
|
|
1578
|
+
* @param args.cancel - 取消那格的 `label` 与 `onClick`;不给就少一颗钮。
|
|
1579
|
+
* @param args.submit - 提交钮的 `label` 与 `busyLabel`。
|
|
1580
|
+
* @param args.busy - 提交中:提交钮带转圈并换 `busyLabel`(不给就沿用 `label`),`extra` 与取消一起禁用。
|
|
1581
|
+
* @param args.disabled - 只再禁提交钮(如没改动可存),其余动作不受影响。
|
|
1582
|
+
* @param args.onSubmitClick - 提交钮点下去做什么,通常是把这一拍交给 `Form` 的提交处理。
|
|
1583
|
+
* @returns 给 `FormActions` 的动作清单;没给 `extra` 也没给 `cancel` 时只剩提交那一颗。
|
|
1584
|
+
*/
|
|
1585
|
+
function formActionsOf(args) {
|
|
1586
|
+
const submit = {
|
|
1587
|
+
key: "submit",
|
|
1588
|
+
label: args.busy ? args.submit.busyLabel ?? args.submit.label : args.submit.label,
|
|
1589
|
+
kind: "primary",
|
|
1590
|
+
busy: args.busy,
|
|
1591
|
+
disabled: args.busy || args.disabled,
|
|
1592
|
+
onClick: args.onSubmitClick
|
|
1593
|
+
};
|
|
1594
|
+
const cancel = args.cancel === void 0 ? [] : [{
|
|
1595
|
+
key: "cancel",
|
|
1596
|
+
label: args.cancel.label,
|
|
1597
|
+
kind: "default",
|
|
1598
|
+
disabled: args.busy,
|
|
1599
|
+
onClick: args.cancel.onClick
|
|
1600
|
+
}];
|
|
1601
|
+
return [
|
|
1602
|
+
...(args.extra ?? []).map((action) => args.busy ? {
|
|
1603
|
+
...action,
|
|
1604
|
+
disabled: true
|
|
1605
|
+
} : action),
|
|
1606
|
+
...cancel,
|
|
1607
|
+
submit
|
|
1608
|
+
];
|
|
1609
|
+
}
|
|
1610
|
+
/**
|
|
1611
|
+
* 把整张表单的行画出来 —— 每格一个 `FormRow`,且**直接**是 `FormRows` 的孩子。
|
|
1612
|
+
* 中间不许再包一层:`FormRow` 一旦不是 `.wb-formRows` 的网格项,`FormRows.css` 里那条 `subgrid` 就不匹配,
|
|
1613
|
+
* 每行各自算列宽,控件左沿就参差了。
|
|
1614
|
+
* @param args.fields - 要画的格子(通常是已经过滤过可见性的那份),顺序就是行的顺序。
|
|
1615
|
+
* @param args.problems - `formProblemsOf` 那张表,决定哪一格显示错误文案(按**真值**判,假值不当错)。
|
|
1616
|
+
* @param args.showProblem - 这一拍该不该显示错误(还没提交过时为 false,一格都不显示)。
|
|
1617
|
+
* @param args.busy - 提交中:每格的绑定 `disabled` 为真。
|
|
1618
|
+
* @returns `FormRow` 组成的数组;没有可画的格子时给空数组。
|
|
1619
|
+
*/
|
|
1620
|
+
function formRowsOf(args) {
|
|
1621
|
+
return args.fields.map((field) => h(FormRow, {
|
|
1622
|
+
key: field.key,
|
|
1623
|
+
label: field.label,
|
|
1624
|
+
hint: field.hint,
|
|
1625
|
+
problem: args.showProblem ? args.problems[field.key] : void 0,
|
|
1626
|
+
layout: field.layout
|
|
1627
|
+
}, field.control({
|
|
1628
|
+
id: `wb-form-${field.key}`,
|
|
1629
|
+
name: field.key,
|
|
1630
|
+
invalid: args.showProblem && Boolean(args.problems[field.key]),
|
|
1631
|
+
disabled: args.busy || field.disabled === true
|
|
1632
|
+
})));
|
|
1633
|
+
}
|
|
1634
|
+
//#endregion
|
|
1635
|
+
//#region ../shared/dist/lib/form-problem.js
|
|
1636
|
+
var PROBLEM_SELECTOR = "[data-wb-problem]";
|
|
1637
|
+
var FOCUSABLE_SELECTOR = [
|
|
1638
|
+
"input:not([disabled])",
|
|
1639
|
+
"select:not([disabled])",
|
|
1640
|
+
"textarea:not([disabled])",
|
|
1641
|
+
"button:not([disabled])",
|
|
1642
|
+
"a[href]",
|
|
1643
|
+
"[tabindex]:not([tabindex=\"-1\"])"
|
|
1644
|
+
].join(", ");
|
|
1645
|
+
/**
|
|
1646
|
+
* 找 `root` 里第一个带 `[data-wb-problem]` 标记的元素 —— 表单校验失败时,调用方拿它定位「哪一格错了」。
|
|
1647
|
+
* @param root - 要搜的范围(表单容器,或 document)。
|
|
1648
|
+
* @returns 第一个出问题的元素;一个标记都没有就给 `null`。
|
|
1649
|
+
*/
|
|
1650
|
+
function firstProblemOf(root) {
|
|
1651
|
+
return root.querySelector(PROBLEM_SELECTOR);
|
|
1652
|
+
}
|
|
1653
|
+
/**
|
|
1654
|
+
* 把第一个出问题的元素滚进视野、并把焦点交给它里面第一个可聚焦控件(输入框 / 按钮 / 链接等)。
|
|
1655
|
+
* @param root - 要搜的范围。
|
|
1656
|
+
* @returns 找到并滚过给 `true`;没有问题给 `false`(不滚、不抢焦点);元素不可滚或没有可聚焦控件也不报错,只是少做一步。
|
|
1657
|
+
*/
|
|
1658
|
+
function revealFirstProblem(root) {
|
|
1659
|
+
const problem = firstProblemOf(root);
|
|
1660
|
+
if (problem === null) return false;
|
|
1661
|
+
problem.scrollIntoView?.({ block: "nearest" });
|
|
1662
|
+
problem.querySelector(FOCUSABLE_SELECTOR)?.focus?.();
|
|
1663
|
+
return true;
|
|
1664
|
+
}
|
|
1665
|
+
//#endregion
|
|
1666
|
+
//#region ../shared/dist/components/Form.js
|
|
1667
|
+
/**
|
|
1668
|
+
* 整张表单:`fields` 进,行、错误、操作区、(被挡住的)提交都由它安排 —— 它自己一个值都不存,
|
|
1669
|
+
* 值仍归调用点的 model(`value` 只读给校验看)。
|
|
1670
|
+
* 还没提交过时一格错都不显示;第一次提交之后每次渲染重算,改好了当场消。
|
|
1671
|
+
* 提交那一拍永远先算一遍:有错就不调 `onSubmit`,并把第一个有错的 `FormRow` 带进视口、聚焦它里面的控件。
|
|
1672
|
+
* 回车与点提交钮走的是同一条路:真 `<form>` 的隐式提交在**只有一个文本框**时也会 fire,所以 `busy` / `disabled` 时回车同样不提交。
|
|
1673
|
+
* 调用点只管数据与语义:行怎么排、错误摆哪、什么时候校验、按钮在哪,这里没有口子。
|
|
1674
|
+
* @param props.fields - 每格的键 / 标签 / 值 / 校验 / 控件;`visible: false` 的那格当它不存在(不渲染、不校验、不进 `values`)。
|
|
1675
|
+
* @param props.onSubmit - 校验全过的那一拍,回的是从 `fields` 现取的键值表;被挡住时不会被调。
|
|
1676
|
+
* @param props.submit - 提交钮文案;`busyLabel` 是提交中换的那句,不给就沿用 `label`。
|
|
1677
|
+
* @param props.cancel - 取消钮;给了就排在提交钮左边,`busy` 时一起禁用。
|
|
1678
|
+
* @param props.extra - 其余动作(default / danger),排在最左,`busy` 时一起禁用。
|
|
1679
|
+
* @param props.busy - 提交中(默认 false):整表控件的绑定 `disabled` 为真,所有动作一起禁用,回车也不提交。
|
|
1680
|
+
* @param props.disabled - 只再禁提交钮(如没改动可存),各格控件与其余动作不受影响,回车也不提交。
|
|
1681
|
+
* @param props.problem - 整表级那句错(提交失败),落在行与操作区之间;不给就不画。
|
|
1682
|
+
* @returns 一个 `<form>`(`noValidate`:报错形状归 `FormRow`,不走浏览器的气泡)。
|
|
1683
|
+
*/
|
|
1684
|
+
function Form(props) {
|
|
1685
|
+
const { fields, onSubmit, submit, cancel, extra, busy = false, disabled = false, problem } = props;
|
|
1686
|
+
const [done, setDone] = useState(false);
|
|
1687
|
+
const [reveal, setReveal] = useState(0);
|
|
1688
|
+
const rootRef = useRef(null);
|
|
1689
|
+
const shown = visibleFieldsOf(fields);
|
|
1690
|
+
const problems = formProblemsOf(shown, done);
|
|
1691
|
+
reportDuplicateKeys(shown);
|
|
1692
|
+
useEffect(() => {
|
|
1693
|
+
if (reveal === 0) return;
|
|
1694
|
+
const root = rootRef.current;
|
|
1695
|
+
if (root !== null) revealFirstProblem(root);
|
|
1696
|
+
}, [reveal]);
|
|
1697
|
+
const submitForm = () => {
|
|
1698
|
+
if (busy || disabled) return;
|
|
1699
|
+
const outcome = formSubmitOf(visibleFieldsOf(fields));
|
|
1700
|
+
setDone(true);
|
|
1701
|
+
if (outcome.blocked) {
|
|
1702
|
+
setReveal((count) => count + 1);
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1705
|
+
onSubmit(outcome.values);
|
|
1706
|
+
};
|
|
1707
|
+
return h("form", {
|
|
1708
|
+
className: "wb-form",
|
|
1709
|
+
ref: rootRef,
|
|
1710
|
+
noValidate: true,
|
|
1711
|
+
onSubmit: (event) => {
|
|
1712
|
+
event.preventDefault();
|
|
1713
|
+
submitForm();
|
|
1714
|
+
}
|
|
1715
|
+
}, h(FormRows, null, formRowsOf({
|
|
1716
|
+
fields: shown,
|
|
1717
|
+
problems,
|
|
1718
|
+
showProblem: done,
|
|
1719
|
+
busy
|
|
1720
|
+
})), problem === void 0 ? null : h(Note, {
|
|
1721
|
+
tone: "problem",
|
|
1722
|
+
role: "alert"
|
|
1723
|
+
}, problem), h(FormActions, { actions: formActionsOf({
|
|
1724
|
+
extra,
|
|
1725
|
+
cancel,
|
|
1726
|
+
submit,
|
|
1727
|
+
busy,
|
|
1728
|
+
disabled,
|
|
1729
|
+
onSubmitClick: submitForm
|
|
1730
|
+
}) }));
|
|
1731
|
+
}
|
|
1732
|
+
//#endregion
|
|
1057
1733
|
//#region ../shared/dist/components/Link.js
|
|
1734
|
+
/**
|
|
1735
|
+
* 唯一的外链写法:自带新窗口、`rel="noopener noreferrer"`、正文色与行尾那颗小箭头。
|
|
1736
|
+
* @param props.href - 目标地址,必给。
|
|
1737
|
+
* @param props.children - 链接文字(别自己再带 `→`)。
|
|
1738
|
+
* @param props.title - 原生 title 提示;不给就不写这个属性。
|
|
1739
|
+
* @param props.external - 默认 true:新窗口打开并画那颗 ↗;站内跳转给 false,箭头也一起不画。
|
|
1740
|
+
* @param props.className - 追加在基础类名之后,不是替换。
|
|
1741
|
+
* @returns 一个 `<a>`。
|
|
1742
|
+
*/
|
|
1058
1743
|
function Link({ href, children, title, external = true, className }) {
|
|
1059
1744
|
return h("a", {
|
|
1060
1745
|
className: className === void 0 ? "wb-link" : `wb-link ${className}`,
|
|
@@ -1074,6 +1759,19 @@ function RowLink({ href, text }) {
|
|
|
1074
1759
|
className: "wb-longTaskLink"
|
|
1075
1760
|
}, text);
|
|
1076
1761
|
}
|
|
1762
|
+
/**
|
|
1763
|
+
* 长任务那一行:状态点 + 标题 + 链接,跑失败时把步骤与原始输出收在两处可展开里。
|
|
1764
|
+
* 发布、扫描、迁移这类跑得久的事都用它,别自己画进度。
|
|
1765
|
+
* @param props.status - `longTaskDot` 认的四态之一,决定状态点颜色与要不要画"失败"那两块。
|
|
1766
|
+
* @param props.headline - 这一行在干什么(一句话)。
|
|
1767
|
+
* @param props.problem - 失败原因;不给不画。
|
|
1768
|
+
* @param props.links - 行尾的链接,通常指向产物或日志。
|
|
1769
|
+
* @param props.steps - 步骤文本;只在失败时画,且要同时给 `stepsTitle` 才成一块可展开。
|
|
1770
|
+
* @param props.raw - 原始输出;只在失败时画,且要同时给 `rawTitle` 才成一块可展开。
|
|
1771
|
+
* @param props.stepsTitle - 步骤那块展开行的标题;`rawTitle` 同理是原始输出那块。
|
|
1772
|
+
* @param props.copyLabel - 复制钮文案:给了才画复制钮;`copiedLabel` 是复制成功后那句。
|
|
1773
|
+
* @returns 一行长任务。
|
|
1774
|
+
*/
|
|
1077
1775
|
function LongTaskRow(props) {
|
|
1078
1776
|
const [stepsOpen, setStepsOpen] = useState(false);
|
|
1079
1777
|
const [rawOpen, setRawOpen] = useState(false);
|
|
@@ -1122,6 +1820,11 @@ function LongTaskRow(props) {
|
|
|
1122
1820
|
}
|
|
1123
1821
|
//#endregion
|
|
1124
1822
|
//#region ../shared/dist/components/ResourceStates.js
|
|
1823
|
+
/**
|
|
1824
|
+
* 骨架屏:读数期间已经知道大概形状时用它(连形状都不知道就用 `CenteredState` 那句"正在读")。
|
|
1825
|
+
* @param props.rows - 画几行骨架(默认 4);整块 `aria-hidden`,不读给读屏。
|
|
1826
|
+
* @returns 一叠占位条。
|
|
1827
|
+
*/
|
|
1125
1828
|
function SkeletonRows({ rows = 4 }) {
|
|
1126
1829
|
return h("div", {
|
|
1127
1830
|
className: "wb-skeleton",
|
|
@@ -1131,6 +1834,16 @@ function SkeletonRows({ rows = 4 }) {
|
|
|
1131
1834
|
className: "wb-skeletonRow"
|
|
1132
1835
|
}, h("span", { className: "wb-skeletonBar wb-skeletonBarTitle" }), h("span", { className: "wb-skeletonBar wb-skeletonBarMeta" }))));
|
|
1133
1836
|
}
|
|
1837
|
+
/**
|
|
1838
|
+
* 居中一屏:要他先选一个 / 正在读 / 读不到时用它占住卡片版面。
|
|
1839
|
+
* @param props.icon - 标题上方那枚图标;给 `null` 就只留标题(加载与报错常见)。
|
|
1840
|
+
* @param props.title - 正中那行大字。
|
|
1841
|
+
* @param props.hint - 标题下的一行说明。
|
|
1842
|
+
* @param props.detail - 更细的一行(如原始错误码与那句话);"读不到"时把错误放这里,绝不显示 0。
|
|
1843
|
+
* @param props.action - 底部动作(如"重试");不给不画。
|
|
1844
|
+
* @param props.compact - 紧凑档(默认 false),卡里空间小的时候给 true。
|
|
1845
|
+
* @returns 一个 `role="status"` 的居中块。
|
|
1846
|
+
*/
|
|
1134
1847
|
function CenteredState({ icon, title, hint, detail, action, compact = false }) {
|
|
1135
1848
|
return h("div", {
|
|
1136
1849
|
className: compact ? "wb-centered wb-centeredCompact" : "wb-centered",
|
|
@@ -1140,6 +1853,13 @@ function CenteredState({ icon, title, hint, detail, action, compact = false }) {
|
|
|
1140
1853
|
"aria-hidden": "true"
|
|
1141
1854
|
}, icon), h("div", { className: "wb-centeredTitle" }, title), hint === void 0 ? null : h("div", { className: "wb-centeredHint" }, hint), detail === void 0 ? null : h("div", { className: "wb-centeredDetail" }, detail), action === void 0 ? null : h("div", { className: "wb-centeredAction" }, action));
|
|
1142
1855
|
}
|
|
1856
|
+
/**
|
|
1857
|
+
* 就绪但空:它只是 `CenteredState` 的简写,标题就是那句空态文案。
|
|
1858
|
+
* @param props.text - 空态那句话。
|
|
1859
|
+
* @param props.icon - 标题上方的图标;默认 `null`,不画图标。
|
|
1860
|
+
* @param props.compact - 紧凑档,默认 false。
|
|
1861
|
+
* @returns 一个居中块。
|
|
1862
|
+
*/
|
|
1143
1863
|
function EmptyState({ text, icon = null, compact = false }) {
|
|
1144
1864
|
return h(CenteredState, {
|
|
1145
1865
|
icon,
|
|
@@ -1149,14 +1869,34 @@ function EmptyState({ text, icon = null, compact = false }) {
|
|
|
1149
1869
|
}
|
|
1150
1870
|
//#endregion
|
|
1151
1871
|
//#region ../shared/dist/components/Rows.js
|
|
1872
|
+
/**
|
|
1873
|
+
* 键值行的容器:分隔线、行距与两端对齐在它和 `Row` 里,别自己写 `ul` / `li` 拼。
|
|
1874
|
+
* @param props.children - 一串 `Row`。
|
|
1875
|
+
* @returns 竖排的 div。
|
|
1876
|
+
*/
|
|
1152
1877
|
function Rows({ children }) {
|
|
1153
1878
|
return h("div", { className: "wb-rows" }, children);
|
|
1154
1879
|
}
|
|
1880
|
+
/**
|
|
1881
|
+
* 一行键值:左边名字、右边值;要成对说明一项数据就用它,别自己写两栏。
|
|
1882
|
+
* @param props.label - 左边那格(键)。
|
|
1883
|
+
* @param props.value - 右边那格(值),可以是数字、时间或一小段节点。
|
|
1884
|
+
* @returns 一行两格。
|
|
1885
|
+
*/
|
|
1155
1886
|
function Row({ label, value }) {
|
|
1156
1887
|
return h("div", { className: "wb-row" }, h("span", { className: "wb-rowKey" }, label), h("span", { className: "wb-rowValue" }, value));
|
|
1157
1888
|
}
|
|
1158
1889
|
//#endregion
|
|
1159
1890
|
//#region ../shared/dist/components/SaveBar.js
|
|
1891
|
+
/**
|
|
1892
|
+
* 设置面底下那条"取消 / 保存":就是 `FormActions` 的两颗固定动作,顺序与间距不归调用点。
|
|
1893
|
+
* @param props.busy - 保存中:两颗钮一起禁用,保存那颗换成 `saving` 文案并带转圈。
|
|
1894
|
+
* @param props.disabled - 再额外禁掉保存钮(如没改动可存);默认不禁,取消钮不受它管。
|
|
1895
|
+
* @param props.labels - 三句文案:`cancel` / `save` / `saving`。
|
|
1896
|
+
* @param props.onCancel - 点取消。
|
|
1897
|
+
* @param props.onSave - 点保存。
|
|
1898
|
+
* @returns 一组按钮。
|
|
1899
|
+
*/
|
|
1160
1900
|
function SaveBar({ busy, disabled, labels, onCancel, onSave }) {
|
|
1161
1901
|
return h(FormActions, { actions: [{
|
|
1162
1902
|
key: "cancel",
|
|
@@ -1175,6 +1915,21 @@ function SaveBar({ busy, disabled, labels, onCancel, onSave }) {
|
|
|
1175
1915
|
}
|
|
1176
1916
|
//#endregion
|
|
1177
1917
|
//#region ../shared/dist/components/SelectFieldNodes.js
|
|
1918
|
+
/**
|
|
1919
|
+
* 下拉触发器那颗按钮:图标 + 当前值 + 箭头,交给 `Menu` 当 anchor;宽窄两档共用一个形状。
|
|
1920
|
+
* @param args.id - 触发器 id。
|
|
1921
|
+
* @param args.className - 触发器类名(已含 variant 与 iconOnly 的档)。
|
|
1922
|
+
* @param args.disabled - 是否禁用。
|
|
1923
|
+
* @param args.invalid - 置真写 `aria-invalid`。
|
|
1924
|
+
* @param args.open - 列表是否开着,写进 `aria-expanded`。
|
|
1925
|
+
* @param args.ariaLabel - 读屏名。
|
|
1926
|
+
* @param args.title - 原生提示。
|
|
1927
|
+
* @param args.icon - 值左边那枚图标;不给不占位。
|
|
1928
|
+
* @param args.value - 已渲染好的当前值节点(文本或占位)。
|
|
1929
|
+
* @param args.iconOnly - 只画图标(窄栏那颗切换钮),值与箭头都不画。
|
|
1930
|
+
* @param args.onOpen - 点它做什么,通常是把列表打开。
|
|
1931
|
+
* @returns 一颗 `<button>`。
|
|
1932
|
+
*/
|
|
1178
1933
|
function selectTriggerNode(args) {
|
|
1179
1934
|
return h("button", {
|
|
1180
1935
|
type: "button",
|
|
@@ -1189,6 +1944,15 @@ function selectTriggerNode(args) {
|
|
|
1189
1944
|
onClick: args.onOpen
|
|
1190
1945
|
}, args.iconOnly ? h("span", { className: "wb-selectIcon" }, args.icon) : h(Fragment, null, args.icon === void 0 ? null : h("span", { className: "wb-selectIcon" }, args.icon), h("span", { className: "wb-selectValue" }, args.value), h("span", { className: "wb-selectChevron" }, h(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { size: 14 }))));
|
|
1191
1946
|
}
|
|
1947
|
+
/**
|
|
1948
|
+
* 名单还没读到时的触发器:禁用 + `aria-busy` 的按钮,`SelectField` 在 `loading` 那档画它。
|
|
1949
|
+
* @param args.id - 触发器 id。
|
|
1950
|
+
* @param args.className - 触发器类名;它后面会接上 loading 那档的类。
|
|
1951
|
+
* @param args.invalid - 置真写 `aria-invalid`。
|
|
1952
|
+
* @param args.ariaLabel - 读屏名。
|
|
1953
|
+
* @param args.loadingText - 占位文案;不给就是 `…`。
|
|
1954
|
+
* @returns 一颗禁用且 `aria-busy` 的按钮。
|
|
1955
|
+
*/
|
|
1192
1956
|
function selectLoadingNode(args) {
|
|
1193
1957
|
return h("button", {
|
|
1194
1958
|
type: "button",
|
|
@@ -1203,6 +1967,11 @@ function selectLoadingNode(args) {
|
|
|
1203
1967
|
}
|
|
1204
1968
|
//#endregion
|
|
1205
1969
|
//#region ../shared/dist/components/TextField.js
|
|
1970
|
+
/**
|
|
1971
|
+
* 单行文本输入:设置面与筛选框都用它,`invalid` 之外的属性全部透传给原生 `<input>`。
|
|
1972
|
+
* @param props.invalid - 置真标红并写 `aria-invalid`(默认 false);错在哪一句归 `FormRow.problem`。
|
|
1973
|
+
* @returns 输入框元素;`className` 是追加在基础类名之后,而不是替换它。
|
|
1974
|
+
*/
|
|
1206
1975
|
function TextField({ invalid = false, className, ...rest }) {
|
|
1207
1976
|
return h("input", {
|
|
1208
1977
|
...rest,
|
|
@@ -1294,27 +2063,33 @@ function framed(label, hint, className, control) {
|
|
|
1294
2063
|
}, control);
|
|
1295
2064
|
return className === void 0 ? inner : h("div", { className }, inner);
|
|
1296
2065
|
}
|
|
2066
|
+
/** 算候选项用来匹配搜索的文本:有 `searchText` 就用它,否则取字符串标签;标签不是字符串又没给它是空串(这项搜不到)。 */
|
|
1297
2067
|
function searchTextOf(option) {
|
|
1298
2068
|
if (option.searchText !== void 0) return option.searchText;
|
|
1299
2069
|
return typeof option.label === "string" ? option.label : "";
|
|
1300
2070
|
}
|
|
2071
|
+
/** 默认匹配:查询去空白折成小写后看它是不是 `searchTextOf` 的子串;查询为空或纯空白时一律命中(留在列表里)。 */
|
|
1301
2072
|
function defaultSelectFilter(option, query) {
|
|
1302
2073
|
const needle = query.trim().toLowerCase();
|
|
1303
2074
|
if (needle === "") return true;
|
|
1304
2075
|
return searchTextOf(option).toLowerCase().includes(needle);
|
|
1305
2076
|
}
|
|
2077
|
+
/** 按查询过滤候选 —— 组件与模块自己算列表都用它,好让同一份口径管两处:`filter` 不给就用 `defaultSelectFilter`,顺序不变。 */
|
|
1306
2078
|
function filterSelectOptions(options, query, filter = defaultSelectFilter) {
|
|
1307
2079
|
return options.filter((option) => filter(option, query));
|
|
1308
2080
|
}
|
|
2081
|
+
/** 把键盘游标换算成当前该高亮那项的 value:游标 `null`(还没动过键盘)或列表为空时没有高亮;太大的游标收到最后一项,负游标取不到项也回 `null`。 */
|
|
1309
2082
|
function selectCursorValue(shown, cursor) {
|
|
1310
2083
|
if (cursor === null || shown.length === 0) return null;
|
|
1311
2084
|
return shown[Math.min(cursor, shown.length - 1)]?.value ?? null;
|
|
1312
2085
|
}
|
|
2086
|
+
/** 按上下键移动游标(两头环绕):还没选过时向下取第一项、向上取最后一项;列表为空回 `null`(一步都动不了)。`step` 1 向下、-1 向上。 */
|
|
1313
2087
|
function stepSelectCursor(shown, cursor, step) {
|
|
1314
2088
|
if (shown.length === 0) return null;
|
|
1315
2089
|
if (cursor === null) return step === 1 ? 0 : shown.length - 1;
|
|
1316
2090
|
return (cursor + step + shown.length) % shown.length;
|
|
1317
2091
|
}
|
|
2092
|
+
/** 把候选排成 `Menu` 要的条目表:按 `group` 插分组标题;一项都没有时退回 `emptyText` 那一行(不给就是空表)。`revealId` 是开列表时要滚进可视区的那个 value。 */
|
|
1318
2093
|
function selectEntries(shown, emptyText, revealId) {
|
|
1319
2094
|
if (shown.length === 0) return emptyText === void 0 ? [] : [{
|
|
1320
2095
|
type: "label",
|
|
@@ -1395,6 +2170,22 @@ function useSelectState(props) {
|
|
|
1395
2170
|
empty: typeof emptyText === "function" ? emptyText(query) : emptyText
|
|
1396
2171
|
};
|
|
1397
2172
|
}
|
|
2173
|
+
/**
|
|
2174
|
+
* 下拉选择:默认是跟 `TextField` 一套的常规下拉框(不是原生 `<select>`),无边框那种给 `variant: 'ghost'`。
|
|
2175
|
+
* `open` 不给就内部自己管(两种接法下 `onOpenChange` 都会通知),`loading` 把触发器换成转圈 + `loadingText`(默认 `…`),
|
|
2176
|
+
* `selection` 选选中行标记(`fill` 整行底色 / `check` 行尾勾),`footer` 是列表底部那一条(点它走 `onFooter`,不改当前值)。
|
|
2177
|
+
* @param props.value - 当前值;在 `options` 里找不到就按"没选"画 `placeholder`。
|
|
2178
|
+
* @param props.options - 全量候选;空数组且给了 `fallback` 时改画手填输入框。
|
|
2179
|
+
* @param props.onChange - 选中一项后的回调,回的是那一项的 `value`。
|
|
2180
|
+
* @param props.label - 没进 `FormRow` 时的标签兜底;进了那一行就别再给它和 `hint`,否则会多一个标签。
|
|
2181
|
+
* @param props.renderValue - 自己渲染触发器上那份当前值;不给就用候选项的 `label`。
|
|
2182
|
+
* @param props.placeholder - 没选中时那句话;不给是 `—`。
|
|
2183
|
+
* @param props.search - 是否可搜(默认 true);`false` 时不画搜索框、也不自动聚焦。
|
|
2184
|
+
* @param props.filter - 自定义匹配;不给用 `defaultSelectFilter`(空白查询一律命中)。
|
|
2185
|
+
* @param props.emptyText - 无匹配时的文案,或按查询生成文案的函数(能说"没有匹配 X 的项")。
|
|
2186
|
+
* @param props.fallback - 退路:`options` 为空时改成手填(`value` + `onChange`)。
|
|
2187
|
+
* @returns 触发器,以及打开时的搜索框与列表。
|
|
2188
|
+
*/
|
|
1398
2189
|
function SelectField(props) {
|
|
1399
2190
|
const { value, options, onChange, label, hint, icon, renderValue, placeholder, search = true, searchLabel, searchPlaceholder, footer, onFooter, disabled = false, invalid = false, loading = false, loadingText, fallback, selection = "fill", variant = "boxed", iconOnly = false, revealId, ariaLabel, title, id, name, className, menuClassName } = props;
|
|
1400
2191
|
const state = useSelectState(props);
|
|
@@ -1483,6 +2274,14 @@ function SelectField(props) {
|
|
|
1483
2274
|
}
|
|
1484
2275
|
//#endregion
|
|
1485
2276
|
//#region ../shared/dist/components/SettingsSection.js
|
|
2277
|
+
/**
|
|
2278
|
+
* 设置面里的一节:标题 + 右上那颗动作 + 一节内容,把一屏设置分组。
|
|
2279
|
+
* @param props.label - 只给读屏的组名(`aria-label`),不是标题。
|
|
2280
|
+
* @param props.title - 人看的标题。
|
|
2281
|
+
* @param props.action - 标题右侧的动作(如"添加");不给不占位。
|
|
2282
|
+
* @param props.children - 这一节的内容。
|
|
2283
|
+
* @returns 一个 `role="group"` 的 section。
|
|
2284
|
+
*/
|
|
1486
2285
|
function SettingsSection({ label, title, action, children }) {
|
|
1487
2286
|
return h("section", {
|
|
1488
2287
|
className: "wb-settings",
|
|
@@ -1492,11 +2291,26 @@ function SettingsSection({ label, title, action, children }) {
|
|
|
1492
2291
|
}
|
|
1493
2292
|
//#endregion
|
|
1494
2293
|
//#region ../shared/dist/components/Stack.js
|
|
2294
|
+
/**
|
|
2295
|
+
* 竖排容器:把相邻内容按统一间距摞起来,懒得自己分组时的默认外包装。
|
|
2296
|
+
* @param props.children - 要竖排的内容;不给就渲染一个空容器。
|
|
2297
|
+
* @returns 竖排的 div。
|
|
2298
|
+
*/
|
|
1495
2299
|
function Stack({ children }) {
|
|
1496
2300
|
return h("div", { className: "wb-stack" }, children);
|
|
1497
2301
|
}
|
|
1498
2302
|
//#endregion
|
|
1499
2303
|
//#region ../shared/dist/components/StateBlock.js
|
|
2304
|
+
/**
|
|
2305
|
+
* 有内容那一段:一个标题 + 一行提示 + 正文,卡里已经读到东西时用它开头。
|
|
2306
|
+
* @param props.title - 标题那行;它与 `dot` 都不给时整行不画。
|
|
2307
|
+
* @param props.dot - 标题前那枚状态点。
|
|
2308
|
+
* @param props.hint - 标题下那行小字(如"3 条 · 刚刚");不给不画。
|
|
2309
|
+
* @param props.resolving - "正在读"那行,读数期间挂上去;不给不画。
|
|
2310
|
+
* @param props.actions - 底部动作区;给了才画那一条。
|
|
2311
|
+
* @param props.children - 正文。
|
|
2312
|
+
* @returns 一个 div。
|
|
2313
|
+
*/
|
|
1500
2314
|
function StateBlock({ title, dot, hint, actions, resolving, children }) {
|
|
1501
2315
|
return h("div", { className: "wb-stateBlock" }, title === void 0 && dot === void 0 ? null : h("p", { className: "wb-stateBlockTitle" }, dot, title), resolving === void 0 ? null : h("p", { className: "wb-stateBlockResolving" }, resolving), hint === void 0 ? null : h("p", { className: "wb-stateBlockHint" }, hint), children, actions === void 0 ? null : h("div", { className: "wb-stateBlockActions" }, actions));
|
|
1502
2316
|
}
|
|
@@ -1514,6 +2328,11 @@ function Shell({ size, strokeWidth = 1, viewBox = "0 0 16 16", children }) {
|
|
|
1514
2328
|
style: { display: "block" }
|
|
1515
2329
|
}, children);
|
|
1516
2330
|
}
|
|
2331
|
+
/**
|
|
2332
|
+
* 会话图标:一枚对话气泡,dsh 的图标表里没有,留给我们自己用;默认 16px。
|
|
2333
|
+
* @param props.size - 边长像素,同时给 `width` 与 `height`。
|
|
2334
|
+
* @returns 一枚 `aria-hidden` 的 svg。
|
|
2335
|
+
*/
|
|
1517
2336
|
function IconConversation({ size = 16 }) {
|
|
1518
2337
|
return h(Shell, {
|
|
1519
2338
|
size,
|
|
@@ -1524,6 +2343,11 @@ function IconConversation({ size = 16 }) {
|
|
|
1524
2343
|
strokeLinejoin: "round"
|
|
1525
2344
|
}));
|
|
1526
2345
|
}
|
|
2346
|
+
/**
|
|
2347
|
+
* 品牌标:侧栏顶上那枚工作台方块标;默认 24px(它是品牌物,别拿它当通用图标)。
|
|
2348
|
+
* @param props.size - 边长像素,同时给 `width` 与 `height`。
|
|
2349
|
+
* @returns 一枚 `aria-hidden` 的 svg。
|
|
2350
|
+
*/
|
|
1527
2351
|
function IconBrandMark({ size = 24 }) {
|
|
1528
2352
|
return h(Shell, {
|
|
1529
2353
|
size,
|
|
@@ -1542,6 +2366,11 @@ function IconBrandMark({ size = 24 }) {
|
|
|
1542
2366
|
strokeLinecap: "round"
|
|
1543
2367
|
}));
|
|
1544
2368
|
}
|
|
2369
|
+
/**
|
|
2370
|
+
* opencli 的标:包类型那一格用它;颜色写死的品牌物,不跟主题走。默认 16px。
|
|
2371
|
+
* @param props.size - 边长像素,同时给 `width` 与 `height`。
|
|
2372
|
+
* @returns 一枚 `aria-hidden` 的 svg。
|
|
2373
|
+
*/
|
|
1545
2374
|
function IconOpencli({ size = 16 }) {
|
|
1546
2375
|
return h(Shell, {
|
|
1547
2376
|
size,
|
|
@@ -1577,6 +2406,11 @@ function IconOpencli({ size = 16 }) {
|
|
|
1577
2406
|
fill: "url(#opencli-mark)"
|
|
1578
2407
|
}, ">_"));
|
|
1579
2408
|
}
|
|
2409
|
+
/**
|
|
2410
|
+
* npm 的标:包类型那一格用它;保留品牌红,不跟主题走。默认 16px。
|
|
2411
|
+
* @param props.size - 边长像素,同时给 `width` 与 `height`。
|
|
2412
|
+
* @returns 一枚 `aria-hidden` 的 svg。
|
|
2413
|
+
*/
|
|
1580
2414
|
function IconNpm({ size = 16 }) {
|
|
1581
2415
|
return h(Shell, {
|
|
1582
2416
|
size,
|
|
@@ -1586,6 +2420,11 @@ function IconNpm({ size = 16 }) {
|
|
|
1586
2420
|
fill: "#CB3837"
|
|
1587
2421
|
}));
|
|
1588
2422
|
}
|
|
2423
|
+
/**
|
|
2424
|
+
* 四宫格:"模块"这个概念的通用单色图标(侧栏、面板那颗钮、市场节的标题);默认 16px。
|
|
2425
|
+
* @param props.size - 边长像素,同时给 `width` 与 `height`。
|
|
2426
|
+
* @returns 一枚 `aria-hidden` 的 svg。
|
|
2427
|
+
*/
|
|
1589
2428
|
function IconModules({ size = 16 }) {
|
|
1590
2429
|
return h("svg", {
|
|
1591
2430
|
width: size,
|
|
@@ -1627,6 +2466,11 @@ function IconModules({ size = 16 }) {
|
|
|
1627
2466
|
strokeWidth: "1.2"
|
|
1628
2467
|
}));
|
|
1629
2468
|
}
|
|
2469
|
+
/**
|
|
2470
|
+
* 模块类型标:渐变方块 + 白四宫格,用在"这是个模块"的行首;品牌物,颜色不跟主题走。默认 16px。
|
|
2471
|
+
* @param props.size - 边长像素,同时给 `width` 与 `height`。
|
|
2472
|
+
* @returns 一枚 `aria-hidden` 的 svg。
|
|
2473
|
+
*/
|
|
1630
2474
|
function IconModuleMark({ size = 16 }) {
|
|
1631
2475
|
return h(Shell, {
|
|
1632
2476
|
size,
|
|
@@ -1683,6 +2527,11 @@ function IconModuleMark({ size = 16 }) {
|
|
|
1683
2527
|
fill: "#ffffff"
|
|
1684
2528
|
}));
|
|
1685
2529
|
}
|
|
2530
|
+
/**
|
|
2531
|
+
* 面板 / 卡片那类的图标:整屏与柱状那种形状,给"面板"这一档用;默认 16px。
|
|
2532
|
+
* @param props.size - 边长像素,同时给 `width` 与 `height`。
|
|
2533
|
+
* @returns 一枚 `aria-hidden` 的 svg。
|
|
2534
|
+
*/
|
|
1686
2535
|
function IconPanelScreen({ size = 16 }) {
|
|
1687
2536
|
return h("svg", {
|
|
1688
2537
|
width: size,
|
|
@@ -1699,6 +2548,7 @@ function IconPanelScreen({ size = 16 }) {
|
|
|
1699
2548
|
}
|
|
1700
2549
|
//#endregion
|
|
1701
2550
|
//#region ../shared/dist/config/storage.js
|
|
2551
|
+
/** 读 localStorage 里的一段文本;没有这个键、或存储不可用(隐私模式)时返回 null。 */
|
|
1702
2552
|
function readText(key) {
|
|
1703
2553
|
try {
|
|
1704
2554
|
return window.localStorage.getItem(key);
|
|
@@ -1706,22 +2556,26 @@ function readText(key) {
|
|
|
1706
2556
|
return null;
|
|
1707
2557
|
}
|
|
1708
2558
|
}
|
|
2559
|
+
/** 写一段文本进 localStorage;`value` 为 null 时删掉这个键,写不进去就静默作罢。 */
|
|
1709
2560
|
function writeText(key, value) {
|
|
1710
2561
|
try {
|
|
1711
2562
|
if (value === null) window.localStorage.removeItem(key);
|
|
1712
2563
|
else window.localStorage.setItem(key, value);
|
|
1713
2564
|
} catch {}
|
|
1714
2565
|
}
|
|
2566
|
+
/** 读一个布尔开关:键不存在时返回 `fallback`,只有存进去的 `'true'` 算真。 */
|
|
1715
2567
|
function readFlag(key, fallback) {
|
|
1716
2568
|
const raw = readText(key);
|
|
1717
2569
|
if (raw === null) return fallback;
|
|
1718
2570
|
return raw === "true";
|
|
1719
2571
|
}
|
|
2572
|
+
/** 把一个布尔开关写进 localStorage(存 `'true'` / `'false'`);失败静默。 */
|
|
1720
2573
|
function writeFlag(key, value) {
|
|
1721
2574
|
writeText(key, value ? "true" : "false");
|
|
1722
2575
|
}
|
|
1723
2576
|
//#endregion
|
|
1724
2577
|
//#region ../shared/dist/i18n/en.js
|
|
2578
|
+
/** 外壳自带的英文词表:键必须与 `zh` 逐一对应,值不许为空串。 */
|
|
1725
2579
|
var en = {
|
|
1726
2580
|
"brand.name": "Workbench",
|
|
1727
2581
|
"toggle.open": "Open sidebar",
|
|
@@ -2132,23 +2986,37 @@ var en = {
|
|
|
2132
2986
|
"configSync.noSource": "This machine has no other profile to sync from",
|
|
2133
2987
|
"configSync.emptyProviders": "The workbench has no model provider yet — sync the llm- rows from some profile, or configure one under Models.",
|
|
2134
2988
|
"configSync.failed": "The sync did not go through; try again.",
|
|
2135
|
-
"debug.
|
|
2136
|
-
"debug.status
|
|
2137
|
-
"debug.
|
|
2989
|
+
"debug.workspace": "this workspace",
|
|
2990
|
+
"debug.status": "Debugging “{title}”",
|
|
2991
|
+
"debug.status.trouble": "Debugging needs your attention ({title})",
|
|
2992
|
+
"debug.stalled": "Debugging paused ({title})",
|
|
2138
2993
|
"debug.act.pause": "Pause debugging",
|
|
2139
2994
|
"debug.act.resume": "Resume debugging",
|
|
2140
2995
|
"debug.act.stop": "Stop debugging",
|
|
2141
2996
|
"debug.act.stop.ask": "Confirm stop",
|
|
2142
|
-
"debug.card.here.title": "
|
|
2997
|
+
"debug.card.here.title": "Debugging “{title}”",
|
|
2143
2998
|
"debug.card.here.note": "Do not switch workspaces or touch the panel",
|
|
2144
|
-
"debug.card.away.
|
|
2145
|
-
"debug.card.away.note": "Switch to the Workbench DIY workspace",
|
|
2999
|
+
"debug.card.away.note": "Switch back to “{title}”",
|
|
2146
3000
|
"debug.card.paused.note": "Paused",
|
|
2147
|
-
"debug.card.hidden.note": "Switch to the Workbench panel",
|
|
2148
|
-
"
|
|
3001
|
+
"debug.card.hidden.note": "Switch back to the Workbench panel",
|
|
3002
|
+
"record.waiting": "Recording handoff · your turn",
|
|
3003
|
+
"record.waiting.note": "Press \"Start recording\" on that page, then \"Stop recording\" when done (it will not switch you back)",
|
|
3004
|
+
"record.recording": "Recording",
|
|
3005
|
+
"record.recording.note": "Press \"Stop recording\" when done; if the bar is gone press Halt so the agent grabs it first",
|
|
3006
|
+
"record.finished": "Recording finished",
|
|
3007
|
+
"record.finished.note": "This run is done — the agent will grab it and wrap up on its own",
|
|
3008
|
+
"record.act.cancel": "Cancel",
|
|
3009
|
+
"record.act.halt": "Halt",
|
|
3010
|
+
"approval.record.site": "Site",
|
|
3011
|
+
"approval.record.what": "Records",
|
|
3012
|
+
"approval.record.lands": "Lands in",
|
|
3013
|
+
"approval.record.noUrl": "no site given (this call gets refused)",
|
|
3014
|
+
"approval.record.oneAction": "one action",
|
|
3015
|
+
"approval.record.noSwitch": "it will not switch you back (the leftbar footer shows the state)"
|
|
2149
3016
|
};
|
|
2150
3017
|
//#endregion
|
|
2151
3018
|
//#region ../shared/dist/i18n/zh.js
|
|
3019
|
+
/** 外壳自带的中文词表(命名空间 `workbench`):`en` 与它逐键对齐,模块那份在它之上合并。 */
|
|
2152
3020
|
var zh = {
|
|
2153
3021
|
"brand.name": "工作台",
|
|
2154
3022
|
"toggle.open": "打开侧边栏",
|
|
@@ -2559,23 +3427,37 @@ var zh = {
|
|
|
2559
3427
|
"configSync.noSource": "这台机器上只有工作台这一个 profile,没有可同步的来源",
|
|
2560
3428
|
"configSync.emptyProviders": "工作台还没有任何模型供应商 —— 去「配置同步」从某个 profile 把 llm- 那几行搬过来,或自己去「模型」里配。",
|
|
2561
3429
|
"configSync.failed": "同步没成功,再试一次。",
|
|
2562
|
-
"debug.
|
|
2563
|
-
"debug.status
|
|
2564
|
-
"debug.
|
|
3430
|
+
"debug.workspace": "这个工作区",
|
|
3431
|
+
"debug.status": "「{title}」调试中",
|
|
3432
|
+
"debug.status.trouble": "调试要你看一眼({title})",
|
|
3433
|
+
"debug.stalled": "调试已暂停({title})",
|
|
2565
3434
|
"debug.act.pause": "暂停调试",
|
|
2566
3435
|
"debug.act.resume": "继续调试",
|
|
2567
3436
|
"debug.act.stop": "结束调试",
|
|
2568
3437
|
"debug.act.stop.ask": "确认结束",
|
|
2569
|
-
"debug.card.here.title": "
|
|
3438
|
+
"debug.card.here.title": "正在调试「{title}」",
|
|
2570
3439
|
"debug.card.here.note": "请勿切换工作区和操作面板",
|
|
2571
|
-
"debug.card.away.
|
|
2572
|
-
"debug.card.away.note": "请切换到工作台 DIY 工作区",
|
|
3440
|
+
"debug.card.away.note": "请切回「{title}」那一屏",
|
|
2573
3441
|
"debug.card.paused.note": "已暂停",
|
|
2574
|
-
"debug.card.hidden.note": "
|
|
2575
|
-
"
|
|
3442
|
+
"debug.card.hidden.note": "请切回工作台面板",
|
|
3443
|
+
"record.waiting": "取证交接 · 等你出手",
|
|
3444
|
+
"record.waiting.note": "请在那一页按「开始录制」,做完按「结束录制」(录完不替你切回来)",
|
|
3445
|
+
"record.recording": "录制中",
|
|
3446
|
+
"record.recording.note": "做完按「结束录制」;浮条没了按「停」,让 agent 先取再收",
|
|
3447
|
+
"record.finished": "录制完成",
|
|
3448
|
+
"record.finished.note": "这一段录完了 —— agent 会自己来取并收工,不用你点",
|
|
3449
|
+
"record.act.cancel": "取消",
|
|
3450
|
+
"record.act.halt": "停",
|
|
3451
|
+
"approval.record.site": "站点",
|
|
3452
|
+
"approval.record.what": "录制功能",
|
|
3453
|
+
"approval.record.lands": "落点",
|
|
3454
|
+
"approval.record.noUrl": "没给站点地址(这次会被当场拒)",
|
|
3455
|
+
"approval.record.oneAction": "一次操作",
|
|
3456
|
+
"approval.record.noSwitch": "录完不会替你切回来(左栏底部会亮一条状态)"
|
|
2576
3457
|
};
|
|
2577
3458
|
//#endregion
|
|
2578
3459
|
//#region ../shared/dist/i18n/index.js
|
|
3460
|
+
/** 外壳自带的两份词表(`zh` 为基准、`en` 同构):`client.tsx` 拿它当合并各套件词表的底座。 */
|
|
2579
3461
|
var dictionaries = {
|
|
2580
3462
|
zh,
|
|
2581
3463
|
en
|
|
@@ -2588,6 +3470,7 @@ function assertSelfConsistent(unit, messages) {
|
|
|
2588
3470
|
if (zhKeys.length !== enKeys.length || zhKeys.some((key, index) => key !== enKeys[index])) throw new Error(`套件 ${unit} 的文案两语言不同构:zh ${zhKeys.length} 键 / en ${enKeys.length} 键`);
|
|
2589
3471
|
for (const [language, dictionary] of [["zh", messages.zh], ["en", messages.en]]) for (const [key, value] of Object.entries(dictionary)) if (value.trim() === "") throw new Error(`套件 ${unit} 的文案 ${language}.${key} 是空的`);
|
|
2590
3472
|
}
|
|
3473
|
+
/** 把各套件的词表合到外壳底座上:键必须以 `<unit>.` 开头、不许撞已有键,违规当场抛错。 */
|
|
2591
3474
|
function mergeMessages(base, contributions) {
|
|
2592
3475
|
const zh = { ...base.zh };
|
|
2593
3476
|
const en = { ...base.en };
|
|
@@ -2614,6 +3497,7 @@ function reasonOf(error) {
|
|
|
2614
3497
|
if (error instanceof Error) return error.message;
|
|
2615
3498
|
return typeof error === "string" ? error : String(error);
|
|
2616
3499
|
}
|
|
3500
|
+
/** 逐份试合、坏的跳过:一份贡献不合规只记进 `problems`,不影响其余套件与已有词表。 */
|
|
2617
3501
|
function mergeMessagesSkipping(base, contributions) {
|
|
2618
3502
|
let dictionaries = base;
|
|
2619
3503
|
const accepted = [];
|
|
@@ -2637,9 +3521,22 @@ function mergeMessagesSkipping(base, contributions) {
|
|
|
2637
3521
|
}
|
|
2638
3522
|
//#endregion
|
|
2639
3523
|
//#region ../shared/dist/lib/blocker-action.js
|
|
3524
|
+
/**
|
|
3525
|
+
* 这颗钮此刻该不该按成等待态:这一轮忙还没收,或有一支正在跑。
|
|
3526
|
+
* @param busy - 这一轮忙是不是还在。
|
|
3527
|
+
* @param running - 正在跑的那一支的 label;没有就给 `null`。
|
|
3528
|
+
* @returns 该等待给 `true`,否则 `false`。
|
|
3529
|
+
*/
|
|
2640
3530
|
function blockerPending(busy, running) {
|
|
2641
3531
|
return busy || running !== null;
|
|
2642
3532
|
}
|
|
3533
|
+
/**
|
|
3534
|
+
* 这颗钮此刻该显示什么字:正在重试说「重试中…」,正在跑的那一支说「修复中…」,刚复制过的说「已复制」,其余原样。
|
|
3535
|
+
* @param action - 这颗钮的形状(行为 + 平时文案)。
|
|
3536
|
+
* @param state - 此刻的运行态。
|
|
3537
|
+
* @param t - i18n 取词函数。
|
|
3538
|
+
* @returns 要显示的文案;三种临时态都不成立时就是 `action.label`。
|
|
3539
|
+
*/
|
|
2643
3540
|
function blockerActionLabel(action, state, t) {
|
|
2644
3541
|
if (action.kind === "retry" && state.retrying) return t("blocker.retry.running");
|
|
2645
3542
|
if (state.running === action.label) return t("blocker.fix.running");
|
|
@@ -2647,55 +3544,36 @@ function blockerActionLabel(action, state, t) {
|
|
|
2647
3544
|
return action.label;
|
|
2648
3545
|
}
|
|
2649
3546
|
//#endregion
|
|
2650
|
-
//#region ../shared/dist/lib/busy.js
|
|
2651
|
-
function holdBusy(since, now, floorMs) {
|
|
2652
|
-
if (since === null) return {
|
|
2653
|
-
visible: false,
|
|
2654
|
-
releaseInMs: 0
|
|
2655
|
-
};
|
|
2656
|
-
const left = floorMs - Math.max(0, now - since);
|
|
2657
|
-
return left <= 0 ? {
|
|
2658
|
-
visible: false,
|
|
2659
|
-
releaseInMs: 0
|
|
2660
|
-
} : {
|
|
2661
|
-
visible: true,
|
|
2662
|
-
releaseInMs: left
|
|
2663
|
-
};
|
|
2664
|
-
}
|
|
2665
|
-
//#endregion
|
|
2666
|
-
//#region ../shared/dist/lib/form-problem.js
|
|
2667
|
-
var PROBLEM_SELECTOR = "[data-wb-problem]";
|
|
2668
|
-
var FOCUSABLE_SELECTOR = [
|
|
2669
|
-
"input:not([disabled])",
|
|
2670
|
-
"select:not([disabled])",
|
|
2671
|
-
"textarea:not([disabled])",
|
|
2672
|
-
"button:not([disabled])",
|
|
2673
|
-
"a[href]",
|
|
2674
|
-
"[tabindex]:not([tabindex=\"-1\"])"
|
|
2675
|
-
].join(", ");
|
|
2676
|
-
function firstProblemOf(root) {
|
|
2677
|
-
return root.querySelector(PROBLEM_SELECTOR);
|
|
2678
|
-
}
|
|
2679
|
-
function revealFirstProblem(root) {
|
|
2680
|
-
const problem = firstProblemOf(root);
|
|
2681
|
-
if (problem === null) return false;
|
|
2682
|
-
problem.scrollIntoView?.({ block: "nearest" });
|
|
2683
|
-
problem.querySelector(FOCUSABLE_SELECTOR)?.focus?.();
|
|
2684
|
-
return true;
|
|
2685
|
-
}
|
|
2686
|
-
//#endregion
|
|
2687
3547
|
//#region ../shared/dist/lib/board-fact.js
|
|
3548
|
+
/**
|
|
3549
|
+
* 判一个路径落不落在这个工作区里(按路径前缀比,不是字符串包含)。
|
|
3550
|
+
* @param root - 工作区根路径。
|
|
3551
|
+
* @param target - 要判的路径。
|
|
3552
|
+
* @returns 同一个路径或在其下给 `true`;`root` 末尾带不带斜杠都认(`/a` 不匹配 `/ab`)。
|
|
3553
|
+
*/
|
|
2688
3554
|
function insideWorkshop(root, target) {
|
|
2689
3555
|
if (target === root) return true;
|
|
2690
3556
|
const base = root.endsWith("/") ? root : `${root}/`;
|
|
2691
3557
|
return target.startsWith(base);
|
|
2692
3558
|
}
|
|
3559
|
+
/**
|
|
3560
|
+
* 把一次探针读数归成椅面归属。
|
|
3561
|
+
* @param probe - 探针读数。
|
|
3562
|
+
* @param workshop - 当前工作区根路径;`null` 表示还不知道当前是哪个工作区。
|
|
3563
|
+
* @returns 外壳不在、或板路径与工作区缺一 → `unknown`;右栏没开或没画出来 → `hidden`;板在本工作区 → `workshop`,否则 `other`。
|
|
3564
|
+
*/
|
|
2693
3565
|
function boardFactOf(probe, workshop) {
|
|
2694
3566
|
if (!probe.workbench) return "unknown";
|
|
2695
3567
|
if (!probe.bar || !probe.open || !probe.drawn) return "hidden";
|
|
2696
3568
|
if (probe.board === "" || workshop === null) return "unknown";
|
|
2697
3569
|
return insideWorkshop(workshop, probe.board) ? "workshop" : "other";
|
|
2698
3570
|
}
|
|
3571
|
+
/**
|
|
3572
|
+
* 把探针读数归成左栏那句人话的档位。
|
|
3573
|
+
* @param probe - 探针读数。
|
|
3574
|
+
* @param workshop - 当前工作区根路径;`null` 一律 `unknown`。
|
|
3575
|
+
* @returns 椅面画着 → 本板 `ok` / 别板 `other-board`;没画着 → 页面已走 `off-workspace`,否则 `panel-closed`。
|
|
3576
|
+
*/
|
|
2699
3577
|
function boardSituation(probe, workshop) {
|
|
2700
3578
|
if (!probe.workbench || workshop === null) return "unknown";
|
|
2701
3579
|
if (probe.bar && probe.open && probe.drawn) {
|
|
@@ -2706,27 +3584,62 @@ function boardSituation(probe, workshop) {
|
|
|
2706
3584
|
return "panel-closed";
|
|
2707
3585
|
}
|
|
2708
3586
|
//#endregion
|
|
3587
|
+
//#region ../shared/dist/lib/busy.js
|
|
3588
|
+
/**
|
|
3589
|
+
* 按「至少显示 floorMs」算这一轮忙此刻该不该收:没到下限就继续显示,并给出剩余时长供调用方起定时器。
|
|
3590
|
+
* @param since - 这一轮忙开始的时间戳;`null`(没开过这一轮)一律不显示。
|
|
3591
|
+
* @param now - 当前时间戳。
|
|
3592
|
+
* @param floorMs - 至少显示的时长(毫秒)。
|
|
3593
|
+
* @returns 还该不该显示 + 剩余毫秒;到点或已过下限给不显示,时钟倒退按「刚开头」算(剩余 = 下限,不给负数)。
|
|
3594
|
+
*/
|
|
3595
|
+
function holdBusy(since, now, floorMs) {
|
|
3596
|
+
if (since === null) return {
|
|
3597
|
+
visible: false,
|
|
3598
|
+
releaseInMs: 0
|
|
3599
|
+
};
|
|
3600
|
+
const left = floorMs - Math.max(0, now - since);
|
|
3601
|
+
return left <= 0 ? {
|
|
3602
|
+
visible: false,
|
|
3603
|
+
releaseInMs: 0
|
|
3604
|
+
} : {
|
|
3605
|
+
visible: true,
|
|
3606
|
+
releaseInMs: left
|
|
3607
|
+
};
|
|
3608
|
+
}
|
|
3609
|
+
//#endregion
|
|
2709
3610
|
//#region ../shared/dist/lib/diy-debug.js
|
|
3611
|
+
/**
|
|
3612
|
+
* 把工具入参收成人话动作。
|
|
3613
|
+
* @param value - 任意入参值。
|
|
3614
|
+
* @returns `'pause'` / `'resume'` / `'stop'` 原样;别的值(含 `undefined`、多余空白、大小写不同)给 `null`,由调用方拒。
|
|
3615
|
+
*/
|
|
2710
3616
|
function parseDebugIntent(value) {
|
|
2711
3617
|
return value === "pause" || value === "resume" || value === "stop" ? value : null;
|
|
2712
3618
|
}
|
|
3619
|
+
/**
|
|
3620
|
+
* 调试约定的有效期(4 小时,毫秒):超过它没动静的约定算过期、当场让人。
|
|
3621
|
+
*/
|
|
2713
3622
|
var DEBUG_STALE_MS = 144e5;
|
|
2714
|
-
function alive(state, now) {
|
|
3623
|
+
function alive$1(state, now) {
|
|
2715
3624
|
if (state === null) return null;
|
|
2716
3625
|
return now - state.at <= 144e5 ? state : null;
|
|
2717
3626
|
}
|
|
2718
|
-
function ownerOf(state, sessionId, now) {
|
|
2719
|
-
const held = alive(state, now);
|
|
3627
|
+
function ownerOf$1(state, sessionId, now) {
|
|
3628
|
+
const held = alive$1(state, now);
|
|
2720
3629
|
if (held === null) return "none";
|
|
2721
3630
|
return held.sessionId === sessionId ? held : "not-owner";
|
|
2722
3631
|
}
|
|
3632
|
+
/**
|
|
3633
|
+
* 造一份新的调试约定存储(进程内存,同一时刻只可能有一份有效约定)。
|
|
3634
|
+
* @returns 存取口;动作成不成都在返回的 `DebugMove` 里,不抛异常。
|
|
3635
|
+
*/
|
|
2723
3636
|
function createDebugStore() {
|
|
2724
3637
|
let held = null;
|
|
2725
|
-
const live = (now) => alive(held, now);
|
|
3638
|
+
const live = (now) => alive$1(held, now);
|
|
2726
3639
|
return {
|
|
2727
3640
|
live,
|
|
2728
3641
|
begin(pact) {
|
|
2729
|
-
const current = alive(held, pact.now);
|
|
3642
|
+
const current = alive$1(held, pact.now);
|
|
2730
3643
|
if (current !== null) return {
|
|
2731
3644
|
ok: false,
|
|
2732
3645
|
code: current.sessionId === pact.sessionId ? "already-held" : "held-by-other"
|
|
@@ -2734,7 +3647,8 @@ function createDebugStore() {
|
|
|
2734
3647
|
const state = {
|
|
2735
3648
|
phase: "debugging",
|
|
2736
3649
|
sessionId: pact.sessionId,
|
|
2737
|
-
|
|
3650
|
+
workspacePath: pact.workspacePath,
|
|
3651
|
+
title: pact.title,
|
|
2738
3652
|
board: pact.board,
|
|
2739
3653
|
unit: pact.unit,
|
|
2740
3654
|
name: pact.name,
|
|
@@ -2748,7 +3662,7 @@ function createDebugStore() {
|
|
|
2748
3662
|
};
|
|
2749
3663
|
},
|
|
2750
3664
|
pause(sessionId, now) {
|
|
2751
|
-
const found = ownerOf(held, sessionId, now);
|
|
3665
|
+
const found = ownerOf$1(held, sessionId, now);
|
|
2752
3666
|
if (typeof found === "string") return {
|
|
2753
3667
|
ok: false,
|
|
2754
3668
|
code: found
|
|
@@ -2769,7 +3683,7 @@ function createDebugStore() {
|
|
|
2769
3683
|
};
|
|
2770
3684
|
},
|
|
2771
3685
|
resume(sessionId, now) {
|
|
2772
|
-
const found = ownerOf(held, sessionId, now);
|
|
3686
|
+
const found = ownerOf$1(held, sessionId, now);
|
|
2773
3687
|
if (typeof found === "string") return {
|
|
2774
3688
|
ok: false,
|
|
2775
3689
|
code: found
|
|
@@ -2790,7 +3704,7 @@ function createDebugStore() {
|
|
|
2790
3704
|
};
|
|
2791
3705
|
},
|
|
2792
3706
|
stop(sessionId, now) {
|
|
2793
|
-
const found = ownerOf(held, sessionId, now);
|
|
3707
|
+
const found = ownerOf$1(held, sessionId, now);
|
|
2794
3708
|
if (typeof found === "string") return {
|
|
2795
3709
|
ok: false,
|
|
2796
3710
|
code: found
|
|
@@ -2803,10 +3717,152 @@ function createDebugStore() {
|
|
|
2803
3717
|
}
|
|
2804
3718
|
};
|
|
2805
3719
|
}
|
|
3720
|
+
/**
|
|
3721
|
+
* 「谁还占着」的一句话,用于别人来抢时说清现况。
|
|
3722
|
+
* @param state - 当前有效的那份约定。
|
|
3723
|
+
* @returns 形如「会话 x(自 HH:mm:ssZ 起在调试 y)」的中文串。
|
|
3724
|
+
*/
|
|
2806
3725
|
function debugOwnerText(state) {
|
|
2807
3726
|
return `会话 ${state.sessionId}(自 ${new Date(state.startedAt).toISOString().slice(11, 19)}Z 起在调试 ${state.unit})`;
|
|
2808
3727
|
}
|
|
3728
|
+
//#endregion
|
|
3729
|
+
//#region ../shared/dist/lib/diy-record.js
|
|
3730
|
+
/**
|
|
3731
|
+
* 录制约定的有效期(15 分钟,毫秒):超过它没动静的约定算过期、当场让人。
|
|
3732
|
+
*/
|
|
3733
|
+
var RECORD_STALE_MS = 9e5;
|
|
3734
|
+
/**
|
|
3735
|
+
* 把工具入参收成人话动作。
|
|
3736
|
+
* @param raw - 任意入参值。
|
|
3737
|
+
* @returns `'peek'` / `'halt'` / `'stop'` 原样;别的值(含 `undefined`、多余空白)给 `null`,由调用方拒。
|
|
3738
|
+
*/
|
|
3739
|
+
function parseRecordIntent(raw) {
|
|
3740
|
+
return raw === "peek" || raw === "halt" || raw === "stop" ? raw : null;
|
|
3741
|
+
}
|
|
3742
|
+
function alive(state, now) {
|
|
3743
|
+
if (state === null) return null;
|
|
3744
|
+
return now - state.at <= 9e5 ? state : null;
|
|
3745
|
+
}
|
|
3746
|
+
function ownerOf(state, sessionId, now) {
|
|
3747
|
+
const held = alive(state, now);
|
|
3748
|
+
if (held === null) return "none";
|
|
3749
|
+
return held.sessionId === sessionId ? held : "not-owner";
|
|
3750
|
+
}
|
|
3751
|
+
/**
|
|
3752
|
+
* 造一份新的录制约定存储(进程内存,同一时刻只可能有一份有效约定)。
|
|
3753
|
+
* @returns 存取口;动作成不成都在返回的 `RecordMove` 里,不抛异常。
|
|
3754
|
+
*/
|
|
3755
|
+
function createRecordStore() {
|
|
3756
|
+
let held = null;
|
|
3757
|
+
const live = (now) => alive(held, now);
|
|
3758
|
+
return {
|
|
3759
|
+
live,
|
|
3760
|
+
begin(pact) {
|
|
3761
|
+
const current = alive(held, pact.now);
|
|
3762
|
+
if (current !== null) return {
|
|
3763
|
+
ok: false,
|
|
3764
|
+
code: current.sessionId === pact.sessionId ? "already-held" : "held-by-other"
|
|
3765
|
+
};
|
|
3766
|
+
const state = {
|
|
3767
|
+
phase: "armed",
|
|
3768
|
+
sessionId: pact.sessionId,
|
|
3769
|
+
workspace: pact.workspace,
|
|
3770
|
+
unit: pact.unit,
|
|
3771
|
+
name: pact.name,
|
|
3772
|
+
url: pact.url,
|
|
3773
|
+
title: pact.title,
|
|
3774
|
+
action: pact.action,
|
|
3775
|
+
expect: pact.expect,
|
|
3776
|
+
captureFile: pact.captureFile,
|
|
3777
|
+
startedAt: pact.now,
|
|
3778
|
+
t0: null,
|
|
3779
|
+
t1: null,
|
|
3780
|
+
at: pact.now
|
|
3781
|
+
};
|
|
3782
|
+
held = state;
|
|
3783
|
+
return {
|
|
3784
|
+
ok: true,
|
|
3785
|
+
state
|
|
3786
|
+
};
|
|
3787
|
+
},
|
|
3788
|
+
started(sessionId, at, now) {
|
|
3789
|
+
const found = ownerOf(held, sessionId, now);
|
|
3790
|
+
if (typeof found === "string") return {
|
|
3791
|
+
ok: false,
|
|
3792
|
+
code: found
|
|
3793
|
+
};
|
|
3794
|
+
if (found.phase === "recording") return {
|
|
3795
|
+
ok: false,
|
|
3796
|
+
code: "already-recording"
|
|
3797
|
+
};
|
|
3798
|
+
if (found.phase !== "armed") return {
|
|
3799
|
+
ok: false,
|
|
3800
|
+
code: "not-armed"
|
|
3801
|
+
};
|
|
3802
|
+
const state = {
|
|
3803
|
+
...found,
|
|
3804
|
+
phase: "recording",
|
|
3805
|
+
t0: at,
|
|
3806
|
+
at: now
|
|
3807
|
+
};
|
|
3808
|
+
held = state;
|
|
3809
|
+
return {
|
|
3810
|
+
ok: true,
|
|
3811
|
+
state
|
|
3812
|
+
};
|
|
3813
|
+
},
|
|
3814
|
+
finished(sessionId, at, now) {
|
|
3815
|
+
const found = ownerOf(held, sessionId, now);
|
|
3816
|
+
if (typeof found === "string") return {
|
|
3817
|
+
ok: false,
|
|
3818
|
+
code: found
|
|
3819
|
+
};
|
|
3820
|
+
if (found.phase !== "recording") return {
|
|
3821
|
+
ok: false,
|
|
3822
|
+
code: "not-recording"
|
|
3823
|
+
};
|
|
3824
|
+
const state = {
|
|
3825
|
+
...found,
|
|
3826
|
+
phase: "finished",
|
|
3827
|
+
t1: at,
|
|
3828
|
+
at: now
|
|
3829
|
+
};
|
|
3830
|
+
held = state;
|
|
3831
|
+
return {
|
|
3832
|
+
ok: true,
|
|
3833
|
+
state
|
|
3834
|
+
};
|
|
3835
|
+
},
|
|
3836
|
+
stop(sessionId, now) {
|
|
3837
|
+
const found = ownerOf(held, sessionId, now);
|
|
3838
|
+
if (typeof found === "string") return {
|
|
3839
|
+
ok: false,
|
|
3840
|
+
code: found
|
|
3841
|
+
};
|
|
3842
|
+
held = null;
|
|
3843
|
+
return {
|
|
3844
|
+
ok: true,
|
|
3845
|
+
state: found
|
|
3846
|
+
};
|
|
3847
|
+
}
|
|
3848
|
+
};
|
|
3849
|
+
}
|
|
3850
|
+
/**
|
|
3851
|
+
* 「谁还占着、在录哪个动作」的一句话,用于别人来抢时说清现况。
|
|
3852
|
+
* @param state - 当前有效的那份约定。
|
|
3853
|
+
* @returns 形如「会话 x(自 HH:mm:ssZ 起在录 y 的「动作」)」的中文串。
|
|
3854
|
+
*/
|
|
3855
|
+
function recordOwnerText(state) {
|
|
3856
|
+
const at = new Date(state.startedAt).toISOString().slice(11, 19);
|
|
3857
|
+
return `会话 ${state.sessionId}(自 ${at}Z 起在录 ${state.unit} 的「${state.action}」)`;
|
|
3858
|
+
}
|
|
3859
|
+
/**
|
|
3860
|
+
* 同一原因的连续崩溃算进同一次计数的窗口(10 分钟,毫秒)。
|
|
3861
|
+
*/
|
|
2809
3862
|
var PANEL_STATE_CRASH_WINDOW_MS = 6e5;
|
|
3863
|
+
/**
|
|
3864
|
+
* 上报文本字段的截断长度(2000 字符;workspace / reason / message 共用)。
|
|
3865
|
+
*/
|
|
2810
3866
|
var PANEL_STATE_MAX_TEXT = 2e3;
|
|
2811
3867
|
var PHASES = [
|
|
2812
3868
|
"idle",
|
|
@@ -2817,7 +3873,7 @@ var PHASES = [
|
|
|
2817
3873
|
function asRecord(value) {
|
|
2818
3874
|
return typeof value === "object" && value !== null ? value : void 0;
|
|
2819
3875
|
}
|
|
2820
|
-
function textOf(value, max) {
|
|
3876
|
+
function textOf$1(value, max) {
|
|
2821
3877
|
if (typeof value !== "string") return "";
|
|
2822
3878
|
const trimmed = value.trim();
|
|
2823
3879
|
return trimmed.length > max ? trimmed.slice(0, max) : trimmed;
|
|
@@ -2830,21 +3886,27 @@ function atOf(value) {
|
|
|
2830
3886
|
function errorOf(raw) {
|
|
2831
3887
|
const record = asRecord(raw);
|
|
2832
3888
|
if (record === void 0) return void 0;
|
|
2833
|
-
const code = textOf(record["code"], 120);
|
|
2834
|
-
const message = textOf(record["message"], PANEL_STATE_MAX_TEXT);
|
|
3889
|
+
const code = textOf$1(record["code"], 120);
|
|
3890
|
+
const message = textOf$1(record["message"], PANEL_STATE_MAX_TEXT);
|
|
2835
3891
|
if (code === "" && message === "") return void 0;
|
|
2836
3892
|
return {
|
|
2837
3893
|
code: code === "" ? "unknown" : code,
|
|
2838
3894
|
message
|
|
2839
3895
|
};
|
|
2840
3896
|
}
|
|
3897
|
+
/**
|
|
3898
|
+
* 收一批卡片读数上报。
|
|
3899
|
+
* @param payload - `POST` 的请求体。
|
|
3900
|
+
* @returns 至少收到一条能认的卡片才 `ok: true`;请求体不是对象、`workspace` 为空、`cards` 不是数组,
|
|
3901
|
+
* 或一条都认不出(`unit` / `route` / `phase` / `at` 缺一)时 `ok: false` + 中文原因;认不出的单条静默跳过。
|
|
3902
|
+
*/
|
|
2841
3903
|
function parseCardsReport(payload) {
|
|
2842
3904
|
const record = asRecord(payload);
|
|
2843
3905
|
if (record === void 0) return {
|
|
2844
3906
|
ok: false,
|
|
2845
3907
|
message: "请求体要是一个对象"
|
|
2846
3908
|
};
|
|
2847
|
-
const workspace = textOf(record["workspace"], PANEL_STATE_MAX_TEXT);
|
|
3909
|
+
const workspace = textOf$1(record["workspace"], PANEL_STATE_MAX_TEXT);
|
|
2848
3910
|
if (workspace === "") return {
|
|
2849
3911
|
ok: false,
|
|
2850
3912
|
message: "workspace 不能是空的 —— 面板按工作区存"
|
|
@@ -2858,9 +3920,9 @@ function parseCardsReport(payload) {
|
|
|
2858
3920
|
for (const item of raw.slice(0, 32)) {
|
|
2859
3921
|
const card = asRecord(item);
|
|
2860
3922
|
if (card === void 0) continue;
|
|
2861
|
-
const unit = textOf(card["unit"], 200);
|
|
2862
|
-
const route = textOf(card["route"], 400);
|
|
2863
|
-
const phase = textOf(card["phase"], 20);
|
|
3923
|
+
const unit = textOf$1(card["unit"], 200);
|
|
3924
|
+
const route = textOf$1(card["route"], 400);
|
|
3925
|
+
const phase = textOf$1(card["phase"], 20);
|
|
2864
3926
|
const at = atOf(card["at"]);
|
|
2865
3927
|
if (unit === "" || route === "" || at === null || !PHASES.includes(phase)) continue;
|
|
2866
3928
|
const error = errorOf(card["error"]);
|
|
@@ -2884,15 +3946,20 @@ function parseCardsReport(payload) {
|
|
|
2884
3946
|
}
|
|
2885
3947
|
};
|
|
2886
3948
|
}
|
|
3949
|
+
/**
|
|
3950
|
+
* 收一次卡片崩溃上报。
|
|
3951
|
+
* @param payload - `POST` 的请求体。
|
|
3952
|
+
* @returns `workspace` / `unit` / `reason` 都不能空,缺一给 `ok: false` + 中文原因;`at` 缺省或不合法时取当前时间。
|
|
3953
|
+
*/
|
|
2887
3954
|
function parseCrashReport(payload) {
|
|
2888
3955
|
const record = asRecord(payload);
|
|
2889
3956
|
if (record === void 0) return {
|
|
2890
3957
|
ok: false,
|
|
2891
3958
|
message: "请求体要是一个对象"
|
|
2892
3959
|
};
|
|
2893
|
-
const workspace = textOf(record["workspace"], PANEL_STATE_MAX_TEXT);
|
|
2894
|
-
const unit = textOf(record["unit"], 200);
|
|
2895
|
-
const reason = textOf(record["reason"], PANEL_STATE_MAX_TEXT);
|
|
3960
|
+
const workspace = textOf$1(record["workspace"], PANEL_STATE_MAX_TEXT);
|
|
3961
|
+
const unit = textOf$1(record["unit"], 200);
|
|
3962
|
+
const reason = textOf$1(record["reason"], PANEL_STATE_MAX_TEXT);
|
|
2896
3963
|
if (workspace === "") return {
|
|
2897
3964
|
ok: false,
|
|
2898
3965
|
message: "workspace 不能是空的"
|
|
@@ -2915,6 +3982,10 @@ function parseCrashReport(payload) {
|
|
|
2915
3982
|
}
|
|
2916
3983
|
};
|
|
2917
3984
|
}
|
|
3985
|
+
/**
|
|
3986
|
+
* 造一份面板运行态的留存(进程内存、按工作区分桶,带上面那几条上限的 LRU)。
|
|
3987
|
+
* @returns 留存口:`cards` / `crash` 收上报,`snapshot(workspace)` 取全量;没存过的工作区(含 `null`)给一份空的。
|
|
3988
|
+
*/
|
|
2918
3989
|
function createPanelStateStore() {
|
|
2919
3990
|
const workspaces = /* @__PURE__ */ new Map();
|
|
2920
3991
|
function trim(entry, max) {
|
|
@@ -3005,9 +4076,20 @@ function createPanelStateStore() {
|
|
|
3005
4076
|
}
|
|
3006
4077
|
//#endregion
|
|
3007
4078
|
//#region ../shared/dist/lib/text.js
|
|
4079
|
+
/**
|
|
4080
|
+
* 把一个值裹成 shell 里的单引号字面量(值里的单引号一并转义),保证元字符按字面量传递。
|
|
4081
|
+
* @param value - 任意值;不是字符串的先 `String()`。
|
|
4082
|
+
* @returns 可安全拼进 `/bin/sh -c` 的一段文本 —— 含空格 / `$()` / `;` / 通配符的值都不会被当成语法。
|
|
4083
|
+
*/
|
|
3008
4084
|
function quoteShellArg(value) {
|
|
3009
4085
|
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
3010
4086
|
}
|
|
4087
|
+
/**
|
|
4088
|
+
* 取一段文本的末尾若干行(如命令输出),顺带去掉首尾空白。
|
|
4089
|
+
* @param text - 原文;`null` / `undefined` 当空串。
|
|
4090
|
+
* @param lines - 最多留几行,默认 6;0 给全篇、负数从开头砍掉那么多行(都是 `slice` 语义),调用方传正数。
|
|
4091
|
+
* @returns 末尾若干行、去首尾空行后的文本;原文行数不够就全给,空输入给空串。
|
|
4092
|
+
*/
|
|
3011
4093
|
function tailLines(text, lines = 6) {
|
|
3012
4094
|
return String(text ?? "").trim().split("\n").slice(-lines).join("\n");
|
|
3013
4095
|
}
|
|
@@ -3025,6 +4107,11 @@ function candidateStarts(raw) {
|
|
|
3025
4107
|
}
|
|
3026
4108
|
return starts;
|
|
3027
4109
|
}
|
|
4110
|
+
/**
|
|
4111
|
+
* 宽松解析一段前后可能夹着人话的 JSON:整段不通就从行首的 `[` / `{` 起、截到最后一个闭合符再试。
|
|
4112
|
+
* @param text - 原文;`null` / `undefined` 当空串。
|
|
4113
|
+
* @returns 解析出的值(对象 / 数组 / 标量都原样);空输入或怎么都解析不出给 `undefined`,调用方据此报「输出认不出」。
|
|
4114
|
+
*/
|
|
3028
4115
|
function parseJsonLoose(text) {
|
|
3029
4116
|
const raw = String(text ?? "").trim();
|
|
3030
4117
|
if (!raw) return void 0;
|
|
@@ -3047,6 +4134,12 @@ function parseJsonLoose(text) {
|
|
|
3047
4134
|
var MARKDOWN_IMAGE = /!\[[^\]]*\]\([^)]*\)/g;
|
|
3048
4135
|
var MARKDOWN_LINK = /\[([^\]]*)\]\([^)]*\)/g;
|
|
3049
4136
|
var MARKDOWN_MARKS = /[*`_>#]/g;
|
|
4137
|
+
/**
|
|
4138
|
+
* 把一段 Markdown 压成一行纯文本摘要:图片剥掉、链接只留可见文字、标记符号压成空格,超长按字符截断。
|
|
4139
|
+
* @param text - 原文;`null` / `undefined` 当空串。
|
|
4140
|
+
* @param limit - 摘要最多多少字符,默认 80。
|
|
4141
|
+
* @returns 单行摘要;没超限原样给,超了截到 `limit` 并补省略号(总长 `limit + 1`;第 `limit` 个字符是空白时会被 `trimEnd` 去掉、略短),空输入给空串。
|
|
4142
|
+
*/
|
|
3050
4143
|
function excerpt(text, limit = 80) {
|
|
3051
4144
|
const flat = String(text ?? "").replace(MARKDOWN_IMAGE, " ").replace(MARKDOWN_LINK, "$1").replace(MARKDOWN_MARKS, " ").replace(/\s+/g, " ").trim();
|
|
3052
4145
|
if (flat.length <= limit) return flat;
|
|
@@ -3078,10 +4171,14 @@ var dist_exports = /* @__PURE__ */ __exportAll({
|
|
|
3078
4171
|
DIY_DEBUG_ACT_PATH: () => DIY_DEBUG_ACT_PATH,
|
|
3079
4172
|
DIY_DEBUG_PATH: () => DIY_DEBUG_PATH,
|
|
3080
4173
|
DIY_DEBUG_SERVICE: () => DIY_DEBUG_SERVICE,
|
|
4174
|
+
DIY_RECORD_ACT_PATH: () => DIY_RECORD_ACT_PATH,
|
|
4175
|
+
DIY_RECORD_PATH: () => DIY_RECORD_PATH,
|
|
4176
|
+
DIY_RECORD_SERVICE: () => DIY_RECORD_SERVICE,
|
|
3081
4177
|
EVENTS_PATH: () => EVENTS_PATH,
|
|
3082
4178
|
EmptyState: () => EmptyState,
|
|
3083
4179
|
FACT_SCOPE_SUFFIX: () => "*",
|
|
3084
4180
|
Field: () => Field,
|
|
4181
|
+
Form: () => Form,
|
|
3085
4182
|
FormActions: () => FormActions,
|
|
3086
4183
|
FormRow: () => FormRow,
|
|
3087
4184
|
FormRows: () => FormRows,
|
|
@@ -3122,10 +4219,12 @@ var dist_exports = /* @__PURE__ */ __exportAll({
|
|
|
3122
4219
|
PREFS_PREFIX: () => PREFS_PREFIX,
|
|
3123
4220
|
PROBE_TTL_MS: () => PROBE_TTL_MS,
|
|
3124
4221
|
PROVISION_PREFIX: () => PROVISION_PREFIX,
|
|
4222
|
+
RECORD_STALE_MS: () => RECORD_STALE_MS,
|
|
3125
4223
|
RELEASE_SIBLINGS: () => RELEASE_SIBLINGS,
|
|
3126
4224
|
RIGHTBAR_FULLSCREEN_WIDTH: () => 768,
|
|
3127
4225
|
Row: () => Row,
|
|
3128
4226
|
Rows: () => Rows,
|
|
4227
|
+
SESSION_PROJECTIONS_SERVICE: () => SESSION_PROJECTIONS_SERVICE,
|
|
3129
4228
|
STORAGE_KEY_PROJECT: () => STORAGE_KEY_PROJECT,
|
|
3130
4229
|
STORAGE_KEY_RIGHTBAR: () => STORAGE_KEY_RIGHTBAR,
|
|
3131
4230
|
STORAGE_KEY_RIGHTBAR_COLUMN: () => STORAGE_KEY_RIGHTBAR_COLUMN,
|
|
@@ -3158,12 +4257,14 @@ var dist_exports = /* @__PURE__ */ __exportAll({
|
|
|
3158
4257
|
createDebugStore: () => createDebugStore,
|
|
3159
4258
|
createFactChannel: () => createFactChannel,
|
|
3160
4259
|
createPanelStateStore: () => createPanelStateStore,
|
|
4260
|
+
createRecordStore: () => createRecordStore,
|
|
3161
4261
|
cx: () => cx,
|
|
3162
4262
|
debugOwnerText: () => debugOwnerText,
|
|
3163
4263
|
declarationProblemsOf: () => declarationProblemsOf,
|
|
3164
4264
|
decodeRef: () => decodeRef,
|
|
3165
4265
|
defaultSelectFilter: () => defaultSelectFilter,
|
|
3166
4266
|
dictionaries: () => dictionaries,
|
|
4267
|
+
duplicateKeysOf: () => duplicateKeysOf,
|
|
3167
4268
|
en: () => en,
|
|
3168
4269
|
encodeRef: () => encodeRef,
|
|
3169
4270
|
errorReasonOf: () => errorReasonOf,
|
|
@@ -3171,6 +4272,12 @@ var dist_exports = /* @__PURE__ */ __exportAll({
|
|
|
3171
4272
|
factOfRoute: () => factOfRoute,
|
|
3172
4273
|
filterSelectOptions: () => filterSelectOptions,
|
|
3173
4274
|
firstProblemOf: () => firstProblemOf,
|
|
4275
|
+
formActionsOf: () => formActionsOf,
|
|
4276
|
+
formFirstProblemOf: () => formFirstProblemOf,
|
|
4277
|
+
formProblemsOf: () => formProblemsOf,
|
|
4278
|
+
formRowsOf: () => formRowsOf,
|
|
4279
|
+
formSubmitOf: () => formSubmitOf,
|
|
4280
|
+
formValuesOf: () => formValuesOf,
|
|
3174
4281
|
gateOf: () => gateOf,
|
|
3175
4282
|
h: () => h,
|
|
3176
4283
|
hasEnvSupply: () => hasEnvSupply,
|
|
@@ -3190,21 +4297,26 @@ var dist_exports = /* @__PURE__ */ __exportAll({
|
|
|
3190
4297
|
parseJsonLoose: () => parseJsonLoose,
|
|
3191
4298
|
parseLocalTimestamp: () => parseLocalTimestamp,
|
|
3192
4299
|
parseMarkers: () => parseMarkers,
|
|
4300
|
+
parseRecordIntent: () => parseRecordIntent,
|
|
3193
4301
|
probeKeyOf: () => probeKeyOf,
|
|
3194
4302
|
quoteShellArg: () => quoteShellArg,
|
|
3195
4303
|
readDeclaration: () => readDeclaration,
|
|
3196
4304
|
readFlag: () => readFlag,
|
|
3197
4305
|
readText: () => readText,
|
|
4306
|
+
recordOwnerText: () => recordOwnerText,
|
|
3198
4307
|
relativeTime: () => relativeTime,
|
|
3199
4308
|
relativeTimeAgo: () => relativeTimeAgo,
|
|
3200
4309
|
relativeTimeBucket: () => relativeTimeBucket,
|
|
3201
4310
|
relativeTimeCompact: () => relativeTimeCompact,
|
|
4311
|
+
reportDuplicateKeys: () => reportDuplicateKeys,
|
|
3202
4312
|
revealFirstProblem: () => revealFirstProblem,
|
|
3203
4313
|
runsRouteOf: () => runsRouteOf,
|
|
3204
4314
|
scopePrefixOf: () => scopePrefixOf,
|
|
3205
4315
|
searchTextOf: () => searchTextOf,
|
|
3206
4316
|
selectCursorValue: () => selectCursorValue,
|
|
3207
4317
|
selectEntries: () => selectEntries,
|
|
4318
|
+
selectLoadingNode: () => selectLoadingNode,
|
|
4319
|
+
selectTriggerNode: () => selectTriggerNode,
|
|
3208
4320
|
shortenPath: () => shortenPath,
|
|
3209
4321
|
splitBlocker: () => splitBlocker,
|
|
3210
4322
|
stepSelectCursor: () => stepSelectCursor,
|
|
@@ -3218,6 +4330,7 @@ var dist_exports = /* @__PURE__ */ __exportAll({
|
|
|
3218
4330
|
useRef: () => useRef,
|
|
3219
4331
|
useState: () => useState,
|
|
3220
4332
|
useSyncExternalStore: () => useSyncExternalStore,
|
|
4333
|
+
visibleFieldsOf: () => visibleFieldsOf,
|
|
3221
4334
|
writeFlag: () => writeFlag,
|
|
3222
4335
|
writeOutcomeOf: () => writeOutcomeOf,
|
|
3223
4336
|
writeRoute: () => writeRoute,
|
|
@@ -3226,6 +4339,14 @@ var dist_exports = /* @__PURE__ */ __exportAll({
|
|
|
3226
4339
|
});
|
|
3227
4340
|
//#endregion
|
|
3228
4341
|
//#region src/shared/components/Tip.tsx
|
|
4342
|
+
/**
|
|
4343
|
+
* dsh `Tooltip` 的外壳默认值版:说明统一按右栏习惯(`bottom` / `end` / `gap 6` / 挂 body)来,其余 prop 原样转给 `Tooltip`。
|
|
4344
|
+
* @param props.side - 气泡出现在锚点哪一侧(默认 `'bottom'`)。
|
|
4345
|
+
* @param props.align - 底 / 顶气泡贴锚点哪条边(默认 `'end'`)。
|
|
4346
|
+
* @param props.gap - 锚点到气泡的间距(默认 `6`)。
|
|
4347
|
+
* @param props.portal - 是否挂到 `document.body`,以逃出裁剪容器与层叠上下文(默认 `true`)。
|
|
4348
|
+
* @param props.children - 单个锚点元素;`label` / `shortcutKeys` / `openOnClick` 等其余 prop 与 dsh 同形。
|
|
4349
|
+
*/
|
|
3229
4350
|
function Tip({ side = "bottom", align = "end", gap = 6, portal = true, ...rest }) {
|
|
3230
4351
|
return /* @__PURE__ */ h(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
3231
4352
|
side,
|
|
@@ -3295,6 +4416,10 @@ function pollTransport() {
|
|
|
3295
4416
|
};
|
|
3296
4417
|
} };
|
|
3297
4418
|
}
|
|
4419
|
+
/**
|
|
4420
|
+
* 事实通道的传输选择:有 `EventSource` 就先用 SSE,连不上(重试一拍仍失败)自动降级成长轮询;
|
|
4421
|
+
* 没有 `EventSource` 的运行时直接轮询。返回值是停掉当前这条传输的函数。
|
|
4422
|
+
*/
|
|
3298
4423
|
function createAdaptiveTransport() {
|
|
3299
4424
|
return { start(handlers) {
|
|
3300
4425
|
let stopped = false;
|
|
@@ -3319,17 +4444,30 @@ var use_facts_exports = /* @__PURE__ */ __exportAll({
|
|
|
3319
4444
|
useFactRevision: () => useFactRevision
|
|
3320
4445
|
});
|
|
3321
4446
|
var channel = createFactChannel({ transport: createAdaptiveTransport() });
|
|
4447
|
+
/**
|
|
4448
|
+
* 渲染里要“这条事实的版本号”时调用:版本一变,喂给 `useApiResource` 的 key 就变、读自动重来。
|
|
4449
|
+
* 卡片读数默认订的 `factOfRoute(route)` 已经接好,只有要订别的事实才显式传 `fact`。
|
|
4450
|
+
*/
|
|
3322
4451
|
function useFactRevision(fact) {
|
|
3323
4452
|
return useSyncExternalStore(useCallback((listener) => channel.subscribe(fact, listener), [fact]), useCallback(() => channel.revisionOf(fact), [fact]));
|
|
3324
4453
|
}
|
|
4454
|
+
/**
|
|
4455
|
+
* 不在渲染里的地方(宿主事件、定时器里看到的旧值)要听事实变化时用它;返回值就是退订函数,用完记得退。
|
|
4456
|
+
*/
|
|
3325
4457
|
function subscribeFactRevision(fact, listener) {
|
|
3326
4458
|
return channel.subscribe(fact, listener);
|
|
3327
4459
|
}
|
|
4460
|
+
/**
|
|
4461
|
+
* 写完之后把这条事实标脏时调用:不标,面板就停在旧值;不传 `fact` 是把所有事实一起标脏。
|
|
4462
|
+
*/
|
|
3328
4463
|
function useFactInvalidate() {
|
|
3329
4464
|
return useCallback((fact) => channel.refresh(fact), []);
|
|
3330
4465
|
}
|
|
3331
4466
|
//#endregion
|
|
3332
4467
|
//#region src/shared/hooks/use-capabilities.ts
|
|
4468
|
+
/**
|
|
4469
|
+
* 纯函数:`refreshToken` 与上一次不同,这一次就该强制重探。
|
|
4470
|
+
*/
|
|
3333
4471
|
function shouldForce(refreshToken, previousToken) {
|
|
3334
4472
|
return refreshToken !== previousToken;
|
|
3335
4473
|
}
|
|
@@ -3338,14 +4476,23 @@ var NO_PROBE = {
|
|
|
3338
4476
|
checking: false
|
|
3339
4477
|
};
|
|
3340
4478
|
var silentNextProbe = false;
|
|
4479
|
+
/**
|
|
4480
|
+
* 让下一次强探静默(不点亮 `checking`)—— 装机预检那类不该惊动界面的探用。
|
|
4481
|
+
*/
|
|
3341
4482
|
function markNextProbeSilent() {
|
|
3342
4483
|
silentNextProbe = true;
|
|
3343
4484
|
}
|
|
3344
4485
|
var probe$1 = NO_PROBE;
|
|
3345
4486
|
var probeListeners = /* @__PURE__ */ new Set();
|
|
4487
|
+
/**
|
|
4488
|
+
* 探针状态的取值口,给 `useSyncExternalStore` 用;渲染里要状态请用 `useCapabilityProbe`。
|
|
4489
|
+
*/
|
|
3346
4490
|
function probeValue() {
|
|
3347
4491
|
return probe$1;
|
|
3348
4492
|
}
|
|
4493
|
+
/**
|
|
4494
|
+
* 探针状态的订阅口,返回退订函数;渲染里要状态请用 `useCapabilityProbe`。
|
|
4495
|
+
*/
|
|
3349
4496
|
function subscribeProbe(listener) {
|
|
3350
4497
|
probeListeners.add(listener);
|
|
3351
4498
|
return () => {
|
|
@@ -3357,19 +4504,31 @@ function setProbe(next) {
|
|
|
3357
4504
|
probe$1 = next;
|
|
3358
4505
|
for (const listener of [...probeListeners]) listener();
|
|
3359
4506
|
}
|
|
4507
|
+
/**
|
|
4508
|
+
* 能力表那条事实的名字:写完之后 `useFactInvalidate(CAPABILITY_FACT)` 标它,读者自动重取。
|
|
4509
|
+
*/
|
|
3360
4510
|
var CAPABILITY_FACT = "capability";
|
|
3361
4511
|
var shared = null;
|
|
3362
4512
|
var current$1 = null;
|
|
3363
4513
|
var listeners$4 = /* @__PURE__ */ new Set();
|
|
4514
|
+
/**
|
|
4515
|
+
* 当前整张能力表的取值口(没探过是 `null`),给 `useSyncExternalStore` 用;渲染里请用 `useCapabilities`。
|
|
4516
|
+
*/
|
|
3364
4517
|
function capabilityValue() {
|
|
3365
4518
|
return current$1;
|
|
3366
4519
|
}
|
|
4520
|
+
/**
|
|
4521
|
+
* 能力表的订阅口,返回退订函数;渲染里请用 `useCapabilities`。
|
|
4522
|
+
*/
|
|
3367
4523
|
function subscribeCapabilities(listener) {
|
|
3368
4524
|
listeners$4.add(listener);
|
|
3369
4525
|
return () => {
|
|
3370
4526
|
listeners$4.delete(listener);
|
|
3371
4527
|
};
|
|
3372
4528
|
}
|
|
4529
|
+
/**
|
|
4530
|
+
* 写入口:换整张表并通知订阅者(同值不通知);传 `null` 清探针状态,`rechecked: true` 时顺手记下 `checkedAt`。
|
|
4531
|
+
*/
|
|
3373
4532
|
function setCapabilities(next, rechecked = false) {
|
|
3374
4533
|
if (next === null) setProbe(NO_PROBE);
|
|
3375
4534
|
else if (rechecked) setProbe({
|
|
@@ -3380,6 +4539,9 @@ function setCapabilities(next, rechecked = false) {
|
|
|
3380
4539
|
current$1 = next;
|
|
3381
4540
|
for (const listener of [...listeners$4]) listener();
|
|
3382
4541
|
}
|
|
4542
|
+
/**
|
|
4543
|
+
* 一次强探开始:点亮“正在探”;已经在探就跳过。
|
|
4544
|
+
*/
|
|
3383
4545
|
function beginProbe() {
|
|
3384
4546
|
if (probe$1.checking) return;
|
|
3385
4547
|
setProbe({
|
|
@@ -3387,6 +4549,9 @@ function beginProbe() {
|
|
|
3387
4549
|
checking: true
|
|
3388
4550
|
});
|
|
3389
4551
|
}
|
|
4552
|
+
/**
|
|
4553
|
+
* 一次强探收尾:熄灭“正在探”。
|
|
4554
|
+
*/
|
|
3390
4555
|
function endProbe() {
|
|
3391
4556
|
setProbe({
|
|
3392
4557
|
...probe$1,
|
|
@@ -3398,6 +4563,10 @@ async function fetchAll(force) {
|
|
|
3398
4563
|
if (response?.ok !== true || !Array.isArray(response.units)) return null;
|
|
3399
4564
|
return Object.fromEntries(response.units.map((unit) => [unit.unit, unit]));
|
|
3400
4565
|
}
|
|
4566
|
+
/**
|
|
4567
|
+
* 把一次探测的结果发布出去:读到了就广播并回 `true`;没读到(`null`)时已有结论就留着回 `false`,
|
|
4568
|
+
* 从来没有过结论才落一张空表回 `true`(“探不动”不等于“还没探”)。
|
|
4569
|
+
*/
|
|
3401
4570
|
function publishCapability(result, rechecked = false) {
|
|
3402
4571
|
if (result !== null) {
|
|
3403
4572
|
setCapabilities(result, rechecked);
|
|
@@ -3407,6 +4576,10 @@ function publishCapability(result, rechecked = false) {
|
|
|
3407
4576
|
setCapabilities({});
|
|
3408
4577
|
return true;
|
|
3409
4578
|
}
|
|
4579
|
+
/**
|
|
4580
|
+
* 同一语义(同一个 `force`)的在飞探测搭车:并发调用共享同一个 promise;落地或失败就清掉,
|
|
4581
|
+
* 下一次强探会真的再跑一遍;`force` 不同不搭车。
|
|
4582
|
+
*/
|
|
3410
4583
|
function shareCapabilityFetch(force, load) {
|
|
3411
4584
|
if (shared !== null && shared.force === force) return shared.promise;
|
|
3412
4585
|
const promise = load(force).finally(() => {
|
|
@@ -3420,6 +4593,10 @@ function shareCapabilityFetch(force, load) {
|
|
|
3420
4593
|
}
|
|
3421
4594
|
var readSeq$1 = 0;
|
|
3422
4595
|
var newestForceSeq$1 = -1;
|
|
4596
|
+
/**
|
|
4597
|
+
* 探一次能力表并发布:`force` 决定这是“重探”还是顺带读 —— 只有重探负责点亮 / 熄灭探针(`silent` 时连点亮都不做),
|
|
4598
|
+
* 被更新的一次重探盖过的非强制结果会丢掉。
|
|
4599
|
+
*/
|
|
3423
4600
|
function runCapabilityRead(options) {
|
|
3424
4601
|
const { force, silent = false, load = fetchAll } = options;
|
|
3425
4602
|
const seq = readSeq$1 += 1;
|
|
@@ -3432,6 +4609,10 @@ function runCapabilityRead(options) {
|
|
|
3432
4609
|
if (force) endProbe();
|
|
3433
4610
|
});
|
|
3434
4611
|
}
|
|
4612
|
+
/**
|
|
4613
|
+
* 渲染里要整张能力表时调用:所有读者共享同一份结论,没探过是 `null`。
|
|
4614
|
+
* `refreshToken` 变化算一次强制重探,事实版本(`CAPABILITY_FACT`)与 `reloadToken` 变化各触发一次重读。
|
|
4615
|
+
*/
|
|
3435
4616
|
function useCapabilities(refreshToken, reloadToken = 0) {
|
|
3436
4617
|
const value = useSyncExternalStore(subscribeCapabilities, capabilityValue);
|
|
3437
4618
|
const previous = useRef(refreshToken);
|
|
@@ -3451,6 +4632,9 @@ function useCapabilities(refreshToken, reloadToken = 0) {
|
|
|
3451
4632
|
]);
|
|
3452
4633
|
return value;
|
|
3453
4634
|
}
|
|
4635
|
+
/**
|
|
4636
|
+
* 渲染里要探针状态(`checking` / `checkedAt`)时调用,比如“最近检查”那一行。
|
|
4637
|
+
*/
|
|
3454
4638
|
function useCapabilityProbe() {
|
|
3455
4639
|
return useSyncExternalStore(subscribeProbe, probeValue);
|
|
3456
4640
|
}
|
|
@@ -3460,6 +4644,11 @@ var use_capability_gate_exports = /* @__PURE__ */ __exportAll({
|
|
|
3460
4644
|
useCapabilityGate: () => useCapabilityGate,
|
|
3461
4645
|
useCapabilityMap: () => useCapabilityMap
|
|
3462
4646
|
});
|
|
4647
|
+
/**
|
|
4648
|
+
* 卡片里判断“这一格现在能不能画”时调用:`refreshToken` 变化触发一次重探。
|
|
4649
|
+
* `options.mode` 换门的口径(默认 `'capability'`)、`options.fixture` 给夹具一份假能力;
|
|
4650
|
+
* `gated` 按口径算 —— 读数还没到先放行(让它去读),读到明确不通过才拦;`forceProbe()` 是“现在就去探一次”。
|
|
4651
|
+
*/
|
|
3463
4652
|
function useCapabilityGate(unit, refreshToken, options = {}) {
|
|
3464
4653
|
const [probeNonce, setProbeNonce] = useState(0);
|
|
3465
4654
|
const forceProbe = useCallback(() => setProbeNonce((value) => value + 1), []);
|
|
@@ -3471,6 +4660,10 @@ function useCapabilityGate(unit, refreshToken, options = {}) {
|
|
|
3471
4660
|
forceProbe
|
|
3472
4661
|
};
|
|
3473
4662
|
}
|
|
4663
|
+
/**
|
|
4664
|
+
* 设置页 / 体检那类“要全部单元的能力表”时调用:`reload()` 重取整张表、`forceProbe()` 立刻探一次、
|
|
4665
|
+
* `checking` 是探针在跑;没探过时 `capabilities` 是 `null`。
|
|
4666
|
+
*/
|
|
3474
4667
|
function useCapabilityMap(refreshToken) {
|
|
3475
4668
|
const [probeNonce, setProbeNonce] = useState(0);
|
|
3476
4669
|
const [reloadNonce, setReloadNonce] = useState(0);
|
|
@@ -4081,6 +5274,11 @@ function marketHintOf(input) {
|
|
|
4081
5274
|
//#endregion
|
|
4082
5275
|
//#region src/shared/hooks/use-host-write.ts
|
|
4083
5276
|
var use_host_write_exports = /* @__PURE__ */ __exportAll({ useHostWrite: () => useHostWrite });
|
|
5277
|
+
/**
|
|
5278
|
+
* 组件里要写(发 POST)时调用 —— 写只走这条,别在组件里自己 `fetch`。
|
|
5279
|
+
* `send` 失败自动落到 `failed` + `detail`(界面直接显示,别自己拼);`silent: true` 是不打扰:不动 `busy` / `failed`,
|
|
5280
|
+
* 结果只从返回值拿。返回的 `busy` 是这一路写有没有在飞。
|
|
5281
|
+
*/
|
|
4084
5282
|
function useHostWrite(options) {
|
|
4085
5283
|
const { channel, networkText } = options;
|
|
4086
5284
|
const route = writeRoute(channel, options.resource ?? "");
|
|
@@ -4137,15 +5335,26 @@ var use_visible_busy_exports = /* @__PURE__ */ __exportAll({
|
|
|
4137
5335
|
heldPhase: () => heldPhase,
|
|
4138
5336
|
useVisibleBusy: () => useVisibleBusy
|
|
4139
5337
|
});
|
|
5338
|
+
/**
|
|
5339
|
+
* 把“正在刷新”折进相位:`refreshing` 且已是 `ready` 记作 `loading`,让“旧值还显示、新的在路上”有名字。
|
|
5340
|
+
*/
|
|
4140
5341
|
function heldPhase(phase, refreshing) {
|
|
4141
5342
|
return refreshing && phase === "ready" ? "loading" : phase;
|
|
4142
5343
|
}
|
|
5344
|
+
/**
|
|
5345
|
+
* 由 `active` 与 `useVisibleBusy` 挂出来的 `visible` 投影出 `{ busy, settling }`;纯函数,好测。
|
|
5346
|
+
*/
|
|
4143
5347
|
function busyView(active, visible) {
|
|
4144
5348
|
return {
|
|
4145
5349
|
busy: visible,
|
|
4146
5350
|
settling: visible && !active
|
|
4147
5351
|
};
|
|
4148
5352
|
}
|
|
5353
|
+
/**
|
|
5354
|
+
* 需要“最少转一会儿”的忙态时调用:`active` 变真立刻 `busy`;变假时若这次没转满 `floorMs`,`busy` 先挂着,
|
|
5355
|
+
* 这期间 `settling` 为真表示读数在回来的路上。`floorMs` 传共享包的 `MIN_BUSY_MS`,别自己编 ——
|
|
5356
|
+
* 取数几毫秒就回来时不挂这一会儿,用户看到的是“闪一下”,比不转更难读。
|
|
5357
|
+
*/
|
|
4149
5358
|
function useVisibleBusy(active, floorMs) {
|
|
4150
5359
|
const [visible, setVisible] = useState(active);
|
|
4151
5360
|
const since = useRef(null);
|
|
@@ -4869,6 +6078,12 @@ var PanelFoot_module_default = {
|
|
|
4869
6078
|
};
|
|
4870
6079
|
//#endregion
|
|
4871
6080
|
//#region src/shared/components/PanelFoot.tsx
|
|
6081
|
+
/**
|
|
6082
|
+
* 面板底部那行脚注:左侧一句 `text`,右侧放 `children`,两样都不给就是一个空的页脚壳。
|
|
6083
|
+
* @param props.text - 左侧那句说明文字;不传时左侧什么都不渲染。
|
|
6084
|
+
* @param props.size - 文字档(默认 `'sm'`,11px 三级色;`'md'` 是 14px 二级色,给更宽的面板用)。
|
|
6085
|
+
* @param props.children - 右侧那一格内容(一般是按钮或状态),可省略。
|
|
6086
|
+
*/
|
|
4872
6087
|
function PanelFoot({ text, size = "sm", children }) {
|
|
4873
6088
|
return /* @__PURE__ */ h("footer", { className: PanelFoot_module_default.foot }, text === void 0 ? null : /* @__PURE__ */ h("span", { className: size === "md" ? PanelFoot_module_default.footTextMd : PanelFoot_module_default.footText }, text), children ?? null);
|
|
4874
6089
|
}
|
|
@@ -5379,18 +6594,30 @@ var MODULE_VERSIONS_ROUTE = "module-versions";
|
|
|
5379
6594
|
var INSTALLED_PLUGINS_ROUTE = "panels/plugins";
|
|
5380
6595
|
//#endregion
|
|
5381
6596
|
//#region src/shared/hooks/bundle-queries.ts
|
|
6597
|
+
/**
|
|
6598
|
+
* 读模块源注册表:装模块时能从哪些源取、当前解析到哪一个。
|
|
6599
|
+
*/
|
|
5382
6600
|
function readBundleRegistries() {
|
|
5383
6601
|
return apiGet(BUNDLE_REGISTRIES_ROUTE);
|
|
5384
6602
|
}
|
|
6603
|
+
/**
|
|
6604
|
+
* 装之前先看清一个 spec 是什么(收了 / 拒了 / 是个插件);`registry` 省略或空就按默认源解析。
|
|
6605
|
+
*/
|
|
5385
6606
|
function readBundleInspection(spec, registry) {
|
|
5386
6607
|
return apiGet(BUNDLE_INSPECT_ROUTE, {
|
|
5387
6608
|
spec,
|
|
5388
6609
|
...registry === void 0 || registry === "" ? {} : { registry }
|
|
5389
6610
|
});
|
|
5390
6611
|
}
|
|
6612
|
+
/**
|
|
6613
|
+
* 问模块有没有新版;`force: true` 绕过缓存重新问源(“更新”那条路用)。
|
|
6614
|
+
*/
|
|
5391
6615
|
function readModuleVersions(force = false) {
|
|
5392
6616
|
return apiGet(MODULE_VERSIONS_ROUTE, force ? { force: "1" } : void 0);
|
|
5393
6617
|
}
|
|
6618
|
+
/**
|
|
6619
|
+
* 读已装的 opencli 插件台账;`force: true` 绕过缓存重新问一遍。
|
|
6620
|
+
*/
|
|
5394
6621
|
function readInstalledPlugins(force = false) {
|
|
5395
6622
|
return apiGet(INSTALLED_PLUGINS_ROUTE, force ? { force: "1" } : void 0);
|
|
5396
6623
|
}
|
|
@@ -6178,33 +7405,30 @@ function registerMarketPanel(ctx, units) {
|
|
|
6178
7405
|
}, MarketPanel));
|
|
6179
7406
|
}
|
|
6180
7407
|
//#endregion
|
|
6181
|
-
//#region src/shared/api/diy.ts
|
|
6182
|
-
var DIY_PRESET_ID = "workbench-diy";
|
|
6183
|
-
var WORKSHOP_RELATIVE = "workbench/diy";
|
|
6184
|
-
var WORKSHOP_TITLE = "工作台DIY";
|
|
6185
|
-
var WORKSHOP_PAST_TITLES = ["DIY 工坊", "工作台自带 · DIY 模块住这儿"];
|
|
6186
|
-
function isWorkshopPath(path) {
|
|
6187
|
-
return path.replace(/\\/g, "/").replace(/\/+$/, "").endsWith(`/${WORKSHOP_RELATIVE}`);
|
|
6188
|
-
}
|
|
6189
|
-
function diyStartOptions(workspaceId, workshopId) {
|
|
6190
|
-
return workshopId !== void 0 && workshopId === workspaceId ? { agentPreset: DIY_PRESET_ID } : void 0;
|
|
6191
|
-
}
|
|
6192
|
-
//#endregion
|
|
6193
7408
|
//#region src/shared/hooks/panel-state-report.ts
|
|
6194
7409
|
var FLUSH_MS = 400;
|
|
6195
7410
|
var workspace = null;
|
|
6196
7411
|
var timer = null;
|
|
6197
7412
|
var pending = /* @__PURE__ */ new Map();
|
|
7413
|
+
/**
|
|
7414
|
+
* 从路由里切出单元 id(`cmdb/runs` → `cmdb`);切不出来(没有前缀)回 `null`。
|
|
7415
|
+
*/
|
|
6198
7416
|
function unitOfRoute(route) {
|
|
6199
7417
|
const cut = route.indexOf("/");
|
|
6200
7418
|
return cut <= 0 ? null : route.slice(0, cut);
|
|
6201
7419
|
}
|
|
7420
|
+
/**
|
|
7421
|
+
* 告诉上报这沓“现在的工作区是哪个”;换工作区会丢掉还没冲出去的待报读数。
|
|
7422
|
+
*/
|
|
6202
7423
|
function setPanelWorkspace(path) {
|
|
6203
7424
|
if (path === workspace) return;
|
|
6204
7425
|
const previous = workspace;
|
|
6205
7426
|
workspace = path;
|
|
6206
7427
|
if (previous !== null) pending.clear();
|
|
6207
7428
|
}
|
|
7429
|
+
/**
|
|
7430
|
+
* 卡片读数落地时调它(`useApiResource` 已经接好):同一单元同一条路由只留最新一条,攒一拍再一起冲给宿主。
|
|
7431
|
+
*/
|
|
6208
7432
|
function reportPanelRead(input) {
|
|
6209
7433
|
pending.set(`${input.unit}\u0000${input.route}`, {
|
|
6210
7434
|
unit: input.unit,
|
|
@@ -6216,6 +7440,9 @@ function reportPanelRead(input) {
|
|
|
6216
7440
|
if (timer !== null) return;
|
|
6217
7441
|
timer = setTimeout(flush, FLUSH_MS);
|
|
6218
7442
|
}
|
|
7443
|
+
/**
|
|
7444
|
+
* 卡片崩了时调它:`unit` 与原因立刻报给宿主(不攒);还不知道工作区时不报。
|
|
7445
|
+
*/
|
|
6219
7446
|
function reportPanelCrash(input) {
|
|
6220
7447
|
const target = workspace;
|
|
6221
7448
|
if (target === null) return;
|
|
@@ -6245,9 +7472,15 @@ var use_api_resource_exports = /* @__PURE__ */ __exportAll({
|
|
|
6245
7472
|
resourceIdentity: () => resourceIdentity,
|
|
6246
7473
|
useApiResource: () => useApiResource
|
|
6247
7474
|
});
|
|
7475
|
+
/**
|
|
7476
|
+
* 这次读的身份:`route` 加排好序的 `query`(排序是为了同一次读只有一个 key);给了 `override` 就用它。
|
|
7477
|
+
*/
|
|
6248
7478
|
function resourceIdentity(route, query, override) {
|
|
6249
7479
|
return override ?? requestKeyOf(route, query);
|
|
6250
7480
|
}
|
|
7481
|
+
/**
|
|
7482
|
+
* 把身份与两个版本号拼成合流用的 key:同一个 key 的并发读共享同一条请求。
|
|
7483
|
+
*/
|
|
6251
7484
|
function readKeyOf(identity, refreshToken, factRev) {
|
|
6252
7485
|
return `${identity}@${String(refreshToken)}@${String(factRev)}`;
|
|
6253
7486
|
}
|
|
@@ -6255,6 +7488,10 @@ function requestKeyOf(route, query) {
|
|
|
6255
7488
|
return `${route}?${Object.entries(query).filter(([, value]) => value !== void 0).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => `${key}=${String(value)}`).join("&")}`;
|
|
6256
7489
|
}
|
|
6257
7490
|
var inflight = /* @__PURE__ */ new Map();
|
|
7491
|
+
/**
|
|
7492
|
+
* 非 hook 的取数本体(要自己管缓存时才直接调):同一个 `key` 只发一次,并发调用共享同一个 `task`;
|
|
7493
|
+
* 用它就一定要 `release`(一般放 `finally`),最后一个 `release` 才 abort,否则那条请求永不取消。
|
|
7494
|
+
*/
|
|
6258
7495
|
function requestResource(route, query, key) {
|
|
6259
7496
|
const pending = inflight.get(key);
|
|
6260
7497
|
if (pending !== void 0) {
|
|
@@ -6285,6 +7522,13 @@ function release(key, entry) {
|
|
|
6285
7522
|
inflight.delete(key);
|
|
6286
7523
|
entry.controller.abort();
|
|
6287
7524
|
}
|
|
7525
|
+
/**
|
|
7526
|
+
* 卡片里所有的读都走它:按身份发一次 `apiGet`,同 key 合流、订阅事实通道(这条变了自动重取)、
|
|
7527
|
+
* 并把读数上报面板(`workbench_diy_panel` 看的就是它);身份或版本号一变就换一条读,旧的当场取消。
|
|
7528
|
+
* `options.enabled` 为 `false` 时不发请求、相位恒为 `idle`;`key` 覆盖身份、`fact` 换订阅哪条事实
|
|
7529
|
+
* (默认 `factOfRoute(route)`)、`report: false` 不上报(夹具与后台探针用)。身份没变的重取会留住上一格
|
|
7530
|
+
* 的 `value`,相位降到 `loading`。
|
|
7531
|
+
*/
|
|
6288
7532
|
function useApiResource(route, query, refreshToken, options = {}) {
|
|
6289
7533
|
const enabled = options.enabled !== false;
|
|
6290
7534
|
const identity = resourceIdentity(route, query, options.key);
|
|
@@ -6383,8 +7627,18 @@ function useApiResource(route, query, refreshToken, options = {}) {
|
|
|
6383
7627
|
}
|
|
6384
7628
|
//#endregion
|
|
6385
7629
|
//#region src/shared/hooks/use-diy-debug.ts
|
|
7630
|
+
/**
|
|
7631
|
+
* 调试约定的读路由(宿主侧那半同名)。
|
|
7632
|
+
*/
|
|
6386
7633
|
var DIY_DEBUG_ROUTE = "panels/diy-debug";
|
|
7634
|
+
/**
|
|
7635
|
+
* 调试约定那条事实的名字:写完调 `useFactInvalidate(DIY_DEBUG_FACT)`,读者自动重取。
|
|
7636
|
+
*/
|
|
6387
7637
|
var DIY_DEBUG_FACT = "diy-debug";
|
|
7638
|
+
/**
|
|
7639
|
+
* 要读“现在的调试约定是什么”时调用(左栏底部那枚状态);跟着事实变化自动重取,不上报面板;
|
|
7640
|
+
* 还没读到或后端说没有约定时都是 `null`。
|
|
7641
|
+
*/
|
|
6388
7642
|
function useDiyDebugState() {
|
|
6389
7643
|
const read = useApiResource(DIY_DEBUG_ROUTE, {}, 0, {
|
|
6390
7644
|
fact: DIY_DEBUG_FACT,
|
|
@@ -6393,6 +7647,9 @@ function useDiyDebugState() {
|
|
|
6393
7647
|
if (read.value === void 0) return null;
|
|
6394
7648
|
return read.value.state ?? null;
|
|
6395
7649
|
}
|
|
7650
|
+
/**
|
|
7651
|
+
* 要发“开始 / 暂停 / 继续 / 结束调试”那几把动作时调用;写走 `diy-debug/act` 通道。
|
|
7652
|
+
*/
|
|
6396
7653
|
function useDiyDebugAct() {
|
|
6397
7654
|
return useHostWrite({
|
|
6398
7655
|
channel: "diy-debug",
|
|
@@ -6432,32 +7689,33 @@ function subscribeBoardProbe(listener) {
|
|
|
6432
7689
|
};
|
|
6433
7690
|
}
|
|
6434
7691
|
var DebugFooterAction_module_default = {
|
|
6435
|
-
slot: "
|
|
6436
|
-
action: "
|
|
6437
|
-
live: "
|
|
6438
|
-
paused: "
|
|
6439
|
-
trouble: "
|
|
6440
|
-
pulse: "
|
|
6441
|
-
"wb-debug-breathe": "_wb-debug-
|
|
6442
|
-
entry: "
|
|
6443
|
-
entryInner: "
|
|
6444
|
-
acts: "
|
|
6445
|
-
act: "
|
|
6446
|
-
actStop: "
|
|
6447
|
-
actArmed: "
|
|
6448
|
-
actLabel: "
|
|
6449
|
-
entryLine: "
|
|
6450
|
-
actionRail: "
|
|
6451
|
-
card: "
|
|
6452
|
-
cardTitle: "
|
|
6453
|
-
cardNote: "
|
|
7692
|
+
slot: "_slot_1t7dx_1",
|
|
7693
|
+
action: "_action_1t7dx_12",
|
|
7694
|
+
live: "_live_1t7dx_31",
|
|
7695
|
+
paused: "_paused_1t7dx_35",
|
|
7696
|
+
trouble: "_trouble_1t7dx_39",
|
|
7697
|
+
pulse: "_pulse_1t7dx_43",
|
|
7698
|
+
"wb-debug-breathe": "_wb-debug-breathe_1t7dx_1",
|
|
7699
|
+
entry: "_entry_1t7dx_64",
|
|
7700
|
+
entryInner: "_entryInner_1t7dx_71",
|
|
7701
|
+
acts: "_acts_1t7dx_78",
|
|
7702
|
+
act: "_act_1t7dx_12",
|
|
7703
|
+
actStop: "_actStop_1t7dx_110",
|
|
7704
|
+
actArmed: "_actArmed_1t7dx_115",
|
|
7705
|
+
actLabel: "_actLabel_1t7dx_125",
|
|
7706
|
+
entryLine: "_entryLine_1t7dx_131",
|
|
7707
|
+
actionRail: "_actionRail_1t7dx_138",
|
|
7708
|
+
card: "_card_1t7dx_150",
|
|
7709
|
+
cardTitle: "_cardTitle_1t7dx_156",
|
|
7710
|
+
cardNote: "_cardNote_1t7dx_162"
|
|
6454
7711
|
};
|
|
6455
7712
|
//#endregion
|
|
6456
7713
|
//#region src/app/layouts/sidebar/DebugFooterAction.tsx
|
|
6457
7714
|
function debugFooterView(state, t, trouble = "none") {
|
|
6458
7715
|
const shown = state.phase === "paused" ? "none" : trouble;
|
|
6459
|
-
const
|
|
6460
|
-
const
|
|
7716
|
+
const title = state.title === "" ? t("debug.workspace") : state.title;
|
|
7717
|
+
const label = shown !== "none" ? t("debug.status.trouble", { title }) : state.phase === "paused" ? t("debug.stalled", { title }) : t("debug.status", { title });
|
|
7718
|
+
const noteOf = (kind) => kind === "panel" ? t("debug.card.hidden.note") : t("debug.card.away.note", { title });
|
|
6461
7719
|
if (state.phase === "paused") return {
|
|
6462
7720
|
label,
|
|
6463
7721
|
title: label,
|
|
@@ -6474,7 +7732,7 @@ function debugFooterView(state, t, trouble = "none") {
|
|
|
6474
7732
|
};
|
|
6475
7733
|
return {
|
|
6476
7734
|
label,
|
|
6477
|
-
title: t("debug.card.here.title"),
|
|
7735
|
+
title: t("debug.card.here.title", { title }),
|
|
6478
7736
|
note: t("debug.card.here.note"),
|
|
6479
7737
|
trouble: "none",
|
|
6480
7738
|
stalled: false
|
|
@@ -6493,16 +7751,14 @@ function DebugFooterAction({ wide, t, useWorkspaces, useSessions }) {
|
|
|
6493
7751
|
const state = useDiyDebugState();
|
|
6494
7752
|
const act = useDiyDebugAct();
|
|
6495
7753
|
const probe = useSyncExternalStore(subscribeBoardProbe, boardProbe);
|
|
6496
|
-
const
|
|
6497
|
-
const here = useBoardWorkspace(workspaces, useSessions?.((snapshot) => snapshot) ?? EMPTY_SESSIONS);
|
|
6498
|
-
const workshop = workspaces.items.find((item) => isWorkshopPath(item.path));
|
|
7754
|
+
const here = useBoardWorkspace(useWorkspaces?.((snapshot) => snapshot) ?? EMPTY_WORKSPACES, useSessions?.((snapshot) => snapshot) ?? EMPTY_SESSIONS);
|
|
6499
7755
|
const [armed, setArmed] = useState(false);
|
|
6500
7756
|
if (state === null) return null;
|
|
6501
|
-
const
|
|
7757
|
+
const workspacePath = state.workspacePath === void 0 || state.workspacePath === "" ? null : state.workspacePath;
|
|
6502
7758
|
const situation = boardSituation({
|
|
6503
7759
|
...probe,
|
|
6504
7760
|
where: here.path ?? ""
|
|
6505
|
-
},
|
|
7761
|
+
}, workspacePath);
|
|
6506
7762
|
const view = debugFooterView(state, t, situation === "off-workspace" || situation === "other-board" ? "workspace" : situation === "panel-closed" ? "panel" : "none");
|
|
6507
7763
|
const dot = /* @__PURE__ */ h(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
|
|
6508
7764
|
state: view.trouble !== "none" ? "error" : view.stalled ? "warning" : "done",
|
|
@@ -6568,6 +7824,127 @@ function registerDebugFooter(ctx) {
|
|
|
6568
7824
|
}, DebugFooterAction));
|
|
6569
7825
|
}
|
|
6570
7826
|
//#endregion
|
|
7827
|
+
//#region src/shared/hooks/use-diy-record.ts
|
|
7828
|
+
/**
|
|
7829
|
+
* 录制交接的读路由(宿主侧那半同名)。
|
|
7830
|
+
*/
|
|
7831
|
+
var DIY_RECORD_ROUTE = "panels/diy-record";
|
|
7832
|
+
/**
|
|
7833
|
+
* 录制交接那条事实的名字:写完调 `useFactInvalidate(DIY_RECORD_FACT)`,读者自动重取。
|
|
7834
|
+
*/
|
|
7835
|
+
var DIY_RECORD_FACT = "diy-record";
|
|
7836
|
+
/**
|
|
7837
|
+
* 要读“这一段录制交接进行到哪了”时调用(左栏底部那枚状态);跟着事实变化自动重取,不上报面板;
|
|
7838
|
+
* 还没读到或后端说没有交接时都是 `null`。
|
|
7839
|
+
*/
|
|
7840
|
+
function useDiyRecordState() {
|
|
7841
|
+
const read = useApiResource(DIY_RECORD_ROUTE, {}, 0, {
|
|
7842
|
+
fact: DIY_RECORD_FACT,
|
|
7843
|
+
report: false
|
|
7844
|
+
});
|
|
7845
|
+
if (read.value === void 0) return null;
|
|
7846
|
+
return read.value.state ?? null;
|
|
7847
|
+
}
|
|
7848
|
+
/**
|
|
7849
|
+
* 要发录制交接那几把动作(准备 / 读回 / 收尾)时调用;写走 `diy-record/act` 通道。
|
|
7850
|
+
*/
|
|
7851
|
+
function useDiyRecordAct() {
|
|
7852
|
+
return useHostWrite({
|
|
7853
|
+
channel: "diy-record",
|
|
7854
|
+
resource: "act",
|
|
7855
|
+
networkText: "网络不通,动作没发出去"
|
|
7856
|
+
});
|
|
7857
|
+
}
|
|
7858
|
+
var RecordFooterAction_module_default = {
|
|
7859
|
+
slot: "_slot_1gkj9_1",
|
|
7860
|
+
action: "_action_1gkj9_12",
|
|
7861
|
+
live: "_live_1gkj9_31",
|
|
7862
|
+
done: "_done_1gkj9_35",
|
|
7863
|
+
pulse: "_pulse_1gkj9_39",
|
|
7864
|
+
"wb-record-breathe": "_wb-record-breathe_1gkj9_1",
|
|
7865
|
+
entry: "_entry_1gkj9_60",
|
|
7866
|
+
entryInner: "_entryInner_1gkj9_67",
|
|
7867
|
+
acts: "_acts_1gkj9_74",
|
|
7868
|
+
act: "_act_1gkj9_12",
|
|
7869
|
+
entryLine: "_entryLine_1gkj9_108",
|
|
7870
|
+
actionRail: "_actionRail_1gkj9_115",
|
|
7871
|
+
card: "_card_1gkj9_127",
|
|
7872
|
+
cardTitle: "_cardTitle_1gkj9_133",
|
|
7873
|
+
cardNote: "_cardNote_1gkj9_139"
|
|
7874
|
+
};
|
|
7875
|
+
//#endregion
|
|
7876
|
+
//#region src/app/layouts/sidebar/RecordFooterAction.tsx
|
|
7877
|
+
function recordFooterView(state, t) {
|
|
7878
|
+
if (state.phase === "recording") return {
|
|
7879
|
+
label: t("record.recording"),
|
|
7880
|
+
note: t("record.recording.note"),
|
|
7881
|
+
acts: [{
|
|
7882
|
+
intent: "halt",
|
|
7883
|
+
label: t("record.act.halt")
|
|
7884
|
+
}]
|
|
7885
|
+
};
|
|
7886
|
+
if (state.phase === "finished") return {
|
|
7887
|
+
label: t("record.finished"),
|
|
7888
|
+
note: t("record.finished.note"),
|
|
7889
|
+
acts: []
|
|
7890
|
+
};
|
|
7891
|
+
return {
|
|
7892
|
+
label: t("record.waiting"),
|
|
7893
|
+
note: t("record.waiting.note"),
|
|
7894
|
+
acts: [{
|
|
7895
|
+
intent: "stop",
|
|
7896
|
+
label: t("record.act.cancel")
|
|
7897
|
+
}]
|
|
7898
|
+
};
|
|
7899
|
+
}
|
|
7900
|
+
function RecordFooterAction({ wide, t }) {
|
|
7901
|
+
const state = useDiyRecordState();
|
|
7902
|
+
const act = useDiyRecordAct();
|
|
7903
|
+
if (state === null) return null;
|
|
7904
|
+
const view = recordFooterView(state, t);
|
|
7905
|
+
const dot = /* @__PURE__ */ h(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
|
|
7906
|
+
state: state.phase === "finished" ? "done" : "warning",
|
|
7907
|
+
className: state.phase === "armed" ? RecordFooterAction_module_default.pulse : void 0
|
|
7908
|
+
});
|
|
7909
|
+
const tone = state.phase === "finished" ? RecordFooterAction_module_default.done : RecordFooterAction_module_default.live;
|
|
7910
|
+
const acts = /* @__PURE__ */ h("span", { className: RecordFooterAction_module_default.acts }, view.acts.map((one) => /* @__PURE__ */ h("button", {
|
|
7911
|
+
key: one.intent,
|
|
7912
|
+
type: "button",
|
|
7913
|
+
className: RecordFooterAction_module_default.act,
|
|
7914
|
+
"aria-label": one.label,
|
|
7915
|
+
onClick: (event) => {
|
|
7916
|
+
event.stopPropagation();
|
|
7917
|
+
act.send({ intent: one.intent });
|
|
7918
|
+
}
|
|
7919
|
+
}, one.label)));
|
|
7920
|
+
const status = /* @__PURE__ */ h("span", { className: RecordFooterAction_module_default.entryInner }, dot, wide === true ? /* @__PURE__ */ h("span", { className: RecordFooterAction_module_default.entryLine }, view.label) : null);
|
|
7921
|
+
const row = /* @__PURE__ */ h("div", { className: cx(RecordFooterAction_module_default.action, wide === true ? void 0 : RecordFooterAction_module_default.actionRail, tone) }, /* @__PURE__ */ h("span", {
|
|
7922
|
+
className: RecordFooterAction_module_default.entry,
|
|
7923
|
+
role: "status",
|
|
7924
|
+
"aria-label": `${view.label},${view.note}`
|
|
7925
|
+
}, wide === true ? /* @__PURE__ */ h(Tip, {
|
|
7926
|
+
label: view.note,
|
|
7927
|
+
side: "top"
|
|
7928
|
+
}, status) : status), wide === true ? acts : null);
|
|
7929
|
+
if (wide === true) return /* @__PURE__ */ h("span", { className: RecordFooterAction_module_default.slot }, row);
|
|
7930
|
+
return /* @__PURE__ */ h("span", { className: RecordFooterAction_module_default.slot }, /* @__PURE__ */ h(_deepseek_ai_dsh_client_ui_primitives.HoverCard, {
|
|
7931
|
+
anchor: row,
|
|
7932
|
+
content: /* @__PURE__ */ h("div", { className: RecordFooterAction_module_default.card }, /* @__PURE__ */ h("div", { className: RecordFooterAction_module_default.cardTitle }, view.label), /* @__PURE__ */ h("div", { className: RecordFooterAction_module_default.cardNote }, view.note), acts),
|
|
7933
|
+
openDelayMs: 200
|
|
7934
|
+
}));
|
|
7935
|
+
}
|
|
7936
|
+
//#endregion
|
|
7937
|
+
//#region src/app/layouts/sidebar/record-footer.tsx
|
|
7938
|
+
var RECORD_FOOTER_ID = "workbench-record";
|
|
7939
|
+
function registerRecordFooter(ctx) {
|
|
7940
|
+
ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
|
|
7941
|
+
name: "sidebar.footer.action",
|
|
7942
|
+
id: RECORD_FOOTER_ID,
|
|
7943
|
+
order: 11,
|
|
7944
|
+
locale: LOCALE_NS
|
|
7945
|
+
}, RecordFooterAction));
|
|
7946
|
+
}
|
|
7947
|
+
//#endregion
|
|
6571
7948
|
//#region src/shared/api/config-sync.ts
|
|
6572
7949
|
var CONFIG_SYNC_ROUTE = "config-sync";
|
|
6573
7950
|
var CONFIG_SYNC_RESOURCE = "configSync";
|
|
@@ -6819,6 +8196,18 @@ function ConfigSyncSection({ t }) {
|
|
|
6819
8196
|
}, chosen.length === 0 ? t("configSync.applyNone") : busy.busy ? t("configSync.applying") : t("configSync.apply", { count: chosen.length }))) : null) : null));
|
|
6820
8197
|
}
|
|
6821
8198
|
//#endregion
|
|
8199
|
+
//#region src/shared/api/diy.ts
|
|
8200
|
+
var DIY_PRESET_ID = "workbench-diy";
|
|
8201
|
+
var WORKSHOP_RELATIVE = "workbench/diy";
|
|
8202
|
+
var WORKSHOP_TITLE = "工作台DIY";
|
|
8203
|
+
var WORKSHOP_PAST_TITLES = ["DIY 工坊", "工作台自带 · DIY 模块住这儿"];
|
|
8204
|
+
function isWorkshopPath(path) {
|
|
8205
|
+
return path.replace(/\\/g, "/").replace(/\/+$/, "").endsWith(`/${WORKSHOP_RELATIVE}`);
|
|
8206
|
+
}
|
|
8207
|
+
function diyStartOptions(workspaceId, workshopId) {
|
|
8208
|
+
return workshopId !== void 0 && workshopId === workspaceId ? { agentPreset: DIY_PRESET_ID } : void 0;
|
|
8209
|
+
}
|
|
8210
|
+
//#endregion
|
|
6822
8211
|
//#region src/app/units/index.ts
|
|
6823
8212
|
var CLIENT_UNITS = [];
|
|
6824
8213
|
function assembleClientUnits(registry) {
|
|
@@ -7442,6 +8831,209 @@ function createBootGate(ctx, options = {}) {
|
|
|
7442
8831
|
return { close };
|
|
7443
8832
|
}
|
|
7444
8833
|
//#endregion
|
|
8834
|
+
//#region src/modules/panels/unit.ts
|
|
8835
|
+
var PANELS_LIST_TOOL = "workbench_panels_list";
|
|
8836
|
+
var PANELS_SHOW_TOOL = "workbench_panels_show";
|
|
8837
|
+
var PANELS_HIDE_TOOL = "workbench_panels_hide";
|
|
8838
|
+
var PANELS_MOVE_TOOL = "workbench_panels_move";
|
|
8839
|
+
var PANELS_RESET_TOOL = "workbench_panels_reset";
|
|
8840
|
+
var PANELS_FOLLOW_TOOL = "workbench_panels_follow";
|
|
8841
|
+
var MODULES_LIST_TOOL = "workbench_modules_list";
|
|
8842
|
+
var MODULES_INSTALL_TOOL = "workbench_modules_install";
|
|
8843
|
+
var MODULES_UPDATE_TOOL = "workbench_modules_update";
|
|
8844
|
+
var MODULES_UNINSTALL_TOOL = "workbench_modules_uninstall";
|
|
8845
|
+
var MODULES_INSTALL_BUNDLE_TOOL = "workbench_modules_install_bundle";
|
|
8846
|
+
var MODULES_UPDATE_DEPENDENCY_TOOL = "workbench_modules_update_dependency";
|
|
8847
|
+
var MODULES_UPDATE_PLUGIN_TOOL = "workbench_modules_update_plugin";
|
|
8848
|
+
var MODULES_UNINSTALL_PLUGIN_TOOL = "workbench_modules_uninstall_plugin";
|
|
8849
|
+
var MODULES_UPDATE_WORKBENCH_TOOL = "workbench_modules_update_workbench";
|
|
8850
|
+
var DIY_LIST_TOOL = "workbench_diy_list";
|
|
8851
|
+
var DIY_STATUS_TOOL = "workbench_diy_status";
|
|
8852
|
+
var DIY_PANEL_TOOL = "workbench_diy_panel";
|
|
8853
|
+
var DIY_COMPONENTS_TOOL = "workbench_diy_components";
|
|
8854
|
+
var DIY_RECON_TOOL = "workbench_diy_recon";
|
|
8855
|
+
var DIY_SPEC_TOOL = "workbench_diy_spec";
|
|
8856
|
+
var DIY_INSTALL_TOOL = "workbench_diy_install";
|
|
8857
|
+
var DIY_SHOW_TOOL = "workbench_diy_show";
|
|
8858
|
+
var DIY_STATE_TOOL = "workbench_diy_state";
|
|
8859
|
+
var DIY_HTML_TOOL = "workbench_diy_html";
|
|
8860
|
+
var DIY_FIND_TOOL = "workbench_diy_find";
|
|
8861
|
+
var DIY_CLICK_TOOL = "workbench_diy_click";
|
|
8862
|
+
var DIY_HOVER_TOOL = "workbench_diy_hover";
|
|
8863
|
+
var DIY_TYPE_TOOL = "workbench_diy_type";
|
|
8864
|
+
var DIY_FILL_TOOL = "workbench_diy_fill";
|
|
8865
|
+
var DIY_KEYS_TOOL = "workbench_diy_keys";
|
|
8866
|
+
var DIY_SCROLL_TOOL = "workbench_diy_scroll";
|
|
8867
|
+
var DIY_WAIT_TOOL = "workbench_diy_wait";
|
|
8868
|
+
var DIY_EVAL_TOOL = "workbench_diy_eval";
|
|
8869
|
+
var DIY_SCREENSHOT_TOOL = "workbench_diy_screenshot";
|
|
8870
|
+
var DIY_NETWORK_TOOL = "workbench_diy_network";
|
|
8871
|
+
var DIY_DIALOG_TOOL = "workbench_diy_dialog";
|
|
8872
|
+
var DIY_LOGS_WATCH_TOOL = "workbench_diy_logs_watch";
|
|
8873
|
+
var DIY_LOGS_READ_TOOL = "workbench_diy_logs_read";
|
|
8874
|
+
var DIY_LOGS_STOP_TOOL = "workbench_diy_logs_stop";
|
|
8875
|
+
var DIY_RECORD_PREPARE_TOOL = "workbench_diy_record_prepare";
|
|
8876
|
+
var DIY_RECORD_READ_TOOL = "workbench_diy_record_read";
|
|
8877
|
+
var DIY_RECORD_DETAIL_TOOL = "workbench_diy_record_detail";
|
|
8878
|
+
var DIY_RECORD_STOP_TOOL = "workbench_diy_record_stop";
|
|
8879
|
+
var DIY_DEBUG_START_TOOL = "workbench_diy_debug_start";
|
|
8880
|
+
var DIY_DEBUG_PAUSE_TOOL = "workbench_diy_debug_pause";
|
|
8881
|
+
var DIY_DEBUG_RESUME_TOOL = "workbench_diy_debug_resume";
|
|
8882
|
+
var DIY_DEBUG_STOP_TOOL = "workbench_diy_debug_stop";
|
|
8883
|
+
var ALL_TOOLS = [
|
|
8884
|
+
PANELS_LIST_TOOL,
|
|
8885
|
+
PANELS_SHOW_TOOL,
|
|
8886
|
+
PANELS_HIDE_TOOL,
|
|
8887
|
+
PANELS_MOVE_TOOL,
|
|
8888
|
+
PANELS_RESET_TOOL,
|
|
8889
|
+
PANELS_FOLLOW_TOOL,
|
|
8890
|
+
MODULES_LIST_TOOL,
|
|
8891
|
+
MODULES_INSTALL_TOOL,
|
|
8892
|
+
MODULES_UPDATE_TOOL,
|
|
8893
|
+
MODULES_UNINSTALL_TOOL,
|
|
8894
|
+
MODULES_INSTALL_BUNDLE_TOOL,
|
|
8895
|
+
MODULES_UPDATE_DEPENDENCY_TOOL,
|
|
8896
|
+
MODULES_UPDATE_PLUGIN_TOOL,
|
|
8897
|
+
MODULES_UNINSTALL_PLUGIN_TOOL,
|
|
8898
|
+
MODULES_UPDATE_WORKBENCH_TOOL,
|
|
8899
|
+
DIY_LIST_TOOL,
|
|
8900
|
+
DIY_STATUS_TOOL,
|
|
8901
|
+
DIY_PANEL_TOOL,
|
|
8902
|
+
DIY_COMPONENTS_TOOL,
|
|
8903
|
+
DIY_RECON_TOOL,
|
|
8904
|
+
DIY_SPEC_TOOL,
|
|
8905
|
+
DIY_INSTALL_TOOL,
|
|
8906
|
+
DIY_SHOW_TOOL,
|
|
8907
|
+
DIY_STATE_TOOL,
|
|
8908
|
+
DIY_HTML_TOOL,
|
|
8909
|
+
DIY_FIND_TOOL,
|
|
8910
|
+
DIY_CLICK_TOOL,
|
|
8911
|
+
DIY_HOVER_TOOL,
|
|
8912
|
+
DIY_TYPE_TOOL,
|
|
8913
|
+
DIY_FILL_TOOL,
|
|
8914
|
+
DIY_KEYS_TOOL,
|
|
8915
|
+
DIY_SCROLL_TOOL,
|
|
8916
|
+
DIY_WAIT_TOOL,
|
|
8917
|
+
DIY_EVAL_TOOL,
|
|
8918
|
+
DIY_SCREENSHOT_TOOL,
|
|
8919
|
+
DIY_NETWORK_TOOL,
|
|
8920
|
+
DIY_DIALOG_TOOL,
|
|
8921
|
+
DIY_LOGS_WATCH_TOOL,
|
|
8922
|
+
DIY_LOGS_READ_TOOL,
|
|
8923
|
+
DIY_LOGS_STOP_TOOL,
|
|
8924
|
+
DIY_RECORD_PREPARE_TOOL,
|
|
8925
|
+
DIY_RECORD_READ_TOOL,
|
|
8926
|
+
DIY_RECORD_DETAIL_TOOL,
|
|
8927
|
+
DIY_RECORD_STOP_TOOL,
|
|
8928
|
+
DIY_DEBUG_START_TOOL,
|
|
8929
|
+
DIY_DEBUG_PAUSE_TOOL,
|
|
8930
|
+
DIY_DEBUG_RESUME_TOOL,
|
|
8931
|
+
DIY_DEBUG_STOP_TOOL
|
|
8932
|
+
];
|
|
8933
|
+
var READ_TOOLS = [
|
|
8934
|
+
PANELS_LIST_TOOL,
|
|
8935
|
+
MODULES_LIST_TOOL,
|
|
8936
|
+
DIY_LIST_TOOL,
|
|
8937
|
+
DIY_STATUS_TOOL,
|
|
8938
|
+
DIY_PANEL_TOOL,
|
|
8939
|
+
DIY_COMPONENTS_TOOL,
|
|
8940
|
+
DIY_RECON_TOOL,
|
|
8941
|
+
DIY_SPEC_TOOL,
|
|
8942
|
+
DIY_STATE_TOOL,
|
|
8943
|
+
DIY_HTML_TOOL,
|
|
8944
|
+
DIY_FIND_TOOL,
|
|
8945
|
+
DIY_CLICK_TOOL,
|
|
8946
|
+
DIY_HOVER_TOOL,
|
|
8947
|
+
DIY_TYPE_TOOL,
|
|
8948
|
+
DIY_FILL_TOOL,
|
|
8949
|
+
DIY_KEYS_TOOL,
|
|
8950
|
+
DIY_SCROLL_TOOL,
|
|
8951
|
+
DIY_WAIT_TOOL,
|
|
8952
|
+
DIY_EVAL_TOOL,
|
|
8953
|
+
DIY_SCREENSHOT_TOOL,
|
|
8954
|
+
DIY_NETWORK_TOOL,
|
|
8955
|
+
DIY_DIALOG_TOOL,
|
|
8956
|
+
DIY_LOGS_WATCH_TOOL,
|
|
8957
|
+
DIY_LOGS_READ_TOOL,
|
|
8958
|
+
DIY_LOGS_STOP_TOOL,
|
|
8959
|
+
DIY_RECORD_READ_TOOL,
|
|
8960
|
+
DIY_RECORD_DETAIL_TOOL,
|
|
8961
|
+
DIY_RECORD_STOP_TOOL
|
|
8962
|
+
];
|
|
8963
|
+
var WRITE_TOOLS = [
|
|
8964
|
+
PANELS_SHOW_TOOL,
|
|
8965
|
+
PANELS_HIDE_TOOL,
|
|
8966
|
+
PANELS_MOVE_TOOL,
|
|
8967
|
+
PANELS_RESET_TOOL,
|
|
8968
|
+
PANELS_FOLLOW_TOOL,
|
|
8969
|
+
MODULES_INSTALL_TOOL,
|
|
8970
|
+
MODULES_UPDATE_TOOL,
|
|
8971
|
+
MODULES_UNINSTALL_TOOL,
|
|
8972
|
+
MODULES_INSTALL_BUNDLE_TOOL,
|
|
8973
|
+
MODULES_UPDATE_DEPENDENCY_TOOL,
|
|
8974
|
+
MODULES_UPDATE_PLUGIN_TOOL,
|
|
8975
|
+
MODULES_UNINSTALL_PLUGIN_TOOL,
|
|
8976
|
+
MODULES_UPDATE_WORKBENCH_TOOL,
|
|
8977
|
+
DIY_INSTALL_TOOL,
|
|
8978
|
+
DIY_SHOW_TOOL,
|
|
8979
|
+
DIY_RECORD_PREPARE_TOOL,
|
|
8980
|
+
DIY_DEBUG_START_TOOL,
|
|
8981
|
+
DIY_DEBUG_PAUSE_TOOL,
|
|
8982
|
+
DIY_DEBUG_RESUME_TOOL,
|
|
8983
|
+
DIY_DEBUG_STOP_TOOL
|
|
8984
|
+
];
|
|
8985
|
+
[...READ_TOOLS.map((name) => ({
|
|
8986
|
+
name,
|
|
8987
|
+
writes: false
|
|
8988
|
+
})), ...WRITE_TOOLS.map((name) => ({
|
|
8989
|
+
name,
|
|
8990
|
+
writes: true
|
|
8991
|
+
}))];
|
|
8992
|
+
//#endregion
|
|
8993
|
+
//#region src/app/layouts/approval-detail.tsx
|
|
8994
|
+
function textOf(args, key) {
|
|
8995
|
+
const value = args[key];
|
|
8996
|
+
return typeof value === "string" ? value.replace(/\s+/g, " ").trim() : "";
|
|
8997
|
+
}
|
|
8998
|
+
function recordApprovalRows(args, t) {
|
|
8999
|
+
const unit = textOf(args, "unit");
|
|
9000
|
+
const doing = textOf(args, "doing");
|
|
9001
|
+
const url = textOf(args, "url");
|
|
9002
|
+
return [
|
|
9003
|
+
{
|
|
9004
|
+
label: t("approval.record.site"),
|
|
9005
|
+
value: url === "" ? t("approval.record.noUrl") : url
|
|
9006
|
+
},
|
|
9007
|
+
{
|
|
9008
|
+
label: t("approval.record.what"),
|
|
9009
|
+
value: doing === "" ? t("approval.record.oneAction") : `「${doing}」`
|
|
9010
|
+
},
|
|
9011
|
+
{
|
|
9012
|
+
label: t("approval.record.lands"),
|
|
9013
|
+
value: `shots/rec-${unit === "" ? "<unit>" : unit}.jsonl`
|
|
9014
|
+
}
|
|
9015
|
+
];
|
|
9016
|
+
}
|
|
9017
|
+
function shellClaimsApprovalDetail(tool) {
|
|
9018
|
+
return ALL_TOOLS.includes(tool);
|
|
9019
|
+
}
|
|
9020
|
+
function shellApprovalPlan(input, t) {
|
|
9021
|
+
if (input.tool === "workbench_diy_record_prepare") return {
|
|
9022
|
+
rows: recordApprovalRows(input.args, t),
|
|
9023
|
+
warn: t("approval.record.noSwitch")
|
|
9024
|
+
};
|
|
9025
|
+
return shellClaimsApprovalDetail(input.tool) ? { rows: [] } : void 0;
|
|
9026
|
+
}
|
|
9027
|
+
function shellApprovalDetail(input, t) {
|
|
9028
|
+
const plan = shellApprovalPlan(input, t);
|
|
9029
|
+
if (plan === void 0) return void 0;
|
|
9030
|
+
if (plan.rows.length === 0) return h(Fragment, null);
|
|
9031
|
+
return /* @__PURE__ */ h(ApprovalPlan, {
|
|
9032
|
+
rows: plan.rows,
|
|
9033
|
+
warn: plan.warn
|
|
9034
|
+
});
|
|
9035
|
+
}
|
|
9036
|
+
//#endregion
|
|
7445
9037
|
//#region src/app/layouts/rightbar/store.ts
|
|
7446
9038
|
var browserPersistence = {
|
|
7447
9039
|
readFlag,
|
|
@@ -8827,12 +10419,19 @@ var context_chips_exports = /* @__PURE__ */ __exportAll({
|
|
|
8827
10419
|
installContextChips: () => installContextChips,
|
|
8828
10420
|
serializeChipRef: () => serializeChipRef
|
|
8829
10421
|
});
|
|
10422
|
+
/**
|
|
10423
|
+
* 对话 `@` 引用源报名用的名字:引用、lexicon 与编解码都挂在这个 source 名下。
|
|
10424
|
+
*/
|
|
8830
10425
|
var CONTEXT_SOURCE = "workbench";
|
|
8831
10426
|
var runtime = null;
|
|
8832
10427
|
var inserted = /* @__PURE__ */ new Set();
|
|
8833
10428
|
var lexiconListeners = /* @__PURE__ */ new Set();
|
|
8834
10429
|
var INSERT_RETRY_MAX = 5;
|
|
8835
10430
|
var INSERT_RETRY_DELAY_MS = 80;
|
|
10431
|
+
/**
|
|
10432
|
+
* 外壳启动、拿到 dsh 的 client context 之后调一次:把 `@` 引用源注册进对话输入框;
|
|
10433
|
+
* dsh 没给 `inputTriggers` 时不装、也不报错。
|
|
10434
|
+
*/
|
|
8836
10435
|
function installContextChips(ctx, deps) {
|
|
8837
10436
|
runtime = {
|
|
8838
10437
|
ctx,
|
|
@@ -8856,6 +10455,10 @@ function installContextChips(ctx, deps) {
|
|
|
8856
10455
|
}
|
|
8857
10456
|
}), "dsh-workbench: 对话引用源");
|
|
8858
10457
|
}
|
|
10458
|
+
/**
|
|
10459
|
+
* 要往当前对话输入框插一条 `@` 引用时调用(卡片上“发到对话”那类动作):同步返回,只反映当场这一拍 ——
|
|
10460
|
+
* 没插进去会自己再试几拍,后面成功了也不会回头改这个返回值。没装过 / 没会话 / 拿不到输入框都回 `unavailable`。
|
|
10461
|
+
*/
|
|
8859
10462
|
function addContextChip(ref, label) {
|
|
8860
10463
|
const here = runtime;
|
|
8861
10464
|
if (here === null) return "unavailable";
|
|
@@ -8903,6 +10506,9 @@ function addContextChip(ref, label) {
|
|
|
8903
10506
|
attempt(INSERT_RETRY_MAX);
|
|
8904
10507
|
return settled;
|
|
8905
10508
|
}
|
|
10509
|
+
/**
|
|
10510
|
+
* 把编好的引用串码成带 `@` 的标记文本(输入框里显示与复制到剪贴板都是这一份);认不出的串原样加个 `@`。
|
|
10511
|
+
*/
|
|
8906
10512
|
function serializeChipRef(encoded) {
|
|
8907
10513
|
const at = encoded.indexOf(":");
|
|
8908
10514
|
const kind = at > 0 ? encoded.slice(0, at) : "";
|
|
@@ -9798,7 +11404,7 @@ var scale_default = ":root {\n --wb-dur-0-12: 0.12s;\n --wb-dur-0-9: 0.9s;\n
|
|
|
9798
11404
|
var sidebar_app_default = ".wb-wsSection {\n position: relative;\n flex: none;\n --dsh-session-list-edge-inset: var(--dsh-sidebar-inline-padding);\n --dsh-session-list-scrollbar-width: 5px;\n --dsh-session-list-scrollbar-offset: 2px;\n margin: 0 var(--dsh-session-list-scrollbar-offset) var(--wb-len-4) 0;\n padding-right: calc( var(--dsh-session-list-edge-inset) - var(--dsh-session-list-scrollbar-width) - var(--dsh-session-list-scrollbar-offset) );\n}.wb-sectionHeader {\n box-sizing: border-box;\n display: flex;\n justify-content: flex-start;\n align-items: center;\n gap: var(--wb-len-4);\n height: var(--wb-len-36);\n flex: none;\n margin-bottom: var(--wb-len-4);\n padding-left: var(--wb-len-8);\n padding-right: var(--wb-len-2);\n border-radius: var(--dsw-radius-md);\n color: var(--dsw-alias-label-tertiary);\n overflow: hidden;\n}.wb-wsNew {\n margin-left: auto;\n}.wb-sectionLabel {\n flex: none;\n min-width: 0;\n max-width: 45%;\n overflow: hidden;\n white-space: nowrap;\n line-height: var(--wb-line-20);\n}.wb-collapsed .wb-wsSection {\n margin: 0 0 var(--wb-len-12);\n padding-right: 0;\n}.wb-collapsed .wb-sectionHeader {\n justify-content: flex-start;\n gap: 0;\n margin-bottom: 0;\n padding-left: 0;\n padding-right: 0;\n}.wb-collapsed .wb-wsNew {\n margin-left: 0;\n}.wb-sessions {\n --dsh-session-list-edge-inset: var(--dsh-sidebar-inline-padding);\n --dsh-session-list-scrollbar-width: 5px;\n --dsh-session-list-scrollbar-offset: 2px;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n margin-left: var(--wb-len-neg-4);\n margin-right: var(--dsh-session-list-scrollbar-offset);\n padding-left: var(--wb-len-4);\n padding-right: calc( var(--dsh-session-list-edge-inset) - var(--dsh-session-list-scrollbar-width) - var(--dsh-session-list-scrollbar-offset) );\n padding-bottom: var(--wb-len-16);\n scrollbar-gutter: stable;\n --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);\n --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);\n}.wb-sessions.wb-fadeTop {\n mask-image: linear-gradient(\n to bottom,\n transparent 0,\n var(--wb-static-mask-opaque) var(--wb-len-24),\n var(--wb-static-mask-opaque) 100%\n );\n}.wb-sessions.wb-fadeBottom {\n mask-image: linear-gradient(\n to bottom,\n var(--wb-static-mask-opaque) 0,\n var(--wb-static-mask-opaque) calc(100% - var(--wb-len-24)),\n transparent 100%\n );\n}.wb-sessions.wb-fadeTop.wb-fadeBottom {\n mask-image: linear-gradient(\n to bottom,\n transparent 0,\n var(--wb-static-mask-opaque) var(--wb-len-24),\n var(--wb-static-mask-opaque) calc(100% - var(--wb-len-24)),\n transparent 100%\n );\n}.wb-sessions > * {\n flex: none;\n}.wb-sessions > * + * {\n margin-top: var(--wb-len-2);\n}.wb-sessionLeading {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-16);\n height: var(--wb-len-20);\n color: var(--dsw-alias-label-tertiary);\n}.wb-sessionPin {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-16);\n height: var(--wb-len-20);\n margin-left: var(--wb-len-6);\n color: var(--dsw-alias-label-caption);\n}.wb-rowActions {\n flex: none;\n display: none;\n align-items: center;\n gap: var(--wb-len-15);\n}.wb-rowActions .wb-iconButton {\n width: var(--wb-len-16);\n height: var(--wb-len-16);\n border-radius: var(--dsw-radius-xs);\n color: var(--dsw-alias-label-tertiary);\n}.wb-rowActions .wb-iconButton:hover {\n background: transparent;\n color: var(--dsw-alias-label-primary);\n}.wb-sessionRow:hover .wb-rowActions,\n.wb-sessionRow.wb-menuOpen .wb-rowActions {\n display: inline-flex;\n}.wb-sessionRow:hover .wb-sessionTime,\n.wb-sessionRow.wb-menuOpen .wb-sessionTime,\n.wb-sessionRow:hover .wb-sessionPin,\n.wb-sessionRow.wb-menuOpen .wb-sessionPin {\n display: none;\n}.wb-sessionRow.wb-menuOpen {\n background: var(--dsw-alias-interactive-bg-hover);\n}.wb-sessionRow {\n position: relative;\n flex: none;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: 0;\n width: 100%;\n height: var(--wb-len-32);\n padding: 0 var(--wb-len-8);\n border: none;\n border-radius: var(--dsw-radius-md);\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n text-align: left;\n cursor: pointer;\n user-select: none;\n}.wb-sessionRow:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}.wb-sessionRow:focus-visible {\n outline: var(--dsw-focus-ring-width) solid\n var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: -2px;\n}.wb-visuallyHidden {\n clip: rect(0 0 0 0);\n white-space: nowrap;\n width: var(--wb-len-1);\n height: var(--wb-len-1);\n position: absolute;\n overflow: hidden;\n}.wb-sessionTitle {\n flex: 1;\n min-width: 0;\n margin: 0 var(--wb-len-6) 0 var(--wb-len-4);\n font-size: var(--wb-font-row);\n line-height: var(--wb-line-20);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}.wb-sessionTitle[data-scrolled] {\n mask-image: linear-gradient(90deg, transparent, var(--wb-static-mask-opaque) var(--wb-len-12));\n}.wb-sessionTitle[data-clipped] {\n mask-image: linear-gradient(270deg, transparent, var(--wb-static-mask-opaque) var(--wb-len-12));\n}.wb-sessionTitle[data-scrolled][data-clipped] {\n mask-image: linear-gradient(\n 90deg,\n transparent,\n var(--wb-static-mask-opaque) var(--wb-len-12) calc(100% - var(--wb-len-12)),\n transparent\n );\n}@media (hover: hover) {\n .wb-sessionRow:hover .wb-sessionTitle,\n .wb-sessionRow.wb-menuOpen .wb-sessionTitle {\n text-overflow: clip;\n }\n}.wb-sessionHover {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-8);\n}.wb-sessionHoverTitle {\n color: var(--dsw-static-neutral-bluish-00);\n font-size: var(--dsw-font-s-14-font-size);\n line-height: var(--wb-line-20);\n overflow-wrap: break-word;\n}.wb-sessionHoverTime {\n color: var(--dsw-static-neutral-bluish-300);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-16);\n}.wb-sessionHoverStatus {\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n color: var(--dsw-static-neutral-bluish-400);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-20);\n}.wb-sessionTime {\n flex: none;\n font-size: var(--wb-font-10);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n}.wb-workspaceBusy {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n margin: var(--wb-len-4) var(--wb-len-8) 0;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n}.wb-workspaceError {\n margin: var(--wb-len-4) var(--wb-len-8) 0;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-state-error-primary);\n}.wb-empty {\n padding: var(--wb-len-16) var(--wb-len-12);\n font-size: var(--dsw-font-xs-13-font-size);\n color: var(--dsw-alias-label-tertiary);\n}.wb-sessionRow.wb-selected {\n background: var(--dsw-alias-interactive-bg-hover);\n}.wb-panelTag {\n flex: none;\n margin-left: auto;\n}.wb-panelGlyph {\n position: relative;\n}.wb-panelDot {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n top: var(--wb-len-neg-3);\n right: var(--wb-len-neg-3);\n}button.pXSMma_workspace {\n display: none;\n}";
|
|
9799
11405
|
//#endregion
|
|
9800
11406
|
//#region src/shared/styles/sidebar.css?raw
|
|
9801
|
-
var sidebar_default = ".wb-root{--dsh-sidebar-inline-padding:12px;height:100%;padding:var(--wb-len-6) var(--dsh-sidebar-inline-padding);box-sizing:border-box;background:var(--dsw-specific-sidebar-fill);color:var(--dsw-alias-label-primary);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);flex-direction:column;font-size:var(--dsw-font-s-14-font-size);display:flex}[data-platform=darwin] .wb-root{background:0 0}.wb-root.wb-collapsed{padding:var(--wb-len-18) var(--wb-len-10) var(--wb-len-6)}[data-windows-titlebar] .wb-root .wb-logoRow{height:var(--wb-len-40);margin:0;padding:0}[data-windows-titlebar] .wb-toggle{top:calc((var(--dsh-windows-titlebar-height) - var(--wb-len-28)) / 2);z-index:var(--wb-z-30);-webkit-app-region:no-drag;position:fixed;left:var(--wb-len-12)}[data-windows-titlebar] .wb-root.wb-collapsed .wb-logoRow{height:0}[data-windows-titlebar] .wb-root:not(.wb-collapsed) .wb-brand{padding-left:var(--wb-len-4)}[data-windows-titlebar] .wb-brandIdentity{transform:translateY(1px)}[data-windows-titlebar] .wb-brandMark{transform:translate(1px)}[data-windows-titlebar] .wb-brandName{font-weight:400}[data-windows-titlebar] .wb-root.wb-collapsed{padding:0}[data-windows-titlebar] .wb-collapsed .wb-panelList,[data-windows-titlebar] .wb-collapsed .wb-regionArea,[data-windows-titlebar] .wb-collapsed .wb-footArea{display:none}html[data-windows-titlebar]:has([data-sidebar-collapsed=true]){--dsh-windows-menu-start:84px}[data-windows-titlebar] .wb-collapsed .wb-toggle{corner-shape:round;width:var(--wb-len-28);height:var(--wb-len-28);color:var(--dsw-alias-label-secondary);border-radius:50%}[data-windows-titlebar] .wb-collapsed .wb-toggle .wb-panelIcon{display:inline-flex}.wb-logoRow{box-sizing:border-box;flex:none;justify-content:flex-end;align-items:center;gap:var(--wb-len-8);height:var(--wb-len-60);margin-bottom:var(--wb-len-4);padding:var(--wb-len-8) 0 var(--wb-len-8) var(--wb-len-4);display:flex;overflow:hidden}.wb-collapsed .wb-logoRow{justify-content:flex-start;height:var(--wb-len-36);margin-bottom:var(--wb-len-12);padding:0;overflow:visible}.wb-brand{min-width:0;color:inherit;cursor:pointer;background:0 0;border:none;flex:1;align-items:center;padding:0;display:inline-flex;overflow:hidden}[data-platform=darwin] .wb-brand{cursor:default}.wb-brandIdentity{align-items:center;gap:var(--wb-len-8);min-width:0;height:var(--wb-len-24);display:inline-flex}.wb-brandMark{flex:none;justify-content:center;align-items:center;display:inline-flex}.wb-brandName{letter-spacing:var(--wb-track-brand);align-items:center;gap:var(--wb-len-6);min-width:0;height:var(--wb-len-24);font-size:var(--wb-font-18);font-weight:600;line-height:var(--wb-line-24);display:inline-flex}.wb-panelIcon{display:inline-flex;align-items:center;justify-content:center}.wb-iconButton{border-radius:var(--dsw-radius-sm);cursor:pointer;width:var(--wb-len-28);height:var(--wb-len-28);color:var(--dsw-alias-label-secondary);background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex;position:relative}.wb-iconButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.wb-iconButton.wb-toggle:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-2px}.wb-collapsed .wb-iconButton{border-radius:var(--dsw-radius-md);width:var(--wb-len-36);height:var(--wb-len-36)}.wb-collapsed .wb-toggle .wb-panelIcon{display:none}.wb-collapsed .wb-toggle:hover .wb-panelIcon{display:inline}.wb-collapsed .wb-toggle:hover .wb-railMark{display:none}.wb-railMark{justify-content:center;align-items:center;display:inline-flex}.wb-collapsed .wb-iconButton{color:var(--dsw-alias-label-primary)}.wb-panelList{flex-direction:column;flex:none;gap:var(--wb-len-4);margin-bottom:var(--wb-len-8);display:flex}.wb-panelRow{box-sizing:border-box;border-radius:var(--dsw-radius-md);min-height:var(--wb-len-36);color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:var(--wb-len-8);margin:0 var(--wb-len-2);padding:var(--wb-len-7) var(--wb-len-8);line-height:var(--wb-line-22);display:flex}.wb-panelRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.wb-panelRow.wb-panelActive{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.wb-panelRow:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-2px}.wb-panelGlyph{flex:none;justify-content:center;align-items:center;display:inline-flex}.wb-panelTitle{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.wb-collapsed .wb-panelList{gap:var(--wb-len-12);margin-bottom:var(--wb-len-12)}.wb-collapsed .wb-panelRow{width:var(--wb-len-36);height:var(--wb-len-36);color:var(--dsw-alias-label-primary);justify-content:center;margin:0;padding:0}.wb-regionArea{min-height:0;margin-left:var(--wb-len-neg-4);margin-right:calc(-1 * var(--dsh-sidebar-inline-padding));flex-direction:column;flex:1;padding-left:var(--wb-len-4);display:flex;overflow:hidden}.wb-collapsed .wb-regionArea{margin-left:0;margin-right:0;padding-left:0}.wb-footArea{flex-direction:column;flex:none;display:flex}.wb-settingsArea,.wb-footerActions{flex:none;width:100%;min-width:0}.wb-footerActions{display:flex}.wb-collapsed .wb-footArea{align-items:center}.wb-collapsed .wb-settingsArea,.wb-collapsed .wb-footerActions{justify-content:center;width:auto;display:flex}\n";
|
|
11407
|
+
var sidebar_default = ".wb-root{--dsh-sidebar-inline-padding:12px;height:100%;padding:var(--wb-len-6) var(--dsh-sidebar-inline-padding);box-sizing:border-box;background:var(--dsw-specific-sidebar-fill);color:var(--dsw-alias-label-primary);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);flex-direction:column;font-size:var(--dsw-font-s-14-font-size);display:flex}[data-platform=darwin] .wb-root{background:0 0}.wb-root.wb-collapsed{padding:var(--wb-len-18) var(--wb-len-10) var(--wb-len-6)}[data-windows-titlebar] .wb-root .wb-logoRow{height:var(--wb-len-40);margin:0;padding:0}[data-windows-titlebar] .wb-toggle{top:calc((var(--dsh-windows-titlebar-height) - var(--wb-len-28)) / 2);z-index:var(--wb-z-30);-webkit-app-region:no-drag;position:fixed;left:var(--wb-len-12)}[data-windows-titlebar] .wb-root.wb-collapsed .wb-logoRow{height:0}[data-windows-titlebar] .wb-root:not(.wb-collapsed) .wb-brand{padding-left:var(--wb-len-4)}[data-windows-titlebar] .wb-brandIdentity{transform:translateY(1px)}[data-windows-titlebar] .wb-brandMark{transform:translate(1px)}[data-windows-titlebar] .wb-brandName{font-weight:400}[data-windows-titlebar] .wb-root.wb-collapsed{padding:0}[data-windows-titlebar] .wb-collapsed .wb-panelList,[data-windows-titlebar] .wb-collapsed .wb-regionArea,[data-windows-titlebar] .wb-collapsed .wb-footArea{display:none}html[data-windows-titlebar]:has([data-sidebar-collapsed=true]){--dsh-windows-menu-start:84px}[data-windows-titlebar] .wb-collapsed .wb-toggle{corner-shape:round;width:var(--wb-len-28);height:var(--wb-len-28);color:var(--dsw-alias-label-secondary);border-radius:50%}[data-windows-titlebar] .wb-collapsed .wb-toggle .wb-panelIcon{display:inline-flex}.wb-logoRow{box-sizing:border-box;flex:none;justify-content:flex-end;align-items:center;gap:var(--wb-len-8);height:var(--wb-len-60);margin-bottom:var(--wb-len-4);padding:var(--wb-len-8) 0 var(--wb-len-8) var(--wb-len-4);display:flex;overflow:hidden}.wb-collapsed .wb-logoRow{justify-content:flex-start;height:var(--wb-len-36);margin-bottom:var(--wb-len-12);padding:0;overflow:visible}.wb-brand{min-width:0;color:inherit;cursor:pointer;background:0 0;border:none;flex:1;align-items:center;padding:0;display:inline-flex;overflow:hidden}[data-platform=darwin] .wb-brand{cursor:default}.wb-brandIdentity{align-items:center;gap:var(--wb-len-8);min-width:0;height:var(--wb-len-24);display:inline-flex}.wb-brandMark{flex:none;justify-content:center;align-items:center;display:inline-flex}.wb-brandName{letter-spacing:var(--wb-track-brand);align-items:center;gap:var(--wb-len-6);min-width:0;height:var(--wb-len-24);font-size:var(--wb-font-18);font-weight:600;line-height:var(--wb-line-24);display:inline-flex}.wb-panelIcon{display:inline-flex;align-items:center;justify-content:center}.wb-iconButton{border-radius:var(--dsw-radius-sm);cursor:pointer;width:var(--wb-len-28);height:var(--wb-len-28);color:var(--dsw-alias-label-secondary);background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex;position:relative}.wb-iconButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.wb-iconButton.wb-toggle:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-2px}.wb-collapsed .wb-iconButton{border-radius:var(--dsw-radius-md);width:var(--wb-len-36);height:var(--wb-len-36)}.wb-collapsed .wb-toggle .wb-panelIcon{display:none}.wb-collapsed .wb-toggle:hover .wb-panelIcon{display:inline}.wb-collapsed .wb-toggle:hover .wb-railMark{display:none}.wb-railMark{justify-content:center;align-items:center;display:inline-flex}.wb-collapsed .wb-iconButton{color:var(--dsw-alias-label-primary)}.wb-panelList{flex-direction:column;flex:none;gap:var(--wb-len-4);margin-bottom:var(--wb-len-8);display:flex}.wb-panelRow{box-sizing:border-box;border-radius:var(--dsw-radius-md);min-height:var(--wb-len-36);color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:var(--wb-len-8);margin:0 var(--wb-len-2);padding:var(--wb-len-7) var(--wb-len-8);line-height:var(--wb-line-22);display:flex}.wb-panelRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.wb-panelRow.wb-panelActive{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.wb-panelRow:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-2px}.wb-panelGlyph{flex:none;justify-content:center;align-items:center;display:inline-flex}.wb-panelTitle{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.wb-collapsed .wb-panelList{gap:var(--wb-len-12);margin-bottom:var(--wb-len-12)}.wb-collapsed .wb-panelRow{width:var(--wb-len-36);height:var(--wb-len-36);color:var(--dsw-alias-label-primary);justify-content:center;margin:0;padding:0}.wb-regionArea{min-height:0;margin-left:var(--wb-len-neg-4);margin-right:calc(-1 * var(--dsh-sidebar-inline-padding));flex-direction:column;flex:1;padding-left:var(--wb-len-4);display:flex;overflow:hidden}.wb-collapsed .wb-regionArea{margin-left:0;margin-right:0;padding-left:0}.wb-footArea{flex-direction:column;flex:none;display:flex}.wb-settingsArea,.wb-footerActions{flex:none;width:100%;min-width:0}.wb-footerActions{display:flex;flex-wrap:wrap;row-gap:var(--wb-len-6)}.wb-collapsed .wb-footArea{align-items:center}.wb-collapsed .wb-settingsArea,.wb-collapsed .wb-footerActions{justify-content:center;width:auto;display:flex}\n";
|
|
9802
11408
|
//#endregion
|
|
9803
11409
|
//#region src/shared/styles/chrome.css?raw
|
|
9804
11410
|
var chrome_default = ".wb-stripButton {\n width: var(--wb-len-28);\n height: var(--wb-len-28);\n padding: 0;\n color: var(--dsw-alias-label-secondary);\n}.wb-stripIconFlip {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n transform: scaleX(-1);\n}.wb-stripButton:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}.wb-stripButton:disabled {\n cursor: default;\n opacity: 1;\n}.wb-stripButtonActive {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}@keyframes wb-spin {\n from {\n transform: rotate(0deg);\n }to {\n transform: rotate(360deg);\n }}";
|
|
@@ -9811,6 +11417,10 @@ var motion_default = "[data-animating],\n[data-sidebar-right-panel] {\n --ds-tr
|
|
|
9811
11417
|
//#endregion
|
|
9812
11418
|
//#region src/shared/hooks/use-card-summary.ts
|
|
9813
11419
|
var use_card_summary_exports = /* @__PURE__ */ __exportAll({ useCardSummary: () => useCardSummary });
|
|
11420
|
+
/**
|
|
11421
|
+
* 自己搭卡片、要把 `{ refreshing, at }` 在变化时交给调用点上报面板时调用;`onSummary` 要稳定引用
|
|
11422
|
+
* (一般 `useCallback`),否则每次渲染都会上报一次。`useUnitBoard` 已经把这条接好。
|
|
11423
|
+
*/
|
|
9814
11424
|
function useCardSummary(onSummary, summary) {
|
|
9815
11425
|
const { refreshing } = summary;
|
|
9816
11426
|
const at = summary.at ?? null;
|
|
@@ -9828,6 +11438,11 @@ function useCardSummary(onSummary, summary) {
|
|
|
9828
11438
|
//#endregion
|
|
9829
11439
|
//#region src/shared/hooks/use-long-task.ts
|
|
9830
11440
|
var use_long_task_exports = /* @__PURE__ */ __exportAll({ useLongTask: () => useLongTask });
|
|
11441
|
+
/**
|
|
11442
|
+
* 卡片要轮询长任务那一行时调用:有在跑的(`running` / `needs-login`)按 `longTaskPollMs` 走快档、空闲走慢档;
|
|
11443
|
+
* `workspace` 为 `null`、`mocked: true` 或 `enabled: false` 时不轮。换单元 / 换工作区就是换读数身份,
|
|
11444
|
+
* 旧那批立刻清空、读数回来前 `runs` 是空数组。
|
|
11445
|
+
*/
|
|
9831
11446
|
function useLongTask(options) {
|
|
9832
11447
|
const enabled = options.enabled !== false && options.mocked !== true && options.workspace !== null;
|
|
9833
11448
|
const [tick, setTick] = useState(0);
|
|
@@ -9843,6 +11458,10 @@ function useLongTask(options) {
|
|
|
9843
11458
|
//#endregion
|
|
9844
11459
|
//#region src/shared/hooks/use-unit-board.ts
|
|
9845
11460
|
var use_unit_board_exports = /* @__PURE__ */ __exportAll({ useUnitBoard: () => useUnitBoard });
|
|
11461
|
+
/**
|
|
11462
|
+
* 卡片起步就用它:把“gate 不放行就不读”、忙 / 安定(按 `MIN_BUSY_MS` 挂最短可见时长)、读数报错时
|
|
11463
|
+
* 自动 `forceProbe`、`useCardSummary` 上报面板、blocker 拆分一次叠好。`read(gated)` 里自己调 `useApiResource`。
|
|
11464
|
+
*/
|
|
9846
11465
|
function useUnitBoard(options) {
|
|
9847
11466
|
const { gate, onRefresh, onSummary, t } = options;
|
|
9848
11467
|
const feed = options.read(gate.gated && options.enabled !== false);
|
|
@@ -9880,6 +11499,11 @@ function useUnitBoard(options) {
|
|
|
9880
11499
|
}
|
|
9881
11500
|
//#endregion
|
|
9882
11501
|
//#region src/shared/hooks/use-blocker-actions.ts
|
|
11502
|
+
/**
|
|
11503
|
+
* `<BlockerState>` 用它把 blocker 的动作接到实处:`retry` 与修复成功后的重试走 `onRetry`、`run-fix` 走 provision
|
|
11504
|
+
* 写通道、`copy` 写剪贴板、`open-url` 开新窗;`open-market` 没给 `onOpenMarket` 时退回 `onRetry`。
|
|
11505
|
+
* 自己画 blocker 那一块才直接用。
|
|
11506
|
+
*/
|
|
9883
11507
|
function useBlockerActions(onRetry, onOpenMarket) {
|
|
9884
11508
|
const [copied, setCopied] = useState(null);
|
|
9885
11509
|
const [running, setRunning] = useState(null);
|
|
@@ -9962,6 +11586,15 @@ var BlockerState_module_default = {
|
|
|
9962
11586
|
//#endregion
|
|
9963
11587
|
//#region src/shared/components/BlockerState.tsx
|
|
9964
11588
|
var BlockerState_exports = /* @__PURE__ */ __exportAll({ BlockerState: () => BlockerState });
|
|
11589
|
+
/**
|
|
11590
|
+
* 卡片被挡住(或要给一句 notice)时渲染的那一块:按 `blocker.severity` 出块状或一行提示,动作接重试 / 跑修复 / 复制。
|
|
11591
|
+
* @param props.blocker - 要显示的那份 blocker:`title` / `hint` / `detail` / `actions` / `severity`。
|
|
11592
|
+
* @param props.t - 翻译函数,这一块出现的每句话都从它来。
|
|
11593
|
+
* @param props.onRetry - `retry` 动作与修复成功后的重试回调。
|
|
11594
|
+
* @param props.onOpenMarket - `open-market` 动作;没给就退回 `onRetry`。
|
|
11595
|
+
* @param props.busy - 外层是不是在忙(默认 `false`);为真时动作一并禁用。
|
|
11596
|
+
* @param props.flush - 是否贴着容器边(默认 `false`):去掉图标、收窄留白,给卡片内嵌用。
|
|
11597
|
+
*/
|
|
9965
11598
|
function BlockerState({ blocker, t, onRetry, busy = false, flush = false, onOpenMarket }) {
|
|
9966
11599
|
const { run, copied, running, failure } = useBlockerActions(onRetry, onOpenMarket);
|
|
9967
11600
|
const [rawOpen, setRawOpen] = useState(false);
|
|
@@ -10055,7 +11688,7 @@ function messagesOf(units) {
|
|
|
10055
11688
|
...face.messages === void 0 ? {} : { messages: face.messages }
|
|
10056
11689
|
}));
|
|
10057
11690
|
}
|
|
10058
|
-
var COMPONENT_CSS_MARKER = "\n.wb-activityBlock {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-6);\n padding-top: var(--wb-len-10);\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n\n.wb-activityBlock:first-child {\n padding-top: 0;\n border-top: none;\n}\n\n.wb-activityBlockHead {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--wb-len-8);\n}\n\n.wb-activityLine {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-secondary);\n}\n\n.wb-activityLineText {\n flex: none;\n min-width: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n max-height: var(--wb-len-72);\n overflow-y: auto;\n}\n\n.wb-activityLineAt {\n flex: none;\n margin-left: auto;\n font-size: var(--wb-font-10);\n line-height: var(--wb-line-16);\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-activityLine > .wb-activityLineAt,\n.wb-activityLine > .wb-activityLineActions {\n margin-left: auto;\n}\n\n.wb-activityLine > .wb-activityLineAt + .wb-activityLineActions {\n margin-left: 0;\n}\n\n.wb-activityLineActions {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n}\n\n.wb-activityActionFailed {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.wb-note {\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n.wb-problem {\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-state-error-primary);\n overflow-wrap: anywhere;\n}\n\n.wb-approvalCommand {\n max-width: 100%;\n}\n.wb-approvalPlan {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-6);\n}\n.wb-approvalHint {\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-secondary);\n}\n.wb-approvalRows {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-2);\n margin: 0;\n}\n.wb-approvalRow {\n display: flex;\n align-items: baseline;\n gap: var(--wb-len-8);\n}\n.wb-approvalLabel {\n flex: none;\n width: var(--wb-len-56);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n.wb-approvalValue {\n margin: 0;\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-18);\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n overflow-wrap: anywhere;\n}\n.wb-approvalWarn {\n color: var(--dsw-alias-label-secondary);\n}\n\n.wb-cardHead {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n flex: none;\n padding: var(--wb-len-8) var(--wb-len-10) var(--wb-len-8) var(--wb-card-gutter);\n border-bottom: 0.5px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.wb-cardTitle {\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n font-weight: 600;\n color: var(--dsw-alias-label-secondary);\n}\n\n.wb-cardMeta {\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.wb-cardMeta::before {\n content: '\\00b7';\n margin-right: var(--wb-len-6);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-cardOpen {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n margin-left: auto;\n flex: none;\n width: var(--wb-len-22);\n height: var(--wb-len-22);\n padding: var(--wb-len-4);\n border-radius: var(--wb-radius-6);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-cardOpen ~ .wb-cardRefresh {\n margin-left: 0;\n}\n\n.wb-cardOpen:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.wb-cardRefresh {\n margin-left: auto;\n flex: none;\n width: var(--wb-len-22);\n height: var(--wb-len-22);\n padding: var(--wb-len-4);\n border-radius: var(--wb-radius-6);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-cardRefresh:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n\n.wb-cardRefresh:disabled {\n cursor: default;\n opacity: 1;\n}\n\n.wb-cardGear {\n flex: none;\n width: var(--wb-len-22);\n height: var(--wb-len-22);\n padding: var(--wb-len-3);\n border-radius: var(--wb-radius-6);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-cardGear:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n\n.wb-card {\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-xl);\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n flex: none;\n}\n.wb-cardBody {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-12);\n padding: var(--wb-len-12) var(--wb-card-gutter);\n font-size: var(--dsw-font-xxs-12-font-size);\n}\n.wb-cardBleed {\n margin-inline: calc(-1 * var(--wb-card-gutter));\n}\n._anchor_yq4s2_1 {\n display: contents;\n}\n\n.wb-spinner {\n display: inline-flex;\n align-items: center;\n flex: none;\n}\n\n.wb-choiceMenu {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-2);\n background: transparent;\n}\n\n.wb-choiceMenu[data-variant='boxed'] {\n padding: var(--wb-len-4);\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n}\n\n.wb-choiceOption {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-height: var(--wb-len-28);\n padding: var(--wb-len-4) var(--wb-len-8);\n border-radius: var(--dsw-radius-md);\n cursor: pointer;\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-20);\n color: var(--dsw-alias-label-primary);\n}\n\n.wb-choiceOptionOn {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.wb-checkbox {\n position: absolute;\n width: var(--wb-len-16);\n height: var(--wb-len-16);\n margin: 0;\n opacity: 0;\n pointer-events: none;\n}\n\n.wb-checkboxBox {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n flex: none;\n width: var(--wb-len-16);\n height: var(--wb-len-16);\n border: 1px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-xs);\n corner-shape: round;\n color: var(--dsw-alias-label-primary-foreground);\n transition:\n background-color var(--wb-dur-0-12) ease, border-color var(--wb-dur-0-12) ease;\n}\n\n.wb-choiceOption:hover .wb-checkboxBox {\n border-color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-checkbox:checked + .wb-checkboxBox {\n border-color: var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n}\n\n.wb-checkbox:disabled + .wb-checkboxBox {\n cursor: default;\n}\n\n.wb-checkbox:focus-visible + .wb-checkboxBox {\n outline: var(--dsw-focus-ring-width, var(--wb-len-2)) solid\n var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: 2px;\n}\n\n.wb-choiceOption:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.wb-choiceOption:has(:disabled) {\n cursor: default;\n opacity: 0.5;\n}\n\n.wb-choiceOption:has(:disabled),\n.wb-choiceOption:has(:disabled):hover {\n background: transparent;\n}\n\n.wb-choiceLabel {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.wb-choiceLabelText {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.wb-choiceLabel:has(.wb-choiceDescription) .wb-choiceLabelText {\n overflow: visible;\n white-space: normal;\n overflow-wrap: anywhere;\n}\n\n.wb-choiceDescription {\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n overflow-wrap: anywhere;\n}\n\n.wb-choiceLoading {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-height: var(--wb-len-28);\n padding: var(--wb-len-4) var(--wb-len-8);\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-20);\n color: var(--dsw-alias-label-secondary);\n}\n\n.wb-choiceLoadingText {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.wb-choiceEmpty {\n display: flex;\n align-items: center;\n min-height: var(--wb-len-28);\n padding: var(--wb-len-4) var(--wb-len-8);\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-20);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-radio {\n appearance: none;\n -webkit-appearance: none;\n flex: none;\n box-sizing: border-box;\n width: var(--wb-len-12);\n height: var(--wb-len-12);\n margin: 0;\n border: 1px solid var(--dsw-alias-border-l3);\n border-radius: 50%;\n corner-shape: round;\n background-color: transparent;\n cursor: pointer;\n transition:\n background-color var(--wb-dur-0-12) ease, border-color var(--wb-dur-0-12) ease;\n}\n\n.wb-radio:not(:checked):hover {\n border-color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-radio:checked {\n border-color: var(--dsw-alias-brand-primary);\n background-image: radial-gradient(\n circle at center,\n var(--dsw-alias-brand-primary) 0 3px,\n transparent 3px\n );\n}\n\n.wb-radio:disabled {\n cursor: default;\n}\n\n.wb-radio:focus-visible {\n outline: var(--dsw-focus-ring-width, var(--wb-len-2)) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: 2px;\n}.wb-field {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-6);\n font-size: var(--dsw-font-xs-13-font-size);\n}\n\n.wb-fieldLabel {\n color: var(--dsw-alias-label-secondary);\n}\n\n.wb-fieldHint {\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-field:has(:disabled) .wb-fieldLabel {\n opacity: 0.4;\n}\n.wb-formActions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n gap: var(--wb-len-8);\n}\n\n.wb-formActionDanger {\n color: var(--dsw-alias-state-error-primary);\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 30%, transparent);\n --dsw-alias-interactive-bg-hover: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);\n}\n.wb-formRows {\n display: grid;\n grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);\n column-gap: var(--wb-len-8);\n row-gap: var(--wb-len-12);\n}\n\n.wb-formRows > :not(.wb-formRow) {\n grid-column: 1 / -1;\n}\n\n.wb-formRow {\n display: grid;\n grid-column: 1 / -1;\n grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);\n align-items: center;\n column-gap: var(--wb-len-8);\n row-gap: var(--wb-len-8);\n}\n\n.wb-formRow[data-layout='stacked'] {\n grid-template-columns: minmax(0, 1fr);\n align-items: stretch;\n gap: var(--wb-len-6);\n}\n\n.wb-formLabel {\n min-width: 0;\n font-size: var(--dsw-font-xs-13-font-size);\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n white-space: nowrap;\n}\n\n.wb-formRow[data-layout='stacked'] .wb-formLabel {\n white-space: normal;\n}\n\n.wb-formControl {\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.wb-formHint {\n grid-column: 2;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-formProblem {\n grid-column: 2;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.wb-formRow:has(.wb-formProblem) .wb-formLabel {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.wb-formRow:has(:disabled) .wb-formLabel {\n opacity: 0.4;\n}\n\n.wb-formRows > .wb-formRow {\n grid-template-columns: subgrid;\n}\n\n@supports not (grid-template-columns: subgrid) {\n .wb-formRows > .wb-formRow {\n grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);\n }\n}\n:where(.wb-link) {\n margin-left: var(--wb-len-2);\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-2);\n font: inherit;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-primary);\n text-decoration: none;\n white-space: nowrap;\n vertical-align: baseline;\n}\n\n:where(.wb-link:hover) {\n text-decoration: underline;\n}\n\n:where(.wb-link:focus-visible) {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: -2px;\n}\n\n.wb-longTask {\n padding-top: var(--wb-len-12);\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-2);\n}\n\n.wb-longTaskHead {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n margin: 0;\n}\n\n.wb-longTaskLink {\n flex: none;\n}\n\n.wb-longTaskHeadline {\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-secondary);\n}\n\n.wb-longTaskProblem {\n margin: 0;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-state-error-primary);\n overflow-wrap: anywhere;\n}\n\n.wb-longTaskDump {\n margin: var(--wb-len-2) 0 0;\n font-size: var(--dsw-font-xxxs-11-font-size);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-longTaskDump pre {\n margin: var(--wb-len-4) 0 0;\n max-height: var(--wb-len-220);\n overflow: auto;\n}\n.wb-centered.wb-centeredCompact {\n flex: none;\n min-height: 0;\n gap: var(--wb-len-8);\n padding: var(--wb-len-20) var(--wb-len-16);\n}\n\n.wb-centered.wb-centeredCompact .wb-centeredHero {\n margin-bottom: var(--wb-len-4);\n}\n\n.wb-skeleton {\n display: flex;\n flex-direction: column;\n}\n\n.wb-skeletonRow {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-8);\n padding: var(--wb-len-8);\n border-radius: var(--dsw-radius-md);\n}\n\n.wb-skeletonRow + .wb-skeletonRow::before {\n content: '';\n align-self: stretch;\n height: var(--wb-len-0-5);\n margin: 0 var(--wb-len-8) var(--wb-len-neg-0-5);\n background: var(--dsw-alias-border-l2);\n}\n\n.wb-skeletonBar {\n display: block;\n height: var(--wb-len-13);\n border-radius: var(--dsw-radius-xs);\n background: var(--dsw-alias-bg-skeleton);\n animation: wb-skeleton-pulse var(--wb-dur-1-4) var(--ds-ease-in-out) infinite;\n}\n\n.wb-skeletonBarTitle {\n width: 62%;\n}\n\n.wb-skeletonBarMeta {\n width: 32%;\n height: var(--wb-len-10);\n}\n\n.wb-skeletonRow:nth-child(2n) .wb-skeletonBarTitle {\n width: 74%;\n}\n\n.wb-skeletonRow:nth-child(3n) .wb-skeletonBarTitle {\n width: 52%;\n}\n\n@keyframes wb-skeleton-pulse {\n 50% {\n opacity: 0.45;\n }\n}\n\n.wb-centered {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n gap: var(--wb-len-14);\n flex: 1;\n min-height: var(--wb-len-240);\n padding: 0 var(--wb-len-24) var(--wb-len-24);\n text-align: center;\n}\n\n.wb-centeredHero {\n display: flex;\n margin-bottom: var(--wb-len-16);\n color: var(--dsw-alias-label-dimmed);\n}\n\n.wb-centeredTitle {\n font-size: var(--dsw-font-s-14-font-size);\n line-height: var(--wb-line-22);\n color: var(--dsw-alias-label-primary);\n}\n\n.wb-centeredHint {\n max-width: var(--wb-len-300);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-centeredDetail {\n max-width: var(--wb-len-320);\n font-family: var(--ds-font-family-code, monospace);\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-dimmed);\n word-break: break-all;\n}\n\n.wb-centeredAction {\n display: flex;\n justify-content: center;\n gap: var(--wb-len-8);\n margin-top: var(--wb-len-2);\n}\n@media (prefers-reduced-motion: reduce) {\n .wb-skeletonBar {\n animation: none;\n }}\n.wb-rows {\n display: grid;\n grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);\n column-gap: var(--wb-len-8);\n}\n.wb-rows > :not(.wb-row) {\n grid-column: 1 / -1;\n}\n.wb-row {\n display: grid;\n grid-column: 1 / -1;\n grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);\n align-items: baseline;\n gap: var(--wb-len-8);\n padding: var(--wb-len-4) 0;\n}\n.wb-row + .wb-row {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.wb-rowKey {\n white-space: nowrap;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n}\n.wb-rowValue {\n min-width: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-primary);\n overflow-wrap: anywhere;\n}\n\n.wb-rows > .wb-row {\n grid-template-columns: subgrid;\n}\n\n@supports not (grid-template-columns: subgrid) {\n .wb-rows > .wb-row {\n grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);\n }\n}\n.wb-textField {\n box-sizing: border-box;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-primary);\n outline: none;\n}\n\n.wb-textField:focus {\n border-color: var(--dsw-alias-state-business-primary);\n box-shadow: inset 0 0 0 0.5px var(--dsw-alias-state-business-primary);\n}\n\n.wb-textField:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.wb-textField[aria-invalid='true'] {\n border-color: var(--dsw-alias-state-error-primary);\n}\n\n.wb-textField[aria-invalid='true']:focus {\n box-shadow: inset 0 0 0 0.5px var(--dsw-alias-state-error-primary);\n}\n\n:where(.wb-textField) {\n min-height: var(--wb-len-28);\n padding: var(--wb-len-4) var(--wb-len-10);\n}\n:where(.wb-selectTrigger) {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n width: 100%;\n min-height: var(--wb-len-28);\n padding: var(--wb-len-4) var(--wb-len-10);\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-primary);\n text-align: left;\n cursor: pointer;\n}\n\n.wb-selectTrigger:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-state-business-primary);\n box-shadow: inset 0 0 0 0.5px var(--dsw-alias-state-business-primary);\n}\n\n.wb-selectTrigger[aria-invalid='true'] {\n border-color: var(--dsw-alias-state-error-primary);\n}\n\n.wb-selectTrigger[aria-invalid='true']:focus-visible {\n box-shadow: inset 0 0 0 0.5px var(--dsw-alias-state-error-primary);\n}\n\n.wb-selectTrigger:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.wb-selectLoading:disabled {\n cursor: default;\n opacity: 1;\n}\n\n.wb-selectGhost {\n gap: var(--wb-gap-xs);\n min-height: 0;\n height: var(--wb-len-34);\n padding: 0 var(--wb-len-8);\n border: none;\n background: transparent;\n font-size: var(--wb-font-row);\n}\n\n.wb-selectGhost:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.wb-selectGhost:focus-visible {\n outline: var(--dsw-focus-ring-width) solid\n var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: -2px;\n border-color: transparent;\n box-shadow: none;\n}\n\n.wb-selectIconOnly {\n width: var(--wb-len-36);\n height: var(--wb-len-36);\n min-height: 0;\n gap: 0;\n padding: 0;\n justify-content: center;\n}\n\n.wb-selectReveal {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.wb-selectIconOnly .wb-selectIcon {\n width: 100%;\n height: 100%;\n}\n\n.wb-selectAnchor {\n display: block;\n width: 100%;\n}\n\n.wb-selectIcon {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-16);\n height: var(--wb-len-20);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-selectValue {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: baseline;\n gap: var(--wb-len-6);\n line-height: var(--wb-line-20);\n overflow: hidden;\n}\n\n.wb-selectPlaceholder {\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-selectChevron {\n flex: none;\n display: inline-flex;\n color: var(--dsw-alias-label-caption);\n}\n\n.wb-selectMenu {\n min-width: var(--wb-len-240);\n max-width: var(--wb-len-360);\n max-height: min(var(--wb-len-320), calc(100vh - var(--wb-len-24)));\n}\n\n:where(.wb-selectSearch) {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n width: 100%;\n min-height: var(--wb-len-28);\n padding: var(--wb-len-4) var(--wb-len-10);\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n}\n\n.wb-selectSearch:focus-within {\n border-color: var(--dsw-alias-state-business-primary);\n box-shadow: inset 0 0 0 0.5px var(--dsw-alias-state-business-primary);\n}\n\n.wb-selectSearch.wb-selectGhost {\n gap: var(--wb-gap-xs);\n min-height: 0;\n height: var(--wb-len-34);\n padding: 0 var(--wb-len-8);\n border: 0.5px solid var(--dsw-alias-border-l3);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.wb-selectSearch.wb-selectGhost:focus-within {\n border-color: var(--dsw-alias-state-business-primary);\n box-shadow: none;\n}\n\n.wb-selectSearchIcon {\n flex: none;\n display: inline-flex;\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-textField.wb-selectSearchInput {\n flex: 1;\n min-width: 0;\n min-height: 0;\n padding: 0;\n border: none;\n background: transparent;\n}\n\n.wb-textField.wb-selectSearchInput:focus {\n box-shadow: none;\n}\n\n.wb-selectFallback {\n width: 100%;\n}\n\n.wb-selectHint {\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n\nsection.wb-settings {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-12);\n padding: var(--wb-len-12) var(--wb-len-16);\n border: 0;\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-settings-card-fill);\n}\n.wb-settingsHead {\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n}\n.wb-settings .wb-settingsTitle {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--dsw-font-s-strong-14-font-size);\n line-height: var(--wb-line-24);\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n.wb-stack {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-10);\n min-height: 0;\n}\n\n.wb-stateBlock {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-6);\n}\n.wb-stateBlockTitle {\n margin: 0;\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-primary);\n}\n.wb-stateBlockHint {\n margin: 0;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n}\n.wb-stateBlockActions {\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n margin-top: var(--wb-len-2);\n}\n.wb-stateBlockResolving {\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-secondary);\n}\n._marketList_csyus_1 {\n list-style: none;\n margin: 0;\n padding: var(--wb-len-6);\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-2);\n}\n\n._marketRow_csyus_10 {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr) auto;\n align-items: center;\n column-gap: var(--wb-len-14);\n row-gap: var(--wb-len-4);\n padding: var(--wb-len-8);\n border-radius: var(--dsw-radius-lg);\n}\n\n._marketIcon_csyus_20 {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-40);\n height: var(--wb-len-40);\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n color: var(--dsw-alias-label-secondary);\n}\n\n._marketMain_csyus_32 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-4);\n min-width: 0;\n}\n\n._marketName_csyus_39 {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font: var(--dsw-font-base-strong-16);\n color: var(--dsw-alias-label-primary);\n}\n\n._marketDesc_csyus_48 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-width: 0;\n overflow: hidden;\n white-space: nowrap;\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-label-secondary);\n}\n\n._marketUsedBy_csyus_59 {\n margin-left: var(--wb-len-8);\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n opacity: 0.75;\n}\n\n._marketUsedBy_csyus_59::before {\n content: '·';\n margin-right: var(--wb-len-6);\n opacity: 0.8;\n}\n\n._marketName_csyus_39 ._marketVersion_csyus_73 {\n margin-left: var(--wb-len-6);\n font-size: var(--dsw-font-xxs-12-font-size);\n font-weight: 400;\n line-height: var(--wb-line-18);\n}\n\n._marketVersion_csyus_73 {\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-caption);\n}\n\n._marketVersion_csyus_73::before {\n content: '';\n display: inline-block;\n width: var(--wb-len-1);\n height: var(--wb-len-10);\n margin: 0 var(--wb-len-8) 0 var(--wb-len-2);\n vertical-align: -1px;\n background: var(--dsw-alias-border-l2);\n}\n\n._marketLocalTag_csyus_95 {\n margin-left: var(--wb-len-8);\n padding: 0 var(--wb-len-6);\n border: var(--wb-len-1) solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n font-size: var(--dsw-font-xxs-12-font-size);\n font-weight: 400;\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-caption);\n}\n\n._marketEnd_csyus_106 {\n flex: none;\n display: flex;\n align-items: center;\n gap: var(--wb-len-10);\n}\n\n._marketSwitchSeat_csyus_113 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-10);\n}\n\n._marketSwitchSeat_csyus_113::before {\n content: '';\n width: 0;\n height: var(--wb-len-14);\n border-left: 0.5px solid var(--dsw-alias-border-l3);\n}\n\n._marketActions_csyus_126 {\n flex: none;\n display: flex;\n gap: var(--wb-len-6);\n}\n\n._marketUpdateAction_csyus_132 {\n color: var(--dsw-alias-state-warn-primary);\n border-color: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 30%, transparent);\n --dsw-alias-interactive-bg-hover: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);\n}\n\n._marketSelfDivider_csyus_138 {\n height: 0;\n border-top: 0.5px solid var(--dsw-alias-border-l3);\n}\n\n._marketSection_csyus_143 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-8);\n min-width: 0;\n}\n\n._marketSectionHead_csyus_150 {\n display: flex;\n align-items: baseline;\n gap: var(--wb-len-8);\n}\n\n._marketSectionIcon_csyus_156 {\n display: inline-flex;\n align-items: center;\n align-self: center;\n color: var(--dsw-alias-label-caption);\n}\n\n._marketSectionTitle_csyus_163 {\n margin: 0;\n font: var(--dsw-font-base-strong-16);\n color: var(--dsw-alias-label-primary);\n}\n\n._marketSectionCount_csyus_169 {\n font: var(--dsw-font-s-14);\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-caption);\n}\n\n\n._marketProgress_csyus_176 {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-8);\n min-height: var(--wb-len-32);\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-label-secondary);\n}\n\n._marketNote_csyus_186 {\n grid-column: 2 / -1;\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-state-warn-primary);\n overflow-wrap: anywhere;\n}\n\n._marketNotePlain_csyus_193 {\n grid-column: 2 / -1;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-caption);\n overflow-wrap: anywhere;\n}\n\n._marketFailure_csyus_201 {\n grid-column: 2 / -1;\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-state-error-primary);\n overflow-wrap: anywhere;\n}\n\n._marketEmpty_csyus_208 {\n padding: var(--wb-len-18) var(--wb-len-16);\n text-align: center;\n}\n\n._marketPage_csyus_213 {\n box-sizing: border-box;\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--wb-len-32);\n padding: 0 clamp(var(--wb-len-24), 4vw, var(--wb-len-48)) var(--wb-len-48);\n overflow-x: hidden;\n overflow-y: auto;\n color: var(--dsw-alias-label-primary);\n}\n\n._marketPage_csyus_213 > * {\n width: 100%;\n max-width: var(--wb-len-960);\n}\n\n._marketPageHead_csyus_231 {\n box-sizing: border-box;\n display: flex;\n align-items: flex-start;\n gap: var(--wb-len-16);\n padding-top: var(--wb-len-28);\n}\n\n._marketPageTitle_csyus_239 {\n margin: 0;\n font: var(--dsw-font-l-20);\n}\n\n._marketPageIntro_csyus_244 {\n margin: var(--wb-len-4) 0 0;\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-secondary);\n}\n\n._marketPageTools_csyus_250 {\n flex: none;\n align-self: center;\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: var(--wb-len-16);\n}\n\n._marketIconButton_csyus_259 {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-28);\n height: var(--wb-len-28);\n padding: 0;\n border: 0;\n border-radius: var(--dsw-radius-sm);\n background: transparent;\n color: var(--dsw-alias-label-caption);\n cursor: pointer;\n}\n\n._marketIconButton_csyus_259:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n\n._marketIconButton_csyus_259:disabled {\n cursor: default;\n opacity: 0.5;\n}\n\n._marketIconWrap_csyus_284 {\n display: inline-flex;\n}\n\n._marketIconButtonSpinning_csyus_288 svg {\n animation: _wb-spin_csyus_1 var(--wb-dur-0-9) linear infinite;\n}\n\n._marketAddButton_csyus_292 {\n height: var(--wb-len-32);\n padding: 0 var(--wb-len-12);\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-20);\n border-radius: var(--dsw-radius-md);\n}\n\n._marketEmpty_csyus_208 {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--wb-len-8);\n padding: var(--wb-len-64) var(--wb-len-16);\n text-align: center;\n}\n\n._marketChecking_csyus_309 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-label-secondary);\n}\n\n._marketEmptyTitle_csyus_317 {\n font: var(--dsw-font-base-strong-16);\n color: var(--dsw-alias-label-primary);\n}\n\n@keyframes _wb-spin_csyus_1 {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n._foot_1ud1j_1 {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--wb-len-8);\n padding: var(--wb-len-8) var(--wb-len-14) var(--wb-len-10);\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n}\n\n._footText_1ud1j_13 {\n flex: 1;\n min-width: 0;\n}\n\n._footTextMd_1ud1j_18 {\n flex: 1;\n min-width: 0;\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-label-secondary);\n}\n._wide_1lv8f_1 {\n justify-content: center;\n width: 100%;\n height: var(--wb-len-40);\n border-radius: var(--dsw-radius-md);\n}\n\n._dialog_1lv8f_8 {\n width: min(var(--wb-len-560), 100%);\n max-height: min(var(--wb-len-800), 100%);\n}\n\n._content_1lv8f_13 {\n min-height: 0;\n overflow: auto;\n}\n\n._stack_1lv8f_18 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-12);\n min-width: 0;\n}\n\n._body_1lv8f_25 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-12);\n min-width: 0;\n}\n\n._field_1lv8f_32 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-6);\n font-size: var(--dsw-font-xs-13-font-size);\n}\n\n._input_1lv8f_39 {\n width: 100%;\n height: var(--wb-len-40);\n padding: 0 var(--wb-len-14);\n}\n\n._registryField_1lv8f_45 {\n height: var(--wb-len-32);\n margin-left: var(--wb-len-26);\n padding: 0 var(--wb-len-10);\n}\n\n._options_1lv8f_51 {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--wb-len-8) var(--wb-len-12);\n}\n\n._guideToggle_1lv8f_59 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-4);\n align-self: flex-start;\n margin-top: var(--wb-len-4);\n padding: 0;\n border: 0;\n background: transparent;\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n._guideToggle_1lv8f_59:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n._guideToggle_1lv8f_59 svg,\n._registryToggle_1lv8f_78 svg {\n transition: transform var(--wb-dur-0-12) ease;\n}\n\n._guideToggle_1lv8f_59[aria-expanded='true'] svg,\n._registryToggle_1lv8f_78[aria-expanded='true'] svg {\n transform: rotate(180deg);\n}\n\n._registryWrap_1lv8f_87 {\n position: relative;\n flex: none;\n}\n\n._registryToggle_1lv8f_78 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n height: var(--wb-len-26);\n padding: 0 var(--wb-len-8) 0 var(--wb-len-10);\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-2);\n font: inherit;\n font-size: var(--wb-font-12-5);\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n._registryToggle_1lv8f_78:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n\n._registryToggle_1lv8f_78:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n._registryToggle_1lv8f_78[aria-expanded='true'] {\n border-color: var(--dsw-alias-border-l3);\n background: var(--dsw-alias-bg-layer-3);\n}\n\n._registryChosen_1lv8f_121 {\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n\n._registry_1lv8f_45 {\n position: fixed;\n z-index: var(--wb-z-1100);\n box-sizing: border-box;\n width: min(var(--wb-len-440), 100vw - var(--wb-len-24));\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-4);\n margin: 0;\n padding: var(--wb-len-8) var(--wb-len-10) var(--wb-len-12);\n border: 0;\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-alias-bg-layer-2);\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l3);\n box-shadow: var(--dsw-elevation-prominent);\n}\n\n._registryOption_1lv8f_143 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-4);\n padding: var(--wb-len-8) var(--wb-len-10);\n border: 0.5px solid transparent;\n border-radius: var(--dsw-radius-lg);\n cursor: pointer;\n}\n\nlabel._registryOption_1lv8f_143 {\n flex-direction: row;\n align-items: flex-start;\n gap: var(--wb-len-10);\n}\n\n._registryPick_1lv8f_159 {\n display: flex;\n align-items: flex-start;\n gap: var(--wb-len-10);\n cursor: pointer;\n}\n\n._registryOption_1lv8f_143[data-checked='true'] {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 40%, transparent);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n._registryOption_1lv8f_143 input[type='radio'] {\n flex: none;\n width: var(--wb-len-16);\n height: var(--wb-len-16);\n margin: var(--wb-len-2) 0 0;\n accent-color: var(--dsw-alias-brand-primary);\n}\n\n._registryTitle_1lv8f_179 {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--wb-len-8);\n font: var(--dsw-font-xs-13);\n line-height: var(--wb-line-20);\n color: var(--dsw-alias-label-primary);\n}\n\n._registryHint_1lv8f_189 {\n margin-left: var(--wb-len-26);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n overflow-wrap: anywhere;\n}\n\n._inputError_1lv8f_197 {\n margin: var(--wb-len-neg-4) 0 0 var(--wb-len-26);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-state-error-primary);\n}\n\n._guide_1lv8f_59 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-10);\n padding: var(--wb-len-8) var(--wb-len-14) var(--wb-len-14);\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-alias-bg-layer-1);\n}\n\n._guideList_1lv8f_214 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-2);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n._guideItem_1lv8f_223 {\n display: flex;\n align-items: flex-start;\n gap: var(--wb-len-10);\n padding: var(--wb-len-8) 0;\n}\n\n._guideIndex_1lv8f_230 {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-20);\n height: var(--wb-len-20);\n border-radius: var(--wb-radius-pill);\n corner-shape: round;\n background: var(--dsw-alias-bg-module-platform);\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-secondary);\n}\n\n._guideMain_1lv8f_244 {\n display: flex;\n flex-direction: column;\n flex: 1;\n gap: 0;\n min-width: 0;\n}\n\n._guideTitle_1lv8f_252 {\n font: var(--dsw-font-s-14);\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n._guideHint_1lv8f_258 {\n margin: 0;\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-caption);\n}\n\n._guideExample_1lv8f_264 {\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n}\n\n._guideExample_1lv8f_264 code {\n font-family: var(--dsw-font-mono, monospace);\n}\n\n._guideExampleLabel_1lv8f_274 {\n color: var(--dsw-alias-label-caption);\n}\n\n._footer_1lv8f_278 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-20);\n width: 100%;\n}\n\n._hero_1lv8f_285 {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--wb-len-10);\n padding: var(--wb-len-8) 0 var(--wb-len-4);\n text-align: center;\n}\n\n._heroIcon_1lv8f_294 {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-44);\n height: var(--wb-len-44);\n color: var(--dsw-alias-label-secondary);\n}\n\n._heroIcon_1lv8f_294[data-state='done'] {\n color: var(--dsw-alias-state-success-secondary);\n}\n\n._heroIcon_1lv8f_294[data-state='error'] {\n color: var(--dsw-alias-state-warn-label);\n}\n\n._pendingTitle_1lv8f_311 {\n margin: 0;\n font-size: var(--dsw-font-s-14-font-size);\n line-height: var(--wb-line-22);\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n._wizardTitle_1lv8f_319 {\n margin: 0;\n font-size: var(--wb-font-18);\n line-height: var(--wb-len-26);\n font-weight: 600;\n}\n\n._subject_1lv8f_326 {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--wb-len-6);\n padding: var(--wb-len-16);\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-lg);\n text-align: center;\n}\n\n._subjectName_1lv8f_337 {\n margin: 0;\n font: var(--dsw-font-base-strong-16);\n overflow-wrap: anywhere;\n}\n\n._subjectMeta_1lv8f_343,\n._subjectDesc_1lv8f_344 {\n margin: 0;\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n}\n\n._result_1lv8f_351,\n._resultWarn_1lv8f_352 {\n margin: 0;\n padding: var(--wb-len-8) var(--wb-len-12);\n border-radius: var(--dsw-radius-md);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent);\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-label-primary);\n}\n\n._resultWarn_1lv8f_352 {\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n}\n\n._resultMeta_1lv8f_365 {\n margin: 0;\n padding: 0 var(--wb-len-12);\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n}\n\n._approval_1lv8f_373 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-8);\n padding: var(--wb-len-12) var(--wb-len-14);\n border: 0.5px solid var(--dsw-alias-state-warn-primary);\n border-radius: var(--dsw-radius-lg);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);\n}\n\n._approvalTitle_1lv8f_383 {\n margin: 0;\n font: var(--dsw-font-s-14);\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._approvalText_1lv8f_390 {\n margin: 0;\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-secondary);\n}\n\n._approvalCaution_1lv8f_396 {\n margin: 0;\n font: var(--dsw-font-xs-13);\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n._note_1lv8f_403 {\n margin: 0;\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n}\n\n._noteWarn_1lv8f_410 {\n color: var(--dsw-alias-state-warn-primary);\n}\n\n._noteError_1lv8f_414 {\n color: var(--dsw-alias-state-error-primary);\n}\n\n._problem_1lv8f_418 {\n margin: 0;\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-state-error-primary);\n overflow-wrap: anywhere;\n}\n\n._detailLabel_1lv8f_425 {\n margin: 0;\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-caption);\n}\n\n._detail_1lv8f_425 {\n margin: 0;\n padding: var(--wb-len-8) var(--wb-len-10);\n border: 0.5px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-3);\n font-family: var(--dsw-font-mono, monospace);\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n._note_1enlz_1 {\n display: flex;\n align-items: flex-start;\n gap: var(--wb-len-8);\n margin: 0;\n padding: var(--wb-len-10) var(--wb-len-12);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-state-warn-tertiary);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-secondary);\n}\n\n._note_1enlz_1 > svg {\n flex: none;\n margin-top: var(--wb-len-2);\n color: var(--dsw-alias-state-warn-primary);\n}\n._slot_1og2k_1 {\n display: flex;\n flex: 1 1 0;\n min-width: 0;\n}\n\n._slot_1og2k_1 > * {\n flex: 1 1 0;\n min-width: 0;\n}\n\n._action_1og2k_12 {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n flex: 1 1 0;\n width: 100%;\n min-width: 0;\n min-height: var(--wb-len-36);\n margin: 0 var(--wb-len-2);\n padding: var(--wb-len-7) var(--wb-len-8);\n border-radius: var(--dsw-radius-md);\n cursor: default;\n overflow: hidden;\n gap: var(--wb-len-4);\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-18);\n}\n\n._live_1og2k_31 {\n color: var(--dsw-alias-state-success-primary);\n}\n\n._paused_1og2k_35 {\n color: var(--dsw-alias-state-warn-primary);\n}\n\n._trouble_1og2k_39 {\n color: var(--dsw-alias-state-error-primary);\n}\n\n._pulse_1og2k_43 {\n animation: _wb-debug-breathe_1og2k_1 var(--wb-dur-1-5) var(--ds-ease-in-out, ease-in-out) infinite;\n}\n\n@keyframes _wb-debug-breathe_1og2k_1 {\n 0%,\n 100% {\n opacity: 1;\n }\n\n 50% {\n opacity: 0.35;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._pulse_1og2k_43 {\n animation: none;\n }\n}\n\n._entry_1og2k_64 {\n display: flex;\n align-items: center;\n flex: 1 1 auto;\n min-width: 0;\n}\n\n._entryInner_1og2k_71 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-width: 0;\n}\n\n._acts_1og2k_78 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-2);\n flex: none;\n}\n\n._act_1og2k_12 {\n appearance: none;\n border: 0;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-22);\n height: var(--wb-len-22);\n padding: 0;\n border-radius: var(--dsw-radius-sm, var(--wb-len-6));\n flex: none;\n cursor: pointer;\n}\n\n._act_1og2k_12:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._act_1og2k_12:focus-visible {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: -2px;\n}\n\n._actStop_1og2k_110:hover,\n._actStop_1og2k_110:focus-visible {\n color: var(--dsw-alias-state-error-primary);\n}\n\n._actArmed_1og2k_115,\n._actArmed_1og2k_115:hover,\n._actArmed_1og2k_115:focus-visible {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent);\n width: auto;\n color: var(--dsw-alias-state-error-primary);\n gap: var(--wb-len-4);\n padding: 0 var(--wb-len-7);\n}\n\n._actLabel_1og2k_125 {\n white-space: nowrap;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-18);\n}\n\n._entryLine_1og2k_131 {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._actionRail_1og2k_138 {\n justify-content: center;\n flex: none;\n width: var(--wb-len-36);\n min-width: var(--wb-len-36);\n height: var(--wb-len-36);\n margin: 0;\n padding: 0;\n corner-shape: round;\n border-radius: 50%;\n}\n\n._card_1og2k_150 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-4);\n}\n\n._cardTitle_1og2k_156 {\n color: var(--dsw-alias-label-primary);\n font-size: var(--dsw-font-s-14-font-size);\n line-height: var(--wb-line-20);\n}\n\n._cardNote_1og2k_162 {\n color: var(--dsw-alias-label-secondary);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n}\n._body_lw2ph_1 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-12);\n}\n\n._lead_lw2ph_7 {\n margin: 0;\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-secondary);\n}\n\n._sources_lw2ph_14 {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--wb-len-8);\n}\n\n._sourcesLabel_lw2ph_21 {\n font-size: var(--dsw-font-xxs-12-font-size);\n color: var(--dsw-alias-label-secondary);\n}\n\nbutton._sourceOn_lw2ph_26 {\n border-color: var(--dsw-alias-brand-primary);\n}\n._sourceCount_lw2ph_29 {\n margin-left: var(--wb-len-4);\n font-variant-numeric: tabular-nums;\n font-size: var(--dsw-font-xxs-12-font-size);\n color: var(--dsw-alias-label-tertiary);\n}\n\n._reading_lw2ph_36 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-4);\n}\n\n._status_lw2ph_42 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n\n._failure_lw2ph_52 {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n column-gap: var(--wb-len-10);\n row-gap: var(--wb-len-2);\n color: var(--dsw-alias-state-error-primary);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n}\n\n._failureTitle_lw2ph_62 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-width: 0;\n}\n\n._failureHint_lw2ph_69 {\n grid-column: 1;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._failureAction_lw2ph_74 {\n grid-column: 2;\n grid-row: 1;\n justify-self: end;\n}\n\n._rows_lw2ph_80 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-8);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n._row_lw2ph_80 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-6);\n padding: var(--wb-len-12) var(--wb-len-14);\n border: 0.5px solid var(--dsw-alias-settings-card-stroke);\n border-radius: var(--dsw-radius-xl);\n background: var(--dsw-alias-settings-card-fill);\n}\n\n._head_lw2ph_99 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n min-width: 0;\n}\n\n._pick_lw2ph_106 {\n flex: 0 1 auto;\n min-width: 0;\n font-size: var(--dsw-font-xs-13-font-size);\n}\n\n._pick_lw2ph_106 > span {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._code_lw2ph_118 {\n --dsl-code-block-background: var(--dsw-alias-bg-layer-1);\n margin: 0;\n}\n\n._missing_lw2ph_123,\n._conflict_lw2ph_124 {\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-state-warn-primary);\n}\n\n._foot_lw2ph_130 {\n display: flex;\n justify-content: flex-end;\n}\n._actions_jlw8j_1[hidden],\n._progress_jlw8j_2[hidden],\n._commandRow_jlw8j_3[hidden],\n._bridge_jlw8j_4[hidden],\n._raw_jlw8j_5[hidden] {\n display: none;\n}\n\n._gate_jlw8j_9 {\n position: fixed;\n inset: 0;\n z-index: var(--wb-z-top);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--wb-len-24);\n background: var(--dsw-alias-bg-base);\n}\n\n._card_jlw8j_20 {\n width: 100%;\n max-width: var(--wb-len-420);\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--wb-len-16);\n text-align: center;\n}\n\n._card_jlw8j_20:has(._actions_jlw8j_1:not([hidden])),\n._card_jlw8j_20:has(._bridge_jlw8j_4:not([hidden])) {\n max-width: var(--wb-len-520);\n}\n\n._title_jlw8j_35 {\n margin: 0;\n font-size: var(--dsw-font-base-16-font-size);\n line-height: var(--wb-line-24);\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._hint_jlw8j_43 {\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n\n._steps_jlw8j_50 {\n list-style: none;\n margin: var(--wb-len-6) 0 0;\n padding: 0;\n width: 100%;\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-2);\n text-align: left;\n}\n\n._step_jlw8j_50 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n padding: var(--wb-len-6) var(--wb-len-10);\n border-radius: var(--dsw-radius-sm);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-1);\n}\n\n._step_jlw8j_50[data-status='running'] {\n color: var(--dsw-alias-label-primary);\n}\n\n._mark_jlw8j_77 {\n flex: none;\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-14);\n height: var(--wb-len-14);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n font-variant-numeric: tabular-nums;\n}\n\n._step_jlw8j_50[data-status='ok'] ._mark_jlw8j_77 {\n color: var(--dsw-alias-state-success-primary);\n}\n\n._step_jlw8j_50[data-status='warn'] ._mark_jlw8j_77 {\n color: var(--dsw-alias-state-warn-primary);\n}\n\n._step_jlw8j_50[data-status='failed'] ._mark_jlw8j_77 {\n color: var(--dsw-alias-state-error-primary);\n}\n\n._label_jlw8j_102 {\n flex: none;\n}\n\n._detail_jlw8j_106 {\n margin-left: auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._progress_jlw8j_2 {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--wb-len-8);\n margin-top: var(--wb-len-4);\n max-width: 100%;\n}\n\n._elapsed_jlw8j_124 {\n flex: none;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n font-variant-numeric: tabular-nums;\n}\n\n._error_jlw8j_132 {\n margin: 0;\n padding: var(--wb-len-8) var(--wb-len-10);\n max-height: var(--wb-len-120);\n overflow: auto;\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-1);\n font-family: var(--ds-font-family-code, monospace);\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n white-space: pre-wrap;\n word-break: break-all;\n text-align: left;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._commandRow_jlw8j_3 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-4);\n margin: 0 0 var(--wb-len-8);\n padding-right: var(--wb-len-4);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n._copy_jlw8j_158 {\n flex: none;\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-24);\n height: var(--wb-len-24);\n padding: 0;\n border: none;\n border-radius: var(--wb-radius-6);\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n\n._copy_jlw8j_158:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._command_jlw8j_3 {\n flex: 1;\n min-width: 0;\n padding: var(--wb-len-8) var(--wb-len-10);\n border-radius: var(--dsw-radius-sm);\n background: transparent;\n font-family: var(--ds-font-family-code, monospace);\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-primary);\n}\n\n._buttons_jlw8j_191 {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--wb-len-12);\n}\n\n._mockSlot_jlw8j_198 {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n justify-content: center;\n background: var(--dsw-alias-bg-base);\n}\n\n._button_jlw8j_191 {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: var(--wb-len-28);\n padding: 0 var(--wb-len-10);\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-sm);\n background: transparent;\n font: inherit;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n\n._button_jlw8j_191:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._button_jlw8j_191:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n._actions_jlw8j_1,\n._bridge_jlw8j_4 {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--wb-len-10);\n margin-top: var(--wb-len-4);\n padding: var(--wb-len-14) var(--wb-len-16);\n border: 0.5px solid var(--dsw-alias-border-l2);\n border-radius: var(--wb-radius-14);\n background: var(--dsw-alias-bg-layer-1);\n text-align: left;\n}\n\n._fixTitle_jlw8j_249 {\n margin: 0;\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-20);\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._actions_jlw8j_1 ._hint_jlw8j_43,\n._bridge_jlw8j_4 ._hint_jlw8j_43 {\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-19);\n color: var(--dsw-alias-label-secondary);\n}\n\n._actions_jlw8j_1 ._commandRow_jlw8j_3,\n._bridge_jlw8j_4 ._commandRow_jlw8j_3 {\n margin: 0;\n}\n\n._actions_jlw8j_1 ._buttons_jlw8j_191,\n._bridge_jlw8j_4 ._buttons_jlw8j_191 {\n justify-content: flex-start;\n}\n\n._raw_jlw8j_5 {\n margin: 0;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n}\n\n._rawSummary_jlw8j_282 {\n cursor: pointer;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._actions_jlw8j_1 ._error_jlw8j_132,\n._bridge_jlw8j_4 ._error_jlw8j_132 {\n margin-top: var(--wb-len-6);\n}\n\n._bridgeLines_jlw8j_292 {\n margin: 0;\n padding-left: var(--wb-len-18);\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-8);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-19);\n color: var(--dsw-alias-label-secondary);\n}\n\n._bridgeLine_jlw8j_292 a {\n display: block;\n margin-top: var(--wb-len-4);\n width: fit-content;\n}\n\n._link_jlw8j_309 {\n color: var(--dsw-alias-label-primary);\n text-decoration: none;\n}\n\n._link_jlw8j_309::after {\n content: '↗';\n margin-left: var(--wb-len-2);\n}\n\n._link_jlw8j_309:hover {\n text-decoration: underline;\n}\n\n._loading_jlw8j_323 {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._loading_jlw8j_323[hidden] {\n display: none;\n}\n\n._loadingMotion_jlw8j_332 {\n transform-origin: center;\n animation: _wb-spin_jlw8j_1 var(--wb-dur-1-5) linear infinite;\n}\n\n._loadingTrack_jlw8j_337,\n._loadingArc_jlw8j_338 {\n fill: none;\n stroke: currentColor;\n stroke-width: 2;\n stroke-linecap: round;\n}\n\n._loadingTrack_jlw8j_337 {\n opacity: 0.25;\n}\n\n._loadingArc_jlw8j_338 {\n stroke-dasharray: 12 150;\n animation: _wb-dash_jlw8j_1 var(--wb-dur-1-5) ease-in-out infinite;\n}\n\n@keyframes _wb-spin_jlw8j_1 {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n@keyframes _wb-dash_jlw8j_1 {\n 0% {\n stroke-dasharray: 12 150;\n stroke-dashoffset: 0;\n }\n 50% {\n stroke-dasharray: 24 150;\n stroke-dashoffset: -6;\n }\n to {\n stroke-dasharray: 12 150;\n stroke-dashoffset: 0;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._loadingMotion_jlw8j_332,\n ._loadingArc_jlw8j_338 {\n animation: none;\n }\n}\n._group_1hxis_1 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-2);\n}\n\n._button_1hxis_7 {\n flex: none;\n width: var(--wb-len-28);\n height: var(--wb-len-28);\n padding: 0;\n color: var(--dsw-alias-label-secondary);\n}\n\n._button_1hxis_7:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n\n._active_1hxis_19 {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._icon_1hxis_23 {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n._icon_1hxis_23 svg {\n display: block;\n width: var(--wb-len-15);\n height: var(--wb-len-15);\n}\n\n._mirror_1hxis_35 {\n transform: scaleX(-1);\n}\n._stripTabs_1dqp4_1 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-4);\n min-width: 0;\n overflow: hidden;\n}\n\n._tab_1dqp4_9 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n flex: none;\n height: var(--wb-len-28);\n padding: 0 var(--wb-len-10);\n border: 0;\n border-radius: var(--dsw-radius-sm);\n background: none;\n font: inherit;\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-16);\n max-width: 100%;\n}\n\n._tabActive_1dqp4_25 {\n color: var(--dsw-alias-label-primary);\n}\n\n._tabQuiet_1dqp4_29 {\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n\n._tabQuiet_1dqp4_29:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._tabTitle_1dqp4_39 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._sep_1dqp4_49 {\n flex: none;\n color: var(--dsw-alias-label-dimmed);\n}\n._trigger_15ptp_1 {\n display: flex;\n align-items: center;\n}\n\n._pop_15ptp_6 {\n position: absolute;\n top: calc(var(--wb-len-38) + var(--wb-len-8));\n right: var(--wb-len-6);\n z-index: var(--wb-z-30);\n width: min(var(--wb-len-360), calc(100% - var(--wb-len-12)));\n max-width: calc(100vw - var(--wb-len-48));\n border: 0.5px solid var(--dsw-alias-border-l2);\n border-radius: var(--wb-radius-14);\n background: var(--dsw-alias-bg-layer-2);\n box-shadow: var(--dsw-shadow-lv3);\n overflow: hidden;\n}\n\n._head_15ptp_20 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n padding: var(--wb-len-10) var(--wb-len-12) var(--wb-len-9) var(--wb-len-14);\n border-bottom: 0.5px solid var(--dsw-alias-border-l2);\n}\n\n._title_15ptp_28 {\n flex: 1;\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-20);\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._rowControls_15ptp_36 {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-8);\n}\n\n._reset_15ptp_43 {\n flex: none;\n padding: var(--wb-len-3) var(--wb-len-8);\n border: none;\n border-radius: var(--wb-radius-6);\n background: transparent;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n\n._reset_15ptp_43:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._reset_15ptp_43:disabled {\n cursor: default;\n opacity: 0.5;\n}\n\n._list_15ptp_65 {\n list-style: none;\n margin: 0;\n padding: var(--wb-len-6);\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-2);\n}\n\n._row_15ptp_36 {\n position: relative;\n display: grid;\n grid-template-columns: 12px minmax(0, 1fr) auto;\n align-items: center;\n gap: var(--wb-len-8);\n padding: var(--wb-len-7) var(--wb-len-8);\n border-radius: var(--dsw-radius-sm);\n cursor: default;\n}\n\n._rowDragging_15ptp_85 {\n cursor: grabbing;\n}\n\n._rowBlocked_15ptp_89 {\n cursor: not-allowed;\n}\n\n._listDragging_15ptp_93 ._rowControls_15ptp_36 {\n pointer-events: none;\n}\n\n._row_15ptp_36:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._rowOff_15ptp_101 {\n opacity: 0.55;\n}\n\n._rowOff_15ptp_101:hover {\n opacity: 1;\n}\n\n._rowOver_15ptp_109::before {\n content: '';\n position: absolute;\n top: var(--wb-len-neg-3);\n left: var(--wb-len-8);\n right: var(--wb-len-8);\n height: var(--wb-len-2);\n background: var(--dsw-alias-brand-primary);\n}\n\n._ghost_15ptp_119 {\n position: fixed;\n z-index: var(--wb-z-40);\n pointer-events: none;\n padding: var(--wb-len-4) var(--wb-len-10);\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-1);\n box-shadow: var(--wb-static-shadow-ghost);\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-primary);\n white-space: nowrap;\n}\n\n._grip_15ptp_134 {\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n text-align: center;\n color: var(--dsw-alias-label-tertiary);\n user-select: none;\n cursor: grab;\n touch-action: none;\n}\n\n._gripDragging_15ptp_144 {\n cursor: grabbing;\n}\n\n._gripBlocked_15ptp_148 {\n cursor: not-allowed;\n}\n\n._label_15ptp_152 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-width: 0;\n}\n\n._name_15ptp_159 {\n min-width: 0;\n flex: 0 1 auto;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-primary);\n}\n\n._error_15ptp_170 {\n margin: 0;\n padding: 0 var(--wb-len-14) var(--wb-len-10);\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-state-error-primary);\n}\n\n._dep_15ptp_178 {\n flex: none;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n}\n\n._group_15ptp_186 {\n padding-top: var(--wb-len-6);\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n\n._groupTitle_15ptp_191 {\n margin: 0;\n padding: var(--wb-len-2) var(--wb-len-8) 0 var(--wb-len-14);\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n font-weight: 400;\n color: var(--dsw-alias-label-tertiary);\n}\n._panel_1whum_1 {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n z-index: var(--wb-z-10);\n visibility: hidden;\n}\n\n._panel_1whum_1[data-fullscreen] {\n z-index: var(--wb-z-40);\n}\n\n._panel_1whum_1[data-open] {\n visibility: visible;\n}\n\n._columns_1whum_18 {\n display: block;\n column-gap: var(--wb-len-12);\n}\n\n._cell_1whum_23 {\n display: flow-root;\n min-width: 0;\n break-inside: avoid;\n margin-bottom: var(--wb-len-12);\n}\n._root_1cmz0_1 {\n position: relative;\n flex: none;\n margin: 0 var(--wb-len-2) var(--wb-len-4);\n}\n\n._rail_1cmz0_7 {\n margin: 0 0 var(--wb-len-4);\n}\n\n._glyphBox_1cmz0_11 {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n}\n\n._glyph_1cmz0_11 {\n position: relative;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-16);\n height: var(--wb-len-20);\n color: var(--dsw-alias-label-tertiary);\n}\n\n._glyphActive_1cmz0_30 {\n color: var(--dsw-alias-state-business-primary);\n}\n\n._triggerName_1cmz0_34 {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: baseline;\n gap: var(--wb-len-6);\n font-size: var(--wb-font-row);\n line-height: var(--wb-line-20);\n overflow: hidden;\n}\n\n._dir_1cmz0_45 {\n flex: 0 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._name_1cmz0_53 {\n flex: 0 1 auto;\n max-width: 50%;\n font-size: var(--dsw-font-xxs-12-font-size);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._triggerName_1cmz0_34 ._name_1cmz0_53 {\n color: var(--dsw-alias-label-tertiary);\n}\n\n._row_1cmz0_66 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n width: 100%;\n min-width: 0;\n}\n\n._trailing_1cmz0_74 {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-20);\n height: var(--wb-len-20);\n margin-inline-start: auto;\n}\n\n._trailing_1cmz0_74 ._rowAction_1cmz0_84 {\n width: var(--wb-len-20);\n min-width: var(--wb-len-20);\n height: var(--wb-len-20);\n min-height: var(--wb-len-20);\n padding: 0;\n border-radius: var(--dsw-radius-sm);\n}\n\n._row_1cmz0_66 ._name_1cmz0_53 {\n color: var(--dsw-alias-label-tertiary);\n}\n\n._current_1cmz0_97 {\n flex: none;\n display: inline-flex;\n align-items: center;\n color: var(--dsw-alias-label-primary);\n}\n._dot_sosf1_1 {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n._overlay_sosf1_8 {\n position: absolute;\n inset-block-start: var(--wb-len-neg-3);\n inset-inline-end: var(--wb-len-neg-3);\n}\n._tag_g9dg8_1 {\n flex: none;\n margin-inline-start: auto;\n}\n._dialog_1vye5_1 {\n width: min(var(--wb-len-420), 100%);\n}\n\n._stack_1vye5_5 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-8);\n min-width: 0;\n}\n\n._input_1vye5_12 {\n width: 100%;\n height: var(--wb-len-40);\n padding: 0 var(--wb-len-12);\n}\n\n._meta_1vye5_18 {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--wb-len-12);\n min-width: 0;\n}\n._blocker_1oaj0_1 {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--wb-len-6);\n padding: var(--wb-len-20) var(--wb-len-16);\n text-align: center;\n}\n\n._icon_1oaj0_10 {\n display: flex;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._title_1oaj0_15 {\n margin: var(--wb-len-2) 0 0;\n font-size: var(--dsw-font-s-14-font-size);\n line-height: var(--wb-line-22);\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._hint_1oaj0_23 {\n margin: 0;\n max-width: var(--wb-len-42em);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n text-wrap: pretty;\n}\n\n._blocker_1oaj0_1._blockerInline_1oaj0_32 {\n align-items: flex-start;\n gap: var(--wb-len-6);\n padding: var(--wb-len-4) 0 var(--wb-len-2);\n text-align: left;\n}\n\n._blocker_1oaj0_1._blockerInline_1oaj0_32 ._title_1oaj0_15 {\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-20);\n}\n\n._blocker_1oaj0_1._blockerInline_1oaj0_32 ._hint_1oaj0_23 {\n max-width: 100%;\n}\n\n._blocker_1oaj0_1._blockerInline_1oaj0_32 ._actions_1oaj0_48 {\n margin-top: var(--wb-len-8);\n}\n\n._blocker_1oaj0_1._blockerInline_1oaj0_32 ._raw_1oaj0_52 {\n margin-top: var(--wb-len-4);\n max-width: 100%;\n}\n\n._actions_1oaj0_48 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-10);\n margin-top: var(--wb-len-6);\n}\n\n._raw_1oaj0_52 {\n margin-top: var(--wb-len-10);\n width: 100%;\n max-width: var(--wb-len-360);\n text-align: left;\n}\n\n._notice_1oaj0_71 {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: start;\n column-gap: var(--wb-len-10);\n margin: 0 0 var(--wb-len-10);\n padding: var(--wb-len-10) var(--wb-len-12);\n border: 0.5px solid var(--dsw-alias-border-l2);\n border-left: 2px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-1);\n}\n\n._notice_1oaj0_71._noticeFlat_1oaj0_84 {\n margin: 0;\n padding: 0;\n border: 0;\n background: transparent;\n}\n\n._noticeText_1oaj0_91 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-3);\n min-width: 0;\n}\n\n._noticeTitle_1oaj0_98 {\n font-size: var(--wb-font-12-5);\n line-height: var(--wb-line-18);\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._noticeHint_1oaj0_105 {\n font-size: var(--wb-font-11-5);\n line-height: var(--wb-line-17);\n color: var(--dsw-alias-label-tertiary);\n overflow-wrap: anywhere;\n}\n\n._noticeActions_1oaj0_112 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n margin-top: var(--wb-len-neg-2);\n}\n\n._failure_1oaj0_119 {\n margin: var(--wb-len-8) 0 0;\n font-size: var(--wb-font-11-5);\n line-height: var(--wb-line-17);\n color: var(--dsw-alias-state-error-primary);\n overflow-wrap: anywhere;\n}\n\n._failureDetail_1oaj0_127 {\n display: block;\n margin-top: var(--wb-len-2);\n color: var(--dsw-alias-label-tertiary);\n white-space: pre-wrap;\n}\n\n._inlineAction_1oaj0_134 {\n padding: 0;\n border: none;\n background: transparent;\n cursor: pointer;\n}\n\n._inlineAction_1oaj0_134:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n._rawText_1oaj0_146 {\n margin: var(--wb-len-6) 0 0;\n max-width: 100%;\n}\n/*$vite$:1*/";
|
|
11691
|
+
var COMPONENT_CSS_MARKER = "\n.wb-activityBlock {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-6);\n padding-top: var(--wb-len-10);\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n\n.wb-activityBlock:first-child {\n padding-top: 0;\n border-top: none;\n}\n\n.wb-activityBlockHead {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--wb-len-8);\n}\n\n.wb-activityLine {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-secondary);\n}\n\n.wb-activityLineText {\n flex: none;\n min-width: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n max-height: var(--wb-len-72);\n overflow-y: auto;\n}\n\n.wb-activityLineAt {\n flex: none;\n margin-left: auto;\n font-size: var(--wb-font-10);\n line-height: var(--wb-line-16);\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-activityLine > .wb-activityLineAt,\n.wb-activityLine > .wb-activityLineActions {\n margin-left: auto;\n}\n\n.wb-activityLine > .wb-activityLineAt + .wb-activityLineActions {\n margin-left: 0;\n}\n\n.wb-activityLineActions {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n}\n\n.wb-activityActionFailed {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.wb-note {\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n.wb-problem {\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-state-error-primary);\n overflow-wrap: anywhere;\n}\n\n.wb-approvalCommand {\n max-width: 100%;\n}\n.wb-approvalPlan {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-6);\n}\n.wb-approvalHint {\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-secondary);\n}\n.wb-approvalRows {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-2);\n margin: 0;\n}\n.wb-approvalRow {\n display: flex;\n align-items: baseline;\n gap: var(--wb-len-8);\n}\n.wb-approvalLabel {\n flex: none;\n width: var(--wb-len-56);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n.wb-approvalValue {\n margin: 0;\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-18);\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n overflow-wrap: anywhere;\n}\n.wb-approvalWarn {\n color: var(--dsw-alias-label-secondary);\n}\n\n.wb-cardHead {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n flex: none;\n padding: var(--wb-len-8) var(--wb-len-10) var(--wb-len-8) var(--wb-card-gutter);\n border-bottom: 0.5px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.wb-cardTitle {\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n font-weight: 600;\n color: var(--dsw-alias-label-secondary);\n}\n\n.wb-cardMeta {\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.wb-cardMeta::before {\n content: '\\00b7';\n margin-right: var(--wb-len-6);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-cardOpen {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n margin-left: auto;\n flex: none;\n width: var(--wb-len-22);\n height: var(--wb-len-22);\n padding: var(--wb-len-4);\n border-radius: var(--wb-radius-6);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-cardOpen ~ .wb-cardRefresh {\n margin-left: 0;\n}\n\n.wb-cardOpen:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.wb-cardRefresh {\n margin-left: auto;\n flex: none;\n width: var(--wb-len-22);\n height: var(--wb-len-22);\n padding: var(--wb-len-4);\n border-radius: var(--wb-radius-6);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-cardRefresh:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n\n.wb-cardRefresh:disabled {\n cursor: default;\n opacity: 1;\n}\n\n.wb-cardGear {\n flex: none;\n width: var(--wb-len-22);\n height: var(--wb-len-22);\n padding: var(--wb-len-3);\n border-radius: var(--wb-radius-6);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-cardGear:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n\n.wb-card {\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-xl);\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n flex: none;\n}\n.wb-cardBody {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-12);\n padding: var(--wb-len-12) var(--wb-card-gutter);\n font-size: var(--dsw-font-xxs-12-font-size);\n}\n.wb-cardBleed {\n margin-inline: calc(-1 * var(--wb-card-gutter));\n}\n._anchor_yq4s2_1 {\n display: contents;\n}\n\n.wb-spinner {\n display: inline-flex;\n align-items: center;\n flex: none;\n}\n\n.wb-choiceMenu {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-2);\n background: transparent;\n}\n\n.wb-choiceMenu[data-variant='boxed'] {\n padding: var(--wb-len-4);\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n}\n\n.wb-choiceOption {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-height: var(--wb-len-28);\n padding: var(--wb-len-4) var(--wb-len-8);\n border-radius: var(--dsw-radius-md);\n cursor: pointer;\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-20);\n color: var(--dsw-alias-label-primary);\n}\n\n.wb-choiceOptionOn {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.wb-checkbox {\n position: absolute;\n width: var(--wb-len-16);\n height: var(--wb-len-16);\n margin: 0;\n opacity: 0;\n pointer-events: none;\n}\n\n.wb-checkboxBox {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n flex: none;\n width: var(--wb-len-16);\n height: var(--wb-len-16);\n border: 1px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-xs);\n corner-shape: round;\n color: var(--dsw-alias-label-primary-foreground);\n transition:\n background-color var(--wb-dur-0-12) ease, border-color var(--wb-dur-0-12) ease;\n}\n\n.wb-choiceOption:hover .wb-checkboxBox {\n border-color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-checkbox:checked + .wb-checkboxBox {\n border-color: var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n}\n\n.wb-checkbox:disabled + .wb-checkboxBox {\n cursor: default;\n}\n\n.wb-checkbox:focus-visible + .wb-checkboxBox {\n outline: var(--dsw-focus-ring-width, var(--wb-len-2)) solid\n var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: 2px;\n}\n\n.wb-choiceOption:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.wb-choiceOption:has(:disabled) {\n cursor: default;\n opacity: 0.5;\n}\n\n.wb-choiceOption:has(:disabled),\n.wb-choiceOption:has(:disabled):hover {\n background: transparent;\n}\n\n.wb-choiceLabel {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.wb-choiceLabelText {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.wb-choiceLabel:has(.wb-choiceDescription) .wb-choiceLabelText {\n overflow: visible;\n white-space: normal;\n overflow-wrap: anywhere;\n}\n\n.wb-choiceDescription {\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n overflow-wrap: anywhere;\n}\n\n.wb-choiceLoading {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-height: var(--wb-len-28);\n padding: var(--wb-len-4) var(--wb-len-8);\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-20);\n color: var(--dsw-alias-label-secondary);\n}\n\n.wb-choiceLoadingText {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.wb-choiceEmpty {\n display: flex;\n align-items: center;\n min-height: var(--wb-len-28);\n padding: var(--wb-len-4) var(--wb-len-8);\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-20);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-radio {\n appearance: none;\n -webkit-appearance: none;\n flex: none;\n box-sizing: border-box;\n width: var(--wb-len-12);\n height: var(--wb-len-12);\n margin: 0;\n border: 1px solid var(--dsw-alias-border-l3);\n border-radius: 50%;\n corner-shape: round;\n background-color: transparent;\n cursor: pointer;\n transition:\n background-color var(--wb-dur-0-12) ease, border-color var(--wb-dur-0-12) ease;\n}\n\n.wb-radio:not(:checked):hover {\n border-color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-radio:checked {\n border-color: var(--dsw-alias-brand-primary);\n background-image: radial-gradient(\n circle at center,\n var(--dsw-alias-brand-primary) 0 3px,\n transparent 3px\n );\n}\n\n.wb-radio:disabled {\n cursor: default;\n}\n\n.wb-radio:focus-visible {\n outline: var(--dsw-focus-ring-width, var(--wb-len-2)) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: 2px;\n}.wb-field {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-6);\n font-size: var(--dsw-font-xs-13-font-size);\n}\n\n.wb-fieldLabel {\n color: var(--dsw-alias-label-secondary);\n}\n\n.wb-fieldHint {\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-field:has(:disabled) .wb-fieldLabel {\n opacity: 0.4;\n}\n.wb-formActions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n gap: var(--wb-len-8);\n}\n\n.wb-formActionDanger {\n color: var(--dsw-alias-state-error-primary);\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 30%, transparent);\n --dsw-alias-interactive-bg-hover: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);\n}\n.wb-formRows {\n display: grid;\n grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);\n column-gap: var(--wb-len-8);\n row-gap: var(--wb-len-12);\n}\n\n.wb-formRows > :not(.wb-formRow) {\n grid-column: 1 / -1;\n}\n\n.wb-formRow {\n display: grid;\n grid-column: 1 / -1;\n grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);\n align-items: center;\n column-gap: var(--wb-len-8);\n row-gap: var(--wb-len-8);\n}\n\n.wb-formRow[data-layout='stacked'] {\n grid-template-columns: minmax(0, 1fr);\n align-items: stretch;\n gap: var(--wb-len-6);\n}\n\n.wb-formLabel {\n min-width: 0;\n font-size: var(--dsw-font-xs-13-font-size);\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n white-space: nowrap;\n}\n\n.wb-formRow[data-layout='stacked'] .wb-formLabel {\n white-space: normal;\n}\n\n.wb-formControl {\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.wb-formHint {\n grid-column: 2;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-formProblem {\n grid-column: 2;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.wb-formRow:has(.wb-formProblem) .wb-formLabel {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.wb-formRow:has(:disabled) .wb-formLabel {\n opacity: 0.4;\n}\n\n.wb-formRows > .wb-formRow {\n grid-template-columns: subgrid;\n}\n\n@supports not (grid-template-columns: subgrid) {\n .wb-formRows > .wb-formRow {\n grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);\n }\n}\n.wb-form {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-12);\n width: 100%;\n}:where(.wb-link) {\n margin-left: var(--wb-len-2);\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-2);\n font: inherit;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-primary);\n text-decoration: none;\n white-space: nowrap;\n vertical-align: baseline;\n}\n\n:where(.wb-link:hover) {\n text-decoration: underline;\n}\n\n:where(.wb-link:focus-visible) {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: -2px;\n}\n\n.wb-longTask {\n padding-top: var(--wb-len-12);\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-2);\n}\n\n.wb-longTaskHead {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n margin: 0;\n}\n\n.wb-longTaskLink {\n flex: none;\n}\n\n.wb-longTaskHeadline {\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-secondary);\n}\n\n.wb-longTaskProblem {\n margin: 0;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-state-error-primary);\n overflow-wrap: anywhere;\n}\n\n.wb-longTaskDump {\n margin: var(--wb-len-2) 0 0;\n font-size: var(--dsw-font-xxxs-11-font-size);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-longTaskDump pre {\n margin: var(--wb-len-4) 0 0;\n max-height: var(--wb-len-220);\n overflow: auto;\n}\n.wb-centered.wb-centeredCompact {\n flex: none;\n min-height: 0;\n gap: var(--wb-len-8);\n padding: var(--wb-len-20) var(--wb-len-16);\n}\n\n.wb-centered.wb-centeredCompact .wb-centeredHero {\n margin-bottom: var(--wb-len-4);\n}\n\n.wb-skeleton {\n display: flex;\n flex-direction: column;\n}\n\n.wb-skeletonRow {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-8);\n padding: var(--wb-len-8);\n border-radius: var(--dsw-radius-md);\n}\n\n.wb-skeletonRow + .wb-skeletonRow::before {\n content: '';\n align-self: stretch;\n height: var(--wb-len-0-5);\n margin: 0 var(--wb-len-8) var(--wb-len-neg-0-5);\n background: var(--dsw-alias-border-l2);\n}\n\n.wb-skeletonBar {\n display: block;\n height: var(--wb-len-13);\n border-radius: var(--dsw-radius-xs);\n background: var(--dsw-alias-bg-skeleton);\n animation: wb-skeleton-pulse var(--wb-dur-1-4) var(--ds-ease-in-out) infinite;\n}\n\n.wb-skeletonBarTitle {\n width: 62%;\n}\n\n.wb-skeletonBarMeta {\n width: 32%;\n height: var(--wb-len-10);\n}\n\n.wb-skeletonRow:nth-child(2n) .wb-skeletonBarTitle {\n width: 74%;\n}\n\n.wb-skeletonRow:nth-child(3n) .wb-skeletonBarTitle {\n width: 52%;\n}\n\n@keyframes wb-skeleton-pulse {\n 50% {\n opacity: 0.45;\n }\n}\n\n.wb-centered {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n gap: var(--wb-len-14);\n flex: 1;\n min-height: var(--wb-len-240);\n padding: 0 var(--wb-len-24) var(--wb-len-24);\n text-align: center;\n}\n\n.wb-centeredHero {\n display: flex;\n margin-bottom: var(--wb-len-16);\n color: var(--dsw-alias-label-dimmed);\n}\n\n.wb-centeredTitle {\n font-size: var(--dsw-font-s-14-font-size);\n line-height: var(--wb-line-22);\n color: var(--dsw-alias-label-primary);\n}\n\n.wb-centeredHint {\n max-width: var(--wb-len-300);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-centeredDetail {\n max-width: var(--wb-len-320);\n font-family: var(--ds-font-family-code, monospace);\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-dimmed);\n word-break: break-all;\n}\n\n.wb-centeredAction {\n display: flex;\n justify-content: center;\n gap: var(--wb-len-8);\n margin-top: var(--wb-len-2);\n}\n@media (prefers-reduced-motion: reduce) {\n .wb-skeletonBar {\n animation: none;\n }}\n.wb-rows {\n display: grid;\n grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);\n column-gap: var(--wb-len-8);\n}\n.wb-rows > :not(.wb-row) {\n grid-column: 1 / -1;\n}\n.wb-row {\n display: grid;\n grid-column: 1 / -1;\n grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);\n align-items: baseline;\n gap: var(--wb-len-8);\n padding: var(--wb-len-4) 0;\n}\n.wb-row + .wb-row {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.wb-rowKey {\n white-space: nowrap;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n}\n.wb-rowValue {\n min-width: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-primary);\n overflow-wrap: anywhere;\n}\n\n.wb-rows > .wb-row {\n grid-template-columns: subgrid;\n}\n\n@supports not (grid-template-columns: subgrid) {\n .wb-rows > .wb-row {\n grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);\n }\n}\n.wb-textField {\n box-sizing: border-box;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-primary);\n outline: none;\n}\n\n.wb-textField:focus {\n border-color: var(--dsw-alias-state-business-primary);\n box-shadow: inset 0 0 0 0.5px var(--dsw-alias-state-business-primary);\n}\n\n.wb-textField:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.wb-textField[aria-invalid='true'] {\n border-color: var(--dsw-alias-state-error-primary);\n}\n\n.wb-textField[aria-invalid='true']:focus {\n box-shadow: inset 0 0 0 0.5px var(--dsw-alias-state-error-primary);\n}\n\n:where(.wb-textField) {\n min-height: var(--wb-len-28);\n padding: var(--wb-len-4) var(--wb-len-10);\n}\n:where(.wb-selectTrigger) {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n width: 100%;\n min-height: var(--wb-len-28);\n padding: var(--wb-len-4) var(--wb-len-10);\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-primary);\n text-align: left;\n cursor: pointer;\n}\n\n.wb-selectTrigger:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-state-business-primary);\n box-shadow: inset 0 0 0 0.5px var(--dsw-alias-state-business-primary);\n}\n\n.wb-selectTrigger[aria-invalid='true'] {\n border-color: var(--dsw-alias-state-error-primary);\n}\n\n.wb-selectTrigger[aria-invalid='true']:focus-visible {\n box-shadow: inset 0 0 0 0.5px var(--dsw-alias-state-error-primary);\n}\n\n.wb-selectTrigger:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.wb-selectLoading:disabled {\n cursor: default;\n opacity: 1;\n}\n\n.wb-selectGhost {\n gap: var(--wb-gap-xs);\n min-height: 0;\n height: var(--wb-len-34);\n padding: 0 var(--wb-len-8);\n border: none;\n background: transparent;\n font-size: var(--wb-font-row);\n}\n\n.wb-selectGhost:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.wb-selectGhost:focus-visible {\n outline: var(--dsw-focus-ring-width) solid\n var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: -2px;\n border-color: transparent;\n box-shadow: none;\n}\n\n.wb-selectIconOnly {\n width: var(--wb-len-36);\n height: var(--wb-len-36);\n min-height: 0;\n gap: 0;\n padding: 0;\n justify-content: center;\n}\n\n.wb-selectReveal {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.wb-selectIconOnly .wb-selectIcon {\n width: 100%;\n height: 100%;\n}\n\n.wb-selectAnchor {\n display: block;\n width: 100%;\n}\n\n.wb-selectIcon {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-16);\n height: var(--wb-len-20);\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-selectValue {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: baseline;\n gap: var(--wb-len-6);\n line-height: var(--wb-line-20);\n overflow: hidden;\n}\n\n.wb-selectPlaceholder {\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-selectChevron {\n flex: none;\n display: inline-flex;\n color: var(--dsw-alias-label-caption);\n}\n\n.wb-selectMenu {\n min-width: var(--wb-len-240);\n max-width: var(--wb-len-360);\n max-height: min(var(--wb-len-320), calc(100vh - var(--wb-len-24)));\n}\n\n:where(.wb-selectSearch) {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n width: 100%;\n min-height: var(--wb-len-28);\n padding: var(--wb-len-4) var(--wb-len-10);\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n}\n\n.wb-selectSearch:focus-within {\n border-color: var(--dsw-alias-state-business-primary);\n box-shadow: inset 0 0 0 0.5px var(--dsw-alias-state-business-primary);\n}\n\n.wb-selectSearch.wb-selectGhost {\n gap: var(--wb-gap-xs);\n min-height: 0;\n height: var(--wb-len-34);\n padding: 0 var(--wb-len-8);\n border: 0.5px solid var(--dsw-alias-border-l3);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.wb-selectSearch.wb-selectGhost:focus-within {\n border-color: var(--dsw-alias-state-business-primary);\n box-shadow: none;\n}\n\n.wb-selectSearchIcon {\n flex: none;\n display: inline-flex;\n color: var(--dsw-alias-label-tertiary);\n}\n\n.wb-textField.wb-selectSearchInput {\n flex: 1;\n min-width: 0;\n min-height: 0;\n padding: 0;\n border: none;\n background: transparent;\n}\n\n.wb-textField.wb-selectSearchInput:focus {\n box-shadow: none;\n}\n\n.wb-selectFallback {\n width: 100%;\n}\n\n.wb-selectHint {\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n\nsection.wb-settings {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-12);\n padding: var(--wb-len-12) var(--wb-len-16);\n border: 0;\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-settings-card-fill);\n}\n.wb-settingsHead {\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n}\n.wb-settings .wb-settingsTitle {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--dsw-font-s-strong-14-font-size);\n line-height: var(--wb-line-24);\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n.wb-stack {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-10);\n min-height: 0;\n}\n\n.wb-stateBlock {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-6);\n}\n.wb-stateBlockTitle {\n margin: 0;\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-primary);\n}\n.wb-stateBlockHint {\n margin: 0;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n}\n.wb-stateBlockActions {\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n margin-top: var(--wb-len-2);\n}\n.wb-stateBlockResolving {\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-secondary);\n}\n._marketList_csyus_1 {\n list-style: none;\n margin: 0;\n padding: var(--wb-len-6);\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-2);\n}\n\n._marketRow_csyus_10 {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr) auto;\n align-items: center;\n column-gap: var(--wb-len-14);\n row-gap: var(--wb-len-4);\n padding: var(--wb-len-8);\n border-radius: var(--dsw-radius-lg);\n}\n\n._marketIcon_csyus_20 {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-40);\n height: var(--wb-len-40);\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n color: var(--dsw-alias-label-secondary);\n}\n\n._marketMain_csyus_32 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-4);\n min-width: 0;\n}\n\n._marketName_csyus_39 {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font: var(--dsw-font-base-strong-16);\n color: var(--dsw-alias-label-primary);\n}\n\n._marketDesc_csyus_48 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-width: 0;\n overflow: hidden;\n white-space: nowrap;\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-label-secondary);\n}\n\n._marketUsedBy_csyus_59 {\n margin-left: var(--wb-len-8);\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n opacity: 0.75;\n}\n\n._marketUsedBy_csyus_59::before {\n content: '·';\n margin-right: var(--wb-len-6);\n opacity: 0.8;\n}\n\n._marketName_csyus_39 ._marketVersion_csyus_73 {\n margin-left: var(--wb-len-6);\n font-size: var(--dsw-font-xxs-12-font-size);\n font-weight: 400;\n line-height: var(--wb-line-18);\n}\n\n._marketVersion_csyus_73 {\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-caption);\n}\n\n._marketVersion_csyus_73::before {\n content: '';\n display: inline-block;\n width: var(--wb-len-1);\n height: var(--wb-len-10);\n margin: 0 var(--wb-len-8) 0 var(--wb-len-2);\n vertical-align: -1px;\n background: var(--dsw-alias-border-l2);\n}\n\n._marketLocalTag_csyus_95 {\n margin-left: var(--wb-len-8);\n padding: 0 var(--wb-len-6);\n border: var(--wb-len-1) solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n font-size: var(--dsw-font-xxs-12-font-size);\n font-weight: 400;\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-caption);\n}\n\n._marketEnd_csyus_106 {\n flex: none;\n display: flex;\n align-items: center;\n gap: var(--wb-len-10);\n}\n\n._marketSwitchSeat_csyus_113 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-10);\n}\n\n._marketSwitchSeat_csyus_113::before {\n content: '';\n width: 0;\n height: var(--wb-len-14);\n border-left: 0.5px solid var(--dsw-alias-border-l3);\n}\n\n._marketActions_csyus_126 {\n flex: none;\n display: flex;\n gap: var(--wb-len-6);\n}\n\n._marketUpdateAction_csyus_132 {\n color: var(--dsw-alias-state-warn-primary);\n border-color: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 30%, transparent);\n --dsw-alias-interactive-bg-hover: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);\n}\n\n._marketSelfDivider_csyus_138 {\n height: 0;\n border-top: 0.5px solid var(--dsw-alias-border-l3);\n}\n\n._marketSection_csyus_143 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-8);\n min-width: 0;\n}\n\n._marketSectionHead_csyus_150 {\n display: flex;\n align-items: baseline;\n gap: var(--wb-len-8);\n}\n\n._marketSectionIcon_csyus_156 {\n display: inline-flex;\n align-items: center;\n align-self: center;\n color: var(--dsw-alias-label-caption);\n}\n\n._marketSectionTitle_csyus_163 {\n margin: 0;\n font: var(--dsw-font-base-strong-16);\n color: var(--dsw-alias-label-primary);\n}\n\n._marketSectionCount_csyus_169 {\n font: var(--dsw-font-s-14);\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-caption);\n}\n\n\n._marketProgress_csyus_176 {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-8);\n min-height: var(--wb-len-32);\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-label-secondary);\n}\n\n._marketNote_csyus_186 {\n grid-column: 2 / -1;\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-state-warn-primary);\n overflow-wrap: anywhere;\n}\n\n._marketNotePlain_csyus_193 {\n grid-column: 2 / -1;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-caption);\n overflow-wrap: anywhere;\n}\n\n._marketFailure_csyus_201 {\n grid-column: 2 / -1;\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-state-error-primary);\n overflow-wrap: anywhere;\n}\n\n._marketEmpty_csyus_208 {\n padding: var(--wb-len-18) var(--wb-len-16);\n text-align: center;\n}\n\n._marketPage_csyus_213 {\n box-sizing: border-box;\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--wb-len-32);\n padding: 0 clamp(var(--wb-len-24), 4vw, var(--wb-len-48)) var(--wb-len-48);\n overflow-x: hidden;\n overflow-y: auto;\n color: var(--dsw-alias-label-primary);\n}\n\n._marketPage_csyus_213 > * {\n width: 100%;\n max-width: var(--wb-len-960);\n}\n\n._marketPageHead_csyus_231 {\n box-sizing: border-box;\n display: flex;\n align-items: flex-start;\n gap: var(--wb-len-16);\n padding-top: var(--wb-len-28);\n}\n\n._marketPageTitle_csyus_239 {\n margin: 0;\n font: var(--dsw-font-l-20);\n}\n\n._marketPageIntro_csyus_244 {\n margin: var(--wb-len-4) 0 0;\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-secondary);\n}\n\n._marketPageTools_csyus_250 {\n flex: none;\n align-self: center;\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: var(--wb-len-16);\n}\n\n._marketIconButton_csyus_259 {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-28);\n height: var(--wb-len-28);\n padding: 0;\n border: 0;\n border-radius: var(--dsw-radius-sm);\n background: transparent;\n color: var(--dsw-alias-label-caption);\n cursor: pointer;\n}\n\n._marketIconButton_csyus_259:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n\n._marketIconButton_csyus_259:disabled {\n cursor: default;\n opacity: 0.5;\n}\n\n._marketIconWrap_csyus_284 {\n display: inline-flex;\n}\n\n._marketIconButtonSpinning_csyus_288 svg {\n animation: _wb-spin_csyus_1 var(--wb-dur-0-9) linear infinite;\n}\n\n._marketAddButton_csyus_292 {\n height: var(--wb-len-32);\n padding: 0 var(--wb-len-12);\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-20);\n border-radius: var(--dsw-radius-md);\n}\n\n._marketEmpty_csyus_208 {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--wb-len-8);\n padding: var(--wb-len-64) var(--wb-len-16);\n text-align: center;\n}\n\n._marketChecking_csyus_309 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-label-secondary);\n}\n\n._marketEmptyTitle_csyus_317 {\n font: var(--dsw-font-base-strong-16);\n color: var(--dsw-alias-label-primary);\n}\n\n@keyframes _wb-spin_csyus_1 {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n._foot_1ud1j_1 {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--wb-len-8);\n padding: var(--wb-len-8) var(--wb-len-14) var(--wb-len-10);\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n}\n\n._footText_1ud1j_13 {\n flex: 1;\n min-width: 0;\n}\n\n._footTextMd_1ud1j_18 {\n flex: 1;\n min-width: 0;\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-label-secondary);\n}\n._wide_1lv8f_1 {\n justify-content: center;\n width: 100%;\n height: var(--wb-len-40);\n border-radius: var(--dsw-radius-md);\n}\n\n._dialog_1lv8f_8 {\n width: min(var(--wb-len-560), 100%);\n max-height: min(var(--wb-len-800), 100%);\n}\n\n._content_1lv8f_13 {\n min-height: 0;\n overflow: auto;\n}\n\n._stack_1lv8f_18 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-12);\n min-width: 0;\n}\n\n._body_1lv8f_25 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-12);\n min-width: 0;\n}\n\n._field_1lv8f_32 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-6);\n font-size: var(--dsw-font-xs-13-font-size);\n}\n\n._input_1lv8f_39 {\n width: 100%;\n height: var(--wb-len-40);\n padding: 0 var(--wb-len-14);\n}\n\n._registryField_1lv8f_45 {\n height: var(--wb-len-32);\n margin-left: var(--wb-len-26);\n padding: 0 var(--wb-len-10);\n}\n\n._options_1lv8f_51 {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--wb-len-8) var(--wb-len-12);\n}\n\n._guideToggle_1lv8f_59 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-4);\n align-self: flex-start;\n margin-top: var(--wb-len-4);\n padding: 0;\n border: 0;\n background: transparent;\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n._guideToggle_1lv8f_59:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n._guideToggle_1lv8f_59 svg,\n._registryToggle_1lv8f_78 svg {\n transition: transform var(--wb-dur-0-12) ease;\n}\n\n._guideToggle_1lv8f_59[aria-expanded='true'] svg,\n._registryToggle_1lv8f_78[aria-expanded='true'] svg {\n transform: rotate(180deg);\n}\n\n._registryWrap_1lv8f_87 {\n position: relative;\n flex: none;\n}\n\n._registryToggle_1lv8f_78 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n height: var(--wb-len-26);\n padding: 0 var(--wb-len-8) 0 var(--wb-len-10);\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-2);\n font: inherit;\n font-size: var(--wb-font-12-5);\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n._registryToggle_1lv8f_78:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n\n._registryToggle_1lv8f_78:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n._registryToggle_1lv8f_78[aria-expanded='true'] {\n border-color: var(--dsw-alias-border-l3);\n background: var(--dsw-alias-bg-layer-3);\n}\n\n._registryChosen_1lv8f_121 {\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n\n._registry_1lv8f_45 {\n position: fixed;\n z-index: var(--wb-z-1100);\n box-sizing: border-box;\n width: min(var(--wb-len-440), 100vw - var(--wb-len-24));\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-4);\n margin: 0;\n padding: var(--wb-len-8) var(--wb-len-10) var(--wb-len-12);\n border: 0;\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-alias-bg-layer-2);\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l3);\n box-shadow: var(--dsw-elevation-prominent);\n}\n\n._registryOption_1lv8f_143 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-4);\n padding: var(--wb-len-8) var(--wb-len-10);\n border: 0.5px solid transparent;\n border-radius: var(--dsw-radius-lg);\n cursor: pointer;\n}\n\nlabel._registryOption_1lv8f_143 {\n flex-direction: row;\n align-items: flex-start;\n gap: var(--wb-len-10);\n}\n\n._registryPick_1lv8f_159 {\n display: flex;\n align-items: flex-start;\n gap: var(--wb-len-10);\n cursor: pointer;\n}\n\n._registryOption_1lv8f_143[data-checked='true'] {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 40%, transparent);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n._registryOption_1lv8f_143 input[type='radio'] {\n flex: none;\n width: var(--wb-len-16);\n height: var(--wb-len-16);\n margin: var(--wb-len-2) 0 0;\n accent-color: var(--dsw-alias-brand-primary);\n}\n\n._registryTitle_1lv8f_179 {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--wb-len-8);\n font: var(--dsw-font-xs-13);\n line-height: var(--wb-line-20);\n color: var(--dsw-alias-label-primary);\n}\n\n._registryHint_1lv8f_189 {\n margin-left: var(--wb-len-26);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n overflow-wrap: anywhere;\n}\n\n._inputError_1lv8f_197 {\n margin: var(--wb-len-neg-4) 0 0 var(--wb-len-26);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-state-error-primary);\n}\n\n._guide_1lv8f_59 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-10);\n padding: var(--wb-len-8) var(--wb-len-14) var(--wb-len-14);\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-alias-bg-layer-1);\n}\n\n._guideList_1lv8f_214 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-2);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n._guideItem_1lv8f_223 {\n display: flex;\n align-items: flex-start;\n gap: var(--wb-len-10);\n padding: var(--wb-len-8) 0;\n}\n\n._guideIndex_1lv8f_230 {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-20);\n height: var(--wb-len-20);\n border-radius: var(--wb-radius-pill);\n corner-shape: round;\n background: var(--dsw-alias-bg-module-platform);\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-secondary);\n}\n\n._guideMain_1lv8f_244 {\n display: flex;\n flex-direction: column;\n flex: 1;\n gap: 0;\n min-width: 0;\n}\n\n._guideTitle_1lv8f_252 {\n font: var(--dsw-font-s-14);\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n._guideHint_1lv8f_258 {\n margin: 0;\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-caption);\n}\n\n._guideExample_1lv8f_264 {\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n}\n\n._guideExample_1lv8f_264 code {\n font-family: var(--dsw-font-mono, monospace);\n}\n\n._guideExampleLabel_1lv8f_274 {\n color: var(--dsw-alias-label-caption);\n}\n\n._footer_1lv8f_278 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-20);\n width: 100%;\n}\n\n._hero_1lv8f_285 {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--wb-len-10);\n padding: var(--wb-len-8) 0 var(--wb-len-4);\n text-align: center;\n}\n\n._heroIcon_1lv8f_294 {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-44);\n height: var(--wb-len-44);\n color: var(--dsw-alias-label-secondary);\n}\n\n._heroIcon_1lv8f_294[data-state='done'] {\n color: var(--dsw-alias-state-success-secondary);\n}\n\n._heroIcon_1lv8f_294[data-state='error'] {\n color: var(--dsw-alias-state-warn-label);\n}\n\n._pendingTitle_1lv8f_311 {\n margin: 0;\n font-size: var(--dsw-font-s-14-font-size);\n line-height: var(--wb-line-22);\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n._wizardTitle_1lv8f_319 {\n margin: 0;\n font-size: var(--wb-font-18);\n line-height: var(--wb-len-26);\n font-weight: 600;\n}\n\n._subject_1lv8f_326 {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--wb-len-6);\n padding: var(--wb-len-16);\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-lg);\n text-align: center;\n}\n\n._subjectName_1lv8f_337 {\n margin: 0;\n font: var(--dsw-font-base-strong-16);\n overflow-wrap: anywhere;\n}\n\n._subjectMeta_1lv8f_343,\n._subjectDesc_1lv8f_344 {\n margin: 0;\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n}\n\n._result_1lv8f_351,\n._resultWarn_1lv8f_352 {\n margin: 0;\n padding: var(--wb-len-8) var(--wb-len-12);\n border-radius: var(--dsw-radius-md);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent);\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-label-primary);\n}\n\n._resultWarn_1lv8f_352 {\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n}\n\n._resultMeta_1lv8f_365 {\n margin: 0;\n padding: 0 var(--wb-len-12);\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n}\n\n._approval_1lv8f_373 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-8);\n padding: var(--wb-len-12) var(--wb-len-14);\n border: 0.5px solid var(--dsw-alias-state-warn-primary);\n border-radius: var(--dsw-radius-lg);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);\n}\n\n._approvalTitle_1lv8f_383 {\n margin: 0;\n font: var(--dsw-font-s-14);\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._approvalText_1lv8f_390 {\n margin: 0;\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-secondary);\n}\n\n._approvalCaution_1lv8f_396 {\n margin: 0;\n font: var(--dsw-font-xs-13);\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n._note_1lv8f_403 {\n margin: 0;\n font: var(--dsw-font-s-14);\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n}\n\n._noteWarn_1lv8f_410 {\n color: var(--dsw-alias-state-warn-primary);\n}\n\n._noteError_1lv8f_414 {\n color: var(--dsw-alias-state-error-primary);\n}\n\n._problem_1lv8f_418 {\n margin: 0;\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-state-error-primary);\n overflow-wrap: anywhere;\n}\n\n._detailLabel_1lv8f_425 {\n margin: 0;\n font: var(--dsw-font-xs-13);\n color: var(--dsw-alias-label-caption);\n}\n\n._detail_1lv8f_425 {\n margin: 0;\n padding: var(--wb-len-8) var(--wb-len-10);\n border: 0.5px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-3);\n font-family: var(--dsw-font-mono, monospace);\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n._note_1enlz_1 {\n display: flex;\n align-items: flex-start;\n gap: var(--wb-len-8);\n margin: 0;\n padding: var(--wb-len-10) var(--wb-len-12);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-state-warn-tertiary);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-secondary);\n}\n\n._note_1enlz_1 > svg {\n flex: none;\n margin-top: var(--wb-len-2);\n color: var(--dsw-alias-state-warn-primary);\n}\n._slot_1t7dx_1 {\n display: flex;\n flex: 0 0 100%;\n min-width: 0;\n}\n\n._slot_1t7dx_1 > * {\n flex: 0 0 100%;\n min-width: 0;\n}\n\n._action_1t7dx_12 {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n flex: 1 1 0;\n width: 100%;\n min-width: 0;\n min-height: var(--wb-len-36);\n margin: 0 var(--wb-len-2);\n padding: var(--wb-len-7) var(--wb-len-8);\n border-radius: var(--dsw-radius-md);\n cursor: default;\n overflow: hidden;\n gap: var(--wb-len-4);\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-18);\n}\n\n._live_1t7dx_31 {\n color: var(--dsw-alias-state-success-primary);\n}\n\n._paused_1t7dx_35 {\n color: var(--dsw-alias-state-warn-primary);\n}\n\n._trouble_1t7dx_39 {\n color: var(--dsw-alias-state-error-primary);\n}\n\n._pulse_1t7dx_43 {\n animation: _wb-debug-breathe_1t7dx_1 var(--wb-dur-1-5) var(--ds-ease-in-out, ease-in-out) infinite;\n}\n\n@keyframes _wb-debug-breathe_1t7dx_1 {\n 0%,\n 100% {\n opacity: 1;\n }\n\n 50% {\n opacity: 0.35;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._pulse_1t7dx_43 {\n animation: none;\n }\n}\n\n._entry_1t7dx_64 {\n display: flex;\n align-items: center;\n flex: 1 1 auto;\n min-width: 0;\n}\n\n._entryInner_1t7dx_71 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-width: 0;\n}\n\n._acts_1t7dx_78 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-2);\n flex: none;\n}\n\n._act_1t7dx_12 {\n appearance: none;\n border: 0;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-22);\n height: var(--wb-len-22);\n padding: 0;\n border-radius: var(--dsw-radius-sm, var(--wb-len-6));\n flex: none;\n cursor: pointer;\n}\n\n._act_1t7dx_12:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._act_1t7dx_12:focus-visible {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: -2px;\n}\n\n._actStop_1t7dx_110:hover,\n._actStop_1t7dx_110:focus-visible {\n color: var(--dsw-alias-state-error-primary);\n}\n\n._actArmed_1t7dx_115,\n._actArmed_1t7dx_115:hover,\n._actArmed_1t7dx_115:focus-visible {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent);\n width: auto;\n color: var(--dsw-alias-state-error-primary);\n gap: var(--wb-len-4);\n padding: 0 var(--wb-len-7);\n}\n\n._actLabel_1t7dx_125 {\n white-space: nowrap;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-18);\n}\n\n._entryLine_1t7dx_131 {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._actionRail_1t7dx_138 {\n justify-content: center;\n flex: none;\n width: var(--wb-len-36);\n min-width: var(--wb-len-36);\n height: var(--wb-len-36);\n margin: 0;\n padding: 0;\n corner-shape: round;\n border-radius: 50%;\n}\n\n._card_1t7dx_150 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-4);\n}\n\n._cardTitle_1t7dx_156 {\n color: var(--dsw-alias-label-primary);\n font-size: var(--dsw-font-s-14-font-size);\n line-height: var(--wb-line-20);\n}\n\n._cardNote_1t7dx_162 {\n color: var(--dsw-alias-label-secondary);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n}\n._slot_1gkj9_1 {\n display: flex;\n flex: 0 0 100%;\n min-width: 0;\n}\n\n._slot_1gkj9_1 > * {\n flex: 0 0 100%;\n min-width: 0;\n}\n\n._action_1gkj9_12 {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n flex: 1 1 0;\n width: 100%;\n min-width: 0;\n min-height: var(--wb-len-36);\n margin: 0 var(--wb-len-2);\n padding: var(--wb-len-7) var(--wb-len-8);\n border-radius: var(--dsw-radius-md);\n cursor: default;\n overflow: hidden;\n gap: var(--wb-len-4);\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-18);\n}\n\n._live_1gkj9_31 {\n color: var(--dsw-alias-state-warn-primary);\n}\n\n._done_1gkj9_35 {\n color: var(--dsw-alias-state-success-primary);\n}\n\n._pulse_1gkj9_39 {\n animation: _wb-record-breathe_1gkj9_1 var(--wb-dur-1-5) var(--ds-ease-in-out, ease-in-out) infinite;\n}\n\n@keyframes _wb-record-breathe_1gkj9_1 {\n 0%,\n 100% {\n opacity: 1;\n }\n\n 50% {\n opacity: 0.35;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._pulse_1gkj9_39 {\n animation: none;\n }\n}\n\n._entry_1gkj9_60 {\n display: flex;\n align-items: center;\n flex: 1 1 auto;\n min-width: 0;\n}\n\n._entryInner_1gkj9_67 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-width: 0;\n}\n\n._acts_1gkj9_74 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-2);\n flex: none;\n}\n\n._act_1gkj9_12 {\n appearance: none;\n border: 0;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: var(--wb-len-22);\n padding: 0 var(--wb-len-7);\n border-radius: var(--dsw-radius-sm, var(--wb-len-6));\n flex: none;\n cursor: pointer;\n white-space: nowrap;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-18);\n}\n\n._act_1gkj9_12:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._act_1gkj9_12:focus-visible {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: -2px;\n}\n\n._entryLine_1gkj9_108 {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._actionRail_1gkj9_115 {\n justify-content: center;\n flex: none;\n width: var(--wb-len-36);\n min-width: var(--wb-len-36);\n height: var(--wb-len-36);\n margin: 0;\n padding: 0;\n corner-shape: round;\n border-radius: 50%;\n}\n\n._card_1gkj9_127 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-4);\n}\n\n._cardTitle_1gkj9_133 {\n color: var(--dsw-alias-label-primary);\n font-size: var(--dsw-font-s-14-font-size);\n line-height: var(--wb-line-20);\n}\n\n._cardNote_1gkj9_139 {\n color: var(--dsw-alias-label-secondary);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n}\n._body_lw2ph_1 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-12);\n}\n\n._lead_lw2ph_7 {\n margin: 0;\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-secondary);\n}\n\n._sources_lw2ph_14 {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--wb-len-8);\n}\n\n._sourcesLabel_lw2ph_21 {\n font-size: var(--dsw-font-xxs-12-font-size);\n color: var(--dsw-alias-label-secondary);\n}\n\nbutton._sourceOn_lw2ph_26 {\n border-color: var(--dsw-alias-brand-primary);\n}\n._sourceCount_lw2ph_29 {\n margin-left: var(--wb-len-4);\n font-variant-numeric: tabular-nums;\n font-size: var(--dsw-font-xxs-12-font-size);\n color: var(--dsw-alias-label-tertiary);\n}\n\n._reading_lw2ph_36 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-4);\n}\n\n._status_lw2ph_42 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n\n._failure_lw2ph_52 {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n column-gap: var(--wb-len-10);\n row-gap: var(--wb-len-2);\n color: var(--dsw-alias-state-error-primary);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n}\n\n._failureTitle_lw2ph_62 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-width: 0;\n}\n\n._failureHint_lw2ph_69 {\n grid-column: 1;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._failureAction_lw2ph_74 {\n grid-column: 2;\n grid-row: 1;\n justify-self: end;\n}\n\n._rows_lw2ph_80 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-8);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n._row_lw2ph_80 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-6);\n padding: var(--wb-len-12) var(--wb-len-14);\n border: 0.5px solid var(--dsw-alias-settings-card-stroke);\n border-radius: var(--dsw-radius-xl);\n background: var(--dsw-alias-settings-card-fill);\n}\n\n._head_lw2ph_99 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n min-width: 0;\n}\n\n._pick_lw2ph_106 {\n flex: 0 1 auto;\n min-width: 0;\n font-size: var(--dsw-font-xs-13-font-size);\n}\n\n._pick_lw2ph_106 > span {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._code_lw2ph_118 {\n --dsl-code-block-background: var(--dsw-alias-bg-layer-1);\n margin: 0;\n}\n\n._missing_lw2ph_123,\n._conflict_lw2ph_124 {\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-state-warn-primary);\n}\n\n._foot_lw2ph_130 {\n display: flex;\n justify-content: flex-end;\n}\n._actions_jlw8j_1[hidden],\n._progress_jlw8j_2[hidden],\n._commandRow_jlw8j_3[hidden],\n._bridge_jlw8j_4[hidden],\n._raw_jlw8j_5[hidden] {\n display: none;\n}\n\n._gate_jlw8j_9 {\n position: fixed;\n inset: 0;\n z-index: var(--wb-z-top);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--wb-len-24);\n background: var(--dsw-alias-bg-base);\n}\n\n._card_jlw8j_20 {\n width: 100%;\n max-width: var(--wb-len-420);\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--wb-len-16);\n text-align: center;\n}\n\n._card_jlw8j_20:has(._actions_jlw8j_1:not([hidden])),\n._card_jlw8j_20:has(._bridge_jlw8j_4:not([hidden])) {\n max-width: var(--wb-len-520);\n}\n\n._title_jlw8j_35 {\n margin: 0;\n font-size: var(--dsw-font-base-16-font-size);\n line-height: var(--wb-line-24);\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._hint_jlw8j_43 {\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n}\n\n._steps_jlw8j_50 {\n list-style: none;\n margin: var(--wb-len-6) 0 0;\n padding: 0;\n width: 100%;\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-2);\n text-align: left;\n}\n\n._step_jlw8j_50 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n padding: var(--wb-len-6) var(--wb-len-10);\n border-radius: var(--dsw-radius-sm);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-1);\n}\n\n._step_jlw8j_50[data-status='running'] {\n color: var(--dsw-alias-label-primary);\n}\n\n._mark_jlw8j_77 {\n flex: none;\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-14);\n height: var(--wb-len-14);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n font-variant-numeric: tabular-nums;\n}\n\n._step_jlw8j_50[data-status='ok'] ._mark_jlw8j_77 {\n color: var(--dsw-alias-state-success-primary);\n}\n\n._step_jlw8j_50[data-status='warn'] ._mark_jlw8j_77 {\n color: var(--dsw-alias-state-warn-primary);\n}\n\n._step_jlw8j_50[data-status='failed'] ._mark_jlw8j_77 {\n color: var(--dsw-alias-state-error-primary);\n}\n\n._label_jlw8j_102 {\n flex: none;\n}\n\n._detail_jlw8j_106 {\n margin-left: auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._progress_jlw8j_2 {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--wb-len-8);\n margin-top: var(--wb-len-4);\n max-width: 100%;\n}\n\n._elapsed_jlw8j_124 {\n flex: none;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n font-variant-numeric: tabular-nums;\n}\n\n._error_jlw8j_132 {\n margin: 0;\n padding: var(--wb-len-8) var(--wb-len-10);\n max-height: var(--wb-len-120);\n overflow: auto;\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-1);\n font-family: var(--ds-font-family-code, monospace);\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n white-space: pre-wrap;\n word-break: break-all;\n text-align: left;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._commandRow_jlw8j_3 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-4);\n margin: 0 0 var(--wb-len-8);\n padding-right: var(--wb-len-4);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n._copy_jlw8j_158 {\n flex: none;\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-24);\n height: var(--wb-len-24);\n padding: 0;\n border: none;\n border-radius: var(--wb-radius-6);\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n\n._copy_jlw8j_158:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._command_jlw8j_3 {\n flex: 1;\n min-width: 0;\n padding: var(--wb-len-8) var(--wb-len-10);\n border-radius: var(--dsw-radius-sm);\n background: transparent;\n font-family: var(--ds-font-family-code, monospace);\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-primary);\n}\n\n._buttons_jlw8j_191 {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--wb-len-12);\n}\n\n._mockSlot_jlw8j_198 {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n justify-content: center;\n background: var(--dsw-alias-bg-base);\n}\n\n._button_jlw8j_191 {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: var(--wb-len-28);\n padding: 0 var(--wb-len-10);\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-sm);\n background: transparent;\n font: inherit;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n\n._button_jlw8j_191:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._button_jlw8j_191:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n._actions_jlw8j_1,\n._bridge_jlw8j_4 {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--wb-len-10);\n margin-top: var(--wb-len-4);\n padding: var(--wb-len-14) var(--wb-len-16);\n border: 0.5px solid var(--dsw-alias-border-l2);\n border-radius: var(--wb-radius-14);\n background: var(--dsw-alias-bg-layer-1);\n text-align: left;\n}\n\n._fixTitle_jlw8j_249 {\n margin: 0;\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-20);\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._actions_jlw8j_1 ._hint_jlw8j_43,\n._bridge_jlw8j_4 ._hint_jlw8j_43 {\n margin: 0;\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-19);\n color: var(--dsw-alias-label-secondary);\n}\n\n._actions_jlw8j_1 ._commandRow_jlw8j_3,\n._bridge_jlw8j_4 ._commandRow_jlw8j_3 {\n margin: 0;\n}\n\n._actions_jlw8j_1 ._buttons_jlw8j_191,\n._bridge_jlw8j_4 ._buttons_jlw8j_191 {\n justify-content: flex-start;\n}\n\n._raw_jlw8j_5 {\n margin: 0;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n}\n\n._rawSummary_jlw8j_282 {\n cursor: pointer;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._actions_jlw8j_1 ._error_jlw8j_132,\n._bridge_jlw8j_4 ._error_jlw8j_132 {\n margin-top: var(--wb-len-6);\n}\n\n._bridgeLines_jlw8j_292 {\n margin: 0;\n padding-left: var(--wb-len-18);\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-8);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-19);\n color: var(--dsw-alias-label-secondary);\n}\n\n._bridgeLine_jlw8j_292 a {\n display: block;\n margin-top: var(--wb-len-4);\n width: fit-content;\n}\n\n._link_jlw8j_309 {\n color: var(--dsw-alias-label-primary);\n text-decoration: none;\n}\n\n._link_jlw8j_309::after {\n content: '↗';\n margin-left: var(--wb-len-2);\n}\n\n._link_jlw8j_309:hover {\n text-decoration: underline;\n}\n\n._loading_jlw8j_323 {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._loading_jlw8j_323[hidden] {\n display: none;\n}\n\n._loadingMotion_jlw8j_332 {\n transform-origin: center;\n animation: _wb-spin_jlw8j_1 var(--wb-dur-1-5) linear infinite;\n}\n\n._loadingTrack_jlw8j_337,\n._loadingArc_jlw8j_338 {\n fill: none;\n stroke: currentColor;\n stroke-width: 2;\n stroke-linecap: round;\n}\n\n._loadingTrack_jlw8j_337 {\n opacity: 0.25;\n}\n\n._loadingArc_jlw8j_338 {\n stroke-dasharray: 12 150;\n animation: _wb-dash_jlw8j_1 var(--wb-dur-1-5) ease-in-out infinite;\n}\n\n@keyframes _wb-spin_jlw8j_1 {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n@keyframes _wb-dash_jlw8j_1 {\n 0% {\n stroke-dasharray: 12 150;\n stroke-dashoffset: 0;\n }\n 50% {\n stroke-dasharray: 24 150;\n stroke-dashoffset: -6;\n }\n to {\n stroke-dasharray: 12 150;\n stroke-dashoffset: 0;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._loadingMotion_jlw8j_332,\n ._loadingArc_jlw8j_338 {\n animation: none;\n }\n}\n._group_1hxis_1 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-2);\n}\n\n._button_1hxis_7 {\n flex: none;\n width: var(--wb-len-28);\n height: var(--wb-len-28);\n padding: 0;\n color: var(--dsw-alias-label-secondary);\n}\n\n._button_1hxis_7:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n\n._active_1hxis_19 {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._icon_1hxis_23 {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n._icon_1hxis_23 svg {\n display: block;\n width: var(--wb-len-15);\n height: var(--wb-len-15);\n}\n\n._mirror_1hxis_35 {\n transform: scaleX(-1);\n}\n._stripTabs_1dqp4_1 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-4);\n min-width: 0;\n overflow: hidden;\n}\n\n._tab_1dqp4_9 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n flex: none;\n height: var(--wb-len-28);\n padding: 0 var(--wb-len-10);\n border: 0;\n border-radius: var(--dsw-radius-sm);\n background: none;\n font: inherit;\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-16);\n max-width: 100%;\n}\n\n._tabActive_1dqp4_25 {\n color: var(--dsw-alias-label-primary);\n}\n\n._tabQuiet_1dqp4_29 {\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n\n._tabQuiet_1dqp4_29:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._tabTitle_1dqp4_39 {\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._sep_1dqp4_49 {\n flex: none;\n color: var(--dsw-alias-label-dimmed);\n}\n._trigger_15ptp_1 {\n display: flex;\n align-items: center;\n}\n\n._pop_15ptp_6 {\n position: absolute;\n top: calc(var(--wb-len-38) + var(--wb-len-8));\n right: var(--wb-len-6);\n z-index: var(--wb-z-30);\n width: min(var(--wb-len-360), calc(100% - var(--wb-len-12)));\n max-width: calc(100vw - var(--wb-len-48));\n border: 0.5px solid var(--dsw-alias-border-l2);\n border-radius: var(--wb-radius-14);\n background: var(--dsw-alias-bg-layer-2);\n box-shadow: var(--dsw-shadow-lv3);\n overflow: hidden;\n}\n\n._head_15ptp_20 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-8);\n padding: var(--wb-len-10) var(--wb-len-12) var(--wb-len-9) var(--wb-len-14);\n border-bottom: 0.5px solid var(--dsw-alias-border-l2);\n}\n\n._title_15ptp_28 {\n flex: 1;\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-20);\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._rowControls_15ptp_36 {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: var(--wb-len-8);\n}\n\n._reset_15ptp_43 {\n flex: none;\n padding: var(--wb-len-3) var(--wb-len-8);\n border: none;\n border-radius: var(--wb-radius-6);\n background: transparent;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n\n._reset_15ptp_43:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._reset_15ptp_43:disabled {\n cursor: default;\n opacity: 0.5;\n}\n\n._list_15ptp_65 {\n list-style: none;\n margin: 0;\n padding: var(--wb-len-6);\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-2);\n}\n\n._row_15ptp_36 {\n position: relative;\n display: grid;\n grid-template-columns: 12px minmax(0, 1fr) auto;\n align-items: center;\n gap: var(--wb-len-8);\n padding: var(--wb-len-7) var(--wb-len-8);\n border-radius: var(--dsw-radius-sm);\n cursor: default;\n}\n\n._rowDragging_15ptp_85 {\n cursor: grabbing;\n}\n\n._rowBlocked_15ptp_89 {\n cursor: not-allowed;\n}\n\n._listDragging_15ptp_93 ._rowControls_15ptp_36 {\n pointer-events: none;\n}\n\n._row_15ptp_36:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._rowOff_15ptp_101 {\n opacity: 0.55;\n}\n\n._rowOff_15ptp_101:hover {\n opacity: 1;\n}\n\n._rowOver_15ptp_109::before {\n content: '';\n position: absolute;\n top: var(--wb-len-neg-3);\n left: var(--wb-len-8);\n right: var(--wb-len-8);\n height: var(--wb-len-2);\n background: var(--dsw-alias-brand-primary);\n}\n\n._ghost_15ptp_119 {\n position: fixed;\n z-index: var(--wb-z-40);\n pointer-events: none;\n padding: var(--wb-len-4) var(--wb-len-10);\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-1);\n box-shadow: var(--wb-static-shadow-ghost);\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-primary);\n white-space: nowrap;\n}\n\n._grip_15ptp_134 {\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n text-align: center;\n color: var(--dsw-alias-label-tertiary);\n user-select: none;\n cursor: grab;\n touch-action: none;\n}\n\n._gripDragging_15ptp_144 {\n cursor: grabbing;\n}\n\n._gripBlocked_15ptp_148 {\n cursor: not-allowed;\n}\n\n._label_15ptp_152 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n min-width: 0;\n}\n\n._name_15ptp_159 {\n min-width: 0;\n flex: 0 1 auto;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-primary);\n}\n\n._error_15ptp_170 {\n margin: 0;\n padding: 0 var(--wb-len-14) var(--wb-len-10);\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-state-error-primary);\n}\n\n._dep_15ptp_178 {\n flex: none;\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n}\n\n._group_15ptp_186 {\n padding-top: var(--wb-len-6);\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n\n._groupTitle_15ptp_191 {\n margin: 0;\n padding: var(--wb-len-2) var(--wb-len-8) 0 var(--wb-len-14);\n font-size: var(--dsw-font-xxxs-11-font-size);\n line-height: var(--wb-line-16);\n font-weight: 400;\n color: var(--dsw-alias-label-tertiary);\n}\n._panel_1whum_1 {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n z-index: var(--wb-z-10);\n visibility: hidden;\n}\n\n._panel_1whum_1[data-fullscreen] {\n z-index: var(--wb-z-40);\n}\n\n._panel_1whum_1[data-open] {\n visibility: visible;\n}\n\n._columns_1whum_18 {\n display: block;\n column-gap: var(--wb-len-12);\n}\n\n._cell_1whum_23 {\n display: flow-root;\n min-width: 0;\n break-inside: avoid;\n margin-bottom: var(--wb-len-12);\n}\n._root_1cmz0_1 {\n position: relative;\n flex: none;\n margin: 0 var(--wb-len-2) var(--wb-len-4);\n}\n\n._rail_1cmz0_7 {\n margin: 0 0 var(--wb-len-4);\n}\n\n._glyphBox_1cmz0_11 {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n}\n\n._glyph_1cmz0_11 {\n position: relative;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-16);\n height: var(--wb-len-20);\n color: var(--dsw-alias-label-tertiary);\n}\n\n._glyphActive_1cmz0_30 {\n color: var(--dsw-alias-state-business-primary);\n}\n\n._triggerName_1cmz0_34 {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: baseline;\n gap: var(--wb-len-6);\n font-size: var(--wb-font-row);\n line-height: var(--wb-line-20);\n overflow: hidden;\n}\n\n._dir_1cmz0_45 {\n flex: 0 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._name_1cmz0_53 {\n flex: 0 1 auto;\n max-width: 50%;\n font-size: var(--dsw-font-xxs-12-font-size);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._triggerName_1cmz0_34 ._name_1cmz0_53 {\n color: var(--dsw-alias-label-tertiary);\n}\n\n._row_1cmz0_66 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n width: 100%;\n min-width: 0;\n}\n\n._trailing_1cmz0_74 {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--wb-len-20);\n height: var(--wb-len-20);\n margin-inline-start: auto;\n}\n\n._trailing_1cmz0_74 ._rowAction_1cmz0_84 {\n width: var(--wb-len-20);\n min-width: var(--wb-len-20);\n height: var(--wb-len-20);\n min-height: var(--wb-len-20);\n padding: 0;\n border-radius: var(--dsw-radius-sm);\n}\n\n._row_1cmz0_66 ._name_1cmz0_53 {\n color: var(--dsw-alias-label-tertiary);\n}\n\n._current_1cmz0_97 {\n flex: none;\n display: inline-flex;\n align-items: center;\n color: var(--dsw-alias-label-primary);\n}\n._dot_sosf1_1 {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n._overlay_sosf1_8 {\n position: absolute;\n inset-block-start: var(--wb-len-neg-3);\n inset-inline-end: var(--wb-len-neg-3);\n}\n._tag_g9dg8_1 {\n flex: none;\n margin-inline-start: auto;\n}\n._dialog_1vye5_1 {\n width: min(var(--wb-len-420), 100%);\n}\n\n._stack_1vye5_5 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-8);\n min-width: 0;\n}\n\n._input_1vye5_12 {\n width: 100%;\n height: var(--wb-len-40);\n padding: 0 var(--wb-len-12);\n}\n\n._meta_1vye5_18 {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--wb-len-12);\n min-width: 0;\n}\n._blocker_1oaj0_1 {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--wb-len-6);\n padding: var(--wb-len-20) var(--wb-len-16);\n text-align: center;\n}\n\n._icon_1oaj0_10 {\n display: flex;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._title_1oaj0_15 {\n margin: var(--wb-len-2) 0 0;\n font-size: var(--dsw-font-s-14-font-size);\n line-height: var(--wb-line-22);\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._hint_1oaj0_23 {\n margin: 0;\n max-width: var(--wb-len-42em);\n font-size: var(--dsw-font-xxs-12-font-size);\n line-height: var(--wb-line-18);\n color: var(--dsw-alias-label-tertiary);\n text-wrap: pretty;\n}\n\n._blocker_1oaj0_1._blockerInline_1oaj0_32 {\n align-items: flex-start;\n gap: var(--wb-len-6);\n padding: var(--wb-len-4) 0 var(--wb-len-2);\n text-align: left;\n}\n\n._blocker_1oaj0_1._blockerInline_1oaj0_32 ._title_1oaj0_15 {\n font-size: var(--dsw-font-xs-13-font-size);\n line-height: var(--wb-line-20);\n}\n\n._blocker_1oaj0_1._blockerInline_1oaj0_32 ._hint_1oaj0_23 {\n max-width: 100%;\n}\n\n._blocker_1oaj0_1._blockerInline_1oaj0_32 ._actions_1oaj0_48 {\n margin-top: var(--wb-len-8);\n}\n\n._blocker_1oaj0_1._blockerInline_1oaj0_32 ._raw_1oaj0_52 {\n margin-top: var(--wb-len-4);\n max-width: 100%;\n}\n\n._actions_1oaj0_48 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-10);\n margin-top: var(--wb-len-6);\n}\n\n._raw_1oaj0_52 {\n margin-top: var(--wb-len-10);\n width: 100%;\n max-width: var(--wb-len-360);\n text-align: left;\n}\n\n._notice_1oaj0_71 {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: start;\n column-gap: var(--wb-len-10);\n margin: 0 0 var(--wb-len-10);\n padding: var(--wb-len-10) var(--wb-len-12);\n border: 0.5px solid var(--dsw-alias-border-l2);\n border-left: 2px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-1);\n}\n\n._notice_1oaj0_71._noticeFlat_1oaj0_84 {\n margin: 0;\n padding: 0;\n border: 0;\n background: transparent;\n}\n\n._noticeText_1oaj0_91 {\n display: flex;\n flex-direction: column;\n gap: var(--wb-len-3);\n min-width: 0;\n}\n\n._noticeTitle_1oaj0_98 {\n font-size: var(--wb-font-12-5);\n line-height: var(--wb-line-18);\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._noticeHint_1oaj0_105 {\n font-size: var(--wb-font-11-5);\n line-height: var(--wb-line-17);\n color: var(--dsw-alias-label-tertiary);\n overflow-wrap: anywhere;\n}\n\n._noticeActions_1oaj0_112 {\n display: flex;\n align-items: center;\n gap: var(--wb-len-6);\n margin-top: var(--wb-len-neg-2);\n}\n\n._failure_1oaj0_119 {\n margin: var(--wb-len-8) 0 0;\n font-size: var(--wb-font-11-5);\n line-height: var(--wb-line-17);\n color: var(--dsw-alias-state-error-primary);\n overflow-wrap: anywhere;\n}\n\n._failureDetail_1oaj0_127 {\n display: block;\n margin-top: var(--wb-len-2);\n color: var(--dsw-alias-label-tertiary);\n white-space: pre-wrap;\n}\n\n._inlineAction_1oaj0_134 {\n padding: 0;\n border: none;\n background: transparent;\n cursor: pointer;\n}\n\n._inlineAction_1oaj0_134:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n._rawText_1oaj0_146 {\n margin: var(--wb-len-6) 0 0;\n max-width: 100%;\n}\n/*$vite$:1*/";
|
|
10059
11692
|
function workbenchCss() {
|
|
10060
11693
|
return `${tokens_default}\n${palette_default}\n${scale_default}\n${sidebar_default}\n${sidebar_app_default}\n${rightbar_default}\n${chrome_default}\n${board_default}\n${motion_default}\n${COMPONENT_CSS_MARKER}`;
|
|
10061
11694
|
}
|
|
@@ -10246,6 +11879,7 @@ function mount(ctx) {
|
|
|
10246
11879
|
}, Sidebar));
|
|
10247
11880
|
registerMarketPanel(ctx, units);
|
|
10248
11881
|
registerDebugFooter(ctx);
|
|
11882
|
+
registerRecordFooter(ctx);
|
|
10249
11883
|
registerConfigSyncSection(ctx);
|
|
10250
11884
|
ctx.effect(() => {
|
|
10251
11885
|
const workshop = workshopWorkspace();
|
|
@@ -10261,7 +11895,8 @@ function mount(ctx) {
|
|
|
10261
11895
|
locale: LOCALE_NS,
|
|
10262
11896
|
inject: () => ({
|
|
10263
11897
|
t: ctx.locale.bind(LOCALE_NS),
|
|
10264
|
-
units: units.all()
|
|
11898
|
+
units: units.all(),
|
|
11899
|
+
renderShell: shellApprovalDetail
|
|
10265
11900
|
})
|
|
10266
11901
|
}, ApprovalDetail));
|
|
10267
11902
|
ctx.slots.inject("conversation.session.header.corner", () => ctx.slots.register({
|