@proveanything/smartlinks-utils-ui 0.12.6 → 0.12.8
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/chunk-WCUKTVWC.js +382 -0
- package/dist/chunk-WCUKTVWC.js.map +1 -0
- package/dist/components/AssetPicker/index.css +14 -6
- package/dist/components/AssetPicker/index.css.map +1 -1
- package/dist/components/ConditionsEditor/index.css +14 -6
- package/dist/components/ConditionsEditor/index.css.map +1 -1
- package/dist/components/ConditionsEditor/index.js +1 -1
- package/dist/components/FontPicker/index.css +14 -6
- package/dist/components/FontPicker/index.css.map +1 -1
- package/dist/components/IconPicker/index.css +14 -6
- package/dist/components/IconPicker/index.css.map +1 -1
- package/dist/components/LinkPicker/index.css +3990 -0
- package/dist/components/LinkPicker/index.css.map +1 -0
- package/dist/components/LinkPicker/index.d.ts +131 -0
- package/dist/components/LinkPicker/index.js +6 -0
- package/dist/components/LinkPicker/index.js.map +1 -0
- package/dist/components/RecordsAdmin/index.css +14 -6
- package/dist/components/RecordsAdmin/index.css.map +1 -1
- package/dist/components/RecordsAdmin/index.d.ts +44 -3
- package/dist/components/RecordsAdmin/index.js +772 -392
- package/dist/components/RecordsAdmin/index.js.map +1 -1
- package/dist/index.css +14 -6
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
import { parsedRefToTarget, parsedRefToScope, matchRecords, scopesEqual, getRecordById, listRecords, upsertRecord, updateRecord, createRecord, removeRecord } from '../../chunk-KA4MKRHL.js';
|
|
2
|
+
export { bulkDelete, bulkUpsert, createRecord, getRecordById, listRecords, matchRecords, parsedRefToScope, parsedRefToTarget, removeRecord, restoreRecord, scopesEqual, upsertRecord } from '../../chunk-KA4MKRHL.js';
|
|
1
3
|
import { useIntroState, AdminPageHeader } from '../../chunk-3RRHM4LP.js';
|
|
2
|
-
import { assertComponentStylesLoaded } from '../../chunk-OLYC54YT.js';
|
|
3
|
-
import '../../chunk-5UQQYXCX.js';
|
|
4
4
|
import { FacetRuleEditor } from '../../chunk-JMCV6FOW.js';
|
|
5
5
|
import { useFacets } from '../../chunk-4LHF5JB7.js';
|
|
6
|
+
import { assertComponentStylesLoaded } from '../../chunk-OLYC54YT.js';
|
|
7
|
+
import '../../chunk-5UQQYXCX.js';
|
|
6
8
|
import { cn } from '../../chunk-L7FQ52F5.js';
|
|
7
|
-
import { parsedRefToTarget, parsedRefToScope, matchRecords, scopesEqual, getRecordById, listRecords, upsertRecord, updateRecord, createRecord, removeRecord } from '../../chunk-KA4MKRHL.js';
|
|
8
|
-
export { bulkDelete, bulkUpsert, createRecord, getRecordById, listRecords, matchRecords, parsedRefToScope, parsedRefToTarget, removeRecord, restoreRecord, scopesEqual, upsertRecord } from '../../chunk-KA4MKRHL.js';
|
|
9
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, Check, Rows3, ChevronRight, Eraser, FilePlus2, CopyPlus, ClipboardPaste, Box, X, Search, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, CornerDownLeft, Circle, ArrowUpDown, ArrowUp, ArrowDown, MinusCircle, XCircle, AlertCircle, Undo2, Save, Loader2, Archive, ArrowRight, Globe2, Sparkles, Settings2 } from 'lucide-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, Check, Rows3, ChevronRight, Eraser, FilePlus2, CopyPlus, ClipboardPaste, Box, X, Search, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, PanelLeftClose, CornerDownLeft, Circle, ArrowUpDown, ArrowUp, ArrowDown, MinusCircle, XCircle, AlertCircle, Undo2, Save, Loader2, Archive, ArrowRight, Globe2, Sparkles, 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';
|
|
@@ -183,6 +183,8 @@ var DEFAULT_I18N = {
|
|
|
183
183
|
editor: "Editor",
|
|
184
184
|
closePreview: "Close preview",
|
|
185
185
|
openPreview: "Open preview",
|
|
186
|
+
closeList: "Hide list",
|
|
187
|
+
openList: "Show list",
|
|
186
188
|
previewAs: "Preview as",
|
|
187
189
|
previewAsDefault: "Same as edited",
|
|
188
190
|
confirmDelete: "Confirm delete",
|
|
@@ -276,7 +278,15 @@ var DEFAULT_I18N = {
|
|
|
276
278
|
conflictArchiveDuplicates: "Archive duplicates",
|
|
277
279
|
conflictDeleteDuplicates: "Delete duplicates",
|
|
278
280
|
conflictDeleteConfirm: "Permanently delete {n} duplicate record(s)? This cannot be undone.",
|
|
279
|
-
conflictResolveLabel: "Resolve"
|
|
281
|
+
conflictResolveLabel: "Resolve",
|
|
282
|
+
ruleSortLabel: "Sort",
|
|
283
|
+
ruleSortRecent: "Recently updated",
|
|
284
|
+
ruleSortName: "Name",
|
|
285
|
+
ruleSortActiveCount: "Active count",
|
|
286
|
+
ruleSortHasArchived: "Has archived",
|
|
287
|
+
lifecycleBadgeActive: "{n} active",
|
|
288
|
+
lifecycleBadgeArchived: "{n} archived",
|
|
289
|
+
lifecycleBadgeDraft: "{n} draft"
|
|
280
290
|
};
|
|
281
291
|
|
|
282
292
|
// src/components/RecordsAdmin/types/presentation.ts
|
|
@@ -851,6 +861,24 @@ var useRecordList = (args) => {
|
|
|
851
861
|
}
|
|
852
862
|
return map;
|
|
853
863
|
}, [historyItems]);
|
|
864
|
+
const ruleLifecycleCounts = useMemo(() => {
|
|
865
|
+
const map = /* @__PURE__ */ new Map();
|
|
866
|
+
for (const r of items) {
|
|
867
|
+
const h = ruleHash(r.facetRule ?? null);
|
|
868
|
+
if (!h) continue;
|
|
869
|
+
let bucket = map.get(h);
|
|
870
|
+
if (!bucket) {
|
|
871
|
+
bucket = { active: 0, archived: 0, draft: 0, other: 0 };
|
|
872
|
+
map.set(h, bucket);
|
|
873
|
+
}
|
|
874
|
+
const ls = r.lifecycleStatus;
|
|
875
|
+
if (ls == null || ls === "" || activeStatuses.includes(ls)) bucket.active += 1;
|
|
876
|
+
else if (ls === "archived") bucket.archived += 1;
|
|
877
|
+
else if (ls === "draft") bucket.draft += 1;
|
|
878
|
+
else bucket.other += 1;
|
|
879
|
+
}
|
|
880
|
+
return map;
|
|
881
|
+
}, [items, activeStatuses]);
|
|
854
882
|
const refetch = useCallback(() => queryClient.refetchQueries({
|
|
855
883
|
queryKey: [...QK_BASE2, ctx.collectionId, ctx.appId, ctx.recordType]
|
|
856
884
|
}), [queryClient, ctx.collectionId, ctx.appId, ctx.recordType]);
|
|
@@ -861,6 +889,7 @@ var useRecordList = (args) => {
|
|
|
861
889
|
activeItems,
|
|
862
890
|
historyItems,
|
|
863
891
|
historyBySlot,
|
|
892
|
+
ruleLifecycleCounts,
|
|
864
893
|
total,
|
|
865
894
|
counts,
|
|
866
895
|
isLoading: query.isLoading,
|
|
@@ -2185,10 +2214,54 @@ function useShellClipboard(args) {
|
|
|
2185
2214
|
};
|
|
2186
2215
|
}
|
|
2187
2216
|
var useShellPreviewPane = (args) => {
|
|
2188
|
-
const {
|
|
2217
|
+
const {
|
|
2218
|
+
editingScope,
|
|
2219
|
+
activeScope,
|
|
2220
|
+
selectedProductId,
|
|
2221
|
+
productBrowseItems,
|
|
2222
|
+
pinPreviewMinWidth = 1400,
|
|
2223
|
+
preferenceStorageKey = "smartlinks-ui:recordsAdmin:sidePreviewOpen"
|
|
2224
|
+
} = args;
|
|
2189
2225
|
const [previewScope, setPreviewScope] = useState(null);
|
|
2190
2226
|
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
2191
|
-
const
|
|
2227
|
+
const readStoredPref = () => {
|
|
2228
|
+
if (typeof window === "undefined") return null;
|
|
2229
|
+
try {
|
|
2230
|
+
const raw = window.sessionStorage.getItem(preferenceStorageKey);
|
|
2231
|
+
if (raw === "1") return true;
|
|
2232
|
+
if (raw === "0") return false;
|
|
2233
|
+
} catch {
|
|
2234
|
+
}
|
|
2235
|
+
return null;
|
|
2236
|
+
};
|
|
2237
|
+
const initialIsWide = typeof window !== "undefined" ? window.innerWidth >= pinPreviewMinWidth : true;
|
|
2238
|
+
const [isWide, setIsWide] = useState(initialIsWide);
|
|
2239
|
+
const userPrefRef = useRef(readStoredPref());
|
|
2240
|
+
const [sidePreviewOpen, setSidePreviewOpenState] = useState(
|
|
2241
|
+
userPrefRef.current ?? initialIsWide
|
|
2242
|
+
);
|
|
2243
|
+
useEffect(() => {
|
|
2244
|
+
if (typeof window === "undefined") return;
|
|
2245
|
+
const mql = window.matchMedia(`(min-width: ${pinPreviewMinWidth}px)`);
|
|
2246
|
+
const onChange = () => {
|
|
2247
|
+
const wide = mql.matches;
|
|
2248
|
+
setIsWide(wide);
|
|
2249
|
+
if (userPrefRef.current === null) {
|
|
2250
|
+
setSidePreviewOpenState(wide);
|
|
2251
|
+
}
|
|
2252
|
+
};
|
|
2253
|
+
onChange();
|
|
2254
|
+
mql.addEventListener("change", onChange);
|
|
2255
|
+
return () => mql.removeEventListener("change", onChange);
|
|
2256
|
+
}, [pinPreviewMinWidth]);
|
|
2257
|
+
const setSidePreviewOpen = useCallback((next) => {
|
|
2258
|
+
userPrefRef.current = next;
|
|
2259
|
+
try {
|
|
2260
|
+
window.sessionStorage.setItem(preferenceStorageKey, next ? "1" : "0");
|
|
2261
|
+
} catch {
|
|
2262
|
+
}
|
|
2263
|
+
setSidePreviewOpenState(next);
|
|
2264
|
+
}, [preferenceStorageKey]);
|
|
2192
2265
|
useEffect(() => {
|
|
2193
2266
|
if (!editingScope) return;
|
|
2194
2267
|
setPreviewScope((cur) => cur === null ? editingScope : cur);
|
|
@@ -2222,6 +2295,7 @@ var useShellPreviewPane = (args) => {
|
|
|
2222
2295
|
setDrawerOpen,
|
|
2223
2296
|
sidePreviewOpen,
|
|
2224
2297
|
setSidePreviewOpen,
|
|
2298
|
+
isPreviewNarrow: !isWide,
|
|
2225
2299
|
editorHeaderLabel,
|
|
2226
2300
|
editorHeaderSubtitle,
|
|
2227
2301
|
editorHeaderMeta
|
|
@@ -6881,6 +6955,8 @@ function ItemListView({
|
|
|
6881
6955
|
hasNextPage,
|
|
6882
6956
|
isFetchingNextPage,
|
|
6883
6957
|
onLoadMore,
|
|
6958
|
+
groupByLifecycle = false,
|
|
6959
|
+
lifecycle,
|
|
6884
6960
|
i18n
|
|
6885
6961
|
}) {
|
|
6886
6962
|
const newLabel = i18n.newItem.includes("{noun}") ? i18n.newItem.replace("{noun}", itemNoun) : i18n.newItem;
|
|
@@ -6955,6 +7031,69 @@ function ItemListView({
|
|
|
6955
7031
|
}), [ctx]);
|
|
6956
7032
|
const confirmName = pendingRecord?.label ?? itemNoun;
|
|
6957
7033
|
const confirmBody = i18n.deleteConfirmBody.includes("{name}") ? i18n.deleteConfirmBody.replace("{name}", confirmName) : i18n.deleteConfirmBody;
|
|
7034
|
+
const activeValues = useMemo(
|
|
7035
|
+
() => getActiveStatusValues(lifecycle),
|
|
7036
|
+
[lifecycle]
|
|
7037
|
+
);
|
|
7038
|
+
const buckets = useMemo(() => {
|
|
7039
|
+
if (!groupByLifecycle) return null;
|
|
7040
|
+
const map = /* @__PURE__ */ new Map();
|
|
7041
|
+
for (const item of visibleItems) {
|
|
7042
|
+
const def = resolveLifecycleStatus(item, lifecycle);
|
|
7043
|
+
const existing = map.get(def.value);
|
|
7044
|
+
if (existing) existing.items.push(item);
|
|
7045
|
+
else map.set(def.value, { label: def.label, items: [item] });
|
|
7046
|
+
}
|
|
7047
|
+
return Array.from(map.entries()).map(([key, v]) => ({
|
|
7048
|
+
key,
|
|
7049
|
+
label: v.label,
|
|
7050
|
+
items: v.items,
|
|
7051
|
+
isActive: activeValues.includes(key)
|
|
7052
|
+
})).sort((a, b) => compareLifecycleBuckets(a.key, b.key)).filter((b) => b.items.length > 0);
|
|
7053
|
+
}, [groupByLifecycle, visibleItems, lifecycle, activeValues]);
|
|
7054
|
+
const [collapsedBuckets, setCollapsedBuckets] = useState(() => /* @__PURE__ */ new Set());
|
|
7055
|
+
const toggleBucket = (key) => {
|
|
7056
|
+
setCollapsedBuckets((prev) => {
|
|
7057
|
+
const next = new Set(prev);
|
|
7058
|
+
if (next.has(key)) next.delete(key);
|
|
7059
|
+
else next.add(key);
|
|
7060
|
+
return next;
|
|
7061
|
+
});
|
|
7062
|
+
};
|
|
7063
|
+
const renderBody = (rows) => {
|
|
7064
|
+
if (renderItemList) return renderItemList(rows, guardedCtx);
|
|
7065
|
+
if (view === "table") {
|
|
7066
|
+
return /* @__PURE__ */ jsx(
|
|
7067
|
+
DefaultItemTable,
|
|
7068
|
+
{
|
|
7069
|
+
items: rows,
|
|
7070
|
+
columns: itemColumns,
|
|
7071
|
+
selectedId: guardedCtx.selectedId,
|
|
7072
|
+
onOpen: guardedCtx.onOpen,
|
|
7073
|
+
onDelete: guardedCtx.onDelete,
|
|
7074
|
+
sort,
|
|
7075
|
+
onToggleSort,
|
|
7076
|
+
rowActions,
|
|
7077
|
+
rowClipboard,
|
|
7078
|
+
i18n
|
|
7079
|
+
}
|
|
7080
|
+
);
|
|
7081
|
+
}
|
|
7082
|
+
return /* @__PURE__ */ jsx(
|
|
7083
|
+
DefaultItemCards,
|
|
7084
|
+
{
|
|
7085
|
+
items: rows,
|
|
7086
|
+
variant: view,
|
|
7087
|
+
selectedId: guardedCtx.selectedId,
|
|
7088
|
+
ctx: guardedCtx,
|
|
7089
|
+
renderCard: renderItemCard,
|
|
7090
|
+
cardSize,
|
|
7091
|
+
rowActions,
|
|
7092
|
+
rowClipboard,
|
|
7093
|
+
i18n
|
|
7094
|
+
}
|
|
7095
|
+
);
|
|
7096
|
+
};
|
|
6958
7097
|
const toolbar = /* @__PURE__ */ jsxs("div", { className: "ra-item-toolbar", children: [
|
|
6959
7098
|
/* @__PURE__ */ jsxs("div", { className: "ra-item-toolbar-title", children: [
|
|
6960
7099
|
/* @__PURE__ */ jsx("h2", { className: "ra-display", style: { fontSize: "0.95rem", margin: 0 }, children: i18n.itemListTitle }),
|
|
@@ -7072,39 +7211,62 @@ function ItemListView({
|
|
|
7072
7211
|
body: `No ${itemNoun}s match "${search}".`
|
|
7073
7212
|
}
|
|
7074
7213
|
);
|
|
7075
|
-
} else if (
|
|
7076
|
-
body =
|
|
7077
|
-
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
|
|
7084
|
-
|
|
7085
|
-
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7214
|
+
} else if (buckets && buckets.length > 0) {
|
|
7215
|
+
body = /* @__PURE__ */ jsx("div", { className: "ra-item-buckets", children: buckets.map((bucket) => {
|
|
7216
|
+
const open = bucket.isActive || !collapsedBuckets.has(bucket.key);
|
|
7217
|
+
return /* @__PURE__ */ jsxs(
|
|
7218
|
+
"section",
|
|
7219
|
+
{
|
|
7220
|
+
className: "ra-item-bucket",
|
|
7221
|
+
"data-bucket": bucket.key,
|
|
7222
|
+
children: [
|
|
7223
|
+
/* @__PURE__ */ jsxs(
|
|
7224
|
+
"button",
|
|
7225
|
+
{
|
|
7226
|
+
type: "button",
|
|
7227
|
+
className: "ra-item-bucket-header",
|
|
7228
|
+
onClick: () => !bucket.isActive && toggleBucket(bucket.key),
|
|
7229
|
+
"aria-expanded": open,
|
|
7230
|
+
disabled: bucket.isActive,
|
|
7231
|
+
style: {
|
|
7232
|
+
display: "flex",
|
|
7233
|
+
alignItems: "center",
|
|
7234
|
+
gap: "6px",
|
|
7235
|
+
width: "100%",
|
|
7236
|
+
padding: "6px 12px",
|
|
7237
|
+
background: "transparent",
|
|
7238
|
+
border: 0,
|
|
7239
|
+
borderTop: "1px solid hsl(var(--ra-border))",
|
|
7240
|
+
font: "inherit",
|
|
7241
|
+
fontSize: "11px",
|
|
7242
|
+
fontWeight: 600,
|
|
7243
|
+
textTransform: "uppercase",
|
|
7244
|
+
letterSpacing: "0.04em",
|
|
7245
|
+
color: "hsl(var(--ra-muted-text))",
|
|
7246
|
+
cursor: bucket.isActive ? "default" : "pointer"
|
|
7247
|
+
},
|
|
7248
|
+
children: [
|
|
7249
|
+
!bucket.isActive ? open ? /* @__PURE__ */ jsx(ChevronDown, { className: "w-3 h-3", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3", "aria-hidden": "true" }) : null,
|
|
7250
|
+
/* @__PURE__ */ jsx("span", { children: bucket.label }),
|
|
7251
|
+
/* @__PURE__ */ jsx("span", { style: { marginLeft: "auto", fontWeight: 500 }, children: bucket.items.length })
|
|
7252
|
+
]
|
|
7253
|
+
}
|
|
7254
|
+
),
|
|
7255
|
+
open && /* @__PURE__ */ jsx(
|
|
7256
|
+
"div",
|
|
7257
|
+
{
|
|
7258
|
+
className: "ra-item-bucket-body",
|
|
7259
|
+
style: bucket.isActive ? void 0 : { opacity: 0.75 },
|
|
7260
|
+
children: renderBody(bucket.items)
|
|
7261
|
+
}
|
|
7262
|
+
)
|
|
7263
|
+
]
|
|
7264
|
+
},
|
|
7265
|
+
bucket.key
|
|
7266
|
+
);
|
|
7267
|
+
}) });
|
|
7093
7268
|
} else {
|
|
7094
|
-
body =
|
|
7095
|
-
DefaultItemCards,
|
|
7096
|
-
{
|
|
7097
|
-
items: visibleItems,
|
|
7098
|
-
variant: view,
|
|
7099
|
-
selectedId: guardedCtx.selectedId,
|
|
7100
|
-
ctx: guardedCtx,
|
|
7101
|
-
renderCard: renderItemCard,
|
|
7102
|
-
cardSize,
|
|
7103
|
-
rowActions,
|
|
7104
|
-
rowClipboard,
|
|
7105
|
-
i18n
|
|
7106
|
-
}
|
|
7107
|
-
);
|
|
7269
|
+
body = renderBody(visibleItems);
|
|
7108
7270
|
}
|
|
7109
7271
|
return /* @__PURE__ */ jsxs("div", { className: "ra-item-list", children: [
|
|
7110
7272
|
toolbar,
|
|
@@ -7247,10 +7409,42 @@ function SiblingRail({
|
|
|
7247
7409
|
isFetchingNextPage,
|
|
7248
7410
|
onLoadMore,
|
|
7249
7411
|
rowClipboard,
|
|
7250
|
-
rowActions
|
|
7412
|
+
rowActions,
|
|
7413
|
+
groupByLifecycle = false,
|
|
7414
|
+
lifecycle
|
|
7251
7415
|
}) {
|
|
7252
7416
|
const ruleLabelLookup = useRuleLabelLookup();
|
|
7253
7417
|
const newLabel = i18n.newItem.includes("{noun}") ? i18n.newItem.replace("{noun}", itemNoun ?? "item") : i18n.newItem;
|
|
7418
|
+
const activeValues = useMemo(
|
|
7419
|
+
() => getActiveStatusValues(lifecycle),
|
|
7420
|
+
[lifecycle]
|
|
7421
|
+
);
|
|
7422
|
+
const buckets = useMemo(() => {
|
|
7423
|
+
if (!groupByLifecycle) return null;
|
|
7424
|
+
const map = /* @__PURE__ */ new Map();
|
|
7425
|
+
for (const item of items) {
|
|
7426
|
+
const def = resolveLifecycleStatus(item, lifecycle);
|
|
7427
|
+
const key = def.value;
|
|
7428
|
+
const existing = map.get(key);
|
|
7429
|
+
if (existing) existing.items.push(item);
|
|
7430
|
+
else map.set(key, { label: def.label, items: [item] });
|
|
7431
|
+
}
|
|
7432
|
+
return Array.from(map.entries()).map(([key, v]) => ({
|
|
7433
|
+
key,
|
|
7434
|
+
label: v.label,
|
|
7435
|
+
items: v.items,
|
|
7436
|
+
isActive: activeValues.includes(key)
|
|
7437
|
+
})).sort((a, b) => compareLifecycleBuckets(a.key, b.key)).filter((b) => b.items.length > 0);
|
|
7438
|
+
}, [groupByLifecycle, items, lifecycle, activeValues]);
|
|
7439
|
+
const [collapsed, setCollapsed] = useState(() => /* @__PURE__ */ new Set());
|
|
7440
|
+
const toggleBucket = (key) => {
|
|
7441
|
+
setCollapsed((prev) => {
|
|
7442
|
+
const next = new Set(prev);
|
|
7443
|
+
if (next.has(key)) next.delete(key);
|
|
7444
|
+
else next.add(key);
|
|
7445
|
+
return next;
|
|
7446
|
+
});
|
|
7447
|
+
};
|
|
7254
7448
|
return /* @__PURE__ */ jsxs("div", { className: "ra-sibling-rail", children: [
|
|
7255
7449
|
(onBack || contextKind) && /* @__PURE__ */ jsxs("div", { className: "ra-sibling-context", children: [
|
|
7256
7450
|
onBack && /* @__PURE__ */ jsx(
|
|
@@ -7276,79 +7470,125 @@ function SiblingRail({
|
|
|
7276
7470
|
isLoading && /* @__PURE__ */ jsx(LoadingState, {}),
|
|
7277
7471
|
!isLoading && error && /* @__PURE__ */ jsx(ErrorState, { error }),
|
|
7278
7472
|
!isLoading && !error && items.length === 0 && /* @__PURE__ */ jsx(EmptyState, { title: i18n.noItemsTitle, body: i18n.noItemsBody }),
|
|
7279
|
-
!isLoading && !error && items.length > 0 &&
|
|
7280
|
-
const
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
/* @__PURE__ */ jsxs(
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
type: "button",
|
|
7294
|
-
onClick: () => onSelect(id),
|
|
7295
|
-
className: "ra-row",
|
|
7296
|
-
"data-selected": selected,
|
|
7297
|
-
children: [
|
|
7298
|
-
/* @__PURE__ */ jsxs("div", { className: "ra-row-body", children: [
|
|
7299
|
-
/* @__PURE__ */ jsx("div", { className: "ra-row-title", children: item.label }),
|
|
7300
|
-
item.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-row-sub", children: item.subtitle })
|
|
7301
|
-
] }),
|
|
7302
|
-
isTargeted && /* @__PURE__ */ jsx(
|
|
7303
|
-
"span",
|
|
7304
|
-
{
|
|
7305
|
-
className: "ra-row-rule-pip",
|
|
7306
|
-
title: ruleSummary ? `Targeted: ${ruleSummary}` : "This item has targeting rules",
|
|
7307
|
-
"aria-label": ruleSummary ? `Targeted: ${ruleSummary}` : "This item has targeting rules",
|
|
7308
|
-
children: /* @__PURE__ */ jsx(Target, { className: "w-3 h-3", "aria-hidden": "true" })
|
|
7309
|
-
}
|
|
7310
|
-
),
|
|
7311
|
-
hasError ? /* @__PURE__ */ jsx(
|
|
7312
|
-
"span",
|
|
7313
|
-
{
|
|
7314
|
-
className: "ra-error-pip",
|
|
7315
|
-
title: "Save failed",
|
|
7316
|
-
"aria-label": "Save failed"
|
|
7317
|
-
}
|
|
7318
|
-
) : isDirty ? /* @__PURE__ */ jsx(
|
|
7319
|
-
"span",
|
|
7320
|
-
{
|
|
7321
|
-
className: "ra-dirty-pip",
|
|
7322
|
-
title: "Unsaved changes",
|
|
7323
|
-
"aria-label": "Unsaved changes"
|
|
7324
|
-
}
|
|
7325
|
-
) : null
|
|
7326
|
-
]
|
|
7327
|
-
}
|
|
7328
|
-
),
|
|
7329
|
-
(() => {
|
|
7330
|
-
const cb = rowClipboard ? rowClipboard(item) : null;
|
|
7331
|
-
const extra = rowActions ? rowActions(item) ?? void 0 : void 0;
|
|
7332
|
-
if (!cb?.onCopy && !cb?.onDuplicate && !cb?.onCopyAndNewRule && !(extra && extra.length)) {
|
|
7333
|
-
return null;
|
|
7334
|
-
}
|
|
7335
|
-
return /* @__PURE__ */ jsx(
|
|
7336
|
-
RowContextMenu,
|
|
7473
|
+
!isLoading && !error && items.length > 0 && (() => {
|
|
7474
|
+
const renderRow = (item, idx, dimmed) => {
|
|
7475
|
+
const id = item.itemId ?? "";
|
|
7476
|
+
const key = item.id ?? (id || anchorKey(item.scope) || `pos:${idx}`);
|
|
7477
|
+
const akey = anchorKey(item.scope);
|
|
7478
|
+
const selected = selectedItemId === id;
|
|
7479
|
+
const isDirty = !!(id && dirtyKeys?.has(id) || akey && dirtyKeys?.has(akey));
|
|
7480
|
+
const hasError = !!(id && errorKeys?.has(id) || akey && errorKeys?.has(akey));
|
|
7481
|
+
const ruleClauses = item.facetRule ? summarizeFacetRule(item.facetRule, ruleLabelLookup) : [];
|
|
7482
|
+
const isTargeted = ruleClauses.length > 0;
|
|
7483
|
+
const ruleSummary = isTargeted ? ruleClauses.map((c) => c.label).join(" \xB7 ") : null;
|
|
7484
|
+
return /* @__PURE__ */ jsx("li", { "data-dimmed": dimmed || void 0, children: /* @__PURE__ */ jsxs("div", { className: "ra-row-shell", "data-selected": selected, children: [
|
|
7485
|
+
/* @__PURE__ */ jsxs(
|
|
7486
|
+
"button",
|
|
7337
7487
|
{
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7488
|
+
type: "button",
|
|
7489
|
+
onClick: () => onSelect(id),
|
|
7490
|
+
className: "ra-row",
|
|
7491
|
+
"data-selected": selected,
|
|
7492
|
+
style: dimmed ? { opacity: 0.7 } : void 0,
|
|
7493
|
+
children: [
|
|
7494
|
+
/* @__PURE__ */ jsxs("div", { className: "ra-row-body", children: [
|
|
7495
|
+
/* @__PURE__ */ jsx("div", { className: "ra-row-title", children: item.label }),
|
|
7496
|
+
item.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-row-sub", children: item.subtitle })
|
|
7497
|
+
] }),
|
|
7498
|
+
isTargeted && /* @__PURE__ */ jsx(
|
|
7499
|
+
"span",
|
|
7500
|
+
{
|
|
7501
|
+
className: "ra-row-rule-pip",
|
|
7502
|
+
title: ruleSummary ? `Targeted: ${ruleSummary}` : "This item has targeting rules",
|
|
7503
|
+
"aria-label": ruleSummary ? `Targeted: ${ruleSummary}` : "This item has targeting rules",
|
|
7504
|
+
children: /* @__PURE__ */ jsx(Target, { className: "w-3 h-3", "aria-hidden": "true" })
|
|
7505
|
+
}
|
|
7506
|
+
),
|
|
7507
|
+
hasError ? /* @__PURE__ */ jsx(
|
|
7508
|
+
"span",
|
|
7509
|
+
{
|
|
7510
|
+
className: "ra-error-pip",
|
|
7511
|
+
title: "Save failed",
|
|
7512
|
+
"aria-label": "Save failed"
|
|
7513
|
+
}
|
|
7514
|
+
) : isDirty ? /* @__PURE__ */ jsx(
|
|
7515
|
+
"span",
|
|
7516
|
+
{
|
|
7517
|
+
className: "ra-dirty-pip",
|
|
7518
|
+
title: "Unsaved changes",
|
|
7519
|
+
"aria-label": "Unsaved changes"
|
|
7520
|
+
}
|
|
7521
|
+
) : null
|
|
7522
|
+
]
|
|
7523
|
+
}
|
|
7524
|
+
),
|
|
7525
|
+
(() => {
|
|
7526
|
+
const cb = rowClipboard ? rowClipboard(item) : null;
|
|
7527
|
+
const extra = rowActions ? rowActions(item) ?? void 0 : void 0;
|
|
7528
|
+
if (!cb?.onCopy && !cb?.onDuplicate && !cb?.onCopyAndNewRule && !(extra && extra.length)) {
|
|
7529
|
+
return null;
|
|
7530
|
+
}
|
|
7531
|
+
return /* @__PURE__ */ jsx(
|
|
7532
|
+
RowContextMenu,
|
|
7533
|
+
{
|
|
7534
|
+
onCopy: cb?.onCopy,
|
|
7535
|
+
onDuplicate: cb?.onDuplicate,
|
|
7536
|
+
onCopyAndNewRule: cb?.onCopyAndNewRule,
|
|
7537
|
+
actions: extra,
|
|
7538
|
+
i18n: {
|
|
7539
|
+
copy: i18n.copy,
|
|
7540
|
+
duplicateAction: i18n.duplicateAction,
|
|
7541
|
+
copyAndNewRuleAction: i18n.copyAndNewRuleAction
|
|
7542
|
+
}
|
|
7346
7543
|
}
|
|
7544
|
+
);
|
|
7545
|
+
})()
|
|
7546
|
+
] }) }, key);
|
|
7547
|
+
};
|
|
7548
|
+
if (!buckets) {
|
|
7549
|
+
return /* @__PURE__ */ jsx("ul", { className: "ra-sibling-list", children: items.map((item, idx) => renderRow(item, idx, false)) });
|
|
7550
|
+
}
|
|
7551
|
+
return /* @__PURE__ */ jsx("div", { className: "ra-sibling-buckets", children: buckets.map((bucket) => {
|
|
7552
|
+
const open = bucket.isActive || !collapsed.has(bucket.key);
|
|
7553
|
+
return /* @__PURE__ */ jsxs("section", { className: "ra-sibling-bucket", "data-bucket": bucket.key, children: [
|
|
7554
|
+
/* @__PURE__ */ jsxs(
|
|
7555
|
+
"button",
|
|
7556
|
+
{
|
|
7557
|
+
type: "button",
|
|
7558
|
+
className: "ra-sibling-bucket-header",
|
|
7559
|
+
onClick: () => !bucket.isActive && toggleBucket(bucket.key),
|
|
7560
|
+
"aria-expanded": open,
|
|
7561
|
+
disabled: bucket.isActive,
|
|
7562
|
+
style: {
|
|
7563
|
+
display: "flex",
|
|
7564
|
+
alignItems: "center",
|
|
7565
|
+
gap: "6px",
|
|
7566
|
+
width: "100%",
|
|
7567
|
+
padding: "6px 10px",
|
|
7568
|
+
background: "transparent",
|
|
7569
|
+
border: 0,
|
|
7570
|
+
borderTop: "1px solid hsl(var(--ra-border))",
|
|
7571
|
+
font: "inherit",
|
|
7572
|
+
fontSize: "11px",
|
|
7573
|
+
fontWeight: 600,
|
|
7574
|
+
textTransform: "uppercase",
|
|
7575
|
+
letterSpacing: "0.04em",
|
|
7576
|
+
color: "hsl(var(--ra-muted-text))",
|
|
7577
|
+
cursor: bucket.isActive ? "default" : "pointer"
|
|
7578
|
+
},
|
|
7579
|
+
children: [
|
|
7580
|
+
!bucket.isActive ? open ? /* @__PURE__ */ jsx(ChevronDown, { className: "w-3 h-3", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3", "aria-hidden": "true" }) : null,
|
|
7581
|
+
/* @__PURE__ */ jsx("span", { children: bucket.label }),
|
|
7582
|
+
/* @__PURE__ */ jsx("span", { style: { marginLeft: "auto", fontWeight: 500 }, children: bucket.items.length })
|
|
7583
|
+
]
|
|
7347
7584
|
}
|
|
7348
|
-
)
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
|
|
7585
|
+
),
|
|
7586
|
+
open && /* @__PURE__ */ jsx("ul", { className: "ra-sibling-list", children: bucket.items.map(
|
|
7587
|
+
(item, idx) => renderRow(item, idx, !bucket.isActive)
|
|
7588
|
+
) })
|
|
7589
|
+
] }, bucket.key);
|
|
7590
|
+
}) });
|
|
7591
|
+
})()
|
|
7352
7592
|
] }),
|
|
7353
7593
|
onLoadMore && /* @__PURE__ */ jsx(
|
|
7354
7594
|
LoadMoreFooter,
|
|
@@ -8413,14 +8653,21 @@ var SaveAllProgress = ({
|
|
|
8413
8653
|
}
|
|
8414
8654
|
);
|
|
8415
8655
|
};
|
|
8416
|
-
function PreviewReopenPill({
|
|
8656
|
+
function PreviewReopenPill({
|
|
8657
|
+
anchorRef,
|
|
8658
|
+
onClick,
|
|
8659
|
+
ariaLabel,
|
|
8660
|
+
title,
|
|
8661
|
+
children,
|
|
8662
|
+
side = "right"
|
|
8663
|
+
}) {
|
|
8417
8664
|
const [pos, setPos] = useState(null);
|
|
8418
8665
|
const rafRef = useRef(null);
|
|
8419
8666
|
useLayoutEffect(() => {
|
|
8420
8667
|
const el = anchorRef.current;
|
|
8421
8668
|
if (typeof window === "undefined") return;
|
|
8422
8669
|
if (!el) {
|
|
8423
|
-
setPos({ top: window.innerHeight / 2, right: 8 });
|
|
8670
|
+
setPos({ top: window.innerHeight / 2, right: 8, left: 8 });
|
|
8424
8671
|
return;
|
|
8425
8672
|
}
|
|
8426
8673
|
const measure = () => {
|
|
@@ -8428,12 +8675,13 @@ function PreviewReopenPill({ anchorRef, onClick, ariaLabel, title, children }) {
|
|
|
8428
8675
|
rafRef.current = requestAnimationFrame(() => {
|
|
8429
8676
|
const rect = el.getBoundingClientRect();
|
|
8430
8677
|
if (rect.width === 0 && rect.height === 0) {
|
|
8431
|
-
setPos({ top: window.innerHeight / 2, right: 8 });
|
|
8678
|
+
setPos({ top: window.innerHeight / 2, right: 8, left: 8 });
|
|
8432
8679
|
return;
|
|
8433
8680
|
}
|
|
8434
8681
|
setPos({
|
|
8435
8682
|
top: rect.top + rect.height / 2,
|
|
8436
|
-
right: Math.max(0, window.innerWidth - rect.right)
|
|
8683
|
+
right: Math.max(0, window.innerWidth - rect.right),
|
|
8684
|
+
left: Math.max(0, rect.left)
|
|
8437
8685
|
});
|
|
8438
8686
|
});
|
|
8439
8687
|
};
|
|
@@ -8453,7 +8701,8 @@ function PreviewReopenPill({ anchorRef, onClick, ariaLabel, title, children }) {
|
|
|
8453
8701
|
if (typeof document === "undefined") return null;
|
|
8454
8702
|
const effectivePos = pos ?? {
|
|
8455
8703
|
top: typeof window !== "undefined" ? window.innerHeight / 2 : 200,
|
|
8456
|
-
right: 8
|
|
8704
|
+
right: 8,
|
|
8705
|
+
left: 8
|
|
8457
8706
|
};
|
|
8458
8707
|
return createPortal(
|
|
8459
8708
|
/* @__PURE__ */ jsx(
|
|
@@ -8467,10 +8716,10 @@ function PreviewReopenPill({ anchorRef, onClick, ariaLabel, title, children }) {
|
|
|
8467
8716
|
style: {
|
|
8468
8717
|
position: "fixed",
|
|
8469
8718
|
top: effectivePos.top,
|
|
8470
|
-
right: effectivePos.right,
|
|
8719
|
+
...side === "right" ? { right: effectivePos.right } : { left: effectivePos.left },
|
|
8471
8720
|
// Pull half the pill width out into the gutter so it visually
|
|
8472
8721
|
// anchors *to* the editor edge rather than sitting inside it.
|
|
8473
|
-
transform: "translate(50%, -50%)"
|
|
8722
|
+
transform: side === "right" ? "translate(50%, -50%)" : "translate(-50%, -50%)"
|
|
8474
8723
|
},
|
|
8475
8724
|
children
|
|
8476
8725
|
}
|
|
@@ -8892,6 +9141,7 @@ function RecordsAdminShellInner(props) {
|
|
|
8892
9141
|
onTelemetry?.({ type: "presentation.change", recordType, from: presentation, to: next });
|
|
8893
9142
|
setPresentation(next);
|
|
8894
9143
|
}, [onTelemetry, recordType, presentation, setPresentation]);
|
|
9144
|
+
const [ruleSort, setRuleSort] = useState("recent");
|
|
8895
9145
|
const [itemView, setItemView] = useItemViewPref({
|
|
8896
9146
|
appId,
|
|
8897
9147
|
recordType,
|
|
@@ -9502,6 +9752,25 @@ function RecordsAdminShellInner(props) {
|
|
|
9502
9752
|
const ruleCatalogueRef = useRef([]);
|
|
9503
9753
|
const onCreateRuleFromClipboardRef = useRef(null);
|
|
9504
9754
|
const previewReopenAnchorRef = useRef(null);
|
|
9755
|
+
const railReopenAnchorRef = useRef(null);
|
|
9756
|
+
const RAIL_OPEN_STORAGE_KEY = "smartlinks-ui:recordsAdmin:railOpen";
|
|
9757
|
+
const [railOpen, setRailOpenState] = useState(() => {
|
|
9758
|
+
if (typeof window === "undefined") return true;
|
|
9759
|
+
try {
|
|
9760
|
+
const raw = window.sessionStorage.getItem(RAIL_OPEN_STORAGE_KEY);
|
|
9761
|
+
if (raw === "0") return false;
|
|
9762
|
+
if (raw === "1") return true;
|
|
9763
|
+
} catch {
|
|
9764
|
+
}
|
|
9765
|
+
return true;
|
|
9766
|
+
});
|
|
9767
|
+
const setRailOpen = useCallback((next) => {
|
|
9768
|
+
try {
|
|
9769
|
+
window.sessionStorage.setItem(RAIL_OPEN_STORAGE_KEY, next ? "1" : "0");
|
|
9770
|
+
} catch {
|
|
9771
|
+
}
|
|
9772
|
+
setRailOpenState(next);
|
|
9773
|
+
}, []);
|
|
9505
9774
|
const { runWithGuard } = useDirtyNavigation({
|
|
9506
9775
|
strategy: dirtyStrategy,
|
|
9507
9776
|
isDirty: editorCtx.isDirty,
|
|
@@ -9532,6 +9801,7 @@ function RecordsAdminShellInner(props) {
|
|
|
9532
9801
|
setDrawerOpen,
|
|
9533
9802
|
sidePreviewOpen,
|
|
9534
9803
|
setSidePreviewOpen,
|
|
9804
|
+
isPreviewNarrow,
|
|
9535
9805
|
editorHeaderLabel: editorHeaderLabelRaw,
|
|
9536
9806
|
editorHeaderSubtitle,
|
|
9537
9807
|
editorHeaderMeta
|
|
@@ -9853,6 +10123,23 @@ function RecordsAdminShellInner(props) {
|
|
|
9853
10123
|
] })
|
|
9854
10124
|
);
|
|
9855
10125
|
}
|
|
10126
|
+
if (isPreviewNarrow) {
|
|
10127
|
+
return withNav(
|
|
10128
|
+
/* @__PURE__ */ jsxs("div", { className: "relative h-full", ref: previewAnchorRef, children: [
|
|
10129
|
+
baseEditor(),
|
|
10130
|
+
/* @__PURE__ */ jsx(
|
|
10131
|
+
DrawerPreview,
|
|
10132
|
+
{
|
|
10133
|
+
open: true,
|
|
10134
|
+
onClose: () => setSidePreviewOpen(false),
|
|
10135
|
+
label: i18n.preview,
|
|
10136
|
+
scopePicker,
|
|
10137
|
+
children: previewBody
|
|
10138
|
+
}
|
|
10139
|
+
)
|
|
10140
|
+
] })
|
|
10141
|
+
);
|
|
10142
|
+
}
|
|
9856
10143
|
return withNav(
|
|
9857
10144
|
/* @__PURE__ */ jsxs("div", { className: "grid h-full", style: { gridTemplateColumns: "minmax(0, 1fr) minmax(280px, 420px)" }, children: [
|
|
9858
10145
|
/* @__PURE__ */ jsx("div", { className: "overflow-hidden", children: baseEditor() }),
|
|
@@ -10070,6 +10357,7 @@ function RecordsAdminShellInner(props) {
|
|
|
10070
10357
|
if (cardinality === "collection") {
|
|
10071
10358
|
setRuleWizardStep(2);
|
|
10072
10359
|
if (ruleWizardSeedMode) {
|
|
10360
|
+
skipNextItemResetRef.current = true;
|
|
10073
10361
|
const id = coerceDraftItemId2(generateItemId);
|
|
10074
10362
|
setSelectedItemId(id);
|
|
10075
10363
|
}
|
|
@@ -10080,7 +10368,7 @@ function RecordsAdminShellInner(props) {
|
|
|
10080
10368
|
setSelectedRecordId(DRAFT_ID3);
|
|
10081
10369
|
}
|
|
10082
10370
|
}
|
|
10083
|
-
}, [cardinality, ruleWizardSeedMode, mintRuleWizardDraftKey, generateItemId]);
|
|
10371
|
+
}, [cardinality, ruleWizardSeedMode, mintRuleWizardDraftKey, generateItemId, skipNextItemResetRef]);
|
|
10084
10372
|
const startRuleWizardDraft = useCallback((seed) => {
|
|
10085
10373
|
setRuleWizardSeedMode(seed);
|
|
10086
10374
|
setRuleWizardDraftKey(mintRuleWizardDraftKey());
|
|
@@ -10134,17 +10422,51 @@ function RecordsAdminShellInner(props) {
|
|
|
10134
10422
|
buckets.set(hash, { rep: item, count: 1 });
|
|
10135
10423
|
}
|
|
10136
10424
|
}
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
|
|
10142
|
-
|
|
10143
|
-
|
|
10144
|
-
|
|
10145
|
-
|
|
10146
|
-
|
|
10147
|
-
|
|
10425
|
+
const counts = recordList.ruleLifecycleCounts;
|
|
10426
|
+
return Array.from(buckets.entries()).map(([hash, { rep, count }]) => {
|
|
10427
|
+
const lc = counts.get(hash) ?? { active: 0, archived: 0, draft: 0, other: 0 };
|
|
10428
|
+
const lifecycleBadges = [];
|
|
10429
|
+
if (lc.active > 0) lifecycleBadges.push({
|
|
10430
|
+
label: i18n.lifecycleBadgeActive.replace("{n}", String(lc.active)),
|
|
10431
|
+
tone: "success"
|
|
10432
|
+
});
|
|
10433
|
+
if (lc.draft > 0) lifecycleBadges.push({
|
|
10434
|
+
label: i18n.lifecycleBadgeDraft.replace("{n}", String(lc.draft)),
|
|
10435
|
+
tone: "warning"
|
|
10436
|
+
});
|
|
10437
|
+
if (lc.archived > 0) lifecycleBadges.push({
|
|
10438
|
+
label: i18n.lifecycleBadgeArchived.replace("{n}", String(lc.archived)),
|
|
10439
|
+
tone: "neutral"
|
|
10440
|
+
});
|
|
10441
|
+
return {
|
|
10442
|
+
...rep,
|
|
10443
|
+
// Title carries the count + identity; the rule chips below render
|
|
10444
|
+
// the friendly facet/value labels (via the lookup) so we don't
|
|
10445
|
+
// repeat the same information in two places.
|
|
10446
|
+
label: `${count} ${itemNoun}${count === 1 ? "" : "s"}`,
|
|
10447
|
+
subtitle: void 0,
|
|
10448
|
+
badges: [...rep.badges ?? [], ...lifecycleBadges],
|
|
10449
|
+
// Stash counts on the row for the sort comparator below.
|
|
10450
|
+
__lifecycleCounts: lc
|
|
10451
|
+
};
|
|
10452
|
+
});
|
|
10453
|
+
}, [isRuleTab, isCollection, filteredRuleItems, itemNoun, recordList.ruleLifecycleCounts, i18n]);
|
|
10454
|
+
const sortedCollectionRuleRailItems = useMemo(() => {
|
|
10455
|
+
if (!isRuleTab || !isCollection || ruleSort === "recent") return collectionRuleRailItems;
|
|
10456
|
+
const arr = [...collectionRuleRailItems];
|
|
10457
|
+
const counts = (r) => r.__lifecycleCounts ?? { active: 0, archived: 0 };
|
|
10458
|
+
if (ruleSort === "name") arr.sort((a, b) => a.label.localeCompare(b.label));
|
|
10459
|
+
else if (ruleSort === "activeCount") arr.sort((a, b) => counts(b).active - counts(a).active);
|
|
10460
|
+
else if (ruleSort === "hasArchived") {
|
|
10461
|
+
arr.sort((a, b) => {
|
|
10462
|
+
const ah = counts(a).archived > 0 ? 1 : 0;
|
|
10463
|
+
const bh = counts(b).archived > 0 ? 1 : 0;
|
|
10464
|
+
if (ah !== bh) return bh - ah;
|
|
10465
|
+
return counts(b).archived - counts(a).archived;
|
|
10466
|
+
});
|
|
10467
|
+
}
|
|
10468
|
+
return arr;
|
|
10469
|
+
}, [collectionRuleRailItems, isRuleTab, isCollection, ruleSort]);
|
|
10148
10470
|
const activeRuleSummary = useMemo(() => {
|
|
10149
10471
|
if (!isRuleTab || !isCollection) return null;
|
|
10150
10472
|
if (!selectedRecordId || isDraftId3(selectedRecordId)) return null;
|
|
@@ -10283,9 +10605,9 @@ function RecordsAdminShellInner(props) {
|
|
|
10283
10605
|
});
|
|
10284
10606
|
}, [isLifecycleRail, selectedLifecycleKey, lcGroupBy, collectionItems.items]);
|
|
10285
10607
|
const leftItems = isProductTab ? productListItems : isRuleTab ? applyFacetBrowseFilter(
|
|
10286
|
-
isCollection ?
|
|
10608
|
+
isCollection ? sortedCollectionRuleRailItems : filteredRuleItems
|
|
10287
10609
|
) : isLifecycleRail ? lifecycleRows : (isGlobalTab || isAllTab) && isCollection ? [collectionGlobalAllRow] : isRecordsTab ? applyFacetBrowseFilter(recordList.items) : [];
|
|
10288
|
-
const railShowsHistoryDisclosure = isRecordsTab && !isLifecycleRail && !
|
|
10610
|
+
const railShowsHistoryDisclosure = isRecordsTab && !isLifecycleRail && !isCollection;
|
|
10289
10611
|
const filteredLeftItems = useMemo(() => {
|
|
10290
10612
|
if (!railShowsHistoryDisclosure) return leftItems;
|
|
10291
10613
|
return leftItems.filter((r) => {
|
|
@@ -10529,295 +10851,351 @@ function RecordsAdminShellInner(props) {
|
|
|
10529
10851
|
{
|
|
10530
10852
|
className: "flex-1 grid border-t overflow-hidden",
|
|
10531
10853
|
style: {
|
|
10532
|
-
gridTemplateColumns: railHidden ? "1fr" : "minmax(260px, 320px) 1fr",
|
|
10854
|
+
gridTemplateColumns: railHidden || !railOpen ? "1fr" : "minmax(260px, 320px) 1fr",
|
|
10533
10855
|
borderColor: "hsl(var(--ra-border))"
|
|
10534
10856
|
},
|
|
10535
10857
|
children: [
|
|
10536
|
-
!railHidden && /* @__PURE__ */
|
|
10537
|
-
|
|
10538
|
-
|
|
10539
|
-
items: scopedCollectionItemsList,
|
|
10540
|
-
selectedItemId,
|
|
10541
|
-
isLoading: collectionItems.isLoading,
|
|
10542
|
-
error: collectionItems.error,
|
|
10543
|
-
onBack: onItemBack,
|
|
10544
|
-
onSelect: onItemOpen,
|
|
10545
|
-
onCreate: onItemCreate,
|
|
10546
|
-
itemNoun: itemNounLabel,
|
|
10547
|
-
dirtyKeys,
|
|
10548
|
-
errorKeys,
|
|
10549
|
-
hasNextPage: !!collectionItems.hasNextPage,
|
|
10550
|
-
isFetchingNextPage: !!collectionItems.isFetchingNextPage,
|
|
10551
|
-
onLoadMore: () => {
|
|
10552
|
-
void collectionItems.fetchNextPage();
|
|
10553
|
-
},
|
|
10554
|
-
rowClipboard,
|
|
10555
|
-
rowActions: wrappedRecordActions,
|
|
10556
|
-
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,
|
|
10557
|
-
contextSummary: isLifecycleRailEarly && lifecycleBucketLabel ? `${scopedCollectionItemsList.length} ${itemNounLabel}${scopedCollectionItemsList.length === 1 ? "" : "s"}` : activeScope === "rule" ? activeRuleSummary : activeScope === "product" ? editorHeaderLabel ?? null : null,
|
|
10558
|
-
i18n
|
|
10559
|
-
}
|
|
10560
|
-
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10561
|
-
/* @__PURE__ */ jsx("div", { className: "px-1.5 py-2", children: /* @__PURE__ */ jsx(
|
|
10562
|
-
ScopeTabs,
|
|
10858
|
+
!railHidden && railOpen && /* @__PURE__ */ jsxs("aside", { className: "border-r overflow-hidden flex flex-col relative", style: { borderColor: "hsl(var(--ra-border))", background: "hsl(var(--ra-surface))" }, children: [
|
|
10859
|
+
/* @__PURE__ */ jsx(
|
|
10860
|
+
"button",
|
|
10563
10861
|
{
|
|
10564
|
-
|
|
10565
|
-
|
|
10566
|
-
|
|
10567
|
-
|
|
10568
|
-
|
|
10569
|
-
|
|
10570
|
-
|
|
10571
|
-
|
|
10572
|
-
|
|
10573
|
-
|
|
10574
|
-
|
|
10575
|
-
|
|
10576
|
-
|
|
10577
|
-
|
|
10578
|
-
|
|
10579
|
-
|
|
10580
|
-
|
|
10581
|
-
|
|
10582
|
-
|
|
10583
|
-
|
|
10584
|
-
|
|
10585
|
-
|
|
10586
|
-
|
|
10587
|
-
|
|
10588
|
-
|
|
10589
|
-
|
|
10590
|
-
// is fine — the badges just appear once data lands.
|
|
10591
|
-
collection: scopeCounts.counts.collection,
|
|
10592
|
-
rule: scopeCounts.counts.rule,
|
|
10593
|
-
variant: scopeCounts.counts.variant,
|
|
10594
|
-
batch: scopeCounts.counts.batch,
|
|
10595
|
-
facet: scopeCounts.counts.facet,
|
|
10596
|
-
all: scopeCounts.counts.all
|
|
10862
|
+
type: "button",
|
|
10863
|
+
onClick: () => setRailOpen(false),
|
|
10864
|
+
"aria-label": i18n.closeList,
|
|
10865
|
+
title: i18n.closeList,
|
|
10866
|
+
className: "absolute top-1.5 right-1.5 z-10 p-1 rounded hover:bg-[hsl(var(--ra-muted))]",
|
|
10867
|
+
style: { color: "hsl(var(--ra-muted-text))" },
|
|
10868
|
+
children: /* @__PURE__ */ jsx(PanelLeftClose, { className: "w-3.5 h-3.5" })
|
|
10869
|
+
}
|
|
10870
|
+
),
|
|
10871
|
+
isCollection && selectedItemId && collectionRailMode === "siblings" && ruleWizardStep === null ? /* @__PURE__ */ jsx(
|
|
10872
|
+
SiblingRail,
|
|
10873
|
+
{
|
|
10874
|
+
items: scopedCollectionItemsList,
|
|
10875
|
+
selectedItemId,
|
|
10876
|
+
isLoading: collectionItems.isLoading,
|
|
10877
|
+
error: collectionItems.error,
|
|
10878
|
+
onBack: onItemBack,
|
|
10879
|
+
onSelect: onItemOpen,
|
|
10880
|
+
onCreate: onItemCreate,
|
|
10881
|
+
itemNoun: itemNounLabel,
|
|
10882
|
+
dirtyKeys,
|
|
10883
|
+
errorKeys,
|
|
10884
|
+
hasNextPage: !!collectionItems.hasNextPage,
|
|
10885
|
+
isFetchingNextPage: !!collectionItems.isFetchingNextPage,
|
|
10886
|
+
onLoadMore: () => {
|
|
10887
|
+
void collectionItems.fetchNextPage();
|
|
10597
10888
|
},
|
|
10598
|
-
|
|
10599
|
-
|
|
10889
|
+
rowClipboard,
|
|
10890
|
+
rowActions: wrappedRecordActions,
|
|
10891
|
+
groupByLifecycle: true,
|
|
10892
|
+
lifecycle: lifecycleConfig,
|
|
10893
|
+
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,
|
|
10894
|
+
contextSummary: isLifecycleRailEarly && lifecycleBucketLabel ? `${scopedCollectionItemsList.length} ${itemNounLabel}${scopedCollectionItemsList.length === 1 ? "" : "s"}` : activeScope === "rule" ? activeRuleSummary : activeScope === "product" ? editorHeaderLabel ?? null : null,
|
|
10895
|
+
i18n
|
|
10600
10896
|
}
|
|
10601
|
-
)
|
|
10602
|
-
|
|
10603
|
-
|
|
10604
|
-
"button",
|
|
10897
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10898
|
+
/* @__PURE__ */ jsx("div", { className: "px-1.5 py-2", children: /* @__PURE__ */ jsx(
|
|
10899
|
+
ScopeTabs,
|
|
10605
10900
|
{
|
|
10606
|
-
|
|
10607
|
-
|
|
10608
|
-
|
|
10609
|
-
|
|
10610
|
-
|
|
10611
|
-
|
|
10612
|
-
|
|
10613
|
-
|
|
10614
|
-
|
|
10901
|
+
scopes: effectiveTopLevelScopes,
|
|
10902
|
+
active: activeScope,
|
|
10903
|
+
onChange: (s) => {
|
|
10904
|
+
void runWithGuard(() => {
|
|
10905
|
+
onTelemetry?.({ type: "scope.change", recordType, from: activeScope, to: s });
|
|
10906
|
+
if (ruleWizardStep !== null) {
|
|
10907
|
+
setRuleWizardStep(null);
|
|
10908
|
+
setRuleWizardRule(null);
|
|
10909
|
+
setDraftKind(null);
|
|
10910
|
+
}
|
|
10911
|
+
setActiveScope(s);
|
|
10912
|
+
});
|
|
10913
|
+
},
|
|
10914
|
+
loading: probe.isLoading,
|
|
10915
|
+
counts: {
|
|
10916
|
+
// Products badge counts DISTINCT products that have at
|
|
10917
|
+
// least one custom record — same semantics as Global /
|
|
10918
|
+
// Rules. Catalogue size (which can be 1k–10k+) was
|
|
10919
|
+
// misleading: "Products: 247" implied 247 customised
|
|
10920
|
+
// products when in fact zero might be configured. Falls
|
|
10921
|
+
// back to a lower bound when scope-counts truncated at
|
|
10922
|
+
// the hard cap.
|
|
10923
|
+
product: scopeCounts.productIds.size,
|
|
10924
|
+
// The remaining tabs show actual record counts so hidden
|
|
10925
|
+
// state (e.g. a rule-scoped competition) is visible from
|
|
10926
|
+
// any tab. `useScopeCounts` returns 0 while loading, which
|
|
10927
|
+
// is fine — the badges just appear once data lands.
|
|
10928
|
+
collection: scopeCounts.counts.collection,
|
|
10929
|
+
rule: scopeCounts.counts.rule,
|
|
10930
|
+
variant: scopeCounts.counts.variant,
|
|
10931
|
+
batch: scopeCounts.counts.batch,
|
|
10932
|
+
facet: scopeCounts.counts.facet,
|
|
10933
|
+
all: scopeCounts.counts.all
|
|
10934
|
+
},
|
|
10935
|
+
tooltips: { rule: i18n.rulesTabTooltip },
|
|
10936
|
+
icons: icons.scope
|
|
10615
10937
|
}
|
|
10616
10938
|
) }),
|
|
10617
|
-
|
|
10618
|
-
"
|
|
10619
|
-
|
|
10620
|
-
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
10624
|
-
|
|
10625
|
-
|
|
10626
|
-
|
|
10627
|
-
|
|
10628
|
-
|
|
10629
|
-
|
|
10630
|
-
|
|
10631
|
-
|
|
10632
|
-
/* @__PURE__ */ jsxs(
|
|
10633
|
-
|
|
10634
|
-
|
|
10939
|
+
/* @__PURE__ */ jsxs("div", { className: "p-3 space-y-2.5 border-b", style: { borderColor: "hsl(var(--ra-border))" }, children: [
|
|
10940
|
+
isRuleTab && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1.5", children: /* @__PURE__ */ jsxs(
|
|
10941
|
+
"button",
|
|
10942
|
+
{
|
|
10943
|
+
type: "button",
|
|
10944
|
+
onClick: () => onCreateRule(),
|
|
10945
|
+
className: "ra-btn w-full",
|
|
10946
|
+
"data-variant": "primary",
|
|
10947
|
+
"aria-label": "New rule",
|
|
10948
|
+
children: [
|
|
10949
|
+
/* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5", "aria-hidden": "true" }),
|
|
10950
|
+
/* @__PURE__ */ jsx("span", { children: "New rule" })
|
|
10951
|
+
]
|
|
10952
|
+
}
|
|
10953
|
+
) }),
|
|
10954
|
+
showCreateGlobal && /* @__PURE__ */ jsxs(
|
|
10955
|
+
"button",
|
|
10956
|
+
{
|
|
10957
|
+
type: "button",
|
|
10958
|
+
onClick: onCreateGlobal,
|
|
10959
|
+
className: "ra-btn w-full",
|
|
10960
|
+
"data-variant": "primary",
|
|
10961
|
+
"aria-label": "New global default",
|
|
10962
|
+
children: [
|
|
10963
|
+
/* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5", "aria-hidden": "true" }),
|
|
10964
|
+
/* @__PURE__ */ jsx("span", { children: "New global default" })
|
|
10965
|
+
]
|
|
10966
|
+
}
|
|
10967
|
+
),
|
|
10968
|
+
!(isGlobalTab && !isCollection) && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10969
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
10970
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex-1 min-w-0", children: [
|
|
10971
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-3.5 h-3.5 opacity-50" }),
|
|
10972
|
+
/* @__PURE__ */ jsx(
|
|
10973
|
+
"input",
|
|
10974
|
+
{
|
|
10975
|
+
type: "text",
|
|
10976
|
+
value: search,
|
|
10977
|
+
onChange: (e) => setSearch(e.target.value),
|
|
10978
|
+
placeholder: i18n.searchPlaceholder,
|
|
10979
|
+
className: "w-full pl-8 pr-3 py-1.5 text-xs rounded-md border bg-transparent focus:outline-none focus:ring-1",
|
|
10980
|
+
style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" }
|
|
10981
|
+
}
|
|
10982
|
+
)
|
|
10983
|
+
] }),
|
|
10635
10984
|
/* @__PURE__ */ jsx(
|
|
10636
|
-
|
|
10985
|
+
PresentationSwitcher,
|
|
10637
10986
|
{
|
|
10638
|
-
|
|
10639
|
-
value:
|
|
10640
|
-
onChange:
|
|
10641
|
-
|
|
10642
|
-
className: "w-full pl-8 pr-3 py-1.5 text-xs rounded-md border bg-transparent focus:outline-none focus:ring-1",
|
|
10643
|
-
style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" }
|
|
10987
|
+
options: showPresentationSwitcher ? presentations : [],
|
|
10988
|
+
value: presentation,
|
|
10989
|
+
onChange: onPresentationChange,
|
|
10990
|
+
i18n
|
|
10644
10991
|
}
|
|
10645
10992
|
)
|
|
10646
10993
|
] }),
|
|
10647
|
-
|
|
10648
|
-
|
|
10649
|
-
|
|
10650
|
-
|
|
10651
|
-
|
|
10652
|
-
|
|
10653
|
-
|
|
10654
|
-
|
|
10655
|
-
|
|
10656
|
-
|
|
10657
|
-
|
|
10658
|
-
|
|
10659
|
-
|
|
10660
|
-
|
|
10661
|
-
|
|
10662
|
-
|
|
10663
|
-
|
|
10994
|
+
isProductTab && !productPinned && (() => {
|
|
10995
|
+
const cfg = scopeCounts.productIds;
|
|
10996
|
+
let configured = 0;
|
|
10997
|
+
for (const p of productBrowse.items) if (cfg.has(p.id)) configured += 1;
|
|
10998
|
+
const total = productBrowse.items.length;
|
|
10999
|
+
return /* @__PURE__ */ jsx(
|
|
11000
|
+
StatusFilterPills,
|
|
11001
|
+
{
|
|
11002
|
+
value: filter,
|
|
11003
|
+
onChange: setFilter,
|
|
11004
|
+
counts: {
|
|
11005
|
+
all: total,
|
|
11006
|
+
configured,
|
|
11007
|
+
partial: 0,
|
|
11008
|
+
empty: total - configured
|
|
11009
|
+
},
|
|
11010
|
+
hideZero: ["partial"],
|
|
11011
|
+
i18n
|
|
11012
|
+
}
|
|
11013
|
+
);
|
|
11014
|
+
})(),
|
|
11015
|
+
isRuleTab && /* @__PURE__ */ jsx(
|
|
11016
|
+
FacetBrowseFilter,
|
|
10664
11017
|
{
|
|
10665
|
-
|
|
10666
|
-
|
|
10667
|
-
|
|
10668
|
-
|
|
10669
|
-
configured,
|
|
10670
|
-
partial: 0,
|
|
10671
|
-
empty: total - configured
|
|
10672
|
-
},
|
|
10673
|
-
hideZero: ["partial"],
|
|
10674
|
-
i18n
|
|
11018
|
+
facets: facetBrowseFacets,
|
|
11019
|
+
value: facetBrowseFilter,
|
|
11020
|
+
onChange: setFacetBrowseFilter,
|
|
11021
|
+
isLoading: facetBrowse.isLoading
|
|
10675
11022
|
}
|
|
10676
|
-
)
|
|
10677
|
-
|
|
10678
|
-
|
|
10679
|
-
|
|
11023
|
+
),
|
|
11024
|
+
isRuleTab && isCollection && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs", children: [
|
|
11025
|
+
/* @__PURE__ */ jsx(
|
|
11026
|
+
"label",
|
|
11027
|
+
{
|
|
11028
|
+
htmlFor: "ra-rule-sort",
|
|
11029
|
+
style: { color: "hsl(var(--ra-text-muted))" },
|
|
11030
|
+
children: i18n.ruleSortLabel
|
|
11031
|
+
}
|
|
11032
|
+
),
|
|
11033
|
+
/* @__PURE__ */ jsxs(
|
|
11034
|
+
"select",
|
|
11035
|
+
{
|
|
11036
|
+
id: "ra-rule-sort",
|
|
11037
|
+
value: ruleSort,
|
|
11038
|
+
onChange: (e) => setRuleSort(e.target.value),
|
|
11039
|
+
className: "text-xs px-2 py-1 rounded-md border bg-transparent focus:outline-none focus:ring-1",
|
|
11040
|
+
style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" },
|
|
11041
|
+
children: [
|
|
11042
|
+
/* @__PURE__ */ jsx("option", { value: "recent", children: i18n.ruleSortRecent }),
|
|
11043
|
+
/* @__PURE__ */ jsx("option", { value: "name", children: i18n.ruleSortName }),
|
|
11044
|
+
/* @__PURE__ */ jsx("option", { value: "activeCount", children: i18n.ruleSortActiveCount }),
|
|
11045
|
+
/* @__PURE__ */ jsx("option", { value: "hasArchived", children: i18n.ruleSortHasArchived })
|
|
11046
|
+
]
|
|
11047
|
+
}
|
|
11048
|
+
)
|
|
11049
|
+
] })
|
|
11050
|
+
] })
|
|
11051
|
+
] }),
|
|
11052
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
|
|
11053
|
+
hasSingletonConflicts && /* @__PURE__ */ jsx(
|
|
11054
|
+
SingletonConflictBanner,
|
|
10680
11055
|
{
|
|
10681
|
-
|
|
10682
|
-
|
|
10683
|
-
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
] }),
|
|
10689
|
-
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
|
|
10690
|
-
hasSingletonConflicts && /* @__PURE__ */ jsx(
|
|
10691
|
-
SingletonConflictBanner,
|
|
10692
|
-
{
|
|
10693
|
-
conflictCount: singletonConflicts.length,
|
|
10694
|
-
duplicateCount: totalDuplicateCount,
|
|
10695
|
-
onResolve: () => {
|
|
10696
|
-
const first = singletonConflicts[0]?.duplicates[0] ?? singletonConflicts[0]?.active;
|
|
10697
|
-
if (first?.id) {
|
|
10698
|
-
void runWithGuard(() => {
|
|
10699
|
-
setSelectedRecordId(first.id);
|
|
10700
|
-
});
|
|
10701
|
-
}
|
|
10702
|
-
},
|
|
10703
|
-
onArchiveDuplicates: enableArchiveDuplicates ? async () => {
|
|
10704
|
-
const ids = singletonConflicts.flatMap((c) => c.duplicates.map((d) => d.id)).filter((id) => !!id);
|
|
10705
|
-
for (const id of ids) {
|
|
10706
|
-
try {
|
|
10707
|
-
const updated = await SL.app.records.update(collectionId, appId, id, { status: archivedStatusValue }, true);
|
|
10708
|
-
if (updated) patchRecordIntoCaches(queryClient, ctx, updated);
|
|
10709
|
-
onTelemetry?.({
|
|
10710
|
-
type: "recordAction.invoke",
|
|
10711
|
-
recordType,
|
|
10712
|
-
key: "conflict.archiveDuplicates",
|
|
10713
|
-
ref: id
|
|
11056
|
+
conflictCount: singletonConflicts.length,
|
|
11057
|
+
duplicateCount: totalDuplicateCount,
|
|
11058
|
+
onResolve: () => {
|
|
11059
|
+
const first = singletonConflicts[0]?.duplicates[0] ?? singletonConflicts[0]?.active;
|
|
11060
|
+
if (first?.id) {
|
|
11061
|
+
void runWithGuard(() => {
|
|
11062
|
+
setSelectedRecordId(first.id);
|
|
10714
11063
|
});
|
|
10715
|
-
} catch (err) {
|
|
10716
|
-
console.warn("[RecordsAdminShell] archive-duplicate failed", id, err);
|
|
10717
11064
|
}
|
|
10718
|
-
}
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
|
|
11065
|
+
},
|
|
11066
|
+
onArchiveDuplicates: enableArchiveDuplicates ? async () => {
|
|
11067
|
+
const ids = singletonConflicts.flatMap((c) => c.duplicates.map((d) => d.id)).filter((id) => !!id);
|
|
11068
|
+
for (const id of ids) {
|
|
11069
|
+
try {
|
|
11070
|
+
const updated = await SL.app.records.update(collectionId, appId, id, { status: archivedStatusValue }, true);
|
|
11071
|
+
if (updated) patchRecordIntoCaches(queryClient, ctx, updated);
|
|
11072
|
+
onTelemetry?.({
|
|
11073
|
+
type: "recordAction.invoke",
|
|
11074
|
+
recordType,
|
|
11075
|
+
key: "conflict.archiveDuplicates",
|
|
11076
|
+
ref: id
|
|
11077
|
+
});
|
|
11078
|
+
} catch (err) {
|
|
11079
|
+
console.warn("[RecordsAdminShell] archive-duplicate failed", id, err);
|
|
11080
|
+
}
|
|
11081
|
+
}
|
|
11082
|
+
queryClient.invalidateQueries({
|
|
11083
|
+
queryKey: scopeCountsQueryKey(ctx.collectionId, ctx.appId, ctx.recordType)
|
|
11084
|
+
});
|
|
11085
|
+
} : void 0,
|
|
11086
|
+
onDeleteDuplicates: enableDeleteDuplicates ? async () => {
|
|
11087
|
+
const ids = singletonConflicts.flatMap((c) => c.duplicates.map((d) => d.id)).filter((id) => !!id);
|
|
11088
|
+
for (const id of ids) {
|
|
11089
|
+
try {
|
|
11090
|
+
await SL.app.records.remove(collectionId, appId, id, true);
|
|
11091
|
+
removeRecordFromCaches(queryClient, ctx, id);
|
|
11092
|
+
onTelemetry?.({
|
|
11093
|
+
type: "recordAction.invoke",
|
|
11094
|
+
recordType,
|
|
11095
|
+
key: "conflict.deleteDuplicates",
|
|
11096
|
+
ref: id
|
|
11097
|
+
});
|
|
11098
|
+
} catch (err) {
|
|
11099
|
+
console.warn("[RecordsAdminShell] delete-duplicate failed", id, err);
|
|
11100
|
+
}
|
|
10737
11101
|
}
|
|
11102
|
+
queryClient.invalidateQueries({
|
|
11103
|
+
queryKey: scopeCountsQueryKey(ctx.collectionId, ctx.appId, ctx.recordType)
|
|
11104
|
+
});
|
|
11105
|
+
} : void 0,
|
|
11106
|
+
i18n: {
|
|
11107
|
+
title: i18n.conflictBannerTitle,
|
|
11108
|
+
bodyOne: i18n.conflictBannerBodyOne,
|
|
11109
|
+
bodyMany: i18n.conflictBannerBodyMany,
|
|
11110
|
+
archiveLabel: i18n.conflictArchiveDuplicates,
|
|
11111
|
+
deleteLabel: i18n.conflictDeleteDuplicates,
|
|
11112
|
+
deleteConfirm: i18n.conflictDeleteConfirm,
|
|
11113
|
+
resolveLabel: i18n.conflictResolveLabel
|
|
10738
11114
|
}
|
|
10739
|
-
queryClient.invalidateQueries({
|
|
10740
|
-
queryKey: scopeCountsQueryKey(ctx.collectionId, ctx.appId, ctx.recordType)
|
|
10741
|
-
});
|
|
10742
|
-
} : void 0,
|
|
10743
|
-
i18n: {
|
|
10744
|
-
title: i18n.conflictBannerTitle,
|
|
10745
|
-
bodyOne: i18n.conflictBannerBodyOne,
|
|
10746
|
-
bodyMany: i18n.conflictBannerBodyMany,
|
|
10747
|
-
archiveLabel: i18n.conflictArchiveDuplicates,
|
|
10748
|
-
deleteLabel: i18n.conflictDeleteDuplicates,
|
|
10749
|
-
deleteConfirm: i18n.conflictDeleteConfirm,
|
|
10750
|
-
resolveLabel: i18n.conflictResolveLabel
|
|
10751
|
-
}
|
|
10752
|
-
}
|
|
10753
|
-
),
|
|
10754
|
-
isGlobalTab && !isCollection && !hasSingletonConflicts ? null : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10755
|
-
leftLoading && /* @__PURE__ */ jsx(LoadingState, {}),
|
|
10756
|
-
!leftLoading && leftError && /* @__PURE__ */ jsx(ErrorState, { error: leftError }),
|
|
10757
|
-
!leftLoading && !leftError && decoratedLeftItems.length === 0 && (renderEmptyState ? renderEmptyState({ scope: activeScope }) : /* @__PURE__ */ jsx(
|
|
10758
|
-
EmptyState,
|
|
10759
|
-
{
|
|
10760
|
-
icon: search ? icons.empty.search : icons.empty.default,
|
|
10761
|
-
title: search ? i18n.noResults : i18n.railEmptyTitle,
|
|
10762
|
-
body: search ? void 0 : isRuleTab ? i18n.rulesEmptyBody : i18n.railEmptyBody
|
|
10763
11115
|
}
|
|
10764
|
-
)
|
|
10765
|
-
|
|
10766
|
-
/* @__PURE__ */ jsx(
|
|
10767
|
-
|
|
11116
|
+
),
|
|
11117
|
+
isGlobalTab && !isCollection && !hasSingletonConflicts ? null : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11118
|
+
leftLoading && /* @__PURE__ */ jsx(LoadingState, {}),
|
|
11119
|
+
!leftLoading && leftError && /* @__PURE__ */ jsx(ErrorState, { error: leftError }),
|
|
11120
|
+
!leftLoading && !leftError && decoratedLeftItems.length === 0 && (renderEmptyState ? renderEmptyState({ scope: activeScope }) : /* @__PURE__ */ jsx(
|
|
11121
|
+
EmptyState,
|
|
10768
11122
|
{
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
onSelect: onLeftSelect,
|
|
10773
|
-
dirtyId,
|
|
10774
|
-
dirtyAnchorKey,
|
|
10775
|
-
dirtyKeys,
|
|
10776
|
-
errorKeys,
|
|
10777
|
-
presentation: effectivePresentation,
|
|
10778
|
-
renderListRow,
|
|
10779
|
-
groupBy: (
|
|
10780
|
-
// The synthetic "All items" row in collection mode is a
|
|
10781
|
-
// navigational anchor, not a real record — applying the
|
|
10782
|
-
// host's groupBy bucketed it under "Other" (its
|
|
10783
|
-
// data is null). Skip grouping for that single-row rail.
|
|
10784
|
-
(isGlobalTab || isAllTab) && isCollection || isLifecycleRail ? void 0 : effectiveGroupBy
|
|
10785
|
-
),
|
|
10786
|
-
renderGroupActions: renderRuleGroupActions,
|
|
10787
|
-
rowClipboard,
|
|
10788
|
-
rowActions: wrappedRecordActions,
|
|
10789
|
-
i18n,
|
|
10790
|
-
historyBySlot: railHistoryBySlot
|
|
11123
|
+
icon: search ? icons.empty.search : icons.empty.default,
|
|
11124
|
+
title: search ? i18n.noResults : i18n.railEmptyTitle,
|
|
11125
|
+
body: search ? void 0 : isRuleTab ? i18n.rulesEmptyBody : i18n.railEmptyBody
|
|
10791
11126
|
}
|
|
10792
|
-
),
|
|
10793
|
-
|
|
10794
|
-
|
|
10795
|
-
|
|
10796
|
-
|
|
10797
|
-
|
|
10798
|
-
|
|
10799
|
-
|
|
10800
|
-
|
|
11127
|
+
)),
|
|
11128
|
+
!leftLoading && !leftError && decoratedLeftItems.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11129
|
+
/* @__PURE__ */ jsx(
|
|
11130
|
+
RecordList,
|
|
11131
|
+
{
|
|
11132
|
+
items: decoratedLeftItems,
|
|
11133
|
+
selectedId: leftSelectedId,
|
|
11134
|
+
selectedAnchorKey: leftSelectedAnchorKey,
|
|
11135
|
+
onSelect: onLeftSelect,
|
|
11136
|
+
dirtyId,
|
|
11137
|
+
dirtyAnchorKey,
|
|
11138
|
+
dirtyKeys,
|
|
11139
|
+
errorKeys,
|
|
11140
|
+
presentation: effectivePresentation,
|
|
11141
|
+
renderListRow,
|
|
11142
|
+
groupBy: (
|
|
11143
|
+
// The synthetic "All items" row in collection mode is a
|
|
11144
|
+
// navigational anchor, not a real record — applying the
|
|
11145
|
+
// host's groupBy bucketed it under "Other" (its
|
|
11146
|
+
// data is null). Skip grouping for that single-row rail.
|
|
11147
|
+
(isGlobalTab || isAllTab) && isCollection || isLifecycleRail ? void 0 : effectiveGroupBy
|
|
11148
|
+
),
|
|
11149
|
+
renderGroupActions: renderRuleGroupActions,
|
|
11150
|
+
rowClipboard,
|
|
11151
|
+
rowActions: wrappedRecordActions,
|
|
11152
|
+
i18n,
|
|
11153
|
+
historyBySlot: railHistoryBySlot
|
|
10801
11154
|
}
|
|
10802
|
-
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
|
|
10812
|
-
void recordList.fetchNextPage();
|
|
11155
|
+
),
|
|
11156
|
+
isProductTab && !productPinned && /* @__PURE__ */ jsx(
|
|
11157
|
+
LoadMoreFooter,
|
|
11158
|
+
{
|
|
11159
|
+
shown: leftItems.length,
|
|
11160
|
+
hasNextPage: !!productBrowse.hasNextPage,
|
|
11161
|
+
isFetchingNextPage: !!productBrowse.isFetchingNextPage,
|
|
11162
|
+
onLoadMore: () => {
|
|
11163
|
+
void productBrowse.fetchNextPage();
|
|
11164
|
+
}
|
|
10813
11165
|
}
|
|
10814
|
-
|
|
10815
|
-
|
|
11166
|
+
),
|
|
11167
|
+
isRecordsTab && (!isCollection || !(isAllTab || isGlobalTab)) && /* @__PURE__ */ jsx(
|
|
11168
|
+
LoadMoreFooter,
|
|
11169
|
+
{
|
|
11170
|
+
shown: recordList.items.length,
|
|
11171
|
+
total: recordList.total,
|
|
11172
|
+
hasNextPage: !!recordList.hasNextPage,
|
|
11173
|
+
isFetchingNextPage: !!recordList.isFetchingNextPage,
|
|
11174
|
+
onLoadMore: () => {
|
|
11175
|
+
void recordList.fetchNextPage();
|
|
11176
|
+
}
|
|
11177
|
+
}
|
|
11178
|
+
)
|
|
11179
|
+
] })
|
|
10816
11180
|
] })
|
|
10817
11181
|
] })
|
|
10818
11182
|
] })
|
|
10819
|
-
] })
|
|
10820
|
-
/* @__PURE__ */ jsxs("main", { className: "overflow-hidden", children: [
|
|
11183
|
+
] }),
|
|
11184
|
+
/* @__PURE__ */ jsxs("main", { className: "overflow-hidden relative", ref: railReopenAnchorRef, children: [
|
|
11185
|
+
!railHidden && !railOpen && /* @__PURE__ */ jsxs(
|
|
11186
|
+
PreviewReopenPill,
|
|
11187
|
+
{
|
|
11188
|
+
anchorRef: railReopenAnchorRef,
|
|
11189
|
+
side: "left",
|
|
11190
|
+
onClick: () => setRailOpen(true),
|
|
11191
|
+
ariaLabel: i18n.openList,
|
|
11192
|
+
title: i18n.openList,
|
|
11193
|
+
children: [
|
|
11194
|
+
/* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true" }),
|
|
11195
|
+
i18n.openList
|
|
11196
|
+
]
|
|
11197
|
+
}
|
|
11198
|
+
),
|
|
10821
11199
|
ruleWizardStep !== null && /* @__PURE__ */ jsxs(
|
|
10822
11200
|
NewRuleWizard,
|
|
10823
11201
|
{
|
|
@@ -10920,6 +11298,8 @@ function RecordsAdminShellInner(props) {
|
|
|
10920
11298
|
onLoadMore: () => {
|
|
10921
11299
|
void collectionItems.fetchNextPage();
|
|
10922
11300
|
},
|
|
11301
|
+
groupByLifecycle: true,
|
|
11302
|
+
lifecycle: lifecycleConfig,
|
|
10923
11303
|
i18n
|
|
10924
11304
|
}
|
|
10925
11305
|
),
|