@firecms/core 3.0.0-canary.5 → 3.0.0-canary.50
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/README.md +2 -2
- package/dist/components/ClearFilterSortButton.d.ts +5 -0
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -11
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
- package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +5 -3
- package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +3 -2
- package/dist/components/EntityCollectionTable/column_utils.d.ts +1 -2
- package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
- package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +1 -1
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +12 -3
- package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
- package/dist/components/EntityCollectionView/useSelectionController.d.ts +2 -0
- package/dist/components/EntityPreview.d.ts +25 -7
- package/dist/components/EntityView.d.ts +11 -0
- package/dist/components/FieldCaption.d.ts +5 -0
- package/dist/components/FireCMSAppBar.d.ts +3 -2
- package/dist/components/HomePage/NavigationCard.d.ts +8 -0
- package/dist/components/HomePage/{NavigationCollectionCard.d.ts → NavigationCardBinding.d.ts} +2 -2
- package/dist/components/HomePage/SmallNavigationCard.d.ts +6 -0
- package/dist/components/HomePage/index.d.ts +3 -1
- package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +1 -1
- package/dist/components/common/types.d.ts +4 -6
- package/dist/components/common/useDataSourceEntityCollectionTableController.d.ts +3 -0
- package/dist/components/index.d.ts +4 -2
- package/dist/contexts/AuthControllerContext.d.ts +1 -1
- package/dist/core/{EntityView.d.ts → EntityEditView.d.ts} +2 -2
- package/dist/core/NavigationRoutes.d.ts +1 -1
- package/dist/core/Scaffold.d.ts +1 -1
- package/dist/form/EntityForm.d.ts +1 -1
- package/dist/form/components/ErrorFocus.d.ts +1 -1
- package/dist/form/components/StorageItemPreview.d.ts +3 -2
- package/dist/form/components/StorageUploadProgress.d.ts +1 -1
- package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +4 -3
- package/dist/form/field_bindings/TextFieldBinding.d.ts +2 -2
- package/dist/form/validation.d.ts +1 -1
- package/dist/hooks/data/delete.d.ts +2 -2
- package/dist/hooks/data/save.d.ts +2 -3
- package/dist/hooks/data/useDataSource.d.ts +2 -2
- package/dist/hooks/data/useEntityFetch.d.ts +3 -3
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useBuildNavigationController.d.ts +6 -4
- package/dist/hooks/useProjectLog.d.ts +6 -2
- package/dist/hooks/useStorageSource.d.ts +2 -2
- package/dist/hooks/useValidateAuthenticator.d.ts +21 -0
- package/dist/index.es.js +10402 -9898
- 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 -12
- package/dist/preview/PropertyPreview.d.ts +1 -1
- package/dist/preview/PropertyPreviewProps.d.ts +1 -4
- package/dist/preview/components/BooleanPreview.d.ts +5 -1
- package/dist/preview/components/EnumValuesChip.d.ts +1 -1
- package/dist/preview/components/ReferencePreview.d.ts +1 -7
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/auth.d.ts +37 -1
- package/dist/types/collections.d.ts +29 -5
- package/dist/types/datasource.d.ts +3 -6
- package/dist/types/entities.d.ts +5 -1
- package/dist/types/entity_actions.d.ts +14 -0
- package/dist/types/entity_callbacks.d.ts +2 -2
- package/dist/types/entity_overrides.d.ts +6 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/navigation.d.ts +14 -13
- package/dist/types/permissions.d.ts +5 -1
- package/dist/types/plugins.d.ts +20 -20
- package/dist/types/properties.d.ts +4 -4
- package/dist/types/property_config.d.ts +2 -2
- package/dist/types/roles.d.ts +31 -0
- package/dist/types/storage.d.ts +11 -3
- package/dist/types/user.d.ts +5 -0
- package/dist/util/collections.d.ts +9 -1
- package/dist/util/entities.d.ts +1 -1
- package/dist/util/icon_synonyms.d.ts +1 -4
- package/dist/util/icons.d.ts +8 -2
- package/dist/util/navigation_utils.d.ts +2 -2
- package/dist/util/permissions.d.ts +4 -4
- package/dist/util/references.d.ts +4 -2
- package/dist/util/resolutions.d.ts +9 -13
- package/dist/util/useTraceUpdate.d.ts +1 -0
- package/package.json +139 -119
- package/src/components/ClearFilterSortButton.tsx +41 -0
- package/src/components/DeleteEntityDialog.tsx +4 -4
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +2 -2
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +275 -278
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +9 -5
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +44 -44
- package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +9 -16
- package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +3 -3
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +27 -32
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +11 -6
- package/src/components/EntityCollectionTable/internal/default_entity_actions.tsx +9 -5
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +2 -4
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +69 -64
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +5 -6
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
- package/src/components/EntityCollectionView/useSelectionController.tsx +30 -0
- package/src/components/EntityPreview.tsx +207 -70
- package/src/components/EntityView.tsx +84 -0
- package/src/components/FieldCaption.tsx +14 -0
- package/src/components/FireCMSAppBar.tsx +33 -11
- package/src/components/HomePage/DefaultHomePage.tsx +15 -11
- package/src/components/HomePage/NavigationCard.tsx +69 -0
- package/src/components/HomePage/NavigationCardBinding.tsx +116 -0
- package/src/components/HomePage/SmallNavigationCard.tsx +45 -0
- package/src/components/HomePage/index.tsx +3 -1
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +4 -4
- package/src/components/ReferenceWidget.tsx +4 -4
- package/src/components/SearchIconsView.tsx +4 -4
- package/src/components/SelectableTable/SelectableTable.tsx +1 -1
- package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
- package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +23 -8
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +35 -24
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
- package/src/components/VirtualTable/VirtualTable.tsx +28 -20
- package/src/components/VirtualTable/VirtualTableProps.tsx +1 -1
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +1 -1
- package/src/components/common/types.tsx +4 -6
- package/src/components/common/useDataSourceEntityCollectionTableController.tsx +12 -1
- package/src/components/index.tsx +4 -2
- package/src/contexts/AuthControllerContext.tsx +1 -1
- package/src/core/Drawer.tsx +66 -39
- package/src/core/{EntityView.tsx → EntityEditView.tsx} +21 -40
- package/src/core/EntitySidePanel.tsx +2 -2
- package/src/core/FireCMS.tsx +18 -3
- package/src/core/NavigationRoutes.tsx +11 -4
- package/src/core/Scaffold.tsx +5 -4
- package/src/core/field_configs.tsx +1 -2
- package/src/form/EntityForm.tsx +40 -21
- package/src/form/PropertyFieldBinding.tsx +0 -2
- package/src/form/components/StorageItemPreview.tsx +5 -3
- package/src/form/components/StorageUploadProgress.tsx +7 -6
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +8 -12
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +15 -15
- package/src/form/field_bindings/MapFieldBinding.tsx +15 -15
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +1 -1
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +1 -0
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +14 -5
- package/src/form/field_bindings/TextFieldBinding.tsx +7 -5
- package/src/form/validation.ts +3 -4
- package/src/hooks/data/delete.ts +3 -3
- package/src/hooks/data/save.ts +2 -2
- package/src/hooks/data/useCollectionFetch.tsx +1 -1
- package/src/hooks/data/useDataSource.tsx +8 -3
- package/src/hooks/data/useEntityFetch.tsx +4 -4
- package/src/hooks/index.tsx +2 -0
- package/src/hooks/useBuildLocalConfigurationPersistence.tsx +9 -10
- package/src/hooks/useBuildModeController.tsx +11 -5
- package/src/hooks/useBuildNavigationController.tsx +199 -81
- package/src/hooks/useProjectLog.tsx +17 -7
- package/src/hooks/useReferenceDialog.tsx +2 -2
- package/src/hooks/useStorageSource.tsx +7 -2
- package/src/hooks/useValidateAuthenticator.tsx +115 -0
- package/src/internal/useBuildDataSource.ts +42 -44
- package/src/internal/useBuildSideEntityController.tsx +86 -20
- package/src/preview/PropertyPreview.tsx +3 -14
- package/src/preview/PropertyPreviewProps.tsx +1 -11
- package/src/preview/components/BooleanPreview.tsx +19 -4
- package/src/preview/components/EnumValuesChip.tsx +1 -1
- package/src/preview/components/ReferencePreview.tsx +55 -147
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +0 -1
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +0 -1
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +0 -1
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +0 -1
- package/src/preview/property_previews/ArrayOneOfPreview.tsx +0 -1
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +0 -1
- package/src/preview/property_previews/StringPropertyPreview.tsx +8 -7
- package/src/types/analytics.ts +1 -0
- package/src/types/auth.tsx +50 -1
- package/src/types/collections.ts +33 -5
- package/src/types/datasource.ts +8 -5
- package/src/types/entities.ts +9 -1
- package/src/types/entity_actions.tsx +17 -0
- package/src/types/entity_callbacks.ts +2 -2
- package/src/types/entity_overrides.tsx +7 -0
- package/src/types/firecms.tsx +0 -1
- package/src/types/index.ts +2 -1
- package/src/types/navigation.ts +17 -16
- package/src/types/permissions.ts +6 -1
- package/src/types/plugins.tsx +26 -28
- package/src/types/properties.ts +8 -6
- package/src/types/property_config.tsx +2 -2
- package/src/types/roles.ts +41 -0
- package/src/types/side_entity_controller.tsx +1 -0
- package/src/types/storage.ts +12 -3
- package/src/types/user.ts +7 -0
- package/src/util/collections.ts +22 -0
- package/src/util/entities.ts +1 -1
- package/src/util/icon_list.ts +2 -2
- package/src/util/icon_synonyms.ts +1 -4
- package/src/util/icons.tsx +11 -3
- package/src/util/navigation_utils.ts +6 -6
- package/src/util/objects.ts +0 -14
- package/src/util/permissions.ts +11 -8
- package/src/util/references.ts +36 -5
- package/src/util/resolutions.ts +6 -24
- package/src/util/strings.ts +2 -2
- package/src/util/useTraceUpdate.tsx +2 -1
- package/dist/core/SideEntityView.d.ts +0 -7
- package/dist/internal/useLocaleConfig.d.ts +0 -1
- package/dist/types/appcheck.d.ts +0 -26
- package/src/components/HomePage/NavigationCollectionCard.tsx +0 -146
- package/src/core/SideEntityView.tsx +0 -38
- package/src/internal/useLocaleConfig.tsx +0 -18
- package/src/types/appcheck.ts +0 -29
|
@@ -1,84 +1,221 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
|
|
4
|
+
import { Entity, EntityCollection, ResolvedProperty } from "../types";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
getEntityImagePreviewPropertyKey,
|
|
8
|
+
getEntityPreviewKeys,
|
|
9
|
+
getEntityTitlePropertyKey,
|
|
10
|
+
getValueInPath,
|
|
11
|
+
resolveCollection
|
|
12
|
+
} from "../util";
|
|
13
|
+
import { cn, defaultBorderMixin, IconButton, KeyboardTabIcon, Skeleton, Tooltip, Typography } from "@firecms/ui";
|
|
14
|
+
import { PreviewSize, PropertyPreview, SkeletonPropertyComponent } from "../preview";
|
|
15
|
+
import { useCustomizationController, useNavigationController, useSideEntityController } from "../hooks";
|
|
16
|
+
import { useAnalyticsController } from "../hooks/useAnalyticsController";
|
|
17
|
+
|
|
18
|
+
export type EntityPreviewProps = {
|
|
19
|
+
size: PreviewSize,
|
|
20
|
+
actions?: React.ReactNode,
|
|
21
|
+
collection?: EntityCollection,
|
|
22
|
+
hover?: boolean;
|
|
23
|
+
previewProperties?: string[],
|
|
24
|
+
disabled: undefined | boolean,
|
|
25
|
+
entity: Entity<any>,
|
|
26
|
+
includeEntityNavigation?: boolean,
|
|
27
|
+
onClick?: (e: React.SyntheticEvent) => void;
|
|
28
|
+
};
|
|
8
29
|
|
|
9
30
|
/**
|
|
10
|
-
*
|
|
31
|
+
* This view is used to display a preview of an entity.
|
|
32
|
+
* It is used by default in reference fields and whenever a reference is displayed.
|
|
11
33
|
*/
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
34
|
+
export function EntityPreview({
|
|
35
|
+
actions,
|
|
36
|
+
disabled,
|
|
37
|
+
hover,
|
|
38
|
+
collection: collectionProp,
|
|
39
|
+
previewProperties,
|
|
40
|
+
onClick,
|
|
41
|
+
size,
|
|
42
|
+
includeEntityNavigation,
|
|
43
|
+
entity
|
|
44
|
+
}: EntityPreviewProps) {
|
|
18
45
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
46
|
+
const analyticsController = useAnalyticsController();
|
|
47
|
+
const sideEntityController = useSideEntityController();
|
|
48
|
+
const customizationController = useCustomizationController();
|
|
49
|
+
|
|
50
|
+
const navigationController = useNavigationController();
|
|
51
|
+
|
|
52
|
+
const collection = collectionProp ?? navigationController.getCollection(entity.path);
|
|
26
53
|
|
|
27
|
-
|
|
28
|
-
|
|
54
|
+
if (!collection) {
|
|
55
|
+
throw Error(`Couldn't find the corresponding collection view for the path: ${entity.path}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const resolvedCollection = React.useMemo(() => resolveCollection({
|
|
29
59
|
collection,
|
|
30
|
-
path,
|
|
31
|
-
entityId: entity.id,
|
|
60
|
+
path: entity.path,
|
|
32
61
|
values: entity.values,
|
|
33
62
|
fields: customizationController.propertyConfigs
|
|
34
|
-
}), [collection
|
|
63
|
+
}), [collection]);
|
|
35
64
|
|
|
36
|
-
const
|
|
65
|
+
const listProperties = useMemo(() => getEntityPreviewKeys(resolvedCollection, customizationController.propertyConfigs, previewProperties, size === "small" || size === "medium" ? 3 : 1),
|
|
66
|
+
[previewProperties, resolvedCollection, size]);
|
|
37
67
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
68
|
+
const titleProperty = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
|
|
69
|
+
const imagePropertyKey = getEntityImagePreviewPropertyKey(resolvedCollection);
|
|
70
|
+
const imageProperty = imagePropertyKey ? resolvedCollection.properties[imagePropertyKey] : undefined;
|
|
71
|
+
|
|
72
|
+
const restProperties = listProperties.filter(p => p !== titleProperty && p !== imagePropertyKey);
|
|
73
|
+
|
|
74
|
+
return <EntityPreviewContainer onClick={disabled ? undefined : onClick}
|
|
75
|
+
hover={disabled ? undefined : hover}
|
|
76
|
+
size={size}>
|
|
77
|
+
{imageProperty && (
|
|
78
|
+
<div className={cn("w-10 h-10 mr-2 shrink-0 grow-0", size === "tiny" ? "my-0.5" : "m-2 self-start")}>
|
|
79
|
+
<PropertyPreview property={imageProperty}
|
|
80
|
+
propertyKey={imagePropertyKey as string}
|
|
81
|
+
size={"tiny"}
|
|
82
|
+
value={getValueInPath(entity.values, imagePropertyKey as string)}/>
|
|
83
|
+
</div>
|
|
84
|
+
)}
|
|
85
|
+
|
|
86
|
+
<div className={"flex flex-col flex-grow w-full m-1"}>
|
|
87
|
+
|
|
88
|
+
{size !== "tiny" && (
|
|
89
|
+
entity
|
|
90
|
+
? <div className={`${
|
|
91
|
+
size !== "medium"
|
|
92
|
+
? "block whitespace-nowrap overflow-hidden truncate"
|
|
93
|
+
: ""
|
|
94
|
+
}`}>
|
|
95
|
+
<Typography variant={"caption"}
|
|
96
|
+
color={"disabled"}
|
|
97
|
+
className={"font-mono"}>
|
|
98
|
+
{entity.id}
|
|
99
|
+
</Typography>
|
|
57
100
|
</div>
|
|
101
|
+
: <Skeleton/>)}
|
|
102
|
+
|
|
103
|
+
{titleProperty && (
|
|
104
|
+
<div className={"my-0.5 text-sm font-medium"}>
|
|
105
|
+
{
|
|
106
|
+
entity
|
|
107
|
+
? <PropertyPreview
|
|
108
|
+
propertyKey={titleProperty as string}
|
|
109
|
+
value={getValueInPath(entity.values, titleProperty)}
|
|
110
|
+
property={resolvedCollection.properties[titleProperty as string] as ResolvedProperty}
|
|
111
|
+
size={"medium"}/>
|
|
112
|
+
: <SkeletonPropertyComponent
|
|
113
|
+
property={resolvedCollection.properties[titleProperty as string] as ResolvedProperty}
|
|
114
|
+
size={"medium"}/>
|
|
115
|
+
}
|
|
58
116
|
</div>
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
117
|
+
)}
|
|
118
|
+
|
|
119
|
+
{restProperties && restProperties.map((key) => {
|
|
120
|
+
const childProperty = resolvedCollection.properties[key as string];
|
|
121
|
+
if (!childProperty) return null;
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<div key={"ref_prev_" + key}
|
|
125
|
+
className={restProperties.length > 1 ? "my-0.5" : "my-0"}>
|
|
126
|
+
{
|
|
127
|
+
entity
|
|
128
|
+
? <PropertyPreview
|
|
129
|
+
propertyKey={key as string}
|
|
130
|
+
value={getValueInPath(entity.values, key)}
|
|
131
|
+
property={childProperty as ResolvedProperty}
|
|
132
|
+
size={"tiny"}/>
|
|
133
|
+
: <SkeletonPropertyComponent
|
|
134
|
+
property={childProperty as ResolvedProperty}
|
|
135
|
+
size={"tiny"}/>
|
|
136
|
+
}
|
|
137
|
+
</div>
|
|
138
|
+
);
|
|
139
|
+
})}
|
|
140
|
+
|
|
82
141
|
</div>
|
|
83
|
-
|
|
142
|
+
|
|
143
|
+
{entity && includeEntityNavigation &&
|
|
144
|
+
<Tooltip title={`See details for ${entity.id}`}
|
|
145
|
+
className={size !== "tiny" ? "self-start" : ""}>
|
|
146
|
+
<IconButton
|
|
147
|
+
color={"inherit"}
|
|
148
|
+
size={"small"}
|
|
149
|
+
onClick={(e) => {
|
|
150
|
+
e.stopPropagation();
|
|
151
|
+
analyticsController.onAnalyticsEvent?.("entity_click_from_reference", {
|
|
152
|
+
path: entity.path,
|
|
153
|
+
entityId: entity.id
|
|
154
|
+
});
|
|
155
|
+
sideEntityController.open({
|
|
156
|
+
entityId: entity.id,
|
|
157
|
+
path: entity.path,
|
|
158
|
+
collection,
|
|
159
|
+
updateUrl: true
|
|
160
|
+
});
|
|
161
|
+
}}>
|
|
162
|
+
<KeyboardTabIcon size={"small"}/>
|
|
163
|
+
</IconButton>
|
|
164
|
+
</Tooltip>}
|
|
165
|
+
|
|
166
|
+
{actions}
|
|
167
|
+
|
|
168
|
+
</EntityPreviewContainer>;
|
|
84
169
|
}
|
|
170
|
+
|
|
171
|
+
export type EntityPreviewContainerProps = {
|
|
172
|
+
children: React.ReactNode;
|
|
173
|
+
hover?: boolean;
|
|
174
|
+
fullwidth?: boolean;
|
|
175
|
+
size: PreviewSize;
|
|
176
|
+
className?: string;
|
|
177
|
+
style?: React.CSSProperties;
|
|
178
|
+
onClick?: (e: React.SyntheticEvent) => void;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const EntityPreviewContainerInner = React.forwardRef<HTMLDivElement, EntityPreviewContainerProps>(({
|
|
182
|
+
children,
|
|
183
|
+
hover,
|
|
184
|
+
onClick,
|
|
185
|
+
size,
|
|
186
|
+
style,
|
|
187
|
+
className,
|
|
188
|
+
fullwidth = true,
|
|
189
|
+
...props
|
|
190
|
+
}, ref) => {
|
|
191
|
+
return <div
|
|
192
|
+
ref={ref}
|
|
193
|
+
style={{
|
|
194
|
+
...style,
|
|
195
|
+
// @ts-ignore
|
|
196
|
+
tabindex: 0
|
|
197
|
+
}}
|
|
198
|
+
className={cn(
|
|
199
|
+
"bg-white dark:bg-gray-900",
|
|
200
|
+
fullwidth ? "w-full" : "",
|
|
201
|
+
"items-center",
|
|
202
|
+
hover ? "hover:bg-slate-50 dark:hover:bg-gray-800 group-hover:bg-slate-50 dark:group-hover:bg-gray-800" : "",
|
|
203
|
+
size === "tiny" ? "p-1" : "p-2",
|
|
204
|
+
"flex border rounded-lg",
|
|
205
|
+
onClick ? "cursor-pointer" : "",
|
|
206
|
+
defaultBorderMixin,
|
|
207
|
+
className)}
|
|
208
|
+
onClick={(event) => {
|
|
209
|
+
if (onClick) {
|
|
210
|
+
event.preventDefault();
|
|
211
|
+
onClick(event);
|
|
212
|
+
}
|
|
213
|
+
}}
|
|
214
|
+
{...props}>
|
|
215
|
+
{children}
|
|
216
|
+
</div>;
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
EntityPreviewContainerInner.displayName = "EntityPreviewContainer";
|
|
220
|
+
|
|
221
|
+
export const EntityPreviewContainer = React.memo(EntityPreviewContainerInner) as React.FC<EntityPreviewContainerProps>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
import { PropertyPreview } from "../preview";
|
|
3
|
+
import { Entity, EntityCollection, ResolvedEntityCollection, ResolvedProperties } from "../types";
|
|
4
|
+
import { resolveCollection } from "../util";
|
|
5
|
+
import { cn, defaultBorderMixin, IconButton, OpenInNewIcon } from "@firecms/ui";
|
|
6
|
+
import { CustomizationController } from "../types/customization_controller";
|
|
7
|
+
import { useCustomizationController } from "../hooks/useCustomizationController";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @group Components
|
|
11
|
+
*/
|
|
12
|
+
export interface EntityViewProps<M extends Record<string, any>> {
|
|
13
|
+
entity: Entity<M>;
|
|
14
|
+
collection: EntityCollection<M>;
|
|
15
|
+
path: string;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function EntityView<M extends Record<string, any>>(
|
|
20
|
+
{
|
|
21
|
+
entity,
|
|
22
|
+
collection,
|
|
23
|
+
path,
|
|
24
|
+
className
|
|
25
|
+
}: EntityViewProps<M>) {
|
|
26
|
+
|
|
27
|
+
const customizationController: CustomizationController = useCustomizationController();
|
|
28
|
+
const resolvedCollection: ResolvedEntityCollection<M> = useMemo(() => resolveCollection<M>({
|
|
29
|
+
collection,
|
|
30
|
+
path,
|
|
31
|
+
entityId: entity.id,
|
|
32
|
+
values: entity.values,
|
|
33
|
+
fields: customizationController.propertyConfigs
|
|
34
|
+
}), [collection, path, entity]);
|
|
35
|
+
|
|
36
|
+
const properties: ResolvedProperties = resolvedCollection.properties;
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div className={"w-full " + className}>
|
|
40
|
+
<div className={"w-full mb-4"}>
|
|
41
|
+
<div className={cn(defaultBorderMixin, "flex justify-between py-2 border-b last:border-b-0")}>
|
|
42
|
+
<div className="flex items-center w-1/4">
|
|
43
|
+
<span className="pl-2 text-sm text-gray-600">Id</span>
|
|
44
|
+
</div>
|
|
45
|
+
<div
|
|
46
|
+
className="flex-grow p-2 ml-2 w-3/4 text-gray-900 dark:text-white min-h-[56px] flex items-center">
|
|
47
|
+
<span className="flex-grow mr-2">{entity.id}</span>
|
|
48
|
+
{customizationController?.entityLinkBuilder &&
|
|
49
|
+
<a href={customizationController.entityLinkBuilder({ entity })}
|
|
50
|
+
rel="noopener noreferrer"
|
|
51
|
+
target="_blank">
|
|
52
|
+
<IconButton>
|
|
53
|
+
<OpenInNewIcon
|
|
54
|
+
size={"small"}/>
|
|
55
|
+
</IconButton>
|
|
56
|
+
</a>}
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
{Object.entries(properties)
|
|
60
|
+
.map(([key, property]) => {
|
|
61
|
+
const value = entity.values?.[key];
|
|
62
|
+
return (
|
|
63
|
+
<div
|
|
64
|
+
key={`reference_previews_${key}`}
|
|
65
|
+
className={cn(defaultBorderMixin, "flex justify-between py-2 border-b last:border-b-0")}>
|
|
66
|
+
<div className="flex items-center w-1/4">
|
|
67
|
+
<span className="pl-2 text-sm text-gray-600">{property.name}</span>
|
|
68
|
+
</div>
|
|
69
|
+
<div
|
|
70
|
+
className="flex-grow p-2 ml-2 w-3/4 text-gray-900 dark:text-white min-h-[56px] flex items-center">
|
|
71
|
+
<PropertyPreview
|
|
72
|
+
propertyKey={key}
|
|
73
|
+
value={value}
|
|
74
|
+
// entity={entity}
|
|
75
|
+
property={property}
|
|
76
|
+
size={"medium"}/>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
)
|
|
80
|
+
})}
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Typography } from "@firecms/ui";
|
|
3
|
+
|
|
4
|
+
export function FieldCaption({
|
|
5
|
+
error,
|
|
6
|
+
children
|
|
7
|
+
}: { error?: boolean, children?: React.ReactNode }) {
|
|
8
|
+
if (!children) return null;
|
|
9
|
+
return (
|
|
10
|
+
<Typography variant={"caption"} color={error ? "error" : "secondary"} className={"ml-3.5 mt-0.5"}>
|
|
11
|
+
{children}
|
|
12
|
+
</Typography>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
3
|
import { Link as ReactLink } from "react-router-dom";
|
|
4
|
-
import { ErrorBoundary } from "../components";
|
|
4
|
+
import { ErrorBoundary, FireCMSLogo } from "../components";
|
|
5
5
|
import {
|
|
6
6
|
Avatar,
|
|
7
7
|
cn,
|
|
@@ -18,7 +18,8 @@ import { useAuthController, useLargeLayout, useModeController, useNavigationCont
|
|
|
18
18
|
import { User } from "../types";
|
|
19
19
|
|
|
20
20
|
export type FireCMSAppBarProps<ADDITIONAL_PROPS = object> = {
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
title: React.ReactNode;
|
|
22
23
|
/**
|
|
23
24
|
* A component that gets rendered on the upper side of the main toolbar
|
|
24
25
|
*/
|
|
@@ -36,6 +37,8 @@ export type FireCMSAppBarProps<ADDITIONAL_PROPS = object> = {
|
|
|
36
37
|
|
|
37
38
|
style?: React.CSSProperties;
|
|
38
39
|
|
|
40
|
+
logo?: string;
|
|
41
|
+
|
|
39
42
|
user?: User;
|
|
40
43
|
} & ADDITIONAL_PROPS;
|
|
41
44
|
|
|
@@ -57,6 +60,7 @@ export const FireCMSAppBar = function FireCMSAppBar({
|
|
|
57
60
|
includeDrawer,
|
|
58
61
|
className,
|
|
59
62
|
style,
|
|
63
|
+
logo,
|
|
60
64
|
user: userProp
|
|
61
65
|
}: FireCMSAppBarProps) {
|
|
62
66
|
const navigation = useNavigationController();
|
|
@@ -92,7 +96,7 @@ export const FireCMSAppBar = function FireCMSAppBar({
|
|
|
92
96
|
className={cn("pr-2",
|
|
93
97
|
{
|
|
94
98
|
"ml-[17rem]": drawerOpen && largeLayout,
|
|
95
|
-
"ml-16": includeDrawer && !(drawerOpen && largeLayout)
|
|
99
|
+
"ml-16": includeDrawer && !(drawerOpen && largeLayout),
|
|
96
100
|
"h-16": true,
|
|
97
101
|
"z-10": largeLayout,
|
|
98
102
|
"transition-all": true,
|
|
@@ -102,27 +106,37 @@ export const FireCMSAppBar = function FireCMSAppBar({
|
|
|
102
106
|
"w-[calc(100%-64px)]": includeDrawer && !(drawerOpen && largeLayout),
|
|
103
107
|
"w-[calc(100%-17rem)]": includeDrawer && (drawerOpen && largeLayout),
|
|
104
108
|
"duration-150": drawerOpen && largeLayout,
|
|
105
|
-
fixed: true
|
|
109
|
+
fixed: true
|
|
106
110
|
},
|
|
107
111
|
className)}>
|
|
108
112
|
|
|
109
113
|
<div className="flex flex-row gap-2 px-4 h-full items-center">
|
|
110
114
|
|
|
111
|
-
{startAdornment}
|
|
112
|
-
|
|
113
115
|
{navigation && <div className="mr-8 hidden lg:block">
|
|
114
116
|
<ReactLink
|
|
115
117
|
className="visited:text-inherit visited:dark:text-inherit"
|
|
116
118
|
to={navigation?.basePath ?? "/"}
|
|
117
119
|
>
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
<div className={"flex flex-row gap-4"}>
|
|
121
|
+
{!includeDrawer && (logo
|
|
122
|
+
? <img src={logo}
|
|
123
|
+
alt="Logo"
|
|
124
|
+
className={cn("w-[32px] h-[32px]")}/>
|
|
125
|
+
: <FireCMSLogo width={"32px"} height={"32px"}/>)}
|
|
126
|
+
|
|
127
|
+
{typeof title === "string"
|
|
128
|
+
? <Typography variant="subtitle1"
|
|
129
|
+
noWrap
|
|
130
|
+
className={"ml-2 !font-medium"}>
|
|
131
|
+
{title}
|
|
132
|
+
</Typography>
|
|
133
|
+
: title}
|
|
134
|
+
</div>
|
|
123
135
|
</ReactLink>
|
|
124
136
|
</div>}
|
|
125
137
|
|
|
138
|
+
{startAdornment}
|
|
139
|
+
|
|
126
140
|
<div className={"flex-grow"}/>
|
|
127
141
|
|
|
128
142
|
{endAdornment &&
|
|
@@ -141,6 +155,14 @@ export const FireCMSAppBar = function FireCMSAppBar({
|
|
|
141
155
|
</IconButton>
|
|
142
156
|
|
|
143
157
|
<Menu trigger={avatarComponent}>
|
|
158
|
+
{user && <div className={"px-4 py-2 mb-2"}>
|
|
159
|
+
{user.displayName && <Typography variant={"body1"} color={"secondary"}>
|
|
160
|
+
{user.displayName}
|
|
161
|
+
</Typography>}
|
|
162
|
+
{user.email && <Typography variant={"body2"} color={"secondary"}>
|
|
163
|
+
{user.email}
|
|
164
|
+
</Typography>}
|
|
165
|
+
</div>}
|
|
144
166
|
|
|
145
167
|
{dropDownActions}
|
|
146
168
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useState } from "react";
|
|
2
2
|
|
|
3
3
|
import { useCustomizationController, useFireCMSContext, useNavigationController } from "../../hooks";
|
|
4
|
-
import { PluginGenericProps, PluginHomePageAdditionalCardsProps } from "../../types";
|
|
4
|
+
import { CMSAnalyticsEvent, PluginGenericProps, PluginHomePageAdditionalCardsProps } from "../../types";
|
|
5
5
|
|
|
6
6
|
import { toArray } from "../../util/arrays";
|
|
7
7
|
import { NavigationGroup } from "./NavigationGroup";
|
|
8
|
-
import {
|
|
8
|
+
import { NavigationCardBinding } from "./NavigationCardBinding";
|
|
9
9
|
|
|
10
10
|
// @ts-ignore
|
|
11
11
|
import * as JsSearch from "js-search";
|
|
@@ -102,7 +102,7 @@ export function DefaultHomePage({
|
|
|
102
102
|
return (
|
|
103
103
|
<NavigationGroup
|
|
104
104
|
group={section.title}
|
|
105
|
-
key={`plugin_section_${plugin.
|
|
105
|
+
key={`plugin_section_${plugin.key}`}>
|
|
106
106
|
{section.children}
|
|
107
107
|
</NavigationGroup>
|
|
108
108
|
);
|
|
@@ -173,21 +173,25 @@ export function DefaultHomePage({
|
|
|
173
173
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
174
174
|
{thisGroupCollections.map((entry) => (
|
|
175
175
|
<div key={`nav_${entry.group}_${entry.name}`} className="col-span-1">
|
|
176
|
-
<
|
|
176
|
+
<NavigationCardBinding
|
|
177
177
|
{...entry}
|
|
178
178
|
onClick={() => {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
179
|
+
let event: CMSAnalyticsEvent;
|
|
180
|
+
if (entry.type === "collection") {
|
|
181
|
+
event = "home_navigate_to_collection";
|
|
182
|
+
} else if (entry.type === "view") {
|
|
183
|
+
event = "home_navigate_to_view";
|
|
184
|
+
} else if (entry.type === "admin") {
|
|
185
|
+
event = "home_navigate_to_admin_view";
|
|
186
|
+
} else {
|
|
187
|
+
event = "unmapped_event";
|
|
188
|
+
}
|
|
185
189
|
context.analyticsController?.onAnalyticsEvent?.(event, { path: entry.path });
|
|
186
190
|
}}
|
|
187
191
|
/>
|
|
188
192
|
</div>
|
|
189
193
|
))}
|
|
190
|
-
{AdditionalCards &&
|
|
194
|
+
{group?.toLowerCase() !== "admin" && AdditionalCards &&
|
|
191
195
|
AdditionalCards.map((AdditionalCard, i) => (
|
|
192
196
|
<div key={`nav_${group}_add_${i}`}>
|
|
193
197
|
<AdditionalCard {...actionProps} />
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ArrowForwardIcon, Card, cn, Markdown, Typography, } from "@firecms/ui";
|
|
2
|
+
|
|
3
|
+
export type NavigationCardProps = {
|
|
4
|
+
name: string,
|
|
5
|
+
description?: string;
|
|
6
|
+
actions: React.ReactNode;
|
|
7
|
+
icon: React.ReactNode;
|
|
8
|
+
onClick?: () => void,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function NavigationCard({
|
|
12
|
+
name,
|
|
13
|
+
description,
|
|
14
|
+
icon,
|
|
15
|
+
actions,
|
|
16
|
+
onClick,
|
|
17
|
+
}: NavigationCardProps) {
|
|
18
|
+
|
|
19
|
+
return (<Card
|
|
20
|
+
className={cn("h-full p-4 cursor-pointer min-h-[230px]")}
|
|
21
|
+
onClick={() => {
|
|
22
|
+
onClick?.();
|
|
23
|
+
}}>
|
|
24
|
+
|
|
25
|
+
<div className="flex flex-col items-start h-full">
|
|
26
|
+
<div
|
|
27
|
+
className="flex-grow w-full">
|
|
28
|
+
|
|
29
|
+
<div
|
|
30
|
+
className="h-10 flex items-center w-full justify-between text-gray-300 dark:text-gray-600">
|
|
31
|
+
|
|
32
|
+
{icon}
|
|
33
|
+
|
|
34
|
+
<div
|
|
35
|
+
className="flex items-center gap-1"
|
|
36
|
+
onClick={(event: React.MouseEvent) => {
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
event.stopPropagation();
|
|
39
|
+
}}>
|
|
40
|
+
|
|
41
|
+
{actions}
|
|
42
|
+
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<Typography gutterBottom variant="h5"
|
|
48
|
+
component="h2">
|
|
49
|
+
{name}
|
|
50
|
+
</Typography>
|
|
51
|
+
|
|
52
|
+
{description && <Typography variant="body2"
|
|
53
|
+
color="secondary"
|
|
54
|
+
component="div">
|
|
55
|
+
<Markdown source={description} size={"small"}/>
|
|
56
|
+
</Typography>}
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div style={{ alignSelf: "flex-end" }}>
|
|
60
|
+
|
|
61
|
+
<div className={"p-4"}>
|
|
62
|
+
<ArrowForwardIcon className="text-primary"/>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
</Card>)
|
|
69
|
+
}
|