@open-mercato/ui 0.6.1-develop.3291.1.6fad645fd0 → 0.6.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/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +2 -0
- package/dist/ai/AiAssistantLauncher.js +8 -8
- package/dist/ai/AiAssistantLauncher.js.map +2 -2
- package/dist/ai/AiChat.js +92 -93
- package/dist/ai/AiChat.js.map +2 -2
- package/dist/ai/AiIcon.js +17 -0
- package/dist/ai/AiIcon.js.map +7 -0
- package/dist/ai/LoopDisabledBanner.js +28 -0
- package/dist/ai/LoopDisabledBanner.js.map +7 -0
- package/dist/ai/LoopTracePanel.js +123 -0
- package/dist/ai/LoopTracePanel.js.map +7 -0
- package/dist/ai/ModelPicker.js.map +1 -1
- package/dist/ai/index.js +8 -0
- package/dist/ai/index.js.map +2 -2
- package/dist/ai/parts/ConfirmationCard.js +1 -5
- package/dist/ai/parts/ConfirmationCard.js.map +2 -2
- package/dist/ai/parts/FieldDiffCard.js +8 -15
- package/dist/ai/parts/FieldDiffCard.js.map +2 -2
- package/dist/ai/parts/MutationResultCard.js +1 -4
- package/dist/ai/parts/MutationResultCard.js.map +2 -2
- package/dist/ai/ui-parts/pending-phase3-placeholder.js +0 -2
- package/dist/ai/ui-parts/pending-phase3-placeholder.js.map +2 -2
- package/dist/ai/useAiChat.js +18 -4
- package/dist/ai/useAiChat.js.map +2 -2
- package/dist/backend/CrudForm.js +24 -2
- package/dist/backend/CrudForm.js.map +2 -2
- package/dist/backend/DataTable.js +2 -2
- package/dist/backend/DataTable.js.map +2 -2
- package/dist/backend/confirm-dialog/ConfirmDialog.js +102 -96
- package/dist/backend/confirm-dialog/ConfirmDialog.js.map +2 -2
- package/dist/backend/detail/CustomDataSection.js +22 -3
- package/dist/backend/detail/CustomDataSection.js.map +2 -2
- package/dist/backend/filters/AdvancedFilterBuilder.js +2 -2
- package/dist/backend/filters/AdvancedFilterBuilder.js.map +2 -2
- package/dist/backend/injection/ComponentOverrideProvider.js +1 -1
- package/dist/backend/injection/ComponentOverrideProvider.js.map +2 -2
- package/dist/backend/inputs/ComboboxInput.js +25 -7
- package/dist/backend/inputs/ComboboxInput.js.map +2 -2
- package/dist/backend/progress/useProgressPoll.js +58 -3
- package/dist/backend/progress/useProgressPoll.js.map +2 -2
- package/dist/backend/progress/useProgressSse.js +15 -2
- package/dist/backend/progress/useProgressSse.js.map +2 -2
- package/dist/backend/utils/bulkDelete.js +76 -0
- package/dist/backend/utils/bulkDelete.js.map +2 -2
- package/package.json +11 -6
- package/src/ai/AiAssistantLauncher.tsx +8 -8
- package/src/ai/AiChat.tsx +44 -38
- package/src/ai/AiIcon.tsx +12 -0
- package/src/ai/LoopDisabledBanner.tsx +38 -0
- package/src/ai/LoopTracePanel.tsx +184 -0
- package/src/ai/ModelPicker.tsx +1 -1
- package/src/ai/__tests__/AiChat.test.tsx +174 -5
- package/src/ai/index.ts +8 -0
- package/src/ai/parts/ConfirmationCard.tsx +1 -5
- package/src/ai/parts/FieldDiffCard.tsx +0 -3
- package/src/ai/parts/MutationResultCard.tsx +1 -4
- package/src/ai/parts/__tests__/MutationResultCard.test.tsx +5 -0
- package/src/ai/ui-parts/pending-phase3-placeholder.tsx +0 -2
- package/src/ai/useAiChat.ts +35 -5
- package/src/backend/CrudForm.tsx +30 -3
- package/src/backend/DataTable.tsx +2 -2
- package/src/backend/__tests__/CrudForm.custom-fields.test.tsx +72 -0
- package/src/backend/__tests__/CustomDataSection.test.tsx +76 -0
- package/src/backend/__tests__/DataTable.render.test.tsx +36 -0
- package/src/backend/__tests__/component-replacement.test.tsx +44 -0
- package/src/backend/confirm-dialog/ConfirmDialog.tsx +101 -91
- package/src/backend/confirm-dialog/__tests__/ConfirmDialog.test.tsx +19 -0
- package/src/backend/detail/CustomDataSection.tsx +26 -3
- package/src/backend/filters/AdvancedFilterBuilder.tsx +6 -6
- package/src/backend/injection/ComponentOverrideProvider.tsx +2 -1
- package/src/backend/inputs/ComboboxInput.tsx +29 -7
- package/src/backend/inputs/__tests__/ComboboxInput.test.tsx +33 -2
- package/src/backend/progress/useProgressPoll.ts +68 -3
- package/src/backend/progress/useProgressSse.ts +16 -2
- package/src/backend/utils/__tests__/bulkDelete.test.ts +42 -0
- package/src/backend/utils/bulkDelete.ts +93 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
+
import { createPortal } from "react-dom";
|
|
4
5
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
5
6
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
6
7
|
import { IconButton } from "../../primitives/icon-button.js";
|
|
@@ -24,6 +25,7 @@ function ConfirmDialog({
|
|
|
24
25
|
const [internalOpen, setInternalOpen] = React.useState(false);
|
|
25
26
|
const cancelButtonRef = React.useRef(null);
|
|
26
27
|
const confirmButtonRef = React.useRef(null);
|
|
28
|
+
const [portalTarget, setPortalTarget] = React.useState(null);
|
|
27
29
|
const reactId = React.useId();
|
|
28
30
|
const titleId = `confirm-dialog-title-${reactId}`;
|
|
29
31
|
const descriptionId = `confirm-dialog-description-${reactId}`;
|
|
@@ -44,7 +46,10 @@ function ConfirmDialog({
|
|
|
44
46
|
setOpen(false);
|
|
45
47
|
handleCancelCallback();
|
|
46
48
|
}, [setOpen, handleCancelCallback]);
|
|
47
|
-
React.
|
|
49
|
+
React.useLayoutEffect(() => {
|
|
50
|
+
setPortalTarget(document.body);
|
|
51
|
+
}, []);
|
|
52
|
+
React.useLayoutEffect(() => {
|
|
48
53
|
const dialog = dialogRef.current;
|
|
49
54
|
if (!dialog) return;
|
|
50
55
|
if (open) {
|
|
@@ -63,7 +68,7 @@ function ConfirmDialog({
|
|
|
63
68
|
dialog.close();
|
|
64
69
|
}
|
|
65
70
|
}
|
|
66
|
-
}, [open, resolvedCancelText]);
|
|
71
|
+
}, [open, resolvedCancelText, portalTarget]);
|
|
67
72
|
React.useEffect(() => {
|
|
68
73
|
const dialog = dialogRef.current;
|
|
69
74
|
if (!dialog) return;
|
|
@@ -107,108 +112,109 @@ function ConfirmDialog({
|
|
|
107
112
|
setOpen(true);
|
|
108
113
|
}
|
|
109
114
|
};
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
"
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
115
|
+
const dialogElement = /* @__PURE__ */ jsx(
|
|
116
|
+
"dialog",
|
|
117
|
+
{
|
|
118
|
+
ref: dialogRef,
|
|
119
|
+
role: "alertdialog",
|
|
120
|
+
"aria-labelledby": titleId,
|
|
121
|
+
"aria-describedby": text ? descriptionId : void 0,
|
|
122
|
+
onClick: handleBackdropClick,
|
|
123
|
+
className: cn(
|
|
124
|
+
// Reset dialog defaults
|
|
125
|
+
"m-0 p-0 max-w-none bg-transparent border-none pointer-events-auto",
|
|
126
|
+
// Backdrop styling
|
|
127
|
+
"backdrop:bg-black/50 backdrop:backdrop-blur-sm backdrop:transition-opacity",
|
|
128
|
+
// Mobile: bottom sheet
|
|
129
|
+
"fixed inset-x-0 bottom-0 top-auto w-full",
|
|
130
|
+
// Desktop: centered
|
|
131
|
+
"sm:inset-auto sm:mx-auto sm:my-auto sm:max-w-md sm:top-1/2 sm:left-1/2 sm:-translate-x-1/2 sm:-translate-y-1/2",
|
|
132
|
+
// Animation with reduced motion support
|
|
133
|
+
"motion-safe:open:animate-in motion-safe:open:fade-in-0 motion-safe:open:slide-in-from-bottom-4",
|
|
134
|
+
"sm:motion-safe:open:slide-in-from-bottom-0 sm:motion-safe:open:zoom-in-95",
|
|
135
|
+
// Duration
|
|
136
|
+
"motion-safe:open:duration-300"
|
|
137
|
+
),
|
|
138
|
+
children: /* @__PURE__ */ jsxs(
|
|
139
|
+
"div",
|
|
140
|
+
{
|
|
141
|
+
role: "document",
|
|
142
|
+
className: cn(
|
|
143
|
+
// Panel container
|
|
144
|
+
"flex flex-col gap-4 rounded-t-2xl border-t bg-card p-6 text-foreground shadow-lg",
|
|
145
|
+
"sm:rounded-xl sm:border",
|
|
146
|
+
// Relative positioning for close button
|
|
147
|
+
"relative"
|
|
148
|
+
),
|
|
149
|
+
children: [
|
|
150
|
+
/* @__PURE__ */ jsx(
|
|
151
|
+
IconButton,
|
|
152
|
+
{
|
|
153
|
+
type: "button",
|
|
154
|
+
variant: "ghost",
|
|
155
|
+
size: "sm",
|
|
156
|
+
onClick: handleCancel,
|
|
157
|
+
disabled: loading,
|
|
158
|
+
"aria-label": closeAriaLabel,
|
|
159
|
+
className: "absolute right-4 top-4 opacity-70 hover:opacity-100",
|
|
160
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
161
|
+
}
|
|
162
|
+
),
|
|
163
|
+
/* @__PURE__ */ jsx(
|
|
164
|
+
"h2",
|
|
165
|
+
{
|
|
166
|
+
id: titleId,
|
|
167
|
+
className: cn(
|
|
168
|
+
"text-sm font-medium leading-snug tracking-tight pr-6",
|
|
169
|
+
// Mobile: centered, Desktop: left-aligned
|
|
170
|
+
"text-center sm:text-left"
|
|
171
|
+
),
|
|
172
|
+
children: resolvedTitle
|
|
173
|
+
}
|
|
145
174
|
),
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
175
|
+
text && /* @__PURE__ */ jsx(
|
|
176
|
+
"p",
|
|
177
|
+
{
|
|
178
|
+
id: descriptionId,
|
|
179
|
+
className: "text-sm font-medium leading-snug text-muted-foreground",
|
|
180
|
+
children: text
|
|
181
|
+
}
|
|
182
|
+
),
|
|
183
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", children: [
|
|
184
|
+
resolvedCancelText !== false && /* @__PURE__ */ jsx(
|
|
185
|
+
Button,
|
|
149
186
|
{
|
|
150
|
-
|
|
151
|
-
variant: "
|
|
152
|
-
size: "sm",
|
|
187
|
+
ref: cancelButtonRef,
|
|
188
|
+
variant: "outline",
|
|
153
189
|
onClick: handleCancel,
|
|
154
190
|
disabled: loading,
|
|
155
|
-
"
|
|
156
|
-
|
|
157
|
-
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
158
|
-
}
|
|
159
|
-
),
|
|
160
|
-
/* @__PURE__ */ jsx(
|
|
161
|
-
"h2",
|
|
162
|
-
{
|
|
163
|
-
id: titleId,
|
|
164
|
-
className: cn(
|
|
165
|
-
"text-sm font-medium leading-snug tracking-tight pr-6",
|
|
166
|
-
// Mobile: centered, Desktop: left-aligned
|
|
167
|
-
"text-center sm:text-left"
|
|
168
|
-
),
|
|
169
|
-
children: resolvedTitle
|
|
191
|
+
className: "w-full sm:w-auto",
|
|
192
|
+
children: resolvedCancelText
|
|
170
193
|
}
|
|
171
194
|
),
|
|
172
|
-
|
|
173
|
-
|
|
195
|
+
resolvedConfirmText !== false && /* @__PURE__ */ jsxs(
|
|
196
|
+
Button,
|
|
174
197
|
{
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
198
|
+
ref: confirmButtonRef,
|
|
199
|
+
variant: variant === "destructive" ? "destructive" : "default",
|
|
200
|
+
onClick: handleConfirm,
|
|
201
|
+
disabled: loading,
|
|
202
|
+
className: "w-full sm:w-auto",
|
|
203
|
+
children: [
|
|
204
|
+
loading && /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
205
|
+
resolvedConfirmText
|
|
206
|
+
]
|
|
178
207
|
}
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
children: resolvedCancelText
|
|
190
|
-
}
|
|
191
|
-
),
|
|
192
|
-
resolvedConfirmText !== false && /* @__PURE__ */ jsxs(
|
|
193
|
-
Button,
|
|
194
|
-
{
|
|
195
|
-
ref: confirmButtonRef,
|
|
196
|
-
variant: variant === "destructive" ? "destructive" : "default",
|
|
197
|
-
onClick: handleConfirm,
|
|
198
|
-
disabled: loading,
|
|
199
|
-
className: "w-full sm:w-auto",
|
|
200
|
-
children: [
|
|
201
|
-
loading && /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
202
|
-
resolvedConfirmText
|
|
203
|
-
]
|
|
204
|
-
}
|
|
205
|
-
)
|
|
206
|
-
] })
|
|
207
|
-
]
|
|
208
|
-
}
|
|
209
|
-
)
|
|
210
|
-
}
|
|
211
|
-
)
|
|
208
|
+
)
|
|
209
|
+
] })
|
|
210
|
+
]
|
|
211
|
+
}
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
216
|
+
trigger && /* @__PURE__ */ jsx("div", { onClick: handleTriggerClick, className: "inline-block", role: "presentation", children: trigger }),
|
|
217
|
+
portalTarget ? createPortal(dialogElement, portalTarget) : null
|
|
212
218
|
] });
|
|
213
219
|
}
|
|
214
220
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/confirm-dialog/ConfirmDialog.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\";\nimport * as React from \"react\";\nimport { useT } from \"@open-mercato/shared/lib/i18n/context\";\nimport { Button } from \"@open-mercato/ui/primitives/button\";\nimport { IconButton } from \"../../primitives/icon-button\";\nimport { cn } from \"@open-mercato/shared/lib/utils\";\nimport { Loader2, X } from \"lucide-react\";\n\nexport type ConfirmDialogProps = {\n /** Whether the dialog is open (controlled mode \u2014 used by useConfirmDialog) */\n open?: boolean;\n /** Callback when open state changes (controlled mode) */\n onOpenChange?: (open: boolean) => void;\n /** Callback when user confirms */\n onConfirm: () => void | Promise<void>;\n /** Callback when user cancels (optional, defaults to closing) */\n onCancel?: () => void;\n /** Dialog title. Defaults to i18n key \"ui.dialogs.confirm.defaultTitle\" (\"Are you sure?\") */\n title?: string;\n /** Dialog body text / description */\n text?: string;\n /** Confirm button label. Defaults to i18n \"ui.dialogs.confirm.confirmText\" (\"Confirm\").\n * Pass `false` to hide the confirm button entirely. */\n confirmText?: string | false;\n /** Cancel button label. Defaults to i18n \"ui.dialogs.confirm.cancelText\" (\"Cancel\").\n * Pass `false` to hide the cancel button entirely. */\n cancelText?: string | false;\n /** Visual variant \u2014 \"destructive\" renders the confirm button in red */\n variant?: \"default\" | \"destructive\";\n /** Whether the confirm button shows a loading spinner.\n * Useful for async onConfirm handlers (e.g., waiting for API response before closing). */\n loading?: boolean;\n /** Trigger element \u2014 when provided, component manages its own open state (declarative mode).\n * Clicking the trigger opens the dialog. */\n trigger?: React.ReactNode;\n};\n\nexport function ConfirmDialog({\n open: controlledOpen,\n onOpenChange,\n onConfirm,\n onCancel,\n title,\n text,\n confirmText,\n cancelText,\n variant = \"default\",\n loading = false,\n trigger,\n}: ConfirmDialogProps) {\n const t = useT();\n const dialogRef = React.useRef<HTMLDialogElement>(null);\n const [internalOpen, setInternalOpen] = React.useState(false);\n const cancelButtonRef = React.useRef<HTMLButtonElement>(null);\n const confirmButtonRef = React.useRef<HTMLButtonElement>(null);\n // Unique IDs so multiple ConfirmDialog instances on the same page don't\n // collide and make `aria-labelledby` resolve to the wrong dialog's title.\n const reactId = React.useId();\n const titleId = `confirm-dialog-title-${reactId}`;\n const descriptionId = `confirm-dialog-description-${reactId}`;\n\n // Determine if we're in controlled mode (open prop provided) or declarative mode (trigger provided)\n const isControlled = controlledOpen !== undefined;\n const open = isControlled ? controlledOpen : internalOpen;\n const setOpen = isControlled\n ? onOpenChange || (() => {})\n : setInternalOpen;\n const handleCancelCallback = React.useCallback(() => {\n if (!isControlled) {\n onCancel?.();\n }\n }, [isControlled, onCancel]);\n\n // Default text values from i18n\n const resolvedTitle =\n title ?? t(\"ui.dialogs.confirm.defaultTitle\", \"Are you sure?\");\n const resolvedConfirmText =\n confirmText === false\n ? false\n : confirmText ?? t(\"ui.dialogs.confirm.confirmText\", \"Confirm\");\n const resolvedCancelText =\n cancelText === false\n ? false\n : cancelText ?? t(\"ui.dialogs.confirm.cancelText\", \"Cancel\");\n const closeAriaLabel = t(\"ui.dialog.close.ariaLabel\", \"Close\");\n const requestClose = React.useCallback(() => {\n setOpen(false);\n handleCancelCallback();\n }, [setOpen, handleCancelCallback]);\n\n // Handle dialog open/close with native showModal/close\n React.
|
|
5
|
-
"mappings": ";AA+
|
|
4
|
+
"sourcesContent": ["\"use client\";\nimport * as React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useT } from \"@open-mercato/shared/lib/i18n/context\";\nimport { Button } from \"@open-mercato/ui/primitives/button\";\nimport { IconButton } from \"../../primitives/icon-button\";\nimport { cn } from \"@open-mercato/shared/lib/utils\";\nimport { Loader2, X } from \"lucide-react\";\n\nexport type ConfirmDialogProps = {\n /** Whether the dialog is open (controlled mode \u2014 used by useConfirmDialog) */\n open?: boolean;\n /** Callback when open state changes (controlled mode) */\n onOpenChange?: (open: boolean) => void;\n /** Callback when user confirms */\n onConfirm: () => void | Promise<void>;\n /** Callback when user cancels (optional, defaults to closing) */\n onCancel?: () => void;\n /** Dialog title. Defaults to i18n key \"ui.dialogs.confirm.defaultTitle\" (\"Are you sure?\") */\n title?: string;\n /** Dialog body text / description */\n text?: string;\n /** Confirm button label. Defaults to i18n \"ui.dialogs.confirm.confirmText\" (\"Confirm\").\n * Pass `false` to hide the confirm button entirely. */\n confirmText?: string | false;\n /** Cancel button label. Defaults to i18n \"ui.dialogs.confirm.cancelText\" (\"Cancel\").\n * Pass `false` to hide the cancel button entirely. */\n cancelText?: string | false;\n /** Visual variant \u2014 \"destructive\" renders the confirm button in red */\n variant?: \"default\" | \"destructive\";\n /** Whether the confirm button shows a loading spinner.\n * Useful for async onConfirm handlers (e.g., waiting for API response before closing). */\n loading?: boolean;\n /** Trigger element \u2014 when provided, component manages its own open state (declarative mode).\n * Clicking the trigger opens the dialog. */\n trigger?: React.ReactNode;\n};\n\nexport function ConfirmDialog({\n open: controlledOpen,\n onOpenChange,\n onConfirm,\n onCancel,\n title,\n text,\n confirmText,\n cancelText,\n variant = \"default\",\n loading = false,\n trigger,\n}: ConfirmDialogProps) {\n const t = useT();\n const dialogRef = React.useRef<HTMLDialogElement>(null);\n const [internalOpen, setInternalOpen] = React.useState(false);\n const cancelButtonRef = React.useRef<HTMLButtonElement>(null);\n const confirmButtonRef = React.useRef<HTMLButtonElement>(null);\n const [portalTarget, setPortalTarget] = React.useState<HTMLElement | null>(null);\n // Unique IDs so multiple ConfirmDialog instances on the same page don't\n // collide and make `aria-labelledby` resolve to the wrong dialog's title.\n const reactId = React.useId();\n const titleId = `confirm-dialog-title-${reactId}`;\n const descriptionId = `confirm-dialog-description-${reactId}`;\n\n // Determine if we're in controlled mode (open prop provided) or declarative mode (trigger provided)\n const isControlled = controlledOpen !== undefined;\n const open = isControlled ? controlledOpen : internalOpen;\n const setOpen = isControlled\n ? onOpenChange || (() => {})\n : setInternalOpen;\n const handleCancelCallback = React.useCallback(() => {\n if (!isControlled) {\n onCancel?.();\n }\n }, [isControlled, onCancel]);\n\n // Default text values from i18n\n const resolvedTitle =\n title ?? t(\"ui.dialogs.confirm.defaultTitle\", \"Are you sure?\");\n const resolvedConfirmText =\n confirmText === false\n ? false\n : confirmText ?? t(\"ui.dialogs.confirm.confirmText\", \"Confirm\");\n const resolvedCancelText =\n cancelText === false\n ? false\n : cancelText ?? t(\"ui.dialogs.confirm.cancelText\", \"Cancel\");\n const closeAriaLabel = t(\"ui.dialog.close.ariaLabel\", \"Close\");\n const requestClose = React.useCallback(() => {\n setOpen(false);\n handleCancelCallback();\n }, [setOpen, handleCancelCallback]);\n\n React.useLayoutEffect(() => {\n setPortalTarget(document.body);\n }, []);\n\n // Handle dialog open/close with native showModal/close\n React.useLayoutEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n if (open) {\n if (!dialog.open) {\n dialog.showModal();\n // Focus cancel button (safe default) or confirm if no cancel\n setTimeout(() => {\n if (resolvedCancelText !== false && cancelButtonRef.current) {\n cancelButtonRef.current.focus();\n } else if (confirmButtonRef.current) {\n confirmButtonRef.current.focus();\n }\n }, 0);\n }\n } else {\n if (dialog.open) {\n dialog.close();\n }\n }\n }, [open, resolvedCancelText, portalTarget]);\n\n // Handle native cancel event (Escape key)\n React.useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const handleCancel = (e: Event) => {\n // Prevent close if loading\n if (loading) {\n e.preventDefault();\n return;\n }\n requestClose();\n };\n\n dialog.addEventListener(\"cancel\", handleCancel);\n return () => dialog.removeEventListener(\"cancel\", handleCancel);\n }, [loading, requestClose]);\n\n // Handle backdrop click\n const handleBackdropClick = (e: React.MouseEvent<HTMLDialogElement>) => {\n // Only close if clicking directly on the dialog (backdrop), not its children\n if (e.target === dialogRef.current && !loading) {\n requestClose();\n }\n };\n\n // Handle keyboard shortcuts\n React.useEffect(() => {\n if (!open) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n // Cmd/Ctrl+Enter confirms\n if ((e.metaKey || e.ctrlKey) && e.key === \"Enter\" && !loading) {\n e.preventDefault();\n handleConfirm();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, loading]);\n\n const handleConfirm = async () => {\n await onConfirm();\n // Don't auto-close if loading \u2014 let the parent control when to close\n if (!loading) {\n setOpen(false);\n }\n };\n\n const handleCancel = () => {\n requestClose();\n };\n\n const handleTriggerClick = () => {\n if (trigger) {\n setOpen(true);\n }\n };\n\n const dialogElement = (\n <dialog\n ref={dialogRef}\n role=\"alertdialog\"\n aria-labelledby={titleId}\n aria-describedby={text ? descriptionId : undefined}\n onClick={handleBackdropClick}\n className={cn(\n // Reset dialog defaults\n \"m-0 p-0 max-w-none bg-transparent border-none pointer-events-auto\",\n // Backdrop styling\n \"backdrop:bg-black/50 backdrop:backdrop-blur-sm backdrop:transition-opacity\",\n // Mobile: bottom sheet\n \"fixed inset-x-0 bottom-0 top-auto w-full\",\n // Desktop: centered\n \"sm:inset-auto sm:mx-auto sm:my-auto sm:max-w-md sm:top-1/2 sm:left-1/2 sm:-translate-x-1/2 sm:-translate-y-1/2\",\n // Animation with reduced motion support\n \"motion-safe:open:animate-in motion-safe:open:fade-in-0 motion-safe:open:slide-in-from-bottom-4\",\n \"sm:motion-safe:open:slide-in-from-bottom-0 sm:motion-safe:open:zoom-in-95\",\n // Duration\n \"motion-safe:open:duration-300\"\n )}\n >\n <div\n role=\"document\"\n className={cn(\n // Panel container\n \"flex flex-col gap-4 rounded-t-2xl border-t bg-card p-6 text-foreground shadow-lg\",\n \"sm:rounded-xl sm:border\",\n // Relative positioning for close button\n \"relative\"\n )}\n >\n {/* Close button */}\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={handleCancel}\n disabled={loading}\n aria-label={closeAriaLabel}\n className=\"absolute right-4 top-4 opacity-70 hover:opacity-100\"\n >\n <X className=\"h-4 w-4\" />\n </IconButton>\n\n {/* Title */}\n <h2\n id={titleId}\n className={cn(\n \"text-sm font-medium leading-snug tracking-tight pr-6\",\n // Mobile: centered, Desktop: left-aligned\n \"text-center sm:text-left\"\n )}\n >\n {resolvedTitle}\n </h2>\n\n {/* Description (optional) */}\n {text && (\n <p\n id={descriptionId}\n className=\"text-sm font-medium leading-snug text-muted-foreground\"\n >\n {text}\n </p>\n )}\n\n {/* Actions */}\n <div className=\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\">\n {resolvedCancelText !== false && (\n <Button\n ref={cancelButtonRef}\n variant=\"outline\"\n onClick={handleCancel}\n disabled={loading}\n className=\"w-full sm:w-auto\"\n >\n {resolvedCancelText}\n </Button>\n )}\n {resolvedConfirmText !== false && (\n <Button\n ref={confirmButtonRef}\n variant={variant === \"destructive\" ? \"destructive\" : \"default\"}\n onClick={handleConfirm}\n disabled={loading}\n className=\"w-full sm:w-auto\"\n >\n {loading && <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />}\n {resolvedConfirmText}\n </Button>\n )}\n </div>\n </div>\n </dialog>\n );\n\n return (\n <>\n {trigger && (\n <div onClick={handleTriggerClick} className=\"inline-block\" role=\"presentation\">\n {trigger}\n </div>\n )}\n\n {portalTarget ? createPortal(dialogElement, portalTarget) : null}\n </>\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["handleCancel"]
|
|
7
7
|
}
|
|
@@ -54,6 +54,16 @@ function extractDictionaryValue(entry) {
|
|
|
54
54
|
}
|
|
55
55
|
return null;
|
|
56
56
|
}
|
|
57
|
+
function readCustomDataFieldValue(values, fieldId) {
|
|
58
|
+
if (!values || !fieldId) return void 0;
|
|
59
|
+
const candidates = fieldId.startsWith("cf_") ? [fieldId, `cf:${fieldId.slice(3)}`, fieldId.slice(3)] : [fieldId, `cf_${fieldId}`, `cf:${fieldId}`];
|
|
60
|
+
for (const candidate of candidates) {
|
|
61
|
+
if (Object.prototype.hasOwnProperty.call(values, candidate)) {
|
|
62
|
+
return values[candidate];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return void 0;
|
|
66
|
+
}
|
|
57
67
|
function formatFieldValue(field, value, emptyLabel, dictionaryMap, remarkPlugins = [], resolvedDisplays) {
|
|
58
68
|
if (dictionaryMap) {
|
|
59
69
|
if (value === void 0 || value === null || value === "") {
|
|
@@ -238,6 +248,15 @@ function CustomDataSectionImpl({
|
|
|
238
248
|
() => customFieldFormsQuery.data?.definitions ?? [],
|
|
239
249
|
[customFieldFormsQuery.data]
|
|
240
250
|
);
|
|
251
|
+
const formInitialValues = React.useMemo(() => {
|
|
252
|
+
const next = { ...values ?? {} };
|
|
253
|
+
fields.forEach((field) => {
|
|
254
|
+
if (!field.id || Object.prototype.hasOwnProperty.call(next, field.id)) return;
|
|
255
|
+
const resolved = readCustomDataFieldValue(values, field.id);
|
|
256
|
+
if (resolved !== void 0) next[field.id] = resolved;
|
|
257
|
+
});
|
|
258
|
+
return next;
|
|
259
|
+
}, [fields, values]);
|
|
241
260
|
const [dictionaryLoading, setDictionaryLoading] = React.useState(false);
|
|
242
261
|
const [relationLoading, setRelationLoading] = React.useState(false);
|
|
243
262
|
const loading = customFieldFormsQuery.isLoading || dictionaryLoading || relationLoading;
|
|
@@ -375,7 +394,7 @@ function CustomDataSectionImpl({
|
|
|
375
394
|
const normalizedKey = field.id.startsWith("cf_") ? field.id.slice(3) : field.id;
|
|
376
395
|
const definition = definitionsByKey.get(normalizedKey.toLowerCase());
|
|
377
396
|
if (!definition || definition.kind !== "relation") return null;
|
|
378
|
-
const relationIds = collectRelationValueIds(values
|
|
397
|
+
const relationIds = collectRelationValueIds(readCustomDataFieldValue(values, field.id));
|
|
379
398
|
if (!relationIds.length) return null;
|
|
380
399
|
return { field, definition, relationIds };
|
|
381
400
|
}).filter((entry) => !!entry);
|
|
@@ -509,7 +528,7 @@ function CustomDataSectionImpl({
|
|
|
509
528
|
entityId: primaryEntityId,
|
|
510
529
|
entityIds: resolvedEntityIds,
|
|
511
530
|
fields,
|
|
512
|
-
initialValues:
|
|
531
|
+
initialValues: formInitialValues,
|
|
513
532
|
onSubmit: handleSubmit,
|
|
514
533
|
submitLabel: labels.saveShortcut,
|
|
515
534
|
isLoading: loading
|
|
@@ -542,7 +561,7 @@ function CustomDataSectionImpl({
|
|
|
542
561
|
/* @__PURE__ */ jsx("p", { className: "text-xs uppercase tracking-wide text-muted-foreground", children: field.label }),
|
|
543
562
|
/* @__PURE__ */ jsx("div", { className: "text-sm break-words", children: formatFieldValue(
|
|
544
563
|
field,
|
|
545
|
-
values
|
|
564
|
+
readCustomDataFieldValue(values, field.id),
|
|
546
565
|
labels.emptyValue,
|
|
547
566
|
dictionaryMapsByField[field.id],
|
|
548
567
|
markdownPlugins,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/detail/CustomDataSection.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport type { PluggableList } from 'unified'\nimport { Pencil, X } from 'lucide-react'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { DataLoader } from '@open-mercato/ui/primitives/DataLoader'\nimport type { CrudField } from '@open-mercato/ui/backend/CrudForm'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { fetchCustomFieldFormFieldsWithDefinitions } from '@open-mercato/ui/backend/utils/customFieldForms'\nimport type { CustomFieldDefDto } from '@open-mercato/ui/backend/utils/customFieldDefs'\nimport {\n DictionaryValue,\n type DictionaryMap,\n} from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { ensureDictionaryEntries } from '@open-mercato/core/modules/dictionaries/components/hooks/useDictionaryEntries'\nimport {\n type ResolvedValueDisplay,\n collectRelationValueIds,\n extractOptionLookupKey,\n extractInlineOptionLabel,\n parseRelationOptionsMetadata,\n getRelationHrefContextFields,\n buildRelationHref,\n fetchRelationRecordDisplays,\n} from '@open-mercato/ui/backend/utils/customFieldRelationDisplay'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { ComponentReplacementHandles } from '@open-mercato/shared/modules/widgets/component-registry'\nimport { MarkdownPreview } from '../markdown'\nimport { useRegisteredComponent } from '../injection/useRegisteredComponent'\n\nconst isTestEnv =\n typeof process !== 'undefined' &&\n (process.env.NODE_ENV === 'test' || typeof process.env.JEST_WORKER_ID !== 'undefined')\n\nlet markdownPluginsPromise: Promise<PluggableList> | null = null\n\nasync function loadMarkdownPlugins(): Promise<PluggableList> {\n if (isTestEnv) return []\n if (!markdownPluginsPromise) {\n markdownPluginsPromise = import('remark-gfm')\n .then((mod) => [mod.default ?? mod] as PluggableList)\n .catch(() => [])\n }\n return markdownPluginsPromise\n}\n\nconst MARKDOWN_FIELD_TYPES = new Set<CrudField['type']>(['text', 'textarea', 'richtext'])\nconst MARKDOWN_CLASSNAME =\n 'text-sm text-foreground break-words [&>*]:mb-2 [&>*:last-child]:mb-0 [&_ul]:ml-4 [&_ul]:list-disc [&_ol]:ml-4 [&_ol]:list-decimal [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre]:text-xs'\n\nfunction renderMarkdownValue(content: string, remarkPlugins: PluggableList) {\n return (\n <MarkdownPreview remarkPlugins={remarkPlugins} className={MARKDOWN_CLASSNAME}>\n {content}\n </MarkdownPreview>\n )\n}\n\nfunction extractDictionaryValue(entry: unknown): string | null {\n if (typeof entry === 'string') {\n const trimmed = entry.trim()\n return trimmed.length ? trimmed : null\n }\n if (!entry || typeof entry !== 'object') return null\n const record = entry as Record<string, unknown>\n const candidate = record.value ?? record.name ?? record.id ?? record.key ?? record.label\n if (typeof candidate === 'string') {\n const trimmed = candidate.trim()\n return trimmed.length ? trimmed : null\n }\n return null\n}\n\nexport type CustomDataLabels = {\n loading: string\n emptyValue: string\n noFields: string\n defineFields?: string\n saveShortcut: string\n edit?: string\n cancel?: string\n}\n\nexport type CustomDataSectionProps = {\n entityId?: string\n entityIds?: string[]\n values: Record<string, unknown>\n onSubmit: (values: Record<string, unknown>) => Promise<void>\n title: string\n scopeVersion?: string | number | null\n loadFields?: (\n entityIds: string[],\n ) => Promise<{ fields: CrudField[]; definitions: CustomFieldDefDto[] }>\n labels: CustomDataLabels\n definitionHref?: string\n}\n\nfunction formatFieldValue(\n field: CrudField,\n value: unknown,\n emptyLabel: string,\n dictionaryMap?: DictionaryMap,\n remarkPlugins: PluggableList = [],\n resolvedDisplays?: Record<string, ResolvedValueDisplay>,\n): React.ReactNode {\n if (dictionaryMap) {\n if (value === undefined || value === null || value === '') {\n return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n }\n\n if (Array.isArray(value)) {\n const normalizedValues = value\n .map((entry) => extractDictionaryValue(entry))\n .filter((entry): entry is string => typeof entry === 'string' && entry.length > 0)\n\n if (!normalizedValues.length) {\n return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n }\n\n return (\n <div className=\"flex flex-wrap gap-1.5\">\n {normalizedValues.map((entry, index) => (\n <DictionaryValue\n key={`${field.id}-${entry}-${index}`}\n value={entry}\n map={dictionaryMap}\n className=\"inline-flex items-center gap-1 rounded-full border border-border bg-card px-2 py-1 text-xs\"\n iconWrapperClassName=\"inline-flex h-4 w-4 items-center justify-center rounded-full border border-border bg-background\"\n iconClassName=\"h-3 w-3\"\n colorClassName=\"h-2.5 w-2.5 rounded-full\"\n />\n ))}\n </div>\n )\n }\n\n const resolved = extractDictionaryValue(value)\n if (!resolved) {\n return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n }\n\n return (\n <DictionaryValue\n value={resolved}\n map={dictionaryMap}\n className=\"inline-flex items-center gap-2 text-sm\"\n fallback={<span className=\"text-muted-foreground\">{emptyLabel}</span>}\n iconWrapperClassName=\"inline-flex h-6 w-6 items-center justify-center rounded border border-border bg-card\"\n iconClassName=\"h-4 w-4\"\n colorClassName=\"h-3 w-3 rounded-full\"\n />\n )\n }\n\n const optionMap =\n 'options' in field && Array.isArray(field.options)\n ? field.options.reduce<Map<string, string>>((acc, option) => {\n acc.set(option.value, option.label)\n return acc\n }, new Map())\n : null\n\n const resolveOptionDisplay = (entry: unknown): ResolvedValueDisplay | null => {\n const lookupKey = extractOptionLookupKey(entry)\n if (lookupKey && resolvedDisplays?.[lookupKey]) {\n return resolvedDisplays[lookupKey]\n }\n const inlineLabel = extractInlineOptionLabel(entry)\n if (lookupKey) {\n return {\n label: inlineLabel ?? optionMap?.get(lookupKey) ?? lookupKey,\n }\n }\n if (inlineLabel) {\n return { label: inlineLabel }\n }\n return null\n }\n\n const renderResolvedDisplay = (display: ResolvedValueDisplay) => {\n if (!display.href) return display.label\n return (\n <Link\n href={display.href}\n className=\"font-medium text-primary underline-offset-2 hover:underline focus-visible:underline\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => event.stopPropagation()}\n >\n {display.label}\n </Link>\n )\n }\n\n if (value === undefined || value === null || value === '') {\n return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n }\n\n if (Array.isArray(value)) {\n if (!value.length) return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n return value.map((entry, index) => (\n <span\n key={`${field.id}-${index}`}\n className=\"mr-1 inline-flex items-center rounded-full bg-muted px-2 py-0.5 text-xs\"\n >\n {(() => {\n const display = resolveOptionDisplay(entry)\n if (!display) return emptyLabel\n return renderResolvedDisplay(display)\n })()}\n </span>\n ))\n }\n\n if (typeof value === 'boolean') {\n return value ? 'Yes' : 'No'\n }\n\n if (resolvedDisplays && Object.keys(resolvedDisplays).length > 0) {\n const resolvedDisplay = resolveOptionDisplay(value)\n if (resolvedDisplay) {\n return renderResolvedDisplay(resolvedDisplay)\n }\n }\n\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value)\n } catch {\n return String(value)\n }\n }\n\n const resolved = optionMap?.get(String(value)) ?? String(value)\n if (typeof value === 'string' && MARKDOWN_FIELD_TYPES.has(field.type)) {\n if (!resolved.trim().length) {\n return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n }\n return renderMarkdownValue(value, remarkPlugins)\n }\n if (!resolved.length) return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n return resolved\n}\n\nfunction CustomDataSectionImpl({\n entityId,\n entityIds,\n values,\n onSubmit,\n title,\n scopeVersion: scopeVersionProp,\n loadFields,\n labels,\n definitionHref: explicitDefinitionHref,\n}: CustomDataSectionProps) {\n const queryClient = useQueryClient()\n const defaultScopeVersion = useOrganizationScopeVersion()\n const scopeVersion = scopeVersionProp ?? defaultScopeVersion\n const resolvedScopeVersion = React.useMemo(\n () => (typeof scopeVersion === 'number' ? scopeVersion : Number(scopeVersion) || 0),\n [scopeVersion],\n )\n const [dictionaryMapsByField, setDictionaryMapsByField] = React.useState<Record<string, DictionaryMap>>({})\n const [resolvedDisplaysByField, setResolvedDisplaysByField] = React.useState<Record<string, Record<string, ResolvedValueDisplay>>>({})\n const [editing, setEditing] = React.useState(false)\n const sectionRef = React.useRef<HTMLDivElement | null>(null)\n const [markdownPlugins, setMarkdownPlugins] = React.useState<PluggableList>([])\n React.useEffect(() => {\n if (isTestEnv) return\n let mounted = true\n void loadMarkdownPlugins().then((plugins) => {\n if (!mounted) return\n setMarkdownPlugins(plugins)\n })\n return () => {\n mounted = false\n }\n }, [])\n const resolvedEntityIds = React.useMemo(() => {\n if (Array.isArray(entityIds) && entityIds.length) {\n const dedup = new Set<string>()\n const list: string[] = []\n entityIds.forEach((id) => {\n const trimmed = typeof id === 'string' ? id.trim() : ''\n if (!trimmed || dedup.has(trimmed)) return\n dedup.add(trimmed)\n list.push(trimmed)\n })\n return list\n }\n if (typeof entityId === 'string' && entityId.trim().length > 0) {\n return [entityId.trim()]\n }\n return []\n }, [entityId, entityIds])\n const primaryEntityId = resolvedEntityIds.length ? resolvedEntityIds[0] : undefined\n const customFieldFormsQuery = useQuery({\n queryKey: ['customFieldForms', resolvedScopeVersion, ...resolvedEntityIds],\n enabled: resolvedEntityIds.length > 0,\n staleTime: 5 * 60 * 1000,\n gcTime: 30 * 60 * 1000,\n queryFn: async () => {\n const loader = loadFields ?? fetchCustomFieldFormFieldsWithDefinitions\n return loader(resolvedEntityIds)\n },\n })\n const fields = React.useMemo(() => customFieldFormsQuery.data?.fields ?? [], [customFieldFormsQuery.data])\n const definitions = React.useMemo(\n () => customFieldFormsQuery.data?.definitions ?? [],\n [customFieldFormsQuery.data],\n )\n const [dictionaryLoading, setDictionaryLoading] = React.useState(false)\n const [relationLoading, setRelationLoading] = React.useState(false)\n const loading = customFieldFormsQuery.isLoading || dictionaryLoading || relationLoading\n const hasFields = fields.length > 0\n const definitionHref = explicitDefinitionHref ?? (primaryEntityId\n ? `/backend/entities/system/${encodeURIComponent(primaryEntityId)}`\n : undefined)\n\n React.useEffect(() => {\n if (!hasFields && editing) {\n setEditing(false)\n }\n }, [editing, hasFields])\n\n const submitActiveForm = React.useCallback(() => {\n const node = sectionRef.current?.querySelector('form')\n if (!node) return\n const form = node as HTMLFormElement\n if (typeof form.requestSubmit === 'function') {\n form.requestSubmit()\n return\n }\n form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }))\n }, [])\n\n const handleEditingKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!editing) return\n if (event.key === 'Escape') {\n event.preventDefault()\n setEditing(false)\n return\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n submitActiveForm()\n }\n },\n [editing, submitActiveForm],\n )\n\n const handleActivate = React.useCallback(() => {\n if (loading || editing || !hasFields) return\n setEditing(true)\n }, [editing, hasFields, loading])\n\n const handleReadOnlyKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (loading || editing || !hasFields) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n setEditing(true)\n }\n },\n [editing, hasFields, loading],\n )\n\n React.useEffect(() => {\n if (!resolvedEntityIds.length || !definitions.length) {\n setDictionaryLoading((prev) => (prev ? false : prev))\n setDictionaryMapsByField((prev) => (Object.keys(prev).length ? {} : prev))\n return\n }\n\n let cancelled = false\n const load = async () => {\n setDictionaryLoading(true)\n try {\n const dictionaryDefs = definitions\n .map((def) => {\n const rawId = typeof def.dictionaryId === 'string' ? def.dictionaryId.trim() : ''\n if (!rawId) return null\n return { keyLower: def.key.toLowerCase(), dictionaryId: rawId }\n })\n .filter((entry): entry is { keyLower: string; dictionaryId: string } => !!entry)\n\n if (!dictionaryDefs.length) {\n if (!cancelled) {\n setDictionaryMapsByField((prev) => (Object.keys(prev).length ? {} : prev))\n }\n return\n }\n\n const uniqueDictionaryIds = Array.from(new Set(dictionaryDefs.map((entry) => entry.dictionaryId)))\n const mapsByDictionaryId: Record<string, DictionaryMap> = {}\n\n await Promise.all(\n uniqueDictionaryIds.map(async (dictionaryId) => {\n try {\n const data = await ensureDictionaryEntries(queryClient, dictionaryId, resolvedScopeVersion)\n mapsByDictionaryId[dictionaryId] = data.map\n } catch {\n mapsByDictionaryId[dictionaryId] = {}\n }\n }),\n )\n\n const dictionaryByKey = dictionaryDefs.reduce<Map<string, string>>((acc, entry) => {\n acc.set(entry.keyLower, entry.dictionaryId)\n return acc\n }, new Map())\n\n const nextMaps: Record<string, DictionaryMap> = {}\n fields.forEach((field) => {\n const id = typeof field.id === 'string' ? field.id : ''\n if (!id) return\n const normalizedKey = id.startsWith('cf_') ? id.slice(3) : id\n const keyLower = normalizedKey.toLowerCase()\n if (!keyLower) return\n const dictionaryId = dictionaryByKey.get(keyLower)\n if (!dictionaryId) return\n nextMaps[id] = mapsByDictionaryId[dictionaryId] ?? {}\n })\n\n if (!cancelled) {\n setDictionaryMapsByField((prev) => {\n const prevKeys = Object.keys(prev)\n const nextKeys = Object.keys(nextMaps)\n if (\n prevKeys.length === nextKeys.length &&\n prevKeys.every((key) => prev[key] === nextMaps[key])\n ) {\n return prev\n }\n return nextMaps\n })\n }\n } catch {\n if (!cancelled) {\n setDictionaryMapsByField((prev) => (Object.keys(prev).length ? {} : prev))\n }\n } finally {\n if (!cancelled) {\n setDictionaryLoading(false)\n }\n }\n }\n\n load().catch(() => {})\n return () => {\n cancelled = true\n }\n }, [definitions, fields, queryClient, resolvedEntityIds, resolvedScopeVersion])\n\n React.useEffect(() => {\n if (!definitions.length || !fields.length) {\n setRelationLoading((prev) => (prev ? false : prev))\n setResolvedDisplaysByField((prev) => (Object.keys(prev).length ? {} : prev))\n return\n }\n\n const definitionsByKey = definitions.reduce<Map<string, CustomFieldDefDto>>((acc, definition) => {\n acc.set(definition.key.toLowerCase(), definition)\n return acc\n }, new Map())\n\n const relationFields = fields\n .map((field) => {\n const normalizedKey = field.id.startsWith('cf_') ? field.id.slice(3) : field.id\n const definition = definitionsByKey.get(normalizedKey.toLowerCase())\n if (!definition || definition.kind !== 'relation') return null\n const relationIds = collectRelationValueIds(values?.[field.id])\n if (!relationIds.length) return null\n return { field, definition, relationIds }\n })\n .filter((entry): entry is { field: CrudField; definition: CustomFieldDefDto; relationIds: string[] } => !!entry)\n\n if (!relationFields.length) {\n setRelationLoading((prev) => (prev ? false : prev))\n setResolvedDisplaysByField((prev) => (Object.keys(prev).length ? {} : prev))\n return\n }\n\n const abortController = new AbortController()\n\n const load = async () => {\n setRelationLoading(true)\n try {\n const nextDisplays: Record<string, Record<string, ResolvedValueDisplay>> = {}\n\n await Promise.all(\n relationFields.map(async ({ field, definition, relationIds }) => {\n const displays: Record<string, ResolvedValueDisplay> = {}\n\n if ('options' in field && Array.isArray(field.options)) {\n field.options.forEach((option) => {\n displays[option.value] = { label: option.label }\n })\n }\n\n if ('loadOptions' in field && typeof field.loadOptions === 'function') {\n try {\n const remoteOptions = await field.loadOptions()\n remoteOptions.forEach((option) => {\n const href = (() => {\n const relation = parseRelationOptionsMetadata(definition.optionsUrl)\n return relation ? buildRelationHref(relation.entityId, option.value) : undefined\n })()\n displays[option.value] = { label: option.label, href }\n })\n } catch (error) {\n console.debug('[CustomDataSection] Failed to load remote options for field', field.id, error)\n }\n }\n\n const relation = parseRelationOptionsMetadata(definition.optionsUrl)\n const needsRouteContext = relation ? getRelationHrefContextFields(relation.entityId).length > 0 : false\n const unresolvedIds = relationIds.filter((relationId) => {\n const display = displays[relationId]\n if (!display) return true\n return needsRouteContext && !display.href\n })\n if (relation && unresolvedIds.length) {\n try {\n const fetchedDisplays = await fetchRelationRecordDisplays(definition.optionsUrl!, relation, unresolvedIds, abortController.signal)\n Object.assign(displays, fetchedDisplays)\n } catch (error) {\n console.debug('[CustomDataSection] Failed to fetch relation record displays for field', field.id, error)\n unresolvedIds.forEach((relationId) => {\n if (!displays[relationId]) {\n displays[relationId] = {\n label: relationId,\n href: buildRelationHref(relation.entityId, relationId),\n }\n }\n })\n }\n }\n\n if (Object.keys(displays).length > 0) {\n nextDisplays[field.id] = displays\n }\n }),\n )\n\n if (!abortController.signal.aborted) {\n setResolvedDisplaysByField((prev) => {\n const previousKeys = Object.keys(prev)\n const nextKeys = Object.keys(nextDisplays)\n if (\n previousKeys.length === nextKeys.length &&\n previousKeys.every((key) => JSON.stringify(prev[key]) === JSON.stringify(nextDisplays[key]))\n ) {\n return prev\n }\n return nextDisplays\n })\n }\n } finally {\n if (!abortController.signal.aborted) {\n setRelationLoading(false)\n }\n }\n }\n\n void load()\n return () => {\n abortController.abort()\n }\n }, [definitions, fields, values])\n\n const handleSubmit = React.useCallback(\n async (input: Record<string, unknown>) => {\n await onSubmit(input)\n setEditing(false)\n },\n [onSubmit],\n )\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between group\">\n <h2 className=\"text-sm font-semibold\">{title}</h2>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n if (!hasFields || loading) return\n setEditing((prev) => !prev)\n }}\n disabled={loading || !hasFields}\n className={\n editing\n ? 'opacity-100 transition-opacity duration-150'\n : 'opacity-100 md:opacity-0 transition-opacity duration-150 md:group-hover:opacity-100 focus-visible:opacity-100'\n }\n >\n {editing ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n <span className=\"sr-only\">{editing ? labels.cancel ?? 'Cancel' : labels.edit ?? 'Edit'}</span>\n </Button>\n </div>\n <DataLoader\n isLoading={loading}\n loadingMessage={labels.loading}\n spinnerSize=\"md\"\n className=\"min-h-[120px]\"\n >\n {editing ? (\n <div\n ref={sectionRef}\n className=\"rounded-lg border bg-card p-3 sm:p-4\"\n onKeyDown={handleEditingKeyDown}\n >\n <CrudForm<Record<string, unknown>>\n embedded\n entityId={primaryEntityId}\n entityIds={resolvedEntityIds}\n fields={fields}\n initialValues={values}\n onSubmit={handleSubmit}\n submitLabel={labels.saveShortcut}\n isLoading={loading}\n />\n </div>\n ) : (\n <div\n className={cn(\n 'rounded-lg border bg-muted/30 p-3 sm:p-4 space-y-2 sm:space-y-3 transition hover:border-border/70 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n hasFields && !loading ? 'cursor-pointer' : 'cursor-default',\n )}\n role={hasFields && !loading ? 'button' : undefined}\n tabIndex={hasFields && !loading ? 0 : -1}\n onClick={hasFields && !loading ? handleActivate : undefined}\n onKeyDown={hasFields && !loading ? handleReadOnlyKeyDown : undefined}\n >\n {!hasFields ? (\n <p className=\"text-sm text-muted-foreground\">\n {labels.noFields}{' '}\n {definitionHref && labels.defineFields ? (\n <Link\n href={definitionHref}\n className=\"font-medium text-primary underline-offset-2 hover:underline focus-visible:underline\"\n >\n {labels.defineFields}\n </Link>\n ) : null}\n </p>\n ) : (\n fields.map((field) => (\n <div key={field.id} className=\"space-y-1\">\n <p className=\"text-xs uppercase tracking-wide text-muted-foreground\">\n {field.label}\n </p>\n <div className=\"text-sm break-words\">\n {formatFieldValue(\n field,\n values?.[field.id],\n labels.emptyValue,\n dictionaryMapsByField[field.id],\n markdownPlugins,\n resolvedDisplaysByField[field.id],\n )}\n </div>\n </div>\n ))\n )}\n </div>\n )}\n </DataLoader>\n </div>\n )\n}\n\nexport function CustomDataSection(props: CustomDataSectionProps) {\n const handle = ComponentReplacementHandles.section('ui.detail', 'CustomDataSection')\n const Resolved = useRegisteredComponent<CustomDataSectionProps>(\n handle,\n CustomDataSectionImpl as React.ComponentType<CustomDataSectionProps>,\n )\n\n return (\n <div data-component-handle={handle}>\n <Resolved {...props} />\n </div>\n )\n}\n\nexport default CustomDataSection\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport type { PluggableList } from 'unified'\nimport { Pencil, X } from 'lucide-react'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { DataLoader } from '@open-mercato/ui/primitives/DataLoader'\nimport type { CrudField } from '@open-mercato/ui/backend/CrudForm'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { fetchCustomFieldFormFieldsWithDefinitions } from '@open-mercato/ui/backend/utils/customFieldForms'\nimport type { CustomFieldDefDto } from '@open-mercato/ui/backend/utils/customFieldDefs'\nimport {\n DictionaryValue,\n type DictionaryMap,\n} from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { ensureDictionaryEntries } from '@open-mercato/core/modules/dictionaries/components/hooks/useDictionaryEntries'\nimport {\n type ResolvedValueDisplay,\n collectRelationValueIds,\n extractOptionLookupKey,\n extractInlineOptionLabel,\n parseRelationOptionsMetadata,\n getRelationHrefContextFields,\n buildRelationHref,\n fetchRelationRecordDisplays,\n} from '@open-mercato/ui/backend/utils/customFieldRelationDisplay'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { ComponentReplacementHandles } from '@open-mercato/shared/modules/widgets/component-registry'\nimport { MarkdownPreview } from '../markdown'\nimport { useRegisteredComponent } from '../injection/useRegisteredComponent'\n\nconst isTestEnv =\n typeof process !== 'undefined' &&\n (process.env.NODE_ENV === 'test' || typeof process.env.JEST_WORKER_ID !== 'undefined')\n\nlet markdownPluginsPromise: Promise<PluggableList> | null = null\n\nasync function loadMarkdownPlugins(): Promise<PluggableList> {\n if (isTestEnv) return []\n if (!markdownPluginsPromise) {\n markdownPluginsPromise = import('remark-gfm')\n .then((mod) => [mod.default ?? mod] as PluggableList)\n .catch(() => [])\n }\n return markdownPluginsPromise\n}\n\nconst MARKDOWN_FIELD_TYPES = new Set<CrudField['type']>(['text', 'textarea', 'richtext'])\nconst MARKDOWN_CLASSNAME =\n 'text-sm text-foreground break-words [&>*]:mb-2 [&>*:last-child]:mb-0 [&_ul]:ml-4 [&_ul]:list-disc [&_ol]:ml-4 [&_ol]:list-decimal [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre]:text-xs'\n\nfunction renderMarkdownValue(content: string, remarkPlugins: PluggableList) {\n return (\n <MarkdownPreview remarkPlugins={remarkPlugins} className={MARKDOWN_CLASSNAME}>\n {content}\n </MarkdownPreview>\n )\n}\n\nfunction extractDictionaryValue(entry: unknown): string | null {\n if (typeof entry === 'string') {\n const trimmed = entry.trim()\n return trimmed.length ? trimmed : null\n }\n if (!entry || typeof entry !== 'object') return null\n const record = entry as Record<string, unknown>\n const candidate = record.value ?? record.name ?? record.id ?? record.key ?? record.label\n if (typeof candidate === 'string') {\n const trimmed = candidate.trim()\n return trimmed.length ? trimmed : null\n }\n return null\n}\n\nfunction readCustomDataFieldValue(values: Record<string, unknown> | undefined, fieldId: string): unknown {\n if (!values || !fieldId) return undefined\n const candidates = fieldId.startsWith('cf_')\n ? [fieldId, `cf:${fieldId.slice(3)}`, fieldId.slice(3)]\n : [fieldId, `cf_${fieldId}`, `cf:${fieldId}`]\n\n for (const candidate of candidates) {\n if (Object.prototype.hasOwnProperty.call(values, candidate)) {\n return values[candidate]\n }\n }\n return undefined\n}\n\nexport type CustomDataLabels = {\n loading: string\n emptyValue: string\n noFields: string\n defineFields?: string\n saveShortcut: string\n edit?: string\n cancel?: string\n}\n\nexport type CustomDataSectionProps = {\n entityId?: string\n entityIds?: string[]\n values: Record<string, unknown>\n onSubmit: (values: Record<string, unknown>) => Promise<void>\n title: string\n scopeVersion?: string | number | null\n loadFields?: (\n entityIds: string[],\n ) => Promise<{ fields: CrudField[]; definitions: CustomFieldDefDto[] }>\n labels: CustomDataLabels\n definitionHref?: string\n}\n\nfunction formatFieldValue(\n field: CrudField,\n value: unknown,\n emptyLabel: string,\n dictionaryMap?: DictionaryMap,\n remarkPlugins: PluggableList = [],\n resolvedDisplays?: Record<string, ResolvedValueDisplay>,\n): React.ReactNode {\n if (dictionaryMap) {\n if (value === undefined || value === null || value === '') {\n return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n }\n\n if (Array.isArray(value)) {\n const normalizedValues = value\n .map((entry) => extractDictionaryValue(entry))\n .filter((entry): entry is string => typeof entry === 'string' && entry.length > 0)\n\n if (!normalizedValues.length) {\n return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n }\n\n return (\n <div className=\"flex flex-wrap gap-1.5\">\n {normalizedValues.map((entry, index) => (\n <DictionaryValue\n key={`${field.id}-${entry}-${index}`}\n value={entry}\n map={dictionaryMap}\n className=\"inline-flex items-center gap-1 rounded-full border border-border bg-card px-2 py-1 text-xs\"\n iconWrapperClassName=\"inline-flex h-4 w-4 items-center justify-center rounded-full border border-border bg-background\"\n iconClassName=\"h-3 w-3\"\n colorClassName=\"h-2.5 w-2.5 rounded-full\"\n />\n ))}\n </div>\n )\n }\n\n const resolved = extractDictionaryValue(value)\n if (!resolved) {\n return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n }\n\n return (\n <DictionaryValue\n value={resolved}\n map={dictionaryMap}\n className=\"inline-flex items-center gap-2 text-sm\"\n fallback={<span className=\"text-muted-foreground\">{emptyLabel}</span>}\n iconWrapperClassName=\"inline-flex h-6 w-6 items-center justify-center rounded border border-border bg-card\"\n iconClassName=\"h-4 w-4\"\n colorClassName=\"h-3 w-3 rounded-full\"\n />\n )\n }\n\n const optionMap =\n 'options' in field && Array.isArray(field.options)\n ? field.options.reduce<Map<string, string>>((acc, option) => {\n acc.set(option.value, option.label)\n return acc\n }, new Map())\n : null\n\n const resolveOptionDisplay = (entry: unknown): ResolvedValueDisplay | null => {\n const lookupKey = extractOptionLookupKey(entry)\n if (lookupKey && resolvedDisplays?.[lookupKey]) {\n return resolvedDisplays[lookupKey]\n }\n const inlineLabel = extractInlineOptionLabel(entry)\n if (lookupKey) {\n return {\n label: inlineLabel ?? optionMap?.get(lookupKey) ?? lookupKey,\n }\n }\n if (inlineLabel) {\n return { label: inlineLabel }\n }\n return null\n }\n\n const renderResolvedDisplay = (display: ResolvedValueDisplay) => {\n if (!display.href) return display.label\n return (\n <Link\n href={display.href}\n className=\"font-medium text-primary underline-offset-2 hover:underline focus-visible:underline\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => event.stopPropagation()}\n >\n {display.label}\n </Link>\n )\n }\n\n if (value === undefined || value === null || value === '') {\n return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n }\n\n if (Array.isArray(value)) {\n if (!value.length) return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n return value.map((entry, index) => (\n <span\n key={`${field.id}-${index}`}\n className=\"mr-1 inline-flex items-center rounded-full bg-muted px-2 py-0.5 text-xs\"\n >\n {(() => {\n const display = resolveOptionDisplay(entry)\n if (!display) return emptyLabel\n return renderResolvedDisplay(display)\n })()}\n </span>\n ))\n }\n\n if (typeof value === 'boolean') {\n return value ? 'Yes' : 'No'\n }\n\n if (resolvedDisplays && Object.keys(resolvedDisplays).length > 0) {\n const resolvedDisplay = resolveOptionDisplay(value)\n if (resolvedDisplay) {\n return renderResolvedDisplay(resolvedDisplay)\n }\n }\n\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value)\n } catch {\n return String(value)\n }\n }\n\n const resolved = optionMap?.get(String(value)) ?? String(value)\n if (typeof value === 'string' && MARKDOWN_FIELD_TYPES.has(field.type)) {\n if (!resolved.trim().length) {\n return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n }\n return renderMarkdownValue(value, remarkPlugins)\n }\n if (!resolved.length) return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n return resolved\n}\n\nfunction CustomDataSectionImpl({\n entityId,\n entityIds,\n values,\n onSubmit,\n title,\n scopeVersion: scopeVersionProp,\n loadFields,\n labels,\n definitionHref: explicitDefinitionHref,\n}: CustomDataSectionProps) {\n const queryClient = useQueryClient()\n const defaultScopeVersion = useOrganizationScopeVersion()\n const scopeVersion = scopeVersionProp ?? defaultScopeVersion\n const resolvedScopeVersion = React.useMemo(\n () => (typeof scopeVersion === 'number' ? scopeVersion : Number(scopeVersion) || 0),\n [scopeVersion],\n )\n const [dictionaryMapsByField, setDictionaryMapsByField] = React.useState<Record<string, DictionaryMap>>({})\n const [resolvedDisplaysByField, setResolvedDisplaysByField] = React.useState<Record<string, Record<string, ResolvedValueDisplay>>>({})\n const [editing, setEditing] = React.useState(false)\n const sectionRef = React.useRef<HTMLDivElement | null>(null)\n const [markdownPlugins, setMarkdownPlugins] = React.useState<PluggableList>([])\n React.useEffect(() => {\n if (isTestEnv) return\n let mounted = true\n void loadMarkdownPlugins().then((plugins) => {\n if (!mounted) return\n setMarkdownPlugins(plugins)\n })\n return () => {\n mounted = false\n }\n }, [])\n const resolvedEntityIds = React.useMemo(() => {\n if (Array.isArray(entityIds) && entityIds.length) {\n const dedup = new Set<string>()\n const list: string[] = []\n entityIds.forEach((id) => {\n const trimmed = typeof id === 'string' ? id.trim() : ''\n if (!trimmed || dedup.has(trimmed)) return\n dedup.add(trimmed)\n list.push(trimmed)\n })\n return list\n }\n if (typeof entityId === 'string' && entityId.trim().length > 0) {\n return [entityId.trim()]\n }\n return []\n }, [entityId, entityIds])\n const primaryEntityId = resolvedEntityIds.length ? resolvedEntityIds[0] : undefined\n const customFieldFormsQuery = useQuery({\n queryKey: ['customFieldForms', resolvedScopeVersion, ...resolvedEntityIds],\n enabled: resolvedEntityIds.length > 0,\n staleTime: 5 * 60 * 1000,\n gcTime: 30 * 60 * 1000,\n queryFn: async () => {\n const loader = loadFields ?? fetchCustomFieldFormFieldsWithDefinitions\n return loader(resolvedEntityIds)\n },\n })\n const fields = React.useMemo(() => customFieldFormsQuery.data?.fields ?? [], [customFieldFormsQuery.data])\n const definitions = React.useMemo(\n () => customFieldFormsQuery.data?.definitions ?? [],\n [customFieldFormsQuery.data],\n )\n const formInitialValues = React.useMemo(() => {\n const next: Record<string, unknown> = { ...(values ?? {}) }\n fields.forEach((field) => {\n if (!field.id || Object.prototype.hasOwnProperty.call(next, field.id)) return\n const resolved = readCustomDataFieldValue(values, field.id)\n if (resolved !== undefined) next[field.id] = resolved\n })\n return next\n }, [fields, values])\n const [dictionaryLoading, setDictionaryLoading] = React.useState(false)\n const [relationLoading, setRelationLoading] = React.useState(false)\n const loading = customFieldFormsQuery.isLoading || dictionaryLoading || relationLoading\n const hasFields = fields.length > 0\n const definitionHref = explicitDefinitionHref ?? (primaryEntityId\n ? `/backend/entities/system/${encodeURIComponent(primaryEntityId)}`\n : undefined)\n\n React.useEffect(() => {\n if (!hasFields && editing) {\n setEditing(false)\n }\n }, [editing, hasFields])\n\n const submitActiveForm = React.useCallback(() => {\n const node = sectionRef.current?.querySelector('form')\n if (!node) return\n const form = node as HTMLFormElement\n if (typeof form.requestSubmit === 'function') {\n form.requestSubmit()\n return\n }\n form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }))\n }, [])\n\n const handleEditingKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!editing) return\n if (event.key === 'Escape') {\n event.preventDefault()\n setEditing(false)\n return\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n submitActiveForm()\n }\n },\n [editing, submitActiveForm],\n )\n\n const handleActivate = React.useCallback(() => {\n if (loading || editing || !hasFields) return\n setEditing(true)\n }, [editing, hasFields, loading])\n\n const handleReadOnlyKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (loading || editing || !hasFields) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n setEditing(true)\n }\n },\n [editing, hasFields, loading],\n )\n\n React.useEffect(() => {\n if (!resolvedEntityIds.length || !definitions.length) {\n setDictionaryLoading((prev) => (prev ? false : prev))\n setDictionaryMapsByField((prev) => (Object.keys(prev).length ? {} : prev))\n return\n }\n\n let cancelled = false\n const load = async () => {\n setDictionaryLoading(true)\n try {\n const dictionaryDefs = definitions\n .map((def) => {\n const rawId = typeof def.dictionaryId === 'string' ? def.dictionaryId.trim() : ''\n if (!rawId) return null\n return { keyLower: def.key.toLowerCase(), dictionaryId: rawId }\n })\n .filter((entry): entry is { keyLower: string; dictionaryId: string } => !!entry)\n\n if (!dictionaryDefs.length) {\n if (!cancelled) {\n setDictionaryMapsByField((prev) => (Object.keys(prev).length ? {} : prev))\n }\n return\n }\n\n const uniqueDictionaryIds = Array.from(new Set(dictionaryDefs.map((entry) => entry.dictionaryId)))\n const mapsByDictionaryId: Record<string, DictionaryMap> = {}\n\n await Promise.all(\n uniqueDictionaryIds.map(async (dictionaryId) => {\n try {\n const data = await ensureDictionaryEntries(queryClient, dictionaryId, resolvedScopeVersion)\n mapsByDictionaryId[dictionaryId] = data.map\n } catch {\n mapsByDictionaryId[dictionaryId] = {}\n }\n }),\n )\n\n const dictionaryByKey = dictionaryDefs.reduce<Map<string, string>>((acc, entry) => {\n acc.set(entry.keyLower, entry.dictionaryId)\n return acc\n }, new Map())\n\n const nextMaps: Record<string, DictionaryMap> = {}\n fields.forEach((field) => {\n const id = typeof field.id === 'string' ? field.id : ''\n if (!id) return\n const normalizedKey = id.startsWith('cf_') ? id.slice(3) : id\n const keyLower = normalizedKey.toLowerCase()\n if (!keyLower) return\n const dictionaryId = dictionaryByKey.get(keyLower)\n if (!dictionaryId) return\n nextMaps[id] = mapsByDictionaryId[dictionaryId] ?? {}\n })\n\n if (!cancelled) {\n setDictionaryMapsByField((prev) => {\n const prevKeys = Object.keys(prev)\n const nextKeys = Object.keys(nextMaps)\n if (\n prevKeys.length === nextKeys.length &&\n prevKeys.every((key) => prev[key] === nextMaps[key])\n ) {\n return prev\n }\n return nextMaps\n })\n }\n } catch {\n if (!cancelled) {\n setDictionaryMapsByField((prev) => (Object.keys(prev).length ? {} : prev))\n }\n } finally {\n if (!cancelled) {\n setDictionaryLoading(false)\n }\n }\n }\n\n load().catch(() => {})\n return () => {\n cancelled = true\n }\n }, [definitions, fields, queryClient, resolvedEntityIds, resolvedScopeVersion])\n\n React.useEffect(() => {\n if (!definitions.length || !fields.length) {\n setRelationLoading((prev) => (prev ? false : prev))\n setResolvedDisplaysByField((prev) => (Object.keys(prev).length ? {} : prev))\n return\n }\n\n const definitionsByKey = definitions.reduce<Map<string, CustomFieldDefDto>>((acc, definition) => {\n acc.set(definition.key.toLowerCase(), definition)\n return acc\n }, new Map())\n\n const relationFields = fields\n .map((field) => {\n const normalizedKey = field.id.startsWith('cf_') ? field.id.slice(3) : field.id\n const definition = definitionsByKey.get(normalizedKey.toLowerCase())\n if (!definition || definition.kind !== 'relation') return null\n const relationIds = collectRelationValueIds(readCustomDataFieldValue(values, field.id))\n if (!relationIds.length) return null\n return { field, definition, relationIds }\n })\n .filter((entry): entry is { field: CrudField; definition: CustomFieldDefDto; relationIds: string[] } => !!entry)\n\n if (!relationFields.length) {\n setRelationLoading((prev) => (prev ? false : prev))\n setResolvedDisplaysByField((prev) => (Object.keys(prev).length ? {} : prev))\n return\n }\n\n const abortController = new AbortController()\n\n const load = async () => {\n setRelationLoading(true)\n try {\n const nextDisplays: Record<string, Record<string, ResolvedValueDisplay>> = {}\n\n await Promise.all(\n relationFields.map(async ({ field, definition, relationIds }) => {\n const displays: Record<string, ResolvedValueDisplay> = {}\n\n if ('options' in field && Array.isArray(field.options)) {\n field.options.forEach((option) => {\n displays[option.value] = { label: option.label }\n })\n }\n\n if ('loadOptions' in field && typeof field.loadOptions === 'function') {\n try {\n const remoteOptions = await field.loadOptions()\n remoteOptions.forEach((option) => {\n const href = (() => {\n const relation = parseRelationOptionsMetadata(definition.optionsUrl)\n return relation ? buildRelationHref(relation.entityId, option.value) : undefined\n })()\n displays[option.value] = { label: option.label, href }\n })\n } catch (error) {\n console.debug('[CustomDataSection] Failed to load remote options for field', field.id, error)\n }\n }\n\n const relation = parseRelationOptionsMetadata(definition.optionsUrl)\n const needsRouteContext = relation ? getRelationHrefContextFields(relation.entityId).length > 0 : false\n const unresolvedIds = relationIds.filter((relationId) => {\n const display = displays[relationId]\n if (!display) return true\n return needsRouteContext && !display.href\n })\n if (relation && unresolvedIds.length) {\n try {\n const fetchedDisplays = await fetchRelationRecordDisplays(definition.optionsUrl!, relation, unresolvedIds, abortController.signal)\n Object.assign(displays, fetchedDisplays)\n } catch (error) {\n console.debug('[CustomDataSection] Failed to fetch relation record displays for field', field.id, error)\n unresolvedIds.forEach((relationId) => {\n if (!displays[relationId]) {\n displays[relationId] = {\n label: relationId,\n href: buildRelationHref(relation.entityId, relationId),\n }\n }\n })\n }\n }\n\n if (Object.keys(displays).length > 0) {\n nextDisplays[field.id] = displays\n }\n }),\n )\n\n if (!abortController.signal.aborted) {\n setResolvedDisplaysByField((prev) => {\n const previousKeys = Object.keys(prev)\n const nextKeys = Object.keys(nextDisplays)\n if (\n previousKeys.length === nextKeys.length &&\n previousKeys.every((key) => JSON.stringify(prev[key]) === JSON.stringify(nextDisplays[key]))\n ) {\n return prev\n }\n return nextDisplays\n })\n }\n } finally {\n if (!abortController.signal.aborted) {\n setRelationLoading(false)\n }\n }\n }\n\n void load()\n return () => {\n abortController.abort()\n }\n }, [definitions, fields, values])\n\n const handleSubmit = React.useCallback(\n async (input: Record<string, unknown>) => {\n await onSubmit(input)\n setEditing(false)\n },\n [onSubmit],\n )\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between group\">\n <h2 className=\"text-sm font-semibold\">{title}</h2>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n if (!hasFields || loading) return\n setEditing((prev) => !prev)\n }}\n disabled={loading || !hasFields}\n className={\n editing\n ? 'opacity-100 transition-opacity duration-150'\n : 'opacity-100 md:opacity-0 transition-opacity duration-150 md:group-hover:opacity-100 focus-visible:opacity-100'\n }\n >\n {editing ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n <span className=\"sr-only\">{editing ? labels.cancel ?? 'Cancel' : labels.edit ?? 'Edit'}</span>\n </Button>\n </div>\n <DataLoader\n isLoading={loading}\n loadingMessage={labels.loading}\n spinnerSize=\"md\"\n className=\"min-h-[120px]\"\n >\n {editing ? (\n <div\n ref={sectionRef}\n className=\"rounded-lg border bg-card p-3 sm:p-4\"\n onKeyDown={handleEditingKeyDown}\n >\n <CrudForm<Record<string, unknown>>\n embedded\n entityId={primaryEntityId}\n entityIds={resolvedEntityIds}\n fields={fields}\n initialValues={formInitialValues}\n onSubmit={handleSubmit}\n submitLabel={labels.saveShortcut}\n isLoading={loading}\n />\n </div>\n ) : (\n <div\n className={cn(\n 'rounded-lg border bg-muted/30 p-3 sm:p-4 space-y-2 sm:space-y-3 transition hover:border-border/70 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n hasFields && !loading ? 'cursor-pointer' : 'cursor-default',\n )}\n role={hasFields && !loading ? 'button' : undefined}\n tabIndex={hasFields && !loading ? 0 : -1}\n onClick={hasFields && !loading ? handleActivate : undefined}\n onKeyDown={hasFields && !loading ? handleReadOnlyKeyDown : undefined}\n >\n {!hasFields ? (\n <p className=\"text-sm text-muted-foreground\">\n {labels.noFields}{' '}\n {definitionHref && labels.defineFields ? (\n <Link\n href={definitionHref}\n className=\"font-medium text-primary underline-offset-2 hover:underline focus-visible:underline\"\n >\n {labels.defineFields}\n </Link>\n ) : null}\n </p>\n ) : (\n fields.map((field) => (\n <div key={field.id} className=\"space-y-1\">\n <p className=\"text-xs uppercase tracking-wide text-muted-foreground\">\n {field.label}\n </p>\n <div className=\"text-sm break-words\">\n {formatFieldValue(\n field,\n readCustomDataFieldValue(values, field.id),\n labels.emptyValue,\n dictionaryMapsByField[field.id],\n markdownPlugins,\n resolvedDisplaysByField[field.id],\n )}\n </div>\n </div>\n ))\n )}\n </div>\n )}\n </DataLoader>\n </div>\n )\n}\n\nexport function CustomDataSection(props: CustomDataSectionProps) {\n const handle = ComponentReplacementHandles.section('ui.detail', 'CustomDataSection')\n const Resolved = useRegisteredComponent<CustomDataSectionProps>(\n handle,\n CustomDataSectionImpl as React.ComponentType<CustomDataSectionProps>,\n )\n\n return (\n <div data-component-handle={handle}>\n <Resolved {...props} />\n </div>\n )\n}\n\nexport default CustomDataSection\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["resolved", "relation"]
|
|
7
7
|
}
|
|
@@ -749,7 +749,7 @@ function GroupToolbar({
|
|
|
749
749
|
}) : t("ui.advancedFilter.limitTotalReached", "Maximum {max} conditions reached", {
|
|
750
750
|
max: TREE_LIMITS.maxTotalRules
|
|
751
751
|
}) : void 0;
|
|
752
|
-
const addGroupLabel = level === 1 ? t("ui.advancedFilter.addGroup", "
|
|
752
|
+
const addGroupLabel = level === 1 ? t("ui.advancedFilter.addGroup", "Add group") : t("ui.advancedFilter.addSubgroup", "Add subgroup");
|
|
753
753
|
const ctaClass = "text-brand-violet hover:text-brand-violet/80 hover:bg-transparent px-0 disabled:text-muted-foreground/50 disabled:hover:text-muted-foreground/50";
|
|
754
754
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
755
755
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
@@ -774,7 +774,7 @@ function GroupToolbar({
|
|
|
774
774
|
className: ctaClass,
|
|
775
775
|
children: [
|
|
776
776
|
/* @__PURE__ */ jsx(Plus, { className: "size-4" }),
|
|
777
|
-
t("ui.advancedFilter.addCondition", "
|
|
777
|
+
t("ui.advancedFilter.addCondition", "Add condition")
|
|
778
778
|
]
|
|
779
779
|
}
|
|
780
780
|
),
|