@proveanything/smartlinks-utils-ui 0.11.11 → 0.12.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/components/AssetPicker/index.css +35 -0
- package/dist/components/AssetPicker/index.css.map +1 -1
- package/dist/components/ConditionsEditor/index.css +35 -0
- package/dist/components/ConditionsEditor/index.css.map +1 -1
- package/dist/components/FontPicker/index.css +35 -0
- package/dist/components/FontPicker/index.css.map +1 -1
- package/dist/components/IconPicker/index.css +35 -0
- package/dist/components/IconPicker/index.css.map +1 -1
- package/dist/components/RecordsAdmin/index.css +35 -0
- package/dist/components/RecordsAdmin/index.css.map +1 -1
- package/dist/components/RecordsAdmin/index.d.ts +310 -41
- package/dist/components/RecordsAdmin/index.js +1007 -121
- package/dist/components/RecordsAdmin/index.js.map +1 -1
- package/dist/index.css +35 -0
- package/dist/index.css.map +1 -1
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@ 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
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, FilePlus2, 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,
|
|
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, ClipboardPaste, Box, X, Search, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, CornerDownLeft, Circle, ArrowUpDown, ArrowUp, ArrowDown, MinusCircle, XCircle, CopyPlus, AlertCircle, Undo2, Save, Loader2, Archive, ArrowRight, Globe2, 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';
|
|
@@ -250,7 +250,26 @@ var DEFAULT_I18N = {
|
|
|
250
250
|
hookBeforeSaveFailed: "Couldn't save: {message}",
|
|
251
251
|
hookAfterSaveFailed: "Saved, but a follow-up step failed: {message}",
|
|
252
252
|
hookBeforeDeleteFailed: "Couldn't delete: {message}",
|
|
253
|
-
hookAfterDeleteFailed: "Deleted, but a follow-up step failed: {message}"
|
|
253
|
+
hookAfterDeleteFailed: "Deleted, but a follow-up step failed: {message}",
|
|
254
|
+
historyDisclosureShow: "Show {n} archived",
|
|
255
|
+
historyDisclosureHide: "Hide {n} archived",
|
|
256
|
+
lifecycleStatusLabel: "Status",
|
|
257
|
+
lifecycleStatusActive: "Active",
|
|
258
|
+
lifecycleStatusArchived: "Archived",
|
|
259
|
+
lifecycleStatusDraft: "Draft",
|
|
260
|
+
lifecycleStatusHint: "Archived records aren't returned to public consumers.",
|
|
261
|
+
actionArchive: "Archive",
|
|
262
|
+
actionRestore: "Restore",
|
|
263
|
+
lifecycleMenuLabel: "Status",
|
|
264
|
+
lifecycleChangeTo: "Change status to {label}",
|
|
265
|
+
lifecycleCurrentBadge: "Current",
|
|
266
|
+
conflictBannerTitle: "Duplicate records detected",
|
|
267
|
+
conflictBannerBodyOne: "{n} extra active record shares this slot. Only the oldest is used.",
|
|
268
|
+
conflictBannerBodyMany: "{slots} slots have duplicates ({dups} extra records). Only the oldest in each is used.",
|
|
269
|
+
conflictArchiveDuplicates: "Archive duplicates",
|
|
270
|
+
conflictDeleteDuplicates: "Delete duplicates",
|
|
271
|
+
conflictDeleteConfirm: "Permanently delete {n} duplicate record(s)? This cannot be undone.",
|
|
272
|
+
conflictResolveLabel: "Resolve"
|
|
254
273
|
};
|
|
255
274
|
|
|
256
275
|
// src/components/RecordsAdmin/types/presentation.ts
|
|
@@ -603,6 +622,72 @@ var useScopeCounts = (args) => {
|
|
|
603
622
|
return result;
|
|
604
623
|
};
|
|
605
624
|
var scopeCountsQueryKey = (collectionId, appId, recordType) => [...QK_BASE, collectionId, appId, recordType ?? null];
|
|
625
|
+
|
|
626
|
+
// src/components/RecordsAdmin/data/singletonConflicts.ts
|
|
627
|
+
var NO_RULE = "__no_rule__";
|
|
628
|
+
var DEFAULT_ACTIVE_STATUSES = ["active"];
|
|
629
|
+
var isActive = (record, activeStatuses = DEFAULT_ACTIVE_STATUSES) => {
|
|
630
|
+
const s = record.lifecycleStatus;
|
|
631
|
+
if (s == null || s === "") return true;
|
|
632
|
+
return activeStatuses.includes(s);
|
|
633
|
+
};
|
|
634
|
+
var slotKey = (record) => {
|
|
635
|
+
const anchor = anchorKey(record.scope);
|
|
636
|
+
const rule = ruleHash(record.facetRule) ?? NO_RULE;
|
|
637
|
+
return `${anchor}::${rule}`;
|
|
638
|
+
};
|
|
639
|
+
var pickActiveRecord = (records) => {
|
|
640
|
+
if (records.length === 0) return null;
|
|
641
|
+
if (records.length === 1) return records[0];
|
|
642
|
+
const sorted = [...records].sort((a, b) => {
|
|
643
|
+
const aT = a.updatedAt;
|
|
644
|
+
const bT = b.updatedAt;
|
|
645
|
+
if (aT && bT) {
|
|
646
|
+
if (aT < bT) return -1;
|
|
647
|
+
if (aT > bT) return 1;
|
|
648
|
+
} else if (aT && !bT) {
|
|
649
|
+
return -1;
|
|
650
|
+
} else if (!aT && bT) {
|
|
651
|
+
return 1;
|
|
652
|
+
}
|
|
653
|
+
const aId = a.id ?? "";
|
|
654
|
+
const bId = b.id ?? "";
|
|
655
|
+
if (aId < bId) return -1;
|
|
656
|
+
if (aId > bId) return 1;
|
|
657
|
+
return 0;
|
|
658
|
+
});
|
|
659
|
+
return sorted[0];
|
|
660
|
+
};
|
|
661
|
+
var groupSingletonConflicts = (items, activeStatuses = DEFAULT_ACTIVE_STATUSES) => {
|
|
662
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
663
|
+
for (const item of items) {
|
|
664
|
+
if (!isActive(item, activeStatuses)) continue;
|
|
665
|
+
const k = slotKey(item);
|
|
666
|
+
const existing = buckets.get(k);
|
|
667
|
+
if (existing) existing.push(item);
|
|
668
|
+
else buckets.set(k, [item]);
|
|
669
|
+
}
|
|
670
|
+
const conflicts = [];
|
|
671
|
+
for (const [key, records] of buckets) {
|
|
672
|
+
if (records.length < 2) continue;
|
|
673
|
+
const active = pickActiveRecord(records);
|
|
674
|
+
conflicts.push({
|
|
675
|
+
key,
|
|
676
|
+
records,
|
|
677
|
+
active,
|
|
678
|
+
duplicates: records.filter((r) => r !== active)
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
return conflicts;
|
|
682
|
+
};
|
|
683
|
+
var findConflictForRecord = (recordId, conflicts) => {
|
|
684
|
+
for (const c of conflicts) {
|
|
685
|
+
if (c.records.some((r) => r.id === recordId)) return c;
|
|
686
|
+
}
|
|
687
|
+
return null;
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
// src/components/RecordsAdmin/hooks/useRecordList.ts
|
|
606
691
|
var defaultClassify = (r) => {
|
|
607
692
|
if (!r.data) return "empty";
|
|
608
693
|
const keys = Object.keys(r.data);
|
|
@@ -662,7 +747,8 @@ var toSummary = (rec) => {
|
|
|
662
747
|
status: "configured",
|
|
663
748
|
label: fallbackLabel,
|
|
664
749
|
updatedAt: rec.updatedAt,
|
|
665
|
-
facetRule
|
|
750
|
+
facetRule,
|
|
751
|
+
lifecycleStatus: rec.status ?? void 0
|
|
666
752
|
};
|
|
667
753
|
};
|
|
668
754
|
var QK_BASE2 = ["records-admin", "list"];
|
|
@@ -676,7 +762,8 @@ var useRecordList = (args) => {
|
|
|
676
762
|
enabled = true,
|
|
677
763
|
scaffolder,
|
|
678
764
|
contextScope,
|
|
679
|
-
pageSize = 100
|
|
765
|
+
pageSize = 100,
|
|
766
|
+
activeStatuses = DEFAULT_ACTIVE_STATUSES
|
|
680
767
|
} = args;
|
|
681
768
|
const queryClient = useQueryClient();
|
|
682
769
|
const queryKey = useMemo(
|
|
@@ -739,6 +826,24 @@ var useRecordList = (args) => {
|
|
|
739
826
|
partial: items.filter((r) => r.status === "partial").length,
|
|
740
827
|
empty: items.filter((r) => r.status === "empty").length
|
|
741
828
|
}), [items]);
|
|
829
|
+
const activeItems = useMemo(
|
|
830
|
+
() => filtered.filter((r) => isActive(r, activeStatuses)),
|
|
831
|
+
[filtered, activeStatuses]
|
|
832
|
+
);
|
|
833
|
+
const historyItems = useMemo(
|
|
834
|
+
() => filtered.filter((r) => !isActive(r, activeStatuses)),
|
|
835
|
+
[filtered, activeStatuses]
|
|
836
|
+
);
|
|
837
|
+
const historyBySlot = useMemo(() => {
|
|
838
|
+
const map = /* @__PURE__ */ new Map();
|
|
839
|
+
for (const r of historyItems) {
|
|
840
|
+
const k = slotKey(r);
|
|
841
|
+
const list = map.get(k);
|
|
842
|
+
if (list) list.push(r);
|
|
843
|
+
else map.set(k, [r]);
|
|
844
|
+
}
|
|
845
|
+
return map;
|
|
846
|
+
}, [historyItems]);
|
|
742
847
|
const refetch = useCallback(() => queryClient.refetchQueries({
|
|
743
848
|
queryKey: [...QK_BASE2, ctx.collectionId, ctx.appId, ctx.recordType]
|
|
744
849
|
}), [queryClient, ctx.collectionId, ctx.appId, ctx.recordType]);
|
|
@@ -746,6 +851,9 @@ var useRecordList = (args) => {
|
|
|
746
851
|
return {
|
|
747
852
|
allItems: items,
|
|
748
853
|
items: filtered,
|
|
854
|
+
activeItems,
|
|
855
|
+
historyItems,
|
|
856
|
+
historyBySlot,
|
|
749
857
|
total,
|
|
750
858
|
counts,
|
|
751
859
|
isLoading: query.isLoading,
|
|
@@ -1021,7 +1129,8 @@ function useShellBrowser(opts) {
|
|
|
1021
1129
|
selectedProductId,
|
|
1022
1130
|
drillTab,
|
|
1023
1131
|
classify: classify3,
|
|
1024
|
-
pageSize
|
|
1132
|
+
pageSize,
|
|
1133
|
+
activeStatuses
|
|
1025
1134
|
} = opts;
|
|
1026
1135
|
const [search, setSearch] = useState("");
|
|
1027
1136
|
const [filter, setFilter] = useState("all");
|
|
@@ -1048,7 +1157,8 @@ function useShellBrowser(opts) {
|
|
|
1048
1157
|
classify: classify3,
|
|
1049
1158
|
contextScope,
|
|
1050
1159
|
enabled: recordListEnabled,
|
|
1051
|
-
pageSize
|
|
1160
|
+
pageSize,
|
|
1161
|
+
activeStatuses
|
|
1052
1162
|
});
|
|
1053
1163
|
const facetBrowse = useFacetBrowse({
|
|
1054
1164
|
SL,
|
|
@@ -2569,7 +2679,11 @@ var createEditorStore = () => {
|
|
|
2569
2679
|
ref: spec.ref,
|
|
2570
2680
|
scope: anchors,
|
|
2571
2681
|
data: persistedValue,
|
|
2572
|
-
facetRule: persistedFacetRule
|
|
2682
|
+
facetRule: persistedFacetRule,
|
|
2683
|
+
// Seed the configured lifecycle default (e.g. 'draft') so
|
|
2684
|
+
// brand-new records land in the right bucket without the host
|
|
2685
|
+
// wiring it into every editor's beforeSave.
|
|
2686
|
+
status: spec.defaultStatus
|
|
2573
2687
|
});
|
|
2574
2688
|
nextRecordId = created?.id ?? nextRecordId;
|
|
2575
2689
|
savedRecord = created;
|
|
@@ -2578,7 +2692,10 @@ var createEditorStore = () => {
|
|
|
2578
2692
|
ref: spec.ref,
|
|
2579
2693
|
scope: anchors,
|
|
2580
2694
|
data: persistedValue,
|
|
2581
|
-
facetRule: persistedFacetRule
|
|
2695
|
+
facetRule: persistedFacetRule,
|
|
2696
|
+
// Same seeding rule applies on the upsert path used by
|
|
2697
|
+
// singleton-cardinality first-time saves.
|
|
2698
|
+
status: !entry.recordId ? spec.defaultStatus : void 0
|
|
2582
2699
|
});
|
|
2583
2700
|
nextRecordId = upserted.record?.id ?? nextRecordId;
|
|
2584
2701
|
savedRecord = upserted.record;
|
|
@@ -3044,7 +3161,8 @@ function useShellEditorTarget(args) {
|
|
|
3044
3161
|
defaultData,
|
|
3045
3162
|
deriveDraftLabel,
|
|
3046
3163
|
onSaved,
|
|
3047
|
-
onDeleted
|
|
3164
|
+
onDeleted,
|
|
3165
|
+
defaultStatus
|
|
3048
3166
|
} = args;
|
|
3049
3167
|
const editorTargetSpec = useMemo(() => {
|
|
3050
3168
|
if (!editingTargetScope) return null;
|
|
@@ -3076,7 +3194,8 @@ function useShellEditorTarget(args) {
|
|
|
3076
3194
|
label,
|
|
3077
3195
|
draftKey,
|
|
3078
3196
|
isDraftScope,
|
|
3079
|
-
initialData: createMode ? ruleWizardInitialData : explicitSingletonInitialData ?? void 0
|
|
3197
|
+
initialData: createMode ? ruleWizardInitialData : explicitSingletonInitialData ?? void 0,
|
|
3198
|
+
defaultStatus
|
|
3080
3199
|
};
|
|
3081
3200
|
}, [
|
|
3082
3201
|
editingTargetScope?.raw,
|
|
@@ -3091,7 +3210,8 @@ function useShellEditorTarget(args) {
|
|
|
3091
3210
|
ruleWizardDraftKey,
|
|
3092
3211
|
ruleWizardInitialData,
|
|
3093
3212
|
explicitSingletonInitialData,
|
|
3094
|
-
ruleWizardRule
|
|
3213
|
+
ruleWizardRule,
|
|
3214
|
+
defaultStatus
|
|
3095
3215
|
]);
|
|
3096
3216
|
const editorCtx = useEditorBridge({
|
|
3097
3217
|
target: editorTargetSpec,
|
|
@@ -3207,7 +3327,7 @@ var ScopeTabs = ({
|
|
|
3207
3327
|
const iconMap = icons ?? DEFAULT_ICONS.scope;
|
|
3208
3328
|
return /* @__PURE__ */ jsx("div", { role: "tablist", className: "ra-tabs", "aria-label": "Record scope", children: scopes.map((s) => {
|
|
3209
3329
|
const Icon = iconMap[s] ?? DEFAULT_ICONS.scope[s];
|
|
3210
|
-
const
|
|
3330
|
+
const isActive2 = active === s;
|
|
3211
3331
|
const count = counts?.[s];
|
|
3212
3332
|
const tooltip = tooltips?.[s];
|
|
3213
3333
|
return /* @__PURE__ */ jsxs(
|
|
@@ -3215,7 +3335,7 @@ var ScopeTabs = ({
|
|
|
3215
3335
|
{
|
|
3216
3336
|
type: "button",
|
|
3217
3337
|
role: "tab",
|
|
3218
|
-
"aria-selected":
|
|
3338
|
+
"aria-selected": isActive2,
|
|
3219
3339
|
onClick: () => onChange(s),
|
|
3220
3340
|
disabled: loading,
|
|
3221
3341
|
className: "ra-tab",
|
|
@@ -3650,7 +3770,8 @@ var RecordList = ({
|
|
|
3650
3770
|
renderGroupActions,
|
|
3651
3771
|
rowClipboard,
|
|
3652
3772
|
rowActions,
|
|
3653
|
-
i18n
|
|
3773
|
+
i18n,
|
|
3774
|
+
historyBySlot
|
|
3654
3775
|
}) => {
|
|
3655
3776
|
const containerRef = useRef(null);
|
|
3656
3777
|
const onKeyDown = useCallback((e) => {
|
|
@@ -3712,12 +3833,53 @@ var RecordList = ({
|
|
|
3712
3833
|
}
|
|
3713
3834
|
return orderedKeys.map((k) => buckets.get(k));
|
|
3714
3835
|
}, [items, groupBy]);
|
|
3836
|
+
const [expandedSlots, setExpandedSlots] = useState(() => /* @__PURE__ */ new Set());
|
|
3837
|
+
const toggleSlot = useCallback((k) => {
|
|
3838
|
+
setExpandedSlots((prev) => {
|
|
3839
|
+
const next = new Set(prev);
|
|
3840
|
+
if (next.has(k)) next.delete(k);
|
|
3841
|
+
else next.add(k);
|
|
3842
|
+
return next;
|
|
3843
|
+
});
|
|
3844
|
+
}, []);
|
|
3715
3845
|
const renderItems = (rows) => {
|
|
3716
3846
|
const compact = presentation === "compact";
|
|
3717
3847
|
return /* @__PURE__ */ jsx("ul", { children: rows.map((item, idx) => {
|
|
3718
3848
|
const ctx = buildCtx(item);
|
|
3719
3849
|
const key = item.id ?? (anchorKey(item.scope) || `pos:${idx}`);
|
|
3720
|
-
|
|
3850
|
+
const sKey = historyBySlot ? slotKey(item) : null;
|
|
3851
|
+
const history = sKey ? historyBySlot.get(sKey) : void 0;
|
|
3852
|
+
const expanded = sKey ? expandedSlots.has(sKey) : false;
|
|
3853
|
+
const showLabel = i18n?.historyDisclosureShow ?? "Show {n} archived";
|
|
3854
|
+
const hideLabel = i18n?.historyDisclosureHide ?? "Hide {n} archived";
|
|
3855
|
+
const label = (expanded ? hideLabel : showLabel).replace("{n}", String(history?.length ?? 0));
|
|
3856
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
3857
|
+
renderListRow ? renderListRow(item, ctx) : /* @__PURE__ */ jsx(DefaultRecordRow, { record: item, ctx, compact }),
|
|
3858
|
+
history && history.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "ra-history-block", children: [
|
|
3859
|
+
expanded ? /* @__PURE__ */ jsx("ul", { className: "ra-history-rows", "aria-label": "Archived records", children: history.map((h, hIdx) => {
|
|
3860
|
+
const hCtx = buildCtx(h);
|
|
3861
|
+
const hKey = h.id ?? `hist:${idx}:${hIdx}`;
|
|
3862
|
+
const badged = {
|
|
3863
|
+
...h,
|
|
3864
|
+
badges: [
|
|
3865
|
+
...h.badges ?? [],
|
|
3866
|
+
{ label: h.lifecycleStatus ?? "archived", tone: "warning" }
|
|
3867
|
+
]
|
|
3868
|
+
};
|
|
3869
|
+
return /* @__PURE__ */ jsx("li", { className: "ra-history-row", "data-history": "true", children: renderListRow ? renderListRow(badged, hCtx) : /* @__PURE__ */ jsx(DefaultRecordRow, { record: badged, ctx: hCtx, compact }) }, hKey);
|
|
3870
|
+
}) }) : null,
|
|
3871
|
+
/* @__PURE__ */ jsx(
|
|
3872
|
+
"button",
|
|
3873
|
+
{
|
|
3874
|
+
type: "button",
|
|
3875
|
+
className: "ra-history-disclosure",
|
|
3876
|
+
onClick: () => sKey && toggleSlot(sKey),
|
|
3877
|
+
"aria-expanded": expanded,
|
|
3878
|
+
children: label
|
|
3879
|
+
}
|
|
3880
|
+
)
|
|
3881
|
+
] }) : null
|
|
3882
|
+
] }, key);
|
|
3721
3883
|
}) });
|
|
3722
3884
|
};
|
|
3723
3885
|
if (groups) {
|
|
@@ -3797,6 +3959,306 @@ var ProductList = RecordList;
|
|
|
3797
3959
|
var FacetList = RecordList;
|
|
3798
3960
|
var VariantList = RecordList;
|
|
3799
3961
|
var BatchList = RecordList;
|
|
3962
|
+
var LifecycleStatusControl = ({
|
|
3963
|
+
SL,
|
|
3964
|
+
collectionId,
|
|
3965
|
+
appId,
|
|
3966
|
+
recordId,
|
|
3967
|
+
current,
|
|
3968
|
+
options,
|
|
3969
|
+
i18n,
|
|
3970
|
+
onChanged
|
|
3971
|
+
}) => {
|
|
3972
|
+
const [busy, setBusy] = useState(false);
|
|
3973
|
+
const value = current ?? "active";
|
|
3974
|
+
const opts = options ?? [
|
|
3975
|
+
{ value: "active", label: i18n.lifecycleStatusActive },
|
|
3976
|
+
{ value: "archived", label: i18n.lifecycleStatusArchived },
|
|
3977
|
+
{ value: "draft", label: i18n.lifecycleStatusDraft }
|
|
3978
|
+
];
|
|
3979
|
+
const onChange = useCallback(async (e) => {
|
|
3980
|
+
const next = e.target.value;
|
|
3981
|
+
if (next === value) return;
|
|
3982
|
+
setBusy(true);
|
|
3983
|
+
try {
|
|
3984
|
+
await SL.app.records.update(collectionId, appId, recordId, { status: next }, true);
|
|
3985
|
+
onChanged?.(next);
|
|
3986
|
+
} catch (err) {
|
|
3987
|
+
console.warn("[LifecycleStatusControl] update failed", err);
|
|
3988
|
+
} finally {
|
|
3989
|
+
setBusy(false);
|
|
3990
|
+
}
|
|
3991
|
+
}, [SL, collectionId, appId, recordId, value, onChanged]);
|
|
3992
|
+
return /* @__PURE__ */ jsxs(
|
|
3993
|
+
"label",
|
|
3994
|
+
{
|
|
3995
|
+
className: "inline-flex items-center gap-1.5 text-[11px] mt-0.5",
|
|
3996
|
+
title: i18n.lifecycleStatusHint,
|
|
3997
|
+
style: { color: "hsl(var(--ra-muted-text))" },
|
|
3998
|
+
children: [
|
|
3999
|
+
/* @__PURE__ */ jsx("span", { className: "uppercase tracking-wide", children: i18n.lifecycleStatusLabel }),
|
|
4000
|
+
/* @__PURE__ */ jsx(
|
|
4001
|
+
"select",
|
|
4002
|
+
{
|
|
4003
|
+
value,
|
|
4004
|
+
onChange,
|
|
4005
|
+
disabled: busy,
|
|
4006
|
+
className: "text-xs px-1.5 py-0.5 rounded border bg-transparent",
|
|
4007
|
+
style: {
|
|
4008
|
+
borderColor: "hsl(var(--ra-border))",
|
|
4009
|
+
color: "hsl(var(--ra-text))",
|
|
4010
|
+
background: "hsl(var(--ra-surface))"
|
|
4011
|
+
},
|
|
4012
|
+
children: opts.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
|
|
4013
|
+
}
|
|
4014
|
+
)
|
|
4015
|
+
]
|
|
4016
|
+
}
|
|
4017
|
+
);
|
|
4018
|
+
};
|
|
4019
|
+
|
|
4020
|
+
// src/components/RecordsAdmin/data/lifecycleStatuses.ts
|
|
4021
|
+
var DEFAULT_LIFECYCLE_STATUSES = [
|
|
4022
|
+
{ value: "draft", label: "Draft", tone: "warning" },
|
|
4023
|
+
{ value: "active", label: "Active", tone: "success", isActive: true },
|
|
4024
|
+
{ value: "archived", label: "Archived", tone: "muted" }
|
|
4025
|
+
];
|
|
4026
|
+
var getLifecycleStatuses = (config) => {
|
|
4027
|
+
if (config?.statuses && config.statuses.length > 0) return config.statuses;
|
|
4028
|
+
return DEFAULT_LIFECYCLE_STATUSES;
|
|
4029
|
+
};
|
|
4030
|
+
var getActiveStatusValues = (config, legacyActiveStatuses) => {
|
|
4031
|
+
const fromDefs = getLifecycleStatuses(config).filter((s) => s.isActive).map((s) => s.value);
|
|
4032
|
+
if (legacyActiveStatuses && legacyActiveStatuses.length > 0) {
|
|
4033
|
+
const set = /* @__PURE__ */ new Set([...fromDefs, ...legacyActiveStatuses]);
|
|
4034
|
+
return Array.from(set);
|
|
4035
|
+
}
|
|
4036
|
+
return fromDefs.length > 0 ? fromDefs : ["active"];
|
|
4037
|
+
};
|
|
4038
|
+
var UNKNOWN_DEF = (value) => ({
|
|
4039
|
+
value,
|
|
4040
|
+
label: value,
|
|
4041
|
+
tone: "default"
|
|
4042
|
+
});
|
|
4043
|
+
var resolveLifecycleStatus = (record, config) => {
|
|
4044
|
+
const defs = getLifecycleStatuses(config);
|
|
4045
|
+
const raw = record.lifecycleStatus;
|
|
4046
|
+
if (raw == null || raw === "") {
|
|
4047
|
+
return defs.find((d) => d.value === "active") ?? defs.find((d) => d.isActive) ?? defs[0];
|
|
4048
|
+
}
|
|
4049
|
+
return defs.find((d) => d.value === raw) ?? UNKNOWN_DEF(raw);
|
|
4050
|
+
};
|
|
4051
|
+
var hasMixedLifecycle = (records, activeValues) => {
|
|
4052
|
+
for (const r of records) {
|
|
4053
|
+
const s = r.lifecycleStatus;
|
|
4054
|
+
if (s == null || s === "") continue;
|
|
4055
|
+
if (!activeValues.includes(s)) return true;
|
|
4056
|
+
}
|
|
4057
|
+
return false;
|
|
4058
|
+
};
|
|
4059
|
+
var LIFECYCLE_BUCKET_ORDER = ["draft", "active", "archived"];
|
|
4060
|
+
var compareLifecycleBuckets = (a, b) => {
|
|
4061
|
+
const ai = LIFECYCLE_BUCKET_ORDER.indexOf(a);
|
|
4062
|
+
const bi = LIFECYCLE_BUCKET_ORDER.indexOf(b);
|
|
4063
|
+
if (ai === -1 && bi === -1) return a.localeCompare(b);
|
|
4064
|
+
if (ai === -1) return 1;
|
|
4065
|
+
if (bi === -1) return -1;
|
|
4066
|
+
return ai - bi;
|
|
4067
|
+
};
|
|
4068
|
+
var toneColor = (tone) => {
|
|
4069
|
+
switch (tone) {
|
|
4070
|
+
case "success":
|
|
4071
|
+
return "hsl(var(--ra-success, 142 70% 40%))";
|
|
4072
|
+
case "warning":
|
|
4073
|
+
return "hsl(var(--ra-warning, 38 92% 50%))";
|
|
4074
|
+
case "danger":
|
|
4075
|
+
return "hsl(var(--ra-danger, 0 70% 45%))";
|
|
4076
|
+
case "muted":
|
|
4077
|
+
return "hsl(var(--ra-muted-text))";
|
|
4078
|
+
default:
|
|
4079
|
+
return "hsl(var(--ra-text))";
|
|
4080
|
+
}
|
|
4081
|
+
};
|
|
4082
|
+
var ToneDot = ({ tone, className }) => /* @__PURE__ */ jsx(
|
|
4083
|
+
"span",
|
|
4084
|
+
{
|
|
4085
|
+
"aria-hidden": "true",
|
|
4086
|
+
className: className ?? "inline-block w-2 h-2 rounded-full shrink-0",
|
|
4087
|
+
style: { background: toneColor(tone) }
|
|
4088
|
+
}
|
|
4089
|
+
);
|
|
4090
|
+
var LifecycleStatusMenu = ({
|
|
4091
|
+
SL,
|
|
4092
|
+
collectionId,
|
|
4093
|
+
appId,
|
|
4094
|
+
recordId,
|
|
4095
|
+
scope,
|
|
4096
|
+
current,
|
|
4097
|
+
statuses,
|
|
4098
|
+
i18n,
|
|
4099
|
+
beforeChange,
|
|
4100
|
+
onChanged,
|
|
4101
|
+
onTelemetry,
|
|
4102
|
+
size = "sm"
|
|
4103
|
+
}) => {
|
|
4104
|
+
const [open, setOpen] = useState(false);
|
|
4105
|
+
const [busy, setBusy] = useState(null);
|
|
4106
|
+
const wrapperRef = useRef(null);
|
|
4107
|
+
const triggerRef = useRef(null);
|
|
4108
|
+
const menuRef = useRef(null);
|
|
4109
|
+
const [pos, setPos] = useState(null);
|
|
4110
|
+
const currentDef = resolveLifecycleStatus({ lifecycleStatus: current }, { statuses });
|
|
4111
|
+
useEffect(() => {
|
|
4112
|
+
if (!open) return;
|
|
4113
|
+
const onDoc = (e) => {
|
|
4114
|
+
const t = e.target;
|
|
4115
|
+
if (wrapperRef.current?.contains(t)) return;
|
|
4116
|
+
if (menuRef.current?.contains(t)) return;
|
|
4117
|
+
setOpen(false);
|
|
4118
|
+
};
|
|
4119
|
+
const onKey = (e) => {
|
|
4120
|
+
if (e.key === "Escape") setOpen(false);
|
|
4121
|
+
};
|
|
4122
|
+
document.addEventListener("mousedown", onDoc);
|
|
4123
|
+
document.addEventListener("keydown", onKey);
|
|
4124
|
+
return () => {
|
|
4125
|
+
document.removeEventListener("mousedown", onDoc);
|
|
4126
|
+
document.removeEventListener("keydown", onKey);
|
|
4127
|
+
};
|
|
4128
|
+
}, [open]);
|
|
4129
|
+
useLayoutEffect(() => {
|
|
4130
|
+
if (!open) {
|
|
4131
|
+
setPos(null);
|
|
4132
|
+
return;
|
|
4133
|
+
}
|
|
4134
|
+
const update = () => {
|
|
4135
|
+
const el = triggerRef.current;
|
|
4136
|
+
if (!el) return;
|
|
4137
|
+
const r = el.getBoundingClientRect();
|
|
4138
|
+
const menuHeight = menuRef.current?.offsetHeight ?? 36 * statuses.length + 16;
|
|
4139
|
+
const menuWidth = Math.max(r.width, 180);
|
|
4140
|
+
const margin = 8;
|
|
4141
|
+
const fitsAbove = r.top - menuHeight - margin >= 0;
|
|
4142
|
+
const top = fitsAbove ? r.top - menuHeight - 4 : r.bottom + 4;
|
|
4143
|
+
const left = Math.max(margin, Math.min(window.innerWidth - menuWidth - margin, r.left));
|
|
4144
|
+
setPos({ top, left, width: menuWidth });
|
|
4145
|
+
};
|
|
4146
|
+
update();
|
|
4147
|
+
window.addEventListener("resize", update);
|
|
4148
|
+
window.addEventListener("scroll", update, true);
|
|
4149
|
+
return () => {
|
|
4150
|
+
window.removeEventListener("resize", update);
|
|
4151
|
+
window.removeEventListener("scroll", update, true);
|
|
4152
|
+
};
|
|
4153
|
+
}, [open, statuses.length]);
|
|
4154
|
+
const choose = useCallback(async (next) => {
|
|
4155
|
+
if (busy) return;
|
|
4156
|
+
if (next.value === (current ?? currentDef.value)) {
|
|
4157
|
+
setOpen(false);
|
|
4158
|
+
return;
|
|
4159
|
+
}
|
|
4160
|
+
if (beforeChange) {
|
|
4161
|
+
try {
|
|
4162
|
+
const ok = await beforeChange({
|
|
4163
|
+
recordId,
|
|
4164
|
+
scope,
|
|
4165
|
+
from: current,
|
|
4166
|
+
to: next.value
|
|
4167
|
+
});
|
|
4168
|
+
if (ok === false) {
|
|
4169
|
+
setOpen(false);
|
|
4170
|
+
return;
|
|
4171
|
+
}
|
|
4172
|
+
} catch {
|
|
4173
|
+
setOpen(false);
|
|
4174
|
+
return;
|
|
4175
|
+
}
|
|
4176
|
+
}
|
|
4177
|
+
setBusy(next.value);
|
|
4178
|
+
try {
|
|
4179
|
+
await SL.app.records.update(collectionId, appId, recordId, { status: next.value }, true);
|
|
4180
|
+
onTelemetry?.({ from: current, to: next.value });
|
|
4181
|
+
onChanged?.(next.value);
|
|
4182
|
+
} catch (err) {
|
|
4183
|
+
console.warn("[LifecycleStatusMenu] update failed", err);
|
|
4184
|
+
} finally {
|
|
4185
|
+
setBusy(null);
|
|
4186
|
+
setOpen(false);
|
|
4187
|
+
}
|
|
4188
|
+
}, [busy, current, currentDef.value, beforeChange, recordId, scope, SL, collectionId, appId, onChanged, onTelemetry]);
|
|
4189
|
+
const padding = size === "xs" ? "px-2 py-1" : "px-3 py-1.5";
|
|
4190
|
+
const fontSize = size === "xs" ? "0.7rem" : "0.75rem";
|
|
4191
|
+
return /* @__PURE__ */ jsxs("div", { ref: wrapperRef, className: "relative inline-flex", children: [
|
|
4192
|
+
/* @__PURE__ */ jsxs(
|
|
4193
|
+
"button",
|
|
4194
|
+
{
|
|
4195
|
+
ref: triggerRef,
|
|
4196
|
+
type: "button",
|
|
4197
|
+
className: `${padding} rounded-md border transition-colors hover:bg-[hsl(var(--ra-muted))] inline-flex items-center gap-1.5`,
|
|
4198
|
+
"aria-haspopup": "menu",
|
|
4199
|
+
"aria-expanded": open,
|
|
4200
|
+
"aria-label": i18n.lifecycleMenuLabel ?? i18n.lifecycleStatusLabel,
|
|
4201
|
+
title: i18n.lifecycleStatusHint,
|
|
4202
|
+
disabled: !!busy,
|
|
4203
|
+
style: {
|
|
4204
|
+
borderColor: "hsl(var(--ra-border))",
|
|
4205
|
+
color: "hsl(var(--ra-text))",
|
|
4206
|
+
background: "hsl(var(--ra-surface))",
|
|
4207
|
+
fontSize
|
|
4208
|
+
},
|
|
4209
|
+
onClick: (e) => {
|
|
4210
|
+
e.stopPropagation();
|
|
4211
|
+
setOpen((v) => !v);
|
|
4212
|
+
},
|
|
4213
|
+
children: [
|
|
4214
|
+
/* @__PURE__ */ jsx(ToneDot, { tone: currentDef.tone }),
|
|
4215
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: currentDef.label }),
|
|
4216
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: "w-3 h-3 opacity-60", "aria-hidden": "true" })
|
|
4217
|
+
]
|
|
4218
|
+
}
|
|
4219
|
+
),
|
|
4220
|
+
open && typeof document !== "undefined" && createPortal(
|
|
4221
|
+
/* @__PURE__ */ jsx(
|
|
4222
|
+
"div",
|
|
4223
|
+
{
|
|
4224
|
+
ref: menuRef,
|
|
4225
|
+
role: "menu",
|
|
4226
|
+
className: "ra-row-menu ra-row-menu-portal",
|
|
4227
|
+
style: pos ? { top: pos.top, left: pos.left, minWidth: pos.width } : { visibility: "hidden" },
|
|
4228
|
+
onClick: (e) => e.stopPropagation(),
|
|
4229
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
4230
|
+
children: statuses.map((s) => {
|
|
4231
|
+
const isCurrent = s.value === (current ?? currentDef.value);
|
|
4232
|
+
const Icon = s.icon;
|
|
4233
|
+
return /* @__PURE__ */ jsxs(
|
|
4234
|
+
"button",
|
|
4235
|
+
{
|
|
4236
|
+
type: "button",
|
|
4237
|
+
role: "menuitemradio",
|
|
4238
|
+
"aria-checked": isCurrent,
|
|
4239
|
+
disabled: busy !== null,
|
|
4240
|
+
className: "ra-row-menu-item",
|
|
4241
|
+
onClick: (e) => {
|
|
4242
|
+
e.stopPropagation();
|
|
4243
|
+
void choose(s);
|
|
4244
|
+
},
|
|
4245
|
+
children: [
|
|
4246
|
+
/* @__PURE__ */ jsx(ToneDot, { tone: s.tone }),
|
|
4247
|
+
Icon && /* @__PURE__ */ jsx(Icon, { className: "w-3.5 h-3.5 opacity-70" }),
|
|
4248
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 text-left", children: s.label }),
|
|
4249
|
+
isCurrent && /* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5 opacity-80", "aria-hidden": "true" }),
|
|
4250
|
+
busy === s.value && /* @__PURE__ */ jsx("span", { className: "opacity-60", children: "\u2026" })
|
|
4251
|
+
]
|
|
4252
|
+
},
|
|
4253
|
+
s.value
|
|
4254
|
+
);
|
|
4255
|
+
})
|
|
4256
|
+
}
|
|
4257
|
+
),
|
|
4258
|
+
document.body
|
|
4259
|
+
)
|
|
4260
|
+
] });
|
|
4261
|
+
};
|
|
3800
4262
|
function LoadMoreFooter({
|
|
3801
4263
|
shown,
|
|
3802
4264
|
total,
|
|
@@ -4514,6 +4976,8 @@ function RecordEditor({
|
|
|
4514
4976
|
preview,
|
|
4515
4977
|
targeting,
|
|
4516
4978
|
targetingControl,
|
|
4979
|
+
lifecycleControl,
|
|
4980
|
+
lifecycleControlFooter,
|
|
4517
4981
|
bulkActions,
|
|
4518
4982
|
footerExtra,
|
|
4519
4983
|
onBeforeDelete,
|
|
@@ -4521,6 +4985,7 @@ function RecordEditor({
|
|
|
4521
4985
|
headerSubtitle,
|
|
4522
4986
|
headerMeta,
|
|
4523
4987
|
headerLeading,
|
|
4988
|
+
headerNotice,
|
|
4524
4989
|
clipboard,
|
|
4525
4990
|
actionLabels,
|
|
4526
4991
|
actionIcons
|
|
@@ -4538,7 +5003,7 @@ function RecordEditor({
|
|
|
4538
5003
|
return Boolean(s?.facetId || s?.productId || s?.variantId || s?.batchId);
|
|
4539
5004
|
})();
|
|
4540
5005
|
const hasLeftContent = Boolean(headerLabel) || hasBreadcrumb || Boolean(headerLeading);
|
|
4541
|
-
const hasRightContent = showInherited || showEmpty || Boolean(headerMeta) || Boolean(bulkActions) || Boolean(targetingControl);
|
|
5006
|
+
const hasRightContent = showInherited || showEmpty || Boolean(headerMeta) || Boolean(bulkActions) || Boolean(targetingControl) || Boolean(lifecycleControl);
|
|
4542
5007
|
const showHeader = hasLeftContent || hasRightContent;
|
|
4543
5008
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
|
|
4544
5009
|
showHeader && /* @__PURE__ */ jsxs(
|
|
@@ -4617,12 +5082,14 @@ function RecordEditor({
|
|
|
4617
5082
|
}
|
|
4618
5083
|
),
|
|
4619
5084
|
bulkActions && /* @__PURE__ */ jsx(BulkActionsMenu, { ...bulkActions, i18n }),
|
|
5085
|
+
lifecycleControl,
|
|
4620
5086
|
targetingControl
|
|
4621
5087
|
] })
|
|
4622
5088
|
]
|
|
4623
5089
|
}
|
|
4624
5090
|
),
|
|
4625
5091
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-5 py-4", children: [
|
|
5092
|
+
headerNotice,
|
|
4626
5093
|
targeting,
|
|
4627
5094
|
children,
|
|
4628
5095
|
preview
|
|
@@ -4658,6 +5125,7 @@ function RecordEditor({
|
|
|
4658
5125
|
icon: DeleteIcon
|
|
4659
5126
|
}
|
|
4660
5127
|
),
|
|
5128
|
+
lifecycleControlFooter,
|
|
4661
5129
|
clipboard && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4662
5130
|
/* @__PURE__ */ jsxs(
|
|
4663
5131
|
"button",
|
|
@@ -5186,21 +5654,21 @@ var ProductDrillDown = ({
|
|
|
5186
5654
|
children: tabs.map((t) => {
|
|
5187
5655
|
const meta = TAB_META[t];
|
|
5188
5656
|
const Icon = meta.icon;
|
|
5189
|
-
const
|
|
5657
|
+
const isActive2 = active === t;
|
|
5190
5658
|
const label = t === "product" ? productLabel : meta.label;
|
|
5191
5659
|
return /* @__PURE__ */ jsxs(
|
|
5192
5660
|
"button",
|
|
5193
5661
|
{
|
|
5194
5662
|
type: "button",
|
|
5195
5663
|
role: "tab",
|
|
5196
|
-
"aria-selected":
|
|
5664
|
+
"aria-selected": isActive2,
|
|
5197
5665
|
onClick: () => onChange(t),
|
|
5198
5666
|
className: cn(
|
|
5199
5667
|
"flex items-center gap-1.5 px-3 py-2 text-xs border-b-2 -mb-px transition-colors",
|
|
5200
|
-
|
|
5668
|
+
isActive2 ? "font-medium" : "opacity-60 hover:opacity-100"
|
|
5201
5669
|
),
|
|
5202
5670
|
style: {
|
|
5203
|
-
borderColor:
|
|
5671
|
+
borderColor: isActive2 ? "hsl(var(--ra-accent))" : "transparent",
|
|
5204
5672
|
color: "hsl(var(--ra-text))"
|
|
5205
5673
|
},
|
|
5206
5674
|
children: [
|
|
@@ -5225,7 +5693,7 @@ var ProductDrillDown = ({
|
|
|
5225
5693
|
childLoading && /* @__PURE__ */ jsx("div", { className: "p-3 space-y-2", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx("div", { className: "h-9 rounded animate-pulse", style: { background: "hsl(var(--ra-muted))" } }, i)) }),
|
|
5226
5694
|
!childLoading && childList.length === 0 && /* @__PURE__ */ jsx("div", { className: "p-4 text-xs", style: { color: "hsl(var(--ra-muted-text))" }, children: childEmptyLabel }),
|
|
5227
5695
|
!childLoading && childList.length > 0 && /* @__PURE__ */ jsx("ul", { className: "divide-y", style: { borderColor: "hsl(var(--ra-border))" }, children: childList.map((c) => {
|
|
5228
|
-
const
|
|
5696
|
+
const isActive2 = c.id === selectedChildId;
|
|
5229
5697
|
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
5230
5698
|
"button",
|
|
5231
5699
|
{
|
|
@@ -5233,7 +5701,7 @@ var ProductDrillDown = ({
|
|
|
5233
5701
|
onClick: () => onSelectChild(c.id),
|
|
5234
5702
|
className: cn(
|
|
5235
5703
|
"w-full text-left px-3 py-2 transition-colors hover:bg-[hsl(var(--ra-muted))]",
|
|
5236
|
-
|
|
5704
|
+
isActive2 && "ra-row-active"
|
|
5237
5705
|
),
|
|
5238
5706
|
children: [
|
|
5239
5707
|
/* @__PURE__ */ jsx("div", { className: "text-sm truncate", style: { color: "hsl(var(--ra-text))" }, children: c.name }),
|
|
@@ -5344,21 +5812,21 @@ var TabbedPreview = ({
|
|
|
5344
5812
|
style: { borderColor: "hsl(var(--ra-border))" },
|
|
5345
5813
|
children: [
|
|
5346
5814
|
["editor", "preview"].map((t) => {
|
|
5347
|
-
const
|
|
5815
|
+
const isActive2 = tab === t;
|
|
5348
5816
|
const lbl = t === "editor" ? i18n?.editor ?? "Editor" : i18n?.preview ?? "Preview";
|
|
5349
5817
|
return /* @__PURE__ */ jsx(
|
|
5350
5818
|
"button",
|
|
5351
5819
|
{
|
|
5352
5820
|
type: "button",
|
|
5353
5821
|
role: "tab",
|
|
5354
|
-
"aria-selected":
|
|
5822
|
+
"aria-selected": isActive2,
|
|
5355
5823
|
onClick: () => setTab(t),
|
|
5356
5824
|
className: cn(
|
|
5357
5825
|
"px-3 py-2 text-xs border-b-2 -mb-px transition-colors",
|
|
5358
|
-
|
|
5826
|
+
isActive2 ? "font-medium" : "opacity-60 hover:opacity-100"
|
|
5359
5827
|
),
|
|
5360
5828
|
style: {
|
|
5361
|
-
borderColor:
|
|
5829
|
+
borderColor: isActive2 ? "hsl(var(--ra-accent))" : "transparent",
|
|
5362
5830
|
color: "hsl(var(--ra-text))"
|
|
5363
5831
|
},
|
|
5364
5832
|
children: lbl
|
|
@@ -7096,6 +7564,117 @@ var RuleGroupEditDialog = ({
|
|
|
7096
7564
|
document.body
|
|
7097
7565
|
);
|
|
7098
7566
|
};
|
|
7567
|
+
var fmt = (s, vars) => s.replace(/\{(\w+)\}/g, (_, k) => String(vars[k] ?? ""));
|
|
7568
|
+
function SingletonConflictBanner({
|
|
7569
|
+
conflictCount,
|
|
7570
|
+
duplicateCount,
|
|
7571
|
+
onResolve,
|
|
7572
|
+
onArchiveDuplicates,
|
|
7573
|
+
onDeleteDuplicates,
|
|
7574
|
+
i18n
|
|
7575
|
+
}) {
|
|
7576
|
+
const [busy, setBusy] = useState(null);
|
|
7577
|
+
const message = conflictCount === 1 ? fmt(i18n.bodyOne, { n: duplicateCount }) : fmt(i18n.bodyMany, { slots: conflictCount, dups: duplicateCount });
|
|
7578
|
+
const showActions = !!(onArchiveDuplicates || onDeleteDuplicates);
|
|
7579
|
+
const runArchive = async () => {
|
|
7580
|
+
if (!onArchiveDuplicates) return;
|
|
7581
|
+
setBusy("archive");
|
|
7582
|
+
try {
|
|
7583
|
+
await onArchiveDuplicates();
|
|
7584
|
+
} finally {
|
|
7585
|
+
setBusy(null);
|
|
7586
|
+
}
|
|
7587
|
+
};
|
|
7588
|
+
const runDelete = async () => {
|
|
7589
|
+
if (!onDeleteDuplicates) return;
|
|
7590
|
+
if (typeof window !== "undefined" && !window.confirm(fmt(i18n.deleteConfirm, { n: duplicateCount }))) {
|
|
7591
|
+
return;
|
|
7592
|
+
}
|
|
7593
|
+
setBusy("delete");
|
|
7594
|
+
try {
|
|
7595
|
+
await onDeleteDuplicates();
|
|
7596
|
+
} finally {
|
|
7597
|
+
setBusy(null);
|
|
7598
|
+
}
|
|
7599
|
+
};
|
|
7600
|
+
return /* @__PURE__ */ jsxs(
|
|
7601
|
+
"div",
|
|
7602
|
+
{
|
|
7603
|
+
role: "alert",
|
|
7604
|
+
className: "px-3 py-2 border-b text-xs flex items-start gap-2 flex-wrap",
|
|
7605
|
+
style: {
|
|
7606
|
+
background: "hsl(var(--ra-danger, 0 70% 45%) / 0.08)",
|
|
7607
|
+
borderColor: "hsl(var(--ra-danger, 0 70% 45%) / 0.35)",
|
|
7608
|
+
color: "hsl(var(--ra-text))"
|
|
7609
|
+
},
|
|
7610
|
+
children: [
|
|
7611
|
+
/* @__PURE__ */ jsx(
|
|
7612
|
+
AlertTriangle,
|
|
7613
|
+
{
|
|
7614
|
+
"aria-hidden": "true",
|
|
7615
|
+
className: "w-3.5 h-3.5 shrink-0 mt-0.5",
|
|
7616
|
+
style: { color: "hsl(var(--ra-danger, 0 70% 45%))" }
|
|
7617
|
+
}
|
|
7618
|
+
),
|
|
7619
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-[10rem]", children: [
|
|
7620
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium leading-tight", children: i18n.title }),
|
|
7621
|
+
/* @__PURE__ */ jsx("div", { className: "leading-tight", style: { color: "hsl(var(--ra-muted-text))" }, children: message })
|
|
7622
|
+
] }),
|
|
7623
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 shrink-0", children: [
|
|
7624
|
+
onArchiveDuplicates && /* @__PURE__ */ jsxs(
|
|
7625
|
+
"button",
|
|
7626
|
+
{
|
|
7627
|
+
type: "button",
|
|
7628
|
+
onClick: runArchive,
|
|
7629
|
+
disabled: busy !== null,
|
|
7630
|
+
className: "ra-btn",
|
|
7631
|
+
"data-variant": "ghost",
|
|
7632
|
+
style: { fontSize: "0.7rem", padding: "0.2rem 0.5rem", display: "inline-flex", alignItems: "center", gap: "0.25rem" },
|
|
7633
|
+
children: [
|
|
7634
|
+
/* @__PURE__ */ jsx(Archive, { className: "w-3 h-3", "aria-hidden": "true" }),
|
|
7635
|
+
busy === "archive" ? "\u2026" : i18n.archiveLabel
|
|
7636
|
+
]
|
|
7637
|
+
}
|
|
7638
|
+
),
|
|
7639
|
+
onDeleteDuplicates && /* @__PURE__ */ jsxs(
|
|
7640
|
+
"button",
|
|
7641
|
+
{
|
|
7642
|
+
type: "button",
|
|
7643
|
+
onClick: runDelete,
|
|
7644
|
+
disabled: busy !== null,
|
|
7645
|
+
className: "ra-btn",
|
|
7646
|
+
"data-variant": "ghost",
|
|
7647
|
+
style: {
|
|
7648
|
+
fontSize: "0.7rem",
|
|
7649
|
+
padding: "0.2rem 0.5rem",
|
|
7650
|
+
display: "inline-flex",
|
|
7651
|
+
alignItems: "center",
|
|
7652
|
+
gap: "0.25rem",
|
|
7653
|
+
color: "hsl(var(--ra-danger, 0 70% 45%))",
|
|
7654
|
+
borderColor: "hsl(var(--ra-danger, 0 70% 45%) / 0.4)"
|
|
7655
|
+
},
|
|
7656
|
+
children: [
|
|
7657
|
+
/* @__PURE__ */ jsx(Trash2, { className: "w-3 h-3", "aria-hidden": "true" }),
|
|
7658
|
+
busy === "delete" ? "\u2026" : i18n.deleteLabel
|
|
7659
|
+
]
|
|
7660
|
+
}
|
|
7661
|
+
),
|
|
7662
|
+
!showActions && onResolve && /* @__PURE__ */ jsx(
|
|
7663
|
+
"button",
|
|
7664
|
+
{
|
|
7665
|
+
type: "button",
|
|
7666
|
+
onClick: onResolve,
|
|
7667
|
+
className: "ra-btn",
|
|
7668
|
+
"data-variant": "ghost",
|
|
7669
|
+
style: { fontSize: "0.7rem", padding: "0.2rem 0.5rem" },
|
|
7670
|
+
children: i18n.resolveLabel
|
|
7671
|
+
}
|
|
7672
|
+
)
|
|
7673
|
+
] })
|
|
7674
|
+
]
|
|
7675
|
+
}
|
|
7676
|
+
);
|
|
7677
|
+
}
|
|
7099
7678
|
var statusDot = (status) => {
|
|
7100
7679
|
switch (status) {
|
|
7101
7680
|
case "saving":
|
|
@@ -7540,20 +8119,20 @@ var EditorMountPool = ({
|
|
|
7540
8119
|
}
|
|
7541
8120
|
const visibleIds = keepMountedHidden ? ids : currentEditorId ? [currentEditorId] : [];
|
|
7542
8121
|
return /* @__PURE__ */ jsx("div", { className, style: { display: "contents" }, children: visibleIds.map((id) => {
|
|
7543
|
-
const
|
|
7544
|
-
return /* @__PURE__ */ jsx(EditorPoolSlot, { editorId: id, isActive, children: renderSlot(id) }, id);
|
|
8122
|
+
const isActive2 = id === currentEditorId;
|
|
8123
|
+
return /* @__PURE__ */ jsx(EditorPoolSlot, { editorId: id, isActive: isActive2, children: renderSlot(id) }, id);
|
|
7545
8124
|
}) });
|
|
7546
8125
|
};
|
|
7547
|
-
var EditorPoolSlot = ({ editorId, isActive, children }) => {
|
|
7548
|
-
const inertProps =
|
|
8126
|
+
var EditorPoolSlot = ({ editorId, isActive: isActive2, children }) => {
|
|
8127
|
+
const inertProps = isActive2 ? {} : { inert: "" };
|
|
7549
8128
|
return /* @__PURE__ */ jsx(
|
|
7550
8129
|
"div",
|
|
7551
8130
|
{
|
|
7552
8131
|
"data-editor-slot": editorId,
|
|
7553
|
-
"data-active":
|
|
7554
|
-
"aria-hidden":
|
|
8132
|
+
"data-active": isActive2 ? "true" : "false",
|
|
8133
|
+
"aria-hidden": isActive2 ? void 0 : true,
|
|
7555
8134
|
style: {
|
|
7556
|
-
display:
|
|
8135
|
+
display: isActive2 ? "contents" : "none"
|
|
7557
8136
|
},
|
|
7558
8137
|
...inertProps,
|
|
7559
8138
|
children
|
|
@@ -7827,8 +8406,28 @@ function RecordsAdminShellInner(props) {
|
|
|
7827
8406
|
icons: iconsOverride,
|
|
7828
8407
|
// Deep linking
|
|
7829
8408
|
deepLink,
|
|
7830
|
-
recordChangeRef
|
|
8409
|
+
recordChangeRef,
|
|
8410
|
+
activeStatuses,
|
|
8411
|
+
conflicts: conflictsConfig,
|
|
8412
|
+
lifecycle: lifecycleConfig
|
|
7831
8413
|
} = props;
|
|
8414
|
+
const lifecycleStatuses = useMemo(
|
|
8415
|
+
() => getLifecycleStatuses(lifecycleConfig),
|
|
8416
|
+
[lifecycleConfig]
|
|
8417
|
+
);
|
|
8418
|
+
const lifecycleSurface = lifecycleConfig?.surface ?? "footer";
|
|
8419
|
+
const lifecycleAutoGroup = lifecycleConfig?.autoGroup ?? true;
|
|
8420
|
+
const lifecycleDefaultStatus = lifecycleConfig?.defaultStatus;
|
|
8421
|
+
const lifecycleBeforeChange = lifecycleConfig?.beforeChange;
|
|
8422
|
+
const resolvedActiveStatuses = useMemo(
|
|
8423
|
+
() => getActiveStatusValues(lifecycleConfig, activeStatuses),
|
|
8424
|
+
[lifecycleConfig, activeStatuses]
|
|
8425
|
+
);
|
|
8426
|
+
const {
|
|
8427
|
+
archiveDuplicates: enableArchiveDuplicates = true,
|
|
8428
|
+
deleteDuplicates: enableDeleteDuplicates = true,
|
|
8429
|
+
archivedStatus: archivedStatusValue = "archived"
|
|
8430
|
+
} = conflictsConfig ?? {};
|
|
7832
8431
|
const {
|
|
7833
8432
|
show: showHeader,
|
|
7834
8433
|
title,
|
|
@@ -8047,7 +8646,8 @@ function RecordsAdminShellInner(props) {
|
|
|
8047
8646
|
selectedProductId,
|
|
8048
8647
|
drillTab,
|
|
8049
8648
|
classify: classify3,
|
|
8050
|
-
pageSize: railPageSize
|
|
8649
|
+
pageSize: railPageSize,
|
|
8650
|
+
activeStatuses
|
|
8051
8651
|
});
|
|
8052
8652
|
const {
|
|
8053
8653
|
search,
|
|
@@ -8066,12 +8666,14 @@ function RecordsAdminShellInner(props) {
|
|
|
8066
8666
|
const ruleScopedList = useRecordList({
|
|
8067
8667
|
ctx,
|
|
8068
8668
|
scopeKind: "rule",
|
|
8069
|
-
enabled: true
|
|
8669
|
+
enabled: true,
|
|
8670
|
+
activeStatuses
|
|
8070
8671
|
});
|
|
8071
8672
|
const globalScopedList = useRecordList({
|
|
8072
8673
|
ctx,
|
|
8073
8674
|
scopeKind: "collection",
|
|
8074
|
-
enabled: cardinality === "singleton"
|
|
8675
|
+
enabled: cardinality === "singleton",
|
|
8676
|
+
activeStatuses
|
|
8075
8677
|
});
|
|
8076
8678
|
const pinnedProduct = useSingleProduct({
|
|
8077
8679
|
SL,
|
|
@@ -8083,6 +8685,20 @@ function RecordsAdminShellInner(props) {
|
|
|
8083
8685
|
if (pinnedProduct.item) return [pinnedProduct.item];
|
|
8084
8686
|
return productBrowse.items;
|
|
8085
8687
|
}, [pinnedProduct.item, productBrowse.items]);
|
|
8688
|
+
const singletonConflicts = useMemo(
|
|
8689
|
+
() => cardinality === "singleton" ? groupSingletonConflicts(recordList.items, activeStatuses) : [],
|
|
8690
|
+
[cardinality, recordList.items, activeStatuses]
|
|
8691
|
+
);
|
|
8692
|
+
const hasSingletonConflicts = singletonConflicts.length > 0;
|
|
8693
|
+
const totalDuplicateCount = useMemo(
|
|
8694
|
+
() => singletonConflicts.reduce((sum, c) => sum + c.duplicates.length, 0),
|
|
8695
|
+
[singletonConflicts]
|
|
8696
|
+
);
|
|
8697
|
+
const activeRecordIdsBySlot = useMemo(() => {
|
|
8698
|
+
const map = /* @__PURE__ */ new Map();
|
|
8699
|
+
for (const c of singletonConflicts) map.set(c.key, c.active.id);
|
|
8700
|
+
return map;
|
|
8701
|
+
}, [singletonConflicts]);
|
|
8086
8702
|
useEffect(() => {
|
|
8087
8703
|
if (activeScope !== "product") return;
|
|
8088
8704
|
if (selectedProductId) return;
|
|
@@ -8102,8 +8718,16 @@ function RecordsAdminShellInner(props) {
|
|
|
8102
8718
|
return;
|
|
8103
8719
|
}
|
|
8104
8720
|
const first = recordList.items[0];
|
|
8105
|
-
if (first?.id)
|
|
8106
|
-
|
|
8721
|
+
if (!first?.id) return;
|
|
8722
|
+
if (cardinality === "singleton") {
|
|
8723
|
+
const conflict = findConflictForRecord(first.id, singletonConflicts);
|
|
8724
|
+
if (conflict?.active.id) {
|
|
8725
|
+
setSelectedRecordId(conflict.active.id);
|
|
8726
|
+
return;
|
|
8727
|
+
}
|
|
8728
|
+
}
|
|
8729
|
+
setSelectedRecordId(first.id);
|
|
8730
|
+
}, [activeScope, selectedRecordId, recordList.items, cardinality, ruleWizardStep, draftKind, isReconcilingRecordSelection, singletonConflicts]);
|
|
8107
8731
|
const editingScopes = useEditingScope({
|
|
8108
8732
|
activeScope,
|
|
8109
8733
|
cardinality,
|
|
@@ -8135,6 +8759,26 @@ function RecordsAdminShellInner(props) {
|
|
|
8135
8759
|
toSummary: itemToSummary,
|
|
8136
8760
|
pageSize: itemsPageSize
|
|
8137
8761
|
});
|
|
8762
|
+
const autoLifecycleGroupBy = useMemo(() => {
|
|
8763
|
+
if (!isCollection) return void 0;
|
|
8764
|
+
if (!lifecycleAutoGroup) return void 0;
|
|
8765
|
+
if (groupBy) return void 0;
|
|
8766
|
+
if (!hasMixedLifecycle(collectionItems.items, resolvedActiveStatuses)) {
|
|
8767
|
+
return void 0;
|
|
8768
|
+
}
|
|
8769
|
+
return (record) => {
|
|
8770
|
+
const def = resolveLifecycleStatus(record, lifecycleConfig);
|
|
8771
|
+
return { key: def.value, label: def.label, tone: def.tone };
|
|
8772
|
+
};
|
|
8773
|
+
}, [
|
|
8774
|
+
isCollection,
|
|
8775
|
+
lifecycleAutoGroup,
|
|
8776
|
+
groupBy,
|
|
8777
|
+
collectionItems.items,
|
|
8778
|
+
resolvedActiveStatuses,
|
|
8779
|
+
lifecycleConfig
|
|
8780
|
+
]);
|
|
8781
|
+
const lcGroupBy = groupBy ?? autoLifecycleGroupBy;
|
|
8138
8782
|
useEffect(() => {
|
|
8139
8783
|
if (skipNextItemResetRef.current) {
|
|
8140
8784
|
skipNextItemResetRef.current = false;
|
|
@@ -8142,32 +8786,32 @@ function RecordsAdminShellInner(props) {
|
|
|
8142
8786
|
}
|
|
8143
8787
|
setSelectedItemId(null);
|
|
8144
8788
|
}, [editingScope?.raw]);
|
|
8145
|
-
const isLifecycleRailEarly = (activeScope === "all" || activeScope === "collection") && isCollection && !!
|
|
8789
|
+
const isLifecycleRailEarly = (activeScope === "all" || activeScope === "collection") && isCollection && !!lcGroupBy;
|
|
8146
8790
|
const lifecycleBucketLabel = useMemo(() => {
|
|
8147
|
-
if (!isLifecycleRailEarly || !selectedLifecycleKey || !
|
|
8791
|
+
if (!isLifecycleRailEarly || !selectedLifecycleKey || !lcGroupBy) return null;
|
|
8148
8792
|
for (const it of collectionItems.items) {
|
|
8149
|
-
const g =
|
|
8793
|
+
const g = lcGroupBy(it);
|
|
8150
8794
|
if (g && g.key === selectedLifecycleKey) return g.label ?? null;
|
|
8151
8795
|
}
|
|
8152
8796
|
return null;
|
|
8153
|
-
}, [isLifecycleRailEarly, selectedLifecycleKey,
|
|
8797
|
+
}, [isLifecycleRailEarly, selectedLifecycleKey, lcGroupBy, collectionItems.items]);
|
|
8154
8798
|
const scopedCollectionItemsList = useMemo(() => {
|
|
8155
|
-
if (!isLifecycleRailEarly || !selectedLifecycleKey || !
|
|
8799
|
+
if (!isLifecycleRailEarly || !selectedLifecycleKey || !lcGroupBy) return collectionItems.items;
|
|
8156
8800
|
return collectionItems.items.filter((it) => {
|
|
8157
|
-
const g =
|
|
8801
|
+
const g = lcGroupBy(it);
|
|
8158
8802
|
return g?.key === selectedLifecycleKey;
|
|
8159
8803
|
});
|
|
8160
|
-
}, [isLifecycleRailEarly, selectedLifecycleKey,
|
|
8804
|
+
}, [isLifecycleRailEarly, selectedLifecycleKey, lcGroupBy, collectionItems.items]);
|
|
8161
8805
|
useEffect(() => {
|
|
8162
|
-
if (!isLifecycleRailEarly || !
|
|
8806
|
+
if (!isLifecycleRailEarly || !lcGroupBy) return;
|
|
8163
8807
|
if (selectedLifecycleKey || !selectedItemId) return;
|
|
8164
8808
|
const row = collectionItems.items.find(
|
|
8165
8809
|
(it) => it.itemId === selectedItemId || it.id === selectedItemId
|
|
8166
8810
|
);
|
|
8167
8811
|
if (!row) return;
|
|
8168
|
-
const g =
|
|
8812
|
+
const g = lcGroupBy(row);
|
|
8169
8813
|
if (g?.key) setSelectedLifecycleKey(g.key);
|
|
8170
|
-
}, [isLifecycleRailEarly,
|
|
8814
|
+
}, [isLifecycleRailEarly, lcGroupBy, selectedItemId, selectedLifecycleKey, collectionItems.items, setSelectedLifecycleKey]);
|
|
8171
8815
|
const scopedCollectionItems = useMemo(() => ({
|
|
8172
8816
|
...collectionItems,
|
|
8173
8817
|
items: scopedCollectionItemsList
|
|
@@ -8302,6 +8946,15 @@ function RecordsAdminShellInner(props) {
|
|
|
8302
8946
|
return JSON.parse(JSON.stringify(globalSeedSource));
|
|
8303
8947
|
}
|
|
8304
8948
|
}
|
|
8949
|
+
if (draftKind === "paste") {
|
|
8950
|
+
const entry = wizardClipboard.entry;
|
|
8951
|
+
if (!entry) return defaultData?.() ?? {};
|
|
8952
|
+
try {
|
|
8953
|
+
return structuredClone(entry.value);
|
|
8954
|
+
} catch {
|
|
8955
|
+
return JSON.parse(JSON.stringify(entry.value));
|
|
8956
|
+
}
|
|
8957
|
+
}
|
|
8305
8958
|
return defaultData?.() ?? {};
|
|
8306
8959
|
}, [
|
|
8307
8960
|
isCollection,
|
|
@@ -8312,7 +8965,8 @@ function RecordsAdminShellInner(props) {
|
|
|
8312
8965
|
directGlobalSeedData,
|
|
8313
8966
|
resolvedGlobalSeed.data,
|
|
8314
8967
|
onCopyOverride,
|
|
8315
|
-
defaultData
|
|
8968
|
+
defaultData,
|
|
8969
|
+
wizardClipboard.entry
|
|
8316
8970
|
]);
|
|
8317
8971
|
const refetchAll = useCallback(async () => {
|
|
8318
8972
|
await Promise.all([
|
|
@@ -8344,6 +8998,7 @@ function RecordsAdminShellInner(props) {
|
|
|
8344
8998
|
},
|
|
8345
8999
|
defaultData,
|
|
8346
9000
|
deriveDraftLabel,
|
|
9001
|
+
defaultStatus: lifecycleDefaultStatus,
|
|
8347
9002
|
onSaved: async (isCreate, savedRecordId) => {
|
|
8348
9003
|
onTelemetry?.({ type: "record.save", recordType, ref: editingTargetScope?.raw ?? "", isCreate });
|
|
8349
9004
|
const savedFromRuleWizard = ruleWizardStep !== null;
|
|
@@ -8521,8 +9176,7 @@ function RecordsAdminShellInner(props) {
|
|
|
8521
9176
|
const rowClipboard = shellClipboard.rowClipboard;
|
|
8522
9177
|
const wrappedRecordActions = recordActions ? (record) => {
|
|
8523
9178
|
const list = recordActions(record, record.scope);
|
|
8524
|
-
|
|
8525
|
-
return list.map((a) => ({
|
|
9179
|
+
const baseList = (list ?? []).map((a) => ({
|
|
8526
9180
|
...a,
|
|
8527
9181
|
onAction: () => {
|
|
8528
9182
|
onTelemetry?.({
|
|
@@ -8534,7 +9188,37 @@ function RecordsAdminShellInner(props) {
|
|
|
8534
9188
|
return a.onAction();
|
|
8535
9189
|
}
|
|
8536
9190
|
}));
|
|
8537
|
-
|
|
9191
|
+
const lifecycleAction = buildLifecycleAction(record);
|
|
9192
|
+
const out = lifecycleAction ? [...baseList, lifecycleAction] : baseList;
|
|
9193
|
+
return out.length > 0 ? out : void 0;
|
|
9194
|
+
} : (record) => {
|
|
9195
|
+
const a = buildLifecycleAction(record);
|
|
9196
|
+
return a ? [a] : void 0;
|
|
9197
|
+
};
|
|
9198
|
+
function buildLifecycleAction(record) {
|
|
9199
|
+
if (!record.id) return null;
|
|
9200
|
+
const allow = activeStatuses ?? ["active"];
|
|
9201
|
+
const s = record.lifecycleStatus;
|
|
9202
|
+
const active = s == null || s === "" || allow.includes(s);
|
|
9203
|
+
const next = active ? "archived" : "active";
|
|
9204
|
+
const label2 = active ? i18n.actionArchive : i18n.actionRestore;
|
|
9205
|
+
return {
|
|
9206
|
+
key: active ? "lifecycle.archive" : "lifecycle.restore",
|
|
9207
|
+
label: label2,
|
|
9208
|
+
onAction: async () => {
|
|
9209
|
+
try {
|
|
9210
|
+
await SL.app.records.update(collectionId, appId, record.id, { status: next }, true);
|
|
9211
|
+
recordList.refetch();
|
|
9212
|
+
if (cardinality === "singleton") {
|
|
9213
|
+
ruleScopedList.refetch();
|
|
9214
|
+
globalScopedList.refetch();
|
|
9215
|
+
}
|
|
9216
|
+
} catch (err) {
|
|
9217
|
+
console.warn("[RecordsAdminShell] lifecycle update failed", err);
|
|
9218
|
+
}
|
|
9219
|
+
}
|
|
9220
|
+
};
|
|
9221
|
+
}
|
|
8538
9222
|
const baseScopeRef = editingScope?.raw ?? "";
|
|
8539
9223
|
const itemNounLabel = itemNoun || "item";
|
|
8540
9224
|
const {
|
|
@@ -8598,6 +9282,70 @@ function RecordsAdminShellInner(props) {
|
|
|
8598
9282
|
i18n
|
|
8599
9283
|
}
|
|
8600
9284
|
) : null;
|
|
9285
|
+
const conflictForCurrent = selectedRecordId && selectedRecordId !== DRAFT_ID3 ? findConflictForRecord(selectedRecordId, singletonConflicts) : null;
|
|
9286
|
+
const editorHeaderNotice = conflictForCurrent ? /* @__PURE__ */ jsxs(
|
|
9287
|
+
"div",
|
|
9288
|
+
{
|
|
9289
|
+
role: "alert",
|
|
9290
|
+
className: "mb-3 px-3 py-2 rounded-md text-xs flex items-start gap-2",
|
|
9291
|
+
style: {
|
|
9292
|
+
background: "hsl(var(--ra-danger, 0 70% 45%) / 0.08)",
|
|
9293
|
+
border: "1px solid hsl(var(--ra-danger, 0 70% 45%) / 0.35)",
|
|
9294
|
+
color: "hsl(var(--ra-text))"
|
|
9295
|
+
},
|
|
9296
|
+
children: [
|
|
9297
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u26A0" }),
|
|
9298
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
9299
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium", children: `This record is 1 of ${conflictForCurrent.records.length} sharing the same slot.` }),
|
|
9300
|
+
/* @__PURE__ */ jsx("div", { style: { color: "hsl(var(--ra-muted-text))" }, children: conflictForCurrent.active.id === selectedRecordId ? "It is the active record \u2014 duplicates below will be ignored at runtime. Delete the duplicates to clean this up." : `Active record: "${conflictForCurrent.active.label}". This duplicate is ignored at runtime \u2014 delete it (or the active one) to resolve.` })
|
|
9301
|
+
] })
|
|
9302
|
+
]
|
|
9303
|
+
}
|
|
9304
|
+
) : null;
|
|
9305
|
+
const selectedSummary = selectedRecordId && selectedRecordId !== DRAFT_ID3 ? recordList.items.find((r) => r.id === selectedRecordId) ?? globalScopedList.items.find((r) => r.id === selectedRecordId) ?? ruleScopedList.items.find((r) => r.id === selectedRecordId) : void 0;
|
|
9306
|
+
const editorLifecycleControl = selectedSummary?.id ? /* @__PURE__ */ jsx(
|
|
9307
|
+
LifecycleStatusControl,
|
|
9308
|
+
{
|
|
9309
|
+
SL,
|
|
9310
|
+
collectionId,
|
|
9311
|
+
appId,
|
|
9312
|
+
recordId: selectedSummary.id,
|
|
9313
|
+
current: selectedSummary.lifecycleStatus,
|
|
9314
|
+
i18n,
|
|
9315
|
+
onChanged: () => {
|
|
9316
|
+
void recordList.refetch();
|
|
9317
|
+
}
|
|
9318
|
+
}
|
|
9319
|
+
) : null;
|
|
9320
|
+
const editorLifecycleFooter = selectedSummary?.id && (lifecycleSurface === "footer" || lifecycleSurface === "both") ? /* @__PURE__ */ jsx(
|
|
9321
|
+
LifecycleStatusMenu,
|
|
9322
|
+
{
|
|
9323
|
+
SL,
|
|
9324
|
+
collectionId,
|
|
9325
|
+
appId,
|
|
9326
|
+
recordId: selectedSummary.id,
|
|
9327
|
+
scope: selectedSummary.scope,
|
|
9328
|
+
current: selectedSummary.lifecycleStatus,
|
|
9329
|
+
statuses: lifecycleStatuses,
|
|
9330
|
+
i18n,
|
|
9331
|
+
beforeChange: lifecycleBeforeChange,
|
|
9332
|
+
onTelemetry: (e) => onTelemetry?.({
|
|
9333
|
+
type: "lifecycle.change",
|
|
9334
|
+
recordType,
|
|
9335
|
+
ref: selectedSummary.id,
|
|
9336
|
+
from: e.from,
|
|
9337
|
+
to: e.to
|
|
9338
|
+
}),
|
|
9339
|
+
onChanged: () => {
|
|
9340
|
+
void recordList.refetch();
|
|
9341
|
+
if (cardinality === "singleton") {
|
|
9342
|
+
ruleScopedList.refetch();
|
|
9343
|
+
globalScopedList.refetch();
|
|
9344
|
+
}
|
|
9345
|
+
}
|
|
9346
|
+
}
|
|
9347
|
+
) : null;
|
|
9348
|
+
const headerLifecycleControl = lifecycleSurface === "header" || lifecycleSurface === "both" ? editorLifecycleControl : null;
|
|
8601
9349
|
const baseEditor = (extraFooter, inlinePreviewBody) => /* @__PURE__ */ jsx(
|
|
8602
9350
|
RecordEditor,
|
|
8603
9351
|
{
|
|
@@ -8635,11 +9383,14 @@ function RecordsAdminShellInner(props) {
|
|
|
8635
9383
|
onCustomise: () => setTargetingExpandNonce((n) => n + 1)
|
|
8636
9384
|
}
|
|
8637
9385
|
) : void 0,
|
|
9386
|
+
lifecycleControl: headerLifecycleControl,
|
|
9387
|
+
lifecycleControlFooter: editorLifecycleFooter,
|
|
8638
9388
|
onBeforeDelete: onBeforeDelete && editingTargetScope ? () => onBeforeDelete(editingTargetScope) : void 0,
|
|
8639
9389
|
headerLabel: editorHeaderLabel,
|
|
8640
9390
|
headerSubtitle: editorHeaderSubtitle,
|
|
8641
9391
|
headerMeta: editorHeaderMeta,
|
|
8642
9392
|
headerLeading: itemNav,
|
|
9393
|
+
headerNotice: editorHeaderNotice,
|
|
8643
9394
|
clipboard: editorClipboard,
|
|
8644
9395
|
actionLabels,
|
|
8645
9396
|
actionIcons,
|
|
@@ -8940,7 +9691,7 @@ function RecordsAdminShellInner(props) {
|
|
|
8940
9691
|
void runWithGuard(() => {
|
|
8941
9692
|
if (activeScope !== "product") setActiveScope("product");
|
|
8942
9693
|
setSelectedRecordId(DRAFT_ID3);
|
|
8943
|
-
setDraftKind(seed === "global" ? "global" : "item");
|
|
9694
|
+
setDraftKind(seed === "global" ? "global" : seed === "paste" ? "paste" : "item");
|
|
8944
9695
|
});
|
|
8945
9696
|
}, [runWithGuard, activeScope]);
|
|
8946
9697
|
const filteredRuleItems = useMemo(
|
|
@@ -9035,13 +9786,13 @@ function RecordsAdminShellInner(props) {
|
|
|
9035
9786
|
}),
|
|
9036
9787
|
[i18n.itemsAllLabel, collectionItems.items.length, itemNoun]
|
|
9037
9788
|
);
|
|
9038
|
-
const isLifecycleRail = (isAllTab || isGlobalTab) && isCollection && !!
|
|
9789
|
+
const isLifecycleRail = (isAllTab || isGlobalTab) && isCollection && !!lcGroupBy;
|
|
9039
9790
|
const lifecycleBuckets = useMemo(() => {
|
|
9040
|
-
if (!isLifecycleRail || !
|
|
9791
|
+
if (!isLifecycleRail || !lcGroupBy) return [];
|
|
9041
9792
|
const map = /* @__PURE__ */ new Map();
|
|
9042
9793
|
const order = [];
|
|
9043
9794
|
for (const item of collectionItems.items) {
|
|
9044
|
-
const g =
|
|
9795
|
+
const g = lcGroupBy(item) ?? { key: "__other", label: "Other" };
|
|
9045
9796
|
let bucket = map.get(g.key);
|
|
9046
9797
|
if (!bucket) {
|
|
9047
9798
|
bucket = { key: g.key, label: g.label, icon: g.icon, tone: g.tone, items: [] };
|
|
@@ -9050,8 +9801,9 @@ function RecordsAdminShellInner(props) {
|
|
|
9050
9801
|
}
|
|
9051
9802
|
bucket.items.push(item);
|
|
9052
9803
|
}
|
|
9053
|
-
|
|
9054
|
-
|
|
9804
|
+
const sortFn = !groupBy ? compareLifecycleBuckets : (a, b) => a.localeCompare(b);
|
|
9805
|
+
return order.sort(sortFn).map((k) => map.get(k));
|
|
9806
|
+
}, [isLifecycleRail, lcGroupBy, groupBy, collectionItems.items]);
|
|
9055
9807
|
const LIFECYCLE_PREFIX = "lifecycle:";
|
|
9056
9808
|
const lifecycleRows = useMemo(() => {
|
|
9057
9809
|
if (!isLifecycleRail) return [];
|
|
@@ -9101,15 +9853,47 @@ function RecordsAdminShellInner(props) {
|
|
|
9101
9853
|
lifecycleSeededRef.current = true;
|
|
9102
9854
|
}, [isLifecycleRail, defaultGroupKey, lifecycleBuckets, selectedLifecycleKey, setSelectedLifecycleKey]);
|
|
9103
9855
|
const filteredCollectionItems = useMemo(() => {
|
|
9104
|
-
if (!isLifecycleRail || !selectedLifecycleKey || !
|
|
9856
|
+
if (!isLifecycleRail || !selectedLifecycleKey || !lcGroupBy) return collectionItems.items;
|
|
9105
9857
|
return collectionItems.items.filter((it) => {
|
|
9106
|
-
const g =
|
|
9858
|
+
const g = lcGroupBy(it) ?? { key: "__other" };
|
|
9107
9859
|
return g.key === selectedLifecycleKey;
|
|
9108
9860
|
});
|
|
9109
|
-
}, [isLifecycleRail, selectedLifecycleKey,
|
|
9861
|
+
}, [isLifecycleRail, selectedLifecycleKey, lcGroupBy, collectionItems.items]);
|
|
9110
9862
|
const leftItems = isProductTab ? productListItems : isRuleTab ? applyFacetBrowseFilter(
|
|
9111
9863
|
isCollection ? collectionRuleRailItems : filteredRuleItems
|
|
9112
9864
|
) : isLifecycleRail ? lifecycleRows : (isGlobalTab || isAllTab) && isCollection ? [collectionGlobalAllRow] : isRecordsTab ? applyFacetBrowseFilter(recordList.items) : [];
|
|
9865
|
+
const railShowsHistoryDisclosure = isRecordsTab && !isLifecycleRail && !((isGlobalTab || isAllTab) && isCollection);
|
|
9866
|
+
const filteredLeftItems = useMemo(() => {
|
|
9867
|
+
if (!railShowsHistoryDisclosure) return leftItems;
|
|
9868
|
+
return leftItems.filter((r) => {
|
|
9869
|
+
const s = r.lifecycleStatus;
|
|
9870
|
+
if (s == null || s === "") return true;
|
|
9871
|
+
const allow = activeStatuses ?? ["active"];
|
|
9872
|
+
return allow.includes(s);
|
|
9873
|
+
});
|
|
9874
|
+
}, [leftItems, railShowsHistoryDisclosure, activeStatuses]);
|
|
9875
|
+
const railHistoryBySlot = useMemo(() => {
|
|
9876
|
+
if (!railShowsHistoryDisclosure) return void 0;
|
|
9877
|
+
return recordList.historyBySlot;
|
|
9878
|
+
}, [railShowsHistoryDisclosure, recordList.historyBySlot]);
|
|
9879
|
+
const decoratedLeftItems = useMemo(() => {
|
|
9880
|
+
if (!hasSingletonConflicts) return filteredLeftItems;
|
|
9881
|
+
return filteredLeftItems.map((row) => {
|
|
9882
|
+
if (!row.id) return row;
|
|
9883
|
+
const key = slotKey(row);
|
|
9884
|
+
const activeId = activeRecordIdsBySlot.get(key);
|
|
9885
|
+
if (activeId === void 0) return row;
|
|
9886
|
+
const isActive2 = row.id === activeId;
|
|
9887
|
+
const conflictBadge = [{
|
|
9888
|
+
label: isActive2 ? "Active" : "Duplicate",
|
|
9889
|
+
tone: isActive2 ? "success" : "warning"
|
|
9890
|
+
}];
|
|
9891
|
+
return {
|
|
9892
|
+
...row,
|
|
9893
|
+
badges: [...conflictBadge, ...row.badges ?? []]
|
|
9894
|
+
};
|
|
9895
|
+
});
|
|
9896
|
+
}, [filteredLeftItems, hasSingletonConflicts, activeRecordIdsBySlot]);
|
|
9113
9897
|
const leftLoading = isProductTab ? !productPinned && productBrowse.isLoading : isRecordsTab ? recordList.isLoading || probe.isLoading : false;
|
|
9114
9898
|
const leftError = isProductTab ? productBrowse.error : isRecordsTab ? recordList.error : null;
|
|
9115
9899
|
const leftSelectedId = isProductTab ? void 0 : isLifecycleRail ? `${LIFECYCLE_PREFIX}${selectedLifecycleKey ?? "__all"}` : selectedRecordId && selectedRecordId !== DRAFT_ID3 ? selectedRecordId : void 0;
|
|
@@ -9456,69 +10240,138 @@ function RecordsAdminShellInner(props) {
|
|
|
9456
10240
|
)
|
|
9457
10241
|
] })
|
|
9458
10242
|
] }),
|
|
9459
|
-
/* @__PURE__ */
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
!leftLoading && !leftError && leftItems.length === 0 && (renderEmptyState ? renderEmptyState({ scope: activeScope }) : /* @__PURE__ */ jsx(
|
|
9463
|
-
EmptyState,
|
|
10243
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
|
|
10244
|
+
hasSingletonConflicts && /* @__PURE__ */ jsx(
|
|
10245
|
+
SingletonConflictBanner,
|
|
9464
10246
|
{
|
|
9465
|
-
|
|
9466
|
-
|
|
9467
|
-
|
|
10247
|
+
conflictCount: singletonConflicts.length,
|
|
10248
|
+
duplicateCount: totalDuplicateCount,
|
|
10249
|
+
onResolve: () => {
|
|
10250
|
+
const first = singletonConflicts[0]?.duplicates[0] ?? singletonConflicts[0]?.active;
|
|
10251
|
+
if (first?.id) {
|
|
10252
|
+
void runWithGuard(() => {
|
|
10253
|
+
setSelectedRecordId(first.id);
|
|
10254
|
+
});
|
|
10255
|
+
}
|
|
10256
|
+
},
|
|
10257
|
+
onArchiveDuplicates: enableArchiveDuplicates ? async () => {
|
|
10258
|
+
const ids = singletonConflicts.flatMap((c) => c.duplicates.map((d) => d.id)).filter((id) => !!id);
|
|
10259
|
+
for (const id of ids) {
|
|
10260
|
+
try {
|
|
10261
|
+
await SL.app.records.update(collectionId, appId, id, { status: archivedStatusValue }, true);
|
|
10262
|
+
onTelemetry?.({
|
|
10263
|
+
type: "recordAction.invoke",
|
|
10264
|
+
recordType,
|
|
10265
|
+
key: "conflict.archiveDuplicates",
|
|
10266
|
+
ref: id
|
|
10267
|
+
});
|
|
10268
|
+
} catch (err) {
|
|
10269
|
+
console.warn("[RecordsAdminShell] archive-duplicate failed", id, err);
|
|
10270
|
+
}
|
|
10271
|
+
}
|
|
10272
|
+
recordList.refetch();
|
|
10273
|
+
if (cardinality === "singleton") {
|
|
10274
|
+
ruleScopedList.refetch();
|
|
10275
|
+
globalScopedList.refetch();
|
|
10276
|
+
}
|
|
10277
|
+
} : void 0,
|
|
10278
|
+
onDeleteDuplicates: enableDeleteDuplicates ? async () => {
|
|
10279
|
+
const ids = singletonConflicts.flatMap((c) => c.duplicates.map((d) => d.id)).filter((id) => !!id);
|
|
10280
|
+
for (const id of ids) {
|
|
10281
|
+
try {
|
|
10282
|
+
await SL.app.records.remove(collectionId, appId, id, true);
|
|
10283
|
+
onTelemetry?.({
|
|
10284
|
+
type: "recordAction.invoke",
|
|
10285
|
+
recordType,
|
|
10286
|
+
key: "conflict.deleteDuplicates",
|
|
10287
|
+
ref: id
|
|
10288
|
+
});
|
|
10289
|
+
} catch (err) {
|
|
10290
|
+
console.warn("[RecordsAdminShell] delete-duplicate failed", id, err);
|
|
10291
|
+
}
|
|
10292
|
+
}
|
|
10293
|
+
recordList.refetch();
|
|
10294
|
+
if (cardinality === "singleton") {
|
|
10295
|
+
ruleScopedList.refetch();
|
|
10296
|
+
globalScopedList.refetch();
|
|
10297
|
+
}
|
|
10298
|
+
} : void 0,
|
|
10299
|
+
i18n: {
|
|
10300
|
+
title: i18n.conflictBannerTitle,
|
|
10301
|
+
bodyOne: i18n.conflictBannerBodyOne,
|
|
10302
|
+
bodyMany: i18n.conflictBannerBodyMany,
|
|
10303
|
+
archiveLabel: i18n.conflictArchiveDuplicates,
|
|
10304
|
+
deleteLabel: i18n.conflictDeleteDuplicates,
|
|
10305
|
+
deleteConfirm: i18n.conflictDeleteConfirm,
|
|
10306
|
+
resolveLabel: i18n.conflictResolveLabel
|
|
10307
|
+
}
|
|
9468
10308
|
}
|
|
9469
|
-
)
|
|
9470
|
-
|
|
9471
|
-
/* @__PURE__ */ jsx(
|
|
9472
|
-
|
|
10309
|
+
),
|
|
10310
|
+
isGlobalTab && !isCollection && !hasSingletonConflicts ? null : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10311
|
+
leftLoading && /* @__PURE__ */ jsx(LoadingState, {}),
|
|
10312
|
+
!leftLoading && leftError && /* @__PURE__ */ jsx(ErrorState, { error: leftError }),
|
|
10313
|
+
!leftLoading && !leftError && decoratedLeftItems.length === 0 && (renderEmptyState ? renderEmptyState({ scope: activeScope }) : /* @__PURE__ */ jsx(
|
|
10314
|
+
EmptyState,
|
|
9473
10315
|
{
|
|
9474
|
-
|
|
9475
|
-
|
|
9476
|
-
|
|
9477
|
-
onSelect: onLeftSelect,
|
|
9478
|
-
dirtyId,
|
|
9479
|
-
dirtyAnchorKey,
|
|
9480
|
-
dirtyKeys,
|
|
9481
|
-
errorKeys,
|
|
9482
|
-
presentation: effectivePresentation,
|
|
9483
|
-
renderListRow,
|
|
9484
|
-
groupBy: (
|
|
9485
|
-
// The synthetic "All items" row in collection mode is a
|
|
9486
|
-
// navigational anchor, not a real record — applying the
|
|
9487
|
-
// host's groupBy bucketed it under "Other" (its
|
|
9488
|
-
// data is null). Skip grouping for that single-row rail.
|
|
9489
|
-
(isGlobalTab || isAllTab) && isCollection || isLifecycleRail ? void 0 : effectiveGroupBy
|
|
9490
|
-
),
|
|
9491
|
-
renderGroupActions: renderRuleGroupActions,
|
|
9492
|
-
rowClipboard,
|
|
9493
|
-
rowActions: wrappedRecordActions,
|
|
9494
|
-
i18n
|
|
10316
|
+
icon: search ? icons.empty.search : icons.empty.default,
|
|
10317
|
+
title: search ? i18n.noResults : i18n.railEmptyTitle,
|
|
10318
|
+
body: search ? void 0 : isRuleTab ? i18n.rulesEmptyBody : i18n.railEmptyBody
|
|
9495
10319
|
}
|
|
9496
|
-
),
|
|
9497
|
-
|
|
9498
|
-
|
|
9499
|
-
|
|
9500
|
-
|
|
9501
|
-
|
|
9502
|
-
|
|
9503
|
-
|
|
9504
|
-
|
|
10320
|
+
)),
|
|
10321
|
+
!leftLoading && !leftError && decoratedLeftItems.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10322
|
+
/* @__PURE__ */ jsx(
|
|
10323
|
+
RecordList,
|
|
10324
|
+
{
|
|
10325
|
+
items: decoratedLeftItems,
|
|
10326
|
+
selectedId: leftSelectedId,
|
|
10327
|
+
selectedAnchorKey: leftSelectedAnchorKey,
|
|
10328
|
+
onSelect: onLeftSelect,
|
|
10329
|
+
dirtyId,
|
|
10330
|
+
dirtyAnchorKey,
|
|
10331
|
+
dirtyKeys,
|
|
10332
|
+
errorKeys,
|
|
10333
|
+
presentation: effectivePresentation,
|
|
10334
|
+
renderListRow,
|
|
10335
|
+
groupBy: (
|
|
10336
|
+
// The synthetic "All items" row in collection mode is a
|
|
10337
|
+
// navigational anchor, not a real record — applying the
|
|
10338
|
+
// host's groupBy bucketed it under "Other" (its
|
|
10339
|
+
// data is null). Skip grouping for that single-row rail.
|
|
10340
|
+
(isGlobalTab || isAllTab) && isCollection || isLifecycleRail ? void 0 : effectiveGroupBy
|
|
10341
|
+
),
|
|
10342
|
+
renderGroupActions: renderRuleGroupActions,
|
|
10343
|
+
rowClipboard,
|
|
10344
|
+
rowActions: wrappedRecordActions,
|
|
10345
|
+
i18n,
|
|
10346
|
+
historyBySlot: railHistoryBySlot
|
|
9505
10347
|
}
|
|
9506
|
-
|
|
9507
|
-
|
|
9508
|
-
|
|
9509
|
-
|
|
9510
|
-
|
|
9511
|
-
|
|
9512
|
-
|
|
9513
|
-
|
|
9514
|
-
|
|
9515
|
-
|
|
9516
|
-
void recordList.fetchNextPage();
|
|
10348
|
+
),
|
|
10349
|
+
isProductTab && !productPinned && /* @__PURE__ */ jsx(
|
|
10350
|
+
LoadMoreFooter,
|
|
10351
|
+
{
|
|
10352
|
+
shown: leftItems.length,
|
|
10353
|
+
hasNextPage: !!productBrowse.hasNextPage,
|
|
10354
|
+
isFetchingNextPage: !!productBrowse.isFetchingNextPage,
|
|
10355
|
+
onLoadMore: () => {
|
|
10356
|
+
void productBrowse.fetchNextPage();
|
|
10357
|
+
}
|
|
9517
10358
|
}
|
|
9518
|
-
|
|
9519
|
-
|
|
10359
|
+
),
|
|
10360
|
+
isRecordsTab && (!isCollection || !(isAllTab || isGlobalTab)) && /* @__PURE__ */ jsx(
|
|
10361
|
+
LoadMoreFooter,
|
|
10362
|
+
{
|
|
10363
|
+
shown: recordList.items.length,
|
|
10364
|
+
total: recordList.total,
|
|
10365
|
+
hasNextPage: !!recordList.hasNextPage,
|
|
10366
|
+
isFetchingNextPage: !!recordList.isFetchingNextPage,
|
|
10367
|
+
onLoadMore: () => {
|
|
10368
|
+
void recordList.fetchNextPage();
|
|
10369
|
+
}
|
|
10370
|
+
}
|
|
10371
|
+
)
|
|
10372
|
+
] })
|
|
9520
10373
|
] })
|
|
9521
|
-
] })
|
|
10374
|
+
] })
|
|
9522
10375
|
] }) }),
|
|
9523
10376
|
/* @__PURE__ */ jsxs("main", { className: "overflow-hidden", children: [
|
|
9524
10377
|
ruleWizardStep !== null && /* @__PURE__ */ jsxs(
|
|
@@ -9666,6 +10519,8 @@ function RecordsAdminShellInner(props) {
|
|
|
9666
10519
|
),
|
|
9667
10520
|
ruleWizardStep === null && isProductTab && selectedProductId && !isCollection && editingTargetScope && resolved.source !== "self" && selectedRecordId !== DRAFT_ID3 ? (() => {
|
|
9668
10521
|
const productName = productLookupItems.find((p) => p.id === selectedProductId)?.name ?? selectedProductId;
|
|
10522
|
+
const pasteEntry = wizardClipboard.entry;
|
|
10523
|
+
const pasteSourceLabel = pasteEntry?.sourceLabel ?? pasteEntry?.sourceScope.raw;
|
|
9669
10524
|
return /* @__PURE__ */ jsx(
|
|
9670
10525
|
CreateRecordChooser,
|
|
9671
10526
|
{
|
|
@@ -9674,7 +10529,9 @@ function RecordsAdminShellInner(props) {
|
|
|
9674
10529
|
primaryLabel: "Start blank",
|
|
9675
10530
|
onPrimary: () => onCreateProductRecord("blank"),
|
|
9676
10531
|
secondaryLabel: singletonGlobalSeedAvailable ? "Copy from global" : void 0,
|
|
9677
|
-
onSecondary: singletonGlobalSeedAvailable ? () => onCreateProductRecord("global") : void 0
|
|
10532
|
+
onSecondary: singletonGlobalSeedAvailable ? () => onCreateProductRecord("global") : void 0,
|
|
10533
|
+
tertiaryLabel: pasteEntry ? pasteSourceLabel ? `Paste from ${pasteSourceLabel}` : "Paste from clipboard" : void 0,
|
|
10534
|
+
onTertiary: pasteEntry ? () => onCreateProductRecord("paste") : void 0
|
|
9678
10535
|
}
|
|
9679
10536
|
);
|
|
9680
10537
|
})() : null,
|
|
@@ -10247,11 +11104,40 @@ function useRecordEditor(args) {
|
|
|
10247
11104
|
if (!resolved.recordId) return;
|
|
10248
11105
|
await removeRecord(ctx, resolved.recordId);
|
|
10249
11106
|
draftStore.clearDraft(draftKey);
|
|
11107
|
+
removeRecordFromCaches(queryClient, ctx, resolved.recordId);
|
|
11108
|
+
const cacheKey = resolvedRecordQueryKey({
|
|
11109
|
+
collectionId: ctx.collectionId,
|
|
11110
|
+
appId: ctx.appId,
|
|
11111
|
+
recordType: ctx.recordType,
|
|
11112
|
+
productId: scope.productId,
|
|
11113
|
+
variantId: scope.variantId,
|
|
11114
|
+
batchId: scope.batchId,
|
|
11115
|
+
facetId: scope.facetId,
|
|
11116
|
+
facetValue: scope.facetValue,
|
|
11117
|
+
proofId: scope.proofId,
|
|
11118
|
+
recordId: resolved.recordId,
|
|
11119
|
+
withParent: true
|
|
11120
|
+
});
|
|
11121
|
+
queryClient.removeQueries({ queryKey: cacheKey });
|
|
11122
|
+
const anchorCacheKey = resolvedRecordQueryKey({
|
|
11123
|
+
collectionId: ctx.collectionId,
|
|
11124
|
+
appId: ctx.appId,
|
|
11125
|
+
recordType: ctx.recordType,
|
|
11126
|
+
productId: scope.productId,
|
|
11127
|
+
variantId: scope.variantId,
|
|
11128
|
+
batchId: scope.batchId,
|
|
11129
|
+
facetId: scope.facetId,
|
|
11130
|
+
facetValue: scope.facetValue,
|
|
11131
|
+
proofId: scope.proofId,
|
|
11132
|
+
recordId: void 0,
|
|
11133
|
+
withParent: true
|
|
11134
|
+
});
|
|
11135
|
+
queryClient.removeQueries({ queryKey: anchorCacheKey });
|
|
10250
11136
|
queryClient.invalidateQueries({
|
|
10251
11137
|
queryKey: scopeCountsQueryKey(ctx.collectionId, ctx.appId, ctx.recordType)
|
|
10252
11138
|
});
|
|
10253
11139
|
onDeleted?.();
|
|
10254
|
-
}, [resolved.source, resolved.recordId, draftKey]);
|
|
11140
|
+
}, [resolved.source, resolved.recordId, draftKey, scope.raw]);
|
|
10255
11141
|
const prevDraftKeyRef = useRef(draftKey);
|
|
10256
11142
|
const prevScopeRawRef = useRef(scope.raw);
|
|
10257
11143
|
useEffect(() => {
|
|
@@ -10728,6 +11614,6 @@ function useMergedRecord(args) {
|
|
|
10728
11614
|
// src/components/RecordsAdmin/index.ts
|
|
10729
11615
|
assertComponentStylesLoaded("records-admin");
|
|
10730
11616
|
|
|
10731
|
-
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 };
|
|
11617
|
+
export { ALL_ITEM_VIEWS, ALL_PRESENTATIONS, BatchList, BulkActionsMenu, DEFAULT_DEEP_LINK_PARAM_NAMES, DEFAULT_I18N, DEFAULT_ICONS, DEFAULT_LIFECYCLE_STATUSES, DefaultItemCards, DefaultItemTable, DefaultRecordCard, DefaultRecordRow, DeleteButton, DirtyDraftProvider, DrawerPreview, EditorItemNav, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, ItemListView, ItemViewSwitcher, LifecycleStatusMenu, 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, compareLifecycleBuckets, createDefaultDeepLinkAdapter, createPostMessageDeepLinkAdapter, createRouterDeepLinkAdapter, downloadBlob, exportCsv, getActiveStatusValues, getLifecycleStatuses, hasMixedLifecycle, importCsv, isInSmartLinksIframe, mergeIcons, normaliseRule, parseRef, pickHeaderIcon, resolutionChain, resolveLifecycleStatus, 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 };
|
|
10732
11618
|
//# sourceMappingURL=index.js.map
|
|
10733
11619
|
//# sourceMappingURL=index.js.map
|