dsh-vault 1.3.0 → 1.4.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js 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;margin-right:4px}.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;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}";
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;margin-right:4px}.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;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,85 +17,89 @@ window.__ModuleLoader__.load({
17
17
  document.head.appendChild(tag);
18
18
  }
19
19
  var VaultSection_module_css_default = {
20
- "rowActions": "t_j5va_rowActions",
21
- "error": "t_j5va_error",
22
- "list": "t_j5va_list",
23
- "policyBar": "t_j5va_policyBar",
24
- "identity": "t_j5va_identity",
25
- "pinStar": "t_j5va_pinStar",
26
- "addButton": "t_j5va_addButton",
27
- "genOptRow": "t_j5va_genOptRow",
28
- "backupButton": "t_j5va_backupButton",
29
- "lockedBanner": "t_j5va_lockedBanner",
30
- "editorBody": "t_j5va_editorBody",
31
- "empty": "t_j5va_empty",
20
+ "deleteButton": "t_j5va_deleteButton",
21
+ "sortButton": "t_j5va_sortButton",
22
+ "badge": "t_j5va_badge",
23
+ "rowDue": "t_j5va_rowDue",
24
+ "reportBox": "t_j5va_reportBox",
32
25
  "searchBox": "t_j5va_searchBox",
33
- "auditRow": "t_j5va_auditRow",
26
+ "tab": "t_j5va_tab",
27
+ "srOnly": "t_j5va_srOnly",
28
+ "editorActions": "t_j5va_editorActions",
29
+ "trashButton": "t_j5va_trashButton",
30
+ "list": "t_j5va_list",
31
+ "genHist": "t_j5va_genHist",
32
+ "auditIssues": "t_j5va_auditIssues",
33
+ "modeReadonly": "t_j5va_modeReadonly",
34
34
  "policyField": "t_j5va_policyField",
35
- "resultCount": "t_j5va_resultCount",
36
35
  "emptyHint": "t_j5va_emptyHint",
37
- "checkField": "t_j5va_checkField",
38
- "healthBar": "t_j5va_healthBar",
39
- "field": "t_j5va_field",
40
- "genOpts": "t_j5va_genOpts",
41
36
  "clearButton": "t_j5va_clearButton",
42
- "kindIcon": "t_j5va_kindIcon",
43
- "detailBox": "t_j5va_detailBox",
44
- "srOnly": "t_j5va_srOnly",
45
- "footer": "t_j5va_footer",
46
- "totp": "t_j5va_totp",
47
- "status": "t_j5va_status",
48
- "pwWeak": "t_j5va_pwWeak",
49
- "kindChip": "t_j5va_kindChip",
50
- "genHist": "t_j5va_genHist",
51
- "totpRing": "t_j5va_totpRing",
37
+ "badgeDanger": "t_j5va_badgeDanger",
38
+ "genOpts": "t_j5va_genOpts",
39
+ "pwBar": "t_j5va_pwBar",
40
+ "pwMeter": "t_j5va_pwMeter",
41
+ "tabPane": "t_j5va_tabPane",
42
+ "reportTitle": "t_j5va_reportTitle",
43
+ "backupButton": "t_j5va_backupButton",
44
+ "reportLine": "t_j5va_reportLine",
45
+ "section": "t_j5va_section",
52
46
  "rowExpired": "t_j5va_rowExpired",
53
- "row": "t_j5va_row",
47
+ "modeAuto": "t_j5va_modeAuto",
48
+ "dupGroup": "t_j5va_dupGroup",
49
+ "reportSub": "t_j5va_reportSub",
50
+ "pwWeak": "t_j5va_pwWeak",
51
+ "rowMain": "t_j5va_rowMain",
52
+ "healthBar": "t_j5va_healthBar",
54
53
  "dupMerge": "t_j5va_dupMerge",
54
+ "empty": "t_j5va_empty",
55
55
  "badgeOk": "t_j5va_badgeOk",
56
- "saveButton": "t_j5va_saveButton",
56
+ "footer": "t_j5va_footer",
57
57
  "kindFilter": "t_j5va_kindFilter",
58
- "badgeWarn": "t_j5va_badgeWarn",
59
- "intro": "t_j5va_intro",
60
- "detailItem": "t_j5va_detailItem",
61
- "pwStrong": "t_j5va_pwStrong",
58
+ "kindIcon": "t_j5va_kindIcon",
59
+ "saveButton": "t_j5va_saveButton",
60
+ "editorBody": "t_j5va_editorBody",
61
+ "detailBox": "t_j5va_detailBox",
62
+ "kindChip": "t_j5va_kindChip",
63
+ "status": "t_j5va_status",
64
+ "editor": "t_j5va_editor",
65
+ "rowActions": "t_j5va_rowActions",
62
66
  "emptyBox": "t_j5va_emptyBox",
63
- "scoreRing": "t_j5va_scoreRing",
64
- "rowMain": "t_j5va_rowMain",
65
- "modeAsk": "t_j5va_modeAsk",
66
- "editorActions": "t_j5va_editorActions",
67
- "pwBar": "t_j5va_pwBar",
68
- "pwMeter": "t_j5va_pwMeter",
69
- "pwLabel": "t_j5va_pwLabel",
70
- "modeAuto": "t_j5va_modeAuto",
71
- "lockedTag": "t_j5va_lockedTag",
72
- "dupNames": "t_j5va_dupNames",
73
- "copied": "t_j5va_copied",
74
- "reportTitle": "t_j5va_reportTitle",
75
- "highBadge": "t_j5va_highBadge",
76
- "badge": "t_j5va_badge",
77
- "section": "t_j5va_section",
78
- "auditIssues": "t_j5va_auditIssues",
67
+ "dangerButton": "t_j5va_dangerButton",
68
+ "tabs": "t_j5va_tabs",
79
69
  "pwFair": "t_j5va_pwFair",
80
- "deleteButton": "t_j5va_deleteButton",
81
- "editor": "t_j5va_editor",
82
- "reportBox": "t_j5va_reportBox",
83
- "revealButton": "t_j5va_revealButton",
84
- "badgeDanger": "t_j5va_badgeDanger",
85
- "rowDue": "t_j5va_rowDue",
70
+ "resultCount": "t_j5va_resultCount",
86
71
  "secretField": "t_j5va_secretField",
72
+ "tabActive": "t_j5va_tabActive",
73
+ "intro": "t_j5va_intro",
74
+ "copied": "t_j5va_copied",
75
+ "totpRing": "t_j5va_totpRing",
76
+ "modeAsk": "t_j5va_modeAsk",
77
+ "dupNames": "t_j5va_dupNames",
78
+ "checkField": "t_j5va_checkField",
87
79
  "uriCode": "t_j5va_uriCode",
88
- "reportLine": "t_j5va_reportLine",
89
- "trashButton": "t_j5va_trashButton",
90
- "toolbar": "t_j5va_toolbar",
91
- "modeReadonly": "t_j5va_modeReadonly",
92
- "sortButton": "t_j5va_sortButton",
93
- "dupGroup": "t_j5va_dupGroup",
94
- "reportSub": "t_j5va_reportSub",
95
- "title": "t_j5va_title",
80
+ "pinStar": "t_j5va_pinStar",
81
+ "row": "t_j5va_row",
82
+ "policyBar": "t_j5va_policyBar",
83
+ "lockedTag": "t_j5va_lockedTag",
84
+ "field": "t_j5va_field",
96
85
  "dueBadge": "t_j5va_dueBadge",
97
- "dangerButton": "t_j5va_dangerButton",
98
- "retryButton": "t_j5va_retryButton"
86
+ "genOptRow": "t_j5va_genOptRow",
87
+ "pwStrong": "t_j5va_pwStrong",
88
+ "title": "t_j5va_title",
89
+ "lockedBanner": "t_j5va_lockedBanner",
90
+ "auditRow": "t_j5va_auditRow",
91
+ "retryButton": "t_j5va_retryButton",
92
+ "addButton": "t_j5va_addButton",
93
+ "pwLabel": "t_j5va_pwLabel",
94
+ "identity": "t_j5va_identity",
95
+ "badgeWarn": "t_j5va_badgeWarn",
96
+ "toolbar": "t_j5va_toolbar",
97
+ "revealButton": "t_j5va_revealButton",
98
+ "scoreRing": "t_j5va_scoreRing",
99
+ "error": "t_j5va_error",
100
+ "highBadge": "t_j5va_highBadge",
101
+ "detailItem": "t_j5va_detailItem",
102
+ "totp": "t_j5va_totp"
99
103
  };
100
104
  //#endregion
101
105
  //#region src/client/VaultSection.tsx
@@ -195,6 +199,12 @@ window.__ModuleLoader__.load({
195
199
  fair: "verdictFair",
196
200
  poor: "verdictPoor"
197
201
  };
202
+ const TAB_KEYS = {
203
+ entries: "tabEntries",
204
+ security: "tabSecurity",
205
+ transfer: "tabTransfer",
206
+ organize: "tabOrganize"
207
+ };
198
208
  const VERDICT_KEYS_SHORT = {
199
209
  weak: "verdictPoor",
200
210
  fair: "verdictFair",
@@ -236,7 +246,7 @@ window.__ModuleLoader__.load({
236
246
  }
237
247
  /** Render the Vault settings section. */
238
248
  function VaultSection(props) {
239
- const { t, config, setAccessMode, setAutoCapture, list, search, get, add, update, remove, trash, rotation, health, duplicates, duplicateGroups, merge, history, stats, backupStatus, backup, recent, restore, undeleteAll, totp, status, switchVault, listVaults, touch, verifyAll, breachCheck, generatePassword, strength, generateUsername, templates, saveTemplate, lock, totpUri, tags, renameTag, generatorHistory, backups, importChrome, keychainImport, searchSystem } = props;
249
+ const { t, config, setAccessMode, setAutoCapture, list, search, get, add, update, remove, trash, rotation, health, duplicates, duplicateGroups, merge, history, stats, backupStatus, backup, recent, restore, undeleteAll, totp, status, switchVault, listVaults, touch, verifyAll, breachCheck, generatePassword, strength, generateUsername, templates, saveTemplate, lock, totpUri, tags, renameTag, generatorHistory, backups, importChrome, importFirefox, keychainImport, searchSystem } = props;
240
250
  const searchId = (0, react.useId)();
241
251
  const [query, setQuery] = (0, react.useState)("");
242
252
  const [state, setState] = (0, react.useState)({ status: "loading" });
@@ -272,6 +282,7 @@ window.__ModuleLoader__.load({
272
282
  const [expandedId, setExpandedId] = (0, react.useState)(null);
273
283
  const [visibleCount, setVisibleCount] = (0, react.useState)(50);
274
284
  const [sortBy, setSortBy] = (0, react.useState)("alpha");
285
+ const [activeTab, setActiveTab] = (0, react.useState)("entries");
275
286
  const [policy, setPolicy] = (0, react.useState)(null);
276
287
  const [showTrash, setShowTrash] = (0, react.useState)(false);
277
288
  const [trashEntries, setTrashEntries] = (0, react.useState)([]);
@@ -393,6 +404,21 @@ window.__ModuleLoader__.load({
393
404
  setBusy(false);
394
405
  }
395
406
  }
407
+ /** Import from Firefox (prompts for the primary password when one is set). */
408
+ async function runFirefoxImport() {
409
+ const mp = window.prompt(t("firefoxMasterPw"));
410
+ if (mp === null) return;
411
+ setBusy(true);
412
+ setMessage(null);
413
+ try {
414
+ setMessage((await importFirefox(mp, false)).note);
415
+ refresh();
416
+ } catch {
417
+ setMessage(t("error"));
418
+ } finally {
419
+ setBusy(false);
420
+ }
421
+ }
396
422
  /** Import from Chrome / Keychain with a confirmation about keychain prompts. */
397
423
  async function runSystemImport(source, preview) {
398
424
  if (source === "keychain" && !preview) {
@@ -885,110 +911,128 @@ window.__ModuleLoader__.load({
885
911
  className: VaultSection_module_css_default.lockedBanner,
886
912
  children: t("lockedBanner")
887
913
  }),
888
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
889
- className: VaultSection_module_css_default.toolbar,
914
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("nav", {
915
+ className: VaultSection_module_css_default.tabs,
916
+ "aria-label": t("sectionTabs"),
890
917
  children: [
891
- locked && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
892
- className: VaultSection_module_css_default.lockedTag,
893
- children: t("lockedShort")
894
- }),
895
- vaults.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
896
- className: VaultSection_module_css_default.kindFilter,
897
- value: vaults.find((v) => v.active)?.name ?? "",
898
- onChange: (event) => void switchVaultTo(event.target.value),
899
- "aria-label": t("vaultSelect"),
900
- disabled: locked,
901
- children: vaults.map((v) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
902
- value: v.name,
918
+ "entries",
919
+ "security",
920
+ "transfer",
921
+ "organize"
922
+ ].map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
923
+ type: "button",
924
+ className: `${VaultSection_module_css_default.tab}${activeTab === tab ? ` ${VaultSection_module_css_default.tabActive}` : ""}`,
925
+ onClick: () => setActiveTab(tab),
926
+ children: t(TAB_KEYS[tab])
927
+ }, tab))
928
+ }),
929
+ activeTab === "entries" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
930
+ className: VaultSection_module_css_default.tabPane,
931
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
932
+ className: VaultSection_module_css_default.toolbar,
933
+ children: [
934
+ locked && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
935
+ className: VaultSection_module_css_default.lockedTag,
936
+ children: t("lockedShort")
937
+ }),
938
+ vaults.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
939
+ className: VaultSection_module_css_default.kindFilter,
940
+ value: vaults.find((v) => v.active)?.name ?? "",
941
+ onChange: (event) => void switchVaultTo(event.target.value),
942
+ "aria-label": t("vaultSelect"),
943
+ disabled: locked,
944
+ children: vaults.map((v) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
945
+ value: v.name,
946
+ children: [
947
+ v.name,
948
+ v.active ? " *" : "",
949
+ v.entries !== void 0 ? ` (${v.entries})` : ""
950
+ ]
951
+ }, v.name))
952
+ }),
953
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
954
+ className: VaultSection_module_css_default.searchBox,
903
955
  children: [
904
- v.name,
905
- v.active ? " *" : "",
906
- v.entries !== void 0 ? ` (${v.entries})` : ""
956
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
957
+ className: VaultSection_module_css_default.srOnly,
958
+ children: t("searchPlaceholder")
959
+ }),
960
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
961
+ id: searchId,
962
+ type: "search",
963
+ placeholder: t("searchPlaceholder"),
964
+ value: query,
965
+ onChange: (event) => setQuery(event.target.value),
966
+ disabled: locked
967
+ }),
968
+ query.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
969
+ type: "button",
970
+ className: VaultSection_module_css_default.clearButton,
971
+ onClick: () => setQuery(""),
972
+ "aria-label": t("clearSearch"),
973
+ children: "×"
974
+ })
907
975
  ]
908
- }, v.name))
909
- }),
910
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
911
- className: VaultSection_module_css_default.searchBox,
912
- children: [
913
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
914
- className: VaultSection_module_css_default.srOnly,
915
- children: t("searchPlaceholder")
916
- }),
917
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
918
- id: searchId,
919
- type: "search",
920
- placeholder: t("searchPlaceholder"),
921
- value: query,
922
- onChange: (event) => setQuery(event.target.value),
923
- disabled: locked
924
- }),
925
- query.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
926
- type: "button",
927
- className: VaultSection_module_css_default.clearButton,
928
- onClick: () => setQuery(""),
929
- "aria-label": t("clearSearch"),
930
- children: "×"
931
- })
932
- ]
933
- }),
934
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
935
- className: VaultSection_module_css_default.kindFilter,
936
- value: kindFilter,
937
- onChange: (e) => setKindFilter(e.target.value),
938
- "aria-label": t("fieldKind"),
939
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
940
- value: "",
941
- children: t("allKinds")
942
- }), Object.entries(KIND_KEYS).map(([value, key]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
943
- value,
944
- children: t(key)
945
- }, value))]
946
- }),
947
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
948
- className: VaultSection_module_css_default.kindFilter,
949
- value: tagFilter,
950
- onChange: (e) => setTagFilter(e.target.value),
951
- "aria-label": t("fieldTags"),
952
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
953
- value: "",
954
- children: t("allTags")
955
- }), [...new Set(state.status === "ready" ? state.entries.flatMap((e) => e.tags ?? []) : [])].sort().map((tag) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
956
- value: tag,
957
- children: tag
958
- }, tag))]
959
- }),
960
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
961
- className: VaultSection_module_css_default.sortButton,
962
- value: sortBy,
963
- onChange: (event) => setSortBy(event.target.value),
964
- "aria-label": t("sortBy"),
965
- children: [
966
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
967
- value: "alpha",
968
- children: t("sortAlpha")
969
- }),
970
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
971
- value: "recent",
972
- children: t("sortRecent")
973
- }),
974
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
975
- value: "favorite",
976
- children: t("sortFavorite")
977
- }),
978
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
979
- value: "smart",
980
- children: t("sortSmart")
981
- })
982
- ]
983
- }),
984
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
985
- type: "button",
986
- className: VaultSection_module_css_default.addButton,
987
- onClick: startCreate,
988
- disabled: busy || readonly || locked,
989
- children: ["+ ", t("add")]
990
- })
991
- ]
976
+ }),
977
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
978
+ className: VaultSection_module_css_default.kindFilter,
979
+ value: kindFilter,
980
+ onChange: (e) => setKindFilter(e.target.value),
981
+ "aria-label": t("fieldKind"),
982
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
983
+ value: "",
984
+ children: t("allKinds")
985
+ }), Object.entries(KIND_KEYS).map(([value, key]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
986
+ value,
987
+ children: t(key)
988
+ }, value))]
989
+ }),
990
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
991
+ className: VaultSection_module_css_default.kindFilter,
992
+ value: tagFilter,
993
+ onChange: (e) => setTagFilter(e.target.value),
994
+ "aria-label": t("fieldTags"),
995
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
996
+ value: "",
997
+ children: t("allTags")
998
+ }), [...new Set(state.status === "ready" ? state.entries.flatMap((e) => e.tags ?? []) : [])].sort().map((tag) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
999
+ value: tag,
1000
+ children: tag
1001
+ }, tag))]
1002
+ }),
1003
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1004
+ className: VaultSection_module_css_default.sortButton,
1005
+ value: sortBy,
1006
+ onChange: (event) => setSortBy(event.target.value),
1007
+ "aria-label": t("sortBy"),
1008
+ children: [
1009
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1010
+ value: "alpha",
1011
+ children: t("sortAlpha")
1012
+ }),
1013
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1014
+ value: "recent",
1015
+ children: t("sortRecent")
1016
+ }),
1017
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1018
+ value: "favorite",
1019
+ children: t("sortFavorite")
1020
+ }),
1021
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1022
+ value: "smart",
1023
+ children: t("sortSmart")
1024
+ })
1025
+ ]
1026
+ }),
1027
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1028
+ type: "button",
1029
+ className: VaultSection_module_css_default.addButton,
1030
+ onClick: startCreate,
1031
+ disabled: busy || readonly || locked,
1032
+ children: ["+ ", t("add")]
1033
+ })
1034
+ ]
1035
+ })
992
1036
  }),
993
1037
  policy !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
994
1038
  className: VaultSection_module_css_default.policyBar,
@@ -1075,798 +1119,836 @@ window.__ModuleLoader__.load({
1075
1119
  })
1076
1120
  ]
1077
1121
  }),
1078
- state.status === "ready" && state.entries.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1079
- className: VaultSection_module_css_default.emptyBox,
1080
- children: [
1081
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1082
- className: VaultSection_module_css_default.empty,
1083
- children: t("empty")
1084
- }),
1085
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1086
- className: VaultSection_module_css_default.emptyHint,
1087
- children: readonly ? t("emptyHintReadonly") : t("emptyHint")
1088
- }),
1089
- !readonly && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1090
- type: "button",
1091
- className: VaultSection_module_css_default.addButton,
1092
- onClick: startCreate,
1093
- children: t("quickAdd")
1094
- })
1095
- ]
1096
- }),
1097
- recentEntries.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1098
- className: VaultSection_module_css_default.reportBox,
1099
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1100
- className: VaultSection_module_css_default.reportTitle,
1101
- children: t("recentlyAdded")
1102
- }), recentEntries.map((e, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1103
- className: VaultSection_module_css_default.reportLine,
1104
- children: [String(e.title ?? ""), relTime(e.updatedAt) !== "" && ` · ${relTime(e.updatedAt)}`]
1105
- }, i))]
1106
- }),
1107
- recentEvents.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1108
- className: VaultSection_module_css_default.reportBox,
1109
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1110
- className: VaultSection_module_css_default.reportTitle,
1111
- children: t("recentActivity")
1112
- }), recentEvents.map((ev, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1113
- className: VaultSection_module_css_default.reportLine,
1114
- children: [
1115
- String(ev.action ?? ""),
1116
- " · ",
1117
- String(ev.title ?? ev.id ?? ""),
1118
- relTime(ev.at) !== "" && ` · ${relTime(ev.at)}`
1119
- ]
1120
- }, i))]
1121
- }),
1122
- report !== null && (report.rotation.length > 0 || report.weak.length > 0 || report.reused.length > 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1123
- className: VaultSection_module_css_default.reportBox,
1124
- children: [
1125
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1126
- className: VaultSection_module_css_default.reportTitle,
1127
- children: t("reportTitle")
1128
- }),
1129
- report.rotation.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1130
- className: VaultSection_module_css_default.reportLine,
1131
- children: [
1132
- t("reportRotation"),
1133
- ": ",
1134
- report.rotation.length
1135
- ]
1136
- }), report.rotation.slice(0, 8).map((item, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1137
- className: VaultSection_module_css_default.reportSub,
1138
- children: [
1139
- "· ",
1140
- String(item.title ?? "?"),
1141
- item.due === "expired" ? ` (${t("dueExpired")})` : item.due === "soon" ? ` (${t("dueExpiring")} ${item.daysLeft ?? 0}d)` : ` (${t("dueNow")})`
1142
- ]
1143
- }, i))] }),
1144
- report.weak.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1145
- className: VaultSection_module_css_default.reportLine,
1146
- children: [
1147
- t("reportWeak"),
1148
- ": ",
1149
- report.weak.length
1150
- ]
1151
- }), report.weak.slice(0, 5).map((item, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1152
- className: VaultSection_module_css_default.reportSub,
1153
- children: ["· ", String(item.title ?? "?")]
1154
- }, i))] }),
1155
- report.reused.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1156
- className: VaultSection_module_css_default.reportLine,
1157
- children: [
1158
- t("reportReused"),
1159
- ": ",
1160
- report.reused.length
1161
- ]
1162
- }), report.reused.slice(0, 3).map((group, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1163
- className: VaultSection_module_css_default.reportSub,
1164
- children: ["· ", (group.entries ?? []).slice(0, 3).map((e) => String(e.title ?? "?")).join(" / ")]
1165
- }, i))] }),
1166
- report.no2fa.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1167
- className: VaultSection_module_css_default.reportLine,
1168
- children: [
1169
- t("no2fa"),
1170
- ": ",
1171
- report.no2fa.length
1172
- ]
1173
- }), report.no2fa.slice(0, 5).map((item, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1174
- className: VaultSection_module_css_default.reportSub,
1175
- children: ["· ", String(item.title ?? "?")]
1176
- }, i))] }),
1177
- report.httpSites.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1178
- className: VaultSection_module_css_default.reportLine,
1179
- children: [
1180
- t("httpSites"),
1181
- ": ",
1182
- report.httpSites.length
1183
- ]
1184
- }), report.httpSites.slice(0, 5).map((item, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1185
- className: VaultSection_module_css_default.reportSub,
1186
- children: ["· ", String(item.title ?? "?")]
1187
- }, i))] })
1188
- ]
1189
- }),
1190
- audit.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1191
- className: VaultSection_module_css_default.reportBox,
1192
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1193
- className: VaultSection_module_css_default.reportTitle,
1194
- children: [
1195
- t("auditTitle"),
1196
- " (",
1197
- audit.length,
1198
- ")"
1199
- ]
1200
- }), audit.slice(0, 6).map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1201
- className: VaultSection_module_css_default.auditRow,
1122
+ activeTab === "entries" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1123
+ className: VaultSection_module_css_default.tabPane,
1124
+ children: state.status === "ready" && state.entries.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1125
+ className: VaultSection_module_css_default.emptyBox,
1202
1126
  children: [
1203
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1204
- className: VaultSection_module_css_default.dupNames,
1205
- children: item.title
1127
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1128
+ className: VaultSection_module_css_default.empty,
1129
+ children: t("empty")
1206
1130
  }),
1207
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1208
- className: VaultSection_module_css_default.auditIssues,
1209
- children: item.issues.join("; ")
1131
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1132
+ className: VaultSection_module_css_default.emptyHint,
1133
+ children: readonly ? t("emptyHintReadonly") : t("emptyHint")
1210
1134
  }),
1211
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1135
+ !readonly && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1212
1136
  type: "button",
1213
- className: VaultSection_module_css_default.dupMerge,
1214
- onClick: () => void startEdit(item.id),
1215
- disabled: busy,
1216
- children: t("auditEdit")
1137
+ className: VaultSection_module_css_default.addButton,
1138
+ onClick: startCreate,
1139
+ children: t("quickAdd")
1217
1140
  })
1218
1141
  ]
1219
- }, item.id))]
1220
- }),
1221
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1222
- className: VaultSection_module_css_default.reportBox,
1223
- children: [
1224
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1225
- className: VaultSection_module_css_default.reportTitle,
1226
- children: t("systemSearch")
1227
- }),
1228
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1229
- className: VaultSection_module_css_default.dupGroup,
1230
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1231
- className: VaultSection_module_css_default.searchBox,
1232
- type: "search",
1233
- placeholder: t("sysSearchPlaceholder"),
1234
- value: sysQuery,
1235
- onChange: (event) => setSysQuery(event.target.value),
1236
- onKeyDown: (event) => {
1237
- if (event.key === "Enter") searchSystemStores();
1238
- }
1239
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1240
- type: "button",
1241
- className: VaultSection_module_css_default.dupMerge,
1242
- onClick: () => void searchSystemStores(),
1243
- disabled: busy,
1244
- children: t("sysSearchGo")
1245
- })]
1246
- }),
1247
- sysMatches.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: sysMatches.map((m, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1248
- className: VaultSection_module_css_default.reportSub,
1249
- children: [
1250
- "[",
1251
- m.source,
1252
- "] ",
1253
- m.name,
1254
- " · ",
1255
- m.username
1256
- ]
1257
- }, i)) })
1258
- ]
1142
+ })
1259
1143
  }),
1260
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1261
- className: VaultSection_module_css_default.reportBox,
1144
+ activeTab === "security" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1145
+ className: VaultSection_module_css_default.tabPane,
1262
1146
  children: [
1263
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1264
- className: VaultSection_module_css_default.reportTitle,
1265
- children: t("systemImport")
1147
+ recentEntries.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1148
+ className: VaultSection_module_css_default.reportBox,
1149
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1150
+ className: VaultSection_module_css_default.reportTitle,
1151
+ children: t("recentlyAdded")
1152
+ }), recentEntries.map((e, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1153
+ className: VaultSection_module_css_default.reportLine,
1154
+ children: [String(e.title ?? ""), relTime(e.updatedAt) !== "" && ` · ${relTime(e.updatedAt)}`]
1155
+ }, i))]
1266
1156
  }),
1267
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1268
- className: VaultSection_module_css_default.dupGroup,
1269
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1270
- className: VaultSection_module_css_default.dupNames,
1271
- children: t("importChromeDesc")
1272
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1273
- type: "button",
1274
- className: VaultSection_module_css_default.dupMerge,
1275
- onClick: () => void runSystemImport("chrome", false),
1276
- disabled: busy || readonly || locked,
1277
- children: t("importChrome")
1278
- })]
1157
+ recentEvents.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1158
+ className: VaultSection_module_css_default.reportBox,
1159
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1160
+ className: VaultSection_module_css_default.reportTitle,
1161
+ children: t("recentActivity")
1162
+ }), recentEvents.map((ev, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1163
+ className: VaultSection_module_css_default.reportLine,
1164
+ children: [
1165
+ String(ev.action ?? ""),
1166
+ " · ",
1167
+ String(ev.title ?? ev.id ?? ""),
1168
+ relTime(ev.at) !== "" && ` · ${relTime(ev.at)}`
1169
+ ]
1170
+ }, i))]
1279
1171
  }),
1280
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1281
- className: VaultSection_module_css_default.dupGroup,
1172
+ report !== null && (report.rotation.length > 0 || report.weak.length > 0 || report.reused.length > 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1173
+ className: VaultSection_module_css_default.reportBox,
1282
1174
  children: [
1283
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1284
- className: VaultSection_module_css_default.dupNames,
1285
- children: t("importKeychainDesc")
1175
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1176
+ className: VaultSection_module_css_default.reportTitle,
1177
+ children: t("reportTitle")
1286
1178
  }),
1287
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1288
- type: "button",
1289
- className: VaultSection_module_css_default.dupMerge,
1290
- onClick: () => void runSystemImport("keychain", true),
1291
- disabled: busy || readonly || locked,
1292
- children: t("keychainPreview")
1293
- }),
1294
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1295
- type: "button",
1296
- className: VaultSection_module_css_default.dupMerge,
1297
- onClick: () => void runSystemImport("keychain", false),
1298
- disabled: busy || readonly || locked,
1299
- children: t("importKeychain")
1300
- })
1179
+ report.rotation.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1180
+ className: VaultSection_module_css_default.reportLine,
1181
+ children: [
1182
+ t("reportRotation"),
1183
+ ": ",
1184
+ report.rotation.length
1185
+ ]
1186
+ }), report.rotation.slice(0, 8).map((item, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1187
+ className: VaultSection_module_css_default.reportSub,
1188
+ children: [
1189
+ ",
1190
+ String(item.title ?? "?"),
1191
+ item.due === "expired" ? ` (${t("dueExpired")})` : item.due === "soon" ? ` (${t("dueExpiring")} ${item.daysLeft ?? 0}d)` : ` (${t("dueNow")})`
1192
+ ]
1193
+ }, i))] }),
1194
+ report.weak.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1195
+ className: VaultSection_module_css_default.reportLine,
1196
+ children: [
1197
+ t("reportWeak"),
1198
+ ": ",
1199
+ report.weak.length
1200
+ ]
1201
+ }), report.weak.slice(0, 5).map((item, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1202
+ className: VaultSection_module_css_default.reportSub,
1203
+ children: ["· ", String(item.title ?? "?")]
1204
+ }, i))] }),
1205
+ report.reused.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1206
+ className: VaultSection_module_css_default.reportLine,
1207
+ children: [
1208
+ t("reportReused"),
1209
+ ": ",
1210
+ report.reused.length
1211
+ ]
1212
+ }), report.reused.slice(0, 3).map((group, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1213
+ className: VaultSection_module_css_default.reportSub,
1214
+ children: ["· ", (group.entries ?? []).slice(0, 3).map((e) => String(e.title ?? "?")).join(" / ")]
1215
+ }, i))] }),
1216
+ report.no2fa.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1217
+ className: VaultSection_module_css_default.reportLine,
1218
+ children: [
1219
+ t("no2fa"),
1220
+ ": ",
1221
+ report.no2fa.length
1222
+ ]
1223
+ }), report.no2fa.slice(0, 5).map((item, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1224
+ className: VaultSection_module_css_default.reportSub,
1225
+ children: ["· ", String(item.title ?? "?")]
1226
+ }, i))] }),
1227
+ report.httpSites.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1228
+ className: VaultSection_module_css_default.reportLine,
1229
+ children: [
1230
+ t("httpSites"),
1231
+ ": ",
1232
+ report.httpSites.length
1233
+ ]
1234
+ }), report.httpSites.slice(0, 5).map((item, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1235
+ className: VaultSection_module_css_default.reportSub,
1236
+ children: ["· ", String(item.title ?? "?")]
1237
+ }, i))] })
1301
1238
  ]
1239
+ }),
1240
+ audit.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1241
+ className: VaultSection_module_css_default.reportBox,
1242
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1243
+ className: VaultSection_module_css_default.reportTitle,
1244
+ children: [
1245
+ t("auditTitle"),
1246
+ " (",
1247
+ audit.length,
1248
+ ")"
1249
+ ]
1250
+ }), audit.slice(0, 6).map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1251
+ className: VaultSection_module_css_default.auditRow,
1252
+ children: [
1253
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1254
+ className: VaultSection_module_css_default.dupNames,
1255
+ children: item.title
1256
+ }),
1257
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1258
+ className: VaultSection_module_css_default.auditIssues,
1259
+ children: item.issues.join("; ")
1260
+ }),
1261
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1262
+ type: "button",
1263
+ className: VaultSection_module_css_default.dupMerge,
1264
+ onClick: () => void startEdit(item.id),
1265
+ disabled: busy,
1266
+ children: t("auditEdit")
1267
+ })
1268
+ ]
1269
+ }, item.id))]
1302
1270
  })
1303
1271
  ]
1304
1272
  }),
1305
- backupList.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1306
- className: VaultSection_module_css_default.reportBox,
1307
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1308
- className: VaultSection_module_css_default.reportTitle,
1309
- children: t("recentBackups")
1310
- }), backupList.map((b) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1311
- className: VaultSection_module_css_default.reportSub,
1312
- children: ["· ", new Date(b.at).toLocaleString()]
1313
- }, b.path))]
1314
- }),
1315
- tagList.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1316
- className: VaultSection_module_css_default.reportBox,
1317
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1318
- className: VaultSection_module_css_default.reportTitle,
1273
+ activeTab === "transfer" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1274
+ className: VaultSection_module_css_default.tabPane,
1275
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1276
+ className: VaultSection_module_css_default.reportBox,
1319
1277
  children: [
1320
- t("tagManage"),
1321
- " (",
1322
- tagList.length,
1323
- ")"
1278
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1279
+ className: VaultSection_module_css_default.reportTitle,
1280
+ children: t("systemSearch")
1281
+ }),
1282
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1283
+ className: VaultSection_module_css_default.dupGroup,
1284
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1285
+ className: VaultSection_module_css_default.searchBox,
1286
+ type: "search",
1287
+ placeholder: t("sysSearchPlaceholder"),
1288
+ value: sysQuery,
1289
+ onChange: (event) => setSysQuery(event.target.value),
1290
+ onKeyDown: (event) => {
1291
+ if (event.key === "Enter") searchSystemStores();
1292
+ }
1293
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1294
+ type: "button",
1295
+ className: VaultSection_module_css_default.dupMerge,
1296
+ onClick: () => void searchSystemStores(),
1297
+ disabled: busy,
1298
+ children: t("sysSearchGo")
1299
+ })]
1300
+ }),
1301
+ sysMatches.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: sysMatches.map((m, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1302
+ className: VaultSection_module_css_default.reportSub,
1303
+ children: [
1304
+ "[",
1305
+ m.source,
1306
+ "] ",
1307
+ m.name,
1308
+ " · ",
1309
+ m.username
1310
+ ]
1311
+ }, i)) })
1324
1312
  ]
1325
- }), tagList.slice(0, 8).map((tag) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1326
- className: VaultSection_module_css_default.dupGroup,
1327
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1328
- className: VaultSection_module_css_default.dupNames,
1329
- children: [
1330
- tag.name,
1331
- " (",
1332
- tag.count,
1333
- ")"
1334
- ]
1335
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1336
- type: "button",
1337
- className: VaultSection_module_css_default.dupMerge,
1338
- onClick: () => void renameTagAll(tag.name),
1339
- disabled: busy || readonly,
1340
- children: t("tagRename")
1341
- })]
1342
- }, tag.name))]
1343
- }),
1344
- dupList.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1345
- className: VaultSection_module_css_default.reportBox,
1346
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1347
- className: VaultSection_module_css_default.reportTitle,
1313
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1314
+ className: VaultSection_module_css_default.reportBox,
1348
1315
  children: [
1349
- t("dupTitle"),
1350
- " (",
1351
- dupList.length,
1352
- ")"
1353
- ]
1354
- }), dupList.slice(0, 5).map((group, gi) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1355
- className: VaultSection_module_css_default.dupGroup,
1356
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1357
- className: VaultSection_module_css_default.dupNames,
1358
- children: group.map((g) => g.title).join(" / ")
1359
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1360
- type: "button",
1361
- className: VaultSection_module_css_default.dupMerge,
1362
- onClick: () => void mergeEntries(group),
1363
- disabled: busy || readonly,
1364
- children: t("dupMerge")
1365
- })]
1366
- }, gi))]
1367
- }),
1368
- state.status === "ready" && filteredCount(state.entries, kindFilter, tagFilter) > visibleCount && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1369
- type: "button",
1370
- className: VaultSection_module_css_default.trashButton,
1371
- onClick: () => setVisibleCount((count) => count + 50),
1372
- children: [
1373
- t("loadMore"),
1374
- " (",
1375
- filteredCount(state.entries, kindFilter, tagFilter) - visibleCount,
1376
- ")"
1377
- ]
1378
- }),
1379
- state.status === "ready" && (state.entries.length > 0 || trashEntries.length > 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1380
- type: "button",
1381
- className: VaultSection_module_css_default.trashButton,
1382
- onClick: () => {
1383
- if (!showTrash) trash().then(setTrashEntries);
1384
- setShowTrash(!showTrash);
1385
- },
1386
- children: [showTrash ? t("hideTrash") : t("showTrash"), trashEntries.length > 0 ? ` (${trashEntries.length})` : ""]
1387
- }),
1388
- showTrash && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
1389
- className: VaultSection_module_css_default.list,
1390
- children: [trashEntries.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
1391
- className: VaultSection_module_css_default.row,
1392
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1393
- className: VaultSection_module_css_default.rowMain,
1394
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1395
- className: VaultSection_module_css_default.title,
1396
- children: entry.title
1397
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1398
- className: VaultSection_module_css_default.identity,
1399
- children: t("trashed")
1400
- })]
1401
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1402
- className: VaultSection_module_css_default.rowActions,
1403
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1404
- type: "button",
1405
- onClick: () => {
1406
- restore(entry.id).then(() => {
1407
- trash().then(setTrashEntries);
1408
- refresh();
1409
- });
1410
- },
1411
- disabled: busy || readonly,
1412
- children: t("restore")
1316
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1317
+ className: VaultSection_module_css_default.reportTitle,
1318
+ children: t("systemImport")
1319
+ }),
1320
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1321
+ className: VaultSection_module_css_default.dupGroup,
1322
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1323
+ className: VaultSection_module_css_default.dupNames,
1324
+ children: t("importChromeDesc")
1325
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1326
+ type: "button",
1327
+ className: VaultSection_module_css_default.dupMerge,
1328
+ onClick: () => void runSystemImport("chrome", false),
1329
+ disabled: busy || readonly || locked,
1330
+ children: t("importChrome")
1331
+ })]
1332
+ }),
1333
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1334
+ className: VaultSection_module_css_default.dupGroup,
1335
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1336
+ className: VaultSection_module_css_default.dupNames,
1337
+ children: t("importFirefoxDesc")
1338
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1339
+ type: "button",
1340
+ className: VaultSection_module_css_default.dupMerge,
1341
+ onClick: () => void runFirefoxImport(),
1342
+ disabled: busy || readonly || locked,
1343
+ children: t("importFirefox")
1344
+ })]
1345
+ }),
1346
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1347
+ className: VaultSection_module_css_default.dupGroup,
1348
+ children: [
1349
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1350
+ className: VaultSection_module_css_default.dupNames,
1351
+ children: t("importKeychainDesc")
1352
+ }),
1353
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1354
+ type: "button",
1355
+ className: VaultSection_module_css_default.dupMerge,
1356
+ onClick: () => void runSystemImport("keychain", true),
1357
+ disabled: busy || readonly || locked,
1358
+ children: t("keychainPreview")
1359
+ }),
1360
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1361
+ type: "button",
1362
+ className: VaultSection_module_css_default.dupMerge,
1363
+ onClick: () => void runSystemImport("keychain", false),
1364
+ disabled: busy || readonly || locked,
1365
+ children: t("importKeychain")
1366
+ })
1367
+ ]
1413
1368
  })
1414
- })]
1415
- }, entry.id)), trashEntries.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1416
- className: VaultSection_module_css_default.empty,
1417
- children: t("trashEmpty")
1369
+ ]
1418
1370
  })]
1419
1371
  }),
1420
- showTrash && trashEntries.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1421
- type: "button",
1422
- className: VaultSection_module_css_default.trashButton,
1423
- onClick: () => {
1424
- setBusy(true);
1425
- undeleteAll().then(() => {
1426
- trash().then(setTrashEntries);
1427
- refresh();
1428
- setBusy(false);
1429
- }, () => setBusy(false));
1430
- },
1431
- disabled: busy || readonly,
1432
- children: t("restoreAll")
1433
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1434
- type: "button",
1435
- className: VaultSection_module_css_default.dangerButton,
1436
- onClick: () => {
1437
- if (!window.confirm(t("clearTrashConfirm"))) return;
1438
- setBusy(true);
1439
- Promise.all(trashEntries.map((e) => remove(e.id))).then(() => {
1440
- trash().then(setTrashEntries);
1441
- refresh();
1442
- setBusy(false);
1443
- }, () => setBusy(false));
1444
- },
1445
- disabled: busy || readonly,
1446
- children: t("clearTrash")
1447
- })] }),
1448
- state.status === "ready" && state.entries.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1449
- className: VaultSection_module_css_default.resultCount,
1372
+ activeTab === "organize" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1373
+ className: VaultSection_module_css_default.tabPane,
1450
1374
  children: [
1451
- t("resultCount"),
1452
- ": ",
1453
- filteredCount(state.entries, kindFilter, tagFilter),
1454
- (() => {
1455
- const byKind = /* @__PURE__ */ new Map();
1456
- for (const e of state.entries) if ((kindFilter === "" || e.kind === kindFilter) && (tagFilter === "" || (e.tags ?? []).includes(tagFilter))) {
1457
- const k = e.kind ?? "login";
1458
- byKind.set(k, (byKind.get(k) ?? 0) + 1);
1459
- }
1460
- return [...byKind.entries()].map(([k, n]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1461
- className: VaultSection_module_css_default.kindChip,
1375
+ backupList.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1376
+ className: VaultSection_module_css_default.reportBox,
1377
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1378
+ className: VaultSection_module_css_default.reportTitle,
1379
+ children: t("recentBackups")
1380
+ }), backupList.map((b) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1381
+ className: VaultSection_module_css_default.reportSub,
1382
+ children: ["· ", new Date(b.at).toLocaleString()]
1383
+ }, b.path))]
1384
+ }),
1385
+ tagList.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1386
+ className: VaultSection_module_css_default.reportBox,
1387
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1388
+ className: VaultSection_module_css_default.reportTitle,
1389
+ children: [
1390
+ t("tagManage"),
1391
+ " (",
1392
+ tagList.length,
1393
+ ")"
1394
+ ]
1395
+ }), tagList.slice(0, 8).map((tag) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1396
+ className: VaultSection_module_css_default.dupGroup,
1397
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1398
+ className: VaultSection_module_css_default.dupNames,
1399
+ children: [
1400
+ tag.name,
1401
+ " (",
1402
+ tag.count,
1403
+ ")"
1404
+ ]
1405
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1406
+ type: "button",
1407
+ className: VaultSection_module_css_default.dupMerge,
1408
+ onClick: () => void renameTagAll(tag.name),
1409
+ disabled: busy || readonly,
1410
+ children: t("tagRename")
1411
+ })]
1412
+ }, tag.name))]
1413
+ }),
1414
+ dupList.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1415
+ className: VaultSection_module_css_default.reportBox,
1416
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1417
+ className: VaultSection_module_css_default.reportTitle,
1462
1418
  children: [
1463
- t(KIND_KEYS[k] ?? "kindCustom"),
1464
- " ",
1465
- n
1419
+ t("dupTitle"),
1420
+ " (",
1421
+ dupList.length,
1422
+ ")"
1466
1423
  ]
1467
- }, k));
1468
- })()
1424
+ }), dupList.slice(0, 5).map((group, gi) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1425
+ className: VaultSection_module_css_default.dupGroup,
1426
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1427
+ className: VaultSection_module_css_default.dupNames,
1428
+ children: group.map((g) => g.title).join(" / ")
1429
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1430
+ type: "button",
1431
+ className: VaultSection_module_css_default.dupMerge,
1432
+ onClick: () => void mergeEntries(group),
1433
+ disabled: busy || readonly,
1434
+ children: t("dupMerge")
1435
+ })]
1436
+ }, gi))]
1437
+ })
1469
1438
  ]
1470
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
1471
- className: VaultSection_module_css_default.list,
1472
- children: state.entries.filter((entry) => (kindFilter === "" || entry.kind === kindFilter) && (tagFilter === "" || (entry.tags ?? []).includes(tagFilter))).sort((a, b) => sortBy === "alpha" ? a.title.localeCompare(b.title) : sortBy === "recent" ? (b.updatedAt ?? 0) - (a.updatedAt ?? 0) : (a.favorite === true ? 0 : 1) - (b.favorite === true ? 0 : 1) || (b.updatedAt ?? 0) - (a.updatedAt ?? 0) || a.title.localeCompare(b.title)).slice(0, visibleCount).map((entry) => {
1473
- const totpInfo = totpMap[entry.id];
1474
- const remaining = totpInfo !== void 0 && totpInfo.until > 0 ? Math.max(0, Math.ceil((totpInfo.until - nowTick) / 1e3)) : void 0;
1475
- const frac = remaining !== void 0 ? remaining / 30 : 0;
1476
- const code = totpInfo?.code;
1477
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
1478
- 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}` : ""}`,
1439
+ }),
1440
+ activeTab === "entries" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1441
+ className: VaultSection_module_css_default.tabPane,
1442
+ children: [
1443
+ state.status === "ready" && filteredCount(state.entries, kindFilter, tagFilter) > visibleCount && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1444
+ type: "button",
1445
+ className: VaultSection_module_css_default.trashButton,
1446
+ onClick: () => setVisibleCount((count) => count + 50),
1479
1447
  children: [
1480
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1448
+ t("loadMore"),
1449
+ " (",
1450
+ filteredCount(state.entries, kindFilter, tagFilter) - visibleCount,
1451
+ ")"
1452
+ ]
1453
+ }),
1454
+ state.status === "ready" && (state.entries.length > 0 || trashEntries.length > 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1455
+ type: "button",
1456
+ className: VaultSection_module_css_default.trashButton,
1457
+ onClick: () => {
1458
+ if (!showTrash) trash().then(setTrashEntries);
1459
+ setShowTrash(!showTrash);
1460
+ },
1461
+ children: [showTrash ? t("hideTrash") : t("showTrash"), trashEntries.length > 0 ? ` (${trashEntries.length})` : ""]
1462
+ }),
1463
+ showTrash && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
1464
+ className: VaultSection_module_css_default.list,
1465
+ children: [trashEntries.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
1466
+ className: VaultSection_module_css_default.row,
1467
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1481
1468
  className: VaultSection_module_css_default.rowMain,
1482
- onClick: () => setExpandedId(expandedId === entry.id ? null : entry.id),
1469
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1470
+ className: VaultSection_module_css_default.title,
1471
+ children: entry.title
1472
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1473
+ className: VaultSection_module_css_default.identity,
1474
+ children: t("trashed")
1475
+ })]
1476
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1477
+ className: VaultSection_module_css_default.rowActions,
1478
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1479
+ type: "button",
1480
+ onClick: () => {
1481
+ restore(entry.id).then(() => {
1482
+ trash().then(setTrashEntries);
1483
+ refresh();
1484
+ });
1485
+ },
1486
+ disabled: busy || readonly,
1487
+ children: t("restore")
1488
+ })
1489
+ })]
1490
+ }, entry.id)), trashEntries.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1491
+ className: VaultSection_module_css_default.empty,
1492
+ children: t("trashEmpty")
1493
+ })]
1494
+ }),
1495
+ showTrash && trashEntries.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1496
+ type: "button",
1497
+ className: VaultSection_module_css_default.trashButton,
1498
+ onClick: () => {
1499
+ setBusy(true);
1500
+ undeleteAll().then(() => {
1501
+ trash().then(setTrashEntries);
1502
+ refresh();
1503
+ setBusy(false);
1504
+ }, () => setBusy(false));
1505
+ },
1506
+ disabled: busy || readonly,
1507
+ children: t("restoreAll")
1508
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1509
+ type: "button",
1510
+ className: VaultSection_module_css_default.dangerButton,
1511
+ onClick: () => {
1512
+ if (!window.confirm(t("clearTrashConfirm"))) return;
1513
+ setBusy(true);
1514
+ Promise.all(trashEntries.map((e) => remove(e.id))).then(() => {
1515
+ trash().then(setTrashEntries);
1516
+ refresh();
1517
+ setBusy(false);
1518
+ }, () => setBusy(false));
1519
+ },
1520
+ disabled: busy || readonly,
1521
+ children: t("clearTrash")
1522
+ })] }),
1523
+ state.status === "ready" && state.entries.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1524
+ className: VaultSection_module_css_default.resultCount,
1525
+ children: [
1526
+ t("resultCount"),
1527
+ ": ",
1528
+ filteredCount(state.entries, kindFilter, tagFilter),
1529
+ (() => {
1530
+ const byKind = /* @__PURE__ */ new Map();
1531
+ for (const e of state.entries) if ((kindFilter === "" || e.kind === kindFilter) && (tagFilter === "" || (e.tags ?? []).includes(tagFilter))) {
1532
+ const k = e.kind ?? "login";
1533
+ byKind.set(k, (byKind.get(k) ?? 0) + 1);
1534
+ }
1535
+ return [...byKind.entries()].map(([k, n]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1536
+ className: VaultSection_module_css_default.kindChip,
1537
+ children: [
1538
+ t(KIND_KEYS[k] ?? "kindCustom"),
1539
+ " ",
1540
+ n
1541
+ ]
1542
+ }, k));
1543
+ })()
1544
+ ]
1545
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
1546
+ className: VaultSection_module_css_default.list,
1547
+ children: state.entries.filter((entry) => (kindFilter === "" || entry.kind === kindFilter) && (tagFilter === "" || (entry.tags ?? []).includes(tagFilter))).sort((a, b) => sortBy === "alpha" ? a.title.localeCompare(b.title) : sortBy === "recent" ? (b.updatedAt ?? 0) - (a.updatedAt ?? 0) : (a.favorite === true ? 0 : 1) - (b.favorite === true ? 0 : 1) || (b.updatedAt ?? 0) - (a.updatedAt ?? 0) || a.title.localeCompare(b.title)).slice(0, visibleCount).map((entry) => {
1548
+ const totpInfo = totpMap[entry.id];
1549
+ const remaining = totpInfo !== void 0 && totpInfo.until > 0 ? Math.max(0, Math.ceil((totpInfo.until - nowTick) / 1e3)) : void 0;
1550
+ const frac = remaining !== void 0 ? remaining / 30 : 0;
1551
+ const code = totpInfo?.code;
1552
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
1553
+ 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}` : ""}`,
1483
1554
  children: [
1484
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1485
- className: VaultSection_module_css_default.title,
1486
- style: entry.color !== void 0 && entry.color !== "" ? {
1487
- borderLeft: `3px solid ${entry.color}`,
1488
- paddingLeft: 6
1489
- } : void 0,
1555
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1556
+ className: VaultSection_module_css_default.rowMain,
1557
+ onClick: () => setExpandedId(expandedId === entry.id ? null : entry.id),
1490
1558
  children: [
1491
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1492
- className: VaultSection_module_css_default.kindIcon,
1493
- children: entry.icon ?? kindIcon(entry.kind)
1559
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1560
+ className: VaultSection_module_css_default.title,
1561
+ style: entry.color !== void 0 && entry.color !== "" ? {
1562
+ borderLeft: `3px solid ${entry.color}`,
1563
+ paddingLeft: 6
1564
+ } : void 0,
1565
+ children: [
1566
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1567
+ className: VaultSection_module_css_default.kindIcon,
1568
+ children: entry.icon ?? kindIcon(entry.kind)
1569
+ }),
1570
+ entry.favorite && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1571
+ className: VaultSection_module_css_default.pinStar,
1572
+ title: t("pinned"),
1573
+ children: "★"
1574
+ }),
1575
+ entry.title,
1576
+ entry.sensitivity === "high" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1577
+ className: VaultSection_module_css_default.highBadge,
1578
+ children: t("highSensitivity")
1579
+ }),
1580
+ dueMap[entry.id] !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1581
+ className: `${VaultSection_module_css_default.dueBadge} ${dueMap[entry.id].due === "expired" ? VaultSection_module_css_default.badgeDanger : VaultSection_module_css_default.badgeWarn}`,
1582
+ children: dueMap[entry.id].due === "expired" ? t("dueExpired") : dueMap[entry.id].due === "soon" ? `${t("dueExpiring")} ${dueMap[entry.id].daysLeft}d` : t("dueNow")
1583
+ }),
1584
+ passwordAge(entry) !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1585
+ className: VaultSection_module_css_default.dueBadge,
1586
+ title: t("ageHint"),
1587
+ children: passwordAge(entry)
1588
+ })
1589
+ ]
1494
1590
  }),
1495
- entry.favorite && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1496
- className: VaultSection_module_css_default.pinStar,
1497
- title: t("pinned"),
1498
- children: "★"
1499
- }),
1500
- entry.title,
1501
- entry.sensitivity === "high" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1502
- className: VaultSection_module_css_default.highBadge,
1503
- children: t("highSensitivity")
1591
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1592
+ className: VaultSection_module_css_default.identity,
1593
+ children: identityLine(entry)
1504
1594
  }),
1505
- dueMap[entry.id] !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1506
- className: `${VaultSection_module_css_default.dueBadge} ${dueMap[entry.id].due === "expired" ? VaultSection_module_css_default.badgeDanger : VaultSection_module_css_default.badgeWarn}`,
1507
- children: dueMap[entry.id].due === "expired" ? t("dueExpired") : dueMap[entry.id].due === "soon" ? `${t("dueExpiring")} ${dueMap[entry.id].daysLeft}d` : t("dueNow")
1595
+ uriMap[entry.id] !== void 0 && uriMap[entry.id] !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1596
+ className: VaultSection_module_css_default.totp,
1597
+ title: t("totpUriHint"),
1598
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
1599
+ className: VaultSection_module_css_default.uriCode,
1600
+ children: uriMap[entry.id]
1601
+ })
1508
1602
  }),
1509
- passwordAge(entry) !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1510
- className: VaultSection_module_css_default.dueBadge,
1511
- title: t("ageHint"),
1512
- children: passwordAge(entry)
1603
+ code !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1604
+ className: VaultSection_module_css_default.totp,
1605
+ children: [
1606
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1607
+ className: VaultSection_module_css_default.totpRing,
1608
+ width: "16",
1609
+ height: "16",
1610
+ viewBox: "0 0 16 16",
1611
+ "aria-hidden": "true",
1612
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
1613
+ cx: "8",
1614
+ cy: "8",
1615
+ r: "6.5",
1616
+ fill: "none",
1617
+ stroke: "var(--dsh-color-border, #ddd)",
1618
+ strokeWidth: "2"
1619
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
1620
+ cx: "8",
1621
+ cy: "8",
1622
+ r: "6.5",
1623
+ fill: "none",
1624
+ stroke: remaining !== void 0 && remaining <= 5 ? "#cf3d3d" : "#2e9e5b",
1625
+ strokeWidth: "2",
1626
+ strokeLinecap: "round",
1627
+ strokeDasharray: `${(frac * 2 * Math.PI * 6.5).toFixed(1)} ${(2 * Math.PI * 6.5).toFixed(1)}`,
1628
+ transform: "rotate(-90 8 8)"
1629
+ })]
1630
+ }),
1631
+ code,
1632
+ remaining !== void 0 ? ` (${remaining}s)` : ""
1633
+ ]
1513
1634
  })
1514
1635
  ]
1515
1636
  }),
1516
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1517
- className: VaultSection_module_css_default.identity,
1518
- children: identityLine(entry)
1519
- }),
1520
- uriMap[entry.id] !== void 0 && uriMap[entry.id] !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1521
- className: VaultSection_module_css_default.totp,
1522
- title: t("totpUriHint"),
1523
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
1524
- className: VaultSection_module_css_default.uriCode,
1525
- children: uriMap[entry.id]
1526
- })
1637
+ expandedId === entry.id && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1638
+ className: VaultSection_module_css_default.detailBox,
1639
+ children: Object.entries(entry).filter(([k]) => ![
1640
+ "id",
1641
+ "title",
1642
+ "favorite"
1643
+ ].includes(k) && entry[k] !== void 0).map(([k, v]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1644
+ className: VaultSection_module_css_default.detailItem,
1645
+ children: [
1646
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: k }),
1647
+ ": ",
1648
+ formatDetail(k, v),
1649
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1650
+ type: "button",
1651
+ className: VaultSection_module_css_default.revealButton,
1652
+ title: t("copyFieldHint"),
1653
+ onClick: () => void copyValue(entry.id, Array.isArray(v) ? v.join(", ") : String(v)),
1654
+ children: "⧉"
1655
+ })
1656
+ ]
1657
+ }, k))
1527
1658
  }),
1528
- code !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1529
- className: VaultSection_module_css_default.totp,
1659
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1660
+ className: VaultSection_module_css_default.rowActions,
1530
1661
  children: [
1531
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1532
- className: VaultSection_module_css_default.totpRing,
1533
- width: "16",
1534
- height: "16",
1535
- viewBox: "0 0 16 16",
1536
- "aria-hidden": "true",
1537
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
1538
- cx: "8",
1539
- cy: "8",
1540
- r: "6.5",
1541
- fill: "none",
1542
- stroke: "var(--dsh-color-border, #ddd)",
1543
- strokeWidth: "2"
1544
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
1545
- cx: "8",
1546
- cy: "8",
1547
- r: "6.5",
1548
- fill: "none",
1549
- stroke: remaining !== void 0 && remaining <= 5 ? "#cf3d3d" : "#2e9e5b",
1550
- strokeWidth: "2",
1551
- strokeLinecap: "round",
1552
- strokeDasharray: `${(frac * 2 * Math.PI * 6.5).toFixed(1)} ${(2 * Math.PI * 6.5).toFixed(1)}`,
1553
- transform: "rotate(-90 8 8)"
1554
- })]
1662
+ copiedId === entry.id && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1663
+ className: VaultSection_module_css_default.copied,
1664
+ children: [
1665
+ t("copied"),
1666
+ " · ",
1667
+ t("clearsIn30s")
1668
+ ]
1669
+ }),
1670
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1671
+ type: "button",
1672
+ onClick: () => void copyValue(entry.id, entry.username ?? entry.title),
1673
+ disabled: busy,
1674
+ children: t("copy")
1675
+ }),
1676
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1677
+ type: "button",
1678
+ onClick: () => {
1679
+ setBusy(true);
1680
+ get(entry.id).then((r) => {
1681
+ if (r.found && r.entry?.password) copyValue(entry.id, r.entry.password);
1682
+ setBusy(false);
1683
+ }, () => setBusy(false));
1684
+ },
1685
+ disabled: busy || readonly,
1686
+ children: t("copyPassword")
1555
1687
  }),
1556
- code,
1557
- remaining !== void 0 ? ` (${remaining}s)` : ""
1688
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1689
+ type: "button",
1690
+ onClick: () => void showTotp(entry.id),
1691
+ disabled: busy,
1692
+ children: t("totp")
1693
+ }),
1694
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1695
+ type: "button",
1696
+ onClick: () => void showTotpUri(entry.id),
1697
+ disabled: busy,
1698
+ title: t("totpUriHint"),
1699
+ children: t("totpUri")
1700
+ }),
1701
+ code !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1702
+ type: "button",
1703
+ onClick: () => void copyValue(entry.id, code),
1704
+ disabled: busy,
1705
+ children: t("copyCode")
1706
+ }),
1707
+ entry.url !== void 0 && entry.url !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1708
+ type: "button",
1709
+ onClick: () => window.open(entry.url, "_blank", "noopener"),
1710
+ title: t("openUrlHint"),
1711
+ children: t("openUrl")
1712
+ }),
1713
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1714
+ type: "button",
1715
+ onClick: () => void touch(entry.id).then(() => void refresh()),
1716
+ disabled: busy || readonly,
1717
+ title: t("touchHint"),
1718
+ children: t("touch")
1719
+ }),
1720
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1721
+ type: "button",
1722
+ onClick: () => void startEdit(entry.id),
1723
+ disabled: busy || readonly,
1724
+ children: t("edit")
1725
+ }),
1726
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1727
+ type: "button",
1728
+ className: VaultSection_module_css_default.deleteButton,
1729
+ onClick: () => void removeEntry(entry.id),
1730
+ disabled: busy || readonly,
1731
+ children: t("delete")
1732
+ })
1558
1733
  ]
1559
1734
  })
1560
1735
  ]
1736
+ }, entry.id);
1737
+ })
1738
+ })] })
1739
+ ]
1740
+ }),
1741
+ activeTab === "security" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1742
+ className: VaultSection_module_css_default.tabPane,
1743
+ children: [
1744
+ state.status === "ready" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1745
+ className: VaultSection_module_css_default.healthBar,
1746
+ children: [
1747
+ vaultStats !== null && typeof vaultStats.total === "number" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1748
+ className: VaultSection_module_css_default.badge,
1749
+ children: [
1750
+ t("entryCount"),
1751
+ ": ",
1752
+ String(vaultStats.total)
1753
+ ]
1561
1754
  }),
1562
- expandedId === entry.id && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1563
- className: VaultSection_module_css_default.detailBox,
1564
- children: Object.entries(entry).filter(([k]) => ![
1565
- "id",
1566
- "title",
1567
- "favorite"
1568
- ].includes(k) && entry[k] !== void 0).map(([k, v]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1569
- className: VaultSection_module_css_default.detailItem,
1570
- children: [
1571
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: k }),
1572
- ": ",
1573
- formatDetail(k, v),
1574
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1575
- type: "button",
1576
- className: VaultSection_module_css_default.revealButton,
1577
- title: t("copyFieldHint"),
1578
- onClick: () => void copyValue(entry.id, Array.isArray(v) ? v.join(", ") : String(v)),
1579
- children: "⧉"
1580
- })
1581
- ]
1582
- }, k))
1755
+ vaultStats !== null && typeof vaultStats.withTotp === "number" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1756
+ className: VaultSection_module_css_default.badge,
1757
+ children: ["TOTP: ", String(vaultStats.withTotp)]
1583
1758
  }),
1584
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1585
- className: VaultSection_module_css_default.rowActions,
1759
+ vaultStats !== null && typeof vaultStats.highSensitivity === "number" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1760
+ className: VaultSection_module_css_default.badge,
1586
1761
  children: [
1587
- copiedId === entry.id && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1588
- className: VaultSection_module_css_default.copied,
1589
- children: [
1590
- t("copied"),
1591
- " · ",
1592
- t("clearsIn30s")
1593
- ]
1594
- }),
1595
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1596
- type: "button",
1597
- onClick: () => void copyValue(entry.id, entry.username ?? entry.title),
1598
- disabled: busy,
1599
- children: t("copy")
1600
- }),
1601
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1602
- type: "button",
1603
- onClick: () => {
1604
- setBusy(true);
1605
- get(entry.id).then((r) => {
1606
- if (r.found && r.entry?.password) copyValue(entry.id, r.entry.password);
1607
- setBusy(false);
1608
- }, () => setBusy(false));
1609
- },
1610
- disabled: busy || readonly,
1611
- children: t("copyPassword")
1612
- }),
1613
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1614
- type: "button",
1615
- onClick: () => void showTotp(entry.id),
1616
- disabled: busy,
1617
- children: t("totp")
1618
- }),
1619
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1620
- type: "button",
1621
- onClick: () => void showTotpUri(entry.id),
1622
- disabled: busy,
1623
- title: t("totpUriHint"),
1624
- children: t("totpUri")
1625
- }),
1626
- code !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1627
- type: "button",
1628
- onClick: () => void copyValue(entry.id, code),
1629
- disabled: busy,
1630
- children: t("copyCode")
1631
- }),
1632
- entry.url !== void 0 && entry.url !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1633
- type: "button",
1634
- onClick: () => window.open(entry.url, "_blank", "noopener"),
1635
- title: t("openUrlHint"),
1636
- children: t("openUrl")
1637
- }),
1638
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1639
- type: "button",
1640
- onClick: () => void touch(entry.id).then(() => void refresh()),
1641
- disabled: busy || readonly,
1642
- title: t("touchHint"),
1643
- children: t("touch")
1644
- }),
1645
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1646
- type: "button",
1647
- onClick: () => void startEdit(entry.id),
1648
- disabled: busy || readonly,
1649
- children: t("edit")
1762
+ t("highSensitivity"),
1763
+ ": ",
1764
+ String(vaultStats.highSensitivity)
1765
+ ]
1766
+ }),
1767
+ report !== null && report.strength !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1768
+ className: `${VaultSection_module_css_default.badge} ${report.strength.weak > 0 ? VaultSection_module_css_default.badgeDanger : VaultSection_module_css_default.badgeOk}`,
1769
+ children: [
1770
+ t("healthStrength"),
1771
+ ": ",
1772
+ report.strength.weak,
1773
+ "W/",
1774
+ report.strength.fair,
1775
+ "F/",
1776
+ report.strength.strong,
1777
+ "S"
1778
+ ]
1779
+ }),
1780
+ report !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1781
+ className: `${VaultSection_module_css_default.badge} ${report.verdict === "good" ? VaultSection_module_css_default.badgeOk : report.verdict === "fair" ? VaultSection_module_css_default.badgeWarn : VaultSection_module_css_default.badgeDanger}`,
1782
+ children: [
1783
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1784
+ className: VaultSection_module_css_default.scoreRing,
1785
+ width: "14",
1786
+ height: "14",
1787
+ viewBox: "0 0 16 16",
1788
+ "aria-hidden": "true",
1789
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
1790
+ cx: "8",
1791
+ cy: "8",
1792
+ r: "6.5",
1793
+ fill: "none",
1794
+ stroke: "var(--dsh-color-border, #ddd)",
1795
+ strokeWidth: "2"
1796
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
1797
+ cx: "8",
1798
+ cy: "8",
1799
+ r: "6.5",
1800
+ fill: "none",
1801
+ stroke: report.verdict === "good" ? "#2e9e5b" : report.verdict === "fair" ? "#c98a1b" : "#cf3d3d",
1802
+ strokeWidth: "2",
1803
+ strokeLinecap: "round",
1804
+ strokeDasharray: `${(report.score / 100 * 2 * Math.PI * 6.5).toFixed(1)} ${(2 * Math.PI * 6.5).toFixed(1)}`,
1805
+ transform: "rotate(-90 8 8)"
1806
+ })]
1650
1807
  }),
1651
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1652
- type: "button",
1653
- className: VaultSection_module_css_default.deleteButton,
1654
- onClick: () => void removeEntry(entry.id),
1655
- disabled: busy || readonly,
1656
- children: t("delete")
1657
- })
1808
+ t("healthScore"),
1809
+ ": ",
1810
+ report.score,
1811
+ " (",
1812
+ t(VERDICT_KEYS[report.verdict] ?? "verdictGood"),
1813
+ ")"
1814
+ ]
1815
+ }),
1816
+ report !== null && report.no2fa.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1817
+ className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeWarn}`,
1818
+ children: [
1819
+ t("no2fa"),
1820
+ ": ",
1821
+ report.no2fa.length
1822
+ ]
1823
+ }),
1824
+ report !== null && report.httpSites.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1825
+ className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeWarn}`,
1826
+ children: [
1827
+ t("httpSites"),
1828
+ ": ",
1829
+ report.httpSites.length
1830
+ ]
1831
+ }),
1832
+ report !== null && report.rotation.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1833
+ className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeWarn}`,
1834
+ children: [
1835
+ t("reportRotation"),
1836
+ ": ",
1837
+ report.rotation.length
1838
+ ]
1839
+ }),
1840
+ vaultStats !== null && typeof vaultStats.expired === "number" && vaultStats.expired > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1841
+ className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeDanger}`,
1842
+ children: [
1843
+ t("dueExpired"),
1844
+ ": ",
1845
+ String(vaultStats.expired)
1846
+ ]
1847
+ }),
1848
+ report !== null && report.weak.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1849
+ className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeDanger}`,
1850
+ children: [
1851
+ t("reportWeak"),
1852
+ ": ",
1853
+ report.weak.length
1854
+ ]
1855
+ }),
1856
+ report !== null && report.reused.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1857
+ className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeDanger}`,
1858
+ children: [
1859
+ t("reportReused"),
1860
+ ": ",
1861
+ report.reused.length
1862
+ ]
1863
+ }),
1864
+ dupGroups > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1865
+ className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeWarn}`,
1866
+ children: [
1867
+ t("dupGroups"),
1868
+ ": ",
1869
+ dupGroups
1870
+ ]
1871
+ }),
1872
+ report !== null && report.rotation.length === 0 && report.weak.length === 0 && report.reused.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1873
+ className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeOk}`,
1874
+ children: t("healthOk")
1875
+ }),
1876
+ backupInfo !== null && backupInfo.daysSinceBackup >= 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1877
+ className: `${VaultSection_module_css_default.badge} ${backupInfo.daysSinceBackup > 14 ? VaultSection_module_css_default.badgeDanger : backupInfo.daysSinceBackup > 7 ? VaultSection_module_css_default.badgeWarn : ""}`,
1878
+ children: [
1879
+ t("healthBackup"),
1880
+ ": ",
1881
+ backupInfo.daysSinceBackup,
1882
+ "d (",
1883
+ backupInfo.backups,
1884
+ ")"
1658
1885
  ]
1886
+ }),
1887
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1888
+ type: "button",
1889
+ className: VaultSection_module_css_default.backupButton,
1890
+ onClick: () => void backupNow(),
1891
+ disabled: busy,
1892
+ children: t("backupNow")
1893
+ }),
1894
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1895
+ type: "button",
1896
+ className: VaultSection_module_css_default.backupButton,
1897
+ onClick: () => void runBreachCheck(),
1898
+ disabled: busy,
1899
+ children: t("breachCheck")
1900
+ }),
1901
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1902
+ type: "button",
1903
+ className: VaultSection_module_css_default.backupButton,
1904
+ onClick: () => void lockNow(),
1905
+ disabled: busy || locked,
1906
+ children: t("lock")
1659
1907
  })
1660
1908
  ]
1661
- }, entry.id);
1662
- })
1663
- })] }),
1664
- state.status === "ready" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1665
- className: VaultSection_module_css_default.healthBar,
1666
- children: [
1667
- vaultStats !== null && typeof vaultStats.total === "number" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1668
- className: VaultSection_module_css_default.badge,
1669
- children: [
1670
- t("entryCount"),
1671
- ": ",
1672
- String(vaultStats.total)
1673
- ]
1674
- }),
1675
- vaultStats !== null && typeof vaultStats.withTotp === "number" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1676
- className: VaultSection_module_css_default.badge,
1677
- children: ["TOTP: ", String(vaultStats.withTotp)]
1678
- }),
1679
- vaultStats !== null && typeof vaultStats.highSensitivity === "number" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1680
- className: VaultSection_module_css_default.badge,
1681
- children: [
1682
- t("highSensitivity"),
1683
- ": ",
1684
- String(vaultStats.highSensitivity)
1685
- ]
1686
- }),
1687
- report !== null && report.strength !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1688
- className: `${VaultSection_module_css_default.badge} ${report.strength.weak > 0 ? VaultSection_module_css_default.badgeDanger : VaultSection_module_css_default.badgeOk}`,
1689
- children: [
1690
- t("healthStrength"),
1691
- ": ",
1692
- report.strength.weak,
1693
- "W/",
1694
- report.strength.fair,
1695
- "F/",
1696
- report.strength.strong,
1697
- "S"
1698
- ]
1699
1909
  }),
1700
- report !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1701
- className: `${VaultSection_module_css_default.badge} ${report.verdict === "good" ? VaultSection_module_css_default.badgeOk : report.verdict === "fair" ? VaultSection_module_css_default.badgeWarn : VaultSection_module_css_default.badgeDanger}`,
1910
+ breach !== null && (breach.pwned.length > 0 || breach.weak.length > 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1911
+ className: VaultSection_module_css_default.reportBox,
1702
1912
  children: [
1703
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1704
- className: VaultSection_module_css_default.scoreRing,
1705
- width: "14",
1706
- height: "14",
1707
- viewBox: "0 0 16 16",
1708
- "aria-hidden": "true",
1709
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
1710
- cx: "8",
1711
- cy: "8",
1712
- r: "6.5",
1713
- fill: "none",
1714
- stroke: "var(--dsh-color-border, #ddd)",
1715
- strokeWidth: "2"
1716
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
1717
- cx: "8",
1718
- cy: "8",
1719
- r: "6.5",
1720
- fill: "none",
1721
- stroke: report.verdict === "good" ? "#2e9e5b" : report.verdict === "fair" ? "#c98a1b" : "#cf3d3d",
1722
- strokeWidth: "2",
1723
- strokeLinecap: "round",
1724
- strokeDasharray: `${(report.score / 100 * 2 * Math.PI * 6.5).toFixed(1)} ${(2 * Math.PI * 6.5).toFixed(1)}`,
1725
- transform: "rotate(-90 8 8)"
1726
- })]
1913
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1914
+ className: VaultSection_module_css_default.reportTitle,
1915
+ children: [t("breachTitle"), breach.offline ? ` (${t("breachOffline")})` : ""]
1727
1916
  }),
1728
- t("healthScore"),
1729
- ": ",
1730
- report.score,
1731
- " (",
1732
- t(VERDICT_KEYS[report.verdict] ?? "verdictGood"),
1733
- ")"
1734
- ]
1735
- }),
1736
- report !== null && report.no2fa.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1737
- className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeWarn}`,
1738
- children: [
1739
- t("no2fa"),
1740
- ": ",
1741
- report.no2fa.length
1742
- ]
1743
- }),
1744
- report !== null && report.httpSites.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1745
- className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeWarn}`,
1746
- children: [
1747
- t("httpSites"),
1748
- ": ",
1749
- report.httpSites.length
1750
- ]
1751
- }),
1752
- report !== null && report.rotation.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1753
- className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeWarn}`,
1754
- children: [
1755
- t("reportRotation"),
1756
- ": ",
1757
- report.rotation.length
1758
- ]
1759
- }),
1760
- vaultStats !== null && typeof vaultStats.expired === "number" && vaultStats.expired > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1761
- className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeDanger}`,
1762
- children: [
1763
- t("dueExpired"),
1764
- ": ",
1765
- String(vaultStats.expired)
1766
- ]
1767
- }),
1768
- report !== null && report.weak.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1769
- className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeDanger}`,
1770
- children: [
1771
- t("reportWeak"),
1772
- ": ",
1773
- report.weak.length
1774
- ]
1775
- }),
1776
- report !== null && report.reused.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1777
- className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeDanger}`,
1778
- children: [
1779
- t("reportReused"),
1780
- ": ",
1781
- report.reused.length
1782
- ]
1783
- }),
1784
- dupGroups > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1785
- className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeWarn}`,
1786
- children: [
1787
- t("dupGroups"),
1788
- ": ",
1789
- dupGroups
1917
+ breach.pwned.slice(0, 6).map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1918
+ className: VaultSection_module_css_default.reportSub,
1919
+ children: [
1920
+ "· ",
1921
+ item.title,
1922
+ "",
1923
+ t("breachPwned"),
1924
+ item.count > 0 ? ` ×${item.count}` : ""
1925
+ ]
1926
+ }, item.id)),
1927
+ breach.weak.slice(0, 6).map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1928
+ className: VaultSection_module_css_default.reportSub,
1929
+ children: [
1930
+ "· ",
1931
+ item.title,
1932
+ " — ",
1933
+ t("breachWeak")
1934
+ ]
1935
+ }, item.id))
1790
1936
  ]
1791
1937
  }),
1792
- report !== null && report.rotation.length === 0 && report.weak.length === 0 && report.reused.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1793
- className: `${VaultSection_module_css_default.badge} ${VaultSection_module_css_default.badgeOk}`,
1794
- children: t("healthOk")
1795
- }),
1796
- backupInfo !== null && backupInfo.daysSinceBackup >= 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1797
- className: `${VaultSection_module_css_default.badge} ${backupInfo.daysSinceBackup > 14 ? VaultSection_module_css_default.badgeDanger : backupInfo.daysSinceBackup > 7 ? VaultSection_module_css_default.badgeWarn : ""}`,
1938
+ state.status === "ready" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1939
+ className: VaultSection_module_css_default.footer,
1798
1940
  children: [
1799
- t("healthBackup"),
1941
+ t("entryCount"),
1800
1942
  ": ",
1801
- backupInfo.daysSinceBackup,
1802
- "d (",
1803
- backupInfo.backups,
1804
- ")"
1943
+ state.entries.length,
1944
+ vaultStats !== null && typeof vaultStats.withTotp === "number" && ` · TOTP: ${String(vaultStats.withTotp)}`,
1945
+ vaultStats !== null && typeof vaultStats.highSensitivity === "number" && ` · ${t("highSensitivity")}: ${String(vaultStats.highSensitivity)}`,
1946
+ backupInfo !== null && backupInfo.daysSinceBackup >= 0 && ` · backup: ${backupInfo.daysSinceBackup}d ago`,
1947
+ vaultStats !== null && typeof vaultStats.byTag === "object" && vaultStats.byTag !== null && Object.keys(vaultStats.byTag).length > 0 && ` · tags: ${Object.entries(vaultStats.byTag).map(([k, v]) => `${k}(${String(v)})`).join(" ")}`
1805
1948
  ]
1806
- }),
1807
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1808
- type: "button",
1809
- className: VaultSection_module_css_default.backupButton,
1810
- onClick: () => void backupNow(),
1811
- disabled: busy,
1812
- children: t("backupNow")
1813
- }),
1814
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1815
- type: "button",
1816
- className: VaultSection_module_css_default.backupButton,
1817
- onClick: () => void runBreachCheck(),
1818
- disabled: busy,
1819
- children: t("breachCheck")
1820
- }),
1821
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1822
- type: "button",
1823
- className: VaultSection_module_css_default.backupButton,
1824
- onClick: () => void lockNow(),
1825
- disabled: busy || locked,
1826
- children: t("lock")
1827
1949
  })
1828
1950
  ]
1829
1951
  }),
1830
- breach !== null && (breach.pwned.length > 0 || breach.weak.length > 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1831
- className: VaultSection_module_css_default.reportBox,
1832
- children: [
1833
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1834
- className: VaultSection_module_css_default.reportTitle,
1835
- children: [t("breachTitle"), breach.offline ? ` (${t("breachOffline")})` : ""]
1836
- }),
1837
- breach.pwned.slice(0, 6).map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1838
- className: VaultSection_module_css_default.reportSub,
1839
- children: [
1840
- "· ",
1841
- item.title,
1842
- " — ",
1843
- t("breachPwned"),
1844
- item.count > 0 ? ` ×${item.count}` : ""
1845
- ]
1846
- }, item.id)),
1847
- breach.weak.slice(0, 6).map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1848
- className: VaultSection_module_css_default.reportSub,
1849
- children: [
1850
- "· ",
1851
- item.title,
1852
- " — ",
1853
- t("breachWeak")
1854
- ]
1855
- }, item.id))
1856
- ]
1857
- }),
1858
- state.status === "ready" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1859
- className: VaultSection_module_css_default.footer,
1860
- children: [
1861
- t("entryCount"),
1862
- ": ",
1863
- state.entries.length,
1864
- vaultStats !== null && typeof vaultStats.withTotp === "number" && ` · TOTP: ${String(vaultStats.withTotp)}`,
1865
- vaultStats !== null && typeof vaultStats.highSensitivity === "number" && ` · ${t("highSensitivity")}: ${String(vaultStats.highSensitivity)}`,
1866
- backupInfo !== null && backupInfo.daysSinceBackup >= 0 && ` · backup: ${backupInfo.daysSinceBackup}d ago`,
1867
- vaultStats !== null && typeof vaultStats.byTag === "object" && vaultStats.byTag !== null && Object.keys(vaultStats.byTag).length > 0 && ` · tags: ${Object.entries(vaultStats.byTag).map(([k, v]) => `${k}(${String(v)})`).join(" ")}`
1868
- ]
1869
- }),
1870
1952
  editor.status !== "closed" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1871
1953
  className: VaultSection_module_css_default.editor,
1872
1954
  role: "dialog",
@@ -2248,6 +2330,14 @@ window.__ModuleLoader__.load({
2248
2330
  systemSearch: "Search system stores",
2249
2331
  sysSearchPlaceholder: "Search Chrome / Keychain…",
2250
2332
  sysSearchGo: "Search",
2333
+ importFirefox: "Import Firefox",
2334
+ importFirefoxDesc: "Firefox profile (logins.json + key4.db)",
2335
+ firefoxMasterPw: "Firefox primary password (leave empty if none):",
2336
+ sectionTabs: "Vault sections",
2337
+ tabEntries: "Entries",
2338
+ tabSecurity: "Security",
2339
+ tabTransfer: "Import / Export",
2340
+ tabOrganize: "Organize",
2251
2341
  lockedShort: "🔒 locked",
2252
2342
  httpSites: "HTTP sites",
2253
2343
  healthStrength: "strength",
@@ -2418,6 +2508,14 @@ window.__ModuleLoader__.load({
2418
2508
  systemSearch: "搜索系统凭据库",
2419
2509
  sysSearchPlaceholder: "搜索 Chrome / 钥匙串…",
2420
2510
  sysSearchGo: "搜索",
2511
+ importFirefox: "导入 Firefox",
2512
+ importFirefoxDesc: "Firefox 配置(logins.json + key4.db)",
2513
+ firefoxMasterPw: "Firefox 主密码(未设置则留空):",
2514
+ sectionTabs: "凭据库分区",
2515
+ tabEntries: "条目",
2516
+ tabSecurity: "安全",
2517
+ tabTransfer: "导入/导出",
2518
+ tabOrganize: "整理",
2421
2519
  lockedShort: "🔒 已锁定",
2422
2520
  httpSites: "HTTP站点",
2423
2521
  healthStrength: "强度",
@@ -2558,6 +2656,10 @@ window.__ModuleLoader__.load({
2558
2656
  generatorHistory: () => invoke("generatorHistory"),
2559
2657
  backups: (limit) => invoke("backups", { limit: limit ?? 5 }),
2560
2658
  importChrome: (overwrite) => invoke("importChrome", { overwrite: overwrite ?? false }),
2659
+ importFirefox: (masterPassword, overwrite) => invoke("importFirefox", {
2660
+ masterPassword: masterPassword ?? "",
2661
+ overwrite: overwrite ?? false
2662
+ }),
2561
2663
  keychainImport: (options) => invoke("keychainImport", { ...options ?? {} }),
2562
2664
  searchSystem: (query, source, limit) => invoke("searchSystem", {
2563
2665
  query,