@rebasepro/admin 0.11.1-canary.gfd39654 → 0.12.1-canary.g009ed95

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 (240) hide show
  1. package/README.md +2 -2
  2. package/dist/{CollectionEditorDialog-o7F_zbGY.js → CollectionEditorDialog-B-iVE9y3.js} +126 -317
  3. package/dist/CollectionEditorDialog-B-iVE9y3.js.map +1 -0
  4. package/dist/{PropertyEditView-DgB2b22q.js → PropertyEditView-DoLEH_bQ.js} +36 -16
  5. package/dist/{PropertyEditView-DgB2b22q.js.map → PropertyEditView-DoLEH_bQ.js.map} +1 -1
  6. package/dist/{RouterCollectionsStudioView-DaLRgPkj.js → RouterCollectionsStudioView-C3669Ezm.js} +5 -5
  7. package/dist/{RouterCollectionsStudioView-DaLRgPkj.js.map → RouterCollectionsStudioView-C3669Ezm.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 +44 -13
  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/collection_editor/CollectionRelationsTab.d.ts +1 -0
  15. package/dist/collection_editor/useLocalCollectionsConfigController.d.ts +8 -0
  16. package/dist/collection_editor_ui.js +5 -5
  17. package/dist/collection_editor_ui.js.map +1 -1
  18. package/dist/components/CollectionEditorDialogs.d.ts +2 -2
  19. package/dist/components/CollectionTableBinding/column_utils.d.ts +7 -1
  20. package/dist/components/CollectionViewBinding/CollectionListViewBinding.d.ts +2 -2
  21. package/dist/components/CollectionViewBinding/SplitListCloseButton.d.ts +10 -0
  22. package/dist/components/CollectionViewBinding/SplitViewContext.d.ts +23 -0
  23. package/dist/components/CollectionViewBinding/hooks/useKanbanDragAndDrop.d.ts +26 -0
  24. package/dist/components/DefaultDrawer.d.ts +3 -3
  25. package/dist/components/DetailViewBinding.d.ts +5 -0
  26. package/dist/components/DrawerNavigationGroup.d.ts +8 -1
  27. package/dist/components/DrawerNavigationItem.d.ts +7 -1
  28. package/dist/components/EditFormActions.d.ts +12 -1
  29. package/dist/components/EditViewBinding.d.ts +7 -2
  30. package/dist/components/EntityIdentityBar.d.ts +53 -0
  31. package/dist/components/EntityInspector.d.ts +29 -0
  32. package/dist/components/EntityPreviewNesting.d.ts +25 -0
  33. package/dist/components/EntityViewBinding.d.ts +9 -0
  34. package/dist/components/InlineEntityPreview.d.ts +47 -0
  35. package/dist/components/RebaseAdmin.d.ts +1 -1
  36. package/dist/components/RebaseAuthGate.d.ts +1 -1
  37. package/dist/components/RebaseLayout.d.ts +5 -1
  38. package/dist/components/RebaseNavigation.d.ts +2 -2
  39. package/dist/components/RebaseRouteDefs.d.ts +1 -1
  40. package/dist/components/RebaseShell.d.ts +6 -1
  41. package/dist/components/RelationSelector.d.ts +14 -0
  42. package/dist/components/SelectableTable/filters/RelationFilterField.d.ts +27 -0
  43. package/dist/components/SelectableTable/filters/null_filter.d.ts +46 -0
  44. package/dist/components/SidePanelProvider.d.ts +2 -2
  45. package/dist/components/app/Scaffold.d.ts +11 -0
  46. package/dist/components/field_configs.d.ts +1 -1
  47. package/dist/components/index.d.ts +2 -0
  48. package/dist/editor.js +18 -10
  49. package/dist/editor.js.map +1 -1
  50. package/dist/{export-BvqhjdEb.js → export-B8DIn-u8.js} +3 -3
  51. package/dist/export-B8DIn-u8.js.map +1 -0
  52. package/dist/form/EntityForm.d.ts +3 -3
  53. package/dist/form/EntityFormActions.d.ts +11 -1
  54. package/dist/form/EntityFormBinding.d.ts +5 -5
  55. package/dist/form/PropertyFieldBinding.d.ts +1 -1
  56. package/dist/form/components/FieldBlock.d.ts +30 -0
  57. package/dist/form/components/FormRail.d.ts +18 -0
  58. package/dist/form/components/FormSections.d.ts +16 -0
  59. package/dist/form/components/index.d.ts +3 -2
  60. package/dist/form/components/useRailVisible.d.ts +24 -0
  61. package/dist/form/field_bindings/BinaryFieldBinding.d.ts +1 -1
  62. package/dist/form/field_bindings/DateTimeFieldBinding.d.ts +1 -1
  63. package/dist/form/field_bindings/GeopointFieldBinding.d.ts +1 -1
  64. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +1 -1
  65. package/dist/form/field_bindings/MultiSelectFieldBinding.d.ts +1 -1
  66. package/dist/form/field_bindings/ReadOnlyFieldBinding.d.ts +1 -1
  67. package/dist/form/field_bindings/SelectFieldBinding.d.ts +1 -1
  68. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +1 -1
  69. package/dist/form/field_bindings/SwitchFieldBinding.d.ts +1 -1
  70. package/dist/form/field_bindings/TextFieldBinding.d.ts +1 -1
  71. package/dist/form/field_bindings/UserSelectFieldBinding.d.ts +1 -1
  72. package/dist/form/field_bindings/VectorFieldBinding.d.ts +1 -1
  73. package/dist/{history-Dz20hH38.js → history-ClwDEtqN.js} +32 -31
  74. package/dist/history-ClwDEtqN.js.map +1 -0
  75. package/dist/hooks/index.d.ts +1 -1
  76. package/dist/hooks/navigation/utils.d.ts +16 -0
  77. package/dist/hooks/useAdminContext.d.ts +29 -0
  78. package/dist/hooks/useBuildSidePanel.d.ts +14 -0
  79. package/dist/hooks/useEntityDisplayTitle.d.ts +18 -0
  80. package/dist/hooks/useHistory.d.ts +7 -11
  81. package/dist/hooks/useRecordActions.d.ts +17 -0
  82. package/dist/{import-DINSB-Vu.js → import-Cwzf4RW5.js} +2 -2
  83. package/dist/{import-DINSB-Vu.js.map → import-Cwzf4RW5.js.map} +1 -1
  84. package/dist/index.js +159 -65
  85. package/dist/index.js.map +1 -1
  86. package/dist/markdown-CklalUUk.js.map +1 -1
  87. package/dist/preview/components/InlineEntityListPreview.d.ts +15 -0
  88. package/dist/preview/index.d.ts +1 -0
  89. package/dist/preview/property_previews/ArrayOfReferencesPreview.d.ts +1 -1
  90. package/dist/preview/property_previews/ArrayOfRelationsPreview.d.ts +1 -1
  91. package/dist/types/components/EntityFormActionsProps.d.ts +0 -1
  92. package/dist/types/components/EntityFormProps.d.ts +1 -6
  93. package/dist/types/fields.d.ts +25 -1
  94. package/dist/{util-BhhfHY1M.js → util-DSh3HRzK.js} +2235 -1264
  95. package/dist/util-DSh3HRzK.js.map +1 -0
  96. package/package.json +32 -34
  97. package/src/collection_editor/CollectionEditorDialogsContext.tsx +1 -1
  98. package/src/collection_editor/ConfigControllerProvider.tsx +2 -2
  99. package/src/collection_editor/_cms_internals.ts +1 -1
  100. package/src/collection_editor/extensibility_types.ts +1 -1
  101. package/src/collection_editor/index.ts +2 -2
  102. package/src/collection_editor/serializable_types.ts +48 -16
  103. package/src/collection_editor/serializable_utils.ts +118 -75
  104. package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +66 -23
  105. package/src/collection_editor/ui/collection_editor/CollectionRLSTab.tsx +102 -69
  106. package/src/collection_editor/ui/collection_editor/CollectionRelationsTab.tsx +3 -1
  107. package/src/collection_editor/ui/collection_editor/EntityActionsEditTab.tsx +1 -1
  108. package/src/collection_editor/ui/collection_editor/GetCodeDialog.tsx +1 -1
  109. package/src/collection_editor/ui/collection_editor/RouterCollectionStudioView.tsx +1 -1
  110. package/src/collection_editor/ui/collection_editor/RouterCollectionsStudioView.tsx +1 -1
  111. package/src/collection_editor/ui/collection_editor/SubcollectionsEditTab.tsx +2 -2
  112. package/src/collection_editor/ui/collection_editor/properties/RelationPropertyField.tsx +16 -0
  113. package/src/collection_editor/useLocalCollectionsConfigController.tsx +127 -15
  114. package/src/collection_editor/validateCollectionJson.ts +3 -3
  115. package/src/components/AdminModeSyncer.tsx +1 -1
  116. package/src/components/CollectionEditorDialogs.tsx +2 -2
  117. package/src/components/CollectionTableBinding/CollectionRowActions.tsx +5 -4
  118. package/src/components/CollectionTableBinding/CollectionTableBinding.tsx +8 -2
  119. package/src/components/CollectionTableBinding/PropertyTableCell.tsx +10 -2
  120. package/src/components/CollectionTableBinding/column_utils.tsx +45 -7
  121. package/src/components/CollectionTableBinding/table_bindings.tsx +12 -11
  122. package/src/components/CollectionViewBinding/CollectionBoardViewBinding.tsx +23 -16
  123. package/src/components/CollectionViewBinding/CollectionListViewBinding.tsx +8 -7
  124. package/src/components/CollectionViewBinding/CollectionViewActions.tsx +9 -3
  125. package/src/components/CollectionViewBinding/CollectionViewBinding.tsx +10 -4
  126. package/src/components/CollectionViewBinding/CollectionViewStartActions.tsx +24 -13
  127. package/src/components/CollectionViewBinding/SplitListCloseButton.tsx +33 -0
  128. package/src/components/CollectionViewBinding/SplitListView.tsx +18 -3
  129. package/src/components/CollectionViewBinding/SplitViewContext.tsx +34 -0
  130. package/src/components/CollectionViewBinding/hooks/useKanbanDragAndDrop.ts +48 -9
  131. package/src/components/CollectionViewBinding/useBoardDataController.tsx +80 -25
  132. package/src/components/CollectionViewBinding/usePreviewSlots.ts +18 -6
  133. package/src/components/DefaultAppBar.tsx +1 -1
  134. package/src/components/DefaultDrawer.tsx +20 -9
  135. package/src/components/DeleteEntityDialog.tsx +2 -2
  136. package/src/components/DetailViewBinding.tsx +119 -142
  137. package/src/components/DrawerNavigationGroup.tsx +47 -4
  138. package/src/components/DrawerNavigationItem.tsx +20 -6
  139. package/src/components/EditFormActions.tsx +58 -132
  140. package/src/components/EditViewBinding.tsx +183 -94
  141. package/src/components/EntityIdentityBar.tsx +288 -0
  142. package/src/components/EntityInspector.tsx +132 -0
  143. package/src/components/EntityPreviewBinding.tsx +6 -2
  144. package/src/components/EntityPreviewNesting.tsx +50 -0
  145. package/src/components/EntityViewBinding.tsx +35 -32
  146. package/src/components/HomePage/ContentHomePage.tsx +4 -4
  147. package/src/components/HomePage/FavouritesView.tsx +1 -1
  148. package/src/components/HomePage/NavigationCardBinding.tsx +1 -1
  149. package/src/components/HomePage/SmallNavigationCard.tsx +1 -1
  150. package/src/components/InlineEntityPreview.tsx +149 -0
  151. package/src/components/RebaseAdmin.tsx +3 -3
  152. package/src/components/RebaseAuthGate.tsx +1 -1
  153. package/src/components/RebaseLayout.tsx +9 -3
  154. package/src/components/RebaseNavigation.tsx +54 -14
  155. package/src/components/RebaseRouteDefs.tsx +3 -3
  156. package/src/components/RebaseShell.tsx +10 -1
  157. package/src/components/RelationSelector.tsx +18 -3
  158. package/src/components/SelectableTable/SelectableTable.tsx +2 -2
  159. package/src/components/SelectableTable/filters/FilterFieldBinding.tsx +1 -1
  160. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +36 -9
  161. package/src/components/SelectableTable/filters/RelationFilterField.tsx +93 -17
  162. package/src/components/SelectableTable/filters/null_filter.ts +63 -0
  163. package/src/components/SidePanelBinding.tsx +19 -13
  164. package/src/components/SidePanelProvider.tsx +2 -2
  165. package/src/components/UserSelector.tsx +12 -6
  166. package/src/components/app/Scaffold.tsx +16 -1
  167. package/src/components/common/default_entity_actions.tsx +4 -3
  168. package/src/components/history/EntityHistoryEntry.tsx +28 -7
  169. package/src/components/history/EntityHistoryView.tsx +20 -20
  170. package/src/components/history/LastEditedByIndicator.tsx +4 -3
  171. package/src/components/index.ts +2 -0
  172. package/src/data_export/export/ExportCollectionAction.tsx +2 -2
  173. package/src/data_import/utils/get_import_inference_type.ts +6 -0
  174. package/src/form/EntityForm.tsx +269 -181
  175. package/src/form/EntityFormActions.tsx +52 -100
  176. package/src/form/EntityFormBinding.tsx +11 -9
  177. package/src/form/PropertyFieldBinding.tsx +4 -0
  178. package/src/form/components/FieldBlock.tsx +119 -0
  179. package/src/form/components/FormRail.tsx +125 -0
  180. package/src/form/components/FormSections.tsx +118 -0
  181. package/src/form/components/index.tsx +3 -2
  182. package/src/form/components/useRailVisible.tsx +46 -0
  183. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +3 -3
  184. package/src/form/field_bindings/BinaryFieldBinding.tsx +3 -2
  185. package/src/form/field_bindings/DateTimeFieldBinding.tsx +3 -2
  186. package/src/form/field_bindings/GeopointFieldBinding.tsx +3 -2
  187. package/src/form/field_bindings/MapFieldBinding.tsx +1 -2
  188. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +3 -2
  189. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +2 -1
  190. package/src/form/field_bindings/MultipleRelationFieldBinding.tsx +16 -5
  191. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +2 -1
  192. package/src/form/field_bindings/ReferenceFieldBinding.tsx +5 -4
  193. package/src/form/field_bindings/RelationFieldBinding.tsx +23 -10
  194. package/src/form/field_bindings/RepeatFieldBinding.tsx +6 -3
  195. package/src/form/field_bindings/SelectFieldBinding.tsx +3 -2
  196. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +31 -8
  197. package/src/form/field_bindings/SwitchFieldBinding.tsx +7 -3
  198. package/src/form/field_bindings/TextFieldBinding.tsx +18 -16
  199. package/src/form/field_bindings/UserSelectFieldBinding.tsx +3 -2
  200. package/src/form/field_bindings/VectorFieldBinding.tsx +2 -1
  201. package/src/hooks/index.ts +1 -1
  202. package/src/hooks/navigation/useBuildUrlController.tsx +1 -1
  203. package/src/hooks/navigation/useNavigationResolution.ts +10 -4
  204. package/src/hooks/navigation/useTopLevelNavigation.ts +18 -7
  205. package/src/hooks/navigation/utils.ts +20 -0
  206. package/src/hooks/{useCMSContext.tsx → useAdminContext.tsx} +10 -10
  207. package/src/hooks/useBuildSideDialogsController.tsx +2 -2
  208. package/src/hooks/useBuildSidePanel.tsx +22 -61
  209. package/src/hooks/useEntityDisplayTitle.tsx +60 -0
  210. package/src/hooks/useHistory.ts +14 -17
  211. package/src/hooks/useRecordActions.tsx +69 -0
  212. package/src/hooks/useResolvedNavigationFrom.tsx +2 -2
  213. package/src/hooks/useResolvedUsers.ts +10 -5
  214. package/src/index.ts +4 -4
  215. package/src/preview/PropertyPreview.tsx +52 -26
  216. package/src/preview/components/InlineEntityListPreview.tsx +42 -0
  217. package/src/preview/components/ReferencePreview.tsx +34 -14
  218. package/src/preview/components/RelationPreview.tsx +35 -15
  219. package/src/preview/index.ts +1 -0
  220. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
  221. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +26 -3
  222. package/src/preview/property_previews/ArrayOfRelationsPreview.tsx +27 -3
  223. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +2 -2
  224. package/src/routes/RebaseRoute.tsx +2 -2
  225. package/src/types/components/EntityFormActionsProps.tsx +0 -1
  226. package/src/types/components/EntityFormProps.tsx +2 -8
  227. package/src/types/fields.tsx +28 -1
  228. package/dist/CollectionEditorDialog-o7F_zbGY.js.map +0 -1
  229. package/dist/collection_editor/pgColumnToProperty.d.ts +0 -7
  230. package/dist/editor/extensions/Image/index.d.ts +0 -6
  231. package/dist/export-BvqhjdEb.js.map +0 -1
  232. package/dist/form/components/FormEntry.d.ts +0 -6
  233. package/dist/form/components/FormLayout.d.ts +0 -5
  234. package/dist/history-Dz20hH38.js.map +0 -1
  235. package/dist/hooks/useCMSContext.d.ts +0 -29
  236. package/dist/util-BhhfHY1M.js.map +0 -1
  237. package/src/collection_editor/pgColumnToProperty.ts +0 -291
  238. package/src/editor/extensions/Image/index.ts +0 -133
  239. package/src/form/components/FormEntry.tsx +0 -22
  240. package/src/form/components/FormLayout.tsx +0 -16
package/README.md CHANGED
@@ -8,7 +8,7 @@ CMS frontend — content management views, forms, routing, visual schema editor,
8
8
  pnpm add @rebasepro/admin
9
9
  ```
10
10
 
11
- **Peer dependencies:** `react >= 19`, `react-dom >= 19`, `react-router ^7`, `react-router-dom ^7`
11
+ **Peer dependencies:** `react >= 19.2.7`, `react-dom >= 19.2.7`, `react-router ^8`
12
12
 
13
13
  ## What This Package Does
14
14
 
@@ -71,7 +71,7 @@ pnpm add @rebasepro/admin
71
71
  | `useSelectionController` | Row selection state for tables |
72
72
  | `useHistory` | Snapshot change history and version revert |
73
73
  | `useBreadcrumbsController` | Breadcrumb navigation state |
74
- | `useCMSContext` | Access the CMS-level context |
74
+ | `useAdminContext` | Access the admin-level context |
75
75
  | `useResolvedNavigationFrom` | Resolve navigation tree from collection configs |
76
76
 
77
77
  ### Data Import/Export
@@ -1,14 +1,14 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { $t as CollectionTableBinding, A as getFieldId, Ct as convertDataToEntity, Dt as useImportConfig, Et as getInferenceType, Ft as FieldCaption, In as useCollectionRegistryController, Nt as PropertyConfigBadge, Ot as ImportSaveInProgress, Pt as SearchIconsView, St as DataNewPropertiesMapping, Zt as useSelectionController, _ as useCollectionsConfigController, i as namespaceToPropertiesOrderPath, in as useUrlController, k as getFieldConfig, kt as ImportFileUpload, l as validateCollectionJson, m as toSerializableCollectionConfig, n as getFullIdPath, o as CollectionGenerationApiError, on as useNavigationStateController, r as idToPropertiesPath, t as getFullId, vt as useCollectionEditorController, xt as ImportNewPropertyFieldPreview } from "./util-BhhfHY1M.js";
3
- import { a as updatePropertyFromWidget, c as useAIModifiedPaths, i as supportedFields, l as useSafeSnackbarController, n as PropertyForm, o as PropertyTree, r as PropertyFormDialog, s as AIModifiedPathsProvider } from "./PropertyEditView-DgB2b22q.js";
2
+ import { $t as CollectionTableBinding, A as getFieldId, Ct as convertDataToEntity, Dt as useImportConfig, Et as getInferenceType, Ft as FieldCaption, Ln as useCollectionRegistryController, Nt as PropertyConfigBadge, Ot as ImportSaveInProgress, Pt as SearchIconsView, St as DataNewPropertiesMapping, Zt as useSelectionController, _ as useCollectionsConfigController, i as namespaceToPropertiesOrderPath, in as useUrlController, k as getFieldConfig, kt as ImportFileUpload, l as validateCollectionJson, m as toSerializableCollectionConfig, n as getFullIdPath, o as CollectionGenerationApiError, on as useNavigationStateController, r as idToPropertiesPath, t as getFullId, vt as useCollectionEditorController, xt as ImportNewPropertyFieldPreview } from "./util-DSh3HRzK.js";
3
+ import { a as updatePropertyFromWidget, c as useAIModifiedPaths, i as supportedFields, l as useSafeSnackbarController, n as PropertyForm, o as PropertyTree, r as PropertyFormDialog, s as AIModifiedPathsProvider } from "./PropertyEditView-DoLEH_bQ.js";
4
4
  import * as React$1 from "react";
5
5
  import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
6
6
  import { Alert, AppWindow, ArrowLeftIcon, BooleanSwitchWithLabel, Button, Card, CheckIcon, Chip, CircularProgress, CircularProgressCenter, CodeIcon, ColumnsIcon, Container, CopyIcon, DebouncedTextField, Dialog, DialogActions, DialogContent, DialogTitle, ErrorBoundary, FileIcon, FileSearchIcon, FileTextIcon, IconButton, KanbanIcon, KeyIcon, LayoutGridIcon, ListIcon, LoadingButton, Menu, MultiSelect, MultiSelectItem, PanelLeftIcon, Paper, PlusIcon, Select, SelectItem, ShoppingCartIcon, SquareIcon, Tab, TableIcon, Tabs, TextField, ToggleButtonGroup, Tooltip, Trash2Icon, Typography, UserIcon, XIcon, cls, coolIconKeys, defaultBorderMixin, iconSize } from "@rebasepro/ui";
7
- import { getEffectiveSecurityRules, getSubcollections, getTableName, isPropertyBuilder } from "@rebasepro/common";
7
+ import { buildCollectionFromTableMetadata, getGeneratedPolicyNames, getSubcollections, getTableName, isPropertyBuilder } from "@rebasepro/common";
8
8
  import { AIIcon, ConfirmationDialog, ErrorView, IconForView, UnsavedChangesDialog, removeInitialAndTrailingSlashes, useAuthController, useCustomizationController, useLargeLayout, useRebaseContext, useUnsavedChangesDialog } from "@rebasepro/app";
9
9
  import { Field, Formex, clone, getIn, useCreateFormex, useFormex } from "@rebasepro/forms";
10
10
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
11
- import { camelCase, getPolicyNamesForRule, getPolicyNamesForRules, isEmptyObject, mergeDeep, prettifyIdentifier, randomString, removeUndefined, singular, slugify, toSnakeCase, unslugify } from "@rebasepro/utils";
11
+ import { camelCase, getPolicyNamesForRule, isEmptyObject, mergeDeep, prettifyIdentifier, randomString, removeUndefined, singular, slugify, toSnakeCase, unslugify } from "@rebasepro/utils";
12
12
  import { getDataSourceCapabilities } from "@rebasepro/types";
13
13
  import { z } from "zod";
14
14
  import { buildEntityPropertiesFromData, buildPropertyFromData } from "@rebasepro/inference";
@@ -696,7 +696,7 @@ function GetCodeDialog({ collection, onOpenChange, open }) {
696
696
  variant: "body2",
697
697
  className: "my-4 mb-8",
698
698
  children: [
699
- "If you want to customise the collection in code, you can add this collection code to your CMS app configuration. More info in the ",
699
+ "If you want to customise the collection in code, you can add this collection code to your admin app configuration. More info in the ",
700
700
  /* @__PURE__ */ jsx("a", {
701
701
  rel: "noopener noreferrer",
702
702
  href: "https://rebase.pro/docs/cloud/quickstart",
@@ -875,7 +875,8 @@ function CollectionPropertiesEditorForm({ showErrors, isNewCollection, propertyE
875
875
  return currentPropertiesOrderRef.current[namespace] ?? getIn(values, namespaceToPropertiesOrderPath(namespace));
876
876
  };
877
877
  const updatePropertiesOrder = (newPropertiesOrder, namespace) => {
878
- setFieldValue(namespaceToPropertiesOrderPath(namespace), newPropertiesOrder, false);
878
+ const propertiesOrderPath = namespaceToPropertiesOrderPath(namespace);
879
+ setFieldValue(propertiesOrderPath, newPropertiesOrder, false);
879
880
  currentPropertiesOrderRef.current[namespace ?? ""] = newPropertiesOrder;
880
881
  };
881
882
  const deleteProperty = (propertyKey, namespace) => {
@@ -884,7 +885,10 @@ function CollectionPropertiesEditorForm({ showErrors, isNewCollection, propertyE
884
885
  if (!fullId) throw Error("collection editor miss config");
885
886
  setFieldValue(idToPropertiesPath(fullId), void 0, false);
886
887
  const currentPropertiesOrder = getCurrentPropertiesOrder(namespace);
887
- if (currentPropertiesOrder) updatePropertiesOrder(currentPropertiesOrder.filter((p) => p !== propertyKey), namespace);
888
+ if (currentPropertiesOrder) {
889
+ const newPropertiesOrder = currentPropertiesOrder.filter((p) => p !== propertyKey);
890
+ updatePropertiesOrder(newPropertiesOrder, namespace);
891
+ }
888
892
  setNewPropertyDialogOpen(false);
889
893
  setSelectedPropertyIndex(void 0);
890
894
  setSelectedPropertyKey(void 0);
@@ -1177,7 +1181,8 @@ function CollectionJsonImportDialog({ open, onClose, onImport }) {
1177
1181
  setErrors([]);
1178
1182
  return;
1179
1183
  }
1180
- setErrors(validateCollectionJson(value).errors);
1184
+ const result = validateCollectionJson(value);
1185
+ setErrors(result.errors);
1181
1186
  }, []);
1182
1187
  const handleImport = useCallback(() => {
1183
1188
  const result = validateCollectionJson(jsonValue);
@@ -2077,7 +2082,8 @@ function CollectionEditorImportMapping({ importConfig, propertyConfigs }) {
2077
2082
  return currentPropertiesOrderRef.current[namespace] ?? getIn(values, namespaceToPropertiesOrderPath(namespace));
2078
2083
  };
2079
2084
  const updatePropertiesOrder = (newPropertiesOrder, namespace) => {
2080
- setFieldValue(namespaceToPropertiesOrderPath(namespace), newPropertiesOrder, false);
2085
+ const propertiesOrderPath = namespaceToPropertiesOrderPath(namespace);
2086
+ setFieldValue(propertiesOrderPath, newPropertiesOrder, false);
2081
2087
  currentPropertiesOrderRef.current[namespace ?? ""] = newPropertiesOrder;
2082
2088
  };
2083
2089
  if (previousId && previousId !== id) {
@@ -2329,9 +2335,58 @@ function sanitizeSqlIdentifier(name) {
2329
2335
  if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) throw new Error(`Invalid SQL identifier: "${name}". Only letters, digits, and underscores are allowed.`);
2330
2336
  return `"${name}"`;
2331
2337
  }
2338
+ /**
2339
+ * `pg_policies` reports the operation and the permissive flag in upper case;
2340
+ * `SecurityRule` names them in lower case. These two used to be `.toLowerCase()`
2341
+ * assigned straight into a `SecurityRule`, which typechecks only against a
2342
+ * `string` field — and this file declared its own local `SecurityRule` with
2343
+ * `operation?: string`, so it did. Against the real type it does not: an
2344
+ * unrecognised `cmd` would have been written into the collection as a policy
2345
+ * operation that compiles to nothing.
2346
+ */
2347
+ function toSecurityOperation(cmd) {
2348
+ switch (cmd) {
2349
+ case "SELECT": return "select";
2350
+ case "INSERT": return "insert";
2351
+ case "UPDATE": return "update";
2352
+ case "DELETE": return "delete";
2353
+ case "ALL": return "all";
2354
+ default: return;
2355
+ }
2356
+ }
2357
+ function toSecurityMode(permissive) {
2358
+ if (!permissive) return void 0;
2359
+ return permissive === "RESTRICTIVE" ? "restrictive" : "permissive";
2360
+ }
2361
+ /**
2362
+ * Build a {@link SecurityRule} from a `pg_policies` row.
2363
+ *
2364
+ * `SecurityRule` is a discriminated union and this is the part the local shadow
2365
+ * type flattened away: a raw-SQL rule *requires* `using`, so a policy with only
2366
+ * a `WITH CHECK` clause — every INSERT-only policy — is not one. It is a
2367
+ * roles-only rule carrying the check. Assembling the object field-by-field
2368
+ * against `operation?: string` accepted all of these and told the compiler
2369
+ * nothing.
2370
+ */
2371
+ function toSecurityRule(policy) {
2372
+ const base = {
2373
+ name: policy.policyname ?? "",
2374
+ operation: toSecurityOperation(policy.cmd),
2375
+ mode: toSecurityMode(policy.permissive),
2376
+ roles: policy.roles ? [...policy.roles] : void 0
2377
+ };
2378
+ if (policy.qual) return {
2379
+ ...base,
2380
+ using: policy.qual,
2381
+ withCheck: policy.with_check || void 0
2382
+ };
2383
+ return base;
2384
+ }
2332
2385
  function CollectionRLSTab() {
2333
2386
  const { values, setFieldValue } = useFormex();
2334
2387
  const [editingPolicy, setEditingPolicy] = useState(null);
2388
+ const { readOnly, readOnlyReason } = useCollectionsConfigController();
2389
+ const readOnlyTitle = readOnlyReason || "This backend does not accept collection edits.";
2335
2390
  const rules = values.securityRules || [];
2336
2391
  const { databaseAdmin } = useRebaseContext();
2337
2392
  const [dbPolicies, setDbPolicies] = useState([]);
@@ -2353,7 +2408,7 @@ function CollectionRLSTab() {
2353
2408
  if (Array.isArray(res)) return res;
2354
2409
  return [];
2355
2410
  };
2356
- setDbPolicies(extractRows(result).map((p) => {
2411
+ const policies = extractRows(result).map((p) => {
2357
2412
  let parsedRoles = [];
2358
2413
  const r = p.roles || p.ROLES;
2359
2414
  if (Array.isArray(r)) parsedRoles = r;
@@ -2367,7 +2422,8 @@ function CollectionRLSTab() {
2367
2422
  qual: p.qual || p.QUAL || null,
2368
2423
  with_check: p.with_check || p.WITH_CHECK || null
2369
2424
  };
2370
- }));
2425
+ });
2426
+ setDbPolicies(policies);
2371
2427
  } catch (e) {
2372
2428
  console.error("Failed to fetch DB policies", e);
2373
2429
  } finally {
@@ -2414,37 +2470,13 @@ function CollectionRLSTab() {
2414
2470
  };
2415
2471
  }, [databaseAdmin]);
2416
2472
  const tableName = values.id || values.table || values.alias;
2417
- /**
2418
- * Every policy name `rebase db push` would write for this collection.
2419
- *
2420
- * Two things make this more than `rules.map(r => r.name)`:
2421
- * - a rule without an explicit `name` becomes `<table>_<op>_<hash>`, so
2422
- * comparing `rule.name` to `policyname` never matches for it;
2423
- * - the generator also injects the safe-by-default baseline
2424
- * (`<table>_default_admin_*`), which is in no collection's `securityRules`.
2425
- *
2426
- * Missing either made Rebase's own policies look hand-written, and offered to
2427
- * import them back into the codebase that produced them.
2428
- */
2429
2473
  const generatedPolicyNames = useMemo(() => {
2430
2474
  if (!tableName) return /* @__PURE__ */ new Set();
2431
- const effectiveRules = getEffectiveSecurityRules(values);
2432
- return getPolicyNamesForRules([...rules, ...effectiveRules], tableName);
2433
- }, [
2434
- rules,
2435
- tableName,
2436
- values
2437
- ]);
2475
+ return getGeneratedPolicyNames(values);
2476
+ }, [tableName, values]);
2438
2477
  const unmappedPolicies = dbPolicies.filter((dp) => !generatedPolicyNames.has(dp.policyname));
2439
2478
  const handleSave = async (newPolicy) => {
2440
- const rule = {
2441
- name: newPolicy.policyname ?? "",
2442
- operation: newPolicy.cmd?.toLowerCase(),
2443
- mode: newPolicy.permissive?.toLowerCase(),
2444
- using: newPolicy.qual || void 0,
2445
- withCheck: newPolicy.with_check || void 0,
2446
- roles: newPolicy.roles
2447
- };
2479
+ const rule = toSecurityRule(newPolicy);
2448
2480
  let newRules;
2449
2481
  if (editingPolicy === "new") newRules = [...rules, rule];
2450
2482
  else newRules = rules.map((r) => r.name === editingPolicy.policyname ? rule : r);
@@ -2464,11 +2496,15 @@ function CollectionRLSTab() {
2464
2496
  children: [/* @__PURE__ */ jsx(Typography, {
2465
2497
  variant: "h5",
2466
2498
  children: "Row Level Security"
2467
- }), /* @__PURE__ */ jsx(Button, {
2468
- variant: "filled",
2469
- color: "neutral",
2470
- onClick: () => setEditingPolicy("new"),
2471
- children: "CREATE POLICY"
2499
+ }), /* @__PURE__ */ jsx(Tooltip, {
2500
+ title: readOnly ? readOnlyTitle : void 0,
2501
+ children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, {
2502
+ variant: "filled",
2503
+ color: "neutral",
2504
+ disabled: readOnly,
2505
+ onClick: () => setEditingPolicy("new"),
2506
+ children: "CREATE POLICY"
2507
+ }) })
2472
2508
  })]
2473
2509
  }),
2474
2510
  rules.length === 0 ? /* @__PURE__ */ jsx("div", {
@@ -2510,18 +2546,20 @@ function CollectionRLSTab() {
2510
2546
  children: [/* @__PURE__ */ jsx(Button, {
2511
2547
  size: "small",
2512
2548
  variant: "text",
2549
+ disabled: readOnly,
2513
2550
  onClick: () => setEditingPolicy({
2514
- policyname: rule.name,
2551
+ policyname: rule.name ?? "",
2515
2552
  tablename: values.id || values.table || values.alias || "your_table",
2516
2553
  permissive: (rule.mode || "permissive").toUpperCase(),
2517
2554
  cmd: (rule.operation || "ALL").toUpperCase(),
2518
- roles: rule.roles || [],
2555
+ roles: [...rule.roles ?? []],
2519
2556
  qual: rule.using || null,
2520
2557
  with_check: rule.withCheck || null
2521
2558
  }),
2522
2559
  children: "EDIT"
2523
2560
  }), /* @__PURE__ */ jsx(IconButton, {
2524
2561
  size: "small",
2562
+ disabled: readOnly,
2525
2563
  onClick: () => {
2526
2564
  setFieldValue("securityRules", rules.filter((r) => r.name !== rule.name));
2527
2565
  },
@@ -2590,22 +2628,19 @@ function CollectionRLSTab() {
2590
2628
  })]
2591
2629
  }), /* @__PURE__ */ jsx("div", {
2592
2630
  className: "flex items-center gap-1 sm:gap-2 shrink-0",
2593
- children: /* @__PURE__ */ jsx(Button, {
2594
- size: "small",
2595
- variant: "outlined",
2596
- color: "primary",
2597
- onClick: () => {
2598
- const rule = {
2599
- name: dp.policyname,
2600
- operation: dp.cmd?.toLowerCase(),
2601
- mode: dp.permissive?.toLowerCase(),
2602
- using: dp.qual || void 0,
2603
- withCheck: dp.with_check || void 0,
2604
- roles: dp.roles
2605
- };
2606
- setFieldValue("securityRules", [...rules, rule]);
2607
- },
2608
- children: "Import to codebase"
2631
+ children: /* @__PURE__ */ jsx(Tooltip, {
2632
+ title: readOnly ? readOnlyTitle : void 0,
2633
+ children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, {
2634
+ size: "small",
2635
+ variant: "outlined",
2636
+ color: "primary",
2637
+ disabled: readOnly,
2638
+ onClick: () => {
2639
+ const rule = toSecurityRule(dp);
2640
+ setFieldValue("securityRules", [...rules, rule]);
2641
+ },
2642
+ children: "Import to codebase"
2643
+ }) })
2609
2644
  })
2610
2645
  })]
2611
2646
  }, dp.policyname))
@@ -2651,7 +2686,7 @@ function InlinePolicyEditor({ policy, table, availableRoles, rolesUnavailable, o
2651
2686
  * from what users hold, so a role that is referenced here but assigned to
2652
2687
  * nobody would otherwise vanish from its own policy on the next save.
2653
2688
  */
2654
- const roleOptions = useMemo(() => Array.from(new Set([...availableRoles, ...roles])).sort(), [availableRoles, roles]);
2689
+ const roleOptions = useMemo(() => Array.from(/* @__PURE__ */ new Set([...availableRoles, ...roles])).sort(), [availableRoles, roles]);
2655
2690
  const addCustomRole = () => {
2656
2691
  const trimmed = customRole.trim();
2657
2692
  if (!trimmed || roles.includes(trimmed)) {
@@ -2843,243 +2878,6 @@ function InlinePolicyEditor({ policy, table, availableRoles, rolesUnavailable, o
2843
2878
  ] });
2844
2879
  }
2845
2880
  //#endregion
2846
- //#region src/collection_editor/pgColumnToProperty.ts
2847
- /**
2848
- * Maps a PostgreSQL column data type to a Rebase property type.
2849
- */
2850
- function pgTypeToRebaseProperty(column) {
2851
- const { column_name, data_type, udt_name, is_nullable, column_default, enum_values } = column;
2852
- const required = is_nullable === "NO";
2853
- const prettifiedName = prettifyIdentifier(column_name);
2854
- const isAutoId = column_default != null && (column_default.includes("nextval") || column_default.includes("gen_random_uuid") || column_default.includes("uuid_generate") || column_default.includes("identity"));
2855
- if (data_type === "USER-DEFINED" && enum_values && enum_values.length > 0) return {
2856
- type: "string",
2857
- name: prettifiedName,
2858
- enum: enum_values.map((v) => ({
2859
- id: v,
2860
- label: prettifyIdentifier(v)
2861
- })),
2862
- validation: required ? { required: true } : void 0
2863
- };
2864
- const dt = data_type.toLowerCase();
2865
- switch (dt) {
2866
- case "character varying":
2867
- case "varchar":
2868
- case "text":
2869
- case "char":
2870
- case "character":
2871
- case "citext": {
2872
- let colType = "varchar";
2873
- if (dt === "text" || dt === "citext") colType = "text";
2874
- if (dt === "char" || dt === "character") colType = "char";
2875
- const prop = {
2876
- type: "string",
2877
- name: prettifiedName,
2878
- columnType: colType,
2879
- validation: required ? { required: true } : void 0
2880
- };
2881
- if (isAutoId) prop.isId = "manual";
2882
- return prop;
2883
- }
2884
- case "uuid": {
2885
- const prop = {
2886
- type: "string",
2887
- name: prettifiedName,
2888
- validation: required ? { required: true } : void 0
2889
- };
2890
- if (isAutoId) prop.isId = "uuid";
2891
- return prop;
2892
- }
2893
- case "integer":
2894
- case "bigint":
2895
- case "smallint": {
2896
- const prop = {
2897
- type: "number",
2898
- name: prettifiedName,
2899
- columnType: dt === "bigint" ? "bigint" : "integer",
2900
- validation: {
2901
- ...required ? { required: true } : {},
2902
- integer: true
2903
- }
2904
- };
2905
- if (isAutoId) prop.isId = "increment";
2906
- return prop;
2907
- }
2908
- case "serial":
2909
- case "bigserial":
2910
- case "smallserial": return {
2911
- type: "number",
2912
- name: prettifiedName,
2913
- columnType: dt === "bigserial" ? "bigserial" : "serial",
2914
- isId: "increment",
2915
- validation: {
2916
- ...required ? { required: true } : {},
2917
- integer: true
2918
- }
2919
- };
2920
- case "numeric":
2921
- case "decimal":
2922
- case "real":
2923
- case "double precision": {
2924
- let colType = "numeric";
2925
- if (dt === "real") colType = "real";
2926
- if (dt === "double precision") colType = "double precision";
2927
- return {
2928
- type: "number",
2929
- name: prettifiedName,
2930
- columnType: colType,
2931
- validation: required ? { required: true } : void 0
2932
- };
2933
- }
2934
- case "boolean": return {
2935
- type: "boolean",
2936
- name: prettifiedName,
2937
- validation: required ? { required: true } : void 0
2938
- };
2939
- case "timestamp with time zone":
2940
- case "timestamp without time zone":
2941
- case "timestamp":
2942
- case "timestamptz":
2943
- case "date":
2944
- case "time with time zone":
2945
- case "time without time zone":
2946
- case "time": {
2947
- let colType = "timestamp";
2948
- if (dt.startsWith("date")) colType = "date";
2949
- if (dt.startsWith("time ") || dt === "time") colType = "time";
2950
- return {
2951
- type: "date",
2952
- name: prettifiedName,
2953
- columnType: colType,
2954
- validation: required ? { required: true } : void 0
2955
- };
2956
- }
2957
- case "jsonb":
2958
- case "json": return {
2959
- type: "map",
2960
- name: prettifiedName,
2961
- columnType: dt === "jsonb" ? "jsonb" : "json",
2962
- keyValue: true,
2963
- properties: {}
2964
- };
2965
- case "array":
2966
- case "ARRAY": {
2967
- let innerType = "string";
2968
- let colType = void 0;
2969
- if (udt_name === "_text" || udt_name === "_varchar") {
2970
- innerType = "string";
2971
- colType = "text[]";
2972
- } else if (udt_name === "_int4" || udt_name === "_int2" || udt_name === "_int8") {
2973
- innerType = "number";
2974
- colType = "integer[]";
2975
- } else if (udt_name === "_bool") {
2976
- innerType = "boolean";
2977
- colType = "boolean[]";
2978
- } else if (udt_name === "_numeric") {
2979
- innerType = "number";
2980
- colType = "numeric[]";
2981
- }
2982
- return {
2983
- type: "array",
2984
- name: prettifiedName,
2985
- columnType: colType,
2986
- of: { type: innerType }
2987
- };
2988
- }
2989
- default: return {
2990
- type: "string",
2991
- name: prettifiedName,
2992
- validation: required ? { required: true } : void 0
2993
- };
2994
- }
2995
- }
2996
- /**
2997
- * Builds a partial AdminCollection from PostgreSQL table metadata.
2998
- * This is used when creating a new collection from an existing database table.
2999
- */
3000
- function buildCollectionFromTableMetadata(tableName, metadata) {
3001
- const properties = {};
3002
- const propertiesOrder = [];
3003
- const relations = [];
3004
- const securityRules = [];
3005
- for (const column of metadata.columns) {
3006
- const property = pgTypeToRebaseProperty(column);
3007
- if (property) {
3008
- const propRecord = property;
3009
- Object.keys(propRecord).forEach((key) => propRecord[key] === void 0 && delete propRecord[key]);
3010
- properties[column.column_name] = property;
3011
- propertiesOrder.push(column.column_name);
3012
- }
3013
- }
3014
- if (metadata.foreignKeys) for (const fk of metadata.foreignKeys) {
3015
- const relName = fk.column_name.endsWith("_id") ? fk.column_name.substring(0, fk.column_name.length - 3) : fk.column_name;
3016
- relations.push({
3017
- id: fk.column_name,
3018
- relationName: relName,
3019
- target: fk.foreign_table_name,
3020
- cardinality: "one",
3021
- direction: "owning",
3022
- localKey: fk.column_name
3023
- });
3024
- }
3025
- if (metadata.junctions) for (const junction of metadata.junctions) {
3026
- const relName = junction.target_table_name;
3027
- relations.push({
3028
- id: junction.target_table_name + "_relation",
3029
- relationName: relName,
3030
- target: junction.target_table_name,
3031
- cardinality: "many",
3032
- direction: "owning",
3033
- through: {
3034
- table: junction.junction_table_name,
3035
- sourceColumn: junction.source_column_name,
3036
- targetColumn: junction.target_column_name
3037
- }
3038
- });
3039
- }
3040
- if (metadata.policies) for (const policy of metadata.policies) {
3041
- let operations = [];
3042
- switch (policy.cmd) {
3043
- case "ALL":
3044
- operations = [
3045
- "read",
3046
- "create",
3047
- "update",
3048
- "delete"
3049
- ];
3050
- break;
3051
- case "SELECT":
3052
- operations = ["read"];
3053
- break;
3054
- case "INSERT":
3055
- operations = ["create"];
3056
- break;
3057
- case "UPDATE":
3058
- operations = ["update"];
3059
- break;
3060
- case "DELETE":
3061
- operations = ["delete"];
3062
- break;
3063
- }
3064
- securityRules.push({
3065
- name: policy.policy_name,
3066
- operations,
3067
- roles: policy.roles ?? [],
3068
- qual: policy.qual,
3069
- with_check: policy.with_check
3070
- });
3071
- }
3072
- return {
3073
- name: prettifyIdentifier(tableName),
3074
- slug: tableName,
3075
- table: tableName,
3076
- properties,
3077
- propertiesOrder,
3078
- ...relations.length > 0 ? { relations } : {},
3079
- ...securityRules.length > 0 ? { securityRules } : {}
3080
- };
3081
- }
3082
- //#endregion
3083
2881
  //#region src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx
3084
2882
  var CollectionEditorDialog_exports = /* @__PURE__ */ __exportAll({
3085
2883
  CollectionEditor: () => CollectionEditor,
@@ -3168,10 +2966,12 @@ function CollectionEditor(props) {
3168
2966
  }, [collection, fallbackSlug]);
3169
2967
  const initialValues = React$1.useMemo(() => {
3170
2968
  return initialCollection ? applyPropertyConfigs(initialCollection, propertyConfigs) : copyFromProp ? (() => {
3171
- const { subcollections: _sub, ...rest } = copyFromProp;
2969
+ const { subcollections: _sub, schema: _schema, auth: _auth, ...rest } = copyFromProp;
3172
2970
  return {
3173
2971
  ...rest,
3174
2972
  name: "",
2973
+ slug: fallbackSlug,
2974
+ table: "",
3175
2975
  ownerId: authController.user?.uid ?? ""
3176
2976
  };
3177
2977
  })() : {
@@ -3206,6 +3006,8 @@ function CollectionEditor(props) {
3206
3006
  });
3207
3007
  }
3208
3008
  function CollectionEditorInternal({ isNewCollection, configController, editedCollectionId, parentCollectionSlugs, parentEntityIds, path, collectionInference, handleClose, extraView, handleCancel, setFormDirty, getUser, parentCollection, getData, existingPaths, existingIds, includeTemplates, collection, setCollection, initialValues, propertyConfigs, existingEntities, initialView: initialViewProp, expandKanban, generateCollection, onAnalyticsEvent, fullScreen, unmappedTables, onFetchTableMetadata, propertyTypePresets, hiddenPropertyTypes, renderExtraPropertyFields, renderExtraCollectionFields, visibleTabs, standalone }) {
3009
+ /** Why the submit buttons below are dead, straight from the backend. */
3010
+ const readOnlyTitle = configController?.readOnlyReason || "This backend does not accept collection edits.";
3209
3011
  const importConfigRaw = useImportConfig();
3210
3012
  const urlControllerRaw = useUrlController();
3211
3013
  const collectionRegistryRaw = useCollectionRegistryController();
@@ -3489,14 +3291,17 @@ function CollectionEditorInternal({ isNewCollection, configController, editedCol
3489
3291
  onAnalyticsEvent
3490
3292
  }), fullScreen && !isNewCollection && /* @__PURE__ */ jsx("div", {
3491
3293
  className: "flex items-center gap-2",
3492
- children: /* @__PURE__ */ jsx(LoadingButton, {
3493
- variant: "filled",
3494
- color: "primary",
3495
- type: "submit",
3496
- onClick: () => formController.handleSubmit(),
3497
- disabled: !dirty || isSubmitting || configController?.readOnly,
3498
- loading: isSubmitting,
3499
- children: configController?.readOnly ? "Update (Read-only)" : "Update"
3294
+ children: /* @__PURE__ */ jsx(Tooltip, {
3295
+ title: configController?.readOnly ? readOnlyTitle : void 0,
3296
+ children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(LoadingButton, {
3297
+ variant: "filled",
3298
+ color: "primary",
3299
+ type: "submit",
3300
+ onClick: () => formController.handleSubmit(),
3301
+ disabled: !dirty || isSubmitting || configController?.readOnly,
3302
+ loading: isSubmitting,
3303
+ children: configController?.readOnly ? "Update (Read-only)" : "Update"
3304
+ }) })
3500
3305
  })
3501
3306
  })]
3502
3307
  })]
@@ -3575,10 +3380,11 @@ function CollectionEditorInternal({ isNewCollection, configController, editedCol
3575
3380
  showErrors: submitCount > 0,
3576
3381
  isNewCollection,
3577
3382
  onPropertyError: (propertyKey, namespace, error) => {
3578
- propertyErrorsRef.current = removeUndefined({
3383
+ const current = removeUndefined({
3579
3384
  ...propertyErrorsRef.current,
3580
3385
  [getFullIdPath(propertyKey, namespace)]: removeUndefined(error, true)
3581
3386
  }, true);
3387
+ propertyErrorsRef.current = current;
3582
3388
  formController.validate();
3583
3389
  },
3584
3390
  getUser,
@@ -3666,13 +3472,16 @@ function CollectionEditorInternal({ isNewCollection, configController, editedCol
3666
3472
  startIcon: currentView === "properties" ? /* @__PURE__ */ jsx(CheckIcon, {}) : void 0,
3667
3473
  children: [currentView === "general" && "Next", currentView === "properties" && "Create collection"]
3668
3474
  }),
3669
- !isNewCollection && !fullScreen && /* @__PURE__ */ jsx(LoadingButton, {
3670
- variant: "filled",
3671
- color: "primary",
3672
- type: "submit",
3673
- disabled: isSubmitting || configController?.readOnly,
3674
- loading: isSubmitting,
3675
- children: configController?.readOnly ? "Update collection (Read-only)" : "Update collection"
3475
+ !isNewCollection && !fullScreen && /* @__PURE__ */ jsx(Tooltip, {
3476
+ title: configController?.readOnly ? readOnlyTitle : void 0,
3477
+ children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(LoadingButton, {
3478
+ variant: "filled",
3479
+ color: "primary",
3480
+ type: "submit",
3481
+ disabled: isSubmitting || configController?.readOnly,
3482
+ loading: isSubmitting,
3483
+ children: configController?.readOnly ? "Update collection (Read-only)" : "Update collection"
3484
+ }) })
3676
3485
  })
3677
3486
  ]
3678
3487
  })]
@@ -3741,4 +3550,4 @@ var validateId = (value, isNewCollection, existingPaths, existingIds) => {
3741
3550
  //#endregion
3742
3551
  export { CollectionEditorDialog as n, CollectionEditorDialog_exports as r, CollectionEditor as t };
3743
3552
 
3744
- //# sourceMappingURL=CollectionEditorDialog-o7F_zbGY.js.map
3553
+ //# sourceMappingURL=CollectionEditorDialog-B-iVE9y3.js.map