@ai-matrx/vault 0.1.15 → 0.1.17
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/CHANGELOG.md +13 -1
- package/dist/index.cjs +1150 -785
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -3
- package/dist/index.d.ts +62 -3
- package/dist/index.js +1081 -716
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -152,24 +152,28 @@ __export(src_exports, {
|
|
|
152
152
|
guardPort: () => guardPort,
|
|
153
153
|
inferFromUrl: () => inferFromUrl,
|
|
154
154
|
isHiddenItem: () => isHiddenItem,
|
|
155
|
+
itemIdAt: () => itemIdAt,
|
|
155
156
|
locationFromParams: () => locationFromParams,
|
|
156
157
|
locationToParams: () => locationToParams,
|
|
157
158
|
loginSiteOf: () => loginSiteOf,
|
|
158
159
|
matchesQuery: () => matchesQuery,
|
|
159
160
|
needsRecentSignIn: () => needsRecentSignIn,
|
|
160
161
|
parseDefinitions: () => parseDefinitions,
|
|
162
|
+
providerOf: () => providerOf,
|
|
161
163
|
siteDomainOf: () => siteDomainOf,
|
|
162
164
|
sortItems: () => sortItems,
|
|
163
165
|
useConfirmed: () => useConfirmed,
|
|
166
|
+
vaultInventoryScope: () => vaultInventoryScope,
|
|
167
|
+
vaultItemFacts: () => vaultItemFacts,
|
|
164
168
|
wasCancelled: () => wasCancelled
|
|
165
169
|
});
|
|
166
170
|
module.exports = __toCommonJS(src_exports);
|
|
167
171
|
|
|
168
172
|
// src/VaultApp.tsx
|
|
169
|
-
var
|
|
170
|
-
var
|
|
171
|
-
var
|
|
172
|
-
var
|
|
173
|
+
var import_react42 = require("react");
|
|
174
|
+
var import_design_system26 = require("@ai-matrx/design-system");
|
|
175
|
+
var import_controls35 = require("@ai-matrx/design-system/controls");
|
|
176
|
+
var import_confirm_opener14 = require("@ai-matrx/kit/confirm-opener");
|
|
173
177
|
|
|
174
178
|
// src/notice.tsx
|
|
175
179
|
var import_react = require("react");
|
|
@@ -703,12 +707,12 @@ var ROW_GRID = {
|
|
|
703
707
|
roomy: "grid-cols-[9rem_minmax(0,1fr)_auto] gap-x-3 px-4",
|
|
704
708
|
viewport: "grid-cols-[5.75rem_minmax(0,1fr)_auto] gap-x-2 px-3 sm:grid-cols-[9rem_minmax(0,1fr)_auto] sm:gap-x-3 sm:px-4"
|
|
705
709
|
};
|
|
706
|
-
function VaultRow({ label, hint, children, actions, top = false, className }) {
|
|
710
|
+
function VaultRow({ label, hint: hint2, children, actions, top = false, className }) {
|
|
707
711
|
const room = (0, import_react4.useContext)(Room);
|
|
708
712
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: (0, import_design_system4.cn)("grid min-h-11 py-1", ROW_GRID[room ?? "viewport"], top ? "items-start" : "items-center", className), children: [
|
|
709
713
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: (0, import_design_system4.cn)("flex min-w-0 flex-col text-xs leading-tight text-muted-foreground", top && "pt-2.5"), children: [
|
|
710
714
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: room === "roomy" ? "truncate" : room === "compact" ? "line-clamp-2 break-words" : "line-clamp-2 break-words sm:truncate", children: label }),
|
|
711
|
-
|
|
715
|
+
hint2 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "line-clamp-2 break-words text-xs text-disabled-foreground", children: hint2 }) : null
|
|
712
716
|
] }),
|
|
713
717
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: (0, import_design_system4.cn)("min-w-0 text-sm", top && "py-1.5"), children }),
|
|
714
718
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: (0, import_design_system4.cn)("flex items-center gap-0.5", top && "pt-1"), children: actions })
|
|
@@ -818,14 +822,14 @@ function TurnOnButton({ label, onTurnOn }) {
|
|
|
818
822
|
}
|
|
819
823
|
);
|
|
820
824
|
}
|
|
821
|
-
function PlainRow({ label, value, hint, openUrl, extra, multiline = false }) {
|
|
825
|
+
function PlainRow({ label, value, hint: hint2, openUrl, extra, multiline = false }) {
|
|
822
826
|
const copyValue2 = useCopy();
|
|
823
827
|
const isUrl = /^https?:\/\//i.test(value);
|
|
824
828
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
825
829
|
VaultRow,
|
|
826
830
|
{
|
|
827
831
|
label,
|
|
828
|
-
hint,
|
|
832
|
+
hint: hint2,
|
|
829
833
|
top: multiline,
|
|
830
834
|
actions: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
831
835
|
extra,
|
|
@@ -855,13 +859,13 @@ function PlainRow({ label, value, hint, openUrl, extra, multiline = false }) {
|
|
|
855
859
|
function AddRow({ label, onAdd, children = "Add" }) {
|
|
856
860
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VaultRow, { label, children: onAdd ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "text-sm text-muted-foreground hover:text-primary", onClick: onAdd, children }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-disabled-foreground", children: "\u2014" }) });
|
|
857
861
|
}
|
|
858
|
-
function EditRow({ label, hint, value, onChange, placeholder, secret = false, multiline = false, onRemove, removeLabel, actions, autoFocus, onBlur, inputMode }) {
|
|
862
|
+
function EditRow({ label, hint: hint2, value, onChange, placeholder, secret = false, multiline = false, onRemove, removeLabel, actions, autoFocus, onBlur, inputMode }) {
|
|
859
863
|
const [shown, setShown] = (0, import_react5.useState)(false);
|
|
860
864
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
861
865
|
VaultRow,
|
|
862
866
|
{
|
|
863
867
|
label,
|
|
864
|
-
hint,
|
|
868
|
+
hint: hint2,
|
|
865
869
|
top: multiline,
|
|
866
870
|
actions: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
867
871
|
secret && value ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.Button, { variant: "quiet", icon: shown ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EyeOffGlyph, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EyeGlyph, {}), "aria-label": shown ? "Hide" : "Show", onClick: () => setShown((s) => !s) }) : null,
|
|
@@ -872,7 +876,7 @@ function EditRow({ label, hint, value, onChange, placeholder, secret = false, mu
|
|
|
872
876
|
}
|
|
873
877
|
);
|
|
874
878
|
}
|
|
875
|
-
function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove }) {
|
|
879
|
+
function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove, extra, onPasteValue }) {
|
|
876
880
|
const [shown, setShown] = (0, import_react5.useState)(false);
|
|
877
881
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
878
882
|
VaultRow,
|
|
@@ -880,9 +884,25 @@ function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove }) {
|
|
|
880
884
|
label: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.Field, { className: "w-full", value: label, onChange: (e) => onLabel(e.target.value), placeholder: "Name", "aria-label": "Field name" }),
|
|
881
885
|
actions: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
882
886
|
secret && value ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.Button, { variant: "quiet", icon: shown ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EyeOffGlyph, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EyeGlyph, {}), "aria-label": shown ? "Hide" : "Show", onClick: () => setShown((x) => !x) }) : null,
|
|
887
|
+
extra,
|
|
883
888
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.Button, { variant: "quiet", removes: true, icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(XGlyph, {}), "aria-label": "Remove field", onClick: onRemove })
|
|
884
889
|
] }),
|
|
885
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
890
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
891
|
+
import_controls2.Field,
|
|
892
|
+
{
|
|
893
|
+
className: "w-full",
|
|
894
|
+
value,
|
|
895
|
+
onChange: (e) => onValue(e.target.value),
|
|
896
|
+
onPaste: onPasteValue ? (e) => {
|
|
897
|
+
if (onPasteValue(e.clipboardData.getData("text"))) e.preventDefault();
|
|
898
|
+
} : void 0,
|
|
899
|
+
type: secret && !shown ? "password" : "text",
|
|
900
|
+
placeholder: secret ? "Secret value" : "Value",
|
|
901
|
+
autoComplete: "off",
|
|
902
|
+
spellCheck: false,
|
|
903
|
+
"aria-label": label ? `${label} value` : "Field value"
|
|
904
|
+
}
|
|
905
|
+
)
|
|
886
906
|
}
|
|
887
907
|
);
|
|
888
908
|
}
|
|
@@ -896,7 +916,7 @@ var import_format = require("@ai-matrx/kit/format");
|
|
|
896
916
|
|
|
897
917
|
// src/model.ts
|
|
898
918
|
var DEFAULT_LOCATION = { vault: "all", view: "all", q: "", sort: "name", itemId: null, mode: "view", kind: null, url: "", panel: null };
|
|
899
|
-
var SORTS = ["name", "website", "updated", "created"];
|
|
919
|
+
var SORTS = ["name", "name-desc", "website", "updated", "created", "viewed"];
|
|
900
920
|
function locationFromParams(params, itemId = params.get("item")) {
|
|
901
921
|
const sort = params.get("sort");
|
|
902
922
|
const mode = params.get("mode");
|
|
@@ -966,10 +986,15 @@ function siteDomainOf(host) {
|
|
|
966
986
|
const keep = TWO_PART_SUFFIX.has(sld) && tld.length <= 3 ? 3 : 2;
|
|
967
987
|
return labels.slice(-keep).join(".");
|
|
968
988
|
}
|
|
969
|
-
function sortItems(items, sort) {
|
|
989
|
+
function sortItems(items, sort, recents) {
|
|
970
990
|
const out = [...items];
|
|
971
|
-
const byName = (a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
|
|
991
|
+
const byName = (a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base", numeric: true });
|
|
972
992
|
if (sort === "name") return out.sort(byName);
|
|
993
|
+
if (sort === "name-desc") return out.sort((a, b) => byName(b, a));
|
|
994
|
+
if (sort === "viewed") {
|
|
995
|
+
const at = new Map((recents ?? []).map((id, i) => [id, i]));
|
|
996
|
+
return out.sort((a, b) => (at.get(a.id) ?? Infinity) - (at.get(b.id) ?? Infinity) || byName(a, b));
|
|
997
|
+
}
|
|
973
998
|
if (sort === "website")
|
|
974
999
|
return out.sort((a, b) => {
|
|
975
1000
|
const x = loginSiteOf(a), y = loginSiteOf(b);
|
|
@@ -2205,7 +2230,7 @@ function TotpEditRow({ value, onChange, hasExisting, item, port, onEnrolled, onR
|
|
|
2205
2230
|
setStatus(null);
|
|
2206
2231
|
onChange(v);
|
|
2207
2232
|
},
|
|
2208
|
-
placeholder: hasExisting ? "Paste a new key to replace" : "
|
|
2233
|
+
placeholder: hasExisting ? "Paste a new key to replace" : "Paste setup key or otpauth link",
|
|
2209
2234
|
status,
|
|
2210
2235
|
...uploadImage ? { onImage: (f) => void uploadImage(f) } : {},
|
|
2211
2236
|
...onRecognized ? { onRecognized } : {}
|
|
@@ -2661,6 +2686,18 @@ function withoutCode(codes, index) {
|
|
|
2661
2686
|
const left = codes.filter((_, i) => i !== index);
|
|
2662
2687
|
return left.length ? left.join("\n") : null;
|
|
2663
2688
|
}
|
|
2689
|
+
function parseEnvAssignment(text) {
|
|
2690
|
+
const m = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=(.*)$/s.exec(text.trim());
|
|
2691
|
+
if (!m || /\n/.test(m[2] ?? "")) return null;
|
|
2692
|
+
let value = (m[2] ?? "").trim();
|
|
2693
|
+
const q = value[0];
|
|
2694
|
+
if ((q === '"' || q === "'") && value.length >= 2 && value.endsWith(q)) value = value.slice(1, -1);
|
|
2695
|
+
return value ? { key: m[1] ?? "", value } : null;
|
|
2696
|
+
}
|
|
2697
|
+
function labelFromEnvKey(key) {
|
|
2698
|
+
const words = key.toLowerCase().split(/[_\s]+/).filter(Boolean).join(" ");
|
|
2699
|
+
return words ? words.charAt(0).toUpperCase() + words.slice(1) : key;
|
|
2700
|
+
}
|
|
2664
2701
|
|
|
2665
2702
|
// src/fields/SettingsPanels.tsx
|
|
2666
2703
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
@@ -3055,11 +3092,11 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
|
|
|
3055
3092
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_controls11.Button, { variant: "primary", disabled: !candidate, onClick: use, children: useLabel })
|
|
3056
3093
|
] });
|
|
3057
3094
|
}
|
|
3058
|
-
function OptionLine({ label, hint, children }) {
|
|
3095
|
+
function OptionLine({ label, hint: hint2, children }) {
|
|
3059
3096
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex min-h-9 items-center justify-between gap-3", children: [
|
|
3060
3097
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex min-w-0 flex-col", children: [
|
|
3061
3098
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "truncate text-sm text-foreground", children: label }),
|
|
3062
|
-
|
|
3099
|
+
hint2 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "truncate text-xs text-muted-foreground", children: hint2 }) : null
|
|
3063
3100
|
] }),
|
|
3064
3101
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex shrink-0 items-center", children })
|
|
3065
3102
|
] });
|
|
@@ -4782,17 +4819,18 @@ function Notices({ draft }) {
|
|
|
4782
4819
|
}
|
|
4783
4820
|
|
|
4784
4821
|
// src/ItemList.tsx
|
|
4785
|
-
var
|
|
4786
|
-
var import_design_system18 = require("@ai-matrx/design-system");
|
|
4822
|
+
var import_react29 = require("react");
|
|
4787
4823
|
var import_design_system19 = require("@ai-matrx/design-system");
|
|
4788
|
-
var
|
|
4824
|
+
var import_design_system20 = require("@ai-matrx/design-system");
|
|
4825
|
+
var import_controls23 = require("@ai-matrx/design-system/controls");
|
|
4826
|
+
var import_icons12 = require("@ai-matrx/design-system/icons");
|
|
4789
4827
|
|
|
4790
4828
|
// src/ItemPane.tsx
|
|
4791
|
-
var
|
|
4792
|
-
var import_design_system16 = require("@ai-matrx/design-system");
|
|
4829
|
+
var import_react28 = require("react");
|
|
4793
4830
|
var import_design_system17 = require("@ai-matrx/design-system");
|
|
4794
|
-
var
|
|
4795
|
-
var
|
|
4831
|
+
var import_design_system18 = require("@ai-matrx/design-system");
|
|
4832
|
+
var import_controls22 = require("@ai-matrx/design-system/controls");
|
|
4833
|
+
var import_confirm_opener10 = require("@ai-matrx/kit/confirm-opener");
|
|
4796
4834
|
|
|
4797
4835
|
// src/activity/FilesSection.tsx
|
|
4798
4836
|
var import_format7 = require("@ai-matrx/kit/format");
|
|
@@ -4813,12 +4851,13 @@ var PROTECTION = [
|
|
|
4813
4851
|
function FilesSection({ item, port, editing, onChanged }) {
|
|
4814
4852
|
const confirmed = useConfirmed();
|
|
4815
4853
|
const canEdit = editing && item.capabilities.canEdit;
|
|
4854
|
+
const canAdd = item.capabilities.canEdit;
|
|
4816
4855
|
const [busy, setBusy] = (0, import_react21.useState)(null);
|
|
4817
4856
|
const [error, setError] = (0, import_react21.useState)(null);
|
|
4818
4857
|
const [pending, setPending] = (0, import_react21.useState)(null);
|
|
4819
4858
|
const [dragging, setDragging] = (0, import_react21.useState)(false);
|
|
4820
4859
|
const picker = (0, import_react21.useRef)(null);
|
|
4821
|
-
if (!
|
|
4860
|
+
if (!canAdd && item.attachments.length === 0) return null;
|
|
4822
4861
|
async function run(key, work, fallback) {
|
|
4823
4862
|
setBusy(key);
|
|
4824
4863
|
setError(null);
|
|
@@ -4840,7 +4879,7 @@ function FilesSection({ item, port, editing, onChanged }) {
|
|
|
4840
4879
|
setPending(file);
|
|
4841
4880
|
}
|
|
4842
4881
|
function drop(e) {
|
|
4843
|
-
if (!
|
|
4882
|
+
if (!canAdd) return;
|
|
4844
4883
|
e.preventDefault();
|
|
4845
4884
|
setDragging(false);
|
|
4846
4885
|
choose(e.dataTransfer.files[0]);
|
|
@@ -4853,22 +4892,23 @@ function FilesSection({ item, port, editing, onChanged }) {
|
|
|
4853
4892
|
"div",
|
|
4854
4893
|
{
|
|
4855
4894
|
className: (0, import_design_system13.cn)("rounded-xl", dragging && "outline outline-2 outline-primary"),
|
|
4856
|
-
onDragOver:
|
|
4895
|
+
onDragOver: canAdd ? (e) => {
|
|
4857
4896
|
e.preventDefault();
|
|
4858
4897
|
setDragging(true);
|
|
4859
4898
|
} : void 0,
|
|
4860
|
-
onDragLeave:
|
|
4861
|
-
onDrop:
|
|
4899
|
+
onDragLeave: canAdd ? () => setDragging(false) : void 0,
|
|
4900
|
+
onDrop: canAdd ? drop : void 0,
|
|
4862
4901
|
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
4863
4902
|
VaultSection,
|
|
4864
4903
|
{
|
|
4865
|
-
title: "Files",
|
|
4866
|
-
actions:
|
|
4904
|
+
title: editing || item.attachments.length > 0 || pending ? "Files" : void 0,
|
|
4905
|
+
actions: canAdd && (editing || item.attachments.length > 0) ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_controls16.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PlusGlyph, {}), disabled: busy !== null, onClick: () => picker.current?.click(), children: "Add file" }) : void 0,
|
|
4867
4906
|
children: [
|
|
4868
|
-
|
|
4907
|
+
canAdd ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { ref: picker, type: "file", hidden: true, "aria-label": "Choose a file", onChange: (e) => {
|
|
4869
4908
|
choose(e.target.files?.[0]);
|
|
4870
4909
|
e.target.value = "";
|
|
4871
4910
|
} }) : null,
|
|
4911
|
+
!editing && canAdd && item.attachments.length === 0 && !pending ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(AddRow, { label: "Files", onAdd: () => picker.current?.click(), children: "Add file" }) : null,
|
|
4872
4912
|
item.attachments.map(
|
|
4873
4913
|
(a) => canEdit ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(EditableFile, { port, item, file: a, busy, run, onDownload: () => void download(a), onTooBig: () => setError(TOO_BIG) }, a.id) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
4874
4914
|
VaultRow,
|
|
@@ -4881,7 +4921,7 @@ function FilesSection({ item, port, editing, onChanged }) {
|
|
|
4881
4921
|
a.id
|
|
4882
4922
|
)
|
|
4883
4923
|
),
|
|
4884
|
-
|
|
4924
|
+
canAdd && pending ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(NewFile, { file: pending, busy: busy === "add", onCancel: () => setPending(null), onAdd: async (details) => {
|
|
4885
4925
|
if (await run("add", () => port.activity.addFile(item, pending, details), "The file could not be added.")) setPending(null);
|
|
4886
4926
|
} }) : null,
|
|
4887
4927
|
canEdit && item.attachments.length === 0 && !pending ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "px-4 py-3 text-sm text-muted-foreground", children: "Drop a file here or choose Add file" }) : null,
|
|
@@ -5002,6 +5042,57 @@ function confirmSeal(label) {
|
|
|
5002
5042
|
variant: "destructive"
|
|
5003
5043
|
});
|
|
5004
5044
|
}
|
|
5045
|
+
function DraftFilesSection({ files, onFiles }) {
|
|
5046
|
+
const [pending, setPending] = (0, import_react21.useState)(null);
|
|
5047
|
+
const [error, setError] = (0, import_react21.useState)(null);
|
|
5048
|
+
const [dragging, setDragging] = (0, import_react21.useState)(false);
|
|
5049
|
+
const picker = (0, import_react21.useRef)(null);
|
|
5050
|
+
const choose = (file) => {
|
|
5051
|
+
if (!file) return;
|
|
5052
|
+
if (fileTooBig(file.size)) return setError(TOO_BIG);
|
|
5053
|
+
setError(null);
|
|
5054
|
+
setPending(file);
|
|
5055
|
+
};
|
|
5056
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
5057
|
+
"div",
|
|
5058
|
+
{
|
|
5059
|
+
className: (0, import_design_system13.cn)("rounded-xl", dragging && "outline outline-2 outline-primary"),
|
|
5060
|
+
onDragOver: (e) => {
|
|
5061
|
+
e.preventDefault();
|
|
5062
|
+
setDragging(true);
|
|
5063
|
+
},
|
|
5064
|
+
onDragLeave: () => setDragging(false),
|
|
5065
|
+
onDrop: (e) => {
|
|
5066
|
+
e.preventDefault();
|
|
5067
|
+
setDragging(false);
|
|
5068
|
+
choose(e.dataTransfer.files[0]);
|
|
5069
|
+
},
|
|
5070
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(VaultSection, { title: files.length > 0 || pending ? "Files" : void 0, actions: files.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_controls16.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PlusGlyph, {}), onClick: () => picker.current?.click(), children: "Add file" }) : void 0, children: [
|
|
5071
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { ref: picker, type: "file", hidden: true, "aria-label": "Choose a file", onChange: (e) => {
|
|
5072
|
+
choose(e.target.files?.[0]);
|
|
5073
|
+
e.target.value = "";
|
|
5074
|
+
} }),
|
|
5075
|
+
files.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(VaultRow, { label: f.label, hint: f.description ?? void 0, actions: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_controls16.Button, { variant: "quiet", removes: true, icon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(XGlyph, {}), "aria-label": `Remove ${f.label}`, onClick: () => onFiles(files.filter((_, j) => j !== i)) }), children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
5076
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "truncate", children: f.file.name }),
|
|
5077
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: (0, import_format7.formatFileSize)(f.file.size) })
|
|
5078
|
+
] }) }, `${f.file.name}-${i}`)),
|
|
5079
|
+
pending ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
5080
|
+
NewFile,
|
|
5081
|
+
{
|
|
5082
|
+
file: pending,
|
|
5083
|
+
busy: false,
|
|
5084
|
+
onCancel: () => setPending(null),
|
|
5085
|
+
onAdd: async (d) => {
|
|
5086
|
+
onFiles([...files, { file: pending, ...d }]);
|
|
5087
|
+
setPending(null);
|
|
5088
|
+
}
|
|
5089
|
+
}
|
|
5090
|
+
) : files.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(AddRow, { label: "Files", onAdd: () => picker.current?.click(), children: "Add file" }) : null,
|
|
5091
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { role: "alert", className: "px-4 py-2 text-sm text-destructive", children: error }) : null
|
|
5092
|
+
] })
|
|
5093
|
+
}
|
|
5094
|
+
);
|
|
5095
|
+
}
|
|
5005
5096
|
|
|
5006
5097
|
// src/fields/RecoveryCodesRow.tsx
|
|
5007
5098
|
var import_react22 = require("react");
|
|
@@ -5109,6 +5200,134 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
|
|
|
5109
5200
|
);
|
|
5110
5201
|
}
|
|
5111
5202
|
|
|
5203
|
+
// src/fields/DraftRows.tsx
|
|
5204
|
+
var import_react23 = require("react");
|
|
5205
|
+
var import_controls18 = require("@ai-matrx/design-system/controls");
|
|
5206
|
+
var import_design_system14 = require("@ai-matrx/design-system");
|
|
5207
|
+
var import_confirm_opener7 = require("@ai-matrx/kit/confirm-opener");
|
|
5208
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
5209
|
+
var HANDLINGS = ["visible", "revealable", "sealed"];
|
|
5210
|
+
var hint = (text, tone = "muted") => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: tone === "destructive" ? "text-destructive" : void 0, title: text, children: text });
|
|
5211
|
+
var hasSecretSettings = (s) => Boolean(s.envKey?.trim() || s.injectIntoSandbox || s.handling && s.handling !== "revealable");
|
|
5212
|
+
function SecretBuilderRow({ field, onChange, onRemove }) {
|
|
5213
|
+
const [open, setOpen] = (0, import_react23.useState)(hasSecretSettings(field));
|
|
5214
|
+
const env = field.envKey ?? "";
|
|
5215
|
+
const envProblem = envKeyProblem(env);
|
|
5216
|
+
const envOk = env.trim() !== "" && !envProblem;
|
|
5217
|
+
const handling = field.handling ?? "revealable";
|
|
5218
|
+
const name = field.label.trim() || "Secret";
|
|
5219
|
+
const chooseHandling = async (next) => {
|
|
5220
|
+
if (next === handling) return;
|
|
5221
|
+
if (next === "sealed") {
|
|
5222
|
+
const ok = await (0, import_confirm_opener7.confirm)({
|
|
5223
|
+
title: `Seal ${name} permanently?`,
|
|
5224
|
+
description: "Once saved, no person can see or copy it again; only automation can use it.",
|
|
5225
|
+
confirmLabel: "Seal",
|
|
5226
|
+
variant: "destructive"
|
|
5227
|
+
});
|
|
5228
|
+
if (!ok) return;
|
|
5229
|
+
}
|
|
5230
|
+
onChange({ handling: next });
|
|
5231
|
+
};
|
|
5232
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
5233
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
5234
|
+
CustomEditRow,
|
|
5235
|
+
{
|
|
5236
|
+
label: field.label,
|
|
5237
|
+
value: field.value,
|
|
5238
|
+
secret: true,
|
|
5239
|
+
onLabel: (v) => onChange({ label: v }),
|
|
5240
|
+
onValue: (v) => onChange({ value: v }),
|
|
5241
|
+
onRemove,
|
|
5242
|
+
onPasteValue: (text) => {
|
|
5243
|
+
const a = parseEnvAssignment(text);
|
|
5244
|
+
if (!a) return false;
|
|
5245
|
+
onChange({ envKey: a.key, value: a.value, ...field.label.trim() ? {} : { label: labelFromEnvKey(a.key) } });
|
|
5246
|
+
setOpen(true);
|
|
5247
|
+
return true;
|
|
5248
|
+
},
|
|
5249
|
+
extra: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
5250
|
+
handling !== "sealed" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GenerateButton, { onUse: (v) => onChange({ value: v }) }) : null,
|
|
5251
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_controls18.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SlidersGlyph, {}), "aria-label": `${name} settings`, pressed: open, onClick: () => setOpen((o) => !o) })
|
|
5252
|
+
] })
|
|
5253
|
+
}
|
|
5254
|
+
),
|
|
5255
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
5256
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VaultRow, { label: "Env key", hint: envProblem ? hint(envProblem, "destructive") : hint("The name sandboxes and workflows use"), children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
5257
|
+
import_controls18.Field,
|
|
5258
|
+
{
|
|
5259
|
+
className: "w-full font-mono",
|
|
5260
|
+
"aria-label": `${name} env key`,
|
|
5261
|
+
"aria-invalid": Boolean(envProblem),
|
|
5262
|
+
placeholder: "e.g. GITHUB_TOKEN",
|
|
5263
|
+
autoComplete: "off",
|
|
5264
|
+
spellCheck: false,
|
|
5265
|
+
value: env,
|
|
5266
|
+
onChange: (e) => onChange({ envKey: e.target.value, ...e.target.value.trim() ? {} : { injectIntoSandbox: false } })
|
|
5267
|
+
}
|
|
5268
|
+
) }),
|
|
5269
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VaultRow, { label: "Who can see it", hint: hint(HANDLING_WORDS[handling].hint), children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
5270
|
+
import_controls18.SegmentedControl,
|
|
5271
|
+
{
|
|
5272
|
+
"aria-label": `Who can see ${name}`,
|
|
5273
|
+
value: handling,
|
|
5274
|
+
onValueChange: (v) => void chooseHandling(v),
|
|
5275
|
+
data: HANDLINGS.map((h) => ({ value: h, label: HANDLING_WORDS[h].label, title: HANDLING_WORDS[h].hint }))
|
|
5276
|
+
}
|
|
5277
|
+
) }),
|
|
5278
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VaultRow, { label: "Use in sandbox", hint: envOk ? hint("Sandboxes get it as an env variable") : hint("Needs an env key"), children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_controls18.Switch, { "aria-label": `Use ${name} in sandbox`, checked: envOk && field.injectIntoSandbox === true, disabled: !envOk, onCheckedChange: (v) => onChange({ injectIntoSandbox: v }) }) })
|
|
5279
|
+
] }) : null
|
|
5280
|
+
] });
|
|
5281
|
+
}
|
|
5282
|
+
function withMfaMethod(custom, v) {
|
|
5283
|
+
const rest = custom.filter((c) => c.key !== MFA_METHOD_KEY);
|
|
5284
|
+
return v === "sms" || v === "push_or_other" ? [...rest, { key: MFA_METHOD_KEY, label: "Two-factor method", value: v }] : rest;
|
|
5285
|
+
}
|
|
5286
|
+
function DraftTwoFactorRow({ custom, onCustom }) {
|
|
5287
|
+
const value = custom.find((c) => c.key === MFA_METHOD_KEY)?.value || "none";
|
|
5288
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VaultRow, { label: "Two-factor", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
5289
|
+
import_controls18.Select,
|
|
5290
|
+
{
|
|
5291
|
+
value: value === "sms" || value === "push_or_other" ? value : "none",
|
|
5292
|
+
"aria-label": "Two-factor method",
|
|
5293
|
+
options: MFA_OPTIONS.map((o) => ({ value: o.value, label: o.label })),
|
|
5294
|
+
onValueChange: (v) => onCustom(withMfaMethod(custom, v))
|
|
5295
|
+
}
|
|
5296
|
+
) });
|
|
5297
|
+
}
|
|
5298
|
+
var defaultBrowserSettings = (hasWebsite) => ({ uriMatchMode: "host", browserFillEnabled: hasWebsite });
|
|
5299
|
+
function DraftBrowserRows({ value, hasWebsite, onChange }) {
|
|
5300
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
5301
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VaultRow, { label: "Website matching", hint: hint(MATCH_WORDS[value.uriMatchMode].hint), children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
5302
|
+
import_controls18.Select,
|
|
5303
|
+
{
|
|
5304
|
+
"aria-label": "Website matching",
|
|
5305
|
+
value: value.uriMatchMode,
|
|
5306
|
+
options: MATCH_MODES.map((m) => ({ value: m, label: MATCH_WORDS[m].label })),
|
|
5307
|
+
onValueChange: (m) => onChange({ ...value, uriMatchMode: m })
|
|
5308
|
+
}
|
|
5309
|
+
) }),
|
|
5310
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VaultRow, { label: "Fill in browser", hint: hint(hasWebsite ? value.browserFillEnabled ? "Offered on matching pages" : "Never filled automatically" : "Add a website first"), children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_controls18.Switch, { "aria-label": "Fill in browser", checked: hasWebsite && value.browserFillEnabled, disabled: !hasWebsite, onCheckedChange: (v) => onChange({ ...value, browserFillEnabled: v }) }) })
|
|
5311
|
+
] });
|
|
5312
|
+
}
|
|
5313
|
+
function AssignResult({ sent, onAnother, onDone }) {
|
|
5314
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5 px-3 py-4 sm:px-6 sm:py-6", role: "status", children: [
|
|
5315
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(VaultSection, { title: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "flex items-center gap-1.5", children: [
|
|
5316
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CheckGlyph, { className: "size-4 text-success" }),
|
|
5317
|
+
"Sent to ",
|
|
5318
|
+
sent.recipientEmail
|
|
5319
|
+
] }), children: [
|
|
5320
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VaultRow, { label: "Name", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "block truncate", children: sent.name }) }),
|
|
5321
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VaultRow, { label: "Item ID", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_design_system14.RecordId, { value: sent.id, label: "Item" }) }),
|
|
5322
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VaultRow, { label: "Password", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "block truncate text-muted-foreground", children: sent.generated ? "Generated privately, never shown to you" : "Theirs now; you keep no access" }) })
|
|
5323
|
+
] }),
|
|
5324
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex justify-end gap-2", children: [
|
|
5325
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_controls18.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PlusGlyph, {}), onClick: onAnother, children: "Create another" }),
|
|
5326
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_controls18.Button, { variant: "primary", onClick: onDone, children: "Done" })
|
|
5327
|
+
] })
|
|
5328
|
+
] });
|
|
5329
|
+
}
|
|
5330
|
+
|
|
5112
5331
|
// src/ItemPane.tsx
|
|
5113
5332
|
var import_icons11 = require("@ai-matrx/design-system/icons");
|
|
5114
5333
|
var import_drafts = require("@ai-matrx/kit/drafts");
|
|
@@ -5235,15 +5454,15 @@ function targetLabel(t) {
|
|
|
5235
5454
|
}
|
|
5236
5455
|
|
|
5237
5456
|
// src/extension/UseOnSiteButton.tsx
|
|
5238
|
-
var
|
|
5239
|
-
var
|
|
5240
|
-
var
|
|
5457
|
+
var import_react24 = require("react");
|
|
5458
|
+
var import_controls19 = require("@ai-matrx/design-system/controls");
|
|
5459
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
5241
5460
|
function canUseOnSite(item, pageUrl) {
|
|
5242
5461
|
return item.capabilities.canEdit && isFillablePage(pageUrl) && !coversPage(item.loginUrls, item.uriMatchMode, pageUrl);
|
|
5243
5462
|
}
|
|
5244
5463
|
function UseOnSiteButton({ port, item, pageUrl, onChanged }) {
|
|
5245
5464
|
const notify = useNotify();
|
|
5246
|
-
const [busy, setBusy] = (0,
|
|
5465
|
+
const [busy, setBusy] = (0, import_react24.useState)(false);
|
|
5247
5466
|
if (!canUseOnSite(item, pageUrl)) return null;
|
|
5248
5467
|
const site = pageSite(pageUrl);
|
|
5249
5468
|
const run = async () => {
|
|
@@ -5258,14 +5477,14 @@ function UseOnSiteButton({ port, item, pageUrl, onChanged }) {
|
|
|
5258
5477
|
setBusy(false);
|
|
5259
5478
|
}
|
|
5260
5479
|
};
|
|
5261
|
-
return /* @__PURE__ */ (0,
|
|
5480
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_controls19.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PlusGlyph, {}), disabled: busy, onClick: () => void run(), title: `Fill this login on ${site}`, children: "Use here" });
|
|
5262
5481
|
}
|
|
5263
5482
|
|
|
5264
5483
|
// src/sharing/SharePanel.tsx
|
|
5265
|
-
var
|
|
5266
|
-
var
|
|
5267
|
-
var
|
|
5268
|
-
var
|
|
5484
|
+
var import_react27 = require("react");
|
|
5485
|
+
var import_confirm_opener9 = require("@ai-matrx/kit/confirm-opener");
|
|
5486
|
+
var import_controls21 = require("@ai-matrx/design-system/controls");
|
|
5487
|
+
var import_design_system16 = require("@ai-matrx/design-system");
|
|
5269
5488
|
var import_icons10 = require("@ai-matrx/design-system/icons");
|
|
5270
5489
|
|
|
5271
5490
|
// src/sharing/logic.ts
|
|
@@ -5320,18 +5539,18 @@ function shareSummary(grants) {
|
|
|
5320
5539
|
var MEMBER_CHOICE_DEFAULT = "default";
|
|
5321
5540
|
|
|
5322
5541
|
// src/sharing/parts.tsx
|
|
5323
|
-
var
|
|
5324
|
-
var
|
|
5325
|
-
var
|
|
5542
|
+
var import_react25 = require("react");
|
|
5543
|
+
var import_design_system15 = require("@ai-matrx/design-system");
|
|
5544
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
5326
5545
|
var message = (e, fallback) => {
|
|
5327
5546
|
const m = e instanceof Error && e.message ? e.message : fallback;
|
|
5328
5547
|
return copyRefusal(m) ?? m;
|
|
5329
5548
|
};
|
|
5330
5549
|
function useConfirmedChange() {
|
|
5331
5550
|
const confirmed = useConfirmed();
|
|
5332
|
-
const [busy, setBusy] = (0,
|
|
5333
|
-
const [error, setError] = (0,
|
|
5334
|
-
const [notice, setNotice] = (0,
|
|
5551
|
+
const [busy, setBusy] = (0, import_react25.useState)(null);
|
|
5552
|
+
const [error, setError] = (0, import_react25.useState)(null);
|
|
5553
|
+
const [notice, setNotice] = (0, import_react25.useState)(null);
|
|
5335
5554
|
async function run(key, fn, done) {
|
|
5336
5555
|
setBusy(key);
|
|
5337
5556
|
setError(null);
|
|
@@ -5350,33 +5569,33 @@ function useConfirmedChange() {
|
|
|
5350
5569
|
return { busy, error, notice, run, setNotice };
|
|
5351
5570
|
}
|
|
5352
5571
|
function AccessLine({ glyph: G, who, meta, children }) {
|
|
5353
|
-
return /* @__PURE__ */ (0,
|
|
5354
|
-
/* @__PURE__ */ (0,
|
|
5355
|
-
/* @__PURE__ */ (0,
|
|
5356
|
-
/* @__PURE__ */ (0,
|
|
5357
|
-
meta ? /* @__PURE__ */ (0,
|
|
5572
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
|
|
5573
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(G, { className: "size-4 shrink-0 text-muted-foreground" }),
|
|
5574
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex min-w-0 flex-1 items-baseline gap-2", children: [
|
|
5575
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "truncate text-sm text-foreground", children: who }),
|
|
5576
|
+
meta ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: meta }) : null
|
|
5358
5577
|
] }),
|
|
5359
|
-
/* @__PURE__ */ (0,
|
|
5578
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex shrink-0 items-center gap-0.5", children })
|
|
5360
5579
|
] });
|
|
5361
5580
|
}
|
|
5362
5581
|
function StatusLine({ error, notice }) {
|
|
5363
5582
|
if (!error && !notice) return null;
|
|
5364
|
-
return /* @__PURE__ */ (0,
|
|
5583
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: (0, import_design_system15.cn)("min-w-0 flex-1 line-clamp-2 text-sm", error ? "text-destructive" : "text-success"), title: error ?? notice ?? void 0, children: error ?? notice });
|
|
5365
5584
|
}
|
|
5366
5585
|
|
|
5367
5586
|
// src/sharing/MovePanel.tsx
|
|
5368
|
-
var
|
|
5369
|
-
var
|
|
5370
|
-
var
|
|
5371
|
-
var
|
|
5587
|
+
var import_react26 = require("react");
|
|
5588
|
+
var import_confirm_opener8 = require("@ai-matrx/kit/confirm-opener");
|
|
5589
|
+
var import_controls20 = require("@ai-matrx/design-system/controls");
|
|
5590
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
5372
5591
|
var NONE = "__none__";
|
|
5373
5592
|
function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
5374
5593
|
const { busy, error, notice, run, setNotice } = useConfirmedChange();
|
|
5375
5594
|
const moves = moveDestinations(item, organizations);
|
|
5376
5595
|
const copies = copyDestinations(organizations, item);
|
|
5377
|
-
const [moveTo, setMoveTo] = (0,
|
|
5378
|
-
const [copyTo, setCopyTo] = (0,
|
|
5379
|
-
const [email, setEmail] = (0,
|
|
5596
|
+
const [moveTo, setMoveTo] = (0, import_react26.useState)("");
|
|
5597
|
+
const [copyTo, setCopyTo] = (0, import_react26.useState)("");
|
|
5598
|
+
const [email, setEmail] = (0, import_react26.useState)("");
|
|
5380
5599
|
const passkey = isPasskey(item);
|
|
5381
5600
|
const canMove = item.capabilities.canManage && !passkey && moves.length > 0;
|
|
5382
5601
|
const canGive = item.capabilities.canManage && item.owner.kind === "me" && !passkey;
|
|
@@ -5386,7 +5605,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5386
5605
|
const move = async () => {
|
|
5387
5606
|
if (!moveChoice) return;
|
|
5388
5607
|
const to = destinationOf(moveChoice.value);
|
|
5389
|
-
const ok = await (0,
|
|
5608
|
+
const ok = await (0, import_confirm_opener8.confirm)({
|
|
5390
5609
|
title: `Move to ${moveChoice.label}?`,
|
|
5391
5610
|
description: `"${item.name}" stays the same item, so everything using it keeps working. ${itemMoveConsequence(item, to)}.`,
|
|
5392
5611
|
confirmLabel: "Move"
|
|
@@ -5401,7 +5620,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5401
5620
|
const give = async () => {
|
|
5402
5621
|
const to = email.trim();
|
|
5403
5622
|
if (!isEmail(to)) return;
|
|
5404
|
-
const ok = await (0,
|
|
5623
|
+
const ok = await (0, import_confirm_opener8.confirm)({ title: "Give ownership away?", description: giveDescription(item, to), confirmLabel: "Give ownership", variant: "destructive" });
|
|
5405
5624
|
if (!ok) return;
|
|
5406
5625
|
const out = await run("give", () => port.sharing.giveOwnership(item, to));
|
|
5407
5626
|
if (!out) return;
|
|
@@ -5414,25 +5633,25 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5414
5633
|
if (made) onChanged();
|
|
5415
5634
|
};
|
|
5416
5635
|
const nothing = !canMove && !canGive && !canCopy;
|
|
5417
|
-
return /* @__PURE__ */ (0,
|
|
5636
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
5418
5637
|
Panel,
|
|
5419
5638
|
{
|
|
5420
5639
|
title: "Move or copy",
|
|
5421
5640
|
size: "md",
|
|
5422
5641
|
onClose,
|
|
5423
|
-
footer: /* @__PURE__ */ (0,
|
|
5424
|
-
children: nothing ? /* @__PURE__ */ (0,
|
|
5425
|
-
canMove && moves.length > 0 ? /* @__PURE__ */ (0,
|
|
5642
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(PanelFooter, { status: error || notice ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Button, { variant: "primary", onClick: onClose, children: "Done" }) }),
|
|
5643
|
+
children: nothing ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Empty, { children: passkey ? "A passkey stays where it was created." : "Only the owner can move or give this item." }) }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(VaultSection, { children: [
|
|
5644
|
+
canMove && moves.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
5426
5645
|
VaultRow,
|
|
5427
5646
|
{
|
|
5428
5647
|
label: "Move to",
|
|
5429
5648
|
hint: moveChoice ? itemMoveConsequence(item, destinationOf(moveChoice.value)) : void 0,
|
|
5430
|
-
actions: /* @__PURE__ */ (0,
|
|
5431
|
-
children: /* @__PURE__ */ (0,
|
|
5649
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Button, { variant: "outline", disabled: busy !== null || !moveChoice, onClick: () => void move(), children: "Move" }),
|
|
5650
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Select, { className: "w-full", "aria-label": "Move to", value: moveTo || NONE, onValueChange: (v) => setMoveTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...moves] })
|
|
5432
5651
|
}
|
|
5433
5652
|
) : null,
|
|
5434
|
-
canGive ? /* @__PURE__ */ (0,
|
|
5435
|
-
|
|
5653
|
+
canGive ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(VaultRow, { label: "Give to", hint: "You lose all access; your shares end", actions: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Button, { variant: "danger", disabled: busy !== null || !isEmail(email), onClick: () => void give(), children: "Give" }), children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
5654
|
+
import_controls20.Field,
|
|
5436
5655
|
{
|
|
5437
5656
|
className: "w-full",
|
|
5438
5657
|
type: "email",
|
|
@@ -5445,20 +5664,20 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5445
5664
|
onChange: (e) => setEmail(e.target.value)
|
|
5446
5665
|
}
|
|
5447
5666
|
) }) : null,
|
|
5448
|
-
canCopy && copies.length > 0 ? /* @__PURE__ */ (0,
|
|
5667
|
+
canCopy && copies.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(VaultRow, { label: "Copy to", hint: "A separate item; edits no longer sync", actions: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Button, { variant: "outline", disabled: busy !== null || !copyChoice, onClick: () => void copy(), children: "Copy" }), children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Select, { className: "w-full", "aria-label": "Copy to", value: copyTo || NONE, onValueChange: (v) => setCopyTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...copies] }) }) : null
|
|
5449
5668
|
] })
|
|
5450
5669
|
}
|
|
5451
5670
|
);
|
|
5452
5671
|
}
|
|
5453
5672
|
|
|
5454
5673
|
// src/sharing/SharePanel.tsx
|
|
5455
|
-
var
|
|
5674
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
5456
5675
|
function useGrants(port, item) {
|
|
5457
|
-
const [grants, setGrants] = (0,
|
|
5458
|
-
const [loadError, setLoadError] = (0,
|
|
5459
|
-
const [nonce, setNonce] = (0,
|
|
5676
|
+
const [grants, setGrants] = (0, import_react27.useState)(null);
|
|
5677
|
+
const [loadError, setLoadError] = (0, import_react27.useState)(null);
|
|
5678
|
+
const [nonce, setNonce] = (0, import_react27.useState)(0);
|
|
5460
5679
|
const allowed = item.capabilities.canManage;
|
|
5461
|
-
(0,
|
|
5680
|
+
(0, import_react27.useEffect)(() => {
|
|
5462
5681
|
if (!allowed) return;
|
|
5463
5682
|
let live = true;
|
|
5464
5683
|
setLoadError(null);
|
|
@@ -5475,9 +5694,9 @@ function useGrants(port, item) {
|
|
|
5475
5694
|
function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
5476
5695
|
const { grants, setGrants, loadError, reload } = useGrants(port, item);
|
|
5477
5696
|
const { busy, error, notice, run } = useConfirmedChange();
|
|
5478
|
-
const [email, setEmail] = (0,
|
|
5479
|
-
const [level, setLevel] = (0,
|
|
5480
|
-
const [more, setMore] = (0,
|
|
5697
|
+
const [email, setEmail] = (0, import_react27.useState)("");
|
|
5698
|
+
const [level, setLevel] = (0, import_react27.useState)("use");
|
|
5699
|
+
const [more, setMore] = (0, import_react27.useState)(false);
|
|
5481
5700
|
const isOrg = item.owner.kind === "organization" && item.owner.organizationId !== null;
|
|
5482
5701
|
const orgName = item.owner.label;
|
|
5483
5702
|
const people = (grants ?? []).filter((g) => g.kind === "person");
|
|
@@ -5496,7 +5715,7 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5496
5715
|
if (updated) setGrants((all) => (all ?? []).map((x) => x.id === g.id ? { ...updated, label: updated.label || g.label } : x));
|
|
5497
5716
|
};
|
|
5498
5717
|
const revoke = async (g) => {
|
|
5499
|
-
const ok = await (0,
|
|
5718
|
+
const ok = await (0, import_confirm_opener9.confirm)({
|
|
5500
5719
|
title: g.kind === "organization" ? `Remove from ${g.label}?` : "Remove access?",
|
|
5501
5720
|
description: g.kind === "organization" ? `${g.label} members can no longer use "${item.name}". It stays in your vault.` : `${g.label} can no longer use "${item.name}". This takes effect at once.`,
|
|
5502
5721
|
confirmLabel: "Remove",
|
|
@@ -5512,7 +5731,7 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5512
5731
|
const setMode = async (mode) => {
|
|
5513
5732
|
if (mode === (item.accessMode === "restricted" ? "restricted" : "all_members")) return;
|
|
5514
5733
|
if (mode === "all_members" && people.length > 0) {
|
|
5515
|
-
const ok = await (0,
|
|
5734
|
+
const ok = await (0, import_confirm_opener9.confirm)({
|
|
5516
5735
|
title: "Open to every member?",
|
|
5517
5736
|
description: `Every member of ${orgName} gets it at their own vault access. The ${people.length === 1 ? "person" : `${people.length} people`} listed here lose their own access.`,
|
|
5518
5737
|
confirmLabel: "Open to members",
|
|
@@ -5527,20 +5746,20 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5527
5746
|
}
|
|
5528
5747
|
};
|
|
5529
5748
|
if (!item.capabilities.canManage) {
|
|
5530
|
-
return /* @__PURE__ */ (0,
|
|
5749
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Panel, { title: "Share", size: "md", onClose, footer: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_controls21.Button, { variant: "primary", onClick: onClose, children: "Done" }), children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Empty, { children: "Only the owner can change who has access." }) }) });
|
|
5531
5750
|
}
|
|
5532
|
-
return /* @__PURE__ */ (0,
|
|
5751
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
5533
5752
|
Panel,
|
|
5534
5753
|
{
|
|
5535
5754
|
title: "Share",
|
|
5536
5755
|
size: "md",
|
|
5537
5756
|
onClose,
|
|
5538
|
-
footer: /* @__PURE__ */ (0,
|
|
5757
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(PanelFooter, { status: error || notice ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_controls21.Button, { variant: "primary", onClick: onClose, children: "Done" }) }),
|
|
5539
5758
|
children: [
|
|
5540
|
-
/* @__PURE__ */ (0,
|
|
5541
|
-
isOrg ? /* @__PURE__ */ (0,
|
|
5542
|
-
isOrg ? /* @__PURE__ */ (0,
|
|
5543
|
-
|
|
5759
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(VaultSection, { title: "Who has access", children: [
|
|
5760
|
+
isOrg ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AccessLine, { glyph: BuildingGlyph, who: `${orgName} admins`, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "px-2 text-sm text-muted-foreground", children: "Full access" }) }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AccessLine, { glyph: PersonGlyph, who: "You", meta: "Owner", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "px-2 text-sm text-muted-foreground", children: "Full access" }) }),
|
|
5761
|
+
isOrg ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AccessLine, { glyph: import_icons10.UsersIcon, who: `${orgName} members`, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
5762
|
+
import_controls21.Select,
|
|
5544
5763
|
{
|
|
5545
5764
|
variant: "inline",
|
|
5546
5765
|
align: "end",
|
|
@@ -5554,14 +5773,14 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5554
5773
|
]
|
|
5555
5774
|
}
|
|
5556
5775
|
) }) : null,
|
|
5557
|
-
loadError ? /* @__PURE__ */ (0,
|
|
5558
|
-
/* @__PURE__ */ (0,
|
|
5559
|
-
/* @__PURE__ */ (0,
|
|
5776
|
+
loadError ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AccessLine, { glyph: XGlyph, who: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-destructive", children: loadError }), children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_controls21.Button, { variant: "quiet", onClick: reload, children: "Retry" }) }) : grants === null ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_controls21.RegionSkeleton, { shape: "rows", count: 2, "aria-label": "Loading who has access", className: "px-3 sm:px-4" }) : grants.map((g) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(AccessLine, { glyph: g.kind === "organization" ? BuildingGlyph : PersonGlyph, who: g.label, ...g.kind === "organization" ? { meta: "Organization vault" } : {}, children: [
|
|
5777
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_controls21.Select, { variant: "inline", align: "end", "aria-label": `What ${g.label} can do`, disabled: busy !== null, value: g.level, onValueChange: (v) => void change(g, v), options: LEVEL_OPTIONS }),
|
|
5778
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_controls21.Button, { variant: "quiet", removes: true, icon: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(XGlyph, {}), "aria-label": `Remove ${g.label}`, disabled: busy !== null, onClick: () => void revoke(g) })
|
|
5560
5779
|
] }, g.id)),
|
|
5561
|
-
/* @__PURE__ */ (0,
|
|
5562
|
-
/* @__PURE__ */ (0,
|
|
5563
|
-
/* @__PURE__ */ (0,
|
|
5564
|
-
|
|
5780
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
|
|
5781
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(PersonGlyph, { className: "size-4 shrink-0 text-muted-foreground" }),
|
|
5782
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
5783
|
+
import_controls21.Field,
|
|
5565
5784
|
{
|
|
5566
5785
|
className: "min-w-0 flex-1",
|
|
5567
5786
|
type: "email",
|
|
@@ -5581,13 +5800,13 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5581
5800
|
}
|
|
5582
5801
|
}
|
|
5583
5802
|
),
|
|
5584
|
-
/* @__PURE__ */ (0,
|
|
5585
|
-
/* @__PURE__ */ (0,
|
|
5803
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_controls21.Select, { variant: "inline", align: "end", "aria-label": "What they can do", value: level, onValueChange: setLevel, options: LEVEL_OPTIONS }),
|
|
5804
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_controls21.Button, { variant: "primary", disabled: busy !== null || !isEmail(email), onClick: () => void add(), children: "Share" })
|
|
5586
5805
|
] })
|
|
5587
5806
|
] }),
|
|
5588
|
-
/* @__PURE__ */ (0,
|
|
5589
|
-
/* @__PURE__ */ (0,
|
|
5590
|
-
more ? isOrg && item.owner.organizationId ? /* @__PURE__ */ (0,
|
|
5807
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-3", children: [
|
|
5808
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_controls21.DisclosureHeader, { open: more, title: "More options", onClick: () => setMore((o) => !o) }),
|
|
5809
|
+
more ? isOrg && item.owner.organizationId ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(MemberAccess, { port, organizationId: item.owner.organizationId, organizationName: orgName }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(IntoOrganization, { item, port, organizations, grants: grants ?? [], onShared: (g) => setGrants((all) => [...(all ?? []).filter((x) => x.id !== g.id), g]) }) : null
|
|
5591
5810
|
] })
|
|
5592
5811
|
]
|
|
5593
5812
|
}
|
|
@@ -5596,17 +5815,17 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5596
5815
|
function IntoOrganization({ item, port, organizations, grants, onShared }) {
|
|
5597
5816
|
const { busy, error, notice, run } = useConfirmedChange();
|
|
5598
5817
|
const open = organizations.filter((o) => !grants.some((g) => g.organizationId === o.id));
|
|
5599
|
-
const [target, setTarget] = (0,
|
|
5600
|
-
const [level, setLevel] = (0,
|
|
5818
|
+
const [target, setTarget] = (0, import_react27.useState)("");
|
|
5819
|
+
const [level, setLevel] = (0, import_react27.useState)("use");
|
|
5601
5820
|
const chosen = open.find((o) => o.id === target);
|
|
5602
5821
|
if (item.owner.kind !== "me") return null;
|
|
5603
|
-
return /* @__PURE__ */ (0,
|
|
5604
|
-
/* @__PURE__ */ (0,
|
|
5605
|
-
/* @__PURE__ */ (0,
|
|
5606
|
-
/* @__PURE__ */ (0,
|
|
5607
|
-
/* @__PURE__ */ (0,
|
|
5608
|
-
/* @__PURE__ */ (0,
|
|
5609
|
-
|
|
5822
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VaultSection, { title: "Share into organization", children: open.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
|
|
5823
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
|
|
5824
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(BuildingGlyph, { className: "size-4 shrink-0 text-muted-foreground" }),
|
|
5825
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_controls21.Select, { className: "min-w-0 flex-1", "aria-label": "Organization", value: target || "__none__", onValueChange: (v) => setTarget(v === "__none__" ? "" : v), options: [{ value: "__none__", label: "Choose an organization" }, ...open.map((o) => ({ value: o.id, label: o.name }))] }),
|
|
5826
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_controls21.Select, { variant: "inline", align: "end", "aria-label": "What its members can do", value: level, onValueChange: setLevel, options: LEVEL_OPTIONS }),
|
|
5827
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
5828
|
+
import_controls21.Button,
|
|
5610
5829
|
{
|
|
5611
5830
|
variant: "outline",
|
|
5612
5831
|
disabled: busy !== null || !chosen,
|
|
@@ -5622,8 +5841,8 @@ function IntoOrganization({ item, port, organizations, grants, onShared }) {
|
|
|
5622
5841
|
}
|
|
5623
5842
|
)
|
|
5624
5843
|
] }),
|
|
5625
|
-
/* @__PURE__ */ (0,
|
|
5626
|
-
] }) : /* @__PURE__ */ (0,
|
|
5844
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "truncate px-3 pb-1 text-xs text-muted-foreground sm:px-4", children: error ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-destructive", children: error }) : notice ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-success", children: notice }) : "It stays yours; its members can use it too" })
|
|
5845
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Empty, { children: organizations.length ? "Already in every organization you belong to." : "You are not in any organization." }) });
|
|
5627
5846
|
}
|
|
5628
5847
|
var CHOICES = [
|
|
5629
5848
|
{ value: MEMBER_CHOICE_DEFAULT, label: "Default" },
|
|
@@ -5632,10 +5851,10 @@ var CHOICES = [
|
|
|
5632
5851
|
{ value: "editor", label: "Can edit", meta: "See and change" }
|
|
5633
5852
|
];
|
|
5634
5853
|
function MemberAccess({ port, organizationId, organizationName }) {
|
|
5635
|
-
const [list, setList] = (0,
|
|
5636
|
-
const [loadError, setLoadError] = (0,
|
|
5854
|
+
const [list, setList] = (0, import_react27.useState)(null);
|
|
5855
|
+
const [loadError, setLoadError] = (0, import_react27.useState)(null);
|
|
5637
5856
|
const { busy, error, run } = useConfirmedChange();
|
|
5638
|
-
(0,
|
|
5857
|
+
(0, import_react27.useEffect)(() => {
|
|
5639
5858
|
let live = true;
|
|
5640
5859
|
port.sharing.memberAccess(organizationId).then(
|
|
5641
5860
|
(l) => live && setList(l),
|
|
@@ -5650,9 +5869,9 @@ function MemberAccess({ port, organizationId, organizationName }) {
|
|
|
5650
5869
|
const effective = await run(userId, () => port.sharing.setMemberAccess(organizationId, userId, access));
|
|
5651
5870
|
if (effective) setList((l) => l ? { ...l, members: l.members.map((m) => m.userId === userId ? { ...m, access, effective } : m) } : l);
|
|
5652
5871
|
};
|
|
5653
|
-
return /* @__PURE__ */ (0,
|
|
5654
|
-
loadError ? /* @__PURE__ */ (0,
|
|
5655
|
-
|
|
5872
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(VaultSection, { title: `${organizationName} vault access`, children: [
|
|
5873
|
+
loadError ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Empty, { children: loadError }) : list === null ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_controls21.RegionSkeleton, { shape: "rows", count: 3, "aria-label": "Loading member access", className: "px-3 sm:px-4" }) : list.members.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Empty, { children: "No members yet." }) : list.members.map((m) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AccessLine, { glyph: PersonGlyph, who: m.email || m.userId, meta: m.role, children: m.effective === "admin" ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "px-2 text-sm text-muted-foreground", children: MEMBER_ACCESS_LABEL.admin }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
5874
|
+
import_controls21.Select,
|
|
5656
5875
|
{
|
|
5657
5876
|
variant: "inline",
|
|
5658
5877
|
align: "end",
|
|
@@ -5663,13 +5882,13 @@ function MemberAccess({ port, organizationId, organizationName }) {
|
|
|
5663
5882
|
options: CHOICES.map((c) => c.value === MEMBER_CHOICE_DEFAULT ? { value: c.value, label: `Default (${MEMBER_ACCESS_LABEL[list.defaultAccess]})` } : c.meta ? { value: c.value, label: c.label, meta: c.meta } : { value: c.value, label: c.label })
|
|
5664
5883
|
}
|
|
5665
5884
|
) }, m.userId)),
|
|
5666
|
-
/* @__PURE__ */ (0,
|
|
5885
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "truncate px-3 pb-1 text-xs text-muted-foreground sm:px-4", children: error ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-destructive", children: error }) : "Applies to every item in this organization" })
|
|
5667
5886
|
] });
|
|
5668
5887
|
}
|
|
5669
5888
|
function SharingSummary({ item, port, className }) {
|
|
5670
|
-
const [text, setText] = (0,
|
|
5889
|
+
const [text, setText] = (0, import_react27.useState)("");
|
|
5671
5890
|
const allowed = item.capabilities.canManage;
|
|
5672
|
-
(0,
|
|
5891
|
+
(0, import_react27.useEffect)(() => {
|
|
5673
5892
|
if (!allowed) return;
|
|
5674
5893
|
let live = true;
|
|
5675
5894
|
port.sharing.grants(item).then(
|
|
@@ -5681,12 +5900,12 @@ function SharingSummary({ item, port, className }) {
|
|
|
5681
5900
|
};
|
|
5682
5901
|
}, [port, item, allowed]);
|
|
5683
5902
|
if (!allowed || !text) return null;
|
|
5684
|
-
return /* @__PURE__ */ (0,
|
|
5903
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: (0, import_design_system16.cn)("truncate text-xs text-muted-foreground", className), children: text });
|
|
5685
5904
|
}
|
|
5686
5905
|
|
|
5687
5906
|
// src/ItemPane.tsx
|
|
5688
5907
|
var import_format8 = require("@ai-matrx/kit/format");
|
|
5689
|
-
var
|
|
5908
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
5690
5909
|
var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
|
|
5691
5910
|
function ItemPane(props) {
|
|
5692
5911
|
const { port, item, definition, mode, host, organizations, defaultOwner, seed, onBack, onMode, onSaved, onDeleted, onDirty, onCancelNew, onPanel, onChanged, favorite, notice, refreshKey } = props;
|
|
@@ -5695,8 +5914,8 @@ function ItemPane(props) {
|
|
|
5695
5914
|
const editing = mode !== "view";
|
|
5696
5915
|
const seedName = seed?.name ?? "";
|
|
5697
5916
|
const seedUrl = seed?.url ?? "";
|
|
5698
|
-
const [loaded, setLoaded] = (0,
|
|
5699
|
-
const base = (0,
|
|
5917
|
+
const [loaded, setLoaded] = (0, import_react28.useState)({});
|
|
5918
|
+
const base = (0, import_react28.useMemo)(() => {
|
|
5700
5919
|
const b = draftOf(item);
|
|
5701
5920
|
if (!item) {
|
|
5702
5921
|
b.name = seedName;
|
|
@@ -5705,24 +5924,27 @@ function ItemPane(props) {
|
|
|
5705
5924
|
b.values = { ...loaded };
|
|
5706
5925
|
return b;
|
|
5707
5926
|
}, [item, seedName, seedUrl, loaded]);
|
|
5708
|
-
const [draft, setDraft] = (0,
|
|
5709
|
-
const [tagsText, setTagsText] = (0,
|
|
5710
|
-
const [showTags, setShowTags] = (0,
|
|
5711
|
-
const [showDescription, setShowDescription] = (0,
|
|
5712
|
-
const [showRecovery, setShowRecovery] = (0,
|
|
5713
|
-
const [settingUpOtp, setSettingUpOtp] = (0,
|
|
5714
|
-
const [owner, setOwner] = (0,
|
|
5715
|
-
const [recipient, setRecipient] = (0,
|
|
5716
|
-
const [generatePrivately, setGeneratePrivately] = (0,
|
|
5717
|
-
const [busy, setBusy] = (0,
|
|
5718
|
-
const [
|
|
5719
|
-
const [
|
|
5927
|
+
const [draft, setDraft] = (0, import_react28.useState)(base);
|
|
5928
|
+
const [tagsText, setTagsText] = (0, import_react28.useState)(base.tags.join(", "));
|
|
5929
|
+
const [showTags, setShowTags] = (0, import_react28.useState)(false);
|
|
5930
|
+
const [showDescription, setShowDescription] = (0, import_react28.useState)(false);
|
|
5931
|
+
const [showRecovery, setShowRecovery] = (0, import_react28.useState)(false);
|
|
5932
|
+
const [settingUpOtp, setSettingUpOtp] = (0, import_react28.useState)(false);
|
|
5933
|
+
const [owner, setOwner] = (0, import_react28.useState)(defaultOwner ?? "me");
|
|
5934
|
+
const [recipient, setRecipient] = (0, import_react28.useState)("");
|
|
5935
|
+
const [generatePrivately, setGeneratePrivately] = (0, import_react28.useState)(false);
|
|
5936
|
+
const [busy, setBusy] = (0, import_react28.useState)(false);
|
|
5937
|
+
const [sent, setSent] = (0, import_react28.useState)(null);
|
|
5938
|
+
const [queuedFiles, setQueuedFiles] = (0, import_react28.useState)([]);
|
|
5939
|
+
const [showBrowser, setShowBrowser] = (0, import_react28.useState)(false);
|
|
5940
|
+
const [error, setError] = (0, import_react28.useState)(null);
|
|
5941
|
+
const [destinations, setDestinations] = (0, import_react28.useState)({});
|
|
5720
5942
|
const dirty = editing && isDirty(base, draft);
|
|
5721
5943
|
const declared = definition?.fields ?? [];
|
|
5722
|
-
const prev = (0,
|
|
5723
|
-
const paneRef = (0,
|
|
5944
|
+
const prev = (0, import_react28.useRef)(null);
|
|
5945
|
+
const paneRef = (0, import_react28.useRef)(null);
|
|
5724
5946
|
const room = useRoomOf(paneRef);
|
|
5725
|
-
(0,
|
|
5947
|
+
(0, import_react28.useEffect)(() => {
|
|
5726
5948
|
const was = prev.current;
|
|
5727
5949
|
const id = item?.id ?? null;
|
|
5728
5950
|
if (was && was.id === id && was.mode === mode && editing) {
|
|
@@ -5735,19 +5957,19 @@ function ItemPane(props) {
|
|
|
5735
5957
|
}
|
|
5736
5958
|
prev.current = { base, id, mode };
|
|
5737
5959
|
}, [base, mode, item?.id, editing]);
|
|
5738
|
-
(0,
|
|
5960
|
+
(0, import_react28.useEffect)(() => {
|
|
5739
5961
|
setLoaded({});
|
|
5740
5962
|
setShowTags(false);
|
|
5741
5963
|
setShowDescription(false);
|
|
5742
5964
|
setShowRecovery(false);
|
|
5743
5965
|
}, [item?.id, mode]);
|
|
5744
|
-
(0,
|
|
5966
|
+
(0, import_react28.useEffect)(() => onDirty(dirty), [dirty, onDirty]);
|
|
5745
5967
|
const keepKey = draftKey(item?.id ?? null, definition?.key ?? item?.definitionKey ?? null);
|
|
5746
|
-
(0,
|
|
5968
|
+
(0, import_react28.useEffect)(() => {
|
|
5747
5969
|
if (editing && dirty) (0, import_drafts.keepDraft)(keepKey, keptFieldsOf(draft), { basedOn: item?.updatedAt ?? "new" });
|
|
5748
5970
|
else if (!editing) (0, import_drafts.dropKeptDraft)(keepKey);
|
|
5749
5971
|
}, [editing, dirty, draft, keepKey, item?.updatedAt]);
|
|
5750
|
-
(0,
|
|
5972
|
+
(0, import_react28.useEffect)(() => {
|
|
5751
5973
|
if (!editing || !item) return;
|
|
5752
5974
|
let live = true;
|
|
5753
5975
|
for (const f of item.fields) {
|
|
@@ -5789,10 +6011,13 @@ function ItemPane(props) {
|
|
|
5789
6011
|
const secretKey = declared.find((f) => f.storage === "encrypted" && f.kind === "secret")?.key ?? null;
|
|
5790
6012
|
const r = await port.sharing.assign({ recipientEmail: recipient.trim(), definition, draft: out, generateFieldKey: generatePrivately ? secretKey : null });
|
|
5791
6013
|
notify(`Sent to ${r.recipientEmail}`);
|
|
5792
|
-
|
|
6014
|
+
(0, import_drafts.dropKeptDraft)(keepKey);
|
|
6015
|
+
onDirty(false);
|
|
6016
|
+
setSent(r);
|
|
5793
6017
|
} else if (definition) {
|
|
5794
6018
|
const r = await port.create(definition, owner === "me" ? null : owner, out);
|
|
5795
|
-
const [
|
|
6019
|
+
const [withCode, n0, enrolled] = await withOtp(r.item, r.notice);
|
|
6020
|
+
const [next, n] = await storeQueuedFiles(withCode, n0);
|
|
5796
6021
|
(0, import_drafts.dropKeptDraft)(keepKey);
|
|
5797
6022
|
onSaved(next, true, n, enrolled);
|
|
5798
6023
|
}
|
|
@@ -5802,9 +6027,32 @@ function ItemPane(props) {
|
|
|
5802
6027
|
setBusy(false);
|
|
5803
6028
|
}
|
|
5804
6029
|
}
|
|
6030
|
+
async function storeQueuedFiles(saved, notice2) {
|
|
6031
|
+
let next = saved;
|
|
6032
|
+
const failed = [];
|
|
6033
|
+
for (const q of queuedFiles) {
|
|
6034
|
+
try {
|
|
6035
|
+
next = await confirmed(() => port.activity.addFile(next, q.file, { label: q.label, description: q.description, handling: q.handling }));
|
|
6036
|
+
} catch {
|
|
6037
|
+
failed.push(q.label);
|
|
6038
|
+
}
|
|
6039
|
+
}
|
|
6040
|
+
setQueuedFiles([]);
|
|
6041
|
+
if (failed.length === 0) return [next, notice2];
|
|
6042
|
+
const said = `Saved, but ${failed.length === 1 ? `the file ${failed[0]} was` : `${failed.length} files were`} not stored. Add ${failed.length === 1 ? "it" : "them"} with Add file.`;
|
|
6043
|
+
return [next, notice2 ? `${notice2} ${said}` : said];
|
|
6044
|
+
}
|
|
6045
|
+
function createAnother() {
|
|
6046
|
+
setSent(null);
|
|
6047
|
+
setDraft(base);
|
|
6048
|
+
setTagsText(base.tags.join(", "));
|
|
6049
|
+
setQueuedFiles([]);
|
|
6050
|
+
setShowBrowser(false);
|
|
6051
|
+
setError(null);
|
|
6052
|
+
}
|
|
5805
6053
|
async function remove() {
|
|
5806
6054
|
if (!item) return;
|
|
5807
|
-
const ok = await (0,
|
|
6055
|
+
const ok = await (0, import_confirm_opener10.confirm)({ title: `Delete \u201C${item.name}\u201D?`, description: "It moves to Trash. You can restore it from there.", confirmLabel: "Delete", variant: "destructive" });
|
|
5808
6056
|
if (!ok) return;
|
|
5809
6057
|
setBusy(true);
|
|
5810
6058
|
try {
|
|
@@ -5845,6 +6093,7 @@ function ItemPane(props) {
|
|
|
5845
6093
|
onChanged();
|
|
5846
6094
|
}
|
|
5847
6095
|
}
|
|
6096
|
+
const fieldSettings = (f) => canEdit ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SlidersGlyph, {}), "aria-label": `${f.label} settings`, title: `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) }) : null;
|
|
5848
6097
|
const turnOnOne = canTurnOn ? (f) => () => turnOn([f]) : () => void 0;
|
|
5849
6098
|
const declaredKeys = new Set(declared.map((f) => f.key));
|
|
5850
6099
|
const extraFields = (item?.fields ?? []).filter((f) => !declaredKeys.has(f.key) && !draft.removed.includes(f.id) && !isAuthenticatorStorage(f.key));
|
|
@@ -5857,35 +6106,35 @@ function ItemPane(props) {
|
|
|
5857
6106
|
const recoveryExtra = extraFields.some(isRecoveryCodesField);
|
|
5858
6107
|
const offerRecovery = isLogin || Boolean(item?.authenticator) || draft.authenticator.trim() !== "";
|
|
5859
6108
|
const recoveryEditing = !recoveryDeclared && !recoveryExtra && (showRecovery || (draft.values[RECOVERY_CODES_KEY] ?? "") !== "");
|
|
5860
|
-
const shownOwner = mode === "new" ? owner === "me" ? { label: "Personal", glyph: /* @__PURE__ */ (0,
|
|
6109
|
+
const shownOwner = mode === "new" ? owner === "me" ? { label: "Personal", glyph: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(PersonGlyph, {}) } : owner === "person" ? { label: "Someone else", glyph: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SendGlyph, {}) } : { label: organizations.find((o) => o.id === owner)?.name ?? "Organization", glyph: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(BuildingGlyph, {}) } : item ? { label: item.owner.label, glyph: item.owner.kind === "me" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(PersonGlyph, {}) : item.owner.kind === "organization" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(BuildingGlyph, {}) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_icons11.UsersIcon, {}) } : null;
|
|
5861
6110
|
const sameNamed = (id) => {
|
|
5862
6111
|
const name = organizations.find((o) => o.id === id)?.name.trim().toLowerCase();
|
|
5863
6112
|
return Boolean(name) && organizations.filter((o) => o.name.trim().toLowerCase() === name).length > 1;
|
|
5864
6113
|
};
|
|
5865
6114
|
const tagsVisible = showTags || draft.tags.length > 0 || tagsText !== "";
|
|
5866
6115
|
const descriptionVisible = showDescription || draft.description !== "";
|
|
5867
|
-
const header = /* @__PURE__ */ (0,
|
|
5868
|
-
onBack ? /* @__PURE__ */ (0,
|
|
5869
|
-
/* @__PURE__ */ (0,
|
|
5870
|
-
/* @__PURE__ */ (0,
|
|
5871
|
-
/* @__PURE__ */ (0,
|
|
5872
|
-
/* @__PURE__ */ (0,
|
|
5873
|
-
typeLabel ? /* @__PURE__ */ (0,
|
|
5874
|
-
shownOwner ? /* @__PURE__ */ (0,
|
|
5875
|
-
item && !editing ? /* @__PURE__ */ (0,
|
|
6116
|
+
const header = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("header", { className: "flex min-h-14 items-center gap-2 border-b border-border px-3 py-2 sm:gap-3 sm:px-5", children: [
|
|
6117
|
+
onBack ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ChevronLeftGlyph, {}), "aria-label": "Back", onClick: mode === "new" ? onCancelNew : onBack }) : null,
|
|
6118
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ItemIcon, { definitionKey: definition?.key ?? item?.definitionKey ?? "custom", family: definition?.family ?? "generic", site: item ? loginSiteOf(item) : loginSiteOf({ loginUrls: draft.loginUrls }), size: "lg" }),
|
|
6119
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
6120
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { className: "truncate text-base font-semibold leading-tight", children: editing ? draft.name || (mode === "new" ? `New ${typeLabel.toLowerCase()}` : item?.name) : item?.name }),
|
|
6121
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "flex min-w-0 items-center gap-1 text-xs text-muted-foreground", children: [
|
|
6122
|
+
typeLabel ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "truncate", children: typeLabel }) : null,
|
|
6123
|
+
shownOwner ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Badge, { className: "shrink-0", icon: shownOwner.glyph, "aria-label": `Saved in ${shownOwner.label}`, children: shownOwner.label }) : null,
|
|
6124
|
+
item && !editing ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SharingSummary, { item, port, className: "hidden truncate before:mr-1 before:content-['\xB7'] sm:inline" }, `${item.updatedAt}-${refreshKey ?? ""}`) : null
|
|
5876
6125
|
] })
|
|
5877
6126
|
] }),
|
|
5878
|
-
editing ? /* @__PURE__ */ (0,
|
|
5879
|
-
dirty ? /* @__PURE__ */ (0,
|
|
5880
|
-
/* @__PURE__ */ (0,
|
|
6127
|
+
editing ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
6128
|
+
dirty ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "hidden items-center gap-1.5 text-xs text-muted-foreground sm:flex", role: "status", children: [
|
|
6129
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "size-1.5 rounded-full bg-warning", "aria-hidden": true }),
|
|
5881
6130
|
"Unsaved"
|
|
5882
6131
|
] }) : null,
|
|
5883
|
-
/* @__PURE__ */ (0,
|
|
5884
|
-
/* @__PURE__ */ (0,
|
|
5885
|
-
] }) : item ? /* @__PURE__ */ (0,
|
|
5886
|
-
host.page && canUseOnSite(item, host.page.url) ? /* @__PURE__ */ (0,
|
|
5887
|
-
host.fill && item.capabilities.canUse ? /* @__PURE__ */ (0,
|
|
5888
|
-
|
|
6132
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { variant: "quiet", disabled: busy, onClick: () => mode === "new" ? onCancelNew() : onMode("view"), children: dirty ? "Discard" : "Cancel" }),
|
|
6133
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { variant: "primary", disabled: busy || sent !== null || draft.name.trim() === "" || mode === "edit" && !dirty || mode === "new" && owner === "person" && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(recipient.trim()), onClick: () => void save(), children: mode === "new" && owner === "person" ? "Send" : "Save" })
|
|
6134
|
+
] }) : item ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
6135
|
+
host.page && canUseOnSite(item, host.page.url) ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(UseOnSiteButton, { port, item, pageUrl: host.page.url, onChanged: (next) => onChanged(next) }) : null,
|
|
6136
|
+
host.fill && item.capabilities.canUse ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
6137
|
+
import_controls22.Button,
|
|
5889
6138
|
{
|
|
5890
6139
|
variant: "primary",
|
|
5891
6140
|
onClick: () => void host.fill?.(item.id).then((outcome) => {
|
|
@@ -5895,44 +6144,44 @@ function ItemPane(props) {
|
|
|
5895
6144
|
children: "Fill"
|
|
5896
6145
|
}
|
|
5897
6146
|
) : null,
|
|
5898
|
-
favorite ? /* @__PURE__ */ (0,
|
|
5899
|
-
canManage ? /* @__PURE__ */ (0,
|
|
5900
|
-
canEdit ? /* @__PURE__ */ (0,
|
|
5901
|
-
/* @__PURE__ */ (0,
|
|
5902
|
-
/* @__PURE__ */ (0,
|
|
5903
|
-
/* @__PURE__ */ (0,
|
|
5904
|
-
favorite ? /* @__PURE__ */ (0,
|
|
5905
|
-
/* @__PURE__ */ (0,
|
|
6147
|
+
favorite ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "hidden sm:contents", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(StarGlyph, { className: favorite.on ? "fill-current text-warning" : "size-4" }), "aria-label": favorite.on ? "Remove from favorites" : "Add to favorites", pressed: favorite.on, onClick: favorite.toggle }) }) : null,
|
|
6148
|
+
canManage ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "hidden sm:contents", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ShareGlyph, {}), "aria-label": "Share", onClick: () => onPanel("share") }) }) : null,
|
|
6149
|
+
canEdit ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(PencilGlyph, {}), collapse: "container", "aria-label": "Edit", onClick: () => onMode("edit"), children: "Edit" }) : null,
|
|
6150
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenu, { children: [
|
|
6151
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_design_system17.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MoreGlyph, {}), "aria-label": "More actions" }) }),
|
|
6152
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuContent, { align: "end", children: [
|
|
6153
|
+
favorite ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { onSelect: favorite.toggle, children: [
|
|
6154
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(StarGlyph, { className: "size-4" }),
|
|
5906
6155
|
favorite.on ? "Remove from favorites" : "Add to favorites"
|
|
5907
6156
|
] }) : null,
|
|
5908
|
-
canManage ? /* @__PURE__ */ (0,
|
|
5909
|
-
/* @__PURE__ */ (0,
|
|
6157
|
+
canManage ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { onSelect: () => onPanel("share"), children: [
|
|
6158
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ShareGlyph, { className: "size-4" }),
|
|
5910
6159
|
"Share"
|
|
5911
6160
|
] }) : null,
|
|
5912
|
-
canManage ? /* @__PURE__ */ (0,
|
|
5913
|
-
/* @__PURE__ */ (0,
|
|
6161
|
+
canManage ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { onSelect: () => onPanel("move"), children: [
|
|
6162
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MoveGlyph, { className: "size-4" }),
|
|
5914
6163
|
"Move or copy"
|
|
5915
6164
|
] }) : null,
|
|
5916
|
-
item.capabilities.canReveal ? /* @__PURE__ */ (0,
|
|
5917
|
-
/* @__PURE__ */ (0,
|
|
6165
|
+
item.capabilities.canReveal ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { onSelect: () => onPanel("send"), children: [
|
|
6166
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SendGlyph, { className: "size-4" }),
|
|
5918
6167
|
"Send securely"
|
|
5919
6168
|
] }) : null,
|
|
5920
|
-
/* @__PURE__ */ (0,
|
|
5921
|
-
/* @__PURE__ */ (0,
|
|
6169
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { onSelect: () => onPanel("history"), children: [
|
|
6170
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_icons11.HistoryIcon, { className: "size-4" }),
|
|
5922
6171
|
"Password history"
|
|
5923
6172
|
] }),
|
|
5924
|
-
/* @__PURE__ */ (0,
|
|
5925
|
-
/* @__PURE__ */ (0,
|
|
6173
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { onSelect: () => onPanel("activity"), children: [
|
|
6174
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ListGlyph, { className: "size-4" }),
|
|
5926
6175
|
"Activity"
|
|
5927
6176
|
] }),
|
|
5928
|
-
canEdit ? /* @__PURE__ */ (0,
|
|
5929
|
-
/* @__PURE__ */ (0,
|
|
6177
|
+
canEdit ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { onSelect: () => onPanel("settings"), children: [
|
|
6178
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_icons11.SettingsIcon, { className: "size-4" }),
|
|
5930
6179
|
"Settings"
|
|
5931
6180
|
] }) : null,
|
|
5932
|
-
canManage ? /* @__PURE__ */ (0,
|
|
5933
|
-
/* @__PURE__ */ (0,
|
|
5934
|
-
/* @__PURE__ */ (0,
|
|
5935
|
-
/* @__PURE__ */ (0,
|
|
6181
|
+
canManage ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
6182
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_design_system17.DropdownMenuSeparator, {}),
|
|
6183
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { className: "text-destructive", disabled: busy, onSelect: () => void remove(), children: [
|
|
6184
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TrashGlyph, { className: "size-4" }),
|
|
5936
6185
|
"Delete"
|
|
5937
6186
|
] })
|
|
5938
6187
|
] }) : null
|
|
@@ -5941,18 +6190,18 @@ function ItemPane(props) {
|
|
|
5941
6190
|
] }) : null
|
|
5942
6191
|
] });
|
|
5943
6192
|
const filesProps = item ? { item, port, host, definition, organizations, arg: null, onClose: () => void 0, onChanged, onPanel } : null;
|
|
5944
|
-
return /* @__PURE__ */ (0,
|
|
6193
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(RoomProvider, { value: room, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("article", { ref: paneRef, "aria-label": item?.name ?? "New item", className: (0, import_design_system18.cn)(import_controls22.CONTROLS_CONTAINER_CLASS, "flex h-full min-h-0 flex-col bg-background"), children: [
|
|
5945
6194
|
header,
|
|
5946
|
-
error ? /* @__PURE__ */ (0,
|
|
5947
|
-
notice && !editing ? /* @__PURE__ */ (0,
|
|
5948
|
-
item && !editing && (itemOff || offFields.length > 0) ? /* @__PURE__ */ (0,
|
|
5949
|
-
/* @__PURE__ */ (0,
|
|
5950
|
-
canTurnOn ? /* @__PURE__ */ (0,
|
|
6195
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { role: "alert", className: "border-b border-border bg-muted px-5 py-2 text-sm text-destructive", children: error }) : null,
|
|
6196
|
+
notice && !editing ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { role: "status", className: "border-b border-border bg-muted px-5 py-2 text-sm text-warning", children: notice }) : null,
|
|
6197
|
+
item && !editing && (itemOff || offFields.length > 0) ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-5 py-2 text-sm", children: [
|
|
6198
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "min-w-0 flex-1 truncate text-warning", children: offFields.length === 0 ? "This item is turned off" : offFields.length === 1 ? "1 field is turned off" : `${offFields.length} fields are turned off` }),
|
|
6199
|
+
canTurnOn ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TurnOnButton, { label: "all fields", onTurnOn: () => turnOn(offFields) }) : null
|
|
5951
6200
|
] }) : null,
|
|
5952
|
-
/* @__PURE__ */ (0,
|
|
5953
|
-
/* @__PURE__ */ (0,
|
|
5954
|
-
mode === "new" ? /* @__PURE__ */ (0,
|
|
5955
|
-
|
|
6201
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto", children: sent ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AssignResult, { sent, onAnother: createAnother, onDone: onCancelNew }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5 px-3 py-4 sm:px-6 sm:py-6", children: editing ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
6202
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(VaultSection, { children: [
|
|
6203
|
+
mode === "new" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(VaultRow, { label: "Save to", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
6204
|
+
import_controls22.OptionCombobox,
|
|
5956
6205
|
{
|
|
5957
6206
|
value: owner,
|
|
5958
6207
|
onChange: setOwner,
|
|
@@ -5966,39 +6215,39 @@ function ItemPane(props) {
|
|
|
5966
6215
|
],
|
|
5967
6216
|
getLabel: (v) => v === "me" ? "Personal" : v === "person" ? "Someone else" : organizations.find((o) => o.id === v)?.name ?? v,
|
|
5968
6217
|
getHint: (v) => v === "me" ? "Only you" : v === "person" ? "Sent by email" : sameNamed(v) ? `ID ${v.slice(0, 8)}` : null,
|
|
5969
|
-
renderIcon: (v) => v === "me" ? /* @__PURE__ */ (0,
|
|
6218
|
+
renderIcon: (v) => v === "me" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(PersonGlyph, { className: "size-4" }) : v === "person" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SendGlyph, { className: "size-4" }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(BuildingGlyph, { className: "size-4" })
|
|
5970
6219
|
}
|
|
5971
6220
|
) }) : null,
|
|
5972
|
-
/* @__PURE__ */ (0,
|
|
5973
|
-
mode === "new" && owner === "person" ? /* @__PURE__ */ (0,
|
|
5974
|
-
/* @__PURE__ */ (0,
|
|
5975
|
-
declared.some((f) => f.storage === "encrypted" && f.kind === "secret") ? /* @__PURE__ */ (0,
|
|
6221
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(EditRow, { label: "Name", value: draft.name, onChange: (v) => patch({ name: v }), placeholder: "Name", autoFocus: mode === "new" }),
|
|
6222
|
+
mode === "new" && owner === "person" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
6223
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(EditRow, { label: "Their email", value: recipient, placeholder: "name@company.com", inputMode: "email", onChange: setRecipient }),
|
|
6224
|
+
declared.some((f) => f.storage === "encrypted" && f.kind === "secret") ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(VaultRow, { label: "Password", hint: "You never see it", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Switch, { checked: generatePrivately, onCheckedChange: setGeneratePrivately, "aria-label": "Generate the password privately" }) }) : null
|
|
5976
6225
|
] }) : null,
|
|
5977
6226
|
declared.map((f) => {
|
|
5978
6227
|
const existing = item?.fields.find((x) => x.key === f.key);
|
|
5979
6228
|
const secretKind = f.storage === "encrypted" && f.kind === "secret";
|
|
5980
6229
|
const value = f.storage === "metadata" ? metaValue(f.key) : draft.values[f.key] ?? "";
|
|
5981
6230
|
const hidden = existing && existing.handling !== "visible" && !(f.key in loaded);
|
|
5982
|
-
return /* @__PURE__ */ (0,
|
|
6231
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
5983
6232
|
EditRow,
|
|
5984
6233
|
{
|
|
5985
6234
|
label: f.label,
|
|
5986
6235
|
value,
|
|
5987
|
-
placeholder: hidden ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : f.required ? "Required" : "",
|
|
6236
|
+
placeholder: hidden ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : f.required ? "Required" : isRecoveryCodesField(f) ? "Backup codes, one per line" : "",
|
|
5988
6237
|
secret: secretKind,
|
|
5989
6238
|
multiline: f.kind === "multiline",
|
|
5990
6239
|
inputMode: f.kind === "url" ? "url" : USERNAME_KEYS.test(f.key) ? "email" : "text",
|
|
5991
6240
|
onChange: (v) => setValue(f.key, v),
|
|
5992
|
-
actions: /* @__PURE__ */ (0,
|
|
5993
|
-
hidden && existing?.handling === "revealable" && item?.capabilities.canReveal ? /* @__PURE__ */ (0,
|
|
5994
|
-
secretKind ? /* @__PURE__ */ (0,
|
|
5995
|
-
existing ? /* @__PURE__ */ (0,
|
|
6241
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
6242
|
+
hidden && existing?.handling === "revealable" && item?.capabilities.canReveal ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
|
|
6243
|
+
secretKind ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(GenerateButton, { onUse: (v) => setValue(f.key, v) }) : null,
|
|
6244
|
+
existing ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_icons11.SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${existing.id}`) }) : null
|
|
5996
6245
|
] })
|
|
5997
6246
|
},
|
|
5998
6247
|
f.key
|
|
5999
6248
|
);
|
|
6000
6249
|
}),
|
|
6001
|
-
extraFields.map((f) => /* @__PURE__ */ (0,
|
|
6250
|
+
extraFields.map((f) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
6002
6251
|
EditRow,
|
|
6003
6252
|
{
|
|
6004
6253
|
label: f.label,
|
|
@@ -6009,18 +6258,18 @@ function ItemPane(props) {
|
|
|
6009
6258
|
onChange: (v) => setValue(f.key, v),
|
|
6010
6259
|
onRemove: () => patch({ removed: [...draft.removed, f.id] }),
|
|
6011
6260
|
removeLabel: `Delete ${f.label}`,
|
|
6012
|
-
actions: /* @__PURE__ */ (0,
|
|
6013
|
-
f.handling === "revealable" && !(f.key in loaded) && item?.capabilities.canReveal ? /* @__PURE__ */ (0,
|
|
6014
|
-
/* @__PURE__ */ (0,
|
|
6261
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
6262
|
+
f.handling === "revealable" && !(f.key in loaded) && item?.capabilities.canReveal ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
|
|
6263
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_icons11.SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) })
|
|
6015
6264
|
] })
|
|
6016
6265
|
},
|
|
6017
6266
|
f.id
|
|
6018
6267
|
)),
|
|
6019
|
-
draft.loginUrls.map((u, i) => /* @__PURE__ */ (0,
|
|
6268
|
+
draft.loginUrls.map((u, i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
6020
6269
|
EditRow,
|
|
6021
6270
|
{
|
|
6022
6271
|
label: i === 0 ? "Website" : `Website ${i + 1}`,
|
|
6023
|
-
hint: destinations[i] && destinations[i].tone !== "success" ? /* @__PURE__ */ (0,
|
|
6272
|
+
hint: destinations[i] && destinations[i].tone !== "success" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: destinations[i].tone === "destructive" ? "text-destructive" : "text-warning", children: destinations[i].message }) : void 0,
|
|
6024
6273
|
value: u,
|
|
6025
6274
|
autoFocus: i > 0 && u === "" && i === draft.loginUrls.length - 1,
|
|
6026
6275
|
placeholder: "https://",
|
|
@@ -6040,10 +6289,11 @@ function ItemPane(props) {
|
|
|
6040
6289
|
},
|
|
6041
6290
|
i
|
|
6042
6291
|
)),
|
|
6043
|
-
/* @__PURE__ */ (0,
|
|
6044
|
-
/* @__PURE__ */ (0,
|
|
6045
|
-
item && isLogin && !item.authenticator ? /* @__PURE__ */ (0,
|
|
6046
|
-
|
|
6292
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AddRow, { label: draft.loginUrls.length === 0 ? "Website" : "", onAdd: () => patch({ loginUrls: [...draft.loginUrls, ""] }), children: draft.loginUrls.length === 0 ? "Add website" : "Add another website" }),
|
|
6293
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }),
|
|
6294
|
+
item && isLogin && !item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TwoFactorMethodRow, { port, item, onChanged }) : null,
|
|
6295
|
+
!item && isLogin && draft.authenticator.trim() === "" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(DraftTwoFactorRow, { custom: draft.custom, onCustom: (custom) => patch({ custom }) }) : null,
|
|
6296
|
+
recoveryEditing ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
6047
6297
|
EditRow,
|
|
6048
6298
|
{
|
|
6049
6299
|
label: "Recovery codes",
|
|
@@ -6062,26 +6312,30 @@ function ItemPane(props) {
|
|
|
6062
6312
|
},
|
|
6063
6313
|
removeLabel: "Remove recovery codes"
|
|
6064
6314
|
}
|
|
6065
|
-
) : !recoveryDeclared && !recoveryExtra && offerRecovery ? /* @__PURE__ */ (0,
|
|
6315
|
+
) : !recoveryDeclared && !recoveryExtra && offerRecovery ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AddRow, { label: "Recovery codes", onAdd: () => setShowRecovery(true), children: "Add backup codes" }) : null
|
|
6066
6316
|
] }),
|
|
6067
|
-
/* @__PURE__ */ (0,
|
|
6068
|
-
/* @__PURE__ */ (0,
|
|
6317
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(EditRow, { label: "Notes", value: draft.notes, multiline: true, placeholder: "Anything worth remembering", onChange: (v) => patch({ notes: v }) }) }),
|
|
6318
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
6069
6319
|
VaultSection,
|
|
6070
6320
|
{
|
|
6071
6321
|
title: "More",
|
|
6072
|
-
actions: /* @__PURE__ */ (0,
|
|
6073
|
-
/* @__PURE__ */ (0,
|
|
6074
|
-
/* @__PURE__ */ (0,
|
|
6075
|
-
/* @__PURE__ */ (0,
|
|
6076
|
-
/* @__PURE__ */ (0,
|
|
6077
|
-
!tagsVisible ? /* @__PURE__ */ (0,
|
|
6078
|
-
!descriptionVisible ? /* @__PURE__ */ (0,
|
|
6079
|
-
|
|
6322
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenu, { children: [
|
|
6323
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_design_system17.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(PlusGlyph, {}), children: "Add" }) }),
|
|
6324
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuContent, { align: "end", children: [
|
|
6325
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_design_system17.DropdownMenuItem, { onSelect: () => patch({ secrets: [...draft.secrets, { key: "", label: "", value: "" }] }), children: "Secret field" }),
|
|
6326
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_design_system17.DropdownMenuItem, { onSelect: () => patch({ custom: [...draft.custom, { key: `custom_${draft.custom.length + 1}_${Date.now() % 1e5}`, label: "", value: "" }] }), children: "Text field" }),
|
|
6327
|
+
!tagsVisible ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_design_system17.DropdownMenuItem, { onSelect: () => setShowTags(true), children: "Tags" }) : null,
|
|
6328
|
+
!descriptionVisible ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_design_system17.DropdownMenuItem, { onSelect: () => setShowDescription(true), children: "Description" }) : null,
|
|
6329
|
+
mode === "new" && !showBrowser ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_design_system17.DropdownMenuItem, { onSelect: () => {
|
|
6330
|
+
setShowBrowser(true);
|
|
6331
|
+
if (!draft.browser) patch({ browser: defaultBrowserSettings(draft.loginUrls.some((u) => u.trim() !== "")) });
|
|
6332
|
+
}, children: "Browser settings" }) : null,
|
|
6333
|
+
!recoveryDeclared && !recoveryExtra && !recoveryEditing ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_design_system17.DropdownMenuItem, { onSelect: () => setShowRecovery(true), children: "Recovery codes" }) : null
|
|
6080
6334
|
] })
|
|
6081
6335
|
] }),
|
|
6082
6336
|
children: [
|
|
6083
|
-
descriptionVisible ? /* @__PURE__ */ (0,
|
|
6084
|
-
tagsVisible ? /* @__PURE__ */ (0,
|
|
6337
|
+
descriptionVisible ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(EditRow, { label: "Description", value: draft.description, placeholder: "What this is for", onChange: (v) => patch({ description: v }) }) : null,
|
|
6338
|
+
tagsVisible ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
6085
6339
|
EditRow,
|
|
6086
6340
|
{
|
|
6087
6341
|
label: "Tags",
|
|
@@ -6093,49 +6347,50 @@ function ItemPane(props) {
|
|
|
6093
6347
|
}
|
|
6094
6348
|
}
|
|
6095
6349
|
) : null,
|
|
6096
|
-
draft.
|
|
6097
|
-
|
|
6098
|
-
|
|
6350
|
+
mode === "new" && showBrowser && draft.browser ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(DraftBrowserRows, { value: draft.browser, hasWebsite: draft.loginUrls.some((u) => u.trim() !== ""), onChange: (browser) => patch({ browser }) }) : null,
|
|
6351
|
+
draft.secrets.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SecretBuilderRow, { field: s, onChange: (p) => setDraft((d) => ({ ...d, secrets: d.secrets.map((x, j) => j === i ? { ...x, ...p } : x) })), onRemove: () => patch({ secrets: draft.secrets.filter((_, j) => j !== i) }) }, `s${i}`)),
|
|
6352
|
+
extraCustom.map((c) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CustomEditRow, { label: c.label, value: c.value, secret: false, onLabel: (v) => patch({ custom: draft.custom.map((x) => x.key === c.key ? { ...x, label: v } : x) }), onValue: (v) => patch({ custom: draft.custom.map((x) => x.key === c.key ? { ...x, value: v } : x) }), onRemove: () => patch({ custom: draft.custom.filter((x) => x.key !== c.key) }) }, c.key)),
|
|
6353
|
+
!descriptionVisible && !tagsVisible && draft.secrets.length === 0 && extraCustom.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AddRow, { label: "Tags", onAdd: () => setShowTags(true), children: "Add tags" }) : null
|
|
6099
6354
|
]
|
|
6100
6355
|
}
|
|
6101
6356
|
),
|
|
6102
|
-
filesProps ? /* @__PURE__ */ (0,
|
|
6103
|
-
] }) : item ? /* @__PURE__ */ (0,
|
|
6104
|
-
/* @__PURE__ */ (0,
|
|
6357
|
+
filesProps ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FilesSection, { ...filesProps, editing: true }) : mode === "new" && owner !== "person" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(DraftFilesSection, { files: queuedFiles, onFiles: setQueuedFiles }) : null
|
|
6358
|
+
] }) : item ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
6359
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(VaultSection, { children: [
|
|
6105
6360
|
declared.map((f) => {
|
|
6106
6361
|
if (f.storage === "metadata") {
|
|
6107
6362
|
const v = metaValue(f.key);
|
|
6108
|
-
return v ? /* @__PURE__ */ (0,
|
|
6363
|
+
return v ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(PlainRow, { label: f.label, value: v, openUrl: host.openUrl }, f.key) : null;
|
|
6109
6364
|
}
|
|
6110
6365
|
const field = item.fields.find((x) => x.key === f.key);
|
|
6111
|
-
if (isRecoveryCodesField(f)) return /* @__PURE__ */ (0,
|
|
6112
|
-
return field ? /* @__PURE__ */ (0,
|
|
6366
|
+
if (isRecoveryCodesField(f)) return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(RecoveryCodesRow, { item, field, port, onChanged }, f.key);
|
|
6367
|
+
return field ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SecretRow, { port, item, field, onTurnOn: turnOnOne(field), extra: fieldSettings(field) }, field.id) : null;
|
|
6113
6368
|
}),
|
|
6114
|
-
extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ (0,
|
|
6115
|
-
item.loginUrls.length > 0 ? item.loginUrls.map((u, i) => /* @__PURE__ */ (0,
|
|
6116
|
-
item.authenticator ? /* @__PURE__ */ (0,
|
|
6369
|
+
extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(RecoveryCodesRow, { item, field: f, port, onChanged }, f.id) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SecretRow, { port, item, field: f, onTurnOn: turnOnOne(f), extra: fieldSettings(f) }, f.id)),
|
|
6370
|
+
item.loginUrls.length > 0 ? item.loginUrls.map((u, i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(PlainRow, { label: i === 0 ? "Website" : `Website ${i + 1}`, value: u, openUrl: host.openUrl }, `${u}-${i}`)) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AddRow, { label: "Website", onAdd: canEdit ? () => onMode("edit") : null, children: "Add website" }),
|
|
6371
|
+
item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TotpRow, { port, item, onChanged }) : seedField && !seedField.active ? (
|
|
6117
6372
|
// The secret is still there, only off: turning it on brings the codes back. Never "Set up",
|
|
6118
6373
|
// which would invite replacing a working two-factor secret.
|
|
6119
|
-
/* @__PURE__ */ (0,
|
|
6120
|
-
) : /* @__PURE__ */ (0,
|
|
6121
|
-
!recoveryDeclared && !recoveryExtra && offerRecovery ? /* @__PURE__ */ (0,
|
|
6122
|
-
!item.authenticator && item.custom.some((c) => c.key === MFA_METHOD_KEY && c.value) ? /* @__PURE__ */ (0,
|
|
6374
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(VaultRow, { label: "Authenticator", actions: canTurnOn ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TurnOnButton, { label: "Authenticator", onTurnOn: () => turnOn([seedField]) }) : null, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-muted-foreground", children: "Turned off" }) })
|
|
6375
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AddRow, { label: "Authenticator", onAdd: canEdit ? () => setSettingUpOtp(true) : null, children: "Set up" }),
|
|
6376
|
+
!recoveryDeclared && !recoveryExtra && offerRecovery ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(RecoveryCodesRow, { item, field: null, port, onChanged }) : null,
|
|
6377
|
+
!item.authenticator && item.custom.some((c) => c.key === MFA_METHOD_KEY && c.value) ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TwoFactorMethodRow, { port, item, onChanged }) : null
|
|
6123
6378
|
] }),
|
|
6124
|
-
/* @__PURE__ */ (0,
|
|
6125
|
-
item.description || item.tags.length > 0 || viewCustom.length > 0 ? /* @__PURE__ */ (0,
|
|
6126
|
-
item.description ? /* @__PURE__ */ (0,
|
|
6127
|
-
item.tags.length > 0 ? /* @__PURE__ */ (0,
|
|
6128
|
-
viewCustom.map((c) => /* @__PURE__ */ (0,
|
|
6379
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(VaultSection, { children: item.notes ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(PlainRow, { label: "Notes", value: item.notes, multiline: true }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AddRow, { label: "Notes", onAdd: canEdit ? () => onMode("edit") : null, children: "Add notes" }) }),
|
|
6380
|
+
item.description || item.tags.length > 0 || viewCustom.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(VaultSection, { title: "More", children: [
|
|
6381
|
+
item.description ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(PlainRow, { label: "Description", value: item.description }) : null,
|
|
6382
|
+
item.tags.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(VaultRow, { label: "Tags", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "flex flex-wrap gap-1", children: item.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "rounded-md bg-muted px-1.5 py-0.5 text-xs", children: t }, t)) }) }) : null,
|
|
6383
|
+
viewCustom.map((c) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(PlainRow, { label: c.label, value: c.value, openUrl: host.openUrl }, c.key))
|
|
6129
6384
|
] }) : null,
|
|
6130
|
-
filesProps ? /* @__PURE__ */ (0,
|
|
6131
|
-
/* @__PURE__ */ (0,
|
|
6385
|
+
filesProps ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FilesSection, { ...filesProps, editing: false }) : null,
|
|
6386
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("p", { className: (0, import_design_system18.cn)("px-1 text-xs text-muted-foreground"), children: [
|
|
6132
6387
|
"Modified ",
|
|
6133
6388
|
(0, import_format8.formatAbsoluteDate)(item.updatedAt, DAY_FORMAT, ""),
|
|
6134
6389
|
" \xB7 Created ",
|
|
6135
6390
|
(0, import_format8.formatAbsoluteDate)(item.createdAt, DAY_FORMAT, "")
|
|
6136
6391
|
] })
|
|
6137
6392
|
] }) : null }) }),
|
|
6138
|
-
settingUpOtp && item ? /* @__PURE__ */ (0,
|
|
6393
|
+
settingUpOtp && item ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
6139
6394
|
AddOtpPanel,
|
|
6140
6395
|
{
|
|
6141
6396
|
port,
|
|
@@ -6154,23 +6409,26 @@ function ItemPane(props) {
|
|
|
6154
6409
|
}
|
|
6155
6410
|
|
|
6156
6411
|
// src/ItemList.tsx
|
|
6157
|
-
var
|
|
6412
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
6158
6413
|
var SORTS2 = [
|
|
6159
|
-
{ value: "name", label: "Name" },
|
|
6414
|
+
{ value: "name", label: "Name A\u2013Z" },
|
|
6415
|
+
{ value: "name-desc", label: "Name Z\u2013A" },
|
|
6160
6416
|
{ value: "website", label: "Website" },
|
|
6161
6417
|
{ value: "updated", label: "Recently changed" },
|
|
6162
|
-
{ value: "created", label: "Recently added" }
|
|
6418
|
+
{ value: "created", label: "Recently added" },
|
|
6419
|
+
{ value: "viewed", label: "Recently viewed" }
|
|
6163
6420
|
];
|
|
6164
6421
|
function subtitleOf(item, withOwner) {
|
|
6165
6422
|
const what = loginSiteOf(item) || item.definitionLabel;
|
|
6166
6423
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
6167
6424
|
}
|
|
6168
|
-
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner }) {
|
|
6425
|
+
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner, canSortViewed = false }) {
|
|
6426
|
+
const sorts = SORTS2.filter((s) => canSortViewed || s.value !== "viewed");
|
|
6169
6427
|
const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
|
|
6170
6428
|
const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
|
|
6171
6429
|
const ordered = [...pinned, ...rest];
|
|
6172
|
-
const listRef = (0,
|
|
6173
|
-
(0,
|
|
6430
|
+
const listRef = (0, import_react29.useRef)(null);
|
|
6431
|
+
(0, import_react29.useEffect)(() => {
|
|
6174
6432
|
if (selectedId) listRef.current?.querySelector(`[data-item="${selectedId}"]`)?.scrollIntoView({ block: "nearest" });
|
|
6175
6433
|
}, [selectedId, items.length]);
|
|
6176
6434
|
const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
|
|
@@ -6185,34 +6443,34 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6185
6443
|
}
|
|
6186
6444
|
};
|
|
6187
6445
|
const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6188
|
-
const row = (i) => /* @__PURE__ */ (0,
|
|
6189
|
-
const sortLabel =
|
|
6190
|
-
return /* @__PURE__ */ (0,
|
|
6191
|
-
/* @__PURE__ */ (0,
|
|
6446
|
+
const row = (i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners }, i.id);
|
|
6447
|
+
const sortLabel = sorts.find((s) => s.value === sort)?.label ?? "Name A\u2013Z";
|
|
6448
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
|
|
6449
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children: [
|
|
6192
6450
|
header,
|
|
6193
|
-
/* @__PURE__ */ (0,
|
|
6194
|
-
/* @__PURE__ */ (0,
|
|
6195
|
-
/* @__PURE__ */ (0,
|
|
6451
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
6452
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.SearchField, { value: query, onChange: (e) => onQuery(e.target.value), onKeyDown, placeholder: `Search ${title}`, className: "min-w-0 flex-1", "aria-label": "Search the vault" }),
|
|
6453
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(PlusGlyph, {}), "aria-label": "New item", onClick: onNew })
|
|
6196
6454
|
] }),
|
|
6197
|
-
/* @__PURE__ */ (0,
|
|
6198
|
-
/* @__PURE__ */ (0,
|
|
6455
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center justify-between gap-2 px-1", children: [
|
|
6456
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "truncate text-xs text-muted-foreground", children: [
|
|
6199
6457
|
items.length,
|
|
6200
6458
|
" ",
|
|
6201
6459
|
items.length === 1 ? "item" : "items"
|
|
6202
6460
|
] }),
|
|
6203
|
-
/* @__PURE__ */ (0,
|
|
6204
|
-
/* @__PURE__ */ (0,
|
|
6205
|
-
/* @__PURE__ */ (0,
|
|
6461
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenu, { children: [
|
|
6462
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SortGlyph, {}), "aria-label": `Sort: ${sortLabel}`, children: sortLabel }) }),
|
|
6463
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuContent, { align: "end", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuRadioGroup, { value: sort, onValueChange: (v) => onSort(sorts.find((s) => s.value === v)?.value ?? "name"), children: sorts.map((s) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuRadioItem, { value: s.value, children: s.label }, s.value)) }) })
|
|
6206
6464
|
] })
|
|
6207
6465
|
] })
|
|
6208
6466
|
] }),
|
|
6209
|
-
/* @__PURE__ */ (0,
|
|
6210
|
-
/* @__PURE__ */ (0,
|
|
6211
|
-
query ? /* @__PURE__ */ (0,
|
|
6212
|
-
] }) : /* @__PURE__ */ (0,
|
|
6213
|
-
pinned.length > 0 ? /* @__PURE__ */ (0,
|
|
6467
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto px-2 pb-3", onKeyDown, children: items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-col items-center gap-3 px-4 py-12 text-center", children: [
|
|
6468
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-sm text-muted-foreground", children: query ? `Nothing matches \u201C${query}\u201D.` : "Nothing here yet." }),
|
|
6469
|
+
query ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "outline", onClick: () => onQuery(""), children: "Clear search" }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(PlusGlyph, {}), onClick: onNew, children: "New item" })
|
|
6470
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("ul", { ref: listRef, className: "flex flex-col gap-px", children: [
|
|
6471
|
+
pinned.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("li", { className: "px-2 pb-1 pt-1 text-xs font-medium text-muted-foreground", children: "This page" }) : null,
|
|
6214
6472
|
pinned.map(row),
|
|
6215
|
-
pinned.length > 0 && rest.length > 0 ? /* @__PURE__ */ (0,
|
|
6473
|
+
pinned.length > 0 && rest.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("li", { className: "px-2 pb-1 pt-3 text-xs font-medium text-muted-foreground", children: "Everything else" }) : null,
|
|
6216
6474
|
rest.map(row)
|
|
6217
6475
|
] }) })
|
|
6218
6476
|
] });
|
|
@@ -6221,48 +6479,93 @@ function ListRow({ item, family, port, on, onSelect, withOwner }) {
|
|
|
6221
6479
|
const confirmed = useConfirmed();
|
|
6222
6480
|
const copy = useCopy();
|
|
6223
6481
|
const notify = useNotify();
|
|
6224
|
-
const [busy, setBusy] = (0,
|
|
6225
|
-
const
|
|
6226
|
-
const
|
|
6227
|
-
const
|
|
6482
|
+
const [busy, setBusy] = (0, import_react29.useState)(false);
|
|
6483
|
+
const [menuOpen, setMenuOpen] = (0, import_react29.useState)(false);
|
|
6484
|
+
const canUse = item.capabilities.canUse;
|
|
6485
|
+
const user = canUse ? item.fields.find((f) => USERNAME_KEYS.test(f.key) && f.handling !== "sealed" && f.active !== false) : void 0;
|
|
6486
|
+
const secret = canUse && item.capabilities.canReveal ? item.fields.find((f) => f.key === "password" && f.handling === "revealable" && f.active !== false) : void 0;
|
|
6487
|
+
const code = canUse && item.authenticator?.enabled ? item.authenticator : null;
|
|
6488
|
+
const run = async (label, read, isSecret) => {
|
|
6228
6489
|
setBusy(true);
|
|
6229
6490
|
try {
|
|
6230
|
-
const v = await confirmed(
|
|
6231
|
-
await copy(v, label, { secret:
|
|
6491
|
+
const v = await confirmed(read);
|
|
6492
|
+
await copy(v, label, { secret: isSecret });
|
|
6232
6493
|
} catch (e) {
|
|
6233
6494
|
if (!wasCancelled(e)) notify(e instanceof Error ? e.message : `${label} could not be read`, "error");
|
|
6234
6495
|
} finally {
|
|
6235
6496
|
setBusy(false);
|
|
6236
6497
|
}
|
|
6237
6498
|
};
|
|
6238
|
-
|
|
6239
|
-
|
|
6499
|
+
const copyUser = () => user && void run(user.label, () => port.reveal(item, user.key), user.handling !== "visible");
|
|
6500
|
+
const copyPassword = () => secret && void run("Password", () => port.reveal(item, secret.key), true);
|
|
6501
|
+
const copyCode = () => code && void run("One-time code", async () => (await port.authenticator.code(item)).code, true);
|
|
6502
|
+
const copyName = () => void copy(item.name, "Name", { secret: false });
|
|
6503
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("li", { className: "group relative", "data-item": item.id, children: [
|
|
6504
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
6240
6505
|
"button",
|
|
6241
6506
|
{
|
|
6242
6507
|
type: "button",
|
|
6243
6508
|
"aria-current": on ? "true" : void 0,
|
|
6244
6509
|
"data-surface": on ? "primary" : void 0,
|
|
6245
6510
|
onClick: () => onSelect(item.id),
|
|
6246
|
-
className: (0,
|
|
6511
|
+
className: (0, import_design_system20.cn)("flex h-12 w-full items-center gap-3 rounded-lg px-2 pr-10 text-left", on ? "bg-primary text-primary-foreground" : "hover:bg-accent"),
|
|
6247
6512
|
children: [
|
|
6248
|
-
/* @__PURE__ */ (0,
|
|
6249
|
-
/* @__PURE__ */ (0,
|
|
6250
|
-
/* @__PURE__ */ (0,
|
|
6251
|
-
/* @__PURE__ */ (0,
|
|
6513
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ItemIcon, { definitionKey: item.definitionKey, family, site: loginSiteOf(item), inverted: on }),
|
|
6514
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
6515
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "truncate text-sm font-medium", children: item.name }),
|
|
6516
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "truncate text-xs text-muted-foreground", children: subtitleOf(item, withOwner) })
|
|
6252
6517
|
] })
|
|
6253
6518
|
]
|
|
6254
6519
|
}
|
|
6255
6520
|
),
|
|
6256
|
-
|
|
6257
|
-
user ? /* @__PURE__ */ (0,
|
|
6258
|
-
|
|
6259
|
-
|
|
6521
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "absolute right-1.5 top-1/2 flex -translate-y-1/2 items-center gap-0.5", "data-surface": on ? "primary" : void 0, children: [
|
|
6522
|
+
user || secret ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: (0, import_design_system20.cn)("hidden items-center gap-0.5 rounded-md pl-2 [@media(hover:hover)]:group-hover:flex [@media(hover:hover)]:group-focus-within:flex", on ? "bg-primary" : "bg-accent"), "data-row-quick": "", children: [
|
|
6523
|
+
user ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(UserGlyph, {}), "aria-label": `Copy ${user.label}`, disabled: busy, onClick: copyUser }) : null,
|
|
6524
|
+
secret ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(KeyGlyph, {}), "aria-label": "Copy password", disabled: busy, onClick: copyPassword }) : null
|
|
6525
|
+
] }) : null,
|
|
6526
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenu, { open: menuOpen, onOpenChange: setMenuOpen, children: [
|
|
6527
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
6528
|
+
import_controls23.Button,
|
|
6529
|
+
{
|
|
6530
|
+
variant: "quiet",
|
|
6531
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(MoreGlyph, {}),
|
|
6532
|
+
"aria-label": `Actions for ${item.name}`,
|
|
6533
|
+
disabled: busy,
|
|
6534
|
+
className: (0, import_design_system20.cn)("[@media(hover:hover)]:invisible [@media(hover:hover)]:group-hover:visible [@media(hover:hover)]:group-focus-within:visible", menuOpen && "[@media(hover:hover)]:visible")
|
|
6535
|
+
}
|
|
6536
|
+
) }),
|
|
6537
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuContent, { align: "end", children: [
|
|
6538
|
+
user ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: copyUser, children: [
|
|
6539
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(UserGlyph, { className: "size-4" }),
|
|
6540
|
+
"Copy ",
|
|
6541
|
+
user.label.toLowerCase()
|
|
6542
|
+
] }) : null,
|
|
6543
|
+
secret ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: copyPassword, children: [
|
|
6544
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(KeyGlyph, { className: "size-4" }),
|
|
6545
|
+
"Copy password"
|
|
6546
|
+
] }) : null,
|
|
6547
|
+
code ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: copyCode, children: [
|
|
6548
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ClockGlyph, { className: "size-4" }),
|
|
6549
|
+
"Copy one-time code"
|
|
6550
|
+
] }) : null,
|
|
6551
|
+
user || secret || code ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuSeparator, {}) : null,
|
|
6552
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: () => onSelect(item.id), children: [
|
|
6553
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronRightGlyph, { className: "size-4" }),
|
|
6554
|
+
"Open"
|
|
6555
|
+
] }),
|
|
6556
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: copyName, children: [
|
|
6557
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_icons12.CopyIcon, { className: "size-4" }),
|
|
6558
|
+
"Copy name"
|
|
6559
|
+
] })
|
|
6560
|
+
] })
|
|
6561
|
+
] })
|
|
6562
|
+
] })
|
|
6260
6563
|
] });
|
|
6261
6564
|
}
|
|
6262
6565
|
|
|
6263
6566
|
// src/lists/TrashView.tsx
|
|
6264
|
-
var
|
|
6265
|
-
var
|
|
6567
|
+
var import_react31 = require("react");
|
|
6568
|
+
var import_controls25 = require("@ai-matrx/design-system/controls");
|
|
6266
6569
|
var import_format9 = require("@ai-matrx/kit/format");
|
|
6267
6570
|
|
|
6268
6571
|
// src/lists/logic.ts
|
|
@@ -6335,16 +6638,16 @@ function refusalText(reason) {
|
|
|
6335
6638
|
}
|
|
6336
6639
|
|
|
6337
6640
|
// src/lists/RestorePanel.tsx
|
|
6338
|
-
var
|
|
6339
|
-
var
|
|
6340
|
-
var
|
|
6641
|
+
var import_react30 = require("react");
|
|
6642
|
+
var import_controls24 = require("@ai-matrx/design-system/controls");
|
|
6643
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
6341
6644
|
var count = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
|
|
6342
6645
|
function RestorePanel({ lists, item, restore, onClose }) {
|
|
6343
|
-
const [preview, setPreview] = (0,
|
|
6344
|
-
const [error, setError] = (0,
|
|
6345
|
-
const [busy, setBusy] = (0,
|
|
6346
|
-
const [loading, setLoading] = (0,
|
|
6347
|
-
(0,
|
|
6646
|
+
const [preview, setPreview] = (0, import_react30.useState)(null);
|
|
6647
|
+
const [error, setError] = (0, import_react30.useState)(null);
|
|
6648
|
+
const [busy, setBusy] = (0, import_react30.useState)(false);
|
|
6649
|
+
const [loading, setLoading] = (0, import_react30.useState)(Boolean(lists.preview));
|
|
6650
|
+
(0, import_react30.useEffect)(() => {
|
|
6348
6651
|
if (!lists.preview) return;
|
|
6349
6652
|
let live = true;
|
|
6350
6653
|
lists.preview(item).then(
|
|
@@ -6376,41 +6679,41 @@ function RestorePanel({ lists, item, restore, onClose }) {
|
|
|
6376
6679
|
setBusy(false);
|
|
6377
6680
|
}
|
|
6378
6681
|
};
|
|
6379
|
-
return /* @__PURE__ */ (0,
|
|
6682
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
6380
6683
|
Panel,
|
|
6381
6684
|
{
|
|
6382
6685
|
title: `Restore "${item.name}"`,
|
|
6383
6686
|
size: "md",
|
|
6384
6687
|
onClose,
|
|
6385
|
-
footer: /* @__PURE__ */ (0,
|
|
6386
|
-
/* @__PURE__ */ (0,
|
|
6387
|
-
refused ? null : /* @__PURE__ */ (0,
|
|
6688
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
|
|
6689
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_controls24.Button, { variant: "quiet", onClick: onClose, children: refused ? "Close" : "Cancel" }),
|
|
6690
|
+
refused ? null : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_controls24.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(RestoreGlyph, {}), disabled: busy || loading || lists.preview !== void 0 && preview === null, onClick: () => void run(), children: busy ? "Restoring\u2026" : "Restore" })
|
|
6388
6691
|
] }),
|
|
6389
6692
|
children: [
|
|
6390
|
-
loading ? /* @__PURE__ */ (0,
|
|
6391
|
-
/* @__PURE__ */ (0,
|
|
6392
|
-
/* @__PURE__ */ (0,
|
|
6393
|
-
preview.passkeys === 1 ? /* @__PURE__ */ (0,
|
|
6394
|
-
/* @__PURE__ */ (0,
|
|
6395
|
-
preview.priorWasDisabled ? /* @__PURE__ */ (0,
|
|
6396
|
-
] }) : preview ? /* @__PURE__ */ (0,
|
|
6397
|
-
error ? /* @__PURE__ */ (0,
|
|
6693
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Empty, { children: "Checking what comes back\u2026" }) }) : preview?.supported ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(VaultSection, { title: "Comes back", children: [
|
|
6694
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(VaultRow, { label: "Fields", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-foreground", children: count(preview.fields, "field") }) }),
|
|
6695
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(VaultRow, { label: "Files", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-foreground", children: count(preview.attachments, "file") }) }),
|
|
6696
|
+
preview.passkeys === 1 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(VaultRow, { label: "Passkey", hint: "Not turned on; the site may not accept it", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-foreground", children: "1 passkey" }) }) : null,
|
|
6697
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(VaultRow, { label: "Stays off", hint: "Turn each back on yourself", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-muted-foreground", children: "Sharing, browser fill, codes, sandboxes, agents" }) }),
|
|
6698
|
+
preview.priorWasDisabled ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(VaultRow, { label: "Before", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-muted-foreground", children: "It was already off before it was deleted." }) }) : null
|
|
6699
|
+
] }) : preview ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Empty, { children: refusalText(preview.reason) }) }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Empty, { children: "It comes back turned off: sharing, browser fill, codes and sandbox use stay off." }) }),
|
|
6700
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { role: "alert", className: "px-1 text-sm text-destructive", children: error }) : null
|
|
6398
6701
|
]
|
|
6399
6702
|
}
|
|
6400
6703
|
);
|
|
6401
6704
|
}
|
|
6402
6705
|
|
|
6403
6706
|
// src/lists/TrashView.tsx
|
|
6404
|
-
var
|
|
6707
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
6405
6708
|
function trashLineOf(item) {
|
|
6406
6709
|
return [item.definitionLabel || null, item.owner.label, item.deletion?.deletedAt ? `Deleted ${(0, import_format9.formatAbsoluteDate)(item.deletion.deletedAt, DAY_FORMAT, "")}` : null].filter(Boolean).join(" \xB7 ");
|
|
6407
6710
|
}
|
|
6408
6711
|
function TrashView({ port, deleted, query, header, onChanged }) {
|
|
6409
6712
|
const confirmed = useConfirmed();
|
|
6410
|
-
const [busyId, setBusyId] = (0,
|
|
6411
|
-
const [message2, setMessage] = (0,
|
|
6713
|
+
const [busyId, setBusyId] = (0, import_react31.useState)(null);
|
|
6714
|
+
const [message2, setMessage] = (0, import_react31.useState)(null);
|
|
6412
6715
|
const shown = deleted.filter((i) => trashItemMatchesQuery(i, query));
|
|
6413
|
-
const [restoring, setRestoring] = (0,
|
|
6716
|
+
const [restoring, setRestoring] = (0, import_react31.useState)(null);
|
|
6414
6717
|
const restore = async (item, deletionId) => {
|
|
6415
6718
|
setBusyId(item.id);
|
|
6416
6719
|
setMessage(null);
|
|
@@ -6426,35 +6729,35 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6426
6729
|
setBusyId(null);
|
|
6427
6730
|
}
|
|
6428
6731
|
};
|
|
6429
|
-
return /* @__PURE__ */ (0,
|
|
6732
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-3", children: [
|
|
6430
6733
|
header,
|
|
6431
|
-
/* @__PURE__ */ (0,
|
|
6734
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(VaultSection, { title: "Trash", children: shown.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Empty, { children: deleted.length === 0 ? "The trash is empty." : "Nothing matches." }) : shown.map((item) => (
|
|
6432
6735
|
// A list row, not a field row: the name gets the whole width (on a phone a label column
|
|
6433
6736
|
// left "Vau…" for every row), the deletion date sits under it.
|
|
6434
|
-
/* @__PURE__ */ (0,
|
|
6435
|
-
/* @__PURE__ */ (0,
|
|
6436
|
-
/* @__PURE__ */ (0,
|
|
6437
|
-
/* @__PURE__ */ (0,
|
|
6737
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex min-h-12 items-center gap-3 px-3 py-1.5 sm:px-4", children: [
|
|
6738
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
6739
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "truncate text-sm text-foreground", children: item.name }),
|
|
6740
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "truncate text-xs text-muted-foreground", children: trashLineOf(item) })
|
|
6438
6741
|
] }),
|
|
6439
|
-
/* @__PURE__ */ (0,
|
|
6742
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_controls25.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(RestoreGlyph, {}), disabled: busyId !== null || !item.deletion, onClick: () => setRestoring(item), children: "Restore" })
|
|
6440
6743
|
] }, item.id)
|
|
6441
6744
|
)) }),
|
|
6442
|
-
restoring ? /* @__PURE__ */ (0,
|
|
6443
|
-
message2 ? /* @__PURE__ */ (0,
|
|
6745
|
+
restoring ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(RestorePanel, { lists: port.lists, item: restoring, restore: (deletionId) => restore(restoring, deletionId), onClose: () => setRestoring(null) }) : null,
|
|
6746
|
+
message2 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { role: "status", className: message2.tone === "error" ? "px-1 text-sm text-destructive" : "px-1 text-sm text-muted-foreground", children: message2.text }) : null
|
|
6444
6747
|
] });
|
|
6445
6748
|
}
|
|
6446
6749
|
|
|
6447
6750
|
// src/NewItemFlow.tsx
|
|
6448
|
-
var
|
|
6449
|
-
var
|
|
6450
|
-
var
|
|
6451
|
-
var
|
|
6452
|
-
var
|
|
6751
|
+
var import_react32 = require("react");
|
|
6752
|
+
var import_design_system21 = require("@ai-matrx/design-system");
|
|
6753
|
+
var import_controls26 = require("@ai-matrx/design-system/controls");
|
|
6754
|
+
var import_icons13 = require("@ai-matrx/design-system/icons");
|
|
6755
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
6453
6756
|
function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
|
|
6454
|
-
const [search, setSearch] = (0,
|
|
6455
|
-
const guess = (0,
|
|
6757
|
+
const [search, setSearch] = (0, import_react32.useState)("");
|
|
6758
|
+
const guess = (0, import_react32.useMemo)(() => inferFromUrl(url, definitions), [url, definitions]);
|
|
6456
6759
|
const common = COMMON_DEFINITION_KEYS.map((k) => definitions.find((d) => d.key === k)).filter((d) => d !== void 0);
|
|
6457
|
-
const matches = (0,
|
|
6760
|
+
const matches = (0, import_react32.useMemo)(() => {
|
|
6458
6761
|
const q = search.trim().toLowerCase();
|
|
6459
6762
|
if (!q) return [];
|
|
6460
6763
|
return definitions.filter((d) => `${d.label} ${d.key} ${d.providerKey ?? ""} ${FAMILY_LABELS[d.family] ?? ""}`.toLowerCase().includes(q)).slice(0, 60);
|
|
@@ -6463,15 +6766,15 @@ function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
|
|
|
6463
6766
|
const alternatives = (guess?.alternatives ?? []).map((k) => definitions.find((d) => d.key === k)).filter((d) => d !== void 0).slice(0, 4);
|
|
6464
6767
|
const use = (d) => onChoose(d.key, guess?.name ?? "", guess?.url ?? url.trim());
|
|
6465
6768
|
const shown = search.trim() ? matches : common;
|
|
6466
|
-
return /* @__PURE__ */ (0,
|
|
6467
|
-
/* @__PURE__ */ (0,
|
|
6468
|
-
/* @__PURE__ */ (0,
|
|
6469
|
-
/* @__PURE__ */ (0,
|
|
6769
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex h-full min-h-0 flex-col bg-background", children: [
|
|
6770
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("header", { className: "flex min-h-14 items-center gap-2 border-b border-border px-3 sm:px-5", children: [
|
|
6771
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_controls26.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ChevronLeftGlyph, {}), "aria-label": "Cancel", onClick: onCancel }),
|
|
6772
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h2", { className: "text-base font-semibold", children: "New item" })
|
|
6470
6773
|
] }),
|
|
6471
|
-
/* @__PURE__ */ (0,
|
|
6472
|
-
/* @__PURE__ */ (0,
|
|
6473
|
-
/* @__PURE__ */ (0,
|
|
6474
|
-
|
|
6774
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "mx-auto flex w-full max-w-2xl flex-col gap-8 px-4 py-8 sm:px-6 sm:py-12", children: [
|
|
6775
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-col gap-3", children: [
|
|
6776
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
6777
|
+
import_controls26.Field,
|
|
6475
6778
|
{
|
|
6476
6779
|
hero: true,
|
|
6477
6780
|
value: url,
|
|
@@ -6483,45 +6786,45 @@ function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
|
|
|
6483
6786
|
"aria-label": "Website address",
|
|
6484
6787
|
inputMode: "url",
|
|
6485
6788
|
autoFocus: true,
|
|
6486
|
-
icon: /* @__PURE__ */ (0,
|
|
6789
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_icons13.GlobeIcon, {})
|
|
6487
6790
|
}
|
|
6488
6791
|
),
|
|
6489
|
-
guess && login ? /* @__PURE__ */ (0,
|
|
6490
|
-
/* @__PURE__ */ (0,
|
|
6491
|
-
/* @__PURE__ */ (0,
|
|
6492
|
-
/* @__PURE__ */ (0,
|
|
6493
|
-
/* @__PURE__ */ (0,
|
|
6494
|
-
/* @__PURE__ */ (0,
|
|
6792
|
+
guess && login ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-col gap-2 rounded-xl border border-border bg-card p-3", children: [
|
|
6793
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
6794
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { "aria-hidden": true, className: "flex size-9 shrink-0 items-center justify-center rounded-lg bg-muted text-sm font-semibold", children: guess.name.charAt(0).toUpperCase() }),
|
|
6795
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
6796
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "truncate text-sm font-medium", children: guess.name }),
|
|
6797
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "truncate text-xs text-muted-foreground", children: guess.url.replace(/^https?:\/\//, "") })
|
|
6495
6798
|
] }),
|
|
6496
|
-
/* @__PURE__ */ (0,
|
|
6799
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_controls26.Button, { variant: "primary", onClick: () => use(login), children: "Save login" })
|
|
6497
6800
|
] }),
|
|
6498
|
-
alternatives.length > 0 ? /* @__PURE__ */ (0,
|
|
6499
|
-
/* @__PURE__ */ (0,
|
|
6500
|
-
alternatives.map((d) => /* @__PURE__ */ (0,
|
|
6801
|
+
alternatives.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5 pl-12", children: [
|
|
6802
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "text-xs text-muted-foreground", children: "Or" }),
|
|
6803
|
+
alternatives.map((d) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_controls26.Button, { variant: "outline", onClick: () => use(d), children: d.label }, d.key))
|
|
6501
6804
|
] }) : null
|
|
6502
|
-
] }) : url.trim() ? /* @__PURE__ */ (0,
|
|
6805
|
+
] }) : url.trim() ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "px-1 text-sm text-muted-foreground", children: "Not a website address. Pick a type below; it is kept." }) : null
|
|
6503
6806
|
] }),
|
|
6504
|
-
/* @__PURE__ */ (0,
|
|
6505
|
-
/* @__PURE__ */ (0,
|
|
6506
|
-
/* @__PURE__ */ (0,
|
|
6807
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-col gap-3", children: [
|
|
6808
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "flex items-center justify-between gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h3", { className: "text-xs font-medium text-muted-foreground", children: search.trim() ? "Matching types" : "Or choose a type" }) }),
|
|
6809
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("ul", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: shown.map((d) => {
|
|
6507
6810
|
const Icon = definitionGlyph(d.key, d.family);
|
|
6508
|
-
return /* @__PURE__ */ (0,
|
|
6509
|
-
/* @__PURE__ */ (0,
|
|
6510
|
-
/* @__PURE__ */ (0,
|
|
6811
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("button", { type: "button", onClick: () => use(d), className: (0, import_design_system21.cn)("flex h-12 w-full items-center gap-3 rounded-xl border border-border bg-card px-3 text-left hover:bg-accent"), children: [
|
|
6812
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Icon, { className: "size-4" }) }),
|
|
6813
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: d.label })
|
|
6511
6814
|
] }) }, d.key);
|
|
6512
6815
|
}) }),
|
|
6513
|
-
search.trim() && matches.length === 0 ? /* @__PURE__ */ (0,
|
|
6514
|
-
/* @__PURE__ */ (0,
|
|
6816
|
+
search.trim() && matches.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "px-1 text-sm text-muted-foreground", children: "No type matches." }) : null,
|
|
6817
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_controls26.SearchField, { value: search, onChange: (e) => setSearch(e.target.value), placeholder: `Search all ${definitions.length} types`, "aria-label": "Search types" })
|
|
6515
6818
|
] })
|
|
6516
6819
|
] }) })
|
|
6517
6820
|
] });
|
|
6518
6821
|
}
|
|
6519
6822
|
|
|
6520
6823
|
// src/sharing/SecureLinkPanel.tsx
|
|
6521
|
-
var
|
|
6522
|
-
var
|
|
6523
|
-
var
|
|
6524
|
-
var
|
|
6824
|
+
var import_react33 = require("react");
|
|
6825
|
+
var import_confirm_opener11 = require("@ai-matrx/kit/confirm-opener");
|
|
6826
|
+
var import_design_system22 = require("@ai-matrx/design-system");
|
|
6827
|
+
var import_controls27 = require("@ai-matrx/design-system/controls");
|
|
6525
6828
|
var import_format11 = require("@ai-matrx/kit/format");
|
|
6526
6829
|
|
|
6527
6830
|
// src/sharing/secure-link-logic.ts
|
|
@@ -6597,24 +6900,24 @@ function sortSent(rows) {
|
|
|
6597
6900
|
}
|
|
6598
6901
|
|
|
6599
6902
|
// src/sharing/SecureLinkPanel.tsx
|
|
6600
|
-
var
|
|
6903
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
6601
6904
|
function SecureLinkPanel({ item, port, onClose }) {
|
|
6602
6905
|
const sharing = port.sharing;
|
|
6603
6906
|
const { busy, error, notice, run, setNotice } = useConfirmedChange();
|
|
6604
|
-
const [remedy, setRemedy] = (0,
|
|
6605
|
-
const [options, setOptions] = (0,
|
|
6606
|
-
const [optionsError, setOptionsError] = (0,
|
|
6607
|
-
const [sent, setSent] = (0,
|
|
6608
|
-
const [sentError, setSentError] = (0,
|
|
6609
|
-
const [nonce, setNonce] = (0,
|
|
6610
|
-
const [email, setEmail] = (0,
|
|
6611
|
-
const [phone, setPhone] = (0,
|
|
6612
|
-
const [name, setName] = (0,
|
|
6613
|
-
const [linkBy, setLinkBy] = (0,
|
|
6614
|
-
const [fields, setFields] = (0,
|
|
6615
|
-
const [note, setNote] = (0,
|
|
6616
|
-
const [sameChannelSent, setSameChannelSent] = (0,
|
|
6617
|
-
(0,
|
|
6907
|
+
const [remedy, setRemedy] = (0, import_react33.useState)(null);
|
|
6908
|
+
const [options, setOptions] = (0, import_react33.useState)(null);
|
|
6909
|
+
const [optionsError, setOptionsError] = (0, import_react33.useState)(null);
|
|
6910
|
+
const [sent, setSent] = (0, import_react33.useState)(null);
|
|
6911
|
+
const [sentError, setSentError] = (0, import_react33.useState)(null);
|
|
6912
|
+
const [nonce, setNonce] = (0, import_react33.useState)(0);
|
|
6913
|
+
const [email, setEmail] = (0, import_react33.useState)("");
|
|
6914
|
+
const [phone, setPhone] = (0, import_react33.useState)("");
|
|
6915
|
+
const [name, setName] = (0, import_react33.useState)("");
|
|
6916
|
+
const [linkBy, setLinkBy] = (0, import_react33.useState)("email");
|
|
6917
|
+
const [fields, setFields] = (0, import_react33.useState)([]);
|
|
6918
|
+
const [note, setNote] = (0, import_react33.useState)("");
|
|
6919
|
+
const [sameChannelSent, setSameChannelSent] = (0, import_react33.useState)(false);
|
|
6920
|
+
(0, import_react33.useEffect)(() => {
|
|
6618
6921
|
let live = true;
|
|
6619
6922
|
setOptionsError(null);
|
|
6620
6923
|
sharing.secureLinkOptions(item).then(
|
|
@@ -6629,7 +6932,7 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6629
6932
|
live = false;
|
|
6630
6933
|
};
|
|
6631
6934
|
}, [sharing, item]);
|
|
6632
|
-
(0,
|
|
6935
|
+
(0, import_react33.useEffect)(() => {
|
|
6633
6936
|
const list = sharing.sentSecureLinks;
|
|
6634
6937
|
if (!list) return;
|
|
6635
6938
|
let live = true;
|
|
@@ -6642,9 +6945,9 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6642
6945
|
live = false;
|
|
6643
6946
|
};
|
|
6644
6947
|
}, [sharing, item, nonce]);
|
|
6645
|
-
const [phoneTyped, setPhoneTyped] = (0,
|
|
6646
|
-
const prefilled = (0,
|
|
6647
|
-
(0,
|
|
6948
|
+
const [phoneTyped, setPhoneTyped] = (0, import_react33.useState)(false);
|
|
6949
|
+
const prefilled = (0, import_react33.useRef)(false);
|
|
6950
|
+
(0, import_react33.useEffect)(() => {
|
|
6648
6951
|
const lookup = sharing.phoneOnFile;
|
|
6649
6952
|
if (!lookup || phoneTyped) return;
|
|
6650
6953
|
const clear = () => {
|
|
@@ -6706,7 +7009,7 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6706
7009
|
setNonce((n) => n + 1);
|
|
6707
7010
|
};
|
|
6708
7011
|
const turnOff = async (row) => {
|
|
6709
|
-
const ok = await (0,
|
|
7012
|
+
const ok = await (0, import_confirm_opener11.confirm)({
|
|
6710
7013
|
title: "Turn off this link?",
|
|
6711
7014
|
description: `The link to ${recipientOf(row)} stops working at once and what it carries is deleted. They will need a new one.`,
|
|
6712
7015
|
confirmLabel: "Turn off",
|
|
@@ -6719,23 +7022,23 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6719
7022
|
setNonce((n) => n + 1);
|
|
6720
7023
|
};
|
|
6721
7024
|
const toggle2 = (key, on) => setFields((cur) => on ? [...cur.filter((k) => k !== key), key] : cur.filter((k) => k !== key));
|
|
6722
|
-
return /* @__PURE__ */ (0,
|
|
7025
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
6723
7026
|
Panel,
|
|
6724
7027
|
{
|
|
6725
7028
|
title: "Send securely",
|
|
6726
7029
|
size: "md",
|
|
6727
7030
|
onClose,
|
|
6728
|
-
footer: /* @__PURE__ */ (0,
|
|
6729
|
-
sameChannelSent && !error ? /* @__PURE__ */ (0,
|
|
6730
|
-
/* @__PURE__ */ (0,
|
|
6731
|
-
/* @__PURE__ */ (0,
|
|
7031
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(PanelFooter, { status: error || notice ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(StatusLine, { error, notice }) : null, children: [
|
|
7032
|
+
sameChannelSent && !error ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_controls27.Badge, { tone: "warning", children: "Both by email" }) : null,
|
|
7033
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_controls27.Button, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
7034
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_controls27.Button, { variant: "primary", disabled: !canSend, onClick: () => void send(), children: busy === "send" ? "Sending\u2026" : "Send link" })
|
|
6732
7035
|
] }),
|
|
6733
7036
|
children: [
|
|
6734
|
-
remedy ? /* @__PURE__ */ (0,
|
|
6735
|
-
/* @__PURE__ */ (0,
|
|
6736
|
-
/* @__PURE__ */ (0,
|
|
6737
|
-
/* @__PURE__ */ (0,
|
|
6738
|
-
|
|
7037
|
+
remedy ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "px-1 text-xs text-muted-foreground", children: remedy }) : null,
|
|
7038
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(VaultSection, { title: "Recipient", children: [
|
|
7039
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(VaultRow, { label: "Email", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_controls27.Field, { type: "email", autoComplete: "off", placeholder: "name@example.com", "aria-label": "Their email", value: email, onChange: (e) => setEmail(e.target.value), className: "w-full" }) }),
|
|
7040
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(VaultRow, { label: "Mobile", hint: "For the code", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7041
|
+
import_controls27.Field,
|
|
6739
7042
|
{
|
|
6740
7043
|
type: "tel",
|
|
6741
7044
|
autoComplete: "off",
|
|
@@ -6750,9 +7053,9 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6750
7053
|
className: "w-full"
|
|
6751
7054
|
}
|
|
6752
7055
|
) }),
|
|
6753
|
-
/* @__PURE__ */ (0,
|
|
6754
|
-
plan && !plan.same ? /* @__PURE__ */ (0,
|
|
6755
|
-
|
|
7056
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(VaultRow, { label: "Name", hint: "Optional", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_controls27.Field, { autoComplete: "off", placeholder: "Their name", "aria-label": "Their name", value: name, onChange: (e) => setName(e.target.value), className: "w-full" }) }),
|
|
7057
|
+
plan && !plan.same ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(VaultRow, { label: "Link by", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7058
|
+
import_controls27.SegmentedControl,
|
|
6756
7059
|
{
|
|
6757
7060
|
"aria-label": "Send the link by",
|
|
6758
7061
|
value: linkBy,
|
|
@@ -6763,28 +7066,28 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6763
7066
|
]
|
|
6764
7067
|
}
|
|
6765
7068
|
) }) : null,
|
|
6766
|
-
email.trim() ? /* @__PURE__ */ (0,
|
|
7069
|
+
email.trim() ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(VaultRow, { label: "Delivery", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: plan?.same ? "text-warning" : "text-foreground", children: planWords(plan) }) }) : null
|
|
6767
7070
|
] }),
|
|
6768
|
-
/* @__PURE__ */ (0,
|
|
6769
|
-
/* @__PURE__ */ (0,
|
|
6770
|
-
/* @__PURE__ */ (0,
|
|
6771
|
-
!f.available && f.reason ? /* @__PURE__ */ (0,
|
|
7071
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(VaultSection, { title: "Include", children: optionsError ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Empty, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-destructive", children: optionsError }) }) : !options ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_controls27.RegionSkeleton, { shape: "rows", count: 2, "aria-label": "Loading what can be sent", className: "px-3 sm:px-4" }) : options.fields.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Empty, { children: "Name and details only" }) : options.fields.map((f) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("label", { className: "flex min-h-11 items-center gap-3 px-3 py-1 sm:px-4", "data-clickable": f.available ? "" : void 0, children: [
|
|
7072
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_design_system22.Checkbox, { checked: fields.includes(f.key), disabled: !f.available, onCheckedChange: (v) => toggle2(f.key, v === true), "aria-label": f.label }),
|
|
7073
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm text-foreground", children: f.label }),
|
|
7074
|
+
!f.available && f.reason ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "min-w-0 max-w-[55%] truncate text-xs text-muted-foreground", title: f.reason, children: f.reason }) : null
|
|
6772
7075
|
] }, f.key)) }),
|
|
6773
|
-
/* @__PURE__ */ (0,
|
|
6774
|
-
options ? /* @__PURE__ */ (0,
|
|
6775
|
-
/* @__PURE__ */ (0,
|
|
6776
|
-
/* @__PURE__ */ (0,
|
|
7076
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(VaultSection, { title: "Message", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "px-3 py-1 sm:px-4", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_controls27.Textarea, { className: "w-full", rows: 2, maxLength: NOTE_MAX, placeholder: "Shown once, with it", "aria-label": "Message", value: note, onChange: (e) => setNote(e.target.value) }) }) }),
|
|
7077
|
+
options ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(VaultSection, { title: "Link", children: [
|
|
7078
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(VaultRow, { label: "Opens", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-foreground", children: "Once" }) }),
|
|
7079
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(VaultRow, { label: "Link expires", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: "text-foreground", children: [
|
|
6777
7080
|
"After ",
|
|
6778
7081
|
lifetimeWords(options.linkMinutes)
|
|
6779
7082
|
] }) }),
|
|
6780
|
-
/* @__PURE__ */ (0,
|
|
7083
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(VaultRow, { label: "Code expires", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: "text-foreground", children: [
|
|
6781
7084
|
"After ",
|
|
6782
7085
|
lifetimeWords(options.codeMinutes)
|
|
6783
7086
|
] }) })
|
|
6784
7087
|
] }) : null,
|
|
6785
|
-
sharing.sentSecureLinks ? /* @__PURE__ */ (0,
|
|
6786
|
-
/* @__PURE__ */ (0,
|
|
6787
|
-
row.status === "pending" ? /* @__PURE__ */ (0,
|
|
7088
|
+
sharing.sentSecureLinks ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(VaultSection, { title: "Sent links", children: sentError ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Empty, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-destructive", children: sentError }) }) : !sent ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_controls27.RegionSkeleton, { shape: "rows", count: 2, "aria-label": "Loading sent links", className: "px-3 sm:px-4" }) : sent.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Empty, { children: "None yet" }) : sent.map((row) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(AccessLine, { glyph: row.status === "pending" ? ClockGlyph : row.fieldKeys.length ? LockGlyph : ShareGlyph, who: recipientOf(row), meta: sentMeta(row, options), children: [
|
|
7089
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_controls27.Badge, { tone: STATUS_TONE[row.status] ?? "neutral", children: statusWord(row.status) }),
|
|
7090
|
+
row.status === "pending" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_controls27.Button, { variant: "quiet", disabled: busy !== null, onClick: () => void turnOff(row), children: "Turn off" }) : null
|
|
6788
7091
|
] }, row.id)) }) : null
|
|
6789
7092
|
]
|
|
6790
7093
|
}
|
|
@@ -6797,9 +7100,9 @@ function sentMeta(row, options) {
|
|
|
6797
7100
|
}
|
|
6798
7101
|
|
|
6799
7102
|
// src/devices/DevicesPanel.tsx
|
|
6800
|
-
var
|
|
6801
|
-
var
|
|
6802
|
-
var
|
|
7103
|
+
var import_react34 = require("react");
|
|
7104
|
+
var import_confirm_opener12 = require("@ai-matrx/kit/confirm-opener");
|
|
7105
|
+
var import_controls28 = require("@ai-matrx/design-system/controls");
|
|
6803
7106
|
var import_format12 = require("@ai-matrx/kit/format");
|
|
6804
7107
|
|
|
6805
7108
|
// src/devices/logic.ts
|
|
@@ -6880,18 +7183,18 @@ function addPasskeyFailure(message2) {
|
|
|
6880
7183
|
var isRevoked = (d) => d.revokedAt !== null;
|
|
6881
7184
|
|
|
6882
7185
|
// src/devices/DevicesPanel.tsx
|
|
6883
|
-
var
|
|
7186
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
6884
7187
|
var messageOf3 = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
|
|
6885
7188
|
function ErrorLine2({ text }) {
|
|
6886
|
-
return text ? /* @__PURE__ */ (0,
|
|
7189
|
+
return text ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { role: "alert", className: "px-1 text-sm text-destructive", children: text }) : null;
|
|
6887
7190
|
}
|
|
6888
7191
|
function DevicesPanel({ port, onClose }) {
|
|
6889
7192
|
const confirmed = useConfirmed();
|
|
6890
7193
|
const notify = useNotify();
|
|
6891
|
-
const [devices, setDevices] = (0,
|
|
6892
|
-
const [error, setError] = (0,
|
|
6893
|
-
const [busyId, setBusyId] = (0,
|
|
6894
|
-
const load = (0,
|
|
7194
|
+
const [devices, setDevices] = (0, import_react34.useState)(null);
|
|
7195
|
+
const [error, setError] = (0, import_react34.useState)(null);
|
|
7196
|
+
const [busyId, setBusyId] = (0, import_react34.useState)(null);
|
|
7197
|
+
const load = (0, import_react34.useCallback)(async () => {
|
|
6895
7198
|
setError(null);
|
|
6896
7199
|
try {
|
|
6897
7200
|
setDevices(await port.devices.list());
|
|
@@ -6899,11 +7202,11 @@ function DevicesPanel({ port, onClose }) {
|
|
|
6899
7202
|
setError(messageOf3(e, "Your browsers could not be read."));
|
|
6900
7203
|
}
|
|
6901
7204
|
}, [port]);
|
|
6902
|
-
(0,
|
|
7205
|
+
(0, import_react34.useEffect)(() => {
|
|
6903
7206
|
void load();
|
|
6904
7207
|
}, [load]);
|
|
6905
7208
|
const revoke = async (device) => {
|
|
6906
|
-
const yes = await (0,
|
|
7209
|
+
const yes = await (0, import_confirm_opener12.confirm)({
|
|
6907
7210
|
title: `Revoke ${device.label}?`,
|
|
6908
7211
|
description: "It stops filling now and the extension there signs out. It fills again only after you sign in there and confirm.",
|
|
6909
7212
|
confirmLabel: "Revoke",
|
|
@@ -6922,19 +7225,19 @@ function DevicesPanel({ port, onClose }) {
|
|
|
6922
7225
|
setBusyId(null);
|
|
6923
7226
|
}
|
|
6924
7227
|
};
|
|
6925
|
-
return /* @__PURE__ */ (0,
|
|
6926
|
-
/* @__PURE__ */ (0,
|
|
6927
|
-
/* @__PURE__ */ (0,
|
|
7228
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Panel, { title: "Browsers that can fill", onClose, size: "md", children: [
|
|
7229
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ErrorLine2, { text: error }),
|
|
7230
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(VaultSection, { children: devices === null ? error ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Empty, { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_controls28.Button, { variant: "outline", onClick: () => void load(), children: "Try again" }) }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_controls28.RegionSkeleton, { shape: "rows", count: 2, "aria-label": "Loading your browsers", className: "px-3 sm:px-4" }) : devices.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Empty, { children: "No browser can fill yet. Turn it on in the extension." }) : devices.map((device) => {
|
|
6928
7231
|
const off = isRevoked(device);
|
|
6929
|
-
return /* @__PURE__ */ (0,
|
|
7232
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
6930
7233
|
VaultRow,
|
|
6931
7234
|
{
|
|
6932
7235
|
label: off ? "Turned off" : "Can fill",
|
|
6933
7236
|
hint: off ? (0, import_format12.formatAbsoluteDate)(device.revokedAt, DAY_FORMAT, "") : void 0,
|
|
6934
|
-
actions: off ? null : /* @__PURE__ */ (0,
|
|
6935
|
-
children: /* @__PURE__ */ (0,
|
|
6936
|
-
/* @__PURE__ */ (0,
|
|
6937
|
-
/* @__PURE__ */ (0,
|
|
7237
|
+
actions: off ? null : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_controls28.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(PowerGlyph, {}), disabled: busyId !== null, onClick: () => void revoke(device), children: "Revoke" }),
|
|
7238
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "flex min-w-0 flex-col", children: [
|
|
7239
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: off ? "truncate text-muted-foreground" : "truncate text-foreground", children: device.label }),
|
|
7240
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "truncate text-xs text-muted-foreground", children: [
|
|
6938
7241
|
device.lastUsedAt ? `Last used ${(0, import_format12.formatAbsoluteDate)(device.lastUsedAt, void 0, "")}` : "Never used",
|
|
6939
7242
|
device.addedAt ? ` \xB7 added ${(0, import_format12.formatAbsoluteDate)(device.addedAt, DAY_FORMAT, "")}` : ""
|
|
6940
7243
|
] })
|
|
@@ -6957,11 +7260,11 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
|
|
|
6957
7260
|
const where = isMac ? "the Mac app" : "the extension";
|
|
6958
7261
|
const passkeys = port.devices.passkeys;
|
|
6959
7262
|
const here = passkeys?.available() ?? false;
|
|
6960
|
-
const [methods, setMethods] = (0,
|
|
6961
|
-
const [busy, setBusy] = (0,
|
|
6962
|
-
const [error, setError] = (0,
|
|
6963
|
-
const [approvedUntil, setApprovedUntil] = (0,
|
|
6964
|
-
const load = (0,
|
|
7263
|
+
const [methods, setMethods] = (0, import_react34.useState)(null);
|
|
7264
|
+
const [busy, setBusy] = (0, import_react34.useState)(null);
|
|
7265
|
+
const [error, setError] = (0, import_react34.useState)(null);
|
|
7266
|
+
const [approvedUntil, setApprovedUntil] = (0, import_react34.useState)(null);
|
|
7267
|
+
const load = (0, import_react34.useCallback)(async () => {
|
|
6965
7268
|
setError(null);
|
|
6966
7269
|
try {
|
|
6967
7270
|
setMethods(await port.devices.stepUpMethods());
|
|
@@ -6969,7 +7272,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
|
|
|
6969
7272
|
setError(messageOf3(e, "Your account could not be checked."));
|
|
6970
7273
|
}
|
|
6971
7274
|
}, [port]);
|
|
6972
|
-
(0,
|
|
7275
|
+
(0, import_react34.useEffect)(() => {
|
|
6973
7276
|
if (key && here) void load();
|
|
6974
7277
|
}, [key, here, load]);
|
|
6975
7278
|
const approve = async () => {
|
|
@@ -7011,55 +7314,55 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
|
|
|
7011
7314
|
};
|
|
7012
7315
|
const canApprove = Boolean(key && passkeys && here && methods?.passkey && !approvedUntil);
|
|
7013
7316
|
const title = isMac ? "Approve this Mac" : name ? `Approve ${name}` : "Approve this browser";
|
|
7014
|
-
const footer = approvedUntil ? /* @__PURE__ */ (0,
|
|
7015
|
-
/* @__PURE__ */ (0,
|
|
7016
|
-
canApprove ? /* @__PURE__ */ (0,
|
|
7317
|
+
const footer = approvedUntil ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_controls28.Button, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
|
|
7318
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_controls28.Button, { variant: "quiet", disabled: busy !== null, onClick: refuse, children: key ? "Refuse" : "Close" }),
|
|
7319
|
+
canApprove ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_controls28.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(FingerprintGlyph, {}), disabled: busy !== null, onClick: () => void approve(), children: busy === "approve" ? "Approving\u2026" : "Approve with passkey" }) : null
|
|
7017
7320
|
] });
|
|
7018
|
-
return /* @__PURE__ */ (0,
|
|
7321
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Panel, { title, onClose: refuse, size: "sm", footer, children: !key ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Empty, { children: [
|
|
7019
7322
|
"This link names no key. Start again from ",
|
|
7020
7323
|
where,
|
|
7021
7324
|
"."
|
|
7022
|
-
] }) }) : /* @__PURE__ */ (0,
|
|
7023
|
-
/* @__PURE__ */ (0,
|
|
7024
|
-
/* @__PURE__ */ (0,
|
|
7025
|
-
name ? /* @__PURE__ */ (0,
|
|
7026
|
-
/* @__PURE__ */ (0,
|
|
7325
|
+
] }) }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
|
|
7326
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(VaultSection, { title: "What is asking", children: [
|
|
7327
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(VaultRow, { label: "Asking", hint: "Approve only if you just asked", children: asker }),
|
|
7328
|
+
name ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(VaultRow, { label: "Name", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "block truncate", children: name }) }) : null,
|
|
7329
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(VaultRow, { label: "Code", hint: `Must match ${where}`, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "font-mono tracking-wider text-foreground", children: shortFingerprint(key) }) })
|
|
7027
7330
|
] }),
|
|
7028
|
-
/* @__PURE__ */ (0,
|
|
7029
|
-
/* @__PURE__ */ (0,
|
|
7331
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ErrorLine2, { text: error }),
|
|
7332
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(VaultSection, { title: "Confirm it\u2019s you", children: approvedUntil ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(VaultRow, { label: "Approved", actions: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CheckGlyph, { className: "size-4 text-primary" }), children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "text-foreground", children: [
|
|
7030
7333
|
"Return to ",
|
|
7031
7334
|
where,
|
|
7032
7335
|
" by ",
|
|
7033
7336
|
(0, import_format12.formatAbsoluteDate)(approvedUntil, void 0, ""),
|
|
7034
7337
|
"."
|
|
7035
|
-
] }) }) : !passkeys ? /* @__PURE__ */ (0,
|
|
7338
|
+
] }) }) : !passkeys ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Empty, { children: [
|
|
7036
7339
|
"Approve with your password in ",
|
|
7037
7340
|
where,
|
|
7038
7341
|
"."
|
|
7039
|
-
] }) : !here ? /* @__PURE__ */ (0,
|
|
7342
|
+
] }) : !here ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
7040
7343
|
VaultRow,
|
|
7041
7344
|
{
|
|
7042
7345
|
label: "Passkey",
|
|
7043
7346
|
hint: `Passkeys work only on ${passkeys.rpId}`,
|
|
7044
|
-
actions: /* @__PURE__ */ (0,
|
|
7045
|
-
children: /* @__PURE__ */ (0,
|
|
7347
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_controls28.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ExternalGlyph, {}), onClick: openOnDomain, children: "Open there" }),
|
|
7348
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-muted-foreground", children: "Not on this page" })
|
|
7046
7349
|
}
|
|
7047
|
-
) : methods === null ? error ? /* @__PURE__ */ (0,
|
|
7350
|
+
) : methods === null ? error ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Empty, { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_controls28.Button, { variant: "outline", onClick: () => void load(), children: "Try again" }) }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_controls28.RegionSkeleton, { shape: "rows", count: 1, "aria-label": "Checking your account", className: "px-3 sm:px-4" }) : !methods.passkey ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
7048
7351
|
VaultRow,
|
|
7049
7352
|
{
|
|
7050
7353
|
label: "Passkey",
|
|
7051
7354
|
hint: methods.password ? `Or type your password in ${where}` : "Add one to approve",
|
|
7052
|
-
actions: /* @__PURE__ */ (0,
|
|
7053
|
-
children: /* @__PURE__ */ (0,
|
|
7355
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_controls28.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(FingerprintGlyph, {}), disabled: busy !== null, onClick: () => void addPasskey(), children: busy === "add" ? "Adding\u2026" : "Add passkey" }),
|
|
7356
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-muted-foreground", children: methods.password ? "None yet" : "No password or passkey" })
|
|
7054
7357
|
}
|
|
7055
|
-
) : /* @__PURE__ */ (0,
|
|
7358
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(VaultRow, { label: "Passkey", hint: "Your device asks for it next", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-foreground", children: "Ready" }) }) })
|
|
7056
7359
|
] }) });
|
|
7057
7360
|
}
|
|
7058
7361
|
|
|
7059
7362
|
// src/native/NativeImportPanel.tsx
|
|
7060
|
-
var
|
|
7061
|
-
var
|
|
7062
|
-
var
|
|
7363
|
+
var import_react36 = require("react");
|
|
7364
|
+
var import_confirm_opener13 = require("@ai-matrx/kit/confirm-opener");
|
|
7365
|
+
var import_controls29 = require("@ai-matrx/design-system/controls");
|
|
7063
7366
|
|
|
7064
7367
|
// src/native/logic.ts
|
|
7065
7368
|
var ACTIVE_PHASES = /* @__PURE__ */ new Set(["authorizing", "importing"]);
|
|
@@ -7120,19 +7423,19 @@ async function loadFullPreview(bridge, operationId, current) {
|
|
|
7120
7423
|
}
|
|
7121
7424
|
|
|
7122
7425
|
// src/native/use-native-import.ts
|
|
7123
|
-
var
|
|
7426
|
+
var import_react35 = require("react");
|
|
7124
7427
|
var fail = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
|
|
7125
7428
|
var RESTART = "Your account changed. The import was stopped; start it again.";
|
|
7126
7429
|
function useNativeImport(bridge, stillAllowed, onImported) {
|
|
7127
|
-
const [screen, setScreen] = (0,
|
|
7128
|
-
const [busy, setBusy] = (0,
|
|
7129
|
-
const generation = (0,
|
|
7130
|
-
const mounted = (0,
|
|
7131
|
-
const op = (0,
|
|
7132
|
-
const last = (0,
|
|
7133
|
-
const timer2 = (0,
|
|
7134
|
-
const polls = (0,
|
|
7135
|
-
const refreshRef = (0,
|
|
7430
|
+
const [screen, setScreen] = (0, import_react35.useState)({ kind: "idle", message: null });
|
|
7431
|
+
const [busy, setBusy] = (0, import_react35.useState)(false);
|
|
7432
|
+
const generation = (0, import_react35.useRef)(0);
|
|
7433
|
+
const mounted = (0, import_react35.useRef)(false);
|
|
7434
|
+
const op = (0, import_react35.useRef)(null);
|
|
7435
|
+
const last = (0, import_react35.useRef)(null);
|
|
7436
|
+
const timer2 = (0, import_react35.useRef)(null);
|
|
7437
|
+
const polls = (0, import_react35.useRef)(0);
|
|
7438
|
+
const refreshRef = (0, import_react35.useRef)(async () => void 0);
|
|
7136
7439
|
const current = (g) => mounted.current && g === generation.current;
|
|
7137
7440
|
const stopPolling = () => {
|
|
7138
7441
|
if (timer2.current !== null) clearTimeout(timer2.current);
|
|
@@ -7233,7 +7536,7 @@ function useNativeImport(bridge, stillAllowed, onImported) {
|
|
|
7233
7536
|
}
|
|
7234
7537
|
};
|
|
7235
7538
|
refreshRef.current = refresh;
|
|
7236
|
-
const
|
|
7539
|
+
const confirm15 = async () => {
|
|
7237
7540
|
if (screen.kind !== "preview") return;
|
|
7238
7541
|
const active = op.current;
|
|
7239
7542
|
if (!active?.organizationId || active.id !== screen.preview.operation_id) return;
|
|
@@ -7301,9 +7604,9 @@ function useNativeImport(bridge, stillAllowed, onImported) {
|
|
|
7301
7604
|
setBusy(false);
|
|
7302
7605
|
setScreen({ kind: "idle", message: null });
|
|
7303
7606
|
};
|
|
7304
|
-
const invalidateRef = (0,
|
|
7607
|
+
const invalidateRef = (0, import_react35.useRef)(invalidate);
|
|
7305
7608
|
invalidateRef.current = invalidate;
|
|
7306
|
-
(0,
|
|
7609
|
+
(0, import_react35.useEffect)(() => {
|
|
7307
7610
|
mounted.current = true;
|
|
7308
7611
|
const off = bridge.subscribe?.(() => {
|
|
7309
7612
|
if (op.current) invalidateRef.current(RESTART);
|
|
@@ -7315,11 +7618,11 @@ function useNativeImport(bridge, stillAllowed, onImported) {
|
|
|
7315
7618
|
off?.();
|
|
7316
7619
|
};
|
|
7317
7620
|
}, [bridge]);
|
|
7318
|
-
return { screen, busy, begin, refresh: () => refresh(false), confirm:
|
|
7621
|
+
return { screen, busy, begin, refresh: () => refresh(false), confirm: confirm15, cancel, recover, reset };
|
|
7319
7622
|
}
|
|
7320
7623
|
|
|
7321
7624
|
// src/native/NativeImportPanel.tsx
|
|
7322
|
-
var
|
|
7625
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
7323
7626
|
var TONE = {
|
|
7324
7627
|
eligible: "success",
|
|
7325
7628
|
committed: "success",
|
|
@@ -7330,19 +7633,19 @@ var TONE = {
|
|
|
7330
7633
|
};
|
|
7331
7634
|
function NativeImportPanel({ bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged }) {
|
|
7332
7635
|
if (!bridge) {
|
|
7333
|
-
return /* @__PURE__ */ (0,
|
|
7636
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Panel, { title: "Import passkeys", size: "md", onClose, footer: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_controls29.Button, { variant: "primary", onClick: onClose, children: "Close" }), children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Empty, { children: "Passkey import needs the desktop app." }) }) });
|
|
7334
7637
|
}
|
|
7335
|
-
return /* @__PURE__ */ (0,
|
|
7638
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Importer, { bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged });
|
|
7336
7639
|
}
|
|
7337
7640
|
function Importer({ bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged }) {
|
|
7338
|
-
const options = (0,
|
|
7339
|
-
const [organizationId, setOrganizationId] = (0,
|
|
7340
|
-
const [limits, setLimits] = (0,
|
|
7341
|
-
const [limitError, setLimitError] = (0,
|
|
7641
|
+
const options = (0, import_react36.useMemo)(() => organizations.map((o) => ({ value: o.id, label: o.name })), [organizations]);
|
|
7642
|
+
const [organizationId, setOrganizationId] = (0, import_react36.useState)(() => organizations.some((o) => o.id === activeOrganizationId) ? activeOrganizationId : organizations[0]?.id ?? "");
|
|
7643
|
+
const [limits, setLimits] = (0, import_react36.useState)(null);
|
|
7644
|
+
const [limitError, setLimitError] = (0, import_react36.useState)(null);
|
|
7342
7645
|
const flow = useNativeImport(bridge, (id) => organizations.some((o) => o.id === id), onChanged);
|
|
7343
7646
|
const { screen, busy } = flow;
|
|
7344
7647
|
const orgName = organizations.find((o) => o.id === organizationId)?.name ?? "this organization";
|
|
7345
|
-
(0,
|
|
7648
|
+
(0, import_react36.useEffect)(() => {
|
|
7346
7649
|
if (!readLimits || !organizationId) return;
|
|
7347
7650
|
let live = true;
|
|
7348
7651
|
setLimits(null);
|
|
@@ -7360,64 +7663,64 @@ function Importer({ bridge, readLimits, activeOrganizationId, organizations, onC
|
|
|
7360
7663
|
const active = status !== null && !TERMINAL_PHASES.has(status.phase);
|
|
7361
7664
|
const ready = preview?.slots.filter((s) => s.disposition === "eligible").length ?? 0;
|
|
7362
7665
|
const importNow = async () => {
|
|
7363
|
-
const yes = await (0,
|
|
7666
|
+
const yes = await (0, import_confirm_opener13.confirm)({ title: `Add ${plural2(ready, "passkey")} to ${orgName}?`, description: "Passkeys already there are skipped.", confirmLabel: "Import" });
|
|
7364
7667
|
if (yes) await flow.confirm();
|
|
7365
7668
|
};
|
|
7366
|
-
const footer = preview ? /* @__PURE__ */ (0,
|
|
7367
|
-
/* @__PURE__ */ (0,
|
|
7368
|
-
/* @__PURE__ */ (0,
|
|
7669
|
+
const footer = preview ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
7670
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_controls29.Button, { variant: "quiet", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel" }),
|
|
7671
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_controls29.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ImportGlyph, { className: "size-4" }), disabled: busy || ready === 0, onClick: () => void importNow(), children: [
|
|
7369
7672
|
"Import ",
|
|
7370
7673
|
ready
|
|
7371
7674
|
] })
|
|
7372
|
-
] }) : status ? active ? /* @__PURE__ */ (0,
|
|
7373
|
-
/* @__PURE__ */ (0,
|
|
7374
|
-
/* @__PURE__ */ (0,
|
|
7375
|
-
] }) : /* @__PURE__ */ (0,
|
|
7376
|
-
/* @__PURE__ */ (0,
|
|
7377
|
-
/* @__PURE__ */ (0,
|
|
7378
|
-
] }) : /* @__PURE__ */ (0,
|
|
7379
|
-
return /* @__PURE__ */ (0,
|
|
7380
|
-
screen.kind === "idle" ? /* @__PURE__ */ (0,
|
|
7381
|
-
/* @__PURE__ */ (0,
|
|
7382
|
-
/* @__PURE__ */ (0,
|
|
7383
|
-
/* @__PURE__ */ (0,
|
|
7675
|
+
] }) : status ? active ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
7676
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_controls29.Button, { variant: "outline", disabled: busy, onClick: () => void flow.refresh(), children: "Refresh" }),
|
|
7677
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_controls29.Button, { variant: "outline", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel import" })
|
|
7678
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
7679
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_controls29.Button, { variant: "quiet", onClick: flow.reset, children: "New file" }),
|
|
7680
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_controls29.Button, { variant: "primary", onClick: onClose, children: "Done" })
|
|
7681
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_controls29.Button, { variant: "quiet", onClick: onClose, children: "Close" });
|
|
7682
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(Panel, { title: "Import passkeys", size: "lg", onClose, footer, children: [
|
|
7683
|
+
screen.kind === "idle" ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(VaultSection, { children: [
|
|
7684
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(VaultRow, { label: "Save to", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_controls29.Select, { value: organizationId, options, "aria-label": "Save to", disabled: busy, onValueChange: setOrganizationId }) }),
|
|
7685
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(VaultRow, { label: "File", hint: limits ? `Up to ${plural2(limits.maxItems, "passkey")}` : "A passkey exchange file", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_controls29.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ImportGlyph, { className: "size-4" }), disabled: busy || !organizationId || limitError !== null, onClick: () => void flow.begin(organizationId), children: busy ? "Opening\u2026" : "Choose file" }) }),
|
|
7686
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(VaultRow, { label: "Interrupted", hint: "Finish or clear an earlier import", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_controls29.Button, { variant: "quiet", disabled: busy, onClick: () => void flow.recover(), children: "Recover" }) })
|
|
7384
7687
|
] }) : null,
|
|
7385
|
-
preview ? /* @__PURE__ */ (0,
|
|
7688
|
+
preview ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(VaultSection, { title: `${ready} of ${preview.total} ready`, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
7386
7689
|
Windowed,
|
|
7387
7690
|
{
|
|
7388
7691
|
items: preview.slots,
|
|
7389
|
-
render: (slot) => /* @__PURE__ */ (0,
|
|
7692
|
+
render: (slot) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(VaultRow, { label: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_controls29.Badge, { tone: TONE[slot.disposition], children: dispositionLabel(slot.disposition) }), hint: void 0, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "block truncate text-foreground", title: slot.reason ?? void 0, children: slot.title ?? "Unnamed passkey" }) }, slot.slot_id)
|
|
7390
7693
|
}
|
|
7391
7694
|
) }) : null,
|
|
7392
|
-
status && !preview ? /* @__PURE__ */ (0,
|
|
7393
|
-
/* @__PURE__ */ (0,
|
|
7394
|
-
/* @__PURE__ */ (0,
|
|
7395
|
-
/* @__PURE__ */ (0,
|
|
7396
|
-
/* @__PURE__ */ (0,
|
|
7397
|
-
status.uncertain > 0 ? /* @__PURE__ */ (0,
|
|
7398
|
-
status.not_attempted > 0 ? /* @__PURE__ */ (0,
|
|
7695
|
+
status && !preview ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(VaultSection, { title: `${accounted(status)} of ${status.total} done`, children: [
|
|
7696
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(VaultRow, { label: "Imported", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-foreground", children: status.committed }) }),
|
|
7697
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(VaultRow, { label: "Already there", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-foreground", children: status.already_present }) }),
|
|
7698
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(VaultRow, { label: "Can't import", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-foreground", children: status.unsupported }) }),
|
|
7699
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(VaultRow, { label: "Failed", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: status.failed > 0 ? "text-destructive" : "text-foreground", children: status.failed }) }),
|
|
7700
|
+
status.uncertain > 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(VaultRow, { label: "Needs recovery", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-foreground", children: status.uncertain }) }) : null,
|
|
7701
|
+
status.not_attempted > 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(VaultRow, { label: "Not tried", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-foreground", children: status.not_attempted }) }) : null
|
|
7399
7702
|
] }) : null,
|
|
7400
|
-
screen.message ? /* @__PURE__ */ (0,
|
|
7401
|
-
/* @__PURE__ */ (0,
|
|
7703
|
+
screen.message ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { role: "status", className: "px-1 text-sm text-muted-foreground", children: screen.message }) : null,
|
|
7704
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ErrorLine, { message: limitError })
|
|
7402
7705
|
] });
|
|
7403
7706
|
}
|
|
7404
7707
|
|
|
7405
7708
|
// src/extension/PageView.tsx
|
|
7406
|
-
var
|
|
7407
|
-
var
|
|
7408
|
-
var
|
|
7409
|
-
var
|
|
7709
|
+
var import_react40 = require("react");
|
|
7710
|
+
var import_design_system24 = require("@ai-matrx/design-system");
|
|
7711
|
+
var import_controls33 = require("@ai-matrx/design-system/controls");
|
|
7712
|
+
var import_icons15 = require("@ai-matrx/design-system/icons");
|
|
7410
7713
|
|
|
7411
7714
|
// src/extension/CaptureCard.tsx
|
|
7412
|
-
var
|
|
7413
|
-
var
|
|
7414
|
-
var
|
|
7715
|
+
var import_react37 = require("react");
|
|
7716
|
+
var import_controls30 = require("@ai-matrx/design-system/controls");
|
|
7717
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
7415
7718
|
var SEARCH_FROM = 4;
|
|
7416
7719
|
function CaptureCard({ capture, onChanged }) {
|
|
7417
|
-
const prompt = (0,
|
|
7720
|
+
const prompt = (0, import_react37.useSyncExternalStore)(capture.subscribe, capture.get, capture.get);
|
|
7418
7721
|
const notify = useNotify();
|
|
7419
|
-
const [busy, setBusy] = (0,
|
|
7420
|
-
const [q, setQ] = (0,
|
|
7722
|
+
const [busy, setBusy] = (0, import_react37.useState)(false);
|
|
7723
|
+
const [q, setQ] = (0, import_react37.useState)("");
|
|
7421
7724
|
if (!prompt) return null;
|
|
7422
7725
|
const decide = async (d) => {
|
|
7423
7726
|
setBusy(true);
|
|
@@ -7435,53 +7738,53 @@ function CaptureCard({ capture, onChanged }) {
|
|
|
7435
7738
|
const existing = prompt.existing;
|
|
7436
7739
|
const needle = q.trim().toLocaleLowerCase();
|
|
7437
7740
|
const shown = needle ? existing.filter((x) => x.name.toLocaleLowerCase().includes(needle)) : existing;
|
|
7438
|
-
return /* @__PURE__ */ (0,
|
|
7439
|
-
/* @__PURE__ */ (0,
|
|
7440
|
-
/* @__PURE__ */ (0,
|
|
7441
|
-
/* @__PURE__ */ (0,
|
|
7442
|
-
/* @__PURE__ */ (0,
|
|
7443
|
-
/* @__PURE__ */ (0,
|
|
7741
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("section", { "aria-label": "Save this login", className: "flex flex-col gap-2 rounded-xl border border-border bg-card px-3 py-2.5", children: [
|
|
7742
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex items-center gap-2.5", children: [
|
|
7743
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ShieldGlyph, { className: "size-5 shrink-0 text-primary" }),
|
|
7744
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
7745
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "truncate text-sm font-medium", children: prompt.unavailable ? "Couldn\u2019t hold this login" : "Save this login?" }),
|
|
7746
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "truncate text-xs text-muted-foreground", children: prompt.username ? `${prompt.host} \xB7 ${prompt.username}` : prompt.host })
|
|
7444
7747
|
] }),
|
|
7445
|
-
/* @__PURE__ */ (0,
|
|
7748
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_controls30.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(XGlyph, {}), "aria-label": "Not now", disabled: busy, onClick: () => void decide({ action: "dismiss" }) })
|
|
7446
7749
|
] }),
|
|
7447
|
-
prompt.unavailable ? /* @__PURE__ */ (0,
|
|
7448
|
-
existing.length > 0 ? /* @__PURE__ */ (0,
|
|
7449
|
-
existing.length >= SEARCH_FROM ? /* @__PURE__ */ (0,
|
|
7450
|
-
/* @__PURE__ */ (0,
|
|
7750
|
+
prompt.unavailable ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-xs text-muted-foreground", children: "Save it by hand with Save a login." }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
|
|
7751
|
+
existing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
7752
|
+
existing.length >= SEARCH_FROM ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_controls30.SearchField, { value: q, onChange: (e) => setQ(e.target.value), placeholder: "Search logins", "aria-label": "Search logins to update" }) : null,
|
|
7753
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("ul", { className: "flex max-h-36 flex-col gap-px overflow-y-auto", children: [
|
|
7451
7754
|
shown.map((x) => {
|
|
7452
7755
|
const tag = distinguish(x, existing);
|
|
7453
|
-
return /* @__PURE__ */ (0,
|
|
7454
|
-
/* @__PURE__ */ (0,
|
|
7756
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("li", { className: "flex h-9 items-center gap-2 px-1", children: [
|
|
7757
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "min-w-0 flex-1 truncate text-sm", children: [
|
|
7455
7758
|
x.name,
|
|
7456
|
-
tag ? /* @__PURE__ */ (0,
|
|
7759
|
+
tag ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
7457
7760
|
" \xB7 ",
|
|
7458
7761
|
tag
|
|
7459
7762
|
] }) : null
|
|
7460
7763
|
] }),
|
|
7461
|
-
/* @__PURE__ */ (0,
|
|
7764
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_controls30.Button, { variant: "primary", disabled: busy, onClick: () => void decide({ action: "update", itemId: x.itemId }), "aria-label": `Update ${x.name}`, children: "Update" })
|
|
7462
7765
|
] }, x.itemId);
|
|
7463
7766
|
}),
|
|
7464
|
-
shown.length === 0 ? /* @__PURE__ */ (0,
|
|
7767
|
+
shown.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("li", { className: "px-1 py-2 text-xs text-muted-foreground", children: "No saved login matches." }) : null
|
|
7465
7768
|
] })
|
|
7466
7769
|
] }) : null,
|
|
7467
|
-
/* @__PURE__ */ (0,
|
|
7468
|
-
/* @__PURE__ */ (0,
|
|
7469
|
-
/* @__PURE__ */ (0,
|
|
7770
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
7771
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_controls30.Button, { variant: existing.length > 0 ? "outline" : "primary", disabled: busy, onClick: () => void decide({ action: "save" }), children: existing.length > 0 ? "Save as new" : "Save" }),
|
|
7772
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_controls30.Button, { variant: "quiet", disabled: busy, onClick: () => void decide({ action: "never" }), children: "Never here" })
|
|
7470
7773
|
] })
|
|
7471
7774
|
] })
|
|
7472
7775
|
] });
|
|
7473
7776
|
}
|
|
7474
7777
|
|
|
7475
7778
|
// src/extension/FillSetupCard.tsx
|
|
7476
|
-
var
|
|
7477
|
-
var
|
|
7478
|
-
var
|
|
7779
|
+
var import_react38 = require("react");
|
|
7780
|
+
var import_controls31 = require("@ai-matrx/design-system/controls");
|
|
7781
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
7479
7782
|
function FillSetupCard({ fillSetup }) {
|
|
7480
7783
|
const notify = useNotify();
|
|
7481
|
-
const state = (0,
|
|
7482
|
-
const box = (0,
|
|
7483
|
-
const [busy, setBusy] = (0,
|
|
7484
|
-
const [error, setError] = (0,
|
|
7784
|
+
const state = (0, import_react38.useSyncExternalStore)(fillSetup.subscribe, fillSetup.get, fillSetup.get);
|
|
7785
|
+
const box = (0, import_react38.useRef)(null);
|
|
7786
|
+
const [busy, setBusy] = (0, import_react38.useState)(false);
|
|
7787
|
+
const [error, setError] = (0, import_react38.useState)(null);
|
|
7485
7788
|
if (state.status !== "off") return null;
|
|
7486
7789
|
const finish = async (run) => {
|
|
7487
7790
|
setBusy(true);
|
|
@@ -7507,15 +7810,15 @@ function FillSetupCard({ fillSetup }) {
|
|
|
7507
7810
|
const neither = m !== null && !m.password && !m.passkey;
|
|
7508
7811
|
const showPassword = !neither && (m === null || m.password);
|
|
7509
7812
|
const showPasskey = state.passkey !== null && (neither || m === null || m.passkey);
|
|
7510
|
-
return /* @__PURE__ */ (0,
|
|
7511
|
-
/* @__PURE__ */ (0,
|
|
7512
|
-
/* @__PURE__ */ (0,
|
|
7513
|
-
/* @__PURE__ */ (0,
|
|
7514
|
-
/* @__PURE__ */ (0,
|
|
7515
|
-
/* @__PURE__ */ (0,
|
|
7813
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("section", { "aria-label": "Turn on filling", "data-testid": "fill-setup", className: "flex flex-col gap-2 rounded-xl border border-border bg-card px-3 py-2.5", children: [
|
|
7814
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-2.5", children: [
|
|
7815
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(KeyGlyph, { className: "size-5 shrink-0 text-primary" }),
|
|
7816
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
7817
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "truncate text-sm font-medium", children: "Turn on filling" }),
|
|
7818
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "truncate text-xs text-muted-foreground", children: neither ? "Add a passkey on the web first." : "Confirm it\u2019s you once in this browser." })
|
|
7516
7819
|
] })
|
|
7517
7820
|
] }),
|
|
7518
|
-
showPassword ? /* @__PURE__ */ (0,
|
|
7821
|
+
showPassword ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
7519
7822
|
"form",
|
|
7520
7823
|
{
|
|
7521
7824
|
className: "flex items-center gap-2",
|
|
@@ -7524,42 +7827,42 @@ function FillSetupCard({ fillSetup }) {
|
|
|
7524
7827
|
withPassword();
|
|
7525
7828
|
},
|
|
7526
7829
|
children: [
|
|
7527
|
-
/* @__PURE__ */ (0,
|
|
7528
|
-
/* @__PURE__ */ (0,
|
|
7830
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_controls31.Field, { ref: box, className: "min-w-0 flex-1", type: "password", autoComplete: "current-password", placeholder: "AI Matrx password", "aria-label": "Your AI Matrx password", disabled: busy }),
|
|
7831
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_controls31.Button, { variant: "primary", type: "submit", disabled: busy, children: "Turn on" })
|
|
7529
7832
|
]
|
|
7530
7833
|
}
|
|
7531
7834
|
) : null,
|
|
7532
|
-
showPasskey ? /* @__PURE__ */ (0,
|
|
7835
|
+
showPasskey ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_controls31.Button, { variant: "outline", iconEnd: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ExternalGlyph, {}), disabled: busy, onClick: () => {
|
|
7533
7836
|
setError(null);
|
|
7534
7837
|
fillSetup.openPasskey();
|
|
7535
7838
|
}, children: neither ? "Add a passkey" : "Use a passkey" }) : null,
|
|
7536
|
-
showPasskey && state.awaitingPasskey && state.passkey ? /* @__PURE__ */ (0,
|
|
7537
|
-
/* @__PURE__ */ (0,
|
|
7839
|
+
showPasskey && state.awaitingPasskey && state.passkey ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-2", "data-testid": "fill-setup-waiting", children: [
|
|
7840
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { className: "min-w-0 flex-1 text-xs text-muted-foreground", children: [
|
|
7538
7841
|
"Approve code ",
|
|
7539
|
-
/* @__PURE__ */ (0,
|
|
7842
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "font-mono text-foreground", children: state.passkey.code }),
|
|
7540
7843
|
" on that page."
|
|
7541
7844
|
] }),
|
|
7542
|
-
/* @__PURE__ */ (0,
|
|
7845
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_controls31.Button, { variant: "primary", disabled: busy, onClick: () => void finish(() => fillSetup.finishPasskey()), children: "I approved" })
|
|
7543
7846
|
] }) : null,
|
|
7544
|
-
error ? /* @__PURE__ */ (0,
|
|
7847
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { role: "alert", className: "text-xs text-destructive", children: error }) : null
|
|
7545
7848
|
] });
|
|
7546
7849
|
}
|
|
7547
7850
|
|
|
7548
7851
|
// src/extension/PageGenerator.tsx
|
|
7549
|
-
var
|
|
7550
|
-
var
|
|
7551
|
-
var
|
|
7552
|
-
var
|
|
7553
|
-
var
|
|
7852
|
+
var import_react39 = require("react");
|
|
7853
|
+
var import_design_system23 = require("@ai-matrx/design-system");
|
|
7854
|
+
var import_controls32 = require("@ai-matrx/design-system/controls");
|
|
7855
|
+
var import_icons14 = require("@ai-matrx/design-system/icons");
|
|
7856
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
7554
7857
|
var HOLD_MS = 6e4;
|
|
7555
7858
|
function PageGenerator({ fields }) {
|
|
7556
7859
|
const limits = useGeneratorLimitsSource();
|
|
7557
7860
|
const copy = useCopy();
|
|
7558
7861
|
const held = useTransientSecret(HOLD_MS);
|
|
7559
|
-
const [open, setOpen] = (0,
|
|
7560
|
-
const [busy, setBusy] = (0,
|
|
7561
|
-
const [targets, setTargets] = (0,
|
|
7562
|
-
const [said, setSaid] = (0,
|
|
7862
|
+
const [open, setOpen] = (0, import_react39.useState)(false);
|
|
7863
|
+
const [busy, setBusy] = (0, import_react39.useState)(false);
|
|
7864
|
+
const [targets, setTargets] = (0, import_react39.useState)([]);
|
|
7865
|
+
const [said, setSaid] = (0, import_react39.useState)(null);
|
|
7563
7866
|
if (!limits) return null;
|
|
7564
7867
|
const say3 = setSaid;
|
|
7565
7868
|
const put = async (targetId, value2) => {
|
|
@@ -7601,30 +7904,30 @@ function PageGenerator({ fields }) {
|
|
|
7601
7904
|
}
|
|
7602
7905
|
};
|
|
7603
7906
|
const value = held.value;
|
|
7604
|
-
return /* @__PURE__ */ (0,
|
|
7605
|
-
/* @__PURE__ */ (0,
|
|
7907
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
|
|
7908
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
7606
7909
|
VaultRow,
|
|
7607
7910
|
{
|
|
7608
7911
|
label: "New password",
|
|
7609
|
-
actions: /* @__PURE__ */ (0,
|
|
7610
|
-
value ? /* @__PURE__ */ (0,
|
|
7611
|
-
/* @__PURE__ */ (0,
|
|
7612
|
-
/* @__PURE__ */ (0,
|
|
7613
|
-
/* @__PURE__ */ (0,
|
|
7912
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
|
|
7913
|
+
value ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_controls32.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_icons14.CopyIcon, {}), "aria-label": "Copy password", onClick: () => void copy(value, "Password") }) : null,
|
|
7914
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_design_system23.Popover, { open, onOpenChange: setOpen, children: [
|
|
7915
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_design_system23.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_controls32.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(KeyGlyph, {}), disabled: busy, children: "Generate" }) }),
|
|
7916
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_design_system23.PopoverContent, { sizing: "content", align: "end", children: open ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PasswordGenerator, { limits, useLabel: "Fill page", onUse: (v) => void onUse(v) }) : null })
|
|
7614
7917
|
] })
|
|
7615
7918
|
] }),
|
|
7616
|
-
children: said ? /* @__PURE__ */ (0,
|
|
7919
|
+
children: said ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { role: "status", className: said.tone === "success" ? "line-clamp-2 text-xs text-foreground" : "line-clamp-2 text-xs text-muted-foreground", children: said.text }) : targets.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "text-xs text-muted-foreground", children: "Choose the boxes to fill." }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "text-xs text-disabled-foreground", children: "Fills the page\u2019s new-password box" })
|
|
7617
7920
|
}
|
|
7618
7921
|
),
|
|
7619
|
-
value && targets.length > 0 ? targets.map((t) => /* @__PURE__ */ (0,
|
|
7922
|
+
value && targets.length > 0 ? targets.map((t) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(VaultRow, { label: t.topFrame ? "This page" : "In a frame", actions: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_controls32.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(CheckGlyph, {}), disabled: busy, onClick: () => void put(t.id, value), children: "Fill" }), children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "block truncate text-sm", children: targetLabel(t) }) }, t.id)) : null
|
|
7620
7923
|
] });
|
|
7621
7924
|
}
|
|
7622
7925
|
|
|
7623
7926
|
// src/extension/PageView.tsx
|
|
7624
|
-
var
|
|
7927
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
7625
7928
|
function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, items, definitions, onOpen, onNewForPage, onBrowse, onChanged, header }) {
|
|
7626
|
-
const [running, setRunning] = (0,
|
|
7627
|
-
const [said, setSaid] = (0,
|
|
7929
|
+
const [running, setRunning] = (0, import_react40.useState)(null);
|
|
7930
|
+
const [said, setSaid] = (0, import_react40.useState)(null);
|
|
7628
7931
|
const site = pageSite(page.url);
|
|
7629
7932
|
const state = page.matchState ?? { status: "ready" };
|
|
7630
7933
|
const fillable = new Set(page.fillableItemIds ?? page.matchingItemIds);
|
|
@@ -7645,20 +7948,20 @@ function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, ite
|
|
|
7645
7948
|
}
|
|
7646
7949
|
};
|
|
7647
7950
|
let body;
|
|
7648
|
-
if (!page.url) body = /* @__PURE__ */ (0,
|
|
7951
|
+
if (!page.url) body = /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Empty, { children: "No page is open in this tab." });
|
|
7649
7952
|
else if (state.status === "error") {
|
|
7650
|
-
body = /* @__PURE__ */ (0,
|
|
7651
|
-
/* @__PURE__ */ (0,
|
|
7652
|
-
/* @__PURE__ */ (0,
|
|
7953
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center gap-2 px-3 py-2 sm:px-4", children: [
|
|
7954
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { role: "alert", className: "min-w-0 flex-1 text-sm text-muted-foreground", children: MATCH_ERROR_WORDS[state.reason] }),
|
|
7955
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(RefreshGlyph, {}), onClick: state.retry, children: "Retry" })
|
|
7653
7956
|
] });
|
|
7654
7957
|
} else if (state.status === "loading") {
|
|
7655
|
-
body = /* @__PURE__ */ (0,
|
|
7656
|
-
/* @__PURE__ */ (0,
|
|
7657
|
-
/* @__PURE__ */ (0,
|
|
7958
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { "aria-busy": "true", "aria-label": "Checking saved logins", className: "flex flex-col", children: [0, 1].map((n) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex h-12 items-center gap-3 px-3", children: [
|
|
7959
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "size-8 animate-pulse rounded-lg bg-muted" }),
|
|
7960
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "h-3 w-1/2 animate-pulse rounded bg-muted" })
|
|
7658
7961
|
] }, n)) });
|
|
7659
|
-
} else if (matches.length === 0) body = /* @__PURE__ */ (0,
|
|
7962
|
+
} else if (matches.length === 0) body = /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Empty, { children: "No saved login for this site." });
|
|
7660
7963
|
else {
|
|
7661
|
-
body = /* @__PURE__ */ (0,
|
|
7964
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("ul", { className: "flex flex-col", children: matches.map(({ itemId, item }) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
7662
7965
|
MatchRow,
|
|
7663
7966
|
{
|
|
7664
7967
|
itemId,
|
|
@@ -7675,40 +7978,40 @@ function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, ite
|
|
|
7675
7978
|
itemId
|
|
7676
7979
|
)) });
|
|
7677
7980
|
}
|
|
7678
|
-
return /* @__PURE__ */ (0,
|
|
7981
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "flex h-full min-h-0 flex-col overflow-y-auto bg-background text-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex flex-col gap-3 px-3 pb-4 pt-3", children: [
|
|
7679
7982
|
header,
|
|
7680
|
-
/* @__PURE__ */ (0,
|
|
7681
|
-
/* @__PURE__ */ (0,
|
|
7682
|
-
/* @__PURE__ */ (0,
|
|
7683
|
-
page.refresh ? /* @__PURE__ */ (0,
|
|
7684
|
-
onBrowse ? /* @__PURE__ */ (0,
|
|
7983
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex min-h-7 items-center gap-2 px-1", children: [
|
|
7984
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_design_system24.SiteIcon, { site: page.url, fallback: import_icons15.GlobeIcon, className: "size-4" }),
|
|
7985
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", title: page.url, children: site || "No page open" }),
|
|
7986
|
+
page.refresh ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(RefreshGlyph, {}), "aria-label": "Check again", onClick: page.refresh }) : null,
|
|
7987
|
+
onBrowse ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ListGlyph, {}), onClick: onBrowse, children: "All items" }) : null
|
|
7685
7988
|
] }),
|
|
7686
|
-
fillSetup ? /* @__PURE__ */ (0,
|
|
7687
|
-
capture ? /* @__PURE__ */ (0,
|
|
7688
|
-
/* @__PURE__ */ (0,
|
|
7989
|
+
fillSetup ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(FillSetupCard, { fillSetup }) : null,
|
|
7990
|
+
capture ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CaptureCard, { capture, onChanged }) : null,
|
|
7991
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
7689
7992
|
VaultSection,
|
|
7690
7993
|
{
|
|
7691
7994
|
title: "This site",
|
|
7692
|
-
actions: canSave ? /* @__PURE__ */ (0,
|
|
7995
|
+
actions: canSave ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PlusGlyph, {}), onClick: () => onNewForPage(normalizeLoginUrl2(page.url) ?? page.url), children: "Save a login" }) : null,
|
|
7693
7996
|
children: body
|
|
7694
7997
|
}
|
|
7695
7998
|
),
|
|
7696
|
-
said ? /* @__PURE__ */ (0,
|
|
7697
|
-
newPasswordFields && canSave ? /* @__PURE__ */ (0,
|
|
7999
|
+
said ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Outcome, { said, onDismiss: () => setSaid(null) }) : page.blocked && page.url && state.status === "ready" ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "px-1 text-xs text-muted-foreground", children: BLOCK_WORDS[page.blocked] }) : null,
|
|
8000
|
+
newPasswordFields && canSave ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PageGenerator, { fields: newPasswordFields }) }) : null
|
|
7698
8001
|
] }) });
|
|
7699
8002
|
}
|
|
7700
8003
|
function Outcome({ said, onDismiss }) {
|
|
7701
|
-
return /* @__PURE__ */ (0,
|
|
7702
|
-
said.tone === "success" ? /* @__PURE__ */ (0,
|
|
7703
|
-
/* @__PURE__ */ (0,
|
|
7704
|
-
/* @__PURE__ */ (0,
|
|
8004
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { role: "status", className: "flex items-center gap-2 px-1", children: [
|
|
8005
|
+
said.tone === "success" ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CheckGlyph, { className: "size-4 shrink-0 text-primary" }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ShieldGlyph, { className: "size-4 shrink-0 text-destructive" }),
|
|
8006
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "min-w-0 flex-1 text-xs text-foreground", children: said.text }),
|
|
8007
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(XGlyph, {}), "aria-label": "Dismiss", onClick: onDismiss })
|
|
7705
8008
|
] });
|
|
7706
8009
|
}
|
|
7707
8010
|
function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFill, onSignIn }) {
|
|
7708
8011
|
const confirmed = useConfirmed();
|
|
7709
8012
|
const copy = useCopy();
|
|
7710
8013
|
const notify = useNotify();
|
|
7711
|
-
const [reading, setReading] = (0,
|
|
8014
|
+
const [reading, setReading] = (0, import_react40.useState)(false);
|
|
7712
8015
|
const usable = item?.capabilities.canUse ?? false;
|
|
7713
8016
|
const user = usable ? item?.fields.find((f) => USERNAME_KEYS.test(f.key) && f.handling !== "sealed" && f.active) : void 0;
|
|
7714
8017
|
const secret = usable && item?.capabilities.canReveal ? item?.fields.find((f) => f.key === "password" && f.handling === "revealable" && f.active) : void 0;
|
|
@@ -7724,27 +8027,27 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
|
|
|
7724
8027
|
}
|
|
7725
8028
|
};
|
|
7726
8029
|
const subtitle = [item ? loginSiteOf(item) || item.definitionLabel : "", tag].filter(Boolean).join(" \xB7 ");
|
|
7727
|
-
return /* @__PURE__ */ (0,
|
|
7728
|
-
/* @__PURE__ */ (0,
|
|
7729
|
-
/* @__PURE__ */ (0,
|
|
7730
|
-
/* @__PURE__ */ (0,
|
|
7731
|
-
/* @__PURE__ */ (0,
|
|
7732
|
-
subtitle ? /* @__PURE__ */ (0,
|
|
8030
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("li", { className: "flex h-12 items-center gap-1 pl-1 pr-2", "data-item": itemId, children: [
|
|
8031
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("button", { type: "button", onClick: () => onOpen(itemId), className: "flex h-11 min-w-0 flex-1 items-center gap-3 rounded-lg px-2 text-left hover:bg-accent", children: [
|
|
8032
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ItemIcon, { definitionKey: item?.definitionKey ?? "website_login", family, site: item ? loginSiteOf(item) : "" }),
|
|
8033
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
8034
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "truncate text-sm font-medium", children: item?.name ?? "Saved login" }),
|
|
8035
|
+
subtitle ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "truncate text-xs text-muted-foreground", children: subtitle }) : null
|
|
7733
8036
|
] })
|
|
7734
8037
|
] }),
|
|
7735
|
-
onFill ? /* @__PURE__ */ (0,
|
|
7736
|
-
user && item ? /* @__PURE__ */ (0,
|
|
7737
|
-
secret && item ? /* @__PURE__ */ (0,
|
|
7738
|
-
otp ? /* @__PURE__ */ (0,
|
|
7739
|
-
onSignIn ? /* @__PURE__ */ (0,
|
|
7740
|
-
/* @__PURE__ */ (0,
|
|
7741
|
-
/* @__PURE__ */ (0,
|
|
7742
|
-
/* @__PURE__ */ (0,
|
|
7743
|
-
/* @__PURE__ */ (0,
|
|
8038
|
+
onFill ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "primary", disabled: busy, "aria-busy": running || void 0, onClick: onFill, "aria-label": `Fill ${item?.name ?? "this login"}`, children: running ? "Filling\u2026" : "Fill" }) : null,
|
|
8039
|
+
user && item ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(UserGlyph, {}), "aria-label": `Copy ${user.label}`, title: `Copy ${user.label}`, disabled: reading, onClick: () => void read(user.label, () => port.reveal(item, user.key)) }) : null,
|
|
8040
|
+
secret && item ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(KeyGlyph, {}), "aria-label": "Copy password", title: "Copy password", disabled: reading, onClick: () => void read("Password", () => port.reveal(item, secret.key)) }) : null,
|
|
8041
|
+
otp ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ClockGlyph, {}), "aria-label": "Copy one-time code", title: "Copy one-time code", disabled: reading, onClick: () => void read("One-time code", async () => (await port.authenticator.code(otp)).code) }) : null,
|
|
8042
|
+
onSignIn ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_design_system24.DropdownMenu, { children: [
|
|
8043
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_design_system24.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(MoreGlyph, {}), "aria-label": "More", disabled: busy }) }),
|
|
8044
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_design_system24.DropdownMenuContent, { align: "end", children: [
|
|
8045
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_design_system24.DropdownMenuItem, { onSelect: onSignIn, children: [
|
|
8046
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ShieldGlyph, { className: "size-4" }),
|
|
7744
8047
|
"Sign me in"
|
|
7745
8048
|
] }),
|
|
7746
|
-
/* @__PURE__ */ (0,
|
|
7747
|
-
/* @__PURE__ */ (0,
|
|
8049
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_design_system24.DropdownMenuItem, { onSelect: () => onOpen(itemId), children: [
|
|
8050
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ListGlyph, { className: "size-4" }),
|
|
7748
8051
|
"Open item"
|
|
7749
8052
|
] })
|
|
7750
8053
|
] })
|
|
@@ -7753,11 +8056,11 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
|
|
|
7753
8056
|
}
|
|
7754
8057
|
|
|
7755
8058
|
// src/Sidebar.tsx
|
|
7756
|
-
var
|
|
7757
|
-
var
|
|
7758
|
-
var
|
|
7759
|
-
var
|
|
7760
|
-
var
|
|
8059
|
+
var import_react41 = require("react");
|
|
8060
|
+
var import_design_system25 = require("@ai-matrx/design-system");
|
|
8061
|
+
var import_controls34 = require("@ai-matrx/design-system/controls");
|
|
8062
|
+
var import_icons16 = require("@ai-matrx/design-system/icons");
|
|
8063
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
7761
8064
|
var AUTHENTICATOR_LABEL = "Authenticator";
|
|
7762
8065
|
function vaultChoices(items, organizations, current) {
|
|
7763
8066
|
const n = (f) => items.filter(f).length;
|
|
@@ -7771,9 +8074,9 @@ function vaultChoices(items, organizations, current) {
|
|
|
7771
8074
|
];
|
|
7772
8075
|
}
|
|
7773
8076
|
function VaultSelect({ value, choices, onChange }) {
|
|
7774
|
-
return /* @__PURE__ */ (0,
|
|
8077
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_controls34.Select, { value, onValueChange: onChange, "aria-label": "Vault", options: choices.map((c) => ({ value: c.value, label: c.label, meta: String(c.count) })) });
|
|
7775
8078
|
}
|
|
7776
|
-
var CATEGORY_GLYPHS = { logins:
|
|
8079
|
+
var CATEGORY_GLYPHS = { logins: import_icons16.GlobeIcon, passkeys: ShieldGlyph, api: KeyGlyph, oauth: PlugGlyph, infra: DatabaseGlyph, env: TerminalGlyph, files: FileGlyph, other: NoteGlyph };
|
|
7777
8080
|
var familyOf = (key, definitions) => definitions.find((d) => d.key === key)?.family ?? "generic";
|
|
7778
8081
|
function itemCategory(item, definitions) {
|
|
7779
8082
|
return categoryOf(item.definitionKey, familyOf(item.definitionKey, definitions));
|
|
@@ -7816,71 +8119,71 @@ function viewOptions(views, allCount, deletedCount, hasFavorites, hasRecents, ha
|
|
|
7816
8119
|
];
|
|
7817
8120
|
}
|
|
7818
8121
|
function Entry({ on, glyph: Icon, label, count: count2, onClick }) {
|
|
7819
|
-
const desktop = (0,
|
|
7820
|
-
return /* @__PURE__ */ (0,
|
|
8122
|
+
const desktop = (0, import_design_system25.useLook)() === "desktop";
|
|
8123
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
|
|
7821
8124
|
"button",
|
|
7822
8125
|
{
|
|
7823
8126
|
type: "button",
|
|
7824
8127
|
"aria-current": on ? "page" : void 0,
|
|
7825
8128
|
onClick,
|
|
7826
|
-
className: (0,
|
|
8129
|
+
className: (0, import_design_system25.cn)("flex h-8 w-full items-center gap-2.5 rounded-lg px-2.5 text-left text-sm", on ? desktop ? "bg-sidebar-accent text-primary" : "bg-sidebar-accent font-medium text-sidebar-accent-foreground" : "text-sidebar-foreground hover:bg-sidebar-accent"),
|
|
7827
8130
|
children: [
|
|
7828
|
-
/* @__PURE__ */ (0,
|
|
7829
|
-
/* @__PURE__ */ (0,
|
|
7830
|
-
count2 !== void 0 ? /* @__PURE__ */ (0,
|
|
8131
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Icon, { className: "size-4 shrink-0" }),
|
|
8132
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "min-w-0 flex-1 truncate", children: label }),
|
|
8133
|
+
count2 !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "text-xs tabular-nums text-muted-foreground", children: count2 }) : null
|
|
7831
8134
|
]
|
|
7832
8135
|
}
|
|
7833
8136
|
);
|
|
7834
8137
|
}
|
|
7835
8138
|
function Group({ title, children }) {
|
|
7836
|
-
return /* @__PURE__ */ (0,
|
|
7837
|
-
/* @__PURE__ */ (0,
|
|
8139
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
|
|
8140
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "px-2.5 pb-1 text-xs font-medium text-muted-foreground", children: title }),
|
|
7838
8141
|
children
|
|
7839
8142
|
] });
|
|
7840
8143
|
}
|
|
7841
8144
|
function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false }) {
|
|
7842
|
-
const [tagsOpen, setTagsOpen] = (0,
|
|
7843
|
-
return /* @__PURE__ */ (0,
|
|
7844
|
-
/* @__PURE__ */ (0,
|
|
7845
|
-
/* @__PURE__ */ (0,
|
|
7846
|
-
/* @__PURE__ */ (0,
|
|
8145
|
+
const [tagsOpen, setTagsOpen] = (0, import_react41.useState)(view.startsWith("tag:"));
|
|
8146
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("nav", { "aria-label": "Vault", className: "flex h-full min-h-0 flex-col border-r border-sidebar-border bg-sidebar-background text-sidebar-foreground", children: [
|
|
8147
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex items-center gap-2 px-3 pb-2 pt-3", children: [
|
|
8148
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(SafeGlyph, { className: "size-5 shrink-0 text-primary" }),
|
|
8149
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(VaultSelect, { value: vault, choices, onChange: onVault }) })
|
|
7847
8150
|
] }),
|
|
7848
|
-
/* @__PURE__ */ (0,
|
|
7849
|
-
/* @__PURE__ */ (0,
|
|
7850
|
-
hasPage ? /* @__PURE__ */ (0,
|
|
7851
|
-
/* @__PURE__ */ (0,
|
|
7852
|
-
hasFavorites ? /* @__PURE__ */ (0,
|
|
7853
|
-
hasRecents ? /* @__PURE__ */ (0,
|
|
7854
|
-
/* @__PURE__ */ (0,
|
|
8151
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex min-h-0 flex-1 flex-col gap-5 overflow-y-auto px-2 pb-3 pt-1", children: [
|
|
8152
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
|
|
8153
|
+
hasPage ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: view === "page", glyph: import_icons16.GlobeIcon, label: "This page", onClick: () => onView("page") }) : null,
|
|
8154
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: view === "all", glyph: GridGlyph, label: "All items", count: allCount, onClick: () => onView("all") }),
|
|
8155
|
+
hasFavorites ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: view === "favorites", glyph: StarGlyph, label: "Favorites", count: views.favorites, onClick: () => onView("favorites") }) : null,
|
|
8156
|
+
hasRecents ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: view === "recent", glyph: ClockGlyph, label: "Recently opened", count: views.recent, onClick: () => onView("recent") }) : null,
|
|
8157
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: view === "authenticator", glyph: LockGlyph, label: AUTHENTICATOR_LABEL, count: views.authenticator, onClick: () => onView("authenticator") })
|
|
7855
8158
|
] }),
|
|
7856
|
-
views.categories.length > 0 ? /* @__PURE__ */ (0,
|
|
7857
|
-
views.tags.length > 0 ? /* @__PURE__ */ (0,
|
|
7858
|
-
/* @__PURE__ */ (0,
|
|
7859
|
-
tagsOpen ? /* @__PURE__ */ (0,
|
|
8159
|
+
views.categories.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Group, { title: "Categories", children: views.categories.map((e) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: view === e.view, glyph: e.glyph, label: e.label, count: e.count, onClick: () => onView(e.view) }, e.view)) }) : null,
|
|
8160
|
+
views.tags.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
|
|
8161
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("button", { type: "button", "aria-expanded": tagsOpen, onClick: () => setTagsOpen((o) => !o), className: "flex h-7 items-center gap-1 rounded-md px-2.5 text-left text-xs font-medium text-muted-foreground hover:text-foreground", children: [
|
|
8162
|
+
tagsOpen ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ChevronDownGlyph, { className: "size-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ChevronRightGlyph, { className: "size-3.5" }),
|
|
7860
8163
|
"Tags",
|
|
7861
|
-
/* @__PURE__ */ (0,
|
|
8164
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "ml-auto tabular-nums", children: views.tags.length })
|
|
7862
8165
|
] }),
|
|
7863
|
-
tagsOpen ? views.tags.map((e) => /* @__PURE__ */ (0,
|
|
8166
|
+
tagsOpen ? views.tags.map((e) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: view === e.view, glyph: e.glyph, label: e.label, count: e.count, onClick: () => onView(e.view) }, e.view)) : null
|
|
7864
8167
|
] }) : null
|
|
7865
8168
|
] }),
|
|
7866
|
-
/* @__PURE__ */ (0,
|
|
7867
|
-
/* @__PURE__ */ (0,
|
|
7868
|
-
/* @__PURE__ */ (0,
|
|
7869
|
-
/* @__PURE__ */ (0,
|
|
7870
|
-
/* @__PURE__ */ (0,
|
|
7871
|
-
/* @__PURE__ */ (0,
|
|
7872
|
-
hasNativeImport ? /* @__PURE__ */ (0,
|
|
7873
|
-
nativeProvider && nativeProvider.status !== "unavailable" ? /* @__PURE__ */ (0,
|
|
7874
|
-
/* @__PURE__ */ (0,
|
|
7875
|
-
/* @__PURE__ */ (0,
|
|
7876
|
-
/* @__PURE__ */ (0,
|
|
8169
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex flex-col gap-0.5 border-t border-sidebar-border p-2", children: [
|
|
8170
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: view === "trash", glyph: TrashGlyph, label: "Trash", count: deletedCount, onClick: () => onView("trash") }),
|
|
8171
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: false, glyph: ImportGlyph, label: "Import", onClick: () => onPanel("import") }),
|
|
8172
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: false, glyph: ExportGlyph, label: "Export", onClick: () => onPanel("export") }),
|
|
8173
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: false, glyph: SafeGlyph, label: "Backup", onClick: () => onPanel("backup") }),
|
|
8174
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: false, glyph: ShieldGlyph, label: "Browsers that fill", onClick: () => onPanel("devices") }),
|
|
8175
|
+
hasNativeImport ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Entry, { on: false, glyph: ImportGlyph, label: "Import passkeys", onClick: () => onPanel("import-passkeys") }) : null,
|
|
8176
|
+
nativeProvider && nativeProvider.status !== "unavailable" ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("button", { type: "button", onClick: nativeProvider.openSetup, className: "flex h-8 w-full items-center gap-2.5 rounded-lg px-2.5 text-left text-sm hover:bg-sidebar-accent", children: [
|
|
8177
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ShieldGlyph, { className: "size-4 shrink-0" }),
|
|
8178
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "min-w-0 flex-1 truncate", children: "System AutoFill" }),
|
|
8179
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: (0, import_design_system25.cn)("text-xs", nativeProvider.status === "ready" ? "text-success" : "text-warning"), children: nativeProvider.status === "ready" ? "On" : "Set up" })
|
|
7877
8180
|
] }) : null
|
|
7878
8181
|
] })
|
|
7879
8182
|
] });
|
|
7880
8183
|
}
|
|
7881
8184
|
|
|
7882
8185
|
// src/VaultApp.tsx
|
|
7883
|
-
var
|
|
8186
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
7884
8187
|
var FULL_AT = 1120;
|
|
7885
8188
|
var SPLIT_AT = 640;
|
|
7886
8189
|
var NO_HOST = {};
|
|
@@ -7899,8 +8202,8 @@ var generatorLimitsFrom = (knobs) => knobs ? async () => {
|
|
|
7899
8202
|
} : void 0;
|
|
7900
8203
|
function ImportWithLimits(props) {
|
|
7901
8204
|
const { knobs, ...rest } = props;
|
|
7902
|
-
const [state, setState] = (0,
|
|
7903
|
-
(0,
|
|
8205
|
+
const [state, setState] = (0, import_react42.useState)(null);
|
|
8206
|
+
(0, import_react42.useEffect)(() => {
|
|
7904
8207
|
if (!knobs) return setState({ error: "Import is not set up for this organization yet." });
|
|
7905
8208
|
knobs().then(
|
|
7906
8209
|
(r) => {
|
|
@@ -7913,18 +8216,18 @@ function ImportWithLimits(props) {
|
|
|
7913
8216
|
(e) => setState({ error: e instanceof Error ? e.message : "The import settings could not be read." })
|
|
7914
8217
|
);
|
|
7915
8218
|
}, [knobs]);
|
|
7916
|
-
if (state && "limits" in state) return /* @__PURE__ */ (0,
|
|
7917
|
-
return /* @__PURE__ */ (0,
|
|
8219
|
+
if (state && "limits" in state) return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ImportPanel, { ...rest, limits: state.limits });
|
|
8220
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Panel, { title: "Import", onClose: rest.onClose, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Empty, { children: state ? state.error : "Reading this organization\u2019s import settings\u2026" }) });
|
|
7918
8221
|
}
|
|
7919
8222
|
function VaultApp(props) {
|
|
7920
8223
|
const lock = props.host?.lock;
|
|
7921
8224
|
const locked = useLocked(lock);
|
|
7922
|
-
const port = (0,
|
|
7923
|
-
return /* @__PURE__ */ (0,
|
|
8225
|
+
const port = (0, import_react42.useMemo)(() => lock ? guardPort(props.port, () => lock.locked()) : props.port, [props.port, lock]);
|
|
8226
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_design_system26.LookScope, { look: props.look ?? "web", className: "h-full min-h-0 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "relative h-full min-h-0 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(NoticeProvider, { notify: props.notify, children: lock && locked ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(LockedScreen, { lock }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ClipboardProvider, { clipboard: props.host?.clipboard, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(RevealSecondsProvider, { seconds: props.host?.revealSeconds, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(IdentityGate, { identity: props.host?.identity, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(GeneratorLimitsProvider, { resolve: generatorLimitsFrom(props.host?.knobs), children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Workspace, { ...props, port }) }) }) }) }) }) }) });
|
|
7924
8227
|
}
|
|
7925
8228
|
function LockedScreen({ lock }) {
|
|
7926
|
-
const [busy, setBusy] = (0,
|
|
7927
|
-
const [error, setError] = (0,
|
|
8229
|
+
const [busy, setBusy] = (0, import_react42.useState)(false);
|
|
8230
|
+
const [error, setError] = (0, import_react42.useState)(null);
|
|
7928
8231
|
const unlock = async () => {
|
|
7929
8232
|
setBusy(true);
|
|
7930
8233
|
setError(null);
|
|
@@ -7936,37 +8239,37 @@ function LockedScreen({ lock }) {
|
|
|
7936
8239
|
setBusy(false);
|
|
7937
8240
|
}
|
|
7938
8241
|
};
|
|
7939
|
-
return /* @__PURE__ */ (0,
|
|
7940
|
-
/* @__PURE__ */ (0,
|
|
7941
|
-
/* @__PURE__ */ (0,
|
|
7942
|
-
/* @__PURE__ */ (0,
|
|
7943
|
-
error ? /* @__PURE__ */ (0,
|
|
8242
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { role: "region", "aria-label": "Vault locked", className: "flex h-full min-h-0 flex-col items-center justify-center gap-3 p-6 text-center", children: [
|
|
8243
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(LockGlyph, { className: "size-8 text-muted-foreground" }),
|
|
8244
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "text-base font-medium text-foreground", children: "Vault locked" }),
|
|
8245
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_controls35.Button, { variant: "primary", disabled: busy, onClick: () => void unlock(), children: lock.unlockLabel ?? "Unlock" }),
|
|
8246
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { role: "alert", className: "max-w-sm text-sm text-destructive", children: error }) : null
|
|
7944
8247
|
] });
|
|
7945
8248
|
}
|
|
7946
|
-
function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocationChange }) {
|
|
7947
|
-
const rootRef = (0,
|
|
8249
|
+
function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocationChange, onInventory }) {
|
|
8250
|
+
const rootRef = (0, import_react42.useRef)(null);
|
|
7948
8251
|
const width = useElementWidth(rootRef);
|
|
7949
8252
|
const mode = layout !== "auto" ? layout : width >= FULL_AT ? "full" : width >= SPLIT_AT ? "split" : "stack";
|
|
7950
8253
|
const notify = useNotify();
|
|
7951
|
-
const [snap, setSnap] = (0,
|
|
7952
|
-
const [items, setItems] = (0,
|
|
7953
|
-
const [deleted, setDeleted] = (0,
|
|
7954
|
-
const [favorites, setFavorites] = (0,
|
|
7955
|
-
const [recents, setRecents] = (0,
|
|
7956
|
-
const [error, setError] = (0,
|
|
7957
|
-
const [inner, setInner] = (0,
|
|
8254
|
+
const [snap, setSnap] = (0, import_react42.useState)(null);
|
|
8255
|
+
const [items, setItems] = (0, import_react42.useState)([]);
|
|
8256
|
+
const [deleted, setDeleted] = (0, import_react42.useState)([]);
|
|
8257
|
+
const [favorites, setFavorites] = (0, import_react42.useState)(null);
|
|
8258
|
+
const [recents, setRecents] = (0, import_react42.useState)(null);
|
|
8259
|
+
const [error, setError] = (0, import_react42.useState)(null);
|
|
8260
|
+
const [inner, setInner] = (0, import_react42.useState)(DEFAULT_LOCATION);
|
|
7958
8261
|
const loc = location ?? inner;
|
|
7959
|
-
const dirty = (0,
|
|
7960
|
-
const [notice, setNotice] = (0,
|
|
7961
|
-
const [firstCode, setFirstCode] = (0,
|
|
7962
|
-
const move = (0,
|
|
8262
|
+
const dirty = (0, import_react42.useRef)(false);
|
|
8263
|
+
const [notice, setNotice] = (0, import_react42.useState)(null);
|
|
8264
|
+
const [firstCode, setFirstCode] = (0, import_react42.useState)(null);
|
|
8265
|
+
const move = (0, import_react42.useCallback)(
|
|
7963
8266
|
(next, how) => {
|
|
7964
8267
|
if (!location) setInner(next);
|
|
7965
8268
|
onLocationChange?.(next, how);
|
|
7966
8269
|
},
|
|
7967
8270
|
[location, onLocationChange]
|
|
7968
8271
|
);
|
|
7969
|
-
const go = (0,
|
|
8272
|
+
const go = (0, import_react42.useCallback)(
|
|
7970
8273
|
(patch, how = "push") => {
|
|
7971
8274
|
const leaving = patch.itemId !== void 0 || patch.mode !== void 0 || patch.vault !== void 0 || patch.view !== void 0;
|
|
7972
8275
|
const next = { ...loc, ...patch };
|
|
@@ -7978,16 +8281,16 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7978
8281
|
move(next, how);
|
|
7979
8282
|
};
|
|
7980
8283
|
if (leaving && dirty.current) {
|
|
7981
|
-
void (0,
|
|
8284
|
+
void (0, import_confirm_opener14.confirm)({ title: "Discard your changes?", description: "What you changed in this item is not saved.", confirmLabel: "Discard", cancelLabel: "Keep editing", variant: "destructive" }).then((ok) => ok && proceed());
|
|
7982
8285
|
return;
|
|
7983
8286
|
}
|
|
7984
8287
|
proceed();
|
|
7985
8288
|
},
|
|
7986
8289
|
[loc, move]
|
|
7987
8290
|
);
|
|
7988
|
-
const keyState = (0,
|
|
8291
|
+
const keyState = (0, import_react42.useRef)({ loc, go });
|
|
7989
8292
|
keyState.current = { loc, go };
|
|
7990
|
-
(0,
|
|
8293
|
+
(0, import_react42.useEffect)(() => {
|
|
7991
8294
|
const onKey = (e) => {
|
|
7992
8295
|
if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.altKey) return;
|
|
7993
8296
|
const root = rootRef.current;
|
|
@@ -8009,10 +8312,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8009
8312
|
document.addEventListener("keydown", onKey);
|
|
8010
8313
|
return () => document.removeEventListener("keydown", onKey);
|
|
8011
8314
|
}, []);
|
|
8012
|
-
const knobsRef = (0,
|
|
8315
|
+
const knobsRef = (0, import_react42.useRef)(host.knobs);
|
|
8013
8316
|
knobsRef.current = host.knobs;
|
|
8014
|
-
const [signedOut, setSignedOut] = (0,
|
|
8015
|
-
const load = (0,
|
|
8317
|
+
const [signedOut, setSignedOut] = (0, import_react42.useState)(false);
|
|
8318
|
+
const load = (0, import_react42.useCallback)(() => {
|
|
8016
8319
|
setError(null);
|
|
8017
8320
|
port.load().then((s) => {
|
|
8018
8321
|
setSnap(s);
|
|
@@ -8030,18 +8333,23 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8030
8333
|
knobsRef.current?.().catch(() => void 0);
|
|
8031
8334
|
port.lists.recents?.list().then(setRecents, () => void 0);
|
|
8032
8335
|
}, [port]);
|
|
8033
|
-
(0,
|
|
8034
|
-
(0,
|
|
8336
|
+
(0, import_react42.useEffect)(load, [load]);
|
|
8337
|
+
const inventoryRef = (0, import_react42.useRef)(onInventory);
|
|
8338
|
+
inventoryRef.current = onInventory;
|
|
8339
|
+
(0, import_react42.useEffect)(() => {
|
|
8340
|
+
if (snap) inventoryRef.current?.({ items, definitions: snap.definitions });
|
|
8341
|
+
}, [snap, items]);
|
|
8342
|
+
(0, import_react42.useEffect)(() => {
|
|
8035
8343
|
if (!loc.itemId || !port.lists.recents) return;
|
|
8036
8344
|
const id = loc.itemId;
|
|
8037
8345
|
port.lists.recents.record(id).then(() => setRecents((r) => [id, ...(r ?? []).filter((x) => x !== id)]), () => void 0);
|
|
8038
8346
|
}, [loc.itemId, port]);
|
|
8039
8347
|
const orgs = snap?.organizations ?? [];
|
|
8040
8348
|
const definitions = snap?.definitions ?? [];
|
|
8041
|
-
const inThisVault = (0,
|
|
8349
|
+
const inThisVault = (0, import_react42.useMemo)(() => items.filter((i) => inVault(i, loc.vault)), [items, loc.vault]);
|
|
8042
8350
|
const vaultMixesOwners = new Set(inThisVault.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
8043
|
-
const views = (0,
|
|
8044
|
-
const visible = (0,
|
|
8351
|
+
const views = (0, import_react42.useMemo)(() => buildViews(inThisVault, definitions, favorites, recents), [inThisVault, definitions, favorites, recents]);
|
|
8352
|
+
const visible = (0, import_react42.useMemo)(() => {
|
|
8045
8353
|
const filtered = inThisVault.filter((i) => {
|
|
8046
8354
|
if (!matchesQuery(i, loc.q)) return false;
|
|
8047
8355
|
if (loc.view === "favorites") return favorites?.has(i.id) ?? false;
|
|
@@ -8050,10 +8358,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8050
8358
|
return inView(i, loc.view);
|
|
8051
8359
|
});
|
|
8052
8360
|
if (loc.view === "recent" && recents) return [...filtered].sort((a, b) => recents.indexOf(a.id) - recents.indexOf(b.id));
|
|
8053
|
-
return sortItems(filtered, loc.sort);
|
|
8361
|
+
return sortItems(filtered, loc.sort, recents);
|
|
8054
8362
|
}, [inThisVault, loc.view, loc.q, loc.sort, favorites, recents, definitions]);
|
|
8055
|
-
const choices = (0,
|
|
8056
|
-
const matchingIds = (0,
|
|
8363
|
+
const choices = (0, import_react42.useMemo)(() => vaultChoices(items, orgs, loc.vault), [items, orgs, loc.vault]);
|
|
8364
|
+
const matchingIds = (0, import_react42.useMemo)(() => host.page ? new Set(host.page.matchingItemIds) : void 0, [host.page]);
|
|
8057
8365
|
const selected = loc.itemId ? items.find((i) => i.id === loc.itemId) ?? null : null;
|
|
8058
8366
|
const replaceItem = (next) => setItems((cur) => cur.some((i) => i.id === next.id) ? cur.map((i) => i.id === next.id ? next : i) : [...cur, next]);
|
|
8059
8367
|
const toggleFavorite = (id) => {
|
|
@@ -8077,35 +8385,35 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8077
8385
|
});
|
|
8078
8386
|
};
|
|
8079
8387
|
if (error) {
|
|
8080
|
-
return /* @__PURE__ */ (0,
|
|
8081
|
-
/* @__PURE__ */ (0,
|
|
8082
|
-
/* @__PURE__ */ (0,
|
|
8083
|
-
/* @__PURE__ */ (0,
|
|
8084
|
-
/* @__PURE__ */ (0,
|
|
8085
|
-
signedOut && host.signIn ? /* @__PURE__ */ (0,
|
|
8086
|
-
/* @__PURE__ */ (0,
|
|
8388
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { ref: rootRef, role: "alert", className: "flex h-full flex-col items-center justify-center gap-3 bg-background p-6 text-center text-sm", children: [
|
|
8389
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(SafeGlyph, { className: "size-8 text-muted-foreground" }),
|
|
8390
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "font-medium", children: "The vault couldn\u2019t open" }),
|
|
8391
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "max-w-xs text-muted-foreground", children: signedOut ? "You\u2019ve been signed out." : plainLoadError(error) }),
|
|
8392
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex gap-2", children: [
|
|
8393
|
+
signedOut && host.signIn ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_controls35.Button, { variant: "primary", onClick: host.signIn, children: "Sign in" }) : null,
|
|
8394
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_controls35.Button, { variant: signedOut && host.signIn ? "outline" : "primary", onClick: load, children: "Try again" })
|
|
8087
8395
|
] })
|
|
8088
8396
|
] });
|
|
8089
8397
|
}
|
|
8090
8398
|
if (!snap) {
|
|
8091
|
-
return /* @__PURE__ */ (0,
|
|
8092
|
-
/* @__PURE__ */ (0,
|
|
8093
|
-
/* @__PURE__ */ (0,
|
|
8094
|
-
/* @__PURE__ */ (0,
|
|
8095
|
-
/* @__PURE__ */ (0,
|
|
8399
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { ref: rootRef, className: "flex h-full bg-background", "aria-busy": "true", "aria-label": "Opening the vault", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "flex w-full max-w-sm flex-col gap-1 p-3", children: [0, 1, 2, 3, 4, 5, 6].map((n) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex h-12 items-center gap-3 px-2", children: [
|
|
8400
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "size-8 animate-pulse rounded-lg bg-muted" }),
|
|
8401
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex flex-1 flex-col gap-1.5", children: [
|
|
8402
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "h-3 w-2/3 animate-pulse rounded bg-muted" }),
|
|
8403
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "h-2.5 w-1/3 animate-pulse rounded bg-muted" })
|
|
8096
8404
|
] })
|
|
8097
8405
|
] }, n)) }) });
|
|
8098
8406
|
}
|
|
8099
8407
|
const hasFavorites = port.lists.favorites !== void 0;
|
|
8100
8408
|
const title = loc.vault === "all" && loc.view === "all" ? "All items" : viewLabel(loc.view, views);
|
|
8101
|
-
const compactHeader = mode === "full" ? void 0 : /* @__PURE__ */ (0,
|
|
8102
|
-
/* @__PURE__ */ (0,
|
|
8103
|
-
/* @__PURE__ */ (0,
|
|
8104
|
-
/* @__PURE__ */ (0,
|
|
8105
|
-
|
|
8409
|
+
const compactHeader = mode === "full" ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_auto] gap-2", children: [
|
|
8410
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(VaultSelect, { value: loc.vault, choices, onChange: (vault) => go({ vault, itemId: null, panel: null }) }),
|
|
8411
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_controls35.Select, { value: loc.view, onValueChange: (view) => go({ view, itemId: null, panel: null }), options: viewOptions(views, inThisVault.length, deleted.length, hasFavorites, port.lists.recents !== void 0, host.page !== void 0), "aria-label": "Show" }),
|
|
8412
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
8413
|
+
import_controls35.Button,
|
|
8106
8414
|
{
|
|
8107
8415
|
variant: loc.view === "authenticator" ? "outline" : "quiet",
|
|
8108
|
-
icon: /* @__PURE__ */ (0,
|
|
8416
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(LockGlyph, {}),
|
|
8109
8417
|
"aria-label": AUTHENTICATOR_LABEL,
|
|
8110
8418
|
"aria-pressed": loc.view === "authenticator",
|
|
8111
8419
|
title: AUTHENTICATOR_LABEL,
|
|
@@ -8113,46 +8421,50 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8113
8421
|
children: mode === "split" ? AUTHENTICATOR_LABEL : null
|
|
8114
8422
|
}
|
|
8115
8423
|
),
|
|
8116
|
-
/* @__PURE__ */ (0,
|
|
8117
|
-
/* @__PURE__ */ (0,
|
|
8118
|
-
/* @__PURE__ */ (0,
|
|
8119
|
-
/* @__PURE__ */ (0,
|
|
8120
|
-
/* @__PURE__ */ (0,
|
|
8424
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenu, { children: [
|
|
8425
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_design_system26.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_controls35.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(MoreGlyph, {}), "aria-label": "Vault actions" }) }),
|
|
8426
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuContent, { align: "end", children: [
|
|
8427
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "import" }), children: [
|
|
8428
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ImportGlyph, { className: "size-4" }),
|
|
8121
8429
|
"Import"
|
|
8122
8430
|
] }),
|
|
8123
|
-
/* @__PURE__ */ (0,
|
|
8124
|
-
/* @__PURE__ */ (0,
|
|
8431
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "export" }), children: [
|
|
8432
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ExportGlyph, { className: "size-4" }),
|
|
8125
8433
|
"Export"
|
|
8126
8434
|
] }),
|
|
8127
|
-
/* @__PURE__ */ (0,
|
|
8128
|
-
/* @__PURE__ */ (0,
|
|
8435
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "backup" }), children: [
|
|
8436
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(SafeGlyph, { className: "size-4" }),
|
|
8129
8437
|
"Backup"
|
|
8130
8438
|
] }),
|
|
8131
|
-
/* @__PURE__ */ (0,
|
|
8132
|
-
/* @__PURE__ */ (0,
|
|
8439
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "devices" }), children: [
|
|
8440
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ShieldGlyph, { className: "size-4" }),
|
|
8133
8441
|
"Browsers that fill"
|
|
8134
8442
|
] }),
|
|
8135
|
-
host.nativeImport ? /* @__PURE__ */ (0,
|
|
8136
|
-
/* @__PURE__ */ (0,
|
|
8443
|
+
host.nativeImport ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "import-passkeys" }), children: [
|
|
8444
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ImportGlyph, { className: "size-4" }),
|
|
8137
8445
|
"Import passkeys"
|
|
8138
8446
|
] }) : null,
|
|
8139
|
-
host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */ (0,
|
|
8140
|
-
/* @__PURE__ */ (0,
|
|
8447
|
+
host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: host.nativeProvider.openSetup, children: [
|
|
8448
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ShieldGlyph, { className: "size-4" }),
|
|
8141
8449
|
"System AutoFill"
|
|
8142
8450
|
] }) : null,
|
|
8143
|
-
host.lock?.lock ? /* @__PURE__ */ (0,
|
|
8144
|
-
/* @__PURE__ */ (0,
|
|
8451
|
+
host.lock?.lock ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => void host.lock?.lock?.(), children: [
|
|
8452
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(LockGlyph, { className: "size-4" }),
|
|
8145
8453
|
"Lock"
|
|
8454
|
+
] }) : null,
|
|
8455
|
+
host.openWebVault ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: host.openWebVault, children: [
|
|
8456
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ExternalGlyph, { className: "size-4" }),
|
|
8457
|
+
"Open on the web"
|
|
8146
8458
|
] }) : null
|
|
8147
8459
|
] })
|
|
8148
8460
|
] })
|
|
8149
8461
|
] });
|
|
8150
|
-
const viewHeader = /* @__PURE__ */ (0,
|
|
8462
|
+
const viewHeader = /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
8151
8463
|
compactHeader,
|
|
8152
|
-
/* @__PURE__ */ (0,
|
|
8464
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_controls35.SearchField, { value: loc.q, onChange: (e) => go({ q: e.target.value }, "replace"), placeholder: `Search ${viewLabel(loc.view, views)}`, "aria-label": `Search ${viewLabel(loc.view, views)}` })
|
|
8153
8465
|
] });
|
|
8154
8466
|
const viewProps = { port, host, items: inThisVault, deleted, definitions, query: loc.q, onOpen: (id) => go({ view: "all", itemId: id, mode: "view", panel: null }), onChanged: load, header: viewHeader };
|
|
8155
|
-
const pageView = loc.view === "page" && host.page && !loc.q ? /* @__PURE__ */ (0,
|
|
8467
|
+
const pageView = loc.view === "page" && host.page && !loc.q ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
8156
8468
|
PageView,
|
|
8157
8469
|
{
|
|
8158
8470
|
port,
|
|
@@ -8170,8 +8482,8 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8170
8482
|
...compactHeader ? { header: compactHeader } : {}
|
|
8171
8483
|
}
|
|
8172
8484
|
) : null;
|
|
8173
|
-
const specialView = pageView ?? (loc.view === "authenticator" ? /* @__PURE__ */ (0,
|
|
8174
|
-
const list = specialView ?? /* @__PURE__ */ (0,
|
|
8485
|
+
const specialView = pageView ?? (loc.view === "authenticator" ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(AuthenticatorView, { ...viewProps }) : loc.view === "trash" ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(TrashView, { ...viewProps }) : null);
|
|
8486
|
+
const list = specialView ?? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
8175
8487
|
ItemList,
|
|
8176
8488
|
{
|
|
8177
8489
|
title,
|
|
@@ -8185,6 +8497,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8185
8497
|
onQuery: (q) => go({ q }, "replace"),
|
|
8186
8498
|
sort: loc.sort,
|
|
8187
8499
|
onSort: (sort) => go({ sort }, "replace"),
|
|
8500
|
+
canSortViewed: port.lists.recents !== void 0,
|
|
8188
8501
|
onNew: () => go({ itemId: null, mode: "new", kind: null, panel: null }),
|
|
8189
8502
|
...matchingIds ? { matchingIds } : {},
|
|
8190
8503
|
...compactHeader ? { header: compactHeader } : {}
|
|
@@ -8198,9 +8511,9 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8198
8511
|
const onPanel = (panel2) => go({ panel: panel2 }, "push");
|
|
8199
8512
|
let detail;
|
|
8200
8513
|
if (loc.mode === "new" && !kindDefinition) {
|
|
8201
|
-
detail = /* @__PURE__ */ (0,
|
|
8514
|
+
detail = /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(NewItemFlow, { definitions, url: loc.url, onUrl: (url) => go({ url }, "replace"), onChoose: (kind, _name, url) => go({ kind, url }, "push"), onCancel: () => go({ mode: "view", kind: null, url: "", itemId: null }) });
|
|
8202
8515
|
} else if (loc.mode === "new" && kindDefinition) {
|
|
8203
|
-
detail = /* @__PURE__ */ (0,
|
|
8516
|
+
detail = /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
8204
8517
|
ItemPane,
|
|
8205
8518
|
{
|
|
8206
8519
|
port,
|
|
@@ -8232,7 +8545,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8232
8545
|
`new-${kindDefinition.key}`
|
|
8233
8546
|
);
|
|
8234
8547
|
} else if (selected) {
|
|
8235
|
-
detail = /* @__PURE__ */ (0,
|
|
8548
|
+
detail = /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
8236
8549
|
ItemPane,
|
|
8237
8550
|
{
|
|
8238
8551
|
port,
|
|
@@ -8276,23 +8589,23 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8276
8589
|
selected.id
|
|
8277
8590
|
);
|
|
8278
8591
|
} else if (loc.itemId) {
|
|
8279
|
-
detail = /* @__PURE__ */ (0,
|
|
8592
|
+
detail = /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Blank, { children: "This item is not in your vault, or you cannot see it." });
|
|
8280
8593
|
} else {
|
|
8281
|
-
detail = /* @__PURE__ */ (0,
|
|
8594
|
+
detail = /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Blank, { children: visible.length === 0 ? "" : "Select an item" });
|
|
8282
8595
|
}
|
|
8283
8596
|
const [panelName, panelArg] = (loc.panel ?? "").split(/:(.*)/s);
|
|
8284
8597
|
const closePanel = () => go({ panel: null }, "push");
|
|
8285
8598
|
const vaultPanelProps = { port, host, items, definitions, organizations: orgs, onClose: closePanel, onChanged: load };
|
|
8286
8599
|
let panel = null;
|
|
8287
|
-
if (panelName === "import") panel = /* @__PURE__ */ (0,
|
|
8288
|
-
else if (panelName === "devices") panel = /* @__PURE__ */ (0,
|
|
8289
|
-
else if (panelName === "approve" && panelArg) panel = /* @__PURE__ */ (0,
|
|
8290
|
-
else if (panelName === "import-passkeys" && host.nativeImport) panel = /* @__PURE__ */ (0,
|
|
8291
|
-
else if (panelName === "export") panel = /* @__PURE__ */ (0,
|
|
8292
|
-
else if (panelName === "backup") panel = /* @__PURE__ */ (0,
|
|
8600
|
+
if (panelName === "import") panel = /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ImportWithLimits, { ...vaultPanelProps, knobs: host.knobs });
|
|
8601
|
+
else if (panelName === "devices") panel = /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(DevicesPanel, { ...vaultPanelProps });
|
|
8602
|
+
else if (panelName === "approve" && panelArg) panel = /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ApprovePanel, { ...vaultPanelProps, ...approvalFromParams(panelArg, new URLSearchParams(globalThis.location?.search ?? "")) });
|
|
8603
|
+
else if (panelName === "import-passkeys" && host.nativeImport) panel = /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(NativeImportPanel, { ...vaultPanelProps, bridge: host.nativeImport, readLimits: port.native.limits, activeOrganizationId: orgs[0]?.id ?? null });
|
|
8604
|
+
else if (panelName === "export") panel = /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ExportPanel, { ...vaultPanelProps });
|
|
8605
|
+
else if (panelName === "backup") panel = /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(BackupPanel, { ...vaultPanelProps });
|
|
8293
8606
|
else if (panelName && selected && ITEM_PANELS[panelName]) {
|
|
8294
8607
|
const P = ITEM_PANELS[panelName];
|
|
8295
|
-
panel = /* @__PURE__ */ (0,
|
|
8608
|
+
panel = /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
8296
8609
|
P,
|
|
8297
8610
|
{
|
|
8298
8611
|
item: selected,
|
|
@@ -8315,17 +8628,17 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8315
8628
|
}
|
|
8316
8629
|
const grid = mode === "full" ? "grid-cols-[15rem_21rem_minmax(0,1fr)]" : mode === "split" ? "grid-cols-[19rem_minmax(0,1fr)]" : "grid-cols-1";
|
|
8317
8630
|
const shown = panesShown(mode, specialView !== null, showingDetail);
|
|
8318
|
-
return /* @__PURE__ */ (0,
|
|
8319
|
-
snap.unavailable.length > 0 ? /* @__PURE__ */ (0,
|
|
8320
|
-
/* @__PURE__ */ (0,
|
|
8631
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { ref: rootRef, className: "flex h-full min-h-0 w-full flex-col bg-background text-foreground", children: [
|
|
8632
|
+
snap.unavailable.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-4 py-2 text-sm", children: [
|
|
8633
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "min-w-0 flex-1 truncate text-warning", children: [
|
|
8321
8634
|
"Couldn\u2019t load ",
|
|
8322
8635
|
snap.unavailable.join(", "),
|
|
8323
8636
|
". Showing the rest."
|
|
8324
8637
|
] }),
|
|
8325
|
-
/* @__PURE__ */ (0,
|
|
8638
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: "shrink-0 text-primary hover:underline", onClick: load, children: "Try again" })
|
|
8326
8639
|
] }) : null,
|
|
8327
|
-
/* @__PURE__ */ (0,
|
|
8328
|
-
mode === "full" ? /* @__PURE__ */ (0,
|
|
8640
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: `grid min-h-0 w-full flex-1 ${grid} overflow-hidden`, children: [
|
|
8641
|
+
mode === "full" ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
8329
8642
|
VaultSidebar,
|
|
8330
8643
|
{
|
|
8331
8644
|
vault: loc.vault,
|
|
@@ -8344,10 +8657,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8344
8657
|
hasPage: host.page !== void 0
|
|
8345
8658
|
}
|
|
8346
8659
|
) : null,
|
|
8347
|
-
shown.list ? /* @__PURE__ */ (0,
|
|
8660
|
+
shown.list ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: specialView && mode !== "stack" ? "col-span-2 min-h-0" : "min-h-0", children: list }) : null,
|
|
8348
8661
|
shown.detail ? detail : null,
|
|
8349
8662
|
panel,
|
|
8350
|
-
firstCode ? /* @__PURE__ */ (0,
|
|
8663
|
+
firstCode ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(FirstCodePanel, { port, item: firstCode, onClose: () => setFirstCode(null), onDone: () => setFirstCode(null) }) : null
|
|
8351
8664
|
] })
|
|
8352
8665
|
] });
|
|
8353
8666
|
}
|
|
@@ -8355,8 +8668,8 @@ function plainLoadError(message2) {
|
|
|
8355
8668
|
return /load failed|failed to fetch|network|timed? ?out/i.test(message2) ? "The connection dropped. Check you\u2019re online, then try again." : message2;
|
|
8356
8669
|
}
|
|
8357
8670
|
function Blank({ children }) {
|
|
8358
|
-
return /* @__PURE__ */ (0,
|
|
8359
|
-
/* @__PURE__ */ (0,
|
|
8671
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex h-full flex-col items-center justify-center gap-3 bg-background text-sm text-muted-foreground", children: [
|
|
8672
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(SafeGlyph, { className: "size-10 text-disabled-foreground" }),
|
|
8360
8673
|
children
|
|
8361
8674
|
] });
|
|
8362
8675
|
}
|
|
@@ -8726,6 +9039,20 @@ function createListsPort(ctx, door) {
|
|
|
8726
9039
|
|
|
8727
9040
|
// src/sharing/api.ts
|
|
8728
9041
|
var account6 = __toESM(require("@ai-matrx/api/account"), 1);
|
|
9042
|
+
|
|
9043
|
+
// src/secret-field-in.ts
|
|
9044
|
+
function secretFieldIn(s) {
|
|
9045
|
+
const envKey = s.envKey?.trim() || null;
|
|
9046
|
+
return {
|
|
9047
|
+
field_key: fieldKeyOf(s.label),
|
|
9048
|
+
value: s.value,
|
|
9049
|
+
handling: s.handling ?? "revealable",
|
|
9050
|
+
...envKey ? { env_key: envKey } : {},
|
|
9051
|
+
...envKey && s.injectIntoSandbox ? { inject_into_sandbox: true } : {}
|
|
9052
|
+
};
|
|
9053
|
+
}
|
|
9054
|
+
|
|
9055
|
+
// src/sharing/api.ts
|
|
8729
9056
|
function grantOf(w) {
|
|
8730
9057
|
const org = Boolean(w.organization_id);
|
|
8731
9058
|
return {
|
|
@@ -8825,7 +9152,7 @@ function createSharingPort(ctx, options = {}) {
|
|
|
8825
9152
|
non_secret_fields: [...meta.map((f) => ({ key: f.key, label: f.label, value: draft.values[f.key] ?? "" })), ...draft.custom.filter((c) => c.label.trim() !== "").map((c) => ({ key: c.key || fieldKeyOf(c.label), label: c.label, value: c.value }))],
|
|
8826
9153
|
fields: [
|
|
8827
9154
|
...encrypted.map((f) => ({ field_key: f.key, value: draft.values[f.key] ?? "", handling: f.handling })),
|
|
8828
|
-
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(
|
|
9155
|
+
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(secretFieldIn)
|
|
8829
9156
|
]
|
|
8830
9157
|
}
|
|
8831
9158
|
});
|
|
@@ -9111,14 +9438,14 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9111
9438
|
login_urls: draft.loginUrls,
|
|
9112
9439
|
// A login a person saves with its website is offered on that website (the server's own
|
|
9113
9440
|
// default is off, which made "Save a login" on a page answer "No saved login" there).
|
|
9114
|
-
...draft.loginUrls.length > 0 ? { browser_fill_enabled: true } : {},
|
|
9441
|
+
...draft.browser ? { uri_match_mode: draft.browser.uriMatchMode, browser_fill_enabled: draft.browser.browserFillEnabled } : draft.loginUrls.length > 0 ? { browser_fill_enabled: true } : {},
|
|
9115
9442
|
notes: draft.notes || null,
|
|
9116
9443
|
principal: organizationId ? { type: "organization", organization_id: organizationId } : { type: "user" },
|
|
9117
9444
|
initiation: "user",
|
|
9118
9445
|
non_secret_fields: [...meta.map((f) => ({ key: f.key, label: f.label, value: draft.values[f.key] ?? "" })), ...draft.custom.filter((c) => c.label.trim() !== "").map((c) => ({ key: c.key || fieldKeyOf(c.label), label: c.label, value: c.value }))],
|
|
9119
9446
|
fields: [
|
|
9120
9447
|
...encrypted.map((f) => ({ field_key: f.key, value: draft.values[f.key] ?? "", handling: f.handling })),
|
|
9121
|
-
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(
|
|
9448
|
+
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(secretFieldIn),
|
|
9122
9449
|
// Backup codes on a type that does not declare them (a website login): their own encrypted field.
|
|
9123
9450
|
...!declared.some((f) => f.key === RECOVERY_CODES_KEY) && (draft.values[RECOVERY_CODES_KEY] ?? "").trim() !== "" ? [{ field_key: RECOVERY_CODES_KEY, value: parseRecoveryCodes(draft.values[RECOVERY_CODES_KEY] ?? "").join("\n"), handling: "revealable", description: "One-time account recovery codes" }] : []
|
|
9124
9451
|
]
|
|
@@ -9158,7 +9485,7 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9158
9485
|
}
|
|
9159
9486
|
for (const s of draft.secrets) {
|
|
9160
9487
|
if (s.label.trim() === "" || s.value === "") continue;
|
|
9161
|
-
await account9.addField(api, { path: { item_id: item.id }, body:
|
|
9488
|
+
await account9.addField(api, { path: { item_id: item.id }, body: secretFieldIn(s) }, opts);
|
|
9162
9489
|
}
|
|
9163
9490
|
for (const id of draft.removed) await account9.deleteField(api, { path: { item_id: item.id, field_id: id } }, opts);
|
|
9164
9491
|
return { item: await refetch(item.id, item.owner), notice: null };
|
|
@@ -9183,4 +9510,42 @@ function createVaultKnobs(client, address) {
|
|
|
9183
9510
|
return snap.resolved;
|
|
9184
9511
|
};
|
|
9185
9512
|
}
|
|
9513
|
+
|
|
9514
|
+
// src/agent-context.ts
|
|
9515
|
+
var hostOf = (url) => {
|
|
9516
|
+
try {
|
|
9517
|
+
return new URL(/^[a-z][a-z0-9+.-]*:\/\//i.test(url) ? url : `https://${url}`).host || null;
|
|
9518
|
+
} catch {
|
|
9519
|
+
return null;
|
|
9520
|
+
}
|
|
9521
|
+
};
|
|
9522
|
+
function providerOf(item, definitions) {
|
|
9523
|
+
return definitions.find((d) => d.key === item.definitionKey)?.providerKey ?? null;
|
|
9524
|
+
}
|
|
9525
|
+
function vaultItemFacts(item, definitions) {
|
|
9526
|
+
const provider = providerOf(item, definitions);
|
|
9527
|
+
const hosts = item.loginUrls.map(hostOf).filter((h) => Boolean(h));
|
|
9528
|
+
const keys = item.fields.map((f) => f.key).filter((k) => !isAuthenticatorStorage(k));
|
|
9529
|
+
return [
|
|
9530
|
+
`Name: ${item.name}`,
|
|
9531
|
+
...item.definitionLabel ? [`Type: ${item.definitionLabel}`] : [],
|
|
9532
|
+
...provider ? [`Provider: ${provider}`] : [],
|
|
9533
|
+
...hosts.length ? [`Sites: ${hosts.join(", ")}`] : [],
|
|
9534
|
+
`Owner: ${item.owner.label}`,
|
|
9535
|
+
`Status: ${item.turnedOff ? "turned off" : "active"}`,
|
|
9536
|
+
...item.accessMode ? [`Access: ${item.accessMode}`] : [],
|
|
9537
|
+
...item.tags.length ? [`Tags: ${item.tags.join(", ")}`] : [],
|
|
9538
|
+
...keys.length ? [`Fields: ${keys.join(", ")}`] : [],
|
|
9539
|
+
...item.authenticator ? ["Has a one-time password"] : []
|
|
9540
|
+
];
|
|
9541
|
+
}
|
|
9542
|
+
function vaultInventoryScope(inventory, clicked = null) {
|
|
9543
|
+
const { items, definitions } = inventory;
|
|
9544
|
+
const providers = [...new Set(items.map((i) => providerOf(i, definitions)).filter((p) => Boolean(p)))];
|
|
9545
|
+
const content = clicked ? vaultItemFacts(clicked, definitions) : [`Vault \u2014 ${items.length} ${items.length === 1 ? "item" : "items"}`, ...items.map((i) => `\u2022 ${i.name}${i.definitionLabel ? ` \u2014 ${i.definitionLabel}` : ""}`)];
|
|
9546
|
+
return { content: content.join("\n"), credential_count: items.length, credential_labels: items.map((i) => i.name), credential_providers: providers };
|
|
9547
|
+
}
|
|
9548
|
+
function itemIdAt(target) {
|
|
9549
|
+
return target?.closest("[data-item]")?.getAttribute("data-item") ?? null;
|
|
9550
|
+
}
|
|
9186
9551
|
//# sourceMappingURL=index.cjs.map
|