@firecms/core 3.5.2-canary.09e1281 → 3.5.2-canary.c5764a3
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/EntityCollectionView.d.ts +0 -5
- package/dist/components/EntityCollectionView/utils.d.ts +3 -3
- package/dist/index.es.js +676 -817
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +670 -811
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useUnsavedChangesDialog.d.ts +12 -0
- package/dist/types/side_dialogs_controller.d.ts +2 -4
- package/package.json +3 -3
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +111 -12
- package/src/components/EntityCollectionView/utils.ts +7 -7
- package/src/components/common/default_entity_actions.tsx +1 -2
- package/src/core/DefaultAppBar.tsx +9 -12
- package/src/core/EntityEditView.tsx +1 -26
- package/src/core/SideDialogs.tsx +13 -6
- package/src/hooks/useReferenceDialog.tsx +2 -2
- package/src/internal/useBuildSideDialogsController.tsx +2 -44
- package/src/internal/useUnsavedChangesDialog.tsx +142 -0
- package/src/types/side_dialogs_controller.tsx +2 -4
- package/dist/components/EntityCollectionView/CollectionCountBadge.d.ts +0 -8
- package/dist/components/EntityCollectionView/CollectionPathTitle.d.ts +0 -24
- package/dist/components/EntityCollectionView/EntityIdHeaderWidget.d.ts +0 -12
- package/dist/internal/useLeavePageConfirmation.d.ts +0 -11
- package/src/components/EntityCollectionView/CollectionCountBadge.tsx +0 -17
- package/src/components/EntityCollectionView/CollectionPathTitle.tsx +0 -68
- package/src/components/EntityCollectionView/EntityIdHeaderWidget.tsx +0 -124
- package/src/internal/useLeavePageConfirmation.ts +0 -25
|
@@ -8,11 +8,9 @@ import { EntityFormProps } from "../form";
|
|
|
8
8
|
export interface SideDialogsController {
|
|
9
9
|
|
|
10
10
|
/**
|
|
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.
|
|
11
|
+
* Close the last panel
|
|
14
12
|
*/
|
|
15
|
-
close: (
|
|
13
|
+
close: () => void;
|
|
16
14
|
|
|
17
15
|
/**
|
|
18
16
|
* List of side panels currently open
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
/**
|
|
3
|
-
* Number of entities in a collection, as shown next to its name.
|
|
4
|
-
* `undefined` renders nothing, `null` a loading placeholder.
|
|
5
|
-
*/
|
|
6
|
-
export declare function CollectionCountBadge({ count }: {
|
|
7
|
-
count: number | null | undefined;
|
|
8
|
-
}): React.JSX.Element | null;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
/**
|
|
3
|
-
* A name and its entity count, under what is above it: breadcrumbs folded on two lines
|
|
4
|
-
* for where a row of them would not fit.
|
|
5
|
-
*/
|
|
6
|
-
export declare function PathTitle({ parents, name, count, className }: {
|
|
7
|
-
parents: string[];
|
|
8
|
-
name: string;
|
|
9
|
-
/** `undefined` shows no count, `null` a loading one. */
|
|
10
|
-
count: number | null | undefined;
|
|
11
|
-
className?: string;
|
|
12
|
-
}): React.JSX.Element;
|
|
13
|
-
/**
|
|
14
|
-
* A collection's name and entity count, under the collections and entities above it,
|
|
15
|
-
* the same things the app bar's breadcrumbs show. A side panel covers those, so it
|
|
16
|
-
* shows a subcollection's in its own top bar.
|
|
17
|
-
*/
|
|
18
|
-
export declare function CollectionPathTitle({ path, name, count }: {
|
|
19
|
-
/** The escaped chain, as in `fullIdPath`. */
|
|
20
|
-
path: string;
|
|
21
|
-
name: string;
|
|
22
|
-
/** `undefined` shows no count, `null` a loading one. */
|
|
23
|
-
count: number | null | undefined;
|
|
24
|
-
}): React.JSX.Element;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { EntityCollection } from "../../types";
|
|
3
|
-
/**
|
|
4
|
-
* "Find by id" in the header of a collection's id column, listing the ids opened in it lately.
|
|
5
|
-
*/
|
|
6
|
-
export declare function EntityIdHeaderWidget({ collection, path, pathSegments, fullIdPath }: {
|
|
7
|
-
collection: EntityCollection;
|
|
8
|
-
path: string;
|
|
9
|
-
/** `path` split at its real segment boundaries, when the caller knows them. */
|
|
10
|
-
pathSegments?: string[];
|
|
11
|
-
fullIdPath: string;
|
|
12
|
-
}): React.JSX.Element;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Asks the browser to confirm leaving the page (reload, tab close, a link that
|
|
3
|
-
* loads another document) while `when` is true.
|
|
4
|
-
*
|
|
5
|
-
* Navigation inside the app is not intercepted: unsaved entity values are kept
|
|
6
|
-
* in the dirty entity cache, so they survive it. Cancelling link clicks here
|
|
7
|
-
* used to leave plain and new-tab links doing nothing, with no dialog shown.
|
|
8
|
-
*
|
|
9
|
-
* @param when - Whether leaving the page should be confirmed.
|
|
10
|
-
*/
|
|
11
|
-
export declare function useLeavePageConfirmation(when: boolean): void;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Skeleton } from "@firecms/ui";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Number of entities in a collection, as shown next to its name.
|
|
6
|
-
* `undefined` renders nothing, `null` a loading placeholder.
|
|
7
|
-
*/
|
|
8
|
-
export function CollectionCountBadge({ count }: { count: number | null | undefined }) {
|
|
9
|
-
if (count === undefined)
|
|
10
|
-
return null;
|
|
11
|
-
if (count === null)
|
|
12
|
-
return <Skeleton className="w-8 h-4 rounded-md"/>;
|
|
13
|
-
return <span
|
|
14
|
-
className="text-xs text-surface-accent-500 dark:text-surface-accent-400 bg-surface-100 dark:bg-surface-700 px-1 py-0 rounded">
|
|
15
|
-
{count}
|
|
16
|
-
</span>;
|
|
17
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import React, { useMemo } from "react";
|
|
2
|
-
import { cls, Typography } from "@firecms/ui";
|
|
3
|
-
import { useNavigationController } from "../../hooks/useNavigationController";
|
|
4
|
-
import { getNavigationEntriesFromPath } from "../../util/navigation_from_path";
|
|
5
|
-
import { CollectionCountBadge } from "./CollectionCountBadge";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A name and its entity count, under what is above it: breadcrumbs folded on two lines
|
|
9
|
-
* for where a row of them would not fit.
|
|
10
|
-
*/
|
|
11
|
-
export function PathTitle({
|
|
12
|
-
parents,
|
|
13
|
-
name,
|
|
14
|
-
count,
|
|
15
|
-
className
|
|
16
|
-
}: {
|
|
17
|
-
parents: string[],
|
|
18
|
-
name: string,
|
|
19
|
-
/** `undefined` shows no count, `null` a loading one. */
|
|
20
|
-
count: number | null | undefined,
|
|
21
|
-
className?: string
|
|
22
|
-
}) {
|
|
23
|
-
return <div className={cls("flex flex-col", className)}>
|
|
24
|
-
{parents.length > 0 && <Typography variant={"caption"} color={"secondary"} noWrap>
|
|
25
|
-
{parents.join(" / ")}
|
|
26
|
-
</Typography>}
|
|
27
|
-
<div className="flex flex-row items-center gap-2 min-w-0">
|
|
28
|
-
<Typography variant={"body2"} noWrap className={"font-medium"}>
|
|
29
|
-
{name}
|
|
30
|
-
</Typography>
|
|
31
|
-
<CollectionCountBadge count={count}/>
|
|
32
|
-
</div>
|
|
33
|
-
</div>;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* A collection's name and entity count, under the collections and entities above it,
|
|
38
|
-
* the same things the app bar's breadcrumbs show. A side panel covers those, so it
|
|
39
|
-
* shows a subcollection's in its own top bar.
|
|
40
|
-
*/
|
|
41
|
-
export function CollectionPathTitle({
|
|
42
|
-
path,
|
|
43
|
-
name,
|
|
44
|
-
count
|
|
45
|
-
}: {
|
|
46
|
-
/** The escaped chain, as in `fullIdPath`. */
|
|
47
|
-
path: string,
|
|
48
|
-
name: string,
|
|
49
|
-
/** `undefined` shows no count, `null` a loading one. */
|
|
50
|
-
count: number | null | undefined
|
|
51
|
-
}) {
|
|
52
|
-
const navigation = useNavigationController();
|
|
53
|
-
const parents = useMemo(() => getNavigationEntriesFromPath({
|
|
54
|
-
path,
|
|
55
|
-
collections: navigation.collections ?? []
|
|
56
|
-
})
|
|
57
|
-
.slice(0, -1)
|
|
58
|
-
.map(entry => entry.type === "entity"
|
|
59
|
-
? entry.entityId
|
|
60
|
-
: entry.type === "collection" ? entry.collection.name : entry.view.name),
|
|
61
|
-
[path, navigation.collections]);
|
|
62
|
-
|
|
63
|
-
// it keeps its width, up to the cap, and the tabs next to it scroll instead
|
|
64
|
-
return <PathTitle parents={parents}
|
|
65
|
-
name={name}
|
|
66
|
-
count={count}
|
|
67
|
-
className={"shrink-0 mx-2 max-w-[140px] sm:max-w-[240px] lg:max-w-[320px]"}/>;
|
|
68
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Button, cls, focusedDisabled, IconButton, KeyboardTabIcon, Popover, SearchIcon, Tooltip } from "@firecms/ui";
|
|
3
|
-
import { EntityCollection, EntityReference } from "../../types";
|
|
4
|
-
import { navigateToEntity } from "../../util/navigation_utils";
|
|
5
|
-
import { ReferencePreview } from "../../preview";
|
|
6
|
-
import { useNavigationController } from "../../hooks/useNavigationController";
|
|
7
|
-
import { useSideEntityController } from "../../hooks/useSideEntityController";
|
|
8
|
-
import { useTranslation } from "../../hooks/useTranslation";
|
|
9
|
-
import { addRecentId, getRecentIds } from "./utils";
|
|
10
|
-
|
|
11
|
-
const DEFAULT_ENTITY_OPEN_MODE: "side_panel" | "full_screen" = "side_panel";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* "Find by id" in the header of a collection's id column, listing the ids opened in it lately.
|
|
15
|
-
*/
|
|
16
|
-
export function EntityIdHeaderWidget({
|
|
17
|
-
collection,
|
|
18
|
-
path,
|
|
19
|
-
pathSegments,
|
|
20
|
-
fullIdPath
|
|
21
|
-
}: {
|
|
22
|
-
collection: EntityCollection,
|
|
23
|
-
path: string,
|
|
24
|
-
/** `path` split at its real segment boundaries, when the caller knows them. */
|
|
25
|
-
pathSegments?: string[],
|
|
26
|
-
fullIdPath: string
|
|
27
|
-
}) {
|
|
28
|
-
|
|
29
|
-
const navigation = useNavigationController();
|
|
30
|
-
const [openPopup, setOpenPopup] = React.useState(false);
|
|
31
|
-
const [searchString, setSearchString] = React.useState("");
|
|
32
|
-
// Kept per full path rather than per collection: a subcollection has the same id under
|
|
33
|
-
// every parent, and an id found under one parent does not exist under the others.
|
|
34
|
-
const [recentIds, setRecentIds] = React.useState<string[]>(() => getRecentIds(fullIdPath));
|
|
35
|
-
const sideEntityController = useSideEntityController();
|
|
36
|
-
const { t } = useTranslation();
|
|
37
|
-
|
|
38
|
-
const openEntityMode = collection?.openEntityMode ?? DEFAULT_ENTITY_OPEN_MODE;
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<Tooltip title={!openPopup ? t("find_by_id") : undefined} asChild={false}>
|
|
42
|
-
<Popover
|
|
43
|
-
open={openPopup}
|
|
44
|
-
onOpenChange={(open) => {
|
|
45
|
-
// rows opened since this header mounted are recent too
|
|
46
|
-
if (open) setRecentIds(getRecentIds(fullIdPath));
|
|
47
|
-
setOpenPopup(open);
|
|
48
|
-
}}
|
|
49
|
-
sideOffset={0}
|
|
50
|
-
align={"start"}
|
|
51
|
-
alignOffset={-117}
|
|
52
|
-
trigger={
|
|
53
|
-
<IconButton size={"small"}>
|
|
54
|
-
<SearchIcon size={"small"} />
|
|
55
|
-
</IconButton>
|
|
56
|
-
}>
|
|
57
|
-
<div
|
|
58
|
-
className={cls("my-2 rounded-lg bg-surface-50 dark:bg-surface-950 text-surface-900 dark:text-white")}>
|
|
59
|
-
<form noValidate={true}
|
|
60
|
-
onSubmit={(e) => {
|
|
61
|
-
e.preventDefault();
|
|
62
|
-
const entityId = searchString.trim();
|
|
63
|
-
// Enter submits even while the button is disabled, and an empty
|
|
64
|
-
// id would open a new entity instead
|
|
65
|
-
if (!entityId) return;
|
|
66
|
-
setOpenPopup(false);
|
|
67
|
-
setRecentIds(addRecentId(fullIdPath, entityId));
|
|
68
|
-
navigateToEntity({
|
|
69
|
-
openEntityMode,
|
|
70
|
-
collection,
|
|
71
|
-
entityId,
|
|
72
|
-
path,
|
|
73
|
-
pathSegments,
|
|
74
|
-
fullIdPath,
|
|
75
|
-
sideEntityController,
|
|
76
|
-
navigation
|
|
77
|
-
})
|
|
78
|
-
}}
|
|
79
|
-
className={"w-96 max-w-full"}>
|
|
80
|
-
|
|
81
|
-
<div className="flex p-2 w-full gap-2">
|
|
82
|
-
<input
|
|
83
|
-
autoFocus={openPopup}
|
|
84
|
-
placeholder={t("find_entity_by_id")}
|
|
85
|
-
// size={"small"}
|
|
86
|
-
onChange={(e) => {
|
|
87
|
-
setSearchString(e.target.value);
|
|
88
|
-
}}
|
|
89
|
-
value={searchString}
|
|
90
|
-
className={"rounded-lg bg-white dark:bg-surface-800 flex-grow bg-transparent outline-none p-2 " + focusedDisabled} />
|
|
91
|
-
<Button variant={"text"}
|
|
92
|
-
disabled={!(searchString.trim())}
|
|
93
|
-
type={"submit"}
|
|
94
|
-
><KeyboardTabIcon /></Button>
|
|
95
|
-
</div>
|
|
96
|
-
</form>
|
|
97
|
-
{recentIds && recentIds.length > 0 && <div className="flex flex-col gap-2 p-2">
|
|
98
|
-
{recentIds.map(id => (
|
|
99
|
-
<ReferencePreview reference={new EntityReference(id, path, undefined, pathSegments)}
|
|
100
|
-
key={id}
|
|
101
|
-
hover={true}
|
|
102
|
-
onClick={() => {
|
|
103
|
-
setOpenPopup(false);
|
|
104
|
-
navigateToEntity({
|
|
105
|
-
openEntityMode,
|
|
106
|
-
collection,
|
|
107
|
-
entityId: id,
|
|
108
|
-
path,
|
|
109
|
-
pathSegments,
|
|
110
|
-
fullIdPath,
|
|
111
|
-
sideEntityController,
|
|
112
|
-
navigation
|
|
113
|
-
})
|
|
114
|
-
}}
|
|
115
|
-
includeEntityLink={false}
|
|
116
|
-
size={"small"} />
|
|
117
|
-
))}
|
|
118
|
-
</div>}
|
|
119
|
-
</div>
|
|
120
|
-
</Popover>
|
|
121
|
-
|
|
122
|
-
</Tooltip>
|
|
123
|
-
);
|
|
124
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
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
|
-
}
|