@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
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Typography, IconButton, RefreshIcon, Button, Tooltip } from "@firecms/ui";
|
|
3
|
+
import { useTranslation } from "../../hooks";
|
|
4
|
+
|
|
5
|
+
export function CollectionDataErrorBanner({ error, onRetry }: { error?: Error, onRetry?: () => void }) {
|
|
6
|
+
const { t } = useTranslation();
|
|
7
|
+
if (!error) return null;
|
|
8
|
+
|
|
9
|
+
const errorMessage = error.message || "";
|
|
10
|
+
// Only extract standard Firestore index errors using the standard matching pattern
|
|
11
|
+
const indexUrl = errorMessage.match(/https:\/\/console\.firebase\.google\.com[^\s]+/)?.[0];
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div className="flex w-full items-center gap-4 px-4 py-3 bg-red-50 dark:bg-red-900/20 border-b border-red-200 dark:border-red-800">
|
|
15
|
+
<Typography variant="body2" className="text-red-700 dark:text-red-300 flex-1 break-words">
|
|
16
|
+
<strong>{t("error")}:</strong>{" "}
|
|
17
|
+
{indexUrl
|
|
18
|
+
? t("error_firestore_index")
|
|
19
|
+
: errorMessage}
|
|
20
|
+
</Typography>
|
|
21
|
+
{onRetry && (
|
|
22
|
+
<Tooltip title={t("refresh_data")}>
|
|
23
|
+
<IconButton
|
|
24
|
+
size="small"
|
|
25
|
+
onClick={onRetry}
|
|
26
|
+
>
|
|
27
|
+
<RefreshIcon size="small" />
|
|
28
|
+
</IconButton>
|
|
29
|
+
</Tooltip>
|
|
30
|
+
)}
|
|
31
|
+
{indexUrl && (
|
|
32
|
+
<Button
|
|
33
|
+
size="small"
|
|
34
|
+
variant="outlined"
|
|
35
|
+
color="error"
|
|
36
|
+
onClick={() => window.open(indexUrl, "_blank")}
|
|
37
|
+
>
|
|
38
|
+
{t("create_index")}
|
|
39
|
+
</Button>
|
|
40
|
+
)}
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -149,7 +149,7 @@ function EntityBoardCardInner<M extends Record<string, any> = any>({
|
|
|
149
149
|
{/* Content */}
|
|
150
150
|
<div className="flex-1 min-w-0">
|
|
151
151
|
{/* Title */}
|
|
152
|
-
<div className="
|
|
152
|
+
<div className="line-clamp-2 text-sm font-medium">
|
|
153
153
|
{titleProperty && titleValue ? (
|
|
154
154
|
<PropertyPreview
|
|
155
155
|
propertyKey={titlePropertyKey as string}
|
|
@@ -111,6 +111,10 @@ export function EntityCard<M extends Record<string, any> = any>({
|
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
113
|
if (onClick) {
|
|
114
|
+
analyticsController.onAnalyticsEvent?.("card_view_entity_click", {
|
|
115
|
+
path: entity.path,
|
|
116
|
+
entityId: entity.id
|
|
117
|
+
});
|
|
114
118
|
onClick(entity);
|
|
115
119
|
}
|
|
116
120
|
};
|
|
@@ -20,9 +20,6 @@ import {
|
|
|
20
20
|
DialogActions,
|
|
21
21
|
DialogContent,
|
|
22
22
|
getColorSchemeForSeed,
|
|
23
|
-
IconButton,
|
|
24
|
-
RefreshIcon,
|
|
25
|
-
Tooltip,
|
|
26
23
|
Typography
|
|
27
24
|
} from "@firecms/ui";
|
|
28
25
|
import { getPropertyInPath, resolveCollection, resolveEnumValues } from "../../util";
|
|
@@ -34,9 +31,12 @@ import {
|
|
|
34
31
|
useFireCMSContext,
|
|
35
32
|
useSideEntityController
|
|
36
33
|
} from "../../hooks";
|
|
34
|
+
import { useAnalyticsController } from "../../hooks/useAnalyticsController";
|
|
37
35
|
import { SaveEntityProps } from "../../types/datasource";
|
|
38
36
|
import { setIn } from "@firecms/formex";
|
|
39
37
|
import { useBoardDataController } from "./useBoardDataController";
|
|
38
|
+
import { CollectionDataErrorBanner } from "./CollectionDataErrorBanner";
|
|
39
|
+
import { useTranslation } from "../../hooks/useTranslation";
|
|
40
40
|
|
|
41
41
|
export type EntityCollectionBoardViewProps<M extends Record<string, any> = any> = {
|
|
42
42
|
collection: EntityCollection<M>;
|
|
@@ -74,7 +74,9 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
74
74
|
const context = useFireCMSContext();
|
|
75
75
|
const dataSource = useDataSource(collection);
|
|
76
76
|
const sideEntityController = useSideEntityController();
|
|
77
|
+
const analyticsController = useAnalyticsController();
|
|
77
78
|
const plugins = customizationController.plugins ?? [];
|
|
79
|
+
const { t } = useTranslation();
|
|
78
80
|
|
|
79
81
|
// State for backfill dialog
|
|
80
82
|
const [showBackfillDialog, setShowBackfillDialog] = useState(false);
|
|
@@ -222,6 +224,10 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
222
224
|
}, [plugins]);
|
|
223
225
|
|
|
224
226
|
const handleColumnReorder = useCallback((newColumns: string[]) => {
|
|
227
|
+
analyticsController.onAnalyticsEvent?.("kanban_column_reorder", {
|
|
228
|
+
path: fullPath,
|
|
229
|
+
columnProperty
|
|
230
|
+
});
|
|
225
231
|
setHasUserReordered(true);
|
|
226
232
|
setLocalColumnsOrder(newColumns);
|
|
227
233
|
plugins
|
|
@@ -235,7 +241,7 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
235
241
|
newColumnsOrder: newColumns
|
|
236
242
|
});
|
|
237
243
|
});
|
|
238
|
-
}, [plugins, fullPath, parentCollectionIds, collection, columnProperty]);
|
|
244
|
+
}, [plugins, fullPath, parentCollectionIds, collection, columnProperty, analyticsController]);
|
|
239
245
|
|
|
240
246
|
// Collection-level count queries to detect missing order property
|
|
241
247
|
// Just TWO counts: total and ordered (for the entire collection, not per column)
|
|
@@ -393,6 +399,13 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
393
399
|
const entity = items.find(item => item.id === moveInfo?.itemId)?.entity;
|
|
394
400
|
if (!entity) return;
|
|
395
401
|
|
|
402
|
+
analyticsController.onAnalyticsEvent?.("kanban_card_moved", {
|
|
403
|
+
path: fullPath,
|
|
404
|
+
entityId: entity.id,
|
|
405
|
+
sourceColumn: moveInfo?.sourceColumn,
|
|
406
|
+
targetColumn: moveInfo?.targetColumn
|
|
407
|
+
});
|
|
408
|
+
|
|
396
409
|
const isColumnChange = moveInfo && moveInfo.sourceColumn !== moveInfo.targetColumn;
|
|
397
410
|
|
|
398
411
|
// If no orderProperty and not a column change, nothing to do
|
|
@@ -440,7 +453,7 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
440
453
|
} catch (e) {
|
|
441
454
|
console.error("Error saving entity:", e);
|
|
442
455
|
}
|
|
443
|
-
}, [collection, columnProperty, orderProperty, context, dataSource, calculateNewOrder, boardDataController]);
|
|
456
|
+
}, [collection, columnProperty, orderProperty, context, dataSource, calculateNewOrder, boardDataController, analyticsController, fullPath]);
|
|
444
457
|
|
|
445
458
|
// Backfill order values for all entities
|
|
446
459
|
const handleBackfill = useCallback(async () => {
|
|
@@ -449,6 +462,9 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
449
462
|
console.log("No orderProperty, returning");
|
|
450
463
|
return;
|
|
451
464
|
}
|
|
465
|
+
analyticsController.onAnalyticsEvent?.("kanban_backfill_order", {
|
|
466
|
+
path: fullPath
|
|
467
|
+
});
|
|
452
468
|
setBackfillLoading(true);
|
|
453
469
|
|
|
454
470
|
try {
|
|
@@ -514,7 +530,7 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
514
530
|
} finally {
|
|
515
531
|
setBackfillLoading(false);
|
|
516
532
|
}
|
|
517
|
-
}, [orderProperty, fullPath, collection, dataSource, context, boardDataController]);
|
|
533
|
+
}, [orderProperty, fullPath, collection, dataSource, context, boardDataController, analyticsController]);
|
|
518
534
|
|
|
519
535
|
const handleEntityClick = useCallback((entity: Entity<M>) => {
|
|
520
536
|
onEntityClick?.(entity);
|
|
@@ -563,19 +579,16 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
563
579
|
|
|
564
580
|
// Check for loading error
|
|
565
581
|
const hasError = Boolean(dataLoadingError);
|
|
566
|
-
const errorMessage = dataLoadingError?.message || "";
|
|
567
|
-
const indexUrl = errorMessage.match(/https:\/\/console\.firebase\.google\.com[^\s]+/)?.[0];
|
|
568
582
|
|
|
569
583
|
// Error: no enum properties available for Kanban columns
|
|
570
584
|
if (!columnProperty || enumColumns.length === 0) {
|
|
571
585
|
return (
|
|
572
586
|
<div className="flex-1 flex flex-col items-center justify-center p-8 gap-4">
|
|
573
587
|
<Typography variant="h6">
|
|
574
|
-
|
|
588
|
+
{t("kanban_view_not_available")}
|
|
575
589
|
</Typography>
|
|
576
590
|
<Typography variant="body2" color="secondary" className="text-center max-w-md">
|
|
577
|
-
|
|
578
|
-
Please add an enum property to your collection schema to use this view.
|
|
591
|
+
{t("kanban_view_requires_enum")}
|
|
579
592
|
</Typography>
|
|
580
593
|
{KanbanSetupComponent && (
|
|
581
594
|
<KanbanSetupComponent
|
|
@@ -596,7 +609,7 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
596
609
|
return (
|
|
597
610
|
<div className="flex-1 flex items-center justify-center p-8">
|
|
598
611
|
<Typography variant="label" color="secondary">
|
|
599
|
-
|
|
612
|
+
{t("no_enum_values_configured", { property: columnProperty })}
|
|
600
613
|
</Typography>
|
|
601
614
|
</div>
|
|
602
615
|
);
|
|
@@ -606,33 +619,10 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
606
619
|
<div className="flex-1 flex flex-col overflow-hidden">
|
|
607
620
|
{/* Error banner - only show when no data loaded */}
|
|
608
621
|
{hasError && allEntities.length === 0 && (
|
|
609
|
-
<
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
{indexUrl
|
|
614
|
-
? "A Firestore index is required for this query."
|
|
615
|
-
: errorMessage}
|
|
616
|
-
</Typography>
|
|
617
|
-
<Tooltip title="Refresh data">
|
|
618
|
-
<IconButton
|
|
619
|
-
size="small"
|
|
620
|
-
onClick={() => boardDataController.refreshAll()}
|
|
621
|
-
>
|
|
622
|
-
<RefreshIcon size="small" />
|
|
623
|
-
</IconButton>
|
|
624
|
-
</Tooltip>
|
|
625
|
-
{indexUrl && (
|
|
626
|
-
<Button
|
|
627
|
-
size="small"
|
|
628
|
-
variant="outlined"
|
|
629
|
-
color="error"
|
|
630
|
-
onClick={() => window.open(indexUrl, "_blank")}
|
|
631
|
-
>
|
|
632
|
-
Create Index
|
|
633
|
-
</Button>
|
|
634
|
-
)}
|
|
635
|
-
</div>
|
|
622
|
+
<CollectionDataErrorBanner
|
|
623
|
+
error={dataLoadingError}
|
|
624
|
+
onRetry={() => boardDataController.refreshAll()}
|
|
625
|
+
/>
|
|
636
626
|
)}
|
|
637
627
|
|
|
638
628
|
{/* Backfill info bar - non-blocking */}
|
|
@@ -640,14 +630,14 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
640
630
|
<div
|
|
641
631
|
className="flex items-center justify-between gap-4 px-4 py-2 bg-amber-50 dark:bg-amber-900/20 border-b border-amber-200 dark:border-amber-800">
|
|
642
632
|
<Typography variant="body2" color="secondary">
|
|
643
|
-
|
|
633
|
+
{t("items_need_backfill")}
|
|
644
634
|
</Typography>
|
|
645
635
|
<Button
|
|
646
636
|
size="small"
|
|
647
637
|
variant="text"
|
|
648
638
|
onClick={() => setShowBackfillDialog(true)}
|
|
649
639
|
>
|
|
650
|
-
|
|
640
|
+
{t("initialize")}
|
|
651
641
|
</Button>
|
|
652
642
|
</div>
|
|
653
643
|
)}
|
|
@@ -667,6 +657,10 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
667
657
|
columnLoadingState={columnLoadingState}
|
|
668
658
|
onLoadMoreColumn={(column) => boardDataController.loadMoreColumn(column)}
|
|
669
659
|
onAddItemToColumn={(column) => {
|
|
660
|
+
analyticsController.onAnalyticsEvent?.("kanban_new_entity_in_column", {
|
|
661
|
+
path: fullPath,
|
|
662
|
+
column
|
|
663
|
+
});
|
|
670
664
|
sideEntityController.open({
|
|
671
665
|
path: fullPath,
|
|
672
666
|
collection,
|
|
@@ -693,18 +687,17 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
693
687
|
{/* Backfill dialog */}
|
|
694
688
|
<Dialog open={showBackfillDialog} onOpenChange={setShowBackfillDialog}>
|
|
695
689
|
<DialogContent>
|
|
696
|
-
<Typography variant="h6" className="mb-4">
|
|
690
|
+
<Typography variant="h6" className="mb-4">{t("initialize_kanban_order")}</Typography>
|
|
697
691
|
<Typography variant="body2">
|
|
698
|
-
|
|
699
|
-
Items will maintain their current order within each column.
|
|
692
|
+
{t("initialize_kanban_order_desc")}
|
|
700
693
|
</Typography>
|
|
701
694
|
</DialogContent>
|
|
702
695
|
<DialogActions>
|
|
703
696
|
<Button variant="text" onClick={() => setShowBackfillDialog(false)} disabled={backfillLoading}>
|
|
704
|
-
|
|
697
|
+
{t("cancel")}
|
|
705
698
|
</Button>
|
|
706
699
|
<Button onClick={handleBackfill} disabled={backfillLoading}>
|
|
707
|
-
{backfillLoading ? <CircularProgress size="smallest" /> : "
|
|
700
|
+
{backfillLoading ? <CircularProgress size="smallest" /> : t("initialize")}
|
|
708
701
|
</Button>
|
|
709
702
|
</DialogActions>
|
|
710
703
|
</Dialog>
|
|
@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useRef } from "react";
|
|
|
2
2
|
import { CollectionSize, Entity, EntityCollection, EntityTableController, SelectionController } from "../../types";
|
|
3
3
|
import { EntityCard } from "./EntityCard";
|
|
4
4
|
import { CircularProgress, cls, Typography } from "@firecms/ui";
|
|
5
|
-
import { useAuthController, useCustomizationController } from "../../hooks";
|
|
5
|
+
import { useAuthController, useCustomizationController, useTranslation } from "../../hooks";
|
|
6
6
|
|
|
7
7
|
export type EntityCollectionCardViewProps<M extends Record<string, any> = any> = {
|
|
8
8
|
collection: EntityCollection<M>;
|
|
@@ -61,17 +61,18 @@ function getGridColumnsClass(size: CollectionSize): string {
|
|
|
61
61
|
* Alternative to the EntityCollectionTable for visual browsing.
|
|
62
62
|
*/
|
|
63
63
|
export function EntityCollectionCardView<M extends Record<string, any> = any>({
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
64
|
+
collection,
|
|
65
|
+
tableController,
|
|
66
|
+
onEntityClick,
|
|
67
|
+
selectionController,
|
|
68
|
+
selectionEnabled = true,
|
|
69
|
+
highlightedEntities,
|
|
70
|
+
emptyComponent,
|
|
71
|
+
onScroll,
|
|
72
|
+
initialScroll,
|
|
73
|
+
size = "m"
|
|
74
|
+
}: EntityCollectionCardViewProps<M>) {
|
|
75
|
+
const { t } = useTranslation();
|
|
75
76
|
const authController = useAuthController();
|
|
76
77
|
const customizationController = useCustomizationController();
|
|
77
78
|
|
|
@@ -178,23 +179,14 @@ export function EntityCollectionCardView<M extends Record<string, any> = any>({
|
|
|
178
179
|
<div className="flex-1 flex items-center justify-center p-8">
|
|
179
180
|
{emptyComponent ?? (
|
|
180
181
|
<Typography variant="label" color="secondary">
|
|
181
|
-
|
|
182
|
+
{t("no_entries_found")}
|
|
182
183
|
</Typography>
|
|
183
184
|
)}
|
|
184
185
|
</div>
|
|
185
186
|
);
|
|
186
187
|
}
|
|
187
188
|
|
|
188
|
-
|
|
189
|
-
if (dataLoadingError) {
|
|
190
|
-
return (
|
|
191
|
-
<div className="flex-1 flex items-center justify-center p-8">
|
|
192
|
-
<Typography className="text-red-500">
|
|
193
|
-
Error loading data: {dataLoadingError.message}
|
|
194
|
-
</Typography>
|
|
195
|
-
</div>
|
|
196
|
-
);
|
|
197
|
-
}
|
|
189
|
+
|
|
198
190
|
|
|
199
191
|
const gridColumnsClass = getGridColumnsClass(size);
|
|
200
192
|
|
|
@@ -230,11 +222,11 @@ export function EntityCollectionCardView<M extends Record<string, any> = any>({
|
|
|
230
222
|
className="flex items-center justify-center py-8"
|
|
231
223
|
>
|
|
232
224
|
{dataLoading && (
|
|
233
|
-
<CircularProgress size="small"/>
|
|
225
|
+
<CircularProgress size="small" />
|
|
234
226
|
)}
|
|
235
227
|
{!dataLoading && noMoreToLoad && data.length > 0 && (
|
|
236
228
|
<Typography variant="caption" color="secondary">
|
|
237
|
-
|
|
229
|
+
{t("all_entries_loaded", { count: data.length.toString() })}
|
|
238
230
|
</Typography>
|
|
239
231
|
)}
|
|
240
232
|
</div>
|
|
@@ -45,13 +45,15 @@ import {
|
|
|
45
45
|
useFireCMSContext,
|
|
46
46
|
useLargeLayout,
|
|
47
47
|
useNavigationController,
|
|
48
|
-
useSideEntityController
|
|
48
|
+
useSideEntityController,
|
|
49
|
+
useTranslation
|
|
49
50
|
} from "../../hooks";
|
|
50
51
|
import { useBreadcrumbsController } from "../../hooks/useBreadcrumbsController";
|
|
51
52
|
import { useUserConfigurationPersistence } from "../../hooks/useUserConfigurationPersistence";
|
|
52
53
|
import { EntityCollectionViewActions } from "./EntityCollectionViewActions";
|
|
53
54
|
import { EntityCollectionCardView } from "./EntityCollectionCardView";
|
|
54
55
|
import { EntityCollectionBoardView } from "./EntityCollectionBoardView";
|
|
56
|
+
import { CollectionDataErrorBanner } from "./CollectionDataErrorBanner";
|
|
55
57
|
import { ViewModeToggle, KanbanPropertyOption } from "./ViewModeToggle";
|
|
56
58
|
import {
|
|
57
59
|
AddIcon,
|
|
@@ -159,6 +161,7 @@ export const EntityCollectionView = React.memo(
|
|
|
159
161
|
) {
|
|
160
162
|
|
|
161
163
|
const context = useFireCMSContext();
|
|
164
|
+
const { t } = useTranslation();
|
|
162
165
|
const navigation = useNavigationController();
|
|
163
166
|
const breadcrumbs = useBreadcrumbsController();
|
|
164
167
|
const fullPath = fullPathProp ?? collectionProp.path;
|
|
@@ -433,12 +436,17 @@ export const EntityCollectionView = React.memo(
|
|
|
433
436
|
|
|
434
437
|
// View mode change: update URL + save to local persistence
|
|
435
438
|
const onViewModeChange = useCallback((mode: ViewMode) => {
|
|
439
|
+
analyticsController.onAnalyticsEvent?.("view_mode_changed", {
|
|
440
|
+
path: fullPath,
|
|
441
|
+
from: viewMode,
|
|
442
|
+
to: mode
|
|
443
|
+
});
|
|
436
444
|
setViewMode(mode);
|
|
437
445
|
// Save to local persistence for next visit
|
|
438
446
|
if (userConfigPersistence) {
|
|
439
447
|
onCollectionModifiedForUser(fullPath, { defaultViewMode: mode } as PartialEntityCollection<M>);
|
|
440
448
|
}
|
|
441
|
-
}, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath]);
|
|
449
|
+
}, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController, viewMode]);
|
|
442
450
|
|
|
443
451
|
const createEnabled = canCreateEntity(collection, authController, fullPath, null);
|
|
444
452
|
|
|
@@ -501,18 +509,24 @@ export const EntityCollectionView = React.memo(
|
|
|
501
509
|
authController,
|
|
502
510
|
}), [collection, fullPath]);
|
|
503
511
|
|
|
504
|
-
// Check if Kanban view is
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
}, [
|
|
512
|
+
// Check if Kanban view is possible (collection has at least one string enum property)
|
|
513
|
+
const hasEnumProperty = useMemo(() => {
|
|
514
|
+
const properties = resolvedCollection.properties;
|
|
515
|
+
return Object.values(properties).some((prop: any) =>
|
|
516
|
+
prop && prop.dataType === "string" && prop.enumValues
|
|
517
|
+
);
|
|
518
|
+
}, [resolvedCollection.properties]);
|
|
511
519
|
|
|
512
|
-
//
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
520
|
+
// Compute the effective enabled views:
|
|
521
|
+
// - Start from collection.enabledViews (defaults to all three)
|
|
522
|
+
// - Filter out kanban if no enum properties exist
|
|
523
|
+
const enabledViews: ViewMode[] = useMemo(() => {
|
|
524
|
+
const configured = collection.enabledViews ?? ["table", "cards", "kanban"];
|
|
525
|
+
if (!hasEnumProperty) {
|
|
526
|
+
return configured.filter(v => v !== "kanban");
|
|
527
|
+
}
|
|
528
|
+
return configured;
|
|
529
|
+
}, [collection.enabledViews, hasEnumProperty]);
|
|
516
530
|
|
|
517
531
|
// Compute available enum properties for kanban column selection
|
|
518
532
|
const kanbanPropertyOptions: KanbanPropertyOption[] = useMemo(() => {
|
|
@@ -562,12 +576,16 @@ export const EntityCollectionView = React.memo(
|
|
|
562
576
|
|
|
563
577
|
// Handle kanban property change
|
|
564
578
|
const onKanbanPropertyChange = useCallback((property: string) => {
|
|
579
|
+
analyticsController.onAnalyticsEvent?.("kanban_property_changed", {
|
|
580
|
+
path: fullPath,
|
|
581
|
+
property
|
|
582
|
+
});
|
|
565
583
|
setSelectedKanbanProperty(property);
|
|
566
584
|
// Save to local persistence
|
|
567
585
|
if (userConfigPersistence) {
|
|
568
586
|
onCollectionModifiedForUser(fullPath, { kanbanColumnProperty: property } as any);
|
|
569
587
|
}
|
|
570
|
-
}, [userConfigPersistence, onCollectionModifiedForUser, fullPath]);
|
|
588
|
+
}, [userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController]);
|
|
571
589
|
|
|
572
590
|
const getPropertyFor = useCallback(({
|
|
573
591
|
propertyKey,
|
|
@@ -680,11 +698,13 @@ export const EntityCollectionView = React.memo(
|
|
|
680
698
|
customEntityActions?: EntityAction[]
|
|
681
699
|
}): EntityAction[] => {
|
|
682
700
|
const deleteEnabled = entity ? canDeleteEntity(collection, authController, fullPath, entity) : true;
|
|
683
|
-
const actions: EntityAction[] = [
|
|
701
|
+
const actions: EntityAction[] = [
|
|
702
|
+
{ ...editEntityAction, name: t("edit") }
|
|
703
|
+
];
|
|
684
704
|
if (createEnabled)
|
|
685
|
-
actions.push(copyEntityAction);
|
|
705
|
+
actions.push({ ...copyEntityAction, name: t("copy") });
|
|
686
706
|
if (deleteEnabled)
|
|
687
|
-
actions.push(deleteEntityAction);
|
|
707
|
+
actions.push({ ...deleteEntityAction, name: t("delete") });
|
|
688
708
|
if (customEntityActions)
|
|
689
709
|
return mergeEntityActions(actions, customEntityActions);
|
|
690
710
|
return actions;
|
|
@@ -819,8 +839,7 @@ export const EntityCollectionView = React.memo(
|
|
|
819
839
|
<ViewModeToggle
|
|
820
840
|
viewMode={viewMode}
|
|
821
841
|
onViewModeChange={onViewModeChange}
|
|
822
|
-
|
|
823
|
-
hasKanbanConfigPlugin={hasKanbanConfigPlugin}
|
|
842
|
+
enabledViews={enabledViews}
|
|
824
843
|
size={viewMode === "table" ? tableSize : viewMode === "cards" ? cardSize : undefined}
|
|
825
844
|
onSizeChanged={viewMode === "table" ? onTableSizeChanged : viewMode === "cards" ? setCardSize : undefined}
|
|
826
845
|
open={viewModePopoverOpen}
|
|
@@ -831,6 +850,24 @@ export const EntityCollectionView = React.memo(
|
|
|
831
850
|
/>
|
|
832
851
|
);
|
|
833
852
|
|
|
853
|
+
// Compute plugin-provided error view for collection loading errors
|
|
854
|
+
const pluginErrorView = useMemo(() => {
|
|
855
|
+
const error = tableController.dataLoadingError;
|
|
856
|
+
if (!error || !customizationController.plugins) return null;
|
|
857
|
+
for (const plugin of customizationController.plugins) {
|
|
858
|
+
if (plugin.collectionView?.CollectionError) {
|
|
859
|
+
const CollectionError = plugin.collectionView.CollectionError;
|
|
860
|
+
return <CollectionError
|
|
861
|
+
path={fullPath}
|
|
862
|
+
collection={collection}
|
|
863
|
+
parentCollectionIds={parentCollectionIds}
|
|
864
|
+
error={error}
|
|
865
|
+
/>;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
return null;
|
|
869
|
+
}, [tableController.dataLoadingError, customizationController.plugins, fullPath, collection, parentCollectionIds]);
|
|
870
|
+
|
|
834
871
|
return (
|
|
835
872
|
<div className={cls("overflow-hidden h-full w-full rounded-md flex flex-col", className)}
|
|
836
873
|
ref={containerRef}>
|
|
@@ -867,7 +904,9 @@ export const EntityCollectionView = React.memo(
|
|
|
867
904
|
/>
|
|
868
905
|
|
|
869
906
|
{/* View content - only the view-specific content changes */}
|
|
870
|
-
{
|
|
907
|
+
{tableController.dataLoadingError ? (
|
|
908
|
+
pluginErrorView ?? <CollectionDataErrorBanner error={tableController.dataLoadingError} />
|
|
909
|
+
) : viewMode === "kanban" && enabledViews.includes("kanban") ? (
|
|
871
910
|
<EntityCollectionBoardView
|
|
872
911
|
key={`kanban-view-${fullPath}-${selectedKanbanProperty}`}
|
|
873
912
|
collection={collection}
|
|
@@ -882,16 +921,16 @@ export const EntityCollectionView = React.memo(
|
|
|
882
921
|
deletedEntities={deletedEntities}
|
|
883
922
|
emptyComponent={canCreateEntities && tableController.filterValues === undefined && tableController.sortBy === undefined
|
|
884
923
|
? <div className="flex flex-col items-center justify-center">
|
|
885
|
-
<Typography variant={"subtitle2"}>
|
|
924
|
+
<Typography variant={"subtitle2"}>{t("so_empty")}</Typography>
|
|
886
925
|
<Button
|
|
887
926
|
onClick={onNewClick}
|
|
888
927
|
className="mt-4"
|
|
889
928
|
>
|
|
890
929
|
<AddIcon />
|
|
891
|
-
|
|
930
|
+
{t("create_your_first_entry")}
|
|
892
931
|
</Button>
|
|
893
932
|
</div>
|
|
894
|
-
: <Typography variant={"label"}>
|
|
933
|
+
: <Typography variant={"label"}>{t("no_results_filter_sort")}</Typography>
|
|
895
934
|
}
|
|
896
935
|
/>
|
|
897
936
|
) : viewMode === "cards" ? (
|
|
@@ -908,16 +947,16 @@ export const EntityCollectionView = React.memo(
|
|
|
908
947
|
size={cardSize}
|
|
909
948
|
emptyComponent={canCreateEntities && tableController.filterValues === undefined && tableController.sortBy === undefined
|
|
910
949
|
? <div className="flex flex-col items-center justify-center">
|
|
911
|
-
<Typography variant={"subtitle2"}>
|
|
950
|
+
<Typography variant={"subtitle2"}>{t("so_empty")}</Typography>
|
|
912
951
|
<Button
|
|
913
952
|
onClick={onNewClick}
|
|
914
953
|
className="mt-4"
|
|
915
954
|
>
|
|
916
955
|
<AddIcon />
|
|
917
|
-
|
|
956
|
+
{t("create_your_first_entry")}
|
|
918
957
|
</Button>
|
|
919
958
|
</div>
|
|
920
|
-
: <Typography variant={"label"}>
|
|
959
|
+
: <Typography variant={"label"}>{t("no_results_filter_sort")}</Typography>
|
|
921
960
|
}
|
|
922
961
|
/>
|
|
923
962
|
) : (
|
|
@@ -946,16 +985,16 @@ export const EntityCollectionView = React.memo(
|
|
|
946
985
|
textSearchEnabled={textSearchEnabled}
|
|
947
986
|
emptyComponent={canCreateEntities && tableController.filterValues === undefined && tableController.sortBy === undefined
|
|
948
987
|
? <div className="flex flex-col items-center justify-center">
|
|
949
|
-
<Typography variant={"subtitle2"}>
|
|
988
|
+
<Typography variant={"subtitle2"}>{t("so_empty")}</Typography>
|
|
950
989
|
<Button
|
|
951
990
|
onClick={onNewClick}
|
|
952
991
|
className="mt-4"
|
|
953
992
|
>
|
|
954
993
|
<AddIcon />
|
|
955
|
-
|
|
994
|
+
{t("create_your_first_entry")}
|
|
956
995
|
</Button>
|
|
957
996
|
</div>
|
|
958
|
-
: <Typography variant={"label"}>
|
|
997
|
+
: <Typography variant={"label"}>{t("no_results_filter_sort")}</Typography>
|
|
959
998
|
}
|
|
960
999
|
hoverRow={hoverRow}
|
|
961
1000
|
inlineEditing={checkInlineEditing()}
|
|
@@ -1126,11 +1165,12 @@ function EntityIdHeaderWidget({
|
|
|
1126
1165
|
const [searchString, setSearchString] = React.useState("");
|
|
1127
1166
|
const [recentIds, setRecentIds] = React.useState<string[]>(getRecentIds(collection.id));
|
|
1128
1167
|
const sideEntityController = useSideEntityController();
|
|
1168
|
+
const { t } = useTranslation();
|
|
1129
1169
|
|
|
1130
1170
|
const openEntityMode = collection?.openEntityMode ?? DEFAULT_ENTITY_OPEN_MODE;
|
|
1131
1171
|
|
|
1132
1172
|
return (
|
|
1133
|
-
<Tooltip title={!openPopup ? "
|
|
1173
|
+
<Tooltip title={!openPopup ? t("find_by_id") : undefined} asChild={false}>
|
|
1134
1174
|
<Popover
|
|
1135
1175
|
open={openPopup}
|
|
1136
1176
|
onOpenChange={setOpenPopup}
|
|
@@ -1166,7 +1206,7 @@ function EntityIdHeaderWidget({
|
|
|
1166
1206
|
<div className="flex p-2 w-full gap-2">
|
|
1167
1207
|
<input
|
|
1168
1208
|
autoFocus={openPopup}
|
|
1169
|
-
placeholder={"
|
|
1209
|
+
placeholder={t("find_entity_by_id")}
|
|
1170
1210
|
// size={"small"}
|
|
1171
1211
|
onChange={(e) => {
|
|
1172
1212
|
setSearchString(e.target.value);
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
} from "@firecms/ui";
|
|
18
18
|
import { toArray } from "../../util/arrays";
|
|
19
19
|
import { ErrorBoundary } from "../ErrorBoundary";
|
|
20
|
+
import { useTranslation } from "../../hooks/useTranslation";
|
|
20
21
|
|
|
21
22
|
export type EntityCollectionViewActionsProps<M extends Record<string, any>> = {
|
|
22
23
|
collection: EntityCollection<M>;
|
|
@@ -45,9 +46,9 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
|
|
|
45
46
|
}: EntityCollectionViewActionsProps<M>) {
|
|
46
47
|
|
|
47
48
|
const context = useFireCMSContext();
|
|
48
|
-
|
|
49
49
|
const customizationController = useCustomizationController();
|
|
50
50
|
const plugins = customizationController.plugins ?? [];
|
|
51
|
+
const { t } = useTranslation();
|
|
51
52
|
|
|
52
53
|
const authController = useAuthController();
|
|
53
54
|
|
|
@@ -63,7 +64,7 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
|
|
|
63
64
|
startIcon={<AddIcon size={"small"} />}
|
|
64
65
|
variant="filled"
|
|
65
66
|
color="primary">
|
|
66
|
-
|
|
67
|
+
{t("add")} {collection.singularName ?? collection.name}
|
|
67
68
|
</Button>
|
|
68
69
|
: <Button
|
|
69
70
|
id={`add_entity_${path}`}
|
|
@@ -98,7 +99,7 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
|
|
|
98
99
|
</IconButton>;
|
|
99
100
|
multipleDeleteButton =
|
|
100
101
|
<Tooltip
|
|
101
|
-
title={multipleDeleteEnabled ? "
|
|
102
|
+
title={multipleDeleteEnabled ? t("delete_selected") : t("cannot_delete_selected")}>
|
|
102
103
|
{button}
|
|
103
104
|
</Tooltip>
|
|
104
105
|
}
|