@firecms/core 3.1.0-canary.1df3b2c → 3.1.0-canary.501d471
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/internal/popup_field/useDraggable.d.ts +2 -2
- package/dist/components/EntityCollectionView/CollectionDataErrorBanner.d.ts +4 -0
- package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +5 -10
- package/dist/components/ErrorBoundary.d.ts +4 -2
- package/dist/components/HomePage/DefaultHomePage.d.ts +0 -1
- package/dist/components/LanguageToggle.d.ts +1 -0
- package/dist/components/UnsavedChangesDialog.d.ts +1 -0
- package/dist/components/VirtualTable/VirtualTableHeader.d.ts +2 -1
- package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +6 -1
- package/dist/components/VirtualTable/types.d.ts +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/core/DrawerNavigationGroup.d.ts +2 -2
- package/dist/editor/components/SlashCommandMenu.d.ts +6 -0
- package/dist/editor/components/editor-bubble-item.d.ts +8 -0
- package/dist/editor/components/editor-bubble.d.ts +8 -0
- package/dist/editor/components/image-bubble.d.ts +5 -0
- package/dist/editor/components/index.d.ts +16 -0
- package/dist/editor/components/table-bubble.d.ts +5 -0
- package/dist/editor/editor.d.ts +30 -0
- package/dist/editor/extensions/HighlightDecorationExtension.d.ts +24 -0
- package/dist/editor/extensions/Image/index.d.ts +6 -0
- package/dist/editor/extensions/Image.d.ts +6 -0
- package/dist/editor/extensions/TextLoadingDecorationExtension.d.ts +16 -0
- package/dist/editor/extensions/clipboard.d.ts +7 -0
- package/dist/editor/extensions/custom-keymap.d.ts +1 -0
- package/dist/editor/extensions/drag-and-drop.d.ts +9 -0
- package/dist/editor/hooks/useProseMirror.d.ts +13 -0
- package/dist/editor/hooks/useProseMirrorContext.d.ts +9 -0
- package/dist/editor/index.d.ts +2 -0
- package/dist/editor/markdown.d.ts +5 -0
- package/dist/editor/nodeViews/ImageComponent.d.ts +3 -0
- package/dist/editor/nodeViews/ReactNodeView.d.ts +29 -0
- package/dist/editor/nodeViews/TaskItemComponent.d.ts +3 -0
- package/dist/editor/nodeViews/index.d.ts +6 -0
- package/dist/editor/plugins/index.d.ts +2 -0
- package/dist/editor/plugins/inputrules.d.ts +6 -0
- package/dist/editor/plugins/placeholderPlugin.d.ts +3 -0
- package/dist/editor/plugins/slashCommandPlugin.d.ts +12 -0
- package/dist/editor/schema.d.ts +2 -0
- package/dist/editor/selectors/ai-selector.d.ts +0 -0
- package/dist/editor/selectors/color-selector.d.ts +10 -0
- package/dist/editor/selectors/link-selector.d.ts +8 -0
- package/dist/editor/selectors/node-selector.d.ts +15 -0
- package/dist/editor/selectors/text-buttons.d.ts +1 -0
- package/dist/editor/types.d.ts +5 -0
- package/dist/editor/useProseMirror.d.ts +16 -0
- package/dist/editor/utils/prosemirror-utils.d.ts +6 -0
- package/dist/editor/utils/remove_classes.d.ts +1 -0
- package/dist/editor/utils/useDebouncedCallback.d.ts +1 -0
- package/dist/form/components/ErrorFocus.d.ts +1 -1
- package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useBuildNavigationController.d.ts +0 -1
- package/dist/hooks/useCollapsedGroups.d.ts +3 -3
- package/dist/hooks/useTranslation.d.ts +17 -0
- package/dist/i18n/FireCMSi18nProvider.d.ts +33 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.es.js +29682 -18363
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +29681 -18382
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useRestoreScroll.d.ts +1 -1
- package/dist/locales/de.d.ts +2 -0
- package/dist/locales/en.d.ts +10 -0
- package/dist/locales/es.d.ts +10 -0
- package/dist/locales/fr.d.ts +2 -0
- package/dist/locales/hi.d.ts +2 -0
- package/dist/locales/it.d.ts +2 -0
- package/dist/locales/pt.d.ts +7 -0
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/collections.d.ts +46 -0
- package/dist/types/customization_controller.d.ts +2 -1
- package/dist/types/firecms.d.ts +2 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/navigation.d.ts +2 -2
- package/dist/types/plugins.d.ts +23 -0
- package/dist/types/properties.d.ts +9 -8
- package/dist/types/storage.d.ts +1 -0
- package/dist/types/translations.d.ts +669 -0
- package/dist/util/entities.d.ts +1 -1
- package/dist/util/index.d.ts +1 -0
- package/dist/util/lazy_eager.d.ts +7 -0
- package/dist/util/objects.d.ts +1 -0
- package/dist/util/resolutions.d.ts +2 -2
- package/dist/util/useStorageUploadController.d.ts +10 -1
- package/package.json +49 -13
- package/src/app/Scaffold.tsx +7 -5
- package/src/components/AIIcon.tsx +3 -1
- package/src/components/ArrayContainer.tsx +6 -4
- package/src/components/ClearFilterSortButton.tsx +6 -3
- package/src/components/ConfirmationDialog.tsx +4 -2
- package/src/components/DeleteEntityDialog.tsx +10 -7
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +9 -3
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +6 -3
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +3 -1
- package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +3 -2
- package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +11 -11
- package/src/components/EntityCollectionView/BoardSortableList.tsx +3 -1
- package/src/components/EntityCollectionView/CollectionDataErrorBanner.tsx +43 -0
- package/src/components/EntityCollectionView/EntityBoardCard.tsx +1 -1
- package/src/components/EntityCollectionView/EntityCard.tsx +4 -0
- package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +39 -46
- package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +17 -25
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +71 -31
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +4 -3
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +4 -2
- package/src/components/EntityCollectionView/FiltersDialog.tsx +8 -5
- package/src/components/EntityCollectionView/ViewModeToggle.tsx +37 -37
- package/src/components/EntityJsonPreview.tsx +2 -1
- package/src/components/EntityView.tsx +3 -2
- package/src/components/ErrorBoundary.tsx +27 -15
- package/src/components/HomePage/DefaultHomePage.tsx +19 -13
- package/src/components/HomePage/HomePageDnD.tsx +3 -1
- package/src/components/HomePage/NavigationGroup.tsx +3 -1
- package/src/components/HomePage/RenameGroupDialog.tsx +15 -13
- package/src/components/LanguageToggle.tsx +66 -0
- package/src/components/NotFoundPage.tsx +5 -3
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +9 -7
- package/src/components/ReferenceWidget.tsx +3 -2
- package/src/components/SearchIconsView.tsx +3 -1
- package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +11 -0
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +15 -2
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +11 -0
- package/src/components/UnsavedChangesDialog.tsx +6 -4
- package/src/components/VirtualTable/VirtualTable.performance.test.tsx +1 -0
- package/src/components/VirtualTable/VirtualTable.tsx +121 -116
- package/src/components/VirtualTable/VirtualTableHeader.tsx +59 -56
- package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +9 -4
- package/src/components/VirtualTable/VirtualTableProps.tsx +7 -1
- package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +3 -3
- package/src/components/VirtualTable/types.tsx +1 -0
- package/src/components/common/default_entity_actions.tsx +4 -0
- package/src/components/common/useDataSourceTableController.tsx +12 -4
- package/src/components/index.tsx +1 -0
- package/src/core/DefaultAppBar.tsx +15 -11
- package/src/core/DefaultDrawer.tsx +8 -2
- package/src/core/DrawerNavigationGroup.tsx +5 -3
- package/src/core/EntityEditView.tsx +54 -8
- package/src/core/EntityEditViewFormActions.tsx +24 -17
- package/src/core/EntitySidePanel.tsx +34 -30
- package/src/core/FireCMS.tsx +33 -6
- package/src/core/field_configs.tsx +18 -11
- package/src/editor/components/SlashCommandMenu.tsx +516 -0
- package/src/editor/components/editor-bubble-item.tsx +32 -0
- package/src/editor/components/editor-bubble.tsx +118 -0
- package/src/editor/components/image-bubble.tsx +156 -0
- package/src/editor/components/index.ts +14 -0
- package/src/editor/components/table-bubble.tsx +165 -0
- package/src/editor/editor.tsx +455 -0
- package/src/editor/extensions/HighlightDecorationExtension.ts +114 -0
- package/src/editor/extensions/Image/index.ts +133 -0
- package/src/editor/extensions/Image.ts +159 -0
- package/src/editor/extensions/TextLoadingDecorationExtension.tsx +107 -0
- package/src/editor/extensions/clipboard.ts +72 -0
- package/src/editor/extensions/custom-keymap.ts +24 -0
- package/src/editor/extensions/drag-and-drop.tsx +480 -0
- package/src/editor/hooks/useProseMirror.ts +124 -0
- package/src/editor/hooks/useProseMirrorContext.ts +15 -0
- package/src/editor/index.ts +2 -0
- package/src/editor/markdown.ts +172 -0
- package/src/editor/nodeViews/ImageComponent.tsx +20 -0
- package/src/editor/nodeViews/ReactNodeView.tsx +89 -0
- package/src/editor/nodeViews/TaskItemComponent.tsx +29 -0
- package/src/editor/nodeViews/index.ts +35 -0
- package/src/editor/plugins/index.ts +58 -0
- package/src/editor/plugins/inputrules.ts +82 -0
- package/src/editor/plugins/placeholderPlugin.ts +55 -0
- package/src/editor/plugins/slashCommandPlugin.ts +61 -0
- package/src/editor/schema.ts +240 -0
- package/src/editor/selectors/ai-selector.tsx +111 -0
- package/src/editor/selectors/color-selector.tsx +200 -0
- package/src/editor/selectors/link-selector.tsx +118 -0
- package/src/editor/selectors/node-selector.tsx +157 -0
- package/src/editor/selectors/text-buttons.tsx +86 -0
- package/src/editor/types.ts +6 -0
- package/src/editor/useProseMirror.ts +126 -0
- package/src/editor/utils/prosemirror-utils.ts +108 -0
- package/src/editor/utils/remove_classes.ts +17 -0
- package/src/editor/utils/useDebouncedCallback.ts +25 -0
- package/src/form/EntityForm.tsx +149 -67
- package/src/form/EntityFormActions.tsx +19 -12
- package/src/form/PropertyFieldBinding.tsx +10 -8
- package/src/form/components/ErrorFocus.tsx +3 -3
- package/src/form/components/LocalChangesMenu.tsx +13 -13
- package/src/form/components/StorageItemPreview.tsx +3 -2
- package/src/form/components/StorageUploadProgress.tsx +18 -3
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +18 -5
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +22 -9
- package/src/form/field_bindings/BlockFieldBinding.tsx +26 -9
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +46 -24
- package/src/form/field_bindings/MapFieldBinding.tsx +27 -11
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +74 -37
- package/src/form/field_bindings/MultiSelectFieldBinding.tsx +15 -1
- package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +25 -11
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +25 -11
- package/src/form/field_bindings/RepeatFieldBinding.tsx +21 -6
- package/src/form/field_bindings/SelectFieldBinding.tsx +7 -5
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +110 -92
- package/src/form/field_bindings/SwitchFieldBinding.tsx +31 -14
- package/src/form/field_bindings/TextFieldBinding.tsx +10 -7
- package/src/form/field_bindings/UserSelectFieldBinding.tsx +7 -5
- package/src/hooks/index.tsx +1 -0
- package/src/hooks/useBuildNavigationController.tsx +49 -22
- package/src/hooks/useCollapsedGroups.ts +7 -6
- package/src/hooks/useTranslation.ts +31 -0
- package/src/hooks/useValidateAuthenticator.tsx +1 -1
- package/src/i18n/FireCMSi18nProvider.tsx +160 -0
- package/src/index.ts +5 -0
- package/src/internal/useBuildDataSource.ts +1 -2
- package/src/internal/useBuildSideEntityController.tsx +22 -20
- package/src/locales/de.ts +718 -0
- package/src/locales/en.ts +730 -0
- package/src/locales/es.ts +730 -0
- package/src/locales/fr.ts +718 -0
- package/src/locales/hi.ts +718 -0
- package/src/locales/it.ts +718 -0
- package/src/locales/pt.ts +727 -0
- package/src/preview/PropertyPreview.tsx +4 -2
- package/src/preview/components/ReferencePreview.tsx +2 -1
- package/src/preview/components/UrlComponentPreview.tsx +4 -2
- package/src/preview/components/UserPreview.tsx +3 -1
- package/src/preview/property_previews/MapPropertyPreview.tsx +49 -27
- package/src/routes/FireCMSRoute.tsx +63 -54
- package/src/types/analytics.ts +10 -0
- package/src/types/collections.ts +49 -0
- package/src/types/customization_controller.tsx +2 -1
- package/src/types/firecms.tsx +2 -1
- package/src/types/index.ts +1 -0
- package/src/types/navigation.ts +2 -2
- package/src/types/plugins.tsx +26 -0
- package/src/types/properties.ts +12 -10
- package/src/types/storage.ts +2 -1
- package/src/types/translations.ts +752 -0
- package/src/util/entities.ts +1 -1
- package/src/util/index.ts +1 -0
- package/src/util/join_collections.ts +10 -8
- package/src/util/lazy_eager.tsx +33 -0
- package/src/util/objects.ts +15 -0
- package/src/util/previews.ts +2 -2
- package/src/util/property_utils.tsx +1 -1
- package/src/util/resolutions.ts +5 -3
- package/src/util/useStorageUploadController.tsx +23 -29
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from "../types";
|
|
12
12
|
|
|
13
13
|
import { resolveProperty } from "../util";
|
|
14
|
+
import { jsonStringifyReplacer } from "../util/objects";
|
|
14
15
|
|
|
15
16
|
import { PropertyPreviewProps } from "./PropertyPreviewProps";
|
|
16
17
|
import { useAuthController, useCustomizationController } from "../hooks";
|
|
@@ -186,6 +187,7 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
186
187
|
if (typeof value === "object") {
|
|
187
188
|
content =
|
|
188
189
|
<MapPropertyPreview {...props}
|
|
190
|
+
value={value as Record<string, CMSType>}
|
|
189
191
|
property={property as ResolvedMapProperty} />;
|
|
190
192
|
} else {
|
|
191
193
|
content = buildWrongValueType(propertyKey, property.dataType, value);
|
|
@@ -233,7 +235,7 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
233
235
|
content = buildWrongValueType(propertyKey, property.dataType, value);
|
|
234
236
|
}
|
|
235
237
|
} else {
|
|
236
|
-
content = JSON.stringify(value);
|
|
238
|
+
content = JSON.stringify(value, jsonStringifyReplacer);
|
|
237
239
|
}
|
|
238
240
|
|
|
239
241
|
return content === undefined || content === null || (Array.isArray(content) && content.length === 0)
|
|
@@ -245,6 +247,6 @@ function buildWrongValueType(name: string | undefined, dataType: string, value:
|
|
|
245
247
|
console.warn(`Unexpected value for property ${name}, of type ${dataType}`, value);
|
|
246
248
|
return (
|
|
247
249
|
<ErrorView title={"Unexpected value"}
|
|
248
|
-
error={`${JSON.stringify(value)}`} />
|
|
250
|
+
error={`${JSON.stringify(value, jsonStringifyReplacer)}`} />
|
|
249
251
|
);
|
|
250
252
|
}
|
|
@@ -6,6 +6,7 @@ import { PreviewSize } from "../PropertyPreviewProps";
|
|
|
6
6
|
import { Skeleton } from "@firecms/ui";
|
|
7
7
|
import { ErrorBoundary, ErrorView } from "../../components";
|
|
8
8
|
import { EntityPreview, EntityPreviewContainer } from "../../components/EntityPreview";
|
|
9
|
+
import { jsonStringifyReplacer } from "../../util/objects";
|
|
9
10
|
|
|
10
11
|
export type ReferencePreviewProps = {
|
|
11
12
|
disabled?: boolean;
|
|
@@ -29,7 +30,7 @@ export const ReferencePreview = function ReferencePreview(props: ReferencePrevie
|
|
|
29
30
|
onClick={props.onClick}
|
|
30
31
|
size={props.size ?? "medium"}>
|
|
31
32
|
<ErrorView error={"Unexpected value. Click to edit"}
|
|
32
|
-
tooltip={JSON.stringify(reference)}/>
|
|
33
|
+
tooltip={JSON.stringify(reference, jsonStringifyReplacer)}/>
|
|
33
34
|
</EntityPreviewContainer>;
|
|
34
35
|
}
|
|
35
36
|
return <ErrorBoundary>
|
|
@@ -6,6 +6,7 @@ import { PreviewType } from "../../types";
|
|
|
6
6
|
import { PreviewSize } from "../PropertyPreviewProps";
|
|
7
7
|
import { cls, DescriptionIcon, OpenInNewIcon, Tooltip, Typography } from "@firecms/ui";
|
|
8
8
|
import { EmptyValue } from "./EmptyValue";
|
|
9
|
+
import { useTranslation } from "../../hooks/useTranslation";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @group Preview components
|
|
@@ -27,6 +28,8 @@ export function UrlComponentPreview({
|
|
|
27
28
|
fill?: boolean
|
|
28
29
|
}): React.ReactElement {
|
|
29
30
|
|
|
31
|
+
const { t } = useTranslation();
|
|
32
|
+
|
|
30
33
|
if (!previewType) {
|
|
31
34
|
if (!url || !url.trim()) return <EmptyValue />;
|
|
32
35
|
return (
|
|
@@ -51,8 +54,7 @@ export function UrlComponentPreview({
|
|
|
51
54
|
return <audio controls
|
|
52
55
|
className={"max-w-100%"}
|
|
53
56
|
src={url}>
|
|
54
|
-
|
|
55
|
-
<code>audio</code> element.
|
|
57
|
+
{t("browser_does_not_support_audio")}
|
|
56
58
|
</audio>;
|
|
57
59
|
} else if (previewType === "video") {
|
|
58
60
|
return <VideoPreview size={size} src={url} interactive={interactive} />;
|
|
@@ -4,6 +4,7 @@ import { useInternalUserManagementController } from "../../hooks";
|
|
|
4
4
|
import { UserDisplay } from "../../components/UserDisplay";
|
|
5
5
|
import { EmptyValue } from "./EmptyValue";
|
|
6
6
|
import { Typography } from "@firecms/ui";
|
|
7
|
+
import { useTranslation } from "../../hooks/useTranslation";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Preview component for displaying user information.
|
|
@@ -13,6 +14,7 @@ import { Typography } from "@firecms/ui";
|
|
|
13
14
|
*/
|
|
14
15
|
export function UserPreview({ value }: PropertyPreviewProps<string>) {
|
|
15
16
|
const { getUser } = useInternalUserManagementController();
|
|
17
|
+
const { t } = useTranslation();
|
|
16
18
|
|
|
17
19
|
if (!value) {
|
|
18
20
|
return <EmptyValue/>;
|
|
@@ -20,7 +22,7 @@ export function UserPreview({ value }: PropertyPreviewProps<string>) {
|
|
|
20
22
|
|
|
21
23
|
const user = getUser(value);
|
|
22
24
|
if (!user) {
|
|
23
|
-
return <Typography variant={"caption"} color={"secondary"}>
|
|
25
|
+
return <Typography variant={"caption"} color={"secondary"}>{t("user_not_found", { value })}</Typography>;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
return <UserDisplay user={user}/>;
|
|
@@ -6,6 +6,7 @@ import { PropertyPreview } from "../PropertyPreview";
|
|
|
6
6
|
import { cls, defaultBorderMixin, Typography } from "@firecms/ui";
|
|
7
7
|
import { ErrorBoundary } from "../../components";
|
|
8
8
|
import { EmptyValue } from "../components/EmptyValue";
|
|
9
|
+
import { DatePreview } from "../components/DatePreview";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @group Preview components
|
|
@@ -111,37 +112,58 @@ export function KeyValuePreview({ value }: { value: any }) {
|
|
|
111
112
|
return <div
|
|
112
113
|
className="flex flex-col gap-1 w-full">
|
|
113
114
|
{
|
|
114
|
-
Object.entries(value).map(([key, childValue]: [string, any]) =>
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
Object.entries(value).map(([key, childValue]: [string, any]) => {
|
|
116
|
+
const isTimestampObj = childValue && typeof childValue === "object" && (
|
|
117
|
+
childValue instanceof Date ||
|
|
118
|
+
("_seconds" in childValue && "_nanoseconds" in childValue && typeof childValue._seconds === "number" && typeof childValue._nanoseconds === "number") ||
|
|
119
|
+
("seconds" in childValue && "nanoseconds" in childValue && typeof childValue.seconds === "number" && typeof childValue.nanoseconds === "number")
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
const isScalar = childValue && (typeof childValue !== "object" || isTimestampObj);
|
|
123
|
+
|
|
124
|
+
return (
|
|
118
125
|
<div
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
key={`table-cell-title-${key}-${key}`}
|
|
122
|
-
className="min-w-[140px] w-[25%] py-1">
|
|
123
|
-
<Typography variant={"caption"}
|
|
124
|
-
className={"font-semibold break-words"}
|
|
125
|
-
color={"secondary"}>
|
|
126
|
-
{key}
|
|
127
|
-
</Typography>
|
|
128
|
-
</div>
|
|
126
|
+
key={`map_preview_table_${key}}`}
|
|
127
|
+
className={cls(defaultBorderMixin, "last:border-b-0 border-b")}>
|
|
129
128
|
<div
|
|
130
|
-
className="flex-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
129
|
+
className={"flex flex-row pt-0.5 pb-0.5 gap-2"}>
|
|
130
|
+
<div
|
|
131
|
+
key={`table-cell-title-${key}-${key}`}
|
|
132
|
+
className="min-w-[140px] w-[25%] py-1">
|
|
133
|
+
<Typography variant={"caption"}
|
|
134
|
+
className={"font-semibold break-words"}
|
|
135
|
+
color={"secondary"}>
|
|
136
|
+
{key}
|
|
137
|
+
</Typography>
|
|
138
|
+
</div>
|
|
139
|
+
<div
|
|
140
|
+
className="flex-grow max-w-[75%]">
|
|
141
|
+
{isScalar && (isTimestampObj ? (
|
|
142
|
+
<ErrorBoundary>
|
|
143
|
+
<DatePreview date={
|
|
144
|
+
childValue instanceof Date ? childValue :
|
|
145
|
+
typeof childValue.toDate === "function" ? childValue.toDate() :
|
|
146
|
+
"_seconds" in childValue ? new Date(childValue._seconds * 1000 + childValue._nanoseconds / 1000000) :
|
|
147
|
+
new Date(childValue.seconds * 1000 + childValue.nanoseconds / 1000000)
|
|
148
|
+
} />
|
|
149
|
+
</ErrorBoundary>
|
|
150
|
+
) : (
|
|
151
|
+
<Typography>
|
|
152
|
+
<ErrorBoundary>
|
|
153
|
+
{childValue.toString()}
|
|
154
|
+
</ErrorBoundary>
|
|
155
|
+
</Typography>
|
|
156
|
+
))}
|
|
157
|
+
</div>
|
|
136
158
|
</div>
|
|
159
|
+
{typeof childValue === "object" && !isTimestampObj &&
|
|
160
|
+
<div className={cls(defaultBorderMixin, "border-l pl-4")}>
|
|
161
|
+
<KeyValuePreview value={childValue}/>
|
|
162
|
+
</div>
|
|
163
|
+
}
|
|
137
164
|
</div>
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
<KeyValuePreview value={childValue}/>
|
|
141
|
-
</div>
|
|
142
|
-
}
|
|
143
|
-
</div>
|
|
144
|
-
))
|
|
165
|
+
);
|
|
166
|
+
})
|
|
145
167
|
}
|
|
146
168
|
</div>;
|
|
147
169
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Blocker, useBlocker, useLocation } from "react-router";
|
|
2
|
-
import {
|
|
2
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
3
3
|
import { useNavigationController } from "../hooks";
|
|
4
|
-
import { useEffect, useRef, useState } from "react";
|
|
5
4
|
import { useNavigate } from "react-router-dom";
|
|
6
5
|
import {
|
|
7
6
|
getNavigationEntriesFromPath,
|
|
@@ -11,7 +10,11 @@ import {
|
|
|
11
10
|
} from "../util/navigation_from_path";
|
|
12
11
|
import { useBreadcrumbsController } from "../hooks/useBreadcrumbsController";
|
|
13
12
|
import { toArray } from "../util/arrays";
|
|
14
|
-
import {
|
|
13
|
+
import { NotFoundPage } from "../components";
|
|
14
|
+
import { lazyEager } from "../util/lazy_eager";
|
|
15
|
+
|
|
16
|
+
const EntityEditView = lazyEager<typeof import("../core/EntityEditView")["EntityEditView"]>(() => import("../core/EntityEditView"), "EntityEditView");
|
|
17
|
+
const EntityCollectionView = lazyEager<typeof import("../components/EntityCollectionView/EntityCollectionView")["EntityCollectionView"]>(() => import("../components/EntityCollectionView/EntityCollectionView"), "EntityCollectionView");
|
|
15
18
|
import { UnsavedChangesDialog } from "../components/UnsavedChangesDialog";
|
|
16
19
|
import { EntityCollection } from "../types";
|
|
17
20
|
|
|
@@ -88,15 +91,17 @@ export function FireCMSRoute() {
|
|
|
88
91
|
collection = navigation.getCollection(navigationEntries[0].path);
|
|
89
92
|
if (!collection)
|
|
90
93
|
return null;
|
|
91
|
-
return <
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
94
|
+
return <React.Suspense fallback={null}>
|
|
95
|
+
<EntityCollectionView
|
|
96
|
+
key={`collection_view_${collection.id ?? collection.path}`}
|
|
97
|
+
isSubCollection={false}
|
|
98
|
+
parentCollectionIds={[]}
|
|
99
|
+
fullPath={collection.path}
|
|
100
|
+
fullIdPath={collection.id}
|
|
101
|
+
updateUrl={true}
|
|
102
|
+
{...collection}
|
|
103
|
+
Actions={toArray(collection.Actions)} />
|
|
104
|
+
</React.Suspense>;
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
if (isSidePanel) {
|
|
@@ -109,15 +114,17 @@ export function FireCMSRoute() {
|
|
|
109
114
|
collection = navigation.getCollection(firstEntry.path);
|
|
110
115
|
if (!collection)
|
|
111
116
|
return null;
|
|
112
|
-
return <
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
return <React.Suspense fallback={null}>
|
|
118
|
+
<EntityCollectionView
|
|
119
|
+
key={`collection_view_${collection.id ?? collection.path}`}
|
|
120
|
+
fullIdPath={collection.id}
|
|
121
|
+
isSubCollection={false}
|
|
122
|
+
parentCollectionIds={[]}
|
|
123
|
+
fullPath={collection.path}
|
|
124
|
+
updateUrl={true}
|
|
125
|
+
{...collection}
|
|
126
|
+
Actions={toArray(collection.Actions)} />
|
|
127
|
+
</React.Suspense>;
|
|
121
128
|
}
|
|
122
129
|
}
|
|
123
130
|
|
|
@@ -215,39 +222,41 @@ function EntityFullScreenRoute({
|
|
|
215
222
|
const fullIdPath = isNew ? lastCollectionEntry!.path : lastEntityEntry!.path;
|
|
216
223
|
const collectionPath = navigation.resolveIdsFrom(fullIdPath);
|
|
217
224
|
return <>
|
|
218
|
-
<
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
225
|
+
<React.Suspense fallback={null}>
|
|
226
|
+
<EntityEditView
|
|
227
|
+
key={collection.id + "_" + (isNew ? "new" : (isCopy ? entityId + "_copy" : entityId))}
|
|
228
|
+
entityId={isNew ? undefined : entityId}
|
|
229
|
+
fullIdPath={fullIdPath}
|
|
230
|
+
collection={collection}
|
|
231
|
+
layout={"full_screen"}
|
|
232
|
+
path={collectionPath}
|
|
233
|
+
copy={isCopy}
|
|
234
|
+
selectedTab={selectedTab ?? undefined}
|
|
235
|
+
onValuesModified={(modified) => blocked.current = modified}
|
|
236
|
+
onSaved={(params) => {
|
|
237
|
+
const newSelectedTab = params.selectedTab;
|
|
238
|
+
const newEntityId = params.entityId;
|
|
239
|
+
if (newSelectedTab) {
|
|
240
|
+
navigate(`${basePath}/${newEntityId}/${newSelectedTab}`, { replace: true });
|
|
241
|
+
} else {
|
|
242
|
+
navigate(`${basePath}/${newEntityId}`, { replace: true });
|
|
243
|
+
}
|
|
244
|
+
}}
|
|
245
|
+
onTabChange={(params) => {
|
|
246
|
+
setSelectedTab(params.selectedTab);
|
|
247
|
+
if (isNew) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const newSelectedTab = params.selectedTab;
|
|
251
|
+
if (newSelectedTab) {
|
|
252
|
+
navigate(`${basePath}/${entityId}/${newSelectedTab}`, { replace: true });
|
|
253
|
+
} else {
|
|
254
|
+
navigate(`${basePath}/${entityId}`, { replace: true });
|
|
255
|
+
}
|
|
256
|
+
}}
|
|
257
|
+
parentCollectionIds={parentCollectionIds}
|
|
258
|
+
/>
|
|
259
|
+
</React.Suspense>
|
|
251
260
|
|
|
252
261
|
<UnsavedChangesDialog
|
|
253
262
|
open={blocker?.state === "blocked"}
|
package/src/types/analytics.ts
CHANGED
|
@@ -34,5 +34,15 @@ export type CMSAnalyticsEvent =
|
|
|
34
34
|
|
|
35
35
|
| "collection_inline_editing"
|
|
36
36
|
|
|
37
|
+
| "view_mode_changed"
|
|
38
|
+
|
|
39
|
+
| "kanban_card_moved"
|
|
40
|
+
| "kanban_column_reorder"
|
|
41
|
+
| "kanban_property_changed"
|
|
42
|
+
| "kanban_new_entity_in_column"
|
|
43
|
+
| "kanban_backfill_order"
|
|
44
|
+
|
|
45
|
+
| "card_view_entity_click"
|
|
46
|
+
|
|
37
47
|
| "unmapped_event"
|
|
38
48
|
;
|
package/src/types/collections.ts
CHANGED
|
@@ -163,6 +163,31 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
163
163
|
*/
|
|
164
164
|
subcollections?: EntityCollection<any, any>[];
|
|
165
165
|
|
|
166
|
+
/**
|
|
167
|
+
* You can group subcollections and custom views into dropdown menus
|
|
168
|
+
* in the entity view tabs. Views listed in a group will be removed
|
|
169
|
+
* from the top-level tabs and shown under a single dropdown instead.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```tsx
|
|
173
|
+
* const productsCollection = buildCollection({
|
|
174
|
+
* id: "products",
|
|
175
|
+
* path: "products",
|
|
176
|
+
* name: "Products",
|
|
177
|
+
* properties: { ... },
|
|
178
|
+
* subcollections: [localesCollection, reviewsCollection],
|
|
179
|
+
* entityViews: [sampleView],
|
|
180
|
+
* viewGroups: [
|
|
181
|
+
* {
|
|
182
|
+
* name: "Related data",
|
|
183
|
+
* views: ["locales", "reviews", "sample_view"]
|
|
184
|
+
* }
|
|
185
|
+
* ]
|
|
186
|
+
* });
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
viewGroups?: ViewGroup[];
|
|
190
|
+
|
|
166
191
|
/**
|
|
167
192
|
* This interface defines all the callbacks that can be used when an entity
|
|
168
193
|
* is being created, updated or deleted.
|
|
@@ -374,6 +399,15 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
374
399
|
*/
|
|
375
400
|
defaultViewMode?: ViewMode;
|
|
376
401
|
|
|
402
|
+
/**
|
|
403
|
+
* Which view modes are available for this collection.
|
|
404
|
+
* Possible values: "table", "cards", "kanban".
|
|
405
|
+
* Defaults to all three: ["table", "cards", "kanban"].
|
|
406
|
+
* Note: "kanban" will only be available if the collection has at least
|
|
407
|
+
* one string property with enumValues defined, regardless of this setting.
|
|
408
|
+
*/
|
|
409
|
+
enabledViews?: ViewMode[];
|
|
410
|
+
|
|
377
411
|
/**
|
|
378
412
|
* Configuration for Kanban board view mode.
|
|
379
413
|
* When set, the Kanban view mode becomes available.
|
|
@@ -404,6 +438,21 @@ export interface KanbanConfig<M extends Record<string, any> = any> {
|
|
|
404
438
|
columnProperty: Extract<keyof M, string>;
|
|
405
439
|
}
|
|
406
440
|
|
|
441
|
+
/**
|
|
442
|
+
* You can group subcollections and custom views into dropdown menus in the entity view tabs.
|
|
443
|
+
* @group Collections
|
|
444
|
+
*/
|
|
445
|
+
export interface ViewGroup {
|
|
446
|
+
/**
|
|
447
|
+
* Name of the group
|
|
448
|
+
*/
|
|
449
|
+
name: string;
|
|
450
|
+
/**
|
|
451
|
+
* Array of subcollection paths/ids or custom view keys
|
|
452
|
+
*/
|
|
453
|
+
views: string[];
|
|
454
|
+
}
|
|
455
|
+
|
|
407
456
|
/**
|
|
408
457
|
* View mode for displaying a collection.
|
|
409
458
|
* @group Collections
|
package/src/types/firecms.tsx
CHANGED
package/src/types/index.ts
CHANGED
package/src/types/navigation.ts
CHANGED
|
@@ -252,7 +252,7 @@ export interface NavigationEntry {
|
|
|
252
252
|
collection?: EntityCollection;
|
|
253
253
|
view?: CMSView;
|
|
254
254
|
description?: string;
|
|
255
|
-
group: string;
|
|
255
|
+
group: string | null;
|
|
256
256
|
}
|
|
257
257
|
|
|
258
258
|
export type NavigationResult = {
|
|
@@ -261,7 +261,7 @@ export type NavigationResult = {
|
|
|
261
261
|
|
|
262
262
|
navigationEntries: NavigationEntry[],
|
|
263
263
|
|
|
264
|
-
groups: string[],
|
|
264
|
+
groups: (string | null)[],
|
|
265
265
|
|
|
266
266
|
onNavigationEntriesUpdate: (entries: NavigationGroupMapping[]) => void;
|
|
267
267
|
};
|
package/src/types/plugins.tsx
CHANGED
|
@@ -28,6 +28,14 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
|
|
|
28
28
|
*/
|
|
29
29
|
loading?: boolean;
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Override any FireCMS UI string, or provide translations for additional
|
|
33
|
+
* locales, specific for this plugin.
|
|
34
|
+
* Keys can be existing `FireCMSTranslations` keys, or new keys if using
|
|
35
|
+
* module augmentation.
|
|
36
|
+
*/
|
|
37
|
+
i18n?: Record<string, Record<string, string>>;
|
|
38
|
+
|
|
31
39
|
/**
|
|
32
40
|
* You can use this prop to add higher order components to the CMS.
|
|
33
41
|
* The components will be added to the root of the CMS, so any component
|
|
@@ -112,6 +120,19 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
|
|
|
112
120
|
|
|
113
121
|
collectionView?: {
|
|
114
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Custom component to render when a collection loading error occurs.
|
|
125
|
+
* If provided, this replaces the default error view in all collection view modes
|
|
126
|
+
* (table, card, kanban).
|
|
127
|
+
* Return `null` from the component to fall back to the default error view.
|
|
128
|
+
*/
|
|
129
|
+
CollectionError?: React.ComponentType<{
|
|
130
|
+
path: string;
|
|
131
|
+
collection: EC;
|
|
132
|
+
parentCollectionIds?: string[];
|
|
133
|
+
error: Error;
|
|
134
|
+
}>;
|
|
135
|
+
|
|
115
136
|
/**
|
|
116
137
|
* Use this component to add custom actions to the entity collections
|
|
117
138
|
* toolbar.
|
|
@@ -229,6 +250,11 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
|
|
|
229
250
|
*/
|
|
230
251
|
ActionsTop?: React.ComponentType<PluginFormActionProps<any, EC>>;
|
|
231
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Add custom content above the entity title in the form view
|
|
255
|
+
*/
|
|
256
|
+
BeforeTitle?: React.ComponentType<PluginFormActionProps<any, EC>>;
|
|
257
|
+
|
|
232
258
|
fieldBuilder?: <T extends CMSType = CMSType>(props: PluginFieldBuilderParams<T, any, EC>) => React.ComponentType<FieldProps<T>> | null;
|
|
233
259
|
|
|
234
260
|
fieldBuilderEnabled?: <T extends CMSType = CMSType>(props: PluginFieldBuilderParams<T>) => boolean;
|
package/src/types/properties.ts
CHANGED
|
@@ -180,6 +180,17 @@ export interface BaseProperty<T extends CMSType, CustomProps = any> {
|
|
|
180
180
|
* @see https://jsonlogic.com/ for JSON Logic syntax
|
|
181
181
|
*/
|
|
182
182
|
conditions?: PropertyConditions;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Set this property to true to provide the UX to explicitly set the value to `null`.
|
|
186
|
+
* Defaults to `false`.
|
|
187
|
+
*/
|
|
188
|
+
nullable?: boolean;
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @deprecated Use `nullable` instead.
|
|
192
|
+
*/
|
|
193
|
+
clearable?: boolean;
|
|
183
194
|
}
|
|
184
195
|
|
|
185
196
|
/**
|
|
@@ -620,11 +631,6 @@ export interface NumberProperty extends BaseProperty<number> {
|
|
|
620
631
|
* Rules for validating this property
|
|
621
632
|
*/
|
|
622
633
|
validation?: NumberPropertyValidationSchema,
|
|
623
|
-
|
|
624
|
-
/**
|
|
625
|
-
* Add an icon to clear the value and set it to `null`. Defaults to `false`
|
|
626
|
-
*/
|
|
627
|
-
clearable?: boolean;
|
|
628
634
|
}
|
|
629
635
|
|
|
630
636
|
/**
|
|
@@ -735,11 +741,6 @@ export interface StringProperty extends BaseProperty<string> {
|
|
|
735
741
|
*/
|
|
736
742
|
validation?: StringPropertyValidationSchema;
|
|
737
743
|
|
|
738
|
-
/**
|
|
739
|
-
* Add an icon to clear the value and set it to `null`. Defaults to `false`
|
|
740
|
-
*/
|
|
741
|
-
clearable?: boolean;
|
|
742
|
-
|
|
743
744
|
/**
|
|
744
745
|
* You can use this property (a string) to behave as a reference to another
|
|
745
746
|
* collection. The stored value is the ID of the entity in the
|
|
@@ -1110,6 +1111,7 @@ export type StorageConfig = {
|
|
|
1110
1111
|
*/
|
|
1111
1112
|
imageResize?: ImageResize;
|
|
1112
1113
|
|
|
1114
|
+
|
|
1113
1115
|
/**
|
|
1114
1116
|
* Specific metadata set in your uploaded file.
|
|
1115
1117
|
* For the default Firebase implementation, the values passed here are of type
|