@compill/admin 1.0.100 → 1.0.102
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/index.js +50 -0
- package/{src → dist}/lib/SectionTitle.d.ts +0 -1
- package/dist/lib/SectionTitle.jsx +3 -0
- package/{src → dist}/lib/breadcrumbs/BreadCrumbs.d.ts +0 -1
- package/dist/lib/breadcrumbs/BreadCrumbs.jsx +43 -0
- package/dist/lib/buttons/DialogButton.jsx +17 -0
- package/{src → dist}/lib/buttons/InvalidateButton.d.ts +0 -1
- package/dist/lib/buttons/InvalidateButton.jsx +10 -0
- package/{src → dist}/lib/buttons/NavigateButton.d.ts +0 -1
- package/dist/lib/buttons/NavigateButton.jsx +13 -0
- package/{src → dist}/lib/buttons/PublishButton.d.ts +0 -1
- package/dist/lib/buttons/PublishButton.jsx +18 -0
- package/{src → dist}/lib/buttons/UpdateButton.d.ts +0 -1
- package/dist/lib/buttons/UpdateButton.jsx +12 -0
- package/{src → dist}/lib/buttons/ViewButton.d.ts +1 -2
- package/dist/lib/buttons/ViewButton.jsx +14 -0
- package/{src → dist}/lib/cells/OrderCell.d.ts +0 -1
- package/dist/lib/cells/OrderCell.jsx +35 -0
- package/{src → dist}/lib/json/DetailsView.d.ts +0 -1
- package/dist/lib/json/DetailsView.jsx +96 -0
- package/{src → dist}/lib/json/EditItemView.d.ts +0 -1
- package/dist/lib/json/EditItemView.jsx +5 -0
- package/{src → dist}/lib/json/MultiQueryWrapper.d.ts +0 -1
- package/dist/lib/json/MultiQueryWrapper.jsx +60 -0
- package/{src → dist}/lib/json/QueryWrapper.d.ts +0 -1
- package/dist/lib/json/QueryWrapper.jsx +28 -0
- package/{src → dist}/lib/json/ScreenRenderer.d.ts +0 -1
- package/dist/lib/json/ScreenRenderer.jsx +18 -0
- package/{src → dist}/lib/json/ScreenTopBar.d.ts +0 -1
- package/dist/lib/json/ScreenTopBar.jsx +39 -0
- package/{src → dist}/lib/json/TabbedView.d.ts +0 -1
- package/dist/lib/json/TabbedView.jsx +28 -0
- package/{src → dist}/lib/json/buttons/ActionButton.d.ts +0 -1
- package/dist/lib/json/buttons/ActionButton.jsx +13 -0
- package/{src → dist}/lib/json/buttons/ConfirmationActionButton.d.ts +0 -1
- package/dist/lib/json/buttons/ConfirmationActionButton.jsx +37 -0
- package/{src → dist}/lib/json/dialog/DialogRenderer.d.ts +0 -1
- package/dist/lib/json/dialog/DialogRenderer.jsx +13 -0
- package/dist/lib/json/dialog/ItemDeleteDialog.jsx +36 -0
- package/dist/lib/json/dialog/ItemEditDialog.jsx +124 -0
- package/{src → dist}/lib/json/dialog/MultiQueryWrapperDialog.d.ts +0 -1
- package/dist/lib/json/dialog/MultiQueryWrapperDialog.jsx +22 -0
- package/{src → dist}/lib/json/dialog/QueryWrapperDialog.d.ts +0 -1
- package/dist/lib/json/dialog/QueryWrapperDialog.jsx +19 -0
- package/{src → dist}/lib/json/table/RefreshButton.d.ts +0 -1
- package/dist/lib/json/table/RefreshButton.jsx +12 -0
- package/{src → dist}/lib/json/table/TableRowActionsView.d.ts +0 -1
- package/dist/lib/json/table/TableRowActionsView.jsx +45 -0
- package/{src → dist}/lib/json/table/TableRowPublishPostButton.d.ts +0 -1
- package/dist/lib/json/table/TableRowPublishPostButton.jsx +21 -0
- package/{src → dist}/lib/json/table/TableView.d.ts +0 -1
- package/dist/lib/json/table/TableView.jsx +100 -0
- package/dist/lib/json/table/TableViewContext.jsx +57 -0
- package/dist/lib/json/table/useTableProps.jsx +56 -0
- package/{src → dist}/lib/json/types/DetailsView.d.ts +0 -1
- package/dist/lib/json/types/DetailsView.js +1 -0
- package/dist/lib/json/types/EditItemDialog.js +1 -0
- package/dist/lib/json/types/MultiQueryWrapper.js +1 -0
- package/dist/lib/json/types/MultiQueryWrapperDialog.js +1 -0
- package/dist/lib/json/types/QueryWrapper.js +1 -0
- package/dist/lib/json/types/QueryWrapperDialog.js +1 -0
- package/dist/lib/json/types/ScreenConfig.js +1 -0
- package/{src → dist}/lib/json/types/TabbedView.d.ts +0 -1
- package/dist/lib/json/types/TabbedView.js +1 -0
- package/{src → dist}/lib/json/types/TableView.d.ts +0 -1
- package/dist/lib/json/types/TableView.js +1 -0
- package/{src → dist}/lib/layout/AdminLayout.d.ts +0 -1
- package/dist/lib/layout/AdminLayout.jsx +24 -0
- package/{src → dist}/lib/layout/ButtonBar.d.ts +1 -1
- package/dist/lib/layout/ButtonBar.jsx +29 -0
- package/{src → dist}/lib/layout/Content.d.ts +0 -1
- package/dist/lib/layout/Content.jsx +10 -0
- package/{src → dist}/lib/layout/PageTitleBar.d.ts +0 -1
- package/dist/lib/layout/PageTitleBar.jsx +12 -0
- package/{src → dist}/lib/layout/Sidebar.d.ts +0 -1
- package/dist/lib/layout/Sidebar.jsx +24 -0
- package/{src → dist}/lib/layout/menu/Menu.d.ts +0 -1
- package/dist/lib/layout/menu/Menu.jsx +30 -0
- package/{src → dist}/lib/layout/menu/MenuButton.d.ts +0 -1
- package/dist/lib/layout/menu/MenuButton.jsx +7 -0
- package/dist/lib/layout/menu/MenuConfig.js +1 -0
- package/{src → dist}/lib/layout/menu/MenuItem.d.ts +0 -1
- package/dist/lib/layout/menu/MenuItem.jsx +20 -0
- package/{src → dist}/lib/layout/menu/NextMenuItem.d.ts +0 -1
- package/dist/lib/layout/menu/NextMenuItem.jsx +20 -0
- package/{src → dist}/lib/layout/menu/SelectedIndicator.d.ts +0 -1
- package/dist/lib/layout/menu/SelectedIndicator.jsx +3 -0
- package/{src → dist}/lib/layout/menu/UserBlock.d.ts +1 -2
- package/dist/lib/layout/menu/UserBlock.jsx +55 -0
- package/{src → dist}/lib/modal/AttachDialog.d.ts +0 -1
- package/dist/lib/modal/AttachDialog.jsx +109 -0
- package/dist/lib/modal/FormActionDialog.jsx +46 -0
- package/{src → dist}/lib/page/PageContainer.d.ts +0 -1
- package/dist/lib/page/PageContainer.jsx +4 -0
- package/{src → dist}/lib/page/PageContentEditor.d.ts +0 -1
- package/dist/lib/page/PageContentEditor.jsx +11 -0
- package/{src → dist}/lib/page/PageMain.d.ts +0 -1
- package/dist/lib/page/PageMain.jsx +4 -0
- package/dist/lib/page/PageQueryStateContainer.jsx +15 -0
- package/{src → dist}/lib/page/PageSectionTitle.d.ts +0 -1
- package/dist/lib/page/PageSectionTitle.jsx +3 -0
- package/{src → dist}/lib/page/PageSidebar.d.ts +0 -1
- package/dist/lib/page/PageSidebar.jsx +3 -0
- package/{src → dist}/lib/page/PageSidebarSection.d.ts +0 -1
- package/dist/lib/page/PageSidebarSection.jsx +7 -0
- package/dist/lib/page/PageStateContainer.jsx +9 -0
- package/{src → dist}/lib/page/PageSubSectionTitle.d.ts +0 -1
- package/dist/lib/page/PageSubSectionTitle.jsx +3 -0
- package/{src → dist}/lib/page/PageTitle.d.ts +0 -1
- package/dist/lib/page/PageTitle.jsx +3 -0
- package/dist/lib/page/PageTopBar.jsx +92 -0
- package/{src → dist}/lib/status/StatusBadge.d.ts +0 -1
- package/dist/lib/status/StatusBadge.jsx +20 -0
- package/dist/lib/table/TableColumnButton.d.ts +1 -0
- package/dist/lib/table/TableColumnButton.jsx +53 -0
- package/{src → dist}/lib/table/TableContainer.d.ts +0 -1
- package/dist/lib/table/TableContainer.jsx +11 -0
- package/dist/lib/table/TableContainerContext.jsx +39 -0
- package/{src → dist}/lib/table/TableCreateButton.d.ts +0 -1
- package/dist/lib/table/TableCreateButton.jsx +9 -0
- package/{src → dist}/lib/table/TableFilterButton.d.ts +0 -1
- package/dist/lib/table/TableFilterButton.jsx +16 -0
- package/{src → dist}/lib/table/TableFilters.d.ts +0 -1
- package/dist/lib/table/TableFilters.jsx +46 -0
- package/{src → dist}/lib/table/TableMassActions.d.ts +0 -1
- package/dist/lib/table/TableMassActions.jsx +15 -0
- package/{src → dist}/lib/table/TableRowActionBar.d.ts +0 -1
- package/dist/lib/table/TableRowActionBar.jsx +14 -0
- package/{src → dist}/lib/table/TableRowActionButton.d.ts +0 -1
- package/dist/lib/table/TableRowActionButton.jsx +7 -0
- package/{src → dist}/lib/table/TableRowActionDialogButton.d.ts +1 -2
- package/dist/lib/table/TableRowActionDialogButton.jsx +8 -0
- package/{src → dist}/lib/table/TableRowDeleteButton.d.ts +0 -1
- package/dist/lib/table/TableRowDeleteButton.jsx +5 -0
- package/{src → dist}/lib/table/TableRowEditButton.d.ts +0 -1
- package/dist/lib/table/TableRowEditButton.jsx +7 -0
- package/{src → dist}/lib/table/TableRowNavigateButton.d.ts +0 -1
- package/dist/lib/table/TableRowNavigateButton.jsx +13 -0
- package/{src → dist}/lib/table/TableRowPublishPostButton.d.ts +0 -1
- package/dist/lib/table/TableRowPublishPostButton.jsx +18 -0
- package/{src → dist}/lib/table/TableRowViewButton.d.ts +0 -1
- package/dist/lib/table/TableRowViewButton.jsx +12 -0
- package/{src → dist}/lib/table/TableTopBar.d.ts +1 -2
- package/dist/lib/table/TableTopBar.jsx +17 -0
- package/package.json +60 -4
- package/README.md +0 -7
- package/index.cjs.d.ts +0 -1
- package/index.cjs.js +0 -3710
- package/index.esm.d.ts +0 -1
- package/index.esm.js +0 -3662
- package/src/lib/table/TableColumnButton.d.ts +0 -0
- /package/{src → dist}/index.d.ts +0 -0
- /package/{src → dist}/lib/buttons/DialogButton.d.ts +0 -0
- /package/{src → dist}/lib/json/dialog/ItemDeleteDialog.d.ts +0 -0
- /package/{src → dist}/lib/json/dialog/ItemEditDialog.d.ts +0 -0
- /package/{src → dist}/lib/json/table/TableViewContext.d.ts +0 -0
- /package/{src → dist}/lib/json/table/useTableProps.d.ts +0 -0
- /package/{src → dist}/lib/json/types/EditItemDialog.d.ts +0 -0
- /package/{src → dist}/lib/json/types/MultiQueryWrapper.d.ts +0 -0
- /package/{src → dist}/lib/json/types/MultiQueryWrapperDialog.d.ts +0 -0
- /package/{src → dist}/lib/json/types/QueryWrapper.d.ts +0 -0
- /package/{src → dist}/lib/json/types/QueryWrapperDialog.d.ts +0 -0
- /package/{src → dist}/lib/json/types/ScreenConfig.d.ts +0 -0
- /package/{src → dist}/lib/layout/menu/MenuConfig.d.ts +0 -0
- /package/{src → dist}/lib/modal/FormActionDialog.d.ts +0 -0
- /package/{src → dist}/lib/page/PageQueryStateContainer.d.ts +0 -0
- /package/{src → dist}/lib/page/PageStateContainer.d.ts +0 -0
- /package/{src → dist}/lib/page/PageTopBar.d.ts +0 -0
- /package/{src → dist}/lib/table/TableContainerContext.d.ts +0 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export * from "./lib/SectionTitle";
|
|
2
|
+
export * from "./lib/breadcrumbs/BreadCrumbs";
|
|
3
|
+
export * from "./lib/buttons/DialogButton";
|
|
4
|
+
export * from "./lib/buttons/InvalidateButton";
|
|
5
|
+
export * from "./lib/buttons/NavigateButton";
|
|
6
|
+
export * from "./lib/buttons/PublishButton";
|
|
7
|
+
export * from "./lib/buttons/UpdateButton";
|
|
8
|
+
export * from "./lib/buttons/ViewButton";
|
|
9
|
+
export * from "./lib/cells/OrderCell";
|
|
10
|
+
export * from "./lib/json/ScreenRenderer";
|
|
11
|
+
export * from "./lib/json/dialog/ItemEditDialog";
|
|
12
|
+
export * from "./lib/json/dialog/ItemDeleteDialog";
|
|
13
|
+
export * from "./lib/json/types/DetailsView";
|
|
14
|
+
export * from "./lib/json/types/EditItemDialog";
|
|
15
|
+
export * from "./lib/json/types/MultiQueryWrapper";
|
|
16
|
+
export * from "./lib/json/types/QueryWrapper";
|
|
17
|
+
export * from "./lib/json/types/QueryWrapperDialog";
|
|
18
|
+
export * from "./lib/json/types/ScreenConfig";
|
|
19
|
+
export * from "./lib/json/types/TabbedView";
|
|
20
|
+
export * from "./lib/json/types/TableView";
|
|
21
|
+
export * from "./lib/layout/AdminLayout";
|
|
22
|
+
export * from "./lib/layout/ButtonBar";
|
|
23
|
+
export * from "./lib/layout/menu/Menu";
|
|
24
|
+
export * from "./lib/layout/menu/MenuConfig";
|
|
25
|
+
export * from "./lib/modal/AttachDialog";
|
|
26
|
+
export * from "./lib/modal/FormActionDialog";
|
|
27
|
+
export * from "./lib/page/PageContainer";
|
|
28
|
+
export * from "./lib/page/PageContentEditor";
|
|
29
|
+
export * from "./lib/page/PageMain";
|
|
30
|
+
export * from "./lib/page/PageQueryStateContainer";
|
|
31
|
+
export * from "./lib/page/PageSectionTitle";
|
|
32
|
+
export * from "./lib/page/PageSidebar";
|
|
33
|
+
export * from "./lib/page/PageSidebarSection";
|
|
34
|
+
export * from "./lib/page/PageStateContainer";
|
|
35
|
+
export * from "./lib/page/PageSubSectionTitle";
|
|
36
|
+
export * from "./lib/page/PageTitle";
|
|
37
|
+
export * from "./lib/page/PageTopBar";
|
|
38
|
+
export * from "./lib/status/StatusBadge";
|
|
39
|
+
export * from "./lib/table/TableContainer";
|
|
40
|
+
export * from "./lib/table/TableCreateButton";
|
|
41
|
+
export * from "./lib/table/TableFilterButton";
|
|
42
|
+
export * from "./lib/table/TableRowActionBar";
|
|
43
|
+
export * from "./lib/table/TableRowActionButton";
|
|
44
|
+
export * from "./lib/table/TableRowActionDialogButton";
|
|
45
|
+
export * from "./lib/table/TableRowDeleteButton";
|
|
46
|
+
export * from "./lib/table/TableRowEditButton";
|
|
47
|
+
export * from "./lib/table/TableRowNavigateButton";
|
|
48
|
+
export * from "./lib/table/TableRowPublishPostButton";
|
|
49
|
+
export * from "./lib/table/TableRowViewButton";
|
|
50
|
+
export * from "./lib/table/TableTopBar";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useApiQuery } from "@compill/api";
|
|
2
|
+
import { Shimmer } from "@compill/components";
|
|
3
|
+
import { mdiCircleSmall } from "@mdi/js";
|
|
4
|
+
import { Icon } from "@valerya/ui";
|
|
5
|
+
import { isArray } from "es-toolkit/compat";
|
|
6
|
+
import Link from "next/link";
|
|
7
|
+
import { useParams } from "react-router-dom";
|
|
8
|
+
export function Breadcrumbs({ breadcrumbs, ...props }) {
|
|
9
|
+
if (isArray(breadcrumbs)) {
|
|
10
|
+
return (<div dflex alignItems="center" trait="typo.h5" {...props}>
|
|
11
|
+
{breadcrumbs.map((b, index) => <BreadcrumbItem key={index} breadcrumb={b} showSeparator={index > 0}/>)}
|
|
12
|
+
</div>);
|
|
13
|
+
}
|
|
14
|
+
return <QueryBreadcrumbs queryFn={breadcrumbs.queryFn} queryField={breadcrumbs.queryField} generate={breadcrumbs.generate}/>;
|
|
15
|
+
}
|
|
16
|
+
function QueryBreadcrumbs({ queryFn, queryField, generate, ...props }) {
|
|
17
|
+
const params = useParams();
|
|
18
|
+
const id = queryField ? params[queryField] : undefined;
|
|
19
|
+
const { data, isLoading, isError } = useApiQuery([""], queryFn, id);
|
|
20
|
+
if (isLoading || isError) {
|
|
21
|
+
return (<div dflex alignItems="center">
|
|
22
|
+
<Shimmer h="8" w="24"/>
|
|
23
|
+
<Icon path={mdiCircleSmall} mx="1"/>
|
|
24
|
+
<Shimmer h="8" w="20"/>
|
|
25
|
+
</div>);
|
|
26
|
+
}
|
|
27
|
+
const breadcrumbs = generate(data);
|
|
28
|
+
return (<div dflex alignItems="center" trait="typo.h5" {...props}>
|
|
29
|
+
{breadcrumbs.map((b, index) => <BreadcrumbItem key={index} breadcrumb={b} showSeparator={index > 0}/>)}
|
|
30
|
+
</div>);
|
|
31
|
+
}
|
|
32
|
+
function BreadcrumbItem({ breadcrumb, showSeparator }) {
|
|
33
|
+
return (<>
|
|
34
|
+
{showSeparator && <Icon path={mdiCircleSmall} mx="1"/>}
|
|
35
|
+
<Link href={`/${breadcrumb.path || "#"}`}>
|
|
36
|
+
<span
|
|
37
|
+
// onClick={breadcrumb.path ? handleClick : undefined}
|
|
38
|
+
hover_textDecoration={breadcrumb.path ? "underline" : undefined} cursor={breadcrumb.path ? "pointer" : undefined}>
|
|
39
|
+
{breadcrumb.label}
|
|
40
|
+
</span>
|
|
41
|
+
</Link>
|
|
42
|
+
</>);
|
|
43
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Button } from "@valerya/ui";
|
|
2
|
+
import React from "react";
|
|
3
|
+
export function DialogButton({ buildDialog, ...props }) {
|
|
4
|
+
const [showDialog, setShowDialog] = React.useState(false);
|
|
5
|
+
const onShowDialog = React.useCallback((event) => {
|
|
6
|
+
event?.preventDefault();
|
|
7
|
+
event?.stopPropagation();
|
|
8
|
+
setShowDialog(true);
|
|
9
|
+
}, [setShowDialog]);
|
|
10
|
+
const onCloseDialog = React.useCallback(() => {
|
|
11
|
+
setShowDialog(false);
|
|
12
|
+
}, [setShowDialog]);
|
|
13
|
+
return (<>
|
|
14
|
+
<Button onClick={onShowDialog} {...props}/>
|
|
15
|
+
{showDialog && buildDialog(onCloseDialog)}
|
|
16
|
+
</>);
|
|
17
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { INVALIDATE_API } from "@compill/admin-api";
|
|
2
|
+
import { useApiMutation, useMutate } from "@compill/api";
|
|
3
|
+
import { mdiDatabaseRefreshOutline } from "@mdi/js";
|
|
4
|
+
import { ButtonBarButton } from "../layout/ButtonBar";
|
|
5
|
+
export function InvalidateButton({ pathOrPermalink, ...props }) {
|
|
6
|
+
const api = INVALIDATE_API.new(pathOrPermalink);
|
|
7
|
+
const mutation = useApiMutation(api.invalidate, api.queryKey);
|
|
8
|
+
const invalidate = useMutate(mutation, { successMsg: "Page successfully invalidated" });
|
|
9
|
+
return (<ButtonBarButton title="Regenerate" disabled={mutation.isLoading} onClick={invalidate} icon={mdiDatabaseRefreshOutline} {...props}/>);
|
|
10
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { mdiPost } from "@mdi/js";
|
|
2
|
+
import { Button, Icon } from "@valerya/ui";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { useNavigate } from "react-router-dom";
|
|
5
|
+
export function NavigateButton({ path, ...props }) {
|
|
6
|
+
const navigate = useNavigate();
|
|
7
|
+
const handleClick = React.useCallback(() => {
|
|
8
|
+
navigate(path);
|
|
9
|
+
}, [navigate, path]);
|
|
10
|
+
return (<Button type="submit" scheme="dark" variant="glass" corners="pill" w="10" h="10" onClick={handleClick} {...props}>
|
|
11
|
+
<Icon path={mdiPost}/>
|
|
12
|
+
</Button>);
|
|
13
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useInvalidateMutation } from "@compill/api";
|
|
2
|
+
import { mdiEye, mdiEyeOff } from "@mdi/js";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { toast } from "react-toastify";
|
|
5
|
+
import { ButtonBarButton } from "../layout/ButtonBar";
|
|
6
|
+
export function PublishButton({ status, queryId, api, ...props }) {
|
|
7
|
+
const isDraft = status == "draft";
|
|
8
|
+
const mutation = useInvalidateMutation(isDraft ? api.publish : api.unpublish, api.queryKey, queryId, { networkMode: "always" });
|
|
9
|
+
const publish = React.useCallback(() => {
|
|
10
|
+
mutation.reset();
|
|
11
|
+
mutation.mutateAsync(queryId)
|
|
12
|
+
.then(() => toast.success(isDraft ? "Published!" : "Unpublished!"))
|
|
13
|
+
.catch(error => toast.error(`Error: ${error}`));
|
|
14
|
+
}, [mutation, queryId]);
|
|
15
|
+
return (<ButtonBarButton disabled={mutation.isLoading} onClick={publish} icon={isDraft ? mdiEye : mdiEyeOff} {...props}>
|
|
16
|
+
{isDraft ? "Publish" : "Switch to draft"}
|
|
17
|
+
</ButtonBarButton>);
|
|
18
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { mdiCloudUpload } from "@mdi/js";
|
|
2
|
+
import { useFormikContext } from "formik";
|
|
3
|
+
import { useHotkeys } from "react-hotkeys-hook";
|
|
4
|
+
import { ButtonBarSubmitButton } from "../layout/ButtonBar";
|
|
5
|
+
export function UpdateButton({ ...props }) {
|
|
6
|
+
const { dirty, handleSubmit } = useFormikContext() ?? { dirty: false, handleSubmit: undefined, values: {} };
|
|
7
|
+
useHotkeys('ctrl+s', () => { if (dirty && !props.disabled)
|
|
8
|
+
handleSubmit(); }, { preventDefault: true }, [dirty, props, handleSubmit]);
|
|
9
|
+
return (<ButtonBarSubmitButton icon={mdiCloudUpload} {...props}>
|
|
10
|
+
Update
|
|
11
|
+
</ButtonBarSubmitButton>);
|
|
12
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import { ButtonBarButtonProps } from "@compill/admin";
|
|
1
|
+
import { ButtonBarButtonProps } from "../layout/ButtonBar";
|
|
3
2
|
export declare function ViewButton({ label, path, icon, ...props }: ButtonBarButtonProps & {
|
|
4
3
|
label?: string;
|
|
5
4
|
path: string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { mdiOpenInNew } from "@mdi/js";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { ButtonBarButton } from "../layout/ButtonBar";
|
|
4
|
+
export function ViewButton({ label, path, icon, ...props }) {
|
|
5
|
+
const openPage = React.useCallback(() => {
|
|
6
|
+
window.open(path, '_blank');
|
|
7
|
+
}, [path]);
|
|
8
|
+
return (<ButtonBarButton onClick={openPage} dflex alignItems="center" gap="2" icon={icon || mdiOpenInNew} {...props}>
|
|
9
|
+
{label}
|
|
10
|
+
</ButtonBarButton>);
|
|
11
|
+
// return (
|
|
12
|
+
// <IconButton icon={icon ? icon : mdiOpenInNew} type="submit" scheme="dark" variant="glass" size="md" onClick={openPage} {...props}/>
|
|
13
|
+
// )
|
|
14
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { FlexCenter } from "@compill/components";
|
|
2
|
+
import { useInvalidateMutation } from "@compill/api";
|
|
3
|
+
import { mdiArrowDownBoldBox, mdiArrowUpBoldBox } from "@mdi/js";
|
|
4
|
+
import { Button, Icon } from "@valerya/ui";
|
|
5
|
+
import React from "react";
|
|
6
|
+
import { toast } from "react-toastify";
|
|
7
|
+
export function OrderCell({ api, postId, order }) {
|
|
8
|
+
const mutationDown = useInvalidateMutation(api.moveDown, api.queryKey);
|
|
9
|
+
const mutationUp = useInvalidateMutation(api.moveUp, api.queryKey);
|
|
10
|
+
const moveDown = React.useCallback((e) => {
|
|
11
|
+
e.stopPropagation();
|
|
12
|
+
mutationDown.mutateAsync(postId)
|
|
13
|
+
.catch(error => {
|
|
14
|
+
toast.error(`Error: ${error}`);
|
|
15
|
+
});
|
|
16
|
+
}, [mutationDown, postId]);
|
|
17
|
+
const moveUp = React.useCallback((e) => {
|
|
18
|
+
e.stopPropagation();
|
|
19
|
+
mutationUp.mutateAsync(postId)
|
|
20
|
+
.catch(error => {
|
|
21
|
+
toast.error(`Error: ${error}`);
|
|
22
|
+
});
|
|
23
|
+
}, [mutationUp, postId]);
|
|
24
|
+
return (<FlexCenter placeContent="start" numericFontVariant="tabular-nums">
|
|
25
|
+
{order}
|
|
26
|
+
|
|
27
|
+
<Button ms="3" variant="borderless" scheme="dark" onClick={moveUp}>
|
|
28
|
+
<Icon path={mdiArrowUpBoldBox}/>
|
|
29
|
+
</Button>
|
|
30
|
+
|
|
31
|
+
<Button variant="borderless" scheme="dark" onClick={moveDown}>
|
|
32
|
+
<Icon path={mdiArrowDownBoldBox}/>
|
|
33
|
+
</Button>
|
|
34
|
+
</FlexCenter>);
|
|
35
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
1
|
import { SoperioComponent } from "@soperio/react";
|
|
3
2
|
import { DetailsViewConfig } from "./types/DetailsView";
|
|
4
3
|
export declare function DetailsView({ queryField, api, useNextRouter, processInput, screen, tabbed, ...props }: DetailsViewConfig & {
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { useInvalidateParentMutation, useMutate } from "@compill/api";
|
|
2
|
+
import { FormProvider, FormRenderer, TextArea } from "@compill/form";
|
|
3
|
+
import { runIfFn } from "@soperio/react";
|
|
4
|
+
import React from "react";
|
|
5
|
+
import { useParams } from "react-router-dom";
|
|
6
|
+
import { PageContainer } from "../page/PageContainer";
|
|
7
|
+
import { PageContentEditor } from "../page/PageContentEditor";
|
|
8
|
+
import { PageQueryStateContainer } from "../page/PageQueryStateContainer";
|
|
9
|
+
import { PageSidebar } from "../page/PageSidebar";
|
|
10
|
+
import { PageSidebarSection } from "../page/PageSidebarSection";
|
|
11
|
+
import { ScreenTopBar } from "./ScreenTopBar";
|
|
12
|
+
import { useRouter } from "next/router";
|
|
13
|
+
import { useInvalidatePage } from "@compill/admin-api";
|
|
14
|
+
function useQueryField(queryField, useNextRouter) {
|
|
15
|
+
if (useNextRouter) {
|
|
16
|
+
const router = useRouter();
|
|
17
|
+
return router.query[queryField];
|
|
18
|
+
}
|
|
19
|
+
const { [queryField]: id } = useParams();
|
|
20
|
+
return id;
|
|
21
|
+
}
|
|
22
|
+
export function DetailsView({ queryField, api, useNextRouter, processInput, screen, tabbed, ...props }) {
|
|
23
|
+
const id = useQueryField(queryField, useNextRouter);
|
|
24
|
+
const ref = React.useRef(null);
|
|
25
|
+
return (<PageQueryStateContainer api={api} apiFn="get" queryId={id} ref={ref} p="5" {...props}>
|
|
26
|
+
{(item) => <Internal item={item} screen={screen} api={api} tabbed={tabbed} processInput={processInput} containerRef={ref}/>}
|
|
27
|
+
</PageQueryStateContainer>);
|
|
28
|
+
}
|
|
29
|
+
function Internal({ item, screen, api, processInput, tabbed, containerRef }) {
|
|
30
|
+
const pScreen = runIfFn(screen, item);
|
|
31
|
+
const { breadcrumbs, schema, initialValues, header, sections, buttonBar, type, invalidateParentQueryKey, invalidatePage } = pScreen;
|
|
32
|
+
const mutation = useInvalidateParentMutation((api.update), invalidateParentQueryKey ?? api.queryKey, { networkMode: "always" });
|
|
33
|
+
const invalidatePageFn = useInvalidatePage(invalidatePage || "");
|
|
34
|
+
const save = useMutate(mutation, {
|
|
35
|
+
processInput,
|
|
36
|
+
successMsg: (item, values) => `${item.title || item.name} updated.`,
|
|
37
|
+
errorMsg: (error, item) => `Error updating ${item.title || item.name}: ${error}`,
|
|
38
|
+
onSuccess: () => {
|
|
39
|
+
if (invalidatePage)
|
|
40
|
+
invalidatePageFn();
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
let editorMaxW = undefined;
|
|
44
|
+
if (!type || type == "post")
|
|
45
|
+
editorMaxW = "calc(1280px - 28rem)";
|
|
46
|
+
else if (type == "section")
|
|
47
|
+
editorMaxW = "calc(1280px - 22rem)";
|
|
48
|
+
return (<FormProvider initialValues={runIfFn(initialValues, item)} validationSchema={schema} onSubmit={save} enableReinitialize>
|
|
49
|
+
<ScreenTopBar tabbed={tabbed} api={api} breadcrumbs={breadcrumbs} buttonBar={buttonBar} item={item} isLoading={mutation.isLoading} trackingRef={containerRef?.current}/>
|
|
50
|
+
|
|
51
|
+
{type == "form" && sections?.map((section, index) => (<Section key={index} section={section} item={item}/>))}
|
|
52
|
+
|
|
53
|
+
{(pScreen.type == "post" || pScreen.type == "section") &&
|
|
54
|
+
(<div p="5" bgColor="slate-100" rounded="lg">
|
|
55
|
+
<PageContainer w={editorMaxW ? "auto" : "full"} size="x2" id="pagecontainer">
|
|
56
|
+
{header}
|
|
57
|
+
|
|
58
|
+
<div dflex gap="5">
|
|
59
|
+
<div dflex flexCol gap="8" flexGrow>
|
|
60
|
+
{pScreen.editor?.type != "textarea" &&
|
|
61
|
+
(
|
|
62
|
+
// TODO Find a way to make this editor shrink in width when resizing the window...
|
|
63
|
+
<PageContentEditor name="content" maxW={editorMaxW} minW="144" shadow rounded="lg"/>)}
|
|
64
|
+
|
|
65
|
+
{pScreen.editor?.type == "textarea" &&
|
|
66
|
+
(<TextArea name={pScreen.editor?.name} maxW={editorMaxW} minW={editorMaxW} w={editorMaxW} minH="128" rows={25} bgColor="white" border="0" shadow p="5" textColor="slate-800"/>)}
|
|
67
|
+
|
|
68
|
+
{pScreen.editorFooter}
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<PageSidebar>
|
|
72
|
+
{sections?.map((section, index) => (<Section key={index} section={section} item={item} cardStyle/>))}
|
|
73
|
+
</PageSidebar>
|
|
74
|
+
</div>
|
|
75
|
+
</PageContainer>
|
|
76
|
+
</div>)}
|
|
77
|
+
</FormProvider>);
|
|
78
|
+
}
|
|
79
|
+
function Section({ section, item, cardStyle }) {
|
|
80
|
+
if (section.type === "section") {
|
|
81
|
+
const style = cardStyle ?
|
|
82
|
+
{
|
|
83
|
+
bgColor: "white",
|
|
84
|
+
rounded: "lg",
|
|
85
|
+
p: "5",
|
|
86
|
+
textSize: "sm",
|
|
87
|
+
shadow: true
|
|
88
|
+
} : {};
|
|
89
|
+
return (<PageSidebarSection title={section.title} {...style}>
|
|
90
|
+
<FormRenderer form={runIfFn(section.form, item)}/>
|
|
91
|
+
</PageSidebarSection>);
|
|
92
|
+
}
|
|
93
|
+
if (section.type === "custom")
|
|
94
|
+
return runIfFn(section.component, item);
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
1
|
import { MultiQueryWrapperConfig } from "./types/MultiQueryWrapper";
|
|
3
2
|
import { SoperioComponent } from "@soperio/react";
|
|
4
3
|
export declare function MultiQueryWrapper({ queries, config, tabbed, ...props }: Omit<MultiQueryWrapperConfig, "type"> & {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useApiQueries } from "@compill/api";
|
|
2
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { useParams } from "react-router-dom";
|
|
5
|
+
import { ScreenRenderer } from "./ScreenRenderer";
|
|
6
|
+
import { isFunction, runIfFn } from "@soperio/react";
|
|
7
|
+
import { QueryLoadingState, RetryOnError } from "@compill/components";
|
|
8
|
+
function useQueries(queries) {
|
|
9
|
+
const params = useParams();
|
|
10
|
+
const { data, isFetching, isError } = useApiQueries(queries.map(q => {
|
|
11
|
+
if (!q.queryField) {
|
|
12
|
+
const api = runIfFn(q.api);
|
|
13
|
+
return {
|
|
14
|
+
queryKey: api.queryKey,
|
|
15
|
+
queryFn: q.fn == "get" ? api.get : api.getAll,
|
|
16
|
+
queryParam: q.params
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const id = params[q.queryField];
|
|
20
|
+
const api = runIfFn(q.api, id);
|
|
21
|
+
return {
|
|
22
|
+
queryKey: api.queryKey,
|
|
23
|
+
queryFn: q.fn == "get" ? api.get : api.getAll,
|
|
24
|
+
queryParam: q.fn == "getAll" ? q.params : isFunction(q.api) ? undefined : id
|
|
25
|
+
};
|
|
26
|
+
}));
|
|
27
|
+
let transformedData = undefined;
|
|
28
|
+
if (!isFetching && !isError) {
|
|
29
|
+
transformedData = data?.map((d, index) => queries[index].transformFn ? queries[index].transformFn?.(d) : d);
|
|
30
|
+
}
|
|
31
|
+
return { data: transformedData, isFetching, isError };
|
|
32
|
+
}
|
|
33
|
+
function useInvalidate(queries) {
|
|
34
|
+
const queryClient = useQueryClient();
|
|
35
|
+
const params = useParams();
|
|
36
|
+
const invalidate = React.useCallback(() => {
|
|
37
|
+
const queryKeys = [];
|
|
38
|
+
queries.forEach(q => {
|
|
39
|
+
if (!q.queryField || !isFunction(q.api)) {
|
|
40
|
+
queryKeys.push(q.api.queryKey);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const id = params[q.queryField];
|
|
44
|
+
const api = runIfFn(q.api, id);
|
|
45
|
+
queryKeys.push(api.queryKey);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
queryClient.invalidateQueries({ predicate: (query) => queryKeys.includes(query.queryKey), });
|
|
49
|
+
}, [queries, queryClient, params]);
|
|
50
|
+
return invalidate;
|
|
51
|
+
}
|
|
52
|
+
export function MultiQueryWrapper({ queries, config, tabbed, ...props }) {
|
|
53
|
+
const { data, isFetching, isError } = useQueries(queries);
|
|
54
|
+
const invalidate = useInvalidate(queries);
|
|
55
|
+
if (isFetching)
|
|
56
|
+
return <QueryLoadingState w="full" h="100vh"/>;
|
|
57
|
+
if (isError || !data)
|
|
58
|
+
return <RetryOnError p="0" w="full" h="100vh" onClick={invalidate}/>;
|
|
59
|
+
return <ScreenRenderer config={config(...data)} tabbed={tabbed} {...props}/>;
|
|
60
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ScreenRenderer } from "./ScreenRenderer";
|
|
3
|
+
import { isFunction, runIfFn } from "@soperio/react";
|
|
4
|
+
import { useParams } from "react-router-dom";
|
|
5
|
+
import { useApiQuery } from "@compill/api";
|
|
6
|
+
function useApi(api, queryField) {
|
|
7
|
+
const params = useParams();
|
|
8
|
+
if (queryField === undefined)
|
|
9
|
+
return { id: undefined, api: api };
|
|
10
|
+
const { [queryField]: id } = params;
|
|
11
|
+
return { id, api: runIfFn(api, id) };
|
|
12
|
+
}
|
|
13
|
+
export function QueryWrapper({ api, queryField, fn, transformFn, config, tabbed, ...props }) {
|
|
14
|
+
const { id, api: mApi } = useApi(api, queryField);
|
|
15
|
+
const { data } = useApiQuery(mApi.queryKey, fn === "get" || fn === "getTransformed" ? mApi.get : mApi.getAll, isFunction(api) ? undefined : id);
|
|
16
|
+
const transformedData = React.useMemo(() => {
|
|
17
|
+
if (data && (fn === "getTransformed" || fn === "getAllTransformed")) {
|
|
18
|
+
if (!transformFn)
|
|
19
|
+
console.warn(`QueryWrapperDialog: you forgot to pass transformFn as parameter for fn ${fn}`);
|
|
20
|
+
return transformFn?.(data);
|
|
21
|
+
}
|
|
22
|
+
return data;
|
|
23
|
+
}, [data]);
|
|
24
|
+
// TODO states
|
|
25
|
+
if (!data)
|
|
26
|
+
return null;
|
|
27
|
+
return <ScreenRenderer config={config(transformedData)} tabbed={tabbed} {...props}/>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { DetailsView } from "./DetailsView";
|
|
2
|
+
import { QueryWrapper } from "./QueryWrapper";
|
|
3
|
+
import { TabbedView } from "./TabbedView";
|
|
4
|
+
import { TableView } from "./table/TableView";
|
|
5
|
+
import { MultiQueryWrapper } from "./MultiQueryWrapper";
|
|
6
|
+
export function ScreenRenderer({ config, tabbed, ...props }) {
|
|
7
|
+
if (config.type === "table")
|
|
8
|
+
return <TableView {...config} {...props}/>;
|
|
9
|
+
if (config.type === "tabbed")
|
|
10
|
+
return <TabbedView {...config} {...props}/>;
|
|
11
|
+
if (config.type === "details")
|
|
12
|
+
return <DetailsView {...config} tabbed={tabbed} {...props}/>;
|
|
13
|
+
if (config.type === "query")
|
|
14
|
+
return <QueryWrapper {...config} tabbed={tabbed} {...props}/>;
|
|
15
|
+
if (config.type === "multiQuery")
|
|
16
|
+
return <MultiQueryWrapper {...config} tabbed={tabbed} {...props}/>;
|
|
17
|
+
return <></>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { API } from "@compill/admin-api";
|
|
2
|
+
import { InvalidateButton } from "../buttons/InvalidateButton";
|
|
3
|
+
import { PublishButton } from "../buttons/PublishButton";
|
|
4
|
+
import { UpdateButton } from "../buttons/UpdateButton";
|
|
5
|
+
import { ViewButton } from "../buttons/ViewButton";
|
|
6
|
+
import { PageTopBar, PageTopBarToolbar } from "../page/PageTopBar";
|
|
7
|
+
import React from "react";
|
|
8
|
+
import { ButtonBar } from "../layout/ButtonBar";
|
|
9
|
+
export function ScreenTopBar({ tabbed, breadcrumbs, api, item, isLoading, buttonBar, trackingRef }) {
|
|
10
|
+
return (<>
|
|
11
|
+
{tabbed &&
|
|
12
|
+
(<PageTopBarToolbar trackingRef={trackingRef}>
|
|
13
|
+
<Buttons api={api} item={item} isLoading={isLoading} buttonBar={buttonBar}/>
|
|
14
|
+
</PageTopBarToolbar>)}
|
|
15
|
+
|
|
16
|
+
{!tabbed &&
|
|
17
|
+
(<PageTopBar breadcrumbs={breadcrumbs}>
|
|
18
|
+
<Buttons api={api} item={item} isLoading={isLoading} buttonBar={buttonBar}/>
|
|
19
|
+
</PageTopBar>)}
|
|
20
|
+
</>);
|
|
21
|
+
}
|
|
22
|
+
function Buttons({ api, item, isLoading, buttonBar }) {
|
|
23
|
+
return (<>
|
|
24
|
+
{buttonBar && buttonBar.length > 0 &&
|
|
25
|
+
(<ButtonBar>
|
|
26
|
+
{buttonBar.map((button, index) => (<React.Fragment key={index}>
|
|
27
|
+
{button.type === "link" && <ViewButton label={button.label} path={button.path} icon={button.icon}/>}
|
|
28
|
+
{button.type === "invalidate" && <InvalidateButton pathOrPermalink={button.pathOrPermalink}/>}
|
|
29
|
+
{button.type == "custom" && button.render(item)}
|
|
30
|
+
</React.Fragment>))}
|
|
31
|
+
</ButtonBar>)}
|
|
32
|
+
|
|
33
|
+
<ButtonBar>
|
|
34
|
+
{api instanceof API && <PublishButton api={api} queryId={item.id} status={item.status} disabled={isLoading}/>}
|
|
35
|
+
|
|
36
|
+
<UpdateButton disabled={isLoading}/>
|
|
37
|
+
</ButtonBar>
|
|
38
|
+
</>);
|
|
39
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useParams } from "react-router-dom";
|
|
2
|
+
import { PageQueryStateContainer } from "../page/PageQueryStateContainer";
|
|
3
|
+
import { PageTabbedTopBar, PageTabbedTopBarProvider } from "../page/PageTopBar";
|
|
4
|
+
import { TabContainer } from "@compill/components";
|
|
5
|
+
import { runIfFn } from "@soperio/react";
|
|
6
|
+
import { ScreenRenderer } from "./ScreenRenderer";
|
|
7
|
+
export function TabbedView({ queryField, api, screen, ...props }) {
|
|
8
|
+
const { [queryField]: id } = useParams();
|
|
9
|
+
return (<PageQueryStateContainer queryId={id} api={api} apiFn="get" p="5">
|
|
10
|
+
{(city) => {
|
|
11
|
+
const { breadcrumbs, tabs } = runIfFn(screen, city);
|
|
12
|
+
return (<PageTabbedTopBarProvider>
|
|
13
|
+
<PageTabbedTopBar breadcrumbs={breadcrumbs} mb="-3"/>
|
|
14
|
+
|
|
15
|
+
<TabContainer tabs={tabs.map(tab => tab.label)} saveKey={`tab-${id}`} mt="-3" mb="3" id="fff">
|
|
16
|
+
{tabs.map((tab, index) => <TabView key={index} tab={tab}/>)}
|
|
17
|
+
</TabContainer>
|
|
18
|
+
</PageTabbedTopBarProvider>);
|
|
19
|
+
}}
|
|
20
|
+
</PageQueryStateContainer>);
|
|
21
|
+
}
|
|
22
|
+
function TabView({ tab }) {
|
|
23
|
+
if (!tab.component && !tab.config)
|
|
24
|
+
throw new Error(`Screen config for tabbed view: one of your tabs does not have a component or config declared: ${tab.label}`);
|
|
25
|
+
if (tab.component)
|
|
26
|
+
return tab.component();
|
|
27
|
+
return <ScreenRenderer config={tab.config} tabbed p="0"/>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useApiMutation, useInvalidateParentMutation, useMutate } from "@compill/api";
|
|
2
|
+
import { Button, Icon } from "@valerya/ui";
|
|
3
|
+
export function ActionButton({ label, buttonProps, icon, queryKey, queryFn, successMsg, errorMsg, invalidateParent }) {
|
|
4
|
+
const mutation = invalidateParent ? useInvalidateParentMutation(queryFn, queryKey) : useApiMutation(queryFn, queryKey);
|
|
5
|
+
const mutate = useMutate(mutation, {
|
|
6
|
+
successMsg,
|
|
7
|
+
errorMsg
|
|
8
|
+
});
|
|
9
|
+
return (<Button display="flex" alignItems="center" gap="3" {...buttonProps} onClick={mutate} disabled={mutation.isLoading}>
|
|
10
|
+
{icon && <Icon path={icon}/>}
|
|
11
|
+
{label}
|
|
12
|
+
</Button>);
|
|
13
|
+
}
|