@icen.ai/ui 0.8.0 → 0.9.0
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/AGENTS.md +63 -14
- package/README.md +17 -9
- package/dist/base.css +4 -3
- package/dist/behaviors/accordion.d.mts +5 -2
- package/dist/behaviors/accordion.mjs +36 -11
- package/dist/behaviors/ai-branch.d.mts +19 -0
- package/dist/behaviors/ai-branch.mjs +217 -0
- package/dist/behaviors/ai-chat.d.mts +11 -7
- package/dist/behaviors/ai-chat.mjs +134 -51
- package/dist/behaviors/ai-composer.d.mts +28 -3
- package/dist/behaviors/ai-composer.mjs +399 -229
- package/dist/behaviors/ai-core.d.mts +9 -4
- package/dist/behaviors/ai-core.mjs +21 -8
- package/dist/behaviors/ai-diff.d.mts +2 -2
- package/dist/behaviors/ai-diff.mjs +172 -41
- package/dist/behaviors/ai-feedback.d.mts +26 -0
- package/dist/behaviors/ai-feedback.mjs +303 -0
- package/dist/behaviors/ai-panel.d.mts +26 -9
- package/dist/behaviors/ai-panel.mjs +211 -110
- package/dist/behaviors/ai-provider.mjs +54 -48
- package/dist/behaviors/ai-threads.d.mts +38 -0
- package/dist/behaviors/ai-threads.mjs +319 -0
- package/dist/behaviors/ai-tool.d.mts +12 -4
- package/dist/behaviors/ai-tool.mjs +316 -263
- package/dist/behaviors/ai-tools.d.mts +9 -6
- package/dist/behaviors/ai-tools.mjs +264 -155
- package/dist/behaviors/back-top.mjs +16 -1
- package/dist/behaviors/carousel.d.mts +5 -2
- package/dist/behaviors/carousel.mjs +53 -26
- package/dist/behaviors/charts.d.mts +170 -22
- package/dist/behaviors/charts.mjs +1016 -150
- package/dist/behaviors/command-palette.d.mts +40 -6
- package/dist/behaviors/command-palette.mjs +143 -15
- package/dist/behaviors/context-menu.d.mts +21 -4
- package/dist/behaviors/context-menu.mjs +122 -38
- package/dist/behaviors/controls.d.mts +59 -0
- package/dist/behaviors/controls.mjs +601 -0
- package/dist/behaviors/copy.d.mts +5 -2
- package/dist/behaviors/copy.mjs +37 -12
- package/dist/behaviors/datatable.d.mts +12 -0
- package/dist/behaviors/datatable.mjs +226 -43
- package/dist/behaviors/date-picker.d.mts +2 -2
- package/dist/behaviors/date-picker.mjs +171 -32
- package/dist/behaviors/dropdown.d.mts +6 -2
- package/dist/behaviors/dropdown.mjs +164 -25
- package/dist/behaviors/events.d.mts +523 -0
- package/dist/behaviors/events.mjs +208 -0
- package/dist/behaviors/input.mjs +25 -12
- package/dist/behaviors/kb-access.d.mts +34 -0
- package/dist/behaviors/kb-access.mjs +569 -0
- package/dist/behaviors/kb-acl.d.mts +50 -0
- package/dist/behaviors/kb-acl.mjs +405 -0
- package/dist/behaviors/kb-answer.d.mts +38 -0
- package/dist/behaviors/kb-answer.mjs +2055 -0
- package/dist/behaviors/kb-audit.d.mts +23 -0
- package/dist/behaviors/kb-audit.mjs +375 -0
- package/dist/behaviors/kb-canvas.d.mts +44 -0
- package/dist/behaviors/kb-canvas.mjs +589 -0
- package/dist/behaviors/kb-chain.d.mts +15 -0
- package/dist/behaviors/kb-chain.mjs +270 -0
- package/dist/behaviors/kb-checkpoint.d.mts +16 -0
- package/dist/behaviors/kb-checkpoint.mjs +342 -0
- package/dist/behaviors/kb-chunks.d.mts +31 -0
- package/dist/behaviors/kb-chunks.mjs +475 -0
- package/dist/behaviors/kb-citation.d.mts +38 -0
- package/dist/behaviors/kb-citation.mjs +677 -0
- package/dist/behaviors/kb-clarify.d.mts +20 -0
- package/dist/behaviors/kb-clarify.mjs +248 -0
- package/dist/behaviors/kb-conflict.d.mts +22 -0
- package/dist/behaviors/kb-conflict.mjs +284 -0
- package/dist/behaviors/kb-connector.d.mts +17 -0
- package/dist/behaviors/kb-connector.mjs +375 -0
- package/dist/behaviors/kb-core.d.mts +529 -0
- package/dist/behaviors/kb-core.mjs +890 -0
- package/dist/behaviors/kb-eval.d.mts +22 -0
- package/dist/behaviors/kb-eval.mjs +408 -0
- package/dist/behaviors/kb-explain.d.mts +11 -0
- package/dist/behaviors/kb-explain.mjs +243 -0
- package/dist/behaviors/kb-filter.d.mts +31 -0
- package/dist/behaviors/kb-filter.mjs +587 -0
- package/dist/behaviors/kb-gap.d.mts +27 -0
- package/dist/behaviors/kb-gap.mjs +273 -0
- package/dist/behaviors/kb-hittest.d.mts +34 -0
- package/dist/behaviors/kb-hittest.mjs +409 -0
- package/dist/behaviors/kb-metadata.d.mts +29 -0
- package/dist/behaviors/kb-metadata.mjs +326 -0
- package/dist/behaviors/kb-passage.d.mts +41 -0
- package/dist/behaviors/kb-passage.mjs +529 -0
- package/dist/behaviors/kb-pipeline.d.mts +18 -0
- package/dist/behaviors/kb-pipeline.mjs +381 -0
- package/dist/behaviors/kb-qa.d.mts +26 -0
- package/dist/behaviors/kb-qa.mjs +332 -0
- package/dist/behaviors/kb-rerank.d.mts +20 -0
- package/dist/behaviors/kb-rerank.mjs +315 -0
- package/dist/behaviors/kb-retrieval.d.mts +49 -0
- package/dist/behaviors/kb-retrieval.mjs +746 -0
- package/dist/behaviors/kb-review.d.mts +44 -0
- package/dist/behaviors/kb-review.mjs +451 -0
- package/dist/behaviors/kb-sandbox.d.mts +33 -0
- package/dist/behaviors/kb-sandbox.mjs +325 -0
- package/dist/behaviors/kb-segment.d.mts +32 -0
- package/dist/behaviors/kb-segment.mjs +499 -0
- package/dist/behaviors/kb-sources.d.mts +27 -0
- package/dist/behaviors/kb-sources.mjs +373 -0
- package/dist/behaviors/kb-sql.d.mts +43 -0
- package/dist/behaviors/kb-sql.mjs +948 -0
- package/dist/behaviors/kb-trace.d.mts +16 -0
- package/dist/behaviors/kb-trace.mjs +414 -0
- package/dist/behaviors/kb-visibility.d.mts +44 -0
- package/dist/behaviors/kb-visibility.mjs +403 -0
- package/dist/behaviors/kb-who-can.d.mts +32 -0
- package/dist/behaviors/kb-who-can.mjs +379 -0
- package/dist/behaviors/modal.d.mts +24 -5
- package/dist/behaviors/modal.mjs +76 -10
- package/dist/behaviors/nav.d.mts +1 -1
- package/dist/behaviors/nav.mjs +33 -7
- package/dist/behaviors/notification.d.mts +20 -4
- package/dist/behaviors/notification.mjs +53 -73
- package/dist/behaviors/popover.d.mts +39 -3
- package/dist/behaviors/popover.mjs +90 -4
- package/dist/behaviors/select.d.mts +4 -2
- package/dist/behaviors/select.mjs +161 -24
- package/dist/behaviors/sidebar.d.mts +5 -2
- package/dist/behaviors/sidebar.mjs +43 -13
- package/dist/behaviors/slider.d.mts +5 -2
- package/dist/behaviors/slider.mjs +54 -43
- package/dist/behaviors/split-pane.d.mts +6 -2
- package/dist/behaviors/split-pane.mjs +62 -21
- package/dist/behaviors/tabs.d.mts +3 -2
- package/dist/behaviors/tabs.mjs +65 -14
- package/dist/behaviors/tag-input.d.mts +5 -2
- package/dist/behaviors/tag-input.mjs +61 -21
- package/dist/behaviors/theme.d.mts +13 -2
- package/dist/behaviors/theme.mjs +48 -4
- package/dist/behaviors/toast.d.mts +30 -8
- package/dist/behaviors/toast.mjs +74 -7
- package/dist/behaviors/tree.d.mts +5 -2
- package/dist/behaviors/tree.mjs +38 -15
- package/dist/behaviors/upload.mjs +21 -23
- package/dist/cli.mjs +1 -1
- package/dist/components/ai-branch.mjs +3 -0
- package/dist/components/ai-chat.css +295 -0
- package/dist/components/ai-feedback.mjs +3 -0
- package/dist/components/ai-panel.css +218 -1
- package/dist/components/ai-threads.mjs +3 -0
- package/dist/components/ai-tool-call.mjs +1 -1
- package/dist/components/badge.css +1 -1
- package/dist/components/breadcrumb.css +0 -32
- package/dist/components/chart-calendar.mjs +1 -2
- package/dist/components/chart-graph.css +57 -0
- package/dist/components/chart-graph.mjs +4 -0
- package/dist/components/chart-map.mjs +3 -0
- package/dist/components/chart-pie.css +0 -6
- package/dist/components/chart-scatter.mjs +1 -1
- package/dist/components/charts.css +33 -1
- package/dist/components/charts.mjs +1 -0
- package/dist/components/content.css +3 -16
- package/dist/components/datatable.css +1 -1
- package/dist/components/date-picker.css +1 -1
- package/dist/components/kb-access.mjs +4 -0
- package/dist/components/kb-acl.mjs +4 -0
- package/dist/components/kb-agent.css +481 -0
- package/dist/components/kb-answer.mjs +4 -0
- package/dist/components/kb-audit.mjs +4 -0
- package/dist/components/kb-canvas.mjs +4 -0
- package/dist/components/kb-chain.mjs +4 -0
- package/dist/components/kb-checkpoint.mjs +4 -0
- package/dist/components/kb-chunks.mjs +4 -0
- package/dist/components/kb-citation.mjs +4 -0
- package/dist/components/kb-clarify.mjs +4 -0
- package/dist/components/kb-conflict.mjs +4 -0
- package/dist/components/kb-connector.mjs +4 -0
- package/dist/components/kb-data.css +649 -0
- package/dist/components/kb-eval.mjs +4 -0
- package/dist/components/kb-explain.mjs +4 -0
- package/dist/components/kb-filter.mjs +4 -0
- package/dist/components/kb-gap.mjs +4 -0
- package/dist/components/kb-ground.css +566 -0
- package/dist/components/kb-hittest.mjs +4 -0
- package/dist/components/kb-ingest.css +898 -0
- package/dist/components/kb-metadata.mjs +4 -0
- package/dist/components/kb-ops.css +548 -0
- package/dist/components/kb-passage.mjs +4 -0
- package/dist/components/kb-perm.css +444 -0
- package/dist/components/kb-pipeline.mjs +4 -0
- package/dist/components/kb-qa.mjs +4 -0
- package/dist/components/kb-rerank.mjs +4 -0
- package/dist/components/kb-retrieval.mjs +4 -0
- package/dist/components/kb-review.mjs +4 -0
- package/dist/components/kb-sandbox.mjs +4 -0
- package/dist/components/kb-search.css +940 -0
- package/dist/components/kb-segment.mjs +4 -0
- package/dist/components/kb-sources.mjs +4 -0
- package/dist/components/kb-sql.mjs +4 -0
- package/dist/components/kb-trace.mjs +4 -0
- package/dist/components/kb-visibility.mjs +4 -0
- package/dist/components/kb-who-can.mjs +4 -0
- package/dist/components/kb.css +252 -0
- package/dist/components/kb.mjs +9 -0
- package/dist/components/notification.css +2 -3
- package/dist/components/pagination.css +3 -1
- package/dist/components/pagination.mjs +1 -0
- package/dist/components/rating.mjs +1 -0
- package/dist/components/segmented.css +9 -1
- package/dist/components/segmented.mjs +1 -1
- package/dist/components/select.css +67 -4
- package/dist/components/steps.css +13 -3
- package/dist/components/steps.mjs +1 -0
- package/dist/components/switch.css +3 -1
- package/dist/components/switch.mjs +1 -0
- package/dist/components/table.mjs +1 -0
- package/dist/components/tabs.css +23 -0
- package/dist/components/tag-input.css +1 -6
- package/dist/components/upload.css +0 -15
- package/dist/index.d.mts +48 -11
- package/dist/index.mjs +13205 -3615
- package/dist/registry.json +366 -15
- package/dist/retro-effects.css +3 -16
- package/dist/tokens/retro-effects.css +3 -16
- package/dist/tokens/style-profiles.css +3 -2
- package/dist/tokens/typography.css +2 -0
- package/dist/tokens.css +5 -2
- package/dist/ui.css +5713 -267
- package/docs/research/2026-10-03-ai-kb-components.md +392 -0
- package/docs/research/2026-10-03-kb-permissions.md +992 -0
- package/docs/spec/ai-native.md +7 -4
- package/docs/spec/kb-family.md +443 -0
- package/package.json +2 -2
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
// src/behaviors/ai-core.ts
|
|
2
|
+
var AI_STATUSES = [
|
|
3
|
+
"pending",
|
|
4
|
+
"running",
|
|
5
|
+
"streaming",
|
|
6
|
+
"approval",
|
|
7
|
+
"done",
|
|
8
|
+
"error",
|
|
9
|
+
"cancelled"
|
|
10
|
+
];
|
|
2
11
|
function aiStatusLabel(s) {
|
|
3
12
|
const labels = {
|
|
4
13
|
pending: "\u7B49\u5F85",
|
|
@@ -171,9 +180,15 @@ function formatDuration(ms) {
|
|
|
171
180
|
const m = Math.floor(ms / 6e4);
|
|
172
181
|
const s = Math.round(ms % 6e4 / 1e3);
|
|
173
182
|
if (ms < 36e5) return s > 0 ? `${m}m${s}s` : `${m}m`;
|
|
174
|
-
const
|
|
183
|
+
const h2 = Math.floor(ms / 36e5);
|
|
175
184
|
const rm = Math.round(ms % 36e5 / 6e4);
|
|
176
|
-
return rm > 0 ? `${
|
|
185
|
+
return rm > 0 ? `${h2}h${rm}m` : `${h2}h`;
|
|
186
|
+
}
|
|
187
|
+
function h(tag, className, text) {
|
|
188
|
+
const node = document.createElement(tag);
|
|
189
|
+
if (className) node.className = className;
|
|
190
|
+
if (text != null) node.textContent = text;
|
|
191
|
+
return node;
|
|
177
192
|
}
|
|
178
193
|
function svgIcon(svg2) {
|
|
179
194
|
if (typeof document === "undefined" || typeof DOMParser === "undefined") return null;
|
|
@@ -187,15 +202,15 @@ function svgIcon(svg2) {
|
|
|
187
202
|
if (!root || root.tagName.toLowerCase() !== "svg" || parsed.querySelector("parsererror")) {
|
|
188
203
|
return null;
|
|
189
204
|
}
|
|
190
|
-
const sanitize = (
|
|
191
|
-
for (const attr of Array.from(
|
|
205
|
+
const sanitize = (el) => {
|
|
206
|
+
for (const attr of Array.from(el.attributes)) {
|
|
192
207
|
const name = attr.name.toLowerCase();
|
|
193
|
-
if (name.startsWith("on"))
|
|
208
|
+
if (name.startsWith("on")) el.removeAttribute(attr.name);
|
|
194
209
|
if ((name === "href" || name === "xlink:href") && attr.value.trim().toLowerCase().startsWith("javascript:")) {
|
|
195
|
-
|
|
210
|
+
el.removeAttribute(attr.name);
|
|
196
211
|
}
|
|
197
212
|
}
|
|
198
|
-
for (const child of Array.from(
|
|
213
|
+
for (const child of Array.from(el.children)) {
|
|
199
214
|
const tag = child.tagName.toLowerCase();
|
|
200
215
|
if (tag === "script" || tag === "foreignobject") {
|
|
201
216
|
child.remove();
|
|
@@ -209,6 +224,44 @@ function svgIcon(svg2) {
|
|
|
209
224
|
}
|
|
210
225
|
|
|
211
226
|
// src/behaviors/popover.ts
|
|
227
|
+
var PANEL_SIZING_ATTRS = {
|
|
228
|
+
width: "data-panel-width",
|
|
229
|
+
minWidth: "data-panel-min",
|
|
230
|
+
maxWidth: "data-panel-max",
|
|
231
|
+
minHeight: "data-panel-min-height",
|
|
232
|
+
maxHeight: "data-panel-max-height"
|
|
233
|
+
};
|
|
234
|
+
function readPanelSizing(el) {
|
|
235
|
+
const out = {};
|
|
236
|
+
if (!el) return out;
|
|
237
|
+
for (const key of Object.keys(PANEL_SIZING_ATTRS)) {
|
|
238
|
+
const raw = el.getAttribute(PANEL_SIZING_ATTRS[key]);
|
|
239
|
+
if (raw == null) continue;
|
|
240
|
+
const n = Number(raw);
|
|
241
|
+
if (Number.isFinite(n) && n > 0) out[key] = n;
|
|
242
|
+
}
|
|
243
|
+
return out;
|
|
244
|
+
}
|
|
245
|
+
function resolvePanelSizing(el, overrides) {
|
|
246
|
+
const base = readPanelSizing(el);
|
|
247
|
+
if (!overrides) return base;
|
|
248
|
+
for (const key of Object.keys(overrides)) {
|
|
249
|
+
const v = overrides[key];
|
|
250
|
+
if (typeof v === "number" && Number.isFinite(v) && v > 0) base[key] = v;
|
|
251
|
+
}
|
|
252
|
+
return base;
|
|
253
|
+
}
|
|
254
|
+
function sizingToLayout(sizing, opts) {
|
|
255
|
+
const out = { ...opts };
|
|
256
|
+
if (sizing.minWidth != null) out.minWidth = sizing.minWidth;
|
|
257
|
+
if (sizing.maxWidth != null) out.maxWidth = sizing.maxWidth;
|
|
258
|
+
if (sizing.width != null) {
|
|
259
|
+
out.minWidth = sizing.width;
|
|
260
|
+
out.maxWidth = sizing.width;
|
|
261
|
+
}
|
|
262
|
+
if (sizing.maxHeight != null) out.maxHeight = sizing.maxHeight;
|
|
263
|
+
return out;
|
|
264
|
+
}
|
|
212
265
|
var DEFAULT_MIN_WIDTH = 220;
|
|
213
266
|
var DEFAULT_MAX_WIDTH = 420;
|
|
214
267
|
var DEFAULT_MIN_HEIGHT = 120;
|
|
@@ -233,13 +286,35 @@ function horizontalAnchor(anchor, width, align) {
|
|
|
233
286
|
function computePopoverLayout(anchor, viewport, opts = {}) {
|
|
234
287
|
const margin = opts.margin ?? 12;
|
|
235
288
|
const offset = opts.offset ?? 8;
|
|
289
|
+
const preferredSide = opts.side ?? "top";
|
|
290
|
+
const align = opts.align ?? "start";
|
|
291
|
+
if (preferredSide === "left" || preferredSide === "right") {
|
|
292
|
+
const availableLeft = Math.max(0, anchor.left - margin - offset);
|
|
293
|
+
const availableRight = Math.max(0, viewport.width - anchor.right - margin - offset);
|
|
294
|
+
const side2 = (preferredSide === "left" ? availableLeft : availableRight) >= DEFAULT_MIN_WIDTH ? preferredSide : preferredSide === "left" ? "right" : "left";
|
|
295
|
+
const minWidth2 = Math.max(1, opts.minWidth ?? DEFAULT_MIN_WIDTH);
|
|
296
|
+
const maxWidth2 = Math.min(
|
|
297
|
+
Math.max(opts.maxWidth ?? DEFAULT_MAX_WIDTH, minWidth2),
|
|
298
|
+
side2 === "left" ? availableLeft : availableRight
|
|
299
|
+
);
|
|
300
|
+
const width2 = minWidth2;
|
|
301
|
+
const left2 = clamp(
|
|
302
|
+
side2 === "left" ? anchor.left - offset - width2 : anchor.right + offset,
|
|
303
|
+
margin,
|
|
304
|
+
viewport.width - margin - width2
|
|
305
|
+
);
|
|
306
|
+
const availableHeight2 = Math.max(80, viewport.height - margin * 2);
|
|
307
|
+
const maxHeight2 = Math.min(opts.maxHeight ?? DEFAULT_MAX_HEIGHT, availableHeight2);
|
|
308
|
+
const desired = clamp(opts.contentHeightHint ?? Math.min(anchor.height, maxHeight2), 40, maxHeight2);
|
|
309
|
+
const anchorTop = align === "center" ? anchor.top + anchor.height / 2 - desired / 2 : align === "end" ? anchor.bottom - desired : anchor.top;
|
|
310
|
+
const top2 = clamp(anchorTop, margin, viewport.height - margin - desired);
|
|
311
|
+
return { side: side2, left: left2, top: top2, width: width2, maxHeight: maxHeight2 };
|
|
312
|
+
}
|
|
236
313
|
const availableWidth = Math.max(80, viewport.width - margin * 2);
|
|
237
314
|
const requestedMinWidth = Math.max(1, opts.minWidth ?? DEFAULT_MIN_WIDTH);
|
|
238
315
|
const requestedMaxWidth = Math.max(requestedMinWidth, opts.maxWidth ?? DEFAULT_MAX_WIDTH);
|
|
239
316
|
const maxWidth = Math.min(requestedMaxWidth, availableWidth);
|
|
240
317
|
const minWidth = Math.min(requestedMinWidth, maxWidth);
|
|
241
|
-
const preferredSide = opts.side ?? "top";
|
|
242
|
-
const align = opts.align ?? "start";
|
|
243
318
|
const availableTop = Math.max(0, anchor.top - margin - offset);
|
|
244
319
|
const availableBottom = Math.max(0, viewport.height - anchor.bottom - margin - offset);
|
|
245
320
|
const availableHeight = Math.max(80, viewport.height - margin * 2);
|
|
@@ -263,8 +338,8 @@ function computePopoverLayout(anchor, viewport, opts = {}) {
|
|
|
263
338
|
return { side, left, top, width, maxHeight };
|
|
264
339
|
}
|
|
265
340
|
var openPanels = /* @__PURE__ */ new Map();
|
|
266
|
-
function rectFromElement(
|
|
267
|
-
const r =
|
|
341
|
+
function rectFromElement(el) {
|
|
342
|
+
const r = el.getBoundingClientRect();
|
|
268
343
|
return { left: r.left, top: r.top, right: r.right, bottom: r.bottom, width: r.width, height: r.height };
|
|
269
344
|
}
|
|
270
345
|
function resolveAnchor(state) {
|
|
@@ -317,7 +392,8 @@ function onKeyDown(e) {
|
|
|
317
392
|
function openPopover(panel, options) {
|
|
318
393
|
if (typeof document === "undefined") return;
|
|
319
394
|
if (openPanels.has(panel)) closePopover(panel);
|
|
320
|
-
const { anchor, onClose, ...
|
|
395
|
+
const { anchor, onClose, sizing, ...rest } = options;
|
|
396
|
+
const layoutOpts = sizingToLayout(resolvePanelSizing(panel, sizing), rest);
|
|
321
397
|
const placeholder = document.createComment("popover-anchor");
|
|
322
398
|
panel.parentNode?.insertBefore(placeholder, panel);
|
|
323
399
|
const wasHidden = panel.hidden;
|
|
@@ -369,32 +445,24 @@ function closePopover(panel) {
|
|
|
369
445
|
state.onClose?.();
|
|
370
446
|
}
|
|
371
447
|
|
|
372
|
-
// src/behaviors/
|
|
373
|
-
function
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
return node;
|
|
448
|
+
// src/behaviors/events.ts
|
|
449
|
+
function emitIcen(source, type, detail) {
|
|
450
|
+
return source.dispatchEvent(
|
|
451
|
+
new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
|
|
452
|
+
);
|
|
378
453
|
}
|
|
454
|
+
|
|
455
|
+
// src/behaviors/ai-panel.ts
|
|
379
456
|
function dispatch(node, name, detail) {
|
|
380
|
-
node
|
|
457
|
+
emitIcen(node, name, detail);
|
|
381
458
|
}
|
|
382
|
-
var STATUS_CLASSES = [
|
|
383
|
-
"pending",
|
|
384
|
-
"running",
|
|
385
|
-
"streaming",
|
|
386
|
-
"approval",
|
|
387
|
-
"done",
|
|
388
|
-
"error",
|
|
389
|
-
"cancelled"
|
|
390
|
-
];
|
|
391
459
|
function stripStatusClasses(node) {
|
|
392
|
-
for (const s of
|
|
460
|
+
for (const s of AI_STATUSES) node.classList.remove(`is-${s}`);
|
|
393
461
|
}
|
|
394
462
|
function buildTodoHead(done, total) {
|
|
395
|
-
const head =
|
|
396
|
-
head.appendChild(
|
|
397
|
-
const bar =
|
|
463
|
+
const head = h("div", "ai-todo-head");
|
|
464
|
+
head.appendChild(h("span", "ai-todo-progress", `${done}/${total}`));
|
|
465
|
+
const bar = h("div", "ai-todo-bar");
|
|
398
466
|
bar.setAttribute("role", "progressbar");
|
|
399
467
|
bar.setAttribute("aria-valuemin", "0");
|
|
400
468
|
bar.setAttribute("aria-valuemax", String(total));
|
|
@@ -406,24 +474,31 @@ function buildTodoHead(done, total) {
|
|
|
406
474
|
head.appendChild(bar);
|
|
407
475
|
return head;
|
|
408
476
|
}
|
|
477
|
+
var ICON_TODO_CHECK = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m3.5 12.5 5 5L20.5 6" pathLength="1"/></svg>';
|
|
409
478
|
function buildTodoItem(item, index) {
|
|
410
|
-
const row =
|
|
479
|
+
const row = h("div", `ai-todo-item is-${item.status}`);
|
|
411
480
|
row.dataset.index = String(index);
|
|
412
|
-
row.appendChild(
|
|
413
|
-
|
|
414
|
-
|
|
481
|
+
row.appendChild(h("span", "ai-item-status"));
|
|
482
|
+
const check = h("span", "ai-todo-check is-anim");
|
|
483
|
+
check.setAttribute("aria-hidden", "true");
|
|
484
|
+
const checkSvg = svgIcon(ICON_TODO_CHECK);
|
|
485
|
+
if (checkSvg) check.appendChild(checkSvg);
|
|
486
|
+
row.appendChild(check);
|
|
487
|
+
row.appendChild(h("span", "ai-todo-text", item.content));
|
|
488
|
+
row.appendChild(h("span", "ai-todo-active", item.activeForm ?? item.content));
|
|
415
489
|
return row;
|
|
416
490
|
}
|
|
417
|
-
function renderAiTodo(
|
|
418
|
-
if (typeof document === "undefined") return;
|
|
419
|
-
|
|
420
|
-
const root =
|
|
491
|
+
function renderAiTodo(el, items) {
|
|
492
|
+
if (typeof document === "undefined") return el;
|
|
493
|
+
el.textContent = "";
|
|
494
|
+
const root = h("div", "ai-todo");
|
|
421
495
|
const list = Array.isArray(items) ? items : [];
|
|
422
496
|
const done = list.filter((i) => i.status === "done").length;
|
|
423
497
|
root.appendChild(buildTodoHead(done, list.length));
|
|
424
498
|
list.forEach((item, i) => root.appendChild(buildTodoItem(item, i)));
|
|
425
499
|
if (list.length > 0 && done === list.length) root.classList.add("is-complete");
|
|
426
|
-
|
|
500
|
+
el.appendChild(root);
|
|
501
|
+
return el;
|
|
427
502
|
}
|
|
428
503
|
var TODO_NEXT = {
|
|
429
504
|
pending: "running",
|
|
@@ -431,7 +506,7 @@ var TODO_NEXT = {
|
|
|
431
506
|
done: "pending"
|
|
432
507
|
};
|
|
433
508
|
function todoItemStatus(item) {
|
|
434
|
-
for (const s of
|
|
509
|
+
for (const s of AI_STATUSES) {
|
|
435
510
|
if (item.classList.contains(`is-${s}`)) return s;
|
|
436
511
|
}
|
|
437
512
|
return "pending";
|
|
@@ -512,8 +587,20 @@ function initAiTodo(root) {
|
|
|
512
587
|
marked.__icenAiTodoInit = false;
|
|
513
588
|
};
|
|
514
589
|
}
|
|
515
|
-
function
|
|
516
|
-
|
|
590
|
+
function metricField(src, key) {
|
|
591
|
+
return typeof src === "object" && src !== null ? src[key] : void 0;
|
|
592
|
+
}
|
|
593
|
+
function metricNum(v) {
|
|
594
|
+
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
595
|
+
}
|
|
596
|
+
function metricStr(v) {
|
|
597
|
+
return typeof v === "string" && v ? v : void 0;
|
|
598
|
+
}
|
|
599
|
+
function trimNum(v) {
|
|
600
|
+
return String(Math.round(v * 10) / 10);
|
|
601
|
+
}
|
|
602
|
+
function renderAiUsage(el, usage, opts = {}) {
|
|
603
|
+
if (typeof document === "undefined") return el;
|
|
517
604
|
const u = normalizeUsage(usage);
|
|
518
605
|
const segs = [
|
|
519
606
|
{ key: "input", className: "ai-usage-seg--input", label: "\u8F93\u5165", value: u.input ?? 0 },
|
|
@@ -525,9 +612,9 @@ function renderAiUsage(elm, usage, opts = {}) {
|
|
|
525
612
|
const activeSegs = segs.filter((s) => s.value > 0);
|
|
526
613
|
const sum2 = activeSegs.reduce((acc, s) => acc + s.value, 0);
|
|
527
614
|
const total = u.total ?? sum2;
|
|
528
|
-
|
|
529
|
-
const root =
|
|
530
|
-
const bar =
|
|
615
|
+
el.textContent = "";
|
|
616
|
+
const root = h("div", "ai-usage");
|
|
617
|
+
const bar = h("div", "ai-usage-bar");
|
|
531
618
|
const summary = activeSegs.length > 0 ? activeSegs.map((s) => `${s.label} ${formatTokens(s.value)}`).join("\uFF0C") : "\u6682\u65E0\u7528\u91CF";
|
|
532
619
|
bar.setAttribute("role", "img");
|
|
533
620
|
bar.setAttribute("aria-label", `\u7528\u91CF\uFF1A${summary}`);
|
|
@@ -539,19 +626,27 @@ function renderAiUsage(elm, usage, opts = {}) {
|
|
|
539
626
|
}
|
|
540
627
|
root.appendChild(bar);
|
|
541
628
|
if (activeSegs.length > 0) {
|
|
542
|
-
const legend =
|
|
629
|
+
const legend = h("div", "ai-usage-legend");
|
|
543
630
|
for (const s of activeSegs) {
|
|
544
|
-
const item =
|
|
631
|
+
const item = h("span", "ai-usage-legend-item");
|
|
545
632
|
const dot = document.createElement("i");
|
|
546
633
|
dot.className = `ai-usage-dot ${s.className}`;
|
|
547
634
|
dot.setAttribute("aria-hidden", "true");
|
|
548
635
|
item.appendChild(dot);
|
|
549
|
-
item.appendChild(
|
|
550
|
-
item.appendChild(
|
|
636
|
+
item.appendChild(h("span", "ai-usage-legend-label", s.label));
|
|
637
|
+
item.appendChild(h("span", "ai-usage-legend-value", formatTokens(s.value)));
|
|
551
638
|
legend.appendChild(item);
|
|
552
639
|
}
|
|
553
640
|
root.appendChild(legend);
|
|
554
641
|
}
|
|
642
|
+
const ttft = metricNum(opts.metrics?.ttftMs) ?? metricNum(metricField(usage, "ttftMs"));
|
|
643
|
+
const tps = metricNum(opts.metrics?.tokensPerSec) ?? metricNum(metricField(usage, "tokensPerSec"));
|
|
644
|
+
const finish = metricStr(opts.metrics?.finishReason) ?? metricStr(metricField(usage, "finishReason"));
|
|
645
|
+
const metricBits = [];
|
|
646
|
+
if (ttft != null) metricBits.push(`TTFT ${formatDuration(ttft)}`);
|
|
647
|
+
if (tps != null && tps > 0) metricBits.push(`${trimNum(tps)} tok/s`);
|
|
648
|
+
if (finish) metricBits.push(`finish: ${finish}`);
|
|
649
|
+
if (metricBits.length > 0) root.appendChild(h("div", "ai-usage-metrics", metricBits.join(" \xB7 ")));
|
|
555
650
|
const totalParts = [formatTokens(total)];
|
|
556
651
|
if (typeof opts.total === "number" && opts.total > 0) {
|
|
557
652
|
const pct = Math.min(100, Math.round(total / opts.total * 100));
|
|
@@ -560,17 +655,18 @@ function renderAiUsage(elm, usage, opts = {}) {
|
|
|
560
655
|
if (typeof opts.cost === "number" && Number.isFinite(opts.cost)) {
|
|
561
656
|
totalParts.push(` \xB7 $${opts.cost.toFixed(4)}`);
|
|
562
657
|
}
|
|
563
|
-
root.appendChild(
|
|
564
|
-
|
|
658
|
+
root.appendChild(h("div", "ai-usage-total", totalParts.join("")));
|
|
659
|
+
el.appendChild(root);
|
|
660
|
+
return el;
|
|
565
661
|
}
|
|
566
|
-
function renderAiUsageRing(
|
|
567
|
-
if (typeof document === "undefined") return;
|
|
662
|
+
function renderAiUsageRing(el, usage, opts = {}) {
|
|
663
|
+
if (typeof document === "undefined") return el;
|
|
568
664
|
const u = normalizeUsage(usage);
|
|
569
665
|
const used = u.total ?? (u.input ?? 0) + (u.output ?? 0) + (u.cacheRead ?? 0) + (u.cacheWrite ?? 0) + (u.reasoning ?? 0);
|
|
570
666
|
const hasLimit = typeof opts.total === "number" && opts.total > 0;
|
|
571
667
|
const pct = hasLimit ? Math.min(100, Math.max(0, Math.round(used / opts.total * 100))) : 0;
|
|
572
|
-
|
|
573
|
-
const btn =
|
|
668
|
+
el.textContent = "";
|
|
669
|
+
const btn = h("button", "ai-usage-ring");
|
|
574
670
|
btn.type = "button";
|
|
575
671
|
btn.classList.add(pct >= 85 ? "is-hot" : pct >= 60 ? "is-warn" : "is-ok");
|
|
576
672
|
btn.setAttribute("aria-haspopup", "true");
|
|
@@ -594,7 +690,7 @@ function renderAiUsageRing(elm, usage, opts = {}) {
|
|
|
594
690
|
svg2.appendChild(c);
|
|
595
691
|
}
|
|
596
692
|
btn.appendChild(svg2);
|
|
597
|
-
btn.appendChild(
|
|
693
|
+
btn.appendChild(h("span", "ai-usage-ring-pct", hasLimit ? `${pct}%` : formatTokens(used)));
|
|
598
694
|
let panel = null;
|
|
599
695
|
const closePanel = () => {
|
|
600
696
|
if (!panel) return;
|
|
@@ -608,10 +704,10 @@ function renderAiUsageRing(elm, usage, opts = {}) {
|
|
|
608
704
|
closePanel();
|
|
609
705
|
return;
|
|
610
706
|
}
|
|
611
|
-
const p =
|
|
707
|
+
const p = h("div", "popover ai-usage-popover");
|
|
612
708
|
p.hidden = true;
|
|
613
|
-
p.appendChild(
|
|
614
|
-
const body =
|
|
709
|
+
p.appendChild(h("div", "ai-usage-popover-title", opts.title ?? "\u4E0A\u4E0B\u6587\u7A97\u53E3"));
|
|
710
|
+
const body = h("div", "ai-usage-popover-body");
|
|
615
711
|
renderAiUsage(body, usage, opts);
|
|
616
712
|
p.appendChild(body);
|
|
617
713
|
openPopover(p, {
|
|
@@ -625,7 +721,8 @@ function renderAiUsageRing(elm, usage, opts = {}) {
|
|
|
625
721
|
});
|
|
626
722
|
panel = p;
|
|
627
723
|
});
|
|
628
|
-
|
|
724
|
+
el.appendChild(btn);
|
|
725
|
+
return el;
|
|
629
726
|
}
|
|
630
727
|
var svgWrap = (inner) => `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${inner}</svg>`;
|
|
631
728
|
var FILE_OUTLINE = '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/>';
|
|
@@ -673,8 +770,8 @@ function fileKindIcon(kind) {
|
|
|
673
770
|
}
|
|
674
771
|
function renderFileChip(file) {
|
|
675
772
|
const kind = fileKind(file.path);
|
|
676
|
-
const chip =
|
|
677
|
-
const icon =
|
|
773
|
+
const chip = h("span", `ai-file-chip ai-file-chip--${kind} is-${file.status ?? "modified"}`);
|
|
774
|
+
const icon = h("span", "ai-file-icon");
|
|
678
775
|
const svg2 = svgIcon(fileKindIcon(kind));
|
|
679
776
|
if (svg2) icon.appendChild(svg2);
|
|
680
777
|
chip.appendChild(icon);
|
|
@@ -682,21 +779,21 @@ function renderFileChip(file) {
|
|
|
682
779
|
return chip;
|
|
683
780
|
}
|
|
684
781
|
function renderSection(title) {
|
|
685
|
-
const section =
|
|
686
|
-
section.appendChild(
|
|
687
|
-
const body =
|
|
782
|
+
const section = h("section", "ai-context-section");
|
|
783
|
+
section.appendChild(h("h3", "", title));
|
|
784
|
+
const body = h("div", "ai-context-section-body");
|
|
688
785
|
section.appendChild(body);
|
|
689
786
|
return { section, body };
|
|
690
787
|
}
|
|
691
|
-
function renderAiContext(
|
|
692
|
-
if (typeof document === "undefined") return;
|
|
693
|
-
|
|
788
|
+
function renderAiContext(el, model) {
|
|
789
|
+
if (typeof document === "undefined") return el;
|
|
790
|
+
el.textContent = "";
|
|
694
791
|
const m = model ?? {};
|
|
695
|
-
const aside =
|
|
792
|
+
const aside = h("aside", "ai-context");
|
|
696
793
|
aside.hidden = true;
|
|
697
|
-
const head =
|
|
698
|
-
head.appendChild(
|
|
699
|
-
const closeBtn =
|
|
794
|
+
const head = h("div", "ai-context-head");
|
|
795
|
+
head.appendChild(h("span", "", "\u4E0A\u4E0B\u6587"));
|
|
796
|
+
const closeBtn = h("button", "", "\xD7");
|
|
700
797
|
closeBtn.type = "button";
|
|
701
798
|
closeBtn.setAttribute("data-ai-context-close", "");
|
|
702
799
|
closeBtn.setAttribute("aria-label", "\u5173\u95ED");
|
|
@@ -716,7 +813,7 @@ function renderAiContext(elm, model) {
|
|
|
716
813
|
const files = Array.isArray(m.files) ? m.files : [];
|
|
717
814
|
if (files.length > 0) {
|
|
718
815
|
const { section, body } = renderSection(`\u6587\u4EF6 (${files.length})`);
|
|
719
|
-
const chips =
|
|
816
|
+
const chips = h("div", "ai-files");
|
|
720
817
|
for (const f of files) chips.appendChild(renderFileChip(f));
|
|
721
818
|
body.appendChild(chips);
|
|
722
819
|
aside.appendChild(section);
|
|
@@ -726,17 +823,17 @@ function renderAiContext(elm, model) {
|
|
|
726
823
|
const { section, body } = renderSection(`MCP (${servers.length})`);
|
|
727
824
|
for (const s of servers) {
|
|
728
825
|
const ok = s.status !== "disconnected";
|
|
729
|
-
const row =
|
|
730
|
-
const icon =
|
|
826
|
+
const row = h("div", `ai-item is-${ok ? "done" : "error"}`);
|
|
827
|
+
const icon = h("span", "ai-item-icon");
|
|
731
828
|
const svg2 = svgIcon(ICON_SERVER);
|
|
732
829
|
if (svg2) icon.appendChild(svg2);
|
|
733
830
|
row.appendChild(icon);
|
|
734
|
-
const main =
|
|
735
|
-
main.appendChild(
|
|
831
|
+
const main = h("span", "ai-item-main");
|
|
832
|
+
main.appendChild(h("span", "ai-item-title", s.name));
|
|
736
833
|
row.appendChild(main);
|
|
737
|
-
const side =
|
|
738
|
-
side.appendChild(
|
|
739
|
-
side.appendChild(
|
|
834
|
+
const side = h("span", "ai-item-side");
|
|
835
|
+
side.appendChild(h("span", "ai-item-status"));
|
|
836
|
+
side.appendChild(h("span", "ai-item-meta", typeof s.tools === "number" ? `${s.tools} \u5DE5\u5177` : ""));
|
|
740
837
|
row.appendChild(side);
|
|
741
838
|
body.appendChild(row);
|
|
742
839
|
}
|
|
@@ -746,20 +843,21 @@ function renderAiContext(elm, model) {
|
|
|
746
843
|
if (skills.length > 0) {
|
|
747
844
|
const { section, body } = renderSection("Skills");
|
|
748
845
|
for (const s of skills) {
|
|
749
|
-
const row =
|
|
750
|
-
const icon =
|
|
846
|
+
const row = h("div", "ai-item");
|
|
847
|
+
const icon = h("span", "ai-item-icon");
|
|
751
848
|
const svg2 = svgIcon(ICON_SPARKLES);
|
|
752
849
|
if (svg2) icon.appendChild(svg2);
|
|
753
850
|
row.appendChild(icon);
|
|
754
|
-
const main =
|
|
755
|
-
main.appendChild(
|
|
756
|
-
if (s.description) main.appendChild(
|
|
851
|
+
const main = h("span", "ai-item-main");
|
|
852
|
+
main.appendChild(h("span", "ai-item-title", s.name));
|
|
853
|
+
if (s.description) main.appendChild(h("span", "ai-item-sub", s.description));
|
|
757
854
|
row.appendChild(main);
|
|
758
855
|
body.appendChild(row);
|
|
759
856
|
}
|
|
760
857
|
aside.appendChild(section);
|
|
761
858
|
}
|
|
762
|
-
|
|
859
|
+
el.appendChild(aside);
|
|
860
|
+
return el;
|
|
763
861
|
}
|
|
764
862
|
function isInline(drawer) {
|
|
765
863
|
return drawer.classList.contains("ai-context--inline");
|
|
@@ -805,6 +903,7 @@ function initAiContext(root) {
|
|
|
805
903
|
void drawer.offsetWidth;
|
|
806
904
|
drawer.classList.add("is-open");
|
|
807
905
|
syncTriggers(drawer, true);
|
|
906
|
+
dispatch(drawer, "icen:ai-context-open", {});
|
|
808
907
|
const closeBtn = drawer.querySelector("[data-ai-context-close]");
|
|
809
908
|
(closeBtn ?? drawer).focus?.();
|
|
810
909
|
}
|
|
@@ -812,6 +911,7 @@ function initAiContext(root) {
|
|
|
812
911
|
if (drawer.hidden && !drawer.classList.contains("is-open")) return;
|
|
813
912
|
drawer.classList.remove("is-open");
|
|
814
913
|
syncTriggers(drawer, false);
|
|
914
|
+
dispatch(drawer, "icen:ai-context-close", {});
|
|
815
915
|
const finish = () => {
|
|
816
916
|
drawer.hidden = true;
|
|
817
917
|
if (restoreFocus && lastTrigger && document.contains(lastTrigger)) {
|
|
@@ -943,55 +1043,55 @@ function buildAuditBody(body, entries, opts = {}) {
|
|
|
943
1043
|
g.requests++;
|
|
944
1044
|
groups.set(key, g);
|
|
945
1045
|
}
|
|
946
|
-
const totals =
|
|
1046
|
+
const totals = h("div", "ai-audit-totals");
|
|
947
1047
|
const bits = [`${entries.length} \u6B21\u8BF7\u6C42`];
|
|
948
1048
|
if (errors > 0) bits.push(`${errors} \u5931\u8D25`);
|
|
949
1049
|
bits.push(`${formatTokens(tokens)} tok`);
|
|
950
1050
|
if (cost > 0) bits.push(`$${(Math.round(cost * 1e6) / 1e6).toFixed(4)}`);
|
|
951
1051
|
if (ttftN > 0) bits.push(`TTFT ${formatDuration(Math.round(ttftSum / ttftN))}`);
|
|
952
|
-
totals.appendChild(
|
|
1052
|
+
totals.appendChild(h("span", "ai-audit-totals-text", bits.join(" \xB7 ")));
|
|
953
1053
|
body.appendChild(totals);
|
|
954
1054
|
const sorted = Array.from(groups.values()).sort((a, b) => b.tokens - a.tokens);
|
|
955
1055
|
if (sorted.length > 0) {
|
|
956
|
-
const list2 =
|
|
1056
|
+
const list2 = h("div", "ai-audit-models");
|
|
957
1057
|
for (const g of sorted) {
|
|
958
|
-
const row =
|
|
959
|
-
row.appendChild(
|
|
960
|
-
row.appendChild(
|
|
1058
|
+
const row = h("div", "ai-audit-model-row");
|
|
1059
|
+
row.appendChild(h("span", "ai-audit-model-name", g.key));
|
|
1060
|
+
row.appendChild(h("span", "ai-audit-model-meta", `${g.requests} \u6B21 \xB7 ${formatTokens(g.tokens)} tok${g.cost > 0 ? ` \xB7 $${g.cost.toFixed(4)}` : ""}`));
|
|
961
1061
|
list2.appendChild(row);
|
|
962
1062
|
}
|
|
963
1063
|
body.appendChild(list2);
|
|
964
1064
|
}
|
|
965
1065
|
const recent = entries.slice(-limit).reverse();
|
|
966
|
-
const list =
|
|
1066
|
+
const list = h("div", "ai-audit-list");
|
|
967
1067
|
for (const e of recent) {
|
|
968
|
-
const item =
|
|
969
|
-
item.appendChild(
|
|
970
|
-
const main =
|
|
971
|
-
main.appendChild(
|
|
1068
|
+
const item = h("div", `ai-audit-item is-${e.status === "ok" ? "done" : "error"}`);
|
|
1069
|
+
item.appendChild(h("span", "ai-audit-dot"));
|
|
1070
|
+
const main = h("span", "ai-audit-item-main");
|
|
1071
|
+
main.appendChild(h("span", "ai-audit-item-model", `${e.provider} \xB7 ${e.model}`));
|
|
972
1072
|
const metaBits = [timeOf(e.ts), formatDuration(e.durationMs)];
|
|
973
1073
|
if (typeof e.ttftMs === "number") metaBits.push(`TTFT ${formatDuration(e.ttftMs)}`);
|
|
974
1074
|
if ((e.usage?.total ?? 0) > 0) metaBits.push(`${formatTokens(e.usage?.total ?? 0)} tok`);
|
|
975
|
-
main.appendChild(
|
|
1075
|
+
main.appendChild(h("span", "ai-audit-item-meta", metaBits.filter(Boolean).join(" \xB7 ")));
|
|
976
1076
|
item.appendChild(main);
|
|
977
|
-
if (e.error) item.appendChild(
|
|
1077
|
+
if (e.error) item.appendChild(h("span", "ai-audit-item-error", e.error));
|
|
978
1078
|
list.appendChild(item);
|
|
979
1079
|
}
|
|
980
1080
|
body.appendChild(list);
|
|
981
1081
|
}
|
|
982
|
-
function renderAiAudit(
|
|
983
|
-
if (typeof document === "undefined") return;
|
|
984
|
-
|
|
985
|
-
const root =
|
|
1082
|
+
function renderAiAudit(el, source, opts = {}) {
|
|
1083
|
+
if (typeof document === "undefined") return el;
|
|
1084
|
+
el.textContent = "";
|
|
1085
|
+
const root = h("div", "ai-audit");
|
|
986
1086
|
const entries = auditEntriesOf(source);
|
|
987
1087
|
if (entries.length === 0) {
|
|
988
|
-
root.appendChild(
|
|
989
|
-
|
|
990
|
-
return;
|
|
1088
|
+
root.appendChild(h("div", "ai-audit-empty", "\u6682\u65E0\u5BA1\u8BA1\u8BB0\u5F55"));
|
|
1089
|
+
el.appendChild(root);
|
|
1090
|
+
return el;
|
|
991
1091
|
}
|
|
992
1092
|
buildAuditBody(root, entries, { limit: opts.limit });
|
|
993
1093
|
if (opts.clearButton !== false) {
|
|
994
|
-
const clear =
|
|
1094
|
+
const clear = h("button", "btn btn-sm ai-audit-clear", "\u6E05\u9664\u5BA1\u8BA1");
|
|
995
1095
|
clear.type = "button";
|
|
996
1096
|
clear.addEventListener("click", () => {
|
|
997
1097
|
if (opts.onClear) opts.onClear();
|
|
@@ -999,7 +1099,8 @@ function renderAiAudit(elm, source, opts = {}) {
|
|
|
999
1099
|
});
|
|
1000
1100
|
root.appendChild(clear);
|
|
1001
1101
|
}
|
|
1002
|
-
|
|
1102
|
+
el.appendChild(root);
|
|
1103
|
+
return el;
|
|
1003
1104
|
}
|
|
1004
1105
|
export {
|
|
1005
1106
|
initAiContext,
|