@hpyperry/dsh-ref-lib 0.7.0 → 0.8.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/README.md +12 -14
- package/lib/client/RefLibDock.d.ts +4 -2
- package/lib/client/RefLibDock.d.ts.map +1 -1
- package/lib/client/RefLibDock.js +31 -23
- package/lib/client/RefLibDock.js.map +1 -1
- package/lib/client/RefLibPanel.d.ts +6 -4
- package/lib/client/RefLibPanel.d.ts.map +1 -1
- package/lib/client/RefLibPanel.js +64 -20
- package/lib/client/RefLibPanel.js.map +1 -1
- package/lib/client/index.d.ts.map +1 -1
- package/lib/client/index.js +5 -2
- package/lib/client/index.js.map +1 -1
- package/lib/client/locales.d.ts +14 -2
- package/lib/client/locales.d.ts.map +1 -1
- package/lib/client/locales.js +22 -8
- package/lib/client/locales.js.map +1 -1
- package/lib/client/styles.d.ts.map +1 -1
- package/lib/client/styles.js +158 -23
- package/lib/client/styles.js.map +1 -1
- package/lib/client.js +446 -134
- package/lib/client.js.map +1 -1
- package/lib/commands.d.ts +2 -1
- package/lib/commands.d.ts.map +1 -1
- package/lib/commands.js +15 -3
- package/lib/commands.js.map +1 -1
- package/lib/index.d.ts +3 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +9 -7
- package/lib/index.js.map +1 -1
- package/lib/render.d.ts +5 -1
- package/lib/render.d.ts.map +1 -1
- package/lib/render.js +101 -11
- package/lib/render.js.map +1 -1
- package/lib/routes.d.ts.map +1 -1
- package/lib/routes.js +42 -2
- package/lib/routes.js.map +1 -1
- package/lib/service.d.ts +22 -1
- package/lib/service.d.ts.map +1 -1
- package/lib/service.js +101 -4
- package/lib/service.js.map +1 -1
- package/package.json +9 -1
package/lib/client.js
CHANGED
|
@@ -313,31 +313,63 @@ window.__ModuleLoader__.load({
|
|
|
313
313
|
* 本组件为纯展示:异步操作与错误归集由 RefLibDock 持有。
|
|
314
314
|
* @module @hpyperry/dsh-ref-lib/src/client/RefLibPanel
|
|
315
315
|
*/
|
|
316
|
+
/** 用途说明最大长度(与 node half service.NOTE_MAX_LENGTH 一致)。 */
|
|
317
|
+
const NOTE_MAX_LENGTH = 120;
|
|
316
318
|
/**
|
|
317
319
|
* 渲染参考库管理面板。
|
|
318
320
|
* @param props - 见 {@link RefLibPanelProps}。
|
|
319
321
|
* @returns 对话框元素(关闭时 Modal 返回 null)。
|
|
320
322
|
*/
|
|
321
323
|
function RefLibPanel(props) {
|
|
322
|
-
const { open, onClose, libs, loading, busy, picking, removingId, error, t, onRemove, onAddPath, onBrowse } = props;
|
|
324
|
+
const { open, onClose, libs, loading, busy, picking, removingId, error, t, onRemove, onAddPath, onUpdateNote, onBrowse } = props;
|
|
323
325
|
const [draft, setDraft] = (0, react.useState)("");
|
|
326
|
+
const [noteDraft, setNoteDraft] = (0, react.useState)("");
|
|
327
|
+
const [detailId, setDetailId] = (0, react.useState)(null);
|
|
328
|
+
const [editNote, setEditNote] = (0, react.useState)("");
|
|
324
329
|
(0, react.useEffect)(() => {
|
|
325
|
-
if (!open)
|
|
330
|
+
if (!open) {
|
|
331
|
+
setDraft("");
|
|
332
|
+
setNoteDraft("");
|
|
333
|
+
setDetailId(null);
|
|
334
|
+
}
|
|
326
335
|
}, [open]);
|
|
327
336
|
const handleSubmit = async () => {
|
|
328
337
|
const trimmed = draft.trim();
|
|
329
338
|
if (trimmed === "") return;
|
|
330
339
|
try {
|
|
331
|
-
|
|
340
|
+
const note = noteDraft.trim();
|
|
341
|
+
await onAddPath(trimmed, note === "" ? void 0 : note);
|
|
332
342
|
setDraft("");
|
|
343
|
+
setNoteDraft("");
|
|
333
344
|
} catch {}
|
|
334
345
|
};
|
|
346
|
+
/** 浏览选中目录 → 填入路径字段(不直接添加,用户可补用途后提交)。 */
|
|
347
|
+
const handleBrowse = async () => {
|
|
348
|
+
const path = await onBrowse();
|
|
349
|
+
if (path !== null) setDraft(path);
|
|
350
|
+
};
|
|
351
|
+
/** 展开/收起条目详情;展开时载入当前用途草稿。 */
|
|
352
|
+
const toggleDetail = (entry) => {
|
|
353
|
+
if (detailId === entry.id) {
|
|
354
|
+
setDetailId(null);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
setDetailId(entry.id);
|
|
358
|
+
setEditNote(entry.note ?? "");
|
|
359
|
+
};
|
|
360
|
+
/** 保存详情编辑的用途说明;成功后收起详情。 */
|
|
361
|
+
const handleSaveNote = async () => {
|
|
362
|
+
if (detailId === null) return;
|
|
363
|
+
await onUpdateNote(detailId, editNote);
|
|
364
|
+
setDetailId(null);
|
|
365
|
+
};
|
|
335
366
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
336
367
|
open,
|
|
337
368
|
onClose,
|
|
338
369
|
title: t("panel.title"),
|
|
339
370
|
closeLabel: t("panel.close"),
|
|
340
371
|
description: t("panel.description", { count: String(libs.length) }),
|
|
372
|
+
className: "reflib-modal",
|
|
341
373
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
342
374
|
className: "reflib-panel",
|
|
343
375
|
children: [
|
|
@@ -380,45 +412,144 @@ window.__ModuleLoader__.load({
|
|
|
380
412
|
children: libs.map((entry) => {
|
|
381
413
|
const name = libBasename(entry.path);
|
|
382
414
|
const removing = removingId === entry.id;
|
|
415
|
+
const detailOpen = detailId === entry.id;
|
|
383
416
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
384
|
-
className: "reflib-
|
|
417
|
+
className: "reflib-listItem",
|
|
385
418
|
"data-removing": removing || void 0,
|
|
386
|
-
children: [
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
className: "reflib-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
420
|
+
className: "reflib-row",
|
|
421
|
+
children: [
|
|
422
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpen16, {
|
|
423
|
+
size: 16,
|
|
424
|
+
className: "reflib-rowIcon"
|
|
425
|
+
}),
|
|
426
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
427
|
+
className: "reflib-rowBody",
|
|
428
|
+
children: [
|
|
429
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
430
|
+
className: "reflib-rowName",
|
|
431
|
+
title: entry.path,
|
|
432
|
+
children: name
|
|
433
|
+
}),
|
|
434
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
435
|
+
className: "reflib-rowPath",
|
|
436
|
+
title: entry.path,
|
|
437
|
+
children: entry.path
|
|
438
|
+
}),
|
|
439
|
+
entry.note !== void 0 && entry.note !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
440
|
+
className: "reflib-rowNote",
|
|
441
|
+
title: entry.note,
|
|
442
|
+
children: entry.note.replace(/\s+/g, " ")
|
|
443
|
+
})
|
|
444
|
+
]
|
|
445
|
+
}),
|
|
446
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
447
|
+
label: t("detail.open"),
|
|
448
|
+
side: "top",
|
|
449
|
+
delayMs: 400,
|
|
450
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
451
|
+
type: "button",
|
|
452
|
+
className: "reflib-rowAction",
|
|
453
|
+
"aria-label": t("detail.open.aria", { name }),
|
|
454
|
+
"aria-expanded": detailOpen || void 0,
|
|
455
|
+
disabled: busy || removingId !== null,
|
|
456
|
+
onClick: () => {
|
|
457
|
+
toggleDetail(entry);
|
|
458
|
+
},
|
|
459
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, { size: 14 })
|
|
460
|
+
})
|
|
461
|
+
}),
|
|
462
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
463
|
+
label: t("list.remove"),
|
|
464
|
+
side: "top",
|
|
465
|
+
delayMs: 400,
|
|
466
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
467
|
+
type: "button",
|
|
468
|
+
className: "reflib-rowRemove",
|
|
469
|
+
"aria-label": t("list.remove.aria", { name }),
|
|
470
|
+
disabled: busy || removingId !== null,
|
|
471
|
+
onClick: () => {
|
|
472
|
+
onRemove(entry.id);
|
|
473
|
+
},
|
|
474
|
+
children: removing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconLoadingOutline16, {
|
|
475
|
+
size: 14,
|
|
476
|
+
className: "reflib-spin"
|
|
477
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 14 })
|
|
478
|
+
})
|
|
419
479
|
})
|
|
420
|
-
|
|
421
|
-
|
|
480
|
+
]
|
|
481
|
+
}), detailOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
482
|
+
className: "reflib-detail",
|
|
483
|
+
children: [
|
|
484
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
485
|
+
className: "reflib-detailMeta",
|
|
486
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
487
|
+
className: "reflib-detailKey",
|
|
488
|
+
children: "ID"
|
|
489
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
490
|
+
className: "reflib-detailValue",
|
|
491
|
+
children: entry.id
|
|
492
|
+
})]
|
|
493
|
+
}),
|
|
494
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
495
|
+
className: "reflib-detailMeta",
|
|
496
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
497
|
+
className: "reflib-detailKey",
|
|
498
|
+
children: t("detail.path")
|
|
499
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
500
|
+
className: "reflib-detailValue",
|
|
501
|
+
title: entry.path,
|
|
502
|
+
children: entry.path
|
|
503
|
+
})]
|
|
504
|
+
}),
|
|
505
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
506
|
+
className: "reflib-detailKey",
|
|
507
|
+
children: t("add.note.label")
|
|
508
|
+
}),
|
|
509
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
510
|
+
className: "reflib-noteWrap",
|
|
511
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
512
|
+
className: "reflib-noteTextarea",
|
|
513
|
+
value: editNote,
|
|
514
|
+
placeholder: t("add.note.placeholder"),
|
|
515
|
+
"aria-label": t("add.note.label"),
|
|
516
|
+
disabled: busy,
|
|
517
|
+
rows: 3,
|
|
518
|
+
maxLength: NOTE_MAX_LENGTH,
|
|
519
|
+
onChange: (event) => {
|
|
520
|
+
setEditNote(event.currentTarget.value);
|
|
521
|
+
}
|
|
522
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
523
|
+
className: "reflib-noteCount",
|
|
524
|
+
children: [
|
|
525
|
+
editNote.length,
|
|
526
|
+
"/",
|
|
527
|
+
NOTE_MAX_LENGTH
|
|
528
|
+
]
|
|
529
|
+
})]
|
|
530
|
+
}),
|
|
531
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
532
|
+
className: "reflib-detailActions",
|
|
533
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
534
|
+
variant: "ghost",
|
|
535
|
+
size: "sm",
|
|
536
|
+
disabled: busy,
|
|
537
|
+
onClick: () => {
|
|
538
|
+
setDetailId(null);
|
|
539
|
+
},
|
|
540
|
+
children: t("detail.cancel")
|
|
541
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
542
|
+
variant: "primary",
|
|
543
|
+
size: "sm",
|
|
544
|
+
disabled: busy,
|
|
545
|
+
onClick: () => {
|
|
546
|
+
handleSaveNote();
|
|
547
|
+
},
|
|
548
|
+
children: t("detail.save")
|
|
549
|
+
})]
|
|
550
|
+
})
|
|
551
|
+
]
|
|
552
|
+
})]
|
|
422
553
|
}, entry.id);
|
|
423
554
|
})
|
|
424
555
|
}),
|
|
@@ -430,49 +561,65 @@ window.__ModuleLoader__.load({
|
|
|
430
561
|
className: "reflib-addLabel",
|
|
431
562
|
children: t("add.label")
|
|
432
563
|
}),
|
|
564
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
565
|
+
className: "reflib-addRow",
|
|
566
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
567
|
+
className: "reflib-addInputWrap",
|
|
568
|
+
value: draft,
|
|
569
|
+
placeholder: t("add.placeholder"),
|
|
570
|
+
"aria-label": t("add.label"),
|
|
571
|
+
disabled: busy || picking,
|
|
572
|
+
onChange: (event) => {
|
|
573
|
+
setDraft(event.currentTarget.value);
|
|
574
|
+
},
|
|
575
|
+
onKeyDown: (event) => {
|
|
576
|
+
if (event.key === "Enter" && !event.nativeEvent.isComposing) {
|
|
577
|
+
event.preventDefault();
|
|
578
|
+
handleSubmit();
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
582
|
+
variant: "outline",
|
|
583
|
+
size: "sm",
|
|
584
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16, { size: 14 }),
|
|
585
|
+
disabled: busy || picking,
|
|
586
|
+
onClick: () => {
|
|
587
|
+
handleBrowse();
|
|
588
|
+
},
|
|
589
|
+
children: t("add.browse")
|
|
590
|
+
})]
|
|
591
|
+
}),
|
|
592
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
593
|
+
className: "reflib-noteWrap",
|
|
594
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
595
|
+
className: "reflib-noteTextarea",
|
|
596
|
+
value: noteDraft,
|
|
597
|
+
placeholder: t("add.note.placeholder"),
|
|
598
|
+
"aria-label": t("add.note.label"),
|
|
599
|
+
disabled: busy || picking,
|
|
600
|
+
rows: 2,
|
|
601
|
+
maxLength: NOTE_MAX_LENGTH,
|
|
602
|
+
onChange: (event) => {
|
|
603
|
+
setNoteDraft(event.currentTarget.value);
|
|
604
|
+
}
|
|
605
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
606
|
+
className: "reflib-noteCount",
|
|
607
|
+
children: [
|
|
608
|
+
noteDraft.length,
|
|
609
|
+
"/",
|
|
610
|
+
NOTE_MAX_LENGTH
|
|
611
|
+
]
|
|
612
|
+
})]
|
|
613
|
+
}),
|
|
433
614
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
434
615
|
variant: "primary",
|
|
435
|
-
className: "reflib-
|
|
436
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
437
|
-
disabled: busy || picking,
|
|
616
|
+
className: "reflib-addSubmit",
|
|
617
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
|
|
618
|
+
disabled: busy || picking || draft.trim() === "",
|
|
438
619
|
onClick: () => {
|
|
439
|
-
|
|
620
|
+
handleSubmit();
|
|
440
621
|
},
|
|
441
|
-
children: t("add.
|
|
442
|
-
}),
|
|
443
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
444
|
-
className: "reflib-addManual",
|
|
445
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
446
|
-
className: "reflib-addManualLabel",
|
|
447
|
-
children: t("add.manual")
|
|
448
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
449
|
-
className: "reflib-addRow",
|
|
450
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
451
|
-
className: "reflib-addInputWrap",
|
|
452
|
-
value: draft,
|
|
453
|
-
placeholder: t("add.placeholder"),
|
|
454
|
-
"aria-label": t("add.label"),
|
|
455
|
-
disabled: busy || picking,
|
|
456
|
-
onChange: (event) => {
|
|
457
|
-
setDraft(event.currentTarget.value);
|
|
458
|
-
},
|
|
459
|
-
onKeyDown: (event) => {
|
|
460
|
-
if (event.key === "Enter" && !event.nativeEvent.isComposing) {
|
|
461
|
-
event.preventDefault();
|
|
462
|
-
handleSubmit();
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
466
|
-
variant: "primary",
|
|
467
|
-
size: "sm",
|
|
468
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
|
|
469
|
-
disabled: busy || picking || draft.trim() === "",
|
|
470
|
-
onClick: () => {
|
|
471
|
-
handleSubmit();
|
|
472
|
-
},
|
|
473
|
-
children: t("add.submit")
|
|
474
|
-
})]
|
|
475
|
-
})]
|
|
622
|
+
children: t("add.submit")
|
|
476
623
|
}),
|
|
477
624
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
478
625
|
className: "reflib-addHint",
|
|
@@ -763,6 +910,12 @@ window.__ModuleLoader__.load({
|
|
|
763
910
|
padding: 0 8px;
|
|
764
911
|
}
|
|
765
912
|
|
|
913
|
+
.reflib-listItem {
|
|
914
|
+
display: flex;
|
|
915
|
+
flex-direction: column;
|
|
916
|
+
min-width: 0;
|
|
917
|
+
}
|
|
918
|
+
|
|
766
919
|
.reflib-row {
|
|
767
920
|
display: flex;
|
|
768
921
|
align-items: center;
|
|
@@ -778,7 +931,7 @@ window.__ModuleLoader__.load({
|
|
|
778
931
|
background: var(--dsw-alias-interactive-bg-hover);
|
|
779
932
|
}
|
|
780
933
|
|
|
781
|
-
.reflib-
|
|
934
|
+
.reflib-listItem[data-removing='true'] {
|
|
782
935
|
opacity: 0.55;
|
|
783
936
|
pointer-events: none;
|
|
784
937
|
}
|
|
@@ -817,6 +970,16 @@ window.__ModuleLoader__.load({
|
|
|
817
970
|
white-space: nowrap;
|
|
818
971
|
}
|
|
819
972
|
|
|
973
|
+
/* 列表行用途说明(Description,v8):单行截断,与路径同属次行层级 */
|
|
974
|
+
.reflib-rowNote {
|
|
975
|
+
overflow: hidden;
|
|
976
|
+
color: var(--dsw-alias-label-secondary);
|
|
977
|
+
font-size: 12px;
|
|
978
|
+
line-height: 16px;
|
|
979
|
+
text-overflow: ellipsis;
|
|
980
|
+
white-space: nowrap;
|
|
981
|
+
}
|
|
982
|
+
|
|
820
983
|
.reflib-rowRemove {
|
|
821
984
|
display: inline-flex;
|
|
822
985
|
align-items: center;
|
|
@@ -843,6 +1006,120 @@ window.__ModuleLoader__.load({
|
|
|
843
1006
|
cursor: default;
|
|
844
1007
|
}
|
|
845
1008
|
|
|
1009
|
+
/* 详情/编辑入口按钮(与移除同尺寸,非危险 hover) */
|
|
1010
|
+
.reflib-rowAction {
|
|
1011
|
+
display: inline-flex;
|
|
1012
|
+
align-items: center;
|
|
1013
|
+
justify-content: center;
|
|
1014
|
+
flex: none;
|
|
1015
|
+
width: 28px;
|
|
1016
|
+
height: 28px;
|
|
1017
|
+
padding: 0;
|
|
1018
|
+
border: none;
|
|
1019
|
+
border-radius: 8px;
|
|
1020
|
+
background: transparent;
|
|
1021
|
+
color: var(--dsw-alias-label-tertiary);
|
|
1022
|
+
cursor: pointer;
|
|
1023
|
+
transition: background-color 120ms ease, color 120ms ease;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
.reflib-rowAction:hover:not(:disabled) {
|
|
1027
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
1028
|
+
color: var(--dsw-alias-label-primary);
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
.reflib-rowAction:disabled {
|
|
1032
|
+
opacity: 0.4;
|
|
1033
|
+
cursor: default;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
/* 条目详情展开区(ID / 路径 / 用途编辑) */
|
|
1037
|
+
.reflib-detail {
|
|
1038
|
+
display: flex;
|
|
1039
|
+
flex-direction: column;
|
|
1040
|
+
gap: 5px;
|
|
1041
|
+
margin: 2px 0 6px;
|
|
1042
|
+
padding: 8px 10px 10px;
|
|
1043
|
+
border-radius: 10px;
|
|
1044
|
+
background: var(--dsw-alias-surface-inset, var(--dsw-alias-surface-raised));
|
|
1045
|
+
min-width: 0;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
.reflib-detailMeta {
|
|
1049
|
+
display: flex;
|
|
1050
|
+
align-items: baseline;
|
|
1051
|
+
gap: 8px;
|
|
1052
|
+
min-width: 0;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
.reflib-detailKey {
|
|
1056
|
+
flex: none;
|
|
1057
|
+
font-size: 11px;
|
|
1058
|
+
line-height: 16px;
|
|
1059
|
+
color: var(--dsw-alias-label-caption);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
.reflib-detailValue {
|
|
1063
|
+
overflow: hidden;
|
|
1064
|
+
min-width: 0;
|
|
1065
|
+
font-size: 12px;
|
|
1066
|
+
line-height: 16px;
|
|
1067
|
+
color: var(--dsw-alias-label-secondary);
|
|
1068
|
+
text-overflow: ellipsis;
|
|
1069
|
+
white-space: nowrap;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
.reflib-detailActions {
|
|
1073
|
+
display: flex;
|
|
1074
|
+
justify-content: flex-end;
|
|
1075
|
+
gap: 6px;
|
|
1076
|
+
margin-top: 2px;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/* 用途说明多行输入(添加表单 + 详情编辑共用) */
|
|
1080
|
+
.reflib-noteWrap {
|
|
1081
|
+
position: relative;
|
|
1082
|
+
display: flex;
|
|
1083
|
+
min-width: 0;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
.reflib-noteTextarea {
|
|
1087
|
+
width: 100%;
|
|
1088
|
+
box-sizing: border-box;
|
|
1089
|
+
padding: 6px 8px;
|
|
1090
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
1091
|
+
border-radius: 8px;
|
|
1092
|
+
background: var(--dsw-alias-surface-field);
|
|
1093
|
+
color: var(--dsw-alias-label-primary);
|
|
1094
|
+
font: inherit;
|
|
1095
|
+
font-size: 13px;
|
|
1096
|
+
line-height: 18px;
|
|
1097
|
+
resize: vertical;
|
|
1098
|
+
min-height: 40px;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
.reflib-noteTextarea:focus {
|
|
1102
|
+
outline: 2px solid var(--dsw-alias-focus-ring, var(--dsw-alias-state-info-primary));
|
|
1103
|
+
outline-offset: -1px;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
.reflib-noteTextarea:disabled {
|
|
1107
|
+
opacity: 0.5;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
.reflib-noteCount {
|
|
1111
|
+
position: absolute;
|
|
1112
|
+
right: 8px;
|
|
1113
|
+
bottom: 6px;
|
|
1114
|
+
padding: 0 4px;
|
|
1115
|
+
border-radius: 4px;
|
|
1116
|
+
background: var(--dsw-alias-surface-field);
|
|
1117
|
+
font-size: 10px;
|
|
1118
|
+
line-height: 14px;
|
|
1119
|
+
color: var(--dsw-alias-label-caption);
|
|
1120
|
+
pointer-events: none;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
846
1123
|
/* 空态 / 加载态 / 错误态 */
|
|
847
1124
|
.reflib-status {
|
|
848
1125
|
display: flex;
|
|
@@ -908,9 +1185,28 @@ window.__ModuleLoader__.load({
|
|
|
908
1185
|
background: var(--dsw-alias-border-l2);
|
|
909
1186
|
}
|
|
910
1187
|
|
|
1188
|
+
/* ── 管理面板 Modal(v8 优化)──
|
|
1189
|
+
宽度放宽到约 1/3 屏(上限 560px);进入动画为柔和缓出(easeOutQuint 风格:
|
|
1190
|
+
280ms 浮起 + 淡入,位移 12px→0、scale 0.96→1),无回弹——更从容、高级感。 */
|
|
1191
|
+
.reflib-modal {
|
|
1192
|
+
width: min(33vw, 560px);
|
|
1193
|
+
animation: reflib-pop 280ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
@keyframes reflib-pop {
|
|
1197
|
+
0% {
|
|
1198
|
+
opacity: 0;
|
|
1199
|
+
transform: scale(0.96) translateY(12px);
|
|
1200
|
+
}
|
|
1201
|
+
100% {
|
|
1202
|
+
opacity: 1;
|
|
1203
|
+
transform: scale(1) translateY(0);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
|
|
911
1207
|
/* ── 添加表单 ──
|
|
912
|
-
|
|
913
|
-
|
|
1208
|
+
统一表单(v8 UI 重构):路径(可输入 / 浏览填充)+ 用途(可选)同一容器,
|
|
1209
|
+
同一「添加」按钮提交——用途与路径强关联,浏览不再直接添加。 */
|
|
914
1210
|
.reflib-add {
|
|
915
1211
|
display: flex;
|
|
916
1212
|
flex-direction: column;
|
|
@@ -925,25 +1221,6 @@ window.__ModuleLoader__.load({
|
|
|
925
1221
|
color: var(--dsw-alias-label-secondary);
|
|
926
1222
|
}
|
|
927
1223
|
|
|
928
|
-
/* 主方式:选择目录 —— 全宽主按钮(优先级最高) */
|
|
929
|
-
.reflib-addBrowseMain {
|
|
930
|
-
width: 100%;
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
/* 备选:手动输入路径组 */
|
|
934
|
-
.reflib-addManual {
|
|
935
|
-
display: flex;
|
|
936
|
-
flex-direction: column;
|
|
937
|
-
gap: 6px;
|
|
938
|
-
min-width: 0;
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
.reflib-addManualLabel {
|
|
942
|
-
font-size: 12px;
|
|
943
|
-
line-height: 16px;
|
|
944
|
-
color: var(--dsw-alias-label-caption);
|
|
945
|
-
}
|
|
946
|
-
|
|
947
1224
|
.reflib-addRow {
|
|
948
1225
|
display: flex;
|
|
949
1226
|
align-items: center;
|
|
@@ -965,13 +1242,18 @@ window.__ModuleLoader__.load({
|
|
|
965
1242
|
line-height: 18px;
|
|
966
1243
|
}
|
|
967
1244
|
|
|
1245
|
+
/* 全宽「添加」主按钮 */
|
|
1246
|
+
.reflib-addSubmit {
|
|
1247
|
+
width: 100%;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
968
1250
|
.reflib-addHint {
|
|
969
1251
|
font-size: 11px;
|
|
970
1252
|
line-height: 16px;
|
|
971
1253
|
color: var(--dsw-alias-label-caption);
|
|
972
1254
|
}
|
|
973
1255
|
|
|
974
|
-
/*
|
|
1256
|
+
/* 窄视口:路径行换行,输入框占满一行 */
|
|
975
1257
|
@media (max-width: 440px) {
|
|
976
1258
|
.reflib-addRow {
|
|
977
1259
|
flex-wrap: wrap;
|
|
@@ -1045,7 +1327,7 @@ window.__ModuleLoader__.load({
|
|
|
1045
1327
|
* @returns 胶囊入口(+ 打开时的管理面板)。
|
|
1046
1328
|
*/
|
|
1047
1329
|
function RefLibDock(props) {
|
|
1048
|
-
const { sessionId, load, add, remove, pickDirectory, listDirectory, t } = props;
|
|
1330
|
+
const { sessionId, load, add, remove, setNote, pickDirectory, listDirectory, t } = props;
|
|
1049
1331
|
const [open, setOpen] = (0, react.useState)(false);
|
|
1050
1332
|
const [libs, setLibs] = (0, react.useState)([]);
|
|
1051
1333
|
const [loading, setLoading] = (0, react.useState)(false);
|
|
@@ -1056,6 +1338,7 @@ window.__ModuleLoader__.load({
|
|
|
1056
1338
|
const seq = (0, react.useRef)(0);
|
|
1057
1339
|
const [pickerMode, setPickerMode] = (0, react.useState)(null);
|
|
1058
1340
|
const [browserOpen, setBrowserOpen] = (0, react.useState)(false);
|
|
1341
|
+
const pendingPick = (0, react.useRef)(null);
|
|
1059
1342
|
const detectPicker = async () => {
|
|
1060
1343
|
if (pickerMode !== null) return pickerMode;
|
|
1061
1344
|
let mode;
|
|
@@ -1106,11 +1389,11 @@ window.__ModuleLoader__.load({
|
|
|
1106
1389
|
setBusy(false);
|
|
1107
1390
|
}
|
|
1108
1391
|
};
|
|
1109
|
-
const handleAddPath = async (path) => {
|
|
1392
|
+
const handleAddPath = async (path, note) => {
|
|
1110
1393
|
setBusy(true);
|
|
1111
1394
|
setError(null);
|
|
1112
1395
|
try {
|
|
1113
|
-
await add(sessionId, path);
|
|
1396
|
+
await add(sessionId, path, note);
|
|
1114
1397
|
await refresh();
|
|
1115
1398
|
} catch (cause) {
|
|
1116
1399
|
setError(formatError(cause, t));
|
|
@@ -1119,47 +1402,59 @@ window.__ModuleLoader__.load({
|
|
|
1119
1402
|
setBusy(false);
|
|
1120
1403
|
}
|
|
1121
1404
|
};
|
|
1122
|
-
/**
|
|
1123
|
-
const
|
|
1405
|
+
/** 更新条目用途说明(编辑详情保存);失败入错误槽、不抛出(编辑区保持打开)。 */
|
|
1406
|
+
const handleUpdateNote = async (id, note) => {
|
|
1124
1407
|
setBusy(true);
|
|
1125
1408
|
setError(null);
|
|
1126
1409
|
try {
|
|
1127
|
-
await
|
|
1410
|
+
await setNote(sessionId, id, note);
|
|
1128
1411
|
await refresh();
|
|
1129
|
-
return true;
|
|
1130
1412
|
} catch (cause) {
|
|
1131
1413
|
setError(formatError(cause, t));
|
|
1132
|
-
return false;
|
|
1133
1414
|
} finally {
|
|
1134
1415
|
setBusy(false);
|
|
1135
1416
|
}
|
|
1136
1417
|
};
|
|
1137
|
-
|
|
1418
|
+
/** 唤起目录选择(browse 应用内浏览器 / native 系统对话框)并返回选中的路径;
|
|
1419
|
+
* 取消或失败返回 null——**不直接添加**,由面板把路径填入表单(用户可补用途后提交)。 */
|
|
1420
|
+
const pickPath = async () => {
|
|
1138
1421
|
setError(null);
|
|
1139
1422
|
let mode;
|
|
1140
1423
|
try {
|
|
1141
1424
|
mode = await detectPicker();
|
|
1142
1425
|
} catch (cause) {
|
|
1143
1426
|
setError(formatError(cause, t));
|
|
1144
|
-
return;
|
|
1427
|
+
return null;
|
|
1145
1428
|
}
|
|
1146
1429
|
if (mode === "browse") {
|
|
1147
1430
|
setBrowserOpen(true);
|
|
1148
|
-
return
|
|
1431
|
+
return await new Promise((resolve) => {
|
|
1432
|
+
pendingPick.current = resolve;
|
|
1433
|
+
});
|
|
1149
1434
|
}
|
|
1150
1435
|
setPicking(true);
|
|
1151
1436
|
try {
|
|
1152
|
-
|
|
1153
|
-
if (picked !== null) await addPath(picked);
|
|
1437
|
+
return await pickDirectory();
|
|
1154
1438
|
} catch (cause) {
|
|
1155
1439
|
setError(formatError(cause, t));
|
|
1440
|
+
return null;
|
|
1156
1441
|
} finally {
|
|
1157
1442
|
setPicking(false);
|
|
1158
1443
|
}
|
|
1159
1444
|
};
|
|
1160
|
-
/** 应用内浏览器选定目录 →
|
|
1161
|
-
const handleBrowserPick =
|
|
1162
|
-
|
|
1445
|
+
/** 应用内浏览器选定目录 → 把路径交给等待中的 pickPath 调用方并关闭浏览器。 */
|
|
1446
|
+
const handleBrowserPick = (path) => {
|
|
1447
|
+
setBrowserOpen(false);
|
|
1448
|
+
const resolve = pendingPick.current;
|
|
1449
|
+
pendingPick.current = null;
|
|
1450
|
+
resolve?.(path);
|
|
1451
|
+
};
|
|
1452
|
+
/** 应用内浏览器取消 → 以 null 结束等待中的 pickPath。 */
|
|
1453
|
+
const handleBrowserClose = () => {
|
|
1454
|
+
setBrowserOpen(false);
|
|
1455
|
+
const resolve = pendingPick.current;
|
|
1456
|
+
pendingPick.current = null;
|
|
1457
|
+
resolve?.(null);
|
|
1163
1458
|
};
|
|
1164
1459
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1165
1460
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -1207,18 +1502,15 @@ window.__ModuleLoader__.load({
|
|
|
1207
1502
|
handleRemove(id);
|
|
1208
1503
|
},
|
|
1209
1504
|
onAddPath: handleAddPath,
|
|
1210
|
-
|
|
1505
|
+
onUpdateNote: handleUpdateNote,
|
|
1506
|
+
onBrowse: pickPath
|
|
1211
1507
|
}),
|
|
1212
1508
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RefLibBrowser, {
|
|
1213
1509
|
open: browserOpen,
|
|
1214
|
-
onClose:
|
|
1215
|
-
setBrowserOpen(false);
|
|
1216
|
-
},
|
|
1510
|
+
onClose: handleBrowserClose,
|
|
1217
1511
|
listDirectory,
|
|
1218
1512
|
t,
|
|
1219
|
-
onOpen:
|
|
1220
|
-
handleBrowserPick(path);
|
|
1221
|
-
}
|
|
1513
|
+
onOpen: handleBrowserPick
|
|
1222
1514
|
})
|
|
1223
1515
|
] });
|
|
1224
1516
|
}
|
|
@@ -1244,14 +1536,20 @@ window.__ModuleLoader__.load({
|
|
|
1244
1536
|
"list.remove": "移除",
|
|
1245
1537
|
"list.remove.aria": "移除参考库 {name}",
|
|
1246
1538
|
"list.empty": "还没有参考库",
|
|
1247
|
-
"list.empty.hint": "
|
|
1539
|
+
"list.empty.hint": "在下方输入目录路径,或点击「浏览」选择目录",
|
|
1248
1540
|
"list.loading": "正在加载…",
|
|
1541
|
+
"detail.open": "查看详情",
|
|
1542
|
+
"detail.open.aria": "查看 {name} 的详情",
|
|
1543
|
+
"detail.path": "路径",
|
|
1544
|
+
"detail.cancel": "取消",
|
|
1545
|
+
"detail.save": "保存",
|
|
1249
1546
|
"add.label": "添加参考库",
|
|
1250
1547
|
"add.placeholder": "输入目录路径(支持 ~ 与相对)",
|
|
1251
1548
|
"add.submit": "添加",
|
|
1252
|
-
"add.
|
|
1253
|
-
"add.
|
|
1254
|
-
"add.
|
|
1549
|
+
"add.browse": "浏览",
|
|
1550
|
+
"add.note.label": "用途说明",
|
|
1551
|
+
"add.note.placeholder": "用途说明(可选,帮助 agent 判断相关性)",
|
|
1552
|
+
"add.hint": "目录仅作只读参考;用途不填时自动提取 README 标题",
|
|
1255
1553
|
"browser.title": "选择目录",
|
|
1256
1554
|
"browser.home": "主目录",
|
|
1257
1555
|
"browser.open": "选择此目录",
|
|
@@ -1278,14 +1576,20 @@ window.__ModuleLoader__.load({
|
|
|
1278
1576
|
"list.remove": "Remove",
|
|
1279
1577
|
"list.remove.aria": "Remove reference library {name}",
|
|
1280
1578
|
"list.empty": "No reference libraries yet",
|
|
1281
|
-
"list.empty.hint": "Enter a directory path below, or click “
|
|
1579
|
+
"list.empty.hint": "Enter a directory path below, or click “Browse” to pick one",
|
|
1282
1580
|
"list.loading": "Loading…",
|
|
1581
|
+
"detail.open": "View details",
|
|
1582
|
+
"detail.open.aria": "View details of {name}",
|
|
1583
|
+
"detail.path": "Path",
|
|
1584
|
+
"detail.cancel": "Cancel",
|
|
1585
|
+
"detail.save": "Save",
|
|
1283
1586
|
"add.label": "Add a reference library",
|
|
1284
1587
|
"add.placeholder": "Enter a directory path (~ or relative)",
|
|
1285
1588
|
"add.submit": "Add",
|
|
1286
|
-
"add.
|
|
1287
|
-
"add.
|
|
1288
|
-
"add.
|
|
1589
|
+
"add.browse": "Browse",
|
|
1590
|
+
"add.note.label": "Description",
|
|
1591
|
+
"add.note.placeholder": "Description (optional; helps the agent judge relevance)",
|
|
1592
|
+
"add.hint": "Directories are read-only references; if no description is given, the README title is used",
|
|
1289
1593
|
"browser.title": "Select Directory",
|
|
1290
1594
|
"browser.home": "Home",
|
|
1291
1595
|
"browser.open": "Select this folder",
|
|
@@ -1344,10 +1648,11 @@ window.__ModuleLoader__.load({
|
|
|
1344
1648
|
}), "ref-lib: dictionaries");
|
|
1345
1649
|
const injected = () => ({
|
|
1346
1650
|
load: async (sessionId) => parseLibsPayload(await api(`/list?session=${encodeURIComponent(sessionId)}`, void 0, "GET")),
|
|
1347
|
-
add: async (sessionId, path) => {
|
|
1651
|
+
add: async (sessionId, path, note) => {
|
|
1348
1652
|
await api("/add", {
|
|
1349
1653
|
session: sessionId,
|
|
1350
|
-
path
|
|
1654
|
+
path,
|
|
1655
|
+
...note === void 0 ? {} : { note }
|
|
1351
1656
|
});
|
|
1352
1657
|
},
|
|
1353
1658
|
remove: async (sessionId, id) => {
|
|
@@ -1356,6 +1661,13 @@ window.__ModuleLoader__.load({
|
|
|
1356
1661
|
id
|
|
1357
1662
|
});
|
|
1358
1663
|
},
|
|
1664
|
+
setNote: async (sessionId, id, note) => {
|
|
1665
|
+
await api("/note", {
|
|
1666
|
+
session: sessionId,
|
|
1667
|
+
id,
|
|
1668
|
+
note
|
|
1669
|
+
});
|
|
1670
|
+
},
|
|
1359
1671
|
pickDirectory: () => ctx.workspaces.pickDirectory(),
|
|
1360
1672
|
listDirectory: (path, signal) => ctx.workspaces.listDirectory(path, signal)
|
|
1361
1673
|
});
|