dsh-vault 1.9.2 → 1.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -7,7 +7,7 @@ window.__ModuleLoader__.load({
7
7
  let react = require("react");
8
8
  let react_jsx_runtime = require("react/jsx-runtime");
9
9
  //#region \0dsh-css:/Users/zhipeng/Desktop/work/dsh test/dsh-vault/src/client/VaultSection.module.css.mjs
10
- const css = ".t_j5va_section{flex-direction:column;gap:12px;padding:16px 0;display:flex}.t_j5va_intro{opacity:.75;margin:0;font-size:13px}.t_j5va_srOnly{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.t_j5va_toolbar{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.t_j5va_searchBox{flex:150px;min-width:150px;display:flex}.t_j5va_searchBox input{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;flex:1;padding:6px 10px;font-size:13px}.t_j5va_addButton,.t_j5va_saveButton{background:var(--color-accent,#4f8cff);color:#fff;cursor:pointer;border:1px solid #0000;border-radius:6px;padding:6px 12px;font-size:13px}.t_j5va_addButton:disabled,.t_j5va_saveButton:disabled,.t_j5va_rowActions button:disabled{opacity:.5;cursor:not-allowed}.t_j5va_list{flex-direction:column;gap:6px;margin:0;padding:0;list-style:none;display:flex}.t_j5va_row{border:1px solid var(--color-border,#333);border-radius:8px;justify-content:space-between;align-items:center;gap:12px;padding:8px 10px;display:flex}.t_j5va_rowMain{flex-direction:column;gap:2px;min-width:0;display:flex}.t_j5va_title{font-size:14px;font-weight:600}.t_j5va_identity{opacity:.7;text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.t_j5va_totp{font-family:var(--font-mono,monospace);color:var(--color-accent,#4f8cff);font-size:13px}.t_j5va_totpRing{vertical-align:-2px;margin-right:4px;display:inline-block}.t_j5va_rowActions{flex-shrink:0;align-items:center;gap:6px;display:flex}.t_j5va_rowActions button{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:4px 8px;font-size:12px}.t_j5va_deleteButton{color:#e5484d}.t_j5va_copied{color:#30a46c;font-size:12px}.t_j5va_empty,.t_j5va_status,.t_j5va_error{opacity:.8;font-size:13px}.t_j5va_lockedBanner{color:#8a5a00;background:#fff4e5;border:1px solid #e0a83a;border-radius:6px;margin:0 0 10px;padding:8px 12px;font-size:13px}.t_j5va_modeReadonly,.t_j5va_modeAsk,.t_j5va_modeAuto{border-radius:999px;width:fit-content;margin:0;padding:4px 10px;font-size:12px;display:inline-block}.t_j5va_modeReadonly{color:#e5484d;border:1px solid #e5484d80}.t_j5va_modeAsk{color:#f5a524;border:1px solid #f5a52480}.t_j5va_modeAuto{color:#30a46c;border:1px solid #30a46c80}.t_j5va_policyBar{flex-direction:column;align-items:flex-start;gap:6px;display:flex}.t_j5va_policyField{align-items:center;gap:8px;font-size:13px;display:flex}.t_j5va_policyField select{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;padding:4px 8px;font-size:13px}.t_j5va_emptyBox{flex-direction:column;gap:4px;display:flex}.t_j5va_emptyHint{opacity:.65;margin:0;font-size:12px}.t_j5va_error{color:#e5484d}.t_j5va_editor{border:1px solid var(--color-border,#444);border-radius:8px;padding:12px}.t_j5va_editorBody{grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px 12px;display:grid}.t_j5va_checkField{align-items:center;gap:8px;font-size:13px;display:inline-flex}.t_j5va_field{flex-direction:column;gap:4px;font-size:12px;display:flex}.t_j5va_field input,.t_j5va_field select{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;padding:5px 8px;font-size:13px}.t_j5va_editorActions{justify-content:flex-end;gap:8px;margin-top:12px;display:flex}.t_j5va_editorActions button{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:6px 12px;font-size:13px}.t_j5va_reportBox{border:1px solid #f5a52466;border-radius:8px;flex-direction:column;gap:2px;padding:8px 10px;font-size:12px;display:flex}.t_j5va_reportTitle{margin:0;font-weight:600}.t_j5va_reportLine{opacity:.8;margin:0}.t_j5va_reportSub{color:var(--dsh-color-text-2,#666);margin:2px 0 0 10px;font-size:12px}.t_j5va_trashButton{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;align-self:flex-start;padding:4px 8px;font-size:12px}.t_j5va_secretField{gap:4px;display:flex}.t_j5va_secretField input{flex:1;min-width:0}.t_j5va_revealButton{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:0 8px;font-size:12px}.t_j5va_kindFilter{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;padding:6px 8px;font-size:13px}.t_j5va_highBadge{color:#e5484d;vertical-align:middle;background:#e5484d26;border-radius:4px;margin-left:6px;padding:1px 6px;font-size:10px;font-weight:600}.t_j5va_pinStar{color:#f5a524;cursor:pointer;background:0 0;border:none;margin-right:4px;padding:0 2px;font-size:13px;line-height:1}.t_j5va_pinOff{color:#80808073}.t_j5va_pinOn{color:#f5a524}.t_j5va_clearButton{color:inherit;cursor:pointer;opacity:.6;background:0 0;border:none;padding:0 8px;font-size:16px}.t_j5va_field textarea{border:1px solid var(--color-border,#444);color:inherit;resize:vertical;background:0 0;border-radius:6px;padding:5px 8px;font-family:inherit;font-size:13px}.t_j5va_row{transition:background .12s}.t_j5va_row:hover{background:var(--color-hover,#80808014)}.t_j5va_healthBar{flex-wrap:wrap;gap:6px;margin:0 0 10px;display:flex}.t_j5va_badge{border:1px solid var(--dsh-color-border,#ddd);background:var(--dsh-color-surface-2,#f7f7f8);color:var(--dsh-color-text-2,#555);border-radius:999px;padding:4px 10px;font-size:12px;line-height:1}.t_j5va_backupButton{border:1px solid var(--dsh-color-border,#ccc);background:var(--dsh-color-surface-2,#f7f7f8);cursor:pointer;border-radius:999px;align-self:flex-start;padding:4px 10px;font-size:12px;line-height:1}.t_j5va_badgeOk{color:#2e9e5b;border-color:#2e9e5b}.t_j5va_badgeWarn{color:#b57f1a;border-color:#c98a1b}.t_j5va_rowDue{border-left:3px solid #c98a1b}.t_j5va_rowExpired{border-left:3px solid #cf3d3d}.t_j5va_dueBadge{border-radius:999px;margin-left:6px;padding:3px 8px;font-size:11px;font-weight:600;line-height:1}.t_j5va_badgeDanger{color:#c03a3a;border-color:#cf3d3d}.t_j5va_footer{opacity:.6;margin:0;font-size:12px}.t_j5va_kindIcon{margin-right:4px;font-size:12px}.t_j5va_dangerButton{color:#e5484d;cursor:pointer;background:0 0;border:1px solid #e5484d80;border-radius:6px;align-self:flex-start;padding:4px 8px;font-size:12px}.t_j5va_rowMain{cursor:pointer}.t_j5va_detailBox{background:var(--color-hover,#8080800f);border-radius:6px;flex-wrap:wrap;grid-column:1/-1;gap:4px 12px;padding:6px 8px;font-size:12px;display:flex}.t_j5va_detailItem{opacity:.85}.t_j5va_sortButton{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:6px 10px;font-size:13px}.t_j5va_dupGroup{justify-content:space-between;align-items:center;gap:8px;margin:4px 0;display:flex}.t_j5va_dupNames{text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.t_j5va_dupMerge{border:1px solid var(--dsh-color-border,#ccc);cursor:pointer;border-radius:6px;flex-shrink:0;padding:2px 8px;font-size:12px}.t_j5va_auditRow{align-items:center;gap:8px;margin:4px 0;display:flex}.t_j5va_auditIssues{color:var(--dsh-color-text-2,#666);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:12px;overflow:hidden}.t_j5va_retryButton{border:1px solid var(--dsh-color-border,#ccc);cursor:pointer;border-radius:6px;margin-left:6px;padding:2px 8px;font-size:12px}.t_j5va_scoreRing{vertical-align:-2px;margin-right:4px;display:inline-block}.t_j5va_genOpts{border:1px solid var(--dsh-color-border,#ddd);border-radius:8px;flex-direction:column;gap:6px;padding:8px 10px;display:flex}.t_j5va_genOptRow{justify-content:space-between;align-items:center;gap:8px;font-size:13px;display:flex}.t_j5va_genOptRow input[type=number]{width:64px}.t_j5va_pwMeter{align-items:center;gap:8px;font-size:12px;display:flex}.t_j5va_pwBar{border-radius:999px;height:6px;transition:width .2s}.t_j5va_pwWeak{background:#cf3d3d}.t_j5va_pwFair{background:#c98a1b}.t_j5va_pwStrong{background:#2e9e5b}.t_j5va_pwLabel{color:var(--dsh-color-text-2,#666)}.t_j5va_resultCount{color:var(--dsh-color-text-2,#666);flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 6px;font-size:12px;display:flex}.t_j5va_kindChip{border:1px solid var(--dsh-color-border,#ddd);border-radius:999px;padding:2px 8px;font-size:11px}.t_j5va_uriCode{overflow-wrap:anywhere;opacity:.85;font-size:10px}.t_j5va_genHist{flex-wrap:wrap;gap:4px;font-size:12px;display:flex}.t_j5va_genHist span{align-self:center}.t_j5va_lockedTag{color:#c98a1b;font-size:12px;font-weight:600}.t_j5va_tabs{flex-wrap:wrap;gap:6px;margin:0 0 12px;display:flex}.t_j5va_tab{border:1px solid var(--dsh-color-border,#ccc);color:inherit;cursor:pointer;background:0 0;border-radius:999px;padding:5px 14px;font-size:13px}.t_j5va_tabActive{background:var(--dsh-color-primary,#4a6cf7);color:#fff;border-color:#0000}.t_j5va_tabPane{margin-top:2px}";
10
+ const css = ".t_j5va_section{flex-direction:column;gap:12px;padding:16px 0;display:flex}.t_j5va_intro{opacity:.75;margin:0;font-size:13px}.t_j5va_srOnly{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.t_j5va_toolbar{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.t_j5va_healthSummary{flex-wrap:wrap;align-items:center;gap:4px;display:inline-flex}.t_j5va_selectActive{border-color:var(--dsh-color-primary,#2e9e5b);color:var(--dsh-color-primary,#2e9e5b)}.t_j5va_bulkBar{background:var(--dsh-color-surface-2,#80808014);border-radius:6px;flex-wrap:wrap;align-items:center;gap:10px;margin:6px 0;padding:6px 10px;display:flex}.t_j5va_bulkItem{align-items:center;gap:6px;font-size:13px;display:inline-flex}.t_j5va_bulkCount{opacity:.8;font-size:13px}.t_j5va_rowCheck{flex-shrink:0;align-self:center;margin:0 8px 0 0}.t_j5va_rowSelected{outline:1px solid var(--dsh-color-primary,#2e9e5b);border-radius:4px}.t_j5va_searchBox{flex:150px;min-width:150px;display:flex}.t_j5va_searchBox input{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;flex:1;padding:6px 10px;font-size:13px}.t_j5va_addButton,.t_j5va_saveButton{background:var(--color-accent,#4f8cff);color:#fff;cursor:pointer;border:1px solid #0000;border-radius:6px;padding:6px 12px;font-size:13px}.t_j5va_addButton:disabled,.t_j5va_saveButton:disabled,.t_j5va_rowActions button:disabled{opacity:.5;cursor:not-allowed}.t_j5va_list{flex-direction:column;gap:6px;margin:0;padding:0;list-style:none;display:flex}.t_j5va_row{border:1px solid var(--color-border,#333);border-radius:8px;justify-content:space-between;align-items:center;gap:12px;padding:8px 10px;display:flex}.t_j5va_rowMain{flex-direction:column;gap:2px;min-width:0;display:flex}.t_j5va_title{font-size:14px;font-weight:600}.t_j5va_identity{opacity:.7;text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.t_j5va_totp{font-family:var(--font-mono,monospace);color:var(--color-accent,#4f8cff);font-size:13px}.t_j5va_totpRing{vertical-align:-2px;margin-right:4px;display:inline-block}.t_j5va_rowActions{flex-shrink:0;align-items:center;gap:6px;display:flex}.t_j5va_rowActions button{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:4px 8px;font-size:12px}.t_j5va_deleteButton{color:#e5484d}.t_j5va_copied{color:#30a46c;font-size:12px}.t_j5va_empty,.t_j5va_status,.t_j5va_error{opacity:.8;font-size:13px}.t_j5va_lockedBanner{color:#8a5a00;background:#fff4e5;border:1px solid #e0a83a;border-radius:6px;margin:0 0 10px;padding:8px 12px;font-size:13px}.t_j5va_modeReadonly,.t_j5va_modeAsk,.t_j5va_modeAuto{border-radius:999px;width:fit-content;margin:0;padding:4px 10px;font-size:12px;display:inline-block}.t_j5va_modeReadonly{color:#e5484d;border:1px solid #e5484d80}.t_j5va_modeAsk{color:#f5a524;border:1px solid #f5a52480}.t_j5va_modeAuto{color:#30a46c;border:1px solid #30a46c80}.t_j5va_policyBar{flex-direction:column;align-items:flex-start;gap:6px;display:flex}.t_j5va_policyField{align-items:center;gap:8px;font-size:13px;display:flex}.t_j5va_policyField select{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;padding:4px 8px;font-size:13px}.t_j5va_emptyBox{flex-direction:column;gap:4px;display:flex}.t_j5va_emptyHint{opacity:.65;margin:0;font-size:12px}.t_j5va_error{color:#e5484d}.t_j5va_editor{border:1px solid var(--color-border,#444);border-radius:8px;padding:12px}.t_j5va_editorBody{grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px 12px;display:grid}.t_j5va_checkField{align-items:center;gap:8px;font-size:13px;display:inline-flex}.t_j5va_field{flex-direction:column;gap:4px;font-size:12px;display:flex}.t_j5va_field input,.t_j5va_field select{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;padding:5px 8px;font-size:13px}.t_j5va_editorActions{justify-content:flex-end;gap:8px;margin-top:12px;display:flex}.t_j5va_editorActions button{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:6px 12px;font-size:13px}.t_j5va_reportBox{border:1px solid #f5a52466;border-radius:8px;flex-direction:column;gap:2px;padding:8px 10px;font-size:12px;display:flex}.t_j5va_reportTitle{margin:0;font-weight:600}.t_j5va_reportLine{opacity:.8;margin:0}.t_j5va_histAdd{color:#2e9e5b}.t_j5va_histDanger{color:#cf3d3d}.t_j5va_histUpdate{color:#c98a1b}.t_j5va_histNeutral{opacity:.7}.t_j5va_reportSub{color:var(--dsh-color-text-2,#666);margin:2px 0 0 10px;font-size:12px}.t_j5va_trashButton{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;align-self:flex-start;padding:4px 8px;font-size:12px}.t_j5va_secretField{gap:4px;display:flex}.t_j5va_secretField input{flex:1;min-width:0}.t_j5va_revealButton{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:0 8px;font-size:12px}.t_j5va_kindFilter{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;padding:6px 8px;font-size:13px}.t_j5va_highBadge{color:#e5484d;vertical-align:middle;background:#e5484d26;border-radius:4px;margin-left:6px;padding:1px 6px;font-size:10px;font-weight:600}.t_j5va_pinStar{color:#f5a524;cursor:pointer;background:0 0;border:none;margin-right:4px;padding:0 2px;font-size:13px;line-height:1}.t_j5va_pinOff{color:#80808073}.t_j5va_pinOn{color:#f5a524}.t_j5va_clearButton{color:inherit;cursor:pointer;opacity:.6;background:0 0;border:none;padding:0 8px;font-size:16px}.t_j5va_field textarea{border:1px solid var(--color-border,#444);color:inherit;resize:vertical;background:0 0;border-radius:6px;padding:5px 8px;font-family:inherit;font-size:13px}.t_j5va_row{transition:background .12s}.t_j5va_row:hover{background:var(--color-hover,#80808014)}.t_j5va_healthBar{flex-wrap:wrap;gap:6px;margin:0 0 10px;display:flex}.t_j5va_badge{border:1px solid var(--dsh-color-border,#ddd);background:var(--dsh-color-surface-2,#f7f7f8);color:var(--dsh-color-text-2,#555);border-radius:999px;padding:4px 10px;font-size:12px;line-height:1}.t_j5va_backupButton{border:1px solid var(--dsh-color-border,#ccc);background:var(--dsh-color-surface-2,#f7f7f8);cursor:pointer;border-radius:999px;align-self:flex-start;padding:4px 10px;font-size:12px;line-height:1}.t_j5va_badgeOk{color:#2e9e5b;border-color:#2e9e5b}.t_j5va_badgeWarn{color:#b57f1a;border-color:#c98a1b}.t_j5va_rowDue{border-left:3px solid #c98a1b}.t_j5va_rowExpired{border-left:3px solid #cf3d3d}.t_j5va_dueBadge{border-radius:999px;margin-left:6px;padding:3px 8px;font-size:11px;font-weight:600;line-height:1}.t_j5va_badgeDanger{color:#c03a3a;border-color:#cf3d3d}.t_j5va_footer{opacity:.6;margin:0;font-size:12px}.t_j5va_kindIcon{margin-right:4px;font-size:12px}.t_j5va_dangerButton{color:#e5484d;cursor:pointer;background:0 0;border:1px solid #e5484d80;border-radius:6px;align-self:flex-start;padding:4px 8px;font-size:12px}.t_j5va_rowMain{cursor:pointer}.t_j5va_detailBox{background:var(--color-hover,#8080800f);border-radius:6px;flex-wrap:wrap;grid-column:1/-1;gap:4px 12px;padding:6px 8px;font-size:12px;display:flex}.t_j5va_detailItem{opacity:.85}.t_j5va_sortButton{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:6px 10px;font-size:13px}.t_j5va_dupGroup{justify-content:space-between;align-items:center;gap:8px;margin:4px 0;display:flex}.t_j5va_dupNames{text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.t_j5va_dupMerge{border:1px solid var(--dsh-color-border,#ccc);cursor:pointer;border-radius:6px;flex-shrink:0;padding:2px 8px;font-size:12px}.t_j5va_auditRow{align-items:center;gap:8px;margin:4px 0;display:flex}.t_j5va_auditIssues{color:var(--dsh-color-text-2,#666);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:12px;overflow:hidden}.t_j5va_retryButton{border:1px solid var(--dsh-color-border,#ccc);cursor:pointer;border-radius:6px;margin-left:6px;padding:2px 8px;font-size:12px}.t_j5va_scoreRing{vertical-align:-2px;margin-right:4px;display:inline-block}.t_j5va_genOpts{border:1px solid var(--dsh-color-border,#ddd);border-radius:8px;flex-direction:column;gap:6px;padding:8px 10px;display:flex}.t_j5va_genOptRow{justify-content:space-between;align-items:center;gap:8px;font-size:13px;display:flex}.t_j5va_genOptRow input[type=number]{width:64px}.t_j5va_pwMeter{align-items:center;gap:8px;font-size:12px;display:flex}.t_j5va_pwBar{border-radius:999px;height:6px;transition:width .2s}.t_j5va_pwWeak{background:#cf3d3d}.t_j5va_pwFair{background:#c98a1b}.t_j5va_pwStrong{background:#2e9e5b}.t_j5va_pwLabel{color:var(--dsh-color-text-2,#666)}.t_j5va_resultCount{color:var(--dsh-color-text-2,#666);flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 6px;font-size:12px;display:flex}.t_j5va_kindChip{border:1px solid var(--dsh-color-border,#ddd);border-radius:999px;padding:2px 8px;font-size:11px}.t_j5va_uriCode{overflow-wrap:anywhere;opacity:.85;font-size:10px}.t_j5va_genHist{flex-wrap:wrap;gap:4px;font-size:12px;display:flex}.t_j5va_genHist span{align-self:center}.t_j5va_lockedTag{color:#c98a1b;font-size:12px;font-weight:600}.t_j5va_tabs{flex-wrap:wrap;gap:6px;margin:0 0 12px;display:flex}.t_j5va_tab{border:1px solid var(--dsh-color-border,#ccc);color:inherit;cursor:pointer;background:0 0;border-radius:999px;padding:5px 14px;font-size:13px}.t_j5va_tabActive{background:var(--dsh-color-primary,#4a6cf7);color:#fff;border-color:#0000}.t_j5va_tabPane{margin-top:2px}";
11
11
  const tagId = "dsh-vault/VaultSection.module.css";
12
12
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
13
13
  const tag = document.createElement("style");
@@ -17,91 +17,102 @@ window.__ModuleLoader__.load({
17
17
  document.head.appendChild(tag);
18
18
  }
19
19
  var VaultSection_module_css_default = {
20
- "deleteButton": "t_j5va_deleteButton",
21
- "trashButton": "t_j5va_trashButton",
22
- "pwMeter": "t_j5va_pwMeter",
23
- "uriCode": "t_j5va_uriCode",
24
- "srOnly": "t_j5va_srOnly",
25
- "reportBox": "t_j5va_reportBox",
26
- "intro": "t_j5va_intro",
27
- "dueBadge": "t_j5va_dueBadge",
28
- "field": "t_j5va_field",
29
- "totp": "t_j5va_totp",
30
- "title": "t_j5va_title",
31
- "rowMain": "t_j5va_rowMain",
32
- "searchBox": "t_j5va_searchBox",
33
- "badgeOk": "t_j5va_badgeOk",
34
- "reportTitle": "t_j5va_reportTitle",
35
- "toolbar": "t_j5va_toolbar",
36
- "policyBar": "t_j5va_policyBar",
37
- "tab": "t_j5va_tab",
38
20
  "addButton": "t_j5va_addButton",
39
- "empty": "t_j5va_empty",
40
- "policyField": "t_j5va_policyField",
41
- "reportLine": "t_j5va_reportLine",
42
- "list": "t_j5va_list",
43
- "reportSub": "t_j5va_reportSub",
21
+ "identity": "t_j5va_identity",
22
+ "pinOff": "t_j5va_pinOff",
23
+ "badgeWarn": "t_j5va_badgeWarn",
44
24
  "retryButton": "t_j5va_retryButton",
45
- "modeAsk": "t_j5va_modeAsk",
46
25
  "editorBody": "t_j5va_editorBody",
47
- "kindFilter": "t_j5va_kindFilter",
48
- "footer": "t_j5va_footer",
49
- "dupGroup": "t_j5va_dupGroup",
50
- "auditRow": "t_j5va_auditRow",
51
- "genOptRow": "t_j5va_genOptRow",
52
- "pwBar": "t_j5va_pwBar",
53
- "genOpts": "t_j5va_genOpts",
54
- "pinOff": "t_j5va_pinOff",
55
- "pwLabel": "t_j5va_pwLabel",
56
- "kindChip": "t_j5va_kindChip",
57
- "saveButton": "t_j5va_saveButton",
58
- "auditIssues": "t_j5va_auditIssues",
59
- "editor": "t_j5va_editor",
60
- "healthBar": "t_j5va_healthBar",
61
- "clearButton": "t_j5va_clearButton",
62
- "dupMerge": "t_j5va_dupMerge",
63
- "pwStrong": "t_j5va_pwStrong",
64
- "emptyHint": "t_j5va_emptyHint",
26
+ "dueBadge": "t_j5va_dueBadge",
27
+ "scoreRing": "t_j5va_scoreRing",
28
+ "genHist": "t_j5va_genHist",
29
+ "bulkCount": "t_j5va_bulkCount",
30
+ "empty": "t_j5va_empty",
31
+ "lockedBanner": "t_j5va_lockedBanner",
32
+ "modeAsk": "t_j5va_modeAsk",
33
+ "reportBox": "t_j5va_reportBox",
34
+ "row": "t_j5va_row",
65
35
  "secretField": "t_j5va_secretField",
66
- "highBadge": "t_j5va_highBadge",
67
- "rowActions": "t_j5va_rowActions",
68
- "rowExpired": "t_j5va_rowExpired",
69
36
  "modeAuto": "t_j5va_modeAuto",
70
- "revealButton": "t_j5va_revealButton",
71
- "resultCount": "t_j5va_resultCount",
72
- "error": "t_j5va_error",
73
- "genHist": "t_j5va_genHist",
74
- "tabActive": "t_j5va_tabActive",
75
- "rowDue": "t_j5va_rowDue",
76
- "kindIcon": "t_j5va_kindIcon",
77
- "editorActions": "t_j5va_editorActions",
37
+ "rowExpired": "t_j5va_rowExpired",
38
+ "footer": "t_j5va_footer",
78
39
  "pinOn": "t_j5va_pinOn",
79
- "lockedBanner": "t_j5va_lockedBanner",
80
- "copied": "t_j5va_copied",
81
- "section": "t_j5va_section",
82
- "detailBox": "t_j5va_detailBox",
83
- "detailItem": "t_j5va_detailItem",
84
- "badgeDanger": "t_j5va_badgeDanger",
85
- "scoreRing": "t_j5va_scoreRing",
86
- "backupButton": "t_j5va_backupButton",
87
- "pwFair": "t_j5va_pwFair",
88
- "tabs": "t_j5va_tabs",
89
40
  "emptyBox": "t_j5va_emptyBox",
41
+ "checkField": "t_j5va_checkField",
42
+ "histUpdate": "t_j5va_histUpdate",
43
+ "clearButton": "t_j5va_clearButton",
44
+ "healthBar": "t_j5va_healthBar",
90
45
  "dupNames": "t_j5va_dupNames",
91
- "modeReadonly": "t_j5va_modeReadonly",
46
+ "selectActive": "t_j5va_selectActive",
47
+ "searchBox": "t_j5va_searchBox",
48
+ "histAdd": "t_j5va_histAdd",
49
+ "deleteButton": "t_j5va_deleteButton",
50
+ "kindChip": "t_j5va_kindChip",
51
+ "tabPane": "t_j5va_tabPane",
52
+ "editorActions": "t_j5va_editorActions",
53
+ "list": "t_j5va_list",
54
+ "status": "t_j5va_status",
55
+ "bulkItem": "t_j5va_bulkItem",
56
+ "kindIcon": "t_j5va_kindIcon",
57
+ "dupGroup": "t_j5va_dupGroup",
58
+ "detailItem": "t_j5va_detailItem",
59
+ "kindFilter": "t_j5va_kindFilter",
60
+ "rowSelected": "t_j5va_rowSelected",
61
+ "pwStrong": "t_j5va_pwStrong",
62
+ "histDanger": "t_j5va_histDanger",
92
63
  "pinStar": "t_j5va_pinStar",
93
- "identity": "t_j5va_identity",
64
+ "policyBar": "t_j5va_policyBar",
94
65
  "lockedTag": "t_j5va_lockedTag",
95
- "checkField": "t_j5va_checkField",
96
- "tabPane": "t_j5va_tabPane",
97
66
  "dangerButton": "t_j5va_dangerButton",
98
- "sortButton": "t_j5va_sortButton",
99
- "row": "t_j5va_row",
67
+ "dupMerge": "t_j5va_dupMerge",
68
+ "resultCount": "t_j5va_resultCount",
69
+ "bulkBar": "t_j5va_bulkBar",
70
+ "revealButton": "t_j5va_revealButton",
100
71
  "totpRing": "t_j5va_totpRing",
72
+ "detailBox": "t_j5va_detailBox",
73
+ "reportTitle": "t_j5va_reportTitle",
74
+ "section": "t_j5va_section",
75
+ "histNeutral": "t_j5va_histNeutral",
76
+ "reportSub": "t_j5va_reportSub",
77
+ "rowDue": "t_j5va_rowDue",
78
+ "pwMeter": "t_j5va_pwMeter",
101
79
  "pwWeak": "t_j5va_pwWeak",
102
- "status": "t_j5va_status",
103
- "badge": "t_j5va_badge",
104
- "badgeWarn": "t_j5va_badgeWarn"
80
+ "rowMain": "t_j5va_rowMain",
81
+ "rowActions": "t_j5va_rowActions",
82
+ "badgeOk": "t_j5va_badgeOk",
83
+ "genOpts": "t_j5va_genOpts",
84
+ "tabActive": "t_j5va_tabActive",
85
+ "reportLine": "t_j5va_reportLine",
86
+ "highBadge": "t_j5va_highBadge",
87
+ "error": "t_j5va_error",
88
+ "intro": "t_j5va_intro",
89
+ "modeReadonly": "t_j5va_modeReadonly",
90
+ "badgeDanger": "t_j5va_badgeDanger",
91
+ "genOptRow": "t_j5va_genOptRow",
92
+ "uriCode": "t_j5va_uriCode",
93
+ "saveButton": "t_j5va_saveButton",
94
+ "toolbar": "t_j5va_toolbar",
95
+ "sortButton": "t_j5va_sortButton",
96
+ "srOnly": "t_j5va_srOnly",
97
+ "rowCheck": "t_j5va_rowCheck",
98
+ "trashButton": "t_j5va_trashButton",
99
+ "auditIssues": "t_j5va_auditIssues",
100
+ "copied": "t_j5va_copied",
101
+ "emptyHint": "t_j5va_emptyHint",
102
+ "editor": "t_j5va_editor",
103
+ "field": "t_j5va_field",
104
+ "tabs": "t_j5va_tabs",
105
+ "auditRow": "t_j5va_auditRow",
106
+ "policyField": "t_j5va_policyField",
107
+ "pwLabel": "t_j5va_pwLabel",
108
+ "title": "t_j5va_title",
109
+ "healthSummary": "t_j5va_healthSummary",
110
+ "totp": "t_j5va_totp",
111
+ "backupButton": "t_j5va_backupButton",
112
+ "tab": "t_j5va_tab",
113
+ "pwFair": "t_j5va_pwFair",
114
+ "pwBar": "t_j5va_pwBar",
115
+ "badge": "t_j5va_badge"
105
116
  };
106
117
  //#endregion
107
118
  //#region src/client/VaultSection.tsx
@@ -333,6 +344,8 @@ window.__ModuleLoader__.load({
333
344
  const [tagFilter, setTagFilter] = (0, react.useState)("");
334
345
  const [expandedId, setExpandedId] = (0, react.useState)(null);
335
346
  const [attachmentsMap, setAttachmentsMap] = (0, react.useState)({});
347
+ const [selectMode, setSelectMode] = (0, react.useState)(false);
348
+ const [selectedIds, setSelectedIds] = (0, react.useState)(/* @__PURE__ */ new Set());
336
349
  const [visibleCount, setVisibleCount] = (0, react.useState)(50);
337
350
  const [sortBy, setSortBy] = (0, react.useState)("alpha");
338
351
  const [activeTab, setActiveTab] = (0, react.useState)("entries");
@@ -425,7 +438,8 @@ window.__ModuleLoader__.load({
425
438
  const timer = window.setTimeout(() => {
426
439
  strength(pw).then((r) => setPwStrength({
427
440
  score: r.score,
428
- verdict: r.verdict
441
+ verdict: r.verdict,
442
+ bits: r.bits
429
443
  }), () => setPwStrength(null));
430
444
  }, 250);
431
445
  return () => window.clearTimeout(timer);
@@ -616,6 +630,7 @@ window.__ModuleLoader__.load({
616
630
  try {
617
631
  setMessage((await import1password(path.trim(), false)).note);
618
632
  refresh();
633
+ refreshHealth();
619
634
  } catch (err) {
620
635
  setMessage(errText(err));
621
636
  } finally {
@@ -650,6 +665,7 @@ window.__ModuleLoader__.load({
650
665
  try {
651
666
  setMessage((await importManagerCsv(path.trim(), false)).note);
652
667
  refresh();
668
+ refreshHealth();
653
669
  } catch (err) {
654
670
  setMessage(errText(err));
655
671
  } finally {
@@ -665,6 +681,7 @@ window.__ModuleLoader__.load({
665
681
  try {
666
682
  setMessage((await importEnpass(path.trim(), false)).note);
667
683
  refresh();
684
+ refreshHealth();
668
685
  } catch (err) {
669
686
  setMessage(errText(err));
670
687
  } finally {
@@ -680,6 +697,7 @@ window.__ModuleLoader__.load({
680
697
  try {
681
698
  setMessage((await importBitwarden(path.trim(), false)).note);
682
699
  refresh();
700
+ refreshHealth();
683
701
  } catch (err) {
684
702
  setMessage(errText(err));
685
703
  } finally {
@@ -697,6 +715,7 @@ window.__ModuleLoader__.load({
697
715
  try {
698
716
  setMessage((await importBitwardenEncrypted(path.trim(), password, false)).note);
699
717
  refresh();
718
+ refreshHealth();
700
719
  } catch (err) {
701
720
  setMessage(errText(err));
702
721
  } finally {
@@ -712,6 +731,7 @@ window.__ModuleLoader__.load({
712
731
  try {
713
732
  setMessage((await import1pif(path.trim(), false)).note);
714
733
  refresh();
734
+ refreshHealth();
715
735
  } catch (err) {
716
736
  setMessage(errText(err));
717
737
  } finally {
@@ -727,6 +747,7 @@ window.__ModuleLoader__.load({
727
747
  try {
728
748
  setMessage((await importKeePassXml(path.trim(), false)).note);
729
749
  refresh();
750
+ refreshHealth();
730
751
  } catch (err) {
731
752
  setMessage(errText(err));
732
753
  } finally {
@@ -743,6 +764,7 @@ window.__ModuleLoader__.load({
743
764
  try {
744
765
  setMessage((await importKdbx(path.trim(), password, "", false)).note);
745
766
  refresh();
767
+ refreshHealth();
746
768
  } catch (err) {
747
769
  setMessage(errText(err));
748
770
  } finally {
@@ -1269,6 +1291,32 @@ window.__ModuleLoader__.load({
1269
1291
  current = false;
1270
1292
  };
1271
1293
  }, [expandedId, attachments]);
1294
+ /** Recompute just the health report (weak/reused/no-2FA/rotation) after a
1295
+ * write so the toolbar badges stay current without a full reload. */
1296
+ const refreshHealth = (0, react.useCallback)(() => {
1297
+ health().then((hl) => {
1298
+ setReport((previous) => ({
1299
+ ...previous ?? {
1300
+ rotation: [],
1301
+ weak: [],
1302
+ reused: [],
1303
+ strength: null,
1304
+ no2fa: [],
1305
+ httpSites: [],
1306
+ score: 100,
1307
+ verdict: "good"
1308
+ },
1309
+ weak: hl?.weak ?? [],
1310
+ reused: hl?.reused ?? [],
1311
+ strength: hl?.strength ?? null,
1312
+ no2fa: hl?.no2fa ?? [],
1313
+ httpSites: hl?.httpSites ?? [],
1314
+ score: Number(hl?.score ?? 100),
1315
+ verdict: String(hl?.verdict ?? "good")
1316
+ }));
1317
+ }).catch(() => {});
1318
+ history().then((events) => setRecentEvents(events ?? [])).catch(() => {});
1319
+ }, [health, history]);
1272
1320
  (0, react.useEffect)(() => {
1273
1321
  let current = true;
1274
1322
  const load = () => {
@@ -1278,9 +1326,11 @@ window.__ModuleLoader__.load({
1278
1326
  rotation().catch(() => []),
1279
1327
  health().catch(() => null),
1280
1328
  recent().catch(() => []),
1329
+ history().catch(() => []),
1281
1330
  duplicates().catch(() => null)
1282
- ]).then(([st, bk, rot, hl, rc, dp]) => {
1331
+ ]).then(([st, bk, rot, hl, rc, hst, dp]) => {
1283
1332
  if (dp !== null && typeof dp === "object" && dp.groups !== void 0) setDupGroups(dp.groups);
1333
+ if (Array.isArray(hst)) setRecentEvents(hst);
1284
1334
  duplicateGroups().then(setDupList).catch(() => {});
1285
1335
  verifyAll().then(setAudit).catch(() => {});
1286
1336
  tags().then(setTagList).catch(() => {});
@@ -1444,6 +1494,7 @@ window.__ModuleLoader__.load({
1444
1494
  }
1445
1495
  setEditor({ status: "closed" });
1446
1496
  await refresh();
1497
+ refreshHealth();
1447
1498
  } catch (err) {
1448
1499
  setMessage(errText(err));
1449
1500
  } finally {
@@ -1453,10 +1504,40 @@ window.__ModuleLoader__.load({
1453
1504
  /** Delete an entry after confirmation. */
1454
1505
  async function removeEntry(id) {
1455
1506
  if (!window.confirm(t("deleteConfirm"))) return;
1507
+ const title = state.status === "ready" ? state.entries.find((e) => e.id === id)?.title ?? "" : "";
1456
1508
  setBusy(true);
1457
1509
  try {
1458
1510
  await remove(id);
1459
1511
  await refresh();
1512
+ refreshHealth();
1513
+ setMessage(title !== "" ? t("deletedWithTitle").replace("{name}", title) : t("deleted"));
1514
+ } catch (err) {
1515
+ setMessage(errText(err));
1516
+ } finally {
1517
+ setBusy(false);
1518
+ }
1519
+ }
1520
+ /** Toggle batch-select mode (Bitwarden-style bulk operations). */
1521
+ function toggleSelectMode() {
1522
+ setSelectMode((m) => {
1523
+ const next = !m;
1524
+ if (!next) setSelectedIds(/* @__PURE__ */ new Set());
1525
+ return next;
1526
+ });
1527
+ }
1528
+ /** Delete all selected entries after one confirmation (bulk operation). */
1529
+ async function removeSelected() {
1530
+ if (selectedIds.size === 0) return;
1531
+ if (!window.confirm(t("bulkDeleteConfirm").replace("{n}", String(selectedIds.size)))) return;
1532
+ const count = selectedIds.size;
1533
+ setBusy(true);
1534
+ try {
1535
+ await Promise.all([...selectedIds].map((id) => remove(id)));
1536
+ setSelectedIds(/* @__PURE__ */ new Set());
1537
+ setSelectMode(false);
1538
+ await refresh();
1539
+ refreshHealth();
1540
+ setMessage(t("bulkDeleted").replace("{n}", String(count)));
1460
1541
  } catch (err) {
1461
1542
  setMessage(errText(err));
1462
1543
  } finally {
@@ -1621,9 +1702,9 @@ window.__ModuleLoader__.load({
1621
1702
  children: t(TAB_KEYS[tab])
1622
1703
  }, tab))
1623
1704
  }),
1624
- activeTab === "entries" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1705
+ activeTab === "entries" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1625
1706
  className: VaultSection_module_css_default.tabPane,
1626
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1707
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1627
1708
  className: VaultSection_module_css_default.toolbar,
1628
1709
  children: [
1629
1710
  locked && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -1743,15 +1824,106 @@ window.__ModuleLoader__.load({
1743
1824
  })
1744
1825
  ]
1745
1826
  }),
1827
+ report !== null && (report.weak.length > 0 || report.reused.length > 0 || report.no2fa.length > 0 || report.httpSites.length > 0 || report.rotation.length > 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1828
+ className: VaultSection_module_css_default.healthSummary,
1829
+ title: t("healthSummaryHint"),
1830
+ children: [
1831
+ report.weak.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1832
+ className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeDanger}`,
1833
+ children: [
1834
+ t("reportWeak"),
1835
+ ": ",
1836
+ report.weak.length
1837
+ ]
1838
+ }),
1839
+ report.reused.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1840
+ className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeDanger}`,
1841
+ children: [
1842
+ t("reportReused"),
1843
+ ": ",
1844
+ report.reused.length
1845
+ ]
1846
+ }),
1847
+ report.no2fa.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1848
+ className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeWarn}`,
1849
+ children: [
1850
+ t("no2fa"),
1851
+ ": ",
1852
+ report.no2fa.length
1853
+ ]
1854
+ }),
1855
+ report.httpSites.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1856
+ className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeWarn}`,
1857
+ children: [
1858
+ t("httpSites"),
1859
+ ": ",
1860
+ report.httpSites.length
1861
+ ]
1862
+ }),
1863
+ report.rotation.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1864
+ className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeWarn}`,
1865
+ children: [
1866
+ t("reportRotation"),
1867
+ ": ",
1868
+ report.rotation.length
1869
+ ]
1870
+ })
1871
+ ]
1872
+ }),
1873
+ report !== null && report.weak.length === 0 && report.reused.length === 0 && report.no2fa.length === 0 && report.httpSites.length === 0 && report.rotation.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1874
+ className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeOk}`,
1875
+ title: t("healthSummaryHint"),
1876
+ children: [t("healthOk"), " ✓"]
1877
+ }),
1746
1878
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1747
1879
  type: "button",
1748
1880
  className: VaultSection_module_css_default.addButton,
1749
1881
  onClick: startCreate,
1750
1882
  disabled: busy || readonly || locked,
1751
1883
  children: ["+ ", t("add")]
1884
+ }),
1885
+ !readonly && !locked && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1886
+ type: "button",
1887
+ className: selectMode ? `${VaultSection_module_css_default.dupMerge} ${VaultSection_module_css_default.selectActive}` : VaultSection_module_css_default.dupMerge,
1888
+ onClick: toggleSelectMode,
1889
+ disabled: busy,
1890
+ children: selectMode ? t("bulkDone") : t("bulkSelect")
1752
1891
  })
1753
1892
  ]
1754
- })
1893
+ }), selectMode && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1894
+ className: VaultSection_module_css_default.bulkBar,
1895
+ children: [
1896
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1897
+ className: VaultSection_module_css_default.bulkItem,
1898
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1899
+ type: "checkbox",
1900
+ checked: state.status === "ready" && state.entries.length > 0 && [...state.entries].every((e) => selectedIds.has(e.id)),
1901
+ onChange: (event) => {
1902
+ if (state.status !== "ready") return;
1903
+ const ids = new Set(selectedIds);
1904
+ for (const e of state.entries) if (event.target.checked) ids.add(e.id);
1905
+ else ids.delete(e.id);
1906
+ setSelectedIds(ids);
1907
+ }
1908
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("bulkSelectAll") })]
1909
+ }),
1910
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1911
+ className: VaultSection_module_css_default.bulkCount,
1912
+ children: [
1913
+ t("bulkSelected"),
1914
+ ": ",
1915
+ selectedIds.size
1916
+ ]
1917
+ }),
1918
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1919
+ type: "button",
1920
+ className: VaultSection_module_css_default.dangerButton,
1921
+ onClick: () => void removeSelected(),
1922
+ disabled: busy || selectedIds.size === 0,
1923
+ children: t("bulkDelete")
1924
+ })
1925
+ ]
1926
+ })]
1755
1927
  }),
1756
1928
  message !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1757
1929
  role: "alert",
@@ -1776,11 +1948,61 @@ window.__ModuleLoader__.load({
1776
1948
  })
1777
1949
  ]
1778
1950
  }),
1779
- activeTab === "entries" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1951
+ activeTab === "entries" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1780
1952
  className: VaultSection_module_css_default.tabPane,
1781
- children: state.status === "ready" && state.entries.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1782
- className: VaultSection_module_css_default.emptyBox,
1953
+ children: [state.status === "ready" && state.entries.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1954
+ className: VaultSection_module_css_default.healthBar,
1783
1955
  children: [
1956
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1957
+ className: VaultSection_module_css_default.badge,
1958
+ children: [
1959
+ t("entryCount"),
1960
+ ": ",
1961
+ state.entries.length
1962
+ ]
1963
+ }),
1964
+ (() => {
1965
+ const byKind = /* @__PURE__ */ new Map();
1966
+ for (const e of state.entries) {
1967
+ const k = e.kind ?? "login";
1968
+ byKind.set(k, (byKind.get(k) ?? 0) + 1);
1969
+ }
1970
+ return [...byKind.entries()].map(([k, n]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1971
+ className: VaultSection_module_css_default.badge,
1972
+ children: [
1973
+ t(KIND_KEYS[k] ?? "kindCustom"),
1974
+ ": ",
1975
+ n
1976
+ ]
1977
+ }, k));
1978
+ })(),
1979
+ vaultStats !== null && typeof vaultStats.withTotp === "number" && vaultStats.withTotp > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1980
+ className: VaultSection_module_css_default.badge,
1981
+ children: ["TOTP: ", String(vaultStats.withTotp)]
1982
+ })
1983
+ ]
1984
+ }), state.status === "ready" && state.entries.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1985
+ className: VaultSection_module_css_default.emptyBox,
1986
+ children: query.trim().length > 0 || kindFilter !== "" || tagFilter !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1987
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1988
+ className: VaultSection_module_css_default.empty,
1989
+ children: t("noFiltered")
1990
+ }),
1991
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1992
+ className: VaultSection_module_css_default.emptyHint,
1993
+ children: t("noFilteredHint")
1994
+ }),
1995
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1996
+ type: "button",
1997
+ className: VaultSection_module_css_default.addButton,
1998
+ onClick: () => {
1999
+ setQuery("");
2000
+ setKindFilter("");
2001
+ setTagFilter("");
2002
+ },
2003
+ children: t("clearFilters")
2004
+ })
2005
+ ] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1784
2006
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1785
2007
  className: VaultSection_module_css_default.empty,
1786
2008
  children: t("empty")
@@ -1795,8 +2017,8 @@ window.__ModuleLoader__.load({
1795
2017
  onClick: startCreate,
1796
2018
  children: t("quickAdd")
1797
2019
  })
1798
- ]
1799
- })
2020
+ ] })
2021
+ })]
1800
2022
  }),
1801
2023
  activeTab === "security" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1802
2024
  className: VaultSection_module_css_default.tabPane,
@@ -1816,15 +2038,22 @@ window.__ModuleLoader__.load({
1816
2038
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1817
2039
  className: VaultSection_module_css_default.reportTitle,
1818
2040
  children: t("recentActivity")
1819
- }), recentEvents.map((ev, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1820
- className: VaultSection_module_css_default.reportLine,
1821
- children: [
1822
- String(ev.action ?? ""),
1823
- " · ",
1824
- String(ev.title ?? ev.id ?? ""),
1825
- relTime(ev.at) !== "" && ` · ${relTime(ev.at)}`
1826
- ]
1827
- }, i))]
2041
+ }), recentEvents.slice(0, 12).map((ev, i) => {
2042
+ const action = String(ev.action ?? "");
2043
+ const icon = action === "add" ? "➕" : action === "delete" ? "🗑️" : action === "restore" ? "♻️" : action === "purge" ? "🔥" : action === "update" ? "✏️" : "•";
2044
+ const cls = action === "delete" || action === "purge" ? VaultSection_module_css_default.histDanger : action === "add" ? VaultSection_module_css_default.histAdd : action === "update" ? VaultSection_module_css_default.histUpdate : VaultSection_module_css_default.histNeutral;
2045
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
2046
+ className: `${VaultSection_module_css_default.reportLine} ${cls}`,
2047
+ children: [
2048
+ icon,
2049
+ " ",
2050
+ action,
2051
+ " · ",
2052
+ String(ev.title ?? ev.id ?? ""),
2053
+ relTime(ev.at) !== "" && ` · ${relTime(ev.at)}`
2054
+ ]
2055
+ }, i);
2056
+ })]
1828
2057
  }),
1829
2058
  report !== null && (report.rotation.length > 0 || report.weak.length > 0 || report.reused.length > 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1830
2059
  className: VaultSection_module_css_default.reportBox,
@@ -2783,6 +3012,7 @@ window.__ModuleLoader__.load({
2783
3012
  restore(entry.id).then(() => {
2784
3013
  trash().then(setTrashEntries);
2785
3014
  refresh();
3015
+ refreshHealth();
2786
3016
  });
2787
3017
  },
2788
3018
  disabled: busy || readonly || locked,
@@ -2811,6 +3041,7 @@ window.__ModuleLoader__.load({
2811
3041
  undeleteAll().then(() => {
2812
3042
  trash().then(setTrashEntries);
2813
3043
  refresh();
3044
+ refreshHealth();
2814
3045
  setBusy(false);
2815
3046
  }, () => setBusy(false));
2816
3047
  },
@@ -2878,11 +3109,34 @@ window.__ModuleLoader__.load({
2878
3109
  const frac = remaining !== void 0 ? remaining / 30 : 0;
2879
3110
  const code = totpInfo?.code;
2880
3111
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
2881
- className: `${VaultSection_module_css_default.row}${dueMap[entry.id] !== void 0 ? ` ${dueMap[entry.id].due === "expired" ? VaultSection_module_css_default.rowExpired : VaultSection_module_css_default.rowDue}` : ""}`,
3112
+ className: `${VaultSection_module_css_default.row}${dueMap[entry.id] !== void 0 ? ` ${dueMap[entry.id].due === "expired" ? VaultSection_module_css_default.rowExpired : VaultSection_module_css_default.rowDue}` : ""}${selectedIds.has(entry.id) ? ` ${VaultSection_module_css_default.rowSelected}` : ""}`,
2882
3113
  children: [
3114
+ selectMode && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3115
+ type: "checkbox",
3116
+ className: VaultSection_module_css_default.rowCheck,
3117
+ checked: selectedIds.has(entry.id),
3118
+ onChange: (event) => {
3119
+ setSelectedIds((prev) => {
3120
+ const next = new Set(prev);
3121
+ if (event.target.checked) next.add(entry.id);
3122
+ else next.delete(entry.id);
3123
+ return next;
3124
+ });
3125
+ },
3126
+ "aria-label": entry.title
3127
+ }),
2883
3128
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2884
3129
  className: VaultSection_module_css_default.rowMain,
3130
+ role: "button",
3131
+ tabIndex: 0,
3132
+ "aria-expanded": expandedId === entry.id,
2885
3133
  onClick: () => setExpandedId(expandedId === entry.id ? null : entry.id),
3134
+ onKeyDown: (event) => {
3135
+ if (event.key === "Enter" || event.key === " ") {
3136
+ event.preventDefault();
3137
+ setExpandedId(expandedId === entry.id ? null : entry.id);
3138
+ }
3139
+ },
2886
3140
  children: [
2887
3141
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2888
3142
  className: VaultSection_module_css_default.title,
@@ -2905,6 +3159,7 @@ window.__ModuleLoader__.load({
2905
3159
  const next = !entry.favorite;
2906
3160
  setFavorite(entry.id, next).then(() => void refresh());
2907
3161
  },
3162
+ onKeyDown: (event) => event.stopPropagation(),
2908
3163
  children: "★"
2909
3164
  }),
2910
3165
  entry.title,
@@ -3043,7 +3298,8 @@ window.__ModuleLoader__.load({
3043
3298
  type: "button",
3044
3299
  onClick: () => void copyValue(entry.id, entry.username ?? entry.title),
3045
3300
  disabled: busy || readonly || locked,
3046
- children: t("copy")
3301
+ title: entry.username !== void 0 && entry.username !== "" ? t("copyUsernameHint") : t("copyTitleHint"),
3302
+ children: entry.username !== void 0 && entry.username !== "" ? t("copyUsername") : t("copy")
3047
3303
  }),
3048
3304
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3049
3305
  type: "button",
@@ -3525,7 +3781,11 @@ window.__ModuleLoader__.load({
3525
3781
  pwStrength.score,
3526
3782
  "/100 (",
3527
3783
  t(VERDICT_KEYS_SHORT[pwStrength.verdict] ?? "verdictGood"),
3528
- ")"
3784
+ ") · ",
3785
+ t("entropyLabel"),
3786
+ ": ",
3787
+ pwStrength.bits,
3788
+ " bits"
3529
3789
  ]
3530
3790
  })]
3531
3791
  }),
@@ -3681,6 +3941,8 @@ window.__ModuleLoader__.load({
3681
3941
  loading: "Loading…",
3682
3942
  empty: "No credentials yet. Add one to get started.",
3683
3943
  noFiltered: "No entries match the current filter.",
3944
+ noFilteredHint: "Try a different search or clear the filters.",
3945
+ clearFilters: "Clear filters",
3684
3946
  emptyHint: "Tip: you can ask the assistant to save an API key or token you share in chat — with auto-capture on it offers to store it for you. Bulk importing? Ask for vault_import_csv with a CSV file path.",
3685
3947
  emptyHintReadonly: "The vault is in readonly mode — credentials can be read but not added here. Switch accessMode to \"readwrite\" to enable writes.",
3686
3948
  modeLabel: "Access mode",
@@ -3700,6 +3962,7 @@ window.__ModuleLoader__.load({
3700
3962
  recentlyAdded: "Recently added",
3701
3963
  reportRotation: "expired / due for rotation",
3702
3964
  reportWeak: "weak passwords",
3965
+ healthSummaryHint: "Vault health: weak/reused/no-2FA/HTTP/rotation counts",
3703
3966
  reportReused: "credentials reused across entries",
3704
3967
  dupGroups: "duplicate groups",
3705
3968
  dupTitle: "Duplicate entries",
@@ -3750,6 +4013,7 @@ window.__ModuleLoader__.load({
3750
4013
  genOptSymbols: "Symbols",
3751
4014
  genOptExcludeAmbiguous: "No ambiguous chars",
3752
4015
  strengthLabel: "Strength",
4016
+ entropyLabel: "Entropy",
3753
4017
  tplApply: "Apply template",
3754
4018
  tplSave: "Save as template",
3755
4019
  tplNamePrompt: "Template name:",
@@ -3931,8 +4195,20 @@ window.__ModuleLoader__.load({
3931
4195
  savedUpdated: "Entry updated.",
3932
4196
  edit: "Edit",
3933
4197
  delete: "Delete",
3934
- deleteConfirm: "Delete this entry? This cannot be undone.",
4198
+ deleteConfirm: "Move this entry to the trash? You can restore it later.",
4199
+ deleted: "Entry moved to trash.",
4200
+ deletedWithTitle: "{name} moved to trash.",
3935
4201
  copy: "Copy",
4202
+ copyUsername: "Copy username",
4203
+ copyUsernameHint: "Copy the username",
4204
+ copyTitleHint: "Copy the title",
4205
+ bulkSelect: "Select",
4206
+ bulkDone: "Done",
4207
+ bulkSelectAll: "Select all",
4208
+ bulkSelected: "Selected",
4209
+ bulkDelete: "Delete selected",
4210
+ bulkDeleteConfirm: "Delete {n} selected entries? They move to the trash.",
4211
+ bulkDeleted: "Deleted {n} entries.",
3936
4212
  copyPassword: "Copy password",
3937
4213
  copyCode: "Copy code",
3938
4214
  copied: "Copied",
@@ -4007,6 +4283,8 @@ window.__ModuleLoader__.load({
4007
4283
  loading: "加载中…",
4008
4284
  empty: "还没有凭据,添加一条开始使用。",
4009
4285
  noFiltered: "当前过滤条件下没有匹配的条目。",
4286
+ noFilteredHint: "试试其他搜索词, 或清除过滤条件。",
4287
+ clearFilters: "清除过滤",
4010
4288
  emptyHint: "提示:你可以在对话中把 API Key 或 token 交给助手保存——开启自动捕获后,它会在你同意时帮你存入本库。批量导入?让助手调用 vault_import_csv 并给出 CSV 路径即可。",
4011
4289
  emptyHintReadonly: "当前为只读模式——只能读取凭据,不能在此添加。将 accessMode 改为 \"readwrite\" 即可启用写入。",
4012
4290
  modeLabel: "访问模式",
@@ -4026,6 +4304,7 @@ window.__ModuleLoader__.load({
4026
4304
  recentlyAdded: "最近添加",
4027
4305
  reportRotation: "已过期 / 待轮换",
4028
4306
  reportWeak: "弱密码",
4307
+ healthSummaryHint: "保险库健康: 弱密码/复用/缺2FA/HTTP站点/到期轮换计数",
4029
4308
  reportReused: "跨条目复用的凭据",
4030
4309
  dupGroups: "重复分组",
4031
4310
  dupTitle: "重复条目",
@@ -4076,6 +4355,7 @@ window.__ModuleLoader__.load({
4076
4355
  genOptSymbols: "符号",
4077
4356
  genOptExcludeAmbiguous: "排除易混淆字符",
4078
4357
  strengthLabel: "强度",
4358
+ entropyLabel: "熵值",
4079
4359
  tplApply: "套用模板",
4080
4360
  tplSave: "存为模板",
4081
4361
  tplNamePrompt: "模板名称:",
@@ -4257,8 +4537,20 @@ window.__ModuleLoader__.load({
4257
4537
  savedUpdated: "条目已更新。",
4258
4538
  edit: "编辑",
4259
4539
  delete: "删除",
4260
- deleteConfirm: "确定删除该条目?此操作不可撤销。",
4540
+ deleteConfirm: "将该条目移入回收站?之后可恢复。",
4541
+ deleted: "条目已移入回收站。",
4542
+ deletedWithTitle: "「{name}」已移入回收站。",
4261
4543
  copy: "复制",
4544
+ copyUsername: "复制用户名",
4545
+ copyUsernameHint: "复制用户名",
4546
+ copyTitleHint: "复制标题",
4547
+ bulkSelect: "批量选择",
4548
+ bulkDone: "完成",
4549
+ bulkSelectAll: "全选",
4550
+ bulkSelected: "已选择",
4551
+ bulkDelete: "删除所选",
4552
+ bulkDeleteConfirm: "删除所选 {n} 条条目?它们将移入回收站。",
4553
+ bulkDeleted: "已删除 {n} 条条目。",
4262
4554
  copyPassword: "复制密码",
4263
4555
  copyCode: "复制验证码",
4264
4556
  copied: "已复制",