@proveanything/smartlinks-utils-ui 0.9.12 → 0.10.0
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 +29 -0
- package/dist/components/AssetPicker/index.css.map +1 -1
- package/dist/components/ConditionsEditor/index.css +29 -0
- package/dist/components/ConditionsEditor/index.css.map +1 -1
- package/dist/components/FontPicker/index.css +29 -0
- package/dist/components/FontPicker/index.css.map +1 -1
- package/dist/components/IconPicker/index.css +29 -0
- package/dist/components/IconPicker/index.css.map +1 -1
- package/dist/components/RecordsAdmin/index.css +29 -0
- package/dist/components/RecordsAdmin/index.css.map +1 -1
- package/dist/components/RecordsAdmin/index.d.ts +125 -14
- package/dist/components/RecordsAdmin/index.js +260 -103
- package/dist/components/RecordsAdmin/index.js.map +1 -1
- package/dist/index.css +29 -0
- package/dist/index.css.map +1 -1
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@ import { cn } from '../../chunk-L7FQ52F5.js';
|
|
|
6
6
|
import { parsedRefToTarget, parsedRefToScope, matchRecords, scopesEqual, getRecordById, listRecords, upsertRecord, updateRecord, createRecord, removeRecord } from '../../chunk-KA4MKRHL.js';
|
|
7
7
|
export { bulkDelete, bulkUpsert, createRecord, getRecordById, listRecords, matchRecords, parsedRefToScope, parsedRefToTarget, removeRecord, restoreRecord, scopesEqual, upsertRecord } from '../../chunk-KA4MKRHL.js';
|
|
8
8
|
import { createContext, useState, useEffect, useCallback, useMemo, useRef, useContext, useSyncExternalStore, useLayoutEffect, createElement, useId } from 'react';
|
|
9
|
-
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, Rows3, ChevronRight, Eraser, ClipboardPaste, Box, X, Search, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, CornerDownLeft, Circle, AlertCircle, Undo2, Save, Loader2, XCircle, ArrowRight, BookOpen, Globe2,
|
|
9
|
+
import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, List, SlidersHorizontal, Globe, Tag, Boxes, Layers, Package, Target, Rows3, ChevronRight, Eraser, ClipboardPaste, Box, X, Search, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, CornerDownLeft, Circle, CopyPlus, AlertCircle, Undo2, Save, Loader2, XCircle, ArrowRight, BookOpen, Globe2, Check, Settings2 } from 'lucide-react';
|
|
10
10
|
import { useQuery, useQueryClient, useInfiniteQuery } from '@tanstack/react-query';
|
|
11
11
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
12
12
|
import { createPortal } from 'react-dom';
|
|
@@ -142,6 +142,8 @@ var DEFAULT_I18N = {
|
|
|
142
142
|
pasteConfirmCancel: "Cancel",
|
|
143
143
|
pasteWarnTitle: "Cross-scope paste",
|
|
144
144
|
pasteWarnContinue: "Continue",
|
|
145
|
+
duplicateAction: "Duplicate",
|
|
146
|
+
duplicateToast: "Duplicated {name}. Review and Save.",
|
|
145
147
|
itemsAllLabel: "All items",
|
|
146
148
|
subtitleEmpty: "Not set",
|
|
147
149
|
subtitleConfigured: "Configured",
|
|
@@ -1549,7 +1551,8 @@ function useShellClipboard(args) {
|
|
|
1549
1551
|
onTelemetry,
|
|
1550
1552
|
onCopyOverride,
|
|
1551
1553
|
onPasteOverride,
|
|
1552
|
-
onLeftSelectRef
|
|
1554
|
+
onLeftSelectRef,
|
|
1555
|
+
onCreateItemDraftRef
|
|
1553
1556
|
} = args;
|
|
1554
1557
|
const clipboard = useRecordClipboard({
|
|
1555
1558
|
appId,
|
|
@@ -1681,8 +1684,7 @@ function useShellClipboard(args) {
|
|
|
1681
1684
|
const rowClipboard = enabled ? (record) => {
|
|
1682
1685
|
const summaryHasData = record.data != null;
|
|
1683
1686
|
const sourceParsed = record.scope;
|
|
1684
|
-
const
|
|
1685
|
-
const sameTarget = clipboard.entry ? clipboard.entry.sourceRecordId && record.id ? clipboard.entry.sourceRecordId === record.id : clipboard.entry.sourceScope.raw === anchorKey(record.scope) : false;
|
|
1687
|
+
const canDuplicate = summaryHasData && isCollection;
|
|
1686
1688
|
return {
|
|
1687
1689
|
onCopy: summaryHasData ? () => {
|
|
1688
1690
|
const value = onCopyOverride ? onCopyOverride({ value: record.data, scope: sourceParsed }) : cloneValue(record.data);
|
|
@@ -1698,15 +1700,27 @@ function useShellClipboard(args) {
|
|
|
1698
1700
|
variant: "copy"
|
|
1699
1701
|
});
|
|
1700
1702
|
} : void 0,
|
|
1701
|
-
|
|
1703
|
+
onDuplicate: canDuplicate ? () => {
|
|
1704
|
+
const value = onCopyOverride ? onCopyOverride({ value: record.data, scope: sourceParsed }) : cloneValue(record.data);
|
|
1705
|
+
clipboard.set({
|
|
1706
|
+
value,
|
|
1707
|
+
sourceScope: sourceParsed,
|
|
1708
|
+
sourceRecordId: record.id ?? void 0,
|
|
1709
|
+
sourceLabel: record.label
|
|
1710
|
+
});
|
|
1711
|
+
onTelemetry?.({ type: "clipboard.copy", recordType, sourceRef: anchorKey(record.scope) });
|
|
1702
1712
|
onLeftSelectRef.current?.(record);
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
)
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1713
|
+
const create = onCreateItemDraftRef?.current;
|
|
1714
|
+
if (!create) return;
|
|
1715
|
+
window.setTimeout(() => {
|
|
1716
|
+
const newId = create();
|
|
1717
|
+
if (newId) setPendingPasteTarget({ kind: "record", recordId: newId });
|
|
1718
|
+
}, 0);
|
|
1719
|
+
setNotice({
|
|
1720
|
+
message: i18n.duplicateToast.replace("{name}", record.label),
|
|
1721
|
+
variant: "copy"
|
|
1722
|
+
});
|
|
1723
|
+
} : void 0
|
|
1710
1724
|
};
|
|
1711
1725
|
} : void 0;
|
|
1712
1726
|
const toast = notice ? /* @__PURE__ */ jsx(
|
|
@@ -1860,14 +1874,17 @@ function useShellNavigation(args) {
|
|
|
1860
1874
|
lastAppliedDLRef
|
|
1861
1875
|
]);
|
|
1862
1876
|
const onItemCreate = useCallback(() => {
|
|
1863
|
-
if (!isCollection) return;
|
|
1877
|
+
if (!isCollection) return void 0;
|
|
1878
|
+
let createdId;
|
|
1864
1879
|
void runWithGuard(() => {
|
|
1865
1880
|
const id = coerceDraftItemId(generateItemId);
|
|
1881
|
+
createdId = id;
|
|
1866
1882
|
setSelectedItemId(id);
|
|
1867
1883
|
onTelemetry?.({ type: "item.create", recordType, scopeRef: baseScopeRef });
|
|
1868
1884
|
deepLinkState.emit({ recordId: null, scope: baseScopeRef || null }, "record.open");
|
|
1869
1885
|
stampEcho(null, baseScopeRef || null);
|
|
1870
1886
|
});
|
|
1887
|
+
return createdId;
|
|
1871
1888
|
}, [
|
|
1872
1889
|
isCollection,
|
|
1873
1890
|
runWithGuard,
|
|
@@ -1951,7 +1968,9 @@ function useShellNavigation(args) {
|
|
|
1951
1968
|
]);
|
|
1952
1969
|
const itemViewCtx = useMemo(() => ({
|
|
1953
1970
|
onOpen: onItemOpen,
|
|
1954
|
-
onCreate:
|
|
1971
|
+
onCreate: () => {
|
|
1972
|
+
onItemCreate();
|
|
1973
|
+
},
|
|
1955
1974
|
onDelete: (id) => {
|
|
1956
1975
|
void onItemDelete(id);
|
|
1957
1976
|
},
|
|
@@ -2108,23 +2127,12 @@ var useShellDeepLink = (args) => {
|
|
|
2108
2127
|
const [pendingDeepLinkRecordId, setPendingDeepLinkRecordId] = useState(null);
|
|
2109
2128
|
const preserveInitialRecordIdRef = useRef(!!deepLinkState.urlState.recordId);
|
|
2110
2129
|
const warnedMissingRef = useRef(/* @__PURE__ */ new Set());
|
|
2111
|
-
const bootLoggedRef = useRef(false);
|
|
2112
|
-
if (!bootLoggedRef.current) {
|
|
2113
|
-
bootLoggedRef.current = true;
|
|
2114
|
-
console.info("[RecordsAdminShell] deep-link boot snapshot", {
|
|
2115
|
-
enabled: deepLinkState.enabled,
|
|
2116
|
-
urlStateRecordId: deepLinkState.urlState.recordId ?? null,
|
|
2117
|
-
urlStateScope: deepLinkState.urlState.scope ?? null,
|
|
2118
|
-
urlStateView: deepLinkState.urlState.view ?? null,
|
|
2119
|
-
urlStateRaw: JSON.stringify(deepLinkState.urlState),
|
|
2120
|
-
paramNames: deepLinkState.paramNames,
|
|
2121
|
-
windowHash: typeof window !== "undefined" ? window.location.hash : null,
|
|
2122
|
-
windowSearch: typeof window !== "undefined" ? window.location.search : null
|
|
2123
|
-
});
|
|
2124
|
-
}
|
|
2125
2130
|
useEffect(() => {
|
|
2126
2131
|
if (!deepLinkState.enabled) return;
|
|
2127
2132
|
if (selectedItemId) return;
|
|
2133
|
+
if (lastAppliedDLRef.current === "" && (deepLinkState.urlState.recordId ?? null) !== null) {
|
|
2134
|
+
return;
|
|
2135
|
+
}
|
|
2128
2136
|
const echoView = deepLinkState.urlState.view ?? "";
|
|
2129
2137
|
const currentDeepLinkedRecordId = pendingDeepLinkRecordId ?? deepLinkState.urlState.recordId ?? null;
|
|
2130
2138
|
const preservingPendingRecordId = preserveInitialRecordIdRef.current && !!currentDeepLinkedRecordId;
|
|
@@ -2137,14 +2145,6 @@ var useShellDeepLink = (args) => {
|
|
|
2137
2145
|
useEffect(() => {
|
|
2138
2146
|
const { recordId, scope, view } = deepLinkState.urlState;
|
|
2139
2147
|
const sig = `${recordId ?? ""}|${scope ?? ""}|${view ?? ""}`;
|
|
2140
|
-
console.info("[RecordsAdminShell] restore effect tick", {
|
|
2141
|
-
enabled: deepLinkState.enabled,
|
|
2142
|
-
recordId,
|
|
2143
|
-
scope,
|
|
2144
|
-
view,
|
|
2145
|
-
sig,
|
|
2146
|
-
lastApplied: lastAppliedDLRef.current
|
|
2147
|
-
});
|
|
2148
2148
|
if (!deepLinkState.enabled) return;
|
|
2149
2149
|
if (sig === lastAppliedDLRef.current) return;
|
|
2150
2150
|
lastAppliedDLRef.current = sig;
|
|
@@ -2171,31 +2171,9 @@ var useShellDeepLink = (args) => {
|
|
|
2171
2171
|
}
|
|
2172
2172
|
setPendingDeepLinkRecordId(recordId ?? null);
|
|
2173
2173
|
if (recordId) preserveInitialRecordIdRef.current = true;
|
|
2174
|
-
if (recordId) {
|
|
2175
|
-
console.info("[RecordsAdminShell] deep-link restore \u2014 pending recordId set", {
|
|
2176
|
-
recordId,
|
|
2177
|
-
scope: scope ?? null,
|
|
2178
|
-
view: view ?? null
|
|
2179
|
-
});
|
|
2180
|
-
}
|
|
2181
|
-
if (!recordId && selectedItemId !== null) {
|
|
2182
|
-
console.info("[RecordsAdminShell] preserving selected item during restore without recordId", {
|
|
2183
|
-
selectedItemId,
|
|
2184
|
-
scope,
|
|
2185
|
-
view
|
|
2186
|
-
});
|
|
2187
|
-
}
|
|
2188
2174
|
}, [deepLinkState.enabled, deepLinkState.urlState]);
|
|
2189
2175
|
useEffect(() => {
|
|
2190
2176
|
const pending = pendingDeepLinkRecordId;
|
|
2191
|
-
console.info("[RecordsAdminShell] resolver tick", {
|
|
2192
|
-
pending,
|
|
2193
|
-
isCollection,
|
|
2194
|
-
collectionItemsCount: collectionItems.items.length,
|
|
2195
|
-
collectionItemsLoading: collectionItems.isLoading,
|
|
2196
|
-
recordListCount: recordListItems.length,
|
|
2197
|
-
recordListLoading
|
|
2198
|
-
});
|
|
2199
2177
|
if (!pending) return;
|
|
2200
2178
|
if (isCollection) {
|
|
2201
2179
|
const hit2 = collectionItems.items.find((it) => it.id === pending || it.itemId === pending);
|
|
@@ -3279,10 +3257,8 @@ var statusToneLabel = (tone) => {
|
|
|
3279
3257
|
};
|
|
3280
3258
|
var RowContextMenu = ({
|
|
3281
3259
|
onCopy,
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
pasteWillReplace,
|
|
3285
|
-
pasteSourceLabel,
|
|
3260
|
+
onDuplicate,
|
|
3261
|
+
actions,
|
|
3286
3262
|
i18n
|
|
3287
3263
|
}) => {
|
|
3288
3264
|
const [open, setOpen] = useState(false);
|
|
@@ -3331,8 +3307,9 @@ var RowContextMenu = ({
|
|
|
3331
3307
|
window.removeEventListener("scroll", update, true);
|
|
3332
3308
|
};
|
|
3333
3309
|
}, [open]);
|
|
3334
|
-
|
|
3335
|
-
|
|
3310
|
+
const hasActions = (actions?.length ?? 0) > 0;
|
|
3311
|
+
if (!onCopy && !onDuplicate && !hasActions) return null;
|
|
3312
|
+
const showDivider = (onCopy || onDuplicate) && hasActions;
|
|
3336
3313
|
return /* @__PURE__ */ jsxs("div", { ref: wrapperRef, className: "ra-row-menu-wrap relative", children: [
|
|
3337
3314
|
/* @__PURE__ */ jsx(
|
|
3338
3315
|
"button",
|
|
@@ -3378,24 +3355,49 @@ var RowContextMenu = ({
|
|
|
3378
3355
|
]
|
|
3379
3356
|
}
|
|
3380
3357
|
),
|
|
3381
|
-
|
|
3358
|
+
onDuplicate && /* @__PURE__ */ jsxs(
|
|
3382
3359
|
"button",
|
|
3383
3360
|
{
|
|
3384
3361
|
type: "button",
|
|
3385
3362
|
role: "menuitem",
|
|
3386
3363
|
className: "ra-row-menu-item",
|
|
3387
|
-
disabled: !canPaste,
|
|
3388
3364
|
onClick: (e) => {
|
|
3389
3365
|
e.stopPropagation();
|
|
3390
3366
|
setOpen(false);
|
|
3391
|
-
|
|
3367
|
+
onDuplicate();
|
|
3392
3368
|
},
|
|
3393
3369
|
children: [
|
|
3394
|
-
/* @__PURE__ */ jsx(
|
|
3395
|
-
/* @__PURE__ */ jsx("span", {
|
|
3370
|
+
/* @__PURE__ */ jsx(CopyPlus, { className: "w-3 h-3", "aria-hidden": "true" }),
|
|
3371
|
+
/* @__PURE__ */ jsx("span", { children: i18n.duplicateAction })
|
|
3396
3372
|
]
|
|
3397
3373
|
}
|
|
3398
|
-
)
|
|
3374
|
+
),
|
|
3375
|
+
showDivider && /* @__PURE__ */ jsx("div", { className: "ra-row-menu-divider", role: "separator" }),
|
|
3376
|
+
hasActions && actions.map((action) => {
|
|
3377
|
+
const Icon = action.icon;
|
|
3378
|
+
return /* @__PURE__ */ jsxs(
|
|
3379
|
+
"button",
|
|
3380
|
+
{
|
|
3381
|
+
type: "button",
|
|
3382
|
+
role: "menuitem",
|
|
3383
|
+
className: "ra-row-menu-item",
|
|
3384
|
+
"data-tone": action.variant === "danger" ? "danger" : void 0,
|
|
3385
|
+
disabled: action.disabled,
|
|
3386
|
+
title: action.disabled ? action.disabledReason : void 0,
|
|
3387
|
+
onClick: (e) => {
|
|
3388
|
+
e.stopPropagation();
|
|
3389
|
+
if (action.disabled) return;
|
|
3390
|
+
setOpen(false);
|
|
3391
|
+
void action.onAction();
|
|
3392
|
+
},
|
|
3393
|
+
children: [
|
|
3394
|
+
Icon && /* @__PURE__ */ jsx(Icon, { className: "w-3 h-3" }),
|
|
3395
|
+
/* @__PURE__ */ jsx("span", { children: action.label })
|
|
3396
|
+
]
|
|
3397
|
+
},
|
|
3398
|
+
action.key
|
|
3399
|
+
);
|
|
3400
|
+
})
|
|
3399
3401
|
]
|
|
3400
3402
|
}
|
|
3401
3403
|
),
|
|
@@ -3444,7 +3446,7 @@ var RuleLabelLookupProvider = ({
|
|
|
3444
3446
|
return /* @__PURE__ */ jsx(RuleLabelLookupContext.Provider, { value: v, children });
|
|
3445
3447
|
};
|
|
3446
3448
|
var DefaultRecordRow = ({ record, ctx, compact = false }) => {
|
|
3447
|
-
const { selected, onSelect, isDirty, hasError, onCopy,
|
|
3449
|
+
const { selected, onSelect, isDirty, hasError, onCopy, onDuplicate, actions } = ctx;
|
|
3448
3450
|
const ruleLabelLookup = useRuleLabelLookup();
|
|
3449
3451
|
const ScopeIcon = record.scope.kind && record.scope.kind !== "collection" ? DEFAULT_ICONS.scope[record.scope.kind] : DEFAULT_ICONS.scope.product;
|
|
3450
3452
|
const tone = resolveTone(void 0, record.status);
|
|
@@ -3497,7 +3499,7 @@ var DefaultRecordRow = ({ record, ctx, compact = false }) => {
|
|
|
3497
3499
|
className: "ra-row-rule-pip",
|
|
3498
3500
|
title: ruleSummary ? `Targeted: ${ruleSummary}` : "This record has targeting rules",
|
|
3499
3501
|
"aria-label": ruleSummary ? `Targeted: ${ruleSummary}` : "This record has targeting rules",
|
|
3500
|
-
children: /* @__PURE__ */ jsx(
|
|
3502
|
+
children: /* @__PURE__ */ jsx(Target, { className: "w-3 h-3", "aria-hidden": "true" })
|
|
3501
3503
|
}
|
|
3502
3504
|
),
|
|
3503
3505
|
hasError ? /* @__PURE__ */ jsx(
|
|
@@ -3516,20 +3518,15 @@ var DefaultRecordRow = ({ record, ctx, compact = false }) => {
|
|
|
3516
3518
|
}
|
|
3517
3519
|
)
|
|
3518
3520
|
] }),
|
|
3519
|
-
(onCopy ||
|
|
3521
|
+
(onCopy || onDuplicate || actions && actions.length > 0) && /* @__PURE__ */ jsx(
|
|
3520
3522
|
RowContextMenu,
|
|
3521
3523
|
{
|
|
3522
3524
|
onCopy,
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
pasteWillReplace,
|
|
3526
|
-
pasteSourceLabel: clipboardSourceLabel,
|
|
3525
|
+
onDuplicate,
|
|
3526
|
+
actions,
|
|
3527
3527
|
i18n: {
|
|
3528
3528
|
copy: DEFAULT_I18N.copy,
|
|
3529
|
-
|
|
3530
|
-
pasteFrom: DEFAULT_I18N.pasteFrom,
|
|
3531
|
-
pasteReplace: DEFAULT_I18N.pasteReplace,
|
|
3532
|
-
clipboardEmpty: DEFAULT_I18N.clipboardEmpty
|
|
3529
|
+
duplicateAction: DEFAULT_I18N.duplicateAction
|
|
3533
3530
|
}
|
|
3534
3531
|
}
|
|
3535
3532
|
)
|
|
@@ -3551,10 +3548,37 @@ var RecordList = ({
|
|
|
3551
3548
|
groupBy,
|
|
3552
3549
|
renderGroupActions,
|
|
3553
3550
|
rowClipboard,
|
|
3551
|
+
rowActions,
|
|
3554
3552
|
i18n
|
|
3555
3553
|
}) => {
|
|
3554
|
+
const containerRef = useRef(null);
|
|
3555
|
+
const onKeyDown = useCallback((e) => {
|
|
3556
|
+
const key = e.key;
|
|
3557
|
+
if (key !== "ArrowDown" && key !== "ArrowUp" && key !== "Home" && key !== "End") {
|
|
3558
|
+
return;
|
|
3559
|
+
}
|
|
3560
|
+
const root = containerRef.current;
|
|
3561
|
+
if (!root) return;
|
|
3562
|
+
const buttons = Array.from(
|
|
3563
|
+
root.querySelectorAll("button.ra-row-hit")
|
|
3564
|
+
).filter((btn) => !btn.hasAttribute("disabled") && btn.offsetParent !== null);
|
|
3565
|
+
if (buttons.length === 0) return;
|
|
3566
|
+
const active = document.activeElement;
|
|
3567
|
+
const currentIdx = active ? buttons.indexOf(active) : -1;
|
|
3568
|
+
let nextIdx = currentIdx;
|
|
3569
|
+
if (key === "ArrowDown") nextIdx = currentIdx < 0 ? 0 : Math.min(currentIdx + 1, buttons.length - 1);
|
|
3570
|
+
else if (key === "ArrowUp") nextIdx = currentIdx <= 0 ? 0 : currentIdx - 1;
|
|
3571
|
+
else if (key === "Home") nextIdx = 0;
|
|
3572
|
+
else if (key === "End") nextIdx = buttons.length - 1;
|
|
3573
|
+
if (nextIdx !== currentIdx && buttons[nextIdx]) {
|
|
3574
|
+
e.preventDefault();
|
|
3575
|
+
buttons[nextIdx].focus();
|
|
3576
|
+
buttons[nextIdx].scrollIntoView({ block: "nearest" });
|
|
3577
|
+
}
|
|
3578
|
+
}, []);
|
|
3556
3579
|
const buildCtx = (item) => {
|
|
3557
3580
|
const cb = rowClipboard ? rowClipboard(item) : null;
|
|
3581
|
+
const extraActions = rowActions ? rowActions(item) ?? void 0 : void 0;
|
|
3558
3582
|
const itemAnchorKey = anchorKey(item.scope);
|
|
3559
3583
|
const idMatch = selectedId != null && item.id != null && item.id === selectedId;
|
|
3560
3584
|
const anchorMatch = selectedAnchorKey != null && !!itemAnchorKey && itemAnchorKey === selectedAnchorKey;
|
|
@@ -3569,7 +3593,8 @@ var RecordList = ({
|
|
|
3569
3593
|
isDirty: dirtyIdMatch || dirtyAnchorMatch || idInStore || anchorInStore,
|
|
3570
3594
|
hasError: errorInStore,
|
|
3571
3595
|
i18n,
|
|
3572
|
-
...cb ?? {}
|
|
3596
|
+
...cb ?? {},
|
|
3597
|
+
actions: extraActions && extraActions.length > 0 ? extraActions : void 0
|
|
3573
3598
|
};
|
|
3574
3599
|
};
|
|
3575
3600
|
const groups = useMemo(() => {
|
|
@@ -3596,15 +3621,33 @@ var RecordList = ({
|
|
|
3596
3621
|
};
|
|
3597
3622
|
if (groups) {
|
|
3598
3623
|
return /* @__PURE__ */ jsx(
|
|
3599
|
-
|
|
3624
|
+
"div",
|
|
3600
3625
|
{
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3626
|
+
ref: containerRef,
|
|
3627
|
+
onKeyDown,
|
|
3628
|
+
role: "listbox",
|
|
3629
|
+
"aria-label": "Records",
|
|
3630
|
+
children: /* @__PURE__ */ jsx(
|
|
3631
|
+
GroupedList,
|
|
3632
|
+
{
|
|
3633
|
+
groups,
|
|
3634
|
+
renderItems,
|
|
3635
|
+
renderGroupActions
|
|
3636
|
+
}
|
|
3637
|
+
)
|
|
3604
3638
|
}
|
|
3605
3639
|
);
|
|
3606
3640
|
}
|
|
3607
|
-
return
|
|
3641
|
+
return /* @__PURE__ */ jsx(
|
|
3642
|
+
"div",
|
|
3643
|
+
{
|
|
3644
|
+
ref: containerRef,
|
|
3645
|
+
onKeyDown,
|
|
3646
|
+
role: "listbox",
|
|
3647
|
+
"aria-label": "Records",
|
|
3648
|
+
children: renderItems(items)
|
|
3649
|
+
}
|
|
3650
|
+
);
|
|
3608
3651
|
};
|
|
3609
3652
|
var GroupedList = ({
|
|
3610
3653
|
groups,
|
|
@@ -5515,6 +5558,8 @@ function DefaultItemTable({
|
|
|
5515
5558
|
selectedId,
|
|
5516
5559
|
onOpen,
|
|
5517
5560
|
onDelete,
|
|
5561
|
+
rowActions,
|
|
5562
|
+
rowClipboard,
|
|
5518
5563
|
i18n
|
|
5519
5564
|
}) {
|
|
5520
5565
|
const cols = columns ?? [];
|
|
@@ -5552,6 +5597,31 @@ function DefaultItemTable({
|
|
|
5552
5597
|
/* @__PURE__ */ jsx("td", { className: "ra-item-row-meta", children: formatDate(item.updatedAt) })
|
|
5553
5598
|
] }) : cols.map((c) => /* @__PURE__ */ jsx("td", { style: { textAlign: c.align ?? "left" }, children: c.render(item) }, c.key)),
|
|
5554
5599
|
/* @__PURE__ */ jsxs("td", { className: "ra-item-row-actions", children: [
|
|
5600
|
+
(() => {
|
|
5601
|
+
const extra = rowActions ? rowActions(item) ?? void 0 : void 0;
|
|
5602
|
+
const cb = rowClipboard ? rowClipboard(item) : null;
|
|
5603
|
+
const hasExtras = !!(extra && extra.length > 0);
|
|
5604
|
+
if (!cb?.onCopy && !cb?.onDuplicate && !hasExtras) return null;
|
|
5605
|
+
return /* @__PURE__ */ jsx(
|
|
5606
|
+
"span",
|
|
5607
|
+
{
|
|
5608
|
+
onClick: (e) => e.stopPropagation(),
|
|
5609
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
5610
|
+
children: /* @__PURE__ */ jsx(
|
|
5611
|
+
RowContextMenu,
|
|
5612
|
+
{
|
|
5613
|
+
onCopy: cb?.onCopy,
|
|
5614
|
+
onDuplicate: cb?.onDuplicate,
|
|
5615
|
+
actions: extra ?? void 0,
|
|
5616
|
+
i18n: {
|
|
5617
|
+
copy: DEFAULT_I18N.copy,
|
|
5618
|
+
duplicateAction: DEFAULT_I18N.duplicateAction
|
|
5619
|
+
}
|
|
5620
|
+
}
|
|
5621
|
+
)
|
|
5622
|
+
}
|
|
5623
|
+
);
|
|
5624
|
+
})(),
|
|
5555
5625
|
/* @__PURE__ */ jsx(
|
|
5556
5626
|
"button",
|
|
5557
5627
|
{
|
|
@@ -5595,6 +5665,8 @@ function DefaultItemCards({
|
|
|
5595
5665
|
ctx,
|
|
5596
5666
|
renderCard,
|
|
5597
5667
|
cardSize = "md",
|
|
5668
|
+
rowActions,
|
|
5669
|
+
rowClipboard,
|
|
5598
5670
|
i18n
|
|
5599
5671
|
}) {
|
|
5600
5672
|
const isGallery = variant === "gallery";
|
|
@@ -5607,10 +5679,13 @@ function DefaultItemCards({
|
|
|
5607
5679
|
const id = item.itemId ?? "";
|
|
5608
5680
|
const key = item.id ?? (id || anchorKey(item.scope) || `pos:${idx}`);
|
|
5609
5681
|
const open = () => ctx.onOpen(id);
|
|
5682
|
+
const extraActions = rowActions ? rowActions(item) ?? void 0 : void 0;
|
|
5683
|
+
const cb = rowClipboard ? rowClipboard(item) : null;
|
|
5610
5684
|
const slotCtx = {
|
|
5611
5685
|
...ctx,
|
|
5612
5686
|
selected: selectedId === id,
|
|
5613
|
-
onSelect: open
|
|
5687
|
+
onSelect: open,
|
|
5688
|
+
actions: extraActions && extraActions.length > 0 ? extraActions : void 0
|
|
5614
5689
|
};
|
|
5615
5690
|
if (renderCard) {
|
|
5616
5691
|
return /* @__PURE__ */ jsx(
|
|
@@ -5637,6 +5712,26 @@ function DefaultItemCards({
|
|
|
5637
5712
|
/* @__PURE__ */ jsx("div", { className: "ra-item-card-title", children: item.label }),
|
|
5638
5713
|
item.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-item-card-sub", children: item.subtitle })
|
|
5639
5714
|
] }),
|
|
5715
|
+
(cb?.onCopy || cb?.onDuplicate || extraActions && extraActions.length > 0) && /* @__PURE__ */ jsx(
|
|
5716
|
+
"span",
|
|
5717
|
+
{
|
|
5718
|
+
className: "ra-item-card-menu",
|
|
5719
|
+
onClick: (e) => e.stopPropagation(),
|
|
5720
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
5721
|
+
children: /* @__PURE__ */ jsx(
|
|
5722
|
+
RowContextMenu,
|
|
5723
|
+
{
|
|
5724
|
+
onCopy: cb?.onCopy,
|
|
5725
|
+
onDuplicate: cb?.onDuplicate,
|
|
5726
|
+
actions: extraActions,
|
|
5727
|
+
i18n: {
|
|
5728
|
+
copy: DEFAULT_I18N.copy,
|
|
5729
|
+
duplicateAction: DEFAULT_I18N.duplicateAction
|
|
5730
|
+
}
|
|
5731
|
+
}
|
|
5732
|
+
)
|
|
5733
|
+
}
|
|
5734
|
+
),
|
|
5640
5735
|
/* @__PURE__ */ jsx(
|
|
5641
5736
|
"button",
|
|
5642
5737
|
{
|
|
@@ -5674,6 +5769,8 @@ function ItemListView({
|
|
|
5674
5769
|
renderItemEmpty,
|
|
5675
5770
|
itemColumns,
|
|
5676
5771
|
cardSize = "md",
|
|
5772
|
+
rowActions,
|
|
5773
|
+
rowClipboard,
|
|
5677
5774
|
i18n
|
|
5678
5775
|
}) {
|
|
5679
5776
|
const newLabel = i18n.newItem.includes("{noun}") ? i18n.newItem.replace("{noun}", itemNoun) : i18n.newItem;
|
|
@@ -5744,6 +5841,8 @@ function ItemListView({
|
|
|
5744
5841
|
selectedId: ctx.selectedId,
|
|
5745
5842
|
onOpen: ctx.onOpen,
|
|
5746
5843
|
onDelete: ctx.onDelete,
|
|
5844
|
+
rowActions,
|
|
5845
|
+
rowClipboard,
|
|
5747
5846
|
i18n
|
|
5748
5847
|
}
|
|
5749
5848
|
);
|
|
@@ -5757,6 +5856,8 @@ function ItemListView({
|
|
|
5757
5856
|
ctx,
|
|
5758
5857
|
renderCard: renderItemCard,
|
|
5759
5858
|
cardSize,
|
|
5859
|
+
rowActions,
|
|
5860
|
+
rowClipboard,
|
|
5760
5861
|
i18n
|
|
5761
5862
|
}
|
|
5762
5863
|
);
|
|
@@ -5887,7 +5988,7 @@ function SiblingRail({
|
|
|
5887
5988
|
className: "ra-row-rule-pip",
|
|
5888
5989
|
title: ruleSummary ? `Targeted: ${ruleSummary}` : "This item has targeting rules",
|
|
5889
5990
|
"aria-label": ruleSummary ? `Targeted: ${ruleSummary}` : "This item has targeting rules",
|
|
5890
|
-
children: /* @__PURE__ */ jsx(
|
|
5991
|
+
children: /* @__PURE__ */ jsx(Target, { className: "w-3 h-3", "aria-hidden": "true" })
|
|
5891
5992
|
}
|
|
5892
5993
|
),
|
|
5893
5994
|
hasError ? /* @__PURE__ */ jsx(
|
|
@@ -7141,6 +7242,7 @@ function RecordsAdminShellInner(props) {
|
|
|
7141
7242
|
unsaved,
|
|
7142
7243
|
clipboard,
|
|
7143
7244
|
actions,
|
|
7245
|
+
recordActions,
|
|
7144
7246
|
icons: iconsOverride,
|
|
7145
7247
|
// Deep linking
|
|
7146
7248
|
deepLink
|
|
@@ -7597,6 +7699,7 @@ function RecordsAdminShellInner(props) {
|
|
|
7597
7699
|
i18n
|
|
7598
7700
|
]);
|
|
7599
7701
|
const onLeftSelectRef = useRef(null);
|
|
7702
|
+
const onCreateItemDraftRef = useRef(null);
|
|
7600
7703
|
const { runWithGuard } = useDirtyNavigation({
|
|
7601
7704
|
strategy: dirtyStrategy,
|
|
7602
7705
|
isDirty: editorCtx.isDirty,
|
|
@@ -7651,19 +7754,37 @@ function RecordsAdminShellInner(props) {
|
|
|
7651
7754
|
onTelemetry,
|
|
7652
7755
|
onCopyOverride,
|
|
7653
7756
|
onPasteOverride,
|
|
7654
|
-
onLeftSelectRef
|
|
7757
|
+
onLeftSelectRef,
|
|
7758
|
+
onCreateItemDraftRef
|
|
7655
7759
|
});
|
|
7656
7760
|
const editorClipboard = shellClipboard.editorClipboard;
|
|
7657
7761
|
const rowClipboard = shellClipboard.rowClipboard;
|
|
7762
|
+
const wrappedRecordActions = recordActions ? (record) => {
|
|
7763
|
+
const list = recordActions(record, record.scope);
|
|
7764
|
+
if (!list || list.length === 0) return list ?? void 0;
|
|
7765
|
+
return list.map((a) => ({
|
|
7766
|
+
...a,
|
|
7767
|
+
onAction: () => {
|
|
7768
|
+
onTelemetry?.({
|
|
7769
|
+
type: "recordAction.invoke",
|
|
7770
|
+
recordType,
|
|
7771
|
+
key: a.key,
|
|
7772
|
+
ref: anchorKey(record.scope)
|
|
7773
|
+
});
|
|
7774
|
+
return a.onAction();
|
|
7775
|
+
}
|
|
7776
|
+
}));
|
|
7777
|
+
} : void 0;
|
|
7658
7778
|
const baseScopeRef = editingScope?.raw ?? "";
|
|
7659
7779
|
const itemNounLabel = itemNoun || "item";
|
|
7660
7780
|
const {
|
|
7661
7781
|
onItemOpen,
|
|
7782
|
+
onItemCreate,
|
|
7662
7783
|
onItemBack,
|
|
7663
7784
|
onItemPrev,
|
|
7664
7785
|
onItemNext,
|
|
7665
7786
|
itemPosition,
|
|
7666
|
-
itemViewCtx} = useShellNavigation({
|
|
7787
|
+
itemViewCtx: baseItemViewCtx} = useShellNavigation({
|
|
7667
7788
|
isCollection,
|
|
7668
7789
|
runWithGuard,
|
|
7669
7790
|
selectedItemId,
|
|
@@ -7683,6 +7804,7 @@ function RecordsAdminShellInner(props) {
|
|
|
7683
7804
|
hooks: props.hooks,
|
|
7684
7805
|
lastAppliedDLRef
|
|
7685
7806
|
});
|
|
7807
|
+
const itemViewCtx = baseItemViewCtx;
|
|
7686
7808
|
const renderEditorWithPreview = () => {
|
|
7687
7809
|
if (!editingTargetScope) return null;
|
|
7688
7810
|
const previewBody = renderPreview && effectivePreviewScope ? renderPreview({ resolved: editorCtx.value, previewScope: effectivePreviewScope }) : null;
|
|
@@ -8148,6 +8270,7 @@ function RecordsAdminShellInner(props) {
|
|
|
8148
8270
|
});
|
|
8149
8271
|
};
|
|
8150
8272
|
onLeftSelectRef.current = onLeftSelect;
|
|
8273
|
+
onCreateItemDraftRef.current = onItemCreate;
|
|
8151
8274
|
return /* @__PURE__ */ jsx(RuleLabelLookupProvider, { value: ruleLabelLookup, children: /* @__PURE__ */ jsxs(
|
|
8152
8275
|
"div",
|
|
8153
8276
|
{
|
|
@@ -8176,7 +8299,7 @@ function RecordsAdminShellInner(props) {
|
|
|
8176
8299
|
}
|
|
8177
8300
|
);
|
|
8178
8301
|
})(),
|
|
8179
|
-
/* @__PURE__ */ jsxs("div", { className: "px-
|
|
8302
|
+
/* @__PURE__ */ jsxs("div", { className: "px-2 pt-2 space-y-2", children: [
|
|
8180
8303
|
intro && !dismissed && !(headerWillRender && resolvedReopenAffordance === "header") && /* @__PURE__ */ jsx(
|
|
8181
8304
|
IntroCard,
|
|
8182
8305
|
{
|
|
@@ -8488,6 +8611,7 @@ function RecordsAdminShellInner(props) {
|
|
|
8488
8611
|
),
|
|
8489
8612
|
renderGroupActions: renderRuleGroupActions,
|
|
8490
8613
|
rowClipboard,
|
|
8614
|
+
rowActions: wrappedRecordActions,
|
|
8491
8615
|
i18n
|
|
8492
8616
|
}
|
|
8493
8617
|
),
|
|
@@ -8586,6 +8710,8 @@ function RecordsAdminShellInner(props) {
|
|
|
8586
8710
|
itemColumns,
|
|
8587
8711
|
cardSize: itemCardSize,
|
|
8588
8712
|
ruleSummary: activeRuleSummary,
|
|
8713
|
+
rowActions: wrappedRecordActions,
|
|
8714
|
+
rowClipboard,
|
|
8589
8715
|
i18n
|
|
8590
8716
|
}
|
|
8591
8717
|
),
|
|
@@ -8672,7 +8798,41 @@ var RecordBrowser = ({
|
|
|
8672
8798
|
scopesLoading,
|
|
8673
8799
|
i18n
|
|
8674
8800
|
}) => {
|
|
8675
|
-
|
|
8801
|
+
const rootRef = useRef(null);
|
|
8802
|
+
const searchRef = useRef(null);
|
|
8803
|
+
useEffect(() => {
|
|
8804
|
+
const root = rootRef.current;
|
|
8805
|
+
if (!root) return;
|
|
8806
|
+
const handler = (e) => {
|
|
8807
|
+
if (e.key !== "/" || e.metaKey || e.ctrlKey || e.altKey) return;
|
|
8808
|
+
const target = e.target;
|
|
8809
|
+
if (!target || !root.contains(target)) return;
|
|
8810
|
+
const tag = target.tagName;
|
|
8811
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || target.isContentEditable) return;
|
|
8812
|
+
e.preventDefault();
|
|
8813
|
+
searchRef.current?.focus();
|
|
8814
|
+
searchRef.current?.select();
|
|
8815
|
+
};
|
|
8816
|
+
root.addEventListener("keydown", handler);
|
|
8817
|
+
return () => root.removeEventListener("keydown", handler);
|
|
8818
|
+
}, []);
|
|
8819
|
+
const onSearchKeyDown = (e) => {
|
|
8820
|
+
if (e.key === "Escape") {
|
|
8821
|
+
if (search) {
|
|
8822
|
+
e.preventDefault();
|
|
8823
|
+
onSearchChange("");
|
|
8824
|
+
} else {
|
|
8825
|
+
e.currentTarget.blur();
|
|
8826
|
+
}
|
|
8827
|
+
} else if (e.key === "ArrowDown") {
|
|
8828
|
+
const first = rootRef.current?.querySelector("button.ra-row-hit");
|
|
8829
|
+
if (first) {
|
|
8830
|
+
e.preventDefault();
|
|
8831
|
+
first.focus();
|
|
8832
|
+
}
|
|
8833
|
+
}
|
|
8834
|
+
};
|
|
8835
|
+
return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: "flex flex-col h-full", style: { background: "hsl(var(--ra-surface))" }, children: [
|
|
8676
8836
|
/* @__PURE__ */ jsx(ScopeTabs, { scopes, active: activeScope, onChange: onActiveScopeChange, loading: scopesLoading }),
|
|
8677
8837
|
/* @__PURE__ */ jsxs("div", { className: "p-3 space-y-2.5 border-b", style: { borderColor: "hsl(var(--ra-border))" }, children: [
|
|
8678
8838
|
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
@@ -8680,9 +8840,11 @@ var RecordBrowser = ({
|
|
|
8680
8840
|
/* @__PURE__ */ jsx(
|
|
8681
8841
|
"input",
|
|
8682
8842
|
{
|
|
8843
|
+
ref: searchRef,
|
|
8683
8844
|
type: "text",
|
|
8684
8845
|
value: search,
|
|
8685
8846
|
onChange: (e) => onSearchChange(e.target.value),
|
|
8847
|
+
onKeyDown: onSearchKeyDown,
|
|
8686
8848
|
placeholder: i18n.searchPlaceholder,
|
|
8687
8849
|
className: "w-full pl-8 pr-3 py-1.5 text-xs rounded-md border bg-transparent focus:outline-none focus:ring-1",
|
|
8688
8850
|
style: {
|
|
@@ -8717,7 +8879,7 @@ var RecordBrowser = ({
|
|
|
8717
8879
|
};
|
|
8718
8880
|
var initials2 = (s) => s.split(/\s+/).filter(Boolean).slice(0, 2).map((p) => p[0]?.toUpperCase() ?? "").join("") || "?";
|
|
8719
8881
|
var DefaultRecordCard = ({ record, ctx, variant = "grid" }) => {
|
|
8720
|
-
const { selected, onSelect, isDirty, hasError, onCopy,
|
|
8882
|
+
const { selected, onSelect, isDirty, hasError, onCopy, onDuplicate, actions } = ctx;
|
|
8721
8883
|
const aspect = variant === "gallery" ? "aspect-video" : "aspect-square";
|
|
8722
8884
|
return /* @__PURE__ */ jsxs(
|
|
8723
8885
|
"button",
|
|
@@ -8778,20 +8940,15 @@ var DefaultRecordCard = ({ record, ctx, variant = "grid" }) => {
|
|
|
8778
8940
|
/* @__PURE__ */ jsxs("div", { className: "p-2.5 min-w-0", children: [
|
|
8779
8941
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-1.5 min-w-0", children: [
|
|
8780
8942
|
/* @__PURE__ */ jsx("div", { className: "ra-row-title flex-1 min-w-0", children: record.label }),
|
|
8781
|
-
(onCopy ||
|
|
8943
|
+
(onCopy || onDuplicate || actions && actions.length > 0) && /* @__PURE__ */ jsx(
|
|
8782
8944
|
RowContextMenu,
|
|
8783
8945
|
{
|
|
8784
8946
|
onCopy,
|
|
8785
|
-
|
|
8786
|
-
|
|
8787
|
-
pasteWillReplace,
|
|
8788
|
-
pasteSourceLabel: clipboardSourceLabel,
|
|
8947
|
+
onDuplicate,
|
|
8948
|
+
actions,
|
|
8789
8949
|
i18n: {
|
|
8790
8950
|
copy: DEFAULT_I18N.copy,
|
|
8791
|
-
|
|
8792
|
-
pasteFrom: DEFAULT_I18N.pasteFrom,
|
|
8793
|
-
pasteReplace: DEFAULT_I18N.pasteReplace,
|
|
8794
|
-
clipboardEmpty: DEFAULT_I18N.clipboardEmpty
|
|
8951
|
+
duplicateAction: DEFAULT_I18N.duplicateAction
|
|
8795
8952
|
}
|
|
8796
8953
|
}
|
|
8797
8954
|
)
|