@rebasepro/admin 0.6.1 → 0.8.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 (187) hide show
  1. package/dist/{CollectionEditorDialog-HNXGxXdO.js → CollectionEditorDialog-BO_aQ-Z4.js} +236 -155
  2. package/dist/CollectionEditorDialog-BO_aQ-Z4.js.map +1 -0
  3. package/dist/{PropertyEditView-C2wp8kQ9.js → PropertyEditView-DKzOpMjR.js} +190 -50
  4. package/dist/PropertyEditView-DKzOpMjR.js.map +1 -0
  5. package/dist/{CollectionsStudioView-B1mN33GB.js → RouterCollectionsStudioView-BQTIExjA.js} +61 -39
  6. package/dist/RouterCollectionsStudioView-BQTIExjA.js.map +1 -0
  7. package/dist/collection_editor/_cms_internals.d.ts +1 -1
  8. package/dist/collection_editor/api/generateCollectionApi.d.ts +3 -2
  9. package/dist/collection_editor/extensibility_types.d.ts +135 -0
  10. package/dist/collection_editor/index.d.ts +6 -0
  11. package/dist/collection_editor/serializable_types.d.ts +370 -0
  12. package/dist/collection_editor/serializable_utils.d.ts +50 -0
  13. package/dist/collection_editor/ui/collection_editor/CollectionEditorDialog.d.ts +3 -3
  14. package/dist/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +12 -1
  15. package/dist/collection_editor/ui/collection_editor/CollectionStudioView.d.ts +13 -1
  16. package/dist/collection_editor/ui/collection_editor/CollectionsStudioView.d.ts +24 -2
  17. package/dist/collection_editor/ui/collection_editor/DisplaySettingsForm.d.ts +2 -1
  18. package/dist/collection_editor/ui/collection_editor/GeneralSettingsForm.d.ts +4 -1
  19. package/dist/collection_editor/ui/collection_editor/PropertyEditView.d.ts +12 -1
  20. package/dist/collection_editor/ui/collection_editor/RouterCollectionStudioView.d.ts +15 -0
  21. package/dist/collection_editor/ui/collection_editor/RouterCollectionsStudioView.d.ts +14 -0
  22. package/dist/collection_editor/useJsonCollectionsConfigController.d.ts +37 -0
  23. package/dist/collection_editor/useSafeSnackbarController.d.ts +2 -0
  24. package/dist/collection_editor_ui.d.ts +4 -0
  25. package/dist/collection_editor_ui.js +33 -4
  26. package/dist/collection_editor_ui.js.map +1 -0
  27. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
  28. package/dist/components/EntityCollectionTable/index.d.ts +1 -1
  29. package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +3 -3
  30. package/dist/components/EntityCollectionView/hooks/useKanbanDragAndDrop.d.ts +3 -3
  31. package/dist/components/EntityEditView.d.ts +3 -2
  32. package/dist/components/RebaseCMS.d.ts +1 -1
  33. package/dist/components/SelectableTable/SelectionStore.d.ts +12 -21
  34. package/dist/components/field_configs.d.ts +1 -1
  35. package/dist/editor/editor.d.ts +0 -6
  36. package/dist/editor.js +1 -3
  37. package/dist/editor.js.map +1 -1
  38. package/dist/form/EntityForm.d.ts +10 -9
  39. package/dist/form/EntityFormBinding.d.ts +27 -0
  40. package/dist/form/components/StorageUploadProgress.d.ts +6 -1
  41. package/dist/form/form_utils.d.ts +8 -0
  42. package/dist/form/index.d.ts +5 -2
  43. package/dist/{history-BO6VT85a.js → history-B3cqBzEV.js} +2 -2
  44. package/dist/{history-BO6VT85a.js.map → history-B3cqBzEV.js.map} +1 -1
  45. package/dist/hooks/navigation/contexts/CollectionRegistryContext.d.ts +1 -1
  46. package/dist/hooks/navigation/useAsyncResolver.d.ts +26 -0
  47. package/dist/hooks/navigation/useBuildCollectionRegistryController.d.ts +2 -0
  48. package/dist/hooks/navigation/useTopLevelNavigation.d.ts +1 -1
  49. package/dist/hooks/navigation/utils.d.ts +1 -1
  50. package/dist/index.d.ts +3 -1
  51. package/dist/index.js +2 -2
  52. package/dist/preview/components/StorageThumbnail.d.ts +3 -1
  53. package/dist/routes/CustomViewRoute.d.ts +2 -1
  54. package/dist/{src-BYniefVu.js → src-cxV1ODRG.js} +1731 -1710
  55. package/dist/src-cxV1ODRG.js.map +1 -0
  56. package/dist/types/components/EntityFormActionsProps.d.ts +1 -1
  57. package/dist/types/components/EntityFormProps.d.ts +59 -0
  58. package/dist/types/components/PropertyPreviewProps.d.ts +2 -1
  59. package/dist/types/fields.d.ts +10 -7
  60. package/dist/util/dataControllerAdapter.d.ts +30 -0
  61. package/dist/util/navigation_utils.d.ts +1 -1
  62. package/dist/util/propertyConfigMapper.d.ts +17 -0
  63. package/package.json +8 -8
  64. package/src/collection_editor/_cms_internals.ts +1 -1
  65. package/src/collection_editor/api/generateCollectionApi.ts +3 -2
  66. package/src/collection_editor/extensibility_types.ts +168 -0
  67. package/src/collection_editor/index.ts +46 -0
  68. package/src/collection_editor/pgColumnToProperty.ts +2 -2
  69. package/src/collection_editor/serializable_types.ts +474 -0
  70. package/src/collection_editor/serializable_utils.ts +576 -0
  71. package/src/collection_editor/ui/collection_editor/AICollectionGeneratorPopover.tsx +6 -6
  72. package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +170 -89
  73. package/src/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.tsx +95 -78
  74. package/src/collection_editor/ui/collection_editor/CollectionStudioView.tsx +23 -20
  75. package/src/collection_editor/ui/collection_editor/CollectionsStudioView.tsx +79 -27
  76. package/src/collection_editor/ui/collection_editor/DisplaySettingsForm.tsx +9 -7
  77. package/src/collection_editor/ui/collection_editor/GeneralSettingsForm.tsx +22 -5
  78. package/src/collection_editor/ui/collection_editor/GetCodeDialog.tsx +3 -3
  79. package/src/collection_editor/ui/collection_editor/PropertyEditView.tsx +154 -18
  80. package/src/collection_editor/ui/collection_editor/PropertyFieldPreview.tsx +6 -6
  81. package/src/collection_editor/ui/collection_editor/PropertyTree.tsx +1 -0
  82. package/src/collection_editor/ui/collection_editor/RouterCollectionStudioView.tsx +44 -0
  83. package/src/collection_editor/ui/collection_editor/RouterCollectionsStudioView.tsx +41 -0
  84. package/src/collection_editor/ui/collection_editor/properties/EnumPropertyField.tsx +4 -3
  85. package/src/collection_editor/ui/collection_editor/properties/StoragePropertyField.tsx +35 -1
  86. package/src/collection_editor/ui/collection_editor/templates/blog_template.ts +1 -1
  87. package/src/collection_editor/ui/collection_editor/utils/supported_fields.tsx +0 -1
  88. package/src/collection_editor/ui/collection_editor/utils/update_property_for_widget.ts +7 -29
  89. package/src/collection_editor/useJsonCollectionsConfigController.tsx +286 -0
  90. package/src/collection_editor/useSafeSnackbarController.ts +9 -0
  91. package/src/collection_editor_ui.ts +6 -0
  92. package/src/components/DefaultDrawer.tsx +14 -4
  93. package/src/components/DrawerNavigationGroup.tsx +2 -2
  94. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +11 -9
  95. package/src/components/EntityCollectionTable/fields/TableMultipleRelationField.tsx +2 -1
  96. package/src/components/EntityCollectionTable/fields/TableRelationField.tsx +2 -1
  97. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +23 -20
  98. package/src/components/EntityCollectionTable/index.tsx +1 -1
  99. package/src/components/EntityCollectionTable/table_bindings.tsx +24 -44
  100. package/src/components/EntityCollectionView/EntityBoardCard.tsx +6 -6
  101. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +13 -12
  102. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +40 -190
  103. package/src/components/EntityCollectionView/EntityCollectionListView.tsx +66 -184
  104. package/src/components/EntityCollectionView/EntityCollectionView.tsx +8 -25
  105. package/src/components/EntityCollectionView/hooks/useCollectionInlineEditor.ts +1 -1
  106. package/src/components/EntityCollectionView/hooks/useKanbanDragAndDrop.ts +6 -6
  107. package/src/components/EntityCollectionView/useBoardDataController.tsx +12 -40
  108. package/src/components/EntityCollectionView/useEntityPreviewSlots.ts +3 -3
  109. package/src/components/EntityDetailView.tsx +2 -2
  110. package/src/components/EntityEditView.tsx +7 -6
  111. package/src/components/EntityEditViewFormActions.tsx +35 -29
  112. package/src/components/HomePage/ContentHomePage.tsx +14 -5
  113. package/src/components/RebaseCMS.tsx +3 -3
  114. package/src/components/RebaseNavigation.tsx +74 -9
  115. package/src/components/RelationSelector.tsx +2 -2
  116. package/src/components/SelectableTable/SelectableTable.tsx +13 -5
  117. package/src/components/SelectableTable/SelectionStore.ts +18 -48
  118. package/src/components/SideDialogs.tsx +0 -7
  119. package/src/components/common/default_entity_actions.tsx +22 -11
  120. package/src/components/field_configs.tsx +0 -14
  121. package/src/contexts/BreacrumbsContext.tsx +15 -6
  122. package/src/editor/editor.tsx +4 -7
  123. package/src/editor/selectors/ai-selector.tsx +0 -1
  124. package/src/form/EntityForm.tsx +191 -428
  125. package/src/form/EntityFormActions.tsx +35 -49
  126. package/src/form/EntityFormBinding.tsx +323 -0
  127. package/src/form/components/FormLayout.tsx +1 -1
  128. package/src/form/components/StorageUploadProgress.tsx +9 -2
  129. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +12 -1
  130. package/src/form/field_bindings/MultipleRelationFieldBinding.tsx +4 -4
  131. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +7 -2
  132. package/src/form/field_bindings/RelationFieldBinding.tsx +5 -7
  133. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +19 -15
  134. package/src/form/form_utils.ts +163 -0
  135. package/src/form/index.tsx +14 -6
  136. package/src/hooks/navigation/contexts/CollectionRegistryContext.tsx +2 -2
  137. package/src/hooks/navigation/contexts/NavigationStateContext.tsx +2 -2
  138. package/src/hooks/navigation/contexts/UrlContext.tsx +1 -2
  139. package/src/hooks/navigation/useAsyncResolver.ts +100 -0
  140. package/src/hooks/navigation/useBuildCollectionRegistryController.tsx +15 -8
  141. package/src/hooks/navigation/useBuildNavigationStateController.tsx +12 -8
  142. package/src/hooks/navigation/useNavigationResolution.ts +33 -0
  143. package/src/hooks/navigation/useResolvedCollections.ts +29 -71
  144. package/src/hooks/navigation/useResolvedViews.tsx +40 -70
  145. package/src/hooks/navigation/useTopLevelNavigation.ts +20 -16
  146. package/src/hooks/navigation/utils.ts +7 -4
  147. package/src/index.ts +6 -1
  148. package/src/preview/PropertyPreview.tsx +1 -16
  149. package/src/preview/components/StorageThumbnail.tsx +24 -7
  150. package/src/routes/CustomViewRoute.tsx +14 -6
  151. package/src/types/components/EntityFormActionsProps.tsx +1 -1
  152. package/src/types/components/EntityFormProps.tsx +68 -0
  153. package/src/types/components/PropertyPreviewProps.tsx +1 -1
  154. package/src/types/fields.tsx +9 -8
  155. package/src/util/dataControllerAdapter.ts +93 -0
  156. package/src/util/navigation_utils.ts +1 -1
  157. package/src/util/previews.ts +20 -0
  158. package/src/util/propertyConfigMapper.ts +134 -0
  159. package/src/util/property_utils.tsx +1 -2
  160. package/dist/CollectionEditorDialog-HNXGxXdO.js.map +0 -1
  161. package/dist/CollectionsStudioView-B1mN33GB.js.map +0 -1
  162. package/dist/PropertyEditView-C2wp8kQ9.js.map +0 -1
  163. package/dist/components/EntityCollectionTable/fields/VirtualTableDateField.d.ts +0 -12
  164. package/dist/components/EntityCollectionTable/fields/VirtualTableInput.d.ts +0 -10
  165. package/dist/components/EntityCollectionTable/fields/VirtualTableNumberInput.d.ts +0 -9
  166. package/dist/components/EntityCollectionTable/fields/VirtualTableSwitch.d.ts +0 -8
  167. package/dist/components/EntityCollectionView/Board.d.ts +0 -3
  168. package/dist/components/EntityCollectionView/BoardColumn.d.ts +0 -42
  169. package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +0 -9
  170. package/dist/components/EntityCollectionView/BoardSortableList.d.ts +0 -14
  171. package/dist/components/EntityCollectionView/board_types.d.ts +0 -105
  172. package/dist/form/field_bindings/ReferenceAsStringFieldBinding.d.ts +0 -11
  173. package/dist/hooks/navigation/useNavigationRegistry.d.ts +0 -12
  174. package/dist/hooks/navigation/useNavigationURLs.d.ts +0 -11
  175. package/dist/src-BYniefVu.js.map +0 -1
  176. package/src/components/EntityCollectionTable/fields/VirtualTableDateField.tsx +0 -39
  177. package/src/components/EntityCollectionTable/fields/VirtualTableInput.tsx +0 -90
  178. package/src/components/EntityCollectionTable/fields/VirtualTableNumberInput.tsx +0 -83
  179. package/src/components/EntityCollectionTable/fields/VirtualTableSwitch.tsx +0 -32
  180. package/src/components/EntityCollectionView/Board.tsx +0 -475
  181. package/src/components/EntityCollectionView/BoardColumn.tsx +0 -165
  182. package/src/components/EntityCollectionView/BoardColumnTitle.tsx +0 -46
  183. package/src/components/EntityCollectionView/BoardSortableList.tsx +0 -177
  184. package/src/components/EntityCollectionView/board_types.ts +0 -113
  185. package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +0 -141
  186. package/src/hooks/navigation/useNavigationRegistry.ts +0 -164
  187. package/src/hooks/navigation/useNavigationURLs.ts +0 -56
@@ -1,30 +1,50 @@
1
-
2
- import { useUnsavedChangesDialog, UnsavedChangesDialog } from "@rebasepro/core";
3
- import { useNavigationStateController, useCollectionRegistryController, useUrlController } from "../../_cms_internals";
4
1
  import * as React from "react";
5
2
  import { useEffect, useRef, useState } from "react";
6
- import { ConfirmationDialog, ErrorView, useAuthController, useCustomizationController, useSnackbarController } from "@rebasepro/core";
7
- import { CircularProgressCenter } from "@rebasepro/ui";
3
+ import {
4
+ ConfirmationDialog,
5
+ ErrorView,
6
+ UnsavedChangesDialog,
7
+ useAuthController,
8
+ useCustomizationController,
9
+ useUnsavedChangesDialog
10
+ } from "@rebasepro/core";
11
+ import {
12
+ getInferenceType,
13
+ ImportSaveInProgress,
14
+ useCollectionRegistryController,
15
+ useImportConfig,
16
+ useNavigationStateController,
17
+ useUrlController
18
+ } from "../../_cms_internals";
19
+ import { useSafeSnackbarController } from "../../useSafeSnackbarController";
8
20
  import {
9
21
  ArrowLeftIcon,
10
22
  Button,
11
23
  CheckIcon,
24
+ CircularProgressCenter,
12
25
  cls,
13
26
  coolIconKeys,
14
27
  defaultBorderMixin,
15
28
  Dialog,
16
- DialogActions,
17
- DialogContent,
18
29
  DialogTitle,
19
30
  IconButton,
20
31
  LoadingButton,
21
32
  Tab,
22
- Tabs,
23
- Typography
33
+ Tabs
24
34
  } from "@rebasepro/ui";
25
- import { Entity, EntityCollection, MapProperty, Properties, Property, PropertyConfig, User, getDataSourceCapabilities } from "@rebasepro/types";
26
- import type { PostgresCollection } from "@rebasepro/types";
27
- import { getSubcollections, isPropertyBuilder, removeInitialAndTrailingSlashes, getTableName } from "@rebasepro/common";
35
+ import {
36
+ EngineProperties,
37
+ Entity,
38
+ EntityCollection,
39
+ getDataSourceCapabilities,
40
+ MapProperty,
41
+ Properties,
42
+ Property,
43
+ PropertyConfig,
44
+ TableMetadata,
45
+ User
46
+ } from "@rebasepro/types";
47
+ import { getSubcollections, getTableName, isPropertyBuilder, removeInitialAndTrailingSlashes } from "@rebasepro/common";
28
48
  import { CollectionEditorSchema } from "./CollectionYupValidation";
29
49
  import { GeneralSettingsForm } from "./GeneralSettingsForm";
30
50
  import { DisplaySettingsForm } from "./DisplaySettingsForm";
@@ -32,7 +52,6 @@ import { CollectionPropertiesEditorForm } from "./CollectionPropertiesEditorForm
32
52
  import { CollectionsConfigController } from "../../types/config_controller";
33
53
  import { CollectionEditorWelcomeView } from "./CollectionEditorWelcomeView";
34
54
  import { CollectionInference } from "../../types/collection_inference";
35
- import { getInferenceType, ImportSaveInProgress, useImportConfig } from "../../_cms_internals";
36
55
  import { buildEntityPropertiesFromData } from "@rebasepro/schema-inference";
37
56
  import { CollectionEditorImportMapping } from "./import/CollectionEditorImportMapping";
38
57
  import { CollectionEditorImportDataPreview } from "./import/CollectionEditorImportDataPreview";
@@ -41,13 +60,13 @@ import { Formex, FormexController, useCreateFormex } from "@rebasepro/formex";
41
60
  import { getFullIdPath } from "./util";
42
61
  import { AICollectionGeneratorPopover } from "./AICollectionGeneratorPopover";
43
62
  import { AIModifiedPathsProvider, useAIModifiedPaths } from "./AIModifiedPathsContext";
44
- import { CollectionOperation, CollectionGenerationCallback } from "../../api/generateCollectionApi";
63
+ import { CollectionGenerationCallback, CollectionOperation } from "../../api/generateCollectionApi";
45
64
  import { CollectionRLSTab } from "./CollectionRLSTab";
46
65
  import { buildCollectionFromTableMetadata } from "../../pgColumnToProperty";
47
- import { TableMetadata } from "@rebasepro/types";
48
66
  import { mergeDeep, randomString, removeUndefined } from "@rebasepro/utils";
67
+ import type { CollectionEditorExtensionProps, CollectionEditorTab } from "../../extensibility_types";
49
68
 
50
- export interface CollectionEditorDialogProps {
69
+ export interface CollectionEditorDialogProps extends CollectionEditorExtensionProps {
51
70
  open: boolean;
52
71
  isNewCollection: boolean;
53
72
  initialValues?: {
@@ -139,6 +158,7 @@ export function CollectionEditorDialog(props: CollectionEditorDialogProps) {
139
158
  fullHeight={true}
140
159
  scrollable={false}
141
160
  maxWidth={"7xl"}
161
+ className="bg-surface-50 dark:bg-surface-800"
142
162
  onOpenChange={(open) => !open ? handleCancel() : undefined}
143
163
  >
144
164
  <DialogTitle hidden>Collection editor</DialogTitle>
@@ -168,17 +188,23 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
168
188
  handleCancel: () => void,
169
189
  setFormDirty: (dirty: boolean) => void
170
190
  }) {
171
- const { propertyConfigs } = useCustomizationController();
191
+ const { standalone } = props;
192
+
193
+ const customizationController = useCustomizationController();
172
194
  const navigationState = useNavigationStateController();
173
195
  const collectionRegistry = useCollectionRegistryController();
174
196
  const authController = useAuthController();
175
197
 
176
- const {
177
- topLevelNavigation
178
- } = navigationState;
179
- const {
180
- collections
181
- } = collectionRegistry;
198
+ // In standalone mode, use safe defaults instead of context values
199
+ const propertyConfigs = standalone
200
+ ? (customizationController?.propertyConfigs ?? {})
201
+ : customizationController.propertyConfigs;
202
+ const topLevelNavigation = standalone
203
+ ? (navigationState?.topLevelNavigation ?? [])
204
+ : navigationState.topLevelNavigation;
205
+ const collections = standalone
206
+ ? (collectionRegistry?.collections ?? [])
207
+ : collectionRegistry.collections;
182
208
 
183
209
  const initialValuesProp = props.initialValues;
184
210
  const copyFromProp = props.copyFrom;
@@ -192,7 +218,13 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
192
218
 
193
219
  useEffect(() => {
194
220
  try {
195
- if (collectionRegistry.initialised) {
221
+ const initialised = (standalone
222
+ ? true
223
+ : (collectionRegistry?.initialised ?? true)) && !props.configController?.loading;
224
+ const getRawCollection = standalone
225
+ ? (() => undefined)
226
+ : collectionRegistry.getRawCollection;
227
+ if (initialised) {
196
228
  if (props.editedCollectionId) {
197
229
  // We must use getRawCollection so the editor schema fields
198
230
  // aren't polluted with dynamically injected runtime `relations`.
@@ -200,7 +232,9 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
200
232
  const collectionPath = [...(props.parentCollectionSlugs ?? []), props.editedCollectionId]
201
233
  .reduce((acc, segment, i) => i === 0 ? segment : `${acc}/fake_id/${segment}`, "");
202
234
 
203
- setCollection(collectionRegistry.getRawCollection(collectionPath) as EntityCollection<any>);
235
+ const registryCol = getRawCollection ? getRawCollection(collectionPath) : undefined;
236
+ const configCol = props.configController?.collections?.find(c => c.slug === props.editedCollectionId);
237
+ setCollection((registryCol ?? configCol) as EntityCollection<any>);
204
238
  } else {
205
239
  setCollection(undefined);
206
240
  }
@@ -209,44 +243,51 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
209
243
  } catch (e) {
210
244
  console.error(e);
211
245
  }
212
- }, [props.editedCollectionId, props.parentCollectionSlugs, props.parentEntityIds, collectionRegistry.initialised, collectionRegistry.getRawCollection]);
246
+ }, [props.editedCollectionId, props.parentCollectionSlugs, props.parentEntityIds, standalone, collectionRegistry.initialised, collectionRegistry.getRawCollection, props.configController.collections, props.configController.loading, collections]);
213
247
 
214
248
 
215
- const initialCollection = collection
216
- ? {
217
- ...collection,
218
- slug: collection.slug ?? randomString(16)
219
- }
220
- : undefined;
249
+ const initialIcon = React.useMemo(() => coolIconKeys[Math.floor(Math.random() * coolIconKeys.length)], []);
250
+ const fallbackSlug = React.useMemo(() => randomString(16), []);
251
+
252
+ const initialCollection = React.useMemo(() => {
253
+ return collection
254
+ ? {
255
+ ...collection,
256
+ slug: collection.slug ?? fallbackSlug
257
+ }
258
+ : undefined;
259
+ }, [collection, fallbackSlug]);
221
260
 
222
261
  // Build initial values - handle copyFrom for duplication
223
- const initialValues: EntityCollection<any> = initialCollection
224
- ? applyPropertyConfigs(initialCollection, propertyConfigs)
225
- : copyFromProp
226
- ? (() => {
227
- // When duplicating, copy all properties but clear identifiers
228
- const { subcollections: _sub, ...rest } = copyFromProp as unknown as Record<string, unknown>;
229
- return {
230
- ...rest,
231
- name: "",
262
+ const initialValues = React.useMemo((): EntityCollection<any> => {
263
+ return (initialCollection
264
+ ? applyPropertyConfigs(initialCollection, propertyConfigs)
265
+ : copyFromProp
266
+ ? (() => {
267
+ // When duplicating, copy all properties but clear identifiers
268
+ const { subcollections: _sub, ...rest } = copyFromProp as unknown as Record<string, unknown>;
269
+ return {
270
+ ...rest,
271
+ name: "",
272
+ ownerId: authController.user?.uid ?? ""
273
+ } as EntityCollection<any>;
274
+ })()
275
+ : {
276
+ slug: initialValuesProp?.slug ?? fallbackSlug,
277
+ table: initialValuesProp?.slug ?? "",
278
+ name: initialValuesProp?.name ?? "",
279
+ properties: {} as EngineProperties,
280
+ propertiesOrder: [],
281
+ icon: initialIcon,
232
282
  ownerId: authController.user?.uid ?? ""
233
- } as EntityCollection<any>;
234
- })()
235
- : {
236
- slug: initialValuesProp?.slug ?? randomString(16),
237
- table: initialValuesProp?.slug ?? "",
238
- name: initialValuesProp?.name ?? "",
239
- properties: {} as Properties,
240
- propertiesOrder: [],
241
- icon: coolIconKeys[Math.floor(Math.random() * coolIconKeys.length)],
242
- ownerId: authController.user?.uid ?? ""
243
- };
283
+ }) as EntityCollection<any>;
284
+ }, [initialCollection, propertyConfigs, copyFromProp, initialValuesProp, fallbackSlug, initialIcon, authController.user?.uid]);
244
285
 
245
286
  if (!initialLoadingCompleted) {
246
287
  return <CircularProgressCenter/>;
247
288
  }
248
289
 
249
- if (!props.isNewCollection && (!collectionRegistry.initialised || !initialLoadingCompleted)) {
290
+ if (!props.isNewCollection && (!(standalone ? true : (collectionRegistry?.initialised ?? true)) || !initialLoadingCompleted)) {
250
291
  return <CircularProgressCenter/>;
251
292
  }
252
293
 
@@ -290,7 +331,13 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
290
331
  onAnalyticsEvent,
291
332
  fullScreen,
292
333
  unmappedTables,
293
- onFetchTableMetadata
334
+ onFetchTableMetadata,
335
+ propertyTypePresets,
336
+ hiddenPropertyTypes,
337
+ renderExtraPropertyFields,
338
+ renderExtraCollectionFields,
339
+ visibleTabs,
340
+ standalone
294
341
  }: CollectionEditorDialogProps & {
295
342
  handleCancel: () => void,
296
343
  setFormDirty: (dirty: boolean) => void,
@@ -304,10 +351,33 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
304
351
  }
305
352
  ) {
306
353
 
307
- const importConfig = useImportConfig();
308
- const urlController = useUrlController();
309
- const collectionRegistry = useCollectionRegistryController();
310
- const snackbarController = useSnackbarController();
354
+ const importConfigRaw = useImportConfig();
355
+ const urlControllerRaw = useUrlController();
356
+ const collectionRegistryRaw = useCollectionRegistryController();
357
+ const snackbarControllerRaw = useSafeSnackbarController();
358
+
359
+ // In standalone mode, use safe defaults
360
+ const importConfig = standalone ? undefined : importConfigRaw;
361
+ const urlController = standalone
362
+ ? {
363
+ basePath: "/",
364
+ baseCollectionPath: "/c",
365
+ urlPathToDataPath: () => "",
366
+ homeUrl: "/",
367
+ isUrlCollectionPath: () => false,
368
+ buildUrlCollectionPath: () => "",
369
+ buildAppUrlPath: () => "",
370
+ resolveDatabasePathsFrom: (p: string) => p,
371
+ navigate: () => { }
372
+ }
373
+ : urlControllerRaw;
374
+ const collectionRegistryInternal = standalone
375
+ ? { convertIdsToPaths: (ids: string[]) => ids }
376
+ : collectionRegistryRaw;
377
+ const snackbarController = snackbarControllerRaw ?? {
378
+ open: () => { },
379
+ close: () => { }
380
+ };
311
381
 
312
382
  // Use this ref to store which properties have errors
313
383
  const propertyErrorsRef = useRef<Record<string, any>>({});
@@ -317,6 +387,12 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
317
387
  : (initialViewProp ?? "properties");
318
388
  const [currentView, setCurrentView] = useState<EditorView>(initialView); // this view can edit either the details view or the properties one
319
389
 
390
+ useEffect(() => {
391
+ if (visibleTabs && !visibleTabs.includes(currentView as CollectionEditorTab)) {
392
+ setCurrentView(visibleTabs[0] || "general");
393
+ }
394
+ }, [visibleTabs, currentView]);
395
+
320
396
  const [error, setError] = React.useState<Error | undefined>();
321
397
 
322
398
  const saveCollection = (updatedCollection: EntityCollection<M>): Promise<boolean> => {
@@ -345,7 +421,7 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
345
421
 
346
422
  const setNextMode = () => {
347
423
  if (currentView === "general") {
348
- if (importConfig.inUse) {
424
+ if (importConfig?.inUse) {
349
425
  setCurrentView("import_data_saving");
350
426
  } else if (extraView) {
351
427
  setCurrentView("extra_view");
@@ -396,7 +472,7 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
396
472
  };
397
473
 
398
474
  if (Object.keys(inferredCollection.properties ?? {}).length > 0) {
399
- values.properties = inferredCollection.properties as Properties;
475
+ values.properties = inferredCollection.properties as EngineProperties;
400
476
  values.propertiesOrder = inferredCollection.propertiesOrder as Extract<keyof M, string>[];
401
477
  }
402
478
 
@@ -439,7 +515,7 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
439
515
  setNextMode();
440
516
  formexController.resetForm({ values: newCollectionState });
441
517
  } else if (currentView === "general") {
442
- if (extraView || importConfig.inUse) {
518
+ if (extraView || importConfig?.inUse) {
443
519
  formexController.resetForm({ values: newCollectionState });
444
520
  setNextMode();
445
521
  } else if (isNewCollection) {
@@ -537,7 +613,7 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
537
613
  const usedPath = getTableName(values);
538
614
  const pathError = validatePath(usedPath, isNewCollection, existingPaths, values.slug);
539
615
 
540
- const parentPaths = !pathError && parentCollectionSlugs ? collectionRegistry.convertIdsToPaths(parentCollectionSlugs) : undefined;
616
+ const parentPaths = !pathError && parentCollectionSlugs ? collectionRegistryInternal.convertIdsToPaths(parentCollectionSlugs) : undefined;
541
617
 
542
618
  const updatedFullPath = parentPaths && parentPaths.length > 0
543
619
  ? [...parentPaths, usedPath].join("/fake_id/")
@@ -558,18 +634,18 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
558
634
  }, [dirty]);
559
635
 
560
636
  function onImportDataSet(data: object[], propertiesOrder?: string[]) {
561
- importConfig.setInUse(true);
637
+ importConfig?.setInUse(true);
562
638
  buildEntityPropertiesFromData(data, getInferenceType)
563
- .then((properties: any) => {
639
+ .then((properties: unknown) => {
564
640
  const res = cleanPropertiesFromImport(properties as Properties);
565
641
 
566
- importConfig.setIdColumn(res.idColumn);
567
- importConfig.setImportData(data);
568
- importConfig.setHeadersMapping(res.headersMapping);
642
+ importConfig?.setIdColumn(res.idColumn);
643
+ importConfig?.setImportData(data);
644
+ importConfig?.setHeadersMapping(res.headersMapping);
569
645
  const filteredHeadingsOrder = ((propertiesOrder ?? [])
570
646
  .filter((key) => res.headersMapping[key]) as string[]) ?? Object.keys(res.properties);
571
- importConfig.setHeadingsOrder(filteredHeadingsOrder);
572
- importConfig.setOriginProperties(res.properties);
647
+ importConfig?.setHeadingsOrder(filteredHeadingsOrder);
648
+ importConfig?.setOriginProperties(res.properties);
573
649
 
574
650
  const mappedHeadings = (propertiesOrder ?? []).map((key) => res.headersMapping[key]).filter(Boolean) as string[] ?? Object.keys(res.properties);
575
651
  setFieldValue("properties", res.properties);
@@ -581,7 +657,7 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
581
657
 
582
658
  const onImportMappingComplete = () => {
583
659
  const updatedProperties = { ...values.properties };
584
- if (importConfig.idColumn)
660
+ if (importConfig?.idColumn)
585
661
  delete updatedProperties[importConfig.idColumn];
586
662
  setFieldValue("properties", updatedProperties);
587
663
  // setFieldValue("propertiesOrder", Object.values(importConfig.headersMapping));
@@ -620,25 +696,25 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
620
696
  }
621
697
  };
622
698
 
623
- return <div className="h-full w-full flex flex-col bg-white dark:bg-surface-950">
699
+ return <div className="h-full w-full flex flex-col bg-surface-50 dark:bg-surface-800">
624
700
  <Formex value={formController}>
625
701
 
626
702
  <>
627
- {!isNewCollection && <div className={cls("px-4 py-2 w-full flex shrink-0 items-center justify-between gap-4 bg-surface-50 dark:bg-surface-950 border-b", defaultBorderMixin)}>
703
+ {!isNewCollection && <div className={cls("px-4 py-2 w-full flex shrink-0 items-center justify-between gap-4 bg-surface-50 dark:bg-surface-900 border-b", defaultBorderMixin)}>
628
704
  <div className="flex flex-1 items-center justify-end gap-4 min-w-0">
629
705
  <Tabs value={currentView}
630
706
  className="bg-transparent !w-fit max-w-full"
631
707
  onValueChange={(v) => setCurrentView(v as EditorView)}>
632
- <Tab value={"general"}>
708
+ {(!visibleTabs || visibleTabs.includes("general")) && <Tab value={"general"}>
633
709
  General
634
- </Tab>
635
- <Tab value={"display"}>
710
+ </Tab>}
711
+ {(!visibleTabs || visibleTabs.includes("display")) && <Tab value={"display"}>
636
712
  Display
637
- </Tab>
638
- <Tab value={"properties"}>
713
+ </Tab>}
714
+ {(!visibleTabs || visibleTabs.includes("properties")) && <Tab value={"properties"}>
639
715
  Properties
640
- </Tab>
641
- {getDataSourceCapabilities(values.driver).supportsRLS && <Tab value={"rls"}>
716
+ </Tab>}
717
+ {(!visibleTabs || visibleTabs.includes("rls")) && getDataSourceCapabilities(values.engine).supportsRLS && <Tab value={"rls"}>
642
718
  RLS
643
719
  </Tab>}
644
720
  </Tabs>
@@ -673,7 +749,7 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
673
749
  onSubmit={formController.handleSubmit}
674
750
  className="flex-grow flex flex-col min-h-0 relative">
675
751
 
676
- <div className="flex-grow flex flex-col min-h-0 overflow-y-auto no-scrollbar relative w-full h-full">
752
+ <div className="flex-grow flex flex-col min-h-0 no-scrollbar relative w-full h-full bg-surface-50 dark:bg-surface-800">
677
753
 
678
754
  {currentView === "loading" &&
679
755
  <CircularProgressCenter/>}
@@ -736,17 +812,19 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
736
812
 
737
813
  {currentView === "general" &&
738
814
  <GeneralSettingsForm
815
+ isNewCollection={isNewCollection}
739
816
  existingPaths={existingPaths}
740
817
  existingIds={existingIds}
741
818
  parentCollection={parentCollection}
742
- isNewCollection={isNewCollection}/>
819
+ renderExtraCollectionFields={renderExtraCollectionFields}
820
+ standalone={standalone}/>
743
821
  }
744
822
 
745
823
  {currentView === "display" &&
746
- <DisplaySettingsForm expandKanban={expandKanban}/>
824
+ <DisplaySettingsForm expandKanban={expandKanban} standalone={standalone}/>
747
825
  }
748
826
 
749
- {currentView === "rls" && getDataSourceCapabilities(values.driver).supportsRLS &&
827
+ {currentView === "rls" && getDataSourceCapabilities(values.engine).supportsRLS &&
750
828
  <CollectionRLSTab/>
751
829
  }
752
830
 
@@ -766,25 +844,28 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
766
844
  getData={getDataWithPath}
767
845
  doCollectionInference={doCollectionInference}
768
846
  propertyConfigs={propertyConfigs}
769
-
847
+ propertyTypePresets={propertyTypePresets}
848
+ hiddenPropertyTypes={hiddenPropertyTypes}
849
+ renderExtraPropertyFields={renderExtraPropertyFields}
770
850
  extraIcon={extraView?.icon &&
771
851
  <IconButton
772
852
  color={"primary"}
773
853
  onClick={() => setCurrentView("extra_view")}>
774
854
  {extraView.icon}
775
- </IconButton>}/>
855
+ </IconButton>}
856
+ standalone={standalone}/>
776
857
  }
777
858
 
778
859
  </div>
779
860
  {(!fullScreen || isNewCollection || !!error) && (
780
- <div className="shrink-0 w-full p-4 sm:px-6 sm:py-4 border-t border-surface-200 dark:border-surface-900 flex items-center justify-between gap-4 bg-white dark:bg-surface-950">
861
+ <div className="shrink-0 w-full p-4 sm:px-6 sm:py-4 border-t border-surface-200 dark:border-surface-900 flex items-center justify-between gap-4 bg-surface-50 dark:bg-surface-900">
781
862
  {error && <ErrorView error={error}/>}
782
863
 
783
864
  {isNewCollection && includeTemplates && currentView === "import_data_mapping" &&
784
865
  <Button variant={"text"}
785
866
  type="button"
786
867
  onClick={() => {
787
- importConfig.setInUse(false);
868
+ importConfig?.setInUse(false);
788
869
  return setCurrentView("welcome");
789
870
  }}>
790
871
  Back
@@ -910,8 +991,8 @@ function applyPropertyConfigs<M extends Record<string, unknown> = Record<string,
910
991
 
911
992
  return {
912
993
  ...rest,
913
- properties: propertiesResult
914
- };
994
+ properties: propertiesResult as EngineProperties
995
+ } as EntityCollection<M>;
915
996
  }
916
997
 
917
998
  function applyPropertiesConfig(property: Property, propertyConfigs: Record<string, PropertyConfig>) {