@rebasepro/admin 0.2.1 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/dist/{CollectionEditorDialog-BXIh2AXg.js → CollectionEditorDialog-D0VqpLPO.js} +73 -256
  2. package/dist/CollectionEditorDialog-D0VqpLPO.js.map +1 -0
  3. package/dist/{CollectionsStudioView-jR8iz_ja.js → CollectionsStudioView-Bc3Rxxc2.js} +5 -4
  4. package/dist/{CollectionsStudioView-jR8iz_ja.js.map → CollectionsStudioView-Bc3Rxxc2.js.map} +1 -1
  5. package/dist/{ExportCollectionAction-CMdiiv1L.js → ExportCollectionAction-Ckc-09BQ.js} +4 -3
  6. package/dist/ExportCollectionAction-Ckc-09BQ.js.map +1 -0
  7. package/dist/{ImportCollectionAction-C05lE0IW.js → ImportCollectionAction-BqjIrC3Z.js} +3 -2
  8. package/dist/{ImportCollectionAction-C05lE0IW.js.map → ImportCollectionAction-BqjIrC3Z.js.map} +1 -1
  9. package/dist/{PropertyEditView-BB5xjnhZ.js → PropertyEditView-CvRSV-A2.js} +430 -445
  10. package/dist/PropertyEditView-CvRSV-A2.js.map +1 -0
  11. package/dist/collection_editor/ConfigControllerProvider.d.ts +0 -5
  12. package/dist/collection_editor/index.d.ts +0 -1
  13. package/dist/collection_editor/types/collection_editor_controller.d.ts +0 -2
  14. package/dist/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +3 -3
  15. package/dist/collection_editor/ui/collection_editor/properties/RelationPropertyField.d.ts +1 -7
  16. package/dist/collection_editor_ui.js +3 -3
  17. package/dist/components/ArrayContainer.d.ts +2 -2
  18. package/dist/components/DefaultAppBar.d.ts +18 -1
  19. package/dist/components/DefaultDrawer.d.ts +51 -3
  20. package/dist/components/EntityCollectionTable/fields/TableStorageUpload.d.ts +2 -2
  21. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +2 -2
  22. package/dist/components/EntityCollectionTable/table_bindings.d.ts +4 -3
  23. package/dist/components/EntityCollectionView/hooks/useKanbanDragAndDrop.d.ts +4 -3
  24. package/dist/components/EntityEditView.d.ts +2 -1
  25. package/dist/components/HomePage/HomePageDnD.d.ts +3 -3
  26. package/dist/components/PropertyCollectionView.d.ts +1 -1
  27. package/dist/components/PropertyIdCopyTooltip.d.ts +1 -1
  28. package/dist/components/SelectableTable/SelectionStore.d.ts +4 -1
  29. package/dist/components/SelectableTable/filters/BooleanFilterField.d.ts +2 -2
  30. package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +2 -2
  31. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +2 -2
  32. package/dist/components/SelectableTable/filters/StringNumberFilterField.d.ts +2 -2
  33. package/dist/components/admin/RolesView.d.ts +3 -3
  34. package/dist/components/admin/UsersView.d.ts +3 -3
  35. package/dist/components/app/Drawer.d.ts +8 -1
  36. package/dist/data_export/export/export.d.ts +3 -3
  37. package/dist/editor/components/editor-bubble.d.ts +5 -1
  38. package/dist/editor/components/image-bubble.d.ts +5 -1
  39. package/dist/editor/components/index.d.ts +3 -3
  40. package/dist/editor/components/table-bubble.d.ts +5 -1
  41. package/dist/editor/nodeViews/ReactNodeView.d.ts +4 -1
  42. package/dist/editor/useProseMirror.d.ts +2 -2
  43. package/dist/editor/utils/remove_classes.d.ts +1 -1
  44. package/dist/editor.js +15 -14
  45. package/dist/editor.js.map +1 -1
  46. package/dist/form/EntityForm.d.ts +2 -2
  47. package/dist/form/components/StorageUploadProgress.d.ts +2 -2
  48. package/dist/form/field_bindings/MultiSelectFieldBinding.d.ts +1 -1
  49. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +1 -1
  50. package/dist/form/validation.d.ts +3 -3
  51. package/dist/hooks/navigation/useResolvedCollections.d.ts +6 -0
  52. package/dist/hooks/navigation/useResolvedViews.d.ts +3 -4
  53. package/dist/{index-BAM9KCmM.js → index-BCcLwgfe.js} +3 -2
  54. package/dist/{index-BAM9KCmM.js.map → index-BCcLwgfe.js.map} +1 -1
  55. package/dist/{index-D5OQhv-T.js → index-DY2k5TtG.js} +3 -3
  56. package/dist/index-DY2k5TtG.js.map +1 -0
  57. package/dist/{index-CoSNm3e3.js → index-UQOMHwt1.js} +3 -3
  58. package/dist/index-UQOMHwt1.js.map +1 -0
  59. package/dist/index.d.ts +1 -1
  60. package/dist/index.js +2813 -372
  61. package/dist/index.js.map +1 -1
  62. package/dist/{markdown-z2Ir7Cgo.js → markdown-DD2JDU1X.js} +2 -2
  63. package/dist/markdown-DD2JDU1X.js.map +1 -0
  64. package/dist/preview/components/UrlComponentPreview.d.ts +1 -0
  65. package/dist/types/components/EntityFormActionsProps.d.ts +1 -1
  66. package/dist/types/components/EntityFormProps.d.ts +2 -2
  67. package/dist/types/fields.d.ts +1 -1
  68. package/dist/{util-DtbWD7LF.js → util-ZM9gQuCv.js} +2104 -2071
  69. package/dist/util-ZM9gQuCv.js.map +1 -0
  70. package/package.json +10 -9
  71. package/src/collection_editor/ConfigControllerProvider.tsx +3 -13
  72. package/src/collection_editor/index.ts +1 -3
  73. package/src/collection_editor/types/collection_editor_controller.tsx +0 -3
  74. package/src/collection_editor/ui/EditorCollectionAction.tsx +1 -6
  75. package/src/collection_editor/ui/EditorCollectionActionStart.tsx +1 -6
  76. package/src/collection_editor/ui/EditorEntityAction.tsx +1 -6
  77. package/src/collection_editor/ui/HomePageEditorCollectionAction.tsx +7 -14
  78. package/src/collection_editor/ui/NewCollectionCard.tsx +1 -5
  79. package/src/collection_editor/ui/PropertyAddColumnComponent.tsx +3 -8
  80. package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +1 -10
  81. package/src/collection_editor/ui/collection_editor/CollectionJsonImportDialog.tsx +8 -12
  82. package/src/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.tsx +21 -21
  83. package/src/collection_editor/ui/collection_editor/CollectionRLSTab.tsx +4 -4
  84. package/src/collection_editor/ui/collection_editor/EnumForm.tsx +1 -1
  85. package/src/collection_editor/ui/collection_editor/properties/BlockPropertyField.tsx +3 -3
  86. package/src/collection_editor/ui/collection_editor/properties/CommonPropertyFields.tsx +3 -3
  87. package/src/collection_editor/ui/collection_editor/properties/DateTimePropertyField.tsx +8 -8
  88. package/src/collection_editor/ui/collection_editor/properties/EnumPropertyField.tsx +5 -5
  89. package/src/collection_editor/ui/collection_editor/properties/MapPropertyField.tsx +2 -2
  90. package/src/collection_editor/ui/collection_editor/properties/MarkdownPropertyField.tsx +5 -5
  91. package/src/collection_editor/ui/collection_editor/properties/NumberPropertyField.tsx +5 -5
  92. package/src/collection_editor/ui/collection_editor/properties/ReferencePropertyField.tsx +2 -2
  93. package/src/collection_editor/ui/collection_editor/properties/RelationPropertyField.tsx +37 -57
  94. package/src/collection_editor/ui/collection_editor/properties/RepeatPropertyField.tsx +2 -2
  95. package/src/collection_editor/ui/collection_editor/properties/StoragePropertyField.tsx +8 -8
  96. package/src/collection_editor/ui/collection_editor/properties/StringPropertyField.tsx +5 -5
  97. package/src/collection_editor/ui/collection_editor/properties/UrlPropertyField.tsx +3 -2
  98. package/src/collection_editor/ui/collection_editor/properties/VectorPropertyField.tsx +2 -2
  99. package/src/collection_editor/ui/collection_editor/properties/validation/ArrayPropertyValidation.tsx +2 -2
  100. package/src/collection_editor/ui/collection_editor/properties/validation/GeneralPropertyValidation.tsx +1 -1
  101. package/src/collection_editor/ui/collection_editor/properties/validation/NumberPropertyValidation.tsx +4 -7
  102. package/src/collection_editor/ui/collection_editor/properties/validation/StringPropertyValidation.tsx +4 -4
  103. package/src/collection_editor/validateCollectionJson.ts +88 -1
  104. package/src/components/ArrayContainer.tsx +3 -3
  105. package/src/components/DefaultAppBar.tsx +52 -31
  106. package/src/components/DefaultDrawer.tsx +279 -66
  107. package/src/components/DrawerNavigationItem.tsx +1 -1
  108. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +6 -5
  109. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +9 -7
  110. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +5 -5
  111. package/src/components/EntityCollectionTable/fields/VirtualTableNumberInput.tsx +12 -9
  112. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +2 -2
  113. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +1 -1
  114. package/src/components/EntityCollectionTable/table_bindings.tsx +5 -4
  115. package/src/components/EntityCollectionView/EntityCollectionView.tsx +6 -4
  116. package/src/components/EntityCollectionView/hooks/useCollectionInlineEditor.ts +1 -1
  117. package/src/components/EntityCollectionView/hooks/useKanbanDragAndDrop.ts +7 -6
  118. package/src/components/EntityDetailView.tsx +46 -24
  119. package/src/components/EntityEditView.tsx +51 -28
  120. package/src/components/EntityEditViewFormActions.tsx +4 -4
  121. package/src/components/EntityPreview.tsx +9 -4
  122. package/src/components/HomePage/HomePageDnD.tsx +3 -2
  123. package/src/components/PropertyCollectionView.tsx +1 -1
  124. package/src/components/PropertyIdCopyTooltip.tsx +1 -1
  125. package/src/components/RebaseLayout.tsx +5 -1
  126. package/src/components/RebaseNavigation.tsx +2 -2
  127. package/src/components/RebaseRouteDefs.tsx +4 -7
  128. package/src/components/RebaseShell.tsx +16 -13
  129. package/src/components/SearchIconsView.tsx +1 -8
  130. package/src/components/SelectableTable/SelectableTable.tsx +8 -11
  131. package/src/components/SelectableTable/SelectionStore.ts +1 -1
  132. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +3 -3
  133. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +3 -3
  134. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +5 -5
  135. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +3 -3
  136. package/src/components/SideEntityProvider.tsx +2 -1
  137. package/src/components/admin/RolesView.tsx +7 -2
  138. package/src/components/admin/UsersView.tsx +12 -6
  139. package/src/components/app/Drawer.tsx +9 -1
  140. package/src/components/app/Scaffold.tsx +5 -1
  141. package/src/data_export/export/export.ts +17 -17
  142. package/src/data_import/components/DataNewPropertiesMapping.tsx +1 -1
  143. package/src/editor/components/editor-bubble.tsx +32 -9
  144. package/src/editor/components/image-bubble.tsx +27 -11
  145. package/src/editor/components/index.ts +3 -3
  146. package/src/editor/components/table-bubble.tsx +79 -17
  147. package/src/editor/extensions/HighlightDecorationExtension.ts +3 -2
  148. package/src/editor/nodeViews/ReactNodeView.tsx +1 -1
  149. package/src/editor/nodeViews/TaskItemComponent.tsx +9 -8
  150. package/src/editor/schema.ts +135 -59
  151. package/src/editor/selectors/link-selector.tsx +8 -5
  152. package/src/editor/useProseMirror.ts +2 -2
  153. package/src/editor/utils/remove_classes.ts +6 -5
  154. package/src/form/EntityForm.tsx +15 -15
  155. package/src/form/EntityFormActions.tsx +2 -2
  156. package/src/form/PropertyFieldBinding.tsx +64 -64
  157. package/src/form/components/FieldHelperText.tsx +4 -4
  158. package/src/form/components/StorageUploadProgress.tsx +2 -2
  159. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +1 -1
  160. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +1 -1
  161. package/src/form/field_bindings/BlockFieldBinding.tsx +54 -53
  162. package/src/form/field_bindings/KeyValueFieldBinding.tsx +290 -289
  163. package/src/form/field_bindings/MapFieldBinding.tsx +2 -2
  164. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +2 -2
  165. package/src/form/field_bindings/MultipleRelationFieldBinding.tsx +1 -1
  166. package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +1 -1
  167. package/src/form/field_bindings/ReferenceFieldBinding.tsx +8 -6
  168. package/src/form/field_bindings/RelationFieldBinding.tsx +4 -4
  169. package/src/form/field_bindings/RepeatFieldBinding.tsx +1 -1
  170. package/src/form/field_bindings/SelectFieldBinding.tsx +1 -1
  171. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +84 -84
  172. package/src/form/field_bindings/SwitchFieldBinding.tsx +16 -16
  173. package/src/form/field_bindings/TextFieldBinding.tsx +77 -73
  174. package/src/form/field_bindings/UserSelectFieldBinding.tsx +17 -17
  175. package/src/form/validation.ts +43 -43
  176. package/src/hooks/navigation/useBuildNavigationStateController.tsx +3 -5
  177. package/src/hooks/navigation/useResolvedCollections.ts +27 -7
  178. package/src/hooks/navigation/useResolvedViews.tsx +24 -44
  179. package/src/index.ts +2 -0
  180. package/src/preview/PropertyPreview.tsx +2 -2
  181. package/src/preview/components/ImagePreview.tsx +2 -1
  182. package/src/preview/components/UrlComponentPreview.tsx +11 -2
  183. package/src/preview/components/UserPreview.tsx +1 -1
  184. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +2 -2
  185. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +4 -4
  186. package/src/preview/property_previews/ArrayOfRelationsPreview.tsx +3 -3
  187. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +3 -3
  188. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +3 -2
  189. package/src/preview/property_previews/ArrayOneOfPreview.tsx +6 -8
  190. package/src/preview/property_previews/ArrayPropertyEnumPreview.tsx +1 -1
  191. package/src/preview/property_previews/ArrayPropertyPreview.tsx +3 -3
  192. package/src/preview/property_previews/MapPropertyPreview.tsx +4 -3
  193. package/src/preview/property_previews/NumberPropertyPreview.tsx +5 -3
  194. package/src/preview/property_previews/StringPropertyPreview.tsx +10 -8
  195. package/src/types/components/EntityFormActionsProps.tsx +1 -1
  196. package/src/types/components/EntityFormProps.tsx +2 -2
  197. package/src/types/fields.tsx +2 -2
  198. package/dist/CollectionEditorDialog-BXIh2AXg.js.map +0 -1
  199. package/dist/ContentHomePage-BQZWuOFb.js +0 -1784
  200. package/dist/ContentHomePage-BQZWuOFb.js.map +0 -1
  201. package/dist/ExportCollectionAction-CMdiiv1L.js.map +0 -1
  202. package/dist/PropertyEditView-BB5xjnhZ.js.map +0 -1
  203. package/dist/RoleChip-QtUFXeTp.js +0 -67
  204. package/dist/RoleChip-QtUFXeTp.js.map +0 -1
  205. package/dist/RolesView-CULIHWZ9.js +0 -437
  206. package/dist/RolesView-CULIHWZ9.js.map +0 -1
  207. package/dist/UsersView-D7_AtJ44.js +0 -408
  208. package/dist/UsersView-D7_AtJ44.js.map +0 -1
  209. package/dist/collection_editor/types/config_permissions.d.ts +0 -19
  210. package/dist/index-CoSNm3e3.js.map +0 -1
  211. package/dist/index-D5OQhv-T.js.map +0 -1
  212. package/dist/markdown-z2Ir7Cgo.js.map +0 -1
  213. package/dist/util-DtbWD7LF.js.map +0 -1
  214. package/src/collection_editor/types/config_permissions.ts +0 -20
@@ -53,7 +53,7 @@ export function MapPropertyField({ disabled, getData, allowDataInference, proper
53
53
  const propertiesPath = idToPropertiesPath(fullId);
54
54
  const propertiesOrderPath = namespaceToPropertiesOrderPath(namespace);
55
55
 
56
- const currentPropertiesOrder: string[] = getIn(values, propertiesOrderPath) ?? Object.keys(getIn(values, namespaceToPropertiesPath(namespace)));
56
+ const currentPropertiesOrder: string[] = (getIn(values, propertiesOrderPath) as string[] | undefined) ?? Object.keys(getIn(values, namespaceToPropertiesPath(namespace)) as object ?? {});
57
57
 
58
58
  setFieldValue(propertiesPath, undefined, false);
59
59
  setFieldValue(propertiesOrderPath, currentPropertiesOrder.filter((p) => p !== propertyKey), false);
@@ -139,7 +139,7 @@ export function MapPropertyField({ disabled, getData, allowDataInference, proper
139
139
  onDelete={deleteProperty}
140
140
  propertyKey={selectedPropertyKey}
141
141
  propertyNamespace={selectedPropertyNamespace}
142
- property={selectedProperty}
142
+ property={selectedProperty as Property | undefined}
143
143
  existingProperty={Boolean(selectedPropertyKey)}
144
144
  autoUpdateId={!selectedPropertyKey}
145
145
  autoOpenTypeSelect={!selectedPropertyKey}
@@ -41,15 +41,15 @@ export function MarkdownPropertyField({
41
41
  const htmlPath = `${baseMarkdownPath}.html`;
42
42
  const transformPastedTextPath = `${baseMarkdownPath}.transformPastedText`;
43
43
 
44
- const fileNameValue = getIn(values, fileName) ?? "{rand}_{file}";
45
- const storagePathValue = getIn(values, storagePath) ?? "/";
44
+ const fileNameValue = (getIn(values, fileName) as string | undefined) ?? "{rand}_{file}";
45
+ const storagePathValue = (getIn(values, storagePath) as string | undefined) ?? "/";
46
46
  const maxSizeValue = getIn(values, maxSize);
47
47
 
48
48
  // Markdown config values - check if markdown is an object or boolean
49
49
  const markdownValue = getIn(values, "markdown");
50
50
  const isMarkdownObject = typeof markdownValue === "object" && markdownValue !== null;
51
- const htmlValue = isMarkdownObject ? (markdownValue.html ?? true) : true;
52
- const transformPastedTextValue = isMarkdownObject ? (markdownValue.transformPastedText ?? false) : false;
51
+ const htmlValue = isMarkdownObject ? (((markdownValue as Record<string, unknown>).html as boolean | undefined) ?? true) : true;
52
+ const transformPastedTextValue = isMarkdownObject ? (((markdownValue as Record<string, unknown>).transformPastedText as boolean | undefined) ?? false) : false;
53
53
 
54
54
  const hasFilenameCallback = typeof fileNameValue === "function";
55
55
  const hasStoragePathCallback = typeof storagePathValue === "function";
@@ -209,7 +209,7 @@ export function MarkdownPropertyField({
209
209
  setFieldValue("defaultValue", e.target.value === "" ? undefined : e.target.value);
210
210
  }}
211
211
  label={t("default_value")}
212
- value={getIn(values, "defaultValue") ?? ""}/>
212
+ value={(getIn(values, "defaultValue") as string | undefined) ?? ""}/>
213
213
 
214
214
  </div>
215
215
  </>
@@ -15,12 +15,12 @@ export function NumberPropertyField({ disabled }: {
15
15
  const { t } = useTranslation();
16
16
 
17
17
  const columnTypePath = "columnType";
18
- const columnTypeValue: string | undefined = getIn(values, columnTypePath);
19
- const columnTypeError: string | undefined = getIn(touched, columnTypePath) && getIn(errors, columnTypePath);
18
+ const columnTypeValue: string | undefined = getIn(values, columnTypePath) as string | undefined;
19
+ const columnTypeError: string | undefined = (getIn(touched, columnTypePath) && getIn(errors, columnTypePath)) as string | undefined;
20
20
 
21
21
  const isIdPath = "isId";
22
- const isIdValue: string | boolean | undefined = getIn(values, isIdPath);
23
- const isIdError: string | undefined = getIn(touched, isIdPath) && getIn(errors, isIdPath);
22
+ const isIdValue: string | boolean | undefined = getIn(values, isIdPath) as string | boolean | undefined;
23
+ const isIdError: string | undefined = (getIn(touched, isIdPath) && getIn(errors, isIdPath)) as string | undefined;
24
24
 
25
25
  return (
26
26
  <>
@@ -109,7 +109,7 @@ export function NumberPropertyField({ disabled }: {
109
109
  setFieldValue("defaultValue", e.target.value === "" ? undefined : parseFloat(e.target.value));
110
110
  }}
111
111
  label={t("default_value")}
112
- value={getIn(values, "defaultValue") ?? ""}/>
112
+ value={(getIn(values, "defaultValue") as string | number | undefined) ?? ""}/>
113
113
 
114
114
  </div>
115
115
  </>
@@ -34,8 +34,8 @@ export function ReferencePropertyField({
34
34
  </div>;
35
35
 
36
36
  const pathPath = asString ? "reference.slug" : (multiple ? "of.slug" : "path");
37
- const pathValue: string | undefined = getIn(values, pathPath);
38
- const pathError: string | undefined = showErrors && getIn(errors, pathPath);
37
+ const pathValue: string | undefined = getIn(values, pathPath) as string | undefined;
38
+ const pathError: string | undefined = (showErrors && getIn(errors, pathPath)) as string | undefined;
39
39
 
40
40
  return (
41
41
  <>
@@ -14,16 +14,25 @@ import { CollectionsSelect } from "./ReferencePropertyField";
14
14
 
15
15
  const ON_ACTION_OPTIONS: OnAction[] = ["cascade", "restrict", "no action", "set null", "set default"];
16
16
 
17
+ function getTargetSlug(target?: string | (() => string | { slug: string } | Record<string, unknown>)): string {
18
+ if (!target) return "";
19
+ if (typeof target === "string") return target;
20
+ try {
21
+ const resolved = target();
22
+ if (typeof resolved === "string") return resolved;
23
+ if (resolved && typeof resolved === "object" && "slug" in resolved && typeof resolved.slug === "string") {
24
+ return resolved.slug;
25
+ }
26
+ return "";
27
+ } catch {
28
+ return "";
29
+ }
30
+ }
31
+
17
32
  /**
18
33
  * Property editor form for `type: "relation"` properties.
19
34
  *
20
- * This component edits both:
21
- * 1. The `RelationProperty` fields on the property itself (relationName, etc.)
22
- * 2. The matching `Relation` entry in `collection.relations[]`
23
- *
24
- * When a user configures a relation property, we sync the relation config
25
- * back to the parent collection's `relations` array so saving the collection
26
- * persists everything in one go.
35
+ * This component edits the `RelationProperty` fields on the property itself (target, relationName, etc.)
27
36
  */
28
37
  export function RelationPropertyField({
29
38
  disabled,
@@ -36,37 +45,22 @@ export function RelationPropertyField({
36
45
  values,
37
46
  errors,
38
47
  setFieldValue
39
- } = useFormex<RelationProperty & { id?: string; _relationConfig?: Record<string, unknown> }>();
48
+ } = useFormex<RelationProperty & { id?: string }>();
40
49
 
41
50
  const collectionRegistry = useCollectionRegistryController();
42
51
 
43
- // ─── Read the parent collection form to sync `relations[]` ───
44
- // The PropertyForm is nested inside a parent Formex for the whole collection.
45
- // We reach it via a second useFormex keyed to the parent context.
46
- // However, the PropertyForm uses its own isolated Formex, so we can't
47
- // directly access the parent. Instead, we store the relation config
48
- // on the property itself and let the save logic merge it.
49
- //
50
- // We store the full relation config on a transient `_relationConfig` key
51
- // so the consumer (CollectionPropertiesEditorForm / save logic) can
52
- // extract it and place it in `collection.relations[]`.
53
-
54
52
  const relationName = values.relationName ?? "";
55
- // Transient config object stored on the property for editor use.
56
- // Contains standard Relation fields plus `_targetSlug` for the UI dropdown.
57
- const relationConfig: Record<string, unknown> = (values._relationConfig as Record<string, unknown>) ?? {};
58
-
59
- const targetSlug = (relationConfig._targetSlug as string) ?? "";
60
- const cardinality = (relationConfig.cardinality as string) ?? "one";
61
- const direction = (relationConfig.direction as string) ?? "owning";
62
- const localKey = (relationConfig.localKey as string) ?? "";
63
- const foreignKeyOnTarget = (relationConfig.foreignKeyOnTarget as string) ?? "";
64
- const through = relationConfig.through as Record<string, string> | undefined;
53
+ const targetSlug = getTargetSlug(values.target);
54
+ const cardinality = values.cardinality ?? "one";
55
+ const direction = values.direction ?? "owning";
56
+ const localKey = values.localKey ?? "";
57
+ const foreignKeyOnTarget = values.foreignKeyOnTarget ?? "";
58
+ const through = values.through;
65
59
  const throughTable = through?.table ?? "";
66
60
  const throughSourceColumn = through?.sourceColumn ?? "";
67
61
  const throughTargetColumn = through?.targetColumn ?? "";
68
- const onUpdate = (relationConfig.onUpdate as string) ?? "no action";
69
- const onDelete = (relationConfig.onDelete as string) ?? "no action";
62
+ const onUpdate = values.onUpdate ?? "no action";
63
+ const onDelete = values.onDelete ?? "no action";
70
64
 
71
65
  // Whether to show the junction table section
72
66
  const showThrough = cardinality === "many" && direction === "owning";
@@ -75,26 +69,12 @@ export function RelationPropertyField({
75
69
  // Whether to show the foreign key on target field
76
70
  const showForeignKey = direction === "inverse";
77
71
 
78
- const updateRelationConfig = useCallback(
79
- (patch: Record<string, unknown>) => {
80
- const current = (values._relationConfig as Record<string, unknown>) ?? {};
81
- setFieldValue("_relationConfig" as keyof (RelationProperty & { _relationConfig?: unknown }), { ...current,
82
- ...patch });
83
- },
84
- [values, setFieldValue]
85
- );
86
-
87
72
  const updateThrough = useCallback(
88
73
  (patch: Record<string, unknown>) => {
89
- const current = (values._relationConfig as Record<string, unknown>) ?? {};
90
- const currentThrough = (current.through as Record<string, unknown>) ?? {};
91
- setFieldValue("_relationConfig" as keyof (RelationProperty & { _relationConfig?: unknown }), {
92
- ...current,
93
- through: { ...currentThrough,
94
- ...patch }
95
- });
74
+ const currentThrough = values.through ?? { table: "", sourceColumn: "", targetColumn: "" };
75
+ setFieldValue("through", { ...currentThrough, ...patch });
96
76
  },
97
- [values, setFieldValue]
77
+ [values.through, setFieldValue]
98
78
  );
99
79
 
100
80
  // Auto-generate relationName from target collection slug
@@ -102,7 +82,7 @@ export function RelationPropertyField({
102
82
  if (targetSlug && !relationName) {
103
83
  setFieldValue("relationName", targetSlug);
104
84
  }
105
- }, [targetSlug]);
85
+ }, [targetSlug, relationName, setFieldValue]);
106
86
 
107
87
  const collections: EntityCollection[] = collectionRegistry?.collections ?? [];
108
88
 
@@ -112,10 +92,10 @@ export function RelationPropertyField({
112
92
  <div className={"col-span-12"}>
113
93
  <CollectionsSelect
114
94
  disabled={disabled}
115
- pathPath={"_relationConfig._targetSlug"}
95
+ pathPath={"target"}
116
96
  value={targetSlug}
117
97
  setFieldValue={(_, value) => {
118
- updateRelationConfig({ _targetSlug: value });
98
+ setFieldValue("target", value);
119
99
  // Auto-generate relation name from target
120
100
  if (!relationName || relationName === targetSlug) {
121
101
  setFieldValue("relationName", value);
@@ -152,7 +132,7 @@ export function RelationPropertyField({
152
132
  <div className={"col-span-12 sm:col-span-6"}>
153
133
  <Select
154
134
  value={cardinality}
155
- onValueChange={(v) => updateRelationConfig({ cardinality: v })}
135
+ onValueChange={(v) => setFieldValue("cardinality", v as "one" | "many")}
156
136
  label={"Cardinality"}
157
137
  disabled={disabled}
158
138
  fullWidth
@@ -184,7 +164,7 @@ export function RelationPropertyField({
184
164
  <div className={"col-span-12 sm:col-span-6"}>
185
165
  <Select
186
166
  value={direction}
187
- onValueChange={(v) => updateRelationConfig({ direction: v })}
167
+ onValueChange={(v) => setFieldValue("direction", v as "owning" | "inverse")}
188
168
  label={"Direction"}
189
169
  disabled={disabled}
190
170
  fullWidth
@@ -218,7 +198,7 @@ export function RelationPropertyField({
218
198
  <TextField
219
199
  value={localKey}
220
200
  onChange={(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) =>
221
- updateRelationConfig({ localKey: e.target.value })
201
+ setFieldValue("localKey", e.target.value)
222
202
  }
223
203
  label={"Local key (foreign key column on this table)"}
224
204
  disabled={disabled}
@@ -236,7 +216,7 @@ export function RelationPropertyField({
236
216
  <TextField
237
217
  value={foreignKeyOnTarget}
238
218
  onChange={(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) =>
239
- updateRelationConfig({ foreignKeyOnTarget: e.target.value })
219
+ setFieldValue("foreignKeyOnTarget", e.target.value)
240
220
  }
241
221
  label={"Foreign key on target table"}
242
222
  disabled={disabled}
@@ -305,7 +285,7 @@ export function RelationPropertyField({
305
285
  <div className={"col-span-12 sm:col-span-6"}>
306
286
  <Select
307
287
  value={onUpdate}
308
- onValueChange={(v) => updateRelationConfig({ onUpdate: v })}
288
+ onValueChange={(v) => setFieldValue("onUpdate", v as OnAction)}
309
289
  label={"On update"}
310
290
  disabled={disabled}
311
291
  fullWidth
@@ -325,7 +305,7 @@ export function RelationPropertyField({
325
305
  <div className={"col-span-12 sm:col-span-6"}>
326
306
  <Select
327
307
  value={onDelete}
328
- onValueChange={(v) => updateRelationConfig({ onDelete: v })}
308
+ onValueChange={(v) => setFieldValue("onDelete", v as OnAction)}
329
309
  label={"On delete"}
330
310
  disabled={disabled}
331
311
  fullWidth
@@ -33,8 +33,8 @@ export function RepeatPropertyField({
33
33
  } = useFormex<ArrayProperty>();
34
34
 
35
35
  const [propertyDialogOpen, setPropertyDialogOpen] = useState(false);
36
- const ofProperty = getIn(values, "of");
37
- const ofPropertyError = getIn(touched, "of") && getIn(errors, "of");
36
+ const ofProperty = getIn(values, "of") as Property | undefined;
37
+ const ofPropertyError = (getIn(touched, "of") && getIn(errors, "of")) as string | undefined;
38
38
 
39
39
  const onPropertyChanged = ({ id, property, namespace }:
40
40
  { id?: string, property: Property, namespace?: string }) => {
@@ -61,16 +61,16 @@ export function StoragePropertyField({
61
61
  const imageResizeFormat = `${imageResize}.format`;
62
62
  const imageResizeQuality = `${imageResize}.quality`;
63
63
 
64
- const fileNameValue = getIn(values, fileName) ?? "{rand}_{file}";
65
- const storagePathValue = getIn(values, storagePath) ?? "/";
66
- const maxSizeValue = getIn(values, maxSize);
64
+ const fileNameValue = (getIn(values, fileName) as string | undefined) ?? "{rand}_{file}";
65
+ const storagePathValue = (getIn(values, storagePath) as string | undefined) ?? "/";
66
+ const maxSizeValue = getIn(values, maxSize) as number | undefined;
67
67
 
68
68
  // Image resize values
69
- const imageResizeMaxWidthValue = getIn(values, imageResizeMaxWidth);
70
- const imageResizeMaxHeightValue = getIn(values, imageResizeMaxHeight);
71
- const imageResizeModeValue = getIn(values, imageResizeMode) ?? "cover";
72
- const imageResizeFormatValue = getIn(values, imageResizeFormat) ?? "original";
73
- const imageResizeQualityValue = getIn(values, imageResizeQuality);
69
+ const imageResizeMaxWidthValue = getIn(values, imageResizeMaxWidth) as number | undefined;
70
+ const imageResizeMaxHeightValue = getIn(values, imageResizeMaxHeight) as number | undefined;
71
+ const imageResizeModeValue = (getIn(values, imageResizeMode) as string | undefined) ?? "cover";
72
+ const imageResizeFormatValue = (getIn(values, imageResizeFormat) as string | undefined) ?? "original";
73
+ const imageResizeQualityValue = getIn(values, imageResizeQuality) as number | undefined;
74
74
 
75
75
  const storedValue = getIn(values, acceptedFiles);
76
76
  const fileTypesValue: string[] | undefined = Array.isArray(storedValue) ? storedValue : undefined;
@@ -21,12 +21,12 @@ export function StringPropertyField({
21
21
  const { t } = useTranslation();
22
22
 
23
23
  const columnTypePath = "columnType";
24
- const columnTypeValue: string | undefined = getIn(values, columnTypePath);
25
- const columnTypeError: string | undefined = getIn(touched, columnTypePath) && getIn(errors, columnTypePath);
24
+ const columnTypeValue: string | undefined = getIn(values, columnTypePath) as string | undefined;
25
+ const columnTypeError: string | undefined = (getIn(touched, columnTypePath) && getIn(errors, columnTypePath)) as string | undefined;
26
26
 
27
27
  const isIdPath = "isId";
28
- const isIdValue: string | boolean | undefined = getIn(values, isIdPath);
29
- const isIdError: string | undefined = getIn(touched, isIdPath) && getIn(errors, isIdPath);
28
+ const isIdValue: string | boolean | undefined = getIn(values, isIdPath) as string | boolean | undefined;
29
+ const isIdError: string | undefined = (getIn(touched, isIdPath) && getIn(errors, isIdPath)) as string | undefined;
30
30
 
31
31
  return (
32
32
  <>
@@ -140,7 +140,7 @@ export function StringPropertyField({
140
140
  setFieldValue("defaultValue", e.target.value === "" ? undefined : e.target.value);
141
141
  }}
142
142
  label={t("default_value")}
143
- value={getIn(values, "defaultValue") ?? ""}/>
143
+ value={(getIn(values, "defaultValue") as string | undefined) ?? ""}/>
144
144
 
145
145
  </div>
146
146
  </>
@@ -15,7 +15,8 @@ export function UrlPropertyField({
15
15
 
16
16
  const { values, setFieldValue } = useFormex();
17
17
 
18
- const urlValue = getIn(values, "url");
18
+ const urlRawValue = getIn(values, "url");
19
+ const urlValue = typeof urlRawValue === "string" ? urlRawValue : "[NONE]";
19
20
 
20
21
  return (
21
22
  <>
@@ -82,7 +83,7 @@ export function UrlPropertyField({
82
83
  setFieldValue("defaultValue", e.target.value === "" ? undefined : e.target.value);
83
84
  }}
84
85
  label={"Default value"}
85
- value={getIn(values, "defaultValue") ?? ""}/>
86
+ value={(getIn(values, "defaultValue") as string | undefined) ?? ""}/>
86
87
 
87
88
  </div>
88
89
  </>
@@ -9,8 +9,8 @@ export function VectorPropertyField({ disabled }: {
9
9
  const { values, setFieldValue, touched, errors } = useFormex();
10
10
 
11
11
  const dimensionsPath = "dimensions";
12
- const dimensionsValue = getIn(values, dimensionsPath);
13
- const dimensionsError = getIn(touched, dimensionsPath) && getIn(errors, dimensionsPath);
12
+ const dimensionsValue = getIn(values, dimensionsPath) as number | undefined;
13
+ const dimensionsError = (getIn(touched, dimensionsPath) && getIn(errors, dimensionsPath)) as string | undefined;
14
14
 
15
15
  return (
16
16
  <div className={"col-span-12"}>
@@ -30,7 +30,7 @@ export function ArrayPropertyValidation({
30
30
  <GeneralPropertyValidation disabled={disabled}/>
31
31
 
32
32
  {min && <div className={"col-span-6"}>
33
- <DebouncedTextField value={getIn(values, validationMin)}
33
+ <DebouncedTextField value={getIn(values, validationMin) as number | undefined}
34
34
  disabled={disabled}
35
35
  label={t("min_length")}
36
36
  name={validationMin}
@@ -39,7 +39,7 @@ export function ArrayPropertyValidation({
39
39
  onChange={handleChange}/>
40
40
  </div>}
41
41
  {max && <div className={"col-span-6"}>
42
- <DebouncedTextField value={getIn(values, validationMax)}
42
+ <DebouncedTextField value={getIn(values, validationMax) as number | undefined}
43
43
  disabled={disabled}
44
44
  label={t("max_length")}
45
45
  name={validationMax}
@@ -52,7 +52,7 @@ export function GeneralPropertyValidation({ disabled }: {
52
52
  {getIn(values, validationRequired) && <div className={"col-span-12"}>
53
53
  <DebouncedTextField
54
54
  disabled={disabled}
55
- value={getIn(values, validationRequiredMessage)}
55
+ value={getIn(values, validationRequiredMessage) as string | undefined}
56
56
  label={t("required_message")}
57
57
  name={validationRequiredMessage}
58
58
  size="small"
@@ -31,7 +31,7 @@ export function NumberPropertyValidation({ disabled }: {
31
31
 
32
32
 
33
33
  <div className={"col-span-6"}>
34
- <DebouncedTextField value={getIn(values, validationMin)}
34
+ <DebouncedTextField value={getIn(values, validationMin) as number | undefined}
35
35
  label={t("min_value")}
36
36
  name={validationMin}
37
37
  type="number"
@@ -41,12 +41,11 @@ export function NumberPropertyValidation({ disabled }: {
41
41
  </div>
42
42
 
43
43
  <div className={"col-span-6"}>
44
- <DebouncedTextField value={getIn(values, validationMax)}
44
+ <DebouncedTextField value={getIn(values, validationMax) as number | undefined}
45
45
  label={t("max_value")}
46
46
  name={validationMax}
47
47
  type="number"
48
48
  size="small"
49
-
50
49
  disabled={disabled}
51
50
  onChange={handleChange}/>
52
51
  </div>
@@ -54,24 +53,22 @@ export function NumberPropertyValidation({ disabled }: {
54
53
 
55
54
  <div className={"col-span-6"}>
56
55
  <DebouncedTextField
57
- value={getIn(values, validationLessThan)}
56
+ value={getIn(values, validationLessThan) as number | undefined}
58
57
  label={t("less_than")}
59
58
  name={validationLessThan}
60
59
  type="number"
61
60
  size="small"
62
-
63
61
  disabled={disabled}
64
62
  onChange={handleChange}/>
65
63
  </div>
66
64
 
67
65
  <div className={"col-span-6"}>
68
66
  <DebouncedTextField
69
- value={getIn(values, validationMoreThan)}
67
+ value={getIn(values, validationMoreThan) as number | undefined}
70
68
  label={t("more_than")}
71
69
  name={validationMoreThan}
72
70
  type="number"
73
71
  size="small"
74
-
75
72
  disabled={disabled}
76
73
  onChange={handleChange}/>
77
74
  </div>
@@ -49,7 +49,7 @@ export function StringPropertyValidation({
49
49
  const matchesError = getIn(errors, validationMatches);
50
50
 
51
51
  const matchesValue = getIn(values, validationMatches);
52
- const matchesStringValue = typeof matchesValue === "string" ? matchesValue : serializeRegExp(matchesValue);
52
+ const matchesStringValue = typeof matchesValue === "string" ? matchesValue : serializeRegExp(matchesValue as RegExp);
53
53
  return (
54
54
  <div className={"grid grid-cols-12 gap-2"}>
55
55
 
@@ -101,7 +101,7 @@ export function StringPropertyValidation({
101
101
  <div className={"grid grid-cols-12 gap-2 col-span-12"}>
102
102
  {length && <div className={"col-span-4"}>
103
103
  <DebouncedTextField
104
- value={getIn(values, validationLength)}
104
+ value={getIn(values, validationLength) as number | undefined}
105
105
  label={t("exact_length")}
106
106
  name={validationLength}
107
107
  type="number"
@@ -112,7 +112,7 @@ export function StringPropertyValidation({
112
112
  </div>}
113
113
 
114
114
  {min && <div className={"col-span-4"}>
115
- <DebouncedTextField value={getIn(values, validationMin)}
115
+ <DebouncedTextField value={getIn(values, validationMin) as number | undefined}
116
116
  label={t("min_length")}
117
117
  name={validationMin}
118
118
  type="number"
@@ -123,7 +123,7 @@ export function StringPropertyValidation({
123
123
  </div>}
124
124
 
125
125
  {max && <div className={"col-span-4"}>
126
- <DebouncedTextField value={getIn(values, validationMax)}
126
+ <DebouncedTextField value={getIn(values, validationMax) as number | undefined}
127
127
  label={t("max_length")}
128
128
  name={validationMax}
129
129
  type="number"
@@ -10,8 +10,11 @@ const VALID_DATA_TYPES = [
10
10
  "date",
11
11
  "geopoint",
12
12
  "reference",
13
+ "relation",
13
14
  "array",
14
- "map"
15
+ "map",
16
+ "vector",
17
+ "binary"
15
18
  ] as const;
16
19
 
17
20
  type DataType = typeof VALID_DATA_TYPES[number];
@@ -109,6 +112,90 @@ function validateProperty(
109
112
  }
110
113
  }
111
114
 
115
+ // Validate relation property
116
+ if (property.dataType === "relation") {
117
+ if (property.target !== undefined && typeof property.target !== "string" && typeof property.target !== "function") {
118
+ errors.push({
119
+ path: `${path}.target`,
120
+ message: "Must be a string (collection slug) or a function"
121
+ });
122
+ }
123
+ if (property.cardinality !== undefined && property.cardinality !== "one" && property.cardinality !== "many") {
124
+ errors.push({
125
+ path: `${path}.cardinality`,
126
+ message: "Must be either 'one' or 'many'"
127
+ });
128
+ }
129
+ if (property.direction !== undefined && property.direction !== "owning" && property.direction !== "inverse") {
130
+ errors.push({
131
+ path: `${path}.direction`,
132
+ message: "Must be either 'owning' or 'inverse'"
133
+ });
134
+ }
135
+ if (property.localKey !== undefined && typeof property.localKey !== "string") {
136
+ errors.push({
137
+ path: `${path}.localKey`,
138
+ message: "Must be a string"
139
+ });
140
+ }
141
+ if (property.foreignKeyOnTarget !== undefined && typeof property.foreignKeyOnTarget !== "string") {
142
+ errors.push({
143
+ path: `${path}.foreignKeyOnTarget`,
144
+ message: "Must be a string"
145
+ });
146
+ }
147
+ if (property.through !== undefined) {
148
+ if (typeof property.through !== "object" || property.through === null) {
149
+ errors.push({
150
+ path: `${path}.through`,
151
+ message: "Must be an object"
152
+ });
153
+ } else {
154
+ const throughObj = property.through as Record<string, unknown>;
155
+ if (throughObj.table !== undefined && typeof throughObj.table !== "string") {
156
+ errors.push({
157
+ path: `${path}.through.table`,
158
+ message: "Must be a string"
159
+ });
160
+ }
161
+ if (throughObj.sourceColumn !== undefined && typeof throughObj.sourceColumn !== "string") {
162
+ errors.push({
163
+ path: `${path}.through.sourceColumn`,
164
+ message: "Must be a string"
165
+ });
166
+ }
167
+ if (throughObj.targetColumn !== undefined && typeof throughObj.targetColumn !== "string") {
168
+ errors.push({
169
+ path: `${path}.through.targetColumn`,
170
+ message: "Must be a string"
171
+ });
172
+ }
173
+ }
174
+ }
175
+ if (property.onUpdate !== undefined && typeof property.onUpdate !== "string") {
176
+ errors.push({
177
+ path: `${path}.onUpdate`,
178
+ message: "Must be a string"
179
+ });
180
+ }
181
+ if (property.onDelete !== undefined && typeof property.onDelete !== "string") {
182
+ errors.push({
183
+ path: `${path}.onDelete`,
184
+ message: "Must be a string"
185
+ });
186
+ }
187
+ }
188
+
189
+ // Validate vector property
190
+ if (property.dataType === "vector") {
191
+ if (property.dimensions !== undefined && (typeof property.dimensions !== "number" || isNaN(property.dimensions) || property.dimensions <= 0)) {
192
+ errors.push({
193
+ path: `${path}.dimensions`,
194
+ message: "Must be a positive number"
195
+ });
196
+ }
197
+ }
198
+
112
199
  // Validate storage config for string
113
200
  if (property.dataType === "string" && property.storage) {
114
201
  if (typeof property.storage !== "object") {
@@ -60,7 +60,7 @@ export interface ArrayContainerProps<T> {
60
60
  max?: number;
61
61
  }
62
62
 
63
- const buildIdsMap = (value: any[]) =>
63
+ const buildIdsMap = (value: unknown[]) =>
64
64
  value && Array.isArray(value) && value.length > 0
65
65
  ? value
66
66
  .map((v, index) => {
@@ -143,7 +143,7 @@ function SortableItem({
143
143
  type ArrayContainerItemProps = {
144
144
  nodeRef: (node: HTMLElement | null) => void;
145
145
  style: React.CSSProperties;
146
- dragHandleProps: any;
146
+ dragHandleProps: Record<string, unknown>;
147
147
  index: number;
148
148
  internalId: number;
149
149
  size?: "small" | "medium";
@@ -220,7 +220,7 @@ export function ArrayItemOptions({
220
220
  sortable,
221
221
  addInIndex
222
222
  }: {
223
- dragHandleProps: any;
223
+ dragHandleProps: Record<string, unknown>;
224
224
  direction?: "row" | "column";
225
225
  disabled: boolean;
226
226
  remove: (index: number) => void;