@rebasepro/admin 0.0.1-canary.eae7889 → 0.1.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 (197) hide show
  1. package/dist/{CollectionEditorDialog-B2M9lCyL.js → CollectionEditorDialog-MbvXGzEq.js} +42 -31
  2. package/dist/CollectionEditorDialog-MbvXGzEq.js.map +1 -0
  3. package/dist/{CollectionsStudioView-WG6soyfs.js → CollectionsStudioView-D9X6aiAr.js} +12 -12
  4. package/dist/CollectionsStudioView-D9X6aiAr.js.map +1 -0
  5. package/dist/{ContentHomePage-CDF_a6Lp.js → ContentHomePage-CfVB1eUo.js} +26 -26
  6. package/dist/ContentHomePage-CfVB1eUo.js.map +1 -0
  7. package/dist/{ExportCollectionAction-Dc0VOWMN.js → ExportCollectionAction-CUwJg4F9.js} +2 -2
  8. package/dist/{ExportCollectionAction-Dc0VOWMN.js.map → ExportCollectionAction-CUwJg4F9.js.map} +1 -1
  9. package/dist/{ImportCollectionAction-DpCagAOy.js → ImportCollectionAction-DGa_SF_8.js} +2 -2
  10. package/dist/{ImportCollectionAction-DpCagAOy.js.map → ImportCollectionAction-DGa_SF_8.js.map} +1 -1
  11. package/dist/{PropertyEditView-DS67DxoT.js → PropertyEditView-C4nlYmAc.js} +82 -104
  12. package/dist/PropertyEditView-C4nlYmAc.js.map +1 -0
  13. package/dist/{RolesView-CIuYBimF.js → RolesView-CNWxnR8e.js} +7 -5
  14. package/dist/RolesView-CNWxnR8e.js.map +1 -0
  15. package/dist/{UsersView-B5zelXnH.js → UsersView-YiTIcXkA.js} +14 -35
  16. package/dist/UsersView-YiTIcXkA.js.map +1 -0
  17. package/dist/collection_editor/ConfigControllerProvider.d.ts +0 -4
  18. package/dist/collection_editor/types/collection_editor_controller.d.ts +6 -3
  19. package/dist/collection_editor/types/config_controller.d.ts +14 -7
  20. package/dist/collection_editor/ui/AddKanbanColumnAction.d.ts +3 -2
  21. package/dist/collection_editor/ui/CollectionViewHeaderAction.d.ts +3 -2
  22. package/dist/collection_editor/ui/EditorCollectionAction.d.ts +1 -1
  23. package/dist/collection_editor/ui/EditorCollectionActionStart.d.ts +1 -1
  24. package/dist/collection_editor/ui/EditorEntityAction.d.ts +1 -1
  25. package/dist/collection_editor/ui/KanbanSetupAction.d.ts +3 -2
  26. package/dist/collection_editor/ui/PropertyAddColumnComponent.d.ts +3 -2
  27. package/dist/collection_editor/ui/collection_editor/CollectionDetailsForm.d.ts +3 -4
  28. package/dist/collection_editor/ui/collection_editor/CollectionEditorDialog.d.ts +2 -3
  29. package/dist/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +1 -2
  30. package/dist/collection_editor/ui/collection_editor/SubcollectionsEditTab.d.ts +3 -2
  31. package/dist/collection_editor_ui.js +3 -3
  32. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
  33. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +1 -1
  34. package/dist/components/EntityCollectionTable/column_utils.d.ts +2 -2
  35. package/dist/components/EntityCollectionTable/fields/TableMultipleRelationField.d.ts +1 -1
  36. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +1 -1
  37. package/dist/components/EntityCollectionTable/fields/TableRelationField.d.ts +1 -1
  38. package/dist/components/EntityCollectionTable/fields/TableRelationSelectorField.d.ts +2 -2
  39. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +5 -1
  40. package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +3 -2
  41. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +2 -1
  42. package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +4 -2
  43. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +4 -2
  44. package/dist/components/EntityCollectionView/FiltersDialog.d.ts +2 -2
  45. package/dist/components/EntityCollectionView/SplitListView.d.ts +3 -2
  46. package/dist/components/EntityEditView.d.ts +9 -2
  47. package/dist/components/RebaseCMS.d.ts +1 -1
  48. package/dist/components/ReferenceTable/EntitySelectionTable.d.ts +2 -2
  49. package/dist/components/ReferenceWidget.d.ts +2 -2
  50. package/dist/components/RelationSelector.d.ts +1 -1
  51. package/dist/components/SelectableTable/SelectableTable.d.ts +2 -2
  52. package/dist/editor.js +2 -2
  53. package/dist/editor.js.map +1 -1
  54. package/dist/hooks/navigation/useNavigationRegistry.d.ts +2 -1
  55. package/dist/hooks/useEntityHistory.d.ts +1 -1
  56. package/dist/{index-CHxgwt6E.js → index-CtzpHzMQ.js} +11 -4
  57. package/dist/index-CtzpHzMQ.js.map +1 -0
  58. package/dist/{index-Dey5WJpO.js → index-DKlrVD1m.js} +3 -3
  59. package/dist/index-DKlrVD1m.js.map +1 -0
  60. package/dist/{index-CBhrgpR7.js → index-kHJXfLNI.js} +3 -3
  61. package/dist/index-kHJXfLNI.js.map +1 -0
  62. package/dist/index.js +79 -63
  63. package/dist/index.js.map +1 -1
  64. package/dist/{useEntityHistory-Dcj4zhGj.js → useEntityHistory-UVsSclfZ.js} +3 -1
  65. package/dist/useEntityHistory-UVsSclfZ.js.map +1 -0
  66. package/dist/util/navigation_utils.d.ts +10 -1
  67. package/dist/{util-BQ82ySL3.js → util-CwLmSpGp.js} +1653 -1257
  68. package/dist/util-CwLmSpGp.js.map +1 -0
  69. package/package.json +9 -17
  70. package/src/collection_editor/ConfigControllerProvider.tsx +19 -28
  71. package/src/collection_editor/types/collection_editor_controller.tsx +3 -3
  72. package/src/collection_editor/types/config_controller.tsx +7 -7
  73. package/src/collection_editor/ui/AddKanbanColumnAction.tsx +4 -4
  74. package/src/collection_editor/ui/CollectionViewHeaderAction.tsx +3 -3
  75. package/src/collection_editor/ui/EditorCollectionAction.tsx +3 -3
  76. package/src/collection_editor/ui/EditorCollectionActionStart.tsx +7 -7
  77. package/src/collection_editor/ui/EditorEntityAction.tsx +3 -3
  78. package/src/collection_editor/ui/HomePageEditorCollectionAction.tsx +4 -2
  79. package/src/collection_editor/ui/KanbanSetupAction.tsx +4 -3
  80. package/src/collection_editor/ui/MissingReferenceWidget.tsx +3 -2
  81. package/src/collection_editor/ui/NewCollectionButton.tsx +2 -1
  82. package/src/collection_editor/ui/NewCollectionCard.tsx +2 -1
  83. package/src/collection_editor/ui/PropertyAddColumnComponent.tsx +3 -3
  84. package/src/collection_editor/ui/collection_editor/CollectionDetailsForm.tsx +5 -50
  85. package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +12 -20
  86. package/src/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.tsx +1 -3
  87. package/src/collection_editor/ui/collection_editor/CollectionRLSTab.tsx +17 -2
  88. package/src/collection_editor/ui/collection_editor/CollectionRelationsTab.tsx +3 -3
  89. package/src/collection_editor/ui/collection_editor/CollectionStudioView.tsx +2 -1
  90. package/src/collection_editor/ui/collection_editor/CollectionsStudioView.tsx +18 -12
  91. package/src/collection_editor/ui/collection_editor/DisplaySettingsForm.tsx +1 -2
  92. package/src/collection_editor/ui/collection_editor/GetCodeDialog.tsx +1 -2
  93. package/src/collection_editor/ui/collection_editor/PropertyFieldPreview.tsx +6 -6
  94. package/src/collection_editor/ui/collection_editor/SubcollectionsEditTab.tsx +4 -4
  95. package/src/collection_editor/ui/collection_editor/properties/MapPropertyField.tsx +2 -2
  96. package/src/collection_editor/ui/collection_editor/properties/ReferencePropertyField.tsx +15 -49
  97. package/src/collection_editor/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +4 -5
  98. package/src/collection_editor/ui/collection_editor/templates/pages_template.ts +1 -1
  99. package/src/collection_editor/ui/collection_editor/templates/products_template.ts +2 -2
  100. package/src/components/DefaultAppBar.tsx +2 -2
  101. package/src/components/DefaultDrawer.tsx +25 -17
  102. package/src/components/DrawerNavigationGroup.tsx +4 -4
  103. package/src/components/DrawerNavigationItem.tsx +6 -6
  104. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +4 -4
  105. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +1 -1
  106. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +4 -4
  107. package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
  108. package/src/components/EntityCollectionTable/fields/TableMultipleRelationField.tsx +3 -3
  109. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +3 -3
  110. package/src/components/EntityCollectionTable/fields/TableRelationField.tsx +4 -4
  111. package/src/components/EntityCollectionTable/fields/TableRelationSelectorField.tsx +3 -3
  112. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +8 -2
  113. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +1 -1
  114. package/src/components/EntityCollectionTable/internal/common.tsx +5 -5
  115. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +1 -1
  116. package/src/components/EntityCollectionTable/table_bindings.tsx +45 -35
  117. package/src/components/EntityCollectionView/EntityBoardCard.tsx +18 -19
  118. package/src/components/EntityCollectionView/EntityCard.tsx +2 -2
  119. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +42 -14
  120. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +4 -3
  121. package/src/components/EntityCollectionView/EntityCollectionListView.tsx +157 -54
  122. package/src/components/EntityCollectionView/EntityCollectionView.tsx +169 -75
  123. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +23 -13
  124. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +21 -12
  125. package/src/components/EntityCollectionView/FiltersDialog.tsx +7 -7
  126. package/src/components/EntityCollectionView/SplitListView.tsx +24 -8
  127. package/src/components/EntityCollectionView/useEntityPreviewSlots.ts +33 -5
  128. package/src/components/EntityEditView.tsx +85 -85
  129. package/src/components/EntitySidePanel.tsx +18 -10
  130. package/src/components/HomePage/ContentHomePage.tsx +24 -15
  131. package/src/components/HomePage/NavigationCard.tsx +4 -4
  132. package/src/components/HomePage/NavigationGroup.tsx +2 -2
  133. package/src/components/RebaseAuthGate.tsx +2 -0
  134. package/src/components/RebaseCMS.tsx +4 -3
  135. package/src/components/RebaseNavigation.tsx +8 -5
  136. package/src/components/ReferenceTable/EntitySelectionTable.tsx +4 -4
  137. package/src/components/ReferenceWidget.tsx +3 -3
  138. package/src/components/RelationSelector.tsx +33 -5
  139. package/src/components/SelectableTable/SelectableTable.tsx +6 -6
  140. package/src/components/UserSelector.tsx +1 -1
  141. package/src/components/admin/RolesView.tsx +10 -3
  142. package/src/components/admin/UsersView.tsx +13 -25
  143. package/src/components/app/Scaffold.tsx +4 -4
  144. package/src/components/field_configs.tsx +29 -32
  145. package/src/components/history/EntityHistoryView.tsx +12 -1
  146. package/src/editor/editor.tsx +2 -2
  147. package/src/form/EntityForm.tsx +5 -4
  148. package/src/form/PropertyFieldBinding.tsx +14 -10
  149. package/src/form/components/FieldHelperText.tsx +1 -1
  150. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +3 -3
  151. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +5 -5
  152. package/src/form/field_bindings/BlockFieldBinding.tsx +4 -4
  153. package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
  154. package/src/form/field_bindings/KeyValueFieldBinding.tsx +1 -1
  155. package/src/form/field_bindings/MapFieldBinding.tsx +7 -7
  156. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +1 -1
  157. package/src/form/field_bindings/MultipleRelationFieldBinding.tsx +3 -3
  158. package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +7 -7
  159. package/src/form/field_bindings/ReferenceFieldBinding.tsx +2 -2
  160. package/src/form/field_bindings/RelationFieldBinding.tsx +4 -4
  161. package/src/form/field_bindings/RepeatFieldBinding.tsx +5 -5
  162. package/src/form/field_bindings/SelectFieldBinding.tsx +1 -1
  163. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +1 -1
  164. package/src/form/field_bindings/SwitchFieldBinding.tsx +1 -1
  165. package/src/form/field_bindings/TextFieldBinding.tsx +7 -7
  166. package/src/form/field_bindings/UserSelectFieldBinding.tsx +1 -1
  167. package/src/form/useClearRestoreValue.tsx +1 -1
  168. package/src/form/validation.ts +1 -1
  169. package/src/hooks/navigation/contexts/CollectionRegistryContext.tsx +2 -1
  170. package/src/hooks/navigation/useBuildCollectionRegistryController.tsx +15 -3
  171. package/src/hooks/navigation/useNavigationRegistry.ts +14 -3
  172. package/src/hooks/navigation/useResolvedViews.tsx +1 -3
  173. package/src/hooks/navigation/useTopLevelNavigation.ts +1 -1
  174. package/src/hooks/navigation/utils.ts +1 -1
  175. package/src/hooks/useEntityHistory.ts +7 -2
  176. package/src/preview/PropertyPreview.tsx +27 -23
  177. package/src/preview/components/StorageThumbnail.tsx +4 -1
  178. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
  179. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +1 -1
  180. package/src/preview/property_previews/ArrayOfRelationsPreview.tsx +1 -1
  181. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +3 -3
  182. package/src/preview/property_previews/StringPropertyPreview.tsx +3 -3
  183. package/src/routes/RebaseRoute.tsx +57 -11
  184. package/src/util/navigation_utils.ts +21 -2
  185. package/src/util/previews.ts +15 -6
  186. package/src/util/property_utils.tsx +3 -3
  187. package/dist/CollectionEditorDialog-B2M9lCyL.js.map +0 -1
  188. package/dist/CollectionsStudioView-WG6soyfs.js.map +0 -1
  189. package/dist/ContentHomePage-CDF_a6Lp.js.map +0 -1
  190. package/dist/PropertyEditView-DS67DxoT.js.map +0 -1
  191. package/dist/RolesView-CIuYBimF.js.map +0 -1
  192. package/dist/UsersView-B5zelXnH.js.map +0 -1
  193. package/dist/index-CBhrgpR7.js.map +0 -1
  194. package/dist/index-CHxgwt6E.js.map +0 -1
  195. package/dist/index-Dey5WJpO.js.map +0 -1
  196. package/dist/useEntityHistory-Dcj4zhGj.js.map +0 -1
  197. package/dist/util-BQ82ySL3.js.map +0 -1
@@ -45,7 +45,7 @@ export function RelationFieldBinding({
45
45
  const manyRelation = relation?.cardinality === "many";
46
46
 
47
47
  // Inline selector mode
48
- const widget = property.widget ?? "select";
48
+ const widget = property.ui?.widget ?? "select";
49
49
 
50
50
  if (widget === "select" && relation) {
51
51
  const normalizedSingle = (!manyRelation && value && !Array.isArray(value)) ? normalizeToEntityRelation(value) : null;
@@ -74,7 +74,7 @@ export function RelationFieldBinding({
74
74
  }
75
75
  }}
76
76
  disabled={disabled || isSubmitting}
77
- forceFilter={property.forceFilter}
77
+ fixedFilter={property.fixedFilter}
78
78
  size={selectorSize}
79
79
  />
80
80
 
@@ -123,7 +123,7 @@ export function RelationFieldBinding({
123
123
  collection,
124
124
  onSingleEntitySelected,
125
125
  selectedEntityIds: validValue && normalizedValue ? [normalizedValue.id] : undefined,
126
- forceFilter: property.forceFilter
126
+ fixedFilter: property.fixedFilter
127
127
  }
128
128
  );
129
129
 
@@ -149,7 +149,7 @@ export function RelationFieldBinding({
149
149
 
150
150
  {usedRelation && <RelationPreview
151
151
  disabled={!usedRelation}
152
- previewProperties={property.previewProperties}
152
+ previewProperties={property.ui?.previewProperties}
153
153
  hover={!disabled}
154
154
  size={size}
155
155
  onClick={disabled || isSubmitting ? undefined : onEntryClick}
@@ -43,7 +43,7 @@ export function RepeatFieldBinding({
43
43
  throw Error("RepeatFieldBinding misconfiguration. Property `type` is not `array`");
44
44
  }
45
45
 
46
- const minimalistView = minimalistViewProp || property.minimalistView;
46
+ const minimalistView = minimalistViewProp || property.ui?.minimalistView;
47
47
 
48
48
  if (!property.of)
49
49
  throw Error("RepeatFieldBinding misconfiguration. Property `of` not set");
@@ -56,7 +56,7 @@ export function RepeatFieldBinding({
56
56
  authController
57
57
  })
58
58
 
59
- const expanded = property.expanded === undefined ? true : property.expanded;
59
+ const expanded = property.ui?.expanded === undefined ? true : property.ui?.expanded;
60
60
  const ofProperty = property.of;
61
61
 
62
62
  const [lastAddedId, setLastAddedId] = useState<number | undefined>();
@@ -91,19 +91,19 @@ export function RepeatFieldBinding({
91
91
  </ErrorBoundary>;
92
92
  };
93
93
 
94
- const canAddElements = !property.disabled && !isSubmitting && !disabled && (property.canAddElements || property.canAddElements === undefined);
94
+ const canAddElements = !property.ui?.disabled && !isSubmitting && !disabled && (property.canAddElements || property.canAddElements === undefined);
95
95
  const sortable = property.sortable === undefined ? true : property.sortable;
96
96
  const arrayContainer = <ArrayContainer droppableId={propertyKey}
97
97
  addLabel={property.name ? t("add_to_field", { fieldName: property.name }) : t("add_entry")}
98
98
  value={value ?? []}
99
99
  buildEntry={buildEntry}
100
100
  onInternalIdAdded={setLastAddedId}
101
- disabled={isSubmitting || Boolean(property.disabled)}
101
+ disabled={isSubmitting || Boolean(property.ui?.disabled)}
102
102
  canAddElements={canAddElements}
103
103
  sortable={sortable}
104
104
  newDefaultEntry={getDefaultValueFor(property.of)}
105
105
  onValueChange={(value) => setFieldValue(propertyKey, value)}
106
- className={property.widthPercentage !== undefined ? "mt-8" : undefined}
106
+ className={property.ui?.widthPercentage !== undefined ? "mt-8" : undefined}
107
107
  />;
108
108
 
109
109
  const title = (<>
@@ -68,7 +68,7 @@ export function SelectFieldBinding({
68
68
  />
69
69
  </PropertyIdCopyTooltip>}
70
70
  endAdornment={
71
- property.clearable && !disabled && <IconButton
71
+ property.ui?.clearable && !disabled && <IconButton
72
72
  size="small"
73
73
  onClick={handleClearClick}>
74
74
  <XIcon/>
@@ -63,7 +63,7 @@ export function StorageUploadFieldBinding({
63
63
  const authController = useAuthController();
64
64
 
65
65
  const storageSource = useStorageSource(context.collection);
66
- const disabled = isReadOnly(property) || !!property.disabled || isSubmitting || context.disabled;
66
+ const disabled = isReadOnly(property) || !!property.ui?.disabled || isSubmitting || context.disabled;
67
67
 
68
68
  const {
69
69
  internalValue,
@@ -43,7 +43,7 @@ export const SwitchFieldBinding = function SwitchFieldBinding({
43
43
  value={value}
44
44
  onValueChange={(v) => setValue(v)}
45
45
  error={showError}
46
- className={property.widthPercentage !== undefined ? "mt-8" : undefined}
46
+ className={property.ui?.widthPercentage !== undefined ? "mt-8" : undefined}
47
47
  label={<LabelWithIcon
48
48
  icon={getIconForProperty(property, "small")}
49
49
  required={property.validation?.required}
@@ -33,8 +33,8 @@ export function TextFieldBinding<T extends string | number>({
33
33
  let multiline: boolean | undefined;
34
34
  let url: boolean | PreviewType | undefined;
35
35
  if (property.type === "string") {
36
- multiline = property.multiline;
37
- url = property.url;
36
+ multiline = property.ui?.multiline;
37
+ url = property.ui?.url;
38
38
  }
39
39
 
40
40
  useClearRestoreValue({
@@ -71,7 +71,7 @@ export function TextFieldBinding<T extends string | number>({
71
71
  inputType = "number";
72
72
  } else if (property.type === "string") {
73
73
  if (property.email) inputType = "email";
74
- else if (property.url) inputType = "url";
74
+ else if (property.ui?.url) inputType = "url";
75
75
  }
76
76
 
77
77
  const label = (
@@ -88,7 +88,7 @@ export function TextFieldBinding<T extends string | number>({
88
88
  fieldBackgroundMixin,
89
89
  fieldBackgroundHoverMixin,
90
90
  showError && error ? "border border-red-500 dark:border-red-600" : "",
91
- property.widthPercentage !== undefined ? "mt-8" : undefined
91
+ property.ui?.widthPercentage !== undefined ? "mt-8" : undefined
92
92
  )}>
93
93
  <div className="pointer-events-none absolute top-1 text-xs font-medium px-3 text-text-secondary dark:text-text-secondary-dark">
94
94
  {label}
@@ -104,7 +104,7 @@ export function TextFieldBinding<T extends string | number>({
104
104
  showError && error ? "text-red-500 dark:text-red-600" : ""
105
105
  )}
106
106
  />
107
- {property.clearable && (
107
+ {property.ui?.clearable && (
108
108
  <div className="flex flex-row justify-center items-center absolute h-full right-0 top-0 mr-4">
109
109
  <IconButton onClick={handleClearClick}>
110
110
  <XIcon/>
@@ -118,7 +118,7 @@ export function TextFieldBinding<T extends string | number>({
118
118
  value={value ?? ""}
119
119
  onChange={onChange}
120
120
  autoFocus={autoFocus}
121
- className={property.widthPercentage !== undefined ? "mt-8" : undefined}
121
+ className={property.ui?.widthPercentage !== undefined ? "mt-8" : undefined}
122
122
  label={<LabelWithIcon
123
123
  icon={getIconForProperty(property, "small")}
124
124
  required={property.validation?.required || property.isId === true}
@@ -126,7 +126,7 @@ export function TextFieldBinding<T extends string | number>({
126
126
  type={inputType}
127
127
  disabled={disabled}
128
128
  endAdornment={
129
- property.clearable && <IconButton
129
+ property.ui?.clearable && <IconButton
130
130
  onClick={handleClearClick}>
131
131
  <XIcon/>
132
132
  </IconButton>
@@ -51,7 +51,7 @@ export function UserSelectFieldBinding({
51
51
  setValue(userId);
52
52
  }}
53
53
  disabled={disabled}
54
- clearable={property.clearable}
54
+ clearable={property.ui?.clearable}
55
55
  size={selectorSize}
56
56
  />
57
57
 
@@ -22,7 +22,7 @@ export function useClearRestoreValue<T>({
22
22
 
23
23
  const clearedValueRef = useRef<T | null>(null);
24
24
  useEffect(() => {
25
- const shouldClearValueIfDisabled = typeof property.disabled === "object" && Boolean(property.disabled.clearOnDisabled);
25
+ const shouldClearValueIfDisabled = typeof property.ui?.disabled === "object" && Boolean(property.ui?.disabled.clearOnDisabled);
26
26
  if (shouldClearValueIfDisabled) {
27
27
  if (value != null) {
28
28
  clearedValueRef.current = value;
@@ -187,7 +187,7 @@ function getZodStringSchema({
187
187
  (value: any) => value == null || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
188
188
  { message: `${property.name} must be an email` }
189
189
  );
190
- if (property.url) {
190
+ if (property.ui?.url) {
191
191
  if (!property.storage || property.storage?.storeUrl) {
192
192
  schema = schema.refine(
193
193
  (value: any) => {
@@ -6,7 +6,8 @@ export const CollectionRegistryContext = createContext<CollectionRegistryControl
6
6
  getCollection: () => undefined,
7
7
  getRawCollection: () => undefined,
8
8
  getParentReferencesFromPath: () => [],
9
- getParentCollectionIds: () => [],
9
+ getParentCollectionSlugs: () => [],
10
+ getParentEntityIds: () => [],
10
11
  convertIdsToPaths: () => [],
11
12
  initialised: false
12
13
  });
@@ -94,7 +94,7 @@ export function useBuildCollectionRegistryController(props: {
94
94
  });
95
95
  }, []);
96
96
 
97
- const getParentCollectionIds = useCallback((path: string): string[] => {
97
+ const getParentCollectionSlugs = useCallback((path: string): string[] => {
98
98
  const registry = collectionRegistryRef.current;
99
99
  if (!registry) {
100
100
  return [];
@@ -126,6 +126,16 @@ export function useBuildCollectionRegistryController(props: {
126
126
  return result.map(r => getCollectionFromPaths(r)?.slug).filter(Boolean) as string[];
127
127
  }, []);
128
128
 
129
+ const getParentEntityIds = useCallback((path: string): string[] => {
130
+ const cleanedPath = removeInitialAndTrailingSlashes(path);
131
+ const strings = cleanedPath.split("/");
132
+ const evenPathSegments = strings.filter((_, i) => i % 2 !== 0);
133
+ if (strings.length % 2 === 0) {
134
+ evenPathSegments.pop();
135
+ }
136
+ return evenPathSegments;
137
+ }, []);
138
+
129
139
  const convertIdsToPaths = useCallback((ids: string[]): string[] => {
130
140
  const registry = collectionRegistryRef.current;
131
141
  if (!registry) return [];
@@ -156,7 +166,8 @@ export function useBuildCollectionRegistryController(props: {
156
166
  getCollection,
157
167
  getRawCollection,
158
168
  getParentReferencesFromPath,
159
- getParentCollectionIds,
169
+ getParentCollectionSlugs,
170
+ getParentEntityIds,
160
171
  convertIdsToPaths,
161
172
  collectionRegistryRef
162
173
  }), [
@@ -165,7 +176,8 @@ export function useBuildCollectionRegistryController(props: {
165
176
  getCollection,
166
177
  getRawCollection,
167
178
  getParentReferencesFromPath,
168
- getParentCollectionIds,
179
+ getParentCollectionSlugs,
180
+ getParentEntityIds,
169
181
  convertIdsToPaths
170
182
  ]);
171
183
  }
@@ -104,7 +104,7 @@ export function useNavigationRegistry(userConfigPersistence?: UserConfigurationP
104
104
  });
105
105
  }, []);
106
106
 
107
- const getParentCollectionIds = useCallback((path: string): string[] => {
107
+ const getParentCollectionSlugs = useCallback((path: string): string[] => {
108
108
  const strings = path.split("/");
109
109
  const oddPathSegments = strings.filter((_, i) => i % 2 === 0);
110
110
  oddPathSegments.pop();
@@ -118,6 +118,15 @@ export function useNavigationRegistry(userConfigPersistence?: UserConfigurationP
118
118
  return result.map(r => getCollectionFromPaths(r)?.slug).filter(Boolean) as string[];
119
119
  }, [getAllParentReferencesForPath, getCollectionFromPaths]);
120
120
 
121
+ const getParentEntityIds = useCallback((path: string): string[] => {
122
+ const strings = path.split("/");
123
+ const evenPathSegments = strings.filter((_, i) => i % 2 !== 0);
124
+ if (strings.length % 2 === 0) {
125
+ evenPathSegments.pop();
126
+ }
127
+ return evenPathSegments;
128
+ }, []);
129
+
121
130
  const convertIdsToPaths = useCallback((ids: string[]): string[] => {
122
131
  const registry = collectionRegistryRef.current;
123
132
  if (!registry) {
@@ -141,13 +150,15 @@ export function useNavigationRegistry(userConfigPersistence?: UserConfigurationP
141
150
  getCollection,
142
151
  getRawCollection,
143
152
  getParentReferencesFromPath: getAllParentReferencesForPath,
144
- getParentCollectionIds,
153
+ getParentCollectionSlugs,
154
+ getParentEntityIds,
145
155
  convertIdsToPaths
146
156
  }), [
147
157
  getCollection,
148
158
  getRawCollection,
149
159
  getAllParentReferencesForPath,
150
- getParentCollectionIds,
160
+ getParentCollectionSlugs,
161
+ getParentEntityIds,
151
162
  convertIdsToPaths
152
163
  ]);
153
164
  }
@@ -21,7 +21,7 @@ import { AuthController, RebaseData, User } from "@rebasepro/types";
21
21
  import { UserManagementDelegate } from "@rebasepro/types";
22
22
 
23
23
  import { resolveAppViews } from "./useNavigationResolution";
24
- import { NAVIGATION_ADMIN_GROUP_NAME } from "./utils";
24
+
25
25
 
26
26
  // Lazy-load admin views — only rendered when navigation reaches /users or /roles
27
27
  const UsersView = lazy(() => import("../../components/admin/UsersView").then(m => ({ default: m.UsersView })));
@@ -128,7 +128,6 @@ export function useResolvedViews<USER extends User>(
128
128
  views.push({
129
129
  slug: "users",
130
130
  name: "Users",
131
- group: NAVIGATION_ADMIN_GROUP_NAME,
132
131
  icon: "Headset",
133
132
  view: usersViewElement
134
133
  });
@@ -136,7 +135,6 @@ export function useResolvedViews<USER extends User>(
136
135
  views.push({
137
136
  slug: "roles",
138
137
  name: "Roles",
139
- group: NAVIGATION_ADMIN_GROUP_NAME,
140
138
  icon: "Shield",
141
139
  view: rolesViewElement
142
140
  });
@@ -152,7 +152,7 @@ export function useTopLevelNavigation(
152
152
  if (adminView.hideFromNavigation) return acc;
153
153
 
154
154
  const pathKey = adminView.slug;
155
- let groupName = adminView.group?.trim() || NAVIGATION_ADMIN_GROUP_NAME;
155
+ let groupName = NAVIGATION_ADMIN_GROUP_NAME;
156
156
 
157
157
  if (finalNavigationGroupMappings) {
158
158
  for (const pluginGroupDef of finalNavigationGroupMappings) {
@@ -11,7 +11,7 @@ export function getGroup(collectionOrView: EntityCollection<any, any> | AppView)
11
11
  if (!trimmed || trimmed === "") {
12
12
  return NAVIGATION_DEFAULT_GROUP_NAME;
13
13
  }
14
- return trimmed ?? NAVIGATION_DEFAULT_GROUP_NAME;
14
+ return trimmed;
15
15
  }
16
16
 
17
17
  export function computeNavigationGroups({
@@ -20,7 +20,7 @@ export interface UseEntityHistoryResult {
20
20
  hasMore: boolean;
21
21
  error?: Error;
22
22
  loadMore: () => void;
23
- revert: (historyId: string) => Promise<void>;
23
+ revert: (historyId: string) => Promise<Record<string, unknown>>;
24
24
  }
25
25
 
26
26
  /**
@@ -129,7 +129,7 @@ signal });
129
129
  }
130
130
  }, [isLoading, hasMore, pageSize, offset, entries.length, total]);
131
131
 
132
- const revert = useCallback(async (historyId: string) => {
132
+ const revert = useCallback(async (historyId: string): Promise<Record<string, unknown>> => {
133
133
  if (!apiConfig?.apiUrl || !entityId) {
134
134
  throw new Error("Cannot revert: missing API configuration or entity ID");
135
135
  }
@@ -149,10 +149,15 @@ headers });
149
149
  throw new Error(errorData.error?.message || `Failed to revert (${response.status})`);
150
150
  }
151
151
 
152
+ const result = await response.json();
153
+
152
154
  // Refresh the history list after revert by resetting the entity ref
153
155
  // and triggering the effect.
154
156
  currentEntityRef.current = undefined;
155
157
  setRefreshTrigger(prev => prev + 1);
158
+
159
+ // Return the reverted entity data so callers can update the form
160
+ return result.data as Record<string, unknown>;
156
161
  }, [apiConfig, slug, entityId]);
157
162
 
158
163
  return useMemo(() => ({
@@ -1,11 +1,11 @@
1
1
  import type { ArrayProperty, MapProperty, NumberProperty, Property, StringProperty } from "@rebasepro/types";
2
- import React, { createElement } from "react";
2
+ import React, { createElement, Suspense } from "react";
3
3
  import { deepEqual as equal } from "fast-equals"
4
4
 
5
5
  import { EntityReference, EntityRelation } from "@rebasepro/types";
6
6
  import type { PropertyPreviewProps } from "../types/components/PropertyPreviewProps";
7
7
  import { resolveProperty, normalizeToEntityRelation } from "@rebasepro/common";
8
- import { useAuthController, useCustomizationController } from "@rebasepro/core";
8
+ import { useAuthController, useCustomizationController, resolveComponentRef } from "@rebasepro/core";
9
9
  import { EmptyValue } from "./components/EmptyValue";
10
10
  import { UrlComponentPreview } from "./components/UrlComponentPreview";
11
11
  import { StorageThumbnail } from "./components/StorageThumbnail";
@@ -56,18 +56,22 @@ export const PropertyPreview = React.memo(function PropertyPreview<P extends Pro
56
56
 
57
57
  if (property === null) {
58
58
  content = <EmptyValue/>;
59
- } else if (property.Preview) {
60
- content = createElement(property.Preview,
61
- {
62
- propertyKey,
63
- value,
64
- property,
65
- size,
66
- height,
67
- width,
68
- // entity,
69
- customProps: property.customProps
70
- });
59
+ } else if (property.ui?.Preview) {
60
+ const ResolvedPreview = resolveComponentRef(property.ui.Preview);
61
+ if (ResolvedPreview) {
62
+ content = <Suspense fallback={null}>
63
+ {createElement(ResolvedPreview,
64
+ {
65
+ propertyKey,
66
+ value,
67
+ property,
68
+ size,
69
+ height,
70
+ width,
71
+ customProps: property.ui?.customProps
72
+ })}
73
+ </Suspense>;
74
+ }
71
75
  } else if (value === undefined || value === null) {
72
76
  content = <EmptyValue/>;
73
77
  } else if (property.type === "string") {
@@ -81,20 +85,20 @@ export const PropertyPreview = React.memo(function PropertyPreview<P extends Pro
81
85
  size={props.size}
82
86
  fill={fill}
83
87
  storagePathOrDownloadUrl={filePath}/>;
84
- } else if (stringProperty.url) {
85
- if (typeof stringProperty.url === "boolean")
88
+ } else if (stringProperty.ui?.url) {
89
+ if (typeof stringProperty.ui?.url === "boolean")
86
90
  content =
87
91
  <UrlComponentPreview size={props.size}
88
92
  url={value}
89
93
  fill={fill}/>;
90
- else if (typeof stringProperty.url === "string")
94
+ else if (typeof stringProperty.ui?.url === "string")
91
95
  content =
92
96
  <UrlComponentPreview size={props.size}
93
97
  url={value}
94
98
  interactive={interactive}
95
99
  fill={fill}
96
- previewType={stringProperty.url}/>;
97
- } else if (stringProperty.markdown) {
100
+ previewType={stringProperty.ui?.url}/>;
101
+ } else if (stringProperty.ui?.markdown) {
98
102
  content = <Markdown source={value} size={"small"}/>;
99
103
  } else if (stringProperty.userSelect) {
100
104
  content = <UserPreview
@@ -107,7 +111,7 @@ export const PropertyPreview = React.memo(function PropertyPreview<P extends Pro
107
111
  if (typeof stringProperty.reference.path === "string") {
108
112
  content = <ReferencePreview
109
113
  disabled={!stringProperty.reference.path}
110
- previewProperties={stringProperty.reference.previewProperties}
114
+ previewProperties={(stringProperty as any).reference?.previewProperties}
111
115
  includeId={stringProperty.reference.includeId}
112
116
  includeEntityLink={stringProperty.reference.includeEntityLink}
113
117
  size={props.size}
@@ -204,7 +208,7 @@ path: stringProperty.reference.path })}
204
208
  if (typeof value === "object" && "isEntityReference" in value && value.isEntityReference()) {
205
209
  content = <ReferencePreview
206
210
  disabled={!property.path}
207
- previewProperties={property.previewProperties}
211
+ previewProperties={property.ui?.previewProperties}
208
212
  includeId={property.includeId}
209
213
  includeEntityLink={property.includeEntityLink}
210
214
  size={props.size}
@@ -232,7 +236,7 @@ path: stringProperty.reference.path })}
232
236
  key={`preview_rel_${propertyKey}_${index}`}>
233
237
  <RelationPreview
234
238
  disabled={!property.relation}
235
- previewProperties={property.previewProperties}
239
+ previewProperties={property.ui?.previewProperties}
236
240
  includeId={property.includeId}
237
241
  includeEntityLink={property.includeEntityLink}
238
242
  size={"small"}
@@ -249,7 +253,7 @@ path: stringProperty.reference.path })}
249
253
  if (relationValue) {
250
254
  content = <RelationPreview
251
255
  disabled={!property.relation}
252
- previewProperties={property.previewProperties}
256
+ previewProperties={property.ui?.previewProperties}
253
257
  includeId={property.includeId}
254
258
  includeEntityLink={property.includeEntityLink}
255
259
  size={props.size}
@@ -5,6 +5,7 @@ import { UrlComponentPreview } from "./UrlComponentPreview";
5
5
  import { ErrorView, useStorageSource } from "@rebasepro/core";
6
6
  import { DownloadConfig, FileType } from "@rebasepro/types";
7
7
  import type { PreviewSize } from "../../types/components/PropertyPreviewProps";
8
+ import { Skeleton } from "@rebasepro/ui";
8
9
  type StorageThumbnailProps = {
9
10
  storagePathOrDownloadUrl: string;
10
11
  storeUrl: boolean;
@@ -76,7 +77,9 @@ export function StorageThumbnailInternal({
76
77
  size={size}
77
78
  fill={fill}
78
79
  hint={storagePathOrDownloadUrl}/>
79
- : renderSkeletonImageThumbnail(size);
80
+ : fill
81
+ ? <Skeleton className="w-full h-full"/>
82
+ : renderSkeletonImageThumbnail(size);
80
83
  }
81
84
 
82
85
  function getFiletype(input: string): FileType {
@@ -28,7 +28,7 @@ export function ArrayOfMapsPreview({
28
28
  throw Error(`You need to specify a 'properties' prop (or specify a custom field) in your map property ${propertyKey}`);
29
29
  }
30
30
  const values = value;
31
- const previewProperties: string[] | undefined = mapProperty.previewProperties;
31
+ const previewProperties: string[] | undefined = (mapProperty.ui as any)?.previewProperties;
32
32
 
33
33
  if (!values) return null;
34
34
 
@@ -30,7 +30,7 @@ export function ArrayOfReferencesPreview({
30
30
  key={`preview_array_ref_${propertyKey}_${index}`}>
31
31
  <ReferencePreview
32
32
  disabled={!ofProperty.path}
33
- previewProperties={ofProperty.previewProperties}
33
+ previewProperties={ofProperty.ui?.previewProperties}
34
34
  size={childSize}
35
35
  reference={reference}
36
36
  includeId={ofProperty.includeId}
@@ -36,7 +36,7 @@ export function ArrayOfRelationsPreview({
36
36
  key={`preview_array_rel_${propertyKey}_${index}`}>
37
37
  <RelationPreview
38
38
  disabled={!ofProperty.relation}
39
- previewProperties={ofProperty.previewProperties}
39
+ previewProperties={ofProperty.ui?.previewProperties}
40
40
  size={"small"}
41
41
  relation={entityRelation}
42
42
  includeId={ofProperty.includeId}
@@ -26,7 +26,7 @@ export function SkeletonPropertyComponent({
26
26
  let content: React.ReactNode | any;
27
27
  if (property.type === "string") {
28
28
  const stringProperty = property as StringProperty;
29
- if (stringProperty.url) {
29
+ if (stringProperty.ui?.url) {
30
30
  content = renderUrlComponent(stringProperty, size);
31
31
  } else if (stringProperty.storage) {
32
32
  content = renderSkeletonImageThumbnail(size);
@@ -79,7 +79,7 @@ function renderMap<T extends Record<string, any>>(property: MapProperty, size: P
79
79
  if (size === "large") {
80
80
  mapPropertyKeys = Object.keys(property.properties);
81
81
  } else {
82
- mapPropertyKeys = (property.previewProperties || Object.keys(property.properties)) as string[];
82
+ mapPropertyKeys = ((property.ui as any)?.previewProperties || Object.keys(property.properties)) as string[];
83
83
  if (size === "medium")
84
84
  mapPropertyKeys = mapPropertyKeys.slice(0, 3);
85
85
  else if (size === "small")
@@ -241,7 +241,7 @@ function renderReference() {
241
241
 
242
242
  function renderUrlComponent(property: StringProperty, size: PreviewSize = "large") {
243
243
 
244
- if (typeof property.url === "boolean") {
244
+ if (typeof property.ui?.url === "boolean") {
245
245
  return <div style={{
246
246
  display: "flex"
247
247
  }}>
@@ -24,7 +24,7 @@ export function StringPropertyPreview({
24
24
  enumKey={enumKey}
25
25
  enumValues={property.enum}
26
26
  size={size}/>;
27
- } else if (property.previewAsTag) {
27
+ } else if (property.ui?.previewAsTag) {
28
28
  const colorScheme = getColorSchemeForSeed(propertyKey ?? "");
29
29
  return (
30
30
  <ErrorBoundary>
@@ -34,11 +34,11 @@ export function StringPropertyPreview({
34
34
  {value}
35
35
  </Chip>
36
36
  </ErrorBoundary>);
37
- } else if (property.url) {
37
+ } else if (property.ui?.url) {
38
38
  return (
39
39
  <UrlComponentPreview size={size}
40
40
  url={value}
41
- previewType={typeof property.url === "string" ? property.url as PreviewType : undefined}/>
41
+ previewType={typeof property.ui?.url === "string" ? property.ui?.url as PreviewType : undefined}/>
42
42
  );
43
43
  } else {
44
44
  if (!value) return <></>;