@firecms/core 3.5.1 → 3.5.2-canary.09e1281
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/CollectionCountBadge.d.ts +8 -0
- package/dist/components/EntityCollectionView/CollectionPathTitle.d.ts +24 -0
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +5 -0
- package/dist/components/EntityCollectionView/EntityIdHeaderWidget.d.ts +12 -0
- package/dist/components/EntityCollectionView/utils.d.ts +3 -3
- package/dist/components/HomePage/HomePageDnD.d.ts +4 -2
- package/dist/{de-CBOjCvsy.js → de-CUF9f7S-.js} +2 -1
- package/dist/{de-CBOjCvsy.js.map → de-CUF9f7S-.js.map} +1 -1
- package/dist/{editor-BSo_aS1I.js → editor-WZytSO_1.js} +172 -137
- package/dist/editor-WZytSO_1.js.map +1 -0
- package/dist/{fr-DRfttcG0.js → fr-DmkMX6hp.js} +2 -1
- package/dist/{fr-DRfttcG0.js.map → fr-DmkMX6hp.js.map} +1 -1
- package/dist/{hi-DwieOZNf.js → hi-BKuaMr7w.js} +2 -1
- package/dist/{hi-DwieOZNf.js.map → hi-BKuaMr7w.js.map} +1 -1
- package/dist/index.es.js +787 -638
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +946 -756
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useLeavePageConfirmation.d.ts +11 -0
- package/dist/{it-l2KXtx9n.js → it-BwQflFGz.js} +2 -1
- package/dist/{it-l2KXtx9n.js.map → it-BwQflFGz.js.map} +1 -1
- package/dist/{pl-DPZrdKhi.js → pl-BPsAvZvc.js} +2 -1
- package/dist/{pl-DPZrdKhi.js.map → pl-BPsAvZvc.js.map} +1 -1
- package/dist/{pt-BoHpabw1.js → pt-D5q7OQp1.js} +2 -1
- package/dist/{pt-BoHpabw1.js.map → pt-D5q7OQp1.js.map} +1 -1
- package/dist/types/side_dialogs_controller.d.ts +4 -2
- package/dist/types/translations.d.ts +1 -0
- package/package.json +3 -3
- package/src/components/EntityCollectionView/CollectionCountBadge.tsx +17 -0
- package/src/components/EntityCollectionView/CollectionPathTitle.tsx +68 -0
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +12 -111
- package/src/components/EntityCollectionView/EntityIdHeaderWidget.tsx +124 -0
- package/src/components/EntityCollectionView/utils.ts +7 -7
- package/src/components/HomePage/DefaultHomePage.tsx +2 -0
- package/src/components/HomePage/HomePageDnD.tsx +12 -4
- package/src/components/common/default_entity_actions.tsx +2 -1
- package/src/core/DefaultAppBar.tsx +12 -9
- package/src/core/EntityEditView.tsx +26 -1
- package/src/core/SideDialogs.tsx +6 -13
- package/src/editor/selectors/link-selector.tsx +37 -12
- package/src/hooks/useReferenceDialog.tsx +2 -2
- package/src/internal/useBuildSideDialogsController.tsx +44 -2
- package/src/internal/useLeavePageConfirmation.ts +25 -0
- package/src/locales/de.ts +1 -0
- package/src/locales/en.ts +1 -0
- package/src/locales/es.ts +1 -0
- package/src/locales/fr.ts +1 -0
- package/src/locales/hi.ts +1 -0
- package/src/locales/it.ts +1 -0
- package/src/locales/pl.ts +1 -0
- package/src/locales/pt.ts +1 -0
- package/src/types/side_dialogs_controller.tsx +4 -2
- package/src/types/translations.ts +1 -0
- package/dist/editor-BSo_aS1I.js.map +0 -1
- package/dist/internal/useUnsavedChangesDialog.d.ts +0 -12
- package/src/internal/useUnsavedChangesDialog.tsx +0 -142
|
@@ -45,8 +45,8 @@ export function useReferenceDialog<M extends Record<string, any>>(referenceDialo
|
|
|
45
45
|
}, [navigation, referenceDialogProps, sideDialogsController]);
|
|
46
46
|
|
|
47
47
|
const close = useCallback(() => {
|
|
48
|
-
sideDialogsController.close();
|
|
49
|
-
}, [sideDialogsController]);
|
|
48
|
+
sideDialogsController.close(`reference_${referenceDialogProps.path}`);
|
|
49
|
+
}, [sideDialogsController, referenceDialogProps.path]);
|
|
50
50
|
|
|
51
51
|
return {
|
|
52
52
|
open,
|
|
@@ -14,6 +14,9 @@ export function useBuildSideDialogsController(): SideDialogsController {
|
|
|
14
14
|
const routesStore = useRef<Record<string, SideDialogPanelProps>>({});
|
|
15
15
|
const routesCount = useRef<number>(0);
|
|
16
16
|
|
|
17
|
+
// The history entry each panel without a URL was opened on, by panel key.
|
|
18
|
+
const entryKeysOfPanelsWithoutUrl = useRef<Record<string, string>>({});
|
|
19
|
+
|
|
17
20
|
const updateSidePanels = (newPanels: SideDialogPanelProps[]) => {
|
|
18
21
|
sidePanelsRef.current = newPanels;
|
|
19
22
|
setSidePanels(newPanels);
|
|
@@ -22,20 +25,55 @@ export function useBuildSideDialogsController(): SideDialogsController {
|
|
|
22
25
|
useEffect(() => {
|
|
23
26
|
const state = location.state as any;
|
|
24
27
|
const panelKeys: string[] = state?.panels ?? [];
|
|
25
|
-
const
|
|
28
|
+
const panelsInHistory = panelKeys
|
|
26
29
|
.map(key => routesStore.current[key])
|
|
27
30
|
.filter(p => Boolean(p)) as SideDialogPanelProps[];
|
|
31
|
+
|
|
32
|
+
// A panel without a URL, like a reference dialog, pushes no history entry, so the
|
|
33
|
+
// entry under it does not list it, and going back to that entry, as closing a
|
|
34
|
+
// panel opened on top of it does, would drop it. It stays open for as long as
|
|
35
|
+
// what it was opened over does: the panel below it or, with none, the entry itself.
|
|
36
|
+
const keptPanels: SideDialogPanelProps[] = [];
|
|
37
|
+
let matched = 0;
|
|
38
|
+
for (const panel of sidePanelsRef.current) {
|
|
39
|
+
if (panelsInHistory[matched]?.key === panel.key) {
|
|
40
|
+
keptPanels.push(panel);
|
|
41
|
+
matched++;
|
|
42
|
+
} else if (!panel.urlPath &&
|
|
43
|
+
(keptPanels.length > 0 || entryKeysOfPanelsWithoutUrl.current[panel.key] === location.key)) {
|
|
44
|
+
keptPanels.push(panel);
|
|
45
|
+
} else {
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const newPanels = [...keptPanels, ...panelsInHistory.slice(matched)];
|
|
50
|
+
|
|
28
51
|
if (!equal(sidePanelsRef.current.map(p => p.key), newPanels.map(p => p.key))) {
|
|
29
52
|
updateSidePanels(newPanels);
|
|
30
53
|
}
|
|
31
54
|
}, [location]);
|
|
32
55
|
|
|
33
|
-
const close = useCallback(() => {
|
|
56
|
+
const close = useCallback((key?: string) => {
|
|
34
57
|
|
|
35
58
|
const currentPanels = sidePanelsRef.current;
|
|
36
59
|
if (currentPanels.length === 0)
|
|
37
60
|
return;
|
|
38
61
|
|
|
62
|
+
// A panel can ask to close itself while another one is open on top of it: the
|
|
63
|
+
// reference dialog does when an entity created from it is saved. Closing the top
|
|
64
|
+
// one instead would close that entity, and then the entity's own close would take
|
|
65
|
+
// the panel under the dialog with it. Only a panel without a URL can be taken out
|
|
66
|
+
// of the middle, since it has no history entry of its own. Should two panels share
|
|
67
|
+
// a key (a reference dialog opened from an entity created in another one for the
|
|
68
|
+
// same collection), it is the upper one.
|
|
69
|
+
const index = key !== undefined ? currentPanels.findLastIndex(p => p.key === key) : -1;
|
|
70
|
+
if (index !== -1 && index < currentPanels.length - 1 && !currentPanels[index].urlPath) {
|
|
71
|
+
updateSidePanels(currentPanels.filter((_, i) => i !== index));
|
|
72
|
+
if (routesCount.current > 0)
|
|
73
|
+
routesCount.current--;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
39
77
|
const lastSidePanel = currentPanels[currentPanels.length - 1];
|
|
40
78
|
const updatedPanels = [...currentPanels.slice(0, -1)];
|
|
41
79
|
updateSidePanels(updatedPanels);
|
|
@@ -65,6 +103,8 @@ export function useBuildSideDialogsController(): SideDialogsController {
|
|
|
65
103
|
|
|
66
104
|
newPanels.forEach((panel) => {
|
|
67
105
|
routesStore.current[panel.key] = panel;
|
|
106
|
+
if (!panel.urlPath)
|
|
107
|
+
entryKeysOfPanelsWithoutUrl.current[panel.key] = location.key;
|
|
68
108
|
});
|
|
69
109
|
routesCount.current = routesCount.current + newPanels.length;
|
|
70
110
|
|
|
@@ -95,6 +135,8 @@ export function useBuildSideDialogsController(): SideDialogsController {
|
|
|
95
135
|
const newPanels: SideDialogPanelProps[] = Array.isArray(panelProps) ? panelProps : [panelProps];
|
|
96
136
|
newPanels.forEach((panel) => {
|
|
97
137
|
routesStore.current[panel.key] = panel;
|
|
138
|
+
if (!panel.urlPath)
|
|
139
|
+
entryKeysOfPanelsWithoutUrl.current[panel.key] = location.key;
|
|
98
140
|
});
|
|
99
141
|
|
|
100
142
|
const baseLocation = (location.state as any)?.base_location ?? location;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Asks the browser to confirm leaving the page (reload, tab close, a link that
|
|
5
|
+
* loads another document) while `when` is true.
|
|
6
|
+
*
|
|
7
|
+
* Navigation inside the app is not intercepted: unsaved entity values are kept
|
|
8
|
+
* in the dirty entity cache, so they survive it. Cancelling link clicks here
|
|
9
|
+
* used to leave plain and new-tab links doing nothing, with no dialog shown.
|
|
10
|
+
*
|
|
11
|
+
* @param when - Whether leaving the page should be confirmed.
|
|
12
|
+
*/
|
|
13
|
+
export function useLeavePageConfirmation(when: boolean): void {
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (!when) return;
|
|
16
|
+
|
|
17
|
+
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
|
|
18
|
+
e.preventDefault();
|
|
19
|
+
e.returnValue = "";
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
23
|
+
return () => window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
24
|
+
}, [when]);
|
|
25
|
+
}
|
package/src/locales/de.ts
CHANGED
|
@@ -651,6 +651,7 @@ export const de: FireCMSTranslations = {
|
|
|
651
651
|
editor_cancel: "Abbrechen",
|
|
652
652
|
editor_remove_link: "Link entfernen",
|
|
653
653
|
editor_paste_or_type_link: "Link einfügen oder eintippen",
|
|
654
|
+
editor_invalid_url: "Ungültige URL",
|
|
654
655
|
editor_open_in_new_window: "In neuem Fenster öffnen",
|
|
655
656
|
editor_bold: "Fett",
|
|
656
657
|
editor_italic: "Kursiv",
|
package/src/locales/en.ts
CHANGED
|
@@ -665,6 +665,7 @@ export const en: FireCMSTranslations = {
|
|
|
665
665
|
editor_cancel: "Cancel",
|
|
666
666
|
editor_remove_link: "Remove link",
|
|
667
667
|
editor_paste_or_type_link: "Paste or type link",
|
|
668
|
+
editor_invalid_url: "Invalid URL",
|
|
668
669
|
editor_open_in_new_window: "Open in new window",
|
|
669
670
|
editor_bold: "Bold",
|
|
670
671
|
editor_italic: "Italic",
|
package/src/locales/es.ts
CHANGED
|
@@ -663,6 +663,7 @@ export const es: FireCMSTranslations = {
|
|
|
663
663
|
editor_cancel: "Cancelar",
|
|
664
664
|
editor_remove_link: "Eliminar enlace",
|
|
665
665
|
editor_paste_or_type_link: "Pega o escribe el enlace",
|
|
666
|
+
editor_invalid_url: "URL no válida",
|
|
666
667
|
editor_open_in_new_window: "Abrir en una ventana nueva",
|
|
667
668
|
editor_bold: "Negrita",
|
|
668
669
|
editor_italic: "Cursiva",
|
package/src/locales/fr.ts
CHANGED
|
@@ -651,6 +651,7 @@ export const fr: FireCMSTranslations = {
|
|
|
651
651
|
editor_cancel: "Annuler",
|
|
652
652
|
editor_remove_link: "Supprimer le lien",
|
|
653
653
|
editor_paste_or_type_link: "Coller ou taper le lien",
|
|
654
|
+
editor_invalid_url: "URL invalide",
|
|
654
655
|
editor_open_in_new_window: "Ouvrir dans une nouvelle fenêtre",
|
|
655
656
|
editor_bold: "Gras",
|
|
656
657
|
editor_italic: "Italique",
|
package/src/locales/hi.ts
CHANGED
|
@@ -651,6 +651,7 @@ export const hi: FireCMSTranslations = {
|
|
|
651
651
|
editor_cancel: "रद्द करें",
|
|
652
652
|
editor_remove_link: "लिंक हटाएं",
|
|
653
653
|
editor_paste_or_type_link: "लिंक पेस्ट करें या टाइप करें",
|
|
654
|
+
editor_invalid_url: "अमान्य URL",
|
|
654
655
|
editor_open_in_new_window: "नई विंडो में खोलें",
|
|
655
656
|
editor_bold: "बोल्ड",
|
|
656
657
|
editor_italic: "इटैलिक",
|
package/src/locales/it.ts
CHANGED
|
@@ -651,6 +651,7 @@ export const it: FireCMSTranslations = {
|
|
|
651
651
|
editor_cancel: "Annulla",
|
|
652
652
|
editor_remove_link: "Rimuovi link",
|
|
653
653
|
editor_paste_or_type_link: "Incolla o digita il link",
|
|
654
|
+
editor_invalid_url: "URL non valido",
|
|
654
655
|
editor_open_in_new_window: "Apri in una nuova finestra",
|
|
655
656
|
editor_bold: "Grassetto",
|
|
656
657
|
editor_italic: "Corsivo",
|
package/src/locales/pl.ts
CHANGED
|
@@ -655,6 +655,7 @@ export const pl: FireCMSTranslations = {
|
|
|
655
655
|
editor_cancel: "Anuluj",
|
|
656
656
|
editor_remove_link: "Usuń link",
|
|
657
657
|
editor_paste_or_type_link: "Wklej lub wpisz link",
|
|
658
|
+
editor_invalid_url: "Nieprawidłowy URL",
|
|
658
659
|
editor_open_in_new_window: "Otwórz w nowym oknie",
|
|
659
660
|
editor_bold: "Pogrubienie",
|
|
660
661
|
editor_italic: "Kursywa",
|
package/src/locales/pt.ts
CHANGED
|
@@ -660,6 +660,7 @@ export const pt: FireCMSTranslations = {
|
|
|
660
660
|
editor_cancel: "Cancelar",
|
|
661
661
|
editor_remove_link: "Remover ligação",
|
|
662
662
|
editor_paste_or_type_link: "Cole ou escreva a ligação",
|
|
663
|
+
editor_invalid_url: "URL inválido",
|
|
663
664
|
editor_open_in_new_window: "Abrir numa nova janela",
|
|
664
665
|
editor_bold: "Negrito",
|
|
665
666
|
editor_italic: "Itálico",
|
|
@@ -8,9 +8,11 @@ import { EntityFormProps } from "../form";
|
|
|
8
8
|
export interface SideDialogsController {
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Close the last panel
|
|
11
|
+
* Close the last panel.
|
|
12
|
+
* When the `key` of a panel without a URL is given, that panel is closed
|
|
13
|
+
* instead, even if other panels are open on top of it.
|
|
12
14
|
*/
|
|
13
|
-
close: () => void;
|
|
15
|
+
close: (key?: string) => void;
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* List of side panels currently open
|
|
@@ -708,6 +708,7 @@ export interface FireCMSTranslations {
|
|
|
708
708
|
editor_cancel: string;
|
|
709
709
|
editor_remove_link: string;
|
|
710
710
|
editor_paste_or_type_link: string;
|
|
711
|
+
editor_invalid_url: string;
|
|
711
712
|
editor_open_in_new_window: string;
|
|
712
713
|
editor_bold: string;
|
|
713
714
|
editor_italic: string;
|