@firecms/core 3.1.0 → 3.2.0-canary.4c3b8f2
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/EntityCollectionView/CollectionDataErrorBanner.d.ts +4 -0
- package/dist/components/ErrorBoundary.d.ts +3 -1
- 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/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/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 +4 -0
- package/dist/index.es.js +12898 -2265
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +12877 -2264
- package/dist/index.umd.js.map +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/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 +7 -0
- package/dist/types/storage.d.ts +1 -0
- package/dist/types/translations.d.ts +646 -0
- package/dist/util/useStorageUploadController.d.ts +10 -1
- package/package.json +45 -9
- 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/fields/TableReferenceField.tsx +6 -3
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +3 -1
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +3 -2
- package/src/components/EntityCollectionView/BoardSortableList.tsx +3 -1
- package/src/components/EntityCollectionView/CollectionDataErrorBanner.tsx +43 -0
- package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +16 -43
- package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +17 -25
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +26 -18
- 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 +11 -8
- 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/VirtualTableHeader.tsx +12 -10
- 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 +14 -10
- package/src/core/DefaultDrawer.tsx +8 -2
- package/src/core/DrawerNavigationGroup.tsx +5 -3
- package/src/core/EntityEditView.tsx +4 -3
- package/src/core/EntityEditViewFormActions.tsx +24 -17
- package/src/core/EntitySidePanel.tsx +6 -5
- package/src/core/FireCMS.tsx +33 -6
- 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 +16 -3
- package/src/form/EntityFormActions.tsx +19 -12
- package/src/form/PropertyFieldBinding.tsx +3 -2
- 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/ArrayOfReferencesFieldBinding.tsx +4 -4
- package/src/form/field_bindings/BlockFieldBinding.tsx +5 -2
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +23 -18
- package/src/form/field_bindings/MapFieldBinding.tsx +4 -3
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +33 -19
- package/src/form/field_bindings/RepeatFieldBinding.tsx +3 -1
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +4 -3
- package/src/hooks/index.tsx +1 -0
- package/src/hooks/useBuildNavigationController.tsx +45 -18
- package/src/hooks/useCollapsedGroups.ts +7 -6
- package/src/hooks/useTranslation.ts +31 -0
- package/src/i18n/FireCMSi18nProvider.tsx +160 -0
- package/src/index.ts +4 -0
- package/src/internal/useBuildSideEntityController.tsx +22 -20
- package/src/locales/de.ts +691 -0
- package/src/locales/en.ts +703 -0
- package/src/locales/es.ts +703 -0
- package/src/locales/fr.ts +691 -0
- package/src/locales/hi.ts +691 -0
- package/src/locales/it.ts +691 -0
- package/src/locales/pt.ts +700 -0
- package/src/preview/components/UrlComponentPreview.tsx +4 -2
- package/src/preview/components/UserPreview.tsx +3 -1
- 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 +8 -0
- package/src/types/properties.ts +1 -0
- package/src/types/storage.ts +2 -1
- package/src/types/translations.ts +725 -0
- package/src/util/useStorageUploadController.tsx +23 -29
|
@@ -30,8 +30,13 @@ import { NavigationCardBinding } from "./NavigationCardBinding";
|
|
|
30
30
|
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
|
31
31
|
import { restrictToVerticalAxis, restrictToWindowEdges } from "@dnd-kit/modifiers";
|
|
32
32
|
import { RenameGroupDialog } from "./RenameGroupDialog";
|
|
33
|
+
import { useTranslation } from "../../hooks/useTranslation";
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Internal sentinel key for ungrouped navigation entries.
|
|
37
|
+
* Not displayed — display components use t("views_group") when group is undefined.
|
|
38
|
+
*/
|
|
39
|
+
const DEFAULT_GROUP_KEY = "__default__";
|
|
35
40
|
export const ADMIN_GROUP_NAME = "Admin";
|
|
36
41
|
|
|
37
42
|
export function DefaultHomePage({
|
|
@@ -47,6 +52,7 @@ export function DefaultHomePage({
|
|
|
47
52
|
const context = useFireCMSContext();
|
|
48
53
|
const customizationController = useCustomizationController();
|
|
49
54
|
const navigationController = useNavigationController();
|
|
55
|
+
const { t } = useTranslation();
|
|
50
56
|
|
|
51
57
|
if (!navigationController.topLevelNavigation)
|
|
52
58
|
throw Error("Navigation not ready");
|
|
@@ -108,7 +114,7 @@ export function DefaultHomePage({
|
|
|
108
114
|
const g =
|
|
109
115
|
e.type === "admin"
|
|
110
116
|
? ADMIN_GROUP_NAME
|
|
111
|
-
: e.group ??
|
|
117
|
+
: e.group ?? DEFAULT_GROUP_KEY;
|
|
112
118
|
(entriesByGroup[g] ??= []).push(e);
|
|
113
119
|
});
|
|
114
120
|
|
|
@@ -119,7 +125,7 @@ export function DefaultHomePage({
|
|
|
119
125
|
|
|
120
126
|
if (performingSearch) {
|
|
121
127
|
const ordered = [
|
|
122
|
-
...new Set(src.map((e) => e.group ??
|
|
128
|
+
...new Set(src.map((e) => e.group ?? DEFAULT_GROUP_KEY))
|
|
123
129
|
];
|
|
124
130
|
allProcessed = ordered
|
|
125
131
|
.map((name) => ({
|
|
@@ -129,11 +135,11 @@ export function DefaultHomePage({
|
|
|
129
135
|
.filter((g) => g.entries.length);
|
|
130
136
|
} else {
|
|
131
137
|
allProcessed = groupOrderFromNavController.map((g) => ({
|
|
132
|
-
name: g,
|
|
133
|
-
entries: entriesByGroup[g] || []
|
|
138
|
+
name: g ?? DEFAULT_GROUP_KEY,
|
|
139
|
+
entries: entriesByGroup[g ?? DEFAULT_GROUP_KEY] || []
|
|
134
140
|
}));
|
|
135
141
|
Object.keys(entriesByGroup).forEach((g) => {
|
|
136
|
-
if (!groupOrderFromNavController.includes(g))
|
|
142
|
+
if (!groupOrderFromNavController.map(x => x ?? DEFAULT_GROUP_KEY).includes(g))
|
|
137
143
|
allProcessed.push({
|
|
138
144
|
name: g,
|
|
139
145
|
entries: entriesByGroup[g]
|
|
@@ -141,9 +147,9 @@ export function DefaultHomePage({
|
|
|
141
147
|
});
|
|
142
148
|
|
|
143
149
|
// Ensure default group exists if there are plugin additional cards but no collections
|
|
144
|
-
if (hasPluginAdditionalCards && !allProcessed.some(g => g.name ===
|
|
150
|
+
if (hasPluginAdditionalCards && !allProcessed.some(g => g.name === DEFAULT_GROUP_KEY)) {
|
|
145
151
|
allProcessed.push({
|
|
146
|
-
name:
|
|
152
|
+
name: DEFAULT_GROUP_KEY,
|
|
147
153
|
entries: []
|
|
148
154
|
});
|
|
149
155
|
}
|
|
@@ -151,7 +157,7 @@ export function DefaultHomePage({
|
|
|
151
157
|
allProcessed = allProcessed.filter(
|
|
152
158
|
(g) =>
|
|
153
159
|
g.entries.length ||
|
|
154
|
-
(g.name ===
|
|
160
|
+
(g.name === DEFAULT_GROUP_KEY && hasPluginAdditionalCards)
|
|
155
161
|
);
|
|
156
162
|
}
|
|
157
163
|
|
|
@@ -362,7 +368,7 @@ export function DefaultHomePage({
|
|
|
362
368
|
>
|
|
363
369
|
<SearchBar
|
|
364
370
|
onTextSearch={updateSearch}
|
|
365
|
-
placeholder="
|
|
371
|
+
placeholder={t("search_collections")}
|
|
366
372
|
autoFocus
|
|
367
373
|
innerClassName="w-full"
|
|
368
374
|
className="w-full flex-grow"
|
|
@@ -412,7 +418,7 @@ export function DefaultHomePage({
|
|
|
412
418
|
|
|
413
419
|
const actionProps: PluginHomePageAdditionalCardsProps = {
|
|
414
420
|
group:
|
|
415
|
-
groupKey ===
|
|
421
|
+
groupKey === DEFAULT_GROUP_KEY
|
|
416
422
|
? undefined
|
|
417
423
|
: groupKey,
|
|
418
424
|
context
|
|
@@ -432,7 +438,7 @@ export function DefaultHomePage({
|
|
|
432
438
|
>
|
|
433
439
|
<NavigationGroup
|
|
434
440
|
group={
|
|
435
|
-
groupKey ===
|
|
441
|
+
groupKey === DEFAULT_GROUP_KEY
|
|
436
442
|
? undefined
|
|
437
443
|
: groupKey
|
|
438
444
|
}
|
|
@@ -535,7 +541,7 @@ export function DefaultHomePage({
|
|
|
535
541
|
<NavigationGroup
|
|
536
542
|
group={
|
|
537
543
|
activeGroupData.name ===
|
|
538
|
-
|
|
544
|
+
DEFAULT_GROUP_KEY
|
|
539
545
|
? undefined
|
|
540
546
|
: activeGroupData.name
|
|
541
547
|
}
|
|
@@ -30,6 +30,7 @@ import { CSS } from "@dnd-kit/utilities";
|
|
|
30
30
|
import { NavigationCardBinding } from "./NavigationCardBinding";
|
|
31
31
|
import { NavigationEntry } from "../../types";
|
|
32
32
|
import { cls, defaultBorderMixin } from "@firecms/ui";
|
|
33
|
+
import { useTranslation } from "../../hooks";
|
|
33
34
|
|
|
34
35
|
const animateLayoutChanges: AnimateLayoutChanges = (args) =>
|
|
35
36
|
defaultAnimateLayoutChanges({
|
|
@@ -669,6 +670,7 @@ export function NewGroupDropZone({
|
|
|
669
670
|
disabled: boolean;
|
|
670
671
|
setIsHovering: (v: boolean) => void;
|
|
671
672
|
}) {
|
|
673
|
+
const { t } = useTranslation();
|
|
672
674
|
const {
|
|
673
675
|
setNodeRef,
|
|
674
676
|
isOver
|
|
@@ -709,7 +711,7 @@ export function NewGroupDropZone({
|
|
|
709
711
|
)}>
|
|
710
712
|
<div className="text-center p-4">
|
|
711
713
|
<span className="block font-medium text-sm">
|
|
712
|
-
|
|
714
|
+
{t("drop_here_create_group")}
|
|
713
715
|
</span>
|
|
714
716
|
</div>
|
|
715
717
|
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { PropsWithChildren, useState } from "react";
|
|
2
2
|
import { cls, EditIcon, IconButton, Typography, ExpandablePanel } from "@firecms/ui";
|
|
3
|
+
import { useTranslation } from "../../hooks/useTranslation";
|
|
3
4
|
|
|
4
5
|
export function NavigationGroup({
|
|
5
6
|
children,
|
|
@@ -22,8 +23,9 @@ export function NavigationGroup({
|
|
|
22
23
|
onToggleCollapsed?: () => void;
|
|
23
24
|
}>) {
|
|
24
25
|
|
|
26
|
+
const { t } = useTranslation();
|
|
25
27
|
const [isHovered, setIsHovered] = useState(false);
|
|
26
|
-
const currentGroupName = group ?? "
|
|
28
|
+
const currentGroupName = group ?? t("views_group");
|
|
27
29
|
|
|
28
30
|
// Show caret only when not in preview and there is a toggle handler
|
|
29
31
|
const showCaret = !isPreview && !!onToggleCollapsed;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from "react";
|
|
2
2
|
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, TextField } from "@firecms/ui";
|
|
3
|
+
import { useTranslation } from "../../hooks/useTranslation";
|
|
3
4
|
|
|
4
5
|
interface RenameGroupDialogProps {
|
|
5
6
|
open: boolean;
|
|
@@ -18,7 +19,8 @@ export function RenameGroupDialog({
|
|
|
18
19
|
}: RenameGroupDialogProps) {
|
|
19
20
|
const [name, setName] = useState(initialName);
|
|
20
21
|
const [error, setError] = useState<string | null>(null);
|
|
21
|
-
const inputRef = useRef<HTMLInputElement | HTMLTextAreaElement | null>(null);
|
|
22
|
+
const inputRef = useRef<HTMLInputElement | HTMLTextAreaElement | null>(null);
|
|
23
|
+
const { t } = useTranslation();
|
|
22
24
|
|
|
23
25
|
useEffect(() => {
|
|
24
26
|
if (open) {
|
|
@@ -38,9 +40,9 @@ export function RenameGroupDialog({
|
|
|
38
40
|
const newName = event.target.value;
|
|
39
41
|
setName(newName);
|
|
40
42
|
if (!newName.trim()) {
|
|
41
|
-
setError("
|
|
43
|
+
setError(t("group_name_empty_error"));
|
|
42
44
|
} else if (existingGroupNames.includes(newName.trim())) {
|
|
43
|
-
setError("
|
|
45
|
+
setError(t("group_name_exists_error"));
|
|
44
46
|
} else {
|
|
45
47
|
setError(null);
|
|
46
48
|
}
|
|
@@ -49,11 +51,11 @@ export function RenameGroupDialog({
|
|
|
49
51
|
const handleSave = () => {
|
|
50
52
|
const trimmedName = name.trim();
|
|
51
53
|
if (!trimmedName) {
|
|
52
|
-
setError("
|
|
54
|
+
setError(t("group_name_empty_error"));
|
|
53
55
|
return;
|
|
54
56
|
}
|
|
55
57
|
if (existingGroupNames.includes(trimmedName)) {
|
|
56
|
-
setError("
|
|
58
|
+
setError(t("group_name_exists_error"));
|
|
57
59
|
return;
|
|
58
60
|
}
|
|
59
61
|
if (!error) {
|
|
@@ -70,9 +72,9 @@ export function RenameGroupDialog({
|
|
|
70
72
|
// because the error state might not have updated if the user types and immediately hits enter.
|
|
71
73
|
let currentError = null;
|
|
72
74
|
if (!trimmedName) {
|
|
73
|
-
currentError = "
|
|
75
|
+
currentError = t("group_name_empty_error");
|
|
74
76
|
} else if (existingGroupNames.includes(trimmedName)) {
|
|
75
|
-
currentError = "
|
|
77
|
+
currentError = t("group_name_exists_error");
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
if (!currentError && trimmedName) {
|
|
@@ -93,14 +95,14 @@ export function RenameGroupDialog({
|
|
|
93
95
|
|
|
94
96
|
return (
|
|
95
97
|
<Dialog open={open}>
|
|
96
|
-
<DialogTitle>
|
|
98
|
+
<DialogTitle>{t("rename_group")}</DialogTitle>
|
|
97
99
|
<DialogContent>
|
|
98
100
|
<TextField
|
|
99
|
-
inputRef={inputRef}
|
|
100
|
-
label="
|
|
101
|
+
inputRef={inputRef}
|
|
102
|
+
label={t("group_name_label")}
|
|
101
103
|
value={name}
|
|
102
104
|
onChange={handleNameChange}
|
|
103
|
-
onKeyDown={handleKeyDown}
|
|
105
|
+
onKeyDown={handleKeyDown}
|
|
104
106
|
error={!!error}
|
|
105
107
|
aria-describedby={error ? "group-name-error" : undefined}
|
|
106
108
|
/>
|
|
@@ -109,11 +111,11 @@ export function RenameGroupDialog({
|
|
|
109
111
|
<DialogActions>
|
|
110
112
|
<Button onClick={onClose}
|
|
111
113
|
variant="text">
|
|
112
|
-
|
|
114
|
+
{t("cancel")}
|
|
113
115
|
</Button>
|
|
114
116
|
<Button onClick={handleSave}
|
|
115
117
|
disabled={!!error || !name.trim()}>
|
|
116
|
-
|
|
118
|
+
{t("save")}
|
|
117
119
|
</Button>
|
|
118
120
|
</DialogActions>
|
|
119
121
|
</Dialog>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { CheckIcon, IconButton, Menu, MenuItem, TranslateIcon, Typography } from "@firecms/ui";
|
|
3
|
+
import { useTranslation } from "../hooks";
|
|
4
|
+
|
|
5
|
+
export function LanguageToggle() {
|
|
6
|
+
const { i18n } = useTranslation();
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<Menu
|
|
10
|
+
trigger={<IconButton
|
|
11
|
+
color="inherit"
|
|
12
|
+
aria-label="Change language">
|
|
13
|
+
<TranslateIcon size="small" />
|
|
14
|
+
</IconButton>}>
|
|
15
|
+
<MenuItem onClick={() => i18n.changeLanguage("en")}>
|
|
16
|
+
<div className="flex w-full items-center justify-between gap-4">
|
|
17
|
+
{/* eslint-disable-next-line i18next/no-literal-string */}
|
|
18
|
+
<Typography variant="body2" className={i18n.language === "en" ? "font-bold" : ""}>English</Typography>
|
|
19
|
+
{i18n.language === "en" && <CheckIcon size="small" />}
|
|
20
|
+
</div>
|
|
21
|
+
</MenuItem>
|
|
22
|
+
<MenuItem onClick={() => i18n.changeLanguage("es")}>
|
|
23
|
+
<div className="flex w-full items-center justify-between gap-4">
|
|
24
|
+
{/* eslint-disable-next-line i18next/no-literal-string */}
|
|
25
|
+
<Typography variant="body2" className={i18n.language === "es" ? "font-bold" : ""}>Español</Typography>
|
|
26
|
+
{i18n.language === "es" && <CheckIcon size="small" />}
|
|
27
|
+
</div>
|
|
28
|
+
</MenuItem>
|
|
29
|
+
<MenuItem onClick={() => i18n.changeLanguage("de")}>
|
|
30
|
+
<div className="flex w-full items-center justify-between gap-4">
|
|
31
|
+
{/* eslint-disable-next-line i18next/no-literal-string */}
|
|
32
|
+
<Typography variant="body2" className={i18n.language === "de" ? "font-bold" : ""}>Deutsch</Typography>
|
|
33
|
+
{i18n.language === "de" && <CheckIcon size="small" />}
|
|
34
|
+
</div>
|
|
35
|
+
</MenuItem>
|
|
36
|
+
<MenuItem onClick={() => i18n.changeLanguage("fr")}>
|
|
37
|
+
<div className="flex w-full items-center justify-between gap-4">
|
|
38
|
+
{/* eslint-disable-next-line i18next/no-literal-string */}
|
|
39
|
+
<Typography variant="body2" className={i18n.language === "fr" ? "font-bold" : ""}>Français</Typography>
|
|
40
|
+
{i18n.language === "fr" && <CheckIcon size="small" />}
|
|
41
|
+
</div>
|
|
42
|
+
</MenuItem>
|
|
43
|
+
<MenuItem onClick={() => i18n.changeLanguage("it")}>
|
|
44
|
+
<div className="flex w-full items-center justify-between gap-4">
|
|
45
|
+
{/* eslint-disable-next-line i18next/no-literal-string */}
|
|
46
|
+
<Typography variant="body2" className={i18n.language === "it" ? "font-bold" : ""}>Italiano</Typography>
|
|
47
|
+
{i18n.language === "it" && <CheckIcon size="small" />}
|
|
48
|
+
</div>
|
|
49
|
+
</MenuItem>
|
|
50
|
+
<MenuItem onClick={() => i18n.changeLanguage("hi")}>
|
|
51
|
+
<div className="flex w-full items-center justify-between gap-4">
|
|
52
|
+
{/* eslint-disable-next-line i18next/no-literal-string */}
|
|
53
|
+
<Typography variant="body2" className={i18n.language === "hi" ? "font-bold" : ""}>हिन्दी</Typography>
|
|
54
|
+
{i18n.language === "hi" && <CheckIcon size="small" />}
|
|
55
|
+
</div>
|
|
56
|
+
</MenuItem>
|
|
57
|
+
<MenuItem onClick={() => i18n.changeLanguage("pt")}>
|
|
58
|
+
<div className="flex w-full items-center justify-between gap-4">
|
|
59
|
+
{/* eslint-disable-next-line i18next/no-literal-string */}
|
|
60
|
+
<Typography variant="body2" className={i18n.language === "pt" ? "font-bold" : ""}>Português</Typography>
|
|
61
|
+
{i18n.language === "pt" && <CheckIcon size="small" />}
|
|
62
|
+
</div>
|
|
63
|
+
</MenuItem>
|
|
64
|
+
</Menu>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Link } from "react-router-dom";
|
|
3
3
|
import { Button, Typography } from "@firecms/ui";
|
|
4
|
+
import { useTranslation } from "../hooks/useTranslation";
|
|
4
5
|
|
|
5
6
|
export function NotFoundPage() {
|
|
7
|
+
const { t } = useTranslation();
|
|
6
8
|
|
|
7
9
|
return (
|
|
8
10
|
<div className="flex w-full h-full">
|
|
@@ -10,15 +12,15 @@ export function NotFoundPage() {
|
|
|
10
12
|
>
|
|
11
13
|
<Typography variant={"h4"} align={"center"}
|
|
12
14
|
gutterBottom={true}>
|
|
13
|
-
|
|
15
|
+
{t("page_not_found")}
|
|
14
16
|
</Typography>
|
|
15
17
|
<Typography align={"center"} gutterBottom={true}>
|
|
16
|
-
|
|
18
|
+
{t("page_not_found_body")}
|
|
17
19
|
</Typography>
|
|
18
20
|
<Button
|
|
19
21
|
variant={"text"}
|
|
20
22
|
component={Link}
|
|
21
|
-
to={"/"}>
|
|
23
|
+
to={"/"}>{t("back_to_home")}</Button>
|
|
22
24
|
</div>
|
|
23
25
|
</div>
|
|
24
26
|
);
|
|
@@ -12,7 +12,8 @@ import {
|
|
|
12
12
|
useDataSource,
|
|
13
13
|
useLargeLayout,
|
|
14
14
|
useNavigationController,
|
|
15
|
-
useSideEntityController
|
|
15
|
+
useSideEntityController,
|
|
16
|
+
useTranslation
|
|
16
17
|
} from "../../hooks";
|
|
17
18
|
import { ErrorView } from "../ErrorView";
|
|
18
19
|
import { AddIcon, Button, DialogActions, Typography } from "@firecms/ui";
|
|
@@ -101,6 +102,7 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
|
|
|
101
102
|
maxSelection,
|
|
102
103
|
}: ReferenceSelectionInnerProps<M>) {
|
|
103
104
|
|
|
105
|
+
const { t } = useTranslation();
|
|
104
106
|
const authController = useAuthController();
|
|
105
107
|
const sideDialogContext = useSideDialogContext();
|
|
106
108
|
const sideEntityController = useSideEntityController();
|
|
@@ -302,8 +304,8 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
|
|
|
302
304
|
collectionOrView={collection}
|
|
303
305
|
className={"text-surface-300 dark:text-surface-600"}/>
|
|
304
306
|
{collection.singularName
|
|
305
|
-
?
|
|
306
|
-
:
|
|
307
|
+
? t("select_specific", { name: collection.singularName })
|
|
308
|
+
: t("select_from", { name: collection.name })}
|
|
307
309
|
</Typography>}
|
|
308
310
|
defaultSize={collection.defaultSize}
|
|
309
311
|
properties={resolvedCollection.properties}
|
|
@@ -327,7 +329,7 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
|
|
|
327
329
|
<Button
|
|
328
330
|
onClick={onDone}
|
|
329
331
|
variant="filled">
|
|
330
|
-
|
|
332
|
+
{t("done")}
|
|
331
333
|
</Button>
|
|
332
334
|
</DialogActions>
|
|
333
335
|
</div>
|
|
@@ -347,7 +349,7 @@ function ReferenceDialogActions({
|
|
|
347
349
|
onClear: () => void,
|
|
348
350
|
onNewClick: () => void
|
|
349
351
|
}) {
|
|
350
|
-
|
|
352
|
+
const { t } = useTranslation();
|
|
351
353
|
const authController = useAuthController();
|
|
352
354
|
|
|
353
355
|
const largeLayout = useLargeLayout();
|
|
@@ -363,7 +365,7 @@ function ReferenceDialogActions({
|
|
|
363
365
|
? <Button
|
|
364
366
|
onClick={onClick}
|
|
365
367
|
startIcon={<AddIcon/>}>
|
|
366
|
-
|
|
368
|
+
{t("add_specific", { name: collection.singularName ?? collection.name })}
|
|
367
369
|
</Button>
|
|
368
370
|
: <Button
|
|
369
371
|
onClick={onClick}>
|
|
@@ -374,7 +376,7 @@ function ReferenceDialogActions({
|
|
|
374
376
|
<>
|
|
375
377
|
<Button onClick={onClear}
|
|
376
378
|
variant={"text"}>
|
|
377
|
-
|
|
379
|
+
{t("clear")}
|
|
378
380
|
</Button>
|
|
379
381
|
{addButton}
|
|
380
382
|
</>
|
|
@@ -3,7 +3,7 @@ import React, { useCallback, useMemo } from "react";
|
|
|
3
3
|
import { Entity, EntityCollection, EntityReference, FilterValues } from "../types";
|
|
4
4
|
import { getReferenceFrom } from "../util";
|
|
5
5
|
import { PreviewSize, ReferencePreview } from "../preview";
|
|
6
|
-
import { useNavigationController, useReferenceDialog } from "../hooks";
|
|
6
|
+
import { useNavigationController, useReferenceDialog, useTranslation } from "../hooks";
|
|
7
7
|
import { Button, cls } from "@firecms/ui";
|
|
8
8
|
|
|
9
9
|
export type ReferenceWidgetProps<M extends Record<string, any>> = {
|
|
@@ -50,6 +50,7 @@ export function ReferenceWidget<M extends Record<string, any>>({
|
|
|
50
50
|
includeEntityLink
|
|
51
51
|
}: ReferenceWidgetProps<M>) {
|
|
52
52
|
|
|
53
|
+
const { t } = useTranslation();
|
|
53
54
|
const navigationController = useNavigationController();
|
|
54
55
|
|
|
55
56
|
const collection: EntityCollection | undefined = useMemo(() => {
|
|
@@ -145,7 +146,7 @@ export function ReferenceWidget<M extends Record<string, any>>({
|
|
|
145
146
|
{!value && <div className="justify-center text-left">
|
|
146
147
|
<Button disabled={disabled}
|
|
147
148
|
onClick={onEntryClick}>
|
|
148
|
-
|
|
149
|
+
{t("edit_name", { name: name ?? "" })}
|
|
149
150
|
</Button>
|
|
150
151
|
</div>}
|
|
151
152
|
|
|
@@ -2,6 +2,7 @@ import React from "react";
|
|
|
2
2
|
|
|
3
3
|
import { coolIconKeys, debounce, Icon, IconButton, iconKeys, SearchBar, Tooltip } from "@firecms/ui";
|
|
4
4
|
import { iconSynonyms, iconsSearch } from "../util";
|
|
5
|
+
import { useTranslation } from "../hooks/useTranslation";
|
|
5
6
|
|
|
6
7
|
const UPDATE_SEARCH_INDEX_WAIT_MS = 220;
|
|
7
8
|
|
|
@@ -22,6 +23,7 @@ export function SearchIconsView({
|
|
|
22
23
|
selectedIcon = "",
|
|
23
24
|
onIconSelected
|
|
24
25
|
}: SearchIconsProps) {
|
|
26
|
+
const { t } = useTranslation();
|
|
25
27
|
const [keys, setKeys] = React.useState<string[] | null>(null);
|
|
26
28
|
const [query, setQuery] = React.useState<string>("");
|
|
27
29
|
|
|
@@ -53,7 +55,7 @@ export function SearchIconsView({
|
|
|
53
55
|
autoFocus={false}
|
|
54
56
|
innerClassName={"w-full sticky top-0 z-10"}
|
|
55
57
|
onTextSearch={(value?: string) => setQuery(value ?? "")}
|
|
56
|
-
placeholder="
|
|
58
|
+
placeholder={t("search_for_more_icons")}
|
|
57
59
|
/>
|
|
58
60
|
|
|
59
61
|
<div className={"flex max-w-full flex-wrap mt-4"}>
|
|
@@ -48,6 +48,17 @@ export function DateTimeFilterField({
|
|
|
48
48
|
const [operation, setOperation] = useState<VirtualTableWhereFilterOp | "is-null">(fieldOperation === "==" && fieldValue === null ? "is-null" : fieldOperation);
|
|
49
49
|
const [internalValue, setInternalValue] = useState<Date | null | undefined>(fieldValue);
|
|
50
50
|
|
|
51
|
+
React.useEffect(() => {
|
|
52
|
+
if (value) {
|
|
53
|
+
const [op, val] = value;
|
|
54
|
+
setOperation(op === "==" && val === null ? "is-null" : op);
|
|
55
|
+
setInternalValue(val);
|
|
56
|
+
} else {
|
|
57
|
+
setOperation(possibleOperations[0]);
|
|
58
|
+
setInternalValue(undefined);
|
|
59
|
+
}
|
|
60
|
+
}, [value, possibleOperations[0]]);
|
|
61
|
+
|
|
51
62
|
const isNullOperation = operation === "is-null";
|
|
52
63
|
|
|
53
64
|
function updateFilter(op: VirtualTableWhereFilterOp | "is-null", val: Date | undefined | null) {
|
|
@@ -3,7 +3,7 @@ import { VirtualTableWhereFilterOp } from "../../VirtualTable";
|
|
|
3
3
|
import { Entity, EntityCollection, EntityReference } from "../../../types";
|
|
4
4
|
import { ReferencePreview } from "../../../preview";
|
|
5
5
|
import { getReferenceFrom } from "../../../util";
|
|
6
|
-
import { useNavigationController, useReferenceDialog } from "../../../hooks";
|
|
6
|
+
import { useNavigationController, useReferenceDialog, useTranslation } from "../../../hooks";
|
|
7
7
|
import { Button, Checkbox, Label, Select, SelectItem } from "@firecms/ui";
|
|
8
8
|
|
|
9
9
|
interface ReferenceFilterFieldProps {
|
|
@@ -44,6 +44,8 @@ export function ReferenceFilterField({
|
|
|
44
44
|
setHidden
|
|
45
45
|
}: ReferenceFilterFieldProps) {
|
|
46
46
|
|
|
47
|
+
const { t } = useTranslation();
|
|
48
|
+
|
|
47
49
|
const possibleOperations: (keyof typeof operationLabels)[] = isArray
|
|
48
50
|
? ["array-contains"]
|
|
49
51
|
: ["==", "!=", ">", "<", ">=", "<="];
|
|
@@ -58,6 +60,17 @@ export function ReferenceFilterField({
|
|
|
58
60
|
const [operation, setOperation] = useState<VirtualTableWhereFilterOp>(fieldOperation);
|
|
59
61
|
const [internalValue, setInternalValue] = useState<EntityReference | EntityReference[] | undefined | null>(fieldValue);
|
|
60
62
|
|
|
63
|
+
React.useEffect(() => {
|
|
64
|
+
if (value) {
|
|
65
|
+
const [op, val] = value;
|
|
66
|
+
setOperation(op);
|
|
67
|
+
setInternalValue(val);
|
|
68
|
+
} else {
|
|
69
|
+
setOperation(possibleOperations[0] as VirtualTableWhereFilterOp);
|
|
70
|
+
setInternalValue(undefined);
|
|
71
|
+
}
|
|
72
|
+
}, [value, possibleOperations[0]]);
|
|
73
|
+
|
|
61
74
|
const selectedEntityIds = internalValue
|
|
62
75
|
? (Array.isArray(internalValue) ? internalValue.map((ref) => {
|
|
63
76
|
if (!(ref?.isEntityReference && ref?.isEntityReference())) {
|
|
@@ -192,7 +205,7 @@ export function ReferenceFilterField({
|
|
|
192
205
|
updateFilter(operation, null);
|
|
193
206
|
else updateFilter(operation, undefined);
|
|
194
207
|
}} />
|
|
195
|
-
|
|
208
|
+
{t("filter_for_null_values")}
|
|
196
209
|
</Label>}
|
|
197
210
|
|
|
198
211
|
</div>
|
|
@@ -61,6 +61,17 @@ export function StringNumberFilterField({
|
|
|
61
61
|
const [operation, setOperation] = useState<VirtualTableWhereFilterOp | "is-null">(fieldOperation === "==" && fieldValue === null ? "is-null" : fieldOperation);
|
|
62
62
|
const [internalValue, setInternalValue] = useState<string | number | string[] | number[] | null | undefined>(fieldValue);
|
|
63
63
|
|
|
64
|
+
React.useEffect(() => {
|
|
65
|
+
if (value) {
|
|
66
|
+
const [op, val] = value;
|
|
67
|
+
setOperation(op === "==" && val === null ? "is-null" : op);
|
|
68
|
+
setInternalValue(val);
|
|
69
|
+
} else {
|
|
70
|
+
setOperation(possibleOperations[0]);
|
|
71
|
+
setInternalValue(undefined);
|
|
72
|
+
}
|
|
73
|
+
}, [value, possibleOperations[0]]);
|
|
74
|
+
|
|
64
75
|
const isNullOperation = operation === "is-null";
|
|
65
76
|
|
|
66
77
|
function updateFilter(op: VirtualTableWhereFilterOp | "is-null", val: string | number | string[] | number[] | null | undefined) {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import React from "react";
|
|
1
2
|
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from "@firecms/ui";
|
|
3
|
+
import { useTranslation } from "../hooks/useTranslation";
|
|
2
4
|
|
|
3
5
|
export interface UnsavedChangesDialogProps {
|
|
4
6
|
open: boolean;
|
|
@@ -15,7 +17,7 @@ export function UnsavedChangesDialog({
|
|
|
15
17
|
body,
|
|
16
18
|
title
|
|
17
19
|
}: UnsavedChangesDialogProps) {
|
|
18
|
-
|
|
20
|
+
const { t } = useTranslation();
|
|
19
21
|
return (
|
|
20
22
|
<Dialog
|
|
21
23
|
onEscapeKeyDown={() => {
|
|
@@ -29,15 +31,15 @@ export function UnsavedChangesDialog({
|
|
|
29
31
|
{body}
|
|
30
32
|
|
|
31
33
|
<Typography>
|
|
32
|
-
|
|
34
|
+
{t("are_you_sure_leave")}
|
|
33
35
|
</Typography>
|
|
34
36
|
|
|
35
37
|
</DialogContent>
|
|
36
38
|
<DialogActions>
|
|
37
39
|
<Button variant="text"
|
|
38
|
-
onClick={handleCancel} autoFocus>
|
|
40
|
+
onClick={handleCancel} autoFocus> {t("cancel")} </Button>
|
|
39
41
|
<Button
|
|
40
|
-
onClick={handleOk}>
|
|
42
|
+
onClick={handleOk}> {t("ok")} </Button>
|
|
41
43
|
</DialogActions>
|
|
42
44
|
</Dialog>
|
|
43
45
|
);
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @jest-environment jsdom
|
|
4
4
|
*/
|
|
5
5
|
import React from 'react';
|
|
6
|
+
/* eslint-disable i18next/no-literal-string */
|
|
6
7
|
import { render, act } from '@testing-library/react';
|
|
7
8
|
import { VirtualTable } from './VirtualTable';
|
|
8
9
|
import { VirtualTableProps } from './VirtualTableProps';
|
|
@@ -2,6 +2,7 @@ import React, { RefObject, useCallback, useEffect, useState } from "react";
|
|
|
2
2
|
import equal from "react-fast-compare";
|
|
3
3
|
|
|
4
4
|
import { VirtualTableColumn, VirtualTableSort, VirtualTableWhereFilterOp } from "./VirtualTableProps";
|
|
5
|
+
import { useTranslation } from "../../hooks";
|
|
5
6
|
import { ErrorBoundary } from "../ErrorBoundary";
|
|
6
7
|
import {
|
|
7
8
|
ArrowUpwardIcon,
|
|
@@ -213,6 +214,8 @@ function FilterForm<M>({
|
|
|
213
214
|
setHidden
|
|
214
215
|
}: FilterFormProps<M>) {
|
|
215
216
|
|
|
217
|
+
const { t } = useTranslation();
|
|
218
|
+
|
|
216
219
|
const id = column.key;
|
|
217
220
|
|
|
218
221
|
const [filterInternal, setFilterInternal] = useState<[VirtualTableWhereFilterOp, any] | undefined>(filter);
|
|
@@ -258,16 +261,15 @@ function FilterForm<M>({
|
|
|
258
261
|
{filterField && <div className="m-4 w-[400px]">
|
|
259
262
|
{filterField}
|
|
260
263
|
</div>}
|
|
261
|
-
<div className="flex justify-end
|
|
262
|
-
<Button
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
type="submit">Filter</Button>
|
|
264
|
+
<div className="flex justify-end p-4 pt-0 gap-2">
|
|
265
|
+
<Button variant={"text"}
|
|
266
|
+
size={"small"}
|
|
267
|
+
aria-label="filter clear"
|
|
268
|
+
onClick={reset}>{t("clear")}</Button>
|
|
269
|
+
|
|
270
|
+
<Button variant={"outlined"}
|
|
271
|
+
size={"small"}
|
|
272
|
+
type="submit">{t("filter")}</Button>
|
|
271
273
|
</div>
|
|
272
274
|
</form>
|
|
273
275
|
);
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// Note: entity action 'name' fields (Edit, Copy, Delete) are plain strings defined
|
|
2
|
+
// at module level. They cannot use hooks. Consumers who need to translate these
|
|
3
|
+
// should override the action name by creating their own EntityAction objects or
|
|
4
|
+
// by using the entityActions prop with custom names for their locale.
|
|
1
5
|
import { DeleteIcon, EditIcon, FileCopyIcon } from "@firecms/ui";
|
|
2
6
|
import { EntityAction } from "../../types";
|
|
3
7
|
import { DeleteEntityDialog } from "../DeleteEntityDialog";
|