@rebasepro/admin 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/LICENSE +21 -0
  2. package/dist/{CollectionEditorDialog-iGgS4rLX.js → CollectionEditorDialog-BO_aQ-Z4.js} +7 -7
  3. package/dist/CollectionEditorDialog-BO_aQ-Z4.js.map +1 -0
  4. package/dist/{PropertyEditView-C9yhLyja.js → PropertyEditView-DKzOpMjR.js} +64 -38
  5. package/dist/PropertyEditView-DKzOpMjR.js.map +1 -0
  6. package/dist/{RouterCollectionsStudioView-Dqx27GD8.js → RouterCollectionsStudioView-BQTIExjA.js} +4 -4
  7. package/dist/{RouterCollectionsStudioView-Dqx27GD8.js.map → RouterCollectionsStudioView-BQTIExjA.js.map} +1 -1
  8. package/dist/collection_editor/_cms_internals.d.ts +1 -1
  9. package/dist/collection_editor/api/generateCollectionApi.d.ts +3 -2
  10. package/dist/collection_editor/serializable_types.d.ts +5 -9
  11. package/dist/collection_editor/serializable_utils.d.ts +2 -2
  12. package/dist/collection_editor/ui/collection_editor/CollectionEditorDialog.d.ts +1 -2
  13. package/dist/collection_editor_ui.js +4 -4
  14. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
  15. package/dist/components/EntityCollectionTable/index.d.ts +1 -1
  16. package/dist/components/RebaseCMS.d.ts +1 -1
  17. package/dist/components/SelectableTable/SelectionStore.d.ts +12 -21
  18. package/dist/components/field_configs.d.ts +1 -1
  19. package/dist/editor/editor.d.ts +0 -6
  20. package/dist/editor.js +1 -3
  21. package/dist/editor.js.map +1 -1
  22. package/dist/form/components/StorageUploadProgress.d.ts +6 -1
  23. package/dist/form/index.d.ts +0 -1
  24. package/dist/{history-ChHgyyvM.js → history-B3cqBzEV.js} +2 -2
  25. package/dist/{history-ChHgyyvM.js.map → history-B3cqBzEV.js.map} +1 -1
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.js +2 -2
  28. package/dist/preview/components/StorageThumbnail.d.ts +3 -1
  29. package/dist/{src-DOX2nOyh.js → src-cxV1ODRG.js} +178 -460
  30. package/dist/src-cxV1ODRG.js.map +1 -0
  31. package/dist/types/components/PropertyPreviewProps.d.ts +2 -1
  32. package/dist/types/fields.d.ts +4 -6
  33. package/package.json +18 -18
  34. package/src/collection_editor/_cms_internals.ts +1 -1
  35. package/src/collection_editor/api/generateCollectionApi.ts +3 -2
  36. package/src/collection_editor/pgColumnToProperty.ts +2 -2
  37. package/src/collection_editor/serializable_types.ts +14 -27
  38. package/src/collection_editor/serializable_utils.ts +25 -37
  39. package/src/collection_editor/ui/collection_editor/AICollectionGeneratorPopover.tsx +2 -2
  40. package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +41 -24
  41. package/src/collection_editor/ui/collection_editor/PropertyEditView.tsx +0 -9
  42. package/src/collection_editor/ui/collection_editor/properties/StoragePropertyField.tsx +35 -1
  43. package/src/collection_editor/ui/collection_editor/templates/blog_template.ts +1 -1
  44. package/src/collection_editor/ui/collection_editor/utils/supported_fields.tsx +0 -1
  45. package/src/collection_editor/ui/collection_editor/utils/update_property_for_widget.ts +7 -29
  46. package/src/collection_editor/useJsonCollectionsConfigController.tsx +2 -2
  47. package/src/components/DefaultDrawer.tsx +1 -1
  48. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +11 -9
  49. package/src/components/EntityCollectionTable/fields/TableMultipleRelationField.tsx +2 -1
  50. package/src/components/EntityCollectionTable/fields/TableRelationField.tsx +2 -1
  51. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +23 -20
  52. package/src/components/EntityCollectionTable/index.tsx +1 -1
  53. package/src/components/EntityCollectionTable/table_bindings.tsx +24 -44
  54. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +1 -1
  55. package/src/components/EntityCollectionView/EntityCollectionListView.tsx +12 -1
  56. package/src/components/EntityCollectionView/EntityCollectionView.tsx +8 -25
  57. package/src/components/EntityCollectionView/hooks/useCollectionInlineEditor.ts +1 -1
  58. package/src/components/EntityCollectionView/useBoardDataController.tsx +12 -40
  59. package/src/components/EntityCollectionView/useEntityPreviewSlots.ts +3 -3
  60. package/src/components/EntityDetailView.tsx +2 -2
  61. package/src/components/EntityEditView.tsx +2 -2
  62. package/src/components/EntityEditViewFormActions.tsx +3 -3
  63. package/src/components/HomePage/ContentHomePage.tsx +1 -1
  64. package/src/components/RebaseCMS.tsx +2 -3
  65. package/src/components/RebaseNavigation.tsx +3 -2
  66. package/src/components/RelationSelector.tsx +2 -2
  67. package/src/components/SelectableTable/SelectableTable.tsx +11 -3
  68. package/src/components/SelectableTable/SelectionStore.ts +18 -48
  69. package/src/components/common/default_entity_actions.tsx +15 -4
  70. package/src/components/field_configs.tsx +0 -14
  71. package/src/editor/editor.tsx +4 -7
  72. package/src/form/EntityFormActions.tsx +2 -2
  73. package/src/form/EntityFormBinding.tsx +1 -1
  74. package/src/form/components/StorageUploadProgress.tsx +9 -2
  75. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +12 -1
  76. package/src/form/field_bindings/MultipleRelationFieldBinding.tsx +4 -4
  77. package/src/form/field_bindings/RelationFieldBinding.tsx +5 -7
  78. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +19 -15
  79. package/src/form/index.tsx +0 -1
  80. package/src/index.ts +1 -1
  81. package/src/preview/PropertyPreview.tsx +1 -16
  82. package/src/preview/components/StorageThumbnail.tsx +24 -7
  83. package/src/types/components/PropertyPreviewProps.tsx +1 -1
  84. package/src/types/fields.tsx +2 -7
  85. package/src/util/previews.ts +20 -0
  86. package/src/util/propertyConfigMapper.ts +3 -3
  87. package/src/util/property_utils.tsx +1 -2
  88. package/dist/CollectionEditorDialog-iGgS4rLX.js.map +0 -1
  89. package/dist/PropertyEditView-C9yhLyja.js.map +0 -1
  90. package/dist/components/EntityCollectionTable/fields/VirtualTableDateField.d.ts +0 -12
  91. package/dist/components/EntityCollectionTable/fields/VirtualTableInput.d.ts +0 -10
  92. package/dist/components/EntityCollectionTable/fields/VirtualTableNumberInput.d.ts +0 -9
  93. package/dist/components/EntityCollectionTable/fields/VirtualTableSwitch.d.ts +0 -8
  94. package/dist/form/field_bindings/ReferenceAsStringFieldBinding.d.ts +0 -11
  95. package/dist/src-DOX2nOyh.js.map +0 -1
  96. package/src/components/EntityCollectionTable/fields/VirtualTableDateField.tsx +0 -39
  97. package/src/components/EntityCollectionTable/fields/VirtualTableInput.tsx +0 -90
  98. package/src/components/EntityCollectionTable/fields/VirtualTableNumberInput.tsx +0 -83
  99. package/src/components/EntityCollectionTable/fields/VirtualTableSwitch.tsx +0 -32
  100. package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +0 -141
@@ -14,10 +14,8 @@ export function updatePropertyFromWidget(propertyData: any,
14
14
  type: "string",
15
15
  propertyConfig: "text_field",
16
16
  storage: undefined,
17
- multiline: undefined,
18
- markdown: undefined,
17
+ ui: { multiline: undefined, markdown: undefined, url: undefined },
19
18
  email: undefined,
20
- url: undefined,
21
19
  enum: undefined,
22
20
  userSelect: undefined
23
21
  } as StringProperty
@@ -29,10 +27,8 @@ export function updatePropertyFromWidget(propertyData: any,
29
27
  type: "string",
30
28
  propertyConfig: "user_select",
31
29
  storage: undefined,
32
- multiline: undefined,
33
- markdown: undefined,
30
+ ui: { multiline: undefined, markdown: undefined, url: undefined },
34
31
  email: undefined,
35
- url: undefined,
36
32
  enum: undefined,
37
33
  userSelect: true
38
34
  } as StringProperty
@@ -43,11 +39,9 @@ export function updatePropertyFromWidget(propertyData: any,
43
39
  {
44
40
  type: "string",
45
41
  propertyConfig: "multiline",
46
- multiline: true,
42
+ ui: { multiline: true, markdown: undefined, url: undefined },
47
43
  storage: undefined,
48
- markdown: undefined,
49
44
  email: undefined,
50
- url: undefined,
51
45
  enum: undefined,
52
46
  userSelect: undefined
53
47
  } as StringProperty
@@ -59,10 +53,8 @@ export function updatePropertyFromWidget(propertyData: any,
59
53
  type: "string",
60
54
  propertyConfig: "markdown",
61
55
  storage: undefined,
62
- multiline: undefined,
63
- markdown: true,
56
+ ui: { multiline: undefined, markdown: true, url: undefined },
64
57
  email: undefined,
65
- url: undefined,
66
58
  userSelect: undefined
67
59
  } as StringProperty
68
60
  );
@@ -73,10 +65,8 @@ export function updatePropertyFromWidget(propertyData: any,
73
65
  type: "string",
74
66
  propertyConfig: "url",
75
67
  storage: undefined,
76
- multiline: undefined,
77
- markdown: undefined,
68
+ ui: { multiline: undefined, markdown: undefined, url: true },
78
69
  email: undefined,
79
- url: true,
80
70
  enum: undefined,
81
71
  userSelect: undefined
82
72
  } as StringProperty
@@ -88,10 +78,8 @@ export function updatePropertyFromWidget(propertyData: any,
88
78
  type: "string",
89
79
  propertyConfig: "email",
90
80
  storage: undefined,
91
- multiline: undefined,
92
- markdown: undefined,
81
+ ui: { multiline: undefined, markdown: undefined, url: undefined },
93
82
  email: true,
94
- url: undefined,
95
83
  enum: undefined,
96
84
  userSelect: undefined
97
85
  } as StringProperty
@@ -103,10 +91,8 @@ export function updatePropertyFromWidget(propertyData: any,
103
91
  type: "string",
104
92
  propertyConfig: "select",
105
93
  storage: undefined,
106
- multiline: undefined,
107
- markdown: undefined,
94
+ ui: { multiline: undefined, markdown: undefined, url: undefined },
108
95
  email: undefined,
109
- url: undefined,
110
96
  enum: propertyData.enum ?? [],
111
97
  userSelect: undefined
112
98
  } as StringProperty
@@ -206,14 +192,6 @@ export function updatePropertyFromWidget(propertyData: any,
206
192
  propertyConfig: "reference"
207
193
  } as Property
208
194
  );
209
- } else if (selectedWidgetId === "reference_as_string") {
210
- updatedProperty = mergeDeep(
211
- propertyData,
212
- {
213
- type: "string",
214
- propertyConfig: "reference_as_string"
215
- } as Property
216
- );
217
195
  } else if (selectedWidgetId === "multi_references") {
218
196
  updatedProperty = mergeDeep(
219
197
  propertyData,
@@ -1,5 +1,5 @@
1
1
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
- import type { EntityCollection, NavigationGroupMapping, Property } from "@rebasepro/types";
2
+ import type { EngineProperties, EntityCollection, NavigationGroupMapping, Property } from "@rebasepro/types";
3
3
  import type {
4
4
  CollectionsConfigController,
5
5
  SaveCollectionParams,
@@ -171,7 +171,7 @@ export function useJsonCollectionsConfigController({
171
171
  collection.properties = {
172
172
  ...collection.properties,
173
173
  [propertyKey]: property,
174
- };
174
+ } as EngineProperties;
175
175
  if (newPropertiesOrder) {
176
176
  collection.propertiesOrder = newPropertiesOrder as typeof collection.propertiesOrder;
177
177
  }
@@ -178,7 +178,7 @@ function CMSNavigationContent() {
178
178
  // Studio mode shows Studio dev views + admin entries (Users/Roles).
179
179
  // Content mode shows collections, CMS custom views, and admin entries — but not Studio dev views.
180
180
  const filteredEntries = adminModeController.mode === "studio"
181
- ? allNavigationEntries.filter(e => e.type === "view" || e.type === "admin")
181
+ ? allNavigationEntries.filter(e => (e.type === "view" && studioViewSlugs.has(e.slug)) || e.type === "admin")
182
182
  : allNavigationEntries.filter(e => e.type !== "view" || !studioViewSlugs.has(e.slug));
183
183
 
184
184
  // Derive groups from the filtered entries, preserving the order from topLevelNavigation.groups
@@ -42,7 +42,7 @@ import { getValueInPath } from "@rebasepro/utils";
42
42
  * @see VirtualTable
43
43
  * @group Components
44
44
  */
45
- export const EntityCollectionTable = function EntityCollectionTable<M extends Record<string, unknown> = any, USER extends User = any>
45
+ export const EntityCollectionTable = function EntityCollectionTable<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>
46
46
  ({
47
47
  className,
48
48
  style,
@@ -113,7 +113,7 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
113
113
  const additionalFieldsMap: Record<string, AdditionalFieldDelegate<M, USER>> = useMemo(() => {
114
114
  return (additionalFields
115
115
  ? additionalFields
116
- .map((aC) => ({ [aC.key]: aC as AdditionalFieldDelegate<M, any> }))
116
+ .map((aC) => ({ [aC.key]: aC as AdditionalFieldDelegate<M, USER> }))
117
117
  .reduce((a, b) => ({ ...a,
118
118
  ...b }), {})
119
119
  : {}) as Record<string, AdditionalFieldDelegate<M, USER>>;
@@ -132,9 +132,10 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
132
132
  isDragging,
133
133
  isDraggable,
134
134
  frozen
135
- }: CellRendererParams<any>) => {
135
+ }: CellRendererParams<Entity<M>>) => {
136
136
 
137
- const entity: Entity<M> = rowData;
137
+ const entity: Entity<M> | undefined = rowData;
138
+ if (!entity) return null;
138
139
 
139
140
  const propertyKey = column.key;
140
141
 
@@ -192,9 +193,10 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
192
193
  isDragging,
193
194
  isDraggable,
194
195
  frozen
195
- }: CellRendererParams<any>) => {
196
+ }: CellRendererParams<Entity<M>>) => {
196
197
 
197
- const entity: Entity<M> = rowData;
198
+ const entity: Entity<M> | undefined = rowData;
199
+ if (!entity) return null;
198
200
 
199
201
  const additionalField = additionalFieldsMap[column.key as string];
200
202
  const value = additionalField.dependencies
@@ -293,7 +295,7 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
293
295
  : collectionColumns) as VirtualTableColumn[]
294
296
  ], [idColumn, displayedColumnIds, collectionColumns]);
295
297
 
296
- const cellRenderer = useCallback((props: CellRendererParams<any>) => {
298
+ const cellRenderer = useCallback((props: CellRendererParams<Entity<M>>) => {
297
299
  const column = props.column;
298
300
  const columns = props.columns;
299
301
  const columnKey = column.key;
@@ -302,13 +304,13 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
302
304
  if (props.columnIndex === 0) {
303
305
  if (tableRowActionsBuilder)
304
306
  return tableRowActionsBuilder({
305
- entity: props.rowData,
307
+ entity: props.rowData!,
306
308
  size,
307
309
  width: column.width,
308
310
  frozen: column.frozen
309
311
  });
310
312
  else
311
- return <EntityCollectionRowActions entity={props.rowData}
313
+ return <EntityCollectionRowActions entity={props.rowData!}
312
314
  width={column.width}
313
315
  frozen={column.frozen}
314
316
  isSelected={false}
@@ -1,5 +1,6 @@
1
1
  import { useEntitySelectionDialog } from "../../../hooks/useEntitySelectionDialog";
2
2
  import type { EntityCollection } from "@rebasepro/types";
3
+ import { getCollectionDataPath } from "@rebasepro/types";
3
4
  import React, { useCallback } from "react";
4
5
  import { deepEqual as equal } from "fast-equals";
5
6
 
@@ -58,7 +59,7 @@ export const TableMultipleRelationFieldInternal = React.memo(
58
59
 
59
60
  const relationDialogController = useEntitySelectionDialog({
60
61
  multiselect: true,
61
- path: collection.slug,
62
+ path: getCollectionDataPath(collection),
62
63
  collection,
63
64
  onMultipleEntitiesSelected,
64
65
  selectedEntityIds,
@@ -1,5 +1,6 @@
1
1
  import { useEntitySelectionDialog } from "../../../hooks/useEntitySelectionDialog";
2
2
  import type { EntityCollection } from "@rebasepro/types";
3
+ import { getCollectionDataPath } from "@rebasepro/types";
3
4
  import React, { useCallback } from "react";
4
5
  import { deepEqual as equal } from "fast-equals"
5
6
 
@@ -90,7 +91,7 @@ export const TableRelationFieldInternal = React.memo(
90
91
 
91
92
  const relationDialogController = useEntitySelectionDialog({
92
93
  multiselect,
93
- path: collection.slug,
94
+ path: getCollectionDataPath(collection),
94
95
  collection,
95
96
  onMultipleEntitiesSelected,
96
97
  onSingleEntitySelected,
@@ -8,7 +8,7 @@ import { useDropzone } from "react-dropzone";
8
8
  import { PropertyPreview } from "../../../preview";
9
9
  import { ErrorBoundary } from "@rebasepro/ui";
10
10
  import { cls, IconButton, PencilIcon, Typography } from "@rebasepro/ui";
11
- import { useSnackbarController, useStorageSource, useTranslation, StorageFieldItem, useStorageUploadController } from "@rebasepro/core";
11
+ import { useSnackbarController, useStorageSource, useTranslation, StorageFieldItem, useStorageUploadController, StorageSourceContext } from "@rebasepro/core";
12
12
  import { getThumbnailMeasure } from "../../../preview/util";
13
13
  import { StorageUploadProgress } from "../../../form/components/StorageUploadProgress";
14
14
  import { EntityTableCellActions } from "../internal/EntityTableCellActions";
@@ -64,7 +64,8 @@ export function TableStorageUpload(props: {
64
64
  storage,
65
65
  onFileUploadComplete,
66
66
  storagePathBuilder,
67
- multipleFilesSupported
67
+ multipleFilesSupported,
68
+ resolvedStorageSource
68
69
  } = useStorageUploadController({
69
70
  entityValues: entity.values,
70
71
  entityId: entity.id,
@@ -79,24 +80,26 @@ export function TableStorageUpload(props: {
79
80
 
80
81
  return (
81
82
 
82
- <StorageUpload
83
- internalValue={internalValue}
84
- setInternalValue={setInternalValue}
85
- name={propertyKey}
86
- disabled={disabled}
87
- autoFocus={false}
88
- openPopup={openPopup}
89
- error={error}
90
- selected={selected}
91
- property={property}
92
- onChange={updateValue}
93
- entity={entity}
94
- storagePathBuilder={storagePathBuilder}
95
- storage={storage}
96
- multipleFilesSupported={multipleFilesSupported}
97
- onFilesAdded={onFilesAdded}
98
- onFileUploadComplete={onFileUploadComplete}
99
- previewSize={previewSize}/>
83
+ <StorageSourceContext.Provider value={resolvedStorageSource}>
84
+ <StorageUpload
85
+ internalValue={internalValue}
86
+ setInternalValue={setInternalValue}
87
+ name={propertyKey}
88
+ disabled={disabled}
89
+ autoFocus={false}
90
+ openPopup={openPopup}
91
+ error={error}
92
+ selected={selected}
93
+ property={property}
94
+ onChange={updateValue}
95
+ entity={entity}
96
+ storagePathBuilder={storagePathBuilder}
97
+ storage={storage}
98
+ multipleFilesSupported={multipleFilesSupported}
99
+ onFilesAdded={onFilesAdded}
100
+ onFileUploadComplete={onFileUploadComplete}
101
+ previewSize={previewSize}/>
102
+ </StorageSourceContext.Provider>
100
103
 
101
104
  );
102
105
  }
@@ -11,4 +11,4 @@ export * from "./EntityCollectionRowActions";
11
11
 
12
12
  export * from "./column_utils";
13
13
 
14
- export { VirtualTableInput } from "./fields/VirtualTableInput";
14
+ export { VirtualTableInput } from "@rebasepro/ui";
@@ -1,12 +1,14 @@
1
1
  import React from "react";
2
2
  import { ArrayProperty, DateProperty, Entity, EntityReference, EntityRelation, NumberProperty, Property, ReferenceProperty, RelationProperty, StringProperty } from "@rebasepro/types";
3
- import { TableSize } from "@rebasepro/core";
3
+ import { TableSize, useCustomizationController } from "@rebasepro/core";
4
+ import {
5
+ VirtualTableInput,
6
+ VirtualTableNumberInput,
7
+ VirtualTableSwitch,
8
+ VirtualTableDateField
9
+ } from "@rebasepro/ui";
4
10
 
5
- import { VirtualTableInput } from "./fields/VirtualTableInput";
6
11
  import { VirtualTableSelect } from "./fields/VirtualTableSelect";
7
- import { VirtualTableNumberInput } from "./fields/VirtualTableNumberInput";
8
- import { VirtualTableSwitch } from "./fields/VirtualTableSwitch";
9
- import { VirtualTableDateField } from "./fields/VirtualTableDateField";
10
12
  import { VirtualTableUserSelect } from "./fields/VirtualTableUserSelect";
11
13
  import { TableStorageUpload } from "./fields/TableStorageUpload";
12
14
  import { TableReferenceField } from "./fields/TableReferenceField";
@@ -63,33 +65,7 @@ export function getTableBindingForProperty(
63
65
  ): TableFieldConfig | undefined {
64
66
  const isAStorageProperty = isStorageProperty(property);
65
67
 
66
- if (property.type === "string" && (property as StringProperty).reference?.path) {
67
- return {
68
- Component: ({ propertyKey, property, internalValue, updateValue, disabled, size, path }: TableFieldBindingProps) => {
69
- const referenceProperty = (property as StringProperty).reference;
70
- if (!referenceProperty) return null;
71
- const referenceValue = internalValue ? new EntityReference({ id: internalValue as string,
72
- path: referenceProperty.path as string }) : undefined;
73
- return (
74
- <TableReferenceField
75
- name={propertyKey}
76
- internalValue={referenceValue}
77
- updateValue={(v) => updateValue(v ? (v as EntityReference).id : null)}
78
- disabled={disabled}
79
- size={size}
80
- path={referenceProperty.path as string}
81
- multiselect={false}
82
- previewProperties={referenceProperty.ui?.previewProperties}
83
- includeId={referenceProperty.includeId}
84
- includeEntityLink={referenceProperty.includeEntityLink}
85
- title={property.name}
86
- fixedFilter={referenceProperty.fixedFilter}
87
- />
88
- );
89
- },
90
- allowScroll: false
91
- };
92
- } else if (isAStorageProperty) {
68
+ if (isAStorageProperty) {
93
69
  return {
94
70
  Component: ({ validationError, error, disabled, selected, openPopup, property, entity, path, internalValue, size, updateValue, propertyKey }: TableFieldBindingProps) => (
95
71
  <TableStorageUpload
@@ -183,7 +159,7 @@ export function getTableBindingForProperty(
183
159
  ),
184
160
  fullHeight: true
185
161
  };
186
- } else if (stringProperty.ui?.markdown || !stringProperty.storage || !stringProperty.reference) {
162
+ } else if (stringProperty.ui?.markdown || !stringProperty.storage) {
187
163
  const multiline = Boolean(stringProperty.ui?.multiline) || Boolean(stringProperty.ui?.markdown);
188
164
  return {
189
165
  Component: ({ error, validationError, disabled, selected, internalValue, updateValue }: TableFieldBindingProps) => (
@@ -213,17 +189,21 @@ export function getTableBindingForProperty(
213
189
  };
214
190
  } else if (property.type === "date") {
215
191
  return {
216
- Component: ({ propertyKey, error, validationError, disabled, selected, property, internalValue, updateValue }: TableFieldBindingProps) => (
217
- <VirtualTableDateField
218
- name={propertyKey}
219
- error={validationError ?? error}
220
- disabled={disabled}
221
- mode={(property as DateProperty).mode}
222
- focused={selected}
223
- internalValue={internalValue as Date}
224
- updateValue={updateValue}
225
- />
226
- ),
192
+ Component: ({ propertyKey, error, validationError, disabled, selected, property, internalValue, updateValue }: TableFieldBindingProps) => {
193
+ const { locale } = useCustomizationController();
194
+ return (
195
+ <VirtualTableDateField
196
+ name={propertyKey}
197
+ error={validationError ?? error}
198
+ disabled={disabled}
199
+ mode={(property as DateProperty).mode}
200
+ focused={selected}
201
+ internalValue={internalValue as Date}
202
+ updateValue={updateValue}
203
+ locale={locale}
204
+ />
205
+ );
206
+ },
227
207
  fullHeight: true,
228
208
  hideOverflow: false,
229
209
  allowScroll: false
@@ -281,7 +281,7 @@ parentEntityIds,
281
281
  }).catch(e => console.warn("Failed to get total count:", e));
282
282
 
283
283
  accessor.count({
284
- where: { [orderProperty]: "neq.null" }
284
+ where: { [orderProperty]: ["!=", null] }
285
285
  }).then(count => {
286
286
  orderedCount = count;
287
287
  completed++;
@@ -402,7 +402,18 @@ export function EntityCollectionListView<M extends Record<string, unknown> = Rec
402
402
  "id"
403
403
  ]);
404
404
 
405
- const availableExtraKeys = allKeys.filter(k => !usedKeys.has(k) && resolvedCollection.properties[k]);
405
+ const availableExtraKeys = allKeys.filter(k => {
406
+ if (usedKeys.has(k)) return false;
407
+ const prop = resolvedCollection.properties[k] as Property | undefined;
408
+ if (!prop) return false;
409
+ // Exclude storage/image properties — they are already rendered in the image slot
410
+ if (prop.type === "string" && (prop.storage || prop.ui?.url === "image")) return false;
411
+ if (prop.type === "array" && prop.of && !Array.isArray(prop.of)) {
412
+ const inner = prop.of;
413
+ if (inner.type === "string" && (inner.storage || inner.ui?.url === "image")) return false;
414
+ }
415
+ return true;
416
+ });
406
417
 
407
418
  availableExtraKeys.forEach(key => {
408
419
  const prop = resolvedCollection.properties[key] as Property;
@@ -7,10 +7,10 @@ import { useSearchParams } from "react-router-dom";
7
7
  import { deepEqual as equal } from "fast-equals"
8
8
 
9
9
 
10
- const EMPTY_ARRAY: any[] = [];
10
+ const EMPTY_ARRAY: never[] = [];
11
11
  const DEFAULT_ENTITY_OPEN_MODE = "split";
12
12
 
13
- import { CollectionSize, Entity, EntityReference, EntityTableController, FilterValues, PartialEntityCollection, ViewMode } from "@rebasepro/types";
13
+ import { CollectionSize, Entity, EntityReference, EntityTableController, FilterValues, getCollectionDataPath, PartialEntityCollection, ViewMode } from "@rebasepro/types";
14
14
  import {
15
15
  EntityCollectionRowActions,
16
16
  EntityCollectionTable
@@ -163,7 +163,7 @@ const EntityCollectionViewInner = React.memo(
163
163
  const collectionRegistry = useCollectionRegistryController();
164
164
  const urlController = useUrlController();
165
165
  const breadcrumbs = useBreadcrumbsController();
166
- const path = pathProp ?? collectionProp.slug;
166
+ const path = pathProp ?? getCollectionDataPath(collectionProp);
167
167
  const dataClient = useData();
168
168
  const sideEntityController = useSideEntityController();
169
169
  const authController = useAuthController();
@@ -215,7 +215,7 @@ const EntityCollectionViewInner = React.memo(
215
215
  }, 2400);
216
216
  }, [highlightedEntity]);
217
217
 
218
- const checkInlineEditing = useCallback((entity?: Entity<any>): boolean => {
218
+ const checkInlineEditing = useCallback((entity?: Entity<M>): boolean => {
219
219
  const collection = collectionRef.current;
220
220
  if (!canEdit(collection, path, entity ?? null)) {
221
221
  return false;
@@ -894,7 +894,7 @@ parentEntityIds,
894
894
  collection={collection}
895
895
  tableController={tableController}
896
896
  path={path}
897
- relativePath={collection.slug}
897
+ relativePath={getCollectionDataPath(collection)}
898
898
  selectionController={usedSelectionController}
899
899
  collectionEntitiesCount={docsCount ?? undefined}
900
900
  resolvedProperties={resolvedCollection.properties}
@@ -909,7 +909,7 @@ parentEntityIds,
909
909
  onNewClick={onNewClick}
910
910
  openNewDocument={openNewDocument}
911
911
  path={path}
912
- relativePath={collection.slug}
912
+ relativePath={getCollectionDataPath(collection)}
913
913
  selectionController={usedSelectionController}
914
914
  selectionEnabled={activeSelectionEnabled}
915
915
  collectionEntitiesCount={docsCount ?? undefined}
@@ -1301,25 +1301,8 @@ function EntitiesCount({
1301
1301
 
1302
1302
  let cancelled = false;
1303
1303
 
1304
- // Convert filterValues to PostgREST where clause
1305
- const whereMap: Record<string, string> = {};
1306
- if (filter) {
1307
- Object.entries(filter).forEach(([key, value]) => {
1308
- if (value && Array.isArray(value)) {
1309
- const [op, val] = value;
1310
- const postgrestOp = op === "==" ? "eq" : op === "!=" ? "neq" : op === ">" ? "gt" : op === ">=" ? "gte" : op === "<" ? "lt" : op === "<=" ? "lte" : op === "in" ? "in" : op === "not-in" ? "nin" : op === "array-contains" ? "cs" : op === "array-contains-any" ? "csa" : "eq";
1311
-
1312
- let stringVal: string;
1313
- if (Array.isArray(val)) {
1314
- stringVal = `(${val.join(",")})`;
1315
- } else {
1316
- stringVal = String(val);
1317
- }
1318
- whereMap[key] = `${postgrestOp}.${stringVal}`;
1319
- }
1320
- });
1321
- }
1322
- const whereParams = Object.keys(whereMap).length > 0 ? whereMap : undefined;
1304
+ // filterValues is already FilterValues — pass directly
1305
+ const whereParams = filter && Object.keys(filter).length > 0 ? filter : undefined;
1323
1306
  const orderByParams = sortByProperty ? `${String(sortByProperty)}:${currentSort}` : undefined;
1324
1307
 
1325
1308
  // Deduplicate inflight count requests (e.g. React StrictMode double-mount)
@@ -22,7 +22,7 @@ export function useCollectionInlineEditor<M extends Record<string, unknown>>({
22
22
  async ({ name, value, property, entityId }: Parameters<UniqueFieldValidator>[0]) => {
23
23
  const accessor = dataClient.collection(path);
24
24
  const res = await accessor.find({
25
- where: { [name]: "eq." + value }
25
+ where: { [name]: ["==", value] }
26
26
  });
27
27
 
28
28
  const conflictingEntities = res.data;
@@ -238,25 +238,11 @@ export function useBoardDataController<M extends Record<string, unknown> = any,
238
238
  return;
239
239
  }
240
240
 
241
- // Build where map for this column
242
- const whereMap: Record<string, string> = {};
243
- if (currentFilterValues) {
244
- Object.entries(currentFilterValues).forEach(([key, value]) => {
245
- if (value && Array.isArray(value)) {
246
- const [op, val] = value;
247
- const postgrestOp = op === "==" ? "eq" : op === "!=" ? "neq" : op === ">" ? "gt" : op === ">=" ? "gte" : op === "<" ? "lt" : op === "<=" ? "lte" : op === "in" ? "in" : op === "not-in" ? "nin" : op === "array-contains" ? "cs" : op === "array-contains-any" ? "csa" : "eq";
248
-
249
- let stringVal: string;
250
- if (Array.isArray(val)) {
251
- stringVal = `(${val.join(",")})`;
252
- } else {
253
- stringVal = String(val);
254
- }
255
- whereMap[key] = `${postgrestOp}.${stringVal}`;
256
- }
257
- });
258
- }
259
- whereMap[currentColumnProperty] = `eq.${column}`;
241
+ // Build filter map for this column — pass FilterValues directly
242
+ const whereFilter: FilterValues<string> = {
243
+ ...(currentFilterValues ?? {}),
244
+ [currentColumnProperty]: ["==", column]
245
+ };
260
246
 
261
247
  const orderByParam = currentOrderProperty ? `${currentOrderProperty}:asc` : undefined;
262
248
 
@@ -420,14 +406,14 @@ values: { ...e.values,
420
406
  const accessor = currentDataClient.collection(currentResolvedPath);
421
407
  if (accessor.listen) {
422
408
  const unsubscribe = accessor.listen({
423
- where: whereMap,
409
+ where: whereFilter,
424
410
  limit: itemCount,
425
411
  orderBy: orderByParam
426
412
  }, res => onUpdate(res.data as Entity<M>[]), onError);
427
413
  unsubscribersRef.current[column] = unsubscribe;
428
414
  } else {
429
415
  accessor.find({
430
- where: whereMap,
416
+ where: whereFilter,
431
417
  limit: itemCount,
432
418
  orderBy: orderByParam
433
419
  })
@@ -479,27 +465,13 @@ values: { ...e.values,
479
465
  const accessor = currentDataClient.collection(currentResolvedPath);
480
466
  if (accessor.count) {
481
467
 
482
- const whereMap: Record<string, string> = {};
483
- if (currentFilterValues) {
484
- Object.entries(currentFilterValues).forEach(([key, value]) => {
485
- if (value && Array.isArray(value)) {
486
- const [op, val] = value;
487
- const postgrestOp = op === "==" ? "eq" : op === "!=" ? "neq" : op === ">" ? "gt" : op === ">=" ? "gte" : op === "<" ? "lt" : op === "<=" ? "lte" : op === "in" ? "in" : op === "not-in" ? "nin" : op === "array-contains" ? "cs" : op === "array-contains-any" ? "csa" : "eq";
488
-
489
- let stringVal: string;
490
- if (Array.isArray(val)) {
491
- stringVal = `(${val.join(",")})`;
492
- } else {
493
- stringVal = String(val);
494
- }
495
- whereMap[key] = `${postgrestOp}.${stringVal}`;
496
- }
497
- });
498
- }
499
- whereMap[currentColumnProperty] = `eq.${column}`;
468
+ const whereFilter: FilterValues<string> = {
469
+ ...(currentFilterValues ?? {}),
470
+ [currentColumnProperty]: ["==", column]
471
+ };
500
472
 
501
473
  accessor.count({
502
- where: whereMap
474
+ where: whereFilter
503
475
  }).then(count => {
504
476
  if (isCleaningUpRef.current) return;
505
477
  setColumnData(prev => ({
@@ -194,8 +194,8 @@ export function resolveCollectionSlotKeys(
194
194
  : [...previewKeys].sort((a, b) => {
195
195
  const propA = collection.properties[a] as Property | undefined;
196
196
  const propB = collection.properties[b] as Property | undefined;
197
- const scoreA = propA?.type === "string" ? (propA.multiline ? 2 : 1) : 0;
198
- const scoreB = propB?.type === "string" ? (propB.multiline ? 2 : 1) : 0;
197
+ const scoreA = propA?.type === "string" ? (propA.ui?.multiline ? 2 : 1) : 0;
198
+ const scoreB = propB?.type === "string" ? (propB.ui?.multiline ? 2 : 1) : 0;
199
199
  return scoreB - scoreA;
200
200
  });
201
201
  const subtitleKey = sortedPreviewKeys.length > 0 ? sortedPreviewKeys[0] : undefined;
@@ -468,7 +468,7 @@ function resolveRelationDisplayName(
468
468
 
469
469
  // Helper to check if a property is a visible, non-id string
470
470
  const isDisplayCandidate = (p: Property): boolean => {
471
- return p.type === "string" && !p.multiline && !p.markdown && !p.storage
471
+ return p.type === "string" && !p.ui?.multiline && !p.ui?.markdown && !p.storage
472
472
  && !("isId" in p && p.isId) && !isHiddenProp(p);
473
473
  };
474
474
 
@@ -2,7 +2,7 @@ import type { ComponentRef, EntityCollection, EntityCustomViewParams, FormViewCo
2
2
  import type { FormContext } from "../types/fields";
3
3
  import type { PluginFormActionProps } from "@rebasepro/types";
4
4
  import React, { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from "react";
5
- import { Entity, EntityStatus, Property } from "@rebasepro/types";
5
+ import { Entity, EntityStatus, getCollectionDataPath, Property } from "@rebasepro/types";
6
6
  import { PluginProviderStack, resolveComponentRef, useComponentOverride, CollectionComponentOverrideProvider } from "@rebasepro/core";
7
7
 
8
8
  import { EntityCollectionView, EntityView } from "../components";
@@ -347,7 +347,7 @@ entityId }
347
347
  // Subcollection views
348
348
  const subCollectionsViews = subcollections && subcollections.map((subcollection) => {
349
349
  const subcollectionId = subcollection.slug;
350
- const newFullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollection.slug)}` : undefined;
350
+ const newFullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(getCollectionDataPath(subcollection))}` : undefined;
351
351
 
352
352
  if (activeTab !== subcollectionId) return null;
353
353
  return (