@firecms/core 3.0.0-beta.7 → 3.0.0-beta.9
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/app/AppBar.d.ts +12 -0
- package/dist/app/Drawer.d.ts +17 -0
- package/dist/app/Scaffold.d.ts +30 -0
- package/dist/app/index.d.ts +4 -0
- package/dist/app/useApp.d.ts +16 -0
- package/dist/components/ArrayContainer.d.ts +2 -1
- package/dist/components/CircularProgressCenter.d.ts +1 -1
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +0 -1
- package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +1 -1
- package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +1 -1
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +1 -1
- package/dist/components/EntityPreview.d.ts +1 -1
- package/dist/components/ErrorView.d.ts +1 -1
- package/dist/components/HomePage/DefaultHomePage.d.ts +1 -1
- package/dist/components/HomePage/NavigationCardBinding.d.ts +1 -1
- package/dist/components/PropertyIdCopyTooltip.d.ts +8 -0
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +14 -6
- package/dist/components/common/useColumnsIds.d.ts +2 -1
- package/dist/components/index.d.ts +2 -1
- package/dist/{components/FireCMSAppBar.d.ts → core/DefaultAppBar.d.ts} +3 -8
- package/dist/core/DefaultDrawer.d.ts +19 -0
- package/dist/core/DrawerNavigationItem.d.ts +2 -1
- package/dist/core/EntityEditView.d.ts +18 -4
- package/dist/core/FireCMS.d.ts +1 -1
- package/dist/core/NavigationRoutes.d.ts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/form/PropertyFieldBinding.d.ts +1 -1
- package/dist/form/components/FieldHelperText.d.ts +3 -3
- package/dist/form/components/FormikArrayContainer.d.ts +2 -1
- package/dist/form/components/LabelWithIcon.d.ts +1 -1
- package/dist/form/components/LabelWithIconAndTooltip.d.ts +15 -0
- package/dist/form/components/StorageItemPreview.d.ts +4 -4
- package/dist/form/components/index.d.ts +1 -0
- package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/BlockFieldBinding.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/MarkdownEditorFieldBinding.d.ts +11 -0
- package/dist/form/field_bindings/{MultiSelectBinding.d.ts → MultiSelectFieldBinding.d.ts} +1 -1
- package/dist/form/field_bindings/ReadOnlyFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/RepeatFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/SelectFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -5
- package/dist/form/field_bindings/TextFieldBinding.d.ts +1 -1
- package/dist/form/index.d.ts +3 -5
- package/dist/form/useClearRestoreValue.d.ts +2 -2
- package/dist/hooks/useProjectLog.d.ts +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +14434 -11300
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +19987 -587
- package/dist/index.umd.js.map +1 -1
- package/dist/preview/PropertyPreviewProps.d.ts +6 -1
- package/dist/preview/components/EnumValuesChip.d.ts +1 -1
- package/dist/preview/components/ReferencePreview.d.ts +1 -1
- package/dist/preview/components/StorageThumbnail.d.ts +2 -1
- package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
- package/dist/types/auth.d.ts +2 -2
- package/dist/types/collections.d.ts +26 -3
- package/dist/types/datasource.d.ts +53 -30
- package/dist/types/entities.d.ts +1 -0
- package/dist/types/entity_overrides.d.ts +2 -2
- package/dist/types/fields.d.ts +47 -41
- package/dist/types/navigation.d.ts +1 -0
- package/dist/types/plugins.d.ts +11 -3
- package/dist/types/properties.d.ts +25 -20
- package/dist/types/side_dialogs_controller.d.ts +10 -0
- package/dist/types/storage.d.ts +75 -0
- package/dist/util/entities.d.ts +1 -1
- package/dist/util/icon_list.d.ts +5 -1
- package/dist/util/icons.d.ts +3 -2
- package/dist/util/index.d.ts +1 -0
- package/dist/util/plurals.d.ts +0 -2
- package/dist/util/property_utils.d.ts +1 -1
- package/dist/util/resolutions.d.ts +15 -1
- package/dist/util/storage.d.ts +23 -2
- package/dist/util/useStorageUploadController.d.ts +3 -3
- package/package.json +18 -29
- package/src/app/AppBar.tsx +18 -0
- package/src/app/Drawer.tsx +25 -0
- package/src/{core → app}/Scaffold.tsx +71 -122
- package/src/app/index.ts +4 -0
- package/src/app/useApp.tsx +32 -0
- package/src/components/ArrayContainer.tsx +15 -10
- package/src/components/CircularProgressCenter.tsx +1 -1
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +11 -18
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +2 -2
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +4 -2
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +21 -14
- package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +12 -4
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +17 -19
- package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +19 -7
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +5 -6
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +33 -29
- package/src/components/EntityCollectionView/useSelectionController.tsx +19 -7
- package/src/components/EntityPreview.tsx +30 -31
- package/src/components/ErrorView.tsx +1 -1
- package/src/components/HomePage/DefaultHomePage.tsx +24 -18
- package/src/components/HomePage/NavigationCardBinding.tsx +1 -1
- package/src/components/HomePage/SmallNavigationCard.tsx +1 -2
- package/src/components/PropertyIdCopyTooltip.tsx +48 -0
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +7 -6
- package/src/components/SearchIconsView.tsx +5 -2
- package/src/components/SelectableTable/SelectableTable.tsx +2 -4
- package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +1 -1
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +54 -7
- package/src/components/VirtualTable/VirtualTable.tsx +36 -10
- package/src/components/VirtualTable/VirtualTableCell.tsx +1 -9
- package/src/components/VirtualTable/VirtualTableProps.tsx +17 -8
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +3 -3
- package/src/components/VirtualTable/fields/VirtualTableInput.tsx +2 -1
- package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +2 -1
- package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +14 -28
- package/src/components/common/useColumnsIds.tsx +13 -0
- package/src/components/common/useDataSourceEntityCollectionTableController.tsx +12 -12
- package/src/components/common/useTableSearchHelper.ts +53 -12
- package/src/components/index.tsx +2 -1
- package/src/contexts/DialogsProvider.tsx +2 -2
- package/src/{components/FireCMSAppBar.tsx → core/DefaultAppBar.tsx} +28 -30
- package/src/core/DefaultDrawer.tsx +183 -0
- package/src/core/DrawerNavigationItem.tsx +31 -27
- package/src/core/EntityEditView.tsx +712 -145
- package/src/core/EntitySidePanel.tsx +0 -1
- package/src/core/FireCMS.tsx +2 -2
- package/src/core/NavigationRoutes.tsx +4 -4
- package/src/core/SideDialogs.tsx +1 -0
- package/src/core/field_configs.tsx +5 -5
- package/src/core/index.tsx +2 -2
- package/src/form/PropertyFieldBinding.tsx +53 -19
- package/src/form/components/CustomIdField.tsx +4 -2
- package/src/form/components/FieldHelperText.tsx +4 -4
- package/src/form/components/FormikArrayContainer.tsx +4 -1
- package/src/form/components/LabelWithIcon.tsx +27 -19
- package/src/form/components/LabelWithIconAndTooltip.tsx +28 -0
- package/src/form/components/StorageItemPreview.tsx +20 -10
- package/src/form/components/StorageUploadProgress.tsx +0 -1
- package/src/form/components/index.tsx +1 -0
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +26 -15
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +28 -25
- package/src/form/field_bindings/BlockFieldBinding.tsx +13 -11
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +17 -14
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +48 -42
- package/src/form/field_bindings/MapFieldBinding.tsx +17 -17
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +150 -0
- package/src/form/field_bindings/{MultiSelectBinding.tsx → MultiSelectFieldBinding.tsx} +25 -20
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +9 -14
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +27 -18
- package/src/form/field_bindings/RepeatFieldBinding.tsx +32 -19
- package/src/form/field_bindings/SelectFieldBinding.tsx +17 -10
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +33 -43
- package/src/form/field_bindings/SwitchFieldBinding.tsx +9 -5
- package/src/form/field_bindings/TextFieldBinding.tsx +26 -23
- package/src/form/index.tsx +4 -9
- package/src/form/useClearRestoreValue.tsx +2 -2
- package/src/form/validation.ts +1 -17
- package/src/hooks/data/delete.ts +2 -1
- package/src/hooks/data/save.ts +5 -2
- package/src/hooks/data/useDataSource.tsx +11 -3
- package/src/hooks/useBuildNavigationController.tsx +10 -3
- package/src/hooks/useProjectLog.tsx +18 -7
- package/src/index.ts +1 -0
- package/src/internal/useBuildDataSource.ts +69 -74
- package/src/internal/useBuildSideDialogsController.tsx +1 -0
- package/src/internal/useBuildSideEntityController.tsx +17 -4
- package/src/internal/useUnsavedChangesDialog.tsx +3 -1
- package/src/preview/PropertyPreview.tsx +7 -4
- package/src/preview/PropertyPreviewProps.tsx +7 -1
- package/src/preview/components/BooleanPreview.tsx +1 -1
- package/src/preview/components/EnumValuesChip.tsx +1 -1
- package/src/preview/components/ImagePreview.tsx +24 -34
- package/src/preview/components/ReferencePreview.tsx +2 -12
- package/src/preview/components/StorageThumbnail.tsx +5 -1
- package/src/preview/components/UrlComponentPreview.tsx +44 -11
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +1 -1
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +1 -1
- package/src/preview/property_previews/ArrayOneOfPreview.tsx +2 -2
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +1 -1
- package/src/preview/property_previews/MapPropertyPreview.tsx +1 -1
- package/src/preview/property_previews/SkeletonPropertyComponent.tsx +2 -2
- package/src/preview/property_previews/StringPropertyPreview.tsx +2 -2
- package/src/preview/util.ts +2 -2
- package/src/types/auth.tsx +2 -2
- package/src/types/collections.ts +29 -4
- package/src/types/customization_controller.tsx +0 -1
- package/src/types/datasource.ts +62 -43
- package/src/types/entities.ts +2 -0
- package/src/types/entity_overrides.tsx +2 -2
- package/src/types/fields.tsx +51 -45
- package/src/types/navigation.ts +1 -0
- package/src/types/plugins.tsx +12 -3
- package/src/types/properties.ts +25 -19
- package/src/types/side_dialogs_controller.tsx +13 -0
- package/src/types/storage.ts +82 -0
- package/src/util/entities.ts +5 -4
- package/src/util/icon_list.ts +14 -9
- package/src/util/icons.tsx +8 -2
- package/src/util/index.ts +1 -0
- package/src/util/objects.ts +17 -7
- package/src/util/permissions.ts +1 -0
- package/src/util/plurals.ts +0 -2
- package/src/util/property_utils.tsx +1 -1
- package/src/util/references.ts +3 -0
- package/src/util/resolutions.ts +43 -11
- package/src/util/storage.ts +79 -21
- package/src/util/useStorageUploadController.tsx +33 -7
- package/dist/components/PropertyIdCopyTooltipContent.d.ts +0 -3
- package/dist/core/Drawer.d.ts +0 -16
- package/dist/core/Scaffold.d.ts +0 -51
- package/dist/form/EntityForm.d.ts +0 -77
- package/dist/form/field_bindings/MarkdownFieldBinding.d.ts +0 -9
- package/src/components/PropertyIdCopyTooltipContent.tsx +0 -27
- package/src/core/Drawer.tsx +0 -139
- package/src/form/EntityForm.tsx +0 -736
- package/src/form/field_bindings/MarkdownFieldBinding.tsx +0 -695
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from "react";
|
|
2
2
|
import { useDebouncedCallback } from "../../../util";
|
|
3
|
+
import { cls, focusedDisabled } from "@firecms/ui";
|
|
3
4
|
|
|
4
5
|
export function VirtualTableNumberInput(props: {
|
|
5
6
|
error: Error | undefined;
|
|
@@ -65,7 +66,7 @@ export function VirtualTableNumberInput(props: {
|
|
|
65
66
|
return (
|
|
66
67
|
<input
|
|
67
68
|
ref={ref}
|
|
68
|
-
className="w-full text-right p-0 m-0 bg-transparent border-none resize-none outline-none font-normal leading-normal text-unset"
|
|
69
|
+
className={cls("w-full text-right p-0 m-0 bg-transparent border-none resize-none outline-none font-normal leading-normal text-unset", focusedDisabled)}
|
|
69
70
|
style={{
|
|
70
71
|
textAlign: align
|
|
71
72
|
}}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EnumValueConfig } from "../../../types";
|
|
2
|
-
import {
|
|
2
|
+
import { EnumValuesChip } from "../../../preview";
|
|
3
3
|
import React, { useCallback, useEffect } from "react";
|
|
4
4
|
import { MultiSelect, MultiSelectItem, Select, SelectItem } from "@firecms/ui";
|
|
5
5
|
|
|
@@ -18,9 +18,7 @@ export function VirtualTableSelect(props: {
|
|
|
18
18
|
}) {
|
|
19
19
|
|
|
20
20
|
const {
|
|
21
|
-
name,
|
|
22
21
|
enumValues,
|
|
23
|
-
error,
|
|
24
22
|
internalValue,
|
|
25
23
|
disabled,
|
|
26
24
|
small,
|
|
@@ -41,6 +39,7 @@ export function VirtualTableSelect(props: {
|
|
|
41
39
|
}, [focused, ref]);
|
|
42
40
|
|
|
43
41
|
const onChange = useCallback((updatedValue: string | string[]) => {
|
|
42
|
+
console.trace("onChange");
|
|
44
43
|
if (valueType === "number") {
|
|
45
44
|
if (multiple) {
|
|
46
45
|
const newValue = (updatedValue as string[]).map((v) => parseFloat(v));
|
|
@@ -58,37 +57,27 @@ export function VirtualTableSelect(props: {
|
|
|
58
57
|
}
|
|
59
58
|
}, [multiple, updateValue, valueType]);
|
|
60
59
|
|
|
61
|
-
const renderValue = (enumKey
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
enumValues={enumValues}
|
|
68
|
-
size={small ? "small" : "medium"}/>;
|
|
69
|
-
} else {
|
|
70
|
-
return <EnumValuesChip
|
|
71
|
-
key={`${enumKey}-${index}`}
|
|
72
|
-
enumKey={enumKey}
|
|
73
|
-
enumValues={enumValues}
|
|
74
|
-
size={small ? "small" : "medium"}/>;
|
|
75
|
-
}
|
|
60
|
+
const renderValue = (enumKey?: string | number) => {
|
|
61
|
+
return <EnumValuesChip
|
|
62
|
+
key={`${enumKey}`}
|
|
63
|
+
enumKey={String(enumKey)}
|
|
64
|
+
enumValues={enumValues}
|
|
65
|
+
size={small ? "small" : "medium"}/>;
|
|
76
66
|
};
|
|
67
|
+
|
|
77
68
|
return (
|
|
78
69
|
multiple
|
|
79
70
|
? <MultiSelect
|
|
80
71
|
inputRef={ref}
|
|
81
|
-
containerClassName="w-full h-full"
|
|
82
72
|
className="w-full h-full p-0 bg-transparent"
|
|
83
73
|
position={"item-aligned"}
|
|
84
74
|
disabled={disabled}
|
|
85
|
-
|
|
86
|
-
|
|
75
|
+
includeClear={false}
|
|
76
|
+
useChips={false}
|
|
87
77
|
value={validValue
|
|
88
78
|
? ((internalValue as any[]).map(v => v.toString()))
|
|
89
79
|
: ([])}
|
|
90
|
-
|
|
91
|
-
renderValue={renderValue}>
|
|
80
|
+
onValueChange={onChange}>
|
|
92
81
|
{enumValues?.map((enumConfig) => (
|
|
93
82
|
<MultiSelectItem
|
|
94
83
|
key={enumConfig.id}
|
|
@@ -105,14 +94,11 @@ export function VirtualTableSelect(props: {
|
|
|
105
94
|
className="w-full h-full p-0 bg-transparent"
|
|
106
95
|
position={"item-aligned"}
|
|
107
96
|
disabled={disabled}
|
|
108
|
-
multiple={multiple}
|
|
109
97
|
padding={false}
|
|
110
|
-
includeFocusOutline={false}
|
|
111
98
|
value={validValue
|
|
112
|
-
?
|
|
113
|
-
:
|
|
99
|
+
? internalValue?.toString()
|
|
100
|
+
: ""}
|
|
114
101
|
onValueChange={onChange}
|
|
115
|
-
onMultiValueChange={onChange}
|
|
116
102
|
renderValue={renderValue}>
|
|
117
103
|
{enumValues?.map((enumConfig) => (
|
|
118
104
|
<SelectItem
|
|
@@ -106,3 +106,16 @@ export function getColumnKeysForProperty(property: ResolvedProperty, key: string
|
|
|
106
106
|
disabled: disabled || Boolean(property.disabled) || Boolean(property.readOnly)
|
|
107
107
|
}];
|
|
108
108
|
}
|
|
109
|
+
|
|
110
|
+
export function getFormFieldKeys(collection: EntityCollection): string[] {
|
|
111
|
+
const propertyKeys = Object.keys(collection.properties);
|
|
112
|
+
const additionalFields = collection.additionalFields ?? [];
|
|
113
|
+
const allKeys = [
|
|
114
|
+
...propertyKeys,
|
|
115
|
+
...additionalFields.map((field) => field.key)
|
|
116
|
+
];
|
|
117
|
+
if (collection.propertiesOrder) {
|
|
118
|
+
return collection.propertiesOrder.filter(key => allKeys.includes(key));
|
|
119
|
+
}
|
|
120
|
+
return allKeys;
|
|
121
|
+
}
|
|
@@ -80,6 +80,18 @@ export function useDataSourceEntityCollectionTableController<M extends Record<st
|
|
|
80
80
|
const [searchString, setSearchString] = React.useState<string | undefined>();
|
|
81
81
|
const [itemCount, setItemCount] = React.useState<number | undefined>(paginationEnabled ? pageSize : undefined);
|
|
82
82
|
|
|
83
|
+
const checkFilterCombination = useCallback((filterValues: FilterValues<any>,
|
|
84
|
+
sortBy?: [string, "asc" | "desc"]) => {
|
|
85
|
+
if (!dataSource.isFilterCombinationValid)
|
|
86
|
+
return true;
|
|
87
|
+
return dataSource.isFilterCombinationValid({
|
|
88
|
+
path: resolvedPath,
|
|
89
|
+
collection,
|
|
90
|
+
filterValues,
|
|
91
|
+
sortBy
|
|
92
|
+
})
|
|
93
|
+
}, []);
|
|
94
|
+
|
|
83
95
|
const initialSortInternal = useMemo(() => {
|
|
84
96
|
if (initialSort && forceFilter && !checkFilterCombination(forceFilter, initialSort)) {
|
|
85
97
|
console.warn("Initial sort is not compatible with the force filter. Ignoring initial sort");
|
|
@@ -108,18 +120,6 @@ export function useDataSourceEntityCollectionTableController<M extends Record<st
|
|
|
108
120
|
const [dataLoadingError, setDataLoadingError] = useState<Error | undefined>();
|
|
109
121
|
const [noMoreToLoad, setNoMoreToLoad] = useState<boolean>(false);
|
|
110
122
|
|
|
111
|
-
const checkFilterCombination = useCallback((filterValues: FilterValues<any>,
|
|
112
|
-
sortBy?: [string, "asc" | "desc"]) => {
|
|
113
|
-
if (!dataSource.isFilterCombinationValid)
|
|
114
|
-
return true;
|
|
115
|
-
return dataSource.isFilterCombinationValid({
|
|
116
|
-
path: resolvedPath,
|
|
117
|
-
collection,
|
|
118
|
-
filterValues,
|
|
119
|
-
sortBy
|
|
120
|
-
})
|
|
121
|
-
}, []);
|
|
122
|
-
|
|
123
123
|
const clearFilter = useCallback(() => setFilterValues(forceFilter ?? undefined), [forceFilter]);
|
|
124
124
|
|
|
125
125
|
const updateFilterValues = useCallback((updatedFilter: FilterValues<Extract<keyof M, string>> | undefined) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
|
|
3
3
|
import { EntityCollection } from "../../types";
|
|
4
|
-
import { useCustomizationController, useFireCMSContext } from "../../hooks";
|
|
4
|
+
import { useCustomizationController, useDataSource, useFireCMSContext } from "../../hooks";
|
|
5
5
|
|
|
6
6
|
export interface UseTableSearchHelperParams<M extends Record<string, any>> {
|
|
7
7
|
collection: EntityCollection<M>;
|
|
@@ -9,27 +9,58 @@ export interface UseTableSearchHelperParams<M extends Record<string, any>> {
|
|
|
9
9
|
parentCollectionIds?: string[];
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export function useTableSearchHelper<M extends Record<string, any>>({
|
|
12
|
+
export function useTableSearchHelper<M extends Record<string, any>>({
|
|
13
|
+
collection,
|
|
14
|
+
fullPath,
|
|
15
|
+
parentCollectionIds
|
|
16
|
+
}: UseTableSearchHelperParams<M>) {
|
|
13
17
|
|
|
14
18
|
const context = useFireCMSContext();
|
|
15
19
|
const customizationController = useCustomizationController();
|
|
20
|
+
const dataSource = useDataSource();
|
|
16
21
|
|
|
17
22
|
const [textSearchLoading, setTextSearchLoading] = useState<boolean>(false);
|
|
18
23
|
const [textSearchInitialised, setTextSearchInitialised] = useState<boolean>(false);
|
|
24
|
+
|
|
19
25
|
let onTextSearchClick: (() => void) | undefined;
|
|
20
26
|
let textSearchEnabled = Boolean(collection.textSearchEnabled);
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
|
|
28
|
+
const props = {
|
|
29
|
+
context,
|
|
30
|
+
path: fullPath,
|
|
31
|
+
databaseId: collection.databaseId,
|
|
32
|
+
collection,
|
|
33
|
+
parentCollectionIds
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const searchBlocked = customizationController.plugins?.find(p => {
|
|
37
|
+
return p.collectionView?.blockSearch?.(props);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const addTextSearchClickListener = Boolean(dataSource?.initTextSearch) || customizationController.plugins?.find(p => Boolean(p.collectionView?.onTextSearchClick));
|
|
41
|
+
|
|
42
|
+
if (addTextSearchClickListener) {
|
|
23
43
|
|
|
24
44
|
onTextSearchClick = addTextSearchClickListener
|
|
25
45
|
? () => {
|
|
26
46
|
setTextSearchLoading(true);
|
|
27
|
-
Promise
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
.
|
|
47
|
+
const promises: Promise<boolean>[] = [];
|
|
48
|
+
if (dataSource?.initTextSearch && !searchBlocked) {
|
|
49
|
+
promises.push(dataSource.initTextSearch(props));
|
|
50
|
+
}
|
|
51
|
+
if (searchBlocked) {
|
|
52
|
+
customizationController.plugins?.forEach(p => {
|
|
53
|
+
if (p.collectionView?.onTextSearchClick)
|
|
54
|
+
promises.push(p.collectionView.onTextSearchClick({
|
|
55
|
+
context,
|
|
56
|
+
path: fullPath,
|
|
57
|
+
collection,
|
|
58
|
+
parentCollectionIds
|
|
59
|
+
}));
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
return Promise.all(promises)
|
|
63
|
+
.then((res: boolean[]) => {
|
|
33
64
|
if (res.every(Boolean)) setTextSearchInitialised(true);
|
|
34
65
|
})
|
|
35
66
|
.finally(() => setTextSearchLoading(false));
|
|
@@ -39,9 +70,19 @@ export function useTableSearchHelper<M extends Record<string, any>>({ collection
|
|
|
39
70
|
customizationController.plugins?.forEach(p => {
|
|
40
71
|
if (!textSearchEnabled)
|
|
41
72
|
if (p.collectionView?.showTextSearchBar) {
|
|
42
|
-
textSearchEnabled = p.collectionView.showTextSearchBar({
|
|
73
|
+
textSearchEnabled = p.collectionView.showTextSearchBar({
|
|
74
|
+
context,
|
|
75
|
+
path: fullPath,
|
|
76
|
+
collection,
|
|
77
|
+
parentCollectionIds
|
|
78
|
+
});
|
|
43
79
|
}
|
|
44
80
|
})
|
|
45
81
|
}
|
|
46
|
-
return {
|
|
82
|
+
return {
|
|
83
|
+
textSearchLoading,
|
|
84
|
+
textSearchInitialised,
|
|
85
|
+
onTextSearchClick,
|
|
86
|
+
textSearchEnabled
|
|
87
|
+
};
|
|
47
88
|
}
|
package/src/components/index.tsx
CHANGED
|
@@ -19,6 +19,7 @@ export * from "./EntityCollectionView/EntityCollectionViewActions";
|
|
|
19
19
|
export * from "./EntityCollectionView/useSelectionController";
|
|
20
20
|
|
|
21
21
|
export * from "./PropertyConfigBadge";
|
|
22
|
+
export * from "./PropertyIdCopyTooltip";
|
|
22
23
|
|
|
23
24
|
export * from "./EntityCollectionTable";
|
|
24
25
|
export * from "./NotFoundPage";
|
|
@@ -29,7 +30,7 @@ export * from "./DeleteConfirmationDialog";
|
|
|
29
30
|
|
|
30
31
|
export * from "./FireCMSLogo";
|
|
31
32
|
|
|
32
|
-
export * from "
|
|
33
|
+
export * from "../core/DefaultAppBar";
|
|
33
34
|
|
|
34
35
|
export * from "./ArrayContainer";
|
|
35
36
|
export * from "./ReferenceWidget";
|
|
@@ -18,14 +18,14 @@ export const DialogsProvider: React.FC<PropsWithChildren<{}>> = ({ children }) =
|
|
|
18
18
|
if (dialogEntries.length === 0)
|
|
19
19
|
return;
|
|
20
20
|
|
|
21
|
-
const updatedPanels = [...
|
|
21
|
+
const updatedPanels = [...dialogEntriesRef.current.slice(0, -1)];
|
|
22
22
|
updateDialogEntries(updatedPanels);
|
|
23
23
|
|
|
24
24
|
}, [dialogEntries]);
|
|
25
25
|
|
|
26
26
|
const open = useCallback((dialogEntry: DialogControllerEntryProps) => {
|
|
27
27
|
|
|
28
|
-
const updatedPanels = [...
|
|
28
|
+
const updatedPanels = [...dialogEntriesRef.current, dialogEntry];
|
|
29
29
|
updateDialogEntries(updatedPanels);
|
|
30
30
|
|
|
31
31
|
return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { Link as ReactLink } from "react-router-dom";
|
|
3
|
+
import { Link as ReactLink, useNavigate } from "react-router-dom";
|
|
4
4
|
import { ErrorBoundary, FireCMSLogo } from "../components";
|
|
5
5
|
import {
|
|
6
6
|
Avatar,
|
|
@@ -16,8 +16,9 @@ import {
|
|
|
16
16
|
} from "@firecms/ui";
|
|
17
17
|
import { useAuthController, useLargeLayout, useModeController, useNavigationController } from "../hooks";
|
|
18
18
|
import { User } from "../types";
|
|
19
|
+
import { useApp } from "../app/useApp";
|
|
19
20
|
|
|
20
|
-
export type
|
|
21
|
+
export type DefaultAppBarProps<ADDITIONAL_PROPS = object> = {
|
|
21
22
|
|
|
22
23
|
title?: React.ReactNode;
|
|
23
24
|
/**
|
|
@@ -29,12 +30,8 @@ export type FireCMSAppBarProps<ADDITIONAL_PROPS = object> = {
|
|
|
29
30
|
|
|
30
31
|
dropDownActions?: React.ReactNode;
|
|
31
32
|
|
|
32
|
-
includeDrawer?: boolean;
|
|
33
|
-
|
|
34
33
|
includeModeToggle?: boolean;
|
|
35
34
|
|
|
36
|
-
drawerOpen: boolean;
|
|
37
|
-
|
|
38
35
|
className?: string;
|
|
39
36
|
|
|
40
37
|
style?: React.CSSProperties;
|
|
@@ -48,24 +45,24 @@ export type FireCMSAppBarProps<ADDITIONAL_PROPS = object> = {
|
|
|
48
45
|
* This component renders the main app bar of FireCMS.
|
|
49
46
|
* You will likely not need to use this component directly.
|
|
50
47
|
*
|
|
51
|
-
|
|
52
|
-
* @param toolbarExtraWidget
|
|
53
|
-
* @param drawerOpen
|
|
54
|
-
* @constructor
|
|
48
|
+
|
|
55
49
|
*/
|
|
56
|
-
export const
|
|
50
|
+
export const DefaultAppBar = function DefaultAppBar({
|
|
57
51
|
title,
|
|
58
52
|
endAdornment,
|
|
59
53
|
startAdornment,
|
|
60
|
-
drawerOpen,
|
|
61
54
|
dropDownActions,
|
|
62
|
-
includeDrawer,
|
|
63
55
|
includeModeToggle = true,
|
|
64
56
|
className,
|
|
65
57
|
style,
|
|
66
|
-
logo,
|
|
67
58
|
user: userProp
|
|
68
|
-
}:
|
|
59
|
+
}: DefaultAppBarProps) {
|
|
60
|
+
|
|
61
|
+
const {
|
|
62
|
+
hasDrawer,
|
|
63
|
+
drawerOpen,
|
|
64
|
+
logo
|
|
65
|
+
} = useApp();
|
|
69
66
|
const navigation = useNavigationController();
|
|
70
67
|
|
|
71
68
|
const authController = useAuthController();
|
|
@@ -74,6 +71,8 @@ export const FireCMSAppBar = function FireCMSAppBar({
|
|
|
74
71
|
toggleMode
|
|
75
72
|
} = useModeController();
|
|
76
73
|
|
|
74
|
+
const navigate = useNavigate();
|
|
75
|
+
|
|
77
76
|
const largeLayout = useLargeLayout();
|
|
78
77
|
|
|
79
78
|
const user = userProp ?? authController.user;
|
|
@@ -96,20 +95,15 @@ export const FireCMSAppBar = function FireCMSAppBar({
|
|
|
96
95
|
return (
|
|
97
96
|
<div
|
|
98
97
|
style={style}
|
|
99
|
-
className={cls("
|
|
98
|
+
className={cls("w-full h-16 transition-all ease-in duration-75 fixed",
|
|
100
99
|
{
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"h-16": true,
|
|
100
|
+
"pl-[17rem]": drawerOpen && largeLayout,
|
|
101
|
+
"pl-20": hasDrawer && !(drawerOpen && largeLayout),
|
|
104
102
|
"z-10": largeLayout,
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"w-full": !includeDrawer,
|
|
109
|
-
"w-[calc(100%-64px)]": includeDrawer && !(drawerOpen && largeLayout),
|
|
110
|
-
"w-[calc(100%-17rem)]": includeDrawer && (drawerOpen && largeLayout),
|
|
103
|
+
// "w-full": !hasDrawer,
|
|
104
|
+
// "w-[calc(100%-64px)]": hasDrawer && !(drawerOpen && largeLayout),
|
|
105
|
+
// "w-[calc(100%-17rem)]": hasDrawer && (drawerOpen && largeLayout),
|
|
111
106
|
"duration-150": drawerOpen && largeLayout,
|
|
112
|
-
fixed: true
|
|
113
107
|
},
|
|
114
108
|
className)}>
|
|
115
109
|
|
|
@@ -121,16 +115,16 @@ export const FireCMSAppBar = function FireCMSAppBar({
|
|
|
121
115
|
to={navigation?.basePath ?? "/"}
|
|
122
116
|
>
|
|
123
117
|
<div className={"flex flex-row gap-4"}>
|
|
124
|
-
{!
|
|
118
|
+
{!hasDrawer && (logo
|
|
125
119
|
? <img src={logo}
|
|
126
120
|
alt="Logo"
|
|
127
|
-
className={cls("w-[32px] h-[32px]")}/>
|
|
121
|
+
className={cls("w-[32px] h-[32px] object-contain")}/>
|
|
128
122
|
: <FireCMSLogo width={"32px"} height={"32px"}/>)}
|
|
129
123
|
|
|
130
124
|
{typeof title === "string"
|
|
131
125
|
? <Typography variant="subtitle1"
|
|
132
126
|
noWrap
|
|
133
|
-
className={"ml-2
|
|
127
|
+
className={cls("transition-all", drawerOpen ? "ml-2" : "")}>
|
|
134
128
|
{title}
|
|
135
129
|
</Typography>
|
|
136
130
|
: title}
|
|
@@ -169,7 +163,11 @@ export const FireCMSAppBar = function FireCMSAppBar({
|
|
|
169
163
|
|
|
170
164
|
{dropDownActions}
|
|
171
165
|
|
|
172
|
-
{!dropDownActions && <MenuItem onClick={
|
|
166
|
+
{!dropDownActions && <MenuItem onClick={async () => {
|
|
167
|
+
await authController.signOut();
|
|
168
|
+
// replace current route with home
|
|
169
|
+
navigate("/");
|
|
170
|
+
}}>
|
|
173
171
|
<LogoutIcon/>
|
|
174
172
|
Log Out
|
|
175
173
|
</MenuItem>}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import React, { useCallback } from "react";
|
|
2
|
+
|
|
3
|
+
import { useLargeLayout, useNavigationController } from "../hooks";
|
|
4
|
+
|
|
5
|
+
import { Link, useNavigate } from "react-router-dom";
|
|
6
|
+
import { CMSAnalyticsEvent, TopNavigationEntry, TopNavigationResult } from "../types";
|
|
7
|
+
import { IconForView } from "../util";
|
|
8
|
+
import { cls, IconButton, Menu, MenuItem, MoreVertIcon, Tooltip, Typography } from "@firecms/ui";
|
|
9
|
+
import { useAnalyticsController } from "../hooks/useAnalyticsController";
|
|
10
|
+
import { DrawerNavigationItem } from "./DrawerNavigationItem";
|
|
11
|
+
import { FireCMSLogo } from "../components";
|
|
12
|
+
import { useApp } from "../app/useApp";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Default drawer used in the CMS
|
|
16
|
+
* @group Core
|
|
17
|
+
*/
|
|
18
|
+
export function DefaultDrawer({
|
|
19
|
+
className,
|
|
20
|
+
style,
|
|
21
|
+
}: {
|
|
22
|
+
className?: string
|
|
23
|
+
style?: React.CSSProperties,
|
|
24
|
+
}) {
|
|
25
|
+
|
|
26
|
+
const {
|
|
27
|
+
drawerHovered,
|
|
28
|
+
drawerOpen,
|
|
29
|
+
closeDrawer,
|
|
30
|
+
logo
|
|
31
|
+
} = useApp();
|
|
32
|
+
|
|
33
|
+
const [adminMenuOpen, setAdminMenuOpen] = React.useState(false);
|
|
34
|
+
|
|
35
|
+
const analyticsController = useAnalyticsController();
|
|
36
|
+
const navigation = useNavigationController();
|
|
37
|
+
|
|
38
|
+
const tooltipsOpen = drawerHovered && !drawerOpen && !adminMenuOpen;
|
|
39
|
+
const largeLayout = useLargeLayout();
|
|
40
|
+
const navigate = useNavigate();
|
|
41
|
+
|
|
42
|
+
if (!navigation.topLevelNavigation)
|
|
43
|
+
throw Error("Navigation not ready in Drawer");
|
|
44
|
+
|
|
45
|
+
const {
|
|
46
|
+
navigationEntries,
|
|
47
|
+
groups
|
|
48
|
+
}: TopNavigationResult = navigation.topLevelNavigation;
|
|
49
|
+
|
|
50
|
+
const adminViews = navigationEntries.filter(e => e.type === "admin") ?? [];
|
|
51
|
+
const groupsWithoutAdmin = groups.filter(g => g !== "Admin");
|
|
52
|
+
|
|
53
|
+
const buildGroupHeader = useCallback((group?: string) => {
|
|
54
|
+
if (!drawerOpen) return <div className="w-full"/>;
|
|
55
|
+
return <div
|
|
56
|
+
className="pl-6 pr-8 py-4 flex flex-row items-center">
|
|
57
|
+
<Typography variant={"caption"}
|
|
58
|
+
color={"secondary"}
|
|
59
|
+
className="font-medium flex-grow line-clamp-1">
|
|
60
|
+
{group ? group.toUpperCase() : "Views".toUpperCase()}
|
|
61
|
+
</Typography>
|
|
62
|
+
|
|
63
|
+
</div>;
|
|
64
|
+
}, [drawerOpen]);
|
|
65
|
+
|
|
66
|
+
const onClick = (view: TopNavigationEntry) => {
|
|
67
|
+
const eventName: CMSAnalyticsEvent = view.type === "collection"
|
|
68
|
+
? "drawer_navigate_to_collection"
|
|
69
|
+
: (view.type === "view" ? "drawer_navigate_to_view" : "unmapped_event");
|
|
70
|
+
analyticsController.onAnalyticsEvent?.(eventName, { url: view.url });
|
|
71
|
+
if (!largeLayout)
|
|
72
|
+
closeDrawer();
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<>
|
|
77
|
+
<div className={cls("flex flex-col h-full relative flex-grow w-full", className)} style={style}>
|
|
78
|
+
|
|
79
|
+
<DrawerLogo logo={logo}/>
|
|
80
|
+
|
|
81
|
+
<div className={"mt-4 flex-grow overflow-scroll no-scrollbar"}
|
|
82
|
+
style={{
|
|
83
|
+
maskImage: "linear-gradient(to bottom, transparent 0, black 20px, black calc(100% - 20px), transparent 100%)",
|
|
84
|
+
}}>
|
|
85
|
+
|
|
86
|
+
{groupsWithoutAdmin.map((group) => (
|
|
87
|
+
<div
|
|
88
|
+
className={"bg-gray-50 dark:bg-gray-800 dark:bg-opacity-30 my-4 rounded-lg ml-4"}
|
|
89
|
+
key={`drawer_group_${group}`}>
|
|
90
|
+
{buildGroupHeader(group)}
|
|
91
|
+
{Object.values(navigationEntries)
|
|
92
|
+
.filter(e => e.group === group)
|
|
93
|
+
.map((view, index) =>
|
|
94
|
+
<DrawerNavigationItem
|
|
95
|
+
key={`navigation_${index}`}
|
|
96
|
+
icon={<IconForView collectionOrView={view.collection ?? view.view} size={"small"}/>}
|
|
97
|
+
tooltipsOpen={tooltipsOpen}
|
|
98
|
+
adminMenuOpen={adminMenuOpen}
|
|
99
|
+
drawerOpen={drawerOpen}
|
|
100
|
+
onClick={() => onClick(view)}
|
|
101
|
+
url={view.url}
|
|
102
|
+
name={view.name}/>)}
|
|
103
|
+
</div>
|
|
104
|
+
))}
|
|
105
|
+
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
{adminViews.length > 0 && <Menu
|
|
109
|
+
side={"right"}
|
|
110
|
+
open={adminMenuOpen}
|
|
111
|
+
onOpenChange={setAdminMenuOpen}
|
|
112
|
+
trigger={
|
|
113
|
+
<IconButton
|
|
114
|
+
shape={"square"}
|
|
115
|
+
className={"m-4 text-gray-900 dark:text-white w-fit"}>
|
|
116
|
+
<Tooltip title={"Admin"}
|
|
117
|
+
open={tooltipsOpen}
|
|
118
|
+
side={"right"} sideOffset={28}>
|
|
119
|
+
<MoreVertIcon/>
|
|
120
|
+
</Tooltip>
|
|
121
|
+
{drawerOpen && <div
|
|
122
|
+
className={cls(
|
|
123
|
+
drawerOpen ? "opacity-100" : "opacity-0 hidden",
|
|
124
|
+
"mx-4 font-inherit text-inherit"
|
|
125
|
+
)}>
|
|
126
|
+
ADMIN
|
|
127
|
+
</div>}
|
|
128
|
+
</IconButton>}
|
|
129
|
+
>
|
|
130
|
+
{adminViews.map((entry, index) =>
|
|
131
|
+
<MenuItem
|
|
132
|
+
onClick={(event) => {
|
|
133
|
+
event.preventDefault();
|
|
134
|
+
navigate(entry.path);
|
|
135
|
+
}}
|
|
136
|
+
key={`navigation_${index}`}>
|
|
137
|
+
{<IconForView collectionOrView={entry.view}/>}
|
|
138
|
+
{entry.name}
|
|
139
|
+
</MenuItem>)}
|
|
140
|
+
|
|
141
|
+
</Menu>}
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
</>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* This is the logo displayed in the drawer
|
|
150
|
+
* It expands when the drawer is open.
|
|
151
|
+
*
|
|
152
|
+
* @param logo
|
|
153
|
+
|
|
154
|
+
*/
|
|
155
|
+
export function DrawerLogo({ logo }: {
|
|
156
|
+
logo?: string;
|
|
157
|
+
}) {
|
|
158
|
+
|
|
159
|
+
const navigation = useNavigationController();
|
|
160
|
+
const { drawerOpen } = useApp();
|
|
161
|
+
return <div
|
|
162
|
+
style={{
|
|
163
|
+
transition: "padding 100ms cubic-bezier(0.4, 0, 0.6, 1) 0ms",
|
|
164
|
+
padding: drawerOpen ? "32px 144px 0px 24px" : "72px 12px 0px 12px"
|
|
165
|
+
}}
|
|
166
|
+
className={cls("cursor-pointer ml-4")}>
|
|
167
|
+
|
|
168
|
+
<Tooltip title={"Home"}
|
|
169
|
+
sideOffset={20}
|
|
170
|
+
side="right">
|
|
171
|
+
<Link
|
|
172
|
+
to={navigation.basePath}>
|
|
173
|
+
{logo
|
|
174
|
+
? <img src={logo}
|
|
175
|
+
alt="Logo"
|
|
176
|
+
className={cls("max-w-full max-h-full",
|
|
177
|
+
drawerOpen ?? "w-[112px] h-[112px]")}/>
|
|
178
|
+
: <FireCMSLogo/>}
|
|
179
|
+
|
|
180
|
+
</Link>
|
|
181
|
+
</Tooltip>
|
|
182
|
+
</div>;
|
|
183
|
+
}
|