@rebasepro/admin 0.11.1-canary.gfd39654 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/README.md +1 -1
  2. package/dist/{CollectionEditorDialog-o7F_zbGY.js → CollectionEditorDialog-Dpc75wIZ.js} +56 -260
  3. package/dist/CollectionEditorDialog-Dpc75wIZ.js.map +1 -0
  4. package/dist/{PropertyEditView-DgB2b22q.js → PropertyEditView-DH3XZC2x.js} +2 -2
  5. package/dist/{PropertyEditView-DgB2b22q.js.map → PropertyEditView-DH3XZC2x.js.map} +1 -1
  6. package/dist/{RouterCollectionsStudioView-DaLRgPkj.js → RouterCollectionsStudioView-BZLq4MGp.js} +4 -4
  7. package/dist/{RouterCollectionsStudioView-DaLRgPkj.js.map → RouterCollectionsStudioView-BZLq4MGp.js.map} +1 -1
  8. package/dist/collection_editor/CollectionEditorDialogsContext.d.ts +1 -1
  9. package/dist/collection_editor/_cms_internals.d.ts +1 -1
  10. package/dist/collection_editor/extensibility_types.d.ts +1 -1
  11. package/dist/collection_editor/serializable_types.d.ts +40 -12
  12. package/dist/collection_editor/serializable_utils.d.ts +1 -1
  13. package/dist/collection_editor/ui/collection_editor/CollectionRLSTab.d.ts +1 -11
  14. package/dist/collection_editor_ui.js +4 -4
  15. package/dist/components/CollectionEditorDialogs.d.ts +2 -2
  16. package/dist/components/CollectionTableBinding/column_utils.d.ts +7 -1
  17. package/dist/components/CollectionViewBinding/CollectionListViewBinding.d.ts +2 -2
  18. package/dist/components/DefaultDrawer.d.ts +3 -3
  19. package/dist/components/DrawerNavigationGroup.d.ts +8 -1
  20. package/dist/components/DrawerNavigationItem.d.ts +7 -1
  21. package/dist/components/EditViewBinding.d.ts +1 -1
  22. package/dist/components/RebaseAdmin.d.ts +1 -1
  23. package/dist/components/RebaseAuthGate.d.ts +1 -1
  24. package/dist/components/RebaseLayout.d.ts +5 -1
  25. package/dist/components/RebaseNavigation.d.ts +2 -2
  26. package/dist/components/RebaseRouteDefs.d.ts +1 -1
  27. package/dist/components/RebaseShell.d.ts +6 -1
  28. package/dist/components/RelationSelector.d.ts +14 -0
  29. package/dist/components/SelectableTable/filters/RelationFilterField.d.ts +27 -0
  30. package/dist/components/SelectableTable/filters/null_filter.d.ts +46 -0
  31. package/dist/components/SidePanelProvider.d.ts +2 -2
  32. package/dist/components/app/Scaffold.d.ts +11 -0
  33. package/dist/components/field_configs.d.ts +1 -1
  34. package/dist/{export-BvqhjdEb.js → export-BzIpUdSK.js} +3 -3
  35. package/dist/export-BzIpUdSK.js.map +1 -0
  36. package/dist/form/EntityForm.d.ts +2 -2
  37. package/dist/form/EntityFormBinding.d.ts +5 -5
  38. package/dist/{history-Dz20hH38.js → history-g9688IaK.js} +2 -2
  39. package/dist/{history-Dz20hH38.js.map → history-g9688IaK.js.map} +1 -1
  40. package/dist/hooks/index.d.ts +1 -1
  41. package/dist/hooks/useAdminContext.d.ts +29 -0
  42. package/dist/hooks/useHistory.d.ts +7 -11
  43. package/dist/{import-DINSB-Vu.js → import-BjUG-cIY.js} +2 -2
  44. package/dist/{import-DINSB-Vu.js.map → import-BjUG-cIY.js.map} +1 -1
  45. package/dist/index.js +61 -38
  46. package/dist/index.js.map +1 -1
  47. package/dist/types/components/EntityFormProps.d.ts +1 -1
  48. package/dist/types/fields.d.ts +1 -1
  49. package/dist/{util-BhhfHY1M.js → util-B5fJm1FA.js} +296 -169
  50. package/dist/util-B5fJm1FA.js.map +1 -0
  51. package/package.json +9 -9
  52. package/src/collection_editor/CollectionEditorDialogsContext.tsx +1 -1
  53. package/src/collection_editor/ConfigControllerProvider.tsx +1 -1
  54. package/src/collection_editor/_cms_internals.ts +1 -1
  55. package/src/collection_editor/extensibility_types.ts +1 -1
  56. package/src/collection_editor/index.ts +2 -2
  57. package/src/collection_editor/serializable_types.ts +44 -13
  58. package/src/collection_editor/serializable_utils.ts +68 -59
  59. package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +1 -1
  60. package/src/collection_editor/ui/collection_editor/CollectionRLSTab.tsx +66 -41
  61. package/src/collection_editor/ui/collection_editor/EntityActionsEditTab.tsx +1 -1
  62. package/src/collection_editor/ui/collection_editor/GetCodeDialog.tsx +1 -1
  63. package/src/collection_editor/ui/collection_editor/SubcollectionsEditTab.tsx +2 -2
  64. package/src/components/CollectionEditorDialogs.tsx +2 -2
  65. package/src/components/CollectionTableBinding/CollectionRowActions.tsx +5 -4
  66. package/src/components/CollectionTableBinding/CollectionTableBinding.tsx +8 -2
  67. package/src/components/CollectionTableBinding/column_utils.tsx +19 -5
  68. package/src/components/CollectionTableBinding/table_bindings.tsx +10 -10
  69. package/src/components/CollectionViewBinding/CollectionListViewBinding.tsx +8 -7
  70. package/src/components/CollectionViewBinding/CollectionViewActions.tsx +2 -2
  71. package/src/components/CollectionViewBinding/CollectionViewBinding.tsx +2 -2
  72. package/src/components/CollectionViewBinding/CollectionViewStartActions.tsx +2 -2
  73. package/src/components/DefaultDrawer.tsx +19 -8
  74. package/src/components/DeleteEntityDialog.tsx +2 -2
  75. package/src/components/DetailViewBinding.tsx +21 -1
  76. package/src/components/DrawerNavigationGroup.tsx +47 -4
  77. package/src/components/DrawerNavigationItem.tsx +19 -5
  78. package/src/components/EditFormActions.tsx +4 -3
  79. package/src/components/EditViewBinding.tsx +1 -1
  80. package/src/components/HomePage/ContentHomePage.tsx +4 -4
  81. package/src/components/RebaseAdmin.tsx +3 -3
  82. package/src/components/RebaseAuthGate.tsx +1 -1
  83. package/src/components/RebaseLayout.tsx +8 -2
  84. package/src/components/RebaseNavigation.tsx +9 -9
  85. package/src/components/RebaseRouteDefs.tsx +2 -2
  86. package/src/components/RebaseShell.tsx +10 -1
  87. package/src/components/RelationSelector.tsx +18 -3
  88. package/src/components/SelectableTable/filters/FilterFieldBinding.tsx +1 -1
  89. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +36 -9
  90. package/src/components/SelectableTable/filters/RelationFilterField.tsx +93 -17
  91. package/src/components/SelectableTable/filters/null_filter.ts +63 -0
  92. package/src/components/SidePanelProvider.tsx +2 -2
  93. package/src/components/app/Scaffold.tsx +16 -1
  94. package/src/data_export/export/ExportCollectionAction.tsx +2 -2
  95. package/src/form/EntityForm.tsx +2 -2
  96. package/src/form/EntityFormActions.tsx +2 -1
  97. package/src/form/EntityFormBinding.tsx +7 -7
  98. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +3 -3
  99. package/src/form/field_bindings/MultipleRelationFieldBinding.tsx +16 -5
  100. package/src/form/field_bindings/ReferenceFieldBinding.tsx +3 -3
  101. package/src/form/field_bindings/RelationFieldBinding.tsx +17 -6
  102. package/src/form/field_bindings/RepeatFieldBinding.tsx +2 -2
  103. package/src/hooks/index.ts +1 -1
  104. package/src/hooks/navigation/useNavigationResolution.ts +10 -4
  105. package/src/hooks/{useCMSContext.tsx → useAdminContext.tsx} +10 -10
  106. package/src/hooks/useHistory.ts +7 -11
  107. package/src/hooks/useResolvedNavigationFrom.tsx +2 -2
  108. package/src/index.ts +4 -4
  109. package/src/preview/PropertyPreview.tsx +6 -6
  110. package/src/preview/components/RelationPreview.tsx +1 -1
  111. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
  112. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +2 -2
  113. package/src/preview/property_previews/ArrayOfRelationsPreview.tsx +2 -2
  114. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +2 -2
  115. package/src/types/components/EntityFormProps.tsx +2 -2
  116. package/src/types/fields.tsx +1 -1
  117. package/dist/CollectionEditorDialog-o7F_zbGY.js.map +0 -1
  118. package/dist/collection_editor/pgColumnToProperty.d.ts +0 -7
  119. package/dist/editor/extensions/Image/index.d.ts +0 -6
  120. package/dist/export-BvqhjdEb.js.map +0 -1
  121. package/dist/hooks/useCMSContext.d.ts +0 -29
  122. package/dist/util-BhhfHY1M.js.map +0 -1
  123. package/src/collection_editor/pgColumnToProperty.ts +0 -291
  124. package/src/editor/extensions/Image/index.ts +0 -133
@@ -1,9 +1,9 @@
1
1
  import * as React$1 from "react";
2
- import React, { Suspense, createContext, createElement, forwardRef, lazy, memo, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
2
+ import React, { Suspense, createContext, createElement, forwardRef, lazy, memo, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
3
3
  import { deepEqual } from "fast-equals";
4
4
  import { Alert, AlertCircleIcon, AlertTriangleIcon, AlignLeftIcon, ArrowLeftIcon, ArrowRightToLineIcon, Badge, BooleanSwitchWithLabel, Button, CHIP_COLORS, CalendarIcon, Card, CardView, CenteredView, CheckCircleIcon, CheckIcon, Checkbox, ChevronDownIcon, ChevronRightIcon, ChevronUpIcon, ChevronsUpDownIcon, Chip, CircleIcon, CircularProgress, CircularProgressCenter, CodeIcon, Collapse, ColumnsIcon, CopyIcon, DateTimeField, Dialog, DialogActions, DialogContent, DialogTitle, ErrorBoundary, ExpandablePanel, ExternalLinkIcon, EyeIcon, EyeOffIcon, FileTextIcon, FileUpload, FilterChip, FilterIcon, FilterXIcon, FlagIcon, FolderUpIcon, FunctionSquareIcon, GlobeIcon, HandleIcon, HashIcon, HistoryIcon, IconButton, ImageOffIcon, KanbanIcon, KanbanView, KeyRoundIcon, Label, LayoutGridIcon, Link2Icon, LinkIcon, ListIcon, ListOrderedIcon, ListView, LoaderIcon, LoadingButton, MailIcon, Markdown, Maximize2Icon, Menu, MenuItem, MinusIcon, MoreVerticalIcon, MultiSelect, MultiSelectItem, PencilIcon, PlusIcon, Popover, PopoverPrimitive, Portal, QuoteIcon, RadioGroup, RadioGroupItem, RefreshCwIcon, RepeatIcon, ResizablePanels, Rows3Icon, SearchBar, SearchIcon, Select, SelectItem, Separator, SettingsIcon, Sheet, Skeleton, Tab, Table, TableBody, TableCell, TableHeader, TableIcon, TableRow, TableView, Tabs, TextField, TextIcon, TextareaAutosize, ToggleButtonGroup, Tooltip, Trash2Icon, Typography, Unlink2Icon, UploadIcon, UserIcon, VirtualTableDateField, VirtualTableInput, VirtualTableInput as VirtualTableInput$1, VirtualTableNumberInput, VirtualTableSwitch, VoteIcon, XCircleIcon, XIcon, cls, coolIconKeys, createVirtualTableSelectionStore, debounce, defaultBorderMixin, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, fieldBackgroundInvisibleMixin, fieldBackgroundMixin, focusedDisabled, getColorSchemeForSeed, iconSize, lucideIcons, paperMixin, useDebouncedCallback, useInjectStyles, useOutsideAlerter } from "@rebasepro/ui";
5
5
  import { CollectionRegistry, DEFAULT_ONE_OF_TYPE, DEFAULT_ONE_OF_VALUE, canReadCollection, enumToObjectEntries, getArrayResolvedProperties, getDefaultValueFor, getDefaultValueFortype, getDefaultValuesFor, getEntityChildViews, getLabelOrConfigFrom, getReferenceFrom, getRelationFrom, getSubcollections, getTableName, isPropertyBuilder, normalizeToEntityRelation, resolveArrayProperties, resolveEnumValues, resolveProperty, resolveRelationProperty, resolveStorageFilenameString, resolveStoragePathString, resolveStorageSource } from "@rebasepro/common";
6
- import { ADDITIONAL_TAB_WIDTH, CONTAINER_FULL_WIDTH, CollectionScopeProvider, DEFAULT_PAGE_SIZE, ErrorTooltip, ErrorView, FORM_CONTAINER_WIDTH, IconForView, PluginProviderStack, StorageSourceContext, UnsavedChangesDialog, UserDisplay, addInitialSlash, buildEnumLabel, createFormexStub, deleteEntityWithCallbacks, flattenKeys, getAdminEntityChildViews, getCollectionBySlugWithin, getCollectionPathsCombinations, getColorScheme, getColumnKeysForProperty, getEntityFromCache, getEntityFromMemoryCache, getEntityImagePreviewPropertyKey, getFormFieldKeys, getIcon, getLastSegment as getLastSegment$1, getLocalChangesBackup, getNavigationEntriesFromPath, getParentReferencesFromPath, getRelationIncludeParams, getRowHeight, getTitlePropertyCandidates, getTitlePropertyKey, getTitlePropertyKeyForValues, iconsSearch, isHidden, isReadOnly, looksLikeIdentifierValue, removeEntityFromCache, removeEntityFromMemoryCache, removeInitialAndTrailingSlashes, removeInitialAndTrailingSlashes as removeInitialAndTrailingSlashes$1, removeInitialSlash, removeTrailingSlash, removeTrailingSlash as removeTrailingSlash$1, resolveCollectionPathIds, resolveCollectionPathIds as resolveCollectionPathIds$1, resolveComponentRef, resolveDefaultSelectedView, resolveFilterOperators, saveEntityToCache, saveEntityToMemoryCache, saveEntityWithCallbacks, useAnalyticsController, useApiConfig, useAuthController, useCollectionScope, useColumnIds, useComponentOverride, useCustomizationController, useData, useDataTableController, useFetch, useLargeLayout, useModeController, useNavigationBlocker, usePermissions, useRebaseClient, useRebaseContext, useRelationSelector, useResolvedComponent, useScrollRestoration, useSlot, useSnackbarController, useStorageSource, useStorageSources, useStorageUploadController, useTranslation, useUnsavedChangesDialog, useUserConfigurationPersistence } from "@rebasepro/app";
6
+ import { ADDITIONAL_TAB_WIDTH, CONTAINER_FULL_WIDTH, CollectionScopeProvider, DEFAULT_PAGE_SIZE, ErrorTooltip, ErrorView, FORM_CONTAINER_WIDTH, IconForView, PluginProviderStack, StorageSourceContext, UnsavedChangesDialog, UserDisplay, addInitialSlash, buildEnumLabel, createFormexStub, deleteEntityWithCallbacks, flattenKeys, getAdminEntityChildViews, getCollectionBySlugWithin, getCollectionPathsCombinations, getColorScheme, getColumnKeysForProperty, getEntityFromCache, getEntityFromMemoryCache, getEntityImagePreviewPropertyKey, getFormFieldKeys, getIcon, getLastSegment as getLastSegment$1, getLocalChangesBackup, getNavigationEntriesFromPath, getParentReferencesFromPath, getRelationIncludeParams, getRowHeight, getTitlePropertyCandidates, getTitlePropertyKey, getTitlePropertyKeyForValues, iconsSearch, isFilterableRelation, isHidden, isReadOnly, looksLikeIdentifierValue, removeEntityFromCache, removeEntityFromMemoryCache, removeInitialAndTrailingSlashes, removeInitialAndTrailingSlashes as removeInitialAndTrailingSlashes$1, removeInitialSlash, removeTrailingSlash, removeTrailingSlash as removeTrailingSlash$1, resolveCollectionPathIds, resolveCollectionPathIds as resolveCollectionPathIds$1, resolveComponentRef, resolveDefaultSelectedView, resolveFilterOperators, saveEntityToCache, saveEntityToMemoryCache, saveEntityWithCallbacks, useAnalyticsController, useApiConfig, useAuthController, useCollectionScope, useColumnIds, useComponentOverride, useCustomizationController, useData, useDataTableController, useFetch, useLargeLayout, useModeController, useNavigationBlocker, usePermissions, useRebaseClient, useRebaseContext, useRelationSelector, useResolvedComponent, useScrollRestoration, useSlot, useSnackbarController, useStorageSource, useStorageSources, useStorageUploadController, useTranslation, useUnsavedChangesDialog, useUserConfigurationPersistence } from "@rebasepro/app";
7
7
  import { Field, Formex, getIn, setIn, useCreateFormex, useFormex } from "@rebasepro/forms";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { defaultDateFormat, getHashValue, getValueInPath, hydrateRegExp, isObject, mergeDeep, randomString, toArray } from "@rebasepro/utils";
@@ -11,7 +11,7 @@ import { format } from "date-fns";
11
11
  import * as locales from "date-fns/locale";
12
12
  import { Command } from "cmdk";
13
13
  import { useDropzone } from "react-dropzone";
14
- import { EntityReference, EntityRelation, GeoPoint, Vector, getCollectionDataPath, getDataSourceCapabilities } from "@rebasepro/types";
14
+ import { EntityReference, EntityRelation, GeoPoint, Vector, getCollectionDataPath, getDataSourceCapabilities, isRelationalCollectionConfig } from "@rebasepro/types";
15
15
  import { z } from "zod";
16
16
  import useMeasure from "react-use-measure";
17
17
  import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
@@ -335,7 +335,7 @@ function SkeletonPropertyComponent({ property, size }) {
335
335
  } else if (property.type === "array") {
336
336
  const arrayProperty = property;
337
337
  if (arrayProperty.of) if (Array.isArray(arrayProperty.of)) content = /* @__PURE__ */ jsxs(Fragment, { children: [arrayProperty.of.map((p, i) => renderGenericArrayCell(p, i)), " "] });
338
- else if (arrayProperty.of.type === "map" && arrayProperty.of.properties) content = renderArrayOfMaps(arrayProperty.of.properties, size, arrayProperty.of.previewProperties);
338
+ else if (arrayProperty.of.type === "map" && arrayProperty.of.properties) content = renderArrayOfMaps(arrayProperty.of.properties, size, arrayProperty.of.admin?.previewProperties);
339
339
  else if (arrayProperty.of.type === "string") if (arrayProperty.of.enum) content = renderArrayEnumTableCell();
340
340
  else if (arrayProperty.of.storage) content = renderGenericArrayCell(arrayProperty.of);
341
341
  else content = renderArrayOfStrings();
@@ -352,7 +352,7 @@ function renderMap(property, size) {
352
352
  let mapPropertyKeys;
353
353
  if (size === "large") mapPropertyKeys = Object.keys(property.properties);
354
354
  else {
355
- mapPropertyKeys = property.previewProperties || Object.keys(property.properties);
355
+ mapPropertyKeys = property.admin?.previewProperties || Object.keys(property.properties);
356
356
  if (size === "medium") mapPropertyKeys = mapPropertyKeys.slice(0, 3);
357
357
  else if (size === "small") mapPropertyKeys = mapPropertyKeys.slice(0, 1);
358
358
  }
@@ -1195,8 +1195,8 @@ function ArrayOfReferencesPreview({ propertyKey, value, property, size }) {
1195
1195
  previewProperties: ofProperty.admin?.previewProperties,
1196
1196
  size: childSize,
1197
1197
  reference,
1198
- includeId: ofProperty.includeId,
1199
- includeEntityLink: ofProperty.includeEntityLink
1198
+ includeId: ofProperty.admin?.includeId,
1199
+ includeEntityLink: ofProperty.admin?.includeEntityLink
1200
1200
  })
1201
1201
  }, `preview_array_ref_${propertyKey}_${index}`);
1202
1202
  }) : null
@@ -1388,8 +1388,8 @@ function ArrayOfRelationsPreview({ propertyKey, value, property, size }) {
1388
1388
  previewProperties: ofProperty.admin?.previewProperties,
1389
1389
  size: "small",
1390
1390
  relation: entityRelation,
1391
- includeId: ofProperty.includeId,
1392
- includeEntityLink: ofProperty.includeEntityLink
1391
+ includeId: ofProperty.admin?.includeId,
1392
+ includeEntityLink: ofProperty.admin?.includeEntityLink
1393
1393
  })
1394
1394
  }, `preview_array_rel_${propertyKey}_${index}`);
1395
1395
  }) : null
@@ -1943,8 +1943,8 @@ var PropertyPreview = React.memo(function PropertyPreview(props) {
1943
1943
  else if (property.type === "reference") if (typeof property.path === "string") if (typeof value === "object" && value !== null && "isEntityReference" in value && value.isEntityReference()) content = /* @__PURE__ */ jsx(ReferencePreview, {
1944
1944
  disabled: !property.path,
1945
1945
  previewProperties: property.admin?.previewProperties,
1946
- includeId: property.includeId,
1947
- includeEntityLink: property.includeEntityLink,
1946
+ includeId: property.admin?.includeId,
1947
+ includeEntityLink: property.admin?.includeEntityLink,
1948
1948
  size: props.size,
1949
1949
  reference: value,
1950
1950
  textOnly: props.textOnly
@@ -1962,8 +1962,8 @@ var PropertyPreview = React.memo(function PropertyPreview(props) {
1962
1962
  children: /* @__PURE__ */ jsx(RelationPreview, {
1963
1963
  disabled: !property.relation,
1964
1964
  previewProperties: property.admin?.previewProperties,
1965
- includeId: property.includeId,
1966
- includeEntityLink: property.includeEntityLink,
1965
+ includeId: property.admin?.includeId,
1966
+ includeEntityLink: property.admin?.includeEntityLink,
1967
1967
  size: "small",
1968
1968
  relation: entityRelation,
1969
1969
  textOnly: props.textOnly
@@ -1976,8 +1976,8 @@ var PropertyPreview = React.memo(function PropertyPreview(props) {
1976
1976
  if (relationValue) content = /* @__PURE__ */ jsx(RelationPreview, {
1977
1977
  disabled: !property.relation,
1978
1978
  previewProperties: property.admin?.previewProperties,
1979
- includeId: property.includeId,
1980
- includeEntityLink: property.includeEntityLink,
1979
+ includeId: property.admin?.includeId,
1980
+ includeEntityLink: property.admin?.includeEntityLink,
1981
1981
  size: props.size,
1982
1982
  relation: relationValue,
1983
1983
  textOnly: props.textOnly
@@ -2018,7 +2018,7 @@ function ArrayOfMapsPreview({ propertyKey, value, property, size }) {
2018
2018
  const properties = mapProperty.properties;
2019
2019
  if (!properties) throw Error(`You need to specify a 'properties' prop (or specify a custom field) in your map property '${propertyKey}'${mapProperty.name ? ` ("${mapProperty.name}")` : ""}`);
2020
2020
  const values = value;
2021
- const previewProperties = mapProperty.previewProperties;
2021
+ const previewProperties = mapProperty.admin?.previewProperties;
2022
2022
  if (!values) return null;
2023
2023
  let mapProperties = previewProperties;
2024
2024
  if (!mapProperties || !mapProperties.length) {
@@ -3202,11 +3202,11 @@ function relationCardinality$3(relation) {
3202
3202
  if (relation.kind === "belongsTo" || relation.kind === "hasOne") return "one";
3203
3203
  return relation.cardinality;
3204
3204
  }
3205
- var RelationSelector = React$1.forwardRef(({ value, size = "medium", onValueChange, invisible, disabled, placeholder, useChips = true, className, relation, fixedFilter, pageSize, emptyPlaceholder, searchPlaceholder = "Search...", noResultsText = "No relations found.", loadingText = "Loading..." }, ref) => {
3205
+ var RelationSelector = React$1.forwardRef(({ value, size = "medium", onValueChange, invisible, disabled, placeholder, useChips = true, className, relation, multiple: multipleOverride, fixedFilter, pageSize, emptyPlaceholder, searchPlaceholder = "Search...", noResultsText = "No relations found.", loadingText = "Loading..." }, ref) => {
3206
3206
  const collection = relation.target();
3207
3207
  const dataClient = useData();
3208
3208
  const sidePanelController = useSidePanel();
3209
- const multiple = relationCardinality$3(relation) === "many";
3209
+ const multiple = multipleOverride ?? relationCardinality$3(relation) === "many";
3210
3210
  const [isPopoverOpen, setIsPopoverOpen] = useState(false);
3211
3211
  const isPopoverOpenRef = useRef(false);
3212
3212
  const [selectedItems, setSelectedItems] = useState([]);
@@ -3840,10 +3840,10 @@ function getTableBindingForProperty(property, selected) {
3840
3840
  path: property.path,
3841
3841
  multiselect: false,
3842
3842
  previewProperties: property.admin?.previewProperties,
3843
- includeId: property.includeId,
3844
- includeEntityLink: property.includeEntityLink,
3843
+ includeId: property.admin?.includeId,
3844
+ includeEntityLink: property.admin?.includeEntityLink,
3845
3845
  title: property.name ?? propertyKey,
3846
- fixedFilter: property.fixedFilter
3846
+ fixedFilter: property.admin?.fixedFilter
3847
3847
  });
3848
3848
  },
3849
3849
  allowScroll: false
@@ -3893,9 +3893,9 @@ function getTableBindingForProperty(property, selected) {
3893
3893
  path: refOfProp.path,
3894
3894
  previewProperties: refOfProp.admin?.previewProperties,
3895
3895
  title: arrayProperty.name,
3896
- fixedFilter: refOfProp.fixedFilter,
3897
- includeId: refOfProp.includeId,
3898
- includeEntityLink: refOfProp.includeEntityLink
3896
+ fixedFilter: refOfProp.admin?.fixedFilter,
3897
+ includeId: refOfProp.admin?.includeId,
3898
+ includeEntityLink: refOfProp.admin?.includeEntityLink
3899
3899
  }),
3900
3900
  allowScroll: false
3901
3901
  };
@@ -3915,10 +3915,10 @@ function RelationDialogBindingComponent({ propertyKey, internalValue, updateValu
3915
3915
  multiselect: false,
3916
3916
  relation: relProp.relation,
3917
3917
  previewProperties: relProp.admin?.previewProperties,
3918
- includeId: relProp.includeId,
3919
- includeEntityLink: relProp.includeEntityLink,
3918
+ includeId: relProp.admin?.includeId,
3919
+ includeEntityLink: relProp.admin?.includeEntityLink,
3920
3920
  title: relProp.name ?? propertyKey,
3921
- fixedFilter: relProp.fixedFilter
3921
+ fixedFilter: relProp.admin?.fixedFilter
3922
3922
  });
3923
3923
  }
3924
3924
  /** Stable component for relation fields rendered with the inline selector */
@@ -3931,7 +3931,7 @@ function RelationSelectorBindingComponent({ propertyKey, internalValue, updateVa
3931
3931
  disabled,
3932
3932
  size: "small",
3933
3933
  relation: relProp.relation,
3934
- fixedFilter: relProp.fixedFilter
3934
+ fixedFilter: relProp.admin?.fixedFilter
3935
3935
  });
3936
3936
  }
3937
3937
  //#endregion
@@ -4569,18 +4569,18 @@ function useUrlController() {
4569
4569
  return context;
4570
4570
  }
4571
4571
  //#endregion
4572
- //#region src/hooks/useCMSContext.tsx
4572
+ //#region src/hooks/useAdminContext.tsx
4573
4573
  /**
4574
- * Hook that builds a fully-populated CMS context by combining the
4575
- * core {@link RebaseContext} with CMS-specific controllers.
4574
+ * Hook that builds a fully-populated admin context by combining the
4575
+ * core {@link RebaseContext} with admin-specific controllers.
4576
4576
  *
4577
- * Use this instead of `useRebaseContext()` in CMS components that
4577
+ * Use this instead of `useRebaseContext()` in admin components that
4578
4578
  * need to pass context to entity action callbacks, plugin slots,
4579
- * or any consumer that expects CMS controllers on the context object.
4579
+ * or any consumer that expects admin controllers on the context object.
4580
4580
  *
4581
4581
  * @group Hooks and utilities
4582
4582
  */
4583
- function useCMSContext() {
4583
+ function useAdminContext() {
4584
4584
  const baseContext = useRebaseContext();
4585
4585
  const sidePanelController = useSidePanel();
4586
4586
  const sideDialogsController = useSideDialogsController();
@@ -4619,7 +4619,7 @@ function useCMSContext() {
4619
4619
  * @group Collection components
4620
4620
  */
4621
4621
  var CollectionRowActions = function CollectionRowActions({ entity, collection, path, width, frozen, isSelected, selectionEnabled, size, highlightEntity, onCollectionChange, unhighlightEntity, actions = [], hideId, selectionController, openEntityMode, sortableNodeRef, sortableStyle, sortableAttributes, isDragging, isDraggable }) {
4622
- const context = useCMSContext();
4622
+ const context = useAdminContext();
4623
4623
  const sidePanelCtrl = context.sidePanelController;
4624
4624
  const { t } = useTranslation();
4625
4625
  const onCheckedChange = useCallback((checked) => {
@@ -4666,7 +4666,7 @@ var CollectionRowActions = function CollectionRowActions({ entity, collection, p
4666
4666
  });
4667
4667
  },
4668
4668
  size: iconSize,
4669
- children: action.icon
4669
+ children: getIcon(action.icon, void 0, void 0, "smallest")
4670
4670
  });
4671
4671
  if (isEditAction && hasDraft) iconButton = /* @__PURE__ */ jsx(Badge, {
4672
4672
  color: "warning",
@@ -4700,7 +4700,7 @@ var CollectionRowActions = function CollectionRowActions({ entity, collection, p
4700
4700
  openEntityMode: openEntityMode ?? collection?.openEntityMode
4701
4701
  });
4702
4702
  },
4703
- children: [action.icon, action.name]
4703
+ children: [getIcon(action.icon, void 0, void 0, "smallest"), action.name]
4704
4704
  }, index))
4705
4705
  }),
4706
4706
  selectionEnabled && /* @__PURE__ */ jsx(Tooltip, {
@@ -4817,12 +4817,12 @@ function getSubcollectionColumnId(collection) {
4817
4817
  }
4818
4818
  //#endregion
4819
4819
  //#region src/components/CollectionTableBinding/column_utils.tsx
4820
- function propertiesToColumns({ properties, sortable, fixedFilter, AdditionalHeaderWidget }) {
4820
+ function propertiesToColumns({ properties, sortable, fixedFilter, engine, AdditionalHeaderWidget }) {
4821
4821
  const disabledFilter = Boolean(fixedFilter);
4822
4822
  return Object.entries(properties).flatMap(([key, property]) => getColumnKeysForProperty(property, key)).map(({ key, disabled }) => {
4823
4823
  const property = getResolvedPropertyInPath(properties, key);
4824
4824
  if (!property) throw Error("Internal error: no property found in path " + key);
4825
- const filterable = filterableProperty(property);
4825
+ const filterable = filterableProperty(property, false, engine);
4826
4826
  return {
4827
4827
  key,
4828
4828
  align: getTableCellAlignment(property),
@@ -4844,7 +4844,8 @@ function propertiesToColumns({ properties, sortable, fixedFilter, AdditionalHead
4844
4844
  };
4845
4845
  });
4846
4846
  }
4847
- function filterableProperty(property, partOfArray = false) {
4847
+ function filterableProperty(property, partOfArray = false, engine) {
4848
+ if (!isFilterableRelation(property, engine)) return false;
4848
4849
  if (partOfArray) return [
4849
4850
  "string",
4850
4851
  "number",
@@ -4852,7 +4853,7 @@ function filterableProperty(property, partOfArray = false) {
4852
4853
  "reference",
4853
4854
  "relation"
4854
4855
  ].includes(property.type);
4855
- if (property.type === "array") if (property.of && !Array.isArray(property.of)) return filterableProperty(property.of, true);
4856
+ if (property.type === "array") if (property.of && !Array.isArray(property.of)) return filterableProperty(property.of, true, engine);
4856
4857
  else return false;
4857
4858
  return [
4858
4859
  "string",
@@ -5146,6 +5147,39 @@ function DateTimeFilterField({ name, isArray, mode, value, setValue, title, time
5146
5147
  });
5147
5148
  }
5148
5149
  //#endregion
5150
+ //#region src/components/SelectableTable/filters/null_filter.ts
5151
+ /** Whether `op` asks about absence rather than about a value. */
5152
+ function isNullFilterOperator(op) {
5153
+ return op === "is-null" || op === "is-not-null";
5154
+ }
5155
+ /**
5156
+ * The null check carrying the same sense as `op`.
5157
+ *
5158
+ * The checkbox is a toggle, not an operator, so the operator it is ticked
5159
+ * alongside is what says which way round it means: `==`/`in` are asking for
5160
+ * a match, so their null form is "has nothing"; `!=`/`not-in` are asking for
5161
+ * the absence of one, so theirs is "has something".
5162
+ */
5163
+ function nullFilterOperatorFor(op) {
5164
+ if (op === "!=" || op === "not-in" || op === "is-not-null") return "is-not-null";
5165
+ return "is-null";
5166
+ }
5167
+ /**
5168
+ * The value operator to return to when the checkbox is unticked.
5169
+ *
5170
+ * `is-null` could have been reached from `==` or from `in` — the field cannot
5171
+ * know which, and it does not matter. What matters is landing on an operator
5172
+ * the dropdown actually offers, in the same sense, so the control does not
5173
+ * come back showing something it cannot render.
5174
+ */
5175
+ function valueOperatorFor(op, offered) {
5176
+ return (op === "is-not-null" ? ["!=", "not-in"] : [
5177
+ "==",
5178
+ "in",
5179
+ "array-contains"
5180
+ ]).find((candidate) => offered.includes(candidate)) ?? offered.find((candidate) => !isNullFilterOperator(candidate));
5181
+ }
5182
+ //#endregion
5149
5183
  //#region src/components/SelectableTable/filters/ReferenceFilterField.tsx
5150
5184
  var operationLabels$1 = {
5151
5185
  "==": "==",
@@ -5157,7 +5191,9 @@ var operationLabels$1 = {
5157
5191
  in: "In",
5158
5192
  "not-in": "Not in",
5159
5193
  "array-contains": "Contains",
5160
- "array-contains-any": "Contains Any"
5194
+ "array-contains-any": "Contains Any",
5195
+ "is-null": "Is null",
5196
+ "is-not-null": "Is not null"
5161
5197
  };
5162
5198
  var multipleSelectOperations$1 = [
5163
5199
  "array-contains-any",
@@ -5176,6 +5212,7 @@ function ReferenceFilterField({ value, setValue, isArray, path, includeId = true
5176
5212
  ];
5177
5213
  if (isArray) possibleOperations.push("array-contains-any");
5178
5214
  else possibleOperations.push("in", "not-in");
5215
+ possibleOperations.push("is-null", "is-not-null");
5179
5216
  if (operators) possibleOperations = possibleOperations.filter((op) => operators.includes(op));
5180
5217
  const [fieldOperation, fieldValue] = value || [possibleOperations[0], void 0];
5181
5218
  const [operation, setOperation] = useState(fieldOperation);
@@ -5191,6 +5228,10 @@ function ReferenceFilterField({ value, setValue, isArray, path, includeId = true
5191
5228
  if (prevOpIsArray !== newOpIsArray) newValue = newOpIsArray ? newValue && !Array.isArray(newValue) && newValue.isEntityReference?.() ? [newValue] : [] : void 0;
5192
5229
  setOperation(op);
5193
5230
  setInternalValue(newValue);
5231
+ if (isNullFilterOperator(op)) {
5232
+ setValue([op, null]);
5233
+ return;
5234
+ }
5194
5235
  const hasNewValue = newValue !== null && Array.isArray(newValue) ? newValue.length > 0 : newValue !== void 0;
5195
5236
  if (op && hasNewValue) setValue([op, newValue]);
5196
5237
  else setValue(void 0);
@@ -5206,6 +5247,8 @@ function ReferenceFilterField({ value, setValue, isArray, path, includeId = true
5206
5247
  updateFilter(operation, entities.map((e) => getReferenceFrom(e)));
5207
5248
  };
5208
5249
  const multiple = multipleSelectOperations$1.includes(operation);
5250
+ const nullFiltered = isNullFilterOperator(operation);
5251
+ const nullFilterId = useId();
5209
5252
  const referenceDialogController = useSelectionDialog({
5210
5253
  multiselect: multiple,
5211
5254
  path,
@@ -5264,14 +5307,14 @@ function ReferenceFilterField({ value, setValue, isArray, path, includeId = true
5264
5307
  }),
5265
5308
  !isArray && /* @__PURE__ */ jsxs(Label, {
5266
5309
  className: "border cursor-pointer rounded-md p-2 flex items-center gap-2 bg-surface-50 dark:bg-surface-900 hover:bg-surface-100 dark:hover:bg-surface-800",
5267
- htmlFor: "null-filter",
5310
+ htmlFor: nullFilterId,
5268
5311
  children: [/* @__PURE__ */ jsx(Checkbox, {
5269
- id: "null-filter",
5270
- checked: internalValue === null,
5312
+ id: nullFilterId,
5313
+ checked: nullFiltered,
5271
5314
  size: "small",
5272
- onCheckedChange: (checked) => {
5273
- if (internalValue !== null) updateFilter(operation, null);
5274
- else updateFilter(operation, void 0);
5315
+ onCheckedChange: () => {
5316
+ if (!nullFiltered) updateFilter(nullFilterOperatorFor(operation), null);
5317
+ else updateFilter(valueOperatorFor(operation, possibleOperations) ?? operation, void 0);
5275
5318
  }
5276
5319
  }), t("filter_for_null_values")]
5277
5320
  })
@@ -5299,26 +5342,68 @@ var operationLabels = {
5299
5342
  in: "In",
5300
5343
  "not-in": "Not in",
5301
5344
  "array-contains": "Contains",
5302
- "array-contains-any": "Contains Any"
5345
+ "array-contains-any": "Contains Any",
5346
+ "is-null": "Is empty",
5347
+ "is-not-null": "Is not empty"
5303
5348
  };
5304
5349
  var multipleSelectOperations = [
5305
5350
  "array-contains-any",
5306
5351
  "in",
5307
5352
  "not-in"
5308
5353
  ];
5354
+ /**
5355
+ * What this field can render, before `operators` narrows it.
5356
+ *
5357
+ * Every relation gets the whole set. The value selector is told how many
5358
+ * values to take by the *operator* — see the `multiple` prop passed below —
5359
+ * so a to-many relation can be asked `== <one tag>` as readily as
5360
+ * `in <several>`, and the question of what shape the relation stores never
5361
+ * enters into it.
5362
+ *
5363
+ * That is a change: this list used to be split by the value the selector
5364
+ * produced, because the selector took its multiplicity from the relation's
5365
+ * cardinality and so a to-many one could only ever emit a list. Every
5366
+ * single-value operator had to be withheld to keep an array from reaching
5367
+ * `==`. `ReferenceFilterField` never had the problem — it has always sized its
5368
+ * dialog from the operator — which is what made the split look like a
5369
+ * property of relations rather than a limitation of one component.
5370
+ *
5371
+ * The array operators are the exception, and belong only to a to-many link,
5372
+ * which is the only one that *is* a list. On a to-one relation the filter
5373
+ * compiles to a comparison on a scalar foreign key, and `@>` against one is a
5374
+ * type error rather than an empty result.
5375
+ */
5376
+ var RELATION_OPERATIONS = [
5377
+ "==",
5378
+ "!=",
5379
+ ">",
5380
+ "<",
5381
+ ">=",
5382
+ "<=",
5383
+ "in",
5384
+ "not-in",
5385
+ "is-null",
5386
+ "is-not-null"
5387
+ ];
5388
+ var LIST_ONLY_OPERATIONS = ["array-contains", "array-contains-any"];
5389
+ /**
5390
+ * The operators this field will actually put on screen.
5391
+ *
5392
+ * Exported because the failure mode is silence: when the intersection of what
5393
+ * the field can render and what the engine can run comes out empty, the field
5394
+ * returns null and the filter control the table header offered opens onto
5395
+ * nothing. That is a rendering outcome no unit test of either side alone
5396
+ * catches, so the intersection itself is the thing worth pinning.
5397
+ */
5398
+ function renderableRelationOperators(relation, operators) {
5399
+ const possible = relationCardinality$1(relation) === "many" ? [...RELATION_OPERATIONS, ...LIST_ONLY_OPERATIONS] : RELATION_OPERATIONS;
5400
+ if (!operators) return possible;
5401
+ return possible.filter((op) => operators.includes(op));
5402
+ }
5309
5403
  function RelationFilterField({ value, setValue, relation, name: _name, hidden: _hidden, setHidden: _setHidden, operators }) {
5310
5404
  const manyRelation = relationCardinality$1(relation) === "many";
5311
- let possibleOperations = manyRelation ? ["array-contains", "array-contains-any"] : [
5312
- "==",
5313
- "!=",
5314
- ">",
5315
- "<",
5316
- ">=",
5317
- "<=",
5318
- "in",
5319
- "not-in"
5320
- ];
5321
- if (operators) possibleOperations = possibleOperations.filter((op) => operators.includes(op));
5405
+ const nullFilterId = useId();
5406
+ const possibleOperations = renderableRelationOperators(relation, operators);
5322
5407
  const [fieldOperation, fieldValue] = value || [possibleOperations[0], void 0];
5323
5408
  const [operation, setOperation] = useState(fieldOperation);
5324
5409
  const [internalValue, setInternalValue] = useState(fieldValue);
@@ -5329,11 +5414,16 @@ function RelationFilterField({ value, setValue, relation, name: _name, hidden: _
5329
5414
  if (prevOpIsArray !== newOpIsArray) newValue = newOpIsArray ? newValue instanceof EntityRelation ? [newValue] : [] : void 0;
5330
5415
  setOperation(op);
5331
5416
  setInternalValue(newValue);
5417
+ if (isNullFilterOperator(op)) {
5418
+ setValue([op, null]);
5419
+ return;
5420
+ }
5332
5421
  const hasNewValue = newValue !== null && Array.isArray(newValue) ? newValue.length > 0 : newValue !== void 0;
5333
5422
  if (op && hasNewValue) setValue([op, newValue ?? null]);
5334
5423
  else setValue(void 0);
5335
5424
  }
5336
- multipleSelectOperations.includes(operation);
5425
+ const multiple = multipleSelectOperations.includes(operation);
5426
+ const nullFiltered = isNullFilterOperator(operation);
5337
5427
  const relationSelectorValue = useMemo(() => {
5338
5428
  if (internalValue === null || internalValue === void 0) return void 0;
5339
5429
  if (Array.isArray(internalValue)) return internalValue.map((ref) => new EntityRelation(ref.id, ref.path));
@@ -5371,22 +5461,23 @@ function RelationFilterField({ value, setValue, relation, name: _name, hidden: _
5371
5461
  className: "grow ml-2 h-full gap-2 flex flex-col w-[340px]",
5372
5462
  children: [/* @__PURE__ */ jsx(RelationSelector, {
5373
5463
  relation,
5464
+ multiple,
5374
5465
  value: relationSelectorValue,
5375
5466
  onValueChange: handleRelationSelectorChange,
5376
- disabled: internalValue === null,
5467
+ disabled: nullFiltered,
5377
5468
  size: "medium"
5378
- }), !manyRelation && /* @__PURE__ */ jsxs(Label, {
5469
+ }), /* @__PURE__ */ jsxs(Label, {
5379
5470
  className: "border cursor-pointer rounded-md p-2 flex items-center gap-2 bg-surface-50 dark:bg-surface-900 hover:bg-surface-100 dark:hover:bg-surface-800",
5380
- htmlFor: "null-filter",
5471
+ htmlFor: nullFilterId,
5381
5472
  children: [/* @__PURE__ */ jsx(Checkbox, {
5382
- id: "null-filter",
5383
- checked: internalValue === null,
5473
+ id: nullFilterId,
5474
+ checked: nullFiltered,
5384
5475
  size: "small",
5385
5476
  onCheckedChange: () => {
5386
- if (internalValue !== null) updateFilter(operation, null);
5387
- else updateFilter(operation, void 0);
5477
+ if (!nullFiltered) updateFilter(nullFilterOperatorFor(operation), null);
5478
+ else updateFilter(valueOperatorFor(operation, possibleOperations) ?? operation, void 0);
5388
5479
  }
5389
- }), "Filter for null values"]
5480
+ }), manyRelation ? "Filter for empty relations" : "Filter for null values"]
5390
5481
  })]
5391
5482
  })]
5392
5483
  });
@@ -5459,7 +5550,7 @@ function DefaultFilterField({ propertyKey, property, isArray, operators, value,
5459
5550
  operators,
5460
5551
  path: referenceProperty.path,
5461
5552
  title,
5462
- includeId: referenceProperty.includeId,
5553
+ includeId: referenceProperty.admin?.includeId,
5463
5554
  previewProperties: referenceProperty.admin?.previewProperties,
5464
5555
  hidden: hidden ?? false,
5465
5556
  setHidden: setHidden ?? (() => void 0)
@@ -5776,11 +5867,13 @@ var CollectionTableBinding = function CollectionTableBinding({ className, style,
5776
5867
  })?.toString() }) })
5777
5868
  }, `additional_table_cell_${entity.id}_${column.key}`);
5778
5869
  }, [size]);
5870
+ const engine = useCollectionScope()?.engine;
5779
5871
  const collectionColumns = useMemo(() => {
5780
5872
  const columnsResult = propertiesToColumns({
5781
5873
  properties,
5782
5874
  sortable,
5783
5875
  fixedFilter,
5876
+ engine,
5784
5877
  AdditionalHeaderWidget
5785
5878
  });
5786
5879
  const propertyColumnKeys = new Set(columnsResult.map((col) => col.key));
@@ -5796,6 +5889,7 @@ var CollectionTableBinding = function CollectionTableBinding({ className, style,
5796
5889
  properties,
5797
5890
  sortable,
5798
5891
  fixedFilter,
5892
+ engine,
5799
5893
  AdditionalHeaderWidget,
5800
5894
  additionalFields
5801
5895
  ]);
@@ -7438,10 +7532,10 @@ function EditorCollectionAction({ path, parentCollectionSlugs, parentEntityIds,
7438
7532
  }
7439
7533
  //#endregion
7440
7534
  //#region src/components/CollectionViewBinding/CollectionViewActions.tsx
7441
- var ImportCollectionAction = lazy(() => import("./import-DINSB-Vu.js").then((n) => n.t).then((m) => ({ default: m.ImportCollectionAction })));
7442
- var ExportCollectionAction = lazy(() => import("./export-BvqhjdEb.js").then((n) => n.t).then((m) => ({ default: m.ExportCollectionAction })));
7535
+ var ImportCollectionAction = lazy(() => import("./import-BjUG-cIY.js").then((n) => n.t).then((m) => ({ default: m.ImportCollectionAction })));
7536
+ var ExportCollectionAction = lazy(() => import("./export-BzIpUdSK.js").then((n) => n.t).then((m) => ({ default: m.ExportCollectionAction })));
7443
7537
  function CollectionViewActions({ collection, relativePath, parentCollectionSlugs, parentEntityIds, onNewClick, onAddExistingClick, onMultipleDeleteClick, selectionEnabled, path, selectionController, tableController, collectionEntitiesCount, compact, children, openNewDocument }) {
7444
- const context = useCMSContext();
7538
+ const context = useAdminContext();
7445
7539
  const { canCreate, canDelete } = usePermissions();
7446
7540
  const largeLayout = useLargeLayout();
7447
7541
  const { t } = useTranslation();
@@ -8184,8 +8278,8 @@ function formatDateValue(value) {
8184
8278
  });
8185
8279
  }
8186
8280
  /**
8187
- * Classic CMS list view for displaying entities.
8188
- * Designed to be the most familiar, stereotypical CMS content management view:
8281
+ * Classic admin list view for displaying entities.
8282
+ * Designed to be the most familiar, stereotypical admin content management view:
8189
8283
  * - Clean rows with checkbox, icon/avatar, title, metadata, and actions
8190
8284
  * - Column-sortable headers
8191
8285
  * - Infinite scroll
@@ -8194,7 +8288,7 @@ function CollectionListViewBinding({ collection, tableController, onEntityClick,
8194
8288
  const authController = useAuthController();
8195
8289
  const customizationController = useCustomizationController();
8196
8290
  const analyticsController = useAnalyticsController();
8197
- const context = useCMSContext();
8291
+ const context = useAdminContext();
8198
8292
  const containerRef = useRef(null);
8199
8293
  const [containerWidth, setContainerWidth] = useState(1200);
8200
8294
  useEffect(() => {
@@ -8638,7 +8732,7 @@ var ListRow = React.memo(function ListRow({ entity, collection, onClick, selecte
8638
8732
  openEntityMode: openEntityMode ?? collection?.openEntityMode ?? "full_screen"
8639
8733
  });
8640
8734
  },
8641
- children: action.icon
8735
+ children: getIcon(action.icon, void 0, void 0, "smallest")
8642
8736
  })
8643
8737
  }, action.key ?? index))
8644
8738
  })
@@ -8932,7 +9026,7 @@ var MAIN_TAB_VALUE = "__main_##Q$SC^#S6";
8932
9026
  var JSON_TAB_VALUE = "__json";
8933
9027
  //#endregion
8934
9028
  //#region src/components/DetailViewBinding.tsx
8935
- var EntityHistoryView$1 = lazy(() => import("./history-Dz20hH38.js").then((m) => ({ default: m.EntityHistoryView })));
9029
+ var EntityHistoryView$1 = lazy(() => import("./history-g9688IaK.js").then((m) => ({ default: m.EntityHistoryView })));
8936
9030
  function DetailViewBinding({ entityId, ...props }) {
8937
9031
  const { entity, dataLoading, dataLoadingError } = useFetch({
8938
9032
  path: props.path,
@@ -9212,7 +9306,16 @@ function DetailViewBindingInner({ path, entityId, selectedTab: selectedTabProp,
9212
9306
  })
9213
9307
  }, `entity_detail_collection_tab_${view.name}`);
9214
9308
  });
9215
- const shouldShowTopBar = Boolean(barActions) || hasAdditionalViews || layout === "side_panel" || layout === "dialog";
9309
+ const backToCollectionButton = layout === "full_screen" ? /* @__PURE__ */ jsx(Tooltip, {
9310
+ title: t("back"),
9311
+ children: /* @__PURE__ */ jsx(IconButton, {
9312
+ size: "small",
9313
+ "aria-label": t("back"),
9314
+ onClick: () => navigate(urlController.buildUrlCollectionPath(path)),
9315
+ children: /* @__PURE__ */ jsx(ArrowLeftIcon, { size: iconSize.smallest })
9316
+ })
9317
+ }) : null;
9318
+ const shouldShowTopBar = Boolean(barActions) || hasAdditionalViews || layout === "side_panel" || layout === "dialog" || Boolean(backToCollectionButton);
9216
9319
  const fullScreenButton = !barActions && (layout === "side_panel" || layout === "split" || layout === "dialog") && entityId ? /* @__PURE__ */ jsx(Tooltip, {
9217
9320
  title: "Open full screen",
9218
9321
  children: /* @__PURE__ */ jsx(IconButton, {
@@ -9286,6 +9389,7 @@ function DetailViewBindingInner({ path, entityId, selectedTab: selectedTabProp,
9286
9389
  shouldShowTopBar && /* @__PURE__ */ jsxs("div", {
9287
9390
  className: cls("h-[52px] items-center flex overflow-hidden w-full border-b pl-2 pr-2 flex bg-surface-50 dark:bg-surface-900", defaultBorderMixin),
9288
9391
  children: [
9392
+ backToCollectionButton,
9289
9393
  fullScreenButton,
9290
9394
  barActions?.({
9291
9395
  path,
@@ -10955,7 +11059,7 @@ function DeleteEntityDialog({ entityOrEntitiesToDelete, collection, onClose, ope
10955
11059
  const snackbarController = useSnackbarController();
10956
11060
  const { t } = useTranslation();
10957
11061
  const [loading, setLoading] = useState(false);
10958
- const context = useCMSContext();
11062
+ const context = useAdminContext();
10959
11063
  const entityOrEntities = Array.isArray(entityOrEntitiesToDelete) && entityOrEntitiesToDelete.length === 1 ? entityOrEntitiesToDelete[0] : entityOrEntitiesToDelete;
10960
11064
  const multipleEntities = Array.isArray(entityOrEntities);
10961
11065
  const handleCancel = useCallback(() => {
@@ -12239,7 +12343,7 @@ function FilterPresetsButton({ filterPresets, tableController, compact }) {
12239
12343
  //#endregion
12240
12344
  //#region src/components/CollectionViewBinding/CollectionViewStartActions.tsx
12241
12345
  function CollectionViewStartActions({ collection, relativePath, parentCollectionSlugs, parentEntityIds, path, selectionController, tableController, collectionEntitiesCount, resolvedProperties, compact, openNewDocument }) {
12242
- const context = useCMSContext();
12346
+ const context = useAdminContext();
12243
12347
  const largeLayout = useLargeLayout();
12244
12348
  const { t } = useTranslation();
12245
12349
  const navigate = useNavigate();
@@ -12386,7 +12490,7 @@ var EMPTY_ARRAY = [];
12386
12490
  */
12387
12491
  var CollectionViewBindingInner = React.memo(function CollectionViewBindingInner({ path: pathProp, parentCollectionSlugs, parentEntityIds, isSubCollection, className, updateUrl, selectedEntityId: selectedEntityIdProp, selectedTab: selectedTabProp, ...collectionProp }) {
12388
12492
  const { t } = useTranslation();
12389
- const context = useCMSContext();
12493
+ const context = useAdminContext();
12390
12494
  const collectionRegistry = useCollectionRegistryController();
12391
12495
  const urlController = useUrlController();
12392
12496
  const breadcrumbs = useBreadcrumbsController();
@@ -13353,7 +13457,7 @@ function EntityIdHeaderWidget({ collection, path, idPath, openEntityMode }) {
13353
13457
  //#region src/components/EditFormActions.tsx
13354
13458
  function EditFormActions({ collection, path, entity, layout, savingError, formex, disabled, status, pluginActions, openEntityMode, showDefaultActions = true, navigateBack, formContext }) {
13355
13459
  const { canCreate, canDelete } = usePermissions();
13356
- const context = useCMSContext();
13460
+ const context = useAdminContext();
13357
13461
  const sidePanelController = context.sidePanelController;
13358
13462
  const sideDialogContext = useSideDialogContext();
13359
13463
  const customizationController = useCustomizationController();
@@ -13619,13 +13723,13 @@ function EntityActionButton({ action, enabled, props }) {
13619
13723
  });
13620
13724
  }
13621
13725
  },
13622
- children: loading ? /* @__PURE__ */ jsx(CircularProgress, { size: "smallest" }) : action.icon
13726
+ children: loading ? /* @__PURE__ */ jsx(CircularProgress, { size: "smallest" }) : getIcon(action.icon, void 0, void 0, "smallest")
13623
13727
  })
13624
13728
  });
13625
13729
  }
13626
13730
  //#endregion
13627
13731
  //#region src/components/EditViewBinding.tsx
13628
- var EntityHistoryView = lazy(() => import("./history-Dz20hH38.js").then((m) => ({ default: m.EntityHistoryView })));
13732
+ var EntityHistoryView = lazy(() => import("./history-g9688IaK.js").then((m) => ({ default: m.EntityHistoryView })));
13629
13733
  /**
13630
13734
  * This is the default view that is used as the content of a side panel when
13631
13735
  * a record is opened.
@@ -14619,7 +14723,7 @@ function resolveNavigationFrom({ path, context }) {
14619
14723
  * @group Hooks and utilities
14620
14724
  */
14621
14725
  function useResolvedNavigationFrom({ path }) {
14622
- const context = useCMSContext();
14726
+ const context = useAdminContext();
14623
14727
  const { navigationStateController, collectionRegistryController } = context;
14624
14728
  const [data, setData] = useState();
14625
14729
  const [dataLoading, setDataLoading] = useState(false);
@@ -14958,7 +15062,7 @@ function injectAuthCollectionConfig(collections, adminPasswordResetSupported) {
14958
15062
  if (actionToInject) {
14959
15063
  const injectedAction = actionToInject;
14960
15064
  const existing = result.entityActions ?? [];
14961
- if (!existing.some((a) => a.key != null && a.key === injectedAction.key)) result = {
15065
+ if (!existing.some((a) => typeof a === "string" ? a === injectedAction.key : a.key != null && a.key === injectedAction.key)) result = {
14962
15066
  ...result,
14963
15067
  entityActions: [...existing, injectedAction]
14964
15068
  };
@@ -15035,7 +15139,7 @@ async function resolveAppViews(baseViews, authController, data, plugins) {
15035
15139
  slugCounts.set(v.slug, (slugCounts.get(v.slug) ?? 0) + 1);
15036
15140
  });
15037
15141
  slugCounts.forEach((count, slug) => {
15038
- if (count > 1) console.warn(`[Rebase] Duplicate view slug "${slug}" detected (${count} views). Last-write-wins. Ensure unique slugs across CMS views and plugins.`);
15142
+ if (count > 1) console.warn(`[Rebase] Duplicate view slug "${slug}" detected (${count} views). Last-write-wins. Ensure unique slugs across admin views and plugins.`);
15039
15143
  });
15040
15144
  }
15041
15145
  resolvedViews = filterViewsByRole(resolvedViews, authController);
@@ -16052,7 +16156,7 @@ function ArrayOfReferencesFieldBinding({ propertyKey, value, error, showError, d
16052
16156
  collection,
16053
16157
  onMultipleEntitiesSelected,
16054
16158
  selectedEntityIds,
16055
- fixedFilter: ofProperty.fixedFilter
16159
+ fixedFilter: ofProperty.admin?.fixedFilter
16056
16160
  });
16057
16161
  const onEntryClick = (e) => {
16058
16162
  e.preventDefault();
@@ -16068,8 +16172,8 @@ function ArrayOfReferencesFieldBinding({ propertyKey, value, error, showError, d
16068
16172
  onClick: onEntryClick,
16069
16173
  hover: !disabled,
16070
16174
  reference: entryValue,
16071
- includeId: ofProperty.includeId,
16072
- includeEntityLink: ofProperty.includeEntityLink
16175
+ includeId: ofProperty.admin?.includeId,
16176
+ includeEntityLink: ofProperty.admin?.includeEntityLink
16073
16177
  }, internalId);
16074
16178
  }, [
16075
16179
  ofProperty.path,
@@ -17129,7 +17233,7 @@ function ReferenceFieldBindingInternal({ propertyKey, value, setValue, error, sh
17129
17233
  collection,
17130
17234
  onSingleEntitySelected,
17131
17235
  selectedEntityIds: validValue && refValue ? [refValue.id] : void 0,
17132
- fixedFilter: property.fixedFilter
17236
+ fixedFilter: property.admin?.fixedFilter
17133
17237
  });
17134
17238
  const onEntryClick = (e) => {
17135
17239
  e.preventDefault();
@@ -17151,8 +17255,8 @@ function ReferenceFieldBindingInternal({ propertyKey, value, setValue, error, sh
17151
17255
  size,
17152
17256
  onClick: disabled || isSubmitting ? void 0 : onEntryClick,
17153
17257
  reference: refValue,
17154
- includeEntityLink: property.includeEntityLink,
17155
- includeId: property.includeId
17258
+ includeEntityLink: property.admin?.includeEntityLink,
17259
+ includeId: property.admin?.includeId
17156
17260
  }), !refValue && /* @__PURE__ */ jsx("div", {
17157
17261
  className: "justify-center text-left",
17158
17262
  children: /* @__PURE__ */ jsxs(EntityPreviewContainer, {
@@ -17221,8 +17325,8 @@ function RepeatFieldBinding({ propertyKey, value, error, showError, isSubmitting
17221
17325
  index
17222
17326
  }) });
17223
17327
  };
17224
- const canAddElements = !property.admin?.disabled && !isSubmitting && !disabled && (property.canAddElements || property.canAddElements === void 0);
17225
- const sortable = property.sortable === void 0 ? true : property.sortable;
17328
+ const canAddElements = !property.admin?.disabled && !isSubmitting && !disabled && (property.admin?.canAddElements || property.admin?.canAddElements === void 0);
17329
+ const sortable = property.admin?.sortable === void 0 ? true : property.admin.sortable;
17226
17330
  const arrayContainer = /* @__PURE__ */ jsx(ArrayContainer, {
17227
17331
  droppableId: propertyKey,
17228
17332
  addLabel: property.name ? t("add_to_field", { fieldName: property.name }) : t("add_entry"),
@@ -18211,7 +18315,7 @@ function MultipleRelationFieldBinding({ propertyKey, value: valueProp, error, sh
18211
18315
  if (property.type !== "relation") throw Error("RelationFieldBinding expected a property containing a relation");
18212
18316
  const parentCollection = context.collection;
18213
18317
  const capabilities = parentCollection ? getDataSourceCapabilities(parentCollection.engine) : void 0;
18214
- if (!parentCollection || !capabilities?.supportsRelations || !("relations" in parentCollection) || !parentCollection.relations) throw Error("RelationFieldBinding expected a collection with relations support");
18318
+ if (!parentCollection || !capabilities?.supportsRelations) throw Error("MultipleRelationFieldBinding expected a collection whose engine supports relations");
18215
18319
  const relation = resolveRelationProperty(property, parentCollection, propertyKey);
18216
18320
  if (!relation) throw Error("Property relation is required for MultipleRelationFieldBinding");
18217
18321
  const selectedEntityIds = value && Array.isArray(value) ? value.map((ref) => ref.id) : [];
@@ -18225,7 +18329,7 @@ function MultipleRelationFieldBinding({ propertyKey, value: valueProp, error, sh
18225
18329
  collection,
18226
18330
  onMultipleEntitiesSelected,
18227
18331
  selectedEntityIds,
18228
- fixedFilter: property.fixedFilter
18332
+ fixedFilter: property.admin?.fixedFilter
18229
18333
  });
18230
18334
  const onEntryClick = (e) => {
18231
18335
  e.preventDefault();
@@ -18240,8 +18344,8 @@ function MultipleRelationFieldBinding({ propertyKey, value: valueProp, error, sh
18240
18344
  onClick: onEntryClick,
18241
18345
  hover: !disabled,
18242
18346
  relation: entryValue,
18243
- includeId: property.includeId,
18244
- includeEntityLink: property.includeEntityLink
18347
+ includeId: property.admin?.includeId,
18348
+ includeEntityLink: property.admin?.includeEntityLink
18245
18349
  }, internalId);
18246
18350
  }, [
18247
18351
  relation,
@@ -18308,7 +18412,7 @@ function RelationFieldBinding(props) {
18308
18412
  if (property.type !== "relation") throw Error("RelationFieldBinding expected a property containing a relation");
18309
18413
  const collection = context.collection;
18310
18414
  const capabilities = collection ? getDataSourceCapabilities(collection.engine) : void 0;
18311
- if (!collection || !capabilities?.supportsRelations || !("relations" in collection) || !collection.relations) throw Error("RelationFieldBinding expected a collection with relations support");
18415
+ if (!collection || !capabilities?.supportsRelations) throw Error("RelationFieldBinding expected a collection whose engine supports relations");
18312
18416
  const relation = resolveRelationProperty(property, collection, propertyKey);
18313
18417
  const manyRelation = relation?.cardinality === "many";
18314
18418
  if ((property.admin?.widget ?? "select") === "select" && relation) return /* @__PURE__ */ jsx(RelationSelectorBinding, {
@@ -18344,7 +18448,7 @@ function RelationSelectorBinding({ propertyKey, value, size, error, showError, d
18344
18448
  else setValue(!Array.isArray(newVal) ? newVal ?? null : null);
18345
18449
  },
18346
18450
  disabled: disabled || isSubmitting,
18347
- fixedFilter: property.fixedFilter,
18451
+ fixedFilter: property.admin?.fixedFilter,
18348
18452
  size: selectorSize
18349
18453
  }),
18350
18454
  /* @__PURE__ */ jsx(FieldHelperText, {
@@ -18371,7 +18475,7 @@ function SingleRelationFieldBinding({ propertyKey, value, size, error, showError
18371
18475
  collection,
18372
18476
  onSingleEntitySelected,
18373
18477
  selectedEntityIds: validValue && normalizedValue ? [normalizedValue.id] : void 0,
18374
- fixedFilter: property.fixedFilter
18478
+ fixedFilter: property.admin?.fixedFilter
18375
18479
  });
18376
18480
  const onEntryClick = (e) => {
18377
18481
  e.preventDefault();
@@ -18394,8 +18498,8 @@ function SingleRelationFieldBinding({ propertyKey, value, size, error, showError
18394
18498
  size,
18395
18499
  onClick: disabled || isSubmitting ? void 0 : onEntryClick,
18396
18500
  relation: usedRelation,
18397
- includeEntityLink: property.includeEntityLink,
18398
- includeId: property.includeId
18501
+ includeEntityLink: property.admin?.includeEntityLink,
18502
+ includeId: property.admin?.includeId
18399
18503
  }), !value && /* @__PURE__ */ jsx("div", {
18400
18504
  className: "justify-center text-left",
18401
18505
  children: /* @__PURE__ */ jsxs(EntityPreviewContainer, {
@@ -19188,7 +19292,7 @@ function buildBottomActions({ savingError, entity, path, formActions, collection
19188
19292
  formContext
19189
19293
  });
19190
19294
  },
19191
- children: action.icon
19295
+ children: getIcon(action.icon, void 0, void 0, "smallest")
19192
19296
  }, action.name))
19193
19297
  }),
19194
19298
  pluginActions,
@@ -19471,9 +19575,9 @@ function zodToFormErrors(zodError) {
19471
19575
  /**
19472
19576
  * Headless entity form component.
19473
19577
  *
19474
- * Renders a form for a entity collection without any CMS or backend dependencies.
19578
+ * Renders a form for a entity collection without any admin or backend dependencies.
19475
19579
  * All backend concerns (save, caching, analytics, plugin slots) are provided via
19476
- * callback props. For CMS-connected usage, use {@link EntityFormBinding} instead.
19580
+ * callback props. For admin-connected usage, use {@link EntityFormBinding} instead.
19477
19581
  *
19478
19582
  * @group Components
19479
19583
  */
@@ -19906,7 +20010,7 @@ function useOnAutoSave(autoSave, formex, lastSavedValues, save) {
19906
20010
  //#endregion
19907
20011
  //#region src/form/EntityFormBinding.tsx
19908
20012
  /**
19909
- * CMS-connected wrapper around EntityForm.
20013
+ * admin-connected wrapper around EntityForm.
19910
20014
  *
19911
20015
  * Provides all backend concerns that the headless EntityForm delegates via callbacks:
19912
20016
  * - Save via the data layer (`saveEntityWithCallbacks`)
@@ -19917,8 +20021,8 @@ function useOnAutoSave(autoSave, formex, lastSavedValues, save) {
19917
20021
  * - Analytics events
19918
20022
  * - Navigation via side entity controller
19919
20023
  *
19920
- * Use this component inside the CMS (`<RebaseShell>`).
19921
- * For headless usage outside the CMS, use `EntityForm` directly.
20024
+ * Use this component inside the admin (`<RebaseShell>`).
20025
+ * For headless usage outside the admin, use `EntityForm` directly.
19922
20026
  *
19923
20027
  * @group Components
19924
20028
  */
@@ -19930,7 +20034,7 @@ function EntityFormBinding({ path, entityId: entityIdProp, collection, entity, i
19930
20034
  const dataClient = useData();
19931
20035
  const snackbarController = useSnackbarController();
19932
20036
  const customizationController = useCustomizationController();
19933
- const context = useCMSContext();
20037
+ const context = useAdminContext();
19934
20038
  const analyticsController = useAnalyticsController();
19935
20039
  const [status, setStatus] = useState(initialStatus);
19936
20040
  const [entityId, setEntityId] = useState(() => {
@@ -20157,14 +20261,36 @@ var useCollectionsConfigController = () => useContext(ConfigControllerContext);
20157
20261
  //#endregion
20158
20262
  //#region src/collection_editor/serializable_utils.ts
20159
20263
  /**
20264
+ * Conversion utilities between the full Rebase types and their
20265
+ * JSON-serializable counterparts.
20266
+ *
20267
+ * - `toSerializableCollectionConfig` / `toSerializableProperty` — strip non-serializable fields
20268
+ * - `fromSerializableCollectionConfig` / `fromSerializableProperty` — reconstruct original types
20269
+ *
20270
+ * @module
20271
+ */
20272
+ /**
20160
20273
  * Strip non-serializable fields from a `AdminPropertyOptions`.
20161
20274
  * Removes `Field` and `Preview` (ComponentRef).
20162
20275
  */
20276
+ /**
20277
+ * Every `ComponentRef` on a property's admin block. These are components, not
20278
+ * data, and none of them survives `JSON.stringify` — a function-valued key is
20279
+ * dropped from the output object with no error, so a component written here
20280
+ * would leave a key that reads back as missing rather than as itself.
20281
+ *
20282
+ * `Filter` was absent from this list while `Field` and `Preview` were named
20283
+ * twice, once destructured and once compared by string.
20284
+ */
20285
+ var NON_SERIALIZABLE_ADMIN_KEYS = [
20286
+ "Field",
20287
+ "Preview",
20288
+ "Filter"
20289
+ ];
20163
20290
  function toSerializableAdminOptions(ui) {
20164
20291
  if (!ui) return void 0;
20165
- const { Field, Preview, ...rest } = ui;
20166
20292
  const result = {};
20167
- for (const [key, value] of Object.entries(rest)) if (key !== "Field" && key !== "Preview" && value !== void 0) result[key] = value;
20293
+ for (const [key, value] of Object.entries(ui)) if (!NON_SERIALIZABLE_ADMIN_KEYS.includes(key) && value !== void 0) result[key] = value;
20168
20294
  return Object.keys(result).length > 0 ? result : void 0;
20169
20295
  }
20170
20296
  /**
@@ -20209,6 +20335,53 @@ function resolveRelationTarget(target) {
20209
20335
  } catch {}
20210
20336
  }
20211
20337
  /**
20338
+ * A `Relation` as JSON: `target` resolved from its thunk down to a slug.
20339
+ *
20340
+ * Switched on `kind` and assigned without a cast, so the compiler checks that
20341
+ * each branch writes the fields its kind owns and no others. This used to be
20342
+ * built as an untyped bag and cast into place — which is how the target
20343
+ * interface drifted a whole refactor behind the code writing to it.
20344
+ *
20345
+ * Shared by the relation *property* and the collection-level `relations` array,
20346
+ * which had no serializer at all: `buildCollectionFromTableMetadata` fills that
20347
+ * array from the table's foreign keys and junctions on import, and every one of
20348
+ * them was dropped on save.
20349
+ */
20350
+ function toSerializableRelation(link) {
20351
+ const target = resolveRelationTarget(link.target);
20352
+ const common = {
20353
+ ...target ? { target } : {},
20354
+ ...link.relationName ? { relationName: link.relationName } : {},
20355
+ ...link.onUpdate ? { onUpdate: link.onUpdate } : {},
20356
+ ...link.onDelete ? { onDelete: link.onDelete } : {}
20357
+ };
20358
+ switch (link.kind) {
20359
+ case "belongsTo": return {
20360
+ kind: "belongsTo",
20361
+ ...common,
20362
+ ...link.localKey ? { localKey: link.localKey } : {}
20363
+ };
20364
+ case "hasOne":
20365
+ case "hasMany": return {
20366
+ kind: link.kind,
20367
+ ...common,
20368
+ ...link.foreignKeyOnTarget ? { foreignKeyOnTarget: link.foreignKeyOnTarget } : {}
20369
+ };
20370
+ case "manyToMany": return {
20371
+ kind: "manyToMany",
20372
+ ...common,
20373
+ ...link.through ? { through: link.through } : {}
20374
+ };
20375
+ case "via": return {
20376
+ kind: "via",
20377
+ ...common,
20378
+ cardinality: link.cardinality,
20379
+ joinPath: link.joinPath
20380
+ };
20381
+ default: throw new Error(`Unhandled relation kind: ${JSON.stringify(link)}`);
20382
+ }
20383
+ }
20384
+ /**
20212
20385
  * Strip non-serializable base property fields.
20213
20386
  * Returns a clean object with only the common serializable fields from BaseProperty.
20214
20387
  * Validation is intentionally excluded — each property type handles its own.
@@ -20218,6 +20391,7 @@ function toSerializableBaseFields(property) {
20218
20391
  if (property.description) result.description = property.description;
20219
20392
  if (property.propertyConfig) result.propertyConfig = property.propertyConfig;
20220
20393
  if (property.columnName) result.columnName = property.columnName;
20394
+ if (property.excludeFromApi !== void 0) result.excludeFromApi = property.excludeFromApi;
20221
20395
  if (property.defaultValue !== void 0) result.defaultValue = property.defaultValue;
20222
20396
  if (property.conditions) result.conditions = property.conditions;
20223
20397
  if (property.metadata) result.metadata = property.metadata;
@@ -20243,6 +20417,7 @@ function toSerializableProperty(property) {
20243
20417
  if (sp.enum) result.enum = sp.enum;
20244
20418
  if (sp.userSelect) result.userSelect = sp.userSelect;
20245
20419
  if (sp.email) result.email = sp.email;
20420
+ if (sp.url) result.url = sp.url;
20246
20421
  if (sp.validation) {
20247
20422
  const { matches, ...restValidation } = sp.validation;
20248
20423
  const serializedValidation = { ...restValidation };
@@ -20316,9 +20491,6 @@ function toSerializableProperty(property) {
20316
20491
  };
20317
20492
  if (rp.isId !== void 0) result.isId = rp.isId;
20318
20493
  if (rp.path) result.path = rp.path;
20319
- if (rp.fixedFilter) result.fixedFilter = rp.fixedFilter;
20320
- if (rp.includeId !== void 0) result.includeId = rp.includeId;
20321
- if (rp.includeEntityLink !== void 0) result.includeEntityLink = rp.includeEntityLink;
20322
20494
  return result;
20323
20495
  }
20324
20496
  case "relation": {
@@ -20329,52 +20501,7 @@ function toSerializableProperty(property) {
20329
20501
  };
20330
20502
  if (rl.isId !== void 0) result.isId = rl.isId;
20331
20503
  const link = rl.relation;
20332
- if (link) {
20333
- const target = resolveRelationTarget(link.target);
20334
- const common = {
20335
- ...target ? { target } : {},
20336
- ...link.relationName ? { relationName: link.relationName } : {},
20337
- ...link.onUpdate ? { onUpdate: link.onUpdate } : {},
20338
- ...link.onDelete ? { onDelete: link.onDelete } : {}
20339
- };
20340
- switch (link.kind) {
20341
- case "belongsTo":
20342
- result.relation = {
20343
- kind: "belongsTo",
20344
- ...common,
20345
- ...link.localKey ? { localKey: link.localKey } : {}
20346
- };
20347
- break;
20348
- case "hasOne":
20349
- case "hasMany":
20350
- result.relation = {
20351
- kind: link.kind,
20352
- ...common,
20353
- ...link.foreignKeyOnTarget ? { foreignKeyOnTarget: link.foreignKeyOnTarget } : {}
20354
- };
20355
- break;
20356
- case "manyToMany":
20357
- result.relation = {
20358
- kind: "manyToMany",
20359
- ...common,
20360
- ...link.through ? { through: link.through } : {}
20361
- };
20362
- break;
20363
- case "via":
20364
- result.relation = {
20365
- kind: "via",
20366
- ...common,
20367
- cardinality: link.cardinality,
20368
- joinPath: link.joinPath
20369
- };
20370
- break;
20371
- default: throw new Error(`Unhandled relation kind: ${JSON.stringify(link)}`);
20372
- }
20373
- }
20374
- if (rl.fixedFilter) result.fixedFilter = rl.fixedFilter;
20375
- if (rl.includeId !== void 0) result.includeId = rl.includeId;
20376
- if (rl.includeEntityLink !== void 0) result.includeEntityLink = rl.includeEntityLink;
20377
- if (rl.widget) result.widget = rl.widget;
20504
+ if (link) result.relation = toSerializableRelation(link);
20378
20505
  return result;
20379
20506
  }
20380
20507
  case "array": {
@@ -20385,8 +20512,6 @@ function toSerializableProperty(property) {
20385
20512
  };
20386
20513
  if (ap.columnType) result.columnType = ap.columnType;
20387
20514
  if (ap.validation) result.validation = ap.validation;
20388
- if (ap.sortable !== void 0) result.sortable = ap.sortable;
20389
- if (ap.canAddElements !== void 0) result.canAddElements = ap.canAddElements;
20390
20515
  if (ap.of) if (Array.isArray(ap.of)) result.of = ap.of.map(toSerializableProperty);
20391
20516
  else result.of = toSerializableProperty(ap.of);
20392
20517
  if (ap.oneOf) {
@@ -20406,7 +20531,6 @@ function toSerializableProperty(property) {
20406
20531
  if (mp.columnType) result.columnType = mp.columnType;
20407
20532
  if (mp.validation) result.validation = mp.validation;
20408
20533
  if (mp.propertiesOrder) result.propertiesOrder = mp.propertiesOrder;
20409
- if (mp.previewProperties) result.previewProperties = mp.previewProperties;
20410
20534
  if (mp.keyValue) result.keyValue = mp.keyValue;
20411
20535
  if (mp.properties) result.properties = toSerializableProperties(mp.properties);
20412
20536
  return result;
@@ -20464,7 +20588,8 @@ function toSerializableCollectionConfig(collection) {
20464
20588
  if (collection.titleProperty) result.titleProperty = collection.titleProperty;
20465
20589
  if (collection.ownerId) result.ownerId = collection.ownerId;
20466
20590
  if (collection.metadata) result.metadata = collection.metadata;
20467
- if (collection.table) result.table = collection.table;
20591
+ if (isRelationalCollectionConfig(collection) && collection.table) result.table = collection.table;
20592
+ if (isRelationalCollectionConfig(collection) && collection.relations?.length) result.relations = collection.relations.map(toSerializableRelation);
20468
20593
  if ("schema" in collection && collection.schema) result.schema = collection.schema;
20469
20594
  if (collection.orderProperty) result.orderProperty = collection.orderProperty;
20470
20595
  if (typeof collection.icon === "string") result.icon = collection.icon;
@@ -20474,6 +20599,8 @@ function toSerializableCollectionConfig(collection) {
20474
20599
  if (collection.enabledViews) result.enabledViews = collection.enabledViews;
20475
20600
  if (collection.disableDefaultActions) result.disableDefaultActions = collection.disableDefaultActions;
20476
20601
  if (collection.securityRules) result.securityRules = collection.securityRules;
20602
+ if (isRelationalCollectionConfig(collection) && collection.disableDefaultPolicies !== void 0) result.disableDefaultPolicies = collection.disableDefaultPolicies;
20603
+ if (collection.strictWrites !== void 0) result.strictWrites = collection.strictWrites;
20477
20604
  if (collection.openEntityMode) result.openEntityMode = collection.openEntityMode;
20478
20605
  if (collection.defaultEntityAction) result.defaultEntityAction = collection.defaultEntityAction;
20479
20606
  if (collection.defaultViewMode) result.defaultViewMode = collection.defaultViewMode;
@@ -20971,6 +21098,6 @@ function getFullIdPath(propertyKey, propertyNamespace) {
20971
21098
  return idToPropertiesPath(propertyNamespace ? `${propertyNamespace}.${propertyKey}` : propertyKey);
20972
21099
  }
20973
21100
  //#endregion
20974
- export { useBuildCollectionRegistryController as $, StorageThumbnailInternal as $n, CollectionTableBinding as $t, getFieldId as A, ArrayOfReferencesPreview as An, convertFileToJson as At, MapFieldBinding as B, getBracketNotation as Bn, getCollectionBySlugWithin as Bt, removeEmptyContainers as C, MapPropertyPreview as Cn, convertDataToEntity as Ct, getDefaultFieldConfig as D, ArrayEnumPreview as Dn, useImportConfig as Dt, DEFAULT_FIELD_CONFIGS as E, ArrayPropertyEnumPreview as En, getInferenceType as Et, SelectFieldBinding as F, CollectionRegistryContext as Fn, FieldCaption as Ft, useSelectionDialog as G, getPropertyInPath as Gn, removeTrailingSlash$1 as Gt, DateTimeFieldBinding as H, getIconForProperty as Hn, getLastSegment$1 as Ht, RepeatFieldBinding as I, useCollectionRegistryController as In, useBreadcrumbsController as It, useBuildUrlController as J, isRelationProperty as Jn, resolveViewMode as Jt, SelectionTableBinding as K, getResolvedPropertyInPath as Kn, resolveCollectionPathIds$1 as Kt, ReferenceFieldBinding as L, getEntityPreviewKeys as Ln, BreadcrumbsProvider as Lt, TextFieldBinding as M, EntityPreviewBinding as Mn, ArrayContainer as Mt, SwitchFieldBinding as N, SidePanelControllerContext as Nn, PropertyConfigBadge as Nt, getDefaultFieldId as O, ArrayOfStorageComponentsPreview as On, ImportSaveInProgress as Ot, StorageUploadFieldBinding as P, useSidePanel as Pn, SearchIconsView as Pt, useResolvedCollections as Q, StorageThumbnail as Qn, VirtualTableInput$1 as Qt, MultiSelectFieldBinding as R, getEntityTitlePropertyKey as Rn, mergeEntityActions as Rt, getInitialEntityValues as S, KeyValuePreview as Sn, DataNewPropertiesMapping as St, PropertyFieldBinding as T, ArrayOfStringsPreview as Tn, processValueMapping as Tt, BlockFieldBinding as U, getIconForWidget as Un, removeInitialAndTrailingSlashes$1 as Ut, KeyValueFieldBinding as V, getDefaultPropertiesOrder as Vn, getCollectionPathsCombinations as Vt, ArrayOfReferencesFieldBinding as W, getPropertiesWithPropertiesOrder as Wn, removeInitialSlash as Wt, useTopLevelNavigation as X, StringPropertyPreview as Xn, resolveEntityView as Xt, useBuildNavigationStateController as Y, ArrayPropertyPreview as Yn, resolveEntityAction as Yt, useResolvedViews as Z, EnumValuesChip as Zn, useSelectionController as Zt, useCollectionsConfigController as _, getUserLabel as _n, CollectionViewActions as _t, namespaceToPropertiesPath as a, NavigationStateContext as an, UrlComponentPreview as ar, useBuildSidePanel as at, extractTouchedValues as b, BooleanPreview as bn, useCollectionEditorDialogsState as bt, buildCollectionGenerationCallback as c, SideDialogsControllerContext as cn, EmptyValue as cr, copyEntityAction as ct, fromSerializableCollectionConfigs as d, useClearRestoreValue as dn, LabelWithIcon as dr, resetPasswordAction as dt, SelectableTable as en, SkeletonPropertyComponent as er, useHistory as et, fromSerializableProperties as f, ReadOnlyFieldBinding as fn, FormLayout as fr, CreationResultDialog as ft, toSerializableProperty as g, UserPreview as gn, EntityCardBinding as gt, toSerializableProperties as h, PropertyPreview as hn, CollectionCardViewBinding as ht, namespaceToPropertiesOrderPath as i, useUrlController as in, renderSkeletonText as ir, getEntityViewWidth as it, VectorFieldBinding as j, ReferencePreview as jn, unflattenObject as jt, getFieldConfig as k, RelationPreview as kn, ImportFileUpload as kt, validateCollectionJson as l, SelectableTableContext as ln, LabelWithIconAndTooltip as lr, deleteEntityAction as lt, toSerializableCollectionConfig as m, ArrayOfMapsPreview as mn, EntityViewBinding as mt, getFullIdPath as n, useCMSContext as nn, renderSkeletonIcon as nr, useResolvedNavigationFrom as nt, CollectionGenerationApiError as o, useNavigationStateController as on, ImagePreview as or, EditViewBinding as ot, fromSerializableProperty as p, FieldHelperText as pn, FormEntry as pr, DetailViewBinding as pt, SideDialogs as q, isReferenceProperty as qn, resolveOpenEntityMode as qt, idToPropertiesPath as r, UrlContext as rn, renderSkeletonImageThumbnail as rr, buildSidePanelsFromUrl as rt, DEFAULT_COLLECTION_GENERATION_ENDPOINT as s, useSideDialogsController as sn, sanitizeUrl as sr, CollectionViewBinding as st, getFullId as t, CollectionRowActions as tn, renderSkeletonCaptionText as tr, resolveNavigationFrom as tt, fromSerializableCollectionConfig as u, ArrayCustomShapedFieldBinding as un, PropertyIdCopyTooltip as ur, editEntityAction as ut, EntityFormBinding as v, useResolvedUser as vn, useCollectionEditorController as vt, zodToFormErrors as w, ArrayOneOfPreview as wn, flattenEntry as wt, getChanges as x, DatePreview as xn, ImportNewPropertyFieldPreview as xt, EntityForm as y, NumberPropertyPreview as yn, ConfigControllerProvider as yt, MarkdownEditorFieldBinding as z, getEntityTitlePropertyKeyForEntity as zn, addInitialSlash as zt };
21101
+ export { useBuildCollectionRegistryController as $, StorageThumbnailInternal as $n, CollectionTableBinding as $t, getFieldId as A, ArrayOfReferencesPreview as An, convertFileToJson as At, MapFieldBinding as B, getBracketNotation as Bn, getCollectionBySlugWithin as Bt, removeEmptyContainers as C, MapPropertyPreview as Cn, convertDataToEntity as Ct, getDefaultFieldConfig as D, ArrayEnumPreview as Dn, useImportConfig as Dt, DEFAULT_FIELD_CONFIGS as E, ArrayPropertyEnumPreview as En, getInferenceType as Et, SelectFieldBinding as F, CollectionRegistryContext as Fn, FieldCaption as Ft, useSelectionDialog as G, getPropertyInPath as Gn, removeTrailingSlash$1 as Gt, DateTimeFieldBinding as H, getIconForProperty as Hn, getLastSegment$1 as Ht, RepeatFieldBinding as I, useCollectionRegistryController as In, useBreadcrumbsController as It, useBuildUrlController as J, isRelationProperty as Jn, resolveViewMode as Jt, SelectionTableBinding as K, getResolvedPropertyInPath as Kn, resolveCollectionPathIds$1 as Kt, ReferenceFieldBinding as L, getEntityPreviewKeys as Ln, BreadcrumbsProvider as Lt, TextFieldBinding as M, EntityPreviewBinding as Mn, ArrayContainer as Mt, SwitchFieldBinding as N, SidePanelControllerContext as Nn, PropertyConfigBadge as Nt, getDefaultFieldId as O, ArrayOfStorageComponentsPreview as On, ImportSaveInProgress as Ot, StorageUploadFieldBinding as P, useSidePanel as Pn, SearchIconsView as Pt, useResolvedCollections as Q, StorageThumbnail as Qn, VirtualTableInput$1 as Qt, MultiSelectFieldBinding as R, getEntityTitlePropertyKey as Rn, mergeEntityActions as Rt, getInitialEntityValues as S, KeyValuePreview as Sn, DataNewPropertiesMapping as St, PropertyFieldBinding as T, ArrayOfStringsPreview as Tn, processValueMapping as Tt, BlockFieldBinding as U, getIconForWidget as Un, removeInitialAndTrailingSlashes$1 as Ut, KeyValueFieldBinding as V, getDefaultPropertiesOrder as Vn, getCollectionPathsCombinations as Vt, ArrayOfReferencesFieldBinding as W, getPropertiesWithPropertiesOrder as Wn, removeInitialSlash as Wt, useTopLevelNavigation as X, StringPropertyPreview as Xn, resolveEntityView as Xt, useBuildNavigationStateController as Y, ArrayPropertyPreview as Yn, resolveEntityAction as Yt, useResolvedViews as Z, EnumValuesChip as Zn, useSelectionController as Zt, useCollectionsConfigController as _, getUserLabel as _n, CollectionViewActions as _t, namespaceToPropertiesPath as a, NavigationStateContext as an, UrlComponentPreview as ar, useBuildSidePanel as at, extractTouchedValues as b, BooleanPreview as bn, useCollectionEditorDialogsState as bt, buildCollectionGenerationCallback as c, SideDialogsControllerContext as cn, EmptyValue as cr, copyEntityAction as ct, fromSerializableCollectionConfigs as d, useClearRestoreValue as dn, LabelWithIcon as dr, resetPasswordAction as dt, SelectableTable as en, SkeletonPropertyComponent as er, useHistory as et, fromSerializableProperties as f, ReadOnlyFieldBinding as fn, FormLayout as fr, CreationResultDialog as ft, toSerializableProperty as g, UserPreview as gn, EntityCardBinding as gt, toSerializableProperties as h, PropertyPreview as hn, CollectionCardViewBinding as ht, namespaceToPropertiesOrderPath as i, useUrlController as in, renderSkeletonText as ir, getEntityViewWidth as it, VectorFieldBinding as j, ReferencePreview as jn, unflattenObject as jt, getFieldConfig as k, RelationPreview as kn, ImportFileUpload as kt, validateCollectionJson as l, SelectableTableContext as ln, LabelWithIconAndTooltip as lr, deleteEntityAction as lt, toSerializableCollectionConfig as m, ArrayOfMapsPreview as mn, EntityViewBinding as mt, getFullIdPath as n, useAdminContext as nn, renderSkeletonIcon as nr, useResolvedNavigationFrom as nt, CollectionGenerationApiError as o, useNavigationStateController as on, ImagePreview as or, EditViewBinding as ot, fromSerializableProperty as p, FieldHelperText as pn, FormEntry as pr, DetailViewBinding as pt, SideDialogs as q, isReferenceProperty as qn, resolveOpenEntityMode as qt, idToPropertiesPath as r, UrlContext as rn, renderSkeletonImageThumbnail as rr, buildSidePanelsFromUrl as rt, DEFAULT_COLLECTION_GENERATION_ENDPOINT as s, useSideDialogsController as sn, sanitizeUrl as sr, CollectionViewBinding as st, getFullId as t, CollectionRowActions as tn, renderSkeletonCaptionText as tr, resolveNavigationFrom as tt, fromSerializableCollectionConfig as u, ArrayCustomShapedFieldBinding as un, PropertyIdCopyTooltip as ur, editEntityAction as ut, EntityFormBinding as v, useResolvedUser as vn, useCollectionEditorController as vt, zodToFormErrors as w, ArrayOneOfPreview as wn, flattenEntry as wt, getChanges as x, DatePreview as xn, ImportNewPropertyFieldPreview as xt, EntityForm as y, NumberPropertyPreview as yn, ConfigControllerProvider as yt, MarkdownEditorFieldBinding as z, getEntityTitlePropertyKeyForEntity as zn, addInitialSlash as zt };
20975
21102
 
20976
- //# sourceMappingURL=util-BhhfHY1M.js.map
21103
+ //# sourceMappingURL=util-B5fJm1FA.js.map