@firecms/core 3.0.0-alpha.81 → 3.0.0-alpha.82
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/EntityCollectionTable/EntityCollectionTableProps.d.ts +3 -3
- package/dist/components/EntityCollectionTable/column_utils.d.ts +2 -2
- package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +5 -1
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +1 -1
- package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +1 -1
- package/dist/contexts/AnalyticsContext.d.ts +3 -0
- package/dist/contexts/CustomizationControllerContext.d.ts +3 -0
- package/dist/core/field_configs.d.ts +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useAnalyticsController.d.ts +5 -0
- package/dist/hooks/useCustomizationController.d.ts +11 -0
- package/dist/hooks/useFireCMSContext.d.ts +0 -1
- package/dist/index.es.js +4614 -4592
- 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/useBuildCustomizationController.d.ts +2 -0
- package/dist/types/analytics_controller.d.ts +7 -0
- package/dist/types/collections.d.ts +3 -0
- package/dist/types/customization_controller.d.ts +47 -0
- package/dist/types/entity_callbacks.d.ts +17 -3
- package/dist/types/firecms_context.d.ts +6 -46
- package/dist/types/index.d.ts +2 -0
- package/dist/util/icons.d.ts +4 -1
- package/dist/util/useTraceUpdate.d.ts +1 -1
- package/package.json +3 -3
- package/src/components/DeleteEntityDialog.tsx +9 -3
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +28 -5
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +4 -5
- package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +125 -122
- package/src/components/EntityCollectionTable/filters/DateTimeFilterField.tsx +2 -2
- package/src/components/EntityCollectionTable/internal/default_entity_actions.tsx +3 -3
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +4 -3
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +74 -50
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +5 -3
- package/src/components/EntityPreview.tsx +11 -7
- package/src/components/HomePage/DefaultHomePage.tsx +9 -8
- package/src/components/HomePage/NavigationCollectionCard.tsx +6 -5
- package/src/components/ReferenceSelectionInner.tsx +13 -9
- package/src/components/VirtualTable/VirtualTable.tsx +23 -20
- package/src/components/VirtualTable/VirtualTableCell.tsx +27 -9
- package/src/components/VirtualTable/VirtualTableHeader.tsx +1 -1
- package/src/components/VirtualTable/VirtualTableProps.tsx +2 -2
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +2 -2
- package/src/contexts/AnalyticsContext.tsx +4 -0
- package/src/contexts/CustomizationControllerContext.tsx +4 -0
- package/src/core/Drawer.tsx +7 -6
- package/src/core/FireCMS.tsx +39 -29
- package/src/form/EntityForm.tsx +16 -5
- package/src/form/PropertyFieldBinding.tsx +8 -10
- package/src/form/components/CustomIdField.tsx +7 -5
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +1 -2
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +2 -2
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +4 -6
- package/src/hooks/data/save.ts +8 -3
- package/src/hooks/index.tsx +1 -0
- package/src/hooks/useAnalyticsController.tsx +8 -0
- package/src/hooks/useCustomizationController.tsx +14 -0
- package/src/hooks/useFireCMSContext.tsx +8 -7
- package/src/internal/EntityView.tsx +4 -2
- package/src/internal/useBuildCustomizationController.tsx +5 -0
- package/src/internal/useBuildSideDialogsController.tsx +0 -1
- package/src/preview/PropertyPreview.tsx +4 -3
- package/src/preview/components/DatePreview.tsx +4 -5
- package/src/preview/components/ReferencePreview.tsx +17 -8
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +3 -3
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +3 -3
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +3 -3
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +4 -4
- package/src/preview/property_previews/ArrayOneOfPreview.tsx +3 -3
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +3 -3
- package/src/types/analytics_controller.tsx +10 -0
- package/src/types/collections.ts +3 -0
- package/src/types/customization_controller.tsx +58 -0
- package/src/types/entity_callbacks.ts +22 -3
- package/src/types/firecms_context.tsx +6 -51
- package/src/types/index.ts +2 -0
- package/src/util/icons.tsx +22 -19
- package/src/util/useTraceUpdate.tsx +5 -5
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
3
|
import { canCreateEntity, canDeleteEntity, fullPathToCollectionSegments } from "../../util";
|
|
4
|
-
import { useAuthController, useFireCMSContext, useLargeLayout } from "../../hooks";
|
|
5
|
-
import { CollectionActionsProps, EntityCollection,
|
|
4
|
+
import { useAuthController, useCustomizationController, useFireCMSContext, useLargeLayout } from "../../hooks";
|
|
5
|
+
import { CollectionActionsProps, EntityCollection, EntityTableController, SelectionController } from "../../types";
|
|
6
6
|
import { AddIcon, Button, DeleteIcon, IconButton, Tooltip } from "@firecms/ui";
|
|
7
7
|
import { toArray } from "../../util/arrays";
|
|
8
8
|
import { ErrorBoundary } from "../ErrorBoundary";
|
|
@@ -34,7 +34,9 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
|
|
|
34
34
|
}: EntityCollectionViewActionsProps<M>) {
|
|
35
35
|
|
|
36
36
|
const context = useFireCMSContext();
|
|
37
|
-
|
|
37
|
+
|
|
38
|
+
const customizationController = useCustomizationController();
|
|
39
|
+
const plugins = customizationController.plugins ?? [];
|
|
38
40
|
|
|
39
41
|
const authController = useAuthController();
|
|
40
42
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import React, { useMemo } from "react";
|
|
2
2
|
import { PropertyPreview } from "../preview";
|
|
3
|
-
import { Entity, EntityCollection,
|
|
3
|
+
import { Entity, EntityCollection, ResolvedEntityCollection, ResolvedProperties } from "../types";
|
|
4
4
|
import { resolveCollection } from "../util";
|
|
5
5
|
import { useFireCMSContext } from "../hooks";
|
|
6
6
|
import { cn, defaultBorderMixin, IconButton, OpenInNewIcon } from "@firecms/ui";
|
|
7
|
+
import { CustomizationController } from "../types/customization_controller";
|
|
8
|
+
import { useCustomizationController } from "../hooks/useCustomizationController";
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* @group Components
|
|
@@ -29,10 +31,10 @@ export function EntityPreview<M extends Record<string, any>>(
|
|
|
29
31
|
path,
|
|
30
32
|
entityId: entity.id,
|
|
31
33
|
values: entity.values,
|
|
32
|
-
fields:
|
|
34
|
+
fields: customizationController.propertyConfigs
|
|
33
35
|
}), [collection, path, entity]);
|
|
34
36
|
|
|
35
|
-
const
|
|
37
|
+
const customizationController: CustomizationController = useCustomizationController();
|
|
36
38
|
|
|
37
39
|
const properties: ResolvedProperties = resolvedCollection.properties;
|
|
38
40
|
|
|
@@ -43,10 +45,11 @@ export function EntityPreview<M extends Record<string, any>>(
|
|
|
43
45
|
<div className="flex items-center w-1/4">
|
|
44
46
|
<span className="pl-2 text-sm text-gray-600">Id</span>
|
|
45
47
|
</div>
|
|
46
|
-
<div
|
|
48
|
+
<div
|
|
49
|
+
className="flex-grow p-2 ml-2 w-3/4 text-gray-900 dark:text-white min-h-[56px] flex items-center">
|
|
47
50
|
<span className="flex-grow mr-2">{entity.id}</span>
|
|
48
|
-
{
|
|
49
|
-
<a href={
|
|
51
|
+
{customizationController?.entityLinkBuilder &&
|
|
52
|
+
<a href={customizationController.entityLinkBuilder({ entity })}
|
|
50
53
|
rel="noopener noreferrer"
|
|
51
54
|
target="_blank">
|
|
52
55
|
<IconButton>
|
|
@@ -66,7 +69,8 @@ export function EntityPreview<M extends Record<string, any>>(
|
|
|
66
69
|
<div className="flex items-center w-1/4">
|
|
67
70
|
<span className="pl-2 text-sm text-gray-600">{property.name}</span>
|
|
68
71
|
</div>
|
|
69
|
-
<div
|
|
72
|
+
<div
|
|
73
|
+
className="flex-grow p-2 ml-2 w-3/4 text-gray-900 dark:text-white min-h-[56px] flex items-center">
|
|
70
74
|
<PropertyPreview
|
|
71
75
|
propertyKey={key}
|
|
72
76
|
value={value}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useState } from "react";
|
|
2
2
|
|
|
3
|
-
import { useFireCMSContext, useNavigationController } from "../../hooks";
|
|
3
|
+
import { useCustomizationController, useFireCMSContext, useNavigationController } from "../../hooks";
|
|
4
4
|
import { PluginGenericProps, PluginHomePageAdditionalCardsProps } from "../../types";
|
|
5
5
|
|
|
6
6
|
import { toArray } from "../../util/arrays";
|
|
@@ -46,6 +46,7 @@ export function DefaultHomePage({
|
|
|
46
46
|
}) {
|
|
47
47
|
|
|
48
48
|
const context = useFireCMSContext();
|
|
49
|
+
const customizationController = useCustomizationController();
|
|
49
50
|
const navigationController = useNavigationController();
|
|
50
51
|
|
|
51
52
|
if (!navigationController.topLevelNavigation)
|
|
@@ -90,12 +91,12 @@ export function DefaultHomePage({
|
|
|
90
91
|
let additionalPluginChildrenStart: React.ReactNode | undefined;
|
|
91
92
|
let additionalPluginChildrenEnd: React.ReactNode | undefined;
|
|
92
93
|
let additionalPluginSections: React.ReactNode | undefined;
|
|
93
|
-
if (
|
|
94
|
+
if (customizationController.plugins) {
|
|
94
95
|
const sectionProps: PluginGenericProps = {
|
|
95
96
|
context
|
|
96
97
|
};
|
|
97
98
|
additionalPluginSections = <>
|
|
98
|
-
{
|
|
99
|
+
{customizationController.plugins.filter(plugin => plugin.homePage?.includeSection)
|
|
99
100
|
.map((plugin, i) => {
|
|
100
101
|
const section = plugin.homePage!.includeSection!(sectionProps)
|
|
101
102
|
return (
|
|
@@ -108,14 +109,14 @@ export function DefaultHomePage({
|
|
|
108
109
|
})}
|
|
109
110
|
</>;
|
|
110
111
|
additionalPluginChildrenStart = <div className={"flex flex-col gap-2"}>
|
|
111
|
-
{
|
|
112
|
+
{customizationController.plugins.filter(plugin => plugin.homePage?.additionalChildrenStart)
|
|
112
113
|
.map((plugin, i) => {
|
|
113
114
|
return <div key={`plugin_children_start_${i}`}>{plugin.homePage!.additionalChildrenStart}</div>;
|
|
114
115
|
})}
|
|
115
116
|
</div>;
|
|
116
117
|
|
|
117
118
|
additionalPluginChildrenEnd = <div className={"flex flex-col gap-2"}>
|
|
118
|
-
{
|
|
119
|
+
{customizationController.plugins.filter(plugin => plugin.homePage?.additionalChildrenEnd)
|
|
119
120
|
.map((plugin, i) => {
|
|
120
121
|
return <div key={`plugin_children_start_${i}`}>{plugin.homePage!.additionalChildrenEnd}</div>;
|
|
121
122
|
})}
|
|
@@ -152,8 +153,8 @@ export function DefaultHomePage({
|
|
|
152
153
|
context
|
|
153
154
|
};
|
|
154
155
|
|
|
155
|
-
if (
|
|
156
|
-
|
|
156
|
+
if (customizationController.plugins) {
|
|
157
|
+
customizationController.plugins.forEach(plugin => {
|
|
157
158
|
if (plugin.homePage?.AdditionalCards) {
|
|
158
159
|
AdditionalCards.push(...toArray(plugin.homePage?.AdditionalCards));
|
|
159
160
|
}
|
|
@@ -181,7 +182,7 @@ export function DefaultHomePage({
|
|
|
181
182
|
: entry.type === "view"
|
|
182
183
|
? "home_navigate_to_view"
|
|
183
184
|
: "unmapped_event";
|
|
184
|
-
context.onAnalyticsEvent?.(event, { path: entry.path });
|
|
185
|
+
context.analyticsController?.onAnalyticsEvent?.(event, { path: entry.path });
|
|
185
186
|
}}
|
|
186
187
|
/>
|
|
187
188
|
</div>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useNavigate } from "react-router-dom";
|
|
2
2
|
|
|
3
|
-
import { useFireCMSContext } from "../../hooks";
|
|
3
|
+
import { useCustomizationController, useFireCMSContext } from "../../hooks";
|
|
4
4
|
import { PluginHomePageActionsProps, TopNavigationEntry } from "../../types";
|
|
5
|
-
import {
|
|
5
|
+
import { IconForView } from "../../util";
|
|
6
6
|
import { useUserConfigurationPersistence } from "../../hooks/useUserConfigurationPersistence";
|
|
7
7
|
import { ArrowForwardIcon, Card, cn, IconButton, Markdown, StarBorderIcon, StarIcon, Typography } from "@firecms/ui";
|
|
8
8
|
|
|
@@ -32,22 +32,23 @@ export function NavigationCollectionCard({
|
|
|
32
32
|
}) {
|
|
33
33
|
|
|
34
34
|
const userConfigurationPersistence = useUserConfigurationPersistence();
|
|
35
|
-
const collectionIcon =
|
|
35
|
+
const collectionIcon = <IconForView collectionOrView={collection ?? view}/>;
|
|
36
36
|
|
|
37
37
|
const navigate = useNavigate();
|
|
38
38
|
const context = useFireCMSContext();
|
|
39
|
+
const customizationController = useCustomizationController();
|
|
39
40
|
|
|
40
41
|
const favourite = (userConfigurationPersistence?.favouritePaths ?? []).includes(path);
|
|
41
42
|
|
|
42
43
|
let actions: React.ReactNode | undefined;
|
|
43
|
-
if (
|
|
44
|
+
if (customizationController.plugins && collection) {
|
|
44
45
|
const actionProps: PluginHomePageActionsProps = {
|
|
45
46
|
path,
|
|
46
47
|
collection,
|
|
47
48
|
context
|
|
48
49
|
};
|
|
49
50
|
actions = <>
|
|
50
|
-
{
|
|
51
|
+
{customizationController.plugins.map((plugin, i) => (
|
|
51
52
|
plugin.homePage?.CollectionActions
|
|
52
53
|
? <plugin.homePage.CollectionActions
|
|
53
54
|
key={`actions_${i}`}
|
|
@@ -5,8 +5,8 @@ import { EntityCollectionTable } from "./EntityCollectionTable";
|
|
|
5
5
|
import { EntityCollectionRowActions } from "./EntityCollectionTable/EntityCollectionRowActions";
|
|
6
6
|
import {
|
|
7
7
|
useAuthController,
|
|
8
|
+
useCustomizationController,
|
|
8
9
|
useDataSource,
|
|
9
|
-
useFireCMSContext,
|
|
10
10
|
useLargeLayout,
|
|
11
11
|
useNavigationController,
|
|
12
12
|
useSideEntityController
|
|
@@ -15,9 +15,12 @@ import { ErrorView } from "./ErrorView";
|
|
|
15
15
|
import { AddIcon, Button, DialogActions, Typography } from "@firecms/ui";
|
|
16
16
|
import { canCreateEntity, fullPathToCollectionSegments, resolveCollection } from "../util";
|
|
17
17
|
import { useSelectionController } from "./EntityCollectionView/EntityCollectionView";
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
useDataSourceEntityCollectionTableController
|
|
20
|
+
} from "./EntityCollectionTable/useDataSourceEntityCollectionTableController";
|
|
19
21
|
import { useColumnIds } from "./EntityCollectionView/useColumnsIds";
|
|
20
22
|
import { useSideDialogContext } from "../core";
|
|
23
|
+
import { useAnalyticsController } from "../hooks/useAnalyticsController";
|
|
21
24
|
|
|
22
25
|
/**
|
|
23
26
|
* @group Components
|
|
@@ -101,7 +104,8 @@ export function ReferenceSelectionInner<M extends Record<string, any>>(
|
|
|
101
104
|
const sideDialogContext = useSideDialogContext();
|
|
102
105
|
const sideEntityController = useSideEntityController();
|
|
103
106
|
const navigation = useNavigationController();
|
|
104
|
-
const
|
|
107
|
+
const analyticsController = useAnalyticsController();
|
|
108
|
+
const customizationController = useCustomizationController();
|
|
105
109
|
|
|
106
110
|
const fullPath = navigation.resolveAliasesFrom(pathInput);
|
|
107
111
|
|
|
@@ -142,7 +146,7 @@ export function ReferenceSelectionInner<M extends Record<string, any>>(
|
|
|
142
146
|
}, [dataSource, fullPath, selectedEntityIdsProp, collection, selectionController.setSelectedEntities]);
|
|
143
147
|
|
|
144
148
|
const onClear = () => {
|
|
145
|
-
|
|
149
|
+
analyticsController.onAnalyticsEvent?.("reference_selection_clear", {
|
|
146
150
|
path: fullPath
|
|
147
151
|
});
|
|
148
152
|
selectionController.setSelectedEntities([]);
|
|
@@ -158,7 +162,7 @@ export function ReferenceSelectionInner<M extends Record<string, any>>(
|
|
|
158
162
|
let newValue;
|
|
159
163
|
const selectedEntities = selectionController.selectedEntities;
|
|
160
164
|
|
|
161
|
-
|
|
165
|
+
analyticsController.onAnalyticsEvent?.("reference_selection_toggle", {
|
|
162
166
|
path: fullPath,
|
|
163
167
|
entityId: entity.id
|
|
164
168
|
});
|
|
@@ -182,7 +186,7 @@ export function ReferenceSelectionInner<M extends Record<string, any>>(
|
|
|
182
186
|
console.debug("ReferenceSelectionInner onEntityClick", entity);
|
|
183
187
|
|
|
184
188
|
if (!multiselect && onSingleEntitySelected) {
|
|
185
|
-
|
|
189
|
+
analyticsController.onAnalyticsEvent?.("reference_selected_single", {
|
|
186
190
|
path: fullPath,
|
|
187
191
|
entityId: entity.id
|
|
188
192
|
});
|
|
@@ -195,7 +199,7 @@ export function ReferenceSelectionInner<M extends Record<string, any>>(
|
|
|
195
199
|
|
|
196
200
|
// create a new entity from within the reference dialog
|
|
197
201
|
const onNewClick = () => {
|
|
198
|
-
|
|
202
|
+
analyticsController.onAnalyticsEvent?.("reference_selection_new_entity", {
|
|
199
203
|
path: fullPath
|
|
200
204
|
});
|
|
201
205
|
sideEntityController.open({
|
|
@@ -251,8 +255,8 @@ export function ReferenceSelectionInner<M extends Record<string, any>>(
|
|
|
251
255
|
collection: collection,
|
|
252
256
|
path: fullPath,
|
|
253
257
|
values: {},
|
|
254
|
-
fields:
|
|
255
|
-
}), [collection,
|
|
258
|
+
fields: customizationController.propertyConfigs
|
|
259
|
+
}), [collection, customizationController.propertyConfigs, fullPath]);
|
|
256
260
|
|
|
257
261
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
258
262
|
const displayedColumnIds = useColumnIds(resolvedCollection, false);
|
|
@@ -257,31 +257,34 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
|
|
|
257
257
|
const empty = !loading && (data?.length ?? 0) === 0;
|
|
258
258
|
const customView = error ? buildErrorView() : (empty ? buildEmptyView() : undefined);
|
|
259
259
|
|
|
260
|
+
const virtualListController = {
|
|
261
|
+
data,
|
|
262
|
+
size,
|
|
263
|
+
cellRenderer,
|
|
264
|
+
columns,
|
|
265
|
+
currentSort,
|
|
266
|
+
onRowClick,
|
|
267
|
+
customView,
|
|
268
|
+
onColumnResize: onColumnResizeInternal,
|
|
269
|
+
onColumnResizeEnd: onColumnResizeEndInternal,
|
|
270
|
+
filter: filterRef.current,
|
|
271
|
+
onColumnSort,
|
|
272
|
+
onFilterUpdate: onFilterUpdateInternal,
|
|
273
|
+
sortByProperty,
|
|
274
|
+
hoverRow: hoverRow ?? false,
|
|
275
|
+
createFilterField,
|
|
276
|
+
rowClassName,
|
|
277
|
+
endAdornment,
|
|
278
|
+
AddColumnComponent
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
// useTraceUpdate(virtualListController);
|
|
260
282
|
return (
|
|
261
283
|
<div
|
|
262
284
|
ref={measureRef}
|
|
263
285
|
className={cn("h-full w-full", className)}>
|
|
264
286
|
<VirtualListContext.Provider
|
|
265
|
-
value={
|
|
266
|
-
data,
|
|
267
|
-
size,
|
|
268
|
-
cellRenderer,
|
|
269
|
-
columns,
|
|
270
|
-
currentSort,
|
|
271
|
-
onRowClick,
|
|
272
|
-
customView,
|
|
273
|
-
onColumnResize: onColumnResizeInternal,
|
|
274
|
-
onColumnResizeEnd: onColumnResizeEndInternal,
|
|
275
|
-
filter: filterRef.current,
|
|
276
|
-
onColumnSort,
|
|
277
|
-
onFilterUpdate: onFilterUpdateInternal,
|
|
278
|
-
sortByProperty,
|
|
279
|
-
hoverRow: hoverRow ?? false,
|
|
280
|
-
createFilterField,
|
|
281
|
-
rowClassName,
|
|
282
|
-
endAdornment,
|
|
283
|
-
AddColumnComponent
|
|
284
|
-
}}>
|
|
287
|
+
value={virtualListController}>
|
|
285
288
|
|
|
286
289
|
<MemoizedList
|
|
287
290
|
outerRef={tableRef}
|
|
@@ -17,16 +17,34 @@ type VirtualTableCellProps<T extends any> = {
|
|
|
17
17
|
|
|
18
18
|
export const VirtualTableCell = React.memo<VirtualTableCellProps<any>>(
|
|
19
19
|
function VirtualTableCell<T extends any>(props: VirtualTableCellProps<T>) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
// @ts-ignore
|
|
21
|
+
return props.rowData && props.cellRenderer(
|
|
22
|
+
{
|
|
23
|
+
cellData: props.cellData,
|
|
24
|
+
rowData: props.rowData,
|
|
25
|
+
rowIndex: props.rowIndex,
|
|
26
|
+
isScrolling: false,
|
|
27
|
+
column: props.column,
|
|
28
|
+
columns: props.columns,
|
|
29
|
+
columnIndex: props.columnIndex,
|
|
30
|
+
width: props.column.width
|
|
31
|
+
} as CellRendererParams<T>
|
|
32
|
+
);
|
|
33
|
+
// return props.rowData && <props.cellRenderer
|
|
34
|
+
// rowData={props.rowData}
|
|
35
|
+
// rowIndex={props.rowIndex}
|
|
36
|
+
// isScrolling={false}
|
|
37
|
+
// column={props.column}
|
|
38
|
+
// columns={props.columns}
|
|
39
|
+
// columnIndex={props.columnIndex}
|
|
40
|
+
// width={props.column.width}/>
|
|
28
41
|
},
|
|
29
42
|
(a, b) => {
|
|
30
|
-
return equal(a, b)
|
|
43
|
+
return equal(a.rowData, b.rowData) &&
|
|
44
|
+
equal(a.column, b.column) &&
|
|
45
|
+
equal(a.cellData, b.cellData) &&
|
|
46
|
+
equal(a.rowIndex, b.rowIndex) &&
|
|
47
|
+
equal(a.cellRenderer, b.cellRenderer) &&
|
|
48
|
+
equal(a.columnIndex, b.columnIndex)
|
|
31
49
|
}
|
|
32
50
|
);
|
|
@@ -106,7 +106,7 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
|
106
106
|
<div
|
|
107
107
|
className={`flex items-center justify-${column.headerAlign} flex-row`}>
|
|
108
108
|
|
|
109
|
-
{column.icon
|
|
109
|
+
{column.icon}
|
|
110
110
|
|
|
111
111
|
<div
|
|
112
112
|
className="truncate -webkit-box w-full mx-1 overflow-hidden"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { WhereFilterOp } from "../../types";
|
|
3
3
|
import { FilterFormFieldProps } from "./VirtualTableHeader";
|
|
4
4
|
|
|
5
5
|
export type OnRowClickParams<T extends Record<string, any>> = {
|
|
@@ -188,7 +188,7 @@ export interface VirtualTableColumn<CustomProps extends any = any> {
|
|
|
188
188
|
/**
|
|
189
189
|
* Icon displayed in the header
|
|
190
190
|
*/
|
|
191
|
-
icon?:
|
|
191
|
+
icon?: React.ReactNode;
|
|
192
192
|
|
|
193
193
|
/**
|
|
194
194
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { DateTimeField } from "@firecms/ui";
|
|
3
|
-
import {
|
|
3
|
+
import { useCustomizationController } from "../../../hooks";
|
|
4
4
|
|
|
5
5
|
export function VirtualTableDateField(props: {
|
|
6
6
|
name: string;
|
|
@@ -13,7 +13,7 @@ export function VirtualTableDateField(props: {
|
|
|
13
13
|
onBlur?: React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>;
|
|
14
14
|
}) {
|
|
15
15
|
|
|
16
|
-
const { locale } =
|
|
16
|
+
const { locale } = useCustomizationController();
|
|
17
17
|
const {
|
|
18
18
|
disabled,
|
|
19
19
|
error,
|
package/src/core/Drawer.tsx
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React, { useCallback } from "react";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useLargeLayout, useNavigationController } from "../hooks";
|
|
4
4
|
|
|
5
5
|
import { NavLink } from "react-router-dom";
|
|
6
6
|
import { CMSAnalyticsEvent, TopNavigationEntry, TopNavigationResult } from "../types";
|
|
7
|
-
import {
|
|
7
|
+
import { IconForView } from "../util";
|
|
8
8
|
import { cn, Tooltip, Typography } from "@firecms/ui";
|
|
9
|
+
import { useAnalyticsController } from "../hooks/useAnalyticsController";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Props used in case you need to override the default drawer
|
|
@@ -27,7 +28,7 @@ export function Drawer({
|
|
|
27
28
|
closeDrawer
|
|
28
29
|
}: DrawerProps) {
|
|
29
30
|
|
|
30
|
-
const
|
|
31
|
+
const analyticsController = useAnalyticsController();
|
|
31
32
|
const navigation = useNavigationController();
|
|
32
33
|
|
|
33
34
|
const tooltipsOpen = hovered && !drawerOpen;
|
|
@@ -60,7 +61,7 @@ export function Drawer({
|
|
|
60
61
|
const eventName: CMSAnalyticsEvent = view.type === "collection"
|
|
61
62
|
? "drawer_navigate_to_collection"
|
|
62
63
|
: (view.type === "view" ? "drawer_navigate_to_view" : "unmapped_event");
|
|
63
|
-
|
|
64
|
+
analyticsController.onAnalyticsEvent?.(eventName, { url: view.url });
|
|
64
65
|
if (!largeLayout)
|
|
65
66
|
closeDrawer();
|
|
66
67
|
};
|
|
@@ -77,7 +78,7 @@ export function Drawer({
|
|
|
77
78
|
.map((view, index) =>
|
|
78
79
|
<DrawerNavigationItem
|
|
79
80
|
key={`navigation_${index}`}
|
|
80
|
-
icon={
|
|
81
|
+
icon={<IconForView collectionOrView={view.collection ?? view.view}/>}
|
|
81
82
|
tooltipsOpen={tooltipsOpen}
|
|
82
83
|
drawerOpen={drawerOpen}
|
|
83
84
|
onClick={() => onClick(view)}
|
|
@@ -92,7 +93,7 @@ export function Drawer({
|
|
|
92
93
|
|
|
93
94
|
return <DrawerNavigationItem
|
|
94
95
|
key={`navigation_${index}`}
|
|
95
|
-
icon={
|
|
96
|
+
icon={<IconForView collectionOrView={view.collection ?? view.view}/>}
|
|
96
97
|
tooltipsOpen={tooltipsOpen}
|
|
97
98
|
onClick={() => onClick(view)}
|
|
98
99
|
drawerOpen={drawerOpen}
|
package/src/core/FireCMS.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import React, { useMemo } from "react";
|
|
|
3
3
|
import { EntityCollection, FireCMSContext, FireCMSPlugin, FireCMSProps, User } from "../types";
|
|
4
4
|
import { AuthControllerContext, ModeControllerContext } from "../contexts";
|
|
5
5
|
import { useBuildSideEntityController } from "../internal/useBuildSideEntityController";
|
|
6
|
-
import {
|
|
6
|
+
import { useCustomizationController, useFireCMSContext, useModeController } from "../hooks";
|
|
7
7
|
import { useBuildSideDialogsController } from "../internal/useBuildSideDialogsController";
|
|
8
8
|
import { ErrorView } from "../components";
|
|
9
9
|
import { StorageSourceContext } from "../contexts/StorageSourceContext";
|
|
@@ -17,6 +17,9 @@ import { CenteredView } from "@firecms/ui";
|
|
|
17
17
|
import { DialogsProvider } from "../contexts/DialogsProvider";
|
|
18
18
|
import { useBuildNavigationController } from "../internal/useBuildNavigationController";
|
|
19
19
|
import { useBuildDataSource } from "../internal/useBuildDataSource";
|
|
20
|
+
import { useBuildCustomizationController } from "../internal/useBuildCustomizationController";
|
|
21
|
+
import { CustomizationControllerContext } from "../contexts/CustomizationControllerContext";
|
|
22
|
+
import { AnalyticsContext } from "../contexts/AnalyticsContext";
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
25
|
* If you are using independent components of the CMS
|
|
@@ -82,16 +85,19 @@ export function FireCMS<UserType extends User, EC extends EntityCollection>(prop
|
|
|
82
85
|
|
|
83
86
|
const loading = authController.initialLoading || navigationController.loading || pluginsLoading;
|
|
84
87
|
|
|
85
|
-
const
|
|
86
|
-
entityLinkBuilder,
|
|
88
|
+
const customizationController = useBuildCustomizationController({
|
|
87
89
|
dateTimeFormat,
|
|
88
90
|
locale,
|
|
91
|
+
entityLinkBuilder,
|
|
89
92
|
plugins,
|
|
90
|
-
onAnalyticsEvent,
|
|
91
93
|
entityViews: entityViews ?? [],
|
|
92
94
|
propertyConfigs: propertyConfigs ?? {},
|
|
93
95
|
components
|
|
94
|
-
})
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
const analyticsController = useMemo(() => ({
|
|
99
|
+
onAnalyticsEvent
|
|
100
|
+
}), []);
|
|
95
101
|
|
|
96
102
|
if (navigationController.navigationLoadingError) {
|
|
97
103
|
return (
|
|
@@ -115,35 +121,37 @@ export function FireCMS<UserType extends User, EC extends EntityCollection>(prop
|
|
|
115
121
|
|
|
116
122
|
return (
|
|
117
123
|
<ModeControllerContext.Provider value={modeController}>
|
|
118
|
-
<
|
|
119
|
-
<
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
124
|
+
<AnalyticsContext.Provider value={analyticsController}>
|
|
125
|
+
<CustomizationControllerContext.Provider value={customizationController}>
|
|
126
|
+
<UserConfigurationPersistenceContext.Provider
|
|
127
|
+
value={userConfigPersistence}>
|
|
128
|
+
<StorageSourceContext.Provider
|
|
129
|
+
value={storageSource}>
|
|
130
|
+
<DataSourceContext.Provider
|
|
131
|
+
value={dataSource}>
|
|
132
|
+
<AuthControllerContext.Provider
|
|
133
|
+
value={authController}>
|
|
134
|
+
<SideDialogsControllerContext.Provider
|
|
135
|
+
value={sideDialogsController}>
|
|
136
|
+
<SideEntityControllerContext.Provider
|
|
137
|
+
value={sideEntityController}>
|
|
138
|
+
<NavigationContext.Provider
|
|
139
|
+
value={navigationController}>
|
|
133
140
|
<DialogsProvider>
|
|
134
141
|
<FireCMSInternal
|
|
135
142
|
loading={loading}>
|
|
136
143
|
{children}
|
|
137
144
|
</FireCMSInternal>
|
|
138
145
|
</DialogsProvider>
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
</NavigationContext.Provider>
|
|
147
|
+
</SideEntityControllerContext.Provider>
|
|
148
|
+
</SideDialogsControllerContext.Provider>
|
|
149
|
+
</AuthControllerContext.Provider>
|
|
150
|
+
</DataSourceContext.Provider>
|
|
151
|
+
</StorageSourceContext.Provider>
|
|
152
|
+
</UserConfigurationPersistenceContext.Provider>
|
|
153
|
+
</CustomizationControllerContext.Provider>
|
|
154
|
+
</AnalyticsContext.Provider>
|
|
147
155
|
</ModeControllerContext.Provider>
|
|
148
156
|
);
|
|
149
157
|
|
|
@@ -161,12 +169,14 @@ function FireCMSInternal({
|
|
|
161
169
|
}) {
|
|
162
170
|
|
|
163
171
|
const context = useFireCMSContext();
|
|
172
|
+
const customizationController = useCustomizationController();
|
|
173
|
+
|
|
164
174
|
let childrenResult = children({
|
|
165
175
|
context,
|
|
166
176
|
loading
|
|
167
177
|
});
|
|
168
178
|
|
|
169
|
-
const plugins =
|
|
179
|
+
const plugins = customizationController.plugins;
|
|
170
180
|
if (!loading && plugins) {
|
|
171
181
|
plugins.forEach((plugin: FireCMSPlugin) => {
|
|
172
182
|
if (plugin.provider) {
|
package/src/form/EntityForm.tsx
CHANGED
|
@@ -25,7 +25,13 @@ import {
|
|
|
25
25
|
isReadOnly,
|
|
26
26
|
resolveCollection
|
|
27
27
|
} from "../util";
|
|
28
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
useAuthController,
|
|
30
|
+
useCustomizationController,
|
|
31
|
+
useDataSource,
|
|
32
|
+
useFireCMSContext,
|
|
33
|
+
useSideEntityController
|
|
34
|
+
} from "../hooks";
|
|
29
35
|
import { ErrorFocus } from "./components/ErrorFocus";
|
|
30
36
|
import { CustomIdField } from "./components/CustomIdField";
|
|
31
37
|
import { Alert, Button, cn, DialogActions, IconButton, Typography } from "@firecms/ui";
|
|
@@ -34,6 +40,7 @@ import {
|
|
|
34
40
|
copyEntityAction,
|
|
35
41
|
deleteEntityAction
|
|
36
42
|
} from "../components/EntityCollectionTable/internal/default_entity_actions";
|
|
43
|
+
import { useAnalyticsController } from "../hooks/useAnalyticsController";
|
|
37
44
|
|
|
38
45
|
/**
|
|
39
46
|
* @group Components
|
|
@@ -148,15 +155,19 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
148
155
|
onIdUpdateError
|
|
149
156
|
}: EntityFormProps<M>) {
|
|
150
157
|
|
|
158
|
+
const analyticsController = useAnalyticsController();
|
|
159
|
+
|
|
160
|
+
const customizationController = useCustomizationController();
|
|
161
|
+
|
|
151
162
|
const context = useFireCMSContext();
|
|
152
163
|
const dataSource = useDataSource();
|
|
153
|
-
const plugins =
|
|
164
|
+
const plugins = customizationController.plugins;
|
|
154
165
|
|
|
155
166
|
const initialResolvedCollection = useMemo(() => resolveCollection({
|
|
156
167
|
collection: inputCollection,
|
|
157
168
|
path,
|
|
158
169
|
values: entity?.values,
|
|
159
|
-
fields:
|
|
170
|
+
fields: customizationController.propertyConfigs
|
|
160
171
|
}), [entity?.values, path]);
|
|
161
172
|
|
|
162
173
|
const mustSetCustomId: boolean = (status === "new" || status === "copy") &&
|
|
@@ -219,7 +230,7 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
219
230
|
entityId,
|
|
220
231
|
values: internalValues,
|
|
221
232
|
previousValues: initialValues,
|
|
222
|
-
fields:
|
|
233
|
+
fields: customizationController.propertyConfigs
|
|
223
234
|
});
|
|
224
235
|
|
|
225
236
|
const onIdUpdate = inputCollection.callbacks?.onIdUpdate;
|
|
@@ -274,7 +285,7 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
274
285
|
const eventName: CMSAnalyticsEvent = status === "new"
|
|
275
286
|
? "new_entity_saved"
|
|
276
287
|
: (status === "copy" ? "entity_copied" : (status === "existing" ? "entity_edited" : "unmapped_event"));
|
|
277
|
-
|
|
288
|
+
analyticsController.onAnalyticsEvent?.(eventName, { path });
|
|
278
289
|
initialValuesRef.current = values;
|
|
279
290
|
})
|
|
280
291
|
.catch(e => {
|