@ai-matrx/vault 0.1.21 → 0.1.22
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 +15 -2
- package/dist/index.cjs +245 -120
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -2
- package/dist/index.d.ts +38 -2
- package/dist/index.js +245 -120
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.22
|
|
4
|
+
|
|
5
|
+
- **A member's credential shared into an organization is the organization's, never "Personal".** An item in an organization's list is the viewer's own only when the viewer owns it (`platform.list_my_organizations` `user_id`, else the owner of the person's own list); a member's own credential shared into the organization is attributed to that organization (`VaultOwner.memberShared`), counted there, its badge says "A member's own credential, shared into <org>", and Share / Delete show disabled with the reason (`manageUnavailableReason`, `ownerDetail`); Copy stays offered to an editor. Consumer action: none.
|
|
6
|
+
- **The person's own items show first.** `VaultPort.load(onProgress?)` hands partial snapshots (`VaultSnapshot.pending`): the own list and the type catalog open the vault, each organization's list streams in as it answers; the list's count line says "loading <org>…" (no layout jump). A Refresh still applies only the finished read. Consumer action: none (a host with its own `VaultPort` may ignore `onProgress`).
|
|
7
|
+
- **The compact Vault and Show pickers keep a real width** (6rem minimum) at split widths (640–1119px): the Authenticator button beside them is icon-only (its name in the tooltip). Consumer action: none.
|
|
8
|
+
- **The star is on every list row** — the row's hover quick actions and its More / right-click menu (`ItemList` `favorites`, `onToggleFavorite`). Consumer action: none.
|
|
9
|
+
- **Every organization stays in the vault switcher**, empty ones too (count 0); an empty organization opens on "Nothing here yet" with New item saving there. Consumer action: none.
|
|
10
|
+
- **A host's own right-click menu reads the row's entries**: `rowMenuEntriesAt(target)` returns the clicked row's entries (`RowMenuEntry.kind` `copy` / `favorite` / `open` / `copy-name` / `host`) — the same list the row's own menu renders. **Consumer action:** web app (`rowContextMenu: "host"`): add the `copy` and `favorite` entries of `rowMenuEntriesAt(target)` to its v3 menu. Extension and desktop: none.
|
|
11
|
+
|
|
3
12
|
## 0.1.21
|
|
4
13
|
|
|
5
|
-
|
|
6
|
-
|
|
14
|
+
SOURCE CHANGED WITH NO RELEASE NOTE. This release shipped source changes that nobody described in an Unreleased entry,
|
|
15
|
+
so they may include breaking API changes. Consumer action is UNKNOWN: read the diff before upgrading.
|
|
16
|
+
Diff: `git diff 8efbb129f3 4abc64ee28 -- apps/shared/vault/src`
|
|
17
|
+
|
|
18
|
+
Changed shipped source files (1):
|
|
19
|
+
- `apps/shared/vault/src/FieldRows.tsx`
|
|
7
20
|
|
|
8
21
|
## 0.1.20
|
|
9
22
|
|
package/dist/index.cjs
CHANGED
|
@@ -160,6 +160,7 @@ __export(src_exports, {
|
|
|
160
160
|
needsRecentSignIn: () => needsRecentSignIn,
|
|
161
161
|
parseDefinitions: () => parseDefinitions,
|
|
162
162
|
providerOf: () => providerOf,
|
|
163
|
+
rowMenuEntriesAt: () => rowMenuEntriesAt,
|
|
163
164
|
siteDomainOf: () => siteDomainOf,
|
|
164
165
|
sortItems: () => sortItems,
|
|
165
166
|
useConfirmed: () => useConfirmed,
|
|
@@ -918,6 +919,19 @@ var import_format3 = require("@ai-matrx/kit/format");
|
|
|
918
919
|
var import_format = require("@ai-matrx/kit/format");
|
|
919
920
|
|
|
920
921
|
// src/model.ts
|
|
922
|
+
function manageUnavailableReason(item) {
|
|
923
|
+
if (item.capabilities.canManage) return null;
|
|
924
|
+
if (item.owner.memberShared) return "Only the member who owns it can share, move or delete it";
|
|
925
|
+
if (item.owner.kind === "shared") return "Only its owner can share, move or delete it";
|
|
926
|
+
if (item.owner.kind === "organization") return "Only this organization's vault admins can change that";
|
|
927
|
+
return "You can use this item but not share, move or delete it";
|
|
928
|
+
}
|
|
929
|
+
function ownerDetail(owner) {
|
|
930
|
+
if (owner.memberShared) return `A member's own credential, shared into ${owner.label}`;
|
|
931
|
+
if (owner.kind === "organization") return `Organization: ${owner.label}`;
|
|
932
|
+
if (owner.kind === "shared") return "Shared with you by its owner";
|
|
933
|
+
return "Your own vault";
|
|
934
|
+
}
|
|
921
935
|
var DEFAULT_LOCATION = { vault: "all", view: "all", q: "", sort: "name", itemId: null, mode: "view", kind: null, url: "", panel: null };
|
|
922
936
|
var SORTS = ["name", "name-desc", "website", "updated", "created", "viewed"];
|
|
923
937
|
function locationFromParams(params, itemId = params.get("item")) {
|
|
@@ -6057,6 +6071,7 @@ function ItemPane(props) {
|
|
|
6057
6071
|
const setValue = (key, v) => setDraft((d) => ({ ...d, values: { ...d.values, [key]: v } }));
|
|
6058
6072
|
const canEdit = item ? item.capabilities.canEdit || item.capabilities.canManage : true;
|
|
6059
6073
|
const canManage = item?.capabilities.canManage ?? false;
|
|
6074
|
+
const manageReason = item ? manageUnavailableReason(item) : null;
|
|
6060
6075
|
async function save() {
|
|
6061
6076
|
if (!definition && !item) return;
|
|
6062
6077
|
setBusy(true);
|
|
@@ -6203,7 +6218,8 @@ function ItemPane(props) {
|
|
|
6203
6218
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { className: "truncate text-base font-semibold leading-tight", children: editing ? draft.name || (mode === "new" ? `New ${typeLabel.toLowerCase()}` : item?.name) : item?.name }),
|
|
6204
6219
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "flex min-w-0 items-center gap-1 text-xs text-muted-foreground", children: [
|
|
6205
6220
|
typeLabel ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "truncate", children: typeLabel }) : null,
|
|
6206
|
-
shownOwner ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Badge, { className: "shrink-0", icon: shownOwner.glyph, "aria-label": `Saved in ${shownOwner.label}`, children: shownOwner.label }) : null,
|
|
6221
|
+
shownOwner ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Badge, { className: "shrink-0", icon: shownOwner.glyph, "aria-label": `Saved in ${shownOwner.label}`, title: item && mode !== "new" ? ownerDetail(item.owner) : void 0, children: shownOwner.label }) : null,
|
|
6222
|
+
item && mode !== "new" && item.owner.memberShared ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "shrink-0", "data-member-shared": "", children: "\xB7 A member\u2019s own" }) : null,
|
|
6207
6223
|
item && !editing ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SharingSummary, { item, port, className: "hidden truncate before:mr-1 before:content-['\xB7'] sm:inline" }, `${item.updatedAt}-${refreshKey ?? ""}`) : null
|
|
6208
6224
|
] })
|
|
6209
6225
|
] }),
|
|
@@ -6241,9 +6257,9 @@ function ItemPane(props) {
|
|
|
6241
6257
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ShareGlyph, { className: "size-4" }),
|
|
6242
6258
|
"Share"
|
|
6243
6259
|
] }) : null,
|
|
6244
|
-
canManage ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { onSelect: () => onPanel("move"), children: [
|
|
6260
|
+
canManage || item.capabilities.canEdit ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { onSelect: () => onPanel("move"), children: [
|
|
6245
6261
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MoveGlyph, { className: "size-4" }),
|
|
6246
|
-
"Move or copy"
|
|
6262
|
+
canManage ? "Move or copy" : "Copy to\u2026"
|
|
6247
6263
|
] }) : null,
|
|
6248
6264
|
item.capabilities.canReveal ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { onSelect: () => onPanel("send"), children: [
|
|
6249
6265
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SendGlyph, { className: "size-4" }),
|
|
@@ -6267,6 +6283,17 @@ function ItemPane(props) {
|
|
|
6267
6283
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TrashGlyph, { className: "size-4" }),
|
|
6268
6284
|
"Delete"
|
|
6269
6285
|
] })
|
|
6286
|
+
] }) : manageReason ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
6287
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_design_system17.DropdownMenuSeparator, {}),
|
|
6288
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { disabled: true, children: [
|
|
6289
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ShareGlyph, { className: "size-4" }),
|
|
6290
|
+
"Share"
|
|
6291
|
+
] }),
|
|
6292
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { disabled: true, children: [
|
|
6293
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TrashGlyph, { className: "size-4" }),
|
|
6294
|
+
"Delete"
|
|
6295
|
+
] }),
|
|
6296
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "max-w-64 px-2 py-1.5 text-xs text-muted-foreground", "data-manage-reason": "", children: manageReason })
|
|
6270
6297
|
] }) : null
|
|
6271
6298
|
] })
|
|
6272
6299
|
] })
|
|
@@ -6497,6 +6524,17 @@ function ItemPane(props) {
|
|
|
6497
6524
|
] }) });
|
|
6498
6525
|
}
|
|
6499
6526
|
|
|
6527
|
+
// src/row-menu.ts
|
|
6528
|
+
var readers = /* @__PURE__ */ new WeakMap();
|
|
6529
|
+
function registerRowMenu(el, read) {
|
|
6530
|
+
if (el) readers.set(el, read);
|
|
6531
|
+
}
|
|
6532
|
+
function rowMenuEntriesAt(target) {
|
|
6533
|
+
const row = target?.closest("[data-item]");
|
|
6534
|
+
const read = row ? readers.get(row) : void 0;
|
|
6535
|
+
return read ? read() : [];
|
|
6536
|
+
}
|
|
6537
|
+
|
|
6500
6538
|
// src/ItemList.tsx
|
|
6501
6539
|
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
6502
6540
|
var RECOVERY_KEYS = /^recovery_codes?$/;
|
|
@@ -6518,7 +6556,7 @@ function subtitleOf(item, withOwner) {
|
|
|
6518
6556
|
const what = loginSiteOf(item) || item.definitionLabel;
|
|
6519
6557
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
6520
6558
|
}
|
|
6521
|
-
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner, canSortViewed = false, onRefresh, refreshing = false, rowContextMenu = "package", rowMenuItems }) {
|
|
6559
|
+
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner, canSortViewed = false, onRefresh, refreshing = false, rowContextMenu = "package", rowMenuItems, stillLoading, favorites, onToggleFavorite }) {
|
|
6522
6560
|
const sorts = SORTS2.filter((s) => canSortViewed || s.value !== "viewed");
|
|
6523
6561
|
const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
|
|
6524
6562
|
const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
|
|
@@ -6539,7 +6577,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6539
6577
|
}
|
|
6540
6578
|
};
|
|
6541
6579
|
const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6542
|
-
const row = (i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners, ownContextMenu: rowContextMenu === "package", extra: rowMenuItems }, i.id);
|
|
6580
|
+
const row = (i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners, ownContextMenu: rowContextMenu === "package", extra: rowMenuItems, favorite: onToggleFavorite ? { on: favorites?.has(i.id) ?? false, toggle: () => onToggleFavorite(i.id) } : void 0 }, i.id);
|
|
6543
6581
|
const sortLabel = sorts.find((s) => s.value === sort)?.label ?? "Name A\u2013Z";
|
|
6544
6582
|
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
|
|
6545
6583
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children: [
|
|
@@ -6549,10 +6587,18 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6549
6587
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(PlusGlyph, {}), "aria-label": "New item", onClick: onNew })
|
|
6550
6588
|
] }),
|
|
6551
6589
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center justify-between gap-2 px-1", children: [
|
|
6552
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "truncate text-xs text-muted-foreground", children: [
|
|
6590
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "flex min-w-0 items-center gap-1.5 truncate text-xs text-muted-foreground", role: "status", "aria-live": "polite", children: [
|
|
6553
6591
|
items.length,
|
|
6554
6592
|
" ",
|
|
6555
|
-
items.length === 1 ? "item" : "items"
|
|
6593
|
+
items.length === 1 ? "item" : "items",
|
|
6594
|
+
stillLoading && stillLoading.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "flex min-w-0 items-center gap-1 truncate", title: `Still loading ${stillLoading.join(", ")}`, "data-still-loading": "", children: [
|
|
6595
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(RefreshGlyph, { className: "size-3 shrink-0 animate-spin" }),
|
|
6596
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "truncate", children: [
|
|
6597
|
+
"loading ",
|
|
6598
|
+
stillLoading.length === 1 ? stillLoading[0] : `${stillLoading.length} more`,
|
|
6599
|
+
"\u2026"
|
|
6600
|
+
] })
|
|
6601
|
+
] }) : null
|
|
6556
6602
|
] }),
|
|
6557
6603
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "flex shrink-0 items-center gap-0.5", children: [
|
|
6558
6604
|
onRefresh ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(RefreshGlyph, { className: refreshing ? "animate-spin" : "" }), "aria-label": "Refresh", title: "Refresh the list", disabled: refreshing, onClick: onRefresh }) : null,
|
|
@@ -6564,7 +6610,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6564
6610
|
] })
|
|
6565
6611
|
] }),
|
|
6566
6612
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto px-2 pb-3", onKeyDown, children: items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-col items-center gap-3 px-4 py-12 text-center", children: [
|
|
6567
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-sm text-muted-foreground", children: query ? `Nothing matches \u201C${query}\u201D.` : "Nothing here yet." }),
|
|
6613
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-sm text-muted-foreground", children: query ? `Nothing matches \u201C${query}\u201D.` : stillLoading && stillLoading.length > 0 ? "Still loading\u2026" : "Nothing here yet." }),
|
|
6568
6614
|
query ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "outline", onClick: () => onQuery(""), children: "Clear search" }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(PlusGlyph, {}), onClick: onNew, children: "New item" })
|
|
6569
6615
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("ul", { ref: listRef, className: "flex flex-col gap-px", children: [
|
|
6570
6616
|
pinned.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("li", { className: "px-2 pb-1 pt-1 text-xs font-medium text-muted-foreground", children: "This page" }) : null,
|
|
@@ -6574,7 +6620,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6574
6620
|
] }) })
|
|
6575
6621
|
] });
|
|
6576
6622
|
}
|
|
6577
|
-
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra }) {
|
|
6623
|
+
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra, favorite }) {
|
|
6578
6624
|
const confirmed = useConfirmed();
|
|
6579
6625
|
const copy = useCopy();
|
|
6580
6626
|
const notify = useNotify();
|
|
@@ -6602,9 +6648,32 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6602
6648
|
const others = otherCopyFields(item, user, secret);
|
|
6603
6649
|
const custom = canUse ? item.custom.filter((c) => c.value) : [];
|
|
6604
6650
|
const hostEntries = extra?.(item) ?? [];
|
|
6651
|
+
const copyEntries = [
|
|
6652
|
+
...user ? [{ id: "copy:username", kind: "copy", label: `Copy ${user.label.toLowerCase()}`, onSelect: copyUser }] : [],
|
|
6653
|
+
...secret ? [{ id: "copy:password", kind: "copy", label: "Copy password", onSelect: copyPassword }] : [],
|
|
6654
|
+
...code ? [{ id: "copy:code", kind: "copy", label: "Copy one-time code", onSelect: copyCode }] : [],
|
|
6655
|
+
...others.map((f) => ({ id: `copy:${f.key}`, kind: "copy", label: `Copy ${f.label.toLowerCase()}`, onSelect: () => void run(f.label, () => port.reveal(item, f.key), f.handling !== "visible") })),
|
|
6656
|
+
...custom.map((c) => ({ id: `copy:custom:${c.key}`, kind: "copy", label: `Copy ${c.label.toLowerCase()}`, onSelect: () => void copy(c.value, c.label, { secret: false }) }))
|
|
6657
|
+
];
|
|
6658
|
+
const favoriteEntry = favorite ? { id: "favorite", kind: "favorite", label: favorite.on ? "Remove from favorites" : "Add to favorites", onSelect: favorite.toggle } : null;
|
|
6659
|
+
const entries = [
|
|
6660
|
+
...copyEntries,
|
|
6661
|
+
...favoriteEntry ? [favoriteEntry] : [],
|
|
6662
|
+
{ id: "open", kind: "open", label: "Open", onSelect: () => onSelect(item.id) },
|
|
6663
|
+
{ id: "copy-name", kind: "copy-name", label: "Copy name", onSelect: copyName },
|
|
6664
|
+
...hostEntries.map((h) => ({ ...h, kind: h.kind ?? "host" }))
|
|
6665
|
+
];
|
|
6666
|
+
const entriesRef = (0, import_react29.useRef)(entries);
|
|
6667
|
+
entriesRef.current = entries;
|
|
6668
|
+
const glyphOf = (e) => e.id === "copy:username" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(UserGlyph, { className: "size-4" }) : e.id === "copy:password" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(KeyGlyph, { className: "size-4" }) : e.id === "copy:code" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ClockGlyph, { className: "size-4" }) : e.kind === "favorite" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(StarGlyph, { className: (0, import_design_system20.cn)("size-4", favorite?.on && "fill-current text-warning") }) : e.kind === "open" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronRightGlyph, { className: "size-4" }) : e.kind === "host" ? null : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_icons12.CopyIcon, { className: "size-4" });
|
|
6669
|
+
const menuItem = (e) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { disabled: e.disabled ?? false, onSelect: e.onSelect, children: [
|
|
6670
|
+
glyphOf(e),
|
|
6671
|
+
e.label
|
|
6672
|
+
] }, e.id ?? e.label);
|
|
6605
6673
|
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
6606
6674
|
"li",
|
|
6607
6675
|
{
|
|
6676
|
+
ref: (el) => registerRowMenu(el, () => entriesRef.current),
|
|
6608
6677
|
className: "group relative",
|
|
6609
6678
|
"data-item": item.id,
|
|
6610
6679
|
onContextMenu: ownContextMenu ? (e) => {
|
|
@@ -6630,7 +6699,8 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6630
6699
|
}
|
|
6631
6700
|
),
|
|
6632
6701
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "absolute right-1.5 top-1/2 flex -translate-y-1/2 items-center gap-0.5", "data-surface": on ? "primary" : void 0, children: [
|
|
6633
|
-
user || secret ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: (0, import_design_system20.cn)("hidden items-center gap-0.5 rounded-md pl-2 [@media(hover:hover)]:group-hover:flex [@media(hover:hover)]:group-focus-within:flex", on ? "bg-primary" : "bg-accent"), "data-row-quick": "", children: [
|
|
6702
|
+
user || secret || favorite ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: (0, import_design_system20.cn)("hidden items-center gap-0.5 rounded-md pl-2 [@media(hover:hover)]:group-hover:flex [@media(hover:hover)]:group-focus-within:flex", on ? "bg-primary" : "bg-accent"), "data-row-quick": "", children: [
|
|
6703
|
+
favorite ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(StarGlyph, { className: favorite.on ? "fill-current text-warning" : "" }), "aria-label": favorite.on ? "Remove from favorites" : "Add to favorites", "aria-pressed": favorite.on, onClick: favorite.toggle }) : null,
|
|
6634
6704
|
user ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(UserGlyph, {}), "aria-label": `Copy ${user.label}`, disabled: busy, onClick: copyUser }) : null,
|
|
6635
6705
|
secret ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(KeyGlyph, {}), "aria-label": "Copy password", disabled: busy, onClick: copyPassword }) : null
|
|
6636
6706
|
] }) : null,
|
|
@@ -6646,40 +6716,11 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6646
6716
|
}
|
|
6647
6717
|
) }),
|
|
6648
6718
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuContent, { align: "end", children: [
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
user.label.toLowerCase()
|
|
6653
|
-
] }) : null,
|
|
6654
|
-
secret ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: copyPassword, children: [
|
|
6655
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(KeyGlyph, { className: "size-4" }),
|
|
6656
|
-
"Copy password"
|
|
6657
|
-
] }) : null,
|
|
6658
|
-
code ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: copyCode, children: [
|
|
6659
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ClockGlyph, { className: "size-4" }),
|
|
6660
|
-
"Copy one-time code"
|
|
6661
|
-
] }) : null,
|
|
6662
|
-
others.map((f) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: () => void run(f.label, () => port.reveal(item, f.key), f.handling !== "visible"), children: [
|
|
6663
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_icons12.CopyIcon, { className: "size-4" }),
|
|
6664
|
-
"Copy ",
|
|
6665
|
-
f.label.toLowerCase()
|
|
6666
|
-
] }, f.key)),
|
|
6667
|
-
custom.map((c) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: () => void copy(c.value, c.label, { secret: false }), children: [
|
|
6668
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_icons12.CopyIcon, { className: "size-4" }),
|
|
6669
|
-
"Copy ",
|
|
6670
|
-
c.label.toLowerCase()
|
|
6671
|
-
] }, `custom:${c.key}`)),
|
|
6672
|
-
user || secret || code || others.length > 0 || custom.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuSeparator, {}) : null,
|
|
6673
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: () => onSelect(item.id), children: [
|
|
6674
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronRightGlyph, { className: "size-4" }),
|
|
6675
|
-
"Open"
|
|
6676
|
-
] }),
|
|
6677
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: copyName, children: [
|
|
6678
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_icons12.CopyIcon, { className: "size-4" }),
|
|
6679
|
-
"Copy name"
|
|
6680
|
-
] }),
|
|
6719
|
+
copyEntries.map(menuItem),
|
|
6720
|
+
copyEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuSeparator, {}) : null,
|
|
6721
|
+
entries.filter((e) => e.kind === "favorite" || e.kind === "open" || e.kind === "copy-name").map(menuItem),
|
|
6681
6722
|
hostEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuSeparator, {}) : null,
|
|
6682
|
-
|
|
6723
|
+
entries.filter((e) => e.kind === "host").map(menuItem)
|
|
6683
6724
|
] })
|
|
6684
6725
|
] })
|
|
6685
6726
|
] })
|
|
@@ -8187,15 +8228,17 @@ var import_controls34 = require("@ai-matrx/design-system/controls");
|
|
|
8187
8228
|
var import_icons16 = require("@ai-matrx/design-system/icons");
|
|
8188
8229
|
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
8189
8230
|
var AUTHENTICATOR_LABEL = "Authenticator";
|
|
8190
|
-
function vaultChoices(items, organizations,
|
|
8231
|
+
function vaultChoices(items, organizations, _current) {
|
|
8191
8232
|
const n = (f) => items.filter(f).length;
|
|
8192
8233
|
const shared = n((i) => i.owner.kind === "shared");
|
|
8193
8234
|
return [
|
|
8194
8235
|
{ value: "all", label: "All items", count: items.length },
|
|
8195
8236
|
{ value: "mine", label: "Personal", count: n((i) => i.owner.kind === "me") },
|
|
8196
8237
|
...shared > 0 ? [{ value: "shared", label: "Shared with me", count: shared }] : [],
|
|
8197
|
-
//
|
|
8198
|
-
|
|
8238
|
+
// Every organization the person belongs to, empty ones too: an empty vault opens on its own
|
|
8239
|
+
// "Nothing here yet" with New item, so the first credential can go there. (The organization
|
|
8240
|
+
// list carries no role, so who may add is the server's answer to the save, said in place.)
|
|
8241
|
+
...organizations.map((o) => ({ value: o.id, label: o.name, count: n((i) => i.owner.organizationId === o.id) }))
|
|
8199
8242
|
];
|
|
8200
8243
|
}
|
|
8201
8244
|
function VaultSelect({ value, choices, onChange }) {
|
|
@@ -8475,7 +8518,16 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8475
8518
|
const load = (0, import_react42.useCallback)(() => {
|
|
8476
8519
|
setError(null);
|
|
8477
8520
|
setRefreshError(null);
|
|
8478
|
-
|
|
8521
|
+
let finished = false;
|
|
8522
|
+
port.load((partial) => {
|
|
8523
|
+
if (finished) return;
|
|
8524
|
+
setSnap(partial);
|
|
8525
|
+
setItems(partial.items);
|
|
8526
|
+
setDeleted(partial.deleted);
|
|
8527
|
+
}).then((s) => {
|
|
8528
|
+
finished = true;
|
|
8529
|
+
apply(s);
|
|
8530
|
+
}).catch((e) => {
|
|
8479
8531
|
setSignedOut(e?.status === 401);
|
|
8480
8532
|
setError(e instanceof Error ? e.message : "The vault could not be loaded.");
|
|
8481
8533
|
});
|
|
@@ -8592,59 +8644,62 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8592
8644
|
}
|
|
8593
8645
|
const hasFavorites = port.lists.favorites !== void 0;
|
|
8594
8646
|
const title = loc.vault === "all" && loc.view === "all" ? "All items" : viewLabel(loc.view, views);
|
|
8595
|
-
const compactHeader = mode === "full" ? void 0 :
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
/* @__PURE__ */ (0, import_jsx_runtime40.
|
|
8599
|
-
|
|
8600
|
-
{
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.
|
|
8613
|
-
/* @__PURE__ */ (0, import_jsx_runtime40.
|
|
8614
|
-
|
|
8615
|
-
"
|
|
8616
|
-
|
|
8617
|
-
|
|
8618
|
-
|
|
8619
|
-
"
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
"
|
|
8624
|
-
|
|
8625
|
-
|
|
8626
|
-
|
|
8627
|
-
"
|
|
8628
|
-
|
|
8629
|
-
|
|
8630
|
-
|
|
8631
|
-
"
|
|
8632
|
-
|
|
8633
|
-
|
|
8634
|
-
|
|
8635
|
-
"
|
|
8636
|
-
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
8641
|
-
|
|
8642
|
-
|
|
8643
|
-
|
|
8644
|
-
|
|
8647
|
+
const compactHeader = mode === "full" ? void 0 : (
|
|
8648
|
+
// The two pickers keep a real width at every compact size (the list column is 19rem in split
|
|
8649
|
+
// mode): the Authenticator button is icon-only beside them, its name in its tooltip.
|
|
8650
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "grid grid-cols-[minmax(6rem,1fr)_minmax(6rem,1fr)_auto_auto] gap-2", "data-vault-compact-header": "", children: [
|
|
8651
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(VaultSelect, { value: loc.vault, choices, onChange: (vault) => go({ vault, itemId: null, panel: null }) }),
|
|
8652
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_controls35.Select, { value: loc.view, onValueChange: (view) => go({ view, itemId: null, panel: null }), options: viewOptions(views, inThisVault.length, deleted.length, hasFavorites, port.lists.recents !== void 0, host.page !== void 0), "aria-label": "Show" }),
|
|
8653
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
8654
|
+
import_controls35.Button,
|
|
8655
|
+
{
|
|
8656
|
+
variant: loc.view === "authenticator" ? "outline" : "quiet",
|
|
8657
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(LockGlyph, {}),
|
|
8658
|
+
"aria-label": AUTHENTICATOR_LABEL,
|
|
8659
|
+
"aria-pressed": loc.view === "authenticator",
|
|
8660
|
+
title: AUTHENTICATOR_LABEL,
|
|
8661
|
+
onClick: () => go({ view: loc.view === "authenticator" ? "all" : "authenticator", itemId: null, mode: "view", panel: null })
|
|
8662
|
+
}
|
|
8663
|
+
),
|
|
8664
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenu, { children: [
|
|
8665
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_design_system26.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_controls35.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(MoreGlyph, {}), "aria-label": "Vault actions" }) }),
|
|
8666
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuContent, { align: "end", children: [
|
|
8667
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "import" }), children: [
|
|
8668
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ImportGlyph, { className: "size-4" }),
|
|
8669
|
+
"Import"
|
|
8670
|
+
] }),
|
|
8671
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "export" }), children: [
|
|
8672
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ExportGlyph, { className: "size-4" }),
|
|
8673
|
+
"Export"
|
|
8674
|
+
] }),
|
|
8675
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "backup" }), children: [
|
|
8676
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(SafeGlyph, { className: "size-4" }),
|
|
8677
|
+
"Backup"
|
|
8678
|
+
] }),
|
|
8679
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "devices" }), children: [
|
|
8680
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ShieldGlyph, { className: "size-4" }),
|
|
8681
|
+
"Browsers that fill"
|
|
8682
|
+
] }),
|
|
8683
|
+
host.nativeImport ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "import-passkeys" }), children: [
|
|
8684
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ImportGlyph, { className: "size-4" }),
|
|
8685
|
+
"Import passkeys"
|
|
8686
|
+
] }) : null,
|
|
8687
|
+
host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: host.nativeProvider.openSetup, children: [
|
|
8688
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ShieldGlyph, { className: "size-4" }),
|
|
8689
|
+
"System AutoFill"
|
|
8690
|
+
] }) : null,
|
|
8691
|
+
host.lock?.lock ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => void host.lock?.lock?.(), children: [
|
|
8692
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(LockGlyph, { className: "size-4" }),
|
|
8693
|
+
"Lock"
|
|
8694
|
+
] }) : null,
|
|
8695
|
+
host.openWebVault ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: host.openWebVault, children: [
|
|
8696
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ExternalGlyph, { className: "size-4" }),
|
|
8697
|
+
"Open on the web"
|
|
8698
|
+
] }) : null
|
|
8699
|
+
] })
|
|
8645
8700
|
] })
|
|
8646
8701
|
] })
|
|
8647
|
-
|
|
8702
|
+
);
|
|
8648
8703
|
const viewHeader = /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
8649
8704
|
compactHeader,
|
|
8650
8705
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_controls35.SearchField, { value: loc.q, onChange: (e) => go({ q: e.target.value }, "replace"), placeholder: `Search ${viewLabel(loc.view, views)}`, "aria-label": `Search ${viewLabel(loc.view, views)}` })
|
|
@@ -8687,6 +8742,8 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8687
8742
|
onNew: () => go({ itemId: null, mode: "new", kind: null, panel: null }),
|
|
8688
8743
|
onRefresh: refresh,
|
|
8689
8744
|
refreshing,
|
|
8745
|
+
...snap.pending && snap.pending.length > 0 ? { stillLoading: snap.pending } : {},
|
|
8746
|
+
...hasFavorites ? { favorites: favorites ?? /* @__PURE__ */ new Set(), onToggleFavorite: toggleFavorite } : {},
|
|
8690
8747
|
rowContextMenu: host.rowContextMenu ?? "package",
|
|
8691
8748
|
...host.rowMenuItems ? { rowMenuItems: host.rowMenuItems } : {},
|
|
8692
8749
|
...matchingIds ? { matchingIds } : {},
|
|
@@ -9576,6 +9633,12 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9576
9633
|
if (id) return { kind: "organization", label: orgs.find((o) => o.id === id)?.name ?? "Organization", organizationId: id };
|
|
9577
9634
|
return mine || userId ? { kind: "me", label: "Personal", organizationId: null } : { kind: "shared", label: "Shared with me", organizationId: null };
|
|
9578
9635
|
};
|
|
9636
|
+
const ownerInOrgList = (w, via, meId) => {
|
|
9637
|
+
if (w.organization_id) return orgOf(w.organization_id, null, false);
|
|
9638
|
+
if (w.user_id && meId && w.user_id === meId) return { kind: "me", label: "Personal", organizationId: null };
|
|
9639
|
+
if (via) return { kind: "organization", label: via.name, organizationId: via.id, memberShared: { userId: w.user_id ?? null } };
|
|
9640
|
+
return { kind: "shared", label: "Shared with me", organizationId: null };
|
|
9641
|
+
};
|
|
9579
9642
|
async function refetch(id, owner) {
|
|
9580
9643
|
const w = await account9.getItem(api, { path: { item_id: id } });
|
|
9581
9644
|
return itemOf(w, owner, defs, auth);
|
|
@@ -9603,38 +9666,100 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9603
9666
|
io: createIoPort(ctx),
|
|
9604
9667
|
fields: createFieldsPort(ctx),
|
|
9605
9668
|
lists: createListsPort(ctx, options.userState),
|
|
9606
|
-
async load() {
|
|
9669
|
+
async load(onProgress) {
|
|
9607
9670
|
const catalogP = retrying(() => apps2.getAppCatalogKind(api, { path: { app: "matrx", kind: "credential_definition" } }));
|
|
9608
9671
|
const authP = retrying(() => apps2.listAuthenticators(api));
|
|
9609
9672
|
const userP = retrying(() => account9.listItems(api, { query: { principal_type: "user" } }));
|
|
9610
9673
|
const sharedP = retrying(() => account9.sharedWithMe(api));
|
|
9611
9674
|
const quiet = (p) => void p.catch(() => void 0);
|
|
9612
9675
|
[catalogP, authP, userP, sharedP].forEach(quiet);
|
|
9613
|
-
const
|
|
9614
|
-
|
|
9615
|
-
|
|
9616
|
-
|
|
9617
|
-
|
|
9618
|
-
const [authSettled, sharedSettled, ...orgSettled] = await Promise.allSettled([authP, sharedP, ...orgListsP]);
|
|
9676
|
+
const raw = {
|
|
9677
|
+
orgLists: [],
|
|
9678
|
+
orgsKnown: options.organizations !== void 0,
|
|
9679
|
+
meId: null
|
|
9680
|
+
};
|
|
9619
9681
|
const unavailable = [];
|
|
9620
|
-
|
|
9621
|
-
const
|
|
9622
|
-
|
|
9623
|
-
|
|
9624
|
-
|
|
9625
|
-
|
|
9626
|
-
|
|
9627
|
-
|
|
9628
|
-
|
|
9629
|
-
|
|
9630
|
-
|
|
9631
|
-
if (seen.has(w.id) || deleted.has(w.id) || isHiddenItem(w)) continue;
|
|
9632
|
-
const owner = sharedList ? orgOf(w.organization_id, null, false) : orgOf(w.organization_id, w.user_id, i === 0);
|
|
9633
|
-
const item = itemOf(w, sharedList && !w.organization_id ? { kind: "shared", label: "Shared with me", organizationId: null } : owner, defs, auth);
|
|
9682
|
+
let done = false;
|
|
9683
|
+
const build = () => {
|
|
9684
|
+
const catalog2 = raw.catalog ?? [];
|
|
9685
|
+
defs = new Map(parseDefinitions(catalog2.filter((e) => e.is_active).map((e) => ({ key: e.key, payload: e.payload, sort_order: e.sort_order }))).map((d) => [d.key, d]));
|
|
9686
|
+
const mineItems = raw.mine?.items ?? [];
|
|
9687
|
+
const meId = raw.meId ?? mineItems.find((w) => w.user_id)?.user_id ?? null;
|
|
9688
|
+
const seen = /* @__PURE__ */ new Map();
|
|
9689
|
+
const deleted = /* @__PURE__ */ new Map();
|
|
9690
|
+
const take = (w, owner) => {
|
|
9691
|
+
if (seen.has(w.id) || deleted.has(w.id) || isHiddenItem(w)) return;
|
|
9692
|
+
const item = itemOf(w, owner, defs, auth);
|
|
9634
9693
|
(isDeleted(w) ? deleted : seen).set(w.id, item);
|
|
9694
|
+
};
|
|
9695
|
+
for (const w of mineItems) take(w, orgOf(w.organization_id, null, true));
|
|
9696
|
+
raw.orgLists.forEach((l, i) => {
|
|
9697
|
+
const via = orgs[i];
|
|
9698
|
+
for (const w of l?.items ?? []) take(w, ownerInOrgList(w, via, meId));
|
|
9699
|
+
});
|
|
9700
|
+
for (const w of raw.shared?.items ?? []) take(w, w.organization_id ? orgOf(w.organization_id, null, false) : { kind: "shared", label: "Shared with me", organizationId: null });
|
|
9701
|
+
const pending = done ? [] : [...raw.orgsKnown ? orgs.filter((_, i) => raw.orgLists[i] === void 0).map((o) => o.name) : ["your organizations"], ...raw.shared ? [] : ["Shared with me"]];
|
|
9702
|
+
return {
|
|
9703
|
+
unavailable: [...unavailable],
|
|
9704
|
+
...pending.length > 0 ? { pending } : {},
|
|
9705
|
+
items: [...seen.values()],
|
|
9706
|
+
deleted: [...deleted.values()],
|
|
9707
|
+
organizations: orgs,
|
|
9708
|
+
definitions: [...defs.values()].sort((a, b) => a.sortOrder - b.sortOrder || a.label.localeCompare(b.label))
|
|
9709
|
+
};
|
|
9710
|
+
};
|
|
9711
|
+
const progress = () => {
|
|
9712
|
+
if (!done && onProgress && raw.catalog && raw.mine) onProgress(build());
|
|
9713
|
+
};
|
|
9714
|
+
const orgReportP = options.organizations ? null : retrying(() => platform.listMyOrganizations(api));
|
|
9715
|
+
if (orgReportP) quiet(orgReportP);
|
|
9716
|
+
const orgListsReady = (async () => {
|
|
9717
|
+
const report = orgReportP ? await orgReportP : null;
|
|
9718
|
+
raw.meId = report?.user_id ?? null;
|
|
9719
|
+
orgs = [...new Map((options.organizations ?? (report?.organizations ?? []).filter((o) => !o.archived_at).map((o) => ({ id: o.id, name: o.name }))).map((o) => [o.id, o])).values()];
|
|
9720
|
+
raw.orgLists = orgs.map(() => void 0);
|
|
9721
|
+
raw.orgsKnown = true;
|
|
9722
|
+
progress();
|
|
9723
|
+
return orgs.map((o, i) => {
|
|
9724
|
+
const p = retrying(() => account9.listItems(api, { query: { principal_type: "organization", organization_id: o.id } }, { organizationId: o.id }));
|
|
9725
|
+
const arrived = p.then((l) => {
|
|
9726
|
+
raw.orgLists[i] = l;
|
|
9727
|
+
progress();
|
|
9728
|
+
return l;
|
|
9729
|
+
});
|
|
9730
|
+
quiet(arrived);
|
|
9731
|
+
return arrived;
|
|
9732
|
+
});
|
|
9733
|
+
})();
|
|
9734
|
+
quiet(orgListsReady);
|
|
9735
|
+
const authDone = authP.then((a) => {
|
|
9736
|
+
auth = new Map((a.entries ?? []).map((e) => [e.credential_item_id, e]));
|
|
9737
|
+
progress();
|
|
9738
|
+
}, () => {
|
|
9739
|
+
unavailable.push("One-time codes");
|
|
9740
|
+
});
|
|
9741
|
+
const sharedDone = sharedP.then((sh) => {
|
|
9742
|
+
raw.shared = sh;
|
|
9743
|
+
progress();
|
|
9744
|
+
}, () => {
|
|
9745
|
+
raw.shared = { items: [], count: 0 };
|
|
9746
|
+
unavailable.push("Shared with me");
|
|
9747
|
+
});
|
|
9748
|
+
const [catalog, mine] = await Promise.all([catalogP, userP]);
|
|
9749
|
+
raw.catalog = catalog;
|
|
9750
|
+
raw.mine = mine;
|
|
9751
|
+
progress();
|
|
9752
|
+
const orgPs = await orgListsReady;
|
|
9753
|
+
const orgSettled = await Promise.allSettled(orgPs);
|
|
9754
|
+
orgSettled.forEach((r, i) => {
|
|
9755
|
+
if (r.status === "rejected") {
|
|
9756
|
+
raw.orgLists[i] = { items: [], count: 0 };
|
|
9757
|
+
unavailable.push(orgs[i]?.name ?? "An organization");
|
|
9635
9758
|
}
|
|
9636
9759
|
});
|
|
9637
|
-
|
|
9760
|
+
await Promise.all([authDone, sharedDone]);
|
|
9761
|
+
done = true;
|
|
9762
|
+
return build();
|
|
9638
9763
|
},
|
|
9639
9764
|
async reveal(item, fieldKey2) {
|
|
9640
9765
|
const field = item.fields.find((f) => f.key === fieldKey2);
|