@ai-matrx/vault 0.1.14 → 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 +33 -2
- package/dist/index.cjs +1546 -1126
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -4
- package/dist/index.d.ts +64 -4
- package/dist/index.js +1398 -978
- package/dist/index.js.map +1 -1
- package/package.json +5 -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");
|
|
@@ -871,9 +887,11 @@ function inView(item, view) {
|
|
|
871
887
|
if (view.startsWith("tag:")) return item.tags.includes(view.slice(4));
|
|
872
888
|
return true;
|
|
873
889
|
}
|
|
890
|
+
var AUTHENTICATOR_WORDS = ["authenticator", "2fa", "two-factor", "two factor", "totp", "one-time password", "verification code", "2-step"];
|
|
874
891
|
function matchesQuery(item, query) {
|
|
875
892
|
const q = query.trim().toLowerCase();
|
|
876
893
|
if (!q) return true;
|
|
894
|
+
if (item.authenticator && AUTHENTICATOR_WORDS.some((w) => w === q || q.length >= 3 && w.startsWith(q))) return true;
|
|
877
895
|
return [item.name, item.definitionLabel, ...item.tags, ...item.loginUrls, ...item.custom.map((c) => `${c.label} ${c.value}`)].some((h) => h.toLowerCase().includes(q));
|
|
878
896
|
}
|
|
879
897
|
var HIDDEN_ITEM_TAG = "matrx:hidden";
|
|
@@ -899,10 +917,15 @@ function siteDomainOf(host) {
|
|
|
899
917
|
const keep = TWO_PART_SUFFIX.has(sld) && tld.length <= 3 ? 3 : 2;
|
|
900
918
|
return labels.slice(-keep).join(".");
|
|
901
919
|
}
|
|
902
|
-
function sortItems(items, sort) {
|
|
920
|
+
function sortItems(items, sort, recents) {
|
|
903
921
|
const out = [...items];
|
|
904
|
-
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 });
|
|
905
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
|
+
}
|
|
906
929
|
if (sort === "website")
|
|
907
930
|
return out.sort((a, b) => {
|
|
908
931
|
const x = loginSiteOf(a), y = loginSiteOf(b);
|
|
@@ -1499,9 +1522,23 @@ function HistoryRow({ item, port, page, entry, label, onRestored, onConflict, on
|
|
|
1499
1522
|
// src/authenticator/AuthenticatorView.tsx
|
|
1500
1523
|
import { useEffect as useEffect11, useState as useState13 } from "react";
|
|
1501
1524
|
import { Button as Button9 } from "@ai-matrx/design-system/controls";
|
|
1502
|
-
import { cn as
|
|
1525
|
+
import { cn as cn7, DropdownMenu as DropdownMenu2, DropdownMenuContent as DropdownMenuContent2, DropdownMenuItem as DropdownMenuItem2, DropdownMenuSeparator as DropdownMenuSeparator2, DropdownMenuTrigger as DropdownMenuTrigger2, TextInputDialog } from "@ai-matrx/design-system";
|
|
1503
1526
|
import { CopyIcon as CopyIcon4 } from "@ai-matrx/design-system/icons";
|
|
1504
1527
|
|
|
1528
|
+
// src/ItemIcon.tsx
|
|
1529
|
+
import { cn as cn5 } from "@ai-matrx/design-system";
|
|
1530
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1531
|
+
function ItemIcon({ definitionKey, family, site, size = "md", inverted = false }) {
|
|
1532
|
+
const box = size === "lg" ? "size-10 rounded-xl text-base" : size === "md" ? "size-8 rounded-lg text-sm" : "size-6 rounded-md text-xs";
|
|
1533
|
+
const tone = inverted ? "bg-primary-foreground text-primary" : "bg-muted text-foreground";
|
|
1534
|
+
const initial = siteDomainOf(site).charAt(0).toUpperCase();
|
|
1535
|
+
if (initial && /[A-Z0-9]/.test(initial)) {
|
|
1536
|
+
return /* @__PURE__ */ jsx8("span", { "aria-hidden": true, className: cn5("flex shrink-0 items-center justify-center font-semibold", box, tone), children: initial });
|
|
1537
|
+
}
|
|
1538
|
+
const Glyph = definitionGlyph(definitionKey, family);
|
|
1539
|
+
return /* @__PURE__ */ jsx8("span", { "aria-hidden": true, className: cn5("flex shrink-0 items-center justify-center", box, tone), children: /* @__PURE__ */ jsx8(Glyph, { className: size === "lg" ? "size-5" : "size-4" }) });
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1505
1542
|
// src/authenticator/AddOtpPanel.tsx
|
|
1506
1543
|
import { useState as useState12 } from "react";
|
|
1507
1544
|
import { Button as Button8, Field as Field4, Select as Select2 } from "@ai-matrx/design-system/controls";
|
|
@@ -1509,7 +1546,7 @@ import { Button as Button8, Field as Field4, Select as Select2 } from "@ai-matrx
|
|
|
1509
1546
|
// src/authenticator/CodeParts.tsx
|
|
1510
1547
|
import { useEffect as useEffect8, useRef as useRef6, useState as useState8 } from "react";
|
|
1511
1548
|
import { Button as Button5 } from "@ai-matrx/design-system/controls";
|
|
1512
|
-
import { cn as
|
|
1549
|
+
import { cn as cn6 } from "@ai-matrx/design-system";
|
|
1513
1550
|
import { CopyIcon as CopyIcon3 } from "@ai-matrx/design-system/icons";
|
|
1514
1551
|
import { groupCode as groupCode2 } from "@ai-matrx/kit/format";
|
|
1515
1552
|
|
|
@@ -1612,16 +1649,16 @@ function matchIssuerToSite(issuer, candidates, siteOf) {
|
|
|
1612
1649
|
}
|
|
1613
1650
|
|
|
1614
1651
|
// src/authenticator/CodeParts.tsx
|
|
1615
|
-
import { jsx as
|
|
1652
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1616
1653
|
function CountdownRing({ remaining, period, loading = false, className }) {
|
|
1617
1654
|
const r = 9.5;
|
|
1618
1655
|
const c = 2 * Math.PI * r;
|
|
1619
1656
|
const p = loading ? 0 : Math.max(0, Math.min(1, remaining / period));
|
|
1620
1657
|
const urgent = !loading && remaining <= 5;
|
|
1621
|
-
return /* @__PURE__ */ jsxs8("span", { className:
|
|
1658
|
+
return /* @__PURE__ */ jsxs8("span", { className: cn6("relative inline-flex size-6 shrink-0 items-center justify-center", className), role: "img", "aria-label": loading ? "Getting code" : `${remaining} seconds left`, children: [
|
|
1622
1659
|
/* @__PURE__ */ jsxs8("svg", { viewBox: "0 0 24 24", className: "absolute inset-0 size-full -rotate-90", "aria-hidden": true, children: [
|
|
1623
|
-
/* @__PURE__ */
|
|
1624
|
-
/* @__PURE__ */
|
|
1660
|
+
/* @__PURE__ */ jsx9("circle", { cx: "12", cy: "12", r, fill: "none", stroke: "currentColor", strokeWidth: 2.5, className: "text-muted" }),
|
|
1661
|
+
/* @__PURE__ */ jsx9(
|
|
1625
1662
|
"circle",
|
|
1626
1663
|
{
|
|
1627
1664
|
cx: "12",
|
|
@@ -1638,7 +1675,7 @@ function CountdownRing({ remaining, period, loading = false, className }) {
|
|
|
1638
1675
|
}
|
|
1639
1676
|
)
|
|
1640
1677
|
] }),
|
|
1641
|
-
/* @__PURE__ */
|
|
1678
|
+
/* @__PURE__ */ jsx9("span", { className: cn6("text-[10px] font-semibold leading-none tabular-nums", urgent ? "text-destructive" : "text-muted-foreground"), children: loading ? "" : remaining })
|
|
1642
1679
|
] });
|
|
1643
1680
|
}
|
|
1644
1681
|
function useCopied() {
|
|
@@ -1668,17 +1705,17 @@ function CodeButton({ live, digits, size = "md", label }) {
|
|
|
1668
1705
|
onClick: () => live.code && void copy(live.code),
|
|
1669
1706
|
"aria-label": live.code ? `Copy ${label} code` : `Getting ${label} code`,
|
|
1670
1707
|
title: live.code ? "Copy" : void 0,
|
|
1671
|
-
className:
|
|
1708
|
+
className: cn6("group -mx-1.5 inline-flex max-w-full items-center gap-2.5 rounded-md px-1.5 py-1 text-left transition-colors hover:bg-accent focus-visible:bg-accent focus-visible:outline-none", size === "lg" && "gap-3"),
|
|
1672
1709
|
children: [
|
|
1673
|
-
/* @__PURE__ */
|
|
1674
|
-
copied ? /* @__PURE__ */
|
|
1710
|
+
/* @__PURE__ */ jsx9("span", { className: cn6("whitespace-nowrap font-mono font-medium tabular-nums tracking-[0.08em]", size === "lg" ? "text-2xl" : "text-[1.0625rem]", live.code ? "text-foreground" : "text-disabled-foreground"), children: shown }),
|
|
1711
|
+
copied ? /* @__PURE__ */ jsx9("span", { className: "inline-flex size-6 items-center justify-center text-success", role: "status", "aria-label": "Copied", children: /* @__PURE__ */ jsx9(CheckGlyph, { className: "size-4" }) }) : /* @__PURE__ */ jsx9(CountdownRing, { remaining: live.remaining, period: live.period, loading: !live.code })
|
|
1675
1712
|
]
|
|
1676
1713
|
}
|
|
1677
1714
|
);
|
|
1678
1715
|
}
|
|
1679
1716
|
function CopyCodeButton({ live, label }) {
|
|
1680
1717
|
const { copied, copy } = useCopied();
|
|
1681
|
-
return /* @__PURE__ */
|
|
1718
|
+
return /* @__PURE__ */ jsx9(Button5, { variant: "quiet", icon: copied ? /* @__PURE__ */ jsx9(CheckGlyph, {}) : /* @__PURE__ */ jsx9(CopyIcon3, {}), ...copied ? { glyphTone: "success" } : {}, "aria-label": `Copy ${label} code`, disabled: !live.code, onClick: () => live.code && void copy(live.code) });
|
|
1682
1719
|
}
|
|
1683
1720
|
|
|
1684
1721
|
// src/authenticator/live-code.ts
|
|
@@ -1770,42 +1807,23 @@ import { useEffect as useEffect10, useRef as useRef8, useState as useState10 } f
|
|
|
1770
1807
|
import { Button as Button6, Field as Field3 } from "@ai-matrx/design-system/controls";
|
|
1771
1808
|
|
|
1772
1809
|
// src/authenticator/qr.ts
|
|
1773
|
-
|
|
1774
|
-
const c = globalThis.BarcodeDetector;
|
|
1775
|
-
return typeof c === "function" ? c : null;
|
|
1776
|
-
}
|
|
1777
|
-
var support = null;
|
|
1810
|
+
import { decodeQrFromElement, decodeQrFromImageFile } from "@ai-matrx/capture/qr";
|
|
1778
1811
|
function canDecodeQrLocally() {
|
|
1779
|
-
if (
|
|
1780
|
-
|
|
1781
|
-
|
|
1812
|
+
if (typeof document === "undefined") return Promise.resolve(false);
|
|
1813
|
+
try {
|
|
1814
|
+
return Promise.resolve(Boolean(document.createElement("canvas").getContext("2d")));
|
|
1815
|
+
} catch {
|
|
1816
|
+
return Promise.resolve(false);
|
|
1782
1817
|
}
|
|
1783
|
-
return support;
|
|
1784
1818
|
}
|
|
1785
1819
|
function hasCamera() {
|
|
1786
1820
|
return typeof navigator !== "undefined" && typeof navigator.mediaDevices?.getUserMedia === "function";
|
|
1787
1821
|
}
|
|
1788
|
-
var detector = null;
|
|
1789
|
-
function qrDetector() {
|
|
1790
|
-
const C = detectorCtor();
|
|
1791
|
-
if (!C) return null;
|
|
1792
|
-
detector ??= new C({ formats: ["qr_code"] });
|
|
1793
|
-
return detector;
|
|
1794
|
-
}
|
|
1795
1822
|
async function decodeQr(source) {
|
|
1796
|
-
|
|
1797
|
-
if (!d) return null;
|
|
1798
|
-
const found = await d.detect(source);
|
|
1799
|
-
return found.find((b) => b.rawValue)?.rawValue ?? null;
|
|
1823
|
+
return decodeQrFromElement(source);
|
|
1800
1824
|
}
|
|
1801
1825
|
async function decodeQrFile(file) {
|
|
1802
|
-
|
|
1803
|
-
const bitmap = await createImageBitmap(file);
|
|
1804
|
-
try {
|
|
1805
|
-
return await decodeQr(bitmap);
|
|
1806
|
-
} finally {
|
|
1807
|
-
bitmap.close();
|
|
1808
|
-
}
|
|
1826
|
+
return decodeQrFromImageFile(file);
|
|
1809
1827
|
}
|
|
1810
1828
|
function imageFrom(data) {
|
|
1811
1829
|
if (!data) return null;
|
|
@@ -1820,7 +1838,7 @@ function imageFrom(data) {
|
|
|
1820
1838
|
}
|
|
1821
1839
|
|
|
1822
1840
|
// src/authenticator/Setup.tsx
|
|
1823
|
-
import { Fragment as Fragment5, jsx as
|
|
1841
|
+
import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1824
1842
|
function useCanScan() {
|
|
1825
1843
|
const [ok, setOk] = useState10(false);
|
|
1826
1844
|
useEffect10(() => {
|
|
@@ -1886,15 +1904,15 @@ function QrScanPanel({ open, onResult, onClose }) {
|
|
|
1886
1904
|
stop();
|
|
1887
1905
|
};
|
|
1888
1906
|
}, [open]);
|
|
1889
|
-
return /* @__PURE__ */ jsxs9(Panel, { title: "Scan QR code", open, onClose, size: "sm", footer: /* @__PURE__ */
|
|
1907
|
+
return /* @__PURE__ */ jsxs9(Panel, { title: "Scan QR code", open, onClose, size: "sm", footer: /* @__PURE__ */ jsx10(Button6, { variant: "quiet", onClick: onClose, children: "Cancel" }), children: [
|
|
1890
1908
|
/* @__PURE__ */ jsxs9("div", { className: "relative mx-auto aspect-square w-full max-w-sm overflow-hidden rounded-xl bg-muted", children: [
|
|
1891
|
-
/* @__PURE__ */
|
|
1892
|
-
error ? /* @__PURE__ */
|
|
1909
|
+
/* @__PURE__ */ jsx10("video", { ref: video, className: "size-full object-cover", playsInline: true, muted: true, "aria-label": "Camera" }),
|
|
1910
|
+
error ? /* @__PURE__ */ jsx10("div", { className: "absolute inset-0 flex items-center justify-center p-6 text-center text-sm text-destructive", children: error }) : /* @__PURE__ */ jsx10("div", { className: "pointer-events-none absolute inset-[18%] rounded-lg border-2 border-primary", "aria-hidden": true })
|
|
1893
1911
|
] }),
|
|
1894
|
-
/* @__PURE__ */
|
|
1912
|
+
/* @__PURE__ */ jsx10("p", { className: "text-center text-xs text-muted-foreground", children: "Point at the site's QR code" })
|
|
1895
1913
|
] });
|
|
1896
1914
|
}
|
|
1897
|
-
function OtpSetupRow({ value, onChange, label = "
|
|
1915
|
+
function OtpSetupRow({ value, onChange, label = "Authenticator", placeholder = "Paste setup key or otpauth link", disabled = false, autoFocus = false, onImage, onRecognized, status }) {
|
|
1898
1916
|
const file = useRef8(null);
|
|
1899
1917
|
const canScan = useCanScan();
|
|
1900
1918
|
const [scanning, setScanning] = useState10(false);
|
|
@@ -1927,9 +1945,9 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
|
|
|
1927
1945
|
setReading(false);
|
|
1928
1946
|
}
|
|
1929
1947
|
};
|
|
1930
|
-
const end = status ? /* @__PURE__ */
|
|
1931
|
-
/* @__PURE__ */
|
|
1932
|
-
/* @__PURE__ */
|
|
1948
|
+
const end = status ? /* @__PURE__ */ jsx10("span", { className: "max-w-48 truncate text-xs text-muted-foreground", children: status }) : reading ? /* @__PURE__ */ jsx10("span", { className: "text-xs text-muted-foreground", children: "Reading\u2026" }) : imageError || error ? /* @__PURE__ */ jsx10("span", { className: "max-w-56 truncate text-xs text-destructive", title: imageError ?? error ?? void 0, role: "alert", children: imageError ?? error }) : parsed ? /* @__PURE__ */ jsxs9("span", { className: "flex max-w-56 items-center gap-1 text-xs text-success", children: [
|
|
1949
|
+
/* @__PURE__ */ jsx10(CheckGlyph, { className: "size-3.5 shrink-0" }),
|
|
1950
|
+
/* @__PURE__ */ jsx10("span", { className: "truncate", children: describeEnrollment(parsed) })
|
|
1933
1951
|
] }) : null;
|
|
1934
1952
|
return /* @__PURE__ */ jsxs9(
|
|
1935
1953
|
"div",
|
|
@@ -1954,11 +1972,11 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
|
|
|
1954
1972
|
{
|
|
1955
1973
|
label,
|
|
1956
1974
|
actions: /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
1957
|
-
/* @__PURE__ */
|
|
1958
|
-
canScan ? /* @__PURE__ */
|
|
1975
|
+
/* @__PURE__ */ jsx10(Button6, { variant: "quiet", icon: /* @__PURE__ */ jsx10(QrGlyph, {}), "aria-label": "Choose QR image", title: "Choose or drop a QR image", disabled: disabled || reading, onClick: () => file.current?.click() }),
|
|
1976
|
+
canScan ? /* @__PURE__ */ jsx10(Button6, { variant: "quiet", icon: /* @__PURE__ */ jsx10(CameraGlyph, {}), "aria-label": "Scan QR code with camera", title: "Scan the site's QR code with the camera", disabled, onClick: () => setScanning(true), children: "Scan" }) : null
|
|
1959
1977
|
] }),
|
|
1960
1978
|
children: [
|
|
1961
|
-
/* @__PURE__ */
|
|
1979
|
+
/* @__PURE__ */ jsx10(
|
|
1962
1980
|
Field3,
|
|
1963
1981
|
{
|
|
1964
1982
|
className: "w-full",
|
|
@@ -1981,7 +1999,7 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
|
|
|
1981
1999
|
end
|
|
1982
2000
|
}
|
|
1983
2001
|
),
|
|
1984
|
-
/* @__PURE__ */
|
|
2002
|
+
/* @__PURE__ */ jsx10(
|
|
1985
2003
|
"input",
|
|
1986
2004
|
{
|
|
1987
2005
|
ref: file,
|
|
@@ -1998,7 +2016,7 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
|
|
|
1998
2016
|
]
|
|
1999
2017
|
}
|
|
2000
2018
|
),
|
|
2001
|
-
canScan ? /* @__PURE__ */
|
|
2019
|
+
canScan ? /* @__PURE__ */ jsx10(
|
|
2002
2020
|
QrScanPanel,
|
|
2003
2021
|
{
|
|
2004
2022
|
open: scanning,
|
|
@@ -2029,7 +2047,7 @@ function mfaMethodOf(item) {
|
|
|
2029
2047
|
}
|
|
2030
2048
|
|
|
2031
2049
|
// src/authenticator/TotpRows.tsx
|
|
2032
|
-
import { Fragment as Fragment6, jsx as
|
|
2050
|
+
import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2033
2051
|
function otpActionError(e, what) {
|
|
2034
2052
|
const status = e?.status;
|
|
2035
2053
|
if (status === 404) return "There is no one-time password here.";
|
|
@@ -2067,7 +2085,7 @@ function useOtpActions(port, item, onChanged) {
|
|
|
2067
2085
|
}),
|
|
2068
2086
|
remove: async () => {
|
|
2069
2087
|
const ok = await confirm2({
|
|
2070
|
-
title: `Remove the
|
|
2088
|
+
title: `Remove the authenticator for ${item.name}?`,
|
|
2071
2089
|
description: "Codes stop here. Two-factor stays on at the site, and your phone app and backup codes still work.",
|
|
2072
2090
|
confirmLabel: "Remove",
|
|
2073
2091
|
variant: "destructive"
|
|
@@ -2087,37 +2105,37 @@ function TotpRow({ port, item, onChanged }) {
|
|
|
2087
2105
|
const canManage = item.capabilities.canManage || item.capabilities.canEdit;
|
|
2088
2106
|
if (a.removed || !item.authenticator) return null;
|
|
2089
2107
|
const menu = canManage ? /* @__PURE__ */ jsxs10(DropdownMenu, { children: [
|
|
2090
|
-
/* @__PURE__ */
|
|
2108
|
+
/* @__PURE__ */ jsx11(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx11(Button7, { variant: "quiet", icon: /* @__PURE__ */ jsx11(MoreGlyph, {}), "aria-label": "Authenticator options", disabled: a.busy }) }),
|
|
2091
2109
|
/* @__PURE__ */ jsxs10(DropdownMenuContent, { align: "end", className: "min-w-44", children: [
|
|
2092
2110
|
/* @__PURE__ */ jsxs10(DropdownMenuItem, { onSelect: () => void a.setEnabled(!a.enabled), children: [
|
|
2093
|
-
/* @__PURE__ */
|
|
2111
|
+
/* @__PURE__ */ jsx11(PowerGlyph, { className: "size-4" }),
|
|
2094
2112
|
a.enabled ? "Turn off" : "Turn on"
|
|
2095
2113
|
] }),
|
|
2096
|
-
/* @__PURE__ */
|
|
2114
|
+
/* @__PURE__ */ jsx11(DropdownMenuSeparator, {}),
|
|
2097
2115
|
/* @__PURE__ */ jsxs10(DropdownMenuItem, { className: "text-destructive focus:text-destructive", onSelect: () => void a.remove(), children: [
|
|
2098
|
-
/* @__PURE__ */
|
|
2116
|
+
/* @__PURE__ */ jsx11(TrashGlyph, { className: "size-4" }),
|
|
2099
2117
|
"Remove"
|
|
2100
2118
|
] })
|
|
2101
2119
|
] })
|
|
2102
2120
|
] }) : null;
|
|
2103
|
-
return /* @__PURE__ */
|
|
2121
|
+
return /* @__PURE__ */ jsx11(
|
|
2104
2122
|
VaultRow,
|
|
2105
2123
|
{
|
|
2106
|
-
label: "
|
|
2124
|
+
label: "Authenticator",
|
|
2107
2125
|
actions: /* @__PURE__ */ jsxs10(Fragment6, { children: [
|
|
2108
|
-
a.enabled ? /* @__PURE__ */
|
|
2126
|
+
a.enabled ? /* @__PURE__ */ jsx11(CopyCodeButton, { live, label: item.name }) : null,
|
|
2109
2127
|
menu
|
|
2110
2128
|
] }),
|
|
2111
2129
|
children: a.error ? /* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-2", children: [
|
|
2112
|
-
/* @__PURE__ */
|
|
2113
|
-
/* @__PURE__ */
|
|
2130
|
+
/* @__PURE__ */ jsx11("span", { className: "truncate text-sm text-destructive", role: "alert", children: a.error }),
|
|
2131
|
+
/* @__PURE__ */ jsx11(Button7, { variant: "quiet", onClick: a.clearError, children: "Dismiss" })
|
|
2114
2132
|
] }) : !a.enabled ? /* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-2", children: [
|
|
2115
|
-
/* @__PURE__ */
|
|
2116
|
-
canManage ? /* @__PURE__ */
|
|
2133
|
+
/* @__PURE__ */ jsx11("span", { className: "text-sm text-disabled-foreground", children: "Off" }),
|
|
2134
|
+
canManage ? /* @__PURE__ */ jsx11(Button7, { variant: "quiet", icon: /* @__PURE__ */ jsx11(PowerGlyph, {}), disabled: a.busy, onClick: () => void a.setEnabled(true), children: "Turn on" }) : null
|
|
2117
2135
|
] }) : live.error ? /* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-2", children: [
|
|
2118
|
-
/* @__PURE__ */
|
|
2119
|
-
/* @__PURE__ */
|
|
2120
|
-
] }) : /* @__PURE__ */
|
|
2136
|
+
/* @__PURE__ */ jsx11("span", { className: "truncate text-sm text-destructive", title: live.error, children: live.error }),
|
|
2137
|
+
/* @__PURE__ */ jsx11(Button7, { variant: "quiet", onClick: live.retry, children: "Retry" })
|
|
2138
|
+
] }) : /* @__PURE__ */ jsx11(CodeButton, { live, digits: item.authenticator.digits, label: item.name })
|
|
2121
2139
|
}
|
|
2122
2140
|
);
|
|
2123
2141
|
}
|
|
@@ -2135,7 +2153,7 @@ function TotpEditRow({ value, onChange, hasExisting, item, port, onEnrolled, onR
|
|
|
2135
2153
|
setStatus(wasCancelled(e) ? null : otpActionError(e, "read that image"));
|
|
2136
2154
|
}
|
|
2137
2155
|
} : void 0;
|
|
2138
|
-
return /* @__PURE__ */
|
|
2156
|
+
return /* @__PURE__ */ jsx11(
|
|
2139
2157
|
OtpSetupRow,
|
|
2140
2158
|
{
|
|
2141
2159
|
value,
|
|
@@ -2160,7 +2178,7 @@ function TwoFactorMethodRow({ port, item, onChanged }) {
|
|
|
2160
2178
|
const [busy, setBusy] = useState11(false);
|
|
2161
2179
|
const [error, setError] = useState11(null);
|
|
2162
2180
|
const canEdit = item.capabilities.canEdit || item.capabilities.canManage;
|
|
2163
|
-
return /* @__PURE__ */
|
|
2181
|
+
return /* @__PURE__ */ jsx11(VaultRow, { label: "Two-factor", hint: error ? /* @__PURE__ */ jsx11("span", { className: "text-destructive", children: error }) : void 0, children: /* @__PURE__ */ jsx11(
|
|
2164
2182
|
Select,
|
|
2165
2183
|
{
|
|
2166
2184
|
value: value ?? "none",
|
|
@@ -2187,7 +2205,7 @@ function TwoFactorMethodRow({ port, item, onChanged }) {
|
|
|
2187
2205
|
}
|
|
2188
2206
|
|
|
2189
2207
|
// src/authenticator/AddOtpPanel.tsx
|
|
2190
|
-
import { Fragment as Fragment7, jsx as
|
|
2208
|
+
import { Fragment as Fragment7, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2191
2209
|
var NEW = "__new__";
|
|
2192
2210
|
var LOGIN_KEYS = ["website_login", "username_password"];
|
|
2193
2211
|
function normalizeWebsite(raw) {
|
|
@@ -2263,23 +2281,23 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2263
2281
|
setBusy(false);
|
|
2264
2282
|
}
|
|
2265
2283
|
};
|
|
2266
|
-
if (saved) return /* @__PURE__ */
|
|
2284
|
+
if (saved) return /* @__PURE__ */ jsx12(AddedPanel, { port, item: saved, onClose, onDone: () => onDone(saved.id) });
|
|
2267
2285
|
return /* @__PURE__ */ jsxs11(
|
|
2268
2286
|
Panel,
|
|
2269
2287
|
{
|
|
2270
|
-
title: "Add
|
|
2288
|
+
title: "Add authenticator",
|
|
2271
2289
|
size: "md",
|
|
2272
2290
|
onClose,
|
|
2273
2291
|
footer: /* @__PURE__ */ jsxs11(Fragment7, { children: [
|
|
2274
|
-
/* @__PURE__ */
|
|
2275
|
-
/* @__PURE__ */
|
|
2292
|
+
/* @__PURE__ */ jsx12(Button8, { variant: "quiet", onClick: onClose, disabled: busy, children: "Cancel" }),
|
|
2293
|
+
/* @__PURE__ */ jsx12(Button8, { variant: "primary", disabled: !ready, onClick: () => void save(), children: busy ? "Adding\u2026" : "Add" })
|
|
2276
2294
|
] }),
|
|
2277
2295
|
children: [
|
|
2278
2296
|
/* @__PURE__ */ jsxs11(VaultSection, { children: [
|
|
2279
|
-
/* @__PURE__ */
|
|
2297
|
+
/* @__PURE__ */ jsx12(
|
|
2280
2298
|
OtpSetupRow,
|
|
2281
2299
|
{
|
|
2282
|
-
label: "Setup
|
|
2300
|
+
label: "Setup key",
|
|
2283
2301
|
value: input,
|
|
2284
2302
|
autoFocus: true,
|
|
2285
2303
|
disabled: busy,
|
|
@@ -2297,7 +2315,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2297
2315
|
status: image ? `QR image ready \xB7 ${image.name}` : null
|
|
2298
2316
|
}
|
|
2299
2317
|
),
|
|
2300
|
-
/* @__PURE__ */
|
|
2318
|
+
itemId ? null : /* @__PURE__ */ jsx12(VaultRow, { label: "Add to", children: /* @__PURE__ */ jsx12(
|
|
2301
2319
|
Select2,
|
|
2302
2320
|
{
|
|
2303
2321
|
value: target,
|
|
@@ -2311,7 +2329,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2311
2329
|
}
|
|
2312
2330
|
) }),
|
|
2313
2331
|
isNew ? /* @__PURE__ */ jsxs11(Fragment7, { children: [
|
|
2314
|
-
/* @__PURE__ */
|
|
2332
|
+
/* @__PURE__ */ jsx12(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx12(
|
|
2315
2333
|
Field4,
|
|
2316
2334
|
{
|
|
2317
2335
|
className: "w-full",
|
|
@@ -2325,24 +2343,27 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2325
2343
|
"aria-label": "Name"
|
|
2326
2344
|
}
|
|
2327
2345
|
) }),
|
|
2328
|
-
/* @__PURE__ */
|
|
2346
|
+
/* @__PURE__ */ jsx12(VaultRow, { label: "Website", hint: websiteBad ? /* @__PURE__ */ jsx12("span", { className: "text-destructive", children: "Not a web address" }) : void 0, children: /* @__PURE__ */ jsx12(Field4, { className: "w-full", type: "url", value: website, disabled: busy || created !== null, onChange: (e) => setWebsite(e.target.value), placeholder: "example.com", "aria-label": "Website", "aria-invalid": websiteBad || void 0 }) })
|
|
2329
2347
|
] }) : null
|
|
2330
2348
|
] }),
|
|
2331
|
-
error ? /* @__PURE__ */
|
|
2349
|
+
error ? /* @__PURE__ */ jsx12("p", { className: "px-1 text-sm text-destructive", role: "alert", children: error }) : null
|
|
2332
2350
|
]
|
|
2333
2351
|
}
|
|
2334
2352
|
);
|
|
2335
2353
|
}
|
|
2354
|
+
function FirstCodePanel(props) {
|
|
2355
|
+
return /* @__PURE__ */ jsx12(AddedPanel, { ...props });
|
|
2356
|
+
}
|
|
2336
2357
|
function AddedPanel({ port, item, onClose, onDone }) {
|
|
2337
2358
|
const live = useLiveCode(port, item, true);
|
|
2338
|
-
return /* @__PURE__ */
|
|
2339
|
-
live.error ? /* @__PURE__ */
|
|
2340
|
-
/* @__PURE__ */
|
|
2359
|
+
return /* @__PURE__ */ jsx12(Panel, { title: item.name, size: "sm", onClose, footer: /* @__PURE__ */ jsx12(Button8, { variant: "primary", onClick: onDone, children: "Done" }), children: /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-2 py-4", children: [
|
|
2360
|
+
live.error ? /* @__PURE__ */ jsx12("span", { className: "text-sm text-destructive", children: live.error }) : /* @__PURE__ */ jsx12(CodeButton, { live, digits: item.authenticator?.digits ?? 6, size: "lg", label: item.name }),
|
|
2361
|
+
/* @__PURE__ */ jsx12("p", { className: "text-xs text-muted-foreground", children: "Enter this code on the site to finish." })
|
|
2341
2362
|
] }) });
|
|
2342
2363
|
}
|
|
2343
2364
|
|
|
2344
2365
|
// src/authenticator/AuthenticatorView.tsx
|
|
2345
|
-
import { Fragment as Fragment8, jsx as
|
|
2366
|
+
import { Fragment as Fragment8, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2346
2367
|
function matchesEntry(entry, q) {
|
|
2347
2368
|
if (!entry || !q) return false;
|
|
2348
2369
|
return [entry.issuer, entry.account].some((v) => v?.toLowerCase().includes(q));
|
|
@@ -2360,7 +2381,7 @@ function otpGroups(items, entries, query, hidden = /* @__PURE__ */ new Set()) {
|
|
|
2360
2381
|
const rank = (k) => k === "me" ? 0 : k === "shared" ? 2 : 1;
|
|
2361
2382
|
return [...groups.entries()].sort(([a, x], [b, y]) => rank(a) - rank(b) || x.label.localeCompare(y.label)).map(([key, g]) => ({ key, ...g }));
|
|
2362
2383
|
}
|
|
2363
|
-
function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged, header }) {
|
|
2384
|
+
function AuthenticatorView({ port, host, items, definitions, query, onOpen, onChanged, header }) {
|
|
2364
2385
|
const [entries, setEntries] = useState13(/* @__PURE__ */ new Map());
|
|
2365
2386
|
const [hidden, setHidden] = useState13(/* @__PURE__ */ new Set());
|
|
2366
2387
|
const [adding, setAdding] = useState13(false);
|
|
@@ -2380,20 +2401,20 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2380
2401
|
const groups = otpGroups(items, entries, query, hidden);
|
|
2381
2402
|
const total = items.filter((i) => i.authenticator && !i.deletion && !hidden.has(i.id)).length;
|
|
2382
2403
|
const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
|
|
2383
|
-
return /* @__PURE__ */ jsxs12("section", { "aria-label": "
|
|
2384
|
-
header ? /* @__PURE__ */
|
|
2404
|
+
return /* @__PURE__ */ jsxs12("section", { "aria-label": "Authenticator", className: "flex h-full min-h-0 flex-col bg-background", children: [
|
|
2405
|
+
header ? /* @__PURE__ */ jsx13("div", { className: "mx-auto w-full max-w-3xl px-3 pt-3 sm:px-4", children: header }) : null,
|
|
2385
2406
|
/* @__PURE__ */ jsxs12("div", { className: "flex min-h-12 items-center justify-between gap-2 px-4 pb-1 pt-3", children: [
|
|
2386
2407
|
/* @__PURE__ */ jsxs12("div", { className: "flex min-w-0 items-baseline gap-2", children: [
|
|
2387
|
-
/* @__PURE__ */
|
|
2388
|
-
total > 0 ? /* @__PURE__ */
|
|
2408
|
+
/* @__PURE__ */ jsx13("h2", { className: "truncate text-sm font-semibold text-foreground", children: "Authenticator" }),
|
|
2409
|
+
total > 0 ? /* @__PURE__ */ jsx13("span", { className: "text-xs tabular-nums text-muted-foreground", children: total }) : null
|
|
2389
2410
|
] }),
|
|
2390
|
-
total > 0 ? /* @__PURE__ */
|
|
2411
|
+
total > 0 ? /* @__PURE__ */ jsx13(Button9, { variant: "outline", icon: /* @__PURE__ */ jsx13(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add" }) : null
|
|
2391
2412
|
] }),
|
|
2392
2413
|
total === 0 ? /* @__PURE__ */ jsxs12("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 px-6 pb-12 text-center", children: [
|
|
2393
|
-
/* @__PURE__ */
|
|
2394
|
-
/* @__PURE__ */
|
|
2395
|
-
/* @__PURE__ */
|
|
2396
|
-
] }) : groups.length === 0 ? /* @__PURE__ */
|
|
2414
|
+
/* @__PURE__ */ jsx13("span", { className: "flex size-12 items-center justify-center rounded-full bg-muted text-muted-foreground", children: /* @__PURE__ */ jsx13(ShieldGlyph, { className: "size-6" }) }),
|
|
2415
|
+
/* @__PURE__ */ jsx13("p", { className: "text-sm font-medium text-foreground", children: "No authenticator codes yet" }),
|
|
2416
|
+
/* @__PURE__ */ jsx13(Button9, { variant: "primary", icon: /* @__PURE__ */ jsx13(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add authenticator" })
|
|
2417
|
+
] }) : groups.length === 0 ? /* @__PURE__ */ jsx13("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: "Nothing matches." }) : /* @__PURE__ */ jsx13("div", { className: "min-h-0 flex-1 overflow-y-auto px-3 pb-6 pt-1 sm:px-4", children: /* @__PURE__ */ jsx13("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: groups.map((g) => /* @__PURE__ */ jsx13(VaultSection, { title: g.label, className: "[&>div]:px-1", children: g.items.map((item) => /* @__PURE__ */ jsx13(
|
|
2397
2418
|
OtpListRow,
|
|
2398
2419
|
{
|
|
2399
2420
|
port,
|
|
@@ -2401,6 +2422,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2401
2422
|
family: familyOf2(item.definitionKey),
|
|
2402
2423
|
entry: entries.get(item.id),
|
|
2403
2424
|
onOpen: () => onOpen(item.id),
|
|
2425
|
+
...host.openItemInNewTab ? { onOpenInNewTab: () => host.openItemInNewTab?.(item.id) } : {},
|
|
2404
2426
|
onRename: () => {
|
|
2405
2427
|
setRenameError(null);
|
|
2406
2428
|
setRenaming(item);
|
|
@@ -2413,7 +2435,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2413
2435
|
},
|
|
2414
2436
|
item.id
|
|
2415
2437
|
)) }, g.key)) }) }),
|
|
2416
|
-
adding ? /* @__PURE__ */
|
|
2438
|
+
adding ? /* @__PURE__ */ jsx13(
|
|
2417
2439
|
AddOtpPanel,
|
|
2418
2440
|
{
|
|
2419
2441
|
port,
|
|
@@ -2427,7 +2449,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2427
2449
|
}
|
|
2428
2450
|
}
|
|
2429
2451
|
) : null,
|
|
2430
|
-
/* @__PURE__ */
|
|
2452
|
+
/* @__PURE__ */ jsx13(
|
|
2431
2453
|
TextInputDialog,
|
|
2432
2454
|
{
|
|
2433
2455
|
open: renaming !== null,
|
|
@@ -2435,7 +2457,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2435
2457
|
if (!o && !renameBusy) setRenaming(null);
|
|
2436
2458
|
},
|
|
2437
2459
|
title: "Rename login",
|
|
2438
|
-
...renameError ? { description: /* @__PURE__ */
|
|
2460
|
+
...renameError ? { description: /* @__PURE__ */ jsx13("span", { className: "text-destructive", children: renameError }) } : {},
|
|
2439
2461
|
placeholder: "Login name",
|
|
2440
2462
|
defaultValue: renaming?.name ?? "",
|
|
2441
2463
|
confirmLabel: "Rename",
|
|
@@ -2458,50 +2480,53 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
|
|
|
2458
2480
|
)
|
|
2459
2481
|
] });
|
|
2460
2482
|
}
|
|
2461
|
-
function OtpListRow({ port, item, family, entry, onOpen, onRename, onChanged, onRemoved }) {
|
|
2483
|
+
function OtpListRow({ port, item, family, entry, onOpen, onOpenInNewTab, onRename, onChanged, onRemoved }) {
|
|
2462
2484
|
const a = useOtpActions(port, item, (next) => next && next.authenticator === null ? onRemoved() : onChanged());
|
|
2463
2485
|
const live = useLiveCode(port, item, a.enabled && !a.removed);
|
|
2464
2486
|
const { copy } = useCopied();
|
|
2465
|
-
const Icon = definitionGlyph(item.definitionKey, family);
|
|
2466
2487
|
const canManage = item.capabilities.canManage || item.capabilities.canEdit;
|
|
2467
2488
|
if (a.removed) return null;
|
|
2468
2489
|
const sub = a.error ?? [entry?.account, loginSiteOf(item) || entry?.issuer].filter((v, i, all) => Boolean(v) && all.indexOf(v) === i).join(" \xB7 ");
|
|
2469
2490
|
return /* @__PURE__ */ jsxs12("div", { className: "grid min-h-14 grid-cols-[2rem_minmax(0,1fr)_auto_auto] items-center gap-x-3 rounded-lg px-2 py-1.5 transition-colors hover:bg-accent/50", children: [
|
|
2470
|
-
/* @__PURE__ */
|
|
2491
|
+
/* @__PURE__ */ jsx13("button", { type: "button", onClick: onOpen, "aria-label": `Open ${item.name}`, tabIndex: -1, className: "flex size-8 items-center justify-center rounded-lg", children: /* @__PURE__ */ jsx13(ItemIcon, { definitionKey: item.definitionKey, family, site: loginSiteOf(item) || (entry?.issuer ?? "") }) }),
|
|
2471
2492
|
/* @__PURE__ */ jsxs12("button", { type: "button", onClick: onOpen, className: "flex min-w-0 flex-col items-start rounded-md text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [
|
|
2472
|
-
/* @__PURE__ */
|
|
2473
|
-
sub ? /* @__PURE__ */
|
|
2493
|
+
/* @__PURE__ */ jsx13("span", { className: cn7("max-w-full truncate text-sm font-medium", a.enabled ? "text-foreground" : "text-muted-foreground"), children: item.name }),
|
|
2494
|
+
sub ? /* @__PURE__ */ jsx13("span", { className: cn7("max-w-full truncate text-xs", a.error ? "text-destructive" : "text-muted-foreground"), title: sub, children: sub }) : null
|
|
2474
2495
|
] }),
|
|
2475
|
-
/* @__PURE__ */
|
|
2476
|
-
/* @__PURE__ */
|
|
2477
|
-
canManage ? /* @__PURE__ */
|
|
2496
|
+
/* @__PURE__ */ jsx13("div", { className: "flex min-w-0 justify-end", children: !a.enabled ? /* @__PURE__ */ jsxs12("span", { className: "flex items-center gap-1.5", children: [
|
|
2497
|
+
/* @__PURE__ */ jsx13("span", { className: "text-sm text-disabled-foreground", children: "Off" }),
|
|
2498
|
+
canManage ? /* @__PURE__ */ jsx13(Button9, { variant: "quiet", disabled: a.busy, onClick: () => void a.setEnabled(true), children: "Turn on" }) : null
|
|
2478
2499
|
] }) : live.error ? /* @__PURE__ */ jsxs12("span", { className: "flex items-center gap-1.5", children: [
|
|
2479
|
-
/* @__PURE__ */
|
|
2480
|
-
/* @__PURE__ */
|
|
2481
|
-
] }) : /* @__PURE__ */
|
|
2500
|
+
/* @__PURE__ */ jsx13("span", { className: "max-w-40 truncate text-xs text-destructive", title: live.error, children: live.error }),
|
|
2501
|
+
/* @__PURE__ */ jsx13(Button9, { variant: "quiet", onClick: live.retry, children: "Retry" })
|
|
2502
|
+
] }) : /* @__PURE__ */ jsx13(CodeButton, { live, digits: item.authenticator?.digits ?? 6, label: item.name }) }),
|
|
2482
2503
|
/* @__PURE__ */ jsxs12(DropdownMenu2, { children: [
|
|
2483
|
-
/* @__PURE__ */
|
|
2504
|
+
/* @__PURE__ */ jsx13(DropdownMenuTrigger2, { asChild: true, children: /* @__PURE__ */ jsx13(Button9, { variant: "quiet", icon: /* @__PURE__ */ jsx13(MoreGlyph, {}), "aria-label": `${item.name} options`, disabled: a.busy }) }),
|
|
2484
2505
|
/* @__PURE__ */ jsxs12(DropdownMenuContent2, { align: "end", className: "min-w-44", children: [
|
|
2485
2506
|
/* @__PURE__ */ jsxs12(DropdownMenuItem2, { onSelect: onOpen, children: [
|
|
2486
|
-
/* @__PURE__ */
|
|
2507
|
+
/* @__PURE__ */ jsx13(ExternalGlyph, { className: "size-4" }),
|
|
2487
2508
|
"Open login"
|
|
2488
2509
|
] }),
|
|
2510
|
+
onOpenInNewTab ? /* @__PURE__ */ jsxs12(DropdownMenuItem2, { onSelect: onOpenInNewTab, children: [
|
|
2511
|
+
/* @__PURE__ */ jsx13(ExternalGlyph, { className: "size-4" }),
|
|
2512
|
+
"Open in new tab"
|
|
2513
|
+
] }) : null,
|
|
2489
2514
|
live.code ? /* @__PURE__ */ jsxs12(DropdownMenuItem2, { onSelect: () => live.code && void copy(live.code), children: [
|
|
2490
|
-
/* @__PURE__ */
|
|
2515
|
+
/* @__PURE__ */ jsx13(CopyIcon4, { className: "size-4" }),
|
|
2491
2516
|
"Copy code"
|
|
2492
2517
|
] }) : null,
|
|
2493
2518
|
canManage ? /* @__PURE__ */ jsxs12(Fragment8, { children: [
|
|
2494
2519
|
/* @__PURE__ */ jsxs12(DropdownMenuItem2, { onSelect: onRename, children: [
|
|
2495
|
-
/* @__PURE__ */
|
|
2520
|
+
/* @__PURE__ */ jsx13(PencilGlyph, { className: "size-4" }),
|
|
2496
2521
|
"Rename"
|
|
2497
2522
|
] }),
|
|
2498
2523
|
/* @__PURE__ */ jsxs12(DropdownMenuItem2, { onSelect: () => void a.setEnabled(!a.enabled), children: [
|
|
2499
|
-
/* @__PURE__ */
|
|
2524
|
+
/* @__PURE__ */ jsx13(PowerGlyph, { className: "size-4" }),
|
|
2500
2525
|
a.enabled ? "Turn off" : "Turn on"
|
|
2501
2526
|
] }),
|
|
2502
|
-
/* @__PURE__ */
|
|
2527
|
+
/* @__PURE__ */ jsx13(DropdownMenuSeparator2, {}),
|
|
2503
2528
|
/* @__PURE__ */ jsxs12(DropdownMenuItem2, { className: "text-destructive focus:text-destructive", onSelect: () => void a.remove(), children: [
|
|
2504
|
-
/* @__PURE__ */
|
|
2529
|
+
/* @__PURE__ */ jsx13(TrashGlyph, { className: "size-4" }),
|
|
2505
2530
|
"Remove"
|
|
2506
2531
|
] })
|
|
2507
2532
|
] }) : null
|
|
@@ -2592,9 +2617,21 @@ function withoutCode(codes, index) {
|
|
|
2592
2617
|
const left = codes.filter((_, i) => i !== index);
|
|
2593
2618
|
return left.length ? left.join("\n") : null;
|
|
2594
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
|
+
}
|
|
2595
2632
|
|
|
2596
2633
|
// src/fields/SettingsPanels.tsx
|
|
2597
|
-
import { jsx as
|
|
2634
|
+
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2598
2635
|
var say = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
|
|
2599
2636
|
function useSaver(onChanged) {
|
|
2600
2637
|
const [busy, setBusy] = useState14(null);
|
|
@@ -2616,14 +2653,14 @@ function useSaver(onChanged) {
|
|
|
2616
2653
|
return { busy, error, setError, save };
|
|
2617
2654
|
}
|
|
2618
2655
|
function Problem({ children }) {
|
|
2619
|
-
return /* @__PURE__ */
|
|
2656
|
+
return /* @__PURE__ */ jsx14("p", { role: "alert", className: "px-1 text-sm text-destructive", children });
|
|
2620
2657
|
}
|
|
2621
|
-
var quietHint = (text, tone = "muted") => /* @__PURE__ */
|
|
2658
|
+
var quietHint = (text, tone = "muted") => /* @__PURE__ */ jsx14("span", { className: tone === "destructive" ? "text-destructive" : void 0, title: text, children: text });
|
|
2622
2659
|
function FieldSettingsPanel(props) {
|
|
2623
2660
|
const field = props.item.fields.find((f) => f.id === props.arg);
|
|
2624
2661
|
if (!field)
|
|
2625
|
-
return /* @__PURE__ */
|
|
2626
|
-
return /* @__PURE__ */
|
|
2662
|
+
return /* @__PURE__ */ jsx14(Panel, { title: "Field settings", size: "md", onClose: props.onClose, footer: /* @__PURE__ */ jsx14(Button10, { variant: "primary", onClick: props.onClose, children: "Done" }), children: /* @__PURE__ */ jsx14(Empty, { children: "This field is no longer on the item." }) });
|
|
2663
|
+
return /* @__PURE__ */ jsx14(FieldSettings, { ...props, field }, field.id);
|
|
2627
2664
|
}
|
|
2628
2665
|
function FieldSettings({ item, port, field, onClose, onChanged }) {
|
|
2629
2666
|
const { busy, error, setError, save } = useSaver((next) => onChanged(next));
|
|
@@ -2662,9 +2699,9 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
|
|
|
2662
2699
|
};
|
|
2663
2700
|
const handling = HANDLING_WORDS[field.handling];
|
|
2664
2701
|
const locked = !canEdit || busy !== null;
|
|
2665
|
-
return /* @__PURE__ */ jsxs13(Panel, { title: `${field.label} settings`, size: "md", onClose, footer: /* @__PURE__ */
|
|
2666
|
-
!canEdit ? /* @__PURE__ */
|
|
2667
|
-
/* @__PURE__ */
|
|
2702
|
+
return /* @__PURE__ */ jsxs13(Panel, { title: `${field.label} settings`, size: "md", onClose, footer: /* @__PURE__ */ jsx14(Button10, { variant: "primary", onClick: onClose, children: "Done" }), children: [
|
|
2703
|
+
!canEdit ? /* @__PURE__ */ jsx14("p", { className: "px-1 text-sm text-muted-foreground", children: "View only: you can\u2019t change these settings." }) : null,
|
|
2704
|
+
/* @__PURE__ */ jsx14(VaultSection, { title: "Who can see it", children: /* @__PURE__ */ jsx14(VaultRow, { label: "Value", hint: quietHint(handling.hint), children: field.handling === "sealed" ? /* @__PURE__ */ jsx14(Badge3, { icon: /* @__PURE__ */ jsx14(LockGlyph, {}), children: "Sealed for good" }) : /* @__PURE__ */ jsx14(
|
|
2668
2705
|
SegmentedControl,
|
|
2669
2706
|
{
|
|
2670
2707
|
"aria-label": "Who can see it",
|
|
@@ -2674,7 +2711,7 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
|
|
|
2674
2711
|
}
|
|
2675
2712
|
) }) }),
|
|
2676
2713
|
/* @__PURE__ */ jsxs13(VaultSection, { title: "Automation", children: [
|
|
2677
|
-
/* @__PURE__ */
|
|
2714
|
+
/* @__PURE__ */ jsx14(VaultRow, { label: "Env key", hint: envProblem ? quietHint(envProblem, "destructive") : quietHint("The name sandboxes and workflows use"), children: /* @__PURE__ */ jsx14(
|
|
2678
2715
|
Field5,
|
|
2679
2716
|
{
|
|
2680
2717
|
ref: envRef,
|
|
@@ -2694,10 +2731,10 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
|
|
|
2694
2731
|
}
|
|
2695
2732
|
}
|
|
2696
2733
|
) }),
|
|
2697
|
-
/* @__PURE__ */
|
|
2734
|
+
/* @__PURE__ */ jsx14(VaultRow, { label: "Use in sandbox", hint: blocker && !field.injectIntoSandbox ? quietHint(blocker) : quietHint("Sandboxes get it as an env variable"), children: /* @__PURE__ */ jsx14(Switch, { "aria-label": "Use in sandbox", checked: field.injectIntoSandbox, disabled: locked, onCheckedChange: (v) => void setSandbox(v) }) })
|
|
2698
2735
|
] }),
|
|
2699
2736
|
/* @__PURE__ */ jsxs13(VaultSection, { title: "Field", children: [
|
|
2700
|
-
/* @__PURE__ */
|
|
2737
|
+
/* @__PURE__ */ jsx14(VaultRow, { label: "Description", children: /* @__PURE__ */ jsx14(
|
|
2701
2738
|
Field5,
|
|
2702
2739
|
{
|
|
2703
2740
|
className: "w-full",
|
|
@@ -2713,10 +2750,10 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
|
|
|
2713
2750
|
}
|
|
2714
2751
|
}
|
|
2715
2752
|
) }),
|
|
2716
|
-
/* @__PURE__ */
|
|
2717
|
-
/* @__PURE__ */
|
|
2753
|
+
/* @__PURE__ */ jsx14(VaultRow, { label: "Editable", hint: quietHint(field.editable ? "The value can be changed" : "The value is locked"), children: /* @__PURE__ */ jsx14(Switch, { "aria-label": "Editable", checked: field.editable, disabled: locked, onCheckedChange: (v) => void update("editable", { editable: v }) }) }),
|
|
2754
|
+
/* @__PURE__ */ jsx14(VaultRow, { label: "Turned on", hint: quietHint(field.active ? "In use" : "Kept, but nothing uses it"), children: /* @__PURE__ */ jsx14(Switch, { "aria-label": "Turned on", checked: field.active, disabled: locked, onCheckedChange: (v) => void update("active", { active: v }) }) })
|
|
2718
2755
|
] }),
|
|
2719
|
-
error ? /* @__PURE__ */
|
|
2756
|
+
error ? /* @__PURE__ */ jsx14(Problem, { children: error }) : null
|
|
2720
2757
|
] });
|
|
2721
2758
|
}
|
|
2722
2759
|
function ItemSettingsPanel({ item, port, onClose, onChanged, onPanel }) {
|
|
@@ -2743,10 +2780,10 @@ function ItemSettingsPanel({ item, port, onClose, onChanged, onPanel }) {
|
|
|
2743
2780
|
});
|
|
2744
2781
|
};
|
|
2745
2782
|
const fillHint = !hasWebsite ? "Add a website first" : item.browserFillEnabled ? "Offered on matching pages" : "Never filled automatically";
|
|
2746
|
-
return /* @__PURE__ */ jsxs13(Panel, { title: "Item settings", size: "md", onClose, footer: /* @__PURE__ */
|
|
2747
|
-
!canEdit ? /* @__PURE__ */
|
|
2783
|
+
return /* @__PURE__ */ jsxs13(Panel, { title: "Item settings", size: "md", onClose, footer: /* @__PURE__ */ jsx14(Button10, { variant: "primary", onClick: onClose, children: "Done" }), children: [
|
|
2784
|
+
!canEdit ? /* @__PURE__ */ jsx14("p", { className: "px-1 text-sm text-muted-foreground", children: "View only: you can\u2019t change these settings." }) : null,
|
|
2748
2785
|
/* @__PURE__ */ jsxs13(VaultSection, { title: "In the browser", children: [
|
|
2749
|
-
/* @__PURE__ */
|
|
2786
|
+
/* @__PURE__ */ jsx14(VaultRow, { label: "Website matching", hint: quietHint(MATCH_WORDS[item.uriMatchMode].hint), children: /* @__PURE__ */ jsx14(
|
|
2750
2787
|
Select3,
|
|
2751
2788
|
{
|
|
2752
2789
|
"aria-label": "Website matching",
|
|
@@ -2756,45 +2793,45 @@ function ItemSettingsPanel({ item, port, onClose, onChanged, onPanel }) {
|
|
|
2756
2793
|
onValueChange: (m) => void save("match", () => port.fields.updateItem(item, { uriMatchMode: m }))
|
|
2757
2794
|
}
|
|
2758
2795
|
) }),
|
|
2759
|
-
/* @__PURE__ */
|
|
2760
|
-
promotable.map((f) => /* @__PURE__ */
|
|
2796
|
+
/* @__PURE__ */ jsx14(VaultRow, { label: "Fill in browser", hint: quietHint(fillHint), children: /* @__PURE__ */ jsx14(Switch, { "aria-label": "Fill in browser", checked: hasWebsite && item.browserFillEnabled, disabled: locked || !hasWebsite, onCheckedChange: (v) => void save("fill", () => port.fields.updateItem(item, { browserFillEnabled: v })) }) }),
|
|
2797
|
+
promotable.map((f) => /* @__PURE__ */ jsx14(
|
|
2761
2798
|
VaultRow,
|
|
2762
2799
|
{
|
|
2763
2800
|
label: f.label,
|
|
2764
2801
|
hint: quietHint("Encrypted, so the browser can\u2019t match it"),
|
|
2765
|
-
actions: /* @__PURE__ */
|
|
2766
|
-
children: /* @__PURE__ */
|
|
2802
|
+
actions: /* @__PURE__ */ jsx14(Button10, { variant: "outline", icon: /* @__PURE__ */ jsx14(GlobeIcon2, {}), disabled: locked, onClick: () => void promote(f), children: "Use as website" }),
|
|
2803
|
+
children: /* @__PURE__ */ jsx14("span", { className: "text-muted-foreground", children: "Not a website yet" })
|
|
2767
2804
|
},
|
|
2768
2805
|
f.id
|
|
2769
2806
|
))
|
|
2770
2807
|
] }),
|
|
2771
2808
|
/* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-1.5", children: [
|
|
2772
|
-
/* @__PURE__ */
|
|
2773
|
-
advanced ? /* @__PURE__ */
|
|
2809
|
+
/* @__PURE__ */ jsx14(DisclosureHeader, { open: advanced, title: "Advanced", meta: item.fields.length ? `${item.fields.length} fields` : void 0, onClick: () => setAdvanced((a) => !a) }),
|
|
2810
|
+
advanced ? /* @__PURE__ */ jsx14(VaultSection, { children: item.fields.length === 0 ? /* @__PURE__ */ jsx14(Empty, { children: "No encrypted fields." }) : item.fields.map((f) => /* @__PURE__ */ jsx14(
|
|
2774
2811
|
VaultRow,
|
|
2775
2812
|
{
|
|
2776
2813
|
label: f.label,
|
|
2777
|
-
actions: /* @__PURE__ */
|
|
2814
|
+
actions: /* @__PURE__ */ jsx14(Button10, { variant: "quiet", icon: /* @__PURE__ */ jsx14(SlidersGlyph, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) }),
|
|
2778
2815
|
children: /* @__PURE__ */ jsxs13("span", { className: "block truncate", children: [
|
|
2779
|
-
/* @__PURE__ */
|
|
2816
|
+
/* @__PURE__ */ jsx14("span", { className: f.handling === "sealed" ? "text-foreground" : "text-muted-foreground", children: HANDLING_WORDS[f.handling].label }),
|
|
2780
2817
|
f.envKey ? /* @__PURE__ */ jsxs13("span", { className: "font-mono text-muted-foreground", children: [
|
|
2781
2818
|
" \xB7 ",
|
|
2782
2819
|
f.envKey
|
|
2783
2820
|
] }) : null,
|
|
2784
|
-
f.injectIntoSandbox ? /* @__PURE__ */
|
|
2785
|
-
!f.active ? /* @__PURE__ */
|
|
2821
|
+
f.injectIntoSandbox ? /* @__PURE__ */ jsx14("span", { className: "text-muted-foreground", children: " \xB7 Sandbox" }) : null,
|
|
2822
|
+
!f.active ? /* @__PURE__ */ jsx14("span", { className: "text-warning", children: " \xB7 Turned off" }) : null
|
|
2786
2823
|
] })
|
|
2787
2824
|
},
|
|
2788
2825
|
f.id
|
|
2789
2826
|
)) }) : null
|
|
2790
2827
|
] }),
|
|
2791
|
-
error ? /* @__PURE__ */
|
|
2828
|
+
error ? /* @__PURE__ */ jsx14(Problem, { children: error }) : null
|
|
2792
2829
|
] });
|
|
2793
2830
|
}
|
|
2794
2831
|
|
|
2795
2832
|
// src/generator/PasswordGenerator.tsx
|
|
2796
2833
|
import { createContext as createContext5, useContext as useContext5, useEffect as useEffect12, useRef as useRef10, useState as useState15 } from "react";
|
|
2797
|
-
import { Popover, PopoverContent, PopoverTrigger, cn as
|
|
2834
|
+
import { Popover, PopoverContent, PopoverTrigger, cn as cn8 } from "@ai-matrx/design-system";
|
|
2798
2835
|
import { Button as Button11, NumberStepper, SegmentedControl as SegmentedControl2, Select as Select4, Switch as Switch2 } from "@ai-matrx/design-system/controls";
|
|
2799
2836
|
import { CopyIcon as CopyIcon5 } from "@ai-matrx/design-system/icons";
|
|
2800
2837
|
|
|
@@ -2854,10 +2891,10 @@ function strengthOf(bits) {
|
|
|
2854
2891
|
}
|
|
2855
2892
|
|
|
2856
2893
|
// src/generator/PasswordGenerator.tsx
|
|
2857
|
-
import { jsx as
|
|
2894
|
+
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2858
2895
|
var LimitsCtx = createContext5(null);
|
|
2859
2896
|
function GeneratorLimitsProvider({ resolve: resolve2, children }) {
|
|
2860
|
-
return /* @__PURE__ */
|
|
2897
|
+
return /* @__PURE__ */ jsx15(LimitsCtx.Provider, { value: resolve2 ?? null, children });
|
|
2861
2898
|
}
|
|
2862
2899
|
function useGeneratorLimitsSource() {
|
|
2863
2900
|
return useContext5(LimitsCtx);
|
|
@@ -2918,11 +2955,11 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
|
|
|
2918
2955
|
useEffect12(() => () => {
|
|
2919
2956
|
if (expiry.current) clearTimeout(expiry.current);
|
|
2920
2957
|
}, []);
|
|
2921
|
-
if (limits.state === "loading") return /* @__PURE__ */
|
|
2958
|
+
if (limits.state === "loading") return /* @__PURE__ */ jsx15("p", { className: "px-1 py-3 text-sm text-muted-foreground", "aria-live": "polite", children: "Reading limits\u2026" });
|
|
2922
2959
|
if (limits.state === "unavailable")
|
|
2923
2960
|
return /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-2 px-1 py-2", children: [
|
|
2924
|
-
/* @__PURE__ */
|
|
2925
|
-
/* @__PURE__ */
|
|
2961
|
+
/* @__PURE__ */ jsx15("p", { role: "alert", className: "text-sm text-destructive", children: limits.message }),
|
|
2962
|
+
/* @__PURE__ */ jsx15(Button11, { variant: "outline", icon: /* @__PURE__ */ jsx15(RefreshGlyph, {}), onClick: () => setRound((n) => n + 1), children: "Try again" })
|
|
2926
2963
|
] });
|
|
2927
2964
|
const ceilings = limits.limits;
|
|
2928
2965
|
const change = (next) => make(next, ceilings);
|
|
@@ -2940,7 +2977,7 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
|
|
|
2940
2977
|
onUse(value);
|
|
2941
2978
|
};
|
|
2942
2979
|
return /* @__PURE__ */ jsxs14("div", { className: "flex w-full flex-col gap-3", "aria-label": "Password generator", children: [
|
|
2943
|
-
/* @__PURE__ */
|
|
2980
|
+
/* @__PURE__ */ jsx15(
|
|
2944
2981
|
SegmentedControl2,
|
|
2945
2982
|
{
|
|
2946
2983
|
fill: true,
|
|
@@ -2952,13 +2989,13 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
|
|
|
2952
2989
|
),
|
|
2953
2990
|
/* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-1 rounded-lg bg-muted px-3 py-2", children: [
|
|
2954
2991
|
/* @__PURE__ */ jsxs14("div", { className: "flex min-h-7 items-start gap-1", children: [
|
|
2955
|
-
/* @__PURE__ */
|
|
2956
|
-
/* @__PURE__ */
|
|
2957
|
-
/* @__PURE__ */
|
|
2958
|
-
/* @__PURE__ */
|
|
2992
|
+
/* @__PURE__ */ jsx15("code", { className: cn8("min-w-0 flex-1 break-all py-1 font-mono text-sm", candidate ? "text-foreground" : "text-muted-foreground"), "data-testid": "generated-value", children: candidate ? revealed ? candidate.value : MASK3 : "\u2014" }),
|
|
2993
|
+
/* @__PURE__ */ jsx15(Button11, { variant: "quiet", icon: revealed ? /* @__PURE__ */ jsx15(EyeOffGlyph, {}) : /* @__PURE__ */ jsx15(EyeGlyph, {}), "aria-label": revealed ? "Hide" : "Reveal", disabled: !candidate, onClick: () => setRevealed((r) => !r) }),
|
|
2994
|
+
/* @__PURE__ */ jsx15(Button11, { variant: "quiet", icon: /* @__PURE__ */ jsx15(CopyIcon5, {}), "aria-label": "Copy", disabled: !candidate, onClick: () => void copy() }),
|
|
2995
|
+
/* @__PURE__ */ jsx15(Button11, { variant: "quiet", icon: /* @__PURE__ */ jsx15(RefreshGlyph, {}), "aria-label": "Generate another", onClick: () => change(settings) })
|
|
2959
2996
|
] }),
|
|
2960
2997
|
strength && candidate ? /* @__PURE__ */ jsxs14("p", { className: "text-xs", children: [
|
|
2961
|
-
/* @__PURE__ */
|
|
2998
|
+
/* @__PURE__ */ jsx15("span", { className: cn8(strength.tone === "success" && "text-success", strength.tone === "primary" && "text-primary", strength.tone === "warning" && "text-warning"), children: strength.label }),
|
|
2962
2999
|
/* @__PURE__ */ jsxs14("span", { className: "text-muted-foreground", children: [
|
|
2963
3000
|
" \xB7 ",
|
|
2964
3001
|
Math.floor(candidate.bits),
|
|
@@ -2967,7 +3004,7 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
|
|
|
2967
3004
|
] }) : null
|
|
2968
3005
|
] }),
|
|
2969
3006
|
settings.kind === "password" ? /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-0.5", children: [
|
|
2970
|
-
/* @__PURE__ */
|
|
3007
|
+
/* @__PURE__ */ jsx15(OptionLine, { label: "Length", children: /* @__PURE__ */ jsx15(NumberStepper, { value: settings.password.length, min: minPasswordLength(settings.password), max: ceilings.maxPasswordLength, fallback: 24, onChange: (length) => setPassword({ length }) }) }),
|
|
2971
3008
|
[
|
|
2972
3009
|
["lowercase", "Lowercase"],
|
|
2973
3010
|
["uppercase", "Uppercase"],
|
|
@@ -2976,26 +3013,26 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
|
|
|
2976
3013
|
].map(([key, label]) => {
|
|
2977
3014
|
const on = settings.password[key];
|
|
2978
3015
|
const last = on && minPasswordLength(settings.password) === 1;
|
|
2979
|
-
return /* @__PURE__ */
|
|
3016
|
+
return /* @__PURE__ */ jsx15(OptionLine, { label, children: /* @__PURE__ */ jsx15(Switch2, { "aria-label": label, checked: on, disabled: last, onCheckedChange: (v) => setPassword({ [key]: v }) }) }, key);
|
|
2980
3017
|
}),
|
|
2981
|
-
/* @__PURE__ */
|
|
3018
|
+
/* @__PURE__ */ jsx15(OptionLine, { label: "Avoid look-alikes", hint: "No 0/O, 1/l/I", children: /* @__PURE__ */ jsx15(Switch2, { "aria-label": "Avoid look-alikes", checked: settings.password.excludeAmbiguous, onCheckedChange: (v) => setPassword({ excludeAmbiguous: v }) }) })
|
|
2982
3019
|
] }) : /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-0.5", children: [
|
|
2983
|
-
/* @__PURE__ */
|
|
2984
|
-
/* @__PURE__ */
|
|
2985
|
-
/* @__PURE__ */
|
|
2986
|
-
/* @__PURE__ */
|
|
3020
|
+
/* @__PURE__ */ jsx15(OptionLine, { label: "Words", children: /* @__PURE__ */ jsx15(NumberStepper, { value: settings.passphrase.wordCount, min: MIN_PASSPHRASE_WORDS, max: ceilings.maxPassphraseWords, fallback: MIN_PASSPHRASE_WORDS, onChange: (wordCount) => change({ ...settings, passphrase: { ...settings.passphrase, wordCount } }) }) }),
|
|
3021
|
+
/* @__PURE__ */ jsx15(OptionLine, { label: "Separator", children: /* @__PURE__ */ jsx15(Select4, { "aria-label": "Separator", variant: "inline", align: "end", value: settings.passphrase.separator, options: SEPARATORS, onValueChange: (separator) => change({ ...settings, passphrase: { ...settings.passphrase, separator } }) }) }),
|
|
3022
|
+
/* @__PURE__ */ jsx15(OptionLine, { label: "Capitalize", children: /* @__PURE__ */ jsx15(Switch2, { "aria-label": "Capitalize", checked: settings.passphrase.capitalize, onCheckedChange: (capitalize) => change({ ...settings, passphrase: { ...settings.passphrase, capitalize } }) }) }),
|
|
3023
|
+
/* @__PURE__ */ jsx15(OptionLine, { label: "Add a digit", children: /* @__PURE__ */ jsx15(Switch2, { "aria-label": "Add a digit", checked: settings.passphrase.appendDigit, onCheckedChange: (appendDigit) => change({ ...settings, passphrase: { ...settings.passphrase, appendDigit } }) }) })
|
|
2987
3024
|
] }),
|
|
2988
|
-
note ? /* @__PURE__ */
|
|
2989
|
-
/* @__PURE__ */
|
|
3025
|
+
note ? /* @__PURE__ */ jsx15("p", { "aria-live": "polite", className: cn8("text-xs", note.tone === "destructive" ? "text-destructive" : note.tone === "success" ? "text-success" : "text-muted-foreground"), children: note.text }) : null,
|
|
3026
|
+
/* @__PURE__ */ jsx15(Button11, { variant: "primary", disabled: !candidate, onClick: use, children: useLabel })
|
|
2990
3027
|
] });
|
|
2991
3028
|
}
|
|
2992
|
-
function OptionLine({ label, hint, children }) {
|
|
3029
|
+
function OptionLine({ label, hint: hint2, children }) {
|
|
2993
3030
|
return /* @__PURE__ */ jsxs14("div", { className: "flex min-h-9 items-center justify-between gap-3", children: [
|
|
2994
3031
|
/* @__PURE__ */ jsxs14("div", { className: "flex min-w-0 flex-col", children: [
|
|
2995
|
-
/* @__PURE__ */
|
|
2996
|
-
|
|
3032
|
+
/* @__PURE__ */ jsx15("span", { className: "truncate text-sm text-foreground", children: label }),
|
|
3033
|
+
hint2 ? /* @__PURE__ */ jsx15("span", { className: "truncate text-xs text-muted-foreground", children: hint2 }) : null
|
|
2997
3034
|
] }),
|
|
2998
|
-
/* @__PURE__ */
|
|
3035
|
+
/* @__PURE__ */ jsx15("div", { className: "flex shrink-0 items-center", children })
|
|
2999
3036
|
] });
|
|
3000
3037
|
}
|
|
3001
3038
|
function GenerateButton({ onUse, label, limits, disabled }) {
|
|
@@ -3005,8 +3042,8 @@ function GenerateButton({ onUse, label, limits, disabled }) {
|
|
|
3005
3042
|
if (!source) return null;
|
|
3006
3043
|
const name = label ?? "Generate password";
|
|
3007
3044
|
return /* @__PURE__ */ jsxs14(Popover, { open, onOpenChange: setOpen, children: [
|
|
3008
|
-
/* @__PURE__ */
|
|
3009
|
-
/* @__PURE__ */
|
|
3045
|
+
/* @__PURE__ */ jsx15(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx15(Button11, { variant: "quiet", icon: /* @__PURE__ */ jsx15(KeyGlyph, {}), "aria-label": name, title: name, disabled }) }),
|
|
3046
|
+
/* @__PURE__ */ jsx15(PopoverContent, { sizing: "content", align: "end", children: open ? /* @__PURE__ */ jsx15(
|
|
3010
3047
|
PasswordGenerator,
|
|
3011
3048
|
{
|
|
3012
3049
|
limits: source,
|
|
@@ -3178,13 +3215,13 @@ function startNewRestoreRun(preview) {
|
|
|
3178
3215
|
import { useState as useState16 } from "react";
|
|
3179
3216
|
import { Checkbox } from "@ai-matrx/design-system";
|
|
3180
3217
|
import { Badge as Badge4, Button as Button12, DisclosureHeader as DisclosureHeader2 } from "@ai-matrx/design-system/controls";
|
|
3181
|
-
import { Fragment as Fragment9, jsx as
|
|
3218
|
+
import { Fragment as Fragment9, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3182
3219
|
function PickLine({ checked, onChange, disabled = false, title, detail, badge, tone }) {
|
|
3183
3220
|
return /* @__PURE__ */ jsxs15("label", { className: "flex min-h-11 items-center gap-3 px-4 py-1", "data-clickable": disabled ? void 0 : "", children: [
|
|
3184
|
-
/* @__PURE__ */
|
|
3185
|
-
/* @__PURE__ */
|
|
3186
|
-
detail ? /* @__PURE__ */
|
|
3187
|
-
badge ? /* @__PURE__ */
|
|
3221
|
+
/* @__PURE__ */ jsx16(Checkbox, { checked, disabled, onCheckedChange: (v) => onChange(v === true), "aria-label": title }),
|
|
3222
|
+
/* @__PURE__ */ jsx16("span", { className: "min-w-0 flex-1 truncate text-sm text-foreground", children: title }),
|
|
3223
|
+
detail ? /* @__PURE__ */ jsx16("span", { className: "hidden min-w-0 max-w-[45%] truncate text-xs text-muted-foreground sm:block", children: detail }) : null,
|
|
3224
|
+
badge ? /* @__PURE__ */ jsx16(Badge4, { tone: tone ?? "neutral", children: badge }) : null
|
|
3188
3225
|
] });
|
|
3189
3226
|
}
|
|
3190
3227
|
function Windowed({ items, size = 150, render }) {
|
|
@@ -3192,7 +3229,7 @@ function Windowed({ items, size = 150, render }) {
|
|
|
3192
3229
|
const shown = all ? items : items.slice(0, size);
|
|
3193
3230
|
return /* @__PURE__ */ jsxs15(Fragment9, { children: [
|
|
3194
3231
|
shown.map(render),
|
|
3195
|
-
items.length > shown.length ? /* @__PURE__ */
|
|
3232
|
+
items.length > shown.length ? /* @__PURE__ */ jsx16("div", { className: "px-4 py-2", children: /* @__PURE__ */ jsxs15(Button12, { variant: "quiet", onClick: () => setAll(true), children: [
|
|
3196
3233
|
"Show all ",
|
|
3197
3234
|
items.length
|
|
3198
3235
|
] }) }) : null
|
|
@@ -3201,17 +3238,17 @@ function Windowed({ items, size = 150, render }) {
|
|
|
3201
3238
|
function More({ title = "More", children }) {
|
|
3202
3239
|
const [open, setOpen] = useState16(false);
|
|
3203
3240
|
return /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-2", children: [
|
|
3204
|
-
/* @__PURE__ */
|
|
3241
|
+
/* @__PURE__ */ jsx16(DisclosureHeader2, { open, title, onClick: () => setOpen((o) => !o) }),
|
|
3205
3242
|
open ? children : null
|
|
3206
3243
|
] });
|
|
3207
3244
|
}
|
|
3208
3245
|
function ErrorLine({ message: message2 }) {
|
|
3209
|
-
return message2 ? /* @__PURE__ */
|
|
3246
|
+
return message2 ? /* @__PURE__ */ jsx16("p", { role: "alert", className: "px-1 text-sm text-destructive", children: message2 }) : null;
|
|
3210
3247
|
}
|
|
3211
3248
|
var plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
|
|
3212
3249
|
|
|
3213
3250
|
// src/io/BackupPanel.tsx
|
|
3214
|
-
import { Fragment as Fragment10, jsx as
|
|
3251
|
+
import { Fragment as Fragment10, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
3215
3252
|
var RECORD_STATUS = {
|
|
3216
3253
|
created: "Restored",
|
|
3217
3254
|
replayed: "Already restored",
|
|
@@ -3224,16 +3261,16 @@ function omissionText(o) {
|
|
|
3224
3261
|
}
|
|
3225
3262
|
function Summary({ value }) {
|
|
3226
3263
|
return /* @__PURE__ */ jsxs16(VaultSection, { children: [
|
|
3227
|
-
/* @__PURE__ */
|
|
3228
|
-
/* @__PURE__ */
|
|
3229
|
-
/* @__PURE__ */
|
|
3264
|
+
/* @__PURE__ */ jsx17(VaultRow, { label: "Credentials", children: value.record_count }),
|
|
3265
|
+
/* @__PURE__ */ jsx17(VaultRow, { label: "Protected fields", children: value.field_count }),
|
|
3266
|
+
/* @__PURE__ */ jsx17(VaultRow, { label: "Files", children: value.attachment_count > 0 ? `${value.attachment_count} \xB7 ${formatFileSize(value.attachment_bytes)}` : "0" })
|
|
3230
3267
|
] });
|
|
3231
3268
|
}
|
|
3232
3269
|
function Omissions({ omissions, accepted, onAccepted, verb }) {
|
|
3233
3270
|
if (omissions.length === 0) return null;
|
|
3234
3271
|
return /* @__PURE__ */ jsxs16(VaultSection, { title: "Left out", children: [
|
|
3235
|
-
omissions.map((o, i) => /* @__PURE__ */
|
|
3236
|
-
/* @__PURE__ */
|
|
3272
|
+
omissions.map((o, i) => /* @__PURE__ */ jsx17(VaultRow, { label: o.component.replaceAll("_", " "), children: /* @__PURE__ */ jsx17("span", { className: "block truncate text-muted-foreground", title: omissionText(o), children: omissionText(o) }) }, `${o.component}-${o.source_item_id ?? i}`)),
|
|
3273
|
+
/* @__PURE__ */ jsx17(VaultRow, { label: "Accept", hint: `${verb} without these`, children: /* @__PURE__ */ jsx17(Switch3, { checked: accepted, onCheckedChange: onAccepted, "aria-label": `${verb} without these` }) })
|
|
3237
3274
|
] });
|
|
3238
3275
|
}
|
|
3239
3276
|
function BackupPanel({ port, items, onClose, onChanged }) {
|
|
@@ -3340,20 +3377,20 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3340
3377
|
const mismatch = repeat !== "" && repeat !== passphrase;
|
|
3341
3378
|
const names = new Map(restorePreview?.records.map((r) => [r.source_item_id, r.display_name]) ?? []);
|
|
3342
3379
|
const footer = mode === "backup" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3343
|
-
/* @__PURE__ */
|
|
3344
|
-
backup ? /* @__PURE__ */
|
|
3380
|
+
/* @__PURE__ */ jsx17(Button13, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
3381
|
+
backup ? /* @__PURE__ */ jsx17(Button13, { variant: "primary", disabled: busy || !passphrase || passphrase !== repeat || backup.omissions.length > 0 && !accepted, onClick: () => void downloadBackup(), children: "Encrypt and download" }) : /* @__PURE__ */ jsxs16(Button13, { variant: "primary", disabled: busy || selected.size === 0, onClick: () => void reviewBackup(), children: [
|
|
3345
3382
|
"Review ",
|
|
3346
3383
|
selected.size
|
|
3347
3384
|
] })
|
|
3348
3385
|
] }) : /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3349
|
-
/* @__PURE__ */
|
|
3350
|
-
result ? retryable ? /* @__PURE__ */
|
|
3386
|
+
/* @__PURE__ */ jsx17(Button13, { variant: "quiet", onClick: onClose, children: result && !retryable ? "Done" : "Close" }),
|
|
3387
|
+
result ? retryable ? /* @__PURE__ */ jsx17(Button13, { variant: "primary", disabled: busy, onClick: () => void restore(), children: "Try again" }) : /* @__PURE__ */ jsx17(Button13, { variant: "outline", disabled: busy, onClick: () => void again(), children: "Restore again" }) : restorePreview ? /* @__PURE__ */ jsxs16(Button13, { variant: "primary", disabled: busy || restorePreview.omissions.length > 0 && !accepted, onClick: () => void restore(), children: [
|
|
3351
3388
|
"Restore ",
|
|
3352
3389
|
restorePreview.record_count
|
|
3353
|
-
] }) : /* @__PURE__ */
|
|
3390
|
+
] }) : /* @__PURE__ */ jsx17(Button13, { variant: "primary", disabled: busy || !file || !passphrase, onClick: () => void reviewRestore(), children: "Review" })
|
|
3354
3391
|
] });
|
|
3355
3392
|
return /* @__PURE__ */ jsxs16(Panel, { title: "Backup", size: "lg", onClose, footer, children: [
|
|
3356
|
-
/* @__PURE__ */
|
|
3393
|
+
/* @__PURE__ */ jsx17(
|
|
3357
3394
|
SegmentedControl3,
|
|
3358
3395
|
{
|
|
3359
3396
|
value: mode,
|
|
@@ -3367,35 +3404,35 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3367
3404
|
}
|
|
3368
3405
|
),
|
|
3369
3406
|
mode === "backup" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3370
|
-
/* @__PURE__ */
|
|
3407
|
+
/* @__PURE__ */ jsx17(
|
|
3371
3408
|
VaultSection,
|
|
3372
3409
|
{
|
|
3373
3410
|
title: `${selected.size} of ${plural(items.length, "credential")}`,
|
|
3374
3411
|
actions: /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3375
|
-
/* @__PURE__ */
|
|
3412
|
+
/* @__PURE__ */ jsx17(Button13, { variant: "quiet", disabled: busy || items.length === 0, onClick: () => {
|
|
3376
3413
|
setBackup(null);
|
|
3377
3414
|
setSelected(new Set(items.map((i) => i.id)));
|
|
3378
3415
|
}, children: "All" }),
|
|
3379
|
-
/* @__PURE__ */
|
|
3416
|
+
/* @__PURE__ */ jsx17(Button13, { variant: "quiet", disabled: busy || selected.size === 0, onClick: () => {
|
|
3380
3417
|
setBackup(null);
|
|
3381
3418
|
setSelected(/* @__PURE__ */ new Set());
|
|
3382
3419
|
}, children: "None" })
|
|
3383
3420
|
] }),
|
|
3384
|
-
children: items.length === 0 ? /* @__PURE__ */
|
|
3421
|
+
children: items.length === 0 ? /* @__PURE__ */ jsx17(Empty, { children: "Nothing to back up yet." }) : /* @__PURE__ */ jsx17(Windowed, { items, render: (i) => /* @__PURE__ */ jsx17(PickLine, { title: i.name, detail: i.definitionLabel, checked: selected.has(i.id), disabled: busy, onChange: (on) => pick(i.id, on) }, i.id) })
|
|
3385
3422
|
}
|
|
3386
3423
|
),
|
|
3387
3424
|
backup ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3388
|
-
/* @__PURE__ */
|
|
3389
|
-
/* @__PURE__ */
|
|
3425
|
+
/* @__PURE__ */ jsx17(Summary, { value: backup }),
|
|
3426
|
+
/* @__PURE__ */ jsx17(Omissions, { omissions: backup.omissions, accepted, onAccepted: setAccepted, verb: "Back up" }),
|
|
3390
3427
|
/* @__PURE__ */ jsxs16(VaultSection, { children: [
|
|
3391
|
-
/* @__PURE__ */
|
|
3392
|
-
/* @__PURE__ */
|
|
3428
|
+
/* @__PURE__ */ jsx17(VaultRow, { label: "Passphrase", hint: "Not saved. It can't be recovered.", children: /* @__PURE__ */ jsx17(Field6, { type: "password", value: passphrase, autoComplete: "new-password", "aria-label": "Backup passphrase", onChange: (e) => setPassphrase(e.target.value) }) }),
|
|
3429
|
+
/* @__PURE__ */ jsx17(VaultRow, { label: "Repeat", ...mismatch ? { hint: "Doesn't match" } : {}, children: /* @__PURE__ */ jsx17(Field6, { type: "password", value: repeat, autoComplete: "new-password", "aria-label": "Repeat the passphrase", onChange: (e) => setRepeat(e.target.value) }) })
|
|
3393
3430
|
] })
|
|
3394
3431
|
] }) : null
|
|
3395
|
-
] }) : /* @__PURE__ */
|
|
3432
|
+
] }) : /* @__PURE__ */ jsx17(Fragment10, { children: !restorePreview ? /* @__PURE__ */ jsxs16(VaultSection, { children: [
|
|
3396
3433
|
/* @__PURE__ */ jsxs16(VaultRow, { label: "File", ...file ? { hint: file.name } : {}, children: [
|
|
3397
|
-
/* @__PURE__ */
|
|
3398
|
-
/* @__PURE__ */
|
|
3434
|
+
/* @__PURE__ */ jsx17(Button13, { variant: "outline", disabled: busy, onClick: () => fileInput.current?.click(), children: "Choose a backup" }),
|
|
3435
|
+
/* @__PURE__ */ jsx17(
|
|
3399
3436
|
"input",
|
|
3400
3437
|
{
|
|
3401
3438
|
ref: fileInput,
|
|
@@ -3409,16 +3446,16 @@ function BackupPanel({ port, items, onClose, onChanged }) {
|
|
|
3409
3446
|
}
|
|
3410
3447
|
)
|
|
3411
3448
|
] }),
|
|
3412
|
-
/* @__PURE__ */
|
|
3449
|
+
/* @__PURE__ */ jsx17(VaultRow, { label: "Passphrase", children: /* @__PURE__ */ jsx17(Field6, { type: "password", value: passphrase, autoComplete: "current-password", "aria-label": "Backup passphrase", onChange: (e) => setPassphrase(e.target.value) }) })
|
|
3413
3450
|
] }) : /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
3414
|
-
/* @__PURE__ */
|
|
3415
|
-
!result ? /* @__PURE__ */
|
|
3416
|
-
!result ? /* @__PURE__ */
|
|
3451
|
+
/* @__PURE__ */ jsx17(Summary, { value: restorePreview }),
|
|
3452
|
+
!result ? /* @__PURE__ */ jsx17(Omissions, { omissions: restorePreview.omissions, accepted, onAccepted: setAccepted, verb: "Restore" }) : null,
|
|
3453
|
+
!result ? /* @__PURE__ */ jsx17("p", { className: "px-1 text-xs text-muted-foreground", children: "Restored items start disabled and restricted." }) : /* @__PURE__ */ jsx17(VaultSection, { title: `${result.created} restored \xB7 ${result.replayed} already \xB7 ${result.refused} refused \xB7 ${result.retryable_failure} to retry`, children: result.results.map((r) => /* @__PURE__ */ jsx17(VaultRow, { label: names.get(r.source_item_id) ?? "Credential", children: /* @__PURE__ */ jsxs16("span", { className: r.status === "refused" || r.status === "retryable_failure" ? "text-destructive" : "text-foreground", children: [
|
|
3417
3454
|
RECORD_STATUS[r.status],
|
|
3418
3455
|
r.reason === "alias_conflict" ? " \xB7 name in use" : ""
|
|
3419
3456
|
] }) }, r.source_item_id)) })
|
|
3420
3457
|
] }) }),
|
|
3421
|
-
/* @__PURE__ */
|
|
3458
|
+
/* @__PURE__ */ jsx17(ErrorLine, { message: error })
|
|
3422
3459
|
] });
|
|
3423
3460
|
}
|
|
3424
3461
|
|
|
@@ -3427,7 +3464,7 @@ import { useMemo, useState as useState18 } from "react";
|
|
|
3427
3464
|
import { Button as Button14, Select as Select5 } from "@ai-matrx/design-system/controls";
|
|
3428
3465
|
import { downloadFile as downloadFile2 } from "@ai-matrx/kit/download";
|
|
3429
3466
|
import { confirm as confirm5 } from "@ai-matrx/kit/confirm-opener";
|
|
3430
|
-
import { Fragment as Fragment11, jsx as
|
|
3467
|
+
import { Fragment as Fragment11, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
3431
3468
|
var FORMATS = [
|
|
3432
3469
|
{ value: "matrx_login_csv_v1", label: "Matrx", hint: "Website logins, all common fields" },
|
|
3433
3470
|
{ value: "firefox_csv_v1", label: "Firefox", hint: "Address, username and password" },
|
|
@@ -3508,8 +3545,8 @@ function ExportPanel({ port, items, onClose }) {
|
|
|
3508
3545
|
size: "lg",
|
|
3509
3546
|
onClose,
|
|
3510
3547
|
footer: /* @__PURE__ */ jsxs17(Fragment11, { children: [
|
|
3511
|
-
/* @__PURE__ */
|
|
3512
|
-
preview ? /* @__PURE__ */ jsxs17(Button14, { variant: "primary", icon: /* @__PURE__ */
|
|
3548
|
+
/* @__PURE__ */ jsx18(Button14, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
3549
|
+
preview ? /* @__PURE__ */ jsxs17(Button14, { variant: "primary", icon: /* @__PURE__ */ jsx18(ExportGlyph, { className: "size-4" }), disabled: busy || eligible === 0, onClick: () => void download(), children: [
|
|
3513
3550
|
"Download ",
|
|
3514
3551
|
eligible
|
|
3515
3552
|
] }) : /* @__PURE__ */ jsxs17(Button14, { variant: "primary", disabled: busy || selected.size === 0, onClick: () => void review(), children: [
|
|
@@ -3518,7 +3555,7 @@ function ExportPanel({ port, items, onClose }) {
|
|
|
3518
3555
|
] })
|
|
3519
3556
|
] }),
|
|
3520
3557
|
children: [
|
|
3521
|
-
/* @__PURE__ */
|
|
3558
|
+
/* @__PURE__ */ jsx18(VaultSection, { children: /* @__PURE__ */ jsx18(VaultRow, { label: "Format", hint: format?.hint, children: /* @__PURE__ */ jsx18(
|
|
3522
3559
|
Select5,
|
|
3523
3560
|
{
|
|
3524
3561
|
value: profile,
|
|
@@ -3530,21 +3567,21 @@ function ExportPanel({ port, items, onClose }) {
|
|
|
3530
3567
|
}
|
|
3531
3568
|
}
|
|
3532
3569
|
) }) }),
|
|
3533
|
-
/* @__PURE__ */
|
|
3570
|
+
/* @__PURE__ */ jsx18(
|
|
3534
3571
|
VaultSection,
|
|
3535
3572
|
{
|
|
3536
3573
|
title: `${selected.size} of ${plural(logins.length, "login")}`,
|
|
3537
3574
|
actions: /* @__PURE__ */ jsxs17(Fragment11, { children: [
|
|
3538
|
-
/* @__PURE__ */
|
|
3575
|
+
/* @__PURE__ */ jsx18(Button14, { variant: "quiet", disabled: busy || logins.length === 0, onClick: () => {
|
|
3539
3576
|
changed();
|
|
3540
3577
|
setSelected(new Set(logins.map((l) => l.id)));
|
|
3541
3578
|
}, children: "All" }),
|
|
3542
|
-
/* @__PURE__ */
|
|
3579
|
+
/* @__PURE__ */ jsx18(Button14, { variant: "quiet", disabled: busy || selected.size === 0, onClick: () => {
|
|
3543
3580
|
changed();
|
|
3544
3581
|
setSelected(/* @__PURE__ */ new Set());
|
|
3545
3582
|
}, children: "None" })
|
|
3546
3583
|
] }),
|
|
3547
|
-
children: logins.length === 0 ? /* @__PURE__ */
|
|
3584
|
+
children: logins.length === 0 ? /* @__PURE__ */ jsx18(Empty, { children: "No website logins to export." }) : /* @__PURE__ */ jsx18(
|
|
3548
3585
|
Windowed,
|
|
3549
3586
|
{
|
|
3550
3587
|
items: logins,
|
|
@@ -3552,7 +3589,7 @@ function ExportPanel({ port, items, onClose }) {
|
|
|
3552
3589
|
const p = reasons.get(item.id);
|
|
3553
3590
|
const left = p && !p.eligible;
|
|
3554
3591
|
const omitted = p ? omissionText2(p.omissions) : "";
|
|
3555
|
-
return /* @__PURE__ */
|
|
3592
|
+
return /* @__PURE__ */ jsx18(
|
|
3556
3593
|
PickLine,
|
|
3557
3594
|
{
|
|
3558
3595
|
title: item.name,
|
|
@@ -3570,7 +3607,7 @@ function ExportPanel({ port, items, onClose }) {
|
|
|
3570
3607
|
)
|
|
3571
3608
|
}
|
|
3572
3609
|
),
|
|
3573
|
-
/* @__PURE__ */
|
|
3610
|
+
/* @__PURE__ */ jsx18(ErrorLine, { message: error })
|
|
3574
3611
|
]
|
|
3575
3612
|
}
|
|
3576
3613
|
);
|
|
@@ -4416,7 +4453,7 @@ async function parseImportFile(source, file, limits, signal) {
|
|
|
4416
4453
|
}
|
|
4417
4454
|
|
|
4418
4455
|
// src/io/ImportPanel.tsx
|
|
4419
|
-
import { Fragment as Fragment12, jsx as
|
|
4456
|
+
import { Fragment as Fragment12, jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
4420
4457
|
var ROLE_OPTIONS = [
|
|
4421
4458
|
{ value: "keep", label: "Keep encrypted" },
|
|
4422
4459
|
{ value: "title", label: "Name" },
|
|
@@ -4592,25 +4629,25 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
|
|
|
4592
4629
|
const stage = done ? "done" : draft ? "review" : "choose";
|
|
4593
4630
|
const busy = running !== null || reading;
|
|
4594
4631
|
const footer = stage === "choose" ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4595
|
-
/* @__PURE__ */
|
|
4596
|
-
source === "env" ? /* @__PURE__ */
|
|
4632
|
+
/* @__PURE__ */ jsx19(Button15, { variant: "quiet", onClick: onClose, children: "Close" }),
|
|
4633
|
+
source === "env" ? /* @__PURE__ */ jsx19(Button15, { variant: "primary", icon: /* @__PURE__ */ jsx19(ImportGlyph, { className: "size-4" }), disabled: !envText.trim(), onClick: () => reviewEnv(envText), children: "Review" }) : null
|
|
4597
4634
|
] }) : stage === "review" ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4598
|
-
running ? /* @__PURE__ */
|
|
4599
|
-
/* @__PURE__ */
|
|
4635
|
+
running ? /* @__PURE__ */ jsx19(Button15, { variant: "outline", onClick: () => stop.current = true, children: "Stop" }) : /* @__PURE__ */ jsx19(Button15, { variant: "quiet", onClick: reset, children: "Back" }),
|
|
4636
|
+
/* @__PURE__ */ jsx19(Button15, { variant: "primary", icon: /* @__PURE__ */ jsx19(ImportGlyph, { className: "size-4" }), disabled: busy || chosen === 0 || ambiguous === true || needsApproval, onClick: start, children: running ? `Importing ${running.done} of ${running.total}` : `Import ${chosen}` })
|
|
4600
4637
|
] }) : /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4601
|
-
done && done.failed.length + done.untried.length > 0 ? /* @__PURE__ */
|
|
4602
|
-
/* @__PURE__ */
|
|
4638
|
+
done && done.failed.length + done.untried.length > 0 ? /* @__PURE__ */ jsx19(Button15, { variant: "outline", disabled: busy, onClick: retry, children: running ? `Importing ${running.done} of ${running.total}` : `Try ${done.failed.length + done.untried.length} again` }) : null,
|
|
4639
|
+
/* @__PURE__ */ jsx19(Button15, { variant: "primary", onClick: onClose, children: "Done" })
|
|
4603
4640
|
] });
|
|
4604
4641
|
return /* @__PURE__ */ jsxs18(Panel, { title: "Import", size: "xl", onClose, footer, children: [
|
|
4605
4642
|
stage === "choose" ? /* @__PURE__ */ jsxs18(VaultSection, { children: [
|
|
4606
|
-
/* @__PURE__ */
|
|
4643
|
+
/* @__PURE__ */ jsx19(VaultRow, { label: "Source", actions: help && host.openUrl ? /* @__PURE__ */ jsx19(Button15, { variant: "quiet", onClick: () => host.openUrl?.(help), children: "How to export" }) : void 0, children: /* @__PURE__ */ jsx19(Select6, { value: source, options: SOURCE_OPTIONS, "aria-label": "Source", onValueChange: (s) => {
|
|
4607
4644
|
setSource(s);
|
|
4608
4645
|
setError(null);
|
|
4609
4646
|
} }) }),
|
|
4610
|
-
source === "env" ? /* @__PURE__ */
|
|
4647
|
+
source === "env" ? /* @__PURE__ */ jsx19(VaultRow, { label: ".env text", hint: "Same key updates in place", top: true, children: /* @__PURE__ */ jsx19(Textarea2, { mono: true, rows: 7, value: envText, autoComplete: "off", spellCheck: false, "aria-label": ".env text", placeholder: "OPENAI_API_KEY=sk-...\nDATABASE_URL=postgres://...", onChange: (e) => setEnvText(e.target.value) }) }) : null,
|
|
4611
4648
|
/* @__PURE__ */ jsxs18(VaultRow, { label: "File", hint: fileName ?? void 0, children: [
|
|
4612
|
-
/* @__PURE__ */
|
|
4613
|
-
/* @__PURE__ */
|
|
4649
|
+
/* @__PURE__ */ jsx19(Button15, { variant: "outline", disabled: reading, onClick: () => fileInput.current?.click(), children: reading ? "Reading\u2026" : source === "env" ? "Load a file" : "Choose a file" }),
|
|
4650
|
+
/* @__PURE__ */ jsx19(
|
|
4614
4651
|
"input",
|
|
4615
4652
|
{
|
|
4616
4653
|
ref: fileInput,
|
|
@@ -4625,44 +4662,44 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
|
|
|
4625
4662
|
}
|
|
4626
4663
|
)
|
|
4627
4664
|
] }),
|
|
4628
|
-
source === "env" ? /* @__PURE__ */
|
|
4665
|
+
source === "env" ? /* @__PURE__ */ jsx19(VaultRow, { label: "Sandboxes", hint: "Pass these values to agent sandboxes", children: /* @__PURE__ */ jsx19(Switch4, { checked: injectSandbox, onCheckedChange: setInjectSandbox, "aria-label": "Use in sandboxes" }) }) : null
|
|
4629
4666
|
] }) : null,
|
|
4630
4667
|
stage === "review" && draft ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4631
|
-
organizations.length > 0 ? /* @__PURE__ */
|
|
4632
|
-
/* @__PURE__ */
|
|
4668
|
+
organizations.length > 0 ? /* @__PURE__ */ jsx19(VaultSection, { children: /* @__PURE__ */ jsx19(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx19(Select6, { value: destination, options: destinationOptions, "aria-label": "Save to", onValueChange: (v) => draft.kind === "file" ? restart({ destination: v }) : setDestination(v) }) }) }) : null,
|
|
4669
|
+
/* @__PURE__ */ jsx19(
|
|
4633
4670
|
VaultSection,
|
|
4634
4671
|
{
|
|
4635
4672
|
title: draft.kind === "env" ? plural(envKeys.length, "value") : summary(counts, lines.length),
|
|
4636
4673
|
actions: /* @__PURE__ */ jsxs18(Fragment12, { children: [
|
|
4637
|
-
/* @__PURE__ */
|
|
4638
|
-
/* @__PURE__ */
|
|
4674
|
+
/* @__PURE__ */ jsx19(Button15, { variant: "quiet", disabled: busy, onClick: () => setSelected(draft.kind === "env" ? new Set(envKeys.map((e) => e.key + e.text)) : defaultSelection(lines)), children: "Reset" }),
|
|
4675
|
+
/* @__PURE__ */ jsx19(Button15, { variant: "quiet", disabled: busy, onClick: () => setSelected(/* @__PURE__ */ new Set()), children: "None" })
|
|
4639
4676
|
] }),
|
|
4640
|
-
children: draft.kind === "env" ? /* @__PURE__ */
|
|
4677
|
+
children: draft.kind === "env" ? /* @__PURE__ */ jsx19(
|
|
4641
4678
|
Windowed,
|
|
4642
4679
|
{
|
|
4643
4680
|
items: envKeys,
|
|
4644
4681
|
render: (e) => {
|
|
4645
4682
|
const id = e.key + e.text;
|
|
4646
|
-
return /* @__PURE__ */
|
|
4683
|
+
return /* @__PURE__ */ jsx19(PickLine, { title: e.key, detail: "Value hidden", checked: selected.has(id), disabled: busy, onChange: (on) => toggle(setSelected, id, on) }, id);
|
|
4647
4684
|
}
|
|
4648
4685
|
}
|
|
4649
|
-
) : lines.length === 0 ? /* @__PURE__ */
|
|
4686
|
+
) : lines.length === 0 ? /* @__PURE__ */ jsx19(Empty, { children: "Nothing to import in this file." }) : /* @__PURE__ */ jsx19(
|
|
4650
4687
|
Windowed,
|
|
4651
4688
|
{
|
|
4652
4689
|
items: lines,
|
|
4653
4690
|
render: (l) => {
|
|
4654
4691
|
const badge = STATE_BADGE[l.state];
|
|
4655
|
-
return /* @__PURE__ */
|
|
4692
|
+
return /* @__PURE__ */ jsx19(PickLine, { title: l.title, detail: l.reason ?? l.detail, checked: selected.has(l.key), disabled: busy || !selectable(l), badge: badge?.text, tone: badge?.tone, onChange: (on) => toggle(setSelected, l.key, on) }, l.key);
|
|
4656
4693
|
}
|
|
4657
4694
|
}
|
|
4658
4695
|
)
|
|
4659
4696
|
}
|
|
4660
4697
|
),
|
|
4661
|
-
draft.kind === "file" && draft.parsed.kind === "structured" ? /* @__PURE__ */
|
|
4662
|
-
draft.kind === "file" ? /* @__PURE__ */
|
|
4663
|
-
draft.kind === "file" ? /* @__PURE__ */
|
|
4664
|
-
/* @__PURE__ */
|
|
4665
|
-
draft.parsed.kind === "csv" ? draft.parsed.preview.headers.map((header, index) => /* @__PURE__ */
|
|
4698
|
+
draft.kind === "file" && draft.parsed.kind === "structured" ? /* @__PURE__ */ jsx19(VaultSection, { children: /* @__PURE__ */ jsx19(VaultRow, { label: "Visible details", hint: "Approve saving websites and public keys in the clear", children: /* @__PURE__ */ jsx19(Switch4, { checked: approvedVisible, disabled: busy, onCheckedChange: setApprovedVisible, "aria-label": "Approve visible details" }) }) }) : null,
|
|
4699
|
+
draft.kind === "file" ? /* @__PURE__ */ jsx19(Notices, { draft }) : null,
|
|
4700
|
+
draft.kind === "file" ? /* @__PURE__ */ jsx19(More, { children: /* @__PURE__ */ jsxs18(VaultSection, { children: [
|
|
4701
|
+
/* @__PURE__ */ jsx19(VaultRow, { label: "Browser fill", hint: "Needs username, password and an https address", children: /* @__PURE__ */ jsx19(Switch4, { checked: browserFill, disabled: busy, onCheckedChange: (on) => restart({ browserFill: on }), "aria-label": "Browser fill" }) }),
|
|
4702
|
+
draft.parsed.kind === "csv" ? draft.parsed.preview.headers.map((header, index) => /* @__PURE__ */ jsx19(VaultRow, { label: header || `Column ${index + 1}`, children: /* @__PURE__ */ jsx19(
|
|
4666
4703
|
Select6,
|
|
4667
4704
|
{
|
|
4668
4705
|
value: draft.mapping[index] ?? "keep",
|
|
@@ -4672,20 +4709,20 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
|
|
|
4672
4709
|
}
|
|
4673
4710
|
) }, `${header}-${index}`)) : null
|
|
4674
4711
|
] }) }) : null,
|
|
4675
|
-
ambiguous ? /* @__PURE__ */
|
|
4712
|
+
ambiguous ? /* @__PURE__ */ jsx19(ErrorLine, { message: "Each of name, username, password, notes and one-time password can be used by one column." }) : null
|
|
4676
4713
|
] }) : null,
|
|
4677
4714
|
stage === "done" && done ? /* @__PURE__ */ jsxs18(VaultSection, { title: "Result", children: [
|
|
4678
|
-
/* @__PURE__ */
|
|
4679
|
-
/* @__PURE__ */
|
|
4680
|
-
/* @__PURE__ */
|
|
4681
|
-
done.untried.length > 0 ? /* @__PURE__ */
|
|
4682
|
-
done.withOtp > 0 ? /* @__PURE__ */
|
|
4715
|
+
/* @__PURE__ */ jsx19(VaultRow, { label: "Created", children: /* @__PURE__ */ jsx19("span", { className: "text-foreground", children: done.created.length }) }),
|
|
4716
|
+
/* @__PURE__ */ jsx19(VaultRow, { label: "Skipped", children: /* @__PURE__ */ jsx19("span", { className: "text-foreground", children: done.skipped }) }),
|
|
4717
|
+
/* @__PURE__ */ jsx19(VaultRow, { label: "Failed", children: /* @__PURE__ */ jsx19("span", { className: done.failed.length > 0 ? "text-destructive" : "text-foreground", children: done.failed.length }) }),
|
|
4718
|
+
done.untried.length > 0 ? /* @__PURE__ */ jsx19(VaultRow, { label: "Not tried", children: /* @__PURE__ */ jsx19("span", { className: "text-foreground", children: done.untried.length }) }) : null,
|
|
4719
|
+
done.withOtp > 0 ? /* @__PURE__ */ jsx19(VaultRow, { label: "Codes", children: /* @__PURE__ */ jsxs18("span", { className: "text-muted-foreground", children: [
|
|
4683
4720
|
plural(done.withOtp, "login"),
|
|
4684
4721
|
" still need the one-time password added."
|
|
4685
4722
|
] }) }) : null,
|
|
4686
|
-
done.failed.map((f) => /* @__PURE__ */
|
|
4723
|
+
done.failed.map((f) => /* @__PURE__ */ jsx19(VaultRow, { label: f.title, children: /* @__PURE__ */ jsx19("span", { className: "block truncate text-destructive", title: f.reason, children: f.reason }) }, f.key))
|
|
4687
4724
|
] }) : null,
|
|
4688
|
-
/* @__PURE__ */
|
|
4725
|
+
/* @__PURE__ */ jsx19(ErrorLine, { message: error })
|
|
4689
4726
|
] });
|
|
4690
4727
|
}
|
|
4691
4728
|
function toggle(set, key, on) {
|
|
@@ -4712,35 +4749,22 @@ function Notices({ draft }) {
|
|
|
4712
4749
|
}
|
|
4713
4750
|
}
|
|
4714
4751
|
if (notes.length === 0) return null;
|
|
4715
|
-
return /* @__PURE__ */
|
|
4752
|
+
return /* @__PURE__ */ jsx19("div", { className: "flex flex-col gap-0.5 px-1 text-xs text-muted-foreground", children: notes.map((n) => /* @__PURE__ */ jsx19("span", { children: n }, n)) });
|
|
4716
4753
|
}
|
|
4717
4754
|
|
|
4718
4755
|
// src/ItemList.tsx
|
|
4719
|
-
import { useEffect as useEffect17, useRef as useRef15, useState as
|
|
4720
|
-
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";
|
|
4721
4758
|
import { cn as cn13 } from "@ai-matrx/design-system";
|
|
4722
|
-
import { Button as
|
|
4723
|
-
|
|
4724
|
-
// src/ItemIcon.tsx
|
|
4725
|
-
import { cn as cn8 } from "@ai-matrx/design-system";
|
|
4726
|
-
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
4727
|
-
function ItemIcon({ definitionKey, family, site, size = "md", inverted = false }) {
|
|
4728
|
-
const box = size === "lg" ? "size-10 rounded-xl text-base" : size === "md" ? "size-8 rounded-lg text-sm" : "size-6 rounded-md text-xs";
|
|
4729
|
-
const tone = inverted ? "bg-primary-foreground text-primary" : "bg-muted text-foreground";
|
|
4730
|
-
const initial = siteDomainOf(site).charAt(0).toUpperCase();
|
|
4731
|
-
if (initial && /[A-Z0-9]/.test(initial)) {
|
|
4732
|
-
return /* @__PURE__ */ jsx19("span", { "aria-hidden": true, className: cn8("flex shrink-0 items-center justify-center font-semibold", box, tone), children: initial });
|
|
4733
|
-
}
|
|
4734
|
-
const Glyph = definitionGlyph(definitionKey, family);
|
|
4735
|
-
return /* @__PURE__ */ jsx19("span", { "aria-hidden": true, className: cn8("flex shrink-0 items-center justify-center", box, tone), children: /* @__PURE__ */ jsx19(Glyph, { className: size === "lg" ? "size-5" : "size-4" }) });
|
|
4736
|
-
}
|
|
4759
|
+
import { Button as Button23, SearchField } from "@ai-matrx/design-system/controls";
|
|
4760
|
+
import { CopyIcon as CopyIcon7 } from "@ai-matrx/design-system/icons";
|
|
4737
4761
|
|
|
4738
4762
|
// src/ItemPane.tsx
|
|
4739
|
-
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";
|
|
4740
4764
|
import { DropdownMenu as DropdownMenu3, DropdownMenuContent as DropdownMenuContent3, DropdownMenuItem as DropdownMenuItem3, DropdownMenuSeparator as DropdownMenuSeparator3, DropdownMenuTrigger as DropdownMenuTrigger3 } from "@ai-matrx/design-system";
|
|
4741
4765
|
import { cn as cn12 } from "@ai-matrx/design-system";
|
|
4742
|
-
import { Badge as Badge7, Button as
|
|
4743
|
-
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";
|
|
4744
4768
|
|
|
4745
4769
|
// src/activity/FilesSection.tsx
|
|
4746
4770
|
import { formatFileSize as formatFileSize2 } from "@ai-matrx/kit/format";
|
|
@@ -4761,12 +4785,13 @@ var PROTECTION = [
|
|
|
4761
4785
|
function FilesSection({ item, port, editing, onChanged }) {
|
|
4762
4786
|
const confirmed = useConfirmed();
|
|
4763
4787
|
const canEdit = editing && item.capabilities.canEdit;
|
|
4788
|
+
const canAdd = item.capabilities.canEdit;
|
|
4764
4789
|
const [busy, setBusy] = useState20(null);
|
|
4765
4790
|
const [error, setError] = useState20(null);
|
|
4766
4791
|
const [pending, setPending] = useState20(null);
|
|
4767
4792
|
const [dragging, setDragging] = useState20(false);
|
|
4768
4793
|
const picker = useRef13(null);
|
|
4769
|
-
if (!
|
|
4794
|
+
if (!canAdd && item.attachments.length === 0) return null;
|
|
4770
4795
|
async function run(key, work, fallback) {
|
|
4771
4796
|
setBusy(key);
|
|
4772
4797
|
setError(null);
|
|
@@ -4788,7 +4813,7 @@ function FilesSection({ item, port, editing, onChanged }) {
|
|
|
4788
4813
|
setPending(file);
|
|
4789
4814
|
}
|
|
4790
4815
|
function drop(e) {
|
|
4791
|
-
if (!
|
|
4816
|
+
if (!canAdd) return;
|
|
4792
4817
|
e.preventDefault();
|
|
4793
4818
|
setDragging(false);
|
|
4794
4819
|
choose(e.dataTransfer.files[0]);
|
|
@@ -4801,22 +4826,23 @@ function FilesSection({ item, port, editing, onChanged }) {
|
|
|
4801
4826
|
"div",
|
|
4802
4827
|
{
|
|
4803
4828
|
className: cn9("rounded-xl", dragging && "outline outline-2 outline-primary"),
|
|
4804
|
-
onDragOver:
|
|
4829
|
+
onDragOver: canAdd ? (e) => {
|
|
4805
4830
|
e.preventDefault();
|
|
4806
4831
|
setDragging(true);
|
|
4807
4832
|
} : void 0,
|
|
4808
|
-
onDragLeave:
|
|
4809
|
-
onDrop:
|
|
4833
|
+
onDragLeave: canAdd ? () => setDragging(false) : void 0,
|
|
4834
|
+
onDrop: canAdd ? drop : void 0,
|
|
4810
4835
|
children: /* @__PURE__ */ jsxs19(
|
|
4811
4836
|
VaultSection,
|
|
4812
4837
|
{
|
|
4813
|
-
title: "Files",
|
|
4814
|
-
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,
|
|
4815
4840
|
children: [
|
|
4816
|
-
|
|
4841
|
+
canAdd ? /* @__PURE__ */ jsx20("input", { ref: picker, type: "file", hidden: true, "aria-label": "Choose a file", onChange: (e) => {
|
|
4817
4842
|
choose(e.target.files?.[0]);
|
|
4818
4843
|
e.target.value = "";
|
|
4819
4844
|
} }) : null,
|
|
4845
|
+
!editing && canAdd && item.attachments.length === 0 && !pending ? /* @__PURE__ */ jsx20(AddRow, { label: "Files", onAdd: () => picker.current?.click(), children: "Add file" }) : null,
|
|
4820
4846
|
item.attachments.map(
|
|
4821
4847
|
(a) => canEdit ? /* @__PURE__ */ jsx20(EditableFile, { port, item, file: a, busy, run, onDownload: () => void download(a), onTooBig: () => setError(TOO_BIG) }, a.id) : /* @__PURE__ */ jsx20(
|
|
4822
4848
|
VaultRow,
|
|
@@ -4829,7 +4855,7 @@ function FilesSection({ item, port, editing, onChanged }) {
|
|
|
4829
4855
|
a.id
|
|
4830
4856
|
)
|
|
4831
4857
|
),
|
|
4832
|
-
|
|
4858
|
+
canAdd && pending ? /* @__PURE__ */ jsx20(NewFile, { file: pending, busy: busy === "add", onCancel: () => setPending(null), onAdd: async (details) => {
|
|
4833
4859
|
if (await run("add", () => port.activity.addFile(item, pending, details), "The file could not be added.")) setPending(null);
|
|
4834
4860
|
} }) : null,
|
|
4835
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,
|
|
@@ -4950,6 +4976,57 @@ function confirmSeal(label) {
|
|
|
4950
4976
|
variant: "destructive"
|
|
4951
4977
|
});
|
|
4952
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
|
+
}
|
|
4953
5030
|
|
|
4954
5031
|
// src/fields/RecoveryCodesRow.tsx
|
|
4955
5032
|
import { useState as useState21 } from "react";
|
|
@@ -5057,6 +5134,134 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
|
|
|
5057
5134
|
);
|
|
5058
5135
|
}
|
|
5059
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
|
+
|
|
5060
5265
|
// src/ItemPane.tsx
|
|
5061
5266
|
import { HistoryIcon, SettingsIcon, UsersIcon as UsersIcon2 } from "@ai-matrx/design-system/icons";
|
|
5062
5267
|
import { dropKeptDraft, keepDraft, readKeptDraft } from "@ai-matrx/kit/drafts";
|
|
@@ -5183,15 +5388,15 @@ function targetLabel(t) {
|
|
|
5183
5388
|
}
|
|
5184
5389
|
|
|
5185
5390
|
// src/extension/UseOnSiteButton.tsx
|
|
5186
|
-
import { useState as
|
|
5187
|
-
import { Button as
|
|
5188
|
-
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";
|
|
5189
5394
|
function canUseOnSite(item, pageUrl) {
|
|
5190
5395
|
return item.capabilities.canEdit && isFillablePage(pageUrl) && !coversPage(item.loginUrls, item.uriMatchMode, pageUrl);
|
|
5191
5396
|
}
|
|
5192
5397
|
function UseOnSiteButton({ port, item, pageUrl, onChanged }) {
|
|
5193
5398
|
const notify = useNotify();
|
|
5194
|
-
const [busy, setBusy] =
|
|
5399
|
+
const [busy, setBusy] = useState23(false);
|
|
5195
5400
|
if (!canUseOnSite(item, pageUrl)) return null;
|
|
5196
5401
|
const site = pageSite(pageUrl);
|
|
5197
5402
|
const run = async () => {
|
|
@@ -5206,13 +5411,13 @@ function UseOnSiteButton({ port, item, pageUrl, onChanged }) {
|
|
|
5206
5411
|
setBusy(false);
|
|
5207
5412
|
}
|
|
5208
5413
|
};
|
|
5209
|
-
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" });
|
|
5210
5415
|
}
|
|
5211
5416
|
|
|
5212
5417
|
// src/sharing/SharePanel.tsx
|
|
5213
|
-
import { useEffect as useEffect15, useState as
|
|
5214
|
-
import { confirm as
|
|
5215
|
-
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";
|
|
5216
5421
|
import { cn as cn11 } from "@ai-matrx/design-system";
|
|
5217
5422
|
import { UsersIcon } from "@ai-matrx/design-system/icons";
|
|
5218
5423
|
|
|
@@ -5268,18 +5473,18 @@ function shareSummary(grants) {
|
|
|
5268
5473
|
var MEMBER_CHOICE_DEFAULT = "default";
|
|
5269
5474
|
|
|
5270
5475
|
// src/sharing/parts.tsx
|
|
5271
|
-
import { useState as
|
|
5476
|
+
import { useState as useState24 } from "react";
|
|
5272
5477
|
import { cn as cn10 } from "@ai-matrx/design-system";
|
|
5273
|
-
import { jsx as
|
|
5478
|
+
import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
5274
5479
|
var message = (e, fallback) => {
|
|
5275
5480
|
const m = e instanceof Error && e.message ? e.message : fallback;
|
|
5276
5481
|
return copyRefusal(m) ?? m;
|
|
5277
5482
|
};
|
|
5278
5483
|
function useConfirmedChange() {
|
|
5279
5484
|
const confirmed = useConfirmed();
|
|
5280
|
-
const [busy, setBusy] =
|
|
5281
|
-
const [error, setError] =
|
|
5282
|
-
const [notice, setNotice] =
|
|
5485
|
+
const [busy, setBusy] = useState24(null);
|
|
5486
|
+
const [error, setError] = useState24(null);
|
|
5487
|
+
const [notice, setNotice] = useState24(null);
|
|
5283
5488
|
async function run(key, fn, done) {
|
|
5284
5489
|
setBusy(key);
|
|
5285
5490
|
setError(null);
|
|
@@ -5298,33 +5503,33 @@ function useConfirmedChange() {
|
|
|
5298
5503
|
return { busy, error, notice, run, setNotice };
|
|
5299
5504
|
}
|
|
5300
5505
|
function AccessLine({ glyph: G, who, meta, children }) {
|
|
5301
|
-
return /* @__PURE__ */
|
|
5302
|
-
/* @__PURE__ */
|
|
5303
|
-
/* @__PURE__ */
|
|
5304
|
-
/* @__PURE__ */
|
|
5305
|
-
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
|
|
5306
5511
|
] }),
|
|
5307
|
-
/* @__PURE__ */
|
|
5512
|
+
/* @__PURE__ */ jsx24("div", { className: "flex shrink-0 items-center gap-0.5", children })
|
|
5308
5513
|
] });
|
|
5309
5514
|
}
|
|
5310
5515
|
function StatusLine({ error, notice }) {
|
|
5311
5516
|
if (!error && !notice) return null;
|
|
5312
|
-
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 });
|
|
5313
5518
|
}
|
|
5314
5519
|
|
|
5315
5520
|
// src/sharing/MovePanel.tsx
|
|
5316
|
-
import { useState as
|
|
5317
|
-
import { confirm as
|
|
5318
|
-
import { Button as
|
|
5319
|
-
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";
|
|
5320
5525
|
var NONE = "__none__";
|
|
5321
5526
|
function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
5322
5527
|
const { busy, error, notice, run, setNotice } = useConfirmedChange();
|
|
5323
5528
|
const moves = moveDestinations(item, organizations);
|
|
5324
5529
|
const copies = copyDestinations(organizations, item);
|
|
5325
|
-
const [moveTo, setMoveTo] =
|
|
5326
|
-
const [copyTo, setCopyTo] =
|
|
5327
|
-
const [email, setEmail] =
|
|
5530
|
+
const [moveTo, setMoveTo] = useState25("");
|
|
5531
|
+
const [copyTo, setCopyTo] = useState25("");
|
|
5532
|
+
const [email, setEmail] = useState25("");
|
|
5328
5533
|
const passkey = isPasskey(item);
|
|
5329
5534
|
const canMove = item.capabilities.canManage && !passkey && moves.length > 0;
|
|
5330
5535
|
const canGive = item.capabilities.canManage && item.owner.kind === "me" && !passkey;
|
|
@@ -5334,7 +5539,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5334
5539
|
const move = async () => {
|
|
5335
5540
|
if (!moveChoice) return;
|
|
5336
5541
|
const to = destinationOf(moveChoice.value);
|
|
5337
|
-
const ok = await
|
|
5542
|
+
const ok = await confirm8({
|
|
5338
5543
|
title: `Move to ${moveChoice.label}?`,
|
|
5339
5544
|
description: `"${item.name}" stays the same item, so everything using it keeps working. ${itemMoveConsequence(item, to)}.`,
|
|
5340
5545
|
confirmLabel: "Move"
|
|
@@ -5349,7 +5554,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5349
5554
|
const give = async () => {
|
|
5350
5555
|
const to = email.trim();
|
|
5351
5556
|
if (!isEmail(to)) return;
|
|
5352
|
-
const ok = await
|
|
5557
|
+
const ok = await confirm8({ title: "Give ownership away?", description: giveDescription(item, to), confirmLabel: "Give ownership", variant: "destructive" });
|
|
5353
5558
|
if (!ok) return;
|
|
5354
5559
|
const out = await run("give", () => port.sharing.giveOwnership(item, to));
|
|
5355
5560
|
if (!out) return;
|
|
@@ -5362,25 +5567,25 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5362
5567
|
if (made) onChanged();
|
|
5363
5568
|
};
|
|
5364
5569
|
const nothing = !canMove && !canGive && !canCopy;
|
|
5365
|
-
return /* @__PURE__ */
|
|
5570
|
+
return /* @__PURE__ */ jsx25(
|
|
5366
5571
|
Panel,
|
|
5367
5572
|
{
|
|
5368
5573
|
title: "Move or copy",
|
|
5369
5574
|
size: "md",
|
|
5370
5575
|
onClose,
|
|
5371
|
-
footer: /* @__PURE__ */
|
|
5372
|
-
children: nothing ? /* @__PURE__ */
|
|
5373
|
-
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(
|
|
5374
5579
|
VaultRow,
|
|
5375
5580
|
{
|
|
5376
5581
|
label: "Move to",
|
|
5377
5582
|
hint: moveChoice ? itemMoveConsequence(item, destinationOf(moveChoice.value)) : void 0,
|
|
5378
|
-
actions: /* @__PURE__ */
|
|
5379
|
-
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] })
|
|
5380
5585
|
}
|
|
5381
5586
|
) : null,
|
|
5382
|
-
canGive ? /* @__PURE__ */
|
|
5383
|
-
|
|
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,
|
|
5384
5589
|
{
|
|
5385
5590
|
className: "w-full",
|
|
5386
5591
|
type: "email",
|
|
@@ -5393,18 +5598,18 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5393
5598
|
onChange: (e) => setEmail(e.target.value)
|
|
5394
5599
|
}
|
|
5395
5600
|
) }) : null,
|
|
5396
|
-
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
|
|
5397
5602
|
] })
|
|
5398
5603
|
}
|
|
5399
5604
|
);
|
|
5400
5605
|
}
|
|
5401
5606
|
|
|
5402
5607
|
// src/sharing/SharePanel.tsx
|
|
5403
|
-
import { Fragment as
|
|
5608
|
+
import { Fragment as Fragment16, jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
5404
5609
|
function useGrants(port, item) {
|
|
5405
|
-
const [grants, setGrants] =
|
|
5406
|
-
const [loadError, setLoadError] =
|
|
5407
|
-
const [nonce, setNonce] =
|
|
5610
|
+
const [grants, setGrants] = useState26(null);
|
|
5611
|
+
const [loadError, setLoadError] = useState26(null);
|
|
5612
|
+
const [nonce, setNonce] = useState26(0);
|
|
5408
5613
|
const allowed = item.capabilities.canManage;
|
|
5409
5614
|
useEffect15(() => {
|
|
5410
5615
|
if (!allowed) return;
|
|
@@ -5423,9 +5628,9 @@ function useGrants(port, item) {
|
|
|
5423
5628
|
function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
5424
5629
|
const { grants, setGrants, loadError, reload } = useGrants(port, item);
|
|
5425
5630
|
const { busy, error, notice, run } = useConfirmedChange();
|
|
5426
|
-
const [email, setEmail] =
|
|
5427
|
-
const [level, setLevel] =
|
|
5428
|
-
const [more, setMore] =
|
|
5631
|
+
const [email, setEmail] = useState26("");
|
|
5632
|
+
const [level, setLevel] = useState26("use");
|
|
5633
|
+
const [more, setMore] = useState26(false);
|
|
5429
5634
|
const isOrg = item.owner.kind === "organization" && item.owner.organizationId !== null;
|
|
5430
5635
|
const orgName = item.owner.label;
|
|
5431
5636
|
const people = (grants ?? []).filter((g) => g.kind === "person");
|
|
@@ -5444,7 +5649,7 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5444
5649
|
if (updated) setGrants((all) => (all ?? []).map((x) => x.id === g.id ? { ...updated, label: updated.label || g.label } : x));
|
|
5445
5650
|
};
|
|
5446
5651
|
const revoke = async (g) => {
|
|
5447
|
-
const ok = await
|
|
5652
|
+
const ok = await confirm9({
|
|
5448
5653
|
title: g.kind === "organization" ? `Remove from ${g.label}?` : "Remove access?",
|
|
5449
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.`,
|
|
5450
5655
|
confirmLabel: "Remove",
|
|
@@ -5460,7 +5665,7 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5460
5665
|
const setMode = async (mode) => {
|
|
5461
5666
|
if (mode === (item.accessMode === "restricted" ? "restricted" : "all_members")) return;
|
|
5462
5667
|
if (mode === "all_members" && people.length > 0) {
|
|
5463
|
-
const ok = await
|
|
5668
|
+
const ok = await confirm9({
|
|
5464
5669
|
title: "Open to every member?",
|
|
5465
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.`,
|
|
5466
5671
|
confirmLabel: "Open to members",
|
|
@@ -5475,20 +5680,20 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5475
5680
|
}
|
|
5476
5681
|
};
|
|
5477
5682
|
if (!item.capabilities.canManage) {
|
|
5478
|
-
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." }) }) });
|
|
5479
5684
|
}
|
|
5480
|
-
return /* @__PURE__ */
|
|
5685
|
+
return /* @__PURE__ */ jsxs24(
|
|
5481
5686
|
Panel,
|
|
5482
5687
|
{
|
|
5483
5688
|
title: "Share",
|
|
5484
5689
|
size: "md",
|
|
5485
5690
|
onClose,
|
|
5486
|
-
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" }) }),
|
|
5487
5692
|
children: [
|
|
5488
|
-
/* @__PURE__ */
|
|
5489
|
-
isOrg ? /* @__PURE__ */
|
|
5490
|
-
isOrg ? /* @__PURE__ */
|
|
5491
|
-
|
|
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,
|
|
5492
5697
|
{
|
|
5493
5698
|
variant: "inline",
|
|
5494
5699
|
align: "end",
|
|
@@ -5502,14 +5707,14 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5502
5707
|
]
|
|
5503
5708
|
}
|
|
5504
5709
|
) }) : null,
|
|
5505
|
-
loadError ? /* @__PURE__ */
|
|
5506
|
-
/* @__PURE__ */
|
|
5507
|
-
/* @__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) })
|
|
5508
5713
|
] }, g.id)),
|
|
5509
|
-
/* @__PURE__ */
|
|
5510
|
-
/* @__PURE__ */
|
|
5511
|
-
/* @__PURE__ */
|
|
5512
|
-
|
|
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,
|
|
5513
5718
|
{
|
|
5514
5719
|
className: "min-w-0 flex-1",
|
|
5515
5720
|
type: "email",
|
|
@@ -5529,13 +5734,13 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5529
5734
|
}
|
|
5530
5735
|
}
|
|
5531
5736
|
),
|
|
5532
|
-
/* @__PURE__ */
|
|
5533
|
-
/* @__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" })
|
|
5534
5739
|
] })
|
|
5535
5740
|
] }),
|
|
5536
|
-
/* @__PURE__ */
|
|
5537
|
-
/* @__PURE__ */
|
|
5538
|
-
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
|
|
5539
5744
|
] })
|
|
5540
5745
|
]
|
|
5541
5746
|
}
|
|
@@ -5544,17 +5749,17 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
|
|
|
5544
5749
|
function IntoOrganization({ item, port, organizations, grants, onShared }) {
|
|
5545
5750
|
const { busy, error, notice, run } = useConfirmedChange();
|
|
5546
5751
|
const open = organizations.filter((o) => !grants.some((g) => g.organizationId === o.id));
|
|
5547
|
-
const [target, setTarget] =
|
|
5548
|
-
const [level, setLevel] =
|
|
5752
|
+
const [target, setTarget] = useState26("");
|
|
5753
|
+
const [level, setLevel] = useState26("use");
|
|
5549
5754
|
const chosen = open.find((o) => o.id === target);
|
|
5550
5755
|
if (item.owner.kind !== "me") return null;
|
|
5551
|
-
return /* @__PURE__ */
|
|
5552
|
-
/* @__PURE__ */
|
|
5553
|
-
/* @__PURE__ */
|
|
5554
|
-
/* @__PURE__ */
|
|
5555
|
-
/* @__PURE__ */
|
|
5556
|
-
/* @__PURE__ */
|
|
5557
|
-
|
|
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,
|
|
5558
5763
|
{
|
|
5559
5764
|
variant: "outline",
|
|
5560
5765
|
disabled: busy !== null || !chosen,
|
|
@@ -5570,8 +5775,8 @@ function IntoOrganization({ item, port, organizations, grants, onShared }) {
|
|
|
5570
5775
|
}
|
|
5571
5776
|
)
|
|
5572
5777
|
] }),
|
|
5573
|
-
/* @__PURE__ */
|
|
5574
|
-
] }) : /* @__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." }) });
|
|
5575
5780
|
}
|
|
5576
5781
|
var CHOICES = [
|
|
5577
5782
|
{ value: MEMBER_CHOICE_DEFAULT, label: "Default" },
|
|
@@ -5580,8 +5785,8 @@ var CHOICES = [
|
|
|
5580
5785
|
{ value: "editor", label: "Can edit", meta: "See and change" }
|
|
5581
5786
|
];
|
|
5582
5787
|
function MemberAccess({ port, organizationId, organizationName }) {
|
|
5583
|
-
const [list, setList] =
|
|
5584
|
-
const [loadError, setLoadError] =
|
|
5788
|
+
const [list, setList] = useState26(null);
|
|
5789
|
+
const [loadError, setLoadError] = useState26(null);
|
|
5585
5790
|
const { busy, error, run } = useConfirmedChange();
|
|
5586
5791
|
useEffect15(() => {
|
|
5587
5792
|
let live = true;
|
|
@@ -5598,9 +5803,9 @@ function MemberAccess({ port, organizationId, organizationName }) {
|
|
|
5598
5803
|
const effective = await run(userId, () => port.sharing.setMemberAccess(organizationId, userId, access));
|
|
5599
5804
|
if (effective) setList((l) => l ? { ...l, members: l.members.map((m) => m.userId === userId ? { ...m, access, effective } : m) } : l);
|
|
5600
5805
|
};
|
|
5601
|
-
return /* @__PURE__ */
|
|
5602
|
-
loadError ? /* @__PURE__ */
|
|
5603
|
-
|
|
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,
|
|
5604
5809
|
{
|
|
5605
5810
|
variant: "inline",
|
|
5606
5811
|
align: "end",
|
|
@@ -5611,11 +5816,11 @@ function MemberAccess({ port, organizationId, organizationName }) {
|
|
|
5611
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 })
|
|
5612
5817
|
}
|
|
5613
5818
|
) }, m.userId)),
|
|
5614
|
-
/* @__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" })
|
|
5615
5820
|
] });
|
|
5616
5821
|
}
|
|
5617
5822
|
function SharingSummary({ item, port, className }) {
|
|
5618
|
-
const [text, setText] =
|
|
5823
|
+
const [text, setText] = useState26("");
|
|
5619
5824
|
const allowed = item.capabilities.canManage;
|
|
5620
5825
|
useEffect15(() => {
|
|
5621
5826
|
if (!allowed) return;
|
|
@@ -5629,12 +5834,12 @@ function SharingSummary({ item, port, className }) {
|
|
|
5629
5834
|
};
|
|
5630
5835
|
}, [port, item, allowed]);
|
|
5631
5836
|
if (!allowed || !text) return null;
|
|
5632
|
-
return /* @__PURE__ */
|
|
5837
|
+
return /* @__PURE__ */ jsx26("span", { className: cn11("truncate text-xs text-muted-foreground", className), children: text });
|
|
5633
5838
|
}
|
|
5634
5839
|
|
|
5635
5840
|
// src/ItemPane.tsx
|
|
5636
5841
|
import { formatAbsoluteDate as formatAbsoluteDate3 } from "@ai-matrx/kit/format";
|
|
5637
|
-
import { Fragment as
|
|
5842
|
+
import { Fragment as Fragment17, jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
5638
5843
|
var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
|
|
5639
5844
|
function ItemPane(props) {
|
|
5640
5845
|
const { port, item, definition, mode, host, organizations, defaultOwner, seed, onBack, onMode, onSaved, onDeleted, onDirty, onCancelNew, onPanel, onChanged, favorite, notice, refreshKey } = props;
|
|
@@ -5643,7 +5848,7 @@ function ItemPane(props) {
|
|
|
5643
5848
|
const editing = mode !== "view";
|
|
5644
5849
|
const seedName = seed?.name ?? "";
|
|
5645
5850
|
const seedUrl = seed?.url ?? "";
|
|
5646
|
-
const [loaded, setLoaded] =
|
|
5851
|
+
const [loaded, setLoaded] = useState27({});
|
|
5647
5852
|
const base = useMemo3(() => {
|
|
5648
5853
|
const b = draftOf(item);
|
|
5649
5854
|
if (!item) {
|
|
@@ -5653,16 +5858,21 @@ function ItemPane(props) {
|
|
|
5653
5858
|
b.values = { ...loaded };
|
|
5654
5859
|
return b;
|
|
5655
5860
|
}, [item, seedName, seedUrl, loaded]);
|
|
5656
|
-
const [draft, setDraft] =
|
|
5657
|
-
const [tagsText, setTagsText] =
|
|
5658
|
-
const [showTags, setShowTags] =
|
|
5659
|
-
const [showDescription, setShowDescription] =
|
|
5660
|
-
const [
|
|
5661
|
-
const [
|
|
5662
|
-
const [
|
|
5663
|
-
const [
|
|
5664
|
-
const [
|
|
5665
|
-
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({});
|
|
5666
5876
|
const dirty = editing && isDirty(base, draft);
|
|
5667
5877
|
const declared = definition?.fields ?? [];
|
|
5668
5878
|
const prev = useRef14(null);
|
|
@@ -5685,6 +5895,7 @@ function ItemPane(props) {
|
|
|
5685
5895
|
setLoaded({});
|
|
5686
5896
|
setShowTags(false);
|
|
5687
5897
|
setShowDescription(false);
|
|
5898
|
+
setShowRecovery(false);
|
|
5688
5899
|
}, [item?.id, mode]);
|
|
5689
5900
|
useEffect16(() => onDirty(dirty), [dirty, onDirty]);
|
|
5690
5901
|
const keepKey = draftKey(item?.id ?? null, definition?.key ?? item?.definitionKey ?? null);
|
|
@@ -5712,33 +5923,37 @@ function ItemPane(props) {
|
|
|
5712
5923
|
setBusy(true);
|
|
5713
5924
|
setError(null);
|
|
5714
5925
|
const out = { ...draft, values: Object.fromEntries(changedValues(base, draft)) };
|
|
5926
|
+
if (out.values[RECOVERY_CODES_KEY] !== void 0) out.values[RECOVERY_CODES_KEY] = parseRecoveryCodes(out.values[RECOVERY_CODES_KEY]).join("\n");
|
|
5715
5927
|
const withOtp = async (saved, notice2) => {
|
|
5716
5928
|
const setup = out.authenticator.trim();
|
|
5717
|
-
if (!setup) return [saved, notice2];
|
|
5929
|
+
if (!setup) return [saved, notice2, false];
|
|
5718
5930
|
try {
|
|
5719
5931
|
await confirmed(() => port.authenticator.enrol(saved, setup));
|
|
5720
|
-
return [await port.get(saved), notice2];
|
|
5932
|
+
return [await port.get(saved), notice2, true];
|
|
5721
5933
|
} catch (e) {
|
|
5722
5934
|
const why = wasCancelled(e) ? "it was not confirmed" : e instanceof Error ? e.message : "it was refused";
|
|
5723
|
-
return [saved, `Saved, but the
|
|
5935
|
+
return [saved, `Saved, but the authenticator was not set up: ${why}. Add it with Edit.`, false];
|
|
5724
5936
|
}
|
|
5725
5937
|
};
|
|
5726
5938
|
try {
|
|
5727
5939
|
if (item) {
|
|
5728
5940
|
const r = await port.save(item, definition, out);
|
|
5729
|
-
const [next, n] = await withOtp(r.item, r.notice);
|
|
5941
|
+
const [next, n, enrolled] = await withOtp(r.item, r.notice);
|
|
5730
5942
|
dropKeptDraft(keepKey);
|
|
5731
|
-
onSaved(next, false, n);
|
|
5943
|
+
onSaved(next, false, n, enrolled);
|
|
5732
5944
|
} else if (definition && owner === "person") {
|
|
5733
5945
|
const secretKey = declared.find((f) => f.storage === "encrypted" && f.kind === "secret")?.key ?? null;
|
|
5734
5946
|
const r = await port.sharing.assign({ recipientEmail: recipient.trim(), definition, draft: out, generateFieldKey: generatePrivately ? secretKey : null });
|
|
5735
5947
|
notify(`Sent to ${r.recipientEmail}`);
|
|
5736
|
-
|
|
5948
|
+
dropKeptDraft(keepKey);
|
|
5949
|
+
onDirty(false);
|
|
5950
|
+
setSent(r);
|
|
5737
5951
|
} else if (definition) {
|
|
5738
5952
|
const r = await port.create(definition, owner === "me" ? null : owner, out);
|
|
5739
|
-
const [
|
|
5953
|
+
const [withCode, n0, enrolled] = await withOtp(r.item, r.notice);
|
|
5954
|
+
const [next, n] = await storeQueuedFiles(withCode, n0);
|
|
5740
5955
|
dropKeptDraft(keepKey);
|
|
5741
|
-
onSaved(next, true, n);
|
|
5956
|
+
onSaved(next, true, n, enrolled);
|
|
5742
5957
|
}
|
|
5743
5958
|
} catch (e) {
|
|
5744
5959
|
setError(e instanceof Error ? e.message : "Saving failed. Nothing was changed.");
|
|
@@ -5746,9 +5961,32 @@ function ItemPane(props) {
|
|
|
5746
5961
|
setBusy(false);
|
|
5747
5962
|
}
|
|
5748
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
|
+
}
|
|
5749
5987
|
async function remove() {
|
|
5750
5988
|
if (!item) return;
|
|
5751
|
-
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" });
|
|
5752
5990
|
if (!ok) return;
|
|
5753
5991
|
setBusy(true);
|
|
5754
5992
|
try {
|
|
@@ -5789,6 +6027,7 @@ function ItemPane(props) {
|
|
|
5789
6027
|
onChanged();
|
|
5790
6028
|
}
|
|
5791
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;
|
|
5792
6031
|
const turnOnOne = canTurnOn ? (f) => () => turnOn([f]) : () => void 0;
|
|
5793
6032
|
const declaredKeys = new Set(declared.map((f) => f.key));
|
|
5794
6033
|
const extraFields = (item?.fields ?? []).filter((f) => !declaredKeys.has(f.key) && !draft.removed.includes(f.id) && !isAuthenticatorStorage(f.key));
|
|
@@ -5797,35 +6036,39 @@ function ItemPane(props) {
|
|
|
5797
6036
|
const viewCustom = (item?.custom ?? []).filter((c) => !declaredKeys.has(c.key) && c.key !== MFA_METHOD_KEY && !isAuthenticatorStorage(c.key));
|
|
5798
6037
|
const isLogin = (item?.definitionKey ?? definition?.key) === "website_login" || (item?.definitionKey ?? definition?.key) === "username_password";
|
|
5799
6038
|
const typeLabel = definition?.label ?? item?.definitionLabel ?? "";
|
|
5800
|
-
const
|
|
6039
|
+
const recoveryDeclared = declaredKeys.has(RECOVERY_CODES_KEY);
|
|
6040
|
+
const recoveryExtra = extraFields.some(isRecoveryCodesField);
|
|
6041
|
+
const offerRecovery = isLogin || Boolean(item?.authenticator) || draft.authenticator.trim() !== "";
|
|
6042
|
+
const recoveryEditing = !recoveryDeclared && !recoveryExtra && (showRecovery || (draft.values[RECOVERY_CODES_KEY] ?? "") !== "");
|
|
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;
|
|
5801
6044
|
const sameNamed = (id) => {
|
|
5802
6045
|
const name = organizations.find((o) => o.id === id)?.name.trim().toLowerCase();
|
|
5803
6046
|
return Boolean(name) && organizations.filter((o) => o.name.trim().toLowerCase() === name).length > 1;
|
|
5804
6047
|
};
|
|
5805
6048
|
const tagsVisible = showTags || draft.tags.length > 0 || tagsText !== "";
|
|
5806
6049
|
const descriptionVisible = showDescription || draft.description !== "";
|
|
5807
|
-
const header = /* @__PURE__ */
|
|
5808
|
-
onBack ? /* @__PURE__ */
|
|
5809
|
-
/* @__PURE__ */
|
|
5810
|
-
/* @__PURE__ */
|
|
5811
|
-
/* @__PURE__ */
|
|
5812
|
-
/* @__PURE__ */
|
|
5813
|
-
typeLabel ? /* @__PURE__ */
|
|
5814
|
-
shownOwner ? /* @__PURE__ */
|
|
5815
|
-
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
|
|
5816
6059
|
] })
|
|
5817
6060
|
] }),
|
|
5818
|
-
editing ? /* @__PURE__ */
|
|
5819
|
-
dirty ? /* @__PURE__ */
|
|
5820
|
-
/* @__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 }),
|
|
5821
6064
|
"Unsaved"
|
|
5822
6065
|
] }) : null,
|
|
5823
|
-
/* @__PURE__ */
|
|
5824
|
-
/* @__PURE__ */
|
|
5825
|
-
] }) : item ? /* @__PURE__ */
|
|
5826
|
-
host.page && canUseOnSite(item, host.page.url) ? /* @__PURE__ */
|
|
5827
|
-
host.fill && item.capabilities.canUse ? /* @__PURE__ */
|
|
5828
|
-
|
|
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,
|
|
5829
6072
|
{
|
|
5830
6073
|
variant: "primary",
|
|
5831
6074
|
onClick: () => void host.fill?.(item.id).then((outcome) => {
|
|
@@ -5835,44 +6078,44 @@ function ItemPane(props) {
|
|
|
5835
6078
|
children: "Fill"
|
|
5836
6079
|
}
|
|
5837
6080
|
) : null,
|
|
5838
|
-
favorite ? /* @__PURE__ */
|
|
5839
|
-
canManage ? /* @__PURE__ */
|
|
5840
|
-
canEdit ? /* @__PURE__ */
|
|
5841
|
-
/* @__PURE__ */
|
|
5842
|
-
/* @__PURE__ */
|
|
5843
|
-
/* @__PURE__ */
|
|
5844
|
-
favorite ? /* @__PURE__ */
|
|
5845
|
-
/* @__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" }),
|
|
5846
6089
|
favorite.on ? "Remove from favorites" : "Add to favorites"
|
|
5847
6090
|
] }) : null,
|
|
5848
|
-
canManage ? /* @__PURE__ */
|
|
5849
|
-
/* @__PURE__ */
|
|
6091
|
+
canManage ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("share"), children: [
|
|
6092
|
+
/* @__PURE__ */ jsx27(ShareGlyph, { className: "size-4" }),
|
|
5850
6093
|
"Share"
|
|
5851
6094
|
] }) : null,
|
|
5852
|
-
canManage ? /* @__PURE__ */
|
|
5853
|
-
/* @__PURE__ */
|
|
6095
|
+
canManage ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("move"), children: [
|
|
6096
|
+
/* @__PURE__ */ jsx27(MoveGlyph, { className: "size-4" }),
|
|
5854
6097
|
"Move or copy"
|
|
5855
6098
|
] }) : null,
|
|
5856
|
-
item.capabilities.canReveal ? /* @__PURE__ */
|
|
5857
|
-
/* @__PURE__ */
|
|
6099
|
+
item.capabilities.canReveal ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("send"), children: [
|
|
6100
|
+
/* @__PURE__ */ jsx27(SendGlyph, { className: "size-4" }),
|
|
5858
6101
|
"Send securely"
|
|
5859
6102
|
] }) : null,
|
|
5860
|
-
/* @__PURE__ */
|
|
5861
|
-
/* @__PURE__ */
|
|
6103
|
+
/* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("history"), children: [
|
|
6104
|
+
/* @__PURE__ */ jsx27(HistoryIcon, { className: "size-4" }),
|
|
5862
6105
|
"Password history"
|
|
5863
6106
|
] }),
|
|
5864
|
-
/* @__PURE__ */
|
|
5865
|
-
/* @__PURE__ */
|
|
6107
|
+
/* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("activity"), children: [
|
|
6108
|
+
/* @__PURE__ */ jsx27(ListGlyph, { className: "size-4" }),
|
|
5866
6109
|
"Activity"
|
|
5867
6110
|
] }),
|
|
5868
|
-
canEdit ? /* @__PURE__ */
|
|
5869
|
-
/* @__PURE__ */
|
|
6111
|
+
canEdit ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("settings"), children: [
|
|
6112
|
+
/* @__PURE__ */ jsx27(SettingsIcon, { className: "size-4" }),
|
|
5870
6113
|
"Settings"
|
|
5871
6114
|
] }) : null,
|
|
5872
|
-
canManage ? /* @__PURE__ */
|
|
5873
|
-
/* @__PURE__ */
|
|
5874
|
-
/* @__PURE__ */
|
|
5875
|
-
/* @__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" }),
|
|
5876
6119
|
"Delete"
|
|
5877
6120
|
] })
|
|
5878
6121
|
] }) : null
|
|
@@ -5881,17 +6124,17 @@ function ItemPane(props) {
|
|
|
5881
6124
|
] }) : null
|
|
5882
6125
|
] });
|
|
5883
6126
|
const filesProps = item ? { item, port, host, definition, organizations, arg: null, onClose: () => void 0, onChanged, onPanel } : null;
|
|
5884
|
-
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: [
|
|
5885
6128
|
header,
|
|
5886
|
-
error ? /* @__PURE__ */
|
|
5887
|
-
notice && !editing ? /* @__PURE__ */
|
|
5888
|
-
item && !editing && (itemOff || offFields.length > 0) ? /* @__PURE__ */
|
|
5889
|
-
/* @__PURE__ */
|
|
5890
|
-
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
|
|
5891
6134
|
] }) : null,
|
|
5892
|
-
/* @__PURE__ */
|
|
5893
|
-
/* @__PURE__ */
|
|
5894
|
-
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(
|
|
5895
6138
|
OptionCombobox,
|
|
5896
6139
|
{
|
|
5897
6140
|
value: owner,
|
|
@@ -5906,20 +6149,20 @@ function ItemPane(props) {
|
|
|
5906
6149
|
],
|
|
5907
6150
|
getLabel: (v) => v === "me" ? "Personal" : v === "person" ? "Someone else" : organizations.find((o) => o.id === v)?.name ?? v,
|
|
5908
6151
|
getHint: (v) => v === "me" ? "Only you" : v === "person" ? "Sent by email" : sameNamed(v) ? `ID ${v.slice(0, 8)}` : null,
|
|
5909
|
-
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" })
|
|
5910
6153
|
}
|
|
5911
6154
|
) }) : null,
|
|
5912
|
-
/* @__PURE__ */
|
|
5913
|
-
mode === "new" && owner === "person" ? /* @__PURE__ */
|
|
5914
|
-
/* @__PURE__ */
|
|
5915
|
-
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
|
|
5916
6159
|
] }) : null,
|
|
5917
6160
|
declared.map((f) => {
|
|
5918
6161
|
const existing = item?.fields.find((x) => x.key === f.key);
|
|
5919
6162
|
const secretKind = f.storage === "encrypted" && f.kind === "secret";
|
|
5920
6163
|
const value = f.storage === "metadata" ? metaValue(f.key) : draft.values[f.key] ?? "";
|
|
5921
6164
|
const hidden = existing && existing.handling !== "visible" && !(f.key in loaded);
|
|
5922
|
-
return /* @__PURE__ */
|
|
6165
|
+
return /* @__PURE__ */ jsx27(
|
|
5923
6166
|
EditRow,
|
|
5924
6167
|
{
|
|
5925
6168
|
label: f.label,
|
|
@@ -5929,37 +6172,38 @@ function ItemPane(props) {
|
|
|
5929
6172
|
multiline: f.kind === "multiline",
|
|
5930
6173
|
inputMode: f.kind === "url" ? "url" : USERNAME_KEYS.test(f.key) ? "email" : "text",
|
|
5931
6174
|
onChange: (v) => setValue(f.key, v),
|
|
5932
|
-
actions: /* @__PURE__ */
|
|
5933
|
-
hidden && existing?.handling === "revealable" && item?.capabilities.canReveal ? /* @__PURE__ */
|
|
5934
|
-
secretKind ? /* @__PURE__ */
|
|
5935
|
-
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
|
|
5936
6179
|
] })
|
|
5937
6180
|
},
|
|
5938
6181
|
f.key
|
|
5939
6182
|
);
|
|
5940
6183
|
}),
|
|
5941
|
-
extraFields.map((f) => /* @__PURE__ */
|
|
6184
|
+
extraFields.map((f) => /* @__PURE__ */ jsx27(
|
|
5942
6185
|
EditRow,
|
|
5943
6186
|
{
|
|
5944
6187
|
label: f.label,
|
|
5945
6188
|
value: draft.values[f.key] ?? "",
|
|
5946
6189
|
placeholder: f.handling === "visible" || f.key in loaded ? "" : "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
5947
|
-
secret: f.handling !== "visible",
|
|
6190
|
+
secret: f.handling !== "visible" && !isRecoveryCodesField(f),
|
|
6191
|
+
multiline: isRecoveryCodesField(f),
|
|
5948
6192
|
onChange: (v) => setValue(f.key, v),
|
|
5949
6193
|
onRemove: () => patch({ removed: [...draft.removed, f.id] }),
|
|
5950
6194
|
removeLabel: `Delete ${f.label}`,
|
|
5951
|
-
actions: /* @__PURE__ */
|
|
5952
|
-
f.handling === "revealable" && !(f.key in loaded) && item?.capabilities.canReveal ? /* @__PURE__ */
|
|
5953
|
-
/* @__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}`) })
|
|
5954
6198
|
] })
|
|
5955
6199
|
},
|
|
5956
6200
|
f.id
|
|
5957
6201
|
)),
|
|
5958
|
-
draft.loginUrls.map((u, i) => /* @__PURE__ */
|
|
6202
|
+
draft.loginUrls.map((u, i) => /* @__PURE__ */ jsx27(
|
|
5959
6203
|
EditRow,
|
|
5960
6204
|
{
|
|
5961
6205
|
label: i === 0 ? "Website" : `Website ${i + 1}`,
|
|
5962
|
-
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,
|
|
5963
6207
|
value: u,
|
|
5964
6208
|
autoFocus: i > 0 && u === "" && i === draft.loginUrls.length - 1,
|
|
5965
6209
|
placeholder: "https://",
|
|
@@ -5979,27 +6223,53 @@ function ItemPane(props) {
|
|
|
5979
6223
|
},
|
|
5980
6224
|
i
|
|
5981
6225
|
)),
|
|
5982
|
-
/* @__PURE__ */
|
|
5983
|
-
/* @__PURE__ */
|
|
5984
|
-
item && isLogin && !item.authenticator ? /* @__PURE__ */
|
|
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(
|
|
6231
|
+
EditRow,
|
|
6232
|
+
{
|
|
6233
|
+
label: "Recovery codes",
|
|
6234
|
+
value: draft.values[RECOVERY_CODES_KEY] ?? "",
|
|
6235
|
+
multiline: true,
|
|
6236
|
+
autoFocus: showRecovery && (draft.values[RECOVERY_CODES_KEY] ?? "") === "",
|
|
6237
|
+
placeholder: "Backup codes, one per line",
|
|
6238
|
+
onChange: (v) => setValue(RECOVERY_CODES_KEY, v),
|
|
6239
|
+
onRemove: () => {
|
|
6240
|
+
setShowRecovery(false);
|
|
6241
|
+
setDraft((d) => {
|
|
6242
|
+
const values = { ...d.values };
|
|
6243
|
+
delete values[RECOVERY_CODES_KEY];
|
|
6244
|
+
return { ...d, values };
|
|
6245
|
+
});
|
|
6246
|
+
},
|
|
6247
|
+
removeLabel: "Remove recovery codes"
|
|
6248
|
+
}
|
|
6249
|
+
) : !recoveryDeclared && !recoveryExtra && offerRecovery ? /* @__PURE__ */ jsx27(AddRow, { label: "Recovery codes", onAdd: () => setShowRecovery(true), children: "Add backup codes" }) : null
|
|
5985
6250
|
] }),
|
|
5986
|
-
/* @__PURE__ */
|
|
5987
|
-
/* @__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(
|
|
5988
6253
|
VaultSection,
|
|
5989
6254
|
{
|
|
5990
6255
|
title: "More",
|
|
5991
|
-
actions: /* @__PURE__ */
|
|
5992
|
-
/* @__PURE__ */
|
|
5993
|
-
/* @__PURE__ */
|
|
5994
|
-
/* @__PURE__ */
|
|
5995
|
-
/* @__PURE__ */
|
|
5996
|
-
!tagsVisible ? /* @__PURE__ */
|
|
5997
|
-
!descriptionVisible ? /* @__PURE__ */
|
|
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
|
|
5998
6268
|
] })
|
|
5999
6269
|
] }),
|
|
6000
6270
|
children: [
|
|
6001
|
-
descriptionVisible ? /* @__PURE__ */
|
|
6002
|
-
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(
|
|
6003
6273
|
EditRow,
|
|
6004
6274
|
{
|
|
6005
6275
|
label: "Tags",
|
|
@@ -6011,63 +6281,83 @@ function ItemPane(props) {
|
|
|
6011
6281
|
}
|
|
6012
6282
|
}
|
|
6013
6283
|
) : null,
|
|
6014
|
-
draft.
|
|
6015
|
-
|
|
6016
|
-
|
|
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
|
|
6017
6288
|
]
|
|
6018
6289
|
}
|
|
6019
6290
|
),
|
|
6020
|
-
filesProps ? /* @__PURE__ */
|
|
6021
|
-
] }) : item ? /* @__PURE__ */
|
|
6022
|
-
/* @__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: [
|
|
6023
6294
|
declared.map((f) => {
|
|
6024
6295
|
if (f.storage === "metadata") {
|
|
6025
6296
|
const v = metaValue(f.key);
|
|
6026
|
-
return v ? /* @__PURE__ */
|
|
6297
|
+
return v ? /* @__PURE__ */ jsx27(PlainRow, { label: f.label, value: v, openUrl: host.openUrl }, f.key) : null;
|
|
6027
6298
|
}
|
|
6028
6299
|
const field = item.fields.find((x) => x.key === f.key);
|
|
6029
|
-
if (isRecoveryCodesField(f)) return /* @__PURE__ */
|
|
6030
|
-
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;
|
|
6031
6302
|
}),
|
|
6032
|
-
extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */
|
|
6033
|
-
item.loginUrls.length > 0 ? item.loginUrls.map((u, i) => /* @__PURE__ */
|
|
6034
|
-
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 ? (
|
|
6035
6306
|
// The secret is still there, only off: turning it on brings the codes back. Never "Set up",
|
|
6036
6307
|
// which would invite replacing a working two-factor secret.
|
|
6037
|
-
/* @__PURE__ */
|
|
6038
|
-
) : /* @__PURE__ */
|
|
6039
|
-
!
|
|
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
|
|
6040
6312
|
] }),
|
|
6041
|
-
/* @__PURE__ */
|
|
6042
|
-
item.description || item.tags.length > 0 || viewCustom.length > 0 ? /* @__PURE__ */
|
|
6043
|
-
item.description ? /* @__PURE__ */
|
|
6044
|
-
item.tags.length > 0 ? /* @__PURE__ */
|
|
6045
|
-
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))
|
|
6046
6318
|
] }) : null,
|
|
6047
|
-
filesProps ? /* @__PURE__ */
|
|
6048
|
-
/* @__PURE__ */
|
|
6319
|
+
filesProps ? /* @__PURE__ */ jsx27(FilesSection, { ...filesProps, editing: false }) : null,
|
|
6320
|
+
/* @__PURE__ */ jsxs25("p", { className: cn12("px-1 text-xs text-muted-foreground"), children: [
|
|
6049
6321
|
"Modified ",
|
|
6050
6322
|
formatAbsoluteDate3(item.updatedAt, DAY_FORMAT, ""),
|
|
6051
6323
|
" \xB7 Created ",
|
|
6052
6324
|
formatAbsoluteDate3(item.createdAt, DAY_FORMAT, "")
|
|
6053
6325
|
] })
|
|
6054
|
-
] }) : null }) })
|
|
6326
|
+
] }) : null }) }),
|
|
6327
|
+
settingUpOtp && item ? /* @__PURE__ */ jsx27(
|
|
6328
|
+
AddOtpPanel,
|
|
6329
|
+
{
|
|
6330
|
+
port,
|
|
6331
|
+
items: [item],
|
|
6332
|
+
definitions: definition ? [definition] : [],
|
|
6333
|
+
itemId: item.id,
|
|
6334
|
+
onClose: () => setSettingUpOtp(false),
|
|
6335
|
+
onChanged: () => onChanged(),
|
|
6336
|
+
onDone: () => {
|
|
6337
|
+
setSettingUpOtp(false);
|
|
6338
|
+
onChanged();
|
|
6339
|
+
}
|
|
6340
|
+
}
|
|
6341
|
+
) : null
|
|
6055
6342
|
] }) });
|
|
6056
6343
|
}
|
|
6057
6344
|
|
|
6058
6345
|
// src/ItemList.tsx
|
|
6059
|
-
import { jsx as
|
|
6346
|
+
import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
6060
6347
|
var SORTS2 = [
|
|
6061
|
-
{ value: "name", label: "Name" },
|
|
6348
|
+
{ value: "name", label: "Name A\u2013Z" },
|
|
6349
|
+
{ value: "name-desc", label: "Name Z\u2013A" },
|
|
6062
6350
|
{ value: "website", label: "Website" },
|
|
6063
6351
|
{ value: "updated", label: "Recently changed" },
|
|
6064
|
-
{ value: "created", label: "Recently added" }
|
|
6352
|
+
{ value: "created", label: "Recently added" },
|
|
6353
|
+
{ value: "viewed", label: "Recently viewed" }
|
|
6065
6354
|
];
|
|
6066
6355
|
function subtitleOf(item, withOwner) {
|
|
6067
6356
|
const what = loginSiteOf(item) || item.definitionLabel;
|
|
6068
6357
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
6069
6358
|
}
|
|
6070
|
-
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");
|
|
6071
6361
|
const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
|
|
6072
6362
|
const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
|
|
6073
6363
|
const ordered = [...pinned, ...rest];
|
|
@@ -6087,34 +6377,34 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6087
6377
|
}
|
|
6088
6378
|
};
|
|
6089
6379
|
const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6090
|
-
const row = (i) => /* @__PURE__ */
|
|
6091
|
-
const sortLabel =
|
|
6092
|
-
return /* @__PURE__ */
|
|
6093
|
-
/* @__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: [
|
|
6094
6384
|
header,
|
|
6095
|
-
/* @__PURE__ */
|
|
6096
|
-
/* @__PURE__ */
|
|
6097
|
-
/* @__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 })
|
|
6098
6388
|
] }),
|
|
6099
|
-
/* @__PURE__ */
|
|
6100
|
-
/* @__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: [
|
|
6101
6391
|
items.length,
|
|
6102
6392
|
" ",
|
|
6103
6393
|
items.length === 1 ? "item" : "items"
|
|
6104
6394
|
] }),
|
|
6105
|
-
/* @__PURE__ */
|
|
6106
|
-
/* @__PURE__ */
|
|
6107
|
-
/* @__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)) }) })
|
|
6108
6398
|
] })
|
|
6109
6399
|
] })
|
|
6110
6400
|
] }),
|
|
6111
|
-
/* @__PURE__ */
|
|
6112
|
-
/* @__PURE__ */
|
|
6113
|
-
query ? /* @__PURE__ */
|
|
6114
|
-
] }) : /* @__PURE__ */
|
|
6115
|
-
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,
|
|
6116
6406
|
pinned.map(row),
|
|
6117
|
-
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,
|
|
6118
6408
|
rest.map(row)
|
|
6119
6409
|
] }) })
|
|
6120
6410
|
] });
|
|
@@ -6123,48 +6413,93 @@ function ListRow({ item, family, port, on, onSelect, withOwner }) {
|
|
|
6123
6413
|
const confirmed = useConfirmed();
|
|
6124
6414
|
const copy = useCopy();
|
|
6125
6415
|
const notify = useNotify();
|
|
6126
|
-
const [busy, setBusy] =
|
|
6127
|
-
const
|
|
6128
|
-
const
|
|
6129
|
-
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) => {
|
|
6130
6423
|
setBusy(true);
|
|
6131
6424
|
try {
|
|
6132
|
-
const v = await confirmed(
|
|
6133
|
-
await copy(v, label, { secret:
|
|
6425
|
+
const v = await confirmed(read);
|
|
6426
|
+
await copy(v, label, { secret: isSecret });
|
|
6134
6427
|
} catch (e) {
|
|
6135
6428
|
if (!wasCancelled(e)) notify(e instanceof Error ? e.message : `${label} could not be read`, "error");
|
|
6136
6429
|
} finally {
|
|
6137
6430
|
setBusy(false);
|
|
6138
6431
|
}
|
|
6139
6432
|
};
|
|
6140
|
-
|
|
6141
|
-
|
|
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(
|
|
6142
6439
|
"button",
|
|
6143
6440
|
{
|
|
6144
6441
|
type: "button",
|
|
6145
6442
|
"aria-current": on ? "true" : void 0,
|
|
6146
6443
|
"data-surface": on ? "primary" : void 0,
|
|
6147
6444
|
onClick: () => onSelect(item.id),
|
|
6148
|
-
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"),
|
|
6149
6446
|
children: [
|
|
6150
|
-
/* @__PURE__ */
|
|
6151
|
-
/* @__PURE__ */
|
|
6152
|
-
/* @__PURE__ */
|
|
6153
|
-
/* @__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) })
|
|
6154
6451
|
] })
|
|
6155
6452
|
]
|
|
6156
6453
|
}
|
|
6157
6454
|
),
|
|
6158
|
-
|
|
6159
|
-
user ? /* @__PURE__ */
|
|
6160
|
-
|
|
6161
|
-
|
|
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
|
+
] })
|
|
6162
6497
|
] });
|
|
6163
6498
|
}
|
|
6164
6499
|
|
|
6165
6500
|
// src/lists/TrashView.tsx
|
|
6166
|
-
import { useState as
|
|
6167
|
-
import { Button as
|
|
6501
|
+
import { useState as useState30 } from "react";
|
|
6502
|
+
import { Button as Button25 } from "@ai-matrx/design-system/controls";
|
|
6168
6503
|
import { formatAbsoluteDate as formatAbsoluteDate4 } from "@ai-matrx/kit/format";
|
|
6169
6504
|
|
|
6170
6505
|
// src/lists/logic.ts
|
|
@@ -6237,15 +6572,15 @@ function refusalText(reason) {
|
|
|
6237
6572
|
}
|
|
6238
6573
|
|
|
6239
6574
|
// src/lists/RestorePanel.tsx
|
|
6240
|
-
import { useEffect as useEffect18, useState as
|
|
6241
|
-
import { Button as
|
|
6242
|
-
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";
|
|
6243
6578
|
var count = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
|
|
6244
6579
|
function RestorePanel({ lists, item, restore, onClose }) {
|
|
6245
|
-
const [preview, setPreview] =
|
|
6246
|
-
const [error, setError] =
|
|
6247
|
-
const [busy, setBusy] =
|
|
6248
|
-
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));
|
|
6249
6584
|
useEffect18(() => {
|
|
6250
6585
|
if (!lists.preview) return;
|
|
6251
6586
|
let live = true;
|
|
@@ -6278,41 +6613,41 @@ function RestorePanel({ lists, item, restore, onClose }) {
|
|
|
6278
6613
|
setBusy(false);
|
|
6279
6614
|
}
|
|
6280
6615
|
};
|
|
6281
|
-
return /* @__PURE__ */
|
|
6616
|
+
return /* @__PURE__ */ jsxs27(
|
|
6282
6617
|
Panel,
|
|
6283
6618
|
{
|
|
6284
6619
|
title: `Restore "${item.name}"`,
|
|
6285
6620
|
size: "md",
|
|
6286
6621
|
onClose,
|
|
6287
|
-
footer: /* @__PURE__ */
|
|
6288
|
-
/* @__PURE__ */
|
|
6289
|
-
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" })
|
|
6290
6625
|
] }),
|
|
6291
6626
|
children: [
|
|
6292
|
-
loading ? /* @__PURE__ */
|
|
6293
|
-
/* @__PURE__ */
|
|
6294
|
-
/* @__PURE__ */
|
|
6295
|
-
preview.passkeys === 1 ? /* @__PURE__ */
|
|
6296
|
-
/* @__PURE__ */
|
|
6297
|
-
preview.priorWasDisabled ? /* @__PURE__ */
|
|
6298
|
-
] }) : preview ? /* @__PURE__ */
|
|
6299
|
-
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
|
|
6300
6635
|
]
|
|
6301
6636
|
}
|
|
6302
6637
|
);
|
|
6303
6638
|
}
|
|
6304
6639
|
|
|
6305
6640
|
// src/lists/TrashView.tsx
|
|
6306
|
-
import { jsx as
|
|
6641
|
+
import { jsx as jsx30, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
6307
6642
|
function trashLineOf(item) {
|
|
6308
6643
|
return [item.definitionLabel || null, item.owner.label, item.deletion?.deletedAt ? `Deleted ${formatAbsoluteDate4(item.deletion.deletedAt, DAY_FORMAT, "")}` : null].filter(Boolean).join(" \xB7 ");
|
|
6309
6644
|
}
|
|
6310
6645
|
function TrashView({ port, deleted, query, header, onChanged }) {
|
|
6311
6646
|
const confirmed = useConfirmed();
|
|
6312
|
-
const [busyId, setBusyId] =
|
|
6313
|
-
const [message2, setMessage] =
|
|
6647
|
+
const [busyId, setBusyId] = useState30(null);
|
|
6648
|
+
const [message2, setMessage] = useState30(null);
|
|
6314
6649
|
const shown = deleted.filter((i) => trashItemMatchesQuery(i, query));
|
|
6315
|
-
const [restoring, setRestoring] =
|
|
6650
|
+
const [restoring, setRestoring] = useState30(null);
|
|
6316
6651
|
const restore = async (item, deletionId) => {
|
|
6317
6652
|
setBusyId(item.id);
|
|
6318
6653
|
setMessage(null);
|
|
@@ -6328,32 +6663,32 @@ function TrashView({ port, deleted, query, header, onChanged }) {
|
|
|
6328
6663
|
setBusyId(null);
|
|
6329
6664
|
}
|
|
6330
6665
|
};
|
|
6331
|
-
return /* @__PURE__ */
|
|
6666
|
+
return /* @__PURE__ */ jsxs28("div", { className: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-3", children: [
|
|
6332
6667
|
header,
|
|
6333
|
-
/* @__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) => (
|
|
6334
6669
|
// A list row, not a field row: the name gets the whole width (on a phone a label column
|
|
6335
6670
|
// left "Vau…" for every row), the deletion date sits under it.
|
|
6336
|
-
/* @__PURE__ */
|
|
6337
|
-
/* @__PURE__ */
|
|
6338
|
-
/* @__PURE__ */
|
|
6339
|
-
/* @__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) })
|
|
6340
6675
|
] }),
|
|
6341
|
-
/* @__PURE__ */
|
|
6676
|
+
/* @__PURE__ */ jsx30(Button25, { variant: "outline", icon: /* @__PURE__ */ jsx30(RestoreGlyph, {}), disabled: busyId !== null || !item.deletion, onClick: () => setRestoring(item), children: "Restore" })
|
|
6342
6677
|
] }, item.id)
|
|
6343
6678
|
)) }),
|
|
6344
|
-
restoring ? /* @__PURE__ */
|
|
6345
|
-
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
|
|
6346
6681
|
] });
|
|
6347
6682
|
}
|
|
6348
6683
|
|
|
6349
6684
|
// src/NewItemFlow.tsx
|
|
6350
|
-
import { useMemo as useMemo4, useState as
|
|
6685
|
+
import { useMemo as useMemo4, useState as useState31 } from "react";
|
|
6351
6686
|
import { cn as cn14 } from "@ai-matrx/design-system";
|
|
6352
|
-
import { Button as
|
|
6687
|
+
import { Button as Button26, Field as Field11, SearchField as SearchField2 } from "@ai-matrx/design-system/controls";
|
|
6353
6688
|
import { GlobeIcon as GlobeIcon3 } from "@ai-matrx/design-system/icons";
|
|
6354
|
-
import { jsx as
|
|
6689
|
+
import { jsx as jsx31, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
6355
6690
|
function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
|
|
6356
|
-
const [search, setSearch] =
|
|
6691
|
+
const [search, setSearch] = useState31("");
|
|
6357
6692
|
const guess = useMemo4(() => inferFromUrl(url, definitions), [url, definitions]);
|
|
6358
6693
|
const common = COMMON_DEFINITION_KEYS.map((k) => definitions.find((d) => d.key === k)).filter((d) => d !== void 0);
|
|
6359
6694
|
const matches = useMemo4(() => {
|
|
@@ -6365,15 +6700,15 @@ function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
|
|
|
6365
6700
|
const alternatives = (guess?.alternatives ?? []).map((k) => definitions.find((d) => d.key === k)).filter((d) => d !== void 0).slice(0, 4);
|
|
6366
6701
|
const use = (d) => onChoose(d.key, guess?.name ?? "", guess?.url ?? url.trim());
|
|
6367
6702
|
const shown = search.trim() ? matches : common;
|
|
6368
|
-
return /* @__PURE__ */
|
|
6369
|
-
/* @__PURE__ */
|
|
6370
|
-
/* @__PURE__ */
|
|
6371
|
-
/* @__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" })
|
|
6372
6707
|
] }),
|
|
6373
|
-
/* @__PURE__ */
|
|
6374
|
-
/* @__PURE__ */
|
|
6375
|
-
/* @__PURE__ */
|
|
6376
|
-
|
|
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,
|
|
6377
6712
|
{
|
|
6378
6713
|
hero: true,
|
|
6379
6714
|
value: url,
|
|
@@ -6385,45 +6720,45 @@ function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
|
|
|
6385
6720
|
"aria-label": "Website address",
|
|
6386
6721
|
inputMode: "url",
|
|
6387
6722
|
autoFocus: true,
|
|
6388
|
-
icon: /* @__PURE__ */
|
|
6723
|
+
icon: /* @__PURE__ */ jsx31(GlobeIcon3, {})
|
|
6389
6724
|
}
|
|
6390
6725
|
),
|
|
6391
|
-
guess && login ? /* @__PURE__ */
|
|
6392
|
-
/* @__PURE__ */
|
|
6393
|
-
/* @__PURE__ */
|
|
6394
|
-
/* @__PURE__ */
|
|
6395
|
-
/* @__PURE__ */
|
|
6396
|
-
/* @__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?:\/\//, "") })
|
|
6397
6732
|
] }),
|
|
6398
|
-
/* @__PURE__ */
|
|
6733
|
+
/* @__PURE__ */ jsx31(Button26, { variant: "primary", onClick: () => use(login), children: "Save login" })
|
|
6399
6734
|
] }),
|
|
6400
|
-
alternatives.length > 0 ? /* @__PURE__ */
|
|
6401
|
-
/* @__PURE__ */
|
|
6402
|
-
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))
|
|
6403
6738
|
] }) : null
|
|
6404
|
-
] }) : 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
|
|
6405
6740
|
] }),
|
|
6406
|
-
/* @__PURE__ */
|
|
6407
|
-
/* @__PURE__ */
|
|
6408
|
-
/* @__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) => {
|
|
6409
6744
|
const Icon = definitionGlyph(d.key, d.family);
|
|
6410
|
-
return /* @__PURE__ */
|
|
6411
|
-
/* @__PURE__ */
|
|
6412
|
-
/* @__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 })
|
|
6413
6748
|
] }) }, d.key);
|
|
6414
6749
|
}) }),
|
|
6415
|
-
search.trim() && matches.length === 0 ? /* @__PURE__ */
|
|
6416
|
-
/* @__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" })
|
|
6417
6752
|
] })
|
|
6418
6753
|
] }) })
|
|
6419
6754
|
] });
|
|
6420
6755
|
}
|
|
6421
6756
|
|
|
6422
6757
|
// src/sharing/SecureLinkPanel.tsx
|
|
6423
|
-
import { useEffect as useEffect19, useRef as useRef16, useState as
|
|
6424
|
-
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";
|
|
6425
6760
|
import { Checkbox as Checkbox2 } from "@ai-matrx/design-system";
|
|
6426
|
-
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";
|
|
6427
6762
|
import { formatAbsoluteDate as formatAbsoluteDate5 } from "@ai-matrx/kit/format";
|
|
6428
6763
|
|
|
6429
6764
|
// src/sharing/secure-link-logic.ts
|
|
@@ -6499,23 +6834,23 @@ function sortSent(rows) {
|
|
|
6499
6834
|
}
|
|
6500
6835
|
|
|
6501
6836
|
// src/sharing/SecureLinkPanel.tsx
|
|
6502
|
-
import { jsx as
|
|
6837
|
+
import { jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
6503
6838
|
function SecureLinkPanel({ item, port, onClose }) {
|
|
6504
6839
|
const sharing = port.sharing;
|
|
6505
6840
|
const { busy, error, notice, run, setNotice } = useConfirmedChange();
|
|
6506
|
-
const [remedy, setRemedy] =
|
|
6507
|
-
const [options, setOptions] =
|
|
6508
|
-
const [optionsError, setOptionsError] =
|
|
6509
|
-
const [sent, setSent] =
|
|
6510
|
-
const [sentError, setSentError] =
|
|
6511
|
-
const [nonce, setNonce] =
|
|
6512
|
-
const [email, setEmail] =
|
|
6513
|
-
const [phone, setPhone] =
|
|
6514
|
-
const [name, setName] =
|
|
6515
|
-
const [linkBy, setLinkBy] =
|
|
6516
|
-
const [fields, setFields] =
|
|
6517
|
-
const [note, setNote] =
|
|
6518
|
-
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);
|
|
6519
6854
|
useEffect19(() => {
|
|
6520
6855
|
let live = true;
|
|
6521
6856
|
setOptionsError(null);
|
|
@@ -6544,7 +6879,7 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6544
6879
|
live = false;
|
|
6545
6880
|
};
|
|
6546
6881
|
}, [sharing, item, nonce]);
|
|
6547
|
-
const [phoneTyped, setPhoneTyped] =
|
|
6882
|
+
const [phoneTyped, setPhoneTyped] = useState32(false);
|
|
6548
6883
|
const prefilled = useRef16(false);
|
|
6549
6884
|
useEffect19(() => {
|
|
6550
6885
|
const lookup = sharing.phoneOnFile;
|
|
@@ -6608,7 +6943,7 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6608
6943
|
setNonce((n) => n + 1);
|
|
6609
6944
|
};
|
|
6610
6945
|
const turnOff = async (row) => {
|
|
6611
|
-
const ok = await
|
|
6946
|
+
const ok = await confirm11({
|
|
6612
6947
|
title: "Turn off this link?",
|
|
6613
6948
|
description: `The link to ${recipientOf(row)} stops working at once and what it carries is deleted. They will need a new one.`,
|
|
6614
6949
|
confirmLabel: "Turn off",
|
|
@@ -6621,23 +6956,23 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6621
6956
|
setNonce((n) => n + 1);
|
|
6622
6957
|
};
|
|
6623
6958
|
const toggle2 = (key, on) => setFields((cur) => on ? [...cur.filter((k) => k !== key), key] : cur.filter((k) => k !== key));
|
|
6624
|
-
return /* @__PURE__ */
|
|
6959
|
+
return /* @__PURE__ */ jsxs30(
|
|
6625
6960
|
Panel,
|
|
6626
6961
|
{
|
|
6627
6962
|
title: "Send securely",
|
|
6628
6963
|
size: "md",
|
|
6629
6964
|
onClose,
|
|
6630
|
-
footer: /* @__PURE__ */
|
|
6631
|
-
sameChannelSent && !error ? /* @__PURE__ */
|
|
6632
|
-
/* @__PURE__ */
|
|
6633
|
-
/* @__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" })
|
|
6634
6969
|
] }),
|
|
6635
6970
|
children: [
|
|
6636
|
-
remedy ? /* @__PURE__ */
|
|
6637
|
-
/* @__PURE__ */
|
|
6638
|
-
/* @__PURE__ */
|
|
6639
|
-
/* @__PURE__ */
|
|
6640
|
-
|
|
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,
|
|
6641
6976
|
{
|
|
6642
6977
|
type: "tel",
|
|
6643
6978
|
autoComplete: "off",
|
|
@@ -6652,9 +6987,9 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6652
6987
|
className: "w-full"
|
|
6653
6988
|
}
|
|
6654
6989
|
) }),
|
|
6655
|
-
/* @__PURE__ */
|
|
6656
|
-
plan && !plan.same ? /* @__PURE__ */
|
|
6657
|
-
|
|
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,
|
|
6658
6993
|
{
|
|
6659
6994
|
"aria-label": "Send the link by",
|
|
6660
6995
|
value: linkBy,
|
|
@@ -6665,28 +7000,28 @@ function SecureLinkPanel({ item, port, onClose }) {
|
|
|
6665
7000
|
]
|
|
6666
7001
|
}
|
|
6667
7002
|
) }) : null,
|
|
6668
|
-
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
|
|
6669
7004
|
] }),
|
|
6670
|
-
/* @__PURE__ */
|
|
6671
|
-
/* @__PURE__ */
|
|
6672
|
-
/* @__PURE__ */
|
|
6673
|
-
!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
|
|
6674
7009
|
] }, f.key)) }),
|
|
6675
|
-
/* @__PURE__ */
|
|
6676
|
-
options ? /* @__PURE__ */
|
|
6677
|
-
/* @__PURE__ */
|
|
6678
|
-
/* @__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: [
|
|
6679
7014
|
"After ",
|
|
6680
7015
|
lifetimeWords(options.linkMinutes)
|
|
6681
7016
|
] }) }),
|
|
6682
|
-
/* @__PURE__ */
|
|
7017
|
+
/* @__PURE__ */ jsx32(VaultRow, { label: "Code expires", children: /* @__PURE__ */ jsxs30("span", { className: "text-foreground", children: [
|
|
6683
7018
|
"After ",
|
|
6684
7019
|
lifetimeWords(options.codeMinutes)
|
|
6685
7020
|
] }) })
|
|
6686
7021
|
] }) : null,
|
|
6687
|
-
sharing.sentSecureLinks ? /* @__PURE__ */
|
|
6688
|
-
/* @__PURE__ */
|
|
6689
|
-
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
|
|
6690
7025
|
] }, row.id)) }) : null
|
|
6691
7026
|
]
|
|
6692
7027
|
}
|
|
@@ -6699,9 +7034,9 @@ function sentMeta(row, options) {
|
|
|
6699
7034
|
}
|
|
6700
7035
|
|
|
6701
7036
|
// src/devices/DevicesPanel.tsx
|
|
6702
|
-
import { useCallback as useCallback4, useEffect as useEffect20, useState as
|
|
6703
|
-
import { confirm as
|
|
6704
|
-
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";
|
|
6705
7040
|
import { formatAbsoluteDate as formatAbsoluteDate6 } from "@ai-matrx/kit/format";
|
|
6706
7041
|
|
|
6707
7042
|
// src/devices/logic.ts
|
|
@@ -6782,17 +7117,17 @@ function addPasskeyFailure(message2) {
|
|
|
6782
7117
|
var isRevoked = (d) => d.revokedAt !== null;
|
|
6783
7118
|
|
|
6784
7119
|
// src/devices/DevicesPanel.tsx
|
|
6785
|
-
import { Fragment as
|
|
7120
|
+
import { Fragment as Fragment19, jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
6786
7121
|
var messageOf3 = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
|
|
6787
7122
|
function ErrorLine2({ text }) {
|
|
6788
|
-
return text ? /* @__PURE__ */
|
|
7123
|
+
return text ? /* @__PURE__ */ jsx33("p", { role: "alert", className: "px-1 text-sm text-destructive", children: text }) : null;
|
|
6789
7124
|
}
|
|
6790
7125
|
function DevicesPanel({ port, onClose }) {
|
|
6791
7126
|
const confirmed = useConfirmed();
|
|
6792
7127
|
const notify = useNotify();
|
|
6793
|
-
const [devices, setDevices] =
|
|
6794
|
-
const [error, setError] =
|
|
6795
|
-
const [busyId, setBusyId] =
|
|
7128
|
+
const [devices, setDevices] = useState33(null);
|
|
7129
|
+
const [error, setError] = useState33(null);
|
|
7130
|
+
const [busyId, setBusyId] = useState33(null);
|
|
6796
7131
|
const load = useCallback4(async () => {
|
|
6797
7132
|
setError(null);
|
|
6798
7133
|
try {
|
|
@@ -6805,7 +7140,7 @@ function DevicesPanel({ port, onClose }) {
|
|
|
6805
7140
|
void load();
|
|
6806
7141
|
}, [load]);
|
|
6807
7142
|
const revoke = async (device) => {
|
|
6808
|
-
const yes = await
|
|
7143
|
+
const yes = await confirm12({
|
|
6809
7144
|
title: `Revoke ${device.label}?`,
|
|
6810
7145
|
description: "It stops filling now and the extension there signs out. It fills again only after you sign in there and confirm.",
|
|
6811
7146
|
confirmLabel: "Revoke",
|
|
@@ -6824,19 +7159,19 @@ function DevicesPanel({ port, onClose }) {
|
|
|
6824
7159
|
setBusyId(null);
|
|
6825
7160
|
}
|
|
6826
7161
|
};
|
|
6827
|
-
return /* @__PURE__ */
|
|
6828
|
-
/* @__PURE__ */
|
|
6829
|
-
/* @__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) => {
|
|
6830
7165
|
const off = isRevoked(device);
|
|
6831
|
-
return /* @__PURE__ */
|
|
7166
|
+
return /* @__PURE__ */ jsx33(
|
|
6832
7167
|
VaultRow,
|
|
6833
7168
|
{
|
|
6834
7169
|
label: off ? "Turned off" : "Can fill",
|
|
6835
7170
|
hint: off ? formatAbsoluteDate6(device.revokedAt, DAY_FORMAT, "") : void 0,
|
|
6836
|
-
actions: off ? null : /* @__PURE__ */
|
|
6837
|
-
children: /* @__PURE__ */
|
|
6838
|
-
/* @__PURE__ */
|
|
6839
|
-
/* @__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: [
|
|
6840
7175
|
device.lastUsedAt ? `Last used ${formatAbsoluteDate6(device.lastUsedAt, void 0, "")}` : "Never used",
|
|
6841
7176
|
device.addedAt ? ` \xB7 added ${formatAbsoluteDate6(device.addedAt, DAY_FORMAT, "")}` : ""
|
|
6842
7177
|
] })
|
|
@@ -6859,10 +7194,10 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
|
|
|
6859
7194
|
const where = isMac ? "the Mac app" : "the extension";
|
|
6860
7195
|
const passkeys = port.devices.passkeys;
|
|
6861
7196
|
const here = passkeys?.available() ?? false;
|
|
6862
|
-
const [methods, setMethods] =
|
|
6863
|
-
const [busy, setBusy] =
|
|
6864
|
-
const [error, setError] =
|
|
6865
|
-
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);
|
|
6866
7201
|
const load = useCallback4(async () => {
|
|
6867
7202
|
setError(null);
|
|
6868
7203
|
try {
|
|
@@ -6913,55 +7248,55 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
|
|
|
6913
7248
|
};
|
|
6914
7249
|
const canApprove = Boolean(key && passkeys && here && methods?.passkey && !approvedUntil);
|
|
6915
7250
|
const title = isMac ? "Approve this Mac" : name ? `Approve ${name}` : "Approve this browser";
|
|
6916
|
-
const footer = approvedUntil ? /* @__PURE__ */
|
|
6917
|
-
/* @__PURE__ */
|
|
6918
|
-
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
|
|
6919
7254
|
] });
|
|
6920
|
-
return /* @__PURE__ */
|
|
7255
|
+
return /* @__PURE__ */ jsx33(Panel, { title, onClose: refuse, size: "sm", footer, children: !key ? /* @__PURE__ */ jsx33(VaultSection, { children: /* @__PURE__ */ jsxs31(Empty, { children: [
|
|
6921
7256
|
"This link names no key. Start again from ",
|
|
6922
7257
|
where,
|
|
6923
7258
|
"."
|
|
6924
|
-
] }) }) : /* @__PURE__ */
|
|
6925
|
-
/* @__PURE__ */
|
|
6926
|
-
/* @__PURE__ */
|
|
6927
|
-
name ? /* @__PURE__ */
|
|
6928
|
-
/* @__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) }) })
|
|
6929
7264
|
] }),
|
|
6930
|
-
/* @__PURE__ */
|
|
6931
|
-
/* @__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: [
|
|
6932
7267
|
"Return to ",
|
|
6933
7268
|
where,
|
|
6934
7269
|
" by ",
|
|
6935
7270
|
formatAbsoluteDate6(approvedUntil, void 0, ""),
|
|
6936
7271
|
"."
|
|
6937
|
-
] }) }) : !passkeys ? /* @__PURE__ */
|
|
7272
|
+
] }) }) : !passkeys ? /* @__PURE__ */ jsxs31(Empty, { children: [
|
|
6938
7273
|
"Approve with your password in ",
|
|
6939
7274
|
where,
|
|
6940
7275
|
"."
|
|
6941
|
-
] }) : !here ? /* @__PURE__ */
|
|
7276
|
+
] }) : !here ? /* @__PURE__ */ jsx33(
|
|
6942
7277
|
VaultRow,
|
|
6943
7278
|
{
|
|
6944
7279
|
label: "Passkey",
|
|
6945
7280
|
hint: `Passkeys work only on ${passkeys.rpId}`,
|
|
6946
|
-
actions: /* @__PURE__ */
|
|
6947
|
-
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" })
|
|
6948
7283
|
}
|
|
6949
|
-
) : 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(
|
|
6950
7285
|
VaultRow,
|
|
6951
7286
|
{
|
|
6952
7287
|
label: "Passkey",
|
|
6953
7288
|
hint: methods.password ? `Or type your password in ${where}` : "Add one to approve",
|
|
6954
|
-
actions: /* @__PURE__ */
|
|
6955
|
-
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" })
|
|
6956
7291
|
}
|
|
6957
|
-
) : /* @__PURE__ */
|
|
7292
|
+
) : /* @__PURE__ */ jsx33(VaultRow, { label: "Passkey", hint: "Your device asks for it next", children: /* @__PURE__ */ jsx33("span", { className: "text-foreground", children: "Ready" }) }) })
|
|
6958
7293
|
] }) });
|
|
6959
7294
|
}
|
|
6960
7295
|
|
|
6961
7296
|
// src/native/NativeImportPanel.tsx
|
|
6962
|
-
import { useEffect as useEffect22, useMemo as useMemo5, useState as
|
|
6963
|
-
import { confirm as
|
|
6964
|
-
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";
|
|
6965
7300
|
|
|
6966
7301
|
// src/native/logic.ts
|
|
6967
7302
|
var ACTIVE_PHASES = /* @__PURE__ */ new Set(["authorizing", "importing"]);
|
|
@@ -7022,12 +7357,12 @@ async function loadFullPreview(bridge, operationId, current) {
|
|
|
7022
7357
|
}
|
|
7023
7358
|
|
|
7024
7359
|
// src/native/use-native-import.ts
|
|
7025
|
-
import { useEffect as useEffect21, useRef as useRef17, useState as
|
|
7360
|
+
import { useEffect as useEffect21, useRef as useRef17, useState as useState34 } from "react";
|
|
7026
7361
|
var fail = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
|
|
7027
7362
|
var RESTART = "Your account changed. The import was stopped; start it again.";
|
|
7028
7363
|
function useNativeImport(bridge, stillAllowed, onImported) {
|
|
7029
|
-
const [screen, setScreen] =
|
|
7030
|
-
const [busy, setBusy] =
|
|
7364
|
+
const [screen, setScreen] = useState34({ kind: "idle", message: null });
|
|
7365
|
+
const [busy, setBusy] = useState34(false);
|
|
7031
7366
|
const generation = useRef17(0);
|
|
7032
7367
|
const mounted = useRef17(false);
|
|
7033
7368
|
const op = useRef17(null);
|
|
@@ -7135,7 +7470,7 @@ function useNativeImport(bridge, stillAllowed, onImported) {
|
|
|
7135
7470
|
}
|
|
7136
7471
|
};
|
|
7137
7472
|
refreshRef.current = refresh;
|
|
7138
|
-
const
|
|
7473
|
+
const confirm15 = async () => {
|
|
7139
7474
|
if (screen.kind !== "preview") return;
|
|
7140
7475
|
const active = op.current;
|
|
7141
7476
|
if (!active?.organizationId || active.id !== screen.preview.operation_id) return;
|
|
@@ -7217,11 +7552,11 @@ function useNativeImport(bridge, stillAllowed, onImported) {
|
|
|
7217
7552
|
off?.();
|
|
7218
7553
|
};
|
|
7219
7554
|
}, [bridge]);
|
|
7220
|
-
return { screen, busy, begin, refresh: () => refresh(false), confirm:
|
|
7555
|
+
return { screen, busy, begin, refresh: () => refresh(false), confirm: confirm15, cancel, recover, reset };
|
|
7221
7556
|
}
|
|
7222
7557
|
|
|
7223
7558
|
// src/native/NativeImportPanel.tsx
|
|
7224
|
-
import { Fragment as
|
|
7559
|
+
import { Fragment as Fragment20, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
7225
7560
|
var TONE = {
|
|
7226
7561
|
eligible: "success",
|
|
7227
7562
|
committed: "success",
|
|
@@ -7232,15 +7567,15 @@ var TONE = {
|
|
|
7232
7567
|
};
|
|
7233
7568
|
function NativeImportPanel({ bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged }) {
|
|
7234
7569
|
if (!bridge) {
|
|
7235
|
-
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." }) }) });
|
|
7236
7571
|
}
|
|
7237
|
-
return /* @__PURE__ */
|
|
7572
|
+
return /* @__PURE__ */ jsx34(Importer, { bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged });
|
|
7238
7573
|
}
|
|
7239
7574
|
function Importer({ bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged }) {
|
|
7240
7575
|
const options = useMemo5(() => organizations.map((o) => ({ value: o.id, label: o.name })), [organizations]);
|
|
7241
|
-
const [organizationId, setOrganizationId] =
|
|
7242
|
-
const [limits, setLimits] =
|
|
7243
|
-
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);
|
|
7244
7579
|
const flow = useNativeImport(bridge, (id) => organizations.some((o) => o.id === id), onChanged);
|
|
7245
7580
|
const { screen, busy } = flow;
|
|
7246
7581
|
const orgName = organizations.find((o) => o.id === organizationId)?.name ?? "this organization";
|
|
@@ -7262,64 +7597,64 @@ function Importer({ bridge, readLimits, activeOrganizationId, organizations, onC
|
|
|
7262
7597
|
const active = status !== null && !TERMINAL_PHASES.has(status.phase);
|
|
7263
7598
|
const ready = preview?.slots.filter((s) => s.disposition === "eligible").length ?? 0;
|
|
7264
7599
|
const importNow = async () => {
|
|
7265
|
-
const yes = await
|
|
7600
|
+
const yes = await confirm13({ title: `Add ${plural2(ready, "passkey")} to ${orgName}?`, description: "Passkeys already there are skipped.", confirmLabel: "Import" });
|
|
7266
7601
|
if (yes) await flow.confirm();
|
|
7267
7602
|
};
|
|
7268
|
-
const footer = preview ? /* @__PURE__ */
|
|
7269
|
-
/* @__PURE__ */
|
|
7270
|
-
/* @__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: [
|
|
7271
7606
|
"Import ",
|
|
7272
7607
|
ready
|
|
7273
7608
|
] })
|
|
7274
|
-
] }) : status ? active ? /* @__PURE__ */
|
|
7275
|
-
/* @__PURE__ */
|
|
7276
|
-
/* @__PURE__ */
|
|
7277
|
-
] }) : /* @__PURE__ */
|
|
7278
|
-
/* @__PURE__ */
|
|
7279
|
-
/* @__PURE__ */
|
|
7280
|
-
] }) : /* @__PURE__ */
|
|
7281
|
-
return /* @__PURE__ */
|
|
7282
|
-
screen.kind === "idle" ? /* @__PURE__ */
|
|
7283
|
-
/* @__PURE__ */
|
|
7284
|
-
/* @__PURE__ */
|
|
7285
|
-
/* @__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" }) })
|
|
7286
7621
|
] }) : null,
|
|
7287
|
-
preview ? /* @__PURE__ */
|
|
7622
|
+
preview ? /* @__PURE__ */ jsx34(VaultSection, { title: `${ready} of ${preview.total} ready`, children: /* @__PURE__ */ jsx34(
|
|
7288
7623
|
Windowed,
|
|
7289
7624
|
{
|
|
7290
7625
|
items: preview.slots,
|
|
7291
|
-
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)
|
|
7292
7627
|
}
|
|
7293
7628
|
) }) : null,
|
|
7294
|
-
status && !preview ? /* @__PURE__ */
|
|
7295
|
-
/* @__PURE__ */
|
|
7296
|
-
/* @__PURE__ */
|
|
7297
|
-
/* @__PURE__ */
|
|
7298
|
-
/* @__PURE__ */
|
|
7299
|
-
status.uncertain > 0 ? /* @__PURE__ */
|
|
7300
|
-
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
|
|
7301
7636
|
] }) : null,
|
|
7302
|
-
screen.message ? /* @__PURE__ */
|
|
7303
|
-
/* @__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 })
|
|
7304
7639
|
] });
|
|
7305
7640
|
}
|
|
7306
7641
|
|
|
7307
7642
|
// src/extension/PageView.tsx
|
|
7308
|
-
import { useState as
|
|
7309
|
-
import { DropdownMenu as DropdownMenu5, DropdownMenuContent as DropdownMenuContent5, DropdownMenuItem as
|
|
7310
|
-
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";
|
|
7311
7646
|
import { GlobeIcon as GlobeIcon4 } from "@ai-matrx/design-system/icons";
|
|
7312
7647
|
|
|
7313
7648
|
// src/extension/CaptureCard.tsx
|
|
7314
|
-
import { useState as
|
|
7315
|
-
import { Button as
|
|
7316
|
-
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";
|
|
7317
7652
|
var SEARCH_FROM = 4;
|
|
7318
7653
|
function CaptureCard({ capture, onChanged }) {
|
|
7319
7654
|
const prompt = useSyncExternalStore3(capture.subscribe, capture.get, capture.get);
|
|
7320
7655
|
const notify = useNotify();
|
|
7321
|
-
const [busy, setBusy] =
|
|
7322
|
-
const [q, setQ] =
|
|
7656
|
+
const [busy, setBusy] = useState36(false);
|
|
7657
|
+
const [q, setQ] = useState36("");
|
|
7323
7658
|
if (!prompt) return null;
|
|
7324
7659
|
const decide = async (d) => {
|
|
7325
7660
|
setBusy(true);
|
|
@@ -7337,53 +7672,53 @@ function CaptureCard({ capture, onChanged }) {
|
|
|
7337
7672
|
const existing = prompt.existing;
|
|
7338
7673
|
const needle = q.trim().toLocaleLowerCase();
|
|
7339
7674
|
const shown = needle ? existing.filter((x) => x.name.toLocaleLowerCase().includes(needle)) : existing;
|
|
7340
|
-
return /* @__PURE__ */
|
|
7341
|
-
/* @__PURE__ */
|
|
7342
|
-
/* @__PURE__ */
|
|
7343
|
-
/* @__PURE__ */
|
|
7344
|
-
/* @__PURE__ */
|
|
7345
|
-
/* @__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 })
|
|
7346
7681
|
] }),
|
|
7347
|
-
/* @__PURE__ */
|
|
7682
|
+
/* @__PURE__ */ jsx35(Button30, { variant: "quiet", icon: /* @__PURE__ */ jsx35(XGlyph, {}), "aria-label": "Not now", disabled: busy, onClick: () => void decide({ action: "dismiss" }) })
|
|
7348
7683
|
] }),
|
|
7349
|
-
prompt.unavailable ? /* @__PURE__ */
|
|
7350
|
-
existing.length > 0 ? /* @__PURE__ */
|
|
7351
|
-
existing.length >= SEARCH_FROM ? /* @__PURE__ */
|
|
7352
|
-
/* @__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: [
|
|
7353
7688
|
shown.map((x) => {
|
|
7354
7689
|
const tag = distinguish(x, existing);
|
|
7355
|
-
return /* @__PURE__ */
|
|
7356
|
-
/* @__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: [
|
|
7357
7692
|
x.name,
|
|
7358
|
-
tag ? /* @__PURE__ */
|
|
7693
|
+
tag ? /* @__PURE__ */ jsxs33("span", { className: "text-muted-foreground", children: [
|
|
7359
7694
|
" \xB7 ",
|
|
7360
7695
|
tag
|
|
7361
7696
|
] }) : null
|
|
7362
7697
|
] }),
|
|
7363
|
-
/* @__PURE__ */
|
|
7698
|
+
/* @__PURE__ */ jsx35(Button30, { variant: "primary", disabled: busy, onClick: () => void decide({ action: "update", itemId: x.itemId }), "aria-label": `Update ${x.name}`, children: "Update" })
|
|
7364
7699
|
] }, x.itemId);
|
|
7365
7700
|
}),
|
|
7366
|
-
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
|
|
7367
7702
|
] })
|
|
7368
7703
|
] }) : null,
|
|
7369
|
-
/* @__PURE__ */
|
|
7370
|
-
/* @__PURE__ */
|
|
7371
|
-
/* @__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" })
|
|
7372
7707
|
] })
|
|
7373
7708
|
] })
|
|
7374
7709
|
] });
|
|
7375
7710
|
}
|
|
7376
7711
|
|
|
7377
7712
|
// src/extension/FillSetupCard.tsx
|
|
7378
|
-
import { useRef as useRef18, useState as
|
|
7379
|
-
import { Button as
|
|
7380
|
-
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";
|
|
7381
7716
|
function FillSetupCard({ fillSetup }) {
|
|
7382
7717
|
const notify = useNotify();
|
|
7383
7718
|
const state = useSyncExternalStore4(fillSetup.subscribe, fillSetup.get, fillSetup.get);
|
|
7384
7719
|
const box = useRef18(null);
|
|
7385
|
-
const [busy, setBusy] =
|
|
7386
|
-
const [error, setError] =
|
|
7720
|
+
const [busy, setBusy] = useState37(false);
|
|
7721
|
+
const [error, setError] = useState37(null);
|
|
7387
7722
|
if (state.status !== "off") return null;
|
|
7388
7723
|
const finish = async (run) => {
|
|
7389
7724
|
setBusy(true);
|
|
@@ -7409,15 +7744,15 @@ function FillSetupCard({ fillSetup }) {
|
|
|
7409
7744
|
const neither = m !== null && !m.password && !m.passkey;
|
|
7410
7745
|
const showPassword = !neither && (m === null || m.password);
|
|
7411
7746
|
const showPasskey = state.passkey !== null && (neither || m === null || m.passkey);
|
|
7412
|
-
return /* @__PURE__ */
|
|
7413
|
-
/* @__PURE__ */
|
|
7414
|
-
/* @__PURE__ */
|
|
7415
|
-
/* @__PURE__ */
|
|
7416
|
-
/* @__PURE__ */
|
|
7417
|
-
/* @__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." })
|
|
7418
7753
|
] })
|
|
7419
7754
|
] }),
|
|
7420
|
-
showPassword ? /* @__PURE__ */
|
|
7755
|
+
showPassword ? /* @__PURE__ */ jsxs34(
|
|
7421
7756
|
"form",
|
|
7422
7757
|
{
|
|
7423
7758
|
className: "flex items-center gap-2",
|
|
@@ -7426,42 +7761,42 @@ function FillSetupCard({ fillSetup }) {
|
|
|
7426
7761
|
withPassword();
|
|
7427
7762
|
},
|
|
7428
7763
|
children: [
|
|
7429
|
-
/* @__PURE__ */
|
|
7430
|
-
/* @__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" })
|
|
7431
7766
|
]
|
|
7432
7767
|
}
|
|
7433
7768
|
) : null,
|
|
7434
|
-
showPasskey ? /* @__PURE__ */
|
|
7769
|
+
showPasskey ? /* @__PURE__ */ jsx36(Button31, { variant: "outline", iconEnd: /* @__PURE__ */ jsx36(ExternalGlyph, {}), disabled: busy, onClick: () => {
|
|
7435
7770
|
setError(null);
|
|
7436
7771
|
fillSetup.openPasskey();
|
|
7437
7772
|
}, children: neither ? "Add a passkey" : "Use a passkey" }) : null,
|
|
7438
|
-
showPasskey && state.awaitingPasskey && state.passkey ? /* @__PURE__ */
|
|
7439
|
-
/* @__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: [
|
|
7440
7775
|
"Approve code ",
|
|
7441
|
-
/* @__PURE__ */
|
|
7776
|
+
/* @__PURE__ */ jsx36("span", { className: "font-mono text-foreground", children: state.passkey.code }),
|
|
7442
7777
|
" on that page."
|
|
7443
7778
|
] }),
|
|
7444
|
-
/* @__PURE__ */
|
|
7779
|
+
/* @__PURE__ */ jsx36(Button31, { variant: "primary", disabled: busy, onClick: () => void finish(() => fillSetup.finishPasskey()), children: "I approved" })
|
|
7445
7780
|
] }) : null,
|
|
7446
|
-
error ? /* @__PURE__ */
|
|
7781
|
+
error ? /* @__PURE__ */ jsx36("p", { role: "alert", className: "text-xs text-destructive", children: error }) : null
|
|
7447
7782
|
] });
|
|
7448
7783
|
}
|
|
7449
7784
|
|
|
7450
7785
|
// src/extension/PageGenerator.tsx
|
|
7451
|
-
import { useState as
|
|
7786
|
+
import { useState as useState38 } from "react";
|
|
7452
7787
|
import { Popover as Popover2, PopoverContent as PopoverContent2, PopoverTrigger as PopoverTrigger2 } from "@ai-matrx/design-system";
|
|
7453
|
-
import { Button as
|
|
7454
|
-
import { CopyIcon as
|
|
7455
|
-
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";
|
|
7456
7791
|
var HOLD_MS = 6e4;
|
|
7457
7792
|
function PageGenerator({ fields }) {
|
|
7458
7793
|
const limits = useGeneratorLimitsSource();
|
|
7459
7794
|
const copy = useCopy();
|
|
7460
7795
|
const held = useTransientSecret(HOLD_MS);
|
|
7461
|
-
const [open, setOpen] =
|
|
7462
|
-
const [busy, setBusy] =
|
|
7463
|
-
const [targets, setTargets] =
|
|
7464
|
-
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);
|
|
7465
7800
|
if (!limits) return null;
|
|
7466
7801
|
const say3 = setSaid;
|
|
7467
7802
|
const put = async (targetId, value2) => {
|
|
@@ -7503,30 +7838,30 @@ function PageGenerator({ fields }) {
|
|
|
7503
7838
|
}
|
|
7504
7839
|
};
|
|
7505
7840
|
const value = held.value;
|
|
7506
|
-
return /* @__PURE__ */
|
|
7507
|
-
/* @__PURE__ */
|
|
7841
|
+
return /* @__PURE__ */ jsxs35(Fragment22, { children: [
|
|
7842
|
+
/* @__PURE__ */ jsx37(
|
|
7508
7843
|
VaultRow,
|
|
7509
7844
|
{
|
|
7510
7845
|
label: "New password",
|
|
7511
|
-
actions: /* @__PURE__ */
|
|
7512
|
-
value ? /* @__PURE__ */
|
|
7513
|
-
/* @__PURE__ */
|
|
7514
|
-
/* @__PURE__ */
|
|
7515
|
-
/* @__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 })
|
|
7516
7851
|
] })
|
|
7517
7852
|
] }),
|
|
7518
|
-
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" })
|
|
7519
7854
|
}
|
|
7520
7855
|
),
|
|
7521
|
-
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
|
|
7522
7857
|
] });
|
|
7523
7858
|
}
|
|
7524
7859
|
|
|
7525
7860
|
// src/extension/PageView.tsx
|
|
7526
|
-
import { jsx as
|
|
7861
|
+
import { jsx as jsx38, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
7527
7862
|
function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, items, definitions, onOpen, onNewForPage, onBrowse, onChanged, header }) {
|
|
7528
|
-
const [running, setRunning] =
|
|
7529
|
-
const [said, setSaid] =
|
|
7863
|
+
const [running, setRunning] = useState39(null);
|
|
7864
|
+
const [said, setSaid] = useState39(null);
|
|
7530
7865
|
const site = pageSite(page.url);
|
|
7531
7866
|
const state = page.matchState ?? { status: "ready" };
|
|
7532
7867
|
const fillable = new Set(page.fillableItemIds ?? page.matchingItemIds);
|
|
@@ -7547,20 +7882,20 @@ function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, ite
|
|
|
7547
7882
|
}
|
|
7548
7883
|
};
|
|
7549
7884
|
let body;
|
|
7550
|
-
if (!page.url) body = /* @__PURE__ */
|
|
7885
|
+
if (!page.url) body = /* @__PURE__ */ jsx38(Empty, { children: "No page is open in this tab." });
|
|
7551
7886
|
else if (state.status === "error") {
|
|
7552
|
-
body = /* @__PURE__ */
|
|
7553
|
-
/* @__PURE__ */
|
|
7554
|
-
/* @__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" })
|
|
7555
7890
|
] });
|
|
7556
7891
|
} else if (state.status === "loading") {
|
|
7557
|
-
body = /* @__PURE__ */
|
|
7558
|
-
/* @__PURE__ */
|
|
7559
|
-
/* @__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" })
|
|
7560
7895
|
] }, n)) });
|
|
7561
|
-
} else if (matches.length === 0) body = /* @__PURE__ */
|
|
7896
|
+
} else if (matches.length === 0) body = /* @__PURE__ */ jsx38(Empty, { children: "No saved login for this site." });
|
|
7562
7897
|
else {
|
|
7563
|
-
body = /* @__PURE__ */
|
|
7898
|
+
body = /* @__PURE__ */ jsx38("ul", { className: "flex flex-col", children: matches.map(({ itemId, item }) => /* @__PURE__ */ jsx38(
|
|
7564
7899
|
MatchRow,
|
|
7565
7900
|
{
|
|
7566
7901
|
itemId,
|
|
@@ -7577,40 +7912,40 @@ function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, ite
|
|
|
7577
7912
|
itemId
|
|
7578
7913
|
)) });
|
|
7579
7914
|
}
|
|
7580
|
-
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: [
|
|
7581
7916
|
header,
|
|
7582
|
-
/* @__PURE__ */
|
|
7583
|
-
/* @__PURE__ */
|
|
7584
|
-
/* @__PURE__ */
|
|
7585
|
-
page.refresh ? /* @__PURE__ */
|
|
7586
|
-
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
|
|
7587
7922
|
] }),
|
|
7588
|
-
fillSetup ? /* @__PURE__ */
|
|
7589
|
-
capture ? /* @__PURE__ */
|
|
7590
|
-
/* @__PURE__ */
|
|
7923
|
+
fillSetup ? /* @__PURE__ */ jsx38(FillSetupCard, { fillSetup }) : null,
|
|
7924
|
+
capture ? /* @__PURE__ */ jsx38(CaptureCard, { capture, onChanged }) : null,
|
|
7925
|
+
/* @__PURE__ */ jsx38(
|
|
7591
7926
|
VaultSection,
|
|
7592
7927
|
{
|
|
7593
7928
|
title: "This site",
|
|
7594
|
-
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,
|
|
7595
7930
|
children: body
|
|
7596
7931
|
}
|
|
7597
7932
|
),
|
|
7598
|
-
said ? /* @__PURE__ */
|
|
7599
|
-
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
|
|
7600
7935
|
] }) });
|
|
7601
7936
|
}
|
|
7602
7937
|
function Outcome({ said, onDismiss }) {
|
|
7603
|
-
return /* @__PURE__ */
|
|
7604
|
-
said.tone === "success" ? /* @__PURE__ */
|
|
7605
|
-
/* @__PURE__ */
|
|
7606
|
-
/* @__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 })
|
|
7607
7942
|
] });
|
|
7608
7943
|
}
|
|
7609
7944
|
function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFill, onSignIn }) {
|
|
7610
7945
|
const confirmed = useConfirmed();
|
|
7611
7946
|
const copy = useCopy();
|
|
7612
7947
|
const notify = useNotify();
|
|
7613
|
-
const [reading, setReading] =
|
|
7948
|
+
const [reading, setReading] = useState39(false);
|
|
7614
7949
|
const usable = item?.capabilities.canUse ?? false;
|
|
7615
7950
|
const user = usable ? item?.fields.find((f) => USERNAME_KEYS.test(f.key) && f.handling !== "sealed" && f.active) : void 0;
|
|
7616
7951
|
const secret = usable && item?.capabilities.canReveal ? item?.fields.find((f) => f.key === "password" && f.handling === "revealable" && f.active) : void 0;
|
|
@@ -7626,27 +7961,27 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
|
|
|
7626
7961
|
}
|
|
7627
7962
|
};
|
|
7628
7963
|
const subtitle = [item ? loginSiteOf(item) || item.definitionLabel : "", tag].filter(Boolean).join(" \xB7 ");
|
|
7629
|
-
return /* @__PURE__ */
|
|
7630
|
-
/* @__PURE__ */
|
|
7631
|
-
/* @__PURE__ */
|
|
7632
|
-
/* @__PURE__ */
|
|
7633
|
-
/* @__PURE__ */
|
|
7634
|
-
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
|
|
7635
7970
|
] })
|
|
7636
7971
|
] }),
|
|
7637
|
-
onFill ? /* @__PURE__ */
|
|
7638
|
-
user && item ? /* @__PURE__ */
|
|
7639
|
-
secret && item ? /* @__PURE__ */
|
|
7640
|
-
otp ? /* @__PURE__ */
|
|
7641
|
-
onSignIn ? /* @__PURE__ */
|
|
7642
|
-
/* @__PURE__ */
|
|
7643
|
-
/* @__PURE__ */
|
|
7644
|
-
/* @__PURE__ */
|
|
7645
|
-
/* @__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" }),
|
|
7646
7981
|
"Sign me in"
|
|
7647
7982
|
] }),
|
|
7648
|
-
/* @__PURE__ */
|
|
7649
|
-
/* @__PURE__ */
|
|
7983
|
+
/* @__PURE__ */ jsxs36(DropdownMenuItem5, { onSelect: () => onOpen(itemId), children: [
|
|
7984
|
+
/* @__PURE__ */ jsx38(ListGlyph, { className: "size-4" }),
|
|
7650
7985
|
"Open item"
|
|
7651
7986
|
] })
|
|
7652
7987
|
] })
|
|
@@ -7655,11 +7990,12 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
|
|
|
7655
7990
|
}
|
|
7656
7991
|
|
|
7657
7992
|
// src/Sidebar.tsx
|
|
7658
|
-
import { useState as
|
|
7993
|
+
import { useState as useState40 } from "react";
|
|
7659
7994
|
import { cn as cn15, useLook as useLook2 } from "@ai-matrx/design-system";
|
|
7660
|
-
import { Select as
|
|
7995
|
+
import { Select as Select11 } from "@ai-matrx/design-system/controls";
|
|
7661
7996
|
import { GlobeIcon as GlobeIcon5 } from "@ai-matrx/design-system/icons";
|
|
7662
|
-
import { jsx as
|
|
7997
|
+
import { jsx as jsx39, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
7998
|
+
var AUTHENTICATOR_LABEL = "Authenticator";
|
|
7663
7999
|
function vaultChoices(items, organizations, current) {
|
|
7664
8000
|
const n = (f) => items.filter(f).length;
|
|
7665
8001
|
const shared = n((i) => i.owner.kind === "shared");
|
|
@@ -7672,7 +8008,7 @@ function vaultChoices(items, organizations, current) {
|
|
|
7672
8008
|
];
|
|
7673
8009
|
}
|
|
7674
8010
|
function VaultSelect({ value, choices, onChange }) {
|
|
7675
|
-
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) })) });
|
|
7676
8012
|
}
|
|
7677
8013
|
var CATEGORY_GLYPHS = { logins: GlobeIcon5, passkeys: ShieldGlyph, api: KeyGlyph, oauth: PlugGlyph, infra: DatabaseGlyph, env: TerminalGlyph, files: FileGlyph, other: NoteGlyph };
|
|
7678
8014
|
var familyOf = (key, definitions) => definitions.find((d) => d.key === key)?.family ?? "generic";
|
|
@@ -7699,7 +8035,7 @@ function buildViews(items, definitions, favoriteIds2, recentIds2) {
|
|
|
7699
8035
|
function viewLabel(view, views) {
|
|
7700
8036
|
if (view === "favorites") return "Favorites";
|
|
7701
8037
|
if (view === "recent") return "Recently opened";
|
|
7702
|
-
if (view === "authenticator") return
|
|
8038
|
+
if (view === "authenticator") return AUTHENTICATOR_LABEL;
|
|
7703
8039
|
if (view === "trash") return "Trash";
|
|
7704
8040
|
if (view === "page") return "This page";
|
|
7705
8041
|
return [...views.categories, ...views.tags].find((v) => v.view === view)?.label ?? "All items";
|
|
@@ -7710,7 +8046,7 @@ function viewOptions(views, allCount, deletedCount, hasFavorites, hasRecents, ha
|
|
|
7710
8046
|
{ value: "all", label: "Every category", meta: String(allCount) },
|
|
7711
8047
|
...hasFavorites ? [{ value: "favorites", label: "Favorites", meta: views.favorites === void 0 ? "" : String(views.favorites) }] : [],
|
|
7712
8048
|
...hasRecents ? [{ value: "recent", label: "Recently opened", meta: views.recent === void 0 ? "" : String(views.recent) }] : [],
|
|
7713
|
-
{ value: "authenticator", label:
|
|
8049
|
+
{ value: "authenticator", label: AUTHENTICATOR_LABEL, meta: String(views.authenticator) },
|
|
7714
8050
|
...views.categories.map((v) => ({ value: v.view, label: v.label, meta: String(v.count) })),
|
|
7715
8051
|
...views.tags.map((v) => ({ value: v.view, label: `#${v.label}`, meta: String(v.count) })),
|
|
7716
8052
|
{ value: "trash", label: "Trash", meta: String(deletedCount) }
|
|
@@ -7718,7 +8054,7 @@ function viewOptions(views, allCount, deletedCount, hasFavorites, hasRecents, ha
|
|
|
7718
8054
|
}
|
|
7719
8055
|
function Entry({ on, glyph: Icon, label, count: count2, onClick }) {
|
|
7720
8056
|
const desktop = useLook2() === "desktop";
|
|
7721
|
-
return /* @__PURE__ */
|
|
8057
|
+
return /* @__PURE__ */ jsxs37(
|
|
7722
8058
|
"button",
|
|
7723
8059
|
{
|
|
7724
8060
|
type: "button",
|
|
@@ -7726,62 +8062,62 @@ function Entry({ on, glyph: Icon, label, count: count2, onClick }) {
|
|
|
7726
8062
|
onClick,
|
|
7727
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"),
|
|
7728
8064
|
children: [
|
|
7729
|
-
/* @__PURE__ */
|
|
7730
|
-
/* @__PURE__ */
|
|
7731
|
-
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
|
|
7732
8068
|
]
|
|
7733
8069
|
}
|
|
7734
8070
|
);
|
|
7735
8071
|
}
|
|
7736
8072
|
function Group({ title, children }) {
|
|
7737
|
-
return /* @__PURE__ */
|
|
7738
|
-
/* @__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 }),
|
|
7739
8075
|
children
|
|
7740
8076
|
] });
|
|
7741
8077
|
}
|
|
7742
8078
|
function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false }) {
|
|
7743
|
-
const [tagsOpen, setTagsOpen] =
|
|
7744
|
-
return /* @__PURE__ */
|
|
7745
|
-
/* @__PURE__ */
|
|
7746
|
-
/* @__PURE__ */
|
|
7747
|
-
/* @__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 }) })
|
|
7748
8084
|
] }),
|
|
7749
|
-
/* @__PURE__ */
|
|
7750
|
-
/* @__PURE__ */
|
|
7751
|
-
hasPage ? /* @__PURE__ */
|
|
7752
|
-
/* @__PURE__ */
|
|
7753
|
-
hasFavorites ? /* @__PURE__ */
|
|
7754
|
-
hasRecents ? /* @__PURE__ */
|
|
7755
|
-
/* @__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") })
|
|
7756
8092
|
] }),
|
|
7757
|
-
views.categories.length > 0 ? /* @__PURE__ */
|
|
7758
|
-
views.tags.length > 0 ? /* @__PURE__ */
|
|
7759
|
-
/* @__PURE__ */
|
|
7760
|
-
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" }),
|
|
7761
8097
|
"Tags",
|
|
7762
|
-
/* @__PURE__ */
|
|
8098
|
+
/* @__PURE__ */ jsx39("span", { className: "ml-auto tabular-nums", children: views.tags.length })
|
|
7763
8099
|
] }),
|
|
7764
|
-
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
|
|
7765
8101
|
] }) : null
|
|
7766
8102
|
] }),
|
|
7767
|
-
/* @__PURE__ */
|
|
7768
|
-
/* @__PURE__ */
|
|
7769
|
-
/* @__PURE__ */
|
|
7770
|
-
/* @__PURE__ */
|
|
7771
|
-
/* @__PURE__ */
|
|
7772
|
-
/* @__PURE__ */
|
|
7773
|
-
hasNativeImport ? /* @__PURE__ */
|
|
7774
|
-
nativeProvider && nativeProvider.status !== "unavailable" ? /* @__PURE__ */
|
|
7775
|
-
/* @__PURE__ */
|
|
7776
|
-
/* @__PURE__ */
|
|
7777
|
-
/* @__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" })
|
|
7778
8114
|
] }) : null
|
|
7779
8115
|
] })
|
|
7780
8116
|
] });
|
|
7781
8117
|
}
|
|
7782
8118
|
|
|
7783
8119
|
// src/VaultApp.tsx
|
|
7784
|
-
import { jsx as
|
|
8120
|
+
import { jsx as jsx40, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
7785
8121
|
var FULL_AT = 1120;
|
|
7786
8122
|
var SPLIT_AT = 640;
|
|
7787
8123
|
var NO_HOST = {};
|
|
@@ -7800,7 +8136,7 @@ var generatorLimitsFrom = (knobs) => knobs ? async () => {
|
|
|
7800
8136
|
} : void 0;
|
|
7801
8137
|
function ImportWithLimits(props) {
|
|
7802
8138
|
const { knobs, ...rest } = props;
|
|
7803
|
-
const [state, setState] =
|
|
8139
|
+
const [state, setState] = useState41(null);
|
|
7804
8140
|
useEffect23(() => {
|
|
7805
8141
|
if (!knobs) return setState({ error: "Import is not set up for this organization yet." });
|
|
7806
8142
|
knobs().then(
|
|
@@ -7814,18 +8150,18 @@ function ImportWithLimits(props) {
|
|
|
7814
8150
|
(e) => setState({ error: e instanceof Error ? e.message : "The import settings could not be read." })
|
|
7815
8151
|
);
|
|
7816
8152
|
}, [knobs]);
|
|
7817
|
-
if (state && "limits" in state) return /* @__PURE__ */
|
|
7818
|
-
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" }) });
|
|
7819
8155
|
}
|
|
7820
8156
|
function VaultApp(props) {
|
|
7821
8157
|
const lock = props.host?.lock;
|
|
7822
8158
|
const locked = useLocked(lock);
|
|
7823
8159
|
const port = useMemo6(() => lock ? guardPort(props.port, () => lock.locked()) : props.port, [props.port, lock]);
|
|
7824
|
-
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 }) }) }) }) }) }) }) });
|
|
7825
8161
|
}
|
|
7826
8162
|
function LockedScreen({ lock }) {
|
|
7827
|
-
const [busy, setBusy] =
|
|
7828
|
-
const [error, setError] =
|
|
8163
|
+
const [busy, setBusy] = useState41(false);
|
|
8164
|
+
const [error, setError] = useState41(null);
|
|
7829
8165
|
const unlock = async () => {
|
|
7830
8166
|
setBusy(true);
|
|
7831
8167
|
setError(null);
|
|
@@ -7837,28 +8173,29 @@ function LockedScreen({ lock }) {
|
|
|
7837
8173
|
setBusy(false);
|
|
7838
8174
|
}
|
|
7839
8175
|
};
|
|
7840
|
-
return /* @__PURE__ */
|
|
7841
|
-
/* @__PURE__ */
|
|
7842
|
-
/* @__PURE__ */
|
|
7843
|
-
/* @__PURE__ */
|
|
7844
|
-
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
|
|
7845
8181
|
] });
|
|
7846
8182
|
}
|
|
7847
|
-
function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocationChange }) {
|
|
8183
|
+
function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocationChange, onInventory }) {
|
|
7848
8184
|
const rootRef = useRef19(null);
|
|
7849
8185
|
const width = useElementWidth(rootRef);
|
|
7850
8186
|
const mode = layout !== "auto" ? layout : width >= FULL_AT ? "full" : width >= SPLIT_AT ? "split" : "stack";
|
|
7851
8187
|
const notify = useNotify();
|
|
7852
|
-
const [snap, setSnap] =
|
|
7853
|
-
const [items, setItems] =
|
|
7854
|
-
const [deleted, setDeleted] =
|
|
7855
|
-
const [favorites, setFavorites] =
|
|
7856
|
-
const [recents, setRecents] =
|
|
7857
|
-
const [error, setError] =
|
|
7858
|
-
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);
|
|
7859
8195
|
const loc = location ?? inner;
|
|
7860
8196
|
const dirty = useRef19(false);
|
|
7861
|
-
const [notice, setNotice] =
|
|
8197
|
+
const [notice, setNotice] = useState41(null);
|
|
8198
|
+
const [firstCode, setFirstCode] = useState41(null);
|
|
7862
8199
|
const move = useCallback5(
|
|
7863
8200
|
(next, how) => {
|
|
7864
8201
|
if (!location) setInner(next);
|
|
@@ -7878,7 +8215,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7878
8215
|
move(next, how);
|
|
7879
8216
|
};
|
|
7880
8217
|
if (leaving && dirty.current) {
|
|
7881
|
-
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());
|
|
7882
8219
|
return;
|
|
7883
8220
|
}
|
|
7884
8221
|
proceed();
|
|
@@ -7911,7 +8248,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7911
8248
|
}, []);
|
|
7912
8249
|
const knobsRef = useRef19(host.knobs);
|
|
7913
8250
|
knobsRef.current = host.knobs;
|
|
7914
|
-
const [signedOut, setSignedOut] =
|
|
8251
|
+
const [signedOut, setSignedOut] = useState41(false);
|
|
7915
8252
|
const load = useCallback5(() => {
|
|
7916
8253
|
setError(null);
|
|
7917
8254
|
port.load().then((s) => {
|
|
@@ -7931,6 +8268,11 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7931
8268
|
port.lists.recents?.list().then(setRecents, () => void 0);
|
|
7932
8269
|
}, [port]);
|
|
7933
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]);
|
|
7934
8276
|
useEffect23(() => {
|
|
7935
8277
|
if (!loc.itemId || !port.lists.recents) return;
|
|
7936
8278
|
const id = loc.itemId;
|
|
@@ -7950,7 +8292,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7950
8292
|
return inView(i, loc.view);
|
|
7951
8293
|
});
|
|
7952
8294
|
if (loc.view === "recent" && recents) return [...filtered].sort((a, b) => recents.indexOf(a.id) - recents.indexOf(b.id));
|
|
7953
|
-
return sortItems(filtered, loc.sort);
|
|
8295
|
+
return sortItems(filtered, loc.sort, recents);
|
|
7954
8296
|
}, [inThisVault, loc.view, loc.q, loc.sort, favorites, recents, definitions]);
|
|
7955
8297
|
const choices = useMemo6(() => vaultChoices(items, orgs, loc.vault), [items, orgs, loc.vault]);
|
|
7956
8298
|
const matchingIds = useMemo6(() => host.page ? new Set(host.page.matchingItemIds) : void 0, [host.page]);
|
|
@@ -7977,70 +8319,86 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
7977
8319
|
});
|
|
7978
8320
|
};
|
|
7979
8321
|
if (error) {
|
|
7980
|
-
return /* @__PURE__ */
|
|
7981
|
-
/* @__PURE__ */
|
|
7982
|
-
/* @__PURE__ */
|
|
7983
|
-
/* @__PURE__ */
|
|
7984
|
-
/* @__PURE__ */
|
|
7985
|
-
signedOut && host.signIn ? /* @__PURE__ */
|
|
7986
|
-
/* @__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" })
|
|
7987
8329
|
] })
|
|
7988
8330
|
] });
|
|
7989
8331
|
}
|
|
7990
8332
|
if (!snap) {
|
|
7991
|
-
return /* @__PURE__ */
|
|
7992
|
-
/* @__PURE__ */
|
|
7993
|
-
/* @__PURE__ */
|
|
7994
|
-
/* @__PURE__ */
|
|
7995
|
-
/* @__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" })
|
|
7996
8338
|
] })
|
|
7997
8339
|
] }, n)) }) });
|
|
7998
8340
|
}
|
|
7999
8341
|
const hasFavorites = port.lists.favorites !== void 0;
|
|
8000
8342
|
const title = loc.vault === "all" && loc.view === "all" ? "All items" : viewLabel(loc.view, views);
|
|
8001
|
-
const compactHeader = mode === "full" ? void 0 : /* @__PURE__ */
|
|
8002
|
-
/* @__PURE__ */
|
|
8003
|
-
/* @__PURE__ */
|
|
8004
|
-
/* @__PURE__ */
|
|
8005
|
-
|
|
8006
|
-
|
|
8007
|
-
|
|
8008
|
-
|
|
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,
|
|
8348
|
+
{
|
|
8349
|
+
variant: loc.view === "authenticator" ? "outline" : "quiet",
|
|
8350
|
+
icon: /* @__PURE__ */ jsx40(LockGlyph, {}),
|
|
8351
|
+
"aria-label": AUTHENTICATOR_LABEL,
|
|
8352
|
+
"aria-pressed": loc.view === "authenticator",
|
|
8353
|
+
title: AUTHENTICATOR_LABEL,
|
|
8354
|
+
onClick: () => go({ view: loc.view === "authenticator" ? "all" : "authenticator", itemId: null, mode: "view", panel: null }),
|
|
8355
|
+
children: mode === "split" ? AUTHENTICATOR_LABEL : null
|
|
8356
|
+
}
|
|
8357
|
+
),
|
|
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" }),
|
|
8009
8363
|
"Import"
|
|
8010
8364
|
] }),
|
|
8011
|
-
/* @__PURE__ */
|
|
8012
|
-
/* @__PURE__ */
|
|
8365
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => go({ panel: "export" }), children: [
|
|
8366
|
+
/* @__PURE__ */ jsx40(ExportGlyph, { className: "size-4" }),
|
|
8013
8367
|
"Export"
|
|
8014
8368
|
] }),
|
|
8015
|
-
/* @__PURE__ */
|
|
8016
|
-
/* @__PURE__ */
|
|
8369
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => go({ panel: "backup" }), children: [
|
|
8370
|
+
/* @__PURE__ */ jsx40(SafeGlyph, { className: "size-4" }),
|
|
8017
8371
|
"Backup"
|
|
8018
8372
|
] }),
|
|
8019
|
-
/* @__PURE__ */
|
|
8020
|
-
/* @__PURE__ */
|
|
8373
|
+
/* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => go({ panel: "devices" }), children: [
|
|
8374
|
+
/* @__PURE__ */ jsx40(ShieldGlyph, { className: "size-4" }),
|
|
8021
8375
|
"Browsers that fill"
|
|
8022
8376
|
] }),
|
|
8023
|
-
host.nativeImport ? /* @__PURE__ */
|
|
8024
|
-
/* @__PURE__ */
|
|
8377
|
+
host.nativeImport ? /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => go({ panel: "import-passkeys" }), children: [
|
|
8378
|
+
/* @__PURE__ */ jsx40(ImportGlyph, { className: "size-4" }),
|
|
8025
8379
|
"Import passkeys"
|
|
8026
8380
|
] }) : null,
|
|
8027
|
-
host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */
|
|
8028
|
-
/* @__PURE__ */
|
|
8381
|
+
host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: host.nativeProvider.openSetup, children: [
|
|
8382
|
+
/* @__PURE__ */ jsx40(ShieldGlyph, { className: "size-4" }),
|
|
8029
8383
|
"System AutoFill"
|
|
8030
8384
|
] }) : null,
|
|
8031
|
-
host.lock?.lock ? /* @__PURE__ */
|
|
8032
|
-
/* @__PURE__ */
|
|
8385
|
+
host.lock?.lock ? /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => void host.lock?.lock?.(), children: [
|
|
8386
|
+
/* @__PURE__ */ jsx40(LockGlyph, { className: "size-4" }),
|
|
8033
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"
|
|
8034
8392
|
] }) : null
|
|
8035
8393
|
] })
|
|
8036
8394
|
] })
|
|
8037
8395
|
] });
|
|
8038
|
-
const viewHeader = /* @__PURE__ */
|
|
8396
|
+
const viewHeader = /* @__PURE__ */ jsxs38("div", { className: "flex flex-col gap-2", children: [
|
|
8039
8397
|
compactHeader,
|
|
8040
|
-
/* @__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)}` })
|
|
8041
8399
|
] });
|
|
8042
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 };
|
|
8043
|
-
const pageView = loc.view === "page" && host.page && !loc.q ? /* @__PURE__ */
|
|
8401
|
+
const pageView = loc.view === "page" && host.page && !loc.q ? /* @__PURE__ */ jsx40(
|
|
8044
8402
|
PageView,
|
|
8045
8403
|
{
|
|
8046
8404
|
port,
|
|
@@ -8058,8 +8416,8 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8058
8416
|
...compactHeader ? { header: compactHeader } : {}
|
|
8059
8417
|
}
|
|
8060
8418
|
) : null;
|
|
8061
|
-
const specialView = pageView ?? (loc.view === "authenticator" ? /* @__PURE__ */
|
|
8062
|
-
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(
|
|
8063
8421
|
ItemList,
|
|
8064
8422
|
{
|
|
8065
8423
|
title,
|
|
@@ -8073,6 +8431,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8073
8431
|
onQuery: (q) => go({ q }, "replace"),
|
|
8074
8432
|
sort: loc.sort,
|
|
8075
8433
|
onSort: (sort) => go({ sort }, "replace"),
|
|
8434
|
+
canSortViewed: port.lists.recents !== void 0,
|
|
8076
8435
|
onNew: () => go({ itemId: null, mode: "new", kind: null, panel: null }),
|
|
8077
8436
|
...matchingIds ? { matchingIds } : {},
|
|
8078
8437
|
...compactHeader ? { header: compactHeader } : {}
|
|
@@ -8086,9 +8445,9 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8086
8445
|
const onPanel = (panel2) => go({ panel: panel2 }, "push");
|
|
8087
8446
|
let detail;
|
|
8088
8447
|
if (loc.mode === "new" && !kindDefinition) {
|
|
8089
|
-
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 }) });
|
|
8090
8449
|
} else if (loc.mode === "new" && kindDefinition) {
|
|
8091
|
-
detail = /* @__PURE__ */
|
|
8450
|
+
detail = /* @__PURE__ */ jsx40(
|
|
8092
8451
|
ItemPane,
|
|
8093
8452
|
{
|
|
8094
8453
|
port,
|
|
@@ -8101,9 +8460,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8101
8460
|
seed: { name: guess?.name ?? "", url: guess?.url ?? loc.url.trim() },
|
|
8102
8461
|
onBack: () => go({ kind: null }),
|
|
8103
8462
|
onMode: () => void 0,
|
|
8104
|
-
onSaved: (item, _wasNew, n) => {
|
|
8463
|
+
onSaved: (item, _wasNew, n, enrolled) => {
|
|
8105
8464
|
replaceItem(item);
|
|
8106
8465
|
dirty.current = false;
|
|
8466
|
+
if (enrolled) setFirstCode(item);
|
|
8107
8467
|
move({ ...loc, itemId: item.id, mode: "view", kind: null, url: "", panel: null }, "replace");
|
|
8108
8468
|
setNotice(n);
|
|
8109
8469
|
notify("Saved");
|
|
@@ -8119,7 +8479,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8119
8479
|
`new-${kindDefinition.key}`
|
|
8120
8480
|
);
|
|
8121
8481
|
} else if (selected) {
|
|
8122
|
-
detail = /* @__PURE__ */
|
|
8482
|
+
detail = /* @__PURE__ */ jsx40(
|
|
8123
8483
|
ItemPane,
|
|
8124
8484
|
{
|
|
8125
8485
|
port,
|
|
@@ -8132,9 +8492,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8132
8492
|
onBack: back,
|
|
8133
8493
|
onMode: (m) => go({ mode: m, panel: null }),
|
|
8134
8494
|
notice,
|
|
8135
|
-
onSaved: (item, _wasNew, n) => {
|
|
8495
|
+
onSaved: (item, _wasNew, n, enrolled) => {
|
|
8136
8496
|
replaceItem(item);
|
|
8137
8497
|
dirty.current = false;
|
|
8498
|
+
if (enrolled) setFirstCode(item);
|
|
8138
8499
|
move({ ...loc, mode: "view" }, "replace");
|
|
8139
8500
|
setNotice(n);
|
|
8140
8501
|
notify("Saved");
|
|
@@ -8162,23 +8523,23 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8162
8523
|
selected.id
|
|
8163
8524
|
);
|
|
8164
8525
|
} else if (loc.itemId) {
|
|
8165
|
-
detail = /* @__PURE__ */
|
|
8526
|
+
detail = /* @__PURE__ */ jsx40(Blank, { children: "This item is not in your vault, or you cannot see it." });
|
|
8166
8527
|
} else {
|
|
8167
|
-
detail = /* @__PURE__ */
|
|
8528
|
+
detail = /* @__PURE__ */ jsx40(Blank, { children: visible.length === 0 ? "" : "Select an item" });
|
|
8168
8529
|
}
|
|
8169
8530
|
const [panelName, panelArg] = (loc.panel ?? "").split(/:(.*)/s);
|
|
8170
8531
|
const closePanel = () => go({ panel: null }, "push");
|
|
8171
8532
|
const vaultPanelProps = { port, host, items, definitions, organizations: orgs, onClose: closePanel, onChanged: load };
|
|
8172
8533
|
let panel = null;
|
|
8173
|
-
if (panelName === "import") panel = /* @__PURE__ */
|
|
8174
|
-
else if (panelName === "devices") panel = /* @__PURE__ */
|
|
8175
|
-
else if (panelName === "approve" && panelArg) panel = /* @__PURE__ */
|
|
8176
|
-
else if (panelName === "import-passkeys" && host.nativeImport) panel = /* @__PURE__ */
|
|
8177
|
-
else if (panelName === "export") panel = /* @__PURE__ */
|
|
8178
|
-
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 });
|
|
8179
8540
|
else if (panelName && selected && ITEM_PANELS[panelName]) {
|
|
8180
8541
|
const P = ITEM_PANELS[panelName];
|
|
8181
|
-
panel = /* @__PURE__ */
|
|
8542
|
+
panel = /* @__PURE__ */ jsx40(
|
|
8182
8543
|
P,
|
|
8183
8544
|
{
|
|
8184
8545
|
item: selected,
|
|
@@ -8201,17 +8562,17 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8201
8562
|
}
|
|
8202
8563
|
const grid = mode === "full" ? "grid-cols-[15rem_21rem_minmax(0,1fr)]" : mode === "split" ? "grid-cols-[19rem_minmax(0,1fr)]" : "grid-cols-1";
|
|
8203
8564
|
const shown = panesShown(mode, specialView !== null, showingDetail);
|
|
8204
|
-
return /* @__PURE__ */
|
|
8205
|
-
snap.unavailable.length > 0 ? /* @__PURE__ */
|
|
8206
|
-
/* @__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: [
|
|
8207
8568
|
"Couldn\u2019t load ",
|
|
8208
8569
|
snap.unavailable.join(", "),
|
|
8209
8570
|
". Showing the rest."
|
|
8210
8571
|
] }),
|
|
8211
|
-
/* @__PURE__ */
|
|
8572
|
+
/* @__PURE__ */ jsx40("button", { type: "button", className: "shrink-0 text-primary hover:underline", onClick: load, children: "Try again" })
|
|
8212
8573
|
] }) : null,
|
|
8213
|
-
/* @__PURE__ */
|
|
8214
|
-
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(
|
|
8215
8576
|
VaultSidebar,
|
|
8216
8577
|
{
|
|
8217
8578
|
vault: loc.vault,
|
|
@@ -8230,9 +8591,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8230
8591
|
hasPage: host.page !== void 0
|
|
8231
8592
|
}
|
|
8232
8593
|
) : null,
|
|
8233
|
-
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,
|
|
8234
8595
|
shown.detail ? detail : null,
|
|
8235
|
-
panel
|
|
8596
|
+
panel,
|
|
8597
|
+
firstCode ? /* @__PURE__ */ jsx40(FirstCodePanel, { port, item: firstCode, onClose: () => setFirstCode(null), onDone: () => setFirstCode(null) }) : null
|
|
8236
8598
|
] })
|
|
8237
8599
|
] });
|
|
8238
8600
|
}
|
|
@@ -8240,8 +8602,8 @@ function plainLoadError(message2) {
|
|
|
8240
8602
|
return /load failed|failed to fetch|network|timed? ?out/i.test(message2) ? "The connection dropped. Check you\u2019re online, then try again." : message2;
|
|
8241
8603
|
}
|
|
8242
8604
|
function Blank({ children }) {
|
|
8243
|
-
return /* @__PURE__ */
|
|
8244
|
-
/* @__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" }),
|
|
8245
8607
|
children
|
|
8246
8608
|
] });
|
|
8247
8609
|
}
|
|
@@ -8611,6 +8973,20 @@ function createListsPort(ctx, door) {
|
|
|
8611
8973
|
|
|
8612
8974
|
// src/sharing/api.ts
|
|
8613
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
|
|
8614
8990
|
function grantOf(w) {
|
|
8615
8991
|
const org = Boolean(w.organization_id);
|
|
8616
8992
|
return {
|
|
@@ -8710,7 +9086,7 @@ function createSharingPort(ctx, options = {}) {
|
|
|
8710
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 }))],
|
|
8711
9087
|
fields: [
|
|
8712
9088
|
...encrypted.map((f) => ({ field_key: f.key, value: draft.values[f.key] ?? "", handling: f.handling })),
|
|
8713
|
-
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(
|
|
9089
|
+
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(secretFieldIn)
|
|
8714
9090
|
]
|
|
8715
9091
|
}
|
|
8716
9092
|
});
|
|
@@ -8996,14 +9372,16 @@ function createApiVaultPort(api, options = {}) {
|
|
|
8996
9372
|
login_urls: draft.loginUrls,
|
|
8997
9373
|
// A login a person saves with its website is offered on that website (the server's own
|
|
8998
9374
|
// default is off, which made "Save a login" on a page answer "No saved login" there).
|
|
8999
|
-
...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 } : {},
|
|
9000
9376
|
notes: draft.notes || null,
|
|
9001
9377
|
principal: organizationId ? { type: "organization", organization_id: organizationId } : { type: "user" },
|
|
9002
9378
|
initiation: "user",
|
|
9003
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 }))],
|
|
9004
9380
|
fields: [
|
|
9005
9381
|
...encrypted.map((f) => ({ field_key: f.key, value: draft.values[f.key] ?? "", handling: f.handling })),
|
|
9006
|
-
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(
|
|
9382
|
+
...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(secretFieldIn),
|
|
9383
|
+
// Backup codes on a type that does not declare them (a website login): their own encrypted field.
|
|
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" }] : []
|
|
9007
9385
|
]
|
|
9008
9386
|
}
|
|
9009
9387
|
}, organizationId ? { organizationId } : void 0);
|
|
@@ -9041,7 +9419,7 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9041
9419
|
}
|
|
9042
9420
|
for (const s of draft.secrets) {
|
|
9043
9421
|
if (s.label.trim() === "" || s.value === "") continue;
|
|
9044
|
-
await account9.addField(api, { path: { item_id: item.id }, body:
|
|
9422
|
+
await account9.addField(api, { path: { item_id: item.id }, body: secretFieldIn(s) }, opts);
|
|
9045
9423
|
}
|
|
9046
9424
|
for (const id of draft.removed) await account9.deleteField(api, { path: { item_id: item.id, field_id: id } }, opts);
|
|
9047
9425
|
return { item: await refetch(item.id, item.owner), notice: null };
|
|
@@ -9066,6 +9444,44 @@ function createVaultKnobs(client, address) {
|
|
|
9066
9444
|
return snap.resolved;
|
|
9067
9445
|
};
|
|
9068
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
|
+
}
|
|
9069
9485
|
export {
|
|
9070
9486
|
CATEGORIES,
|
|
9071
9487
|
CONFIRM_RETURN_KEY,
|
|
@@ -9084,15 +9500,19 @@ export {
|
|
|
9084
9500
|
guardPort,
|
|
9085
9501
|
inferFromUrl,
|
|
9086
9502
|
isHiddenItem,
|
|
9503
|
+
itemIdAt,
|
|
9087
9504
|
locationFromParams,
|
|
9088
9505
|
locationToParams,
|
|
9089
9506
|
loginSiteOf,
|
|
9090
9507
|
matchesQuery,
|
|
9091
9508
|
needsRecentSignIn,
|
|
9092
9509
|
parseDefinitions,
|
|
9510
|
+
providerOf,
|
|
9093
9511
|
siteDomainOf,
|
|
9094
9512
|
sortItems,
|
|
9095
9513
|
useConfirmed,
|
|
9514
|
+
vaultInventoryScope,
|
|
9515
|
+
vaultItemFacts,
|
|
9096
9516
|
wasCancelled
|
|
9097
9517
|
};
|
|
9098
9518
|
//# sourceMappingURL=index.js.map
|