@firecms/core 3.0.0-beta.5 → 3.0.0-beta.6

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 (67) hide show
  1. package/dist/components/ClearFilterSortButton.d.ts +5 -0
  2. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -11
  3. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +1 -1
  4. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
  5. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +11 -1
  6. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
  7. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  8. package/dist/components/common/types.d.ts +1 -1
  9. package/dist/form/components/ErrorFocus.d.ts +1 -1
  10. package/dist/hooks/useValidateAuthenticator.d.ts +2 -6
  11. package/dist/index.es.js +3516 -3381
  12. package/dist/index.es.js.map +1 -1
  13. package/dist/index.umd.js +5 -5
  14. package/dist/index.umd.js.map +1 -1
  15. package/dist/internal/useBuildDataSource.d.ts +1 -16
  16. package/dist/types/collections.d.ts +5 -1
  17. package/dist/types/datasource.d.ts +2 -5
  18. package/dist/types/entities.d.ts +5 -1
  19. package/dist/types/index.d.ts +0 -1
  20. package/dist/types/navigation.d.ts +1 -1
  21. package/dist/types/plugins.d.ts +3 -1
  22. package/dist/types/properties.d.ts +2 -2
  23. package/dist/util/entities.d.ts +1 -1
  24. package/dist/util/navigation_utils.d.ts +2 -2
  25. package/dist/util/resolutions.d.ts +5 -5
  26. package/package.json +22 -19
  27. package/src/components/ClearFilterSortButton.tsx +41 -0
  28. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +10 -11
  29. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +1 -1
  30. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +16 -19
  31. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +27 -32
  32. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +11 -6
  33. package/src/components/EntityCollectionView/EntityCollectionView.tsx +28 -5
  34. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
  35. package/src/components/EntityView.tsx +1 -1
  36. package/src/components/HomePage/DefaultHomePage.tsx +1 -1
  37. package/src/components/SelectableTable/SelectableTable.tsx +1 -1
  38. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
  39. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +22 -7
  40. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +24 -5
  41. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
  42. package/src/components/VirtualTable/VirtualTable.tsx +28 -20
  43. package/src/components/common/types.tsx +1 -1
  44. package/src/core/FireCMS.tsx +1 -2
  45. package/src/core/field_configs.tsx +1 -2
  46. package/src/hooks/data/save.ts +1 -0
  47. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +9 -10
  48. package/src/hooks/useBuildModeController.tsx +11 -5
  49. package/src/hooks/useBuildNavigationController.tsx +76 -19
  50. package/src/hooks/useProjectLog.tsx +3 -3
  51. package/src/hooks/useValidateAuthenticator.tsx +2 -22
  52. package/src/internal/useBuildDataSource.ts +42 -47
  53. package/src/internal/useBuildSideEntityController.tsx +16 -13
  54. package/src/preview/PropertyPreview.tsx +2 -12
  55. package/src/types/collections.ts +5 -1
  56. package/src/types/datasource.ts +7 -4
  57. package/src/types/entities.ts +9 -1
  58. package/src/types/index.ts +0 -1
  59. package/src/types/navigation.ts +1 -1
  60. package/src/types/plugins.tsx +4 -3
  61. package/src/types/properties.ts +5 -4
  62. package/src/util/entities.ts +1 -1
  63. package/src/util/navigation_utils.ts +6 -6
  64. package/dist/internal/useLocaleConfig.d.ts +0 -1
  65. package/dist/types/appcheck.d.ts +0 -26
  66. package/src/internal/useLocaleConfig.tsx +0 -18
  67. package/src/types/appcheck.ts +0 -29
@@ -1,4 +1,4 @@
1
- import { DataSource, DataSourceDelegate, EntityReference, GeoPoint, NavigationController, PropertyConfig } from "../types";
1
+ import { DataSource, DataSourceDelegate, NavigationController, PropertyConfig } from "../types";
2
2
  /**
3
3
  * Use this hook to build a {@link DataSource} based on Firestore
4
4
  * @param firebaseApp
@@ -9,18 +9,3 @@ export declare function useBuildDataSource({ delegate, propertyConfigs, navigati
9
9
  propertyConfigs?: Record<string, PropertyConfig>;
10
10
  navigationController: NavigationController;
11
11
  }): DataSource;
12
- /**
13
- * Recursive function that converts Firestore data types into CMS or plain
14
- * JS types.
15
- * FireCMS uses Javascript dates internally instead of Firestore timestamps.
16
- * This makes it easier to interact with the rest of the libraries and
17
- * bindings.
18
- * Also, Firestore references are replaced with {@link EntityReference}
19
- * @param data
20
- * @param buildReference
21
- * @param buildGeoPoint
22
- * @param buildDate
23
- * @param buildDelete
24
- * @group Firestore
25
- */
26
- export declare function cmsToDelegateModel(data: any, buildReference: (reference: EntityReference) => any, buildGeoPoint: (geoPoint: GeoPoint) => any, buildDate: (date: Date) => any, buildDelete: () => any): any;
@@ -94,6 +94,10 @@ export interface EntityCollection<M extends Record<string, any> = any, UserType
94
94
  * `subcollection:`. e.g. `subcollection:orders`.
95
95
  * - If you are using a collection group, you will also have an
96
96
  * additional `collectionGroupParent` column.
97
+ * You can use this prop to hide some properties from the table view.
98
+ * Note that if you set this prop, other ways to hide fields, like
99
+ * `hidden` in the property definition,will be ignored.
100
+ * `propertiesOrder` has precedence over `hidden`.
97
101
  */
98
102
  propertiesOrder?: Extract<keyof M, string>[];
99
103
  /**
@@ -445,7 +449,7 @@ export type EntityTableController<M extends Record<string, any> = any> = {
445
449
  filterValues?: FilterValues<Extract<keyof M, string>>;
446
450
  setFilterValues?: (filterValues: FilterValues<Extract<keyof M, string>>) => void;
447
451
  sortBy?: [Extract<keyof M, string>, "asc" | "desc"];
448
- setSortBy?: (sortBy: [Extract<keyof M, string>, "asc" | "desc"]) => void;
452
+ setSortBy?: (sortBy?: [Extract<keyof M, string>, "asc" | "desc"]) => void;
449
453
  searchString?: string;
450
454
  setSearchString?: (searchString?: string) => void;
451
455
  clearFilter?: () => void;
@@ -1,4 +1,4 @@
1
- import { Entity, EntityReference, EntityStatus, EntityValues, GeoPoint } from "./entities";
1
+ import { Entity, EntityStatus, EntityValues } from "./entities";
2
2
  import { EntityCollection, FilterValues } from "./collections";
3
3
  import { ResolvedEntityCollection } from "./resolved_entities";
4
4
  /**
@@ -245,18 +245,15 @@ export interface DataSourceDelegate {
245
245
  * Convert a FireCMS reference to a reference that can be used by the datasource
246
246
  * @param reference
247
247
  */
248
- buildReference: (reference: EntityReference) => any;
249
248
  /**
250
249
  * Convert a FireCMS GeoPoint to a GeoPoint that can be used by the datasource
251
250
  * @param geoPoint
252
251
  */
253
- buildGeoPoint: (geoPoint: GeoPoint) => any;
254
252
  /**
255
253
  * Get the object to generate the current time in the datasource
256
254
  */
257
255
  currentTime(): any;
258
- buildDate: (date: Date) => any;
259
- buildDeleteFieldValue: () => any;
260
256
  delegateToCMSModel: (data: any) => any;
257
+ cmsToDelegateModel: (data: any) => any;
261
258
  setDateToMidnight: (input?: any) => any;
262
259
  }
@@ -31,7 +31,7 @@ export type EntityValues<M extends object> = M;
31
31
  /**
32
32
  * Class used to create a reference to an entity in a different path
33
33
  */
34
- export declare class EntityReference<M extends Record<string, any> = any> {
34
+ export declare class EntityReference {
35
35
  /**
36
36
  * ID of the entity
37
37
  */
@@ -56,3 +56,7 @@ export declare class GeoPoint {
56
56
  readonly longitude: number;
57
57
  constructor(latitude: number, longitude: number);
58
58
  }
59
+ export declare class Vector {
60
+ readonly value: number[];
61
+ constructor(value: number[]);
62
+ }
@@ -23,7 +23,6 @@ export * from "./plugins";
23
23
  export * from "./analytics";
24
24
  export * from "./firecms";
25
25
  export * from "./roles";
26
- export * from "./appcheck";
27
26
  export * from "./export_import";
28
27
  export * from "./modify_collections";
29
28
  export * from "./analytics_controller";
@@ -47,7 +47,7 @@ export type NavigationController<EC extends EntityCollection = EntityCollection<
47
47
  * Get the collection configuration for a given path.
48
48
  * The collection is resolved from the given path or alias.
49
49
  */
50
- getCollection: (pathOrAlias: string, entityId?: string, includeUserOverride?: boolean) => EC | undefined;
50
+ getCollection: (pathOrId: string, entityId?: string, includeUserOverride?: boolean) => EC | undefined;
51
51
  /**
52
52
  * Get the collection configuration from its parent path segments.
53
53
  */
@@ -11,7 +11,7 @@ import { ResolvedProperty } from "./resolved_entities";
11
11
  * NOTE: This is a work in progress and the API is not stable yet.
12
12
  * @group Core
13
13
  */
14
- export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollection = EntityCollection, COL_ACTIONS_PROPS = any> = {
14
+ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollection = EntityCollection, COL_ACTIONS_PROPS = any, COL_ACTIONS_START__PROPS = any> = {
15
15
  /**
16
16
  * Key of the plugin. This is used to identify the plugin in the CMS.
17
17
  */
@@ -78,6 +78,8 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
78
78
  */
79
79
  CollectionActions?: React.ComponentType<CollectionActionsProps<any, any, EC> & COL_ACTIONS_PROPS> | React.ComponentType<CollectionActionsProps<any, any, EC> & COL_ACTIONS_PROPS>[];
80
80
  collectionActionsProps?: COL_ACTIONS_PROPS;
81
+ CollectionActionsStart?: React.ComponentType<CollectionActionsProps<any, any, EC> & COL_ACTIONS_START__PROPS> | React.ComponentType<CollectionActionsProps<any, any, EC> & COL_ACTIONS_START__PROPS>[];
82
+ collectionActionsStartProps?: COL_ACTIONS_START__PROPS;
81
83
  showTextSearchBar?: (props: {
82
84
  context: FireCMSContext;
83
85
  path: string;
@@ -1,14 +1,14 @@
1
1
  import React from "react";
2
2
  import { FieldProps } from "./fields";
3
3
  import { PropertyPreviewProps } from "../preview";
4
- import { EntityReference, EntityValues, GeoPoint } from "./entities";
4
+ import { EntityReference, EntityValues, GeoPoint, Vector } from "./entities";
5
5
  import { ResolvedArrayProperty, ResolvedStringProperty } from "./resolved_entities";
6
6
  import { FilterValues } from "./collections";
7
7
  import { ChipColorKey, ChipColorScheme } from "@firecms/ui";
8
8
  /**
9
9
  * @group Entity properties
10
10
  */
11
- export type DataType<T extends CMSType = CMSType> = T extends string ? "string" : T extends number ? "number" : T extends boolean ? "boolean" : T extends Date ? "date" : T extends GeoPoint ? "geopoint" : T extends EntityReference ? "reference" : T extends Array<CMSType> ? "array" : T extends Record<string, any> ? "map" : never;
11
+ export type DataType<T extends CMSType = CMSType> = T extends string ? "string" : T extends number ? "number" : T extends boolean ? "boolean" : T extends Date ? "date" : T extends GeoPoint ? "geopoint" : T extends Vector ? "vector" : T extends EntityReference ? "reference" : T extends Array<CMSType> ? "array" : T extends Record<string, any> ? "map" : never;
12
12
  /**
13
13
  * @group Entity properties
14
14
  */
@@ -23,6 +23,6 @@ export declare function updateDateAutoValues<M extends Record<string, any>>({ in
23
23
  * @group Datasource
24
24
  */
25
25
  export declare function sanitizeData<M extends Record<string, any>>(values: EntityValues<M>, properties: ResolvedProperties<M>): any;
26
- export declare function getReferenceFrom<M extends Record<string, any>>(entity: Entity<M>): EntityReference<M>;
26
+ export declare function getReferenceFrom<M extends Record<string, any>>(entity: Entity<M>): EntityReference;
27
27
  export declare function traverseValuesProperties<M extends Record<string, any>>(inputValues: Partial<EntityValues<M>>, properties: ResolvedProperties<M>, operation: (value: any, property: Property) => any): EntityValues<M> | undefined;
28
28
  export declare function traverseValueProperty(inputValue: any, property: Property, operation: (value: any, property: Property) => any): any;
@@ -8,10 +8,10 @@ export declare function resolveCollectionPathIds(path: string, allCollections: E
8
8
  /**
9
9
  * Find the corresponding view at any depth for a given path.
10
10
  * Note that path or segments of the paths can be collection aliases.
11
- * @param pathOrAlias
11
+ * @param pathOrId
12
12
  * @param collections
13
13
  */
14
- export declare function getCollectionByPathOrId(pathOrAlias: string, collections: EntityCollection[]): EntityCollection | undefined;
14
+ export declare function getCollectionByPathOrId(pathOrId: string, collections: EntityCollection[]): EntityCollection | undefined;
15
15
  /**
16
16
  * Get the subcollection combinations from a path:
17
17
  * "sites/es/locales" => ["sites/es/locales", "sites"]
@@ -2,11 +2,11 @@ import { ArrayProperty, CMSType, EntityCollection, EntityCustomView, EntityValue
2
2
  export declare const resolveCollection: <M extends Record<string, any>>({ collection, path, entityId, values, previousValues, userConfigPersistence, fields }: {
3
3
  collection: EntityCollection<M> | ResolvedEntityCollection<M>;
4
4
  path: string;
5
- entityId?: string | undefined;
6
- values?: Partial<M> | undefined;
7
- previousValues?: Partial<M> | undefined;
8
- userConfigPersistence?: UserConfigurationPersistence | undefined;
9
- fields?: Record<string, PropertyConfig> | undefined;
5
+ entityId?: string;
6
+ values?: Partial<EntityValues<M>>;
7
+ previousValues?: Partial<EntityValues<M>>;
8
+ userConfigPersistence?: UserConfigurationPersistence;
9
+ fields?: Record<string, PropertyConfig>;
10
10
  }) => ResolvedEntityCollection<M>;
11
11
  /**
12
12
  * Resolve property builders, enums and arrays.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@firecms/core",
3
3
  "type": "module",
4
- "version": "3.0.0-beta.5",
4
+ "version": "3.0.0-beta.6",
5
5
  "description": "Awesome Firebase/Firestore-based headless open-source CMS",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/firecmsco"
@@ -46,17 +46,20 @@
46
46
  "./package.json": "./package.json"
47
47
  },
48
48
  "dependencies": {
49
- "@firecms/formex": "^3.0.0-beta.5",
50
- "@firecms/ui": "^3.0.0-beta.5",
51
- "@fontsource/ibm-plex-mono": "^5.0.12",
52
- "@fontsource/roboto": "^5.0.12",
53
- "@hello-pangea/dnd": "^16.5.0",
49
+ "@firecms/formex": "^3.0.0-beta.6",
50
+ "@firecms/ui": "^3.0.0-beta.6",
51
+ "@fontsource/jetbrains-mono": "^5.0.19",
52
+ "@hello-pangea/dnd": "^16.6.0",
53
+ "@radix-ui/react-portal": "^1.0.4",
54
+ "clsx": "^2.1.0",
54
55
  "date-fns": "^3.6.0",
55
56
  "history": "^5.3.0",
56
57
  "js-search": "^2.0.1",
57
58
  "markdown-it": "^14.1.0",
58
59
  "notistack": "^3.0.1",
59
60
  "object-hash": "^3.0.0",
61
+ "react-dropzone": "^14.2.3",
62
+ "react-fast-compare": "^3.2.2",
60
63
  "react-image-file-resizer": "^0.4.8",
61
64
  "react-markdown-editor-lite": "^1.3.4",
62
65
  "react-transition-group": "^4.4.5",
@@ -81,16 +84,16 @@
81
84
  "devDependencies": {
82
85
  "@jest/globals": "^29.7.0",
83
86
  "@testing-library/jest-dom": "^6.4.2",
84
- "@testing-library/react": "^14.2.1",
87
+ "@testing-library/react": "^14.3.1",
85
88
  "@testing-library/user-event": "^14.5.2",
86
89
  "@types/jest": "^29.5.12",
87
- "@types/node": "^20.11.30",
90
+ "@types/node": "^20.12.7",
88
91
  "@types/object-hash": "^3.0.6",
89
- "@types/react": "^18.2.67",
90
- "@types/react-dom": "^18.2.22",
92
+ "@types/react": "^18.2.79",
93
+ "@types/react-dom": "^18.2.25",
91
94
  "@types/react-measure": "^2.0.12",
92
- "@typescript-eslint/eslint-plugin": "^7.3.1",
93
- "@typescript-eslint/parser": "^7.3.1",
95
+ "@typescript-eslint/eslint-plugin": "^7.7.0",
96
+ "@typescript-eslint/parser": "^7.7.0",
94
97
  "@vitejs/plugin-react": "^4.2.1",
95
98
  "cross-env": "^7.0.3",
96
99
  "eslint": "^8.57.0",
@@ -100,22 +103,22 @@
100
103
  "eslint-plugin-promise": "^6.1.1",
101
104
  "eslint-plugin-react": "^7.34.1",
102
105
  "eslint-plugin-react-hooks": "^4.6.0",
103
- "firebase": "^10.9.0",
106
+ "firebase": "^10.11.0",
104
107
  "jest": "^29.7.0",
105
108
  "npm-run-all": "^4.1.5",
106
- "react-router": "^6.22.0",
107
- "react-router-dom": "^6.22.0",
109
+ "react-router": "^6.22.3",
110
+ "react-router-dom": "^6.22.3",
108
111
  "ts-jest": "^29.1.2",
109
112
  "ts-node": "^10.9.2",
110
- "tsd": "^0.30.7",
111
- "typescript": "^5.4.2",
112
- "vite": "^5.2.3"
113
+ "tsd": "^0.31.0",
114
+ "typescript": "^5.4.5",
115
+ "vite": "^5.2.9"
113
116
  },
114
117
  "files": [
115
118
  "dist",
116
119
  "src"
117
120
  ],
118
- "gitHead": "8bf864185c9617aa3f120e59c873c8b8bda8dac4",
121
+ "gitHead": "ffcbddbd73211bb644ff7503c2c62790bff6202a",
119
122
  "publishConfig": {
120
123
  "access": "public"
121
124
  }
@@ -0,0 +1,41 @@
1
+ import { Button, FilterListOffIcon } from "@firecms/ui";
2
+ import { EntityTableController } from "../types";
3
+
4
+ export function ClearFilterSortButton({
5
+ tableController,
6
+ enabled
7
+ }: {
8
+ enabled: boolean;
9
+ tableController: EntityTableController
10
+ }) {
11
+ if (!enabled) {
12
+ return null;
13
+ }
14
+
15
+ const filterIsSet = !!tableController.filterValues && Object.keys(tableController.filterValues).length > 0;
16
+ const sortIsSet = !!tableController.sortBy && tableController.sortBy.length > 0;
17
+
18
+ if ((filterIsSet || sortIsSet) && (tableController.clearFilter || tableController.setSortBy)) {
19
+ let label;
20
+ if (filterIsSet && sortIsSet) {
21
+ label = "Clear filter and sort";
22
+ } else if (filterIsSet) {
23
+ label = "Clear filter";
24
+ } else {
25
+ label = "Clear sort";
26
+ }
27
+ return <Button
28
+ variant={"outlined"}
29
+ className="h-fit-content"
30
+ aria-label="filter clear"
31
+ onClick={() => {
32
+ tableController.clearFilter?.();
33
+ tableController.setSortBy?.(undefined);
34
+ }}
35
+ size={"small"}>
36
+ <FilterListOffIcon/>
37
+ {label}
38
+ </Button>
39
+ }
40
+ return null;
41
+ }
@@ -16,7 +16,6 @@ import { propertiesToColumns } from "./column_utils";
16
16
  import { ErrorView } from "../ErrorView";
17
17
  import { SelectableTable } from "../SelectableTable/SelectableTable";
18
18
 
19
-
20
19
  /**
21
20
  * This component is in charge of rendering a collection table with a high
22
21
  * degree of customization.
@@ -88,8 +87,6 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
88
87
 
89
88
  const selectedEntityIds = selectedEntities?.map(e => e.id);
90
89
 
91
- const filterIsSet = !!tableController.filterValues && Object.keys(tableController.filterValues).length > 0;
92
-
93
90
  const updateSize = useCallback((size: CollectionSize) => {
94
91
  if (onSizeChanged)
95
92
  onSizeChanged(size);
@@ -179,7 +176,10 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
179
176
 
180
177
  const child = Builder
181
178
  ? <Builder entity={entity} context={context}/>
182
- : <>{additionalField.value?.({ entity, context })}</>;
179
+ : <>{additionalField.value?.({
180
+ entity,
181
+ context
182
+ })}</>;
183
183
 
184
184
  return (
185
185
  <EntityTableCell
@@ -237,10 +237,12 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
237
237
 
238
238
  const columns: VirtualTableColumn[] = [
239
239
  idColumn,
240
- ...displayedColumnIds
241
- .map((p) => {
242
- return collectionColumns.find(c => c.key === p.key);
243
- }).filter(Boolean) as VirtualTableColumn[]
240
+ ...(displayedColumnIds
241
+ ? displayedColumnIds
242
+ .map((p) => {
243
+ return collectionColumns.find(c => c.key === p.key);
244
+ }).filter(Boolean)
245
+ : collectionColumns) as VirtualTableColumn[]
244
246
  ];
245
247
 
246
248
  const cellRenderer = (props: CellRendererParams<any>) => {
@@ -291,12 +293,9 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
291
293
  className="h-full w-full flex flex-col bg-white dark:bg-gray-950">
292
294
 
293
295
  <CollectionTableToolbar
294
- forceFilter={disabledFilterChange}
295
- filterIsSet={filterIsSet}
296
296
  onTextSearch={textSearchEnabled ? onTextSearch : undefined}
297
297
  textSearchLoading={textSearchLoading}
298
298
  onTextSearchClick={textSearchEnabled ? onTextSearchClick : undefined}
299
- clearFilter={tableController.clearFilter}
300
299
  size={size}
301
300
  onSizeChanged={updateSize}
302
301
  title={title}
@@ -92,7 +92,7 @@ export type EntityCollectionTableProps<M extends Record<string, any>,
92
92
  */
93
93
  tableController: EntityTableController<M>;
94
94
 
95
- displayedColumnIds: PropertyColumnConfig[];
95
+ displayedColumnIds?: PropertyColumnConfig[];
96
96
 
97
97
  forceFilter?: FilterValues<Extract<keyof M, string>>;
98
98
 
@@ -95,6 +95,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
95
95
  const internalValueRef = useRef(value);
96
96
 
97
97
  const [error, setError] = useState<Error | undefined>();
98
+ const [validationError, setValidationError] = useState<Error | undefined>();
98
99
  const [saved, setSaved] = useState<boolean>(false);
99
100
 
100
101
  const onValueUpdated = useCallback(() => {
@@ -120,7 +121,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
120
121
  useEffect(
121
122
  () => {
122
123
  if (!equal(value, internalValueRef.current)) {
123
- setError(undefined);
124
+ setValidationError(undefined);
124
125
  setInternalValue(value);
125
126
  internalValueRef.current = value;
126
127
  onValueUpdated();
@@ -136,7 +137,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
136
137
  validation
137
138
  .validate(value)
138
139
  .then(() => {
139
- setError(undefined);
140
+ setValidationError(undefined);
140
141
  internalValueRef.current = value;
141
142
  if (onValueChange) {
142
143
  onValueChange({
@@ -151,17 +152,15 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
151
152
  }
152
153
  })
153
154
  .catch((e) => {
154
- setError(e);
155
+ setValidationError(e);
155
156
  });
156
157
  };
157
158
 
158
159
  useEffect(() => {
159
160
  validation
160
161
  .validate(internalValue)
161
- .then(() => setError(undefined))
162
- .catch((e) => {
163
- setError(e);
164
- });
162
+ .then(() => setValidationError(undefined))
163
+ .catch(setValidationError);
165
164
  }, [internalValue, validation, propertyKey, property, entity]);
166
165
 
167
166
  const updateValue = (newValue: any | null) => {
@@ -237,7 +236,6 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
237
236
  height={getRowHeight(size)}
238
237
  propertyKey={propertyKey}
239
238
  property={property}
240
- // entity={entity}
241
239
  value={internalValue}
242
240
  size={getPreviewSizeFrom(size)}
243
241
  />
@@ -247,7 +245,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
247
245
  if (!customField && (!customPreview || selected)) {
248
246
  const isAStorageProperty = isStorageProperty(property);
249
247
  if (isAStorageProperty) {
250
- innerComponent = <TableStorageUpload error={error}
248
+ innerComponent = <TableStorageUpload error={validationError ?? error}
251
249
  disabled={disabled}
252
250
  focused={selected}
253
251
  selected={selected}
@@ -274,7 +272,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
274
272
  valueType={"number"}
275
273
  small={getPreviewSizeFrom(size) !== "medium"}
276
274
  enumValues={numberProperty.enumValues}
277
- error={error}
275
+ error={validationError ?? error}
278
276
  internalValue={internalValue as string | number}
279
277
  updateValue={updateValue}
280
278
  />;
@@ -282,7 +280,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
282
280
  } else {
283
281
  innerComponent = <VirtualTableNumberInput
284
282
  align={align}
285
- error={error}
283
+ error={validationError ?? error}
286
284
  focused={selected}
287
285
  disabled={disabled}
288
286
  value={internalValue as number}
@@ -300,14 +298,14 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
300
298
  valueType={"string"}
301
299
  small={getPreviewSizeFrom(size) !== "medium"}
302
300
  enumValues={stringProperty.enumValues}
303
- error={error}
301
+ error={validationError ?? error}
304
302
  internalValue={internalValue as string | number}
305
303
  updateValue={updateValue}
306
304
  />;
307
305
  fullHeight = true;
308
306
  } else if (!stringProperty.storage) {
309
307
  const multiline = Boolean(stringProperty.multiline) || Boolean(stringProperty.markdown);
310
- innerComponent = <VirtualTableInput error={error}
308
+ innerComponent = <VirtualTableInput error={validationError ?? error}
311
309
  disabled={disabled}
312
310
  multiline={multiline}
313
311
  focused={selected}
@@ -317,7 +315,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
317
315
  allowScroll = true;
318
316
  }
319
317
  } else if (property.dataType === "boolean") {
320
- innerComponent = <VirtualTableSwitch error={error}
318
+ innerComponent = <VirtualTableSwitch error={validationError ?? error}
321
319
  disabled={disabled}
322
320
  focused={selected}
323
321
  internalValue={internalValue as boolean}
@@ -325,7 +323,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
325
323
  />;
326
324
  } else if (property.dataType === "date") {
327
325
  innerComponent = <VirtualTableDateField name={propertyKey as string}
328
- error={error}
326
+ error={validationError ?? error}
329
327
  disabled={disabled}
330
328
  mode={property.mode}
331
329
  focused={selected}
@@ -368,7 +366,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
368
366
  small={getPreviewSizeFrom(size) !== "medium"}
369
367
  valueType={arrayProperty.of.dataType}
370
368
  enumValues={arrayProperty.of.enumValues}
371
- error={error}
369
+ error={validationError ?? error}
372
370
  internalValue={internalValue as string | number}
373
371
  updateValue={updateValue}
374
372
  />;
@@ -403,9 +401,8 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
403
401
  allowScroll = false;
404
402
  showExpandIcon = selected && !innerComponent && !disabled && !readOnlyProperty;
405
403
  innerComponent = (
406
- <PropertyPreview width={width}
404
+ <PropertyPreview width={width}
407
405
  height={height}
408
- // entity={entity}
409
406
  propertyKey={propertyKey as string}
410
407
  value={internalValue}
411
408
  property={property}
@@ -426,7 +423,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
426
423
  removePadding={removePadding}
427
424
  fullHeight={fullHeight}
428
425
  saved={saved}
429
- error={error}
426
+ error={validationError ?? error}
430
427
  align={align}
431
428
  allowScroll={allowScroll}
432
429
  showExpandIcon={showExpandIcon}
@@ -16,20 +16,27 @@ import { useLargeLayout } from "../../../hooks";
16
16
 
17
17
  interface CollectionTableToolbarProps {
18
18
  size: CollectionSize;
19
- filterIsSet: boolean;
20
19
  loading: boolean;
21
- forceFilter?: boolean;
22
20
  actionsStart?: React.ReactNode;
23
21
  actions?: React.ReactNode;
24
22
  title?: React.ReactNode,
25
23
  onTextSearchClick?: () => void;
26
24
  onTextSearch?: (searchString?: string) => void;
27
25
  onSizeChanged: (size: CollectionSize) => void;
28
- clearFilter?: () => void;
29
26
  textSearchLoading?: boolean;
30
27
  }
31
28
 
32
- export function CollectionTableToolbar(props: CollectionTableToolbarProps) {
29
+ export function CollectionTableToolbar({
30
+ actions,
31
+ actionsStart,
32
+ loading,
33
+ onSizeChanged,
34
+ onTextSearch,
35
+ onTextSearchClick,
36
+ size,
37
+ textSearchLoading,
38
+ title
39
+ }: CollectionTableToolbarProps) {
33
40
 
34
41
  const searchInputRef = React.useRef<HTMLInputElement>(null);
35
42
  const largeLayout = useLargeLayout();
@@ -37,30 +44,20 @@ export function CollectionTableToolbar(props: CollectionTableToolbarProps) {
37
44
  const searchLoading = React.useRef<boolean>(false);
38
45
 
39
46
  useEffect(() => {
40
- if (searchInputRef.current && searchLoading.current && !props.textSearchLoading) {
47
+ if (searchInputRef.current && searchLoading.current && !textSearchLoading) {
41
48
  searchInputRef.current.focus();
42
49
  }
43
- searchLoading.current = props.textSearchLoading ?? false;
44
- }, [props.textSearchLoading]);
45
-
46
- const clearFilterButton = !props.forceFilter && props.filterIsSet && props.clearFilter &&
47
- <Button
48
- variant={"outlined"}
49
- className="h-fit-content"
50
- aria-label="filter clear"
51
- onClick={props.clearFilter}
52
- size={"small"}>
53
- <FilterListOffIcon/>
54
- Clear filter
55
- </Button>;
50
+ searchLoading.current = textSearchLoading ?? false;
51
+ }, [textSearchLoading]);
52
+
56
53
 
57
54
  const sizeSelect = (
58
55
  <Tooltip title={"Table row size"} side={"right"} sideOffset={4}>
59
56
  <Select
60
- value={props.size as string}
57
+ value={size as string}
61
58
  className="w-16 h-10"
62
59
  size={"small"}
63
- onValueChange={(v) => props.onSizeChanged(v as CollectionSize)}
60
+ onValueChange={(v) => onSizeChanged(v as CollectionSize)}
64
61
  renderValue={(v) => <div className={"font-medium"}>{v.toUpperCase()}</div>}
65
62
  >
66
63
  {["xs", "s", "m", "l", "xl"].map((size) => (
@@ -78,36 +75,34 @@ export function CollectionTableToolbar(props: CollectionTableToolbarProps) {
78
75
 
79
76
  <div className="flex items-center gap-2 md:mr-4 mr-2">
80
77
 
81
- {props.title && <div className={"hidden lg:block"}>
82
- {props.title}
78
+ {title && <div className={"hidden lg:block"}>
79
+ {title}
83
80
  </div>}
84
81
 
85
82
  {sizeSelect}
86
83
 
87
- {props.actionsStart}
88
-
89
- {clearFilterButton}
84
+ {actionsStart}
90
85
 
91
86
  </div>
92
87
 
93
88
  <div className="flex items-center gap-2">
94
89
 
95
90
  {largeLayout && <div className="w-[22px]">
96
- {props.loading &&
91
+ {loading &&
97
92
  <CircularProgress size={"small"}/>}
98
93
  </div>}
99
94
 
100
- {(props.onTextSearch || props.onTextSearchClick) &&
95
+ {(onTextSearch || onTextSearchClick) &&
101
96
  <SearchBar
102
97
  key={"search-bar"}
103
98
  inputRef={searchInputRef}
104
- loading={props.textSearchLoading}
105
- disabled={Boolean(props.onTextSearchClick)}
106
- onClick={props.onTextSearchClick}
107
- onTextSearch={props.onTextSearchClick ? undefined : props.onTextSearch}
99
+ loading={textSearchLoading}
100
+ disabled={Boolean(onTextSearchClick)}
101
+ onClick={onTextSearchClick}
102
+ onTextSearch={onTextSearchClick ? undefined : onTextSearch}
108
103
  expandable={true}/>}
109
104
 
110
- {props.actions}
105
+ {actions}
111
106
 
112
107
  </div>
113
108