@rakun-kit/manager-react 1.4.2 → 1.4.4

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.
@@ -8,12 +8,15 @@ exports.ManagerDashboardLayout = exports.ManagerAuthLayout = void 0;
8
8
  const jsx_runtime_1 = require("react/jsx-runtime");
9
9
  const app_sidebar_1 = require("./components/app-sidebar.js");
10
10
  const bread_crumb_1 = __importDefault(require("./components/bread-crumb.js"));
11
+ const scroll_area_1 = require("./components/ui/scroll-area.js");
11
12
  const separator_1 = require("./components/ui/separator.js");
12
13
  const manager_help_1 = require("./help/manager-help.js");
13
14
  const sidebar_1 = require("./components/ui/sidebar.js");
14
- const scroll_area_1 = require("./components/ui/scroll-area.js");
15
15
  const ManagerAuthLayout = ({ children }) => ((0, jsx_runtime_1.jsx)("div", { className: "bg-background flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10", children: (0, jsx_runtime_1.jsx)("div", { className: "w-full max-w-sm", children: children }) }));
16
16
  exports.ManagerAuthLayout = ManagerAuthLayout;
17
- const ManagerDashboardLayout = ({ children, route, contentTypes, pathname, basePath = '', secondaryItems, sidebar, headerStart, headerEnd, }) => ((0, jsx_runtime_1.jsx)(sidebar_1.SidebarProvider, { className: "max-h-screen overflow-hidden", children: (0, jsx_runtime_1.jsxs)(manager_help_1.ManagerHelpProvider, { route: route ?? { kind: 'unknown', pathname: pathname ?? '/' }, children: [sidebar ?? ((0, jsx_runtime_1.jsx)(app_sidebar_1.AppSidebar, { contentTypes: contentTypes, pathname: pathname, basePath: basePath, secondaryItems: secondaryItems })), (0, jsx_runtime_1.jsxs)(sidebar_1.SidebarInset, { className: "p-4 pt-0", children: [(0, jsx_runtime_1.jsxs)(sidebar_1.SidebarHeader, { className: "flex h-16 shrink-0 flex-row items-center justify-between gap-2", "data-tour": "manager-header", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(sidebar_1.SidebarTrigger, { className: "-ml-1" }), (0, jsx_runtime_1.jsx)(separator_1.Separator, { orientation: "vertical", className: "mr-2 data-[orientation=vertical]:h-4" }), headerStart ?? (0, jsx_runtime_1.jsx)(bread_crumb_1.default, { basePath: basePath, pathname: pathname })] }), headerEnd] }), (0, jsx_runtime_1.jsx)(scroll_area_1.ScrollArea, { className: "h-[calc(100vh-5rem)]", "data-tour": "manager-page", children: children })] })] }) }));
17
+ const ManagerDashboardLayout = ({ children, route, contentTypes, pathname, basePath = '', secondaryItems, sidebar, headerStart, headerEnd, }) => {
18
+ const hasInternalPageScroll = route?.kind === 'content-create' || route?.kind === 'content-edit';
19
+ return ((0, jsx_runtime_1.jsx)(sidebar_1.SidebarProvider, { className: "h-svh min-h-0 overflow-hidden", children: (0, jsx_runtime_1.jsxs)(manager_help_1.ManagerHelpProvider, { route: route ?? { kind: 'unknown', pathname: pathname ?? '/' }, children: [sidebar ?? ((0, jsx_runtime_1.jsx)(app_sidebar_1.AppSidebar, { contentTypes: contentTypes, pathname: pathname, basePath: basePath, secondaryItems: secondaryItems })), (0, jsx_runtime_1.jsxs)(sidebar_1.SidebarInset, { className: "min-h-0 overflow-hidden p-4 pt-0", children: [(0, jsx_runtime_1.jsxs)(sidebar_1.SidebarHeader, { className: "flex h-16 shrink-0 flex-row items-center justify-between gap-2", "data-tour": "manager-header", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(sidebar_1.SidebarTrigger, { className: "-ml-1" }), (0, jsx_runtime_1.jsx)(separator_1.Separator, { orientation: "vertical", className: "mr-2 data-[orientation=vertical]:h-4" }), headerStart ?? (0, jsx_runtime_1.jsx)(bread_crumb_1.default, { basePath: basePath, pathname: pathname })] }), headerEnd] }), hasInternalPageScroll ? ((0, jsx_runtime_1.jsx)("div", { className: "min-h-0 flex-1 overflow-hidden", "data-tour": "manager-page", children: children })) : ((0, jsx_runtime_1.jsx)(scroll_area_1.ScrollArea, { className: "min-h-0 flex-1", "data-tour": "manager-page", children: children }))] })] }) }));
20
+ };
18
21
  exports.ManagerDashboardLayout = ManagerDashboardLayout;
19
22
  //# sourceMappingURL=layouts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"layouts.js","sourceRoot":"","sources":["../../src/layouts.tsx"],"names":[],"mappings":";AAAA,YAAY,CAAA;;;;;;;AAMZ,0DAA8E;AAC9E,2EAA0D;AAC1D,yDAAqD;AACrD,sDAAyD;AACzD,qDAKgC;AAChC,6DAAwD;AAoBjD,MAAM,iBAAiB,GAAG,CAAC,EAAE,QAAQ,EAA0B,EAAE,EAAE,CAAC,CACzE,gCAAK,SAAS,EAAC,qFAAqF,YAClG,gCAAK,SAAS,EAAC,iBAAiB,YAAE,QAAQ,GAAO,GAC7C,CACP,CAAA;AAJY,QAAA,iBAAiB,qBAI7B;AAcM,MAAM,sBAAsB,GAAG,CAAC,EACrC,QAAQ,EACR,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,QAAQ,GAAG,EAAE,EACb,cAAc,EACd,OAAO,EACP,WAAW,EACX,SAAS,GACmB,EAAE,EAAE,CAAC,CACjC,uBAAC,yBAAe,IAAC,SAAS,EAAC,8BAA8B,YACvD,wBAAC,kCAAmB,IAAC,KAAK,EAAE,KAAK,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI,GAAG,EAAE,aAChF,OAAO,IAAI,CACV,uBAAC,wBAAU,IACT,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,cAAc,EAAE,cAAc,GAC9B,CACH,EACD,wBAAC,sBAAY,IAAC,SAAS,EAAC,UAAU,aAChC,wBAAC,uBAAa,IACZ,SAAS,EAAC,gEAAgE,eAChE,gBAAgB,aAE1B,iCAAK,SAAS,EAAC,yBAAyB,aACtC,uBAAC,wBAAc,IAAC,SAAS,EAAC,OAAO,GAAG,EACpC,uBAAC,qBAAS,IAAC,WAAW,EAAC,UAAU,EAAC,SAAS,EAAC,sCAAsC,GAAG,EACpF,WAAW,IAAI,uBAAC,qBAAmB,IAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAI,IAC3E,EACL,SAAS,IACI,EAEhB,uBAAC,wBAAU,IAAC,SAAS,EAAC,sBAAsB,eAAW,cAAc,YAClE,QAAQ,GACE,IACA,IACK,GACN,CACnB,CAAA;AAxCY,QAAA,sBAAsB,0BAwClC"}
1
+ {"version":3,"file":"layouts.js","sourceRoot":"","sources":["../../src/layouts.tsx"],"names":[],"mappings":";AAAA,YAAY,CAAA;;;;;;;AAMZ,0DAA8E;AAC9E,2EAA0D;AAC1D,6DAAwD;AACxD,yDAAqD;AACrD,sDAAyD;AACzD,qDAKgC;AAoBzB,MAAM,iBAAiB,GAAG,CAAC,EAAE,QAAQ,EAA0B,EAAE,EAAE,CAAC,CACzE,gCAAK,SAAS,EAAC,qFAAqF,YAClG,gCAAK,SAAS,EAAC,iBAAiB,YAAE,QAAQ,GAAO,GAC7C,CACP,CAAA;AAJY,QAAA,iBAAiB,qBAI7B;AAcM,MAAM,sBAAsB,GAAG,CAAC,EACrC,QAAQ,EACR,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,QAAQ,GAAG,EAAE,EACb,cAAc,EACd,OAAO,EACP,WAAW,EACX,SAAS,GACmB,EAAE,EAAE;IAChC,MAAM,qBAAqB,GAAG,KAAK,EAAE,IAAI,KAAK,gBAAgB,IAAI,KAAK,EAAE,IAAI,KAAK,cAAc,CAAA;IAEhG,OAAO,CACL,uBAAC,yBAAe,IAAC,SAAS,EAAC,+BAA+B,YACxD,wBAAC,kCAAmB,IAAC,KAAK,EAAE,KAAK,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI,GAAG,EAAE,aAChF,OAAO,IAAI,CACV,uBAAC,wBAAU,IACT,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,cAAc,EAAE,cAAc,GAC9B,CACH,EACD,wBAAC,sBAAY,IAAC,SAAS,EAAC,kCAAkC,aACxD,wBAAC,uBAAa,IACZ,SAAS,EAAC,gEAAgE,eAChE,gBAAgB,aAE1B,iCAAK,SAAS,EAAC,yBAAyB,aACtC,uBAAC,wBAAc,IAAC,SAAS,EAAC,OAAO,GAAG,EACpC,uBAAC,qBAAS,IACR,WAAW,EAAC,UAAU,EACtB,SAAS,EAAC,sCAAsC,GAChD,EACD,WAAW,IAAI,uBAAC,qBAAmB,IAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAI,IAC3E,EACL,SAAS,IACI,EAEf,qBAAqB,CAAC,CAAC,CAAC,CACvB,gCAAK,SAAS,EAAC,gCAAgC,eAAW,cAAc,YACrE,QAAQ,GACL,CACP,CAAC,CAAC,CAAC,CACF,uBAAC,wBAAU,IAAC,SAAS,EAAC,gBAAgB,eAAW,cAAc,YAC5D,QAAQ,GACE,CACd,IACY,IACK,GACN,CACnB,CAAA;AACH,CAAC,CAAA;AArDY,QAAA,sBAAsB,0BAqDlC"}
@@ -15,7 +15,7 @@ const tabs_1 = require("../../../../../components/ui/tabs.js");
15
15
  const scroll_area_1 = require("../../../../../components/ui/scroll-area.js");
16
16
  const EditTabPanels = () => {
17
17
  const { activeTab, canRestoreVersions, contentType, contentTypeId, contentTypeName, form, hasVersioning, hasLocaleVariants, onAfterRestore, routeLayout, sections, } = (0, EditPageContext_1.useEditPageContext)();
18
- return ((0, jsx_runtime_1.jsx)(scroll_area_1.ScrollArea, { className: "h-full pr-4", "data-rakun-manager-edit-scroll-area": true, children: (0, jsx_runtime_1.jsxs)("div", { className: "min-w-0 h-[calc(100vh-14rem)]", children: [sections.hasIterables ? ((0, jsx_runtime_1.jsx)(tabs_1.TabsContent, { value: "content", forceMount: true, hidden: activeTab !== 'content', className: "w-full h-full", "data-rakun-manager-tab-panel": "content", "data-tour": "content-edit-fields", children: (0, jsx_runtime_1.jsx)(ContentTypeEdit_1.default, { defaultData: form.draft.current, ref: form.iterablesRef, contentType: sections.iterables, parentContentType: contentType, id: contentTypeName, collapsible: true, hideTitle: true }, `iterables:${form.formRevision}`) })) : null, sections.hasNonIterables ? ((0, jsx_runtime_1.jsx)(tabs_1.TabsContent, { value: "info", forceMount: true, hidden: activeTab !== 'info', className: "w-full h-full", "data-tour": "content-edit-fields", children: (0, jsx_runtime_1.jsx)(ContentTypeEdit_1.default, { defaultData: form.draft.current, ref: form.nonIterablesRef, contentType: sections.nonIterables, id: contentTypeName }, `info:${form.formRevision}`) })) : null, sections.hasSeo ? ((0, jsx_runtime_1.jsx)(tabs_1.TabsContent, { value: "seo", forceMount: true, hidden: activeTab !== 'seo', className: "w-full h-full", "data-tour": "content-edit-fields", children: (0, jsx_runtime_1.jsx)(ContentTypeEdit_1.default, { defaultData: form.draft.current, ref: form.seoRef, contentType: sections.seo, id: contentTypeName, hideTitle: true }, `seo:${form.formRevision}`) })) : null, routeLayout.routeLayoutModules.map((layoutModule) => ((0, jsx_runtime_1.jsx)(RouteLayoutModuleTabContent_1.RouteLayoutModuleTabContent, { layoutModule: layoutModule }, layoutModule._id))), hasLocaleVariants ? ((0, jsx_runtime_1.jsx)(tabs_1.TabsContent, { value: "locale-variants", children: (0, jsx_runtime_1.jsx)(LocaleVariants_1.LocaleVariants, {}) })) : null, hasVersioning && contentTypeId ? ((0, jsx_runtime_1.jsx)(tabs_1.TabsContent, { value: "versions", children: (0, jsx_runtime_1.jsx)(Versions_1.default, { contentType: contentTypeName, documentId: contentTypeId, canRestore: canRestoreVersions, onRestored: onAfterRestore }) })) : null] }) }));
18
+ return ((0, jsx_runtime_1.jsx)(scroll_area_1.ScrollArea, { className: "h-full min-h-0 pr-4", "data-rakun-manager-edit-scroll-area": true, children: (0, jsx_runtime_1.jsxs)("div", { className: "min-h-full min-w-0", children: [sections.hasIterables ? ((0, jsx_runtime_1.jsx)(tabs_1.TabsContent, { value: "content", forceMount: true, hidden: activeTab !== 'content', className: "w-full h-full", "data-rakun-manager-tab-panel": "content", "data-tour": "content-edit-fields", children: (0, jsx_runtime_1.jsx)(ContentTypeEdit_1.default, { defaultData: form.draft.current, ref: form.iterablesRef, contentType: sections.iterables, parentContentType: contentType, id: contentTypeName, collapsible: true, hideTitle: true }, `iterables:${form.formRevision}`) })) : null, sections.hasNonIterables ? ((0, jsx_runtime_1.jsx)(tabs_1.TabsContent, { value: "info", forceMount: true, hidden: activeTab !== 'info', className: "w-full h-full", "data-tour": "content-edit-fields", children: (0, jsx_runtime_1.jsx)(ContentTypeEdit_1.default, { defaultData: form.draft.current, ref: form.nonIterablesRef, contentType: sections.nonIterables, id: contentTypeName }, `info:${form.formRevision}`) })) : null, sections.hasSeo ? ((0, jsx_runtime_1.jsx)(tabs_1.TabsContent, { value: "seo", forceMount: true, hidden: activeTab !== 'seo', className: "w-full h-full", "data-tour": "content-edit-fields", children: (0, jsx_runtime_1.jsx)(ContentTypeEdit_1.default, { defaultData: form.draft.current, ref: form.seoRef, contentType: sections.seo, id: contentTypeName, hideTitle: true }, `seo:${form.formRevision}`) })) : null, routeLayout.routeLayoutModules.map((layoutModule) => ((0, jsx_runtime_1.jsx)(RouteLayoutModuleTabContent_1.RouteLayoutModuleTabContent, { layoutModule: layoutModule }, layoutModule._id))), hasLocaleVariants ? ((0, jsx_runtime_1.jsx)(tabs_1.TabsContent, { value: "locale-variants", children: (0, jsx_runtime_1.jsx)(LocaleVariants_1.LocaleVariants, {}) })) : null, hasVersioning && contentTypeId ? ((0, jsx_runtime_1.jsx)(tabs_1.TabsContent, { value: "versions", children: (0, jsx_runtime_1.jsx)(Versions_1.default, { contentType: contentTypeName, documentId: contentTypeId, canRestore: canRestoreVersions, onRestored: onAfterRestore }) })) : null] }) }));
19
19
  };
20
20
  exports.EditTabPanels = EditTabPanels;
21
21
  //# sourceMappingURL=EditTabPanels.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"EditTabPanels.js","sourceRoot":"","sources":["../../../../../../../src/router/dashboard/[contentType]/[edit]/_components/EditTabPanels.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"EditTabPanels.js","sourceRoot":"","sources":["../../../../../../../src/router/dashboard/[contentType]/[edit]/_components/EditTabPanels.tsx"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ const lucide_react_1 = require("lucide-react");
8
8
  const react_1 = require("react");
9
9
  const badge_1 = require("../../../../../components/ui/badge.js");
10
10
  const button_1 = require("../../../../../components/ui/button.js");
11
+ const collapsible_1 = require("../../../../../components/ui/collapsible.js");
11
12
  const dialog_1 = require("../../../../../components/ui/dialog.js");
12
13
  const select_1 = require("../../../../../components/ui/select.js");
13
14
  const tooltip_1 = require("../../../../../components/ui/tooltip.js");
@@ -30,6 +31,7 @@ const cleanDynamicBindings = (bindings) => {
30
31
  };
31
32
  const isRecord = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
32
33
  const isListField = (field) => field.config.ui === 'List' || field.config.ui === 'Iterator';
34
+ const isRelatedCollectionSource = (source) => !!source && 'kind' in source && source.kind === 'relatedCollection';
33
35
  const isDynamicVisibleField = (field) => (field.visibility ?? 'all') === 'all' && field.isDynamic !== false;
34
36
  const isDynamicFieldEnabled = (contentType, field) => {
35
37
  return (contentType.dynamicData !== false &&
@@ -60,6 +62,8 @@ const getFieldKind = (field) => {
60
62
  }
61
63
  if (field.config.type === 'Relation')
62
64
  return 'object';
65
+ if (field.config.ui === 'SimpleList')
66
+ return 'array';
63
67
  if (isListField(field))
64
68
  return 'array';
65
69
  return 'unknown';
@@ -69,6 +73,29 @@ const isCompatibleSourceKind = (sourceKind, targetField) => {
69
73
  return sourceKind !== 'object' && sourceKind !== 'array';
70
74
  return sourceKind === getFieldKind(targetField);
71
75
  };
76
+ const getMultipleFileField = (field) => field.config.type === 'File' &&
77
+ field.isMultiple
78
+ ? field
79
+ : undefined;
80
+ const areFieldKindsCompatible = (sourceField, targetField) => {
81
+ const sourceKind = getFieldKind(sourceField);
82
+ if (!targetField)
83
+ return isCompatibleSourceKind(sourceKind);
84
+ const targetKind = getFieldKind(targetField);
85
+ if (sourceKind !== targetKind)
86
+ return false;
87
+ if (sourceKind !== 'array')
88
+ return true;
89
+ const sourceFile = getMultipleFileField(sourceField);
90
+ const targetFile = getMultipleFileField(targetField);
91
+ if (!sourceFile && !targetFile)
92
+ return true;
93
+ if (!sourceFile || !targetFile)
94
+ return false;
95
+ return (sourceFile.mediaType === 'Any' ||
96
+ targetFile.mediaType === 'Any' ||
97
+ sourceFile.mediaType === targetFile.mediaType);
98
+ };
72
99
  const fieldLabel = (path) => path.startsWith('_seo.') ? `seo.${path.slice('_seo.'.length)}` : path;
73
100
  const isSeoPath = (path) => path === '_seo' ||
74
101
  path === 'seo' ||
@@ -121,10 +148,22 @@ const nestedSourceFieldOptions = ({ contentType, prefix = '', targetField, depth
121
148
  depth: depth + 1,
122
149
  });
123
150
  }
151
+ if (field.config.type === 'File' &&
152
+ field.isMultiple) {
153
+ if (!areFieldKindsCompatible(field, targetField))
154
+ return [];
155
+ return [
156
+ {
157
+ label: fieldLabel(path),
158
+ value: path,
159
+ kind,
160
+ },
161
+ ];
162
+ }
124
163
  if (field.config.type === 'File') {
125
164
  return fileFieldOptions(path, targetField);
126
165
  }
127
- if (!isCompatibleSourceKind(kind, targetField))
166
+ if (!areFieldKindsCompatible(field, targetField))
128
167
  return [];
129
168
  return [
130
169
  {
@@ -149,6 +188,26 @@ const createSource = (contentType, value, id) => value === '$href'
149
188
  : { contentType, id, path: value };
150
189
  const sourceValue = (source) => source?.virtual === 'href' ? '$href' : source?.path || '';
151
190
  const sourceLabel = (source) => source?.virtual === 'href' ? 'href' : fieldLabel(source?.path || '');
191
+ const mappingSourceSummary = (source, currentSourceName) => {
192
+ if (!source) {
193
+ return {
194
+ mode: 'Not configured',
195
+ detail: 'Choose a mapping source',
196
+ };
197
+ }
198
+ if (!isRelatedCollectionSource(source)) {
199
+ return {
200
+ mode: 'Direct field',
201
+ detail: `${currentSourceName}.${sourceLabel(source)}`,
202
+ };
203
+ }
204
+ const sort = Object.entries(source.sort ?? {})[0];
205
+ const sortSummary = sort ? ` · sort ${sort[0]} ${sort[1]}` : '';
206
+ return {
207
+ mode: 'Related collection',
208
+ detail: `${source.contentType}.${source.relation} → ${currentSourceName} · collect ${source.path} · limit ${source.limit}${sortSummary}`,
209
+ };
210
+ };
152
211
  const sourceContentTypeLabel = (source, documentContentTypeName) => source.contentType === documentContentTypeName && !source.id
153
212
  ? 'Current document'
154
213
  : source.contentType;
@@ -216,6 +275,7 @@ const bindingSummary = ({ list, fieldBinding, listBinding, documentContentTypeNa
216
275
  return `${sourceContentTypeLabel(fieldBinding, documentContentTypeName)} -> ${sourceLabel(fieldBinding)}`;
217
276
  };
218
277
  const PanelSection = ({ title, children, }) => ((0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-3 rounded-md border border-border bg-muted/20 p-3', children: [(0, jsx_runtime_1.jsx)("div", { className: 'text-xs font-semibold uppercase text-muted-foreground', children: title }), children] }));
278
+ const ControlLabel = ({ children, help, }) => ((0, jsx_runtime_1.jsxs)("div", { className: 'flex items-center gap-1.5', children: [(0, jsx_runtime_1.jsx)(label_1.Label, { children: children }), (0, jsx_runtime_1.jsxs)(tooltip_1.Tooltip, { children: [(0, jsx_runtime_1.jsx)(tooltip_1.TooltipTrigger, { asChild: true, children: (0, jsx_runtime_1.jsx)("button", { type: 'button', className: 'rounded-sm text-muted-foreground outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring', "aria-label": help, children: (0, jsx_runtime_1.jsx)(lucide_react_1.HelpCircle, { className: 'h-3.5 w-3.5' }) }) }), (0, jsx_runtime_1.jsx)(tooltip_1.TooltipContent, { side: 'top', sideOffset: 6, className: 'max-w-xs', children: help })] })] }));
219
279
  const FieldBindingEditor = ({ contentTypes, documentContentType, currentDocumentSourceEnabled, targetField, binding, onChange, }) => {
220
280
  const { language } = (0, LanguageClientProvider_1.useLanguage)();
221
281
  const [sourceType, setSourceType] = (0, react_1.useState)(binding?.contentType || '');
@@ -245,6 +305,9 @@ const FieldBindingEditor = ({ contentTypes, documentContentType, currentDocument
245
305
  selectedContentType?.dynamicDataSource === true,
246
306
  });
247
307
  const items = (sourceItemsQuery.data?.items ?? []);
308
+ const hasCurrentDocumentItem = currentDocumentSourceEnabled && sourceType === documentContentType.name;
309
+ const hasItemOptions = hasCurrentDocumentItem || items.length > 0;
310
+ const fieldOptions = sourceFieldOptions(selectedContentType, targetField);
248
311
  const emit = (nextType = sourceType, nextId = sourceId, nextPath = fieldPath) => {
249
312
  const usesCurrentDocument = currentDocumentSourceEnabled &&
250
313
  nextType === documentContentType.name &&
@@ -255,7 +318,7 @@ const FieldBindingEditor = ({ contentTypes, documentContentType, currentDocument
255
318
  }
256
319
  onChange(createSource(nextType, nextPath, usesCurrentDocument ? undefined : nextId));
257
320
  };
258
- return ((0, jsx_runtime_1.jsx)(PanelSection, { title: 'Source value', children: (0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-3 md:grid-cols-[1fr_1.4fr_1fr]', children: [(0, jsx_runtime_1.jsxs)(label_1.Label, { className: 'grid gap-1.5', children: ["Source", (0, jsx_runtime_1.jsxs)(select_1.Select, { value: sourceType, onValueChange: (value) => {
321
+ return ((0, jsx_runtime_1.jsx)(PanelSection, { title: 'Source value', children: (0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-3 md:grid-cols-[1fr_1.4fr_1fr]', children: [(0, jsx_runtime_1.jsxs)(label_1.Label, { className: 'grid gap-1.5', children: ["Source", (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: contentTypes.length === 0, value: sourceType, onValueChange: (value) => {
259
322
  const nextId = currentDocumentSourceEnabled &&
260
323
  value === documentContentType.name
261
324
  ? CURRENT_DOCUMENT_ID
@@ -264,24 +327,23 @@ const FieldBindingEditor = ({ contentTypes, documentContentType, currentDocument
264
327
  setSourceId(nextId);
265
328
  setFieldPath('');
266
329
  onChange(undefined);
267
- }, children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: 'Content type' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsx)(select_1.SelectGroup, { children: contentTypes.map((ct) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: ct.name, children: currentDocumentSourceEnabled &&
330
+ }, children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: contentTypes.length > 0 ? 'Content type' : 'No content types' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsx)(select_1.SelectGroup, { children: contentTypes.map((ct) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: ct.name, children: currentDocumentSourceEnabled &&
268
331
  ct.name === documentContentType.name
269
332
  ? `${ct.name} (current document)`
270
- : ct.name }, ct.name))) }) })] })] }), (0, jsx_runtime_1.jsxs)(label_1.Label, { className: 'grid gap-1.5', children: ["Item", (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: !sourceType, value: sourceId, onValueChange: (value) => {
333
+ : ct.name }, ct.name))) }) })] })] }), (0, jsx_runtime_1.jsxs)(label_1.Label, { className: 'grid gap-1.5', children: ["Item", (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: !sourceType || !hasItemOptions, value: sourceId, onValueChange: (value) => {
271
334
  setSourceId(value);
272
335
  emit(sourceType, value, fieldPath);
273
- }, children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: 'Item' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsxs)(select_1.SelectGroup, { children: [currentDocumentSourceEnabled &&
274
- sourceType === documentContentType.name ? ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: CURRENT_DOCUMENT_ID, children: "Current document" })) : null, items.map((item) => {
336
+ }, children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: hasItemOptions ? 'Item' : 'No items available' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsxs)(select_1.SelectGroup, { children: [hasCurrentDocumentItem ? ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: CURRENT_DOCUMENT_ID, children: "Current document" })) : null, items.map((item) => {
275
337
  const label = selectedContentType
276
338
  ? (0, client_1.getListField)(item, selectedContentType.listFields ?? [])
277
339
  : item._id;
278
340
  return ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: item._id, children: (0, client_1.isTranslatableObject)(label)
279
341
  ? label[language.code]
280
342
  : String(label || item._id) }, item._id));
281
- })] }) })] })] }), (0, jsx_runtime_1.jsxs)(label_1.Label, { className: 'grid gap-1.5', children: ["Field", (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: !sourceType || !sourceId, value: fieldPath, onValueChange: (value) => {
343
+ })] }) })] })] }), (0, jsx_runtime_1.jsxs)(label_1.Label, { className: 'grid gap-1.5', children: ["Field", (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: !sourceType || !sourceId || fieldOptions.length === 0, value: fieldPath, onValueChange: (value) => {
282
344
  setFieldPath(value);
283
345
  emit(sourceType, sourceId, value);
284
- }, children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: 'Field' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsx)(select_1.SelectGroup, { children: sourceFieldOptions(selectedContentType, targetField).map((field) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: field.value, children: field.label }, field.value))) }) })] })] })] }) }));
346
+ }, children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: fieldOptions.length > 0 ? 'Field' : 'No compatible fields' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsx)(select_1.SelectGroup, { children: fieldOptions.map((field) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: field.value, children: field.label }, field.value))) }) })] })] })] }) }));
285
347
  };
286
348
  const getListTargetContentType = (field, itemName) => {
287
349
  const entry = field.fields.find((item) => item.name === itemName);
@@ -289,15 +351,140 @@ const getListTargetContentType = (field, itemName) => {
289
351
  return undefined;
290
352
  return entry.field.contentType;
291
353
  };
354
+ const getRelationContentType = (field) => {
355
+ if (field.isTranslatable)
356
+ return undefined;
357
+ if (field.config.type === 'Relation') {
358
+ return field.contentType;
359
+ }
360
+ if (field.config.ui === 'SimpleList') {
361
+ const itemField = field.field;
362
+ if (itemField.config.type === 'Relation') {
363
+ return itemField.contentType;
364
+ }
365
+ }
366
+ return undefined;
367
+ };
368
+ const getRelatedRelationOptions = (contentType, currentSource) => Object.entries(contentType.fields).flatMap(([name, field]) => {
369
+ if (!isDynamicVisibleField(field))
370
+ return [];
371
+ const relationContentType = getRelationContentType(field);
372
+ return relationContentType?.name === currentSource.name ? [name] : [];
373
+ });
374
+ const getRelatedPathOptions = (contentType, targetField) => sourceFieldOptions(contentType, targetField).filter((option) => option.kind === 'array' && option.value !== '$href');
375
+ const getSortFieldOptions = (contentType) => Object.entries(contentType.fields).flatMap(([name, field]) => {
376
+ if (!isDynamicVisibleField(field) ||
377
+ field.isTranslatable ||
378
+ name.startsWith('_') ||
379
+ isSeoPath(name)) {
380
+ return [];
381
+ }
382
+ const kind = getFieldKind(field);
383
+ const isSingleSelect = field.config.type === 'Select' &&
384
+ !field.isMultiple;
385
+ const isSortable = (field.config.type === 'String' && field.config.ui !== 'RichText') ||
386
+ field.config.type === 'Number' ||
387
+ field.config.type === 'Boolean' ||
388
+ field.config.type === 'Date' ||
389
+ isSingleSelect;
390
+ return isSortable ? [{ label: fieldLabel(name), value: name, kind }] : [];
391
+ });
392
+ const createRelatedCollectionSource = ({ contentType, currentSource, targetField, }) => {
393
+ const relation = getRelatedRelationOptions(contentType, currentSource)[0];
394
+ const path = getRelatedPathOptions(contentType, targetField)[0]?.value;
395
+ if (!relation || !path)
396
+ return undefined;
397
+ return {
398
+ kind: 'relatedCollection',
399
+ contentType: contentType.name,
400
+ relation,
401
+ path,
402
+ limit: 10,
403
+ };
404
+ };
405
+ const MappingSourceEditor = ({ contentTypes, currentSource, targetField, source, onChange, }) => {
406
+ const relatedSource = isRelatedCollectionSource(source) ? source : undefined;
407
+ const directSource = source && !isRelatedCollectionSource(source) ? source : undefined;
408
+ const directFieldOptions = sourceFieldOptions(currentSource, targetField);
409
+ const relatedContentTypes = contentTypes.filter((contentType) => getRelatedRelationOptions(contentType, currentSource).length > 0 &&
410
+ getRelatedPathOptions(contentType, targetField).length > 0);
411
+ const selectedRelatedContentType = relatedSource
412
+ ? relatedContentTypes.find((contentType) => contentType.name === relatedSource.contentType)
413
+ : undefined;
414
+ const relationOptions = selectedRelatedContentType
415
+ ? getRelatedRelationOptions(selectedRelatedContentType, currentSource)
416
+ : [];
417
+ const pathOptions = selectedRelatedContentType
418
+ ? getRelatedPathOptions(selectedRelatedContentType, targetField)
419
+ : [];
420
+ const sortOptions = selectedRelatedContentType
421
+ ? getSortFieldOptions(selectedRelatedContentType)
422
+ : [];
423
+ const sortEntry = Object.entries(relatedSource?.sort ?? {})[0];
424
+ const sortField = sortEntry?.[0] ?? '';
425
+ const sortDirection = sortEntry?.[1] ?? 'desc';
426
+ if (!relatedSource) {
427
+ return ((0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-3 md:grid-cols-[0.7fr_1.3fr]', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'grid content-start gap-1.5', children: [(0, jsx_runtime_1.jsx)(ControlLabel, { help: 'Choose a direct field or query a related collection.', children: "Mapping mode" }), (0, jsx_runtime_1.jsxs)(select_1.Select, { value: 'field', onValueChange: (value) => {
428
+ if (value !== 'relatedCollection')
429
+ return;
430
+ const next = relatedContentTypes
431
+ .map((contentType) => createRelatedCollectionSource({
432
+ contentType,
433
+ currentSource,
434
+ targetField,
435
+ }))
436
+ .find(Boolean);
437
+ onChange(next);
438
+ }, children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, {}) }), (0, jsx_runtime_1.jsxs)(select_1.SelectContent, { children: [(0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: 'field', children: "Direct field" }), relatedContentTypes.length > 0 ? ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: 'relatedCollection', children: "Related collection" })) : null] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: 'grid content-start gap-1.5', children: [(0, jsx_runtime_1.jsxs)(ControlLabel, { help: 'Its value will be assigned to this mapped property.', children: ["Field on ", currentSource.name] }), (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: directFieldOptions.length === 0, value: sourceValue(directSource), onValueChange: (value) => onChange(createSource(currentSource.name, value)), children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: directFieldOptions.length > 0
439
+ ? 'Select a source field'
440
+ : 'No compatible fields' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsx)(select_1.SelectGroup, { children: directFieldOptions.map((item) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: item.value, children: item.label }, item.value))) }) })] })] })] }));
441
+ }
442
+ return ((0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-3', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-3 sm:grid-cols-2 lg:grid-cols-4', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'grid content-start gap-1.5', children: [(0, jsx_runtime_1.jsx)(ControlLabel, { help: 'Query records related to the current source item.', children: "Mapping mode" }), (0, jsx_runtime_1.jsxs)(select_1.Select, { value: 'relatedCollection', onValueChange: () => onChange(undefined), children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, {}) }), (0, jsx_runtime_1.jsxs)(select_1.SelectContent, { children: [(0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: 'field', children: "Direct field" }), (0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: 'relatedCollection', children: "Related collection" })] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: 'grid content-start gap-1.5', children: [(0, jsx_runtime_1.jsx)(ControlLabel, { help: 'Content type whose records will be searched.', children: "Collection to query" }), (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: relatedContentTypes.length === 0, value: relatedSource.contentType, onValueChange: (value) => {
443
+ const contentType = relatedContentTypes.find((item) => item.name === value);
444
+ if (!contentType)
445
+ return;
446
+ onChange(createRelatedCollectionSource({
447
+ contentType,
448
+ currentSource,
449
+ targetField,
450
+ }));
451
+ }, children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: relatedContentTypes.length > 0
452
+ ? 'Select a content type'
453
+ : 'No compatible collections' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: relatedContentTypes.map((contentType) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: contentType.name, children: contentType.name }, contentType.name))) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: 'grid content-start gap-1.5', children: [(0, jsx_runtime_1.jsxs)(ControlLabel, { help: `Field on ${relatedSource.contentType} that points to ${currentSource.name}.`, children: ["Relation to ", currentSource.name] }), (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: relationOptions.length === 0, value: relatedSource.relation, onValueChange: (relation) => onChange({ ...relatedSource, relation }), children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: relationOptions.length > 0
454
+ ? 'Select a relation field'
455
+ : 'No compatible relations' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: relationOptions.map((relation) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: relation, children: relation }, relation))) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: 'grid content-start gap-1.5', children: [(0, jsx_runtime_1.jsx)(ControlLabel, { help: 'Arrays from matching records are flattened into one result.', children: "Array field to collect" }), (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: pathOptions.length === 0, value: relatedSource.path, onValueChange: (path) => onChange({ ...relatedSource, path }), children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: pathOptions.length > 0
456
+ ? 'Select an array field'
457
+ : 'No compatible array fields' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: pathOptions.map((option) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: option.value, children: option.label }, option.value))) })] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-3 sm:grid-cols-[0.7fr_1fr_0.7fr]', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'grid content-start gap-1.5', children: [(0, jsx_runtime_1.jsx)(ControlLabel, { help: `Number of ${relatedSource.contentType} records queried per ${currentSource.name}. Minimum 1, maximum 100.`, children: "Maximum related records" }), (0, jsx_runtime_1.jsx)(input_1.Input, { type: 'number', min: 1, max: 100, value: String(relatedSource.limit), onChange: (event) => onChange({
458
+ ...relatedSource,
459
+ limit: Math.min(100, Math.max(1, Number(event.target.value || 10))),
460
+ }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: 'grid content-start gap-1.5', children: [(0, jsx_runtime_1.jsx)(ControlLabel, { help: 'Optional. Only direct scalar fields can be used.', children: "Sort related records by" }), (0, jsx_runtime_1.jsxs)(select_1.Select, { value: sortField || '__none__', onValueChange: (value) => onChange({
461
+ ...relatedSource,
462
+ sort: value === '__none__'
463
+ ? undefined
464
+ : { [value]: sortDirection },
465
+ }), children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: 'No sort' }) }), (0, jsx_runtime_1.jsxs)(select_1.SelectContent, { children: [(0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: '__none__', children: "No sort" }), sortOptions.map((option) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: option.value, children: option.label }, option.value)))] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: 'grid content-start gap-1.5', children: [(0, jsx_runtime_1.jsx)(ControlLabel, { help: 'Applied before collecting and flattening the arrays.', children: "Sort direction" }), (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: !sortField, value: sortDirection, onValueChange: (direction) => sortField
466
+ ? onChange({
467
+ ...relatedSource,
468
+ sort: { [sortField]: direction },
469
+ })
470
+ : undefined, children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, {}) }), (0, jsx_runtime_1.jsxs)(select_1.SelectContent, { children: [(0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: 'asc', children: "Ascending" }), (0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: 'desc', children: "Descending" })] })] })] })] })] }));
471
+ };
292
472
  const ListBindingEditor = ({ contentTypes, field, binding, onChange, }) => {
293
473
  const [sourceType, setSourceType] = (0, react_1.useState)(binding?.contentType || '');
294
474
  const [itemName, setItemName] = (0, react_1.useState)(binding?.itemName || field.fields[0]?.name || '');
295
475
  const [filterState, setFilterState] = (0, react_1.useState)(readFilterState(binding?.query?.filter));
476
+ const [openMappingField, setOpenMappingField] = (0, react_1.useState)(null);
296
477
  const selectedSource = contentTypes.find((ct) => ct.name === sourceType);
297
478
  const targetContentType = getListTargetContentType(field, itemName);
298
479
  const targetFields = (0, react_1.useMemo)(() => targetContentType
299
480
  ? Object.entries(targetContentType.fields).filter(([, targetField]) => isDynamicVisibleField(targetField))
300
481
  : [], [targetContentType]);
482
+ const sortFieldOptions = selectedSource
483
+ ? getSortFieldOptions(selectedSource)
484
+ : [];
485
+ const filterFieldOptions = selectedSource
486
+ ? sourceFieldOptions(selectedSource).filter((item) => item.value !== '$href')
487
+ : [];
301
488
  const emit = (patch) => {
302
489
  const next = {
303
490
  contentType: sourceType,
@@ -321,13 +508,13 @@ const ListBindingEditor = ({ contentTypes, field, binding, onChange, }) => {
321
508
  },
322
509
  });
323
510
  };
324
- return ((0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-3', children: [(0, jsx_runtime_1.jsx)(PanelSection, { title: 'Collection', children: (0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-3 md:grid-cols-2', children: [(0, jsx_runtime_1.jsxs)(label_1.Label, { className: 'grid gap-1.5', children: ["Source", (0, jsx_runtime_1.jsxs)(select_1.Select, { value: sourceType, onValueChange: (value) => {
511
+ return ((0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-3', children: [(0, jsx_runtime_1.jsx)(PanelSection, { title: 'Collection', children: (0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-3 md:grid-cols-2', children: [(0, jsx_runtime_1.jsxs)(label_1.Label, { className: 'grid gap-1.5', children: ["Source", (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: contentTypes.length === 0, value: sourceType, onValueChange: (value) => {
325
512
  setSourceType(value);
326
513
  emit({ contentType: value, map: {} });
327
- }, children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: 'Content type' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsx)(select_1.SelectGroup, { children: contentTypes.map((ct) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: ct.name, children: ct.name }, ct.name))) }) })] })] }), (0, jsx_runtime_1.jsxs)(label_1.Label, { className: 'grid gap-1.5', children: ["Item", (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: !sourceType, value: itemName, onValueChange: (value) => {
514
+ }, children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: contentTypes.length > 0 ? 'Content type' : 'No content types' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsx)(select_1.SelectGroup, { children: contentTypes.map((ct) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: ct.name, children: ct.name }, ct.name))) }) })] })] }), (0, jsx_runtime_1.jsxs)(label_1.Label, { className: 'grid gap-1.5', children: ["Item", (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: !sourceType || field.fields.length === 0, value: itemName, onValueChange: (value) => {
328
515
  setItemName(value);
329
516
  emit({ itemName: value, map: {} });
330
- }, children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: 'Item type' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsx)(select_1.SelectGroup, { children: field.fields.map((item) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: item.name, children: item.name }, item.name))) }) })] })] })] }) }), (0, jsx_runtime_1.jsx)(PanelSection, { title: 'Query', children: (0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-3 md:grid-cols-[0.7fr_1fr_1.1fr]', children: [(0, jsx_runtime_1.jsxs)(label_1.Label, { className: 'grid gap-1.5', children: ["Limit", (0, jsx_runtime_1.jsx)(input_1.Input, { type: 'number', min: 1, value: String(binding?.query?.options?.limit ?? 10), onChange: (event) => emit({
517
+ }, children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: field.fields.length > 0 ? 'Item type' : 'No item types' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsx)(select_1.SelectGroup, { children: field.fields.map((item) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: item.name, children: item.name }, item.name))) }) })] })] })] }) }), (0, jsx_runtime_1.jsx)(PanelSection, { title: 'Query', children: (0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-3 md:grid-cols-[0.7fr_1fr_1.1fr]', children: [(0, jsx_runtime_1.jsxs)(label_1.Label, { className: 'grid gap-1.5', children: ["Limit", (0, jsx_runtime_1.jsx)(input_1.Input, { type: 'number', min: 1, value: String(binding?.query?.options?.limit ?? 10), onChange: (event) => emit({
331
518
  query: {
332
519
  ...binding?.query,
333
520
  options: {
@@ -335,7 +522,7 @@ const ListBindingEditor = ({ contentTypes, field, binding, onChange, }) => {
335
522
  limit: Number(event.target.value || 10),
336
523
  },
337
524
  },
338
- }) })] }), (0, jsx_runtime_1.jsxs)(label_1.Label, { className: 'grid gap-1.5', children: ["Sort", (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: !selectedSource, value: Object.keys(binding?.query?.options?.sort ?? {})[0] ?? '', onValueChange: (value) => emit({
525
+ }) })] }), (0, jsx_runtime_1.jsxs)(label_1.Label, { className: 'grid gap-1.5', children: ["Sort", (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: sortFieldOptions.length === 0, value: Object.keys(binding?.query?.options?.sort ?? {})[0] ?? '', onValueChange: (value) => emit({
339
526
  query: {
340
527
  ...binding?.query,
341
528
  options: {
@@ -343,17 +530,17 @@ const ListBindingEditor = ({ contentTypes, field, binding, onChange, }) => {
343
530
  sort: value ? { [value]: 'desc' } : undefined,
344
531
  },
345
532
  },
346
- }), children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: 'Field' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsx)(select_1.SelectGroup, { children: sourceFieldOptions(selectedSource)
347
- .filter((item) => item.value !== '$href')
348
- .map((item) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: item.value, children: item.label }, item.value))) }) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-1.5', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'flex items-center justify-between gap-2', children: [(0, jsx_runtime_1.jsx)("span", { className: 'text-sm font-medium', children: "Filter" }), (0, jsx_runtime_1.jsxs)(button_1.Button, { type: 'button', size: 'icon', variant: 'ghost', className: 'size-7', onClick: () => updateFilter(undefined), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: 'h-4 w-4' }), (0, jsx_runtime_1.jsx)("span", { className: 'sr-only', children: "Clear filter" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-2 sm:grid-cols-[1fr_0.9fr_1fr]', children: [(0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: !selectedSource, value: filterState?.field || '', onValueChange: (value) => updateFilter(value
533
+ }), children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: sortFieldOptions.length > 0
534
+ ? 'Field'
535
+ : 'No sortable fields' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsx)(select_1.SelectGroup, { children: sortFieldOptions.map((item) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: item.value, children: item.label }, item.value))) }) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-1.5', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'flex items-center justify-between gap-2', children: [(0, jsx_runtime_1.jsx)("span", { className: 'text-sm font-medium', children: "Filter" }), (0, jsx_runtime_1.jsxs)(button_1.Button, { type: 'button', size: 'icon', variant: 'ghost', className: 'size-7', onClick: () => updateFilter(undefined), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: 'h-4 w-4' }), (0, jsx_runtime_1.jsx)("span", { className: 'sr-only', children: "Clear filter" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: 'grid gap-2 sm:grid-cols-[1fr_0.9fr_1fr]', children: [(0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: filterFieldOptions.length === 0, value: filterState?.field || '', onValueChange: (value) => updateFilter(value
349
536
  ? {
350
537
  field: value,
351
538
  operator: filterState?.operator ?? 'equals',
352
539
  value: filterState?.value ?? '',
353
540
  }
354
- : undefined), children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: 'Field' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsx)(select_1.SelectGroup, { children: sourceFieldOptions(selectedSource)
355
- .filter((item) => item.value !== '$href')
356
- .map((item) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: item.value, children: item.label }, item.value))) }) })] }), (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: !filterState?.field, value: filterState?.operator || 'equals', onValueChange: (value) => filterState
541
+ : undefined), children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: filterFieldOptions.length > 0
542
+ ? 'Field'
543
+ : 'No filterable fields' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsx)(select_1.SelectGroup, { children: filterFieldOptions.map((item) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: item.value, children: item.label }, item.value))) }) })] }), (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: !filterState?.field, value: filterState?.operator || 'equals', onValueChange: (value) => filterState
357
544
  ? updateFilter({
358
545
  ...filterState,
359
546
  operator: value,
@@ -369,12 +556,18 @@ const ListBindingEditor = ({ contentTypes, field, binding, onChange, }) => {
369
556
  })
370
557
  : undefined }))] })] })] }) }), (0, jsx_runtime_1.jsx)(PanelSection, { title: 'Mapping', children: (0, jsx_runtime_1.jsx)("div", { className: 'grid gap-2', children: targetFields.map(([targetField, targetFieldConfig]) => {
371
558
  const source = binding?.map?.[targetField];
372
- return ((0, jsx_runtime_1.jsxs)("div", { className: 'grid items-center gap-2 rounded-md border border-border bg-background/70 px-3 py-2 md:grid-cols-[minmax(8rem,0.7fr)_auto_minmax(12rem,1.3fr)]', children: [(0, jsx_runtime_1.jsx)("span", { className: 'truncate text-sm font-medium', children: targetField }), (0, jsx_runtime_1.jsx)("span", { className: 'hidden text-xs text-muted-foreground md:block', children: '->' }), (0, jsx_runtime_1.jsxs)(select_1.Select, { disabled: !selectedSource, value: sourceValue(source), onValueChange: (value) => emit({
373
- map: {
374
- ...binding?.map,
375
- [targetField]: createSource(sourceType, value),
376
- },
377
- }), children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: 'w-full', children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: 'Source field' }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: (0, jsx_runtime_1.jsx)(select_1.SelectGroup, { children: sourceFieldOptions(selectedSource, targetFieldConfig).map((item) => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { value: item.value, children: item.label }, item.value))) }) })] })] }, targetField));
559
+ const summary = mappingSourceSummary(source, selectedSource?.name ?? 'Source');
560
+ const isOpen = openMappingField === targetField;
561
+ return ((0, jsx_runtime_1.jsx)(collapsible_1.Collapsible, { open: isOpen, onOpenChange: (open) => setOpenMappingField(open ? targetField : null), children: (0, jsx_runtime_1.jsxs)("div", { className: 'overflow-hidden rounded-md border border-border bg-background/70 transition-colors hover:border-foreground/20', children: [(0, jsx_runtime_1.jsx)(collapsible_1.CollapsibleTrigger, { asChild: true, children: (0, jsx_runtime_1.jsxs)("button", { type: 'button', disabled: !selectedSource, className: 'group grid w-full grid-cols-[minmax(6rem,0.45fr)_auto_minmax(0,1fr)_auto] items-center gap-3 px-3 py-2.5 text-left outline-none transition-colors hover:bg-muted/50 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50', children: [(0, jsx_runtime_1.jsx)("span", { className: 'truncate text-sm font-semibold', children: targetField }), (0, jsx_runtime_1.jsx)(badge_1.Badge, { variant: source ? 'secondary' : 'outline', className: 'max-w-40 truncate', children: summary.mode }), (0, jsx_runtime_1.jsx)("span", { className: 'truncate text-sm text-muted-foreground', children: selectedSource
562
+ ? summary.detail
563
+ : 'Select a source collection first' }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: 'h-4 w-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-90' }), (0, jsx_runtime_1.jsxs)("span", { className: 'sr-only', children: ["Configure ", targetField, " mapping"] })] }) }), (0, jsx_runtime_1.jsx)(collapsible_1.CollapsibleContent, { children: (0, jsx_runtime_1.jsx)("div", { className: 'border-t border-border bg-muted/20 p-3', children: selectedSource ? ((0, jsx_runtime_1.jsx)(MappingSourceEditor, { contentTypes: contentTypes, currentSource: selectedSource, targetField: targetFieldConfig, source: source, onChange: (nextSource) => {
564
+ const map = { ...(binding?.map ?? {}) };
565
+ if (nextSource)
566
+ map[targetField] = nextSource;
567
+ else
568
+ delete map[targetField];
569
+ emit({ map });
570
+ } })) : null }) })] }) }, targetField));
378
571
  }) }) })] }));
379
572
  };
380
573
  const DynamicDataControl = ({ contentType, documentContentType, fieldName, field, contentTypes, bindings, onChange, open, onOpenChange, mode = 'full', }) => {