@proveanything/smartlinks-utils-ui 0.10.9 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{IconPicker-DKpL5Hcc.d.ts → IconPicker-nhY3wWlB.d.ts} +2 -2
- package/dist/{chunk-2MW54ZVG.js → chunk-3RRHM4LP.js} +97 -4
- package/dist/chunk-3RRHM4LP.js.map +1 -0
- package/dist/components/AssetPicker/index.css +3 -0
- package/dist/components/AssetPicker/index.css.map +1 -1
- package/dist/components/AssetPicker/index.d.ts +1 -1
- package/dist/components/ConditionsEditor/index.css +3 -0
- package/dist/components/ConditionsEditor/index.css.map +1 -1
- package/dist/components/ConditionsEditor/index.d.ts +2 -2
- package/dist/components/FacetRuleEditor/index.d.ts +2 -2
- package/dist/components/FontPicker/index.css +3 -0
- package/dist/components/FontPicker/index.css.map +1 -1
- package/dist/components/FontPicker/index.d.ts +2 -2
- package/dist/components/IconPicker/index.css +3 -0
- package/dist/components/IconPicker/index.css.map +1 -1
- package/dist/components/IconPicker/index.d.ts +2 -2
- package/dist/components/RecordsAdmin/index.css +3 -0
- package/dist/components/RecordsAdmin/index.css.map +1 -1
- package/dist/components/RecordsAdmin/index.d.ts +127 -28
- package/dist/components/RecordsAdmin/index.js +535 -95
- package/dist/components/RecordsAdmin/index.js.map +1 -1
- package/dist/index.css +3 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +53 -3
- package/dist/index.js +32 -1
- package/dist/index.js.map +1 -1
- package/dist/{useAssets-BAtXv6D5.d.ts → useAssets-DwUdZePm.d.ts} +2 -2
- package/package.json +3 -3
- package/dist/chunk-2MW54ZVG.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AdminPageHeader } from '../../chunk-
|
|
1
|
+
import { useIntroState, AdminPageHeader } from '../../chunk-3RRHM4LP.js';
|
|
2
2
|
import { assertComponentStylesLoaded } from '../../chunk-OLYC54YT.js';
|
|
3
3
|
import '../../chunk-5UQQYXCX.js';
|
|
4
4
|
import { FacetRuleEditor } from '../../chunk-JMCV6FOW.js';
|
|
@@ -6,12 +6,105 @@ import { useFacets } from '../../chunk-4LHF5JB7.js';
|
|
|
6
6
|
import { cn } from '../../chunk-L7FQ52F5.js';
|
|
7
7
|
import { parsedRefToTarget, parsedRefToScope, matchRecords, scopesEqual, getRecordById, listRecords, upsertRecord, updateRecord, createRecord, removeRecord } from '../../chunk-KA4MKRHL.js';
|
|
8
8
|
export { bulkDelete, bulkUpsert, createRecord, getRecordById, listRecords, matchRecords, parsedRefToScope, parsedRefToTarget, removeRecord, restoreRecord, scopesEqual, upsertRecord } from '../../chunk-KA4MKRHL.js';
|
|
9
|
-
import { createContext, useState, useEffect, useCallback,
|
|
10
|
-
import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, List, SlidersHorizontal, Globe, Tag, Boxes, Layers, Package, Target, Rows3, ChevronRight, Eraser, ClipboardPaste, Box, X, Search, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, CornerDownLeft, Circle, MinusCircle, XCircle, CopyPlus, AlertCircle, Undo2, Save, Loader2, ArrowRight, Globe2, Check, Settings2 } from 'lucide-react';
|
|
9
|
+
import { createContext, useMemo, useState, useEffect, useCallback, useRef, isValidElement, useLayoutEffect, useContext, useSyncExternalStore, createElement } from 'react';
|
|
10
|
+
import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, List, SlidersHorizontal, Globe, Tag, Boxes, Layers, Package, Target, Rows3, ChevronRight, Eraser, ClipboardPaste, Box, X, Search, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, CornerDownLeft, Circle, ArrowUpDown, ArrowUp, ArrowDown, MinusCircle, XCircle, CopyPlus, AlertCircle, Undo2, Save, Loader2, ArrowRight, Globe2, Check, Settings2 } from 'lucide-react';
|
|
11
11
|
import { useQuery, useQueryClient, useInfiniteQuery } from '@tanstack/react-query';
|
|
12
12
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
13
13
|
import { createPortal } from 'react-dom';
|
|
14
14
|
|
|
15
|
+
// src/components/RecordsAdmin/data/recordCache.ts
|
|
16
|
+
var RECORD_LIST_QK = ["records-admin", "list"];
|
|
17
|
+
var COLLECTION_ITEMS_QK = ["records-admin", "collection-items"];
|
|
18
|
+
var matchesCtx = (queryKey, prefix, ctx) => {
|
|
19
|
+
if (queryKey.length < prefix.length + 3) return false;
|
|
20
|
+
for (let i = 0; i < prefix.length; i += 1) {
|
|
21
|
+
if (queryKey[i] !== prefix[i]) return false;
|
|
22
|
+
}
|
|
23
|
+
if (queryKey[prefix.length] !== ctx.collectionId) return false;
|
|
24
|
+
if (queryKey[prefix.length + 1] !== ctx.appId) return false;
|
|
25
|
+
if (queryKey[prefix.length + 2] !== (ctx.recordType ?? void 0) && queryKey[prefix.length + 2] !== ctx.recordType) {
|
|
26
|
+
const slot = queryKey[prefix.length + 2];
|
|
27
|
+
if (slot !== void 0 && slot !== ctx.recordType) return false;
|
|
28
|
+
if (slot === void 0 && ctx.recordType) return false;
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
};
|
|
32
|
+
var replaceOrAppend = (cache, record) => {
|
|
33
|
+
let replaced = false;
|
|
34
|
+
const nextPages = cache.pages.map((page) => {
|
|
35
|
+
const idx = page.data.findIndex((r) => r.id === record.id);
|
|
36
|
+
if (idx === -1) return page;
|
|
37
|
+
replaced = true;
|
|
38
|
+
const nextData = [...page.data];
|
|
39
|
+
nextData[idx] = record;
|
|
40
|
+
return { ...page, data: nextData };
|
|
41
|
+
});
|
|
42
|
+
if (replaced) return { ...cache, pages: nextPages };
|
|
43
|
+
if (nextPages.length === 0) {
|
|
44
|
+
return {
|
|
45
|
+
pageParams: [0],
|
|
46
|
+
pages: [{ data: [record], total: 1, hasMore: false, nextOffset: 1 }]
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const last = nextPages[nextPages.length - 1];
|
|
50
|
+
const updatedLast = {
|
|
51
|
+
...last,
|
|
52
|
+
data: [...last.data, record],
|
|
53
|
+
total: (last.total ?? 0) + 1,
|
|
54
|
+
nextOffset: (last.nextOffset ?? last.data.length) + 1
|
|
55
|
+
};
|
|
56
|
+
const bumped = nextPages.map((p, i) => i === nextPages.length - 1 ? updatedLast : { ...p, total: (p.total ?? 0) + 1 });
|
|
57
|
+
return { ...cache, pages: bumped };
|
|
58
|
+
};
|
|
59
|
+
var removeFromPages = (cache, recordId) => {
|
|
60
|
+
let found = false;
|
|
61
|
+
const nextPages = cache.pages.map((page) => {
|
|
62
|
+
const idx = page.data.findIndex((r) => r.id === recordId);
|
|
63
|
+
if (idx === -1) return page;
|
|
64
|
+
found = true;
|
|
65
|
+
return {
|
|
66
|
+
...page,
|
|
67
|
+
data: page.data.filter((r) => r.id !== recordId),
|
|
68
|
+
total: Math.max(0, (page.total ?? 0) - 1)
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
if (!found) return null;
|
|
72
|
+
const bumped = nextPages.map((p) => p.data.some((r) => r.id === recordId) ? p : { ...p, total: Math.max(0, p.total ?? 0) });
|
|
73
|
+
return { ...cache, pages: bumped };
|
|
74
|
+
};
|
|
75
|
+
function patchRecordIntoCaches(queryClient, ctx, record) {
|
|
76
|
+
if (!record || !record.id) return;
|
|
77
|
+
const all = [
|
|
78
|
+
...queryClient.getQueriesData({ queryKey: RECORD_LIST_QK }),
|
|
79
|
+
...queryClient.getQueriesData({ queryKey: COLLECTION_ITEMS_QK })
|
|
80
|
+
];
|
|
81
|
+
for (const [key, cache] of all) {
|
|
82
|
+
if (!cache || !Array.isArray(cache.pages)) continue;
|
|
83
|
+
const prefix = key[0] === RECORD_LIST_QK[0] && key[1] === RECORD_LIST_QK[1] ? RECORD_LIST_QK : COLLECTION_ITEMS_QK;
|
|
84
|
+
if (!matchesCtx(key, prefix, ctx)) continue;
|
|
85
|
+
queryClient.setQueryData(key, (prev) => {
|
|
86
|
+
if (!prev || !Array.isArray(prev.pages)) return prev;
|
|
87
|
+
return replaceOrAppend(prev, record);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function removeRecordFromCaches(queryClient, ctx, recordId) {
|
|
92
|
+
if (!recordId) return;
|
|
93
|
+
const all = [
|
|
94
|
+
...queryClient.getQueriesData({ queryKey: RECORD_LIST_QK }),
|
|
95
|
+
...queryClient.getQueriesData({ queryKey: COLLECTION_ITEMS_QK })
|
|
96
|
+
];
|
|
97
|
+
for (const [key, cache] of all) {
|
|
98
|
+
if (!cache || !Array.isArray(cache.pages)) continue;
|
|
99
|
+
const prefix = key[0] === RECORD_LIST_QK[0] && key[1] === RECORD_LIST_QK[1] ? RECORD_LIST_QK : COLLECTION_ITEMS_QK;
|
|
100
|
+
if (!matchesCtx(key, prefix, ctx)) continue;
|
|
101
|
+
queryClient.setQueryData(key, (prev) => {
|
|
102
|
+
if (!prev || !Array.isArray(prev.pages)) return prev;
|
|
103
|
+
const next = removeFromPages(prev, recordId);
|
|
104
|
+
return next ?? prev;
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
15
108
|
var DEFAULT_ICONS = {
|
|
16
109
|
scope: {
|
|
17
110
|
collection: Globe,
|
|
@@ -412,58 +505,12 @@ function useResolvedRecord(args) {
|
|
|
412
505
|
error: query.error ?? null
|
|
413
506
|
};
|
|
414
507
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
var useIntroDismissed = (SL,
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
} catch {
|
|
422
|
-
return false;
|
|
423
|
-
}
|
|
424
|
-
});
|
|
425
|
-
useEffect(() => {
|
|
426
|
-
let cancelled = false;
|
|
427
|
-
(async () => {
|
|
428
|
-
try {
|
|
429
|
-
const cfg = await SL?.appConfiguration?.getConfig?.({ collectionId, appId, admin: true });
|
|
430
|
-
if (cancelled) return;
|
|
431
|
-
const flag = cfg?._meta?.introDismissed?.[RT_KEY(recordType)];
|
|
432
|
-
if (flag) setDismissed(true);
|
|
433
|
-
} catch {
|
|
434
|
-
}
|
|
435
|
-
})();
|
|
436
|
-
return () => {
|
|
437
|
-
cancelled = true;
|
|
438
|
-
};
|
|
439
|
-
}, [SL, collectionId, appId, recordType]);
|
|
440
|
-
const dismiss = useCallback(async () => {
|
|
441
|
-
setDismissed(true);
|
|
442
|
-
try {
|
|
443
|
-
localStorage.setItem(lsKey(appId, recordType), "1");
|
|
444
|
-
} catch {
|
|
445
|
-
}
|
|
446
|
-
try {
|
|
447
|
-
const cfg = await SL?.appConfiguration?.getConfig?.({ collectionId, appId, admin: true }).catch(() => ({}));
|
|
448
|
-
const next = {
|
|
449
|
-
...cfg ?? {},
|
|
450
|
-
_meta: {
|
|
451
|
-
...cfg?._meta ?? {},
|
|
452
|
-
introDismissed: { ...cfg?._meta?.introDismissed ?? {}, [RT_KEY(recordType)]: true }
|
|
453
|
-
}
|
|
454
|
-
};
|
|
455
|
-
await SL?.appConfiguration?.setConfig?.({ collectionId, appId, admin: true, config: next });
|
|
456
|
-
} catch {
|
|
457
|
-
}
|
|
458
|
-
}, [SL, collectionId, appId, recordType]);
|
|
459
|
-
const undismiss = useCallback(() => {
|
|
460
|
-
setDismissed(false);
|
|
461
|
-
try {
|
|
462
|
-
localStorage.removeItem(lsKey(appId, recordType));
|
|
463
|
-
} catch {
|
|
464
|
-
}
|
|
465
|
-
}, [appId, recordType]);
|
|
466
|
-
return { dismissed, dismiss, undismiss };
|
|
508
|
+
|
|
509
|
+
// src/components/RecordsAdmin/hooks/useIntroDismissed.ts
|
|
510
|
+
var useIntroDismissed = (SL, _collectionId, appId, recordType) => {
|
|
511
|
+
const persistKey = recordType ? `${appId}:${recordType}` : appId;
|
|
512
|
+
const { dismissed, onDismiss, onReopen } = useIntroState({ SL, persistKey });
|
|
513
|
+
return { dismissed, dismiss: onDismiss, undismiss: onReopen };
|
|
467
514
|
};
|
|
468
515
|
var useScopeProbe = ({ SL, collectionId, admin = true, enabled = true }) => {
|
|
469
516
|
const query = useQuery({
|
|
@@ -1055,7 +1102,8 @@ function useShellBrowser(opts) {
|
|
|
1055
1102
|
probeIsLoading,
|
|
1056
1103
|
selectedProductId,
|
|
1057
1104
|
drillTab,
|
|
1058
|
-
classify: classify3
|
|
1105
|
+
classify: classify3,
|
|
1106
|
+
pageSize
|
|
1059
1107
|
} = opts;
|
|
1060
1108
|
const [search, setSearch] = useState("");
|
|
1061
1109
|
const [filter, setFilter] = useState("all");
|
|
@@ -1081,7 +1129,8 @@ function useShellBrowser(opts) {
|
|
|
1081
1129
|
filter,
|
|
1082
1130
|
classify: classify3,
|
|
1083
1131
|
contextScope,
|
|
1084
|
-
enabled: recordListEnabled
|
|
1132
|
+
enabled: recordListEnabled,
|
|
1133
|
+
pageSize
|
|
1085
1134
|
});
|
|
1086
1135
|
const facetBrowse = useFacetBrowse({
|
|
1087
1136
|
SL,
|
|
@@ -2352,6 +2401,7 @@ var createEditorStore = () => {
|
|
|
2352
2401
|
let nextOrder = 0;
|
|
2353
2402
|
let hooksBundle = null;
|
|
2354
2403
|
let notifier = null;
|
|
2404
|
+
let recordChangeNotifier = null;
|
|
2355
2405
|
const buildRecordSummary = (entry, value) => ({
|
|
2356
2406
|
id: entry.recordId ?? null,
|
|
2357
2407
|
ref: entry.spec.scope.raw,
|
|
@@ -2557,8 +2607,9 @@ var createEditorStore = () => {
|
|
|
2557
2607
|
});
|
|
2558
2608
|
try {
|
|
2559
2609
|
let nextRecordId = entry.recordId;
|
|
2610
|
+
let savedRecord = null;
|
|
2560
2611
|
if (entry.recordId && entry.source === "self") {
|
|
2561
|
-
await updateRecord(ctx, entry.recordId, {
|
|
2612
|
+
savedRecord = await updateRecord(ctx, entry.recordId, {
|
|
2562
2613
|
data: persistedValue,
|
|
2563
2614
|
facetRule: persistedFacetRule
|
|
2564
2615
|
});
|
|
@@ -2577,6 +2628,7 @@ var createEditorStore = () => {
|
|
|
2577
2628
|
facetRule: persistedFacetRule
|
|
2578
2629
|
});
|
|
2579
2630
|
nextRecordId = created?.id ?? nextRecordId;
|
|
2631
|
+
savedRecord = created;
|
|
2580
2632
|
} else {
|
|
2581
2633
|
const upserted = await upsertRecord(ctx, {
|
|
2582
2634
|
ref: spec.ref,
|
|
@@ -2585,6 +2637,7 @@ var createEditorStore = () => {
|
|
|
2585
2637
|
facetRule: persistedFacetRule
|
|
2586
2638
|
});
|
|
2587
2639
|
nextRecordId = upserted.record?.id ?? nextRecordId;
|
|
2640
|
+
savedRecord = upserted.record;
|
|
2588
2641
|
}
|
|
2589
2642
|
update(editorId, (e) => {
|
|
2590
2643
|
if (persistedValue !== entry.value) {
|
|
@@ -2597,6 +2650,12 @@ var createEditorStore = () => {
|
|
|
2597
2650
|
e.status = "saved";
|
|
2598
2651
|
e.error = void 0;
|
|
2599
2652
|
});
|
|
2653
|
+
if (savedRecord && savedRecord.id) {
|
|
2654
|
+
try {
|
|
2655
|
+
recordChangeNotifier?.({ kind: "saved", record: savedRecord, isCreate, ctx });
|
|
2656
|
+
} catch {
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2600
2659
|
if (hooksBundle?.afterSave) {
|
|
2601
2660
|
const refreshed = map.get(editorId);
|
|
2602
2661
|
const hookCtx = {
|
|
@@ -2654,6 +2713,10 @@ var createEditorStore = () => {
|
|
|
2654
2713
|
await removeRecord(entry.saveSpec.ctx, entry.recordId);
|
|
2655
2714
|
map.delete(editorId);
|
|
2656
2715
|
emit();
|
|
2716
|
+
try {
|
|
2717
|
+
recordChangeNotifier?.({ kind: "deleted", recordId: entry.recordId, ctx: entry.saveSpec.ctx });
|
|
2718
|
+
} catch {
|
|
2719
|
+
}
|
|
2657
2720
|
if (hooksBundle?.afterDelete && deletedSnapshot) {
|
|
2658
2721
|
try {
|
|
2659
2722
|
await hooksBundle.afterDelete(deletedSnapshot);
|
|
@@ -2688,6 +2751,9 @@ var createEditorStore = () => {
|
|
|
2688
2751
|
},
|
|
2689
2752
|
setNotifier(notify2) {
|
|
2690
2753
|
notifier = notify2 ?? null;
|
|
2754
|
+
},
|
|
2755
|
+
setRecordChangeNotifier(notify2) {
|
|
2756
|
+
recordChangeNotifier = notify2 ?? null;
|
|
2691
2757
|
}
|
|
2692
2758
|
};
|
|
2693
2759
|
};
|
|
@@ -2711,12 +2777,14 @@ var EditorSessionProvider = ({
|
|
|
2711
2777
|
maxOpenEditors = 8,
|
|
2712
2778
|
defaultValueFactory,
|
|
2713
2779
|
hooks,
|
|
2714
|
-
onHookNotice
|
|
2780
|
+
onHookNotice,
|
|
2781
|
+
onRecordChange
|
|
2715
2782
|
}) => {
|
|
2716
2783
|
const storeRef = useRef(null);
|
|
2717
2784
|
if (!storeRef.current) storeRef.current = createEditorStore();
|
|
2718
2785
|
storeRef.current.setHooks(hooks ?? null);
|
|
2719
2786
|
storeRef.current.setNotifier(onHookNotice ?? null);
|
|
2787
|
+
storeRef.current.setRecordChangeNotifier(onRecordChange ?? null);
|
|
2720
2788
|
const currentRef = useRef(void 0);
|
|
2721
2789
|
const listenersRef = useRef(/* @__PURE__ */ new Set());
|
|
2722
2790
|
const subscribeCurrent = useCallback((cb) => {
|
|
@@ -3749,6 +3817,56 @@ var ProductList = RecordList;
|
|
|
3749
3817
|
var FacetList = RecordList;
|
|
3750
3818
|
var VariantList = RecordList;
|
|
3751
3819
|
var BatchList = RecordList;
|
|
3820
|
+
function LoadMoreFooter({
|
|
3821
|
+
shown,
|
|
3822
|
+
total,
|
|
3823
|
+
hasNextPage,
|
|
3824
|
+
isFetchingNextPage,
|
|
3825
|
+
onLoadMore,
|
|
3826
|
+
label
|
|
3827
|
+
}) {
|
|
3828
|
+
if (!hasNextPage && (total === void 0 || total <= shown)) return null;
|
|
3829
|
+
const knownTotal = typeof total === "number" && total >= shown;
|
|
3830
|
+
const summary = knownTotal ? `Showing ${shown} of ${total}` : `${shown} shown`;
|
|
3831
|
+
return /* @__PURE__ */ jsxs(
|
|
3832
|
+
"div",
|
|
3833
|
+
{
|
|
3834
|
+
className: "ra-loadmore",
|
|
3835
|
+
style: {
|
|
3836
|
+
display: "flex",
|
|
3837
|
+
alignItems: "center",
|
|
3838
|
+
gap: "8px",
|
|
3839
|
+
padding: "8px 12px",
|
|
3840
|
+
borderTop: "1px solid hsl(var(--ra-border))",
|
|
3841
|
+
background: "hsl(var(--ra-surface))"
|
|
3842
|
+
},
|
|
3843
|
+
children: [
|
|
3844
|
+
/* @__PURE__ */ jsx(
|
|
3845
|
+
"span",
|
|
3846
|
+
{
|
|
3847
|
+
style: {
|
|
3848
|
+
fontSize: "11px",
|
|
3849
|
+
color: "hsl(var(--ra-muted-text))",
|
|
3850
|
+
flex: 1
|
|
3851
|
+
},
|
|
3852
|
+
children: summary
|
|
3853
|
+
}
|
|
3854
|
+
),
|
|
3855
|
+
hasNextPage && /* @__PURE__ */ jsx(
|
|
3856
|
+
"button",
|
|
3857
|
+
{
|
|
3858
|
+
type: "button",
|
|
3859
|
+
onClick: onLoadMore,
|
|
3860
|
+
disabled: isFetchingNextPage,
|
|
3861
|
+
className: "ra-btn",
|
|
3862
|
+
style: { fontSize: "11px", padding: "4px 10px" },
|
|
3863
|
+
children: isFetchingNextPage ? "Loading\u2026" : label ?? "Load more"
|
|
3864
|
+
}
|
|
3865
|
+
)
|
|
3866
|
+
]
|
|
3867
|
+
}
|
|
3868
|
+
);
|
|
3869
|
+
}
|
|
3752
3870
|
var COLLAPSED_FACET_CAP = 6;
|
|
3753
3871
|
var COLLAPSED_VALUE_CAP = 12;
|
|
3754
3872
|
var VALUE_SEARCH_THRESHOLD = 12;
|
|
@@ -5659,18 +5777,52 @@ function DefaultItemTable({
|
|
|
5659
5777
|
selectedId,
|
|
5660
5778
|
onOpen,
|
|
5661
5779
|
onDelete,
|
|
5780
|
+
sort,
|
|
5781
|
+
onToggleSort,
|
|
5662
5782
|
rowActions,
|
|
5663
5783
|
rowClipboard,
|
|
5664
5784
|
i18n
|
|
5665
5785
|
}) {
|
|
5666
5786
|
const cols = columns ?? [];
|
|
5667
5787
|
const useFallback = cols.length === 0;
|
|
5788
|
+
const renderSortIcon = (key, sortable) => {
|
|
5789
|
+
if (!sortable) return null;
|
|
5790
|
+
if (sort?.key !== key || !sort?.dir) {
|
|
5791
|
+
return /* @__PURE__ */ jsx(ArrowUpDown, { className: "w-3 h-3 opacity-40", "aria-hidden": "true" });
|
|
5792
|
+
}
|
|
5793
|
+
return sort.dir === "asc" ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3", "aria-hidden": "true" });
|
|
5794
|
+
};
|
|
5668
5795
|
return /* @__PURE__ */ jsx("div", { className: "ra-item-table-wrap", children: /* @__PURE__ */ jsxs("table", { className: "ra-item-table", children: [
|
|
5669
5796
|
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
5670
5797
|
useFallback ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5671
|
-
/* @__PURE__ */ jsx("th", { children:
|
|
5672
|
-
|
|
5673
|
-
|
|
5798
|
+
/* @__PURE__ */ jsx("th", { children: /* @__PURE__ */ jsx(
|
|
5799
|
+
SortableHeader,
|
|
5800
|
+
{
|
|
5801
|
+
label: i18n.itemColumnLabel,
|
|
5802
|
+
sortable: !!onToggleSort,
|
|
5803
|
+
icon: renderSortIcon("__label", !!onToggleSort),
|
|
5804
|
+
onClick: () => onToggleSort?.("__label")
|
|
5805
|
+
}
|
|
5806
|
+
) }),
|
|
5807
|
+
/* @__PURE__ */ jsx("th", { style: { width: "12rem" }, children: /* @__PURE__ */ jsx(
|
|
5808
|
+
SortableHeader,
|
|
5809
|
+
{
|
|
5810
|
+
label: i18n.itemColumnUpdated,
|
|
5811
|
+
sortable: !!onToggleSort,
|
|
5812
|
+
icon: renderSortIcon("__updated", !!onToggleSort),
|
|
5813
|
+
onClick: () => onToggleSort?.("__updated")
|
|
5814
|
+
}
|
|
5815
|
+
) })
|
|
5816
|
+
] }) : cols.map((c) => /* @__PURE__ */ jsx("th", { style: { width: c.width, textAlign: c.align ?? "left" }, children: /* @__PURE__ */ jsx(
|
|
5817
|
+
SortableHeader,
|
|
5818
|
+
{
|
|
5819
|
+
label: c.header,
|
|
5820
|
+
sortable: !!c.sortBy && !!onToggleSort,
|
|
5821
|
+
icon: renderSortIcon(c.key, !!c.sortBy && !!onToggleSort),
|
|
5822
|
+
onClick: () => onToggleSort?.(c.key),
|
|
5823
|
+
align: c.align ?? "left"
|
|
5824
|
+
}
|
|
5825
|
+
) }, c.key)),
|
|
5674
5826
|
/* @__PURE__ */ jsx(
|
|
5675
5827
|
"th",
|
|
5676
5828
|
{
|
|
@@ -5758,6 +5910,39 @@ function DefaultItemTable({
|
|
|
5758
5910
|
}) })
|
|
5759
5911
|
] }) });
|
|
5760
5912
|
}
|
|
5913
|
+
function SortableHeader({
|
|
5914
|
+
label,
|
|
5915
|
+
sortable,
|
|
5916
|
+
icon,
|
|
5917
|
+
onClick,
|
|
5918
|
+
align = "left"
|
|
5919
|
+
}) {
|
|
5920
|
+
if (!sortable) return /* @__PURE__ */ jsx(Fragment, { children: label });
|
|
5921
|
+
return /* @__PURE__ */ jsxs(
|
|
5922
|
+
"button",
|
|
5923
|
+
{
|
|
5924
|
+
type: "button",
|
|
5925
|
+
onClick,
|
|
5926
|
+
className: "ra-item-th-sort",
|
|
5927
|
+
style: {
|
|
5928
|
+
display: "inline-flex",
|
|
5929
|
+
alignItems: "center",
|
|
5930
|
+
gap: "4px",
|
|
5931
|
+
background: "transparent",
|
|
5932
|
+
border: 0,
|
|
5933
|
+
padding: 0,
|
|
5934
|
+
font: "inherit",
|
|
5935
|
+
color: "inherit",
|
|
5936
|
+
cursor: "pointer",
|
|
5937
|
+
textAlign: align
|
|
5938
|
+
},
|
|
5939
|
+
children: [
|
|
5940
|
+
/* @__PURE__ */ jsx("span", { children: label }),
|
|
5941
|
+
icon
|
|
5942
|
+
]
|
|
5943
|
+
}
|
|
5944
|
+
);
|
|
5945
|
+
}
|
|
5761
5946
|
var initials = (label) => label.split(/\s+/).slice(0, 2).map((s) => s[0]?.toUpperCase() ?? "").join("") || "?";
|
|
5762
5947
|
function DefaultItemCards({
|
|
5763
5948
|
items,
|
|
@@ -5872,9 +6057,75 @@ function ItemListView({
|
|
|
5872
6057
|
cardSize = "md",
|
|
5873
6058
|
rowActions,
|
|
5874
6059
|
rowClipboard,
|
|
6060
|
+
searchableFields,
|
|
6061
|
+
searchable = true,
|
|
6062
|
+
total,
|
|
6063
|
+
hasNextPage,
|
|
6064
|
+
isFetchingNextPage,
|
|
6065
|
+
onLoadMore,
|
|
5875
6066
|
i18n
|
|
5876
6067
|
}) {
|
|
5877
6068
|
const newLabel = i18n.newItem.includes("{noun}") ? i18n.newItem.replace("{noun}", itemNoun) : i18n.newItem;
|
|
6069
|
+
const [search, setSearch] = useState("");
|
|
6070
|
+
const [sort, setSort] = useState({ key: null, dir: null });
|
|
6071
|
+
const onToggleSort = (key) => {
|
|
6072
|
+
setSort((cur) => {
|
|
6073
|
+
if (cur.key !== key) return { key, dir: "asc" };
|
|
6074
|
+
const next = cur.dir === "asc" ? "desc" : cur.dir === "desc" ? null : "asc";
|
|
6075
|
+
return { key: next ? key : null, dir: next };
|
|
6076
|
+
});
|
|
6077
|
+
};
|
|
6078
|
+
const wantsFullSet = search.trim().length > 0 || sort.dir !== null;
|
|
6079
|
+
const loadingNextRef = useRef(false);
|
|
6080
|
+
useEffect(() => {
|
|
6081
|
+
if (!wantsFullSet || !hasNextPage || !onLoadMore) return;
|
|
6082
|
+
if (isFetchingNextPage || loadingNextRef.current) return;
|
|
6083
|
+
loadingNextRef.current = true;
|
|
6084
|
+
onLoadMore();
|
|
6085
|
+
}, [wantsFullSet, hasNextPage, onLoadMore, isFetchingNextPage]);
|
|
6086
|
+
useEffect(() => {
|
|
6087
|
+
if (!isFetchingNextPage) loadingNextRef.current = false;
|
|
6088
|
+
}, [isFetchingNextPage]);
|
|
6089
|
+
const lookupColumn = useMemo(() => {
|
|
6090
|
+
const m = /* @__PURE__ */ new Map();
|
|
6091
|
+
(itemColumns ?? []).forEach((c) => m.set(c.key, c));
|
|
6092
|
+
return m;
|
|
6093
|
+
}, [itemColumns]);
|
|
6094
|
+
const visibleItems = useMemo(() => {
|
|
6095
|
+
let out = items;
|
|
6096
|
+
const q = search.trim().toLowerCase();
|
|
6097
|
+
if (q) {
|
|
6098
|
+
out = out.filter((it) => {
|
|
6099
|
+
const fields = [it.label, it.subtitle];
|
|
6100
|
+
if (searchableFields) fields.push(...searchableFields(it));
|
|
6101
|
+
return fields.some((f) => typeof f === "string" && f.toLowerCase().includes(q));
|
|
6102
|
+
});
|
|
6103
|
+
}
|
|
6104
|
+
if (sort.key && sort.dir) {
|
|
6105
|
+
const dir = sort.dir === "asc" ? 1 : -1;
|
|
6106
|
+
const getter = (it) => {
|
|
6107
|
+
if (sort.key === "__label") return it.label;
|
|
6108
|
+
if (sort.key === "__updated") return it.updatedAt;
|
|
6109
|
+
const col = lookupColumn.get(sort.key);
|
|
6110
|
+
return col?.sortBy ? col.sortBy(it) : void 0;
|
|
6111
|
+
};
|
|
6112
|
+
const norm = (v) => {
|
|
6113
|
+
if (v == null) return Number.POSITIVE_INFINITY;
|
|
6114
|
+
if (v instanceof Date) return v.getTime();
|
|
6115
|
+
if (typeof v === "boolean") return v ? 1 : 0;
|
|
6116
|
+
if (typeof v === "number") return v;
|
|
6117
|
+
return String(v).toLowerCase();
|
|
6118
|
+
};
|
|
6119
|
+
out = [...out].sort((a, b) => {
|
|
6120
|
+
const av = norm(getter(a));
|
|
6121
|
+
const bv = norm(getter(b));
|
|
6122
|
+
if (av < bv) return -1 * dir;
|
|
6123
|
+
if (av > bv) return 1 * dir;
|
|
6124
|
+
return 0;
|
|
6125
|
+
});
|
|
6126
|
+
}
|
|
6127
|
+
return out;
|
|
6128
|
+
}, [items, search, sort, lookupColumn, searchableFields]);
|
|
5878
6129
|
const [pendingDeleteId, setPendingDeleteId] = useState(null);
|
|
5879
6130
|
const pendingRecord = useMemo(
|
|
5880
6131
|
() => pendingDeleteId ? items.find((it) => (it.itemId ?? "") === pendingDeleteId) ?? null : null,
|
|
@@ -5889,9 +6140,62 @@ function ItemListView({
|
|
|
5889
6140
|
const toolbar = /* @__PURE__ */ jsxs("div", { className: "ra-item-toolbar", children: [
|
|
5890
6141
|
/* @__PURE__ */ jsxs("div", { className: "ra-item-toolbar-title", children: [
|
|
5891
6142
|
/* @__PURE__ */ jsx("h2", { className: "ra-display", style: { fontSize: "0.95rem", margin: 0 }, children: i18n.itemListTitle }),
|
|
5892
|
-
/* @__PURE__ */ jsx("span", { className: "ra-item-toolbar-count", children: items.length })
|
|
6143
|
+
/* @__PURE__ */ jsx("span", { className: "ra-item-toolbar-count", children: visibleItems.length === items.length ? items.length : `${visibleItems.length} / ${items.length}` })
|
|
5893
6144
|
] }),
|
|
5894
6145
|
/* @__PURE__ */ jsxs("div", { className: "ra-item-toolbar-actions", children: [
|
|
6146
|
+
searchable && items.length > 0 && /* @__PURE__ */ jsxs(
|
|
6147
|
+
"div",
|
|
6148
|
+
{
|
|
6149
|
+
className: "ra-item-search",
|
|
6150
|
+
style: {
|
|
6151
|
+
display: "inline-flex",
|
|
6152
|
+
alignItems: "center",
|
|
6153
|
+
gap: "6px",
|
|
6154
|
+
padding: "4px 8px",
|
|
6155
|
+
border: "1px solid hsl(var(--ra-border))",
|
|
6156
|
+
borderRadius: "6px",
|
|
6157
|
+
background: "hsl(var(--ra-surface))"
|
|
6158
|
+
},
|
|
6159
|
+
children: [
|
|
6160
|
+
/* @__PURE__ */ jsx(Search, { className: "w-3.5 h-3.5", "aria-hidden": "true", style: { opacity: 0.6 } }),
|
|
6161
|
+
/* @__PURE__ */ jsx(
|
|
6162
|
+
"input",
|
|
6163
|
+
{
|
|
6164
|
+
type: "text",
|
|
6165
|
+
value: search,
|
|
6166
|
+
onChange: (e) => setSearch(e.target.value),
|
|
6167
|
+
placeholder: `Search ${itemNoun}s`,
|
|
6168
|
+
"aria-label": `Search ${itemNoun}s`,
|
|
6169
|
+
style: {
|
|
6170
|
+
background: "transparent",
|
|
6171
|
+
border: 0,
|
|
6172
|
+
outline: "none",
|
|
6173
|
+
font: "inherit",
|
|
6174
|
+
fontSize: "12px",
|
|
6175
|
+
color: "inherit",
|
|
6176
|
+
width: "160px"
|
|
6177
|
+
}
|
|
6178
|
+
}
|
|
6179
|
+
),
|
|
6180
|
+
search && /* @__PURE__ */ jsx(
|
|
6181
|
+
"button",
|
|
6182
|
+
{
|
|
6183
|
+
type: "button",
|
|
6184
|
+
onClick: () => setSearch(""),
|
|
6185
|
+
"aria-label": "Clear search",
|
|
6186
|
+
style: {
|
|
6187
|
+
background: "transparent",
|
|
6188
|
+
border: 0,
|
|
6189
|
+
padding: 0,
|
|
6190
|
+
cursor: "pointer",
|
|
6191
|
+
color: "hsl(var(--ra-muted-text))"
|
|
6192
|
+
},
|
|
6193
|
+
children: /* @__PURE__ */ jsx(X, { className: "w-3.5 h-3.5", "aria-hidden": "true" })
|
|
6194
|
+
}
|
|
6195
|
+
)
|
|
6196
|
+
]
|
|
6197
|
+
}
|
|
6198
|
+
),
|
|
5895
6199
|
!renderItemList && /* @__PURE__ */ jsx(
|
|
5896
6200
|
ItemViewSwitcher,
|
|
5897
6201
|
{
|
|
@@ -5942,17 +6246,27 @@ function ItemListView({
|
|
|
5942
6246
|
)
|
|
5943
6247
|
}
|
|
5944
6248
|
);
|
|
6249
|
+
} else if (visibleItems.length === 0) {
|
|
6250
|
+
body = /* @__PURE__ */ jsx(
|
|
6251
|
+
EmptyState,
|
|
6252
|
+
{
|
|
6253
|
+
title: "No matches",
|
|
6254
|
+
body: `No ${itemNoun}s match "${search}".`
|
|
6255
|
+
}
|
|
6256
|
+
);
|
|
5945
6257
|
} else if (renderItemList) {
|
|
5946
|
-
body = renderItemList(
|
|
6258
|
+
body = renderItemList(visibleItems, guardedCtx);
|
|
5947
6259
|
} else if (view === "table") {
|
|
5948
6260
|
body = /* @__PURE__ */ jsx(
|
|
5949
6261
|
DefaultItemTable,
|
|
5950
6262
|
{
|
|
5951
|
-
items,
|
|
6263
|
+
items: visibleItems,
|
|
5952
6264
|
columns: itemColumns,
|
|
5953
6265
|
selectedId: guardedCtx.selectedId,
|
|
5954
6266
|
onOpen: guardedCtx.onOpen,
|
|
5955
6267
|
onDelete: guardedCtx.onDelete,
|
|
6268
|
+
sort,
|
|
6269
|
+
onToggleSort,
|
|
5956
6270
|
rowActions,
|
|
5957
6271
|
rowClipboard,
|
|
5958
6272
|
i18n
|
|
@@ -5962,7 +6276,7 @@ function ItemListView({
|
|
|
5962
6276
|
body = /* @__PURE__ */ jsx(
|
|
5963
6277
|
DefaultItemCards,
|
|
5964
6278
|
{
|
|
5965
|
-
items,
|
|
6279
|
+
items: visibleItems,
|
|
5966
6280
|
variant: view,
|
|
5967
6281
|
selectedId: guardedCtx.selectedId,
|
|
5968
6282
|
ctx: guardedCtx,
|
|
@@ -5998,6 +6312,29 @@ function ItemListView({
|
|
|
5998
6312
|
}
|
|
5999
6313
|
) : null,
|
|
6000
6314
|
/* @__PURE__ */ jsx("div", { className: "ra-item-list-body", children: body }),
|
|
6315
|
+
wantsFullSet && hasNextPage && /* @__PURE__ */ jsx(
|
|
6316
|
+
"div",
|
|
6317
|
+
{
|
|
6318
|
+
style: {
|
|
6319
|
+
padding: "6px 12px",
|
|
6320
|
+
fontSize: "11px",
|
|
6321
|
+
color: "hsl(var(--ra-muted-text))",
|
|
6322
|
+
borderTop: "1px solid hsl(var(--ra-border))",
|
|
6323
|
+
background: "hsl(var(--ra-muted) / 0.4)"
|
|
6324
|
+
},
|
|
6325
|
+
children: isFetchingNextPage ? `Loading more ${itemNoun}s to ${search ? "search" : "sort"}\u2026` : `${search ? "Searching" : "Sorting"} the ${items.length} ${itemNoun}s loaded so far. More available \u2014 keep loading for the full set.`
|
|
6326
|
+
}
|
|
6327
|
+
),
|
|
6328
|
+
onLoadMore && /* @__PURE__ */ jsx(
|
|
6329
|
+
LoadMoreFooter,
|
|
6330
|
+
{
|
|
6331
|
+
shown: items.length,
|
|
6332
|
+
total,
|
|
6333
|
+
hasNextPage: !!hasNextPage,
|
|
6334
|
+
isFetchingNextPage: !!isFetchingNextPage,
|
|
6335
|
+
onLoadMore
|
|
6336
|
+
}
|
|
6337
|
+
),
|
|
6001
6338
|
/* @__PURE__ */ jsx(
|
|
6002
6339
|
ConfirmDialog,
|
|
6003
6340
|
{
|
|
@@ -6086,7 +6423,11 @@ function SiblingRail({
|
|
|
6086
6423
|
itemNoun,
|
|
6087
6424
|
dirtyKeys,
|
|
6088
6425
|
errorKeys,
|
|
6089
|
-
i18n
|
|
6426
|
+
i18n,
|
|
6427
|
+
total,
|
|
6428
|
+
hasNextPage,
|
|
6429
|
+
isFetchingNextPage,
|
|
6430
|
+
onLoadMore
|
|
6090
6431
|
}) {
|
|
6091
6432
|
const ruleLabelLookup = useRuleLabelLookup();
|
|
6092
6433
|
const newLabel = i18n.newItem.includes("{noun}") ? i18n.newItem.replace("{noun}", itemNoun ?? "item") : i18n.newItem;
|
|
@@ -6166,6 +6507,16 @@ function SiblingRail({
|
|
|
6166
6507
|
) }, key);
|
|
6167
6508
|
}) })
|
|
6168
6509
|
] }),
|
|
6510
|
+
onLoadMore && /* @__PURE__ */ jsx(
|
|
6511
|
+
LoadMoreFooter,
|
|
6512
|
+
{
|
|
6513
|
+
shown: items.length,
|
|
6514
|
+
total,
|
|
6515
|
+
hasNextPage: !!hasNextPage,
|
|
6516
|
+
isFetchingNextPage: !!isFetchingNextPage,
|
|
6517
|
+
onLoadMore
|
|
6518
|
+
}
|
|
6519
|
+
),
|
|
6169
6520
|
onCreate && /* @__PURE__ */ jsx("div", { className: "ra-sibling-footer", children: /* @__PURE__ */ jsxs(
|
|
6170
6521
|
"button",
|
|
6171
6522
|
{
|
|
@@ -7039,12 +7390,19 @@ function PreviewReopenPill({ anchorRef, onClick, ariaLabel, title, children }) {
|
|
|
7039
7390
|
const rafRef = useRef(null);
|
|
7040
7391
|
useLayoutEffect(() => {
|
|
7041
7392
|
const el = anchorRef.current;
|
|
7042
|
-
if (
|
|
7393
|
+
if (typeof window === "undefined") return;
|
|
7394
|
+
if (!el) {
|
|
7395
|
+
setPos({ top: window.innerHeight / 2, right: 8 });
|
|
7396
|
+
return;
|
|
7397
|
+
}
|
|
7043
7398
|
const measure = () => {
|
|
7044
7399
|
if (rafRef.current != null) cancelAnimationFrame(rafRef.current);
|
|
7045
7400
|
rafRef.current = requestAnimationFrame(() => {
|
|
7046
7401
|
const rect = el.getBoundingClientRect();
|
|
7047
|
-
if (rect.width === 0 && rect.height === 0)
|
|
7402
|
+
if (rect.width === 0 && rect.height === 0) {
|
|
7403
|
+
setPos({ top: window.innerHeight / 2, right: 8 });
|
|
7404
|
+
return;
|
|
7405
|
+
}
|
|
7048
7406
|
setPos({
|
|
7049
7407
|
top: rect.top + rect.height / 2,
|
|
7050
7408
|
right: Math.max(0, window.innerWidth - rect.right)
|
|
@@ -7064,7 +7422,11 @@ function PreviewReopenPill({ anchorRef, onClick, ariaLabel, title, children }) {
|
|
|
7064
7422
|
if (rafRef.current != null) cancelAnimationFrame(rafRef.current);
|
|
7065
7423
|
};
|
|
7066
7424
|
}, [anchorRef]);
|
|
7067
|
-
if (typeof document === "undefined"
|
|
7425
|
+
if (typeof document === "undefined") return null;
|
|
7426
|
+
const effectivePos = pos ?? {
|
|
7427
|
+
top: typeof window !== "undefined" ? window.innerHeight / 2 : 200,
|
|
7428
|
+
right: 8
|
|
7429
|
+
};
|
|
7068
7430
|
return createPortal(
|
|
7069
7431
|
/* @__PURE__ */ jsx(
|
|
7070
7432
|
"button",
|
|
@@ -7076,8 +7438,8 @@ function PreviewReopenPill({ anchorRef, onClick, ariaLabel, title, children }) {
|
|
|
7076
7438
|
title,
|
|
7077
7439
|
style: {
|
|
7078
7440
|
position: "fixed",
|
|
7079
|
-
top:
|
|
7080
|
-
right:
|
|
7441
|
+
top: effectivePos.top,
|
|
7442
|
+
right: effectivePos.right,
|
|
7081
7443
|
// Pull half the pill width out into the gutter so it visually
|
|
7082
7444
|
// anchors *to* the editor edge rather than sitting inside it.
|
|
7083
7445
|
transform: "translate(50%, -50%)"
|
|
@@ -7334,12 +7696,17 @@ function RecordsAdminShell(props) {
|
|
|
7334
7696
|
}),
|
|
7335
7697
|
[props.SL, props.collectionId, props.appId, props.recordType]
|
|
7336
7698
|
);
|
|
7699
|
+
const recordChangeRef = useRef(null);
|
|
7700
|
+
const onRecordChange = useCallback((notice) => {
|
|
7701
|
+
recordChangeRef.current?.(notice);
|
|
7702
|
+
}, []);
|
|
7337
7703
|
return /* @__PURE__ */ jsx(
|
|
7338
7704
|
EditorSessionProvider,
|
|
7339
7705
|
{
|
|
7340
7706
|
ctx,
|
|
7341
7707
|
defaultValueFactory: props.defaultData,
|
|
7342
7708
|
hooks: props.hooks,
|
|
7709
|
+
onRecordChange,
|
|
7343
7710
|
onHookNotice: (notice) => {
|
|
7344
7711
|
console.warn(`[RecordsAdmin] ${notice.kind} hook failed`, notice.error);
|
|
7345
7712
|
try {
|
|
@@ -7352,7 +7719,7 @@ function RecordsAdminShell(props) {
|
|
|
7352
7719
|
} catch {
|
|
7353
7720
|
}
|
|
7354
7721
|
},
|
|
7355
|
-
children: /* @__PURE__ */ jsx(RecordsAdminShellInner, { ...props })
|
|
7722
|
+
children: /* @__PURE__ */ jsx(RecordsAdminShellInner, { ...props, recordChangeRef })
|
|
7356
7723
|
}
|
|
7357
7724
|
);
|
|
7358
7725
|
}
|
|
@@ -7385,7 +7752,8 @@ function RecordsAdminShellInner(props) {
|
|
|
7385
7752
|
recordActions,
|
|
7386
7753
|
icons: iconsOverride,
|
|
7387
7754
|
// Deep linking
|
|
7388
|
-
deepLink
|
|
7755
|
+
deepLink,
|
|
7756
|
+
recordChangeRef
|
|
7389
7757
|
} = props;
|
|
7390
7758
|
const {
|
|
7391
7759
|
show: showHeader,
|
|
@@ -7412,7 +7780,8 @@ function RecordsAdminShellInner(props) {
|
|
|
7412
7780
|
groupBy,
|
|
7413
7781
|
defaultGroupKey,
|
|
7414
7782
|
onGroupExpanded,
|
|
7415
|
-
density = "comfortable"
|
|
7783
|
+
density = "comfortable",
|
|
7784
|
+
pageSize: railPageSize
|
|
7416
7785
|
} = rail ?? {};
|
|
7417
7786
|
const {
|
|
7418
7787
|
tabs: editorTabs = "off",
|
|
@@ -7435,7 +7804,10 @@ function RecordsAdminShellInner(props) {
|
|
|
7435
7804
|
renderEmpty: renderItemEmpty,
|
|
7436
7805
|
cardSize: itemCardSize = "md",
|
|
7437
7806
|
railMode: collectionRailMode = "siblings",
|
|
7438
|
-
toSummary: itemToSummary
|
|
7807
|
+
toSummary: itemToSummary,
|
|
7808
|
+
pageSize: itemsPageSize,
|
|
7809
|
+
searchableFields: itemsSearchableFields,
|
|
7810
|
+
searchable: itemsSearchable
|
|
7439
7811
|
} = items ?? {};
|
|
7440
7812
|
const {
|
|
7441
7813
|
strategy: dirtyStrategy = "keep",
|
|
@@ -7495,6 +7867,21 @@ function RecordsAdminShellInner(props) {
|
|
|
7495
7867
|
[SL, collectionId, appId, recordType]
|
|
7496
7868
|
);
|
|
7497
7869
|
const queryClient = useQueryClient();
|
|
7870
|
+
useEffect(() => {
|
|
7871
|
+
recordChangeRef.current = (notice) => {
|
|
7872
|
+
if (notice.kind === "saved") {
|
|
7873
|
+
patchRecordIntoCaches(queryClient, notice.ctx, notice.record);
|
|
7874
|
+
} else {
|
|
7875
|
+
removeRecordFromCaches(queryClient, notice.ctx, notice.recordId);
|
|
7876
|
+
}
|
|
7877
|
+
queryClient.invalidateQueries({
|
|
7878
|
+
queryKey: scopeCountsQueryKey(notice.ctx.collectionId, notice.ctx.appId, notice.ctx.recordType)
|
|
7879
|
+
});
|
|
7880
|
+
};
|
|
7881
|
+
return () => {
|
|
7882
|
+
recordChangeRef.current = null;
|
|
7883
|
+
};
|
|
7884
|
+
}, [queryClient, recordChangeRef]);
|
|
7498
7885
|
const probe = useScopeProbe({ SL, collectionId });
|
|
7499
7886
|
const scopeCounts = useScopeCounts({ ctx });
|
|
7500
7887
|
const topLevelScopes = useMemo(() => {
|
|
@@ -7577,7 +7964,8 @@ function RecordsAdminShellInner(props) {
|
|
|
7577
7964
|
probeIsLoading: probe.isLoading,
|
|
7578
7965
|
selectedProductId,
|
|
7579
7966
|
drillTab,
|
|
7580
|
-
classify: classify3
|
|
7967
|
+
classify: classify3,
|
|
7968
|
+
pageSize: railPageSize
|
|
7581
7969
|
});
|
|
7582
7970
|
const {
|
|
7583
7971
|
search,
|
|
@@ -7658,7 +8046,8 @@ function RecordsAdminShellInner(props) {
|
|
|
7658
8046
|
// host-supplied lifecycle grouping has the full picture.
|
|
7659
8047
|
includeAll: isCollection && activeScope === "all",
|
|
7660
8048
|
enabled: isCollection,
|
|
7661
|
-
toSummary: itemToSummary
|
|
8049
|
+
toSummary: itemToSummary,
|
|
8050
|
+
pageSize: itemsPageSize
|
|
7662
8051
|
});
|
|
7663
8052
|
useEffect(() => {
|
|
7664
8053
|
if (skipNextItemResetRef.current) {
|
|
@@ -7667,6 +8056,36 @@ function RecordsAdminShellInner(props) {
|
|
|
7667
8056
|
}
|
|
7668
8057
|
setSelectedItemId(null);
|
|
7669
8058
|
}, [editingScope?.raw]);
|
|
8059
|
+
const isLifecycleRailEarly = (activeScope === "all" || activeScope === "collection") && isCollection && !!groupBy;
|
|
8060
|
+
const lifecycleBucketLabel = useMemo(() => {
|
|
8061
|
+
if (!isLifecycleRailEarly || !selectedLifecycleKey || !groupBy) return null;
|
|
8062
|
+
for (const it of collectionItems.items) {
|
|
8063
|
+
const g = groupBy(it);
|
|
8064
|
+
if (g && g.key === selectedLifecycleKey) return g.label ?? null;
|
|
8065
|
+
}
|
|
8066
|
+
return null;
|
|
8067
|
+
}, [isLifecycleRailEarly, selectedLifecycleKey, groupBy, collectionItems.items]);
|
|
8068
|
+
const scopedCollectionItemsList = useMemo(() => {
|
|
8069
|
+
if (!isLifecycleRailEarly || !selectedLifecycleKey || !groupBy) return collectionItems.items;
|
|
8070
|
+
return collectionItems.items.filter((it) => {
|
|
8071
|
+
const g = groupBy(it);
|
|
8072
|
+
return g?.key === selectedLifecycleKey;
|
|
8073
|
+
});
|
|
8074
|
+
}, [isLifecycleRailEarly, selectedLifecycleKey, groupBy, collectionItems.items]);
|
|
8075
|
+
useEffect(() => {
|
|
8076
|
+
if (!isLifecycleRailEarly || !groupBy) return;
|
|
8077
|
+
if (selectedLifecycleKey || !selectedItemId) return;
|
|
8078
|
+
const row = collectionItems.items.find(
|
|
8079
|
+
(it) => it.itemId === selectedItemId || it.id === selectedItemId
|
|
8080
|
+
);
|
|
8081
|
+
if (!row) return;
|
|
8082
|
+
const g = groupBy(row);
|
|
8083
|
+
if (g?.key) setSelectedLifecycleKey(g.key);
|
|
8084
|
+
}, [isLifecycleRailEarly, groupBy, selectedItemId, selectedLifecycleKey, collectionItems.items, setSelectedLifecycleKey]);
|
|
8085
|
+
const scopedCollectionItems = useMemo(() => ({
|
|
8086
|
+
...collectionItems,
|
|
8087
|
+
items: scopedCollectionItemsList
|
|
8088
|
+
}), [collectionItems, scopedCollectionItemsList]);
|
|
7670
8089
|
const { lastAppliedDLRef } = useShellDeepLink({
|
|
7671
8090
|
deepLinkState,
|
|
7672
8091
|
editingScope,
|
|
@@ -7769,7 +8188,6 @@ function RecordsAdminShellInner(props) {
|
|
|
7769
8188
|
if (isCreate && isCollection && savedRecordId && isDraftId3(selectedItemId)) {
|
|
7770
8189
|
setSelectedItemId(savedRecordId);
|
|
7771
8190
|
}
|
|
7772
|
-
await refetchAll();
|
|
7773
8191
|
if (!isCollection && isCreate && activeScope === "collection") {
|
|
7774
8192
|
setSelectedRecordId(savedRecordId ?? null);
|
|
7775
8193
|
}
|
|
@@ -7788,7 +8206,6 @@ function RecordsAdminShellInner(props) {
|
|
|
7788
8206
|
setSelectedRecordId(null);
|
|
7789
8207
|
setDraftKind(null);
|
|
7790
8208
|
}
|
|
7791
|
-
await refetchAll();
|
|
7792
8209
|
setIsReconcilingRecordSelection(false);
|
|
7793
8210
|
}
|
|
7794
8211
|
});
|
|
@@ -7954,7 +8371,7 @@ function RecordsAdminShellInner(props) {
|
|
|
7954
8371
|
setSelectedItemId,
|
|
7955
8372
|
editingScope,
|
|
7956
8373
|
baseScopeRef,
|
|
7957
|
-
collectionItems,
|
|
8374
|
+
collectionItems: scopedCollectionItems,
|
|
7958
8375
|
queryClient,
|
|
7959
8376
|
ctx,
|
|
7960
8377
|
collectionId,
|
|
@@ -8670,7 +9087,7 @@ function RecordsAdminShellInner(props) {
|
|
|
8670
9087
|
!railHidden && /* @__PURE__ */ jsx("aside", { className: "border-r overflow-hidden flex flex-col", style: { borderColor: "hsl(var(--ra-border))", background: "hsl(var(--ra-surface))" }, children: isCollection && selectedItemId && collectionRailMode === "siblings" && ruleWizardStep === null ? /* @__PURE__ */ jsx(
|
|
8671
9088
|
SiblingRail,
|
|
8672
9089
|
{
|
|
8673
|
-
items:
|
|
9090
|
+
items: scopedCollectionItemsList,
|
|
8674
9091
|
selectedItemId,
|
|
8675
9092
|
isLoading: collectionItems.isLoading,
|
|
8676
9093
|
error: collectionItems.error,
|
|
@@ -8680,8 +9097,13 @@ function RecordsAdminShellInner(props) {
|
|
|
8680
9097
|
itemNoun: itemNounLabel,
|
|
8681
9098
|
dirtyKeys,
|
|
8682
9099
|
errorKeys,
|
|
8683
|
-
|
|
8684
|
-
|
|
9100
|
+
hasNextPage: !!collectionItems.hasNextPage,
|
|
9101
|
+
isFetchingNextPage: !!collectionItems.isFetchingNextPage,
|
|
9102
|
+
onLoadMore: () => {
|
|
9103
|
+
void collectionItems.fetchNextPage();
|
|
9104
|
+
},
|
|
9105
|
+
contextKind: isLifecycleRailEarly && lifecycleBucketLabel ? lifecycleBucketLabel : activeScope === "rule" ? "Rule" : activeScope === "product" ? "Product" : activeScope === "collection" ? "Global" : activeScope === "all" ? "All records" : activeScope === "variant" ? "Variant" : activeScope === "batch" ? "Batch" : activeScope === "facet" ? "Facet" : void 0,
|
|
9106
|
+
contextSummary: isLifecycleRailEarly && lifecycleBucketLabel ? `${scopedCollectionItemsList.length} ${itemNounLabel}${scopedCollectionItemsList.length === 1 ? "" : "s"}` : activeScope === "rule" ? activeRuleSummary : activeScope === "product" ? editorHeaderLabel ?? null : null,
|
|
8685
9107
|
i18n
|
|
8686
9108
|
}
|
|
8687
9109
|
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -8859,19 +9281,29 @@ function RecordsAdminShellInner(props) {
|
|
|
8859
9281
|
i18n
|
|
8860
9282
|
}
|
|
8861
9283
|
),
|
|
8862
|
-
isProductTab && !productPinned &&
|
|
8863
|
-
|
|
9284
|
+
isProductTab && !productPinned && /* @__PURE__ */ jsx(
|
|
9285
|
+
LoadMoreFooter,
|
|
8864
9286
|
{
|
|
8865
|
-
|
|
8866
|
-
|
|
9287
|
+
shown: leftItems.length,
|
|
9288
|
+
hasNextPage: !!productBrowse.hasNextPage,
|
|
9289
|
+
isFetchingNextPage: !!productBrowse.isFetchingNextPage,
|
|
9290
|
+
onLoadMore: () => {
|
|
8867
9291
|
void productBrowse.fetchNextPage();
|
|
8868
|
-
}
|
|
8869
|
-
disabled: productBrowse.isFetchingNextPage,
|
|
8870
|
-
className: "w-full text-xs py-2 rounded-md border transition-opacity disabled:opacity-50 hover:bg-[hsl(var(--ra-muted))]",
|
|
8871
|
-
style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" },
|
|
8872
|
-
children: productBrowse.isFetchingNextPage ? "Loading\u2026" : `Load more (${leftItems.length} shown)`
|
|
9292
|
+
}
|
|
8873
9293
|
}
|
|
8874
|
-
)
|
|
9294
|
+
),
|
|
9295
|
+
isRecordsTab && (!isCollection || !(isAllTab || isGlobalTab)) && /* @__PURE__ */ jsx(
|
|
9296
|
+
LoadMoreFooter,
|
|
9297
|
+
{
|
|
9298
|
+
shown: recordList.items.length,
|
|
9299
|
+
total: recordList.total,
|
|
9300
|
+
hasNextPage: !!recordList.hasNextPage,
|
|
9301
|
+
isFetchingNextPage: !!recordList.isFetchingNextPage,
|
|
9302
|
+
onLoadMore: () => {
|
|
9303
|
+
void recordList.fetchNextPage();
|
|
9304
|
+
}
|
|
9305
|
+
}
|
|
9306
|
+
)
|
|
8875
9307
|
] })
|
|
8876
9308
|
] }) })
|
|
8877
9309
|
] }) }),
|
|
@@ -8956,6 +9388,14 @@ function RecordsAdminShellInner(props) {
|
|
|
8956
9388
|
ruleSummary: activeRuleSummary,
|
|
8957
9389
|
rowActions: wrappedRecordActions,
|
|
8958
9390
|
rowClipboard,
|
|
9391
|
+
searchableFields: itemsSearchableFields,
|
|
9392
|
+
searchable: itemsSearchable,
|
|
9393
|
+
total: collectionItems.total,
|
|
9394
|
+
hasNextPage: !!collectionItems.hasNextPage,
|
|
9395
|
+
isFetchingNextPage: !!collectionItems.isFetchingNextPage,
|
|
9396
|
+
onLoadMore: () => {
|
|
9397
|
+
void collectionItems.fetchNextPage();
|
|
9398
|
+
},
|
|
8959
9399
|
i18n
|
|
8960
9400
|
}
|
|
8961
9401
|
),
|
|
@@ -10045,6 +10485,6 @@ function useMergedRecord(args) {
|
|
|
10045
10485
|
// src/components/RecordsAdmin/index.ts
|
|
10046
10486
|
assertComponentStylesLoaded("records-admin");
|
|
10047
10487
|
|
|
10048
|
-
export { ALL_ITEM_VIEWS, ALL_PRESENTATIONS, BatchList, BulkActionsMenu, DEFAULT_DEEP_LINK_PARAM_NAMES, DEFAULT_I18N, DEFAULT_ICONS, DefaultItemCards, DefaultItemTable, DefaultRecordCard, DefaultRecordRow, DeleteButton, DirtyDraftProvider, DrawerPreview, EditorItemNav, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, ItemListView, ItemViewSwitcher, LoadingState, PresentationSwitcher, PreviewScopePicker, PreviewToggleButton, ProductDrillDown, ProductList, RecordBrowser, RecordEditor, RecordList, RecordsAdminShell, ResolvedPreview, ScopeBreadcrumb, ScopeTabs, SiblingRail, SidePreview, StatusDot, StatusFilterPills, StatusIcon, TabbedPreview, UtilityRow, VariantList, buildDraftKey, buildRef, checkPasteCompatibility, cloneValue, createDefaultDeepLinkAdapter, createPostMessageDeepLinkAdapter, createRouterDeepLinkAdapter, downloadBlob, exportCsv, importCsv, isInSmartLinksIframe, mergeIcons, normaliseRule, parseRef, pickHeaderIcon, resolutionChain, resolveRecord, ruleHash, rulesEqual, scopeCountsQueryKey, statusToneLabel, summariseRule, useCollectedRecords, useCollectionItems, useDeepLinkState, useDirtyDraft, useDirtyDraftActions, useDirtyDraftStore, useDirtyDrafts, useDirtyNavigation, useFacetBrowse, useIntroDismissed, useItemViewPref, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordClipboard, useRecordEditor, useRecordList, useResolveAllRecords, useResolvedRecord, useRulePreview, useScopeCounts, useScopeProbe, useUnsavedGuard };
|
|
10488
|
+
export { ALL_ITEM_VIEWS, ALL_PRESENTATIONS, BatchList, BulkActionsMenu, DEFAULT_DEEP_LINK_PARAM_NAMES, DEFAULT_I18N, DEFAULT_ICONS, DefaultItemCards, DefaultItemTable, DefaultRecordCard, DefaultRecordRow, DeleteButton, DirtyDraftProvider, DrawerPreview, EditorItemNav, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, ItemListView, ItemViewSwitcher, LoadingState, PresentationSwitcher, PreviewReopenPill, PreviewScopePicker, PreviewToggleButton, ProductDrillDown, ProductList, RecordBrowser, RecordEditor, RecordList, RecordsAdminShell, ResolvedPreview, ScopeBreadcrumb, ScopeTabs, SiblingRail, SidePreview, StatusDot, StatusFilterPills, StatusIcon, TabbedPreview, UtilityRow, VariantList, buildDraftKey, buildRef, checkPasteCompatibility, cloneValue, createDefaultDeepLinkAdapter, createPostMessageDeepLinkAdapter, createRouterDeepLinkAdapter, downloadBlob, exportCsv, importCsv, isInSmartLinksIframe, mergeIcons, normaliseRule, parseRef, pickHeaderIcon, resolutionChain, resolveRecord, ruleHash, rulesEqual, scopeCountsQueryKey, statusToneLabel, summariseRule, useCollectedRecords, useCollectionItems, useDeepLinkState, useDirtyDraft, useDirtyDraftActions, useDirtyDraftStore, useDirtyDrafts, useDirtyNavigation, useFacetBrowse, useIntroDismissed, useItemViewPref, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordClipboard, useRecordEditor, useRecordList, useResolveAllRecords, useResolvedRecord, useRulePreview, useScopeCounts, useScopeProbe, useUnsavedGuard };
|
|
10049
10489
|
//# sourceMappingURL=index.js.map
|
|
10050
10490
|
//# sourceMappingURL=index.js.map
|