@proveanything/smartlinks-utils-ui 0.10.6 → 0.10.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{IconPicker-BMMQLR5I.d.ts → IconPicker-DKpL5Hcc.d.ts} +1 -1
- package/dist/chunk-2MW54ZVG.js +92 -0
- package/dist/chunk-2MW54ZVG.js.map +1 -0
- package/dist/components/AssetPicker/index.d.ts +1 -1
- package/dist/components/IconPicker/index.d.ts +2 -2
- package/dist/components/RecordsAdmin/index.d.ts +30 -2
- package/dist/components/RecordsAdmin/index.js +125 -110
- package/dist/components/RecordsAdmin/index.js.map +1 -1
- package/dist/index.css +182 -182
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +62 -4
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/{useAssets-BM1bzzkq.d.ts → useAssets-BAtXv6D5.d.ts} +1 -1
- package/package.json +1 -1
|
@@ -40,4 +40,4 @@ interface IconPickerProps {
|
|
|
40
40
|
|
|
41
41
|
declare const IconPicker: React$1.FC<IconPickerProps>;
|
|
42
42
|
|
|
43
|
-
export {
|
|
43
|
+
export { type IconFamily as I, type IconStyle as a, IconPicker as b, type IconPickerProps as c, type IconSelection as d };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { useId } from 'react';
|
|
2
|
+
import { BookOpen, HelpCircle, AlertTriangle, CheckCircle2, Lightbulb, Info, X } from 'lucide-react';
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
// src/components/AdminPageHeader/AdminPageHeader.tsx
|
|
6
|
+
var TONE_ICON = {
|
|
7
|
+
info: Lightbulb,
|
|
8
|
+
success: CheckCircle2,
|
|
9
|
+
warning: AlertTriangle
|
|
10
|
+
};
|
|
11
|
+
function AdminPageHeader({
|
|
12
|
+
title,
|
|
13
|
+
subtitle,
|
|
14
|
+
icon,
|
|
15
|
+
helpUrl,
|
|
16
|
+
helpLabel,
|
|
17
|
+
actions,
|
|
18
|
+
aside,
|
|
19
|
+
intro,
|
|
20
|
+
className
|
|
21
|
+
}) {
|
|
22
|
+
const titleId = useId();
|
|
23
|
+
const resolvedHelpLabel = helpLabel ?? "Help & documentation";
|
|
24
|
+
const resolvedReopenLabel = intro?.reopenLabel ?? "How it works";
|
|
25
|
+
const showReopen = !!intro && intro.dismissed && !!intro.onReopen;
|
|
26
|
+
const showIntro = !!intro && !intro.dismissed;
|
|
27
|
+
return /* @__PURE__ */ jsxs("header", { className: `sl-aph${className ? ` ${className}` : ""}`, "aria-labelledby": titleId, children: [
|
|
28
|
+
/* @__PURE__ */ jsxs("div", { className: "sl-aph__row", children: [
|
|
29
|
+
/* @__PURE__ */ jsx("div", { className: "sl-aph__main", children: /* @__PURE__ */ jsxs("div", { className: "sl-aph__text", children: [
|
|
30
|
+
/* @__PURE__ */ jsxs("h1", { className: "sl-aph__title", id: titleId, children: [
|
|
31
|
+
icon ? /* @__PURE__ */ jsx("span", { className: "sl-aph__icon", "aria-hidden": "true", children: icon }) : null,
|
|
32
|
+
/* @__PURE__ */ jsx("span", { children: title })
|
|
33
|
+
] }),
|
|
34
|
+
subtitle ? /* @__PURE__ */ jsx("p", { className: "sl-aph__subtitle", children: subtitle }) : null
|
|
35
|
+
] }) }),
|
|
36
|
+
actions || aside || helpUrl || showReopen ? /* @__PURE__ */ jsxs("div", { className: "sl-aph__aside", children: [
|
|
37
|
+
actions,
|
|
38
|
+
aside,
|
|
39
|
+
helpUrl ? /* @__PURE__ */ jsx(
|
|
40
|
+
"a",
|
|
41
|
+
{
|
|
42
|
+
href: helpUrl,
|
|
43
|
+
target: "_blank",
|
|
44
|
+
rel: "noopener noreferrer",
|
|
45
|
+
className: "sl-aph__icon-btn",
|
|
46
|
+
"aria-label": resolvedHelpLabel,
|
|
47
|
+
title: resolvedHelpLabel,
|
|
48
|
+
children: /* @__PURE__ */ jsx(BookOpen, { "aria-hidden": "true" })
|
|
49
|
+
}
|
|
50
|
+
) : null,
|
|
51
|
+
showReopen ? /* @__PURE__ */ jsx(
|
|
52
|
+
"button",
|
|
53
|
+
{
|
|
54
|
+
type: "button",
|
|
55
|
+
onClick: intro.onReopen,
|
|
56
|
+
className: "sl-aph__icon-btn",
|
|
57
|
+
"aria-label": resolvedReopenLabel,
|
|
58
|
+
title: resolvedReopenLabel,
|
|
59
|
+
children: /* @__PURE__ */ jsx(HelpCircle, { "aria-hidden": "true" })
|
|
60
|
+
}
|
|
61
|
+
) : null
|
|
62
|
+
] }) : null
|
|
63
|
+
] }),
|
|
64
|
+
showIntro ? /* @__PURE__ */ jsx(AdminPageHeaderIntroCard, { intro }) : null
|
|
65
|
+
] });
|
|
66
|
+
}
|
|
67
|
+
function AdminPageHeaderIntroCard({ intro }) {
|
|
68
|
+
const tone = intro.tone ?? "info";
|
|
69
|
+
const Icon = TONE_ICON[tone] ?? Info;
|
|
70
|
+
return /* @__PURE__ */ jsxs("div", { className: "sl-aph__intro", "data-tone": tone, role: "note", children: [
|
|
71
|
+
/* @__PURE__ */ jsx("div", { className: "sl-aph__intro-icon", children: /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true", style: { width: "0.95rem", height: "0.95rem" } }) }),
|
|
72
|
+
/* @__PURE__ */ jsxs("div", { className: "sl-aph__intro-body", children: [
|
|
73
|
+
/* @__PURE__ */ jsx("h4", { className: "sl-aph__intro-title", children: intro.title }),
|
|
74
|
+
/* @__PURE__ */ jsx("span", { className: "sl-aph__intro-text", children: intro.body }),
|
|
75
|
+
intro.action ? /* @__PURE__ */ jsx("span", { className: "sl-aph__intro-action", children: intro.action }) : null
|
|
76
|
+
] }),
|
|
77
|
+
/* @__PURE__ */ jsx(
|
|
78
|
+
"button",
|
|
79
|
+
{
|
|
80
|
+
type: "button",
|
|
81
|
+
onClick: intro.onDismiss,
|
|
82
|
+
"aria-label": "Dismiss",
|
|
83
|
+
className: "sl-aph__intro-dismiss",
|
|
84
|
+
children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true", style: { width: "0.875rem", height: "0.875rem" } })
|
|
85
|
+
}
|
|
86
|
+
)
|
|
87
|
+
] });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export { AdminPageHeader };
|
|
91
|
+
//# sourceMappingURL=chunk-2MW54ZVG.js.map
|
|
92
|
+
//# sourceMappingURL=chunk-2MW54ZVG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/AdminPageHeader/AdminPageHeader.tsx"],"names":[],"mappings":"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","file":"chunk-2MW54ZVG.js","sourcesContent":["// =============================================================================\r\n// AdminPageHeader\r\n//\r\n// A standardised page header for any SmartLinks admin surface. Designed to be\r\n// used standalone (lightweight apps that don't need the full RecordsAdminShell)\r\n// or composed inside other shells. Supports:\r\n//\r\n// • Inline icon + title + full-width subtitle\r\n// • Right-aligned slot for app-specific actions (e.g. \"+ New\" button)\r\n// • External help link (icon-button that opens docs in a new tab)\r\n// • Optional dismissible intro card with `?` reopen affordance\r\n// • Optional `aside` slot for extra header content (stats strips, etc.)\r\n//\r\n// Styling is self-contained under `.sl-aph` and reuses the shared `--ra-*`\r\n// design tokens with sensible fallbacks, so it themes correctly whether the\r\n// host has loaded the records-admin token sheet or not.\r\n// =============================================================================\r\nimport { type ReactNode, useId } from 'react';\r\nimport { BookOpen, HelpCircle, X, Lightbulb, CheckCircle2, AlertTriangle, Info } from 'lucide-react';\r\nimport './admin-page-header.css';\r\n\r\nexport type AdminPageHeaderIntroTone = 'info' | 'success' | 'warning';\r\n\r\nexport interface AdminPageHeaderIntro {\r\n /** Short headline shown in bold at the start of the intro card. */\r\n title: string;\r\n /** Body content — plain text or rich nodes. */\r\n body: ReactNode;\r\n /** Visual tone — controls icon and surface tint. Default `'info'`. */\r\n tone?: AdminPageHeaderIntroTone;\r\n /** Optional action node rendered inline after the body (e.g. a Learn-more link). */\r\n action?: ReactNode;\r\n /** Whether the intro is currently dismissed. Controlled. */\r\n dismissed: boolean;\r\n /** Called when the user clicks the dismiss `X`. */\r\n onDismiss: () => void;\r\n /**\r\n * Called when the user clicks the reopen `?` button (only rendered when\r\n * dismissed is true). Omit to hide the reopen affordance entirely.\r\n */\r\n onReopen?: () => void;\r\n /** Tooltip / aria-label for the reopen button. Default \"How it works\". */\r\n reopenLabel?: string;\r\n}\r\n\r\nexport interface AdminPageHeaderProps {\r\n /** Page title — required. */\r\n title: string;\r\n /** Single-line muted subtitle under the title. */\r\n subtitle?: string;\r\n /** Icon rendered inline before the title. Pass a Lucide element or any node. */\r\n icon?: ReactNode;\r\n /**\r\n * External help / documentation URL. When set, renders a small icon-button\r\n * that opens the URL in a new tab. Use this to point at app-specific docs.\r\n */\r\n helpUrl?: string;\r\n /** Tooltip / aria-label for the help link. Default \"Help & documentation\". */\r\n helpLabel?: string;\r\n /**\r\n * Right-aligned action slot — typically a primary \"+ New\" button and/or\r\n * secondary controls. Rendered before the help / intro-reopen icon-buttons.\r\n */\r\n actions?: ReactNode;\r\n /**\r\n * Extra header content rendered between `actions` and the trailing\r\n * help / reopen icon-buttons. Used by RecordsAdminShell for its stats strip;\r\n * standalone apps rarely need it.\r\n */\r\n aside?: ReactNode;\r\n /**\r\n * Optional dismissible intro card rendered below the header row.\r\n * See {@link AdminPageHeaderIntro}.\r\n */\r\n intro?: AdminPageHeaderIntro;\r\n /** Extra class on the root container for layout overrides. */\r\n className?: string;\r\n}\r\n\r\nconst TONE_ICON = {\r\n info: Lightbulb,\r\n success: CheckCircle2,\r\n warning: AlertTriangle,\r\n} as const;\r\n\r\nexport function AdminPageHeader({\r\n title, subtitle, icon, helpUrl, helpLabel,\r\n actions, aside, intro, className,\r\n}: AdminPageHeaderProps) {\r\n const titleId = useId();\r\n const resolvedHelpLabel = helpLabel ?? 'Help & documentation';\r\n const resolvedReopenLabel = intro?.reopenLabel ?? 'How it works';\r\n const showReopen = !!intro && intro.dismissed && !!intro.onReopen;\r\n const showIntro = !!intro && !intro.dismissed;\r\n\r\n return (\r\n <header className={`sl-aph${className ? ` ${className}` : ''}`} aria-labelledby={titleId}>\r\n <div className=\"sl-aph__row\">\r\n <div className=\"sl-aph__main\">\r\n <div className=\"sl-aph__text\">\r\n <h1 className=\"sl-aph__title\" id={titleId}>\r\n {icon ? (\r\n <span className=\"sl-aph__icon\" aria-hidden=\"true\">{icon}</span>\r\n ) : null}\r\n <span>{title}</span>\r\n </h1>\r\n {subtitle ? <p className=\"sl-aph__subtitle\">{subtitle}</p> : null}\r\n </div>\r\n </div>\r\n {(actions || aside || helpUrl || showReopen) ? (\r\n <div className=\"sl-aph__aside\">\r\n {actions}\r\n {aside}\r\n {helpUrl ? (\r\n <a\r\n href={helpUrl}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"sl-aph__icon-btn\"\r\n aria-label={resolvedHelpLabel}\r\n title={resolvedHelpLabel}\r\n >\r\n <BookOpen aria-hidden=\"true\" />\r\n </a>\r\n ) : null}\r\n {showReopen ? (\r\n <button\r\n type=\"button\"\r\n onClick={intro!.onReopen}\r\n className=\"sl-aph__icon-btn\"\r\n aria-label={resolvedReopenLabel}\r\n title={resolvedReopenLabel}\r\n >\r\n <HelpCircle aria-hidden=\"true\" />\r\n </button>\r\n ) : null}\r\n </div>\r\n ) : null}\r\n </div>\r\n {showIntro ? <AdminPageHeaderIntroCard intro={intro!} /> : null}\r\n </header>\r\n );\r\n}\r\n\r\nfunction AdminPageHeaderIntroCard({ intro }: { intro: AdminPageHeaderIntro }) {\r\n const tone = intro.tone ?? 'info';\r\n const Icon = TONE_ICON[tone] ?? Info;\r\n return (\r\n <div className=\"sl-aph__intro\" data-tone={tone} role=\"note\">\r\n <div className=\"sl-aph__intro-icon\">\r\n <Icon aria-hidden=\"true\" style={{ width: '0.95rem', height: '0.95rem' }} />\r\n </div>\r\n <div className=\"sl-aph__intro-body\">\r\n <h4 className=\"sl-aph__intro-title\">{intro.title}</h4>\r\n <span className=\"sl-aph__intro-text\">{intro.body}</span>\r\n {intro.action ? <span className=\"sl-aph__intro-action\">{intro.action}</span> : null}\r\n </div>\r\n <button\r\n type=\"button\"\r\n onClick={intro.onDismiss}\r\n aria-label=\"Dismiss\"\r\n className=\"sl-aph__intro-dismiss\"\r\n >\r\n <X aria-hidden=\"true\" style={{ width: '0.875rem', height: '0.875rem' }} />\r\n </button>\r\n </div>\r\n );\r\n}"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { A as AssetItem, a as AssetPicker, b as AssetPickerMode, c as AssetPickerProps, d as AssetPickerSelection, e as AssetScope, f as AssetViewMode, u as useAssets } from '../../useAssets-BAtXv6D5.js';
|
|
2
2
|
import 'react';
|
|
3
3
|
|
|
4
4
|
interface AppRegistryEntry {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { I as IconFamily, a as IconStyle } from '../../IconPicker-DKpL5Hcc.js';
|
|
2
|
+
export { b as IconPicker, c as IconPickerProps, d as IconSelection } from '../../IconPicker-DKpL5Hcc.js';
|
|
3
3
|
import 'react';
|
|
4
4
|
|
|
5
5
|
declare function toFaClass(id: string, family: IconFamily, style: IconStyle | null): string;
|
|
@@ -962,7 +962,35 @@ interface RailConfig<TData = unknown> {
|
|
|
962
962
|
key: string;
|
|
963
963
|
label: string;
|
|
964
964
|
icon?: ReactNode;
|
|
965
|
+
/**
|
|
966
|
+
* Whether this bucket should be expanded by default (records-driven
|
|
967
|
+
* accordion mode). Last-write-wins per key. Has no effect in the
|
|
968
|
+
* collection-cardinality lifecycle-rail mode where buckets are flat
|
|
969
|
+
* selectable rows rather than accordion sections.
|
|
970
|
+
*/
|
|
971
|
+
defaultOpen?: boolean;
|
|
972
|
+
/**
|
|
973
|
+
* Semantic tone for the bucket — drives a CSS data attribute on the
|
|
974
|
+
* lifecycle bucket row (`data-tone="success" | "warning" | "muted"`).
|
|
975
|
+
* Apps style via `[data-tone="…"]` selectors against existing
|
|
976
|
+
* semantic tokens.
|
|
977
|
+
*/
|
|
978
|
+
tone?: 'default' | 'success' | 'warning' | 'muted' | 'danger';
|
|
965
979
|
} | null;
|
|
980
|
+
/**
|
|
981
|
+
* Initial bucket key to select on first mount of the lifecycle rail
|
|
982
|
+
* (collection cardinality + `'all'` / `'global'` scope + `groupBy`).
|
|
983
|
+
* Ignored when a deep-link state restores a different selection. Pass
|
|
984
|
+
* the same key shape your `groupBy` returns (e.g. `"1-open"`).
|
|
985
|
+
*/
|
|
986
|
+
defaultGroupKey?: string;
|
|
987
|
+
/**
|
|
988
|
+
* EXPERIMENTAL — invoked the first time a lifecycle bucket is selected
|
|
989
|
+
* (collection-cardinality lifecycle rail). Hosts can use this to trigger
|
|
990
|
+
* supplemental fetches before the bucket-filtered table renders. May be
|
|
991
|
+
* called more than once per key. API may change before stabilising.
|
|
992
|
+
*/
|
|
993
|
+
onGroupExpanded?: (key: string) => void;
|
|
966
994
|
/** Visual density. Default `comfortable`. */
|
|
967
995
|
density?: 'comfortable' | 'compact';
|
|
968
996
|
}
|
|
@@ -1696,7 +1724,7 @@ declare const useRecordList: (args: UseRecordListArgs) => {
|
|
|
1696
1724
|
};
|
|
1697
1725
|
isLoading: boolean;
|
|
1698
1726
|
error: Error | null;
|
|
1699
|
-
refetch: () => void
|
|
1727
|
+
refetch: () => Promise<void>;
|
|
1700
1728
|
hasNextPage: boolean;
|
|
1701
1729
|
isFetchingNextPage: boolean;
|
|
1702
1730
|
fetchNextPage: (options?: _tanstack_query_core.FetchNextPageOptions) => Promise<_tanstack_query_core.InfiniteQueryObserverResult<_tanstack_query_core.InfiniteData<{
|
|
@@ -1841,7 +1869,7 @@ declare function useCollectionItems<T = unknown>(args: UseCollectionItemsArgs):
|
|
|
1841
1869
|
hasMore: boolean;
|
|
1842
1870
|
nextOffset: number;
|
|
1843
1871
|
}, unknown>, Error>>;
|
|
1844
|
-
refetch: () => void
|
|
1872
|
+
refetch: () => Promise<void>;
|
|
1845
1873
|
};
|
|
1846
1874
|
|
|
1847
1875
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AdminPageHeader } from '../../chunk-2MW54ZVG.js';
|
|
1
2
|
import { assertComponentStylesLoaded } from '../../chunk-OLYC54YT.js';
|
|
2
3
|
import '../../chunk-5UQQYXCX.js';
|
|
3
4
|
import { FacetRuleEditor } from '../../chunk-JMCV6FOW.js';
|
|
@@ -5,8 +6,8 @@ import { useFacets } from '../../chunk-4LHF5JB7.js';
|
|
|
5
6
|
import { cn } from '../../chunk-L7FQ52F5.js';
|
|
6
7
|
import { parsedRefToTarget, parsedRefToScope, matchRecords, scopesEqual, getRecordById, listRecords, upsertRecord, updateRecord, createRecord, removeRecord } from '../../chunk-KA4MKRHL.js';
|
|
7
8
|
export { bulkDelete, bulkUpsert, createRecord, getRecordById, listRecords, matchRecords, parsedRefToScope, parsedRefToTarget, removeRecord, restoreRecord, scopesEqual, upsertRecord } from '../../chunk-KA4MKRHL.js';
|
|
8
|
-
import { createContext, useState, useEffect, useCallback, useMemo, useRef, useContext, useSyncExternalStore, useLayoutEffect, createElement
|
|
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,
|
|
9
|
+
import { createContext, useState, useEffect, useCallback, useMemo, useRef, useContext, useSyncExternalStore, useLayoutEffect, createElement } from 'react';
|
|
10
|
+
import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, List, SlidersHorizontal, Globe, Tag, Boxes, Layers, Package, Target, Rows3, ChevronRight, Eraser, ClipboardPaste, Box, X, Search, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, CornerDownLeft, Circle, CopyPlus, AlertCircle, Undo2, Save, Loader2, XCircle, ArrowRight, Globe2, Check, Settings2 } from 'lucide-react';
|
|
10
11
|
import { useQuery, useQueryClient, useInfiniteQuery } from '@tanstack/react-query';
|
|
11
12
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
12
13
|
import { createPortal } from 'react-dom';
|
|
@@ -690,9 +691,9 @@ var useRecordList = (args) => {
|
|
|
690
691
|
partial: items.filter((r) => r.status === "partial").length,
|
|
691
692
|
empty: items.filter((r) => r.status === "empty").length
|
|
692
693
|
}), [items]);
|
|
693
|
-
const refetch = useCallback(() => {
|
|
694
|
-
|
|
695
|
-
}, [queryClient, ctx.collectionId, ctx.appId, ctx.recordType]);
|
|
694
|
+
const refetch = useCallback(() => queryClient.refetchQueries({
|
|
695
|
+
queryKey: [...QK_BASE2, ctx.collectionId, ctx.appId, ctx.recordType]
|
|
696
|
+
}), [queryClient, ctx.collectionId, ctx.appId, ctx.recordType]);
|
|
696
697
|
const total = query.data?.pages[query.data.pages.length - 1]?.total ?? items.length;
|
|
697
698
|
return {
|
|
698
699
|
allItems: items,
|
|
@@ -3125,9 +3126,11 @@ var useShellSelection = (args) => {
|
|
|
3125
3126
|
}, [contextScope?.batchId]);
|
|
3126
3127
|
const [selectedItemId, setSelectedItemId] = useState(null);
|
|
3127
3128
|
const skipNextItemResetRef = useRef(false);
|
|
3129
|
+
const [selectedLifecycleKey, setSelectedLifecycleKey] = useState(null);
|
|
3128
3130
|
useEffect(() => {
|
|
3129
3131
|
setSelectedRecordId(null);
|
|
3130
3132
|
setDraftKind(null);
|
|
3133
|
+
setSelectedLifecycleKey(null);
|
|
3131
3134
|
}, [activeScope]);
|
|
3132
3135
|
return {
|
|
3133
3136
|
activeScope,
|
|
@@ -3150,6 +3153,8 @@ var useShellSelection = (args) => {
|
|
|
3150
3153
|
setSelectedBatchId,
|
|
3151
3154
|
selectedItemId,
|
|
3152
3155
|
setSelectedItemId,
|
|
3156
|
+
selectedLifecycleKey,
|
|
3157
|
+
setSelectedLifecycleKey,
|
|
3153
3158
|
skipNextItemResetRef
|
|
3154
3159
|
};
|
|
3155
3160
|
};
|
|
@@ -4086,9 +4091,7 @@ function useCollectionItems(args) {
|
|
|
4086
4091
|
return toSummary2(rec, base);
|
|
4087
4092
|
}).filter((x) => x !== null);
|
|
4088
4093
|
}, [query.data, toSummary2, scope, ruleSignature, includeAll]);
|
|
4089
|
-
const refetch = useCallback(() => {
|
|
4090
|
-
queryClient.invalidateQueries({ queryKey });
|
|
4091
|
-
}, [queryClient, queryKey]);
|
|
4094
|
+
const refetch = useCallback(() => queryClient.refetchQueries({ queryKey }), [queryClient, queryKey]);
|
|
4092
4095
|
return {
|
|
4093
4096
|
items,
|
|
4094
4097
|
total: query.data?.pages[query.data.pages.length - 1]?.total ?? items.length,
|
|
@@ -6193,89 +6196,6 @@ var UtilityRow = ({ label, customLabel, introHidden, onShowIntro }) => {
|
|
|
6193
6196
|
}
|
|
6194
6197
|
);
|
|
6195
6198
|
};
|
|
6196
|
-
var TONE_ICON2 = {
|
|
6197
|
-
info: Lightbulb,
|
|
6198
|
-
success: CheckCircle2,
|
|
6199
|
-
warning: AlertTriangle
|
|
6200
|
-
};
|
|
6201
|
-
function AdminPageHeader({
|
|
6202
|
-
title,
|
|
6203
|
-
subtitle,
|
|
6204
|
-
icon,
|
|
6205
|
-
helpUrl,
|
|
6206
|
-
helpLabel,
|
|
6207
|
-
actions,
|
|
6208
|
-
aside,
|
|
6209
|
-
intro,
|
|
6210
|
-
className
|
|
6211
|
-
}) {
|
|
6212
|
-
const titleId = useId();
|
|
6213
|
-
const resolvedHelpLabel = helpLabel ?? "Help & documentation";
|
|
6214
|
-
const resolvedReopenLabel = intro?.reopenLabel ?? "How it works";
|
|
6215
|
-
const showReopen = !!intro && intro.dismissed && !!intro.onReopen;
|
|
6216
|
-
const showIntro = !!intro && !intro.dismissed;
|
|
6217
|
-
return /* @__PURE__ */ jsxs("header", { className: `sl-aph${className ? ` ${className}` : ""}`, "aria-labelledby": titleId, children: [
|
|
6218
|
-
/* @__PURE__ */ jsxs("div", { className: "sl-aph__row", children: [
|
|
6219
|
-
/* @__PURE__ */ jsx("div", { className: "sl-aph__main", children: /* @__PURE__ */ jsxs("div", { className: "sl-aph__text", children: [
|
|
6220
|
-
/* @__PURE__ */ jsxs("h1", { className: "sl-aph__title", id: titleId, children: [
|
|
6221
|
-
icon ? /* @__PURE__ */ jsx("span", { className: "sl-aph__icon", "aria-hidden": "true", children: icon }) : null,
|
|
6222
|
-
/* @__PURE__ */ jsx("span", { children: title })
|
|
6223
|
-
] }),
|
|
6224
|
-
subtitle ? /* @__PURE__ */ jsx("p", { className: "sl-aph__subtitle", children: subtitle }) : null
|
|
6225
|
-
] }) }),
|
|
6226
|
-
actions || aside || helpUrl || showReopen ? /* @__PURE__ */ jsxs("div", { className: "sl-aph__aside", children: [
|
|
6227
|
-
actions,
|
|
6228
|
-
aside,
|
|
6229
|
-
helpUrl ? /* @__PURE__ */ jsx(
|
|
6230
|
-
"a",
|
|
6231
|
-
{
|
|
6232
|
-
href: helpUrl,
|
|
6233
|
-
target: "_blank",
|
|
6234
|
-
rel: "noopener noreferrer",
|
|
6235
|
-
className: "sl-aph__icon-btn",
|
|
6236
|
-
"aria-label": resolvedHelpLabel,
|
|
6237
|
-
title: resolvedHelpLabel,
|
|
6238
|
-
children: /* @__PURE__ */ jsx(BookOpen, { "aria-hidden": "true" })
|
|
6239
|
-
}
|
|
6240
|
-
) : null,
|
|
6241
|
-
showReopen ? /* @__PURE__ */ jsx(
|
|
6242
|
-
"button",
|
|
6243
|
-
{
|
|
6244
|
-
type: "button",
|
|
6245
|
-
onClick: intro.onReopen,
|
|
6246
|
-
className: "sl-aph__icon-btn",
|
|
6247
|
-
"aria-label": resolvedReopenLabel,
|
|
6248
|
-
title: resolvedReopenLabel,
|
|
6249
|
-
children: /* @__PURE__ */ jsx(HelpCircle, { "aria-hidden": "true" })
|
|
6250
|
-
}
|
|
6251
|
-
) : null
|
|
6252
|
-
] }) : null
|
|
6253
|
-
] }),
|
|
6254
|
-
showIntro ? /* @__PURE__ */ jsx(AdminPageHeaderIntroCard, { intro }) : null
|
|
6255
|
-
] });
|
|
6256
|
-
}
|
|
6257
|
-
function AdminPageHeaderIntroCard({ intro }) {
|
|
6258
|
-
const tone = intro.tone ?? "info";
|
|
6259
|
-
const Icon = TONE_ICON2[tone] ?? Info;
|
|
6260
|
-
return /* @__PURE__ */ jsxs("div", { className: "sl-aph__intro", "data-tone": tone, role: "note", children: [
|
|
6261
|
-
/* @__PURE__ */ jsx("div", { className: "sl-aph__intro-icon", children: /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true", style: { width: "0.95rem", height: "0.95rem" } }) }),
|
|
6262
|
-
/* @__PURE__ */ jsxs("div", { className: "sl-aph__intro-body", children: [
|
|
6263
|
-
/* @__PURE__ */ jsx("h4", { className: "sl-aph__intro-title", children: intro.title }),
|
|
6264
|
-
/* @__PURE__ */ jsx("span", { className: "sl-aph__intro-text", children: intro.body }),
|
|
6265
|
-
intro.action ? /* @__PURE__ */ jsx("span", { className: "sl-aph__intro-action", children: intro.action }) : null
|
|
6266
|
-
] }),
|
|
6267
|
-
/* @__PURE__ */ jsx(
|
|
6268
|
-
"button",
|
|
6269
|
-
{
|
|
6270
|
-
type: "button",
|
|
6271
|
-
onClick: intro.onDismiss,
|
|
6272
|
-
"aria-label": "Dismiss",
|
|
6273
|
-
className: "sl-aph__intro-dismiss",
|
|
6274
|
-
children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true", style: { width: "0.875rem", height: "0.875rem" } })
|
|
6275
|
-
}
|
|
6276
|
-
)
|
|
6277
|
-
] });
|
|
6278
|
-
}
|
|
6279
6199
|
function ShellHeader({
|
|
6280
6200
|
title,
|
|
6281
6201
|
subtitle,
|
|
@@ -7452,6 +7372,8 @@ function RecordsAdminShellInner(props) {
|
|
|
7452
7372
|
renderListRow,
|
|
7453
7373
|
renderEmpty: renderEmptyState,
|
|
7454
7374
|
groupBy,
|
|
7375
|
+
defaultGroupKey,
|
|
7376
|
+
onGroupExpanded,
|
|
7455
7377
|
density = "comfortable"
|
|
7456
7378
|
} = rail ?? {};
|
|
7457
7379
|
const {
|
|
@@ -7592,8 +7514,11 @@ function RecordsAdminShellInner(props) {
|
|
|
7592
7514
|
setSelectedBatchId,
|
|
7593
7515
|
selectedItemId,
|
|
7594
7516
|
setSelectedItemId,
|
|
7517
|
+
selectedLifecycleKey,
|
|
7518
|
+
setSelectedLifecycleKey,
|
|
7595
7519
|
skipNextItemResetRef
|
|
7596
7520
|
} = selection;
|
|
7521
|
+
const [isReconcilingRecordSelection, setIsReconcilingRecordSelection] = useState(false);
|
|
7597
7522
|
const { dismissed, dismiss, undismiss } = useIntroDismissed(SL, collectionId, appId, recordType);
|
|
7598
7523
|
const headerWillRender = useMemo(() => {
|
|
7599
7524
|
const headerCustomised = !!title || !!subtitle || !!headerIcon || !!headerActions || showStats || !!statsItems || !!statsTitle || !!statsIcon || !!helpUrl;
|
|
@@ -7654,6 +7579,7 @@ function RecordsAdminShellInner(props) {
|
|
|
7654
7579
|
useEffect(() => {
|
|
7655
7580
|
if (activeScope !== "rule" && activeScope !== "collection" && activeScope !== "all") return;
|
|
7656
7581
|
if (selectedRecordId !== null) return;
|
|
7582
|
+
if (isReconcilingRecordSelection) return;
|
|
7657
7583
|
if (ruleWizardStep !== null) return;
|
|
7658
7584
|
if (draftKind !== null) return;
|
|
7659
7585
|
if (activeScope === "collection" && cardinality === "collection") {
|
|
@@ -7664,7 +7590,7 @@ function RecordsAdminShellInner(props) {
|
|
|
7664
7590
|
}
|
|
7665
7591
|
const first = recordList.items[0];
|
|
7666
7592
|
if (first?.id) setSelectedRecordId(first.id);
|
|
7667
|
-
}, [activeScope, selectedRecordId, recordList.items, cardinality, ruleWizardStep, draftKind]);
|
|
7593
|
+
}, [activeScope, selectedRecordId, recordList.items, cardinality, ruleWizardStep, draftKind, isReconcilingRecordSelection]);
|
|
7668
7594
|
const editingScopes = useEditingScope({
|
|
7669
7595
|
activeScope,
|
|
7670
7596
|
cardinality,
|
|
@@ -7761,14 +7687,15 @@ function RecordsAdminShellInner(props) {
|
|
|
7761
7687
|
supportedScopes: supportedForResolution,
|
|
7762
7688
|
enabled: !!editingTargetScope
|
|
7763
7689
|
});
|
|
7764
|
-
const refetchAll = useCallback(() => {
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7771
|
-
|
|
7690
|
+
const refetchAll = useCallback(async () => {
|
|
7691
|
+
await Promise.all([
|
|
7692
|
+
recordList.refetch(),
|
|
7693
|
+
isCollection ? collectionItems.refetch() : Promise.resolve(),
|
|
7694
|
+
queryClient.refetchQueries({
|
|
7695
|
+
queryKey: scopeCountsQueryKey(ctx.collectionId, ctx.appId, ctx.recordType)
|
|
7696
|
+
})
|
|
7697
|
+
]);
|
|
7698
|
+
}, [recordList, isCollection, collectionItems, queryClient, ctx.collectionId, ctx.appId, ctx.recordType]);
|
|
7772
7699
|
const { editorCtx } = useShellEditorTarget({
|
|
7773
7700
|
editingTargetScope,
|
|
7774
7701
|
isCollection,
|
|
@@ -7787,7 +7714,7 @@ function RecordsAdminShellInner(props) {
|
|
|
7787
7714
|
},
|
|
7788
7715
|
defaultData,
|
|
7789
7716
|
deriveDraftLabel,
|
|
7790
|
-
onSaved: (isCreate, savedRecordId) => {
|
|
7717
|
+
onSaved: async (isCreate, savedRecordId) => {
|
|
7791
7718
|
onTelemetry?.({ type: "record.save", recordType, ref: editingTargetScope?.raw ?? "", isCreate });
|
|
7792
7719
|
if (ruleWizardStep !== null) {
|
|
7793
7720
|
setRuleWizardStep(null);
|
|
@@ -7795,15 +7722,20 @@ function RecordsAdminShellInner(props) {
|
|
|
7795
7722
|
setDraftKind(null);
|
|
7796
7723
|
}
|
|
7797
7724
|
if (isCreate && selectedRecordId === DRAFT_ID3) {
|
|
7798
|
-
|
|
7725
|
+
setIsReconcilingRecordSelection(true);
|
|
7726
|
+
setSelectedRecordId(null);
|
|
7799
7727
|
setDraftKind(null);
|
|
7800
7728
|
}
|
|
7801
7729
|
if (isCreate && isCollection && savedRecordId && isDraftId3(selectedItemId)) {
|
|
7802
7730
|
setSelectedItemId(savedRecordId);
|
|
7803
7731
|
}
|
|
7804
|
-
refetchAll();
|
|
7732
|
+
await refetchAll();
|
|
7733
|
+
if (!isCollection && isCreate && activeScope === "collection") {
|
|
7734
|
+
setSelectedRecordId(savedRecordId ?? null);
|
|
7735
|
+
}
|
|
7736
|
+
setIsReconcilingRecordSelection(false);
|
|
7805
7737
|
},
|
|
7806
|
-
onDeleted: () => {
|
|
7738
|
+
onDeleted: async () => {
|
|
7807
7739
|
onTelemetry?.({ type: "record.delete", recordType, ref: editingTargetScope?.raw ?? "" });
|
|
7808
7740
|
if (isCollection && selectedItemId) {
|
|
7809
7741
|
setSelectedItemId(null);
|
|
@@ -7812,10 +7744,12 @@ function RecordsAdminShellInner(props) {
|
|
|
7812
7744
|
} else if (drillTab === "batch") {
|
|
7813
7745
|
setSelectedBatchId(void 0);
|
|
7814
7746
|
} else if (selectedRecordId) {
|
|
7747
|
+
setIsReconcilingRecordSelection(true);
|
|
7815
7748
|
setSelectedRecordId(null);
|
|
7816
7749
|
setDraftKind(null);
|
|
7817
7750
|
}
|
|
7818
|
-
refetchAll();
|
|
7751
|
+
await refetchAll();
|
|
7752
|
+
setIsReconcilingRecordSelection(false);
|
|
7819
7753
|
}
|
|
7820
7754
|
});
|
|
7821
7755
|
useUnsavedGuard({
|
|
@@ -8419,23 +8353,104 @@ function RecordsAdminShellInner(props) {
|
|
|
8419
8353
|
ref: "",
|
|
8420
8354
|
scope: parseRef(""),
|
|
8421
8355
|
data: null,
|
|
8422
|
-
|
|
8356
|
+
// The dashed/dotted circle is the "empty / not set" affordance. The
|
|
8357
|
+
// synthetic All-items row aggregates every item-level record under the
|
|
8358
|
+
// collection scope, so it should read as "configured" whenever any
|
|
8359
|
+
// items exist — otherwise users see the same missing-data indicator
|
|
8360
|
+
// they (correctly) see next to truly empty rows on the Products tab.
|
|
8361
|
+
status: collectionItems.items.length ? "configured" : "empty",
|
|
8423
8362
|
label: i18n.itemsAllLabel,
|
|
8424
8363
|
subtitle: collectionItems.items.length ? `${collectionItems.items.length} ${itemNoun}${collectionItems.items.length === 1 ? "" : "s"}` : void 0
|
|
8425
8364
|
}),
|
|
8426
8365
|
[i18n.itemsAllLabel, collectionItems.items.length, itemNoun]
|
|
8427
8366
|
);
|
|
8367
|
+
const isLifecycleRail = (isAllTab || isGlobalTab) && isCollection && !!groupBy;
|
|
8368
|
+
const lifecycleBuckets = useMemo(() => {
|
|
8369
|
+
if (!isLifecycleRail || !groupBy) return [];
|
|
8370
|
+
const map = /* @__PURE__ */ new Map();
|
|
8371
|
+
const order = [];
|
|
8372
|
+
for (const item of collectionItems.items) {
|
|
8373
|
+
const g = groupBy(item) ?? { key: "__other", label: "Other" };
|
|
8374
|
+
let bucket = map.get(g.key);
|
|
8375
|
+
if (!bucket) {
|
|
8376
|
+
bucket = { key: g.key, label: g.label, icon: g.icon, tone: g.tone, items: [] };
|
|
8377
|
+
map.set(g.key, bucket);
|
|
8378
|
+
order.push(g.key);
|
|
8379
|
+
}
|
|
8380
|
+
bucket.items.push(item);
|
|
8381
|
+
}
|
|
8382
|
+
return order.sort().map((k) => map.get(k));
|
|
8383
|
+
}, [isLifecycleRail, groupBy, collectionItems.items]);
|
|
8384
|
+
const LIFECYCLE_PREFIX = "lifecycle:";
|
|
8385
|
+
const lifecycleRows = useMemo(() => {
|
|
8386
|
+
if (!isLifecycleRail) return [];
|
|
8387
|
+
const rows = [
|
|
8388
|
+
{
|
|
8389
|
+
id: `${LIFECYCLE_PREFIX}__all`,
|
|
8390
|
+
ref: "",
|
|
8391
|
+
scope: parseRef(""),
|
|
8392
|
+
data: null,
|
|
8393
|
+
status: collectionItems.items.length ? "configured" : "empty",
|
|
8394
|
+
label: i18n.itemsAllLabel,
|
|
8395
|
+
subtitle: collectionItems.items.length ? `${collectionItems.items.length} ${itemNoun}${collectionItems.items.length === 1 ? "" : "s"}` : void 0
|
|
8396
|
+
}
|
|
8397
|
+
];
|
|
8398
|
+
for (const b of lifecycleBuckets) {
|
|
8399
|
+
rows.push({
|
|
8400
|
+
id: `${LIFECYCLE_PREFIX}${b.key}`,
|
|
8401
|
+
ref: "",
|
|
8402
|
+
scope: parseRef(""),
|
|
8403
|
+
data: null,
|
|
8404
|
+
status: b.items.length ? "configured" : "empty",
|
|
8405
|
+
label: b.label,
|
|
8406
|
+
subtitle: `${b.items.length} ${itemNoun}${b.items.length === 1 ? "" : "s"}`,
|
|
8407
|
+
// Tone surfaces as a chip; we reuse `badges` for that.
|
|
8408
|
+
badges: b.tone && b.tone !== "default" ? [{ label: b.tone, tone: b.tone === "success" ? "success" : b.tone === "warning" ? "warning" : b.tone === "danger" ? "danger" : "neutral" }] : void 0
|
|
8409
|
+
});
|
|
8410
|
+
}
|
|
8411
|
+
return rows;
|
|
8412
|
+
}, [isLifecycleRail, lifecycleBuckets, collectionItems.items.length, i18n.itemsAllLabel, itemNoun]);
|
|
8413
|
+
const lifecycleSeededRef = useRef(false);
|
|
8414
|
+
useEffect(() => {
|
|
8415
|
+
if (!isLifecycleRail) {
|
|
8416
|
+
lifecycleSeededRef.current = false;
|
|
8417
|
+
return;
|
|
8418
|
+
}
|
|
8419
|
+
if (lifecycleSeededRef.current) return;
|
|
8420
|
+
if (selectedLifecycleKey !== null) {
|
|
8421
|
+
lifecycleSeededRef.current = true;
|
|
8422
|
+
return;
|
|
8423
|
+
}
|
|
8424
|
+
if (!defaultGroupKey) return;
|
|
8425
|
+
if (!lifecycleBuckets.some((b) => b.key === defaultGroupKey)) return;
|
|
8426
|
+
setSelectedLifecycleKey(defaultGroupKey);
|
|
8427
|
+
lifecycleSeededRef.current = true;
|
|
8428
|
+
}, [isLifecycleRail, defaultGroupKey, lifecycleBuckets, selectedLifecycleKey, setSelectedLifecycleKey]);
|
|
8429
|
+
const filteredCollectionItems = useMemo(() => {
|
|
8430
|
+
if (!isLifecycleRail || !selectedLifecycleKey || !groupBy) return collectionItems.items;
|
|
8431
|
+
return collectionItems.items.filter((it) => {
|
|
8432
|
+
const g = groupBy(it) ?? { key: "__other" };
|
|
8433
|
+
return g.key === selectedLifecycleKey;
|
|
8434
|
+
});
|
|
8435
|
+
}, [isLifecycleRail, selectedLifecycleKey, groupBy, collectionItems.items]);
|
|
8428
8436
|
const leftItems = isProductTab ? productListItems : isRuleTab ? applyFacetBrowseFilter(
|
|
8429
8437
|
isCollection ? collectionRuleRailItems : filteredRuleItems
|
|
8430
|
-
) : (isGlobalTab || isAllTab) && isCollection ? [collectionGlobalAllRow] : isRecordsTab ? applyFacetBrowseFilter(recordList.items) : [];
|
|
8438
|
+
) : isLifecycleRail ? lifecycleRows : (isGlobalTab || isAllTab) && isCollection ? [collectionGlobalAllRow] : isRecordsTab ? applyFacetBrowseFilter(recordList.items) : [];
|
|
8431
8439
|
const leftLoading = isProductTab ? !productPinned && productBrowse.isLoading : isRecordsTab ? recordList.isLoading || probe.isLoading : false;
|
|
8432
8440
|
const leftError = isProductTab ? productBrowse.error : isRecordsTab ? recordList.error : null;
|
|
8433
|
-
const leftSelectedId = isProductTab ? void 0 : selectedRecordId && selectedRecordId !== DRAFT_ID3 ? selectedRecordId : void 0;
|
|
8441
|
+
const leftSelectedId = isProductTab ? void 0 : isLifecycleRail ? `${LIFECYCLE_PREFIX}${selectedLifecycleKey ?? "__all"}` : selectedRecordId && selectedRecordId !== DRAFT_ID3 ? selectedRecordId : void 0;
|
|
8434
8442
|
const leftSelectedAnchorKey = isProductTab ? selectedProductId ? buildRef({ productId: selectedProductId }) : void 0 : void 0;
|
|
8435
8443
|
const dirtyId = !editorCtx.isDirty ? void 0 : selectedRecordId && selectedRecordId !== DRAFT_ID3 ? selectedRecordId : void 0;
|
|
8436
8444
|
const dirtyAnchorKey = !editorCtx.isDirty ? void 0 : isProductTab ? editingScope?.raw : void 0;
|
|
8437
8445
|
const onLeftSelect = (item) => {
|
|
8438
8446
|
void runWithGuard(() => {
|
|
8447
|
+
if (isLifecycleRail && typeof item.id === "string" && item.id.startsWith(LIFECYCLE_PREFIX)) {
|
|
8448
|
+
const key = item.id.slice(LIFECYCLE_PREFIX.length);
|
|
8449
|
+
const next = key === "__all" ? null : key;
|
|
8450
|
+
setSelectedLifecycleKey(next);
|
|
8451
|
+
if (next && onGroupExpanded) onGroupExpanded(next);
|
|
8452
|
+
return;
|
|
8453
|
+
}
|
|
8439
8454
|
if (isProductTab) {
|
|
8440
8455
|
setSelectedProductId(item.scope.productId);
|
|
8441
8456
|
setSelectedVariantId(void 0);
|
|
@@ -8793,7 +8808,7 @@ function RecordsAdminShellInner(props) {
|
|
|
8793
8808
|
// navigational anchor, not a real record — applying the
|
|
8794
8809
|
// host's groupBy bucketed it under "Other" (its
|
|
8795
8810
|
// data is null). Skip grouping for that single-row rail.
|
|
8796
|
-
(isGlobalTab || isAllTab) && isCollection ? void 0 : effectiveGroupBy
|
|
8811
|
+
(isGlobalTab || isAllTab) && isCollection || isLifecycleRail ? void 0 : effectiveGroupBy
|
|
8797
8812
|
),
|
|
8798
8813
|
renderGroupActions: renderRuleGroupActions,
|
|
8799
8814
|
rowClipboard,
|
|
@@ -8882,7 +8897,7 @@ function RecordsAdminShellInner(props) {
|
|
|
8882
8897
|
ruleWizardStep === null && isCollection && editingScope && !selectedItemId && /* @__PURE__ */ jsx(
|
|
8883
8898
|
ItemListView,
|
|
8884
8899
|
{
|
|
8885
|
-
items:
|
|
8900
|
+
items: filteredCollectionItems,
|
|
8886
8901
|
isLoading: collectionItems.isLoading,
|
|
8887
8902
|
error: collectionItems.error,
|
|
8888
8903
|
ctx: itemViewCtx,
|