@ai-matrx/vault 0.1.15 → 0.1.16
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 +9 -1
- package/dist/index.cjs +1148 -783
- 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 +1079 -714
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -101,10 +101,10 @@ var init_keepass_xml_worker_client = __esm({
|
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
// src/VaultApp.tsx
|
|
104
|
-
import { useCallback as useCallback5, useEffect as useEffect23, useMemo as useMemo6, useRef as useRef19, useState as
|
|
105
|
-
import { DropdownMenu as DropdownMenu6, DropdownMenuContent as DropdownMenuContent6, DropdownMenuItem as
|
|
106
|
-
import { Button as
|
|
107
|
-
import { confirm as
|
|
104
|
+
import { useCallback as useCallback5, useEffect as useEffect23, useMemo as useMemo6, useRef as useRef19, useState as useState41 } from "react";
|
|
105
|
+
import { DropdownMenu as DropdownMenu6, DropdownMenuContent as DropdownMenuContent6, DropdownMenuItem as DropdownMenuItem6, DropdownMenuTrigger as DropdownMenuTrigger6, LookScope } from "@ai-matrx/design-system";
|
|
106
|
+
import { Button as Button34, SearchField as SearchField4, Select as Select12 } from "@ai-matrx/design-system/controls";
|
|
107
|
+
import { confirm as confirm14 } from "@ai-matrx/kit/confirm-opener";
|
|
108
108
|
|
|
109
109
|
// src/notice.tsx
|
|
110
110
|
import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
|
|
@@ -638,12 +638,12 @@ var ROW_GRID = {
|
|
|
638
638
|
roomy: "grid-cols-[9rem_minmax(0,1fr)_auto] gap-x-3 px-4",
|
|
639
639
|
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"
|
|
640
640
|
};
|
|
641
|
-
function VaultRow({ label, hint, children, actions, top = false, className }) {
|
|
641
|
+
function VaultRow({ label, hint: hint2, children, actions, top = false, className }) {
|
|
642
642
|
const room = useContext4(Room);
|
|
643
643
|
return /* @__PURE__ */ jsxs4("div", { className: cn2("grid min-h-11 py-1", ROW_GRID[room ?? "viewport"], top ? "items-start" : "items-center", className), children: [
|
|
644
644
|
/* @__PURE__ */ jsxs4("div", { className: cn2("flex min-w-0 flex-col text-xs leading-tight text-muted-foreground", top && "pt-2.5"), children: [
|
|
645
645
|
/* @__PURE__ */ jsx4("span", { className: room === "roomy" ? "truncate" : room === "compact" ? "line-clamp-2 break-words" : "line-clamp-2 break-words sm:truncate", children: label }),
|
|
646
|
-
|
|
646
|
+
hint2 ? /* @__PURE__ */ jsx4("span", { className: "line-clamp-2 break-words text-xs text-disabled-foreground", children: hint2 }) : null
|
|
647
647
|
] }),
|
|
648
648
|
/* @__PURE__ */ jsx4("div", { className: cn2("min-w-0 text-sm", top && "py-1.5"), children }),
|
|
649
649
|
/* @__PURE__ */ jsx4("div", { className: cn2("flex items-center gap-0.5", top && "pt-1"), children: actions })
|
|
@@ -753,14 +753,14 @@ function TurnOnButton({ label, onTurnOn }) {
|
|
|
753
753
|
}
|
|
754
754
|
);
|
|
755
755
|
}
|
|
756
|
-
function PlainRow({ label, value, hint, openUrl, extra, multiline = false }) {
|
|
756
|
+
function PlainRow({ label, value, hint: hint2, openUrl, extra, multiline = false }) {
|
|
757
757
|
const copyValue2 = useCopy();
|
|
758
758
|
const isUrl = /^https?:\/\//i.test(value);
|
|
759
759
|
return /* @__PURE__ */ jsx5(
|
|
760
760
|
VaultRow,
|
|
761
761
|
{
|
|
762
762
|
label,
|
|
763
|
-
hint,
|
|
763
|
+
hint: hint2,
|
|
764
764
|
top: multiline,
|
|
765
765
|
actions: /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
766
766
|
extra,
|
|
@@ -790,13 +790,13 @@ function PlainRow({ label, value, hint, openUrl, extra, multiline = false }) {
|
|
|
790
790
|
function AddRow({ label, onAdd, children = "Add" }) {
|
|
791
791
|
return /* @__PURE__ */ jsx5(VaultRow, { label, children: onAdd ? /* @__PURE__ */ jsx5("button", { type: "button", className: "text-sm text-muted-foreground hover:text-primary", onClick: onAdd, children }) : /* @__PURE__ */ jsx5("span", { className: "text-disabled-foreground", children: "\u2014" }) });
|
|
792
792
|
}
|
|
793
|
-
function EditRow({ label, hint, value, onChange, placeholder, secret = false, multiline = false, onRemove, removeLabel, actions, autoFocus, onBlur, inputMode }) {
|
|
793
|
+
function EditRow({ label, hint: hint2, value, onChange, placeholder, secret = false, multiline = false, onRemove, removeLabel, actions, autoFocus, onBlur, inputMode }) {
|
|
794
794
|
const [shown, setShown] = useState5(false);
|
|
795
795
|
return /* @__PURE__ */ jsx5(
|
|
796
796
|
VaultRow,
|
|
797
797
|
{
|
|
798
798
|
label,
|
|
799
|
-
hint,
|
|
799
|
+
hint: hint2,
|
|
800
800
|
top: multiline,
|
|
801
801
|
actions: /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
802
802
|
secret && value ? /* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: shown ? /* @__PURE__ */ jsx5(EyeOffGlyph, {}) : /* @__PURE__ */ jsx5(EyeGlyph, {}), "aria-label": shown ? "Hide" : "Show", onClick: () => setShown((s) => !s) }) : null,
|
|
@@ -807,7 +807,7 @@ function EditRow({ label, hint, value, onChange, placeholder, secret = false, mu
|
|
|
807
807
|
}
|
|
808
808
|
);
|
|
809
809
|
}
|
|
810
|
-
function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove }) {
|
|
810
|
+
function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove, extra, onPasteValue }) {
|
|
811
811
|
const [shown, setShown] = useState5(false);
|
|
812
812
|
return /* @__PURE__ */ jsx5(
|
|
813
813
|
VaultRow,
|
|
@@ -815,9 +815,25 @@ function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove }) {
|
|
|
815
815
|
label: /* @__PURE__ */ jsx5(Field2, { className: "w-full", value: label, onChange: (e) => onLabel(e.target.value), placeholder: "Name", "aria-label": "Field name" }),
|
|
816
816
|
actions: /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
817
817
|
secret && value ? /* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: shown ? /* @__PURE__ */ jsx5(EyeOffGlyph, {}) : /* @__PURE__ */ jsx5(EyeGlyph, {}), "aria-label": shown ? "Hide" : "Show", onClick: () => setShown((x) => !x) }) : null,
|
|
818
|
+
extra,
|
|
818
819
|
/* @__PURE__ */ jsx5(Button2, { variant: "quiet", removes: true, icon: /* @__PURE__ */ jsx5(XGlyph, {}), "aria-label": "Remove field", onClick: onRemove })
|
|
819
820
|
] }),
|
|
820
|
-
children: /* @__PURE__ */ jsx5(
|
|
821
|
+
children: /* @__PURE__ */ jsx5(
|
|
822
|
+
Field2,
|
|
823
|
+
{
|
|
824
|
+
className: "w-full",
|
|
825
|
+
value,
|
|
826
|
+
onChange: (e) => onValue(e.target.value),
|
|
827
|
+
onPaste: onPasteValue ? (e) => {
|
|
828
|
+
if (onPasteValue(e.clipboardData.getData("text"))) e.preventDefault();
|
|
829
|
+
} : void 0,
|
|
830
|
+
type: secret && !shown ? "password" : "text",
|
|
831
|
+
placeholder: secret ? "Secret value" : "Value",
|
|
832
|
+
autoComplete: "off",
|
|
833
|
+
spellCheck: false,
|
|
834
|
+
"aria-label": label ? `${label} value` : "Field value"
|
|
835
|
+
}
|
|
836
|
+
)
|
|
821
837
|
}
|
|
822
838
|
);
|
|
823
839
|
}
|
|
@@ -831,7 +847,7 @@ import { formatRelativeTime } from "@ai-matrx/kit/format";
|
|
|
831
847
|
|
|
832
848
|
// src/model.ts
|
|
833
849
|
var DEFAULT_LOCATION = { vault: "all", view: "all", q: "", sort: "name", itemId: null, mode: "view", kind: null, url: "", panel: null };
|
|
834
|
-
var SORTS = ["name", "website", "updated", "created"];
|
|
850
|
+
var SORTS = ["name", "name-desc", "website", "updated", "created", "viewed"];
|
|
835
851
|
function locationFromParams(params, itemId = params.get("item")) {
|
|
836
852
|
const sort = params.get("sort");
|
|
837
853
|
const mode = params.get("mode");
|
|
@@ -901,10 +917,15 @@ function siteDomainOf(host) {
|
|
|
901
917
|
const keep = TWO_PART_SUFFIX.has(sld) && tld.length <= 3 ? 3 : 2;
|
|
902
918
|
return labels.slice(-keep).join(".");
|
|
903
919
|
}
|
|
904
|
-
function sortItems(items, sort) {
|
|
920
|
+
function sortItems(items, sort, recents) {
|
|
905
921
|
const out = [...items];
|
|
906
|
-
const byName = (a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
|
|
922
|
+
const byName = (a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base", numeric: true });
|
|
907
923
|
if (sort === "name") return out.sort(byName);
|
|
924
|
+
if (sort === "name-desc") return out.sort((a, b) => byName(b, a));
|
|
925
|
+
if (sort === "viewed") {
|
|
926
|
+
const at = new Map((recents ?? []).map((id, i) => [id, i]));
|
|
927
|
+
return out.sort((a, b) => (at.get(a.id) ?? Infinity) - (at.get(b.id) ?? Infinity) || byName(a, b));
|
|
928
|
+
}
|
|
908
929
|
if (sort === "website")
|
|
909
930
|
return out.sort((a, b) => {
|
|
910
931
|
const x = loginSiteOf(a), y = loginSiteOf(b);
|
|
@@ -2596,6 +2617,18 @@ function withoutCode(codes, index) {
|
|
|
2596
2617
|
const left = codes.filter((_, i) => i !== index);
|
|
2597
2618
|
return left.length ? left.join("\n") : null;
|
|
2598
2619
|
}
|
|
2620
|
+
function parseEnvAssignment(text) {
|
|
2621
|
+
const m = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=(.*)$/s.exec(text.trim());
|
|
2622
|
+
if (!m || /\n/.test(m[2] ?? "")) return null;
|
|
2623
|
+
let value = (m[2] ?? "").trim();
|
|
2624
|
+
const q = value[0];
|
|
2625
|
+
if ((q === '"' || q === "'") && value.length >= 2 && value.endsWith(q)) value = value.slice(1, -1);
|
|
2626
|
+
return value ? { key: m[1] ?? "", value } : null;
|
|
2627
|
+
}
|
|
2628
|
+
function labelFromEnvKey(key) {
|
|
2629
|
+
const words = key.toLowerCase().split(/[_\s]+/).filter(Boolean).join(" ");
|
|
2630
|
+
return words ? words.charAt(0).toUpperCase() + words.slice(1) : key;
|
|
2631
|
+
}
|
|
2599
2632
|
|
|
2600
2633
|
// src/fields/SettingsPanels.tsx
|
|
2601
2634
|
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
@@ -2993,11 +3026,11 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
|
|
|
2993
3026
|
/* @__PURE__ */ jsx15(Button11, { variant: "primary", disabled: !candidate, onClick: use, children: useLabel })
|
|
2994
3027
|
] });
|
|
2995
3028
|
}
|
|
2996
|
-
function OptionLine({ label, hint, children }) {
|
|
3029
|
+
function OptionLine({ label, hint: hint2, children }) {
|
|
2997
3030
|
return /* @__PURE__ */ jsxs14("div", { className: "flex min-h-9 items-center justify-between gap-3", children: [
|
|
2998
3031
|
/* @__PURE__ */ jsxs14("div", { className: "flex min-w-0 flex-col", children: [
|
|
2999
3032
|
/* @__PURE__ */ jsx15("span", { className: "truncate text-sm text-foreground", children: label }),
|
|
3000
|
-
|
|
3033
|
+
hint2 ? /* @__PURE__ */ jsx15("span", { className: "truncate text-xs text-muted-foreground", children: hint2 }) : null
|
|
3001
3034
|
] }),
|
|
3002
3035
|
/* @__PURE__ */ jsx15("div", { className: "flex shrink-0 items-center", children })
|
|
3003
3036
|
] });
|
|
@@ -4720,17 +4753,18 @@ function Notices({ draft }) {
|
|
|
4720
4753
|
}
|
|
4721
4754
|
|
|
4722
4755
|
// src/ItemList.tsx
|
|
4723
|
-
import { useEffect as useEffect17, useRef as useRef15, useState as
|
|
4724
|
-
import { DropdownMenu as DropdownMenu4, DropdownMenuContent as DropdownMenuContent4, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger as DropdownMenuTrigger4 } from "@ai-matrx/design-system";
|
|
4756
|
+
import { useEffect as useEffect17, useRef as useRef15, useState as useState28 } from "react";
|
|
4757
|
+
import { DropdownMenu as DropdownMenu4, DropdownMenuContent as DropdownMenuContent4, DropdownMenuItem as DropdownMenuItem4, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator as DropdownMenuSeparator4, DropdownMenuTrigger as DropdownMenuTrigger4 } from "@ai-matrx/design-system";
|
|
4725
4758
|
import { cn as cn13 } from "@ai-matrx/design-system";
|
|
4726
|
-
import { Button as
|
|
4759
|
+
import { Button as Button23, SearchField } from "@ai-matrx/design-system/controls";
|
|
4760
|
+
import { CopyIcon as CopyIcon7 } from "@ai-matrx/design-system/icons";
|
|
4727
4761
|
|
|
4728
4762
|
// src/ItemPane.tsx
|
|
4729
|
-
import { useEffect as useEffect16, useMemo as useMemo3, useRef as useRef14, useState as
|
|
4763
|
+
import { useEffect as useEffect16, useMemo as useMemo3, useRef as useRef14, useState as useState27 } from "react";
|
|
4730
4764
|
import { DropdownMenu as DropdownMenu3, DropdownMenuContent as DropdownMenuContent3, DropdownMenuItem as DropdownMenuItem3, DropdownMenuSeparator as DropdownMenuSeparator3, DropdownMenuTrigger as DropdownMenuTrigger3 } from "@ai-matrx/design-system";
|
|
4731
4765
|
import { cn as cn12 } from "@ai-matrx/design-system";
|
|
4732
|
-
import { Badge as Badge7, Button as
|
|
4733
|
-
import { confirm as
|
|
4766
|
+
import { Badge as Badge7, Button as Button22, CONTROLS_CONTAINER_CLASS, OptionCombobox, Switch as Switch6 } from "@ai-matrx/design-system/controls";
|
|
4767
|
+
import { confirm as confirm10 } from "@ai-matrx/kit/confirm-opener";
|
|
4734
4768
|
|
|
4735
4769
|
// src/activity/FilesSection.tsx
|
|
4736
4770
|
import { formatFileSize as formatFileSize2 } from "@ai-matrx/kit/format";
|
|
@@ -4751,12 +4785,13 @@ var PROTECTION = [
|
|
|
4751
4785
|
function FilesSection({ item, port, editing, onChanged }) {
|
|
4752
4786
|
const confirmed = useConfirmed();
|
|
4753
4787
|
const canEdit = editing && item.capabilities.canEdit;
|
|
4788
|
+
const canAdd = item.capabilities.canEdit;
|
|
4754
4789
|
const [busy, setBusy] = useState20(null);
|
|
4755
4790
|
const [error, setError] = useState20(null);
|
|
4756
4791
|
const [pending, setPending] = useState20(null);
|
|
4757
4792
|
const [dragging, setDragging] = useState20(false);
|
|
4758
4793
|
const picker = useRef13(null);
|
|
4759
|
-
if (!
|
|
4794
|
+
if (!canAdd && item.attachments.length === 0) return null;
|
|
4760
4795
|
async function run(key, work, fallback) {
|
|
4761
4796
|
setBusy(key);
|
|
4762
4797
|
setError(null);
|
|
@@ -4778,7 +4813,7 @@ function FilesSection({ item, port, editing, onChanged }) {
|
|
|
4778
4813
|
setPending(file);
|
|
4779
4814
|
}
|
|
4780
4815
|
function drop(e) {
|
|
4781
|
-
if (!
|
|
4816
|
+
if (!canAdd) return;
|
|
4782
4817
|
e.preventDefault();
|
|
4783
4818
|
setDragging(false);
|
|
4784
4819
|
choose(e.dataTransfer.files[0]);
|
|
@@ -4791,22 +4826,23 @@ function FilesSection({ item, port, editing, onChanged }) {
|
|
|
4791
4826
|
"div",
|
|
4792
4827
|
{
|
|
4793
4828
|
className: cn9("rounded-xl", dragging && "outline outline-2 outline-primary"),
|
|
4794
|
-
onDragOver:
|
|
4829
|
+
onDragOver: canAdd ? (e) => {
|
|
4795
4830
|
e.preventDefault();
|
|
4796
4831
|
setDragging(true);
|
|
4797
4832
|
} : void 0,
|
|
4798
|
-
onDragLeave:
|
|
4799
|
-
onDrop:
|
|
4833
|
+
onDragLeave: canAdd ? () => setDragging(false) : void 0,
|
|
4834
|
+
onDrop: canAdd ? drop : void 0,
|
|
4800
4835
|
children: /* @__PURE__ */ jsxs19(
|
|
4801
4836
|
VaultSection,
|
|
4802
4837
|
{
|
|
4803
|
-
title: "Files",
|
|
4804
|
-
actions:
|
|
4838
|
+
title: editing || item.attachments.length > 0 || pending ? "Files" : void 0,
|
|
4839
|
+
actions: canAdd && (editing || item.attachments.length > 0) ? /* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(PlusGlyph, {}), disabled: busy !== null, onClick: () => picker.current?.click(), children: "Add file" }) : void 0,
|
|
4805
4840
|
children: [
|
|
4806
|
-
|
|
4841
|
+
canAdd ? /* @__PURE__ */ jsx20("input", { ref: picker, type: "file", hidden: true, "aria-label": "Choose a file", onChange: (e) => {
|
|
4807
4842
|
choose(e.target.files?.[0]);
|
|
4808
4843
|
e.target.value = "";
|
|
4809
4844
|
} }) : null,
|
|
4845
|
+
!editing && canAdd && item.attachments.length === 0 && !pending ? /* @__PURE__ */ jsx20(AddRow, { label: "Files", onAdd: () => picker.current?.click(), children: "Add file" }) : null,
|
|
4810
4846
|
item.attachments.map(
|
|
4811
4847
|
(a) => canEdit ? /* @__PURE__ */ jsx20(EditableFile, { port, item, file: a, busy, run, onDownload: () => void download(a), onTooBig: () => setError(TOO_BIG) }, a.id) : /* @__PURE__ */ jsx20(
|
|
4812
4848
|
VaultRow,
|
|
@@ -4819,7 +4855,7 @@ function FilesSection({ item, port, editing, onChanged }) {
|
|
|
4819
4855
|
a.id
|
|
4820
4856
|
)
|
|
4821
4857
|
),
|
|
4822
|
-
|
|
4858
|
+
canAdd && pending ? /* @__PURE__ */ jsx20(NewFile, { file: pending, busy: busy === "add", onCancel: () => setPending(null), onAdd: async (details) => {
|
|
4823
4859
|
if (await run("add", () => port.activity.addFile(item, pending, details), "The file could not be added.")) setPending(null);
|
|
4824
4860
|
} }) : null,
|
|
4825
4861
|
canEdit && item.attachments.length === 0 && !pending ? /* @__PURE__ */ jsx20("div", { className: "px-4 py-3 text-sm text-muted-foreground", children: "Drop a file here or choose Add file" }) : null,
|
|
@@ -4940,6 +4976,57 @@ function confirmSeal(label) {
|
|
|
4940
4976
|
variant: "destructive"
|
|
4941
4977
|
});
|
|
4942
4978
|
}
|
|
4979
|
+
function DraftFilesSection({ files, onFiles }) {
|
|
4980
|
+
const [pending, setPending] = useState20(null);
|
|
4981
|
+
const [error, setError] = useState20(null);
|
|
4982
|
+
const [dragging, setDragging] = useState20(false);
|
|
4983
|
+
const picker = useRef13(null);
|
|
4984
|
+
const choose = (file) => {
|
|
4985
|
+
if (!file) return;
|
|
4986
|
+
if (fileTooBig(file.size)) return setError(TOO_BIG);
|
|
4987
|
+
setError(null);
|
|
4988
|
+
setPending(file);
|
|
4989
|
+
};
|
|
4990
|
+
return /* @__PURE__ */ jsx20(
|
|
4991
|
+
"div",
|
|
4992
|
+
{
|
|
4993
|
+
className: cn9("rounded-xl", dragging && "outline outline-2 outline-primary"),
|
|
4994
|
+
onDragOver: (e) => {
|
|
4995
|
+
e.preventDefault();
|
|
4996
|
+
setDragging(true);
|
|
4997
|
+
},
|
|
4998
|
+
onDragLeave: () => setDragging(false),
|
|
4999
|
+
onDrop: (e) => {
|
|
5000
|
+
e.preventDefault();
|
|
5001
|
+
setDragging(false);
|
|
5002
|
+
choose(e.dataTransfer.files[0]);
|
|
5003
|
+
},
|
|
5004
|
+
children: /* @__PURE__ */ jsxs19(VaultSection, { title: files.length > 0 || pending ? "Files" : void 0, actions: files.length > 0 ? /* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(PlusGlyph, {}), onClick: () => picker.current?.click(), children: "Add file" }) : void 0, children: [
|
|
5005
|
+
/* @__PURE__ */ jsx20("input", { ref: picker, type: "file", hidden: true, "aria-label": "Choose a file", onChange: (e) => {
|
|
5006
|
+
choose(e.target.files?.[0]);
|
|
5007
|
+
e.target.value = "";
|
|
5008
|
+
} }),
|
|
5009
|
+
files.map((f, i) => /* @__PURE__ */ jsx20(VaultRow, { label: f.label, hint: f.description ?? void 0, actions: /* @__PURE__ */ jsx20(Button16, { variant: "quiet", removes: true, icon: /* @__PURE__ */ jsx20(XGlyph, {}), "aria-label": `Remove ${f.label}`, onClick: () => onFiles(files.filter((_, j) => j !== i)) }), children: /* @__PURE__ */ jsxs19("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
5010
|
+
/* @__PURE__ */ jsx20("span", { className: "truncate", children: f.file.name }),
|
|
5011
|
+
/* @__PURE__ */ jsx20("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatFileSize2(f.file.size) })
|
|
5012
|
+
] }) }, `${f.file.name}-${i}`)),
|
|
5013
|
+
pending ? /* @__PURE__ */ jsx20(
|
|
5014
|
+
NewFile,
|
|
5015
|
+
{
|
|
5016
|
+
file: pending,
|
|
5017
|
+
busy: false,
|
|
5018
|
+
onCancel: () => setPending(null),
|
|
5019
|
+
onAdd: async (d) => {
|
|
5020
|
+
onFiles([...files, { file: pending, ...d }]);
|
|
5021
|
+
setPending(null);
|
|
5022
|
+
}
|
|
5023
|
+
}
|
|
5024
|
+
) : files.length === 0 ? /* @__PURE__ */ jsx20(AddRow, { label: "Files", onAdd: () => picker.current?.click(), children: "Add file" }) : null,
|
|
5025
|
+
error ? /* @__PURE__ */ jsx20("p", { role: "alert", className: "px-4 py-2 text-sm text-destructive", children: error }) : null
|
|
5026
|
+
] })
|
|
5027
|
+
}
|
|
5028
|
+
);
|
|
5029
|
+
}
|
|
4943
5030
|
|
|
4944
5031
|
// src/fields/RecoveryCodesRow.tsx
|
|
4945
5032
|
import { useState as useState21 } from "react";
|
|
@@ -5047,6 +5134,134 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
|
|
|
5047
5134
|
);
|
|
5048
5135
|
}
|
|
5049
5136
|
|
|
5137
|
+
// src/fields/DraftRows.tsx
|
|
5138
|
+
import { useState as useState22 } from "react";
|
|
5139
|
+
import { Button as Button18, Field as Field8, SegmentedControl as SegmentedControl5, Select as Select7, Switch as Switch5 } from "@ai-matrx/design-system/controls";
|
|
5140
|
+
import { RecordId } from "@ai-matrx/design-system";
|
|
5141
|
+
import { confirm as confirm7 } from "@ai-matrx/kit/confirm-opener";
|
|
5142
|
+
import { Fragment as Fragment15, jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
5143
|
+
var HANDLINGS = ["visible", "revealable", "sealed"];
|
|
5144
|
+
var hint = (text, tone = "muted") => /* @__PURE__ */ jsx22("span", { className: tone === "destructive" ? "text-destructive" : void 0, title: text, children: text });
|
|
5145
|
+
var hasSecretSettings = (s) => Boolean(s.envKey?.trim() || s.injectIntoSandbox || s.handling && s.handling !== "revealable");
|
|
5146
|
+
function SecretBuilderRow({ field, onChange, onRemove }) {
|
|
5147
|
+
const [open, setOpen] = useState22(hasSecretSettings(field));
|
|
5148
|
+
const env = field.envKey ?? "";
|
|
5149
|
+
const envProblem = envKeyProblem(env);
|
|
5150
|
+
const envOk = env.trim() !== "" && !envProblem;
|
|
5151
|
+
const handling = field.handling ?? "revealable";
|
|
5152
|
+
const name = field.label.trim() || "Secret";
|
|
5153
|
+
const chooseHandling = async (next) => {
|
|
5154
|
+
if (next === handling) return;
|
|
5155
|
+
if (next === "sealed") {
|
|
5156
|
+
const ok = await confirm7({
|
|
5157
|
+
title: `Seal ${name} permanently?`,
|
|
5158
|
+
description: "Once saved, no person can see or copy it again; only automation can use it.",
|
|
5159
|
+
confirmLabel: "Seal",
|
|
5160
|
+
variant: "destructive"
|
|
5161
|
+
});
|
|
5162
|
+
if (!ok) return;
|
|
5163
|
+
}
|
|
5164
|
+
onChange({ handling: next });
|
|
5165
|
+
};
|
|
5166
|
+
return /* @__PURE__ */ jsxs21(Fragment15, { children: [
|
|
5167
|
+
/* @__PURE__ */ jsx22(
|
|
5168
|
+
CustomEditRow,
|
|
5169
|
+
{
|
|
5170
|
+
label: field.label,
|
|
5171
|
+
value: field.value,
|
|
5172
|
+
secret: true,
|
|
5173
|
+
onLabel: (v) => onChange({ label: v }),
|
|
5174
|
+
onValue: (v) => onChange({ value: v }),
|
|
5175
|
+
onRemove,
|
|
5176
|
+
onPasteValue: (text) => {
|
|
5177
|
+
const a = parseEnvAssignment(text);
|
|
5178
|
+
if (!a) return false;
|
|
5179
|
+
onChange({ envKey: a.key, value: a.value, ...field.label.trim() ? {} : { label: labelFromEnvKey(a.key) } });
|
|
5180
|
+
setOpen(true);
|
|
5181
|
+
return true;
|
|
5182
|
+
},
|
|
5183
|
+
extra: /* @__PURE__ */ jsxs21(Fragment15, { children: [
|
|
5184
|
+
handling !== "sealed" ? /* @__PURE__ */ jsx22(GenerateButton, { onUse: (v) => onChange({ value: v }) }) : null,
|
|
5185
|
+
/* @__PURE__ */ jsx22(Button18, { variant: "quiet", icon: /* @__PURE__ */ jsx22(SlidersGlyph, {}), "aria-label": `${name} settings`, pressed: open, onClick: () => setOpen((o) => !o) })
|
|
5186
|
+
] })
|
|
5187
|
+
}
|
|
5188
|
+
),
|
|
5189
|
+
open ? /* @__PURE__ */ jsxs21(Fragment15, { children: [
|
|
5190
|
+
/* @__PURE__ */ jsx22(VaultRow, { label: "Env key", hint: envProblem ? hint(envProblem, "destructive") : hint("The name sandboxes and workflows use"), children: /* @__PURE__ */ jsx22(
|
|
5191
|
+
Field8,
|
|
5192
|
+
{
|
|
5193
|
+
className: "w-full font-mono",
|
|
5194
|
+
"aria-label": `${name} env key`,
|
|
5195
|
+
"aria-invalid": Boolean(envProblem),
|
|
5196
|
+
placeholder: "e.g. GITHUB_TOKEN",
|
|
5197
|
+
autoComplete: "off",
|
|
5198
|
+
spellCheck: false,
|
|
5199
|
+
value: env,
|
|
5200
|
+
onChange: (e) => onChange({ envKey: e.target.value, ...e.target.value.trim() ? {} : { injectIntoSandbox: false } })
|
|
5201
|
+
}
|
|
5202
|
+
) }),
|
|
5203
|
+
/* @__PURE__ */ jsx22(VaultRow, { label: "Who can see it", hint: hint(HANDLING_WORDS[handling].hint), children: /* @__PURE__ */ jsx22(
|
|
5204
|
+
SegmentedControl5,
|
|
5205
|
+
{
|
|
5206
|
+
"aria-label": `Who can see ${name}`,
|
|
5207
|
+
value: handling,
|
|
5208
|
+
onValueChange: (v) => void chooseHandling(v),
|
|
5209
|
+
data: HANDLINGS.map((h) => ({ value: h, label: HANDLING_WORDS[h].label, title: HANDLING_WORDS[h].hint }))
|
|
5210
|
+
}
|
|
5211
|
+
) }),
|
|
5212
|
+
/* @__PURE__ */ jsx22(VaultRow, { label: "Use in sandbox", hint: envOk ? hint("Sandboxes get it as an env variable") : hint("Needs an env key"), children: /* @__PURE__ */ jsx22(Switch5, { "aria-label": `Use ${name} in sandbox`, checked: envOk && field.injectIntoSandbox === true, disabled: !envOk, onCheckedChange: (v) => onChange({ injectIntoSandbox: v }) }) })
|
|
5213
|
+
] }) : null
|
|
5214
|
+
] });
|
|
5215
|
+
}
|
|
5216
|
+
function withMfaMethod(custom, v) {
|
|
5217
|
+
const rest = custom.filter((c) => c.key !== MFA_METHOD_KEY);
|
|
5218
|
+
return v === "sms" || v === "push_or_other" ? [...rest, { key: MFA_METHOD_KEY, label: "Two-factor method", value: v }] : rest;
|
|
5219
|
+
}
|
|
5220
|
+
function DraftTwoFactorRow({ custom, onCustom }) {
|
|
5221
|
+
const value = custom.find((c) => c.key === MFA_METHOD_KEY)?.value || "none";
|
|
5222
|
+
return /* @__PURE__ */ jsx22(VaultRow, { label: "Two-factor", children: /* @__PURE__ */ jsx22(
|
|
5223
|
+
Select7,
|
|
5224
|
+
{
|
|
5225
|
+
value: value === "sms" || value === "push_or_other" ? value : "none",
|
|
5226
|
+
"aria-label": "Two-factor method",
|
|
5227
|
+
options: MFA_OPTIONS.map((o) => ({ value: o.value, label: o.label })),
|
|
5228
|
+
onValueChange: (v) => onCustom(withMfaMethod(custom, v))
|
|
5229
|
+
}
|
|
5230
|
+
) });
|
|
5231
|
+
}
|
|
5232
|
+
var defaultBrowserSettings = (hasWebsite) => ({ uriMatchMode: "host", browserFillEnabled: hasWebsite });
|
|
5233
|
+
function DraftBrowserRows({ value, hasWebsite, onChange }) {
|
|
5234
|
+
return /* @__PURE__ */ jsxs21(Fragment15, { children: [
|
|
5235
|
+
/* @__PURE__ */ jsx22(VaultRow, { label: "Website matching", hint: hint(MATCH_WORDS[value.uriMatchMode].hint), children: /* @__PURE__ */ jsx22(
|
|
5236
|
+
Select7,
|
|
5237
|
+
{
|
|
5238
|
+
"aria-label": "Website matching",
|
|
5239
|
+
value: value.uriMatchMode,
|
|
5240
|
+
options: MATCH_MODES.map((m) => ({ value: m, label: MATCH_WORDS[m].label })),
|
|
5241
|
+
onValueChange: (m) => onChange({ ...value, uriMatchMode: m })
|
|
5242
|
+
}
|
|
5243
|
+
) }),
|
|
5244
|
+
/* @__PURE__ */ jsx22(VaultRow, { label: "Fill in browser", hint: hint(hasWebsite ? value.browserFillEnabled ? "Offered on matching pages" : "Never filled automatically" : "Add a website first"), children: /* @__PURE__ */ jsx22(Switch5, { "aria-label": "Fill in browser", checked: hasWebsite && value.browserFillEnabled, disabled: !hasWebsite, onCheckedChange: (v) => onChange({ ...value, browserFillEnabled: v }) }) })
|
|
5245
|
+
] });
|
|
5246
|
+
}
|
|
5247
|
+
function AssignResult({ sent, onAnother, onDone }) {
|
|
5248
|
+
return /* @__PURE__ */ jsxs21("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: [
|
|
5249
|
+
/* @__PURE__ */ jsxs21(VaultSection, { title: /* @__PURE__ */ jsxs21("span", { className: "flex items-center gap-1.5", children: [
|
|
5250
|
+
/* @__PURE__ */ jsx22(CheckGlyph, { className: "size-4 text-success" }),
|
|
5251
|
+
"Sent to ",
|
|
5252
|
+
sent.recipientEmail
|
|
5253
|
+
] }), children: [
|
|
5254
|
+
/* @__PURE__ */ jsx22(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx22("span", { className: "block truncate", children: sent.name }) }),
|
|
5255
|
+
/* @__PURE__ */ jsx22(VaultRow, { label: "Item ID", children: /* @__PURE__ */ jsx22(RecordId, { value: sent.id, label: "Item" }) }),
|
|
5256
|
+
/* @__PURE__ */ jsx22(VaultRow, { label: "Password", children: /* @__PURE__ */ jsx22("span", { className: "block truncate text-muted-foreground", children: sent.generated ? "Generated privately, never shown to you" : "Theirs now; you keep no access" }) })
|
|
5257
|
+
] }),
|
|
5258
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex justify-end gap-2", children: [
|
|
5259
|
+
/* @__PURE__ */ jsx22(Button18, { variant: "outline", icon: /* @__PURE__ */ jsx22(PlusGlyph, {}), onClick: onAnother, children: "Create another" }),
|
|
5260
|
+
/* @__PURE__ */ jsx22(Button18, { variant: "primary", onClick: onDone, children: "Done" })
|
|
5261
|
+
] })
|
|
5262
|
+
] });
|
|
5263
|
+
}
|
|
5264
|
+
|
|
5050
5265
|
// src/ItemPane.tsx
|
|
5051
5266
|
import { HistoryIcon, SettingsIcon, UsersIcon as UsersIcon2 } from "@ai-matrx/design-system/icons";
|
|
5052
5267
|
import { dropKeptDraft, keepDraft, readKeptDraft } from "@ai-matrx/kit/drafts";
|
|
@@ -5173,15 +5388,15 @@ function targetLabel(t) {
|
|
|
5173
5388
|
}
|
|
5174
5389
|
|
|
5175
5390
|
// src/extension/UseOnSiteButton.tsx
|
|
5176
|
-
import { useState as
|
|
5177
|
-
import { Button as
|
|
5178
|
-
import { jsx as
|
|
5391
|
+
import { useState as useState23 } from "react";
|
|
5392
|
+
import { Button as Button19 } from "@ai-matrx/design-system/controls";
|
|
5393
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
5179
5394
|
function canUseOnSite(item, pageUrl) {
|
|
5180
5395
|
return item.capabilities.canEdit && isFillablePage(pageUrl) && !coversPage(item.loginUrls, item.uriMatchMode, pageUrl);
|
|
5181
5396
|
}
|
|
5182
5397
|
function UseOnSiteButton({ port, item, pageUrl, onChanged }) {
|
|
5183
5398
|
const notify = useNotify();
|
|
5184
|
-
const [busy, setBusy] =
|
|
5399
|
+
const [busy, setBusy] = useState23(false);
|
|
5185
5400
|
if (!canUseOnSite(item, pageUrl)) return null;
|
|
5186
5401
|
const site = pageSite(pageUrl);
|
|
5187
5402
|
const run = async () => {
|
|
@@ -5196,13 +5411,13 @@ function UseOnSiteButton({ port, item, pageUrl, onChanged }) {
|
|
|
5196
5411
|
setBusy(false);
|
|
5197
5412
|
}
|
|
5198
5413
|
};
|
|
5199
|
-
return /* @__PURE__ */
|
|
5414
|
+
return /* @__PURE__ */ jsx23(Button19, { variant: "outline", icon: /* @__PURE__ */ jsx23(PlusGlyph, {}), disabled: busy, onClick: () => void run(), title: `Fill this login on ${site}`, children: "Use here" });
|
|
5200
5415
|
}
|
|
5201
5416
|
|
|
5202
5417
|
// src/sharing/SharePanel.tsx
|
|
5203
|
-
import { useEffect as useEffect15, useState as
|
|
5204
|
-
import { confirm as
|
|
5205
|
-
import { Button as
|
|
5418
|
+
import { useEffect as useEffect15, useState as useState26 } from "react";
|
|
5419
|
+
import { confirm as confirm9 } from "@ai-matrx/kit/confirm-opener";
|
|
5420
|
+
import { Button as Button21, DisclosureHeader as DisclosureHeader3, Field as Field10, RegionSkeleton, Select as Select9 } from "@ai-matrx/design-system/controls";
|
|
5206
5421
|
import { cn as cn11 } from "@ai-matrx/design-system";
|
|
5207
5422
|
import { UsersIcon } from "@ai-matrx/design-system/icons";
|
|
5208
5423
|
|
|
@@ -5258,18 +5473,18 @@ function shareSummary(grants) {
|
|
|
5258
5473
|
var MEMBER_CHOICE_DEFAULT = "default";
|
|
5259
5474
|
|
|
5260
5475
|
// src/sharing/parts.tsx
|
|
5261
|
-
import { useState as
|
|
5476
|
+
import { useState as useState24 } from "react";
|
|
5262
5477
|
import { cn as cn10 } from "@ai-matrx/design-system";
|
|
5263
|
-
import { jsx as
|
|
5478
|
+
import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
5264
5479
|
var message = (e, fallback) => {
|
|
5265
5480
|
const m = e instanceof Error && e.message ? e.message : fallback;
|
|
5266
5481
|
return copyRefusal(m) ?? m;
|
|
5267
5482
|
};
|
|
5268
5483
|
function useConfirmedChange() {
|
|
5269
5484
|
const confirmed = useConfirmed();
|
|
5270
|
-
const [busy, setBusy] =
|
|
5271
|
-
const [error, setError] =
|
|
5272
|
-
const [notice, setNotice] =
|
|
5485
|
+
const [busy, setBusy] = useState24(null);
|
|
5486
|
+
const [error, setError] = useState24(null);
|
|
5487
|
+
const [notice, setNotice] = useState24(null);
|
|
5273
5488
|
async function run(key, fn, done) {
|
|
5274
5489
|
setBusy(key);
|
|
5275
5490
|
setError(null);
|
|
@@ -5288,33 +5503,33 @@ function useConfirmedChange() {
|
|
|
5288
5503
|
return { busy, error, notice, run, setNotice };
|
|
5289
5504
|
}
|
|
5290
5505
|
function AccessLine({ glyph: G, who, meta, children }) {
|
|
5291
|
-
return /* @__PURE__ */
|
|
5292
|
-
/* @__PURE__ */
|
|
5293
|
-
/* @__PURE__ */
|
|
5294
|
-
/* @__PURE__ */
|
|
5295
|
-
meta ? /* @__PURE__ */
|
|
5506
|
+
return /* @__PURE__ */ jsxs22("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
|
|
5507
|
+
/* @__PURE__ */ jsx24(G, { className: "size-4 shrink-0 text-muted-foreground" }),
|
|
5508
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex min-w-0 flex-1 items-baseline gap-2", children: [
|
|
5509
|
+
/* @__PURE__ */ jsx24("span", { className: "truncate text-sm text-foreground", children: who }),
|
|
5510
|
+
meta ? /* @__PURE__ */ jsx24("span", { className: "shrink-0 text-xs text-muted-foreground", children: meta }) : null
|
|
5296
5511
|
] }),
|
|
5297
|
-
/* @__PURE__ */
|
|
5512
|
+
/* @__PURE__ */ jsx24("div", { className: "flex shrink-0 items-center gap-0.5", children })
|
|
5298
5513
|
] });
|
|
5299
5514
|
}
|
|
5300
5515
|
function StatusLine({ error, notice }) {
|
|
5301
5516
|
if (!error && !notice) return null;
|
|
5302
|
-
return /* @__PURE__ */
|
|
5517
|
+
return /* @__PURE__ */ jsx24("p", { className: cn10("min-w-0 flex-1 line-clamp-2 text-sm", error ? "text-destructive" : "text-success"), title: error ?? notice ?? void 0, children: error ?? notice });
|
|
5303
5518
|
}
|
|
5304
5519
|
|
|
5305
5520
|
// src/sharing/MovePanel.tsx
|
|
5306
|
-
import { useState as
|
|
5307
|
-
import { confirm as
|
|
5308
|
-
import { Button as
|
|
5309
|
-
import { jsx as
|
|
5521
|
+
import { useState as useState25 } from "react";
|
|
5522
|
+
import { confirm as confirm8 } from "@ai-matrx/kit/confirm-opener";
|
|
5523
|
+
import { Button as Button20, Field as Field9, Select as Select8 } from "@ai-matrx/design-system/controls";
|
|
5524
|
+
import { jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
5310
5525
|
var NONE = "__none__";
|
|
5311
5526
|
function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
5312
5527
|
const { busy, error, notice, run, setNotice } = useConfirmedChange();
|
|
5313
5528
|
const moves = moveDestinations(item, organizations);
|
|
5314
5529
|
const copies = copyDestinations(organizations, item);
|
|
5315
|
-
const [moveTo, setMoveTo] =
|
|
5316
|
-
const [copyTo, setCopyTo] =
|
|
5317
|
-
const [email, setEmail] =
|
|
5530
|
+
const [moveTo, setMoveTo] = useState25("");
|
|
5531
|
+
const [copyTo, setCopyTo] = useState25("");
|
|
5532
|
+
const [email, setEmail] = useState25("");
|
|
5318
5533
|
const passkey = isPasskey(item);
|
|
5319
5534
|
const canMove = item.capabilities.canManage && !passkey && moves.length > 0;
|
|
5320
5535
|
const canGive = item.capabilities.canManage && item.owner.kind === "me" && !passkey;
|
|
@@ -5324,7 +5539,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5324
5539
|
const move = async () => {
|
|
5325
5540
|
if (!moveChoice) return;
|
|
5326
5541
|
const to = destinationOf(moveChoice.value);
|
|
5327
|
-
const ok = await
|
|
5542
|
+
const ok = await confirm8({
|
|
5328
5543
|
title: `Move to ${moveChoice.label}?`,
|
|
5329
5544
|
description: `"${item.name}" stays the same item, so everything using it keeps working. ${itemMoveConsequence(item, to)}.`,
|
|
5330
5545
|
confirmLabel: "Move"
|
|
@@ -5339,7 +5554,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5339
5554
|
const give = async () => {
|
|
5340
5555
|
const to = email.trim();
|
|
5341
5556
|
if (!isEmail(to)) return;
|
|
5342
|
-
const ok = await
|
|
5557
|
+
const ok = await confirm8({ title: "Give ownership away?", description: giveDescription(item, to), confirmLabel: "Give ownership", variant: "destructive" });
|
|
5343
5558
|
if (!ok) return;
|
|
5344
5559
|
const out = await run("give", () => port.sharing.giveOwnership(item, to));
|
|
5345
5560
|
if (!out) return;
|
|
@@ -5352,25 +5567,25 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5352
5567
|
if (made) onChanged();
|
|
5353
5568
|
};
|
|
5354
5569
|
const nothing = !canMove && !canGive && !canCopy;
|
|
5355
|
-
return /* @__PURE__ */
|
|
5570
|
+
return /* @__PURE__ */ jsx25(
|
|
5356
5571
|
Panel,
|
|
5357
5572
|
{
|
|
5358
5573
|
title: "Move or copy",
|
|
5359
5574
|
size: "md",
|
|
5360
5575
|
onClose,
|
|
5361
|
-
footer: /* @__PURE__ */
|
|
5362
|
-
children: nothing ? /* @__PURE__ */
|
|
5363
|
-
canMove && moves.length > 0 ? /* @__PURE__ */
|
|
5576
|
+
footer: /* @__PURE__ */ jsx25(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx25(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ jsx25(Button20, { variant: "primary", onClick: onClose, children: "Done" }) }),
|
|
5577
|
+
children: nothing ? /* @__PURE__ */ jsx25(VaultSection, { children: /* @__PURE__ */ jsx25(Empty, { children: passkey ? "A passkey stays where it was created." : "Only the owner can move or give this item." }) }) : /* @__PURE__ */ jsxs23(VaultSection, { children: [
|
|
5578
|
+
canMove && moves.length > 0 ? /* @__PURE__ */ jsx25(
|
|
5364
5579
|
VaultRow,
|
|
5365
5580
|
{
|
|
5366
5581
|
label: "Move to",
|
|
5367
5582
|
hint: moveChoice ? itemMoveConsequence(item, destinationOf(moveChoice.value)) : void 0,
|
|
5368
|
-
actions: /* @__PURE__ */
|
|
5369
|
-
children: /* @__PURE__ */
|
|
5583
|
+
actions: /* @__PURE__ */ jsx25(Button20, { variant: "outline", disabled: busy !== null || !moveChoice, onClick: () => void move(), children: "Move" }),
|
|
5584
|
+
children: /* @__PURE__ */ jsx25(Select8, { className: "w-full", "aria-label": "Move to", value: moveTo || NONE, onValueChange: (v) => setMoveTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...moves] })
|
|
5370
5585
|
}
|
|
5371
5586
|
) : null,
|
|
5372
|
-
canGive ? /* @__PURE__ */
|
|
5373
|
-
|
|
5587
|
+
canGive ? /* @__PURE__ */ jsx25(VaultRow, { label: "Give to", hint: "You lose all access; your shares end", actions: /* @__PURE__ */ jsx25(Button20, { variant: "danger", disabled: busy !== null || !isEmail(email), onClick: () => void give(), children: "Give" }), children: /* @__PURE__ */ jsx25(
|
|
5588
|
+
Field9,
|
|
5374
5589
|
{
|
|
5375
5590
|
className: "w-full",
|
|
5376
5591
|
type: "email",
|
|
@@ -5383,18 +5598,18 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5383
5598
|
onChange: (e) => setEmail(e.target.value)
|
|
5384
5599
|
}
|
|
5385
5600
|
) }) : null,
|
|
5386
|
-
canCopy && copies.length > 0 ? /* @__PURE__ */
|
|
5601
|
+
canCopy && copies.length > 0 ? /* @__PURE__ */ jsx25(VaultRow, { label: "Copy to", hint: "A separate item; edits no longer sync", actions: /* @__PURE__ */ jsx25(Button20, { variant: "outline", disabled: busy !== null || !copyChoice, onClick: () => void copy(), children: "Copy" }), children: /* @__PURE__ */ jsx25(Select8, { className: "w-full", "aria-label": "Copy to", value: copyTo || NONE, onValueChange: (v) => setCopyTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...copies] }) }) : null
|
|
5387
5602
|
] })
|
|
5388
5603
|
}
|
|
5389
5604
|
);
|
|
5390
5605
|
}
|
|
5391
5606
|
|
|
5392
5607
|
// src/sharing/SharePanel.tsx
|
|
5393
|
-
import { Fragment as
|
|
5608
|
+
import { Fragment as Fragment16, jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
5394
5609
|
function useGrants(port, item) {
|
|
5395
|
-
const [grants, setGrants] =
|
|
5396
|
-
const [loadError, setLoadError] =
|
|
5397
|
-
const [nonce, setNonce] =
|
|
5610
|
+
const [grants, setGrants] = useState26(null);
|
|
5611
|
+
const [loadError, setLoadError] = useState26(null);
|
|
5612
|
+
const [nonce, setNonce] = useState26(0);
|
|
5398
5613
|
const allowed = item.capabilities.canManage;
|
|
5399
5614
|
useEffect15(() => {
|
|
5400
5615
|
if (!allowed) return;
|
|
@@ -5413,9 +5628,9 @@ function useGrants(port, item) {
|
|
|
5413
5628
|
function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
5414
5629
|
const { grants, setGrants, loadError, reload } = useGrants(port, item);
|
|
5415
5630
|
const { busy, error, notice, run } = useConfirmedChange();
|
|
5416
|
-
const [email, setEmail] =
|
|
5417
|
-
const [level, setLevel] =
|
|
5418
|
-
const [more, setMore] =
|
|
5631
|
+
const [email, setEmail] = useState26("");
|
|
5632
|
+
const [level, setLevel] = useState26("use");
|
|
5633
|
+
const [more, setMore] = useState26(false);
|
|
5419
5634
|
const isOrg = item.owner.kind === "organization" && item.owner.organizationId !== null;
|
|
5420
5635
|
const orgName = item.owner.label;
|
|
5421
5636
|
const people = (grants ?? []).filter((g) => g.kind === "person");
|
|
@@ -5434,7 +5649,7 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5434
5649
|
if (updated) setGrants((all) => (all ?? []).map((x) => x.id === g.id ? { ...updated, label: updated.label || g.label } : x));
|
|
5435
5650
|
};
|
|
5436
5651
|
const revoke = async (g) => {
|
|
5437
|
-
const ok = await
|
|
5652
|
+
const ok = await confirm9({
|
|
5438
5653
|
title: g.kind === "organization" ? `Remove from ${g.label}?` : "Remove access?",
|
|
5439
5654
|
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.`,
|
|
5440
5655
|
confirmLabel: "Remove",
|
|
@@ -5450,7 +5665,7 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5450
5665
|
const setMode = async (mode) => {
|
|
5451
5666
|
if (mode === (item.accessMode === "restricted" ? "restricted" : "all_members")) return;
|
|
5452
5667
|
if (mode === "all_members" && people.length > 0) {
|
|
5453
|
-
const ok = await
|
|
5668
|
+
const ok = await confirm9({
|
|
5454
5669
|
title: "Open to every member?",
|
|
5455
5670
|
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.`,
|
|
5456
5671
|
confirmLabel: "Open to members",
|
|
@@ -5465,20 +5680,20 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5465
5680
|
}
|
|
5466
5681
|
};
|
|
5467
5682
|
if (!item.capabilities.canManage) {
|
|
5468
|
-
return /* @__PURE__ */
|
|
5683
|
+
return /* @__PURE__ */ jsx26(Panel, { title: "Share", size: "md", onClose, footer: /* @__PURE__ */ jsx26(Button21, { variant: "primary", onClick: onClose, children: "Done" }), children: /* @__PURE__ */ jsx26(VaultSection, { children: /* @__PURE__ */ jsx26(Empty, { children: "Only the owner can change who has access." }) }) });
|
|
5469
5684
|
}
|
|
5470
|
-
return /* @__PURE__ */
|
|
5685
|
+
return /* @__PURE__ */ jsxs24(
|
|
5471
5686
|
Panel,
|
|
5472
5687
|
{
|
|
5473
5688
|
title: "Share",
|
|
5474
5689
|
size: "md",
|
|
5475
5690
|
onClose,
|
|
5476
|
-
footer: /* @__PURE__ */
|
|
5691
|
+
footer: /* @__PURE__ */ jsx26(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx26(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ jsx26(Button21, { variant: "primary", onClick: onClose, children: "Done" }) }),
|
|
5477
5692
|
children: [
|
|
5478
|
-
/* @__PURE__ */
|
|
5479
|
-
isOrg ? /* @__PURE__ */
|
|
5480
|
-
isOrg ? /* @__PURE__ */
|
|
5481
|
-
|
|
5693
|
+
/* @__PURE__ */ jsxs24(VaultSection, { title: "Who has access", children: [
|
|
5694
|
+
isOrg ? /* @__PURE__ */ jsx26(AccessLine, { glyph: BuildingGlyph, who: `${orgName} admins`, children: /* @__PURE__ */ jsx26("span", { className: "px-2 text-sm text-muted-foreground", children: "Full access" }) }) : /* @__PURE__ */ jsx26(AccessLine, { glyph: PersonGlyph, who: "You", meta: "Owner", children: /* @__PURE__ */ jsx26("span", { className: "px-2 text-sm text-muted-foreground", children: "Full access" }) }),
|
|
5695
|
+
isOrg ? /* @__PURE__ */ jsx26(AccessLine, { glyph: UsersIcon, who: `${orgName} members`, children: /* @__PURE__ */ jsx26(
|
|
5696
|
+
Select9,
|
|
5482
5697
|
{
|
|
5483
5698
|
variant: "inline",
|
|
5484
5699
|
align: "end",
|
|
@@ -5492,14 +5707,14 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5492
5707
|
]
|
|
5493
5708
|
}
|
|
5494
5709
|
) }) : null,
|
|
5495
|
-
loadError ? /* @__PURE__ */
|
|
5496
|
-
/* @__PURE__ */
|
|
5497
|
-
/* @__PURE__ */
|
|
5710
|
+
loadError ? /* @__PURE__ */ jsx26(AccessLine, { glyph: XGlyph, who: /* @__PURE__ */ jsx26("span", { className: "text-destructive", children: loadError }), children: /* @__PURE__ */ jsx26(Button21, { variant: "quiet", onClick: reload, children: "Retry" }) }) : grants === null ? /* @__PURE__ */ jsx26(RegionSkeleton, { shape: "rows", count: 2, "aria-label": "Loading who has access", className: "px-3 sm:px-4" }) : grants.map((g) => /* @__PURE__ */ jsxs24(AccessLine, { glyph: g.kind === "organization" ? BuildingGlyph : PersonGlyph, who: g.label, ...g.kind === "organization" ? { meta: "Organization vault" } : {}, children: [
|
|
5711
|
+
/* @__PURE__ */ jsx26(Select9, { 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 }),
|
|
5712
|
+
/* @__PURE__ */ jsx26(Button21, { variant: "quiet", removes: true, icon: /* @__PURE__ */ jsx26(XGlyph, {}), "aria-label": `Remove ${g.label}`, disabled: busy !== null, onClick: () => void revoke(g) })
|
|
5498
5713
|
] }, g.id)),
|
|
5499
|
-
/* @__PURE__ */
|
|
5500
|
-
/* @__PURE__ */
|
|
5501
|
-
/* @__PURE__ */
|
|
5502
|
-
|
|
5714
|
+
/* @__PURE__ */ jsxs24("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
|
|
5715
|
+
/* @__PURE__ */ jsx26(PersonGlyph, { className: "size-4 shrink-0 text-muted-foreground" }),
|
|
5716
|
+
/* @__PURE__ */ jsx26(
|
|
5717
|
+
Field10,
|
|
5503
5718
|
{
|
|
5504
5719
|
className: "min-w-0 flex-1",
|
|
5505
5720
|
type: "email",
|
|
@@ -5519,13 +5734,13 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5519
5734
|
}
|
|
5520
5735
|
}
|
|
5521
5736
|
),
|
|
5522
|
-
/* @__PURE__ */
|
|
5523
|
-
/* @__PURE__ */
|
|
5737
|
+
/* @__PURE__ */ jsx26(Select9, { variant: "inline", align: "end", "aria-label": "What they can do", value: level, onValueChange: setLevel, options: LEVEL_OPTIONS }),
|
|
5738
|
+
/* @__PURE__ */ jsx26(Button21, { variant: "primary", disabled: busy !== null || !isEmail(email), onClick: () => void add(), children: "Share" })
|
|
5524
5739
|
] })
|
|
5525
5740
|
] }),
|
|
5526
|
-
/* @__PURE__ */
|
|
5527
|
-
/* @__PURE__ */
|
|
5528
|
-
more ? isOrg && item.owner.organizationId ? /* @__PURE__ */
|
|
5741
|
+
/* @__PURE__ */ jsxs24("div", { className: "flex flex-col gap-3", children: [
|
|
5742
|
+
/* @__PURE__ */ jsx26(DisclosureHeader3, { open: more, title: "More options", onClick: () => setMore((o) => !o) }),
|
|
5743
|
+
more ? isOrg && item.owner.organizationId ? /* @__PURE__ */ jsx26(MemberAccess, { port, organizationId: item.owner.organizationId, organizationName: orgName }) : /* @__PURE__ */ jsx26(IntoOrganization, { item, port, organizations, grants: grants ?? [], onShared: (g) => setGrants((all) => [...(all ?? []).filter((x) => x.id !== g.id), g]) }) : null
|
|
5529
5744
|
] })
|
|
5530
5745
|
]
|
|
5531
5746
|
}
|
|
@@ -5534,17 +5749,17 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5534
5749
|
function IntoOrganization({ item, port, organizations, grants, onShared }) {
|
|
5535
5750
|
const { busy, error, notice, run } = useConfirmedChange();
|
|
5536
5751
|
const open = organizations.filter((o) => !grants.some((g) => g.organizationId === o.id));
|
|
5537
|
-
const [target, setTarget] =
|
|
5538
|
-
const [level, setLevel] =
|
|
5752
|
+
const [target, setTarget] = useState26("");
|
|
5753
|
+
const [level, setLevel] = useState26("use");
|
|
5539
5754
|
const chosen = open.find((o) => o.id === target);
|
|
5540
5755
|
if (item.owner.kind !== "me") return null;
|
|
5541
|
-
return /* @__PURE__ */
|
|
5542
|
-
/* @__PURE__ */
|
|
5543
|
-
/* @__PURE__ */
|
|
5544
|
-
/* @__PURE__ */
|
|
5545
|
-
/* @__PURE__ */
|
|
5546
|
-
/* @__PURE__ */
|
|
5547
|
-
|
|
5756
|
+
return /* @__PURE__ */ jsx26(VaultSection, { title: "Share into organization", children: open.length > 0 ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
|
|
5757
|
+
/* @__PURE__ */ jsxs24("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
|
|
5758
|
+
/* @__PURE__ */ jsx26(BuildingGlyph, { className: "size-4 shrink-0 text-muted-foreground" }),
|
|
5759
|
+
/* @__PURE__ */ jsx26(Select9, { 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 }))] }),
|
|
5760
|
+
/* @__PURE__ */ jsx26(Select9, { variant: "inline", align: "end", "aria-label": "What its members can do", value: level, onValueChange: setLevel, options: LEVEL_OPTIONS }),
|
|
5761
|
+
/* @__PURE__ */ jsx26(
|
|
5762
|
+
Button21,
|
|
5548
5763
|
{
|
|
5549
5764
|
variant: "outline",
|
|
5550
5765
|
disabled: busy !== null || !chosen,
|
|
@@ -5560,8 +5775,8 @@ function IntoOrganization({ item, port, organizations, grants, onShared }) {
|
|
|
5560
5775
|
}
|
|
5561
5776
|
)
|
|
5562
5777
|
] }),
|
|
5563
|
-
/* @__PURE__ */
|
|
5564
|
-
] }) : /* @__PURE__ */
|
|
5778
|
+
/* @__PURE__ */ jsx26("p", { className: "truncate px-3 pb-1 text-xs text-muted-foreground sm:px-4", children: error ? /* @__PURE__ */ jsx26("span", { className: "text-destructive", children: error }) : notice ? /* @__PURE__ */ jsx26("span", { className: "text-success", children: notice }) : "It stays yours; its members can use it too" })
|
|
5779
|
+
] }) : /* @__PURE__ */ jsx26(Empty, { children: organizations.length ? "Already in every organization you belong to." : "You are not in any organization." }) });
|
|
5565
5780
|
}
|
|
5566
5781
|
var CHOICES = [
|
|
5567
5782
|
{ value: MEMBER_CHOICE_DEFAULT, label: "Default" },
|
|
@@ -5570,8 +5785,8 @@ var CHOICES = [
|
|
|
5570
5785
|
{ value: "editor", label: "Can edit", meta: "See and change" }
|
|
5571
5786
|
];
|
|
5572
5787
|
function MemberAccess({ port, organizationId, organizationName }) {
|
|
5573
|
-
const [list, setList] =
|
|
5574
|
-
const [loadError, setLoadError] =
|
|
5788
|
+
const [list, setList] = useState26(null);
|
|
5789
|
+
const [loadError, setLoadError] = useState26(null);
|
|
5575
5790
|
const { busy, error, run } = useConfirmedChange();
|
|
5576
5791
|
useEffect15(() => {
|
|
5577
5792
|
let live = true;
|
|
@@ -5588,9 +5803,9 @@ function MemberAccess({ port, organizationId, organizationName }) {
|
|
|
5588
5803
|
const effective = await run(userId, () => port.sharing.setMemberAccess(organizationId, userId, access));
|
|
5589
5804
|
if (effective) setList((l) => l ? { ...l, members: l.members.map((m) => m.userId === userId ? { ...m, access, effective } : m) } : l);
|
|
5590
5805
|
};
|
|
5591
|
-
return /* @__PURE__ */
|
|
5592
|
-
loadError ? /* @__PURE__ */
|
|
5593
|
-
|
|
5806
|
+
return /* @__PURE__ */ jsxs24(VaultSection, { title: `${organizationName} vault access`, children: [
|
|
5807
|
+
loadError ? /* @__PURE__ */ jsx26(Empty, { children: loadError }) : list === null ? /* @__PURE__ */ jsx26(RegionSkeleton, { shape: "rows", count: 3, "aria-label": "Loading member access", className: "px-3 sm:px-4" }) : list.members.length === 0 ? /* @__PURE__ */ jsx26(Empty, { children: "No members yet." }) : list.members.map((m) => /* @__PURE__ */ jsx26(AccessLine, { glyph: PersonGlyph, who: m.email || m.userId, meta: m.role, children: m.effective === "admin" ? /* @__PURE__ */ jsx26("span", { className: "px-2 text-sm text-muted-foreground", children: MEMBER_ACCESS_LABEL.admin }) : /* @__PURE__ */ jsx26(
|
|
5808
|
+
Select9,
|
|
5594
5809
|
{
|
|
5595
5810
|
variant: "inline",
|
|
5596
5811
|
align: "end",
|
|
@@ -5601,11 +5816,11 @@ function MemberAccess({ port, organizationId, organizationName }) {
|
|
|
5601
5816
|
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 })
|
|
5602
5817
|
}
|
|
5603
5818
|
) }, m.userId)),
|
|
5604
|
-
/* @__PURE__ */
|
|
5819
|
+
/* @__PURE__ */ jsx26("p", { className: "truncate px-3 pb-1 text-xs text-muted-foreground sm:px-4", children: error ? /* @__PURE__ */ jsx26("span", { className: "text-destructive", children: error }) : "Applies to every item in this organization" })
|
|
5605
5820
|
] });
|
|
5606
5821
|
}
|
|
5607
5822
|
function SharingSummary({ item, port, className }) {
|
|
5608
|
-
const [text, setText] =
|
|
5823
|
+
const [text, setText] = useState26("");
|
|
5609
5824
|
const allowed = item.capabilities.canManage;
|
|
5610
5825
|
useEffect15(() => {
|
|
5611
5826
|
if (!allowed) return;
|
|
@@ -5619,12 +5834,12 @@ function SharingSummary({ item, port, className }) {
|
|
|
5619
5834
|
};
|
|
5620
5835
|
}, [port, item, allowed]);
|
|
5621
5836
|
if (!allowed || !text) return null;
|
|
5622
|
-
return /* @__PURE__ */
|
|
5837
|
+
return /* @__PURE__ */ jsx26("span", { className: cn11("truncate text-xs text-muted-foreground", className), children: text });
|
|
5623
5838
|
}
|
|
5624
5839
|
|
|
5625
5840
|
// src/ItemPane.tsx
|
|
5626
5841
|
import { formatAbsoluteDate as formatAbsoluteDate3 } from "@ai-matrx/kit/format";
|
|
5627
|
-
import { Fragment as
|
|
5842
|
+
import { Fragment as Fragment17, jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
5628
5843
|
var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
|
|
5629
5844
|
function ItemPane(props) {
|
|
5630
5845
|
const { port, item, definition, mode, host, organizations, defaultOwner, seed, onBack, onMode, onSaved, onDeleted, onDirty, onCancelNew, onPanel, onChanged, favorite, notice, refreshKey } = props;
|
|
@@ -5633,7 +5848,7 @@ function ItemPane(props) {
|
|
|
5633
5848
|
const editing = mode !== "view";
|
|
5634
5849
|
const seedName = seed?.name ?? "";
|
|
5635
5850
|
const seedUrl = seed?.url ?? "";
|
|
5636
|
-
const [loaded, setLoaded] =
|
|
5851
|
+
const [loaded, setLoaded] = useState27({});
|
|
5637
5852
|
const base = useMemo3(() => {
|
|
5638
5853
|
const b = draftOf(item);
|
|
5639
5854
|
if (!item) {
|
|
@@ -5643,18 +5858,21 @@ function ItemPane(props) {
|
|
|
5643
5858
|
b.values = { ...loaded };
|
|
5644
5859
|
return b;
|
|
5645
5860
|
}, [item, seedName, seedUrl, loaded]);
|
|
5646
|
-
const [draft, setDraft] =
|
|
5647
|
-
const [tagsText, setTagsText] =
|
|
5648
|
-
const [showTags, setShowTags] =
|
|
5649
|
-
const [showDescription, setShowDescription] =
|
|
5650
|
-
const [showRecovery, setShowRecovery] =
|
|
5651
|
-
const [settingUpOtp, setSettingUpOtp] =
|
|
5652
|
-
const [owner, setOwner] =
|
|
5653
|
-
const [recipient, setRecipient] =
|
|
5654
|
-
const [generatePrivately, setGeneratePrivately] =
|
|
5655
|
-
const [busy, setBusy] =
|
|
5656
|
-
const [
|
|
5657
|
-
const [
|
|
5861
|
+
const [draft, setDraft] = useState27(base);
|
|
5862
|
+
const [tagsText, setTagsText] = useState27(base.tags.join(", "));
|
|
5863
|
+
const [showTags, setShowTags] = useState27(false);
|
|
5864
|
+
const [showDescription, setShowDescription] = useState27(false);
|
|
5865
|
+
const [showRecovery, setShowRecovery] = useState27(false);
|
|
5866
|
+
const [settingUpOtp, setSettingUpOtp] = useState27(false);
|
|
5867
|
+
const [owner, setOwner] = useState27(defaultOwner ?? "me");
|
|
5868
|
+
const [recipient, setRecipient] = useState27("");
|
|
5869
|
+
const [generatePrivately, setGeneratePrivately] = useState27(false);
|
|
5870
|
+
const [busy, setBusy] = useState27(false);
|
|
5871
|
+
const [sent, setSent] = useState27(null);
|
|
5872
|
+
const [queuedFiles, setQueuedFiles] = useState27([]);
|
|
5873
|
+
const [showBrowser, setShowBrowser] = useState27(false);
|
|
5874
|
+
const [error, setError] = useState27(null);
|
|
5875
|
+
const [destinations, setDestinations] = useState27({});
|
|
5658
5876
|
const dirty = editing && isDirty(base, draft);
|
|
5659
5877
|
const declared = definition?.fields ?? [];
|
|
5660
5878
|
const prev = useRef14(null);
|
|
@@ -5727,10 +5945,13 @@ function ItemPane(props) {
|
|
|
5727
5945
|
const secretKey = declared.find((f) => f.storage === "encrypted" && f.kind === "secret")?.key ?? null;
|
|
5728
5946
|
const r = await port.sharing.assign({ recipientEmail: recipient.trim(), definition, draft: out, generateFieldKey: generatePrivately ? secretKey : null });
|
|
5729
5947
|
notify(`Sent to ${r.recipientEmail}`);
|
|
5730
|
-
|
|
5948
|
+
dropKeptDraft(keepKey);
|
|
5949
|
+
onDirty(false);
|
|
5950
|
+
setSent(r);
|
|
5731
5951
|
} else if (definition) {
|
|
5732
5952
|
const r = await port.create(definition, owner === "me" ? null : owner, out);
|
|
5733
|
-
const [
|
|
5953
|
+
const [withCode, n0, enrolled] = await withOtp(r.item, r.notice);
|
|
5954
|
+
const [next, n] = await storeQueuedFiles(withCode, n0);
|
|
5734
5955
|
dropKeptDraft(keepKey);
|
|
5735
5956
|
onSaved(next, true, n, enrolled);
|
|
5736
5957
|
}
|
|
@@ -5740,9 +5961,32 @@ function ItemPane(props) {
|
|
|
5740
5961
|
setBusy(false);
|
|
5741
5962
|
}
|
|
5742
5963
|
}
|
|
5964
|
+
async function storeQueuedFiles(saved, notice2) {
|
|
5965
|
+
let next = saved;
|
|
5966
|
+
const failed = [];
|
|
5967
|
+
for (const q of queuedFiles) {
|
|
5968
|
+
try {
|
|
5969
|
+
next = await confirmed(() => port.activity.addFile(next, q.file, { label: q.label, description: q.description, handling: q.handling }));
|
|
5970
|
+
} catch {
|
|
5971
|
+
failed.push(q.label);
|
|
5972
|
+
}
|
|
5973
|
+
}
|
|
5974
|
+
setQueuedFiles([]);
|
|
5975
|
+
if (failed.length === 0) return [next, notice2];
|
|
5976
|
+
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.`;
|
|
5977
|
+
return [next, notice2 ? `${notice2} ${said}` : said];
|
|
5978
|
+
}
|
|
5979
|
+
function createAnother() {
|
|
5980
|
+
setSent(null);
|
|
5981
|
+
setDraft(base);
|
|
5982
|
+
setTagsText(base.tags.join(", "));
|
|
5983
|
+
setQueuedFiles([]);
|
|
5984
|
+
setShowBrowser(false);
|
|
5985
|
+
setError(null);
|
|
5986
|
+
}
|
|
5743
5987
|
async function remove() {
|
|
5744
5988
|
if (!item) return;
|
|
5745
|
-
const ok = await
|
|
5989
|
+
const ok = await confirm10({ title: `Delete \u201C${item.name}\u201D?`, description: "It moves to Trash. You can restore it from there.", confirmLabel: "Delete", variant: "destructive" });
|
|
5746
5990
|
if (!ok) return;
|
|
5747
5991
|
setBusy(true);
|
|
5748
5992
|
try {
|
|
@@ -5783,6 +6027,7 @@ function ItemPane(props) {
|
|
|
5783
6027
|
onChanged();
|
|
5784
6028
|
}
|
|
5785
6029
|
}
|
|
6030
|
+
const fieldSettings = (f) => canEdit ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SlidersGlyph, {}), "aria-label": `${f.label} settings`, title: `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) }) : null;
|
|
5786
6031
|
const turnOnOne = canTurnOn ? (f) => () => turnOn([f]) : () => void 0;
|
|
5787
6032
|
const declaredKeys = new Set(declared.map((f) => f.key));
|
|
5788
6033
|
const extraFields = (item?.fields ?? []).filter((f) => !declaredKeys.has(f.key) && !draft.removed.includes(f.id) && !isAuthenticatorStorage(f.key));
|
|
@@ -5795,35 +6040,35 @@ function ItemPane(props) {
|
|
|
5795
6040
|
const recoveryExtra = extraFields.some(isRecoveryCodesField);
|
|
5796
6041
|
const offerRecovery = isLogin || Boolean(item?.authenticator) || draft.authenticator.trim() !== "";
|
|
5797
6042
|
const recoveryEditing = !recoveryDeclared && !recoveryExtra && (showRecovery || (draft.values[RECOVERY_CODES_KEY] ?? "") !== "");
|
|
5798
|
-
const shownOwner = mode === "new" ? owner === "me" ? { label: "Personal", glyph: /* @__PURE__ */
|
|
6043
|
+
const shownOwner = mode === "new" ? owner === "me" ? { label: "Personal", glyph: /* @__PURE__ */ jsx27(PersonGlyph, {}) } : owner === "person" ? { label: "Someone else", glyph: /* @__PURE__ */ jsx27(SendGlyph, {}) } : { label: organizations.find((o) => o.id === owner)?.name ?? "Organization", glyph: /* @__PURE__ */ jsx27(BuildingGlyph, {}) } : item ? { label: item.owner.label, glyph: item.owner.kind === "me" ? /* @__PURE__ */ jsx27(PersonGlyph, {}) : item.owner.kind === "organization" ? /* @__PURE__ */ jsx27(BuildingGlyph, {}) : /* @__PURE__ */ jsx27(UsersIcon2, {}) } : null;
|
|
5799
6044
|
const sameNamed = (id) => {
|
|
5800
6045
|
const name = organizations.find((o) => o.id === id)?.name.trim().toLowerCase();
|
|
5801
6046
|
return Boolean(name) && organizations.filter((o) => o.name.trim().toLowerCase() === name).length > 1;
|
|
5802
6047
|
};
|
|
5803
6048
|
const tagsVisible = showTags || draft.tags.length > 0 || tagsText !== "";
|
|
5804
6049
|
const descriptionVisible = showDescription || draft.description !== "";
|
|
5805
|
-
const header = /* @__PURE__ */
|
|
5806
|
-
onBack ? /* @__PURE__ */
|
|
5807
|
-
/* @__PURE__ */
|
|
5808
|
-
/* @__PURE__ */
|
|
5809
|
-
/* @__PURE__ */
|
|
5810
|
-
/* @__PURE__ */
|
|
5811
|
-
typeLabel ? /* @__PURE__ */
|
|
5812
|
-
shownOwner ? /* @__PURE__ */
|
|
5813
|
-
item && !editing ? /* @__PURE__ */
|
|
6050
|
+
const header = /* @__PURE__ */ jsxs25("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: [
|
|
6051
|
+
onBack ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(ChevronLeftGlyph, {}), "aria-label": "Back", onClick: mode === "new" ? onCancelNew : onBack }) : null,
|
|
6052
|
+
/* @__PURE__ */ jsx27(ItemIcon, { definitionKey: definition?.key ?? item?.definitionKey ?? "custom", family: definition?.family ?? "generic", site: item ? loginSiteOf(item) : loginSiteOf({ loginUrls: draft.loginUrls }), size: "lg" }),
|
|
6053
|
+
/* @__PURE__ */ jsxs25("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
6054
|
+
/* @__PURE__ */ jsx27("h2", { className: "truncate text-base font-semibold leading-tight", children: editing ? draft.name || (mode === "new" ? `New ${typeLabel.toLowerCase()}` : item?.name) : item?.name }),
|
|
6055
|
+
/* @__PURE__ */ jsxs25("span", { className: "flex min-w-0 items-center gap-1 text-xs text-muted-foreground", children: [
|
|
6056
|
+
typeLabel ? /* @__PURE__ */ jsx27("span", { className: "truncate", children: typeLabel }) : null,
|
|
6057
|
+
shownOwner ? /* @__PURE__ */ jsx27(Badge7, { className: "shrink-0", icon: shownOwner.glyph, "aria-label": `Saved in ${shownOwner.label}`, children: shownOwner.label }) : null,
|
|
6058
|
+
item && !editing ? /* @__PURE__ */ jsx27(SharingSummary, { item, port, className: "hidden truncate before:mr-1 before:content-['\xB7'] sm:inline" }, `${item.updatedAt}-${refreshKey ?? ""}`) : null
|
|
5814
6059
|
] })
|
|
5815
6060
|
] }),
|
|
5816
|
-
editing ? /* @__PURE__ */
|
|
5817
|
-
dirty ? /* @__PURE__ */
|
|
5818
|
-
/* @__PURE__ */
|
|
6061
|
+
editing ? /* @__PURE__ */ jsxs25("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
6062
|
+
dirty ? /* @__PURE__ */ jsxs25("span", { className: "hidden items-center gap-1.5 text-xs text-muted-foreground sm:flex", role: "status", children: [
|
|
6063
|
+
/* @__PURE__ */ jsx27("span", { className: "size-1.5 rounded-full bg-warning", "aria-hidden": true }),
|
|
5819
6064
|
"Unsaved"
|
|
5820
6065
|
] }) : null,
|
|
5821
|
-
/* @__PURE__ */
|
|
5822
|
-
/* @__PURE__ */
|
|
5823
|
-
] }) : item ? /* @__PURE__ */
|
|
5824
|
-
host.page && canUseOnSite(item, host.page.url) ? /* @__PURE__ */
|
|
5825
|
-
host.fill && item.capabilities.canUse ? /* @__PURE__ */
|
|
5826
|
-
|
|
6066
|
+
/* @__PURE__ */ jsx27(Button22, { variant: "quiet", disabled: busy, onClick: () => mode === "new" ? onCancelNew() : onMode("view"), children: dirty ? "Discard" : "Cancel" }),
|
|
6067
|
+
/* @__PURE__ */ jsx27(Button22, { 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" })
|
|
6068
|
+
] }) : item ? /* @__PURE__ */ jsxs25("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
6069
|
+
host.page && canUseOnSite(item, host.page.url) ? /* @__PURE__ */ jsx27(UseOnSiteButton, { port, item, pageUrl: host.page.url, onChanged: (next) => onChanged(next) }) : null,
|
|
6070
|
+
host.fill && item.capabilities.canUse ? /* @__PURE__ */ jsx27(
|
|
6071
|
+
Button22,
|
|
5827
6072
|
{
|
|
5828
6073
|
variant: "primary",
|
|
5829
6074
|
onClick: () => void host.fill?.(item.id).then((outcome) => {
|
|
@@ -5833,44 +6078,44 @@ function ItemPane(props) {
|
|
|
5833
6078
|
children: "Fill"
|
|
5834
6079
|
}
|
|
5835
6080
|
) : null,
|
|
5836
|
-
favorite ? /* @__PURE__ */
|
|
5837
|
-
canManage ? /* @__PURE__ */
|
|
5838
|
-
canEdit ? /* @__PURE__ */
|
|
5839
|
-
/* @__PURE__ */
|
|
5840
|
-
/* @__PURE__ */
|
|
5841
|
-
/* @__PURE__ */
|
|
5842
|
-
favorite ? /* @__PURE__ */
|
|
5843
|
-
/* @__PURE__ */
|
|
6081
|
+
favorite ? /* @__PURE__ */ jsx27("span", { className: "hidden sm:contents", children: /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(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,
|
|
6082
|
+
canManage ? /* @__PURE__ */ jsx27("span", { className: "hidden sm:contents", children: /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(ShareGlyph, {}), "aria-label": "Share", onClick: () => onPanel("share") }) }) : null,
|
|
6083
|
+
canEdit ? /* @__PURE__ */ jsx27(Button22, { variant: "outline", icon: /* @__PURE__ */ jsx27(PencilGlyph, {}), collapse: "container", "aria-label": "Edit", onClick: () => onMode("edit"), children: "Edit" }) : null,
|
|
6084
|
+
/* @__PURE__ */ jsxs25(DropdownMenu3, { children: [
|
|
6085
|
+
/* @__PURE__ */ jsx27(DropdownMenuTrigger3, { asChild: true, children: /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(MoreGlyph, {}), "aria-label": "More actions" }) }),
|
|
6086
|
+
/* @__PURE__ */ jsxs25(DropdownMenuContent3, { align: "end", children: [
|
|
6087
|
+
favorite ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: favorite.toggle, children: [
|
|
6088
|
+
/* @__PURE__ */ jsx27(StarGlyph, { className: "size-4" }),
|
|
5844
6089
|
favorite.on ? "Remove from favorites" : "Add to favorites"
|
|
5845
6090
|
] }) : null,
|
|
5846
|
-
canManage ? /* @__PURE__ */
|
|
5847
|
-
/* @__PURE__ */
|
|
6091
|
+
canManage ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("share"), children: [
|
|
6092
|
+
/* @__PURE__ */ jsx27(ShareGlyph, { className: "size-4" }),
|
|
5848
6093
|
"Share"
|
|
5849
6094
|
] }) : null,
|
|
5850
|
-
canManage ? /* @__PURE__ */
|
|
5851
|
-
/* @__PURE__ */
|
|
6095
|
+
canManage ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("move"), children: [
|
|
6096
|
+
/* @__PURE__ */ jsx27(MoveGlyph, { className: "size-4" }),
|
|
5852
6097
|
"Move or copy"
|
|
5853
6098
|
] }) : null,
|
|
5854
|
-
item.capabilities.canReveal ? /* @__PURE__ */
|
|
5855
|
-
/* @__PURE__ */
|
|
6099
|
+
item.capabilities.canReveal ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("send"), children: [
|
|
6100
|
+
/* @__PURE__ */ jsx27(SendGlyph, { className: "size-4" }),
|
|
5856
6101
|
"Send securely"
|
|
5857
6102
|
] }) : null,
|
|
5858
|
-
/* @__PURE__ */
|
|
5859
|
-
/* @__PURE__ */
|
|
6103
|
+
/* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("history"), children: [
|
|
6104
|
+
/* @__PURE__ */ jsx27(HistoryIcon, { className: "size-4" }),
|
|
5860
6105
|
"Password history"
|
|
5861
6106
|
] }),
|
|
5862
|
-
/* @__PURE__ */
|
|
5863
|
-
/* @__PURE__ */
|
|
6107
|
+
/* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("activity"), children: [
|
|
6108
|
+
/* @__PURE__ */ jsx27(ListGlyph, { className: "size-4" }),
|
|
5864
6109
|
"Activity"
|
|
5865
6110
|
] }),
|
|
5866
|
-
canEdit ? /* @__PURE__ */
|
|
5867
|
-
/* @__PURE__ */
|
|
6111
|
+
canEdit ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("settings"), children: [
|
|
6112
|
+
/* @__PURE__ */ jsx27(SettingsIcon, { className: "size-4" }),
|
|
5868
6113
|
"Settings"
|
|
5869
6114
|
] }) : null,
|
|
5870
|
-
canManage ? /* @__PURE__ */
|
|
5871
|
-
/* @__PURE__ */
|
|
5872
|
-
/* @__PURE__ */
|
|
5873
|
-
/* @__PURE__ */
|
|
6115
|
+
canManage ? /* @__PURE__ */ jsxs25(Fragment17, { children: [
|
|
6116
|
+
/* @__PURE__ */ jsx27(DropdownMenuSeparator3, {}),
|
|
6117
|
+
/* @__PURE__ */ jsxs25(DropdownMenuItem3, { className: "text-destructive", disabled: busy, onSelect: () => void remove(), children: [
|
|
6118
|
+
/* @__PURE__ */ jsx27(TrashGlyph, { className: "size-4" }),
|
|
5874
6119
|
"Delete"
|
|
5875
6120
|
] })
|
|
5876
6121
|
] }) : null
|
|
@@ -5879,17 +6124,17 @@ function ItemPane(props) {
|
|
|
5879
6124
|
] }) : null
|
|
5880
6125
|
] });
|
|
5881
6126
|
const filesProps = item ? { item, port, host, definition, organizations, arg: null, onClose: () => void 0, onChanged, onPanel } : null;
|
|
5882
|
-
return /* @__PURE__ */
|
|
6127
|
+
return /* @__PURE__ */ jsx27(RoomProvider, { value: room, children: /* @__PURE__ */ jsxs25("article", { ref: paneRef, "aria-label": item?.name ?? "New item", className: cn12(CONTROLS_CONTAINER_CLASS, "flex h-full min-h-0 flex-col bg-background"), children: [
|
|
5883
6128
|
header,
|
|
5884
|
-
error ? /* @__PURE__ */
|
|
5885
|
-
notice && !editing ? /* @__PURE__ */
|
|
5886
|
-
item && !editing && (itemOff || offFields.length > 0) ? /* @__PURE__ */
|
|
5887
|
-
/* @__PURE__ */
|
|
5888
|
-
canTurnOn ? /* @__PURE__ */
|
|
6129
|
+
error ? /* @__PURE__ */ jsx27("div", { role: "alert", className: "border-b border-border bg-muted px-5 py-2 text-sm text-destructive", children: error }) : null,
|
|
6130
|
+
notice && !editing ? /* @__PURE__ */ jsx27("div", { role: "status", className: "border-b border-border bg-muted px-5 py-2 text-sm text-warning", children: notice }) : null,
|
|
6131
|
+
item && !editing && (itemOff || offFields.length > 0) ? /* @__PURE__ */ jsxs25("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-5 py-2 text-sm", children: [
|
|
6132
|
+
/* @__PURE__ */ jsx27("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` }),
|
|
6133
|
+
canTurnOn ? /* @__PURE__ */ jsx27(TurnOnButton, { label: "all fields", onTurnOn: () => turnOn(offFields) }) : null
|
|
5889
6134
|
] }) : null,
|
|
5890
|
-
/* @__PURE__ */
|
|
5891
|
-
/* @__PURE__ */
|
|
5892
|
-
mode === "new" ? /* @__PURE__ */
|
|
6135
|
+
/* @__PURE__ */ jsx27("div", { className: "min-h-0 flex-1 overflow-y-auto", children: sent ? /* @__PURE__ */ jsx27(AssignResult, { sent, onAnother: createAnother, onDone: onCancelNew }) : /* @__PURE__ */ jsx27("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__ */ jsxs25(Fragment17, { children: [
|
|
6136
|
+
/* @__PURE__ */ jsxs25(VaultSection, { children: [
|
|
6137
|
+
mode === "new" ? /* @__PURE__ */ jsx27(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx27(
|
|
5893
6138
|
OptionCombobox,
|
|
5894
6139
|
{
|
|
5895
6140
|
value: owner,
|
|
@@ -5904,20 +6149,20 @@ function ItemPane(props) {
|
|
|
5904
6149
|
],
|
|
5905
6150
|
getLabel: (v) => v === "me" ? "Personal" : v === "person" ? "Someone else" : organizations.find((o) => o.id === v)?.name ?? v,
|
|
5906
6151
|
getHint: (v) => v === "me" ? "Only you" : v === "person" ? "Sent by email" : sameNamed(v) ? `ID ${v.slice(0, 8)}` : null,
|
|
5907
|
-
renderIcon: (v) => v === "me" ? /* @__PURE__ */
|
|
6152
|
+
renderIcon: (v) => v === "me" ? /* @__PURE__ */ jsx27(PersonGlyph, { className: "size-4" }) : v === "person" ? /* @__PURE__ */ jsx27(SendGlyph, { className: "size-4" }) : /* @__PURE__ */ jsx27(BuildingGlyph, { className: "size-4" })
|
|
5908
6153
|
}
|
|
5909
6154
|
) }) : null,
|
|
5910
|
-
/* @__PURE__ */
|
|
5911
|
-
mode === "new" && owner === "person" ? /* @__PURE__ */
|
|
5912
|
-
/* @__PURE__ */
|
|
5913
|
-
declared.some((f) => f.storage === "encrypted" && f.kind === "secret") ? /* @__PURE__ */
|
|
6155
|
+
/* @__PURE__ */ jsx27(EditRow, { label: "Name", value: draft.name, onChange: (v) => patch({ name: v }), placeholder: "Name", autoFocus: mode === "new" }),
|
|
6156
|
+
mode === "new" && owner === "person" ? /* @__PURE__ */ jsxs25(Fragment17, { children: [
|
|
6157
|
+
/* @__PURE__ */ jsx27(EditRow, { label: "Their email", value: recipient, placeholder: "name@company.com", inputMode: "email", onChange: setRecipient }),
|
|
6158
|
+
declared.some((f) => f.storage === "encrypted" && f.kind === "secret") ? /* @__PURE__ */ jsx27(VaultRow, { label: "Password", hint: "You never see it", children: /* @__PURE__ */ jsx27(Switch6, { checked: generatePrivately, onCheckedChange: setGeneratePrivately, "aria-label": "Generate the password privately" }) }) : null
|
|
5914
6159
|
] }) : null,
|
|
5915
6160
|
declared.map((f) => {
|
|
5916
6161
|
const existing = item?.fields.find((x) => x.key === f.key);
|
|
5917
6162
|
const secretKind = f.storage === "encrypted" && f.kind === "secret";
|
|
5918
6163
|
const value = f.storage === "metadata" ? metaValue(f.key) : draft.values[f.key] ?? "";
|
|
5919
6164
|
const hidden = existing && existing.handling !== "visible" && !(f.key in loaded);
|
|
5920
|
-
return /* @__PURE__ */
|
|
6165
|
+
return /* @__PURE__ */ jsx27(
|
|
5921
6166
|
EditRow,
|
|
5922
6167
|
{
|
|
5923
6168
|
label: f.label,
|
|
@@ -5927,16 +6172,16 @@ function ItemPane(props) {
|
|
|
5927
6172
|
multiline: f.kind === "multiline",
|
|
5928
6173
|
inputMode: f.kind === "url" ? "url" : USERNAME_KEYS.test(f.key) ? "email" : "text",
|
|
5929
6174
|
onChange: (v) => setValue(f.key, v),
|
|
5930
|
-
actions: /* @__PURE__ */
|
|
5931
|
-
hidden && existing?.handling === "revealable" && item?.capabilities.canReveal ? /* @__PURE__ */
|
|
5932
|
-
secretKind ? /* @__PURE__ */
|
|
5933
|
-
existing ? /* @__PURE__ */
|
|
6175
|
+
actions: /* @__PURE__ */ jsxs25(Fragment17, { children: [
|
|
6176
|
+
hidden && existing?.handling === "revealable" && item?.capabilities.canReveal ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
|
|
6177
|
+
secretKind ? /* @__PURE__ */ jsx27(GenerateButton, { onUse: (v) => setValue(f.key, v) }) : null,
|
|
6178
|
+
existing ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${existing.id}`) }) : null
|
|
5934
6179
|
] })
|
|
5935
6180
|
},
|
|
5936
6181
|
f.key
|
|
5937
6182
|
);
|
|
5938
6183
|
}),
|
|
5939
|
-
extraFields.map((f) => /* @__PURE__ */
|
|
6184
|
+
extraFields.map((f) => /* @__PURE__ */ jsx27(
|
|
5940
6185
|
EditRow,
|
|
5941
6186
|
{
|
|
5942
6187
|
label: f.label,
|
|
@@ -5947,18 +6192,18 @@ function ItemPane(props) {
|
|
|
5947
6192
|
onChange: (v) => setValue(f.key, v),
|
|
5948
6193
|
onRemove: () => patch({ removed: [...draft.removed, f.id] }),
|
|
5949
6194
|
removeLabel: `Delete ${f.label}`,
|
|
5950
|
-
actions: /* @__PURE__ */
|
|
5951
|
-
f.handling === "revealable" && !(f.key in loaded) && item?.capabilities.canReveal ? /* @__PURE__ */
|
|
5952
|
-
/* @__PURE__ */
|
|
6195
|
+
actions: /* @__PURE__ */ jsxs25(Fragment17, { children: [
|
|
6196
|
+
f.handling === "revealable" && !(f.key in loaded) && item?.capabilities.canReveal ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
|
|
6197
|
+
/* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) })
|
|
5953
6198
|
] })
|
|
5954
6199
|
},
|
|
5955
6200
|
f.id
|
|
5956
6201
|
)),
|
|
5957
|
-
draft.loginUrls.map((u, i) => /* @__PURE__ */
|
|
6202
|
+
draft.loginUrls.map((u, i) => /* @__PURE__ */ jsx27(
|
|
5958
6203
|
EditRow,
|
|
5959
6204
|
{
|
|
5960
6205
|
label: i === 0 ? "Website" : `Website ${i + 1}`,
|
|
5961
|
-
hint: destinations[i] && destinations[i].tone !== "success" ? /* @__PURE__ */
|
|
6206
|
+
hint: destinations[i] && destinations[i].tone !== "success" ? /* @__PURE__ */ jsx27("span", { className: destinations[i].tone === "destructive" ? "text-destructive" : "text-warning", children: destinations[i].message }) : void 0,
|
|
5962
6207
|
value: u,
|
|
5963
6208
|
autoFocus: i > 0 && u === "" && i === draft.loginUrls.length - 1,
|
|
5964
6209
|
placeholder: "https://",
|
|
@@ -5978,10 +6223,11 @@ function ItemPane(props) {
|
|
|
5978
6223
|
},
|
|
5979
6224
|
i
|
|
5980
6225
|
)),
|
|
5981
|
-
/* @__PURE__ */
|
|
5982
|
-
/* @__PURE__ */
|
|
5983
|
-
item && isLogin && !item.authenticator ? /* @__PURE__ */
|
|
5984
|
-
|
|
6226
|
+
/* @__PURE__ */ jsx27(AddRow, { label: draft.loginUrls.length === 0 ? "Website" : "", onAdd: () => patch({ loginUrls: [...draft.loginUrls, ""] }), children: draft.loginUrls.length === 0 ? "Add website" : "Add another website" }),
|
|
6227
|
+
/* @__PURE__ */ jsx27(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }),
|
|
6228
|
+
item && isLogin && !item.authenticator ? /* @__PURE__ */ jsx27(TwoFactorMethodRow, { port, item, onChanged }) : null,
|
|
6229
|
+
!item && isLogin && draft.authenticator.trim() === "" ? /* @__PURE__ */ jsx27(DraftTwoFactorRow, { custom: draft.custom, onCustom: (custom) => patch({ custom }) }) : null,
|
|
6230
|
+
recoveryEditing ? /* @__PURE__ */ jsx27(
|
|
5985
6231
|
EditRow,
|
|
5986
6232
|
{
|
|
5987
6233
|
label: "Recovery codes",
|
|
@@ -6000,26 +6246,30 @@ function ItemPane(props) {
|
|
|
6000
6246
|
},
|
|
6001
6247
|
removeLabel: "Remove recovery codes"
|
|
6002
6248
|
}
|
|
6003
|
-
) : !recoveryDeclared && !recoveryExtra && offerRecovery ? /* @__PURE__ */
|
|
6249
|
+
) : !recoveryDeclared && !recoveryExtra && offerRecovery ? /* @__PURE__ */ jsx27(AddRow, { label: "Recovery codes", onAdd: () => setShowRecovery(true), children: "Add backup codes" }) : null
|
|
6004
6250
|
] }),
|
|
6005
|
-
/* @__PURE__ */
|
|
6006
|
-
/* @__PURE__ */
|
|
6251
|
+
/* @__PURE__ */ jsx27(VaultSection, { children: /* @__PURE__ */ jsx27(EditRow, { label: "Notes", value: draft.notes, multiline: true, placeholder: "Anything worth remembering", onChange: (v) => patch({ notes: v }) }) }),
|
|
6252
|
+
/* @__PURE__ */ jsxs25(
|
|
6007
6253
|
VaultSection,
|
|
6008
6254
|
{
|
|
6009
6255
|
title: "More",
|
|
6010
|
-
actions: /* @__PURE__ */
|
|
6011
|
-
/* @__PURE__ */
|
|
6012
|
-
/* @__PURE__ */
|
|
6013
|
-
/* @__PURE__ */
|
|
6014
|
-
/* @__PURE__ */
|
|
6015
|
-
!tagsVisible ? /* @__PURE__ */
|
|
6016
|
-
!descriptionVisible ? /* @__PURE__ */
|
|
6017
|
-
|
|
6256
|
+
actions: /* @__PURE__ */ jsxs25(DropdownMenu3, { children: [
|
|
6257
|
+
/* @__PURE__ */ jsx27(DropdownMenuTrigger3, { asChild: true, children: /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(PlusGlyph, {}), children: "Add" }) }),
|
|
6258
|
+
/* @__PURE__ */ jsxs25(DropdownMenuContent3, { align: "end", children: [
|
|
6259
|
+
/* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => patch({ secrets: [...draft.secrets, { key: "", label: "", value: "" }] }), children: "Secret field" }),
|
|
6260
|
+
/* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => patch({ custom: [...draft.custom, { key: `custom_${draft.custom.length + 1}_${Date.now() % 1e5}`, label: "", value: "" }] }), children: "Text field" }),
|
|
6261
|
+
!tagsVisible ? /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => setShowTags(true), children: "Tags" }) : null,
|
|
6262
|
+
!descriptionVisible ? /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => setShowDescription(true), children: "Description" }) : null,
|
|
6263
|
+
mode === "new" && !showBrowser ? /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => {
|
|
6264
|
+
setShowBrowser(true);
|
|
6265
|
+
if (!draft.browser) patch({ browser: defaultBrowserSettings(draft.loginUrls.some((u) => u.trim() !== "")) });
|
|
6266
|
+
}, children: "Browser settings" }) : null,
|
|
6267
|
+
!recoveryDeclared && !recoveryExtra && !recoveryEditing ? /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => setShowRecovery(true), children: "Recovery codes" }) : null
|
|
6018
6268
|
] })
|
|
6019
6269
|
] }),
|
|
6020
6270
|
children: [
|
|
6021
|
-
descriptionVisible ? /* @__PURE__ */
|
|
6022
|
-
tagsVisible ? /* @__PURE__ */
|
|
6271
|
+
descriptionVisible ? /* @__PURE__ */ jsx27(EditRow, { label: "Description", value: draft.description, placeholder: "What this is for", onChange: (v) => patch({ description: v }) }) : null,
|
|
6272
|
+
tagsVisible ? /* @__PURE__ */ jsx27(
|
|
6023
6273
|
EditRow,
|
|
6024
6274
|
{
|
|
6025
6275
|
label: "Tags",
|
|
@@ -6031,49 +6281,50 @@ function ItemPane(props) {
|
|
|
6031
6281
|
}
|
|
6032
6282
|
}
|
|
6033
6283
|
) : null,
|
|
6034
|
-
draft.
|
|
6035
|
-
|
|
6036
|
-
|
|
6284
|
+
mode === "new" && showBrowser && draft.browser ? /* @__PURE__ */ jsx27(DraftBrowserRows, { value: draft.browser, hasWebsite: draft.loginUrls.some((u) => u.trim() !== ""), onChange: (browser) => patch({ browser }) }) : null,
|
|
6285
|
+
draft.secrets.map((s, i) => /* @__PURE__ */ jsx27(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}`)),
|
|
6286
|
+
extraCustom.map((c) => /* @__PURE__ */ jsx27(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)),
|
|
6287
|
+
!descriptionVisible && !tagsVisible && draft.secrets.length === 0 && extraCustom.length === 0 ? /* @__PURE__ */ jsx27(AddRow, { label: "Tags", onAdd: () => setShowTags(true), children: "Add tags" }) : null
|
|
6037
6288
|
]
|
|
6038
6289
|
}
|
|
6039
6290
|
),
|
|
6040
|
-
filesProps ? /* @__PURE__ */
|
|
6041
|
-
] }) : item ? /* @__PURE__ */
|
|
6042
|
-
/* @__PURE__ */
|
|
6291
|
+
filesProps ? /* @__PURE__ */ jsx27(FilesSection, { ...filesProps, editing: true }) : mode === "new" && owner !== "person" ? /* @__PURE__ */ jsx27(DraftFilesSection, { files: queuedFiles, onFiles: setQueuedFiles }) : null
|
|
6292
|
+
] }) : item ? /* @__PURE__ */ jsxs25(Fragment17, { children: [
|
|
6293
|
+
/* @__PURE__ */ jsxs25(VaultSection, { children: [
|
|
6043
6294
|
declared.map((f) => {
|
|
6044
6295
|
if (f.storage === "metadata") {
|
|
6045
6296
|
const v = metaValue(f.key);
|
|
6046
|
-
return v ? /* @__PURE__ */
|
|
6297
|
+
return v ? /* @__PURE__ */ jsx27(PlainRow, { label: f.label, value: v, openUrl: host.openUrl }, f.key) : null;
|
|
6047
6298
|
}
|
|
6048
6299
|
const field = item.fields.find((x) => x.key === f.key);
|
|
6049
|
-
if (isRecoveryCodesField(f)) return /* @__PURE__ */
|
|
6050
|
-
return field ? /* @__PURE__ */
|
|
6300
|
+
if (isRecoveryCodesField(f)) return /* @__PURE__ */ jsx27(RecoveryCodesRow, { item, field, port, onChanged }, f.key);
|
|
6301
|
+
return field ? /* @__PURE__ */ jsx27(SecretRow, { port, item, field, onTurnOn: turnOnOne(field), extra: fieldSettings(field) }, field.id) : null;
|
|
6051
6302
|
}),
|
|
6052
|
-
extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */
|
|
6053
|
-
item.loginUrls.length > 0 ? item.loginUrls.map((u, i) => /* @__PURE__ */
|
|
6054
|
-
item.authenticator ? /* @__PURE__ */
|
|
6303
|
+
extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ jsx27(RecoveryCodesRow, { item, field: f, port, onChanged }, f.id) : /* @__PURE__ */ jsx27(SecretRow, { port, item, field: f, onTurnOn: turnOnOne(f), extra: fieldSettings(f) }, f.id)),
|
|
6304
|
+
item.loginUrls.length > 0 ? item.loginUrls.map((u, i) => /* @__PURE__ */ jsx27(PlainRow, { label: i === 0 ? "Website" : `Website ${i + 1}`, value: u, openUrl: host.openUrl }, `${u}-${i}`)) : /* @__PURE__ */ jsx27(AddRow, { label: "Website", onAdd: canEdit ? () => onMode("edit") : null, children: "Add website" }),
|
|
6305
|
+
item.authenticator ? /* @__PURE__ */ jsx27(TotpRow, { port, item, onChanged }) : seedField && !seedField.active ? (
|
|
6055
6306
|
// The secret is still there, only off: turning it on brings the codes back. Never "Set up",
|
|
6056
6307
|
// which would invite replacing a working two-factor secret.
|
|
6057
|
-
/* @__PURE__ */
|
|
6058
|
-
) : /* @__PURE__ */
|
|
6059
|
-
!recoveryDeclared && !recoveryExtra && offerRecovery ? /* @__PURE__ */
|
|
6060
|
-
!item.authenticator && item.custom.some((c) => c.key === MFA_METHOD_KEY && c.value) ? /* @__PURE__ */
|
|
6308
|
+
/* @__PURE__ */ jsx27(VaultRow, { label: "Authenticator", actions: canTurnOn ? /* @__PURE__ */ jsx27(TurnOnButton, { label: "Authenticator", onTurnOn: () => turnOn([seedField]) }) : null, children: /* @__PURE__ */ jsx27("span", { className: "text-muted-foreground", children: "Turned off" }) })
|
|
6309
|
+
) : /* @__PURE__ */ jsx27(AddRow, { label: "Authenticator", onAdd: canEdit ? () => setSettingUpOtp(true) : null, children: "Set up" }),
|
|
6310
|
+
!recoveryDeclared && !recoveryExtra && offerRecovery ? /* @__PURE__ */ jsx27(RecoveryCodesRow, { item, field: null, port, onChanged }) : null,
|
|
6311
|
+
!item.authenticator && item.custom.some((c) => c.key === MFA_METHOD_KEY && c.value) ? /* @__PURE__ */ jsx27(TwoFactorMethodRow, { port, item, onChanged }) : null
|
|
6061
6312
|
] }),
|
|
6062
|
-
/* @__PURE__ */
|
|
6063
|
-
item.description || item.tags.length > 0 || viewCustom.length > 0 ? /* @__PURE__ */
|
|
6064
|
-
item.description ? /* @__PURE__ */
|
|
6065
|
-
item.tags.length > 0 ? /* @__PURE__ */
|
|
6066
|
-
viewCustom.map((c) => /* @__PURE__ */
|
|
6313
|
+
/* @__PURE__ */ jsx27(VaultSection, { children: item.notes ? /* @__PURE__ */ jsx27(PlainRow, { label: "Notes", value: item.notes, multiline: true }) : /* @__PURE__ */ jsx27(AddRow, { label: "Notes", onAdd: canEdit ? () => onMode("edit") : null, children: "Add notes" }) }),
|
|
6314
|
+
item.description || item.tags.length > 0 || viewCustom.length > 0 ? /* @__PURE__ */ jsxs25(VaultSection, { title: "More", children: [
|
|
6315
|
+
item.description ? /* @__PURE__ */ jsx27(PlainRow, { label: "Description", value: item.description }) : null,
|
|
6316
|
+
item.tags.length > 0 ? /* @__PURE__ */ jsx27(VaultRow, { label: "Tags", children: /* @__PURE__ */ jsx27("div", { className: "flex flex-wrap gap-1", children: item.tags.map((t) => /* @__PURE__ */ jsx27("span", { className: "rounded-md bg-muted px-1.5 py-0.5 text-xs", children: t }, t)) }) }) : null,
|
|
6317
|
+
viewCustom.map((c) => /* @__PURE__ */ jsx27(PlainRow, { label: c.label, value: c.value, openUrl: host.openUrl }, c.key))
|
|
6067
6318
|
] }) : null,
|
|
6068
|
-
filesProps ? /* @__PURE__ */
|
|
6069
|
-
/* @__PURE__ */
|
|
6319
|
+
filesProps ? /* @__PURE__ */ jsx27(FilesSection, { ...filesProps, editing: false }) : null,
|
|
6320
|
+
/* @__PURE__ */ jsxs25("p", { className: cn12("px-1 text-xs text-muted-foreground"), children: [
|
|
6070
6321
|
"Modified ",
|
|
6071
6322
|
formatAbsoluteDate3(item.updatedAt, DAY_FORMAT, ""),
|
|
6072
6323
|
" \xB7 Created ",
|
|
6073
6324
|
formatAbsoluteDate3(item.createdAt, DAY_FORMAT, "")
|
|
6074
6325
|
] })
|
|
6075
6326
|
] }) : null }) }),
|
|
6076
|
-
settingUpOtp && item ? /* @__PURE__ */
|
|
6327
|
+
settingUpOtp && item ? /* @__PURE__ */ jsx27(
|
|
6077
6328
|
AddOtpPanel,
|
|
6078
6329
|
{
|
|
6079
6330
|
port,
|
|
@@ -6092,18 +6343,21 @@ function ItemPane(props) {
|
|
|
6092
6343
|
}
|
|
6093
6344
|
|
|
6094
6345
|
// src/ItemList.tsx
|
|
6095
|
-
import { jsx as
|
|
6346
|
+
import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
6096
6347
|
var SORTS2 = [
|
|
6097
|
-
{ value: "name", label: "Name" },
|
|
6348
|
+
{ value: "name", label: "Name A\u2013Z" },
|
|
6349
|
+
{ value: "name-desc", label: "Name Z\u2013A" },
|
|
6098
6350
|
{ value: "website", label: "Website" },
|
|
6099
6351
|
{ value: "updated", label: "Recently changed" },
|
|
6100
|
-
{ value: "created", label: "Recently added" }
|
|
6352
|
+
{ value: "created", label: "Recently added" },
|
|
6353
|
+
{ value: "viewed", label: "Recently viewed" }
|
|
6101
6354
|
];
|
|
6102
6355
|
function subtitleOf(item, withOwner) {
|
|
6103
6356
|
const what = loginSiteOf(item) || item.definitionLabel;
|
|
6104
6357
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
6105
6358
|
}
|
|
6106
|
-
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner }) {
|
|
6359
|
+
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner, canSortViewed = false }) {
|
|
6360
|
+
const sorts = SORTS2.filter((s) => canSortViewed || s.value !== "viewed");
|
|
6107
6361
|
const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
|
|
6108
6362
|
const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
|
|
6109
6363
|
const ordered = [...pinned, ...rest];
|
|
@@ -6123,34 +6377,34 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6123
6377
|
}
|
|
6124
6378
|
};
|
|
6125
6379
|
const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6126
|
-
const row = (i) => /* @__PURE__ */
|
|
6127
|
-
const sortLabel =
|
|
6128
|
-
return /* @__PURE__ */
|
|
6129
|
-
/* @__PURE__ */
|
|
6380
|
+
const row = (i) => /* @__PURE__ */ jsx28(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners }, i.id);
|
|
6381
|
+
const sortLabel = sorts.find((s) => s.value === sort)?.label ?? "Name A\u2013Z";
|
|
6382
|
+
return /* @__PURE__ */ jsxs26("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
|
|
6383
|
+
/* @__PURE__ */ jsxs26("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children: [
|
|
6130
6384
|
header,
|
|
6131
|
-
/* @__PURE__ */
|
|
6132
|
-
/* @__PURE__ */
|
|
6133
|
-
/* @__PURE__ */
|
|
6385
|
+
/* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-2", children: [
|
|
6386
|
+
/* @__PURE__ */ jsx28(SearchField, { value: query, onChange: (e) => onQuery(e.target.value), onKeyDown, placeholder: `Search ${title}`, className: "min-w-0 flex-1", "aria-label": "Search the vault" }),
|
|
6387
|
+
/* @__PURE__ */ jsx28(Button23, { variant: "primary", icon: /* @__PURE__ */ jsx28(PlusGlyph, {}), "aria-label": "New item", onClick: onNew })
|
|
6134
6388
|
] }),
|
|
6135
|
-
/* @__PURE__ */
|
|
6136
|
-
/* @__PURE__ */
|
|
6389
|
+
/* @__PURE__ */ jsxs26("div", { className: "flex items-center justify-between gap-2 px-1", children: [
|
|
6390
|
+
/* @__PURE__ */ jsxs26("span", { className: "truncate text-xs text-muted-foreground", children: [
|
|
6137
6391
|
items.length,
|
|
6138
6392
|
" ",
|
|
6139
6393
|
items.length === 1 ? "item" : "items"
|
|
6140
6394
|
] }),
|
|
6141
|
-
/* @__PURE__ */
|
|
6142
|
-
/* @__PURE__ */
|
|
6143
|
-
/* @__PURE__ */
|
|
6395
|
+
/* @__PURE__ */ jsxs26(DropdownMenu4, { children: [
|
|
6396
|
+
/* @__PURE__ */ jsx28(DropdownMenuTrigger4, { asChild: true, children: /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(SortGlyph, {}), "aria-label": `Sort: ${sortLabel}`, children: sortLabel }) }),
|
|
6397
|
+
/* @__PURE__ */ jsx28(DropdownMenuContent4, { align: "end", children: /* @__PURE__ */ jsx28(DropdownMenuRadioGroup, { value: sort, onValueChange: (v) => onSort(sorts.find((s) => s.value === v)?.value ?? "name"), children: sorts.map((s) => /* @__PURE__ */ jsx28(DropdownMenuRadioItem, { value: s.value, children: s.label }, s.value)) }) })
|
|
6144
6398
|
] })
|
|
6145
6399
|
] })
|
|
6146
6400
|
] }),
|
|
6147
|
-
/* @__PURE__ */
|
|
6148
|
-
/* @__PURE__ */
|
|
6149
|
-
query ? /* @__PURE__ */
|
|
6150
|
-
] }) : /* @__PURE__ */
|
|
6151
|
-
pinned.length > 0 ? /* @__PURE__ */
|
|
6401
|
+
/* @__PURE__ */ jsx28("div", { className: "min-h-0 flex-1 overflow-y-auto px-2 pb-3", onKeyDown, children: items.length === 0 ? /* @__PURE__ */ jsxs26("div", { className: "flex flex-col items-center gap-3 px-4 py-12 text-center", children: [
|
|
6402
|
+
/* @__PURE__ */ jsx28("span", { className: "text-sm text-muted-foreground", children: query ? `Nothing matches \u201C${query}\u201D.` : "Nothing here yet." }),
|
|
6403
|
+
query ? /* @__PURE__ */ jsx28(Button23, { variant: "outline", onClick: () => onQuery(""), children: "Clear search" }) : /* @__PURE__ */ jsx28(Button23, { variant: "outline", icon: /* @__PURE__ */ jsx28(PlusGlyph, {}), onClick: onNew, children: "New item" })
|
|
6404
|
+
] }) : /* @__PURE__ */ jsxs26("ul", { ref: listRef, className: "flex flex-col gap-px", children: [
|
|
6405
|
+
pinned.length > 0 ? /* @__PURE__ */ jsx28("li", { className: "px-2 pb-1 pt-1 text-xs font-medium text-muted-foreground", children: "This page" }) : null,
|
|
6152
6406
|
pinned.map(row),
|
|
6153
|
-
pinned.length > 0 && rest.length > 0 ? /* @__PURE__ */
|
|
6407
|
+
pinned.length > 0 && rest.length > 0 ? /* @__PURE__ */ jsx28("li", { className: "px-2 pb-1 pt-3 text-xs font-medium text-muted-foreground", children: "Everything else" }) : null,
|
|
6154
6408
|
rest.map(row)
|
|
6155
6409
|
] }) })
|
|
6156
6410
|
] });
|
|
@@ -6159,48 +6413,93 @@ function ListRow({ item, family, port, on, onSelect, withOwner }) {
|
|
|
6159
6413
|
const confirmed = useConfirmed();
|
|
6160
6414
|
const copy = useCopy();
|
|
6161
6415
|
const notify = useNotify();
|
|
6162
|
-
const [busy, setBusy] =
|
|
6163
|
-
const
|
|
6164
|
-
const
|
|
6165
|
-
const
|
|
6416
|
+
const [busy, setBusy] = useState28(false);
|
|
6417
|
+
const [menuOpen, setMenuOpen] = useState28(false);
|
|
6418
|
+
const canUse = item.capabilities.canUse;
|
|
6419
|
+
const user = canUse ? item.fields.find((f) => USERNAME_KEYS.test(f.key) && f.handling !== "sealed" && f.active !== false) : void 0;
|
|
6420
|
+
const secret = canUse && item.capabilities.canReveal ? item.fields.find((f) => f.key === "password" && f.handling === "revealable" && f.active !== false) : void 0;
|
|
6421
|
+
const code = canUse && item.authenticator?.enabled ? item.authenticator : null;
|
|
6422
|
+
const run = async (label, read, isSecret) => {
|
|
6166
6423
|
setBusy(true);
|
|
6167
6424
|
try {
|
|
6168
|
-
const v = await confirmed(
|
|
6169
|
-
await copy(v, label, { secret:
|
|
6425
|
+
const v = await confirmed(read);
|
|
6426
|
+
await copy(v, label, { secret: isSecret });
|
|
6170
6427
|
} catch (e) {
|
|
6171
6428
|
if (!wasCancelled(e)) notify(e instanceof Error ? e.message : `${label} could not be read`, "error");
|
|
6172
6429
|
} finally {
|
|
6173
6430
|
setBusy(false);
|
|
6174
6431
|
}
|
|
6175
6432
|
};
|
|
6176
|
-
|
|
6177
|
-
|
|
6433
|
+
const copyUser = () => user && void run(user.label, () => port.reveal(item, user.key), user.handling !== "visible");
|
|
6434
|
+
const copyPassword = () => secret && void run("Password", () => port.reveal(item, secret.key), true);
|
|
6435
|
+
const copyCode = () => code && void run("One-time code", async () => (await port.authenticator.code(item)).code, true);
|
|
6436
|
+
const copyName = () => void copy(item.name, "Name", { secret: false });
|
|
6437
|
+
return /* @__PURE__ */ jsxs26("li", { className: "group relative", "data-item": item.id, children: [
|
|
6438
|
+
/* @__PURE__ */ jsxs26(
|
|
6178
6439
|
"button",
|
|
6179
6440
|
{
|
|
6180
6441
|
type: "button",
|
|
6181
6442
|
"aria-current": on ? "true" : void 0,
|
|
6182
6443
|
"data-surface": on ? "primary" : void 0,
|
|
6183
6444
|
onClick: () => onSelect(item.id),
|
|
6184
|
-
className: cn13("flex h-12 w-full items-center gap-3 rounded-lg px-2 text-left", on ? "bg-primary text-primary-foreground" : "hover:bg-accent"),
|
|
6445
|
+
className: cn13("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"),
|
|
6185
6446
|
children: [
|
|
6186
|
-
/* @__PURE__ */
|
|
6187
|
-
/* @__PURE__ */
|
|
6188
|
-
/* @__PURE__ */
|
|
6189
|
-
/* @__PURE__ */
|
|
6447
|
+
/* @__PURE__ */ jsx28(ItemIcon, { definitionKey: item.definitionKey, family, site: loginSiteOf(item), inverted: on }),
|
|
6448
|
+
/* @__PURE__ */ jsxs26("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
6449
|
+
/* @__PURE__ */ jsx28("span", { className: "truncate text-sm font-medium", children: item.name }),
|
|
6450
|
+
/* @__PURE__ */ jsx28("span", { className: "truncate text-xs text-muted-foreground", children: subtitleOf(item, withOwner) })
|
|
6190
6451
|
] })
|
|
6191
6452
|
]
|
|
6192
6453
|
}
|
|
6193
6454
|
),
|
|
6194
|
-
|
|
6195
|
-
user ? /* @__PURE__ */
|
|
6196
|
-
|
|
6197
|
-
|
|
6455
|
+
/* @__PURE__ */ jsxs26("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: [
|
|
6456
|
+
user || secret ? /* @__PURE__ */ jsxs26("div", { className: cn13("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: [
|
|
6457
|
+
user ? /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(UserGlyph, {}), "aria-label": `Copy ${user.label}`, disabled: busy, onClick: copyUser }) : null,
|
|
6458
|
+
secret ? /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(KeyGlyph, {}), "aria-label": "Copy password", disabled: busy, onClick: copyPassword }) : null
|
|
6459
|
+
] }) : null,
|
|
6460
|
+
/* @__PURE__ */ jsxs26(DropdownMenu4, { open: menuOpen, onOpenChange: setMenuOpen, children: [
|
|
6461
|
+
/* @__PURE__ */ jsx28(DropdownMenuTrigger4, { asChild: true, children: /* @__PURE__ */ jsx28(
|
|
6462
|
+
Button23,
|
|
6463
|
+
{
|
|
6464
|
+
variant: "quiet",
|
|
6465
|
+
icon: /* @__PURE__ */ jsx28(MoreGlyph, {}),
|
|
6466
|
+
"aria-label": `Actions for ${item.name}`,
|
|
6467
|
+
disabled: busy,
|
|
6468
|
+
className: cn13("[@media(hover:hover)]:invisible [@media(hover:hover)]:group-hover:visible [@media(hover:hover)]:group-focus-within:visible", menuOpen && "[@media(hover:hover)]:visible")
|
|
6469
|
+
}
|
|
6470
|
+
) }),
|
|
6471
|
+
/* @__PURE__ */ jsxs26(DropdownMenuContent4, { align: "end", children: [
|
|
6472
|
+
user ? /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyUser, children: [
|
|
6473
|
+
/* @__PURE__ */ jsx28(UserGlyph, { className: "size-4" }),
|
|
6474
|
+
"Copy ",
|
|
6475
|
+
user.label.toLowerCase()
|
|
6476
|
+
] }) : null,
|
|
6477
|
+
secret ? /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyPassword, children: [
|
|
6478
|
+
/* @__PURE__ */ jsx28(KeyGlyph, { className: "size-4" }),
|
|
6479
|
+
"Copy password"
|
|
6480
|
+
] }) : null,
|
|
6481
|
+
code ? /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyCode, children: [
|
|
6482
|
+
/* @__PURE__ */ jsx28(ClockGlyph, { className: "size-4" }),
|
|
6483
|
+
"Copy one-time code"
|
|
6484
|
+
] }) : null,
|
|
6485
|
+
user || secret || code ? /* @__PURE__ */ jsx28(DropdownMenuSeparator4, {}) : null,
|
|
6486
|
+
/* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: () => onSelect(item.id), children: [
|
|
6487
|
+
/* @__PURE__ */ jsx28(ChevronRightGlyph, { className: "size-4" }),
|
|
6488
|
+
"Open"
|
|
6489
|
+
] }),
|
|
6490
|
+
/* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyName, children: [
|
|
6491
|
+
/* @__PURE__ */ jsx28(CopyIcon7, { className: "size-4" }),
|
|
6492
|
+
"Copy name"
|
|
6493
|
+
] })
|
|
6494
|
+
] })
|
|
6495
|
+
] })
|
|
6496
|
+
] })
|
|
6198
6497
|
] });
|
|
6199
6498
|
}
|
|
6200
6499
|
|
|
6201
6500
|
// src/lists/TrashView.tsx
|
|
6202
|
-
import { useState as
|
|
6203
|
-
import { Button as
|
|
6501
|
+
import { useState as useState30 } from "react";
|
|
6502
|
+
import { Button as Button25 } from "@ai-matrx/design-system/controls";
|
|
6204
6503
|
import { formatAbsoluteDate as formatAbsoluteDate4 } from "@ai-matrx/kit/format";
|
|
6205
6504
|
|
|
6206
6505
|
// src/lists/logic.ts
|
|
@@ -6273,15 +6572,15 @@ function refusalText(reason) {
|
|
|
6273
6572
|
}
|
|
6274
6573
|
|
|
6275
6574
|
// src/lists/RestorePanel.tsx
|
|
6276
|
-
import { useEffect as useEffect18, useState as
|
|
6277
|
-
import { Button as
|
|
6278
|
-
import { Fragment as
|
|
6575
|
+
import { useEffect as useEffect18, useState as useState29 } from "react";
|
|
6576
|
+
import { Button as Button24 } from "@ai-matrx/design-system/controls";
|
|
6577
|
+
import { Fragment as Fragment18, jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
6279
6578
|
var count = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
|
|
6280
6579
|
function RestorePanel({ lists, item, restore, onClose }) {
|
|
6281
|
-
const [preview, setPreview] =
|
|
6282
|
-
const [error, setError] =
|
|
6283
|
-
const [busy, setBusy] =
|
|
6284
|
-
const [loading, setLoading] =
|
|
6580
|
+
const [preview, setPreview] = useState29(null);
|
|
6581
|
+
const [error, setError] = useState29(null);
|
|
6582
|
+
const [busy, setBusy] = useState29(false);
|
|
6583
|
+
const [loading, setLoading] = useState29(Boolean(lists.preview));
|
|
6285
6584
|
useEffect18(() => {
|
|
6286
6585
|
if (!lists.preview) return;
|
|
6287
6586
|
let live = true;
|
|
@@ -6314,41 +6613,41 @@ function RestorePanel({ lists, item, restore, onClose }) {
|
|
|
6314
6613
|
setBusy(false);
|
|
6315
6614
|
}
|
|
6316
6615
|
};
|
|
6317
|
-
return /* @__PURE__ */
|
|
6616
|
+
return /* @__PURE__ */ jsxs27(
|
|
6318
6617
|
Panel,
|
|
6319
6618
|
{
|
|
6320
6619
|
title: `Restore "${item.name}"`,
|
|
6321
6620
|
size: "md",
|
|
6322
6621
|
onClose,
|
|
6323
|
-
footer: /* @__PURE__ */
|
|
6324
|
-
/* @__PURE__ */
|
|
6325
|
-
refused ? null : /* @__PURE__ */
|
|
6622
|
+
footer: /* @__PURE__ */ jsxs27(Fragment18, { children: [
|
|
6623
|
+
/* @__PURE__ */ jsx29(Button24, { variant: "quiet", onClick: onClose, children: refused ? "Close" : "Cancel" }),
|
|
6624
|
+
refused ? null : /* @__PURE__ */ jsx29(Button24, { variant: "primary", icon: /* @__PURE__ */ jsx29(RestoreGlyph, {}), disabled: busy || loading || lists.preview !== void 0 && preview === null, onClick: () => void run(), children: busy ? "Restoring\u2026" : "Restore" })
|
|
6326
6625
|
] }),
|
|
6327
6626
|
children: [
|
|
6328
|
-
loading ? /* @__PURE__ */
|
|
6329
|
-
/* @__PURE__ */
|
|
6330
|
-
/* @__PURE__ */
|
|
6331
|
-
preview.passkeys === 1 ? /* @__PURE__ */
|
|
6332
|
-
/* @__PURE__ */
|
|
6333
|
-
preview.priorWasDisabled ? /* @__PURE__ */
|
|
6334
|
-
] }) : preview ? /* @__PURE__ */
|
|
6335
|
-
error ? /* @__PURE__ */
|
|
6627
|
+
loading ? /* @__PURE__ */ jsx29(VaultSection, { children: /* @__PURE__ */ jsx29(Empty, { children: "Checking what comes back\u2026" }) }) : preview?.supported ? /* @__PURE__ */ jsxs27(VaultSection, { title: "Comes back", children: [
|
|
6628
|
+
/* @__PURE__ */ jsx29(VaultRow, { label: "Fields", children: /* @__PURE__ */ jsx29("span", { className: "text-foreground", children: count(preview.fields, "field") }) }),
|
|
6629
|
+
/* @__PURE__ */ jsx29(VaultRow, { label: "Files", children: /* @__PURE__ */ jsx29("span", { className: "text-foreground", children: count(preview.attachments, "file") }) }),
|
|
6630
|
+
preview.passkeys === 1 ? /* @__PURE__ */ jsx29(VaultRow, { label: "Passkey", hint: "Not turned on; the site may not accept it", children: /* @__PURE__ */ jsx29("span", { className: "text-foreground", children: "1 passkey" }) }) : null,
|
|
6631
|
+
/* @__PURE__ */ jsx29(VaultRow, { label: "Stays off", hint: "Turn each back on yourself", children: /* @__PURE__ */ jsx29("span", { className: "text-muted-foreground", children: "Sharing, browser fill, codes, sandboxes, agents" }) }),
|
|
6632
|
+
preview.priorWasDisabled ? /* @__PURE__ */ jsx29(VaultRow, { label: "Before", children: /* @__PURE__ */ jsx29("span", { className: "text-muted-foreground", children: "It was already off before it was deleted." }) }) : null
|
|
6633
|
+
] }) : preview ? /* @__PURE__ */ jsx29(VaultSection, { children: /* @__PURE__ */ jsx29(Empty, { children: refusalText(preview.reason) }) }) : /* @__PURE__ */ jsx29(VaultSection, { children: /* @__PURE__ */ jsx29(Empty, { children: "It comes back turned off: sharing, browser fill, codes and sandbox use stay off." }) }),
|
|
6634
|
+
error ? /* @__PURE__ */ jsx29("p", { role: "alert", className: "px-1 text-sm text-destructive", children: error }) : null
|
|
6336
6635
|
]
|
|
6337
6636
|
}
|
|
6338
6637
|
);
|
|
6339
6638
|
}
|
|
6340
6639
|
|
|
6341
6640
|
// src/lists/TrashView.tsx
|
|
6342
|
-
import { jsx as
|
|
6641
|
+
import { jsx as jsx30, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
6343
6642
|
function trashLineOf(item) {
|
|
6344
6643
|
return [item.definitionLabel || null, item.owner.label, item.deletion?.deletedAt ? `Deleted ${formatAbsoluteDate4(item.deletion.deletedAt, DAY_FORMAT, "")}` : null].filter(Boolean).join(" \xB7 ");
|
|
6345
6644
|
}
|
|
6346
6645
|
function TrashView({ port, deleted, query, header, onChanged }) {
|
|
6347
6646
|
const confirmed = useConfirmed();
|
|
6348
|
-
const [busyId, setBusyId] =
|
|
6349
|
-
const [message2, setMessage] =
|
|
6647
|
+
const [busyId, setBusyId] = useState30(null);
|
|
6648
|
+
const [message2, setMessage] = useState30(null);
|
|
6350
6649
|
const shown = deleted.filter((i) => trashItemMatchesQuery(i, query));
|
|
6351
|
-
const [restoring, setRestoring] =
|
|
6650
|
+
const [restoring, setRestoring] = useState30(null);
|
|
6352
6651
|
const restore = async (item, deletionId) => {
|
|
6353
6652
|
setBusyId(item.id);
|
|
6354
6653
|
setMessage(null);
|
|
@@ -6364,32 +6663,32 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6364
6663
|
setBusyId(null);
|
|
6365
6664
|
}
|
|
6366
6665
|
};
|
|
6367
|
-
return /* @__PURE__ */
|
|
6666
|
+
return /* @__PURE__ */ jsxs28("div", { className: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-3", children: [
|
|
6368
6667
|
header,
|
|
6369
|
-
/* @__PURE__ */
|
|
6668
|
+
/* @__PURE__ */ jsx30(VaultSection, { title: "Trash", children: shown.length === 0 ? /* @__PURE__ */ jsx30(Empty, { children: deleted.length === 0 ? "The trash is empty." : "Nothing matches." }) : shown.map((item) => (
|
|
6370
6669
|
// A list row, not a field row: the name gets the whole width (on a phone a label column
|
|
6371
6670
|
// left "Vau…" for every row), the deletion date sits under it.
|
|
6372
|
-
/* @__PURE__ */
|
|
6373
|
-
/* @__PURE__ */
|
|
6374
|
-
/* @__PURE__ */
|
|
6375
|
-
/* @__PURE__ */
|
|
6671
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex min-h-12 items-center gap-3 px-3 py-1.5 sm:px-4", children: [
|
|
6672
|
+
/* @__PURE__ */ jsxs28("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
6673
|
+
/* @__PURE__ */ jsx30("span", { className: "truncate text-sm text-foreground", children: item.name }),
|
|
6674
|
+
/* @__PURE__ */ jsx30("span", { className: "truncate text-xs text-muted-foreground", children: trashLineOf(item) })
|
|
6376
6675
|
] }),
|
|
6377
|
-
/* @__PURE__ */
|
|
6676
|
+
/* @__PURE__ */ jsx30(Button25, { variant: "outline", icon: /* @__PURE__ */ jsx30(RestoreGlyph, {}), disabled: busyId !== null || !item.deletion, onClick: () => setRestoring(item), children: "Restore" })
|
|
6378
6677
|
] }, item.id)
|
|
6379
6678
|
)) }),
|
|
6380
|
-
restoring ? /* @__PURE__ */
|
|
6381
|
-
message2 ? /* @__PURE__ */
|
|
6679
|
+
restoring ? /* @__PURE__ */ jsx30(RestorePanel, { lists: port.lists, item: restoring, restore: (deletionId) => restore(restoring, deletionId), onClose: () => setRestoring(null) }) : null,
|
|
6680
|
+
message2 ? /* @__PURE__ */ jsx30("p", { role: "status", className: message2.tone === "error" ? "px-1 text-sm text-destructive" : "px-1 text-sm text-muted-foreground", children: message2.text }) : null
|
|
6382
6681
|
] });
|
|
6383
6682
|
}
|
|
6384
6683
|
|
|
6385
6684
|
// src/NewItemFlow.tsx
|
|
6386
|
-
import { useMemo as useMemo4, useState as
|
|
6685
|
+
import { useMemo as useMemo4, useState as useState31 } from "react";
|
|
6387
6686
|
import { cn as cn14 } from "@ai-matrx/design-system";
|
|
6388
|
-
import { Button as
|
|
6687
|
+
import { Button as Button26, Field as Field11, SearchField as SearchField2 } from "@ai-matrx/design-system/controls";
|
|
6389
6688
|
import { GlobeIcon as GlobeIcon3 } from "@ai-matrx/design-system/icons";
|
|
6390
|
-
import { jsx as
|
|
6689
|
+
import { jsx as jsx31, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
6391
6690
|
function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
|
|
6392
|
-
const [search, setSearch] =
|
|
6691
|
+
const [search, setSearch] = useState31("");
|
|
6393
6692
|
const guess = useMemo4(() => inferFromUrl(url, definitions), [url, definitions]);
|
|
6394
6693
|
const common = COMMON_DEFINITION_KEYS.map((k) => definitions.find((d) => d.key === k)).filter((d) => d !== void 0);
|
|
6395
6694
|
const matches = useMemo4(() => {
|
|
@@ -6401,15 +6700,15 @@ function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
|
|
|
6401
6700
|
const alternatives = (guess?.alternatives ?? []).map((k) => definitions.find((d) => d.key === k)).filter((d) => d !== void 0).slice(0, 4);
|
|
6402
6701
|
const use = (d) => onChoose(d.key, guess?.name ?? "", guess?.url ?? url.trim());
|
|
6403
6702
|
const shown = search.trim() ? matches : common;
|
|
6404
|
-
return /* @__PURE__ */
|
|
6405
|
-
/* @__PURE__ */
|
|
6406
|
-
/* @__PURE__ */
|
|
6407
|
-
/* @__PURE__ */
|
|
6703
|
+
return /* @__PURE__ */ jsxs29("div", { className: "flex h-full min-h-0 flex-col bg-background", children: [
|
|
6704
|
+
/* @__PURE__ */ jsxs29("header", { className: "flex min-h-14 items-center gap-2 border-b border-border px-3 sm:px-5", children: [
|
|
6705
|
+
/* @__PURE__ */ jsx31(Button26, { variant: "quiet", icon: /* @__PURE__ */ jsx31(ChevronLeftGlyph, {}), "aria-label": "Cancel", onClick: onCancel }),
|
|
6706
|
+
/* @__PURE__ */ jsx31("h2", { className: "text-base font-semibold", children: "New item" })
|
|
6408
6707
|
] }),
|
|
6409
|
-
/* @__PURE__ */
|
|
6410
|
-
/* @__PURE__ */
|
|
6411
|
-
/* @__PURE__ */
|
|
6412
|
-
|
|
6708
|
+
/* @__PURE__ */ jsx31("div", { className: "min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ jsxs29("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: [
|
|
6709
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex flex-col gap-3", children: [
|
|
6710
|
+
/* @__PURE__ */ jsx31(
|
|
6711
|
+
Field11,
|
|
6413
6712
|
{
|
|
6414
6713
|
hero: true,
|
|
6415
6714
|
value: url,
|
|
@@ -6421,45 +6720,45 @@ function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
|
|
|
6421
6720
|
"aria-label": "Website address",
|
|
6422
6721
|
inputMode: "url",
|
|
6423
6722
|
autoFocus: true,
|
|
6424
|
-
icon: /* @__PURE__ */
|
|
6723
|
+
icon: /* @__PURE__ */ jsx31(GlobeIcon3, {})
|
|
6425
6724
|
}
|
|
6426
6725
|
),
|
|
6427
|
-
guess && login ? /* @__PURE__ */
|
|
6428
|
-
/* @__PURE__ */
|
|
6429
|
-
/* @__PURE__ */
|
|
6430
|
-
/* @__PURE__ */
|
|
6431
|
-
/* @__PURE__ */
|
|
6432
|
-
/* @__PURE__ */
|
|
6726
|
+
guess && login ? /* @__PURE__ */ jsxs29("div", { className: "flex flex-col gap-2 rounded-xl border border-border bg-card p-3", children: [
|
|
6727
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex items-center gap-3", children: [
|
|
6728
|
+
/* @__PURE__ */ jsx31("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() }),
|
|
6729
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
6730
|
+
/* @__PURE__ */ jsx31("span", { className: "truncate text-sm font-medium", children: guess.name }),
|
|
6731
|
+
/* @__PURE__ */ jsx31("span", { className: "truncate text-xs text-muted-foreground", children: guess.url.replace(/^https?:\/\//, "") })
|
|
6433
6732
|
] }),
|
|
6434
|
-
/* @__PURE__ */
|
|
6733
|
+
/* @__PURE__ */ jsx31(Button26, { variant: "primary", onClick: () => use(login), children: "Save login" })
|
|
6435
6734
|
] }),
|
|
6436
|
-
alternatives.length > 0 ? /* @__PURE__ */
|
|
6437
|
-
/* @__PURE__ */
|
|
6438
|
-
alternatives.map((d) => /* @__PURE__ */
|
|
6735
|
+
alternatives.length > 0 ? /* @__PURE__ */ jsxs29("div", { className: "flex flex-wrap items-center gap-1.5 pl-12", children: [
|
|
6736
|
+
/* @__PURE__ */ jsx31("span", { className: "text-xs text-muted-foreground", children: "Or" }),
|
|
6737
|
+
alternatives.map((d) => /* @__PURE__ */ jsx31(Button26, { variant: "outline", onClick: () => use(d), children: d.label }, d.key))
|
|
6439
6738
|
] }) : null
|
|
6440
|
-
] }) : url.trim() ? /* @__PURE__ */
|
|
6739
|
+
] }) : url.trim() ? /* @__PURE__ */ jsx31("p", { className: "px-1 text-sm text-muted-foreground", children: "Not a website address. Pick a type below; it is kept." }) : null
|
|
6441
6740
|
] }),
|
|
6442
|
-
/* @__PURE__ */
|
|
6443
|
-
/* @__PURE__ */
|
|
6444
|
-
/* @__PURE__ */
|
|
6741
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex flex-col gap-3", children: [
|
|
6742
|
+
/* @__PURE__ */ jsx31("div", { className: "flex items-center justify-between gap-3", children: /* @__PURE__ */ jsx31("h3", { className: "text-xs font-medium text-muted-foreground", children: search.trim() ? "Matching types" : "Or choose a type" }) }),
|
|
6743
|
+
/* @__PURE__ */ jsx31("ul", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: shown.map((d) => {
|
|
6445
6744
|
const Icon = definitionGlyph(d.key, d.family);
|
|
6446
|
-
return /* @__PURE__ */
|
|
6447
|
-
/* @__PURE__ */
|
|
6448
|
-
/* @__PURE__ */
|
|
6745
|
+
return /* @__PURE__ */ jsx31("li", { children: /* @__PURE__ */ jsxs29("button", { type: "button", onClick: () => use(d), className: cn14("flex h-12 w-full items-center gap-3 rounded-xl border border-border bg-card px-3 text-left hover:bg-accent"), children: [
|
|
6746
|
+
/* @__PURE__ */ jsx31("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted", children: /* @__PURE__ */ jsx31(Icon, { className: "size-4" }) }),
|
|
6747
|
+
/* @__PURE__ */ jsx31("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: d.label })
|
|
6449
6748
|
] }) }, d.key);
|
|
6450
6749
|
}) }),
|
|
6451
|
-
search.trim() && matches.length === 0 ? /* @__PURE__ */
|
|
6452
|
-
/* @__PURE__ */
|
|
6750
|
+
search.trim() && matches.length === 0 ? /* @__PURE__ */ jsx31("p", { className: "px-1 text-sm text-muted-foreground", children: "No type matches." }) : null,
|
|
6751
|
+
/* @__PURE__ */ jsx31(SearchField2, { value: search, onChange: (e) => setSearch(e.target.value), placeholder: `Search all ${definitions.length} types`, "aria-label": "Search types" })
|
|
6453
6752
|
] })
|
|
6454
6753
|
] }) })
|
|
6455
6754
|
] });
|
|
6456
6755
|
}
|
|
6457
6756
|
|
|
6458
6757
|
// src/sharing/SecureLinkPanel.tsx
|
|
6459
|
-
import { useEffect as useEffect19, useRef as useRef16, useState as
|
|
6460
|
-
import { confirm as
|
|
6758
|
+
import { useEffect as useEffect19, useRef as useRef16, useState as useState32 } from "react";
|
|
6759
|
+
import { confirm as confirm11 } from "@ai-matrx/kit/confirm-opener";
|
|
6461
6760
|
import { Checkbox as Checkbox2 } from "@ai-matrx/design-system";
|
|
6462
|
-
import { Badge as Badge8, Button as
|
|
6761
|
+
import { Badge as Badge8, Button as Button27, Field as Field12, RegionSkeleton as RegionSkeleton2, SegmentedControl as SegmentedControl6, Textarea as Textarea4 } from "@ai-matrx/design-system/controls";
|
|
6463
6762
|
import { formatAbsoluteDate as formatAbsoluteDate5 } from "@ai-matrx/kit/format";
|
|
6464
6763
|
|
|
6465
6764
|
// src/sharing/secure-link-logic.ts
|
|
@@ -6535,23 +6834,23 @@ function sortSent(rows) {
|
|
|
6535
6834
|
}
|
|
6536
6835
|
|
|
6537
6836
|
// src/sharing/SecureLinkPanel.tsx
|
|
6538
|
-
import { jsx as
|
|
6837
|
+
import { jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
6539
6838
|
function SecureLinkPanel({ item, port, onClose }) {
|
|
6540
6839
|
const sharing = port.sharing;
|
|
6541
6840
|
const { busy, error, notice, run, setNotice } = useConfirmedChange();
|
|
6542
|
-
const [remedy, setRemedy] =
|
|
6543
|
-
const [options, setOptions] =
|
|
6544
|
-
const [optionsError, setOptionsError] =
|
|
6545
|
-
const [sent, setSent] =
|
|
6546
|
-
const [sentError, setSentError] =
|
|
6547
|
-
const [nonce, setNonce] =
|
|
6548
|
-
const [email, setEmail] =
|
|
6549
|
-
const [phone, setPhone] =
|
|
6550
|
-
const [name, setName] =
|
|
6551
|
-
const [linkBy, setLinkBy] =
|
|
6552
|
-
const [fields, setFields] =
|
|
6553
|
-
const [note, setNote] =
|
|
6554
|
-
const [sameChannelSent, setSameChannelSent] =
|
|
6841
|
+
const [remedy, setRemedy] = useState32(null);
|
|
6842
|
+
const [options, setOptions] = useState32(null);
|
|
6843
|
+
const [optionsError, setOptionsError] = useState32(null);
|
|
6844
|
+
const [sent, setSent] = useState32(null);
|
|
6845
|
+
const [sentError, setSentError] = useState32(null);
|
|
6846
|
+
const [nonce, setNonce] = useState32(0);
|
|
6847
|
+
const [email, setEmail] = useState32("");
|
|
6848
|
+
const [phone, setPhone] = useState32("");
|
|
6849
|
+
const [name, setName] = useState32("");
|
|
6850
|
+
const [linkBy, setLinkBy] = useState32("email");
|
|
6851
|
+
const [fields, setFields] = useState32([]);
|
|
6852
|
+
const [note, setNote] = useState32("");
|
|
6853
|
+
const [sameChannelSent, setSameChannelSent] = useState32(false);
|
|
6555
6854
|
useEffect19(() => {
|
|
6556
6855
|
let live = true;
|
|
6557
6856
|
setOptionsError(null);
|
|
@@ -6580,7 +6879,7 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6580
6879
|
live = false;
|
|
6581
6880
|
};
|
|
6582
6881
|
}, [sharing, item, nonce]);
|
|
6583
|
-
const [phoneTyped, setPhoneTyped] =
|
|
6882
|
+
const [phoneTyped, setPhoneTyped] = useState32(false);
|
|
6584
6883
|
const prefilled = useRef16(false);
|
|
6585
6884
|
useEffect19(() => {
|
|
6586
6885
|
const lookup = sharing.phoneOnFile;
|
|
@@ -6644,7 +6943,7 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6644
6943
|
setNonce((n) => n + 1);
|
|
6645
6944
|
};
|
|
6646
6945
|
const turnOff = async (row) => {
|
|
6647
|
-
const ok = await
|
|
6946
|
+
const ok = await confirm11({
|
|
6648
6947
|
title: "Turn off this link?",
|
|
6649
6948
|
description: `The link to ${recipientOf(row)} stops working at once and what it carries is deleted. They will need a new one.`,
|
|
6650
6949
|
confirmLabel: "Turn off",
|
|
@@ -6657,23 +6956,23 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6657
6956
|
setNonce((n) => n + 1);
|
|
6658
6957
|
};
|
|
6659
6958
|
const toggle2 = (key, on) => setFields((cur) => on ? [...cur.filter((k) => k !== key), key] : cur.filter((k) => k !== key));
|
|
6660
|
-
return /* @__PURE__ */
|
|
6959
|
+
return /* @__PURE__ */ jsxs30(
|
|
6661
6960
|
Panel,
|
|
6662
6961
|
{
|
|
6663
6962
|
title: "Send securely",
|
|
6664
6963
|
size: "md",
|
|
6665
6964
|
onClose,
|
|
6666
|
-
footer: /* @__PURE__ */
|
|
6667
|
-
sameChannelSent && !error ? /* @__PURE__ */
|
|
6668
|
-
/* @__PURE__ */
|
|
6669
|
-
/* @__PURE__ */
|
|
6965
|
+
footer: /* @__PURE__ */ jsxs30(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx32(StatusLine, { error, notice }) : null, children: [
|
|
6966
|
+
sameChannelSent && !error ? /* @__PURE__ */ jsx32(Badge8, { tone: "warning", children: "Both by email" }) : null,
|
|
6967
|
+
/* @__PURE__ */ jsx32(Button27, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
6968
|
+
/* @__PURE__ */ jsx32(Button27, { variant: "primary", disabled: !canSend, onClick: () => void send(), children: busy === "send" ? "Sending\u2026" : "Send link" })
|
|
6670
6969
|
] }),
|
|
6671
6970
|
children: [
|
|
6672
|
-
remedy ? /* @__PURE__ */
|
|
6673
|
-
/* @__PURE__ */
|
|
6674
|
-
/* @__PURE__ */
|
|
6675
|
-
/* @__PURE__ */
|
|
6676
|
-
|
|
6971
|
+
remedy ? /* @__PURE__ */ jsx32("p", { className: "px-1 text-xs text-muted-foreground", children: remedy }) : null,
|
|
6972
|
+
/* @__PURE__ */ jsxs30(VaultSection, { title: "Recipient", children: [
|
|
6973
|
+
/* @__PURE__ */ jsx32(VaultRow, { label: "Email", children: /* @__PURE__ */ jsx32(Field12, { type: "email", autoComplete: "off", placeholder: "name@example.com", "aria-label": "Their email", value: email, onChange: (e) => setEmail(e.target.value), className: "w-full" }) }),
|
|
6974
|
+
/* @__PURE__ */ jsx32(VaultRow, { label: "Mobile", hint: "For the code", children: /* @__PURE__ */ jsx32(
|
|
6975
|
+
Field12,
|
|
6677
6976
|
{
|
|
6678
6977
|
type: "tel",
|
|
6679
6978
|
autoComplete: "off",
|
|
@@ -6688,9 +6987,9 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6688
6987
|
className: "w-full"
|
|
6689
6988
|
}
|
|
6690
6989
|
) }),
|
|
6691
|
-
/* @__PURE__ */
|
|
6692
|
-
plan && !plan.same ? /* @__PURE__ */
|
|
6693
|
-
|
|
6990
|
+
/* @__PURE__ */ jsx32(VaultRow, { label: "Name", hint: "Optional", children: /* @__PURE__ */ jsx32(Field12, { autoComplete: "off", placeholder: "Their name", "aria-label": "Their name", value: name, onChange: (e) => setName(e.target.value), className: "w-full" }) }),
|
|
6991
|
+
plan && !plan.same ? /* @__PURE__ */ jsx32(VaultRow, { label: "Link by", children: /* @__PURE__ */ jsx32(
|
|
6992
|
+
SegmentedControl6,
|
|
6694
6993
|
{
|
|
6695
6994
|
"aria-label": "Send the link by",
|
|
6696
6995
|
value: linkBy,
|
|
@@ -6701,28 +7000,28 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6701
7000
|
]
|
|
6702
7001
|
}
|
|
6703
7002
|
) }) : null,
|
|
6704
|
-
email.trim() ? /* @__PURE__ */
|
|
7003
|
+
email.trim() ? /* @__PURE__ */ jsx32(VaultRow, { label: "Delivery", children: /* @__PURE__ */ jsx32("span", { className: plan?.same ? "text-warning" : "text-foreground", children: planWords(plan) }) }) : null
|
|
6705
7004
|
] }),
|
|
6706
|
-
/* @__PURE__ */
|
|
6707
|
-
/* @__PURE__ */
|
|
6708
|
-
/* @__PURE__ */
|
|
6709
|
-
!f.available && f.reason ? /* @__PURE__ */
|
|
7005
|
+
/* @__PURE__ */ jsx32(VaultSection, { title: "Include", children: optionsError ? /* @__PURE__ */ jsx32(Empty, { children: /* @__PURE__ */ jsx32("span", { className: "text-destructive", children: optionsError }) }) : !options ? /* @__PURE__ */ jsx32(RegionSkeleton2, { shape: "rows", count: 2, "aria-label": "Loading what can be sent", className: "px-3 sm:px-4" }) : options.fields.length === 0 ? /* @__PURE__ */ jsx32(Empty, { children: "Name and details only" }) : options.fields.map((f) => /* @__PURE__ */ jsxs30("label", { className: "flex min-h-11 items-center gap-3 px-3 py-1 sm:px-4", "data-clickable": f.available ? "" : void 0, children: [
|
|
7006
|
+
/* @__PURE__ */ jsx32(Checkbox2, { checked: fields.includes(f.key), disabled: !f.available, onCheckedChange: (v) => toggle2(f.key, v === true), "aria-label": f.label }),
|
|
7007
|
+
/* @__PURE__ */ jsx32("span", { className: "min-w-0 flex-1 truncate text-sm text-foreground", children: f.label }),
|
|
7008
|
+
!f.available && f.reason ? /* @__PURE__ */ jsx32("span", { className: "min-w-0 max-w-[55%] truncate text-xs text-muted-foreground", title: f.reason, children: f.reason }) : null
|
|
6710
7009
|
] }, f.key)) }),
|
|
6711
|
-
/* @__PURE__ */
|
|
6712
|
-
options ? /* @__PURE__ */
|
|
6713
|
-
/* @__PURE__ */
|
|
6714
|
-
/* @__PURE__ */
|
|
7010
|
+
/* @__PURE__ */ jsx32(VaultSection, { title: "Message", children: /* @__PURE__ */ jsx32("div", { className: "px-3 py-1 sm:px-4", children: /* @__PURE__ */ jsx32(Textarea4, { className: "w-full", rows: 2, maxLength: NOTE_MAX, placeholder: "Shown once, with it", "aria-label": "Message", value: note, onChange: (e) => setNote(e.target.value) }) }) }),
|
|
7011
|
+
options ? /* @__PURE__ */ jsxs30(VaultSection, { title: "Link", children: [
|
|
7012
|
+
/* @__PURE__ */ jsx32(VaultRow, { label: "Opens", children: /* @__PURE__ */ jsx32("span", { className: "text-foreground", children: "Once" }) }),
|
|
7013
|
+
/* @__PURE__ */ jsx32(VaultRow, { label: "Link expires", children: /* @__PURE__ */ jsxs30("span", { className: "text-foreground", children: [
|
|
6715
7014
|
"After ",
|
|
6716
7015
|
lifetimeWords(options.linkMinutes)
|
|
6717
7016
|
] }) }),
|
|
6718
|
-
/* @__PURE__ */
|
|
7017
|
+
/* @__PURE__ */ jsx32(VaultRow, { label: "Code expires", children: /* @__PURE__ */ jsxs30("span", { className: "text-foreground", children: [
|
|
6719
7018
|
"After ",
|
|
6720
7019
|
lifetimeWords(options.codeMinutes)
|
|
6721
7020
|
] }) })
|
|
6722
7021
|
] }) : null,
|
|
6723
|
-
sharing.sentSecureLinks ? /* @__PURE__ */
|
|
6724
|
-
/* @__PURE__ */
|
|
6725
|
-
row.status === "pending" ? /* @__PURE__ */
|
|
7022
|
+
sharing.sentSecureLinks ? /* @__PURE__ */ jsx32(VaultSection, { title: "Sent links", children: sentError ? /* @__PURE__ */ jsx32(Empty, { children: /* @__PURE__ */ jsx32("span", { className: "text-destructive", children: sentError }) }) : !sent ? /* @__PURE__ */ jsx32(RegionSkeleton2, { shape: "rows", count: 2, "aria-label": "Loading sent links", className: "px-3 sm:px-4" }) : sent.length === 0 ? /* @__PURE__ */ jsx32(Empty, { children: "None yet" }) : sent.map((row) => /* @__PURE__ */ jsxs30(AccessLine, { glyph: row.status === "pending" ? ClockGlyph : row.fieldKeys.length ? LockGlyph : ShareGlyph, who: recipientOf(row), meta: sentMeta(row, options), children: [
|
|
7023
|
+
/* @__PURE__ */ jsx32(Badge8, { tone: STATUS_TONE[row.status] ?? "neutral", children: statusWord(row.status) }),
|
|
7024
|
+
row.status === "pending" ? /* @__PURE__ */ jsx32(Button27, { variant: "quiet", disabled: busy !== null, onClick: () => void turnOff(row), children: "Turn off" }) : null
|
|
6726
7025
|
] }, row.id)) }) : null
|
|
6727
7026
|
]
|
|
6728
7027
|
}
|
|
@@ -6735,9 +7034,9 @@ function sentMeta(row, options) {
|
|
|
6735
7034
|
}
|
|
6736
7035
|
|
|
6737
7036
|
// src/devices/DevicesPanel.tsx
|
|
6738
|
-
import { useCallback as useCallback4, useEffect as useEffect20, useState as
|
|
6739
|
-
import { confirm as
|
|
6740
|
-
import { Button as
|
|
7037
|
+
import { useCallback as useCallback4, useEffect as useEffect20, useState as useState33 } from "react";
|
|
7038
|
+
import { confirm as confirm12 } from "@ai-matrx/kit/confirm-opener";
|
|
7039
|
+
import { Button as Button28, RegionSkeleton as RegionSkeleton3 } from "@ai-matrx/design-system/controls";
|
|
6741
7040
|
import { formatAbsoluteDate as formatAbsoluteDate6 } from "@ai-matrx/kit/format";
|
|
6742
7041
|
|
|
6743
7042
|
// src/devices/logic.ts
|
|
@@ -6818,17 +7117,17 @@ function addPasskeyFailure(message2) {
|
|
|
6818
7117
|
var isRevoked = (d) => d.revokedAt !== null;
|
|
6819
7118
|
|
|
6820
7119
|
// src/devices/DevicesPanel.tsx
|
|
6821
|
-
import { Fragment as
|
|
7120
|
+
import { Fragment as Fragment19, jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
6822
7121
|
var messageOf3 = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
|
|
6823
7122
|
function ErrorLine2({ text }) {
|
|
6824
|
-
return text ? /* @__PURE__ */
|
|
7123
|
+
return text ? /* @__PURE__ */ jsx33("p", { role: "alert", className: "px-1 text-sm text-destructive", children: text }) : null;
|
|
6825
7124
|
}
|
|
6826
7125
|
function DevicesPanel({ port, onClose }) {
|
|
6827
7126
|
const confirmed = useConfirmed();
|
|
6828
7127
|
const notify = useNotify();
|
|
6829
|
-
const [devices, setDevices] =
|
|
6830
|
-
const [error, setError] =
|
|
6831
|
-
const [busyId, setBusyId] =
|
|
7128
|
+
const [devices, setDevices] = useState33(null);
|
|
7129
|
+
const [error, setError] = useState33(null);
|
|
7130
|
+
const [busyId, setBusyId] = useState33(null);
|
|
6832
7131
|
const load = useCallback4(async () => {
|
|
6833
7132
|
setError(null);
|
|
6834
7133
|
try {
|
|
@@ -6841,7 +7140,7 @@ function DevicesPanel({ port, onClose }) {
|
|
|
6841
7140
|
void load();
|
|
6842
7141
|
}, [load]);
|
|
6843
7142
|
const revoke = async (device) => {
|
|
6844
|
-
const yes = await
|
|
7143
|
+
const yes = await confirm12({
|
|
6845
7144
|
title: `Revoke ${device.label}?`,
|
|
6846
7145
|
description: "It stops filling now and the extension there signs out. It fills again only after you sign in there and confirm.",
|
|
6847
7146
|
confirmLabel: "Revoke",
|
|
@@ -6860,19 +7159,19 @@ function DevicesPanel({ port, onClose }) {
|
|
|
6860
7159
|
setBusyId(null);
|
|
6861
7160
|
}
|
|
6862
7161
|
};
|
|
6863
|
-
return /* @__PURE__ */
|
|
6864
|
-
/* @__PURE__ */
|
|
6865
|
-
/* @__PURE__ */
|
|
7162
|
+
return /* @__PURE__ */ jsxs31(Panel, { title: "Browsers that can fill", onClose, size: "md", children: [
|
|
7163
|
+
/* @__PURE__ */ jsx33(ErrorLine2, { text: error }),
|
|
7164
|
+
/* @__PURE__ */ jsx33(VaultSection, { children: devices === null ? error ? /* @__PURE__ */ jsx33(Empty, { children: /* @__PURE__ */ jsx33(Button28, { variant: "outline", onClick: () => void load(), children: "Try again" }) }) : /* @__PURE__ */ jsx33(RegionSkeleton3, { shape: "rows", count: 2, "aria-label": "Loading your browsers", className: "px-3 sm:px-4" }) : devices.length === 0 ? /* @__PURE__ */ jsx33(Empty, { children: "No browser can fill yet. Turn it on in the extension." }) : devices.map((device) => {
|
|
6866
7165
|
const off = isRevoked(device);
|
|
6867
|
-
return /* @__PURE__ */
|
|
7166
|
+
return /* @__PURE__ */ jsx33(
|
|
6868
7167
|
VaultRow,
|
|
6869
7168
|
{
|
|
6870
7169
|
label: off ? "Turned off" : "Can fill",
|
|
6871
7170
|
hint: off ? formatAbsoluteDate6(device.revokedAt, DAY_FORMAT, "") : void 0,
|
|
6872
|
-
actions: off ? null : /* @__PURE__ */
|
|
6873
|
-
children: /* @__PURE__ */
|
|
6874
|
-
/* @__PURE__ */
|
|
6875
|
-
/* @__PURE__ */
|
|
7171
|
+
actions: off ? null : /* @__PURE__ */ jsx33(Button28, { variant: "outline", icon: /* @__PURE__ */ jsx33(PowerGlyph, {}), disabled: busyId !== null, onClick: () => void revoke(device), children: "Revoke" }),
|
|
7172
|
+
children: /* @__PURE__ */ jsxs31("span", { className: "flex min-w-0 flex-col", children: [
|
|
7173
|
+
/* @__PURE__ */ jsx33("span", { className: off ? "truncate text-muted-foreground" : "truncate text-foreground", children: device.label }),
|
|
7174
|
+
/* @__PURE__ */ jsxs31("span", { className: "truncate text-xs text-muted-foreground", children: [
|
|
6876
7175
|
device.lastUsedAt ? `Last used ${formatAbsoluteDate6(device.lastUsedAt, void 0, "")}` : "Never used",
|
|
6877
7176
|
device.addedAt ? ` \xB7 added ${formatAbsoluteDate6(device.addedAt, DAY_FORMAT, "")}` : ""
|
|
6878
7177
|
] })
|
|
@@ -6895,10 +7194,10 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
|
|
|
6895
7194
|
const where = isMac ? "the Mac app" : "the extension";
|
|
6896
7195
|
const passkeys = port.devices.passkeys;
|
|
6897
7196
|
const here = passkeys?.available() ?? false;
|
|
6898
|
-
const [methods, setMethods] =
|
|
6899
|
-
const [busy, setBusy] =
|
|
6900
|
-
const [error, setError] =
|
|
6901
|
-
const [approvedUntil, setApprovedUntil] =
|
|
7197
|
+
const [methods, setMethods] = useState33(null);
|
|
7198
|
+
const [busy, setBusy] = useState33(null);
|
|
7199
|
+
const [error, setError] = useState33(null);
|
|
7200
|
+
const [approvedUntil, setApprovedUntil] = useState33(null);
|
|
6902
7201
|
const load = useCallback4(async () => {
|
|
6903
7202
|
setError(null);
|
|
6904
7203
|
try {
|
|
@@ -6949,55 +7248,55 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
|
|
|
6949
7248
|
};
|
|
6950
7249
|
const canApprove = Boolean(key && passkeys && here && methods?.passkey && !approvedUntil);
|
|
6951
7250
|
const title = isMac ? "Approve this Mac" : name ? `Approve ${name}` : "Approve this browser";
|
|
6952
|
-
const footer = approvedUntil ? /* @__PURE__ */
|
|
6953
|
-
/* @__PURE__ */
|
|
6954
|
-
canApprove ? /* @__PURE__ */
|
|
7251
|
+
const footer = approvedUntil ? /* @__PURE__ */ jsx33(Button28, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ jsxs31(Fragment19, { children: [
|
|
7252
|
+
/* @__PURE__ */ jsx33(Button28, { variant: "quiet", disabled: busy !== null, onClick: refuse, children: key ? "Refuse" : "Close" }),
|
|
7253
|
+
canApprove ? /* @__PURE__ */ jsx33(Button28, { variant: "primary", icon: /* @__PURE__ */ jsx33(FingerprintGlyph, {}), disabled: busy !== null, onClick: () => void approve(), children: busy === "approve" ? "Approving\u2026" : "Approve with passkey" }) : null
|
|
6955
7254
|
] });
|
|
6956
|
-
return /* @__PURE__ */
|
|
7255
|
+
return /* @__PURE__ */ jsx33(Panel, { title, onClose: refuse, size: "sm", footer, children: !key ? /* @__PURE__ */ jsx33(VaultSection, { children: /* @__PURE__ */ jsxs31(Empty, { children: [
|
|
6957
7256
|
"This link names no key. Start again from ",
|
|
6958
7257
|
where,
|
|
6959
7258
|
"."
|
|
6960
|
-
] }) }) : /* @__PURE__ */
|
|
6961
|
-
/* @__PURE__ */
|
|
6962
|
-
/* @__PURE__ */
|
|
6963
|
-
name ? /* @__PURE__ */
|
|
6964
|
-
/* @__PURE__ */
|
|
7259
|
+
] }) }) : /* @__PURE__ */ jsxs31(Fragment19, { children: [
|
|
7260
|
+
/* @__PURE__ */ jsxs31(VaultSection, { title: "What is asking", children: [
|
|
7261
|
+
/* @__PURE__ */ jsx33(VaultRow, { label: "Asking", hint: "Approve only if you just asked", children: asker }),
|
|
7262
|
+
name ? /* @__PURE__ */ jsx33(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx33("span", { className: "block truncate", children: name }) }) : null,
|
|
7263
|
+
/* @__PURE__ */ jsx33(VaultRow, { label: "Code", hint: `Must match ${where}`, children: /* @__PURE__ */ jsx33("span", { className: "font-mono tracking-wider text-foreground", children: shortFingerprint(key) }) })
|
|
6965
7264
|
] }),
|
|
6966
|
-
/* @__PURE__ */
|
|
6967
|
-
/* @__PURE__ */
|
|
7265
|
+
/* @__PURE__ */ jsx33(ErrorLine2, { text: error }),
|
|
7266
|
+
/* @__PURE__ */ jsx33(VaultSection, { title: "Confirm it\u2019s you", children: approvedUntil ? /* @__PURE__ */ jsx33(VaultRow, { label: "Approved", actions: /* @__PURE__ */ jsx33(CheckGlyph, { className: "size-4 text-primary" }), children: /* @__PURE__ */ jsxs31("span", { className: "text-foreground", children: [
|
|
6968
7267
|
"Return to ",
|
|
6969
7268
|
where,
|
|
6970
7269
|
" by ",
|
|
6971
7270
|
formatAbsoluteDate6(approvedUntil, void 0, ""),
|
|
6972
7271
|
"."
|
|
6973
|
-
] }) }) : !passkeys ? /* @__PURE__ */
|
|
7272
|
+
] }) }) : !passkeys ? /* @__PURE__ */ jsxs31(Empty, { children: [
|
|
6974
7273
|
"Approve with your password in ",
|
|
6975
7274
|
where,
|
|
6976
7275
|
"."
|
|
6977
|
-
] }) : !here ? /* @__PURE__ */
|
|
7276
|
+
] }) : !here ? /* @__PURE__ */ jsx33(
|
|
6978
7277
|
VaultRow,
|
|
6979
7278
|
{
|
|
6980
7279
|
label: "Passkey",
|
|
6981
7280
|
hint: `Passkeys work only on ${passkeys.rpId}`,
|
|
6982
|
-
actions: /* @__PURE__ */
|
|
6983
|
-
children: /* @__PURE__ */
|
|
7281
|
+
actions: /* @__PURE__ */ jsx33(Button28, { variant: "outline", icon: /* @__PURE__ */ jsx33(ExternalGlyph, {}), onClick: openOnDomain, children: "Open there" }),
|
|
7282
|
+
children: /* @__PURE__ */ jsx33("span", { className: "text-muted-foreground", children: "Not on this page" })
|
|
6984
7283
|
}
|
|
6985
|
-
) : methods === null ? error ? /* @__PURE__ */
|
|
7284
|
+
) : methods === null ? error ? /* @__PURE__ */ jsx33(Empty, { children: /* @__PURE__ */ jsx33(Button28, { variant: "outline", onClick: () => void load(), children: "Try again" }) }) : /* @__PURE__ */ jsx33(RegionSkeleton3, { shape: "rows", count: 1, "aria-label": "Checking your account", className: "px-3 sm:px-4" }) : !methods.passkey ? /* @__PURE__ */ jsx33(
|
|
6986
7285
|
VaultRow,
|
|
6987
7286
|
{
|
|
6988
7287
|
label: "Passkey",
|
|
6989
7288
|
hint: methods.password ? `Or type your password in ${where}` : "Add one to approve",
|
|
6990
|
-
actions: /* @__PURE__ */
|
|
6991
|
-
children: /* @__PURE__ */
|
|
7289
|
+
actions: /* @__PURE__ */ jsx33(Button28, { variant: "primary", icon: /* @__PURE__ */ jsx33(FingerprintGlyph, {}), disabled: busy !== null, onClick: () => void addPasskey(), children: busy === "add" ? "Adding\u2026" : "Add passkey" }),
|
|
7290
|
+
children: /* @__PURE__ */ jsx33("span", { className: "text-muted-foreground", children: methods.password ? "None yet" : "No password or passkey" })
|
|
6992
7291
|
}
|
|
6993
|
-
) : /* @__PURE__ */
|
|
7292
|
+
) : /* @__PURE__ */ jsx33(VaultRow, { label: "Passkey", hint: "Your device asks for it next", children: /* @__PURE__ */ jsx33("span", { className: "text-foreground", children: "Ready" }) }) })
|
|
6994
7293
|
] }) });
|
|
6995
7294
|
}
|
|
6996
7295
|
|
|
6997
7296
|
// src/native/NativeImportPanel.tsx
|
|
6998
|
-
import { useEffect as useEffect22, useMemo as useMemo5, useState as
|
|
6999
|
-
import { confirm as
|
|
7000
|
-
import { Badge as Badge9, Button as
|
|
7297
|
+
import { useEffect as useEffect22, useMemo as useMemo5, useState as useState35 } from "react";
|
|
7298
|
+
import { confirm as confirm13 } from "@ai-matrx/kit/confirm-opener";
|
|
7299
|
+
import { Badge as Badge9, Button as Button29, Select as Select10 } from "@ai-matrx/design-system/controls";
|
|
7001
7300
|
|
|
7002
7301
|
// src/native/logic.ts
|
|
7003
7302
|
var ACTIVE_PHASES = /* @__PURE__ */ new Set(["authorizing", "importing"]);
|
|
@@ -7058,12 +7357,12 @@ async function loadFullPreview(bridge, operationId, current) {
|
|
|
7058
7357
|
}
|
|
7059
7358
|
|
|
7060
7359
|
// src/native/use-native-import.ts
|
|
7061
|
-
import { useEffect as useEffect21, useRef as useRef17, useState as
|
|
7360
|
+
import { useEffect as useEffect21, useRef as useRef17, useState as useState34 } from "react";
|
|
7062
7361
|
var fail = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
|
|
7063
7362
|
var RESTART = "Your account changed. The import was stopped; start it again.";
|
|
7064
7363
|
function useNativeImport(bridge, stillAllowed, onImported) {
|
|
7065
|
-
const [screen, setScreen] =
|
|
7066
|
-
const [busy, setBusy] =
|
|
7364
|
+
const [screen, setScreen] = useState34({ kind: "idle", message: null });
|
|
7365
|
+
const [busy, setBusy] = useState34(false);
|
|
7067
7366
|
const generation = useRef17(0);
|
|
7068
7367
|
const mounted = useRef17(false);
|
|
7069
7368
|
const op = useRef17(null);
|
|
@@ -7171,7 +7470,7 @@ function useNativeImport(bridge, stillAllowed, onImported) {
|
|
|
7171
7470
|
}
|
|
7172
7471
|
};
|
|
7173
7472
|
refreshRef.current = refresh;
|
|
7174
|
-
const
|
|
7473
|
+
const confirm15 = async () => {
|
|
7175
7474
|
if (screen.kind !== "preview") return;
|
|
7176
7475
|
const active = op.current;
|
|
7177
7476
|
if (!active?.organizationId || active.id !== screen.preview.operation_id) return;
|
|
@@ -7253,11 +7552,11 @@ function useNativeImport(bridge, stillAllowed, onImported) {
|
|
|
7253
7552
|
off?.();
|
|
7254
7553
|
};
|
|
7255
7554
|
}, [bridge]);
|
|
7256
|
-
return { screen, busy, begin, refresh: () => refresh(false), confirm:
|
|
7555
|
+
return { screen, busy, begin, refresh: () => refresh(false), confirm: confirm15, cancel, recover, reset };
|
|
7257
7556
|
}
|
|
7258
7557
|
|
|
7259
7558
|
// src/native/NativeImportPanel.tsx
|
|
7260
|
-
import { Fragment as
|
|
7559
|
+
import { Fragment as Fragment20, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
7261
7560
|
var TONE = {
|
|
7262
7561
|
eligible: "success",
|
|
7263
7562
|
committed: "success",
|
|
@@ -7268,15 +7567,15 @@ var TONE = {
|
|
|
7268
7567
|
};
|
|
7269
7568
|
function NativeImportPanel({ bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged }) {
|
|
7270
7569
|
if (!bridge) {
|
|
7271
|
-
return /* @__PURE__ */
|
|
7570
|
+
return /* @__PURE__ */ jsx34(Panel, { title: "Import passkeys", size: "md", onClose, footer: /* @__PURE__ */ jsx34(Button29, { variant: "primary", onClick: onClose, children: "Close" }), children: /* @__PURE__ */ jsx34(VaultSection, { children: /* @__PURE__ */ jsx34(Empty, { children: "Passkey import needs the desktop app." }) }) });
|
|
7272
7571
|
}
|
|
7273
|
-
return /* @__PURE__ */
|
|
7572
|
+
return /* @__PURE__ */ jsx34(Importer, { bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged });
|
|
7274
7573
|
}
|
|
7275
7574
|
function Importer({ bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged }) {
|
|
7276
7575
|
const options = useMemo5(() => organizations.map((o) => ({ value: o.id, label: o.name })), [organizations]);
|
|
7277
|
-
const [organizationId, setOrganizationId] =
|
|
7278
|
-
const [limits, setLimits] =
|
|
7279
|
-
const [limitError, setLimitError] =
|
|
7576
|
+
const [organizationId, setOrganizationId] = useState35(() => organizations.some((o) => o.id === activeOrganizationId) ? activeOrganizationId : organizations[0]?.id ?? "");
|
|
7577
|
+
const [limits, setLimits] = useState35(null);
|
|
7578
|
+
const [limitError, setLimitError] = useState35(null);
|
|
7280
7579
|
const flow = useNativeImport(bridge, (id) => organizations.some((o) => o.id === id), onChanged);
|
|
7281
7580
|
const { screen, busy } = flow;
|
|
7282
7581
|
const orgName = organizations.find((o) => o.id === organizationId)?.name ?? "this organization";
|
|
@@ -7298,64 +7597,64 @@ function Importer({ bridge, readLimits, activeOrganizationId, organizations, onC
|
|
|
7298
7597
|
const active = status !== null && !TERMINAL_PHASES.has(status.phase);
|
|
7299
7598
|
const ready = preview?.slots.filter((s) => s.disposition === "eligible").length ?? 0;
|
|
7300
7599
|
const importNow = async () => {
|
|
7301
|
-
const yes = await
|
|
7600
|
+
const yes = await confirm13({ title: `Add ${plural2(ready, "passkey")} to ${orgName}?`, description: "Passkeys already there are skipped.", confirmLabel: "Import" });
|
|
7302
7601
|
if (yes) await flow.confirm();
|
|
7303
7602
|
};
|
|
7304
|
-
const footer = preview ? /* @__PURE__ */
|
|
7305
|
-
/* @__PURE__ */
|
|
7306
|
-
/* @__PURE__ */
|
|
7603
|
+
const footer = preview ? /* @__PURE__ */ jsxs32(Fragment20, { children: [
|
|
7604
|
+
/* @__PURE__ */ jsx34(Button29, { variant: "quiet", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel" }),
|
|
7605
|
+
/* @__PURE__ */ jsxs32(Button29, { variant: "primary", icon: /* @__PURE__ */ jsx34(ImportGlyph, { className: "size-4" }), disabled: busy || ready === 0, onClick: () => void importNow(), children: [
|
|
7307
7606
|
"Import ",
|
|
7308
7607
|
ready
|
|
7309
7608
|
] })
|
|
7310
|
-
] }) : status ? active ? /* @__PURE__ */
|
|
7311
|
-
/* @__PURE__ */
|
|
7312
|
-
/* @__PURE__ */
|
|
7313
|
-
] }) : /* @__PURE__ */
|
|
7314
|
-
/* @__PURE__ */
|
|
7315
|
-
/* @__PURE__ */
|
|
7316
|
-
] }) : /* @__PURE__ */
|
|
7317
|
-
return /* @__PURE__ */
|
|
7318
|
-
screen.kind === "idle" ? /* @__PURE__ */
|
|
7319
|
-
/* @__PURE__ */
|
|
7320
|
-
/* @__PURE__ */
|
|
7321
|
-
/* @__PURE__ */
|
|
7609
|
+
] }) : status ? active ? /* @__PURE__ */ jsxs32(Fragment20, { children: [
|
|
7610
|
+
/* @__PURE__ */ jsx34(Button29, { variant: "outline", disabled: busy, onClick: () => void flow.refresh(), children: "Refresh" }),
|
|
7611
|
+
/* @__PURE__ */ jsx34(Button29, { variant: "outline", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel import" })
|
|
7612
|
+
] }) : /* @__PURE__ */ jsxs32(Fragment20, { children: [
|
|
7613
|
+
/* @__PURE__ */ jsx34(Button29, { variant: "quiet", onClick: flow.reset, children: "New file" }),
|
|
7614
|
+
/* @__PURE__ */ jsx34(Button29, { variant: "primary", onClick: onClose, children: "Done" })
|
|
7615
|
+
] }) : /* @__PURE__ */ jsx34(Button29, { variant: "quiet", onClick: onClose, children: "Close" });
|
|
7616
|
+
return /* @__PURE__ */ jsxs32(Panel, { title: "Import passkeys", size: "lg", onClose, footer, children: [
|
|
7617
|
+
screen.kind === "idle" ? /* @__PURE__ */ jsxs32(VaultSection, { children: [
|
|
7618
|
+
/* @__PURE__ */ jsx34(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx34(Select10, { value: organizationId, options, "aria-label": "Save to", disabled: busy, onValueChange: setOrganizationId }) }),
|
|
7619
|
+
/* @__PURE__ */ jsx34(VaultRow, { label: "File", hint: limits ? `Up to ${plural2(limits.maxItems, "passkey")}` : "A passkey exchange file", children: /* @__PURE__ */ jsx34(Button29, { variant: "outline", icon: /* @__PURE__ */ jsx34(ImportGlyph, { className: "size-4" }), disabled: busy || !organizationId || limitError !== null, onClick: () => void flow.begin(organizationId), children: busy ? "Opening\u2026" : "Choose file" }) }),
|
|
7620
|
+
/* @__PURE__ */ jsx34(VaultRow, { label: "Interrupted", hint: "Finish or clear an earlier import", children: /* @__PURE__ */ jsx34(Button29, { variant: "quiet", disabled: busy, onClick: () => void flow.recover(), children: "Recover" }) })
|
|
7322
7621
|
] }) : null,
|
|
7323
|
-
preview ? /* @__PURE__ */
|
|
7622
|
+
preview ? /* @__PURE__ */ jsx34(VaultSection, { title: `${ready} of ${preview.total} ready`, children: /* @__PURE__ */ jsx34(
|
|
7324
7623
|
Windowed,
|
|
7325
7624
|
{
|
|
7326
7625
|
items: preview.slots,
|
|
7327
|
-
render: (slot) => /* @__PURE__ */
|
|
7626
|
+
render: (slot) => /* @__PURE__ */ jsx34(VaultRow, { label: /* @__PURE__ */ jsx34(Badge9, { tone: TONE[slot.disposition], children: dispositionLabel(slot.disposition) }), hint: void 0, children: /* @__PURE__ */ jsx34("span", { className: "block truncate text-foreground", title: slot.reason ?? void 0, children: slot.title ?? "Unnamed passkey" }) }, slot.slot_id)
|
|
7328
7627
|
}
|
|
7329
7628
|
) }) : null,
|
|
7330
|
-
status && !preview ? /* @__PURE__ */
|
|
7331
|
-
/* @__PURE__ */
|
|
7332
|
-
/* @__PURE__ */
|
|
7333
|
-
/* @__PURE__ */
|
|
7334
|
-
/* @__PURE__ */
|
|
7335
|
-
status.uncertain > 0 ? /* @__PURE__ */
|
|
7336
|
-
status.not_attempted > 0 ? /* @__PURE__ */
|
|
7629
|
+
status && !preview ? /* @__PURE__ */ jsxs32(VaultSection, { title: `${accounted(status)} of ${status.total} done`, children: [
|
|
7630
|
+
/* @__PURE__ */ jsx34(VaultRow, { label: "Imported", children: /* @__PURE__ */ jsx34("span", { className: "text-foreground", children: status.committed }) }),
|
|
7631
|
+
/* @__PURE__ */ jsx34(VaultRow, { label: "Already there", children: /* @__PURE__ */ jsx34("span", { className: "text-foreground", children: status.already_present }) }),
|
|
7632
|
+
/* @__PURE__ */ jsx34(VaultRow, { label: "Can't import", children: /* @__PURE__ */ jsx34("span", { className: "text-foreground", children: status.unsupported }) }),
|
|
7633
|
+
/* @__PURE__ */ jsx34(VaultRow, { label: "Failed", children: /* @__PURE__ */ jsx34("span", { className: status.failed > 0 ? "text-destructive" : "text-foreground", children: status.failed }) }),
|
|
7634
|
+
status.uncertain > 0 ? /* @__PURE__ */ jsx34(VaultRow, { label: "Needs recovery", children: /* @__PURE__ */ jsx34("span", { className: "text-foreground", children: status.uncertain }) }) : null,
|
|
7635
|
+
status.not_attempted > 0 ? /* @__PURE__ */ jsx34(VaultRow, { label: "Not tried", children: /* @__PURE__ */ jsx34("span", { className: "text-foreground", children: status.not_attempted }) }) : null
|
|
7337
7636
|
] }) : null,
|
|
7338
|
-
screen.message ? /* @__PURE__ */
|
|
7339
|
-
/* @__PURE__ */
|
|
7637
|
+
screen.message ? /* @__PURE__ */ jsx34("p", { role: "status", className: "px-1 text-sm text-muted-foreground", children: screen.message }) : null,
|
|
7638
|
+
/* @__PURE__ */ jsx34(ErrorLine, { message: limitError })
|
|
7340
7639
|
] });
|
|
7341
7640
|
}
|
|
7342
7641
|
|
|
7343
7642
|
// src/extension/PageView.tsx
|
|
7344
|
-
import { useState as
|
|
7345
|
-
import { DropdownMenu as DropdownMenu5, DropdownMenuContent as DropdownMenuContent5, DropdownMenuItem as
|
|
7346
|
-
import { Button as
|
|
7643
|
+
import { useState as useState39 } from "react";
|
|
7644
|
+
import { DropdownMenu as DropdownMenu5, DropdownMenuContent as DropdownMenuContent5, DropdownMenuItem as DropdownMenuItem5, DropdownMenuTrigger as DropdownMenuTrigger5, SiteIcon } from "@ai-matrx/design-system";
|
|
7645
|
+
import { Button as Button33 } from "@ai-matrx/design-system/controls";
|
|
7347
7646
|
import { GlobeIcon as GlobeIcon4 } from "@ai-matrx/design-system/icons";
|
|
7348
7647
|
|
|
7349
7648
|
// src/extension/CaptureCard.tsx
|
|
7350
|
-
import { useState as
|
|
7351
|
-
import { Button as
|
|
7352
|
-
import { Fragment as
|
|
7649
|
+
import { useState as useState36, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
7650
|
+
import { Button as Button30, SearchField as SearchField3 } from "@ai-matrx/design-system/controls";
|
|
7651
|
+
import { Fragment as Fragment21, jsx as jsx35, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
7353
7652
|
var SEARCH_FROM = 4;
|
|
7354
7653
|
function CaptureCard({ capture, onChanged }) {
|
|
7355
7654
|
const prompt = useSyncExternalStore3(capture.subscribe, capture.get, capture.get);
|
|
7356
7655
|
const notify = useNotify();
|
|
7357
|
-
const [busy, setBusy] =
|
|
7358
|
-
const [q, setQ] =
|
|
7656
|
+
const [busy, setBusy] = useState36(false);
|
|
7657
|
+
const [q, setQ] = useState36("");
|
|
7359
7658
|
if (!prompt) return null;
|
|
7360
7659
|
const decide = async (d) => {
|
|
7361
7660
|
setBusy(true);
|
|
@@ -7373,53 +7672,53 @@ function CaptureCard({ capture, onChanged }) {
|
|
|
7373
7672
|
const existing = prompt.existing;
|
|
7374
7673
|
const needle = q.trim().toLocaleLowerCase();
|
|
7375
7674
|
const shown = needle ? existing.filter((x) => x.name.toLocaleLowerCase().includes(needle)) : existing;
|
|
7376
|
-
return /* @__PURE__ */
|
|
7377
|
-
/* @__PURE__ */
|
|
7378
|
-
/* @__PURE__ */
|
|
7379
|
-
/* @__PURE__ */
|
|
7380
|
-
/* @__PURE__ */
|
|
7381
|
-
/* @__PURE__ */
|
|
7675
|
+
return /* @__PURE__ */ jsxs33("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: [
|
|
7676
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2.5", children: [
|
|
7677
|
+
/* @__PURE__ */ jsx35(ShieldGlyph, { className: "size-5 shrink-0 text-primary" }),
|
|
7678
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
7679
|
+
/* @__PURE__ */ jsx35("span", { className: "truncate text-sm font-medium", children: prompt.unavailable ? "Couldn\u2019t hold this login" : "Save this login?" }),
|
|
7680
|
+
/* @__PURE__ */ jsx35("span", { className: "truncate text-xs text-muted-foreground", children: prompt.username ? `${prompt.host} \xB7 ${prompt.username}` : prompt.host })
|
|
7382
7681
|
] }),
|
|
7383
|
-
/* @__PURE__ */
|
|
7682
|
+
/* @__PURE__ */ jsx35(Button30, { variant: "quiet", icon: /* @__PURE__ */ jsx35(XGlyph, {}), "aria-label": "Not now", disabled: busy, onClick: () => void decide({ action: "dismiss" }) })
|
|
7384
7683
|
] }),
|
|
7385
|
-
prompt.unavailable ? /* @__PURE__ */
|
|
7386
|
-
existing.length > 0 ? /* @__PURE__ */
|
|
7387
|
-
existing.length >= SEARCH_FROM ? /* @__PURE__ */
|
|
7388
|
-
/* @__PURE__ */
|
|
7684
|
+
prompt.unavailable ? /* @__PURE__ */ jsx35("p", { className: "text-xs text-muted-foreground", children: "Save it by hand with Save a login." }) : /* @__PURE__ */ jsxs33(Fragment21, { children: [
|
|
7685
|
+
existing.length > 0 ? /* @__PURE__ */ jsxs33("div", { className: "flex flex-col gap-1", children: [
|
|
7686
|
+
existing.length >= SEARCH_FROM ? /* @__PURE__ */ jsx35(SearchField3, { value: q, onChange: (e) => setQ(e.target.value), placeholder: "Search logins", "aria-label": "Search logins to update" }) : null,
|
|
7687
|
+
/* @__PURE__ */ jsxs33("ul", { className: "flex max-h-36 flex-col gap-px overflow-y-auto", children: [
|
|
7389
7688
|
shown.map((x) => {
|
|
7390
7689
|
const tag = distinguish(x, existing);
|
|
7391
|
-
return /* @__PURE__ */
|
|
7392
|
-
/* @__PURE__ */
|
|
7690
|
+
return /* @__PURE__ */ jsxs33("li", { className: "flex h-9 items-center gap-2 px-1", children: [
|
|
7691
|
+
/* @__PURE__ */ jsxs33("span", { className: "min-w-0 flex-1 truncate text-sm", children: [
|
|
7393
7692
|
x.name,
|
|
7394
|
-
tag ? /* @__PURE__ */
|
|
7693
|
+
tag ? /* @__PURE__ */ jsxs33("span", { className: "text-muted-foreground", children: [
|
|
7395
7694
|
" \xB7 ",
|
|
7396
7695
|
tag
|
|
7397
7696
|
] }) : null
|
|
7398
7697
|
] }),
|
|
7399
|
-
/* @__PURE__ */
|
|
7698
|
+
/* @__PURE__ */ jsx35(Button30, { variant: "primary", disabled: busy, onClick: () => void decide({ action: "update", itemId: x.itemId }), "aria-label": `Update ${x.name}`, children: "Update" })
|
|
7400
7699
|
] }, x.itemId);
|
|
7401
7700
|
}),
|
|
7402
|
-
shown.length === 0 ? /* @__PURE__ */
|
|
7701
|
+
shown.length === 0 ? /* @__PURE__ */ jsx35("li", { className: "px-1 py-2 text-xs text-muted-foreground", children: "No saved login matches." }) : null
|
|
7403
7702
|
] })
|
|
7404
7703
|
] }) : null,
|
|
7405
|
-
/* @__PURE__ */
|
|
7406
|
-
/* @__PURE__ */
|
|
7407
|
-
/* @__PURE__ */
|
|
7704
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
7705
|
+
/* @__PURE__ */ jsx35(Button30, { variant: existing.length > 0 ? "outline" : "primary", disabled: busy, onClick: () => void decide({ action: "save" }), children: existing.length > 0 ? "Save as new" : "Save" }),
|
|
7706
|
+
/* @__PURE__ */ jsx35(Button30, { variant: "quiet", disabled: busy, onClick: () => void decide({ action: "never" }), children: "Never here" })
|
|
7408
7707
|
] })
|
|
7409
7708
|
] })
|
|
7410
7709
|
] });
|
|
7411
7710
|
}
|
|
7412
7711
|
|
|
7413
7712
|
// src/extension/FillSetupCard.tsx
|
|
7414
|
-
import { useRef as useRef18, useState as
|
|
7415
|
-
import { Button as
|
|
7416
|
-
import { jsx as
|
|
7713
|
+
import { useRef as useRef18, useState as useState37, useSyncExternalStore as useSyncExternalStore4 } from "react";
|
|
7714
|
+
import { Button as Button31, Field as Field13 } from "@ai-matrx/design-system/controls";
|
|
7715
|
+
import { jsx as jsx36, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
7417
7716
|
function FillSetupCard({ fillSetup }) {
|
|
7418
7717
|
const notify = useNotify();
|
|
7419
7718
|
const state = useSyncExternalStore4(fillSetup.subscribe, fillSetup.get, fillSetup.get);
|
|
7420
7719
|
const box = useRef18(null);
|
|
7421
|
-
const [busy, setBusy] =
|
|
7422
|
-
const [error, setError] =
|
|
7720
|
+
const [busy, setBusy] = useState37(false);
|
|
7721
|
+
const [error, setError] = useState37(null);
|
|
7423
7722
|
if (state.status !== "off") return null;
|
|
7424
7723
|
const finish = async (run) => {
|
|
7425
7724
|
setBusy(true);
|
|
@@ -7445,15 +7744,15 @@ function FillSetupCard({ fillSetup }) {
|
|
|
7445
7744
|
const neither = m !== null && !m.password && !m.passkey;
|
|
7446
7745
|
const showPassword = !neither && (m === null || m.password);
|
|
7447
7746
|
const showPasskey = state.passkey !== null && (neither || m === null || m.passkey);
|
|
7448
|
-
return /* @__PURE__ */
|
|
7449
|
-
/* @__PURE__ */
|
|
7450
|
-
/* @__PURE__ */
|
|
7451
|
-
/* @__PURE__ */
|
|
7452
|
-
/* @__PURE__ */
|
|
7453
|
-
/* @__PURE__ */
|
|
7747
|
+
return /* @__PURE__ */ jsxs34("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: [
|
|
7748
|
+
/* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2.5", children: [
|
|
7749
|
+
/* @__PURE__ */ jsx36(KeyGlyph, { className: "size-5 shrink-0 text-primary" }),
|
|
7750
|
+
/* @__PURE__ */ jsxs34("div", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
7751
|
+
/* @__PURE__ */ jsx36("span", { className: "truncate text-sm font-medium", children: "Turn on filling" }),
|
|
7752
|
+
/* @__PURE__ */ jsx36("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." })
|
|
7454
7753
|
] })
|
|
7455
7754
|
] }),
|
|
7456
|
-
showPassword ? /* @__PURE__ */
|
|
7755
|
+
showPassword ? /* @__PURE__ */ jsxs34(
|
|
7457
7756
|
"form",
|
|
7458
7757
|
{
|
|
7459
7758
|
className: "flex items-center gap-2",
|
|
@@ -7462,42 +7761,42 @@ function FillSetupCard({ fillSetup }) {
|
|
|
7462
7761
|
withPassword();
|
|
7463
7762
|
},
|
|
7464
7763
|
children: [
|
|
7465
|
-
/* @__PURE__ */
|
|
7466
|
-
/* @__PURE__ */
|
|
7764
|
+
/* @__PURE__ */ jsx36(Field13, { 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 }),
|
|
7765
|
+
/* @__PURE__ */ jsx36(Button31, { variant: "primary", type: "submit", disabled: busy, children: "Turn on" })
|
|
7467
7766
|
]
|
|
7468
7767
|
}
|
|
7469
7768
|
) : null,
|
|
7470
|
-
showPasskey ? /* @__PURE__ */
|
|
7769
|
+
showPasskey ? /* @__PURE__ */ jsx36(Button31, { variant: "outline", iconEnd: /* @__PURE__ */ jsx36(ExternalGlyph, {}), disabled: busy, onClick: () => {
|
|
7471
7770
|
setError(null);
|
|
7472
7771
|
fillSetup.openPasskey();
|
|
7473
7772
|
}, children: neither ? "Add a passkey" : "Use a passkey" }) : null,
|
|
7474
|
-
showPasskey && state.awaitingPasskey && state.passkey ? /* @__PURE__ */
|
|
7475
|
-
/* @__PURE__ */
|
|
7773
|
+
showPasskey && state.awaitingPasskey && state.passkey ? /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2", "data-testid": "fill-setup-waiting", children: [
|
|
7774
|
+
/* @__PURE__ */ jsxs34("span", { className: "min-w-0 flex-1 text-xs text-muted-foreground", children: [
|
|
7476
7775
|
"Approve code ",
|
|
7477
|
-
/* @__PURE__ */
|
|
7776
|
+
/* @__PURE__ */ jsx36("span", { className: "font-mono text-foreground", children: state.passkey.code }),
|
|
7478
7777
|
" on that page."
|
|
7479
7778
|
] }),
|
|
7480
|
-
/* @__PURE__ */
|
|
7779
|
+
/* @__PURE__ */ jsx36(Button31, { variant: "primary", disabled: busy, onClick: () => void finish(() => fillSetup.finishPasskey()), children: "I approved" })
|
|
7481
7780
|
] }) : null,
|
|
7482
|
-
error ? /* @__PURE__ */
|
|
7781
|
+
error ? /* @__PURE__ */ jsx36("p", { role: "alert", className: "text-xs text-destructive", children: error }) : null
|
|
7483
7782
|
] });
|
|
7484
7783
|
}
|
|
7485
7784
|
|
|
7486
7785
|
// src/extension/PageGenerator.tsx
|
|
7487
|
-
import { useState as
|
|
7786
|
+
import { useState as useState38 } from "react";
|
|
7488
7787
|
import { Popover as Popover2, PopoverContent as PopoverContent2, PopoverTrigger as PopoverTrigger2 } from "@ai-matrx/design-system";
|
|
7489
|
-
import { Button as
|
|
7490
|
-
import { CopyIcon as
|
|
7491
|
-
import { Fragment as
|
|
7788
|
+
import { Button as Button32 } from "@ai-matrx/design-system/controls";
|
|
7789
|
+
import { CopyIcon as CopyIcon8 } from "@ai-matrx/design-system/icons";
|
|
7790
|
+
import { Fragment as Fragment22, jsx as jsx37, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
7492
7791
|
var HOLD_MS = 6e4;
|
|
7493
7792
|
function PageGenerator({ fields }) {
|
|
7494
7793
|
const limits = useGeneratorLimitsSource();
|
|
7495
7794
|
const copy = useCopy();
|
|
7496
7795
|
const held = useTransientSecret(HOLD_MS);
|
|
7497
|
-
const [open, setOpen] =
|
|
7498
|
-
const [busy, setBusy] =
|
|
7499
|
-
const [targets, setTargets] =
|
|
7500
|
-
const [said, setSaid] =
|
|
7796
|
+
const [open, setOpen] = useState38(false);
|
|
7797
|
+
const [busy, setBusy] = useState38(false);
|
|
7798
|
+
const [targets, setTargets] = useState38([]);
|
|
7799
|
+
const [said, setSaid] = useState38(null);
|
|
7501
7800
|
if (!limits) return null;
|
|
7502
7801
|
const say3 = setSaid;
|
|
7503
7802
|
const put = async (targetId, value2) => {
|
|
@@ -7539,30 +7838,30 @@ function PageGenerator({ fields }) {
|
|
|
7539
7838
|
}
|
|
7540
7839
|
};
|
|
7541
7840
|
const value = held.value;
|
|
7542
|
-
return /* @__PURE__ */
|
|
7543
|
-
/* @__PURE__ */
|
|
7841
|
+
return /* @__PURE__ */ jsxs35(Fragment22, { children: [
|
|
7842
|
+
/* @__PURE__ */ jsx37(
|
|
7544
7843
|
VaultRow,
|
|
7545
7844
|
{
|
|
7546
7845
|
label: "New password",
|
|
7547
|
-
actions: /* @__PURE__ */
|
|
7548
|
-
value ? /* @__PURE__ */
|
|
7549
|
-
/* @__PURE__ */
|
|
7550
|
-
/* @__PURE__ */
|
|
7551
|
-
/* @__PURE__ */
|
|
7846
|
+
actions: /* @__PURE__ */ jsxs35(Fragment22, { children: [
|
|
7847
|
+
value ? /* @__PURE__ */ jsx37(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx37(CopyIcon8, {}), "aria-label": "Copy password", onClick: () => void copy(value, "Password") }) : null,
|
|
7848
|
+
/* @__PURE__ */ jsxs35(Popover2, { open, onOpenChange: setOpen, children: [
|
|
7849
|
+
/* @__PURE__ */ jsx37(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx37(Button32, { variant: "outline", icon: /* @__PURE__ */ jsx37(KeyGlyph, {}), disabled: busy, children: "Generate" }) }),
|
|
7850
|
+
/* @__PURE__ */ jsx37(PopoverContent2, { sizing: "content", align: "end", children: open ? /* @__PURE__ */ jsx37(PasswordGenerator, { limits, useLabel: "Fill page", onUse: (v) => void onUse(v) }) : null })
|
|
7552
7851
|
] })
|
|
7553
7852
|
] }),
|
|
7554
|
-
children: said ? /* @__PURE__ */
|
|
7853
|
+
children: said ? /* @__PURE__ */ jsx37("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__ */ jsx37("span", { className: "text-xs text-muted-foreground", children: "Choose the boxes to fill." }) : /* @__PURE__ */ jsx37("span", { className: "text-xs text-disabled-foreground", children: "Fills the page\u2019s new-password box" })
|
|
7555
7854
|
}
|
|
7556
7855
|
),
|
|
7557
|
-
value && targets.length > 0 ? targets.map((t) => /* @__PURE__ */
|
|
7856
|
+
value && targets.length > 0 ? targets.map((t) => /* @__PURE__ */ jsx37(VaultRow, { label: t.topFrame ? "This page" : "In a frame", actions: /* @__PURE__ */ jsx37(Button32, { variant: "primary", icon: /* @__PURE__ */ jsx37(CheckGlyph, {}), disabled: busy, onClick: () => void put(t.id, value), children: "Fill" }), children: /* @__PURE__ */ jsx37("span", { className: "block truncate text-sm", children: targetLabel(t) }) }, t.id)) : null
|
|
7558
7857
|
] });
|
|
7559
7858
|
}
|
|
7560
7859
|
|
|
7561
7860
|
// src/extension/PageView.tsx
|
|
7562
|
-
import { jsx as
|
|
7861
|
+
import { jsx as jsx38, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
7563
7862
|
function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, items, definitions, onOpen, onNewForPage, onBrowse, onChanged, header }) {
|
|
7564
|
-
const [running, setRunning] =
|
|
7565
|
-
const [said, setSaid] =
|
|
7863
|
+
const [running, setRunning] = useState39(null);
|
|
7864
|
+
const [said, setSaid] = useState39(null);
|
|
7566
7865
|
const site = pageSite(page.url);
|
|
7567
7866
|
const state = page.matchState ?? { status: "ready" };
|
|
7568
7867
|
const fillable = new Set(page.fillableItemIds ?? page.matchingItemIds);
|
|
@@ -7583,20 +7882,20 @@ function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, ite
|
|
|
7583
7882
|
}
|
|
7584
7883
|
};
|
|
7585
7884
|
let body;
|
|
7586
|
-
if (!page.url) body = /* @__PURE__ */
|
|
7885
|
+
if (!page.url) body = /* @__PURE__ */ jsx38(Empty, { children: "No page is open in this tab." });
|
|
7587
7886
|
else if (state.status === "error") {
|
|
7588
|
-
body = /* @__PURE__ */
|
|
7589
|
-
/* @__PURE__ */
|
|
7590
|
-
/* @__PURE__ */
|
|
7887
|
+
body = /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2 px-3 py-2 sm:px-4", children: [
|
|
7888
|
+
/* @__PURE__ */ jsx38("span", { role: "alert", className: "min-w-0 flex-1 text-sm text-muted-foreground", children: MATCH_ERROR_WORDS[state.reason] }),
|
|
7889
|
+
/* @__PURE__ */ jsx38(Button33, { variant: "outline", icon: /* @__PURE__ */ jsx38(RefreshGlyph, {}), onClick: state.retry, children: "Retry" })
|
|
7591
7890
|
] });
|
|
7592
7891
|
} else if (state.status === "loading") {
|
|
7593
|
-
body = /* @__PURE__ */
|
|
7594
|
-
/* @__PURE__ */
|
|
7595
|
-
/* @__PURE__ */
|
|
7892
|
+
body = /* @__PURE__ */ jsx38("div", { "aria-busy": "true", "aria-label": "Checking saved logins", className: "flex flex-col", children: [0, 1].map((n) => /* @__PURE__ */ jsxs36("div", { className: "flex h-12 items-center gap-3 px-3", children: [
|
|
7893
|
+
/* @__PURE__ */ jsx38("div", { className: "size-8 animate-pulse rounded-lg bg-muted" }),
|
|
7894
|
+
/* @__PURE__ */ jsx38("div", { className: "h-3 w-1/2 animate-pulse rounded bg-muted" })
|
|
7596
7895
|
] }, n)) });
|
|
7597
|
-
} else if (matches.length === 0) body = /* @__PURE__ */
|
|
7896
|
+
} else if (matches.length === 0) body = /* @__PURE__ */ jsx38(Empty, { children: "No saved login for this site." });
|
|
7598
7897
|
else {
|
|
7599
|
-
body = /* @__PURE__ */
|
|
7898
|
+
body = /* @__PURE__ */ jsx38("ul", { className: "flex flex-col", children: matches.map(({ itemId, item }) => /* @__PURE__ */ jsx38(
|
|
7600
7899
|
MatchRow,
|
|
7601
7900
|
{
|
|
7602
7901
|
itemId,
|
|
@@ -7613,40 +7912,40 @@ function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, ite
|
|
|
7613
7912
|
itemId
|
|
7614
7913
|
)) });
|
|
7615
7914
|
}
|
|
7616
|
-
return /* @__PURE__ */
|
|
7915
|
+
return /* @__PURE__ */ jsx38("div", { className: "flex h-full min-h-0 flex-col overflow-y-auto bg-background text-foreground", children: /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-3 px-3 pb-4 pt-3", children: [
|
|
7617
7916
|
header,
|
|
7618
|
-
/* @__PURE__ */
|
|
7619
|
-
/* @__PURE__ */
|
|
7620
|
-
/* @__PURE__ */
|
|
7621
|
-
page.refresh ? /* @__PURE__ */
|
|
7622
|
-
onBrowse ? /* @__PURE__ */
|
|
7917
|
+
/* @__PURE__ */ jsxs36("div", { className: "flex min-h-7 items-center gap-2 px-1", children: [
|
|
7918
|
+
/* @__PURE__ */ jsx38(SiteIcon, { site: page.url, fallback: GlobeIcon4, className: "size-4" }),
|
|
7919
|
+
/* @__PURE__ */ jsx38("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", title: page.url, children: site || "No page open" }),
|
|
7920
|
+
page.refresh ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(RefreshGlyph, {}), "aria-label": "Check again", onClick: page.refresh }) : null,
|
|
7921
|
+
onBrowse ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(ListGlyph, {}), onClick: onBrowse, children: "All items" }) : null
|
|
7623
7922
|
] }),
|
|
7624
|
-
fillSetup ? /* @__PURE__ */
|
|
7625
|
-
capture ? /* @__PURE__ */
|
|
7626
|
-
/* @__PURE__ */
|
|
7923
|
+
fillSetup ? /* @__PURE__ */ jsx38(FillSetupCard, { fillSetup }) : null,
|
|
7924
|
+
capture ? /* @__PURE__ */ jsx38(CaptureCard, { capture, onChanged }) : null,
|
|
7925
|
+
/* @__PURE__ */ jsx38(
|
|
7627
7926
|
VaultSection,
|
|
7628
7927
|
{
|
|
7629
7928
|
title: "This site",
|
|
7630
|
-
actions: canSave ? /* @__PURE__ */
|
|
7929
|
+
actions: canSave ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(PlusGlyph, {}), onClick: () => onNewForPage(normalizeLoginUrl2(page.url) ?? page.url), children: "Save a login" }) : null,
|
|
7631
7930
|
children: body
|
|
7632
7931
|
}
|
|
7633
7932
|
),
|
|
7634
|
-
said ? /* @__PURE__ */
|
|
7635
|
-
newPasswordFields && canSave ? /* @__PURE__ */
|
|
7933
|
+
said ? /* @__PURE__ */ jsx38(Outcome, { said, onDismiss: () => setSaid(null) }) : page.blocked && page.url && state.status === "ready" ? /* @__PURE__ */ jsx38("p", { className: "px-1 text-xs text-muted-foreground", children: BLOCK_WORDS[page.blocked] }) : null,
|
|
7934
|
+
newPasswordFields && canSave ? /* @__PURE__ */ jsx38(VaultSection, { children: /* @__PURE__ */ jsx38(PageGenerator, { fields: newPasswordFields }) }) : null
|
|
7636
7935
|
] }) });
|
|
7637
7936
|
}
|
|
7638
7937
|
function Outcome({ said, onDismiss }) {
|
|
7639
|
-
return /* @__PURE__ */
|
|
7640
|
-
said.tone === "success" ? /* @__PURE__ */
|
|
7641
|
-
/* @__PURE__ */
|
|
7642
|
-
/* @__PURE__ */
|
|
7938
|
+
return /* @__PURE__ */ jsxs36("div", { role: "status", className: "flex items-center gap-2 px-1", children: [
|
|
7939
|
+
said.tone === "success" ? /* @__PURE__ */ jsx38(CheckGlyph, { className: "size-4 shrink-0 text-primary" }) : /* @__PURE__ */ jsx38(ShieldGlyph, { className: "size-4 shrink-0 text-destructive" }),
|
|
7940
|
+
/* @__PURE__ */ jsx38("span", { className: "min-w-0 flex-1 text-xs text-foreground", children: said.text }),
|
|
7941
|
+
/* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(XGlyph, {}), "aria-label": "Dismiss", onClick: onDismiss })
|
|
7643
7942
|
] });
|
|
7644
7943
|
}
|
|
7645
7944
|
function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFill, onSignIn }) {
|
|
7646
7945
|
const confirmed = useConfirmed();
|
|
7647
7946
|
const copy = useCopy();
|
|
7648
7947
|
const notify = useNotify();
|
|
7649
|
-
const [reading, setReading] =
|
|
7948
|
+
const [reading, setReading] = useState39(false);
|
|
7650
7949
|
const usable = item?.capabilities.canUse ?? false;
|
|
7651
7950
|
const user = usable ? item?.fields.find((f) => USERNAME_KEYS.test(f.key) && f.handling !== "sealed" && f.active) : void 0;
|
|
7652
7951
|
const secret = usable && item?.capabilities.canReveal ? item?.fields.find((f) => f.key === "password" && f.handling === "revealable" && f.active) : void 0;
|
|
@@ -7662,27 +7961,27 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
|
|
|
7662
7961
|
}
|
|
7663
7962
|
};
|
|
7664
7963
|
const subtitle = [item ? loginSiteOf(item) || item.definitionLabel : "", tag].filter(Boolean).join(" \xB7 ");
|
|
7665
|
-
return /* @__PURE__ */
|
|
7666
|
-
/* @__PURE__ */
|
|
7667
|
-
/* @__PURE__ */
|
|
7668
|
-
/* @__PURE__ */
|
|
7669
|
-
/* @__PURE__ */
|
|
7670
|
-
subtitle ? /* @__PURE__ */
|
|
7964
|
+
return /* @__PURE__ */ jsxs36("li", { className: "flex h-12 items-center gap-1 pl-1 pr-2", "data-item": itemId, children: [
|
|
7965
|
+
/* @__PURE__ */ jsxs36("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: [
|
|
7966
|
+
/* @__PURE__ */ jsx38(ItemIcon, { definitionKey: item?.definitionKey ?? "website_login", family, site: item ? loginSiteOf(item) : "" }),
|
|
7967
|
+
/* @__PURE__ */ jsxs36("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
|
|
7968
|
+
/* @__PURE__ */ jsx38("span", { className: "truncate text-sm font-medium", children: item?.name ?? "Saved login" }),
|
|
7969
|
+
subtitle ? /* @__PURE__ */ jsx38("span", { className: "truncate text-xs text-muted-foreground", children: subtitle }) : null
|
|
7671
7970
|
] })
|
|
7672
7971
|
] }),
|
|
7673
|
-
onFill ? /* @__PURE__ */
|
|
7674
|
-
user && item ? /* @__PURE__ */
|
|
7675
|
-
secret && item ? /* @__PURE__ */
|
|
7676
|
-
otp ? /* @__PURE__ */
|
|
7677
|
-
onSignIn ? /* @__PURE__ */
|
|
7678
|
-
/* @__PURE__ */
|
|
7679
|
-
/* @__PURE__ */
|
|
7680
|
-
/* @__PURE__ */
|
|
7681
|
-
/* @__PURE__ */
|
|
7972
|
+
onFill ? /* @__PURE__ */ jsx38(Button33, { variant: "primary", disabled: busy, "aria-busy": running || void 0, onClick: onFill, "aria-label": `Fill ${item?.name ?? "this login"}`, children: running ? "Filling\u2026" : "Fill" }) : null,
|
|
7973
|
+
user && item ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(UserGlyph, {}), "aria-label": `Copy ${user.label}`, title: `Copy ${user.label}`, disabled: reading, onClick: () => void read(user.label, () => port.reveal(item, user.key)) }) : null,
|
|
7974
|
+
secret && item ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(KeyGlyph, {}), "aria-label": "Copy password", title: "Copy password", disabled: reading, onClick: () => void read("Password", () => port.reveal(item, secret.key)) }) : null,
|
|
7975
|
+
otp ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(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,
|
|
7976
|
+
onSignIn ? /* @__PURE__ */ jsxs36(DropdownMenu5, { children: [
|
|
7977
|
+
/* @__PURE__ */ jsx38(DropdownMenuTrigger5, { asChild: true, children: /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(MoreGlyph, {}), "aria-label": "More", disabled: busy }) }),
|
|
7978
|
+
/* @__PURE__ */ jsxs36(DropdownMenuContent5, { align: "end", children: [
|
|
7979
|
+
/* @__PURE__ */ jsxs36(DropdownMenuItem5, { onSelect: onSignIn, children: [
|
|
7980
|
+
/* @__PURE__ */ jsx38(ShieldGlyph, { className: "size-4" }),
|
|
7682
7981
|
"Sign me in"
|
|
7683
7982
|
] }),
|
|
7684
|
-
/* @__PURE__ */
|
|
7685
|
-
/* @__PURE__ */
|
|
7983
|
+
/* @__PURE__ */ jsxs36(DropdownMenuItem5, { onSelect: () => onOpen(itemId), children: [
|
|
7984
|
+
/* @__PURE__ */ jsx38(ListGlyph, { className: "size-4" }),
|
|
7686
7985
|
"Open item"
|
|
7687
7986
|
] })
|
|
7688
7987
|
] })
|
|
@@ -7691,11 +7990,11 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
|
|
|
7691
7990
|
}
|
|
7692
7991
|
|
|
7693
7992
|
// src/Sidebar.tsx
|
|
7694
|
-
import { useState as
|
|
7993
|
+
import { useState as useState40 } from "react";
|
|
7695
7994
|
import { cn as cn15, useLook as useLook2 } from "@ai-matrx/design-system";
|
|
7696
|
-
import { Select as
|
|
7995
|
+
import { Select as Select11 } from "@ai-matrx/design-system/controls";
|
|
7697
7996
|
import { GlobeIcon as GlobeIcon5 } from "@ai-matrx/design-system/icons";
|
|
7698
|
-
import { jsx as
|
|
7997
|
+
import { jsx as jsx39, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
7699
7998
|
var AUTHENTICATOR_LABEL = "Authenticator";
|
|
7700
7999
|
function vaultChoices(items, organizations, current) {
|
|
7701
8000
|
const n = (f) => items.filter(f).length;
|
|
@@ -7709,7 +8008,7 @@ function vaultChoices(items, organizations, current) {
|
|
|
7709
8008
|
];
|
|
7710
8009
|
}
|
|
7711
8010
|
function VaultSelect({ value, choices, onChange }) {
|
|
7712
|
-
return /* @__PURE__ */
|
|
8011
|
+
return /* @__PURE__ */ jsx39(Select11, { value, onValueChange: onChange, "aria-label": "Vault", options: choices.map((c) => ({ value: c.value, label: c.label, meta: String(c.count) })) });
|
|
7713
8012
|
}
|
|
7714
8013
|
var CATEGORY_GLYPHS = { logins: GlobeIcon5, passkeys: ShieldGlyph, api: KeyGlyph, oauth: PlugGlyph, infra: DatabaseGlyph, env: TerminalGlyph, files: FileGlyph, other: NoteGlyph };
|
|
7715
8014
|
var familyOf = (key, definitions) => definitions.find((d) => d.key === key)?.family ?? "generic";
|
|
@@ -7755,7 +8054,7 @@ function viewOptions(views, allCount, deletedCount, hasFavorites, hasRecents, ha
|
|
|
7755
8054
|
}
|
|
7756
8055
|
function Entry({ on, glyph: Icon, label, count: count2, onClick }) {
|
|
7757
8056
|
const desktop = useLook2() === "desktop";
|
|
7758
|
-
return /* @__PURE__ */
|
|
8057
|
+
return /* @__PURE__ */ jsxs37(
|
|
7759
8058
|
"button",
|
|
7760
8059
|
{
|
|
7761
8060
|
type: "button",
|
|
@@ -7763,62 +8062,62 @@ function Entry({ on, glyph: Icon, label, count: count2, onClick }) {
|
|
|
7763
8062
|
onClick,
|
|
7764
8063
|
className: cn15("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"),
|
|
7765
8064
|
children: [
|
|
7766
|
-
/* @__PURE__ */
|
|
7767
|
-
/* @__PURE__ */
|
|
7768
|
-
count2 !== void 0 ? /* @__PURE__ */
|
|
8065
|
+
/* @__PURE__ */ jsx39(Icon, { className: "size-4 shrink-0" }),
|
|
8066
|
+
/* @__PURE__ */ jsx39("span", { className: "min-w-0 flex-1 truncate", children: label }),
|
|
8067
|
+
count2 !== void 0 ? /* @__PURE__ */ jsx39("span", { className: "text-xs tabular-nums text-muted-foreground", children: count2 }) : null
|
|
7769
8068
|
]
|
|
7770
8069
|
}
|
|
7771
8070
|
);
|
|
7772
8071
|
}
|
|
7773
8072
|
function Group({ title, children }) {
|
|
7774
|
-
return /* @__PURE__ */
|
|
7775
|
-
/* @__PURE__ */
|
|
8073
|
+
return /* @__PURE__ */ jsxs37("div", { className: "flex flex-col gap-0.5", children: [
|
|
8074
|
+
/* @__PURE__ */ jsx39("div", { className: "px-2.5 pb-1 text-xs font-medium text-muted-foreground", children: title }),
|
|
7776
8075
|
children
|
|
7777
8076
|
] });
|
|
7778
8077
|
}
|
|
7779
8078
|
function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false }) {
|
|
7780
|
-
const [tagsOpen, setTagsOpen] =
|
|
7781
|
-
return /* @__PURE__ */
|
|
7782
|
-
/* @__PURE__ */
|
|
7783
|
-
/* @__PURE__ */
|
|
7784
|
-
/* @__PURE__ */
|
|
8079
|
+
const [tagsOpen, setTagsOpen] = useState40(view.startsWith("tag:"));
|
|
8080
|
+
return /* @__PURE__ */ jsxs37("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: [
|
|
8081
|
+
/* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2 px-3 pb-2 pt-3", children: [
|
|
8082
|
+
/* @__PURE__ */ jsx39(SafeGlyph, { className: "size-5 shrink-0 text-primary" }),
|
|
8083
|
+
/* @__PURE__ */ jsx39("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx39(VaultSelect, { value: vault, choices, onChange: onVault }) })
|
|
7785
8084
|
] }),
|
|
7786
|
-
/* @__PURE__ */
|
|
7787
|
-
/* @__PURE__ */
|
|
7788
|
-
hasPage ? /* @__PURE__ */
|
|
7789
|
-
/* @__PURE__ */
|
|
7790
|
-
hasFavorites ? /* @__PURE__ */
|
|
7791
|
-
hasRecents ? /* @__PURE__ */
|
|
7792
|
-
/* @__PURE__ */
|
|
8085
|
+
/* @__PURE__ */ jsxs37("div", { className: "flex min-h-0 flex-1 flex-col gap-5 overflow-y-auto px-2 pb-3 pt-1", children: [
|
|
8086
|
+
/* @__PURE__ */ jsxs37("div", { className: "flex flex-col gap-0.5", children: [
|
|
8087
|
+
hasPage ? /* @__PURE__ */ jsx39(Entry, { on: view === "page", glyph: GlobeIcon5, label: "This page", onClick: () => onView("page") }) : null,
|
|
8088
|
+
/* @__PURE__ */ jsx39(Entry, { on: view === "all", glyph: GridGlyph, label: "All items", count: allCount, onClick: () => onView("all") }),
|
|
8089
|
+
hasFavorites ? /* @__PURE__ */ jsx39(Entry, { on: view === "favorites", glyph: StarGlyph, label: "Favorites", count: views.favorites, onClick: () => onView("favorites") }) : null,
|
|
8090
|
+
hasRecents ? /* @__PURE__ */ jsx39(Entry, { on: view === "recent", glyph: ClockGlyph, label: "Recently opened", count: views.recent, onClick: () => onView("recent") }) : null,
|
|
8091
|
+
/* @__PURE__ */ jsx39(Entry, { on: view === "authenticator", glyph: LockGlyph, label: AUTHENTICATOR_LABEL, count: views.authenticator, onClick: () => onView("authenticator") })
|
|
7793
8092
|
] }),
|
|
7794
|
-
views.categories.length > 0 ? /* @__PURE__ */
|
|
7795
|
-
views.tags.length > 0 ? /* @__PURE__ */
|
|
7796
|
-
/* @__PURE__ */
|
|
7797
|
-
tagsOpen ? /* @__PURE__ */
|
|
8093
|
+
views.categories.length > 0 ? /* @__PURE__ */ jsx39(Group, { title: "Categories", children: views.categories.map((e) => /* @__PURE__ */ jsx39(Entry, { on: view === e.view, glyph: e.glyph, label: e.label, count: e.count, onClick: () => onView(e.view) }, e.view)) }) : null,
|
|
8094
|
+
views.tags.length > 0 ? /* @__PURE__ */ jsxs37("div", { className: "flex flex-col gap-0.5", children: [
|
|
8095
|
+
/* @__PURE__ */ jsxs37("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: [
|
|
8096
|
+
tagsOpen ? /* @__PURE__ */ jsx39(ChevronDownGlyph, { className: "size-3.5" }) : /* @__PURE__ */ jsx39(ChevronRightGlyph, { className: "size-3.5" }),
|
|
7798
8097
|
"Tags",
|
|
7799
|
-
/* @__PURE__ */
|
|
8098
|
+
/* @__PURE__ */ jsx39("span", { className: "ml-auto tabular-nums", children: views.tags.length })
|
|
7800
8099
|
] }),
|
|
7801
|
-
tagsOpen ? views.tags.map((e) => /* @__PURE__ */
|
|
8100
|
+
tagsOpen ? views.tags.map((e) => /* @__PURE__ */ jsx39(Entry, { on: view === e.view, glyph: e.glyph, label: e.label, count: e.count, onClick: () => onView(e.view) }, e.view)) : null
|
|
7802
8101
|
] }) : null
|
|
7803
8102
|
] }),
|
|
7804
|
-
/* @__PURE__ */
|
|
7805
|
-
/* @__PURE__ */
|
|
7806
|
-
/* @__PURE__ */
|
|
7807
|
-
/* @__PURE__ */
|
|
7808
|
-
/* @__PURE__ */
|
|
7809
|
-
/* @__PURE__ */
|
|
7810
|
-
hasNativeImport ? /* @__PURE__ */
|
|
7811
|
-
nativeProvider && nativeProvider.status !== "unavailable" ? /* @__PURE__ */
|
|
7812
|
-
/* @__PURE__ */
|
|
7813
|
-
/* @__PURE__ */
|
|
7814
|
-
/* @__PURE__ */
|
|
8103
|
+
/* @__PURE__ */ jsxs37("div", { className: "flex flex-col gap-0.5 border-t border-sidebar-border p-2", children: [
|
|
8104
|
+
/* @__PURE__ */ jsx39(Entry, { on: view === "trash", glyph: TrashGlyph, label: "Trash", count: deletedCount, onClick: () => onView("trash") }),
|
|
8105
|
+
/* @__PURE__ */ jsx39(Entry, { on: false, glyph: ImportGlyph, label: "Import", onClick: () => onPanel("import") }),
|
|
8106
|
+
/* @__PURE__ */ jsx39(Entry, { on: false, glyph: ExportGlyph, label: "Export", onClick: () => onPanel("export") }),
|
|
8107
|
+
/* @__PURE__ */ jsx39(Entry, { on: false, glyph: SafeGlyph, label: "Backup", onClick: () => onPanel("backup") }),
|
|
8108
|
+
/* @__PURE__ */ jsx39(Entry, { on: false, glyph: ShieldGlyph, label: "Browsers that fill", onClick: () => onPanel("devices") }),
|
|
8109
|
+
hasNativeImport ? /* @__PURE__ */ jsx39(Entry, { on: false, glyph: ImportGlyph, label: "Import passkeys", onClick: () => onPanel("import-passkeys") }) : null,
|
|
8110
|
+
nativeProvider && nativeProvider.status !== "unavailable" ? /* @__PURE__ */ jsxs37("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: [
|
|
8111
|
+
/* @__PURE__ */ jsx39(ShieldGlyph, { className: "size-4 shrink-0" }),
|
|
8112
|
+
/* @__PURE__ */ jsx39("span", { className: "min-w-0 flex-1 truncate", children: "System AutoFill" }),
|
|
8113
|
+
/* @__PURE__ */ jsx39("span", { className: cn15("text-xs", nativeProvider.status === "ready" ? "text-success" : "text-warning"), children: nativeProvider.status === "ready" ? "On" : "Set up" })
|
|
7815
8114
|
] }) : null
|
|
7816
8115
|
] })
|
|
7817
8116
|
] });
|
|
7818
8117
|
}
|
|
7819
8118
|
|
|
7820
8119
|
// src/VaultApp.tsx
|
|
7821
|
-
import { jsx as
|
|
8120
|
+
import { jsx as jsx40, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
7822
8121
|
var FULL_AT = 1120;
|
|
7823
8122
|
var SPLIT_AT = 640;
|
|
7824
8123
|
var NO_HOST = {};
|
|
@@ -7837,7 +8136,7 @@ var generatorLimitsFrom = (knobs) => knobs ? async () => {
|
|
|
7837
8136
|
} : void 0;
|
|
7838
8137
|
function ImportWithLimits(props) {
|
|
7839
8138
|
const { knobs, ...rest } = props;
|
|
7840
|
-
const [state, setState] =
|
|
8139
|
+
const [state, setState] = useState41(null);
|
|
7841
8140
|
useEffect23(() => {
|
|
7842
8141
|
if (!knobs) return setState({ error: "Import is not set up for this organization yet." });
|
|
7843
8142
|
knobs().then(
|
|
@@ -7851,18 +8150,18 @@ function ImportWithLimits(props) {
|
|
|
7851
8150
|
(e) => setState({ error: e instanceof Error ? e.message : "The import settings could not be read." })
|
|
7852
8151
|
);
|
|
7853
8152
|
}, [knobs]);
|
|
7854
|
-
if (state && "limits" in state) return /* @__PURE__ */
|
|
7855
|
-
return /* @__PURE__ */
|
|
8153
|
+
if (state && "limits" in state) return /* @__PURE__ */ jsx40(ImportPanel, { ...rest, limits: state.limits });
|
|
8154
|
+
return /* @__PURE__ */ jsx40(Panel, { title: "Import", onClose: rest.onClose, children: /* @__PURE__ */ jsx40(Empty, { children: state ? state.error : "Reading this organization\u2019s import settings\u2026" }) });
|
|
7856
8155
|
}
|
|
7857
8156
|
function VaultApp(props) {
|
|
7858
8157
|
const lock = props.host?.lock;
|
|
7859
8158
|
const locked = useLocked(lock);
|
|
7860
8159
|
const port = useMemo6(() => lock ? guardPort(props.port, () => lock.locked()) : props.port, [props.port, lock]);
|
|
7861
|
-
return /* @__PURE__ */
|
|
8160
|
+
return /* @__PURE__ */ jsx40(LookScope, { look: props.look ?? "web", className: "h-full min-h-0 w-full", children: /* @__PURE__ */ jsx40("div", { className: "relative h-full min-h-0 w-full", children: /* @__PURE__ */ jsx40(NoticeProvider, { notify: props.notify, children: lock && locked ? /* @__PURE__ */ jsx40(LockedScreen, { lock }) : /* @__PURE__ */ jsx40(ClipboardProvider, { clipboard: props.host?.clipboard, children: /* @__PURE__ */ jsx40(RevealSecondsProvider, { seconds: props.host?.revealSeconds, children: /* @__PURE__ */ jsx40(IdentityGate, { identity: props.host?.identity, children: /* @__PURE__ */ jsx40(GeneratorLimitsProvider, { resolve: generatorLimitsFrom(props.host?.knobs), children: /* @__PURE__ */ jsx40(Workspace, { ...props, port }) }) }) }) }) }) }) });
|
|
7862
8161
|
}
|
|
7863
8162
|
function LockedScreen({ lock }) {
|
|
7864
|
-
const [busy, setBusy] =
|
|
7865
|
-
const [error, setError] =
|
|
8163
|
+
const [busy, setBusy] = useState41(false);
|
|
8164
|
+
const [error, setError] = useState41(null);
|
|
7866
8165
|
const unlock = async () => {
|
|
7867
8166
|
setBusy(true);
|
|
7868
8167
|
setError(null);
|
|
@@ -7874,29 +8173,29 @@ function LockedScreen({ lock }) {
|
|
|
7874
8173
|
setBusy(false);
|
|
7875
8174
|
}
|
|
7876
8175
|
};
|
|
7877
|
-
return /* @__PURE__ */
|
|
7878
|
-
/* @__PURE__ */
|
|
7879
|
-
/* @__PURE__ */
|
|
7880
|
-
/* @__PURE__ */
|
|
7881
|
-
error ? /* @__PURE__ */
|
|
8176
|
+
return /* @__PURE__ */ jsxs38("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: [
|
|
8177
|
+
/* @__PURE__ */ jsx40(LockGlyph, { className: "size-8 text-muted-foreground" }),
|
|
8178
|
+
/* @__PURE__ */ jsx40("div", { className: "text-base font-medium text-foreground", children: "Vault locked" }),
|
|
8179
|
+
/* @__PURE__ */ jsx40(Button34, { variant: "primary", disabled: busy, onClick: () => void unlock(), children: lock.unlockLabel ?? "Unlock" }),
|
|
8180
|
+
error ? /* @__PURE__ */ jsx40("div", { role: "alert", className: "max-w-sm text-sm text-destructive", children: error }) : null
|
|
7882
8181
|
] });
|
|
7883
8182
|
}
|
|
7884
|
-
function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocationChange }) {
|
|
8183
|
+
function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocationChange, onInventory }) {
|
|
7885
8184
|
const rootRef = useRef19(null);
|
|
7886
8185
|
const width = useElementWidth(rootRef);
|
|
7887
8186
|
const mode = layout !== "auto" ? layout : width >= FULL_AT ? "full" : width >= SPLIT_AT ? "split" : "stack";
|
|
7888
8187
|
const notify = useNotify();
|
|
7889
|
-
const [snap, setSnap] =
|
|
7890
|
-
const [items, setItems] =
|
|
7891
|
-
const [deleted, setDeleted] =
|
|
7892
|
-
const [favorites, setFavorites] =
|
|
7893
|
-
const [recents, setRecents] =
|
|
7894
|
-
const [error, setError] =
|
|
7895
|
-
const [inner, setInner] =
|
|
8188
|
+
const [snap, setSnap] = useState41(null);
|
|
8189
|
+
const [items, setItems] = useState41([]);
|
|
8190
|
+
const [deleted, setDeleted] = useState41([]);
|
|
8191
|
+
const [favorites, setFavorites] = useState41(null);
|
|
8192
|
+
const [recents, setRecents] = useState41(null);
|
|
8193
|
+
const [error, setError] = useState41(null);
|
|
8194
|
+
const [inner, setInner] = useState41(DEFAULT_LOCATION);
|
|
7896
8195
|
const loc = location ?? inner;
|
|
7897
8196
|
const dirty = useRef19(false);
|
|
7898
|
-
const [notice, setNotice] =
|
|
7899
|
-
const [firstCode, setFirstCode] =
|
|
8197
|
+
const [notice, setNotice] = useState41(null);
|
|
8198
|
+
const [firstCode, setFirstCode] = useState41(null);
|
|
7900
8199
|
const move = useCallback5(
|
|
7901
8200
|
(next, how) => {
|
|
7902
8201
|
if (!location) setInner(next);
|
|
@@ -7916,7 +8215,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7916
8215
|
move(next, how);
|
|
7917
8216
|
};
|
|
7918
8217
|
if (leaving && dirty.current) {
|
|
7919
|
-
void
|
|
8218
|
+
void confirm14({ 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());
|
|
7920
8219
|
return;
|
|
7921
8220
|
}
|
|
7922
8221
|
proceed();
|
|
@@ -7949,7 +8248,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7949
8248
|
}, []);
|
|
7950
8249
|
const knobsRef = useRef19(host.knobs);
|
|
7951
8250
|
knobsRef.current = host.knobs;
|
|
7952
|
-
const [signedOut, setSignedOut] =
|
|
8251
|
+
const [signedOut, setSignedOut] = useState41(false);
|
|
7953
8252
|
const load = useCallback5(() => {
|
|
7954
8253
|
setError(null);
|
|
7955
8254
|
port.load().then((s) => {
|
|
@@ -7969,6 +8268,11 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7969
8268
|
port.lists.recents?.list().then(setRecents, () => void 0);
|
|
7970
8269
|
}, [port]);
|
|
7971
8270
|
useEffect23(load, [load]);
|
|
8271
|
+
const inventoryRef = useRef19(onInventory);
|
|
8272
|
+
inventoryRef.current = onInventory;
|
|
8273
|
+
useEffect23(() => {
|
|
8274
|
+
if (snap) inventoryRef.current?.({ items, definitions: snap.definitions });
|
|
8275
|
+
}, [snap, items]);
|
|
7972
8276
|
useEffect23(() => {
|
|
7973
8277
|
if (!loc.itemId || !port.lists.recents) return;
|
|
7974
8278
|
const id = loc.itemId;
|
|
@@ -7988,7 +8292,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7988
8292
|
return inView(i, loc.view);
|
|
7989
8293
|
});
|
|
7990
8294
|
if (loc.view === "recent" && recents) return [...filtered].sort((a, b) => recents.indexOf(a.id) - recents.indexOf(b.id));
|
|
7991
|
-
return sortItems(filtered, loc.sort);
|
|
8295
|
+
return sortItems(filtered, loc.sort, recents);
|
|
7992
8296
|
}, [inThisVault, loc.view, loc.q, loc.sort, favorites, recents, definitions]);
|
|
7993
8297
|
const choices = useMemo6(() => vaultChoices(items, orgs, loc.vault), [items, orgs, loc.vault]);
|
|
7994
8298
|
const matchingIds = useMemo6(() => host.page ? new Set(host.page.matchingItemIds) : void 0, [host.page]);
|
|
@@ -8015,35 +8319,35 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8015
8319
|
});
|
|
8016
8320
|
};
|
|
8017
8321
|
if (error) {
|
|
8018
|
-
return /* @__PURE__ */
|
|
8019
|
-
/* @__PURE__ */
|
|
8020
|
-
/* @__PURE__ */
|
|
8021
|
-
/* @__PURE__ */
|
|
8022
|
-
/* @__PURE__ */
|
|
8023
|
-
signedOut && host.signIn ? /* @__PURE__ */
|
|
8024
|
-
/* @__PURE__ */
|
|
8322
|
+
return /* @__PURE__ */ jsxs38("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: [
|
|
8323
|
+
/* @__PURE__ */ jsx40(SafeGlyph, { className: "size-8 text-muted-foreground" }),
|
|
8324
|
+
/* @__PURE__ */ jsx40("div", { className: "font-medium", children: "The vault couldn\u2019t open" }),
|
|
8325
|
+
/* @__PURE__ */ jsx40("div", { className: "max-w-xs text-muted-foreground", children: signedOut ? "You\u2019ve been signed out." : plainLoadError(error) }),
|
|
8326
|
+
/* @__PURE__ */ jsxs38("div", { className: "flex gap-2", children: [
|
|
8327
|
+
signedOut && host.signIn ? /* @__PURE__ */ jsx40(Button34, { variant: "primary", onClick: host.signIn, children: "Sign in" }) : null,
|
|
8328
|
+
/* @__PURE__ */ jsx40(Button34, { variant: signedOut && host.signIn ? "outline" : "primary", onClick: load, children: "Try again" })
|
|
8025
8329
|
] })
|
|
8026
8330
|
] });
|
|
8027
8331
|
}
|
|
8028
8332
|
if (!snap) {
|
|
8029
|
-
return /* @__PURE__ */
|
|
8030
|
-
/* @__PURE__ */
|
|
8031
|
-
/* @__PURE__ */
|
|
8032
|
-
/* @__PURE__ */
|
|
8033
|
-
/* @__PURE__ */
|
|
8333
|
+
return /* @__PURE__ */ jsx40("div", { ref: rootRef, className: "flex h-full bg-background", "aria-busy": "true", "aria-label": "Opening the vault", children: /* @__PURE__ */ jsx40("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__ */ jsxs38("div", { className: "flex h-12 items-center gap-3 px-2", children: [
|
|
8334
|
+
/* @__PURE__ */ jsx40("div", { className: "size-8 animate-pulse rounded-lg bg-muted" }),
|
|
8335
|
+
/* @__PURE__ */ jsxs38("div", { className: "flex flex-1 flex-col gap-1.5", children: [
|
|
8336
|
+
/* @__PURE__ */ jsx40("div", { className: "h-3 w-2/3 animate-pulse rounded bg-muted" }),
|
|
8337
|
+
/* @__PURE__ */ jsx40("div", { className: "h-2.5 w-1/3 animate-pulse rounded bg-muted" })
|
|
8034
8338
|
] })
|
|
8035
8339
|
] }, n)) }) });
|
|
8036
8340
|
}
|
|
8037
8341
|
const hasFavorites = port.lists.favorites !== void 0;
|
|
8038
8342
|
const title = loc.vault === "all" && loc.view === "all" ? "All items" : viewLabel(loc.view, views);
|
|
8039
|
-
const compactHeader = mode === "full" ? void 0 : /* @__PURE__ */
|
|
8040
|
-
/* @__PURE__ */
|
|
8041
|
-
/* @__PURE__ */
|
|
8042
|
-
/* @__PURE__ */
|
|
8043
|
-
|
|
8343
|
+
const compactHeader = mode === "full" ? void 0 : /* @__PURE__ */ jsxs38("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_auto] gap-2", children: [
|
|
8344
|
+
/* @__PURE__ */ jsx40(VaultSelect, { value: loc.vault, choices, onChange: (vault) => go({ vault, itemId: null, panel: null }) }),
|
|
8345
|
+
/* @__PURE__ */ jsx40(Select12, { 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" }),
|
|
8346
|
+
/* @__PURE__ */ jsx40(
|
|
8347
|
+
Button34,
|
|
8044
8348
|
{
|
|
8045
8349
|
variant: loc.view === "authenticator" ? "outline" : "quiet",
|
|
8046
|
-
icon: /* @__PURE__ */
|
|
8350
|
+
icon: /* @__PURE__ */ jsx40(LockGlyph, {}),
|
|
8047
8351
|
"aria-label": AUTHENTICATOR_LABEL,
|
|
8048
8352
|
"aria-pressed": loc.view === "authenticator",
|
|
8049
8353
|
title: AUTHENTICATOR_LABEL,
|
|
@@ -8051,46 +8355,50 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8051
8355
|
children: mode === "split" ? AUTHENTICATOR_LABEL : null
|
|
8052
8356
|
}
|
|
8053
8357
|
),
|
|
8054
|
-
/* @__PURE__ */
|
|
8055
|
-
/* @__PURE__ */
|
|
8056
|
-
/* @__PURE__ */
|
|
8057
|
-
/* @__PURE__ */
|
|
8058
|
-
/* @__PURE__ */
|
|
8358
|
+
/* @__PURE__ */ jsxs38(DropdownMenu6, { children: [
|
|
8359
|
+
/* @__PURE__ */ jsx40(DropdownMenuTrigger6, { asChild: true, children: /* @__PURE__ */ jsx40(Button34, { variant: "quiet", icon: /* @__PURE__ */ jsx40(MoreGlyph, {}), "aria-label": "Vault actions" }) }),
|
|
8360
|
+
/* @__PURE__ */ jsxs38(DropdownMenuContent6, { align: "end", children: [
|
|
8361
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => go({ panel: "import" }), children: [
|
|
8362
|
+
/* @__PURE__ */ jsx40(ImportGlyph, { className: "size-4" }),
|
|
8059
8363
|
"Import"
|
|
8060
8364
|
] }),
|
|
8061
|
-
/* @__PURE__ */
|
|
8062
|
-
/* @__PURE__ */
|
|
8365
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => go({ panel: "export" }), children: [
|
|
8366
|
+
/* @__PURE__ */ jsx40(ExportGlyph, { className: "size-4" }),
|
|
8063
8367
|
"Export"
|
|
8064
8368
|
] }),
|
|
8065
|
-
/* @__PURE__ */
|
|
8066
|
-
/* @__PURE__ */
|
|
8369
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => go({ panel: "backup" }), children: [
|
|
8370
|
+
/* @__PURE__ */ jsx40(SafeGlyph, { className: "size-4" }),
|
|
8067
8371
|
"Backup"
|
|
8068
8372
|
] }),
|
|
8069
|
-
/* @__PURE__ */
|
|
8070
|
-
/* @__PURE__ */
|
|
8373
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => go({ panel: "devices" }), children: [
|
|
8374
|
+
/* @__PURE__ */ jsx40(ShieldGlyph, { className: "size-4" }),
|
|
8071
8375
|
"Browsers that fill"
|
|
8072
8376
|
] }),
|
|
8073
|
-
host.nativeImport ? /* @__PURE__ */
|
|
8074
|
-
/* @__PURE__ */
|
|
8377
|
+
host.nativeImport ? /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => go({ panel: "import-passkeys" }), children: [
|
|
8378
|
+
/* @__PURE__ */ jsx40(ImportGlyph, { className: "size-4" }),
|
|
8075
8379
|
"Import passkeys"
|
|
8076
8380
|
] }) : null,
|
|
8077
|
-
host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */
|
|
8078
|
-
/* @__PURE__ */
|
|
8381
|
+
host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: host.nativeProvider.openSetup, children: [
|
|
8382
|
+
/* @__PURE__ */ jsx40(ShieldGlyph, { className: "size-4" }),
|
|
8079
8383
|
"System AutoFill"
|
|
8080
8384
|
] }) : null,
|
|
8081
|
-
host.lock?.lock ? /* @__PURE__ */
|
|
8082
|
-
/* @__PURE__ */
|
|
8385
|
+
host.lock?.lock ? /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => void host.lock?.lock?.(), children: [
|
|
8386
|
+
/* @__PURE__ */ jsx40(LockGlyph, { className: "size-4" }),
|
|
8083
8387
|
"Lock"
|
|
8388
|
+
] }) : null,
|
|
8389
|
+
host.openWebVault ? /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: host.openWebVault, children: [
|
|
8390
|
+
/* @__PURE__ */ jsx40(ExternalGlyph, { className: "size-4" }),
|
|
8391
|
+
"Open on the web"
|
|
8084
8392
|
] }) : null
|
|
8085
8393
|
] })
|
|
8086
8394
|
] })
|
|
8087
8395
|
] });
|
|
8088
|
-
const viewHeader = /* @__PURE__ */
|
|
8396
|
+
const viewHeader = /* @__PURE__ */ jsxs38("div", { className: "flex flex-col gap-2", children: [
|
|
8089
8397
|
compactHeader,
|
|
8090
|
-
/* @__PURE__ */
|
|
8398
|
+
/* @__PURE__ */ jsx40(SearchField4, { value: loc.q, onChange: (e) => go({ q: e.target.value }, "replace"), placeholder: `Search ${viewLabel(loc.view, views)}`, "aria-label": `Search ${viewLabel(loc.view, views)}` })
|
|
8091
8399
|
] });
|
|
8092
8400
|
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 };
|
|
8093
|
-
const pageView = loc.view === "page" && host.page && !loc.q ? /* @__PURE__ */
|
|
8401
|
+
const pageView = loc.view === "page" && host.page && !loc.q ? /* @__PURE__ */ jsx40(
|
|
8094
8402
|
PageView,
|
|
8095
8403
|
{
|
|
8096
8404
|
port,
|
|
@@ -8108,8 +8416,8 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8108
8416
|
...compactHeader ? { header: compactHeader } : {}
|
|
8109
8417
|
}
|
|
8110
8418
|
) : null;
|
|
8111
|
-
const specialView = pageView ?? (loc.view === "authenticator" ? /* @__PURE__ */
|
|
8112
|
-
const list = specialView ?? /* @__PURE__ */
|
|
8419
|
+
const specialView = pageView ?? (loc.view === "authenticator" ? /* @__PURE__ */ jsx40(AuthenticatorView, { ...viewProps }) : loc.view === "trash" ? /* @__PURE__ */ jsx40(TrashView, { ...viewProps }) : null);
|
|
8420
|
+
const list = specialView ?? /* @__PURE__ */ jsx40(
|
|
8113
8421
|
ItemList,
|
|
8114
8422
|
{
|
|
8115
8423
|
title,
|
|
@@ -8123,6 +8431,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8123
8431
|
onQuery: (q) => go({ q }, "replace"),
|
|
8124
8432
|
sort: loc.sort,
|
|
8125
8433
|
onSort: (sort) => go({ sort }, "replace"),
|
|
8434
|
+
canSortViewed: port.lists.recents !== void 0,
|
|
8126
8435
|
onNew: () => go({ itemId: null, mode: "new", kind: null, panel: null }),
|
|
8127
8436
|
...matchingIds ? { matchingIds } : {},
|
|
8128
8437
|
...compactHeader ? { header: compactHeader } : {}
|
|
@@ -8136,9 +8445,9 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8136
8445
|
const onPanel = (panel2) => go({ panel: panel2 }, "push");
|
|
8137
8446
|
let detail;
|
|
8138
8447
|
if (loc.mode === "new" && !kindDefinition) {
|
|
8139
|
-
detail = /* @__PURE__ */
|
|
8448
|
+
detail = /* @__PURE__ */ jsx40(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 }) });
|
|
8140
8449
|
} else if (loc.mode === "new" && kindDefinition) {
|
|
8141
|
-
detail = /* @__PURE__ */
|
|
8450
|
+
detail = /* @__PURE__ */ jsx40(
|
|
8142
8451
|
ItemPane,
|
|
8143
8452
|
{
|
|
8144
8453
|
port,
|
|
@@ -8170,7 +8479,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8170
8479
|
`new-${kindDefinition.key}`
|
|
8171
8480
|
);
|
|
8172
8481
|
} else if (selected) {
|
|
8173
|
-
detail = /* @__PURE__ */
|
|
8482
|
+
detail = /* @__PURE__ */ jsx40(
|
|
8174
8483
|
ItemPane,
|
|
8175
8484
|
{
|
|
8176
8485
|
port,
|
|
@@ -8214,23 +8523,23 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8214
8523
|
selected.id
|
|
8215
8524
|
);
|
|
8216
8525
|
} else if (loc.itemId) {
|
|
8217
|
-
detail = /* @__PURE__ */
|
|
8526
|
+
detail = /* @__PURE__ */ jsx40(Blank, { children: "This item is not in your vault, or you cannot see it." });
|
|
8218
8527
|
} else {
|
|
8219
|
-
detail = /* @__PURE__ */
|
|
8528
|
+
detail = /* @__PURE__ */ jsx40(Blank, { children: visible.length === 0 ? "" : "Select an item" });
|
|
8220
8529
|
}
|
|
8221
8530
|
const [panelName, panelArg] = (loc.panel ?? "").split(/:(.*)/s);
|
|
8222
8531
|
const closePanel = () => go({ panel: null }, "push");
|
|
8223
8532
|
const vaultPanelProps = { port, host, items, definitions, organizations: orgs, onClose: closePanel, onChanged: load };
|
|
8224
8533
|
let panel = null;
|
|
8225
|
-
if (panelName === "import") panel = /* @__PURE__ */
|
|
8226
|
-
else if (panelName === "devices") panel = /* @__PURE__ */
|
|
8227
|
-
else if (panelName === "approve" && panelArg) panel = /* @__PURE__ */
|
|
8228
|
-
else if (panelName === "import-passkeys" && host.nativeImport) panel = /* @__PURE__ */
|
|
8229
|
-
else if (panelName === "export") panel = /* @__PURE__ */
|
|
8230
|
-
else if (panelName === "backup") panel = /* @__PURE__ */
|
|
8534
|
+
if (panelName === "import") panel = /* @__PURE__ */ jsx40(ImportWithLimits, { ...vaultPanelProps, knobs: host.knobs });
|
|
8535
|
+
else if (panelName === "devices") panel = /* @__PURE__ */ jsx40(DevicesPanel, { ...vaultPanelProps });
|
|
8536
|
+
else if (panelName === "approve" && panelArg) panel = /* @__PURE__ */ jsx40(ApprovePanel, { ...vaultPanelProps, ...approvalFromParams(panelArg, new URLSearchParams(globalThis.location?.search ?? "")) });
|
|
8537
|
+
else if (panelName === "import-passkeys" && host.nativeImport) panel = /* @__PURE__ */ jsx40(NativeImportPanel, { ...vaultPanelProps, bridge: host.nativeImport, readLimits: port.native.limits, activeOrganizationId: orgs[0]?.id ?? null });
|
|
8538
|
+
else if (panelName === "export") panel = /* @__PURE__ */ jsx40(ExportPanel, { ...vaultPanelProps });
|
|
8539
|
+
else if (panelName === "backup") panel = /* @__PURE__ */ jsx40(BackupPanel, { ...vaultPanelProps });
|
|
8231
8540
|
else if (panelName && selected && ITEM_PANELS[panelName]) {
|
|
8232
8541
|
const P = ITEM_PANELS[panelName];
|
|
8233
|
-
panel = /* @__PURE__ */
|
|
8542
|
+
panel = /* @__PURE__ */ jsx40(
|
|
8234
8543
|
P,
|
|
8235
8544
|
{
|
|
8236
8545
|
item: selected,
|
|
@@ -8253,17 +8562,17 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8253
8562
|
}
|
|
8254
8563
|
const grid = mode === "full" ? "grid-cols-[15rem_21rem_minmax(0,1fr)]" : mode === "split" ? "grid-cols-[19rem_minmax(0,1fr)]" : "grid-cols-1";
|
|
8255
8564
|
const shown = panesShown(mode, specialView !== null, showingDetail);
|
|
8256
|
-
return /* @__PURE__ */
|
|
8257
|
-
snap.unavailable.length > 0 ? /* @__PURE__ */
|
|
8258
|
-
/* @__PURE__ */
|
|
8565
|
+
return /* @__PURE__ */ jsxs38("div", { ref: rootRef, className: "flex h-full min-h-0 w-full flex-col bg-background text-foreground", children: [
|
|
8566
|
+
snap.unavailable.length > 0 ? /* @__PURE__ */ jsxs38("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-4 py-2 text-sm", children: [
|
|
8567
|
+
/* @__PURE__ */ jsxs38("span", { className: "min-w-0 flex-1 truncate text-warning", children: [
|
|
8259
8568
|
"Couldn\u2019t load ",
|
|
8260
8569
|
snap.unavailable.join(", "),
|
|
8261
8570
|
". Showing the rest."
|
|
8262
8571
|
] }),
|
|
8263
|
-
/* @__PURE__ */
|
|
8572
|
+
/* @__PURE__ */ jsx40("button", { type: "button", className: "shrink-0 text-primary hover:underline", onClick: load, children: "Try again" })
|
|
8264
8573
|
] }) : null,
|
|
8265
|
-
/* @__PURE__ */
|
|
8266
|
-
mode === "full" ? /* @__PURE__ */
|
|
8574
|
+
/* @__PURE__ */ jsxs38("div", { className: `grid min-h-0 w-full flex-1 ${grid} overflow-hidden`, children: [
|
|
8575
|
+
mode === "full" ? /* @__PURE__ */ jsx40(
|
|
8267
8576
|
VaultSidebar,
|
|
8268
8577
|
{
|
|
8269
8578
|
vault: loc.vault,
|
|
@@ -8282,10 +8591,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8282
8591
|
hasPage: host.page !== void 0
|
|
8283
8592
|
}
|
|
8284
8593
|
) : null,
|
|
8285
|
-
shown.list ? /* @__PURE__ */
|
|
8594
|
+
shown.list ? /* @__PURE__ */ jsx40("div", { className: specialView && mode !== "stack" ? "col-span-2 min-h-0" : "min-h-0", children: list }) : null,
|
|
8286
8595
|
shown.detail ? detail : null,
|
|
8287
8596
|
panel,
|
|
8288
|
-
firstCode ? /* @__PURE__ */
|
|
8597
|
+
firstCode ? /* @__PURE__ */ jsx40(FirstCodePanel, { port, item: firstCode, onClose: () => setFirstCode(null), onDone: () => setFirstCode(null) }) : null
|
|
8289
8598
|
] })
|
|
8290
8599
|
] });
|
|
8291
8600
|
}
|
|
@@ -8293,8 +8602,8 @@ function plainLoadError(message2) {
|
|
|
8293
8602
|
return /load failed|failed to fetch|network|timed? ?out/i.test(message2) ? "The connection dropped. Check you\u2019re online, then try again." : message2;
|
|
8294
8603
|
}
|
|
8295
8604
|
function Blank({ children }) {
|
|
8296
|
-
return /* @__PURE__ */
|
|
8297
|
-
/* @__PURE__ */
|
|
8605
|
+
return /* @__PURE__ */ jsxs38("div", { className: "flex h-full flex-col items-center justify-center gap-3 bg-background text-sm text-muted-foreground", children: [
|
|
8606
|
+
/* @__PURE__ */ jsx40(SafeGlyph, { className: "size-10 text-disabled-foreground" }),
|
|
8298
8607
|
children
|
|
8299
8608
|
] });
|
|
8300
8609
|
}
|
|
@@ -8664,6 +8973,20 @@ function createListsPort(ctx, door) {
|
|
|
8664
8973
|
|
|
8665
8974
|
// src/sharing/api.ts
|
|
8666
8975
|
import * as account6 from "@ai-matrx/api/account";
|
|
8976
|
+
|
|
8977
|
+
// src/secret-field-in.ts
|
|
8978
|
+
function secretFieldIn(s) {
|
|
8979
|
+
const envKey = s.envKey?.trim() || null;
|
|
8980
|
+
return {
|
|
8981
|
+
field_key: fieldKeyOf(s.label),
|
|
8982
|
+
value: s.value,
|
|
8983
|
+
handling: s.handling ?? "revealable",
|
|
8984
|
+
...envKey ? { env_key: envKey } : {},
|
|
8985
|
+
...envKey && s.injectIntoSandbox ? { inject_into_sandbox: true } : {}
|
|
8986
|
+
};
|
|
8987
|
+
}
|
|
8988
|
+
|
|
8989
|
+
// src/sharing/api.ts
|
|
8667
8990
|
function grantOf(w) {
|
|
8668
8991
|
const org = Boolean(w.organization_id);
|
|
8669
8992
|
return {
|
|
@@ -8763,7 +9086,7 @@ function createSharingPort(ctx, options = {}) {
|
|
|
8763
9086
|
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 }))],
|
|
8764
9087
|
fields: [
|
|
8765
9088
|
...encrypted.map((f) => ({ field_key: f.key, value: draft.values[f.key] ?? "", handling: f.handling })),
|
|
8766
|
-
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(
|
|
9089
|
+
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(secretFieldIn)
|
|
8767
9090
|
]
|
|
8768
9091
|
}
|
|
8769
9092
|
});
|
|
@@ -9049,14 +9372,14 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9049
9372
|
login_urls: draft.loginUrls,
|
|
9050
9373
|
// A login a person saves with its website is offered on that website (the server's own
|
|
9051
9374
|
// default is off, which made "Save a login" on a page answer "No saved login" there).
|
|
9052
|
-
...draft.loginUrls.length > 0 ? { browser_fill_enabled: true } : {},
|
|
9375
|
+
...draft.browser ? { uri_match_mode: draft.browser.uriMatchMode, browser_fill_enabled: draft.browser.browserFillEnabled } : draft.loginUrls.length > 0 ? { browser_fill_enabled: true } : {},
|
|
9053
9376
|
notes: draft.notes || null,
|
|
9054
9377
|
principal: organizationId ? { type: "organization", organization_id: organizationId } : { type: "user" },
|
|
9055
9378
|
initiation: "user",
|
|
9056
9379
|
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 }))],
|
|
9057
9380
|
fields: [
|
|
9058
9381
|
...encrypted.map((f) => ({ field_key: f.key, value: draft.values[f.key] ?? "", handling: f.handling })),
|
|
9059
|
-
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(
|
|
9382
|
+
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(secretFieldIn),
|
|
9060
9383
|
// Backup codes on a type that does not declare them (a website login): their own encrypted field.
|
|
9061
9384
|
...!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" }] : []
|
|
9062
9385
|
]
|
|
@@ -9096,7 +9419,7 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9096
9419
|
}
|
|
9097
9420
|
for (const s of draft.secrets) {
|
|
9098
9421
|
if (s.label.trim() === "" || s.value === "") continue;
|
|
9099
|
-
await account9.addField(api, { path: { item_id: item.id }, body:
|
|
9422
|
+
await account9.addField(api, { path: { item_id: item.id }, body: secretFieldIn(s) }, opts);
|
|
9100
9423
|
}
|
|
9101
9424
|
for (const id of draft.removed) await account9.deleteField(api, { path: { item_id: item.id, field_id: id } }, opts);
|
|
9102
9425
|
return { item: await refetch(item.id, item.owner), notice: null };
|
|
@@ -9121,6 +9444,44 @@ function createVaultKnobs(client, address) {
|
|
|
9121
9444
|
return snap.resolved;
|
|
9122
9445
|
};
|
|
9123
9446
|
}
|
|
9447
|
+
|
|
9448
|
+
// src/agent-context.ts
|
|
9449
|
+
var hostOf = (url) => {
|
|
9450
|
+
try {
|
|
9451
|
+
return new URL(/^[a-z][a-z0-9+.-]*:\/\//i.test(url) ? url : `https://${url}`).host || null;
|
|
9452
|
+
} catch {
|
|
9453
|
+
return null;
|
|
9454
|
+
}
|
|
9455
|
+
};
|
|
9456
|
+
function providerOf(item, definitions) {
|
|
9457
|
+
return definitions.find((d) => d.key === item.definitionKey)?.providerKey ?? null;
|
|
9458
|
+
}
|
|
9459
|
+
function vaultItemFacts(item, definitions) {
|
|
9460
|
+
const provider = providerOf(item, definitions);
|
|
9461
|
+
const hosts = item.loginUrls.map(hostOf).filter((h) => Boolean(h));
|
|
9462
|
+
const keys = item.fields.map((f) => f.key).filter((k) => !isAuthenticatorStorage(k));
|
|
9463
|
+
return [
|
|
9464
|
+
`Name: ${item.name}`,
|
|
9465
|
+
...item.definitionLabel ? [`Type: ${item.definitionLabel}`] : [],
|
|
9466
|
+
...provider ? [`Provider: ${provider}`] : [],
|
|
9467
|
+
...hosts.length ? [`Sites: ${hosts.join(", ")}`] : [],
|
|
9468
|
+
`Owner: ${item.owner.label}`,
|
|
9469
|
+
`Status: ${item.turnedOff ? "turned off" : "active"}`,
|
|
9470
|
+
...item.accessMode ? [`Access: ${item.accessMode}`] : [],
|
|
9471
|
+
...item.tags.length ? [`Tags: ${item.tags.join(", ")}`] : [],
|
|
9472
|
+
...keys.length ? [`Fields: ${keys.join(", ")}`] : [],
|
|
9473
|
+
...item.authenticator ? ["Has a one-time password"] : []
|
|
9474
|
+
];
|
|
9475
|
+
}
|
|
9476
|
+
function vaultInventoryScope(inventory, clicked = null) {
|
|
9477
|
+
const { items, definitions } = inventory;
|
|
9478
|
+
const providers = [...new Set(items.map((i) => providerOf(i, definitions)).filter((p) => Boolean(p)))];
|
|
9479
|
+
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}` : ""}`)];
|
|
9480
|
+
return { content: content.join("\n"), credential_count: items.length, credential_labels: items.map((i) => i.name), credential_providers: providers };
|
|
9481
|
+
}
|
|
9482
|
+
function itemIdAt(target) {
|
|
9483
|
+
return target?.closest("[data-item]")?.getAttribute("data-item") ?? null;
|
|
9484
|
+
}
|
|
9124
9485
|
export {
|
|
9125
9486
|
CATEGORIES,
|
|
9126
9487
|
CONFIRM_RETURN_KEY,
|
|
@@ -9139,15 +9500,19 @@ export {
|
|
|
9139
9500
|
guardPort,
|
|
9140
9501
|
inferFromUrl,
|
|
9141
9502
|
isHiddenItem,
|
|
9503
|
+
itemIdAt,
|
|
9142
9504
|
locationFromParams,
|
|
9143
9505
|
locationToParams,
|
|
9144
9506
|
loginSiteOf,
|
|
9145
9507
|
matchesQuery,
|
|
9146
9508
|
needsRecentSignIn,
|
|
9147
9509
|
parseDefinitions,
|
|
9510
|
+
providerOf,
|
|
9148
9511
|
siteDomainOf,
|
|
9149
9512
|
sortItems,
|
|
9150
9513
|
useConfirmed,
|
|
9514
|
+
vaultInventoryScope,
|
|
9515
|
+
vaultItemFacts,
|
|
9151
9516
|
wasCancelled
|
|
9152
9517
|
};
|
|
9153
9518
|
//# sourceMappingURL=index.js.map
|