@firecms/collection_editor 3.0.0-3.0.0-beta.4.pre.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/dist/ConfigControllerProvider.d.ts +37 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.es.js +5454 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +4 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/types/collection_editor_controller.d.ts +36 -0
- package/dist/types/collection_inference.d.ts +2 -0
- package/dist/types/config_controller.d.ts +51 -0
- package/dist/types/config_permissions.d.ts +19 -0
- package/dist/types/persisted_collection.d.ts +6 -0
- package/dist/ui/CollectionViewHeaderAction.d.ts +10 -0
- package/dist/ui/EditorCollectionAction.d.ts +2 -0
- package/dist/ui/HomePageEditorCollectionAction.d.ts +2 -0
- package/dist/ui/MissingReferenceWidget.d.ts +3 -0
- package/dist/ui/NewCollectionButton.d.ts +1 -0
- package/dist/ui/NewCollectionCard.d.ts +2 -0
- package/dist/ui/PropertyAddColumnComponent.d.ts +6 -0
- package/dist/ui/RootCollectionSuggestions.d.ts +3 -0
- package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +10 -0
- package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +36 -0
- package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +15 -0
- package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +19 -0
- package/dist/ui/collection_editor/CollectionYupValidation.d.ts +14 -0
- package/dist/ui/collection_editor/EntityCustomViewsSelectDialog.d.ts +4 -0
- package/dist/ui/collection_editor/EnumForm.d.ts +12 -0
- package/dist/ui/collection_editor/GetCodeDialog.d.ts +5 -0
- package/dist/ui/collection_editor/PropertyEditView.d.ts +40 -0
- package/dist/ui/collection_editor/PropertyFieldPreview.d.ts +15 -0
- package/dist/ui/collection_editor/PropertySelectItem.d.ts +8 -0
- package/dist/ui/collection_editor/PropertyTree.d.ts +33 -0
- package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +12 -0
- package/dist/ui/collection_editor/SwitchControl.d.ts +8 -0
- package/dist/ui/collection_editor/UnsavedChangesDialog.d.ts +9 -0
- package/dist/ui/collection_editor/import/CollectionEditorImportDataPreview.d.ts +7 -0
- package/dist/ui/collection_editor/import/CollectionEditorImportMapping.d.ts +7 -0
- package/dist/ui/collection_editor/import/clean_import_data.d.ts +7 -0
- package/dist/ui/collection_editor/properties/BlockPropertyField.d.ts +8 -0
- package/dist/ui/collection_editor/properties/BooleanPropertyField.d.ts +3 -0
- package/dist/ui/collection_editor/properties/CommonPropertyFields.d.ts +10 -0
- package/dist/ui/collection_editor/properties/DateTimePropertyField.d.ts +3 -0
- package/dist/ui/collection_editor/properties/EnumPropertyField.d.ts +8 -0
- package/dist/ui/collection_editor/properties/KeyValuePropertyField.d.ts +3 -0
- package/dist/ui/collection_editor/properties/MapPropertyField.d.ts +8 -0
- package/dist/ui/collection_editor/properties/NumberPropertyField.d.ts +3 -0
- package/dist/ui/collection_editor/properties/ReferencePropertyField.d.ts +13 -0
- package/dist/ui/collection_editor/properties/RepeatPropertyField.d.ts +10 -0
- package/dist/ui/collection_editor/properties/StoragePropertyField.d.ts +5 -0
- package/dist/ui/collection_editor/properties/StringPropertyField.d.ts +5 -0
- package/dist/ui/collection_editor/properties/UrlPropertyField.d.ts +4 -0
- package/dist/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.d.ts +3 -0
- package/dist/ui/collection_editor/properties/validation/ArrayPropertyValidation.d.ts +5 -0
- package/dist/ui/collection_editor/properties/validation/GeneralPropertyValidation.d.ts +4 -0
- package/dist/ui/collection_editor/properties/validation/NumberPropertyValidation.d.ts +3 -0
- package/dist/ui/collection_editor/properties/validation/StringPropertyValidation.d.ts +11 -0
- package/dist/ui/collection_editor/properties/validation/ValidationPanel.d.ts +2 -0
- package/dist/ui/collection_editor/templates/blog_template.d.ts +2 -0
- package/dist/ui/collection_editor/templates/pages_template.d.ts +2 -0
- package/dist/ui/collection_editor/templates/products_template.d.ts +2 -0
- package/dist/ui/collection_editor/templates/users_template.d.ts +2 -0
- package/dist/ui/collection_editor/util.d.ts +5 -0
- package/dist/ui/collection_editor/utils/strings.d.ts +1 -0
- package/dist/ui/collection_editor/utils/supported_fields.d.ts +3 -0
- package/dist/ui/collection_editor/utils/update_property_for_widget.d.ts +2 -0
- package/dist/ui/collection_editor/utils/useTraceUpdate.d.ts +1 -0
- package/dist/useCollectionEditorController.d.ts +6 -0
- package/dist/useCollectionEditorPlugin.d.ts +49 -0
- package/dist/useCollectionsConfigController.d.ts +6 -0
- package/dist/utils/arrays.d.ts +1 -0
- package/dist/utils/entities.d.ts +3 -0
- package/package.json +85 -0
- package/src/ConfigControllerProvider.tsx +338 -0
- package/src/index.ts +35 -0
- package/src/types/collection_editor_controller.tsx +43 -0
- package/src/types/collection_inference.ts +3 -0
- package/src/types/config_controller.tsx +60 -0
- package/src/types/config_permissions.ts +20 -0
- package/src/types/persisted_collection.ts +9 -0
- package/src/ui/CollectionViewHeaderAction.tsx +43 -0
- package/src/ui/EditorCollectionAction.tsx +109 -0
- package/src/ui/HomePageEditorCollectionAction.tsx +84 -0
- package/src/ui/MissingReferenceWidget.tsx +37 -0
- package/src/ui/NewCollectionButton.tsx +16 -0
- package/src/ui/NewCollectionCard.tsx +48 -0
- package/src/ui/PropertyAddColumnComponent.tsx +42 -0
- package/src/ui/RootCollectionSuggestions.tsx +63 -0
- package/src/ui/collection_editor/CollectionDetailsForm.tsx +365 -0
- package/src/ui/collection_editor/CollectionEditorDialog.tsx +801 -0
- package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +213 -0
- package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +506 -0
- package/src/ui/collection_editor/CollectionYupValidation.tsx +7 -0
- package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +37 -0
- package/src/ui/collection_editor/EnumForm.tsx +357 -0
- package/src/ui/collection_editor/GetCodeDialog.tsx +110 -0
- package/src/ui/collection_editor/PropertyEditView.tsx +615 -0
- package/src/ui/collection_editor/PropertyFieldPreview.tsx +207 -0
- package/src/ui/collection_editor/PropertySelectItem.tsx +32 -0
- package/src/ui/collection_editor/PropertyTree.tsx +252 -0
- package/src/ui/collection_editor/SubcollectionsEditTab.tsx +262 -0
- package/src/ui/collection_editor/SwitchControl.tsx +39 -0
- package/src/ui/collection_editor/UnsavedChangesDialog.tsx +47 -0
- package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +37 -0
- package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +268 -0
- package/src/ui/collection_editor/import/clean_import_data.ts +53 -0
- package/src/ui/collection_editor/properties/BlockPropertyField.tsx +138 -0
- package/src/ui/collection_editor/properties/BooleanPropertyField.tsx +40 -0
- package/src/ui/collection_editor/properties/CommonPropertyFields.tsx +110 -0
- package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +86 -0
- package/src/ui/collection_editor/properties/EnumPropertyField.tsx +114 -0
- package/src/ui/collection_editor/properties/KeyValuePropertyField.tsx +20 -0
- package/src/ui/collection_editor/properties/MapPropertyField.tsx +150 -0
- package/src/ui/collection_editor/properties/NumberPropertyField.tsx +38 -0
- package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +160 -0
- package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +109 -0
- package/src/ui/collection_editor/properties/StoragePropertyField.tsx +200 -0
- package/src/ui/collection_editor/properties/StringPropertyField.tsx +79 -0
- package/src/ui/collection_editor/properties/UrlPropertyField.tsx +89 -0
- package/src/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +45 -0
- package/src/ui/collection_editor/properties/validation/ArrayPropertyValidation.tsx +50 -0
- package/src/ui/collection_editor/properties/validation/GeneralPropertyValidation.tsx +61 -0
- package/src/ui/collection_editor/properties/validation/NumberPropertyValidation.tsx +115 -0
- package/src/ui/collection_editor/properties/validation/StringPropertyValidation.tsx +150 -0
- package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +28 -0
- package/src/ui/collection_editor/templates/blog_template.ts +115 -0
- package/src/ui/collection_editor/templates/pages_template.ts +188 -0
- package/src/ui/collection_editor/templates/products_template.ts +88 -0
- package/src/ui/collection_editor/templates/users_template.ts +42 -0
- package/src/ui/collection_editor/util.ts +28 -0
- package/src/ui/collection_editor/utils/strings.ts +9 -0
- package/src/ui/collection_editor/utils/supported_fields.tsx +29 -0
- package/src/ui/collection_editor/utils/update_property_for_widget.ts +271 -0
- package/src/ui/collection_editor/utils/useTraceUpdate.tsx +23 -0
- package/src/useCollectionEditorController.tsx +9 -0
- package/src/useCollectionEditorPlugin.tsx +154 -0
- package/src/useCollectionsConfigController.tsx +9 -0
- package/src/utils/arrays.ts +3 -0
- package/src/utils/entities.ts +38 -0
- package/src/vite-env.d.ts +1 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function idToPropertiesPath(id: string): string;
|
|
2
|
+
export declare function namespaceToPropertiesPath(namespace?: string): string;
|
|
3
|
+
export declare function namespaceToPropertiesOrderPath(namespace?: string): string;
|
|
4
|
+
export declare function getFullId(propertyKey: string, propertyNamespace?: string): string;
|
|
5
|
+
export declare function getFullIdPath(propertyKey: string, propertyNamespace?: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function camelCase(str: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useTraceUpdate(props: any): void;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CollectionEditorController } from "./types/collection_editor_controller";
|
|
2
|
+
/**
|
|
3
|
+
* Hook to access the collection editor controller.
|
|
4
|
+
* The methods in this controller can be used to open the collection editor dialog.
|
|
5
|
+
*/
|
|
6
|
+
export declare const useCollectionEditorController: () => CollectionEditorController;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { FireCMSPlugin, User } from "@firecms/core";
|
|
3
|
+
import { CollectionEditorPermissionsBuilder } from "./types/config_permissions";
|
|
4
|
+
import { PersistedCollection } from "./types/persisted_collection";
|
|
5
|
+
import { CollectionInference } from "./types/collection_inference";
|
|
6
|
+
import { CollectionsConfigController } from "./types/config_controller";
|
|
7
|
+
export interface CollectionConfigControllerProps<EC extends PersistedCollection = PersistedCollection, UserType extends User = User> {
|
|
8
|
+
/**
|
|
9
|
+
* Firebase app where the configuration is saved.
|
|
10
|
+
*/
|
|
11
|
+
collectionConfigController: CollectionsConfigController;
|
|
12
|
+
/**
|
|
13
|
+
* Define what actions can be performed on the configuration.
|
|
14
|
+
*/
|
|
15
|
+
configPermissions?: CollectionEditorPermissionsBuilder<UserType, EC>;
|
|
16
|
+
/**
|
|
17
|
+
* The words you define here will not be allowed to be used as group
|
|
18
|
+
* names when creating collections.
|
|
19
|
+
* e.g. ["admin"]
|
|
20
|
+
*/
|
|
21
|
+
reservedGroups: string[];
|
|
22
|
+
extraView?: {
|
|
23
|
+
View: React.ComponentType<{
|
|
24
|
+
path: string;
|
|
25
|
+
}>;
|
|
26
|
+
icon: React.ReactNode;
|
|
27
|
+
};
|
|
28
|
+
pathSuggestions?: (path: string) => Promise<string[]>;
|
|
29
|
+
collectionInference?: CollectionInference;
|
|
30
|
+
getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
|
|
31
|
+
getUser: (uid: string) => UserType | null;
|
|
32
|
+
onAnalyticsEvent?: (event: string, params?: object) => void;
|
|
33
|
+
introMode?: "new_project" | "existing_project";
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Use this hook to initialise the Collection Editor plugin.
|
|
37
|
+
* This is likely the only hook you will need to use.
|
|
38
|
+
* @param firebaseApp Firebase app where your project data lives.
|
|
39
|
+
* @param configPermissions
|
|
40
|
+
* @param reservedGroups
|
|
41
|
+
* @param extraView
|
|
42
|
+
* @param pathSuggestions
|
|
43
|
+
* @param getUser
|
|
44
|
+
* @param collectionInference
|
|
45
|
+
*/
|
|
46
|
+
export declare function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection, UserType extends User = User>({ collectionConfigController, introMode, configPermissions, reservedGroups, extraView, pathSuggestions, getUser, collectionInference, getData, onAnalyticsEvent }: CollectionConfigControllerProps<EC, UserType>): FireCMSPlugin<any, any, PersistedCollection>;
|
|
47
|
+
export declare function IntroWidget({ introMode }: {
|
|
48
|
+
introMode?: "new_project" | "existing_project";
|
|
49
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CollectionsConfigController } from "./types/config_controller";
|
|
2
|
+
/**
|
|
3
|
+
* Use this hook to access the configuration controller.
|
|
4
|
+
* You can use it to get the list of collections, and to save/delete collections.
|
|
5
|
+
*/
|
|
6
|
+
export declare const useCollectionsConfigController: () => CollectionsConfigController;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function toArray<T>(input?: T | T[]): T[];
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Properties, PropertiesOrBuilders, PropertyOrBuilder } from "@firecms/core";
|
|
2
|
+
export declare function editableProperty(property: PropertyOrBuilder | PropertyOrBuilder): boolean;
|
|
3
|
+
export declare function removeNonEditableProperties(properties: PropertiesOrBuilders<any>): Properties;
|
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@firecms/collection_editor",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "3.0.0-3.0.0-beta.4.pre.1.0",
|
|
5
|
+
"main": "./dist/index.umd.js",
|
|
6
|
+
"module": "./dist/index.es.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"source": "src/index.ts",
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"@firecms/data_import_export": "^3.0.0-3.0.0-beta.4.pre.1.0",
|
|
11
|
+
"@firecms/formex": "^3.0.0-3.0.0-beta.4.pre.1.0",
|
|
12
|
+
"@firecms/schema_inference": "^3.0.0-3.0.0-beta.4.pre.1.0",
|
|
13
|
+
"@firecms/ui": "^3.0.0-3.0.0-beta.4.pre.1.0",
|
|
14
|
+
"json5": "^2.2.3",
|
|
15
|
+
"prism-react-renderer": "^2.3.1"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"react": "^18.2.0",
|
|
19
|
+
"react-dom": "^18.2.0",
|
|
20
|
+
"react-router": "^6.22.2",
|
|
21
|
+
"react-router-dom": "^6.22.2"
|
|
22
|
+
},
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"import": "./dist/index.es.js",
|
|
26
|
+
"require": "./dist/index.umd.js",
|
|
27
|
+
"types": "./dist/src/index.d.ts"
|
|
28
|
+
},
|
|
29
|
+
"./package.json": "./package.json"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"dev": "vite",
|
|
33
|
+
"test": "jest",
|
|
34
|
+
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json",
|
|
35
|
+
"clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f"
|
|
36
|
+
},
|
|
37
|
+
"eslintConfig": {
|
|
38
|
+
"extends": [
|
|
39
|
+
"react-app",
|
|
40
|
+
"react-app/jest"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"browserslist": {
|
|
44
|
+
"production": [
|
|
45
|
+
">0.2%",
|
|
46
|
+
"not dead",
|
|
47
|
+
"not op_mini all"
|
|
48
|
+
],
|
|
49
|
+
"development": [
|
|
50
|
+
"last 1 chrome version",
|
|
51
|
+
"last 1 firefox version",
|
|
52
|
+
"last 1 safari version"
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@jest/globals": "^29.7.0",
|
|
57
|
+
"@types/react": "^18.2.67",
|
|
58
|
+
"@types/react-dom": "^18.2.22",
|
|
59
|
+
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
|
60
|
+
"@typescript-eslint/parser": "^7.3.1",
|
|
61
|
+
"@vitejs/plugin-react": "^4.2.1",
|
|
62
|
+
"eslint": "^8.57.0",
|
|
63
|
+
"eslint-config-standard": "^17.1.0",
|
|
64
|
+
"eslint-plugin-import": "^2.29.1",
|
|
65
|
+
"eslint-plugin-n": "^16.6.2",
|
|
66
|
+
"eslint-plugin-promise": "^6.1.1",
|
|
67
|
+
"eslint-plugin-react": "^7.34.1",
|
|
68
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
69
|
+
"jest": "^29.7.0",
|
|
70
|
+
"react-router": "^6.22.3",
|
|
71
|
+
"react-router-dom": "^6.22.3",
|
|
72
|
+
"ts-jest": "^29.1.2",
|
|
73
|
+
"typescript": "^5.4.2",
|
|
74
|
+
"vite": "^5.1.6",
|
|
75
|
+
"vite-plugin-fonts": "^0.7.0"
|
|
76
|
+
},
|
|
77
|
+
"files": [
|
|
78
|
+
"dist",
|
|
79
|
+
"src"
|
|
80
|
+
],
|
|
81
|
+
"publishConfig": {
|
|
82
|
+
"access": "public"
|
|
83
|
+
},
|
|
84
|
+
"gitHead": "bfe875c02132b5763ac0c9d8c8a885c791bb5a24"
|
|
85
|
+
}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import React, { PropsWithChildren, useCallback, useEffect } from "react";
|
|
2
|
+
import equal from "react-fast-compare"
|
|
3
|
+
|
|
4
|
+
import { CollectionsConfigController } from "./types/config_controller";
|
|
5
|
+
import {
|
|
6
|
+
Property,
|
|
7
|
+
useCustomizationController,
|
|
8
|
+
useNavigationController,
|
|
9
|
+
User,
|
|
10
|
+
useSnackbarController
|
|
11
|
+
} from "@firecms/core";
|
|
12
|
+
import { CollectionEditorDialog } from "./ui/collection_editor/CollectionEditorDialog";
|
|
13
|
+
import { useNavigate } from "react-router";
|
|
14
|
+
import { CollectionEditorController } from "./types/collection_editor_controller";
|
|
15
|
+
import { CollectionEditorPermissionsBuilder } from "./types/config_permissions";
|
|
16
|
+
import { CollectionInference } from "./types/collection_inference";
|
|
17
|
+
import { PropertyFormDialog } from "./ui/collection_editor/PropertyEditView";
|
|
18
|
+
import { PersistedCollection } from "./types/persisted_collection";
|
|
19
|
+
|
|
20
|
+
export const ConfigControllerContext = React.createContext<CollectionsConfigController>({} as any);
|
|
21
|
+
export const CollectionEditorContext = React.createContext<CollectionEditorController>({} as any);
|
|
22
|
+
|
|
23
|
+
export interface ConfigControllerProviderProps {
|
|
24
|
+
/**
|
|
25
|
+
* Controller for managing the collections' config.
|
|
26
|
+
*/
|
|
27
|
+
collectionConfigController: CollectionsConfigController;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Callback used to infer the schema from the data.
|
|
31
|
+
*/
|
|
32
|
+
collectionInference?: CollectionInference;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Use this builder to define the permissions for the configuration per user.
|
|
36
|
+
*/
|
|
37
|
+
configPermissions?: CollectionEditorPermissionsBuilder;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Groups that cannot be used to create new collections.
|
|
41
|
+
*/
|
|
42
|
+
reservedGroups?: string[];
|
|
43
|
+
|
|
44
|
+
extraView?: {
|
|
45
|
+
View: React.ComponentType<{
|
|
46
|
+
path: string
|
|
47
|
+
}>,
|
|
48
|
+
icon: React.ReactNode
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
pathSuggestions?: (path?: string) => Promise<string[]>;
|
|
52
|
+
|
|
53
|
+
getUser: (uid: string) => User | null
|
|
54
|
+
|
|
55
|
+
getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
|
|
56
|
+
|
|
57
|
+
onAnalyticsEvent?: (event: string, params?: object) => void;
|
|
58
|
+
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const ConfigControllerProvider = React.memo(
|
|
62
|
+
function ConfigControllerProvider({
|
|
63
|
+
children,
|
|
64
|
+
collectionConfigController,
|
|
65
|
+
configPermissions,
|
|
66
|
+
reservedGroups,
|
|
67
|
+
collectionInference,
|
|
68
|
+
extraView,
|
|
69
|
+
pathSuggestions,
|
|
70
|
+
getUser,
|
|
71
|
+
getData,
|
|
72
|
+
onAnalyticsEvent
|
|
73
|
+
}: PropsWithChildren<ConfigControllerProviderProps>) {
|
|
74
|
+
|
|
75
|
+
const navigation = useNavigationController();
|
|
76
|
+
const navigate = useNavigate();
|
|
77
|
+
const snackbarController = useSnackbarController();
|
|
78
|
+
const { propertyConfigs } = useCustomizationController();
|
|
79
|
+
|
|
80
|
+
const {
|
|
81
|
+
collections
|
|
82
|
+
} = navigation;
|
|
83
|
+
const existingPaths = (collections ?? []).map(col => col.path.trim().toLowerCase());
|
|
84
|
+
|
|
85
|
+
const [rootPathSuggestions, setRootPathSuggestions] = React.useState<string[] | undefined>();
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (pathSuggestions) {
|
|
88
|
+
pathSuggestions().then((paths) => {
|
|
89
|
+
setRootPathSuggestions(paths.filter(p => !existingPaths.includes(p.trim().toLowerCase())));
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}, [pathSuggestions]);
|
|
93
|
+
|
|
94
|
+
const [currentDialog, setCurrentDialog] = React.useState<{
|
|
95
|
+
isNewCollection: boolean,
|
|
96
|
+
parentCollection?: PersistedCollection,
|
|
97
|
+
editedCollectionId?: string,
|
|
98
|
+
fullPath?: string,
|
|
99
|
+
parentCollectionIds: string[],
|
|
100
|
+
initialValues?: {
|
|
101
|
+
path?: string,
|
|
102
|
+
group?: string,
|
|
103
|
+
name?: string
|
|
104
|
+
},
|
|
105
|
+
redirect: boolean
|
|
106
|
+
}>();
|
|
107
|
+
|
|
108
|
+
const [currentPropertyDialog, setCurrentPropertyDialog] = React.useState<{
|
|
109
|
+
propertyKey?: string,
|
|
110
|
+
property?: Property,
|
|
111
|
+
namespace?: string,
|
|
112
|
+
parentCollection?: PersistedCollection,
|
|
113
|
+
currentPropertiesOrder?: string[],
|
|
114
|
+
editedCollectionId: string,
|
|
115
|
+
fullPath?: string,
|
|
116
|
+
parentCollectionIds: string[],
|
|
117
|
+
collectionEditable: boolean;
|
|
118
|
+
}>();
|
|
119
|
+
|
|
120
|
+
const defaultConfigPermissions: CollectionEditorPermissionsBuilder = useCallback(() => ({
|
|
121
|
+
createCollections: true,
|
|
122
|
+
editCollections: true,
|
|
123
|
+
deleteCollections: true
|
|
124
|
+
}), []);
|
|
125
|
+
|
|
126
|
+
const editCollection = useCallback(({
|
|
127
|
+
id,
|
|
128
|
+
fullPath,
|
|
129
|
+
parentCollectionIds,
|
|
130
|
+
parentCollection
|
|
131
|
+
}: {
|
|
132
|
+
id?: string,
|
|
133
|
+
fullPath?: string,
|
|
134
|
+
parentCollectionIds: string[],
|
|
135
|
+
parentCollection?: PersistedCollection
|
|
136
|
+
}) => {
|
|
137
|
+
console.debug("Edit collection", id, fullPath, parentCollectionIds, parentCollection);
|
|
138
|
+
onAnalyticsEvent?.("edit_collection", { id, fullPath });
|
|
139
|
+
setCurrentDialog({
|
|
140
|
+
editedCollectionId: id,
|
|
141
|
+
fullPath,
|
|
142
|
+
parentCollectionIds,
|
|
143
|
+
isNewCollection: false,
|
|
144
|
+
parentCollection,
|
|
145
|
+
redirect: false
|
|
146
|
+
});
|
|
147
|
+
}, []);
|
|
148
|
+
|
|
149
|
+
const editProperty = useCallback(({
|
|
150
|
+
propertyKey,
|
|
151
|
+
property,
|
|
152
|
+
editedCollectionId,
|
|
153
|
+
currentPropertiesOrder,
|
|
154
|
+
parentCollectionIds,
|
|
155
|
+
collection
|
|
156
|
+
}: {
|
|
157
|
+
propertyKey?: string,
|
|
158
|
+
property?: Property,
|
|
159
|
+
currentPropertiesOrder?: string[],
|
|
160
|
+
editedCollectionId: string,
|
|
161
|
+
parentCollectionIds: string[],
|
|
162
|
+
collection: PersistedCollection,
|
|
163
|
+
}) => {
|
|
164
|
+
console.debug("Edit property", propertyKey, property, editedCollectionId, currentPropertiesOrder, parentCollectionIds, collection);
|
|
165
|
+
onAnalyticsEvent?.("edit_property", { propertyKey, editedCollectionId });
|
|
166
|
+
// namespace is all the path until the last dot
|
|
167
|
+
const namespace = propertyKey && propertyKey.includes(".")
|
|
168
|
+
? propertyKey.substring(0, propertyKey.lastIndexOf("."))
|
|
169
|
+
: undefined;
|
|
170
|
+
const propertyKeyWithoutNamespace = propertyKey && propertyKey.includes(".")
|
|
171
|
+
? propertyKey.substring(propertyKey.lastIndexOf(".") + 1)
|
|
172
|
+
: propertyKey;
|
|
173
|
+
setCurrentPropertyDialog({
|
|
174
|
+
propertyKey: propertyKeyWithoutNamespace,
|
|
175
|
+
property,
|
|
176
|
+
namespace,
|
|
177
|
+
currentPropertiesOrder,
|
|
178
|
+
editedCollectionId: editedCollectionId,
|
|
179
|
+
parentCollectionIds,
|
|
180
|
+
collectionEditable: collection?.editable ?? false
|
|
181
|
+
});
|
|
182
|
+
}, []);
|
|
183
|
+
|
|
184
|
+
const createCollection = React.useCallback(({
|
|
185
|
+
parentCollectionIds,
|
|
186
|
+
parentCollection,
|
|
187
|
+
initialValues,
|
|
188
|
+
redirect,
|
|
189
|
+
sourceClick
|
|
190
|
+
}: {
|
|
191
|
+
parentCollectionIds: string[],
|
|
192
|
+
parentCollection?: PersistedCollection
|
|
193
|
+
initialValues?: {
|
|
194
|
+
group?: string,
|
|
195
|
+
path?: string,
|
|
196
|
+
name?: string
|
|
197
|
+
},
|
|
198
|
+
redirect: boolean,
|
|
199
|
+
sourceClick?: string
|
|
200
|
+
}) => {
|
|
201
|
+
console.debug("Create collection", { parentCollectionIds, parentCollection, initialValues, redirect, sourceClick });
|
|
202
|
+
onAnalyticsEvent?.("create_collection", { parentCollectionIds, parentCollection, initialValues, redirect, sourceClick });
|
|
203
|
+
setCurrentDialog({
|
|
204
|
+
isNewCollection: true,
|
|
205
|
+
parentCollectionIds,
|
|
206
|
+
parentCollection,
|
|
207
|
+
initialValues,
|
|
208
|
+
redirect
|
|
209
|
+
});
|
|
210
|
+
}, []);
|
|
211
|
+
|
|
212
|
+
const getPathSuggestions = !pathSuggestions
|
|
213
|
+
? undefined
|
|
214
|
+
: (path?: string) => {
|
|
215
|
+
if (!path && rootPathSuggestions)
|
|
216
|
+
return Promise.resolve(rootPathSuggestions);
|
|
217
|
+
else {
|
|
218
|
+
return pathSuggestions?.(path);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return (
|
|
223
|
+
<ConfigControllerContext.Provider value={collectionConfigController}>
|
|
224
|
+
<CollectionEditorContext.Provider
|
|
225
|
+
value={{
|
|
226
|
+
editCollection,
|
|
227
|
+
createCollection,
|
|
228
|
+
editProperty,
|
|
229
|
+
configPermissions: configPermissions ?? defaultConfigPermissions,
|
|
230
|
+
rootPathSuggestions
|
|
231
|
+
}}>
|
|
232
|
+
|
|
233
|
+
{children}
|
|
234
|
+
|
|
235
|
+
<CollectionEditorDialog
|
|
236
|
+
open={Boolean(currentDialog)}
|
|
237
|
+
configController={collectionConfigController}
|
|
238
|
+
isNewCollection={false}
|
|
239
|
+
collectionInference={collectionInference}
|
|
240
|
+
{...currentDialog}
|
|
241
|
+
getData={getData}
|
|
242
|
+
reservedGroups={reservedGroups}
|
|
243
|
+
extraView={extraView}
|
|
244
|
+
pathSuggestions={getPathSuggestions}
|
|
245
|
+
getUser={getUser}
|
|
246
|
+
handleClose={(collection) => {
|
|
247
|
+
if (currentDialog?.redirect) {
|
|
248
|
+
if (collection && currentDialog?.isNewCollection && !currentDialog.parentCollectionIds.length) {
|
|
249
|
+
const url = navigation.buildUrlCollectionPath(collection.id ?? collection.path);
|
|
250
|
+
navigate(url);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
setCurrentDialog(undefined);
|
|
254
|
+
}}/>
|
|
255
|
+
|
|
256
|
+
{/* Used for editing properties*/}
|
|
257
|
+
<PropertyFormDialog
|
|
258
|
+
open={Boolean(currentPropertyDialog)}
|
|
259
|
+
includeIdAndName={true}
|
|
260
|
+
existingProperty={Boolean(currentPropertyDialog?.propertyKey)}
|
|
261
|
+
autoUpdateId={!currentPropertyDialog ? false : !currentPropertyDialog?.propertyKey}
|
|
262
|
+
autoOpenTypeSelect={!currentPropertyDialog ? false : !currentPropertyDialog?.propertyKey}
|
|
263
|
+
inArray={false}
|
|
264
|
+
collectionEditable={currentPropertyDialog?.collectionEditable ?? false}
|
|
265
|
+
getData={getData && currentPropertyDialog?.editedCollectionId
|
|
266
|
+
? () => {
|
|
267
|
+
console.debug("get data for property", currentPropertyDialog?.editedCollectionId);
|
|
268
|
+
const resolvedPath = navigation.resolveAliasesFrom(currentPropertyDialog.editedCollectionId!)
|
|
269
|
+
return getData(resolvedPath, []);
|
|
270
|
+
}
|
|
271
|
+
: undefined}
|
|
272
|
+
onPropertyChanged={({
|
|
273
|
+
id,
|
|
274
|
+
property
|
|
275
|
+
}) => {
|
|
276
|
+
if (!currentPropertyDialog) return;
|
|
277
|
+
if (!id) return;
|
|
278
|
+
const newProperty = !(currentPropertyDialog.propertyKey);
|
|
279
|
+
return collectionConfigController.saveProperty({
|
|
280
|
+
path: currentPropertyDialog?.editedCollectionId,
|
|
281
|
+
property,
|
|
282
|
+
propertyKey: id,
|
|
283
|
+
newPropertiesOrder: newProperty && currentPropertyDialog.currentPropertiesOrder ? [...currentPropertyDialog.currentPropertiesOrder, id] : undefined,
|
|
284
|
+
namespace: currentPropertyDialog.namespace,
|
|
285
|
+
parentCollectionIds: currentPropertyDialog.parentCollectionIds
|
|
286
|
+
})
|
|
287
|
+
.catch((e) => {
|
|
288
|
+
console.error(e);
|
|
289
|
+
snackbarController.open({
|
|
290
|
+
type: "error",
|
|
291
|
+
message: "Error persisting property: " + (e.message ?? "Details in the console")
|
|
292
|
+
});
|
|
293
|
+
return false;
|
|
294
|
+
});
|
|
295
|
+
}}
|
|
296
|
+
onPropertyChangedImmediate={false}
|
|
297
|
+
onDelete={() => {
|
|
298
|
+
if (!currentPropertyDialog?.propertyKey) return;
|
|
299
|
+
const newPropertiesOrder = currentPropertyDialog?.currentPropertiesOrder?.filter(p => p !== currentPropertyDialog?.propertyKey);
|
|
300
|
+
return collectionConfigController.deleteProperty({
|
|
301
|
+
path: currentPropertyDialog?.editedCollectionId,
|
|
302
|
+
propertyKey: currentPropertyDialog?.propertyKey,
|
|
303
|
+
namespace: currentPropertyDialog?.namespace,
|
|
304
|
+
newPropertiesOrder,
|
|
305
|
+
parentCollectionIds: currentPropertyDialog?.parentCollectionIds
|
|
306
|
+
})
|
|
307
|
+
.then(() => {
|
|
308
|
+
setCurrentPropertyDialog(undefined);
|
|
309
|
+
}).catch((e) => {
|
|
310
|
+
console.error(e);
|
|
311
|
+
snackbarController.open({
|
|
312
|
+
type: "error",
|
|
313
|
+
message: "Error deleting property: " + (e.message ?? "Details in the console")
|
|
314
|
+
});
|
|
315
|
+
return false;
|
|
316
|
+
});
|
|
317
|
+
}}
|
|
318
|
+
onError={() => {
|
|
319
|
+
}}
|
|
320
|
+
onOkClicked={() => {
|
|
321
|
+
setCurrentPropertyDialog(undefined);
|
|
322
|
+
}}
|
|
323
|
+
onCancel={() => {
|
|
324
|
+
setCurrentPropertyDialog(undefined);
|
|
325
|
+
}}
|
|
326
|
+
initialErrors={{}}
|
|
327
|
+
forceShowErrors={false}
|
|
328
|
+
existingPropertyKeys={[]}
|
|
329
|
+
allowDataInference={true}
|
|
330
|
+
propertyConfigs={propertyConfigs}
|
|
331
|
+
property={currentPropertyDialog?.property}
|
|
332
|
+
propertyKey={currentPropertyDialog?.propertyKey}/>
|
|
333
|
+
|
|
334
|
+
</CollectionEditorContext.Provider>
|
|
335
|
+
|
|
336
|
+
</ConfigControllerContext.Provider>
|
|
337
|
+
);
|
|
338
|
+
}, equal);
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export {
|
|
2
|
+
useCollectionEditorPlugin
|
|
3
|
+
} from "./useCollectionEditorPlugin";
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
useCollectionEditorController
|
|
7
|
+
} from "./useCollectionEditorController";
|
|
8
|
+
export {
|
|
9
|
+
useCollectionsConfigController
|
|
10
|
+
} from "./useCollectionsConfigController";
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
editableProperty, removeNonEditableProperties
|
|
14
|
+
} from "./utils/entities";
|
|
15
|
+
|
|
16
|
+
export type {
|
|
17
|
+
CollectionsConfigController, DeleteCollectionParams, SaveCollectionParams, UpdateCollectionParams
|
|
18
|
+
} from "./types/config_controller";
|
|
19
|
+
export type {
|
|
20
|
+
CollectionEditorController
|
|
21
|
+
} from "./types/collection_editor_controller";
|
|
22
|
+
export type {
|
|
23
|
+
CollectionEditorPermissions, CollectionEditorPermissionsBuilder
|
|
24
|
+
} from "./types/config_permissions";
|
|
25
|
+
export type {
|
|
26
|
+
PersistedCollection
|
|
27
|
+
} from "./types/persisted_collection";
|
|
28
|
+
|
|
29
|
+
export type {
|
|
30
|
+
CollectionInference
|
|
31
|
+
} from "./types/collection_inference";
|
|
32
|
+
|
|
33
|
+
export { MissingReferenceWidget } from "./ui/MissingReferenceWidget";
|
|
34
|
+
|
|
35
|
+
export * from "./ui/collection_editor/util";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { CollectionEditorPermissionsBuilder } from "./config_permissions";
|
|
2
|
+
import { Property } from "@firecms/core";
|
|
3
|
+
import { PersistedCollection } from "./persisted_collection";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Controller to open the collection editor dialog.
|
|
7
|
+
* @group Hooks and utilities
|
|
8
|
+
*/
|
|
9
|
+
export interface CollectionEditorController {
|
|
10
|
+
|
|
11
|
+
editCollection: (props: {
|
|
12
|
+
id?: string,
|
|
13
|
+
fullPath?: string,
|
|
14
|
+
parentCollectionIds: string[],
|
|
15
|
+
parentCollection?: PersistedCollection
|
|
16
|
+
}) => void;
|
|
17
|
+
|
|
18
|
+
createCollection: (props: {
|
|
19
|
+
initialValues?: {
|
|
20
|
+
group?: string,
|
|
21
|
+
path?: string,
|
|
22
|
+
name?: string
|
|
23
|
+
},
|
|
24
|
+
parentCollectionIds: string[],
|
|
25
|
+
parentCollection?: PersistedCollection,
|
|
26
|
+
redirect: boolean,
|
|
27
|
+
sourceClick?: string
|
|
28
|
+
}) => void;
|
|
29
|
+
|
|
30
|
+
editProperty: (props: {
|
|
31
|
+
propertyKey?: string,
|
|
32
|
+
property?: Property,
|
|
33
|
+
currentPropertiesOrder?: string[],
|
|
34
|
+
editedCollectionId: string,
|
|
35
|
+
parentCollectionIds: string[],
|
|
36
|
+
collection: PersistedCollection
|
|
37
|
+
}) => void;
|
|
38
|
+
|
|
39
|
+
configPermissions: CollectionEditorPermissionsBuilder;
|
|
40
|
+
|
|
41
|
+
rootPathSuggestions?: string[];
|
|
42
|
+
|
|
43
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { CMSType, Property } from "@firecms/core";
|
|
2
|
+
import { PersistedCollection } from "./persisted_collection";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Use this controller to access the configuration that is stored externally,
|
|
6
|
+
* and not defined in code.
|
|
7
|
+
*/
|
|
8
|
+
export interface CollectionsConfigController {
|
|
9
|
+
|
|
10
|
+
loading: boolean;
|
|
11
|
+
|
|
12
|
+
collections?: PersistedCollection[];
|
|
13
|
+
|
|
14
|
+
getCollection: (id: string) => PersistedCollection;
|
|
15
|
+
|
|
16
|
+
saveCollection: <M extends { [Key: string]: CMSType }>(params: SaveCollectionParams<M>) => Promise<void>;
|
|
17
|
+
updateCollection: <M extends { [Key: string]: CMSType }>(params: UpdateCollectionParams<M>) => Promise<void>;
|
|
18
|
+
|
|
19
|
+
saveProperty: (params: SavePropertyParams) => Promise<void>;
|
|
20
|
+
deleteProperty: (params: DeletePropertyParams) => Promise<void>;
|
|
21
|
+
|
|
22
|
+
deleteCollection: (props: DeleteCollectionParams) => Promise<void>;
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type UpdateCollectionParams<M extends Record<string, any>> = {
|
|
27
|
+
id: string,
|
|
28
|
+
collectionData: Partial<PersistedCollection<M>>,
|
|
29
|
+
previousId?: string,
|
|
30
|
+
parentCollectionIds?: string[]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type SaveCollectionParams<M extends Record<string, any>> = {
|
|
34
|
+
id: string,
|
|
35
|
+
collectionData: PersistedCollection<M>,
|
|
36
|
+
previousId?: string,
|
|
37
|
+
parentCollectionIds?: string[]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type SavePropertyParams = {
|
|
41
|
+
path: string,
|
|
42
|
+
propertyKey: string,
|
|
43
|
+
namespace?: string,
|
|
44
|
+
newPropertiesOrder?: string[],
|
|
45
|
+
property: Property,
|
|
46
|
+
parentCollectionIds?: string[]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type DeletePropertyParams = {
|
|
50
|
+
path: string,
|
|
51
|
+
propertyKey: string,
|
|
52
|
+
namespace?: string,
|
|
53
|
+
newPropertiesOrder?: string[],
|
|
54
|
+
parentCollectionIds?: string[]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type DeleteCollectionParams = {
|
|
58
|
+
id: string,
|
|
59
|
+
parentCollectionIds?: string[]
|
|
60
|
+
}
|