@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.
- package/dist/components/ClearFilterSortButton.d.ts +5 -0
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -11
- package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +1 -1
- package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +11 -1
- package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
- package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
- package/dist/components/common/types.d.ts +1 -1
- package/dist/form/components/ErrorFocus.d.ts +1 -1
- package/dist/hooks/useValidateAuthenticator.d.ts +2 -6
- package/dist/index.es.js +3516 -3381
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +5 -5
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useBuildDataSource.d.ts +1 -16
- package/dist/types/collections.d.ts +5 -1
- package/dist/types/datasource.d.ts +2 -5
- package/dist/types/entities.d.ts +5 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/navigation.d.ts +1 -1
- package/dist/types/plugins.d.ts +3 -1
- package/dist/types/properties.d.ts +2 -2
- package/dist/util/entities.d.ts +1 -1
- package/dist/util/navigation_utils.d.ts +2 -2
- package/dist/util/resolutions.d.ts +5 -5
- package/package.json +22 -19
- package/src/components/ClearFilterSortButton.tsx +41 -0
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +10 -11
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +1 -1
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +16 -19
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +27 -32
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +11 -6
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +28 -5
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
- package/src/components/EntityView.tsx +1 -1
- package/src/components/HomePage/DefaultHomePage.tsx +1 -1
- package/src/components/SelectableTable/SelectableTable.tsx +1 -1
- package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
- package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +22 -7
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +24 -5
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
- package/src/components/VirtualTable/VirtualTable.tsx +28 -20
- package/src/components/common/types.tsx +1 -1
- package/src/core/FireCMS.tsx +1 -2
- package/src/core/field_configs.tsx +1 -2
- package/src/hooks/data/save.ts +1 -0
- package/src/hooks/useBuildLocalConfigurationPersistence.tsx +9 -10
- package/src/hooks/useBuildModeController.tsx +11 -5
- package/src/hooks/useBuildNavigationController.tsx +76 -19
- package/src/hooks/useProjectLog.tsx +3 -3
- package/src/hooks/useValidateAuthenticator.tsx +2 -22
- package/src/internal/useBuildDataSource.ts +42 -47
- package/src/internal/useBuildSideEntityController.tsx +16 -13
- package/src/preview/PropertyPreview.tsx +2 -12
- package/src/types/collections.ts +5 -1
- package/src/types/datasource.ts +7 -4
- package/src/types/entities.ts +9 -1
- package/src/types/index.ts +0 -1
- package/src/types/navigation.ts +1 -1
- package/src/types/plugins.tsx +4 -3
- package/src/types/properties.ts +5 -4
- package/src/util/entities.ts +1 -1
- package/src/util/navigation_utils.ts +6 -6
- package/dist/internal/useLocaleConfig.d.ts +0 -1
- package/dist/types/appcheck.d.ts +0 -26
- package/src/internal/useLocaleConfig.tsx +0 -18
- package/src/types/appcheck.ts +0 -29
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DataSource, DataSourceDelegate,
|
|
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
|
|
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,
|
|
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
|
}
|
package/dist/types/entities.d.ts
CHANGED
|
@@ -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
|
|
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
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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: (
|
|
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
|
*/
|
package/dist/types/plugins.d.ts
CHANGED
|
@@ -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
|
*/
|
package/dist/util/entities.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
11
|
+
* @param pathOrId
|
|
12
12
|
* @param collections
|
|
13
13
|
*/
|
|
14
|
-
export declare function getCollectionByPathOrId(
|
|
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
|
|
6
|
-
values?: Partial<M
|
|
7
|
-
previousValues?: Partial<M
|
|
8
|
-
userConfigPersistence?: UserConfigurationPersistence
|
|
9
|
-
fields?: Record<string, PropertyConfig
|
|
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.
|
|
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.
|
|
50
|
-
"@firecms/ui": "^3.0.0-beta.
|
|
51
|
-
"@fontsource/
|
|
52
|
-
"@
|
|
53
|
-
"@
|
|
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.
|
|
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.
|
|
90
|
+
"@types/node": "^20.12.7",
|
|
88
91
|
"@types/object-hash": "^3.0.6",
|
|
89
|
-
"@types/react": "^18.2.
|
|
90
|
-
"@types/react-dom": "^18.2.
|
|
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.
|
|
93
|
-
"@typescript-eslint/parser": "^7.
|
|
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.
|
|
106
|
+
"firebase": "^10.11.0",
|
|
104
107
|
"jest": "^29.7.0",
|
|
105
108
|
"npm-run-all": "^4.1.5",
|
|
106
|
-
"react-router": "^6.22.
|
|
107
|
-
"react-router-dom": "^6.22.
|
|
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.
|
|
111
|
-
"typescript": "^5.4.
|
|
112
|
-
"vite": "^5.2.
|
|
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": "
|
|
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?.({
|
|
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
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
155
|
+
setValidationError(e);
|
|
155
156
|
});
|
|
156
157
|
};
|
|
157
158
|
|
|
158
159
|
useEffect(() => {
|
|
159
160
|
validation
|
|
160
161
|
.validate(internalValue)
|
|
161
|
-
.then(() =>
|
|
162
|
-
.catch(
|
|
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
|
|
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(
|
|
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 && !
|
|
47
|
+
if (searchInputRef.current && searchLoading.current && !textSearchLoading) {
|
|
41
48
|
searchInputRef.current.focus();
|
|
42
49
|
}
|
|
43
|
-
searchLoading.current =
|
|
44
|
-
}, [
|
|
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={
|
|
57
|
+
value={size as string}
|
|
61
58
|
className="w-16 h-10"
|
|
62
59
|
size={"small"}
|
|
63
|
-
onValueChange={(v) =>
|
|
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
|
-
{
|
|
82
|
-
{
|
|
78
|
+
{title && <div className={"hidden lg:block"}>
|
|
79
|
+
{title}
|
|
83
80
|
</div>}
|
|
84
81
|
|
|
85
82
|
{sizeSelect}
|
|
86
83
|
|
|
87
|
-
{
|
|
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
|
-
{
|
|
91
|
+
{loading &&
|
|
97
92
|
<CircularProgress size={"small"}/>}
|
|
98
93
|
</div>}
|
|
99
94
|
|
|
100
|
-
{(
|
|
95
|
+
{(onTextSearch || onTextSearchClick) &&
|
|
101
96
|
<SearchBar
|
|
102
97
|
key={"search-bar"}
|
|
103
98
|
inputRef={searchInputRef}
|
|
104
|
-
loading={
|
|
105
|
-
disabled={Boolean(
|
|
106
|
-
onClick={
|
|
107
|
-
onTextSearch={
|
|
99
|
+
loading={textSearchLoading}
|
|
100
|
+
disabled={Boolean(onTextSearchClick)}
|
|
101
|
+
onClick={onTextSearchClick}
|
|
102
|
+
onTextSearch={onTextSearchClick ? undefined : onTextSearch}
|
|
108
103
|
expandable={true}/>}
|
|
109
104
|
|
|
110
|
-
{
|
|
105
|
+
{actions}
|
|
111
106
|
|
|
112
107
|
</div>
|
|
113
108
|
|