@rebasepro/admin 0.0.1-canary.f81da60 → 0.1.2

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 (95) hide show
  1. package/dist/{CollectionEditorDialog-D509-IMx.js → CollectionEditorDialog-ywdxhs1L.js} +18 -18
  2. package/dist/CollectionEditorDialog-ywdxhs1L.js.map +1 -0
  3. package/dist/{CollectionsStudioView-B549BDpU.js → CollectionsStudioView-BDzMFzqH.js} +4 -4
  4. package/dist/{CollectionsStudioView-B549BDpU.js.map → CollectionsStudioView-BDzMFzqH.js.map} +1 -1
  5. package/dist/{ContentHomePage--Bl1FXk7.js → ContentHomePage-0tHuEIm_.js} +26 -26
  6. package/dist/ContentHomePage-0tHuEIm_.js.map +1 -0
  7. package/dist/{ExportCollectionAction-CttNAdM1.js → ExportCollectionAction-BIrq92To.js} +2 -2
  8. package/dist/{ExportCollectionAction-CttNAdM1.js.map → ExportCollectionAction-BIrq92To.js.map} +1 -1
  9. package/dist/{ImportCollectionAction-BB33kxAN.js → ImportCollectionAction-h8yg_To8.js} +2 -2
  10. package/dist/{ImportCollectionAction-BB33kxAN.js.map → ImportCollectionAction-h8yg_To8.js.map} +1 -1
  11. package/dist/{PropertyEditView-UtDO8g0A.js → PropertyEditView-BuZrNnBN.js} +79 -101
  12. package/dist/PropertyEditView-BuZrNnBN.js.map +1 -0
  13. package/dist/{RolesView-B0E7L0hE.js → RolesView-CMPsaIXo.js} +2 -2
  14. package/dist/{RolesView-B0E7L0hE.js.map → RolesView-CMPsaIXo.js.map} +1 -1
  15. package/dist/{UsersView-BM2_7VPV.js → UsersView-BkeblMVT.js} +6 -28
  16. package/dist/UsersView-BkeblMVT.js.map +1 -0
  17. package/dist/collection_editor/ConfigControllerProvider.d.ts +0 -4
  18. package/dist/collection_editor/ui/collection_editor/CollectionDetailsForm.d.ts +1 -3
  19. package/dist/collection_editor/ui/collection_editor/CollectionEditorDialog.d.ts +0 -2
  20. package/dist/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +1 -2
  21. package/dist/collection_editor_ui.js +3 -3
  22. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +5 -1
  23. package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +2 -1
  24. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +2 -1
  25. package/dist/components/EntityEditView.d.ts +6 -0
  26. package/dist/components/RebaseCMS.d.ts +1 -1
  27. package/dist/{index-C9YDsMC9.js → index-BuZaHcyc.js} +3 -3
  28. package/dist/index-BuZaHcyc.js.map +1 -0
  29. package/dist/{index-CNDetux9.js → index-CS6uJ7oW.js} +2 -2
  30. package/dist/{index-CNDetux9.js.map → index-CS6uJ7oW.js.map} +1 -1
  31. package/dist/{index-DO7lMeNB.js → index-eRJbMvHi.js} +3 -3
  32. package/dist/index-eRJbMvHi.js.map +1 -0
  33. package/dist/index.js +18 -14
  34. package/dist/index.js.map +1 -1
  35. package/dist/util/navigation_utils.d.ts +10 -1
  36. package/dist/{util-DK1O3uM0.js → util-zfU1zOCX.js} +713 -603
  37. package/dist/util-zfU1zOCX.js.map +1 -0
  38. package/package.json +8 -8
  39. package/src/collection_editor/ConfigControllerProvider.tsx +1 -10
  40. package/src/collection_editor/ui/collection_editor/CollectionDetailsForm.tsx +3 -47
  41. package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +2 -10
  42. package/src/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.tsx +1 -3
  43. package/src/collection_editor/ui/collection_editor/CollectionRelationsTab.tsx +3 -3
  44. package/src/collection_editor/ui/collection_editor/GetCodeDialog.tsx +0 -1
  45. package/src/collection_editor/ui/collection_editor/PropertyFieldPreview.tsx +6 -6
  46. package/src/collection_editor/ui/collection_editor/properties/MapPropertyField.tsx +1 -1
  47. package/src/collection_editor/ui/collection_editor/properties/ReferencePropertyField.tsx +15 -49
  48. package/src/collection_editor/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +2 -3
  49. package/src/collection_editor/ui/collection_editor/templates/pages_template.ts +1 -1
  50. package/src/collection_editor/ui/collection_editor/templates/products_template.ts +2 -2
  51. package/src/components/DefaultAppBar.tsx +2 -2
  52. package/src/components/DefaultDrawer.tsx +25 -17
  53. package/src/components/DrawerNavigationGroup.tsx +4 -4
  54. package/src/components/DrawerNavigationItem.tsx +6 -6
  55. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +5 -3
  56. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +1 -1
  57. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +8 -2
  58. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +2 -2
  59. package/src/components/EntityCollectionTable/table_bindings.tsx +37 -27
  60. package/src/components/EntityCollectionView/EntityCard.tsx +2 -2
  61. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +4 -3
  62. package/src/components/EntityCollectionView/EntityCollectionListView.tsx +7 -6
  63. package/src/components/EntityCollectionView/EntityCollectionView.tsx +50 -7
  64. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +17 -8
  65. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +8 -4
  66. package/src/components/EntityCollectionView/useEntityPreviewSlots.ts +33 -5
  67. package/src/components/EntityEditView.tsx +80 -81
  68. package/src/components/EntitySidePanel.tsx +11 -7
  69. package/src/components/HomePage/ContentHomePage.tsx +24 -15
  70. package/src/components/HomePage/NavigationCard.tsx +4 -4
  71. package/src/components/HomePage/NavigationGroup.tsx +2 -2
  72. package/src/components/RebaseAuthGate.tsx +2 -0
  73. package/src/components/RebaseCMS.tsx +4 -3
  74. package/src/components/RebaseNavigation.tsx +7 -4
  75. package/src/components/RelationSelector.tsx +30 -2
  76. package/src/components/SelectableTable/SelectableTable.tsx +2 -2
  77. package/src/components/UserSelector.tsx +1 -1
  78. package/src/components/admin/UsersView.tsx +2 -17
  79. package/src/components/app/Scaffold.tsx +3 -3
  80. package/src/components/field_configs.tsx +3 -3
  81. package/src/form/PropertyFieldBinding.tsx +10 -6
  82. package/src/hooks/navigation/useResolvedViews.tsx +1 -3
  83. package/src/hooks/navigation/useTopLevelNavigation.ts +1 -1
  84. package/src/hooks/navigation/utils.ts +1 -1
  85. package/src/preview/PropertyPreview.tsx +17 -13
  86. package/src/routes/RebaseRoute.tsx +27 -2
  87. package/src/util/navigation_utils.ts +16 -2
  88. package/src/util/previews.ts +14 -5
  89. package/dist/CollectionEditorDialog-D509-IMx.js.map +0 -1
  90. package/dist/ContentHomePage--Bl1FXk7.js.map +0 -1
  91. package/dist/PropertyEditView-UtDO8g0A.js.map +0 -1
  92. package/dist/UsersView-BM2_7VPV.js.map +0 -1
  93. package/dist/index-C9YDsMC9.js.map +0 -1
  94. package/dist/index-DO7lMeNB.js.map +0 -1
  95. package/dist/util-DK1O3uM0.js.map +0 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rebasepro/admin",
3
3
  "type": "module",
4
- "version": "0.0.1-canary.f81da60",
4
+ "version": "0.1.2",
5
5
  "description": "Rebase CMS — content management views, forms, and routing",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/rebaseco"
@@ -77,13 +77,13 @@
77
77
  "react-use-measure": "^2.1.7",
78
78
  "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz",
79
79
  "zod": "^3.25.0",
80
- "@rebasepro/common": "0.0.1-canary.f81da60",
81
- "@rebasepro/core": "0.0.1-canary.f81da60",
82
- "@rebasepro/formex": "0.0.1-canary.f81da60",
83
- "@rebasepro/schema-inference": "0.0.1-canary.f81da60",
84
- "@rebasepro/types": "0.0.1-canary.f81da60",
85
- "@rebasepro/ui": "0.0.1-canary.f81da60",
86
- "@rebasepro/utils": "0.0.1-canary.f81da60"
80
+ "@rebasepro/common": "0.1.2",
81
+ "@rebasepro/core": "0.1.2",
82
+ "@rebasepro/formex": "0.1.2",
83
+ "@rebasepro/schema-inference": "0.1.2",
84
+ "@rebasepro/types": "0.1.2",
85
+ "@rebasepro/ui": "0.1.2",
86
+ "@rebasepro/utils": "0.1.2"
87
87
  },
88
88
  "peerDependencies": {
89
89
  "react": ">=19.0.0",
@@ -32,11 +32,6 @@ export interface ConfigControllerProviderProps {
32
32
  */
33
33
  configPermissions?: CollectionEditorPermissionsBuilder;
34
34
 
35
- /**
36
- * Groups that cannot be used to create new collections.
37
- */
38
- reservedGroups?: string[];
39
-
40
35
  extraView?: {
41
36
  View: React.ComponentType<{
42
37
  path: string
@@ -65,7 +60,6 @@ export const ConfigControllerProvider = React.memo(
65
60
  children,
66
61
  collectionConfigController,
67
62
  configPermissions,
68
- reservedGroups,
69
63
  collectionInference,
70
64
  extraView,
71
65
  getUser,
@@ -105,7 +99,6 @@ export const ConfigControllerProvider = React.memo(
105
99
  parentCollectionSlugs: string[], parentEntityIds: string[],
106
100
  initialValues?: {
107
101
  path?: string,
108
- group?: string,
109
102
  name?: string
110
103
  },
111
104
  copyFrom?: EntityCollection,
@@ -225,7 +218,6 @@ export const ConfigControllerProvider = React.memo(
225
218
  parentCollectionSlugs: string[], parentEntityIds: string[],
226
219
  parentCollection?: EntityCollection
227
220
  initialValues?: {
228
- group?: string,
229
221
  path?: string,
230
222
  name?: string
231
223
  },
@@ -270,7 +262,6 @@ export const ConfigControllerProvider = React.memo(
270
262
  collectionInference,
271
263
  ...currentDialog,
272
264
  getData,
273
- reservedGroups,
274
265
  extraView,
275
266
  getUser,
276
267
  generateCollection,
@@ -289,7 +280,7 @@ export const ConfigControllerProvider = React.memo(
289
280
  };
290
281
  }, [
291
282
  currentDialog, collectionConfigController, collectionInference,
292
- getData, reservedGroups, extraView, getUser, generateCollection,
283
+ getData, extraView, getUser, generateCollection,
293
284
  onAnalyticsEvent, unmappedTables, onFetchTableMetadata,
294
285
  urlController, navigate
295
286
  ]);
@@ -5,7 +5,7 @@ import React, { useMemo, useState } from "react";
5
5
  import { useAuthController, useCustomizationController } from "@rebasepro/core";
6
6
  import { getFieldConfig, PropertyConfigBadge, SearchIconsView } from "../../_cms_internals";
7
7
  import { EntityCollection, Property } from "@rebasepro/types";
8
- import { BooleanSwitchWithLabel, Chip, cls, Container, DebouncedTextField, Dialog, IconButton, Select, SelectItem, TextField, Tooltip, Typography, useAutoComplete, Button , iconSize } from "@rebasepro/ui";
8
+ import { BooleanSwitchWithLabel, Chip, cls, Container, DebouncedTextField, Dialog, IconButton, Select, SelectItem, TextField, Tooltip, Typography, Button, iconSize } from "@rebasepro/ui";
9
9
  import { XIcon, HistoryIcon } from "lucide-react";
10
10
 
11
11
  import { Field, getIn, useFormex } from "@rebasepro/formex";
@@ -18,24 +18,20 @@ import { singular, toSnakeCase, unslugify } from "@rebasepro/utils";
18
18
 
19
19
  export function CollectionDetailsForm({
20
20
  isNewCollection,
21
- reservedGroups,
22
21
  existingPaths,
23
22
  existingIds,
24
- groups,
25
23
  parentCollection,
26
24
  expandKanban
27
25
  }: {
28
26
  isNewCollection: boolean,
29
- reservedGroups?: string[];
30
27
  existingPaths?: string[];
31
28
  existingIds?: string[];
32
- groups: string[] | null;
33
29
  parentCollection?: EntityCollection;
34
30
  parentCollectionSlugs?: string[], parentEntityIds?: string[];
35
31
  expandKanban?: boolean;
36
32
  }) {
37
33
 
38
- const groupRef = React.useRef<HTMLInputElement>(null);
34
+
39
35
  const {
40
36
  values,
41
37
  setFieldValue,
@@ -98,15 +94,7 @@ export function CollectionDetailsForm({
98
94
 
99
95
  const collectionIcon = <IconForView collectionOrView={values}/>;
100
96
 
101
- const groupOptions = groups?.filter((group) => !reservedGroups?.includes(group));
102
97
 
103
- const {
104
- inputFocused,
105
- autoCompleteOpen,
106
- setAutoCompleteOpen
107
- } = useAutoComplete({
108
- ref: groupRef
109
- });
110
98
 
111
99
  const isSubcollection = !!parentCollection;
112
100
 
@@ -172,39 +160,7 @@ export function CollectionDetailsForm({
172
160
 
173
161
  </div>
174
162
 
175
- {/*{!isSubcollection && <div className={"col-span-12 sm:col-span-4 relative"}>*/}
176
-
177
- {/* <TextField error={showErrors && Boolean(errors.group)}*/}
178
- {/* disabled={isSubmitting}*/}
179
- {/* value={values.group ?? ""}*/}
180
- {/* autoComplete="off"*/}
181
- {/* onChange={(event) => setFieldValue("group", event.target.value)}*/}
182
- {/* name={"group"}*/}
183
- {/* inputRef={groupRef}*/}
184
- {/* label="Group"/>*/}
185
- {/* <Autocomplete*/}
186
- {/* open={autoCompleteOpen && (groupOptions ?? []).length > 0}*/}
187
- {/* setOpen={setAutoCompleteOpen}>*/}
188
- {/* {groupOptions?.map((group, index) => {*/}
189
- {/* return <AutocompleteItem*/}
190
- {/* key={index + "_" + group}*/}
191
- {/* className={"pr-6 pl-14"}*/}
192
- {/* onClick={() => {*/}
193
- {/* setAutoCompleteOpen(false);*/}
194
- {/* setFieldValue("group", group ?? null);*/}
195
- {/* }}*/}
196
- {/* >*/}
197
- {/* <div className={"flex-grow"}>*/}
198
- {/* {group}*/}
199
- {/* </div>*/}
200
- {/* </AutocompleteItem>;*/}
201
- {/* })}*/}
202
- {/* </Autocomplete>*/}
203
- {/* <FieldCaption>*/}
204
- {/* {showErrors && Boolean(errors.group) ? errors.group : "Group in the home page"}*/}
205
- {/* </FieldCaption>*/}
206
-
207
- {/*</div>}*/}
163
+
208
164
 
209
165
  <LayoutModeSwitch
210
166
  className={"col-span-12"}
@@ -37,7 +37,6 @@ export interface CollectionEditorDialogProps {
37
37
  open: boolean;
38
38
  isNewCollection: boolean;
39
39
  initialValues?: {
40
- group?: string,
41
40
  slug?: string,
42
41
  name?: string,
43
42
  }
@@ -51,7 +50,6 @@ export interface CollectionEditorDialogProps {
51
50
  parentCollectionSlugs?: string[], parentEntityIds?: string[]; // path ids of the parent collection, like [`products`]
52
51
  handleClose: (collection?: EntityCollection) => void;
53
52
  configController: CollectionsConfigController;
54
- reservedGroups?: string[];
55
53
  collectionInference?: CollectionInference;
56
54
  extraView?: {
57
55
  View: React.ComponentType<{
@@ -200,7 +198,7 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
200
198
  }
201
199
  }, [props.editedCollectionId, props.parentCollectionSlugs, props.parentEntityIds, collectionRegistry.initialised, collectionRegistry.getRawCollection]);
202
200
 
203
- const groups = topLevelNavigation?.groups ?? [];
201
+
204
202
 
205
203
  const initialCollection = collection
206
204
  ? {
@@ -226,7 +224,6 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
226
224
  slug: initialValuesProp?.slug ?? randomString(16),
227
225
  table: initialValuesProp?.slug ?? "",
228
226
  name: initialValuesProp?.name ?? "",
229
- group: initialValuesProp?.group ?? "",
230
227
  properties: {} as Properties,
231
228
  propertiesOrder: [],
232
229
  icon: coolIconKeys[Math.floor(Math.random() * coolIconKeys.length)],
@@ -249,7 +246,6 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
249
246
  includeTemplates={includeTemplates}
250
247
  collection={collection}
251
248
  setCollection={setCollection}
252
- groups={groups}
253
249
  propertyConfigs={propertyConfigs}/>
254
250
 
255
251
  }
@@ -262,7 +258,6 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
262
258
  path,
263
259
  collectionInference,
264
260
  handleClose,
265
- reservedGroups,
266
261
  extraView,
267
262
  handleCancel,
268
263
  setFormDirty,
@@ -276,7 +271,6 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
276
271
  setCollection,
277
272
  initialValues,
278
273
  propertyConfigs,
279
- groups,
280
274
  existingEntities,
281
275
  initialView: initialViewProp,
282
276
  expandKanban,
@@ -295,7 +289,6 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
295
289
  collection: EntityCollection<M> | undefined,
296
290
  setCollection: (collection: EntityCollection<M>) => void,
297
291
  propertyConfigs: Record<string, PropertyConfig>,
298
- groups: string[],
299
292
  }
300
293
  ) {
301
294
 
@@ -619,7 +612,7 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
619
612
  <Formex value={formController}>
620
613
 
621
614
  <>
622
- {!isNewCollection && <div className={cls("px-4 py-2 w-full flex shrink-0 items-center justify-between gap-4 bg-white dark:bg-surface-950 border-b", defaultBorderMixin)}>
615
+ {!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)}>
623
616
  <div className="flex flex-1 items-center justify-end gap-4 min-w-0">
624
617
  <Tabs value={currentView}
625
618
  className="bg-transparent !w-fit max-w-full"
@@ -756,7 +749,6 @@ function CollectionEditorInternal<M extends Record<string, unknown>>({
756
749
  <CollectionPropertiesEditorForm
757
750
  showErrors={submitCount > 0}
758
751
  isNewCollection={isNewCollection}
759
- reservedGroups={reservedGroups}
760
752
  onPropertyError={(propertyKey, namespace, error) => {
761
753
  const current = removeUndefined({
762
754
  ...propertyErrorsRef.current,
@@ -27,7 +27,6 @@ type CollectionEditorFormProps = {
27
27
  propertyErrorsRef?: React.MutableRefObject<any>;
28
28
  onPropertyError: (propertyKey: string, namespace: string | undefined, error?: Record<string, any>) => void;
29
29
  setDirty?: (dirty: boolean) => void;
30
- reservedGroups?: string[];
31
30
  extraIcon: React.ReactNode | any;
32
31
  getUser?: (uid: string) => User | null;
33
32
  getData?: () => Promise<object[]>;
@@ -42,7 +41,6 @@ export function CollectionPropertiesEditorForm({
42
41
  propertyErrorsRef,
43
42
  onPropertyError,
44
43
  setDirty,
45
- reservedGroups,
46
44
  extraIcon,
47
45
  getUser,
48
46
  getData,
@@ -391,7 +389,7 @@ export function CollectionPropertiesEditorForm({
391
389
  };
392
390
 
393
391
  const body = (
394
- <div className={"grid grid-cols-12 gap-2 h-full bg-surface dark:bg-surface-dark"}>
392
+ <div className={"grid grid-cols-12 gap-2 h-full bg-white dark:bg-surface-950"}>
395
393
  <div className={cls(
396
394
  "bg-surface-50 dark:bg-surface-900",
397
395
  "p-4 md:p-8",
@@ -1,6 +1,6 @@
1
1
 
2
2
  import React, { useState } from "react";
3
- import { Button, IconButton, Typography, Table, TableHeader, TableCell, TableBody, TableRow, TextField, Select, SelectItem, Container, Dialog, DialogTitle, DialogContent, DialogActions } from "@rebasepro/ui";
3
+ import { Button, IconButton, Typography, Table, TableHeader, TableCell, TableBody, TableRow, TextField, Select, SelectItem, Container, Dialog, DialogTitle, DialogContent, DialogActions, cls, defaultBorderMixin } from "@rebasepro/ui";
4
4
  import { Trash2Icon } from "lucide-react";
5
5
  import { useFormex } from "@rebasepro/formex";
6
6
  import { PostgresCollection, Relation } from "@rebasepro/types";
@@ -128,7 +128,7 @@ direction: "owning" });
128
128
  <DialogTitle className="flex justify-between items-center w-full" variant="h6">
129
129
  {editingRelationIndex === -1 ? "New Relation" : "Edit Relation"}
130
130
  </DialogTitle>
131
- <DialogContent includeMargin={false} className="p-4 md:p-6 border-t dark:border-surface-700 bg-surface-50 dark:bg-surface-800">
131
+ <DialogContent includeMargin={false} className={cls("p-4 md:p-6 border-t bg-white dark:bg-surface-900", defaultBorderMixin)}>
132
132
  <div className="flex flex-col gap-4 max-w-2xl mx-auto">
133
133
  <TextField
134
134
  label="Relation Name"
@@ -178,7 +178,7 @@ direction: val as Relation["direction"] } : null)}
178
178
  </Select>
179
179
 
180
180
  {editingRelationState.cardinality === "many" && editingRelationState.direction === "owning" && (
181
- <div className="flex flex-col gap-4 mt-4 pt-4 border-t dark:border-surface-800">
181
+ <div className={cls("flex flex-col gap-4 mt-4 pt-4 border-t", defaultBorderMixin)}>
182
182
  <Typography variant="subtitle2" className="text-text-primary">Intermediate Table</Typography>
183
183
  <Typography variant="body2" className="text-text-secondary -mt-3">
184
184
  Required for many-to-many relationships. This defines the junction table linking both collections.
@@ -123,7 +123,6 @@ function collectionToCode(collection: EntityCollection): object {
123
123
  description: collection.description,
124
124
 
125
125
  icon: collection.icon,
126
- group: collection.group,
127
126
  defaultFilter: collection.defaultFilter,
128
127
  sort: collection.sort,
129
128
  properties: Object.entries({
@@ -39,10 +39,10 @@ export function PropertyFieldPreview({
39
39
  <div onClick={onClick} className={onClick ? "cursor-pointer" : ""}>
40
40
  <Paper
41
41
  className={cls(
42
- "w-full flex flex-row gap-3 items-center px-3 py-2 rounded-lg transition-all duration-200 border border-transparent bg-transparent",
42
+ "w-full flex flex-row gap-3 items-center px-3 py-2 rounded-lg transition-all duration-200 border bg-white dark:bg-surface-800 border-surface-200 dark:border-surface-700 shadow-xs",
43
43
  selected
44
- ? "bg-primary/5 dark:bg-primary/10 ring-1 ring-inset ring-primary"
45
- : "hover:bg-surface-50 dark:hover:bg-surface-800"
44
+ ? "bg-primary/5 dark:bg-primary/10 ring-1 ring-inset ring-primary border-primary/30"
45
+ : "hover:bg-surface-50 dark:hover:bg-surface-750"
46
46
  )}
47
47
  >
48
48
  <PropertyConfigBadge propertyConfig={propertyConfig} size="small"/>
@@ -105,10 +105,10 @@ export function NonEditablePropertyPreview({
105
105
  <div onClick={onClick} className={onClick ? "cursor-pointer" : ""}>
106
106
  <Paper
107
107
  className={cls(
108
- "w-full flex flex-row gap-3 items-center px-3 py-2 rounded-lg transition-all duration-200 border border-transparent bg-transparent",
108
+ "w-full flex flex-row gap-3 items-center px-3 py-2 rounded-lg transition-all duration-200 border bg-white dark:bg-surface-800 border-surface-200 dark:border-surface-700 shadow-xs",
109
109
  selected
110
- ? "bg-primary/5 dark:bg-primary/10 ring-1 ring-inset ring-primary"
111
- : "hover:bg-surface-50 dark:hover:bg-surface-800"
110
+ ? "bg-primary/5 dark:bg-primary/10 ring-1 ring-inset ring-primary border-primary/30"
111
+ : "hover:bg-surface-50 dark:hover:bg-surface-750"
112
112
  )}
113
113
  >
114
114
  <div className={"relative shrink-0"}>
@@ -111,7 +111,7 @@ export function MapPropertyField({ disabled, getData, allowDataInference, proper
111
111
  position={"start"}
112
112
  size={"medium"}
113
113
  label={t("spread_children_as_columns")}
114
- onValueChange={(v) => setFieldValue("spreadChildren", v)}
114
+ onValueChange={(v) => setFieldValue("ui.spreadChildren", v)}
115
115
  value={values.ui?.spreadChildren ?? false}
116
116
  />
117
117
  <FieldCaption>
@@ -4,7 +4,7 @@ import React from "react";
4
4
  import { Field, getIn, useFormex } from "@rebasepro/formex";
5
5
  ;
6
6
  import { NumberProperty, StringProperty } from "@rebasepro/types";
7
- import { CircularProgress, Select, SelectGroup, SelectItem, Typography } from "@rebasepro/ui";
7
+ import { CircularProgress, Select, SelectItem, Typography } from "@rebasepro/ui";
8
8
 
9
9
  export function ReferencePropertyField({
10
10
  existing,
@@ -81,12 +81,6 @@ export function CollectionsSelect({
81
81
 
82
82
  const collections = collectionRegistry.collections ?? [];
83
83
 
84
- const groups: string[] = Array.from(new Set(
85
- Object.values(collections).map(e => e.group).filter(Boolean) as string[]
86
- ).values());
87
-
88
- const ungroupedCollections = collections.filter((col) => !col.group);
89
-
90
84
  return (
91
85
  <>
92
86
  <Select
@@ -113,48 +107,20 @@ export function CollectionsSelect({
113
107
  }}
114
108
  {...props}>
115
109
 
116
- {groups.flatMap((group) => (
117
- <SelectGroup label={group || "Views"}
118
- key={`group_${group}`}>
119
- {
120
- collections.filter(collection => collection.group === group)
121
- .map((collection) => {
122
- return <SelectItem
123
- key={`${collection.slug}-${group}`}
124
- value={collection.slug}>
125
- <div className="flex flex-row">
126
- <IconForView collectionOrView={collection}/>
127
- <Typography
128
- variant={"subtitle2"}
129
- className="ml-4">
130
- {collection?.name.toUpperCase()}
131
- </Typography>
132
- </div>
133
- </SelectItem>;
134
- })
135
-
136
- }
137
- </SelectGroup>
138
- ))}
139
-
140
- {ungroupedCollections && <SelectGroup label={"Views"}>
141
- {ungroupedCollections
142
- .map((collection) => {
143
- return <SelectItem key={collection.slug}
144
- value={collection.slug}>
145
- <div className="flex flex-row">
146
- <IconForView collectionOrView={collection}/>
147
- <Typography
148
- variant={"subtitle2"}
149
- className="ml-4">
150
- {collection?.name.toUpperCase()}
151
- </Typography>
152
- </div>
153
- </SelectItem>;
154
- })
155
-
156
- }
157
- </SelectGroup>}
110
+ {collections.map((collection) => {
111
+ return <SelectItem
112
+ key={collection.slug}
113
+ value={collection.slug}>
114
+ <div className="flex flex-row">
115
+ <IconForView collectionOrView={collection}/>
116
+ <Typography
117
+ variant={"subtitle2"}
118
+ className="ml-4">
119
+ {collection?.name.toUpperCase()}
120
+ </Typography>
121
+ </div>
122
+ </SelectItem>;
123
+ })}
158
124
 
159
125
  </Select>
160
126
 
@@ -7,9 +7,8 @@ export function AdvancedPropertyValidation({ disabled }: {
7
7
  disabled: boolean
8
8
  }) {
9
9
 
10
- const columnWidth = "columnWidth";
11
- const hideFromCollection = "hideFromCollection";
12
- const readOnly = "readOnly";
10
+ const hideFromCollection = "ui.hideFromCollection";
11
+ const readOnly = "ui.readOnly";
13
12
 
14
13
  return (
15
14
 
@@ -176,7 +176,7 @@ export const pagesCollectionTemplate = {
176
176
  is_published: {
177
177
  type: "boolean",
178
178
  name: "Is Published",
179
- columnWidth: 100,
179
+ ui: { columnWidth: 100 },
180
180
  description: "Should this page be live on the site?"
181
181
  }
182
182
  }
@@ -41,7 +41,7 @@ export const productsCollectionTemplate = {
41
41
  available: {
42
42
  type: "boolean",
43
43
  name: "Available",
44
- columnWidth: 100,
44
+ ui: { columnWidth: 100 },
45
45
  description: "Is this product available in the website"
46
46
  },
47
47
  price: {
@@ -55,7 +55,7 @@ export const productsCollectionTemplate = {
55
55
  images: {
56
56
  type: "array",
57
57
  name: "Images",
58
- hideFromCollection: true,
58
+ ui: { hideFromCollection: true },
59
59
  of: {
60
60
  type: "string",
61
61
  storage: {
@@ -110,9 +110,9 @@ export const DefaultAppBar = function DefaultAppBar({
110
110
  <div
111
111
  style={style}
112
112
  role="banner"
113
- className={cls("w-full h-16 transition-all ease-in duration-75 absolute top-0 max-w-full overflow-x-auto no-scrollbar",
113
+ className={cls("w-full h-14 transition-all ease-in duration-75 absolute top-0 max-w-full overflow-x-auto no-scrollbar",
114
114
  "flex flex-row gap-2 px-4 items-center",
115
- "backdrop-blur-md bg-surface-50/80 dark:bg-surface-900/80",
115
+ "backdrop-blur-sm bg-surface-50/95 dark:bg-surface-900/80",
116
116
  {
117
117
  "pl-[19rem]": drawerOpen && largeLayout,
118
118
  "pl-24": hasDrawer && !(drawerOpen && largeLayout),
@@ -1,9 +1,10 @@
1
1
  import type { NavigationEntry, NavigationResult } from "@rebasepro/types";
2
- import React from "react";
2
+ import React, { useMemo } from "react";
3
3
 
4
- import { useCollapsedGroups, useLargeLayout, useAdminModeController, useEffectiveRoleController, useTranslation, useSlot, useRebaseContext, useAnalyticsController, useRebaseRegistry, STUDIO_NAVIGATION_GROUPS } from "@rebasepro/core";
4
+ import { useCollapsedGroups, buildCollapsedDefaults, useLargeLayout, useAdminModeController, useTranslation, useSlot, useRebaseContext, useAnalyticsController, useRebaseRegistry } from "@rebasepro/core";
5
5
  import { useNavigationStateController, useUrlController } from "../hooks";
6
6
 
7
+
7
8
  import { Link, useNavigate } from "react-router-dom";
8
9
  import { AnalyticsEvent } from "@rebasepro/types";
9
10
  import { cls, Tooltip, Typography , iconSize } from "@rebasepro/ui";
@@ -57,22 +58,31 @@ export function DefaultDrawer({
57
58
 
58
59
  const tooltipsOpen = drawerHovered && !drawerOpen && !adminMenuOpen;
59
60
  const largeLayout = useLargeLayout();
60
- const navigate = useNavigate();
61
61
  const adminModeController = useAdminModeController();
62
- const effectiveRoleController = useEffectiveRoleController();
63
62
  const registry = useRebaseRegistry();
64
63
 
65
- const adminViews = navigationState.topLevelNavigation?.navigationEntries.filter(e => e.type === "admin") ?? [];
64
+ const allNavigationEntries = navigationState.topLevelNavigation?.navigationEntries ?? [];
66
65
 
67
- let groupsToRender = navigationState.topLevelNavigation?.groups ?? [];
68
- if (adminModeController.mode === "studio") {
69
- groupsToRender = groupsToRender.filter(g => STUDIO_NAVIGATION_GROUPS.includes(g));
70
- } else {
71
- groupsToRender = groupsToRender.filter(g => !STUDIO_NAVIGATION_GROUPS.includes(g));
72
- }
66
+ // Studio mode shows view-type entries (devViews) + admin entries (Users/Roles).
67
+ // Content mode shows collections and custom entries + admin entries (Users/Roles), but not studio views.
68
+ const filteredEntries = adminModeController.mode === "studio"
69
+ ? allNavigationEntries.filter(e => e.type === "view" || e.type === "admin")
70
+ : allNavigationEntries.filter(e => e.type !== "view");
71
+
72
+ // Derive groups from the filtered entries, preserving the order from topLevelNavigation.groups
73
+ const entryGroups = new Set(filteredEntries.map(e => e.group).filter(Boolean));
74
+ const orderedGroups = navigationState.topLevelNavigation?.groups ?? [];
75
+ const groupsToRender = [
76
+ ...orderedGroups.filter(g => entryGroups.has(g)),
77
+ ...[...entryGroups].filter(g => !orderedGroups.includes(g))
78
+ ];
73
79
 
74
80
  // Collapsible groups state - using "drawer" namespace for independent state from home page
75
- const { isGroupCollapsed, toggleGroupCollapsed } = useCollapsedGroups(groupsToRender, "drawer");
81
+ const collapsedDefaults = useMemo(
82
+ () => buildCollapsedDefaults(registry.cmsConfig?.navigationGroupMappings, "drawer"),
83
+ [registry.cmsConfig?.navigationGroupMappings]
84
+ );
85
+ const { isGroupCollapsed, toggleGroupCollapsed } = useCollapsedGroups(groupsToRender, "drawer", collapsedDefaults);
76
86
 
77
87
  const headerSlot = useSlot("navigation.header", { drawerOpen,
78
88
  drawerHovered,
@@ -84,7 +94,6 @@ context });
84
94
  if (!navigationState.topLevelNavigation)
85
95
  return null;
86
96
 
87
- const navigationEntries = navigationState.topLevelNavigation.navigationEntries;
88
97
  const groups = navigationState.topLevelNavigation.groups;
89
98
 
90
99
  const onItemClick = (view: NavigationEntry) => {
@@ -126,7 +135,7 @@ context });
126
135
  <div
127
136
  ref={scrollRef}
128
137
  onScroll={handleScroll}
129
- className={"flex-grow min-h-0 overflow-y-auto overflow-x-visible no-scrollbar"}
138
+ className={"flex-grow min-h-0 overflow-y-auto overflow-x-hidden no-scrollbar"}
130
139
  style={{
131
140
  maskImage: scrolled
132
141
  ? "linear-gradient(to bottom, transparent 0, black 20px, black calc(100% - 20px), transparent 100%)"
@@ -134,7 +143,7 @@ context });
134
143
  }}>
135
144
 
136
145
  {groupsToRender.map((group) => {
137
- const entriesInGroup = Object.values(navigationEntries).filter(e => e.group === group);
146
+ const entriesInGroup = filteredEntries.filter(e => e.group === group);
138
147
  return (
139
148
  <DrawerNavigationGroup
140
149
  key={`drawer_group_${group}`}
@@ -146,7 +155,6 @@ context });
146
155
  tooltipsOpen={tooltipsOpen}
147
156
  adminMenuOpen={adminMenuOpen}
148
157
  onItemClick={onItemClick}
149
- hideHeader={adminModeController.mode === "studio"}
150
158
  />
151
159
  );
152
160
  })}
@@ -306,7 +314,7 @@ function DrawerModeSwitch({
306
314
  return (
307
315
  <div
308
316
  className={cls(
309
- "overflow-hidden transition-all duration-200 ease-in-out px-3",
317
+ "shrink-0 overflow-hidden transition-all duration-200 ease-in-out px-3",
310
318
  showSwitch ? "opacity-100 h-7 mt-2 mb-0" : "opacity-0 pointer-events-none h-7 mt-2 mb-0"
311
319
  )}
312
320
  >
@@ -75,7 +75,7 @@ export function DrawerNavigationGroup({
75
75
  {/* Group Header */}
76
76
  {!hideHeader && (
77
77
  <div
78
- className={cls("pl-4 pr-2 py-0.5 flex flex-row items-center transition-colors",
78
+ className={cls("pl-3 pr-2 py-0.5 flex flex-row items-center transition-colors",
79
79
  drawerOpen ? "cursor-pointer hover:bg-surface-100 dark:hover:bg-surface-800/40 rounded-lg" : "opacity-0 invisible pointer-events-none"
80
80
  )}
81
81
  onClick={drawerOpen ? onToggleCollapsed : undefined}
@@ -83,14 +83,14 @@ export function DrawerNavigationGroup({
83
83
  <ChevronDownIcon
84
84
  size={iconSize.small}
85
85
  className={cls(
86
- "text-surface-500 dark:text-surface-400 transition-transform duration-200 mr-1",
86
+ "text-surface-400 dark:text-surface-400 transition-transform duration-200 mr-1",
87
87
  collapsed ? "-rotate-90" : "rotate-0"
88
88
  )}
89
89
  />
90
90
  <Typography
91
91
  variant={"caption"}
92
92
  color={"secondary"}
93
- className="font-medium flex-grow line-clamp-1"
93
+ className="font-semibold text-[11px] uppercase tracking-wider flex-grow line-clamp-1 text-surface-400 dark:text-surface-400"
94
94
  >
95
95
  {(group || t("views_group"))}
96
96
  </Typography>
@@ -106,7 +106,7 @@ export function DrawerNavigationGroup({
106
106
  <div
107
107
  className={cls(
108
108
  "transition-all duration-200 ease-in-out",
109
- (!hideHeader && collapsed) ? "overflow-hidden" : "overflow-visible",
109
+ "overflow-hidden",
110
110
  !hideHeader && "dark:bg-transparent",
111
111
  !hideHeader ? (drawerOpen ? "rounded-lg" : "rounded-lg") : "rounded-lg",
112
112
  (!hideHeader && collapsed) ? "max-h-0 opacity-0" : "max-h-[2000px] opacity-100"