@compill/admin 1.0.102 → 1.0.103

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.
Files changed (106) hide show
  1. package/dist/lib/SectionTitle.js +4 -0
  2. package/dist/lib/breadcrumbs/BreadCrumbs.js +29 -0
  3. package/dist/lib/buttons/{DialogButton.jsx → DialogButton.js} +2 -4
  4. package/dist/lib/buttons/{InvalidateButton.jsx → InvalidateButton.js} +2 -1
  5. package/dist/lib/buttons/{NavigateButton.jsx → NavigateButton.js} +2 -3
  6. package/dist/lib/buttons/{PublishButton.jsx → PublishButton.js} +2 -3
  7. package/dist/lib/buttons/{UpdateButton.jsx → UpdateButton.js} +2 -3
  8. package/dist/lib/buttons/{ViewButton.jsx → ViewButton.js} +2 -3
  9. package/dist/lib/cells/{OrderCell.jsx → OrderCell.js} +2 -11
  10. package/dist/lib/json/{DetailsView.jsx → DetailsView.js} +9 -36
  11. package/dist/lib/json/{EditItemView.jsx → EditItemView.js} +2 -1
  12. package/dist/lib/json/{MultiQueryWrapper.jsx → MultiQueryWrapper.js} +4 -3
  13. package/dist/lib/json/{QueryWrapper.jsx → QueryWrapper.js} +2 -1
  14. package/dist/lib/json/{ScreenRenderer.jsx → ScreenRenderer.js} +7 -6
  15. package/dist/lib/json/ScreenTopBar.js +18 -0
  16. package/dist/lib/json/{TabbedView.jsx → TabbedView.js} +5 -12
  17. package/dist/lib/json/buttons/{ActionButton.jsx → ActionButton.js} +2 -4
  18. package/dist/lib/json/buttons/{ConfirmationActionButton.jsx → ConfirmationActionButton.js} +3 -20
  19. package/dist/lib/json/dialog/DialogRenderer.js +14 -0
  20. package/dist/lib/json/dialog/ItemDeleteDialog.js +14 -0
  21. package/dist/lib/json/dialog/ItemEditDialog.js +77 -0
  22. package/dist/lib/json/dialog/{MultiQueryWrapperDialog.jsx → MultiQueryWrapperDialog.js} +2 -1
  23. package/dist/lib/json/dialog/{QueryWrapperDialog.jsx → QueryWrapperDialog.js} +2 -1
  24. package/dist/lib/json/table/{RefreshButton.jsx → RefreshButton.js} +2 -3
  25. package/dist/lib/json/table/{TableRowActionsView.jsx → TableRowActionsView.js} +4 -13
  26. package/dist/lib/json/table/{TableRowPublishPostButton.jsx → TableRowPublishPostButton.js} +2 -3
  27. package/dist/lib/json/table/TableView.js +65 -0
  28. package/dist/lib/json/table/{TableViewContext.jsx → TableViewContext.js} +4 -3
  29. package/dist/lib/json/table/{useTableProps.jsx → useTableProps.js} +2 -1
  30. package/dist/lib/layout/AdminLayout.js +15 -0
  31. package/dist/lib/layout/ButtonBar.js +19 -0
  32. package/dist/lib/layout/Content.js +9 -0
  33. package/dist/lib/layout/PageTitleBar.js +4 -0
  34. package/dist/lib/layout/Sidebar.js +12 -0
  35. package/dist/lib/layout/menu/Menu.js +23 -0
  36. package/dist/lib/layout/menu/MenuButton.js +5 -0
  37. package/dist/lib/layout/menu/MenuItem.js +11 -0
  38. package/dist/lib/layout/menu/NextMenuItem.js +11 -0
  39. package/dist/lib/layout/menu/SelectedIndicator.js +4 -0
  40. package/dist/lib/layout/menu/UserBlock.js +34 -0
  41. package/dist/lib/modal/{AttachDialog.jsx → AttachDialog.js} +4 -40
  42. package/dist/lib/modal/FormActionDialog.js +20 -0
  43. package/dist/lib/page/PageContainer.js +5 -0
  44. package/dist/lib/page/PageContentEditor.js +10 -0
  45. package/dist/lib/page/PageMain.js +5 -0
  46. package/dist/lib/page/{PageQueryStateContainer.jsx → PageQueryStateContainer.js} +4 -3
  47. package/dist/lib/page/PageSectionTitle.js +4 -0
  48. package/dist/lib/page/PageSidebar.js +4 -0
  49. package/dist/lib/page/PageSidebarSection.js +5 -0
  50. package/dist/lib/page/PageStateContainer.js +7 -0
  51. package/dist/lib/page/PageSubSectionTitle.js +4 -0
  52. package/dist/lib/page/PageTitle.js +4 -0
  53. package/dist/lib/page/{PageTopBar.jsx → PageTopBar.js} +4 -18
  54. package/dist/lib/status/{StatusBadge.jsx → StatusBadge.js} +2 -1
  55. package/dist/lib/table/TableContainer.js +6 -0
  56. package/dist/lib/table/{TableContainerContext.jsx → TableContainerContext.js} +2 -1
  57. package/dist/lib/table/{TableCreateButton.jsx → TableCreateButton.js} +2 -4
  58. package/dist/lib/table/TableFilterButton.js +8 -0
  59. package/dist/lib/table/{TableFilters.jsx → TableFilters.js} +3 -22
  60. package/dist/lib/table/TableMassActions.js +9 -0
  61. package/dist/lib/table/TableRowActionBar.js +8 -0
  62. package/dist/lib/table/TableRowActionButton.js +5 -0
  63. package/dist/lib/table/TableRowActionDialogButton.js +6 -0
  64. package/dist/lib/table/{TableRowDeleteButton.jsx → TableRowDeleteButton.js} +2 -1
  65. package/dist/lib/table/{TableRowEditButton.jsx → TableRowEditButton.js} +2 -3
  66. package/dist/lib/table/{TableRowNavigateButton.jsx → TableRowNavigateButton.js} +2 -1
  67. package/dist/lib/table/{TableRowPublishPostButton.jsx → TableRowPublishPostButton.js} +2 -1
  68. package/dist/lib/table/{TableRowViewButton.jsx → TableRowViewButton.js} +2 -1
  69. package/dist/lib/table/TableTopBar.js +5 -0
  70. package/package.json +9 -9
  71. package/dist/lib/SectionTitle.jsx +0 -3
  72. package/dist/lib/breadcrumbs/BreadCrumbs.jsx +0 -43
  73. package/dist/lib/json/ScreenTopBar.jsx +0 -39
  74. package/dist/lib/json/dialog/DialogRenderer.jsx +0 -13
  75. package/dist/lib/json/dialog/ItemDeleteDialog.jsx +0 -36
  76. package/dist/lib/json/dialog/ItemEditDialog.jsx +0 -124
  77. package/dist/lib/json/table/TableView.jsx +0 -100
  78. package/dist/lib/layout/AdminLayout.jsx +0 -24
  79. package/dist/lib/layout/ButtonBar.jsx +0 -29
  80. package/dist/lib/layout/Content.jsx +0 -10
  81. package/dist/lib/layout/PageTitleBar.jsx +0 -12
  82. package/dist/lib/layout/Sidebar.jsx +0 -24
  83. package/dist/lib/layout/menu/Menu.jsx +0 -30
  84. package/dist/lib/layout/menu/MenuButton.jsx +0 -7
  85. package/dist/lib/layout/menu/MenuItem.jsx +0 -20
  86. package/dist/lib/layout/menu/NextMenuItem.jsx +0 -20
  87. package/dist/lib/layout/menu/SelectedIndicator.jsx +0 -3
  88. package/dist/lib/layout/menu/UserBlock.jsx +0 -55
  89. package/dist/lib/modal/FormActionDialog.jsx +0 -46
  90. package/dist/lib/page/PageContainer.jsx +0 -4
  91. package/dist/lib/page/PageContentEditor.jsx +0 -11
  92. package/dist/lib/page/PageMain.jsx +0 -4
  93. package/dist/lib/page/PageSectionTitle.jsx +0 -3
  94. package/dist/lib/page/PageSidebar.jsx +0 -3
  95. package/dist/lib/page/PageSidebarSection.jsx +0 -7
  96. package/dist/lib/page/PageStateContainer.jsx +0 -9
  97. package/dist/lib/page/PageSubSectionTitle.jsx +0 -3
  98. package/dist/lib/page/PageTitle.jsx +0 -3
  99. package/dist/lib/table/TableContainer.jsx +0 -11
  100. package/dist/lib/table/TableFilterButton.jsx +0 -16
  101. package/dist/lib/table/TableMassActions.jsx +0 -15
  102. package/dist/lib/table/TableRowActionBar.jsx +0 -14
  103. package/dist/lib/table/TableRowActionButton.jsx +0 -7
  104. package/dist/lib/table/TableRowActionDialogButton.jsx +0 -8
  105. package/dist/lib/table/TableTopBar.jsx +0 -17
  106. /package/dist/lib/table/{TableColumnButton.jsx → TableColumnButton.js} +0 -0
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@soperio/jsx-runtime";
2
+ import { TableRowViewButton } from "./TableRowViewButton";
3
+ import { TableRowNavigateButton } from "./TableRowNavigateButton";
4
+ import { TableRowEditButton } from "./TableRowEditButton";
5
+ import { TableRowDeleteButton } from "./TableRowDeleteButton";
6
+ export function TableRowActionBar({ publishId, viewPath, navigatePath, editDialog, deleteDialog, children, ...props }) {
7
+ return (_jsxs("div", { dflex: true, spaceX: "1", placeContent: "end", ...props, children: [viewPath && _jsx(TableRowViewButton, { path: viewPath }), navigatePath && _jsx(TableRowNavigateButton, { path: navigatePath }), editDialog && _jsx(TableRowEditButton, { buildDialog: editDialog }), deleteDialog && _jsx(TableRowDeleteButton, { buildDialog: deleteDialog }), children] }));
8
+ }
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@soperio/jsx-runtime";
2
+ import { Button, Icon } from "@valerya/ui";
3
+ export function TableRowActionButton({ icon, children, ...props }) {
4
+ return (_jsxs(Button, { dflex: true, alignContent: "center", placeContent: "center", py: "2.5", px: "3", h: "full", size: "lg", variant: "borderless", corners: "square", gap: "2", ...props, children: [icon && _jsx(Icon, { path: icon, size: "sm" }), children] }));
5
+ }
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@soperio/jsx-runtime";
2
+ import { Icon } from "@valerya/ui";
3
+ import { DialogButton } from "../buttons/DialogButton";
4
+ export function TableRowActionDialogButton({ icon, children, ...props }) {
5
+ return (_jsxs(DialogButton, { dflex: true, alignContent: "center", placeContent: "center", py: "2.5", px: "3", h: "full", size: "lg", variant: "borderless", corners: "square", gap: "2", ...props, children: [icon && _jsx(Icon, { path: icon, size: "sm" }), children] }));
6
+ }
@@ -1,5 +1,6 @@
1
+ import { jsx as _jsx } from "@soperio/jsx-runtime";
1
2
  import { mdiDelete } from "@mdi/js";
2
3
  import { TableRowActionDialogButton } from "./TableRowActionDialogButton";
3
4
  export function TableRowDeleteButton({ children, ...props }) {
4
- return <TableRowActionDialogButton icon={mdiDelete} {...props}>{children}</TableRowActionDialogButton>;
5
+ return _jsx(TableRowActionDialogButton, { icon: mdiDelete, ...props, children: children });
5
6
  }
@@ -1,7 +1,6 @@
1
+ import { jsx as _jsx } from "@soperio/jsx-runtime";
1
2
  import { mdiPencil } from "@mdi/js";
2
3
  import { TableRowActionDialogButton } from "./TableRowActionDialogButton";
3
4
  export function TableRowEditButton({ children, ...props }) {
4
- return (<TableRowActionDialogButton icon={mdiPencil} {...props}>
5
- {children}
6
- </TableRowActionDialogButton>);
5
+ return (_jsx(TableRowActionDialogButton, { icon: mdiPencil, ...props, children: children }));
7
6
  }
@@ -1,3 +1,4 @@
1
+ import { jsx as _jsx } from "@soperio/jsx-runtime";
1
2
  import { mdiEye } from "@mdi/js";
2
3
  import React from "react";
3
4
  import { useNavigate } from "react-router-dom";
@@ -9,5 +10,5 @@ export function TableRowNavigateButton({ path, ...props }) {
9
10
  event?.stopPropagation();
10
11
  navigate(`${path}`);
11
12
  }, [navigate, path]);
12
- return <TableRowActionButton icon={mdiEye} onClick={handleClick} {...props}/>;
13
+ return _jsx(TableRowActionButton, { icon: mdiEye, onClick: handleClick, ...props });
13
14
  }
@@ -1,3 +1,4 @@
1
+ import { jsx as _jsx } from "@soperio/jsx-runtime";
1
2
  import { useInvalidateParentMutation } from "@compill/api";
2
3
  import { mdiPublish, mdiPublishOff } from "@mdi/js";
3
4
  import React from "react";
@@ -14,5 +15,5 @@ export function TableRowPublishPostButton({ id, api, status, invalidateQueryKey,
14
15
  .then(() => toast.success(isDraft ? "Published!" : "Unpublished!"))
15
16
  .catch(error => toast.error(`Error: ${error}`));
16
17
  }, [mutation, id]);
17
- return (<TableRowActionButton icon={isDraft ? mdiPublish : mdiPublishOff} onClick={publish} {...props}/>);
18
+ return (_jsx(TableRowActionButton, { icon: isDraft ? mdiPublish : mdiPublishOff, onClick: publish, ...props }));
18
19
  }
@@ -1,3 +1,4 @@
1
+ import { jsx as _jsx } from "@soperio/jsx-runtime";
1
2
  import { mdiOpenInNew } from "@mdi/js";
2
3
  import React from "react";
3
4
  import { TableRowActionButton } from "./TableRowActionButton";
@@ -8,5 +9,5 @@ export function TableRowViewButton({ path, ...props }) {
8
9
  event?.stopPropagation();
9
10
  window.open(`${AppEnv.websiteUrl()}/${path}`, '_blank');
10
11
  }, [path]);
11
- return <TableRowActionButton icon={mdiOpenInNew} onClick={openPage} {...props}/>;
12
+ return _jsx(TableRowActionButton, { icon: mdiOpenInNew, onClick: openPage, ...props });
12
13
  }
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@soperio/jsx-runtime";
2
+ import { Breadcrumbs } from "../breadcrumbs/BreadCrumbs";
3
+ export function TableTopBar({ title, breadcrumbs, children, ...props }) {
4
+ return (_jsxs("div", { dflex: true, flexRow: true, alignItems: "center", gap: "3", p: "8", ...props, children: [_jsxs("div", { children: [title && _jsx("h2", { textSize: "x2", fontWeight: "600", textColor: "#3f4254", textTransform: "capitalize", children: title }), breadcrumbs && _jsx(Breadcrumbs, { breadcrumbs: breadcrumbs })] }), _jsx("div", { flexGrow: true, children: "\u00A0" }), children] }));
5
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compill/admin",
3
- "version": "1.0.102",
3
+ "version": "1.0.103",
4
4
  "private": false,
5
5
  "sideEffects": false,
6
6
  "type": "module",
@@ -35,17 +35,17 @@
35
35
  "yup": "^1.1.0",
36
36
  "@soperio/react": "1.0.14",
37
37
  "@soperio/jsx-runtime": "1.0.14",
38
- "@valerya/ui": "1.0.9",
39
- "@compill/admin-api": "1.0.55",
38
+ "@valerya/ui": "1.0.11",
39
+ "@compill/admin-api": "1.0.56",
40
40
  "@compill/api": "1.0.57",
41
- "@compill/auth": "1.0.77",
41
+ "@compill/auth": "1.0.78",
42
42
  "@compill/env": "1.0.19",
43
- "@compill/components": "1.0.49",
44
- "@compill/form": "1.0.67",
43
+ "@compill/components": "1.0.51",
44
+ "@compill/editor": "1.0.80",
45
+ "@compill/form": "1.0.68",
45
46
  "@compill/hooks": "1.0.43",
46
- "@compill/table": "1.0.80",
47
- "@compill/editor": "1.0.79",
48
- "@compill/form-editor": "1.0.19"
47
+ "@compill/form-editor": "1.0.20",
48
+ "@compill/table": "1.0.81"
49
49
  },
50
50
  "publishConfig": {
51
51
  "access": "public"
@@ -1,3 +0,0 @@
1
- export function SectionTitle({ children, ...props }) {
2
- return <h2 textSize="xl" fontWeight="600" textColor="slate-800" {...props}>{children}</h2>;
3
- }
@@ -1,43 +0,0 @@
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
- }
@@ -1,39 +0,0 @@
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
- }
@@ -1,13 +0,0 @@
1
- import { ItemEditDialog } from "./ItemEditDialog";
2
- import { QueryWrapperDialog } from "./QueryWrapperDialog";
3
- import { MultiQueryWrapperDialog } from "./MultiQueryWrapperDialog";
4
- export function DialogRenderer({ config, onClose, invalidateQueryKey, queryId }) {
5
- const { type, ...props } = config;
6
- if (config.type === "dialog")
7
- return <ItemEditDialog {...props} queryId={queryId} invalidateQueryKey={invalidateQueryKey} show onClose={onClose}/>;
8
- if (config.type === "query")
9
- return <QueryWrapperDialog {...props} queryId={queryId} invalidateQueryKey={invalidateQueryKey} onClose={onClose}/>;
10
- if (config.type === "multiQuery")
11
- return <MultiQueryWrapperDialog {...props} queryId={queryId} invalidateQueryKey={invalidateQueryKey} onClose={onClose}/>;
12
- return null;
13
- }
@@ -1,36 +0,0 @@
1
- import { useApiMutation, useInvalidateParentMutation, useMutate } from "@compill/api";
2
- import { ModalLoadingOverlay } from "@compill/components";
3
- import { runIfFn } from "@soperio/react";
4
- import { Button, Modal } from "@valerya/ui";
5
- import React from "react";
6
- export function ItemDeleteDialog({ title, actionButtonLabel, closeActionButtonLabel = "Cancel", itemLabel, queryId = "", api, apiFn, invalidateQueriesOnSuccess = true, invalidateQueryKey, size = "lg", md_boxSizing, msg, show, onClose, onSuccess, ...props }) {
7
- const fn = apiFn ? api[apiFn] : api.delete;
8
- const mutation = invalidateQueriesOnSuccess ? useInvalidateParentMutation(fn, invalidateQueryKey ?? api.queryKey)
9
- : useApiMutation(fn, api.queryKey);
10
- const mutate = useMutate(mutation, { onSuccess: () => { onClose?.(); onSuccess?.(); } });
11
- const handleDelete = React.useCallback(() => mutate(queryId), [mutate, queryId]);
12
- return (<Modal size={size} show={show} onClose={onClose} scheme="danger" variant="glass" transition
13
- // closeOnMaskClick={false}
14
- {...props}>
15
- <Modal.Header>
16
- {title || `Delete ${itemLabel}`}
17
- </Modal.Header>
18
-
19
-
20
- <Modal.Body pb="6">
21
- {!msg && `Do you really want to delete ${itemLabel}?`}
22
- {msg && runIfFn(msg, itemLabel)}
23
- </Modal.Body>
24
-
25
- <Modal.Footer dflex placeContent="end" spaceX="3">
26
- <Button disabled={mutation.isPending} onClick={onClose} variant="borderless" scheme="dark" me="2">
27
- {closeActionButtonLabel}
28
- </Button>
29
- <Button scheme="danger" disabled={mutation.isPending} onClick={handleDelete}>
30
- {actionButtonLabel || "Delete"}
31
- </Button>
32
- </Modal.Footer>
33
-
34
- {mutation.isPending && <ModalLoadingOverlay />}
35
- </Modal>);
36
- }
@@ -1,124 +0,0 @@
1
- import { useApiMutation, useApiQuery, useInvalidateParentMutation } from "@compill/api";
2
- import { ModalLoadingOverlay, QueryLoadingState, RetryOnError } from "@compill/components";
3
- import { FormRenderer } from "@compill/form";
4
- import { isFunction } from "@soperio/react";
5
- import { Button, Modal } from "@valerya/ui";
6
- import { Form, Formik } from "formik";
7
- import React from "react";
8
- import { toast } from "react-toastify";
9
- const defaultErrorMsg = "Oops, something went wrong...";
10
- function nonNullValues(data) {
11
- if (data) {
12
- const nonNullData = { ...data };
13
- for (const key in data)
14
- nonNullData[key] = nonNullData[key] ?? "";
15
- return nonNullData;
16
- }
17
- return data;
18
- }
19
- export function ItemEditDialog({ initialValues, itemLabel, queryId = "", api, queryFetchOptions, querySaveOptions, onSuccess, onFetchError, fetchErrorMsg = defaultErrorMsg, onSaveError, saveErrorMsg = defaultErrorMsg, fetchToFormData, formToQueryData, invalidateQueriesOnSuccess = true, invalidateQueryKey, retryText = "Retry", cancelLabel = "Cancel", saveLabel, size = "lg", title, form, show, onClose, formikProps, ...props }) {
20
- const { isInitialLoading, isFetching, data, isError, error /*, error*/, refetch } = useApiQuery(api.queryKey, api.get, queryId, {
21
- enabled: !( /*queryId == 0 || */queryId == "" || queryId == null || queryId == undefined), // means than this query is only enabled if the id is defined
22
- onError: onFetchError,
23
- ...queryFetchOptions
24
- });
25
- // const [activeTab, setActiveTab] = React.useState(form && Array.isArray(form) ? form[0].key : "");
26
- // const [showTab, setShowTab] = React.useState(true);
27
- const mutation = invalidateQueriesOnSuccess ? useInvalidateParentMutation(api.upsert, invalidateQueryKey ?? api.queryKey, querySaveOptions)
28
- : useApiMutation(api.upsert, api.queryKey, queryId, querySaveOptions);
29
- const retry = React.useCallback(() => refetch(), [refetch]);
30
- const saveItem = React.useCallback(async (item, actions) => {
31
- // Clear mutation error if any
32
- mutation.reset();
33
- const formItem = formToQueryData ? formToQueryData(item) : { ...item };
34
- await mutation.mutateAsync(formItem)
35
- .then((response) => {
36
- if (onSuccess)
37
- onSuccess(formItem, response);
38
- else
39
- toast.success(`${title ? title(formItem) : formItem.name ?? formItem.title} ${queryId ? "saved" : "created"}`);
40
- // closing delete modal
41
- onClose?.();
42
- })
43
- .catch(error => {
44
- console.error("on error", error);
45
- if (onSaveError)
46
- onSaveError(item);
47
- else
48
- toast.error(`Couldn't save ${title ? title(formItem) : formItem.name ?? formItem.title}`);
49
- actions.setSubmitting(false);
50
- });
51
- }, [mutation, formToQueryData, onSuccess, onSaveError, onClose]);
52
- // const switchTab = React.useCallback((tab: string) =>
53
- // {
54
- // setActiveTab(tab);
55
- // setShowTab(false);
56
- // setTimeout(function ()
57
- // {
58
- // setActiveTab(tab);
59
- // setShowTab(true);
60
- // }, 150);
61
- // }, [setActiveTab])
62
- return (<Modal size={size} show={show} onClose={onClose} scheme="light" transition
63
- // closeOnMaskClick={false}
64
- {...props}>
65
- <Modal.Header>
66
- {!isInitialLoading && queryId && `Edit ${title ? title(data) : data?.["name"] ?? data?.["title"] ?? data?.["name"] ?? ""}`}
67
-
68
- {!queryId && `Create new ${itemLabel ?? "item"}`}
69
-
70
- {Array.isArray(form) && (<></>
71
- // <ul className="nav nav-bold nav-pills">
72
- // {form.map(item =>
73
- // <li key={item.key} className="nav-item cursor-pointer bg-hover-light rounded" onClick={() => switchTab(item.key)}>
74
- // <span className={clsx("nav-link", activeTab === item.key && "active")} data-toggle="tab">{item.label}</span>
75
- // </li>
76
- // )}
77
- // </ul>
78
- )}
79
- {/* <ModalCloseButton /> */}
80
- </Modal.Header>
81
-
82
- {isInitialLoading && (<Modal.Body>
83
- <QueryLoadingState minW="72"/>
84
- </Modal.Body>)}
85
-
86
- {isError && (<Modal.Body>
87
- <RetryOnError label={`${fetchErrorMsg} ${error}`} onClick={retry}/>
88
- </Modal.Body>)}
89
-
90
- {!isInitialLoading && !isError &&
91
- (<>
92
- <Formik
93
- // initialValues={fetchToFormData && queryId && data ? fetchToFormData(nonNullValues(data)) : nonNullValues(data) ?? initialValues(data) ?? {}}
94
- initialValues={fetchToFormData && queryId && data ? fetchToFormData(nonNullValues(data)) : nonNullValues(initialValues(data)) ?? {}} onSubmit={saveItem} {...formikProps}>
95
- {({ setFieldValue, dirty, handleSubmit, isValid, values }) => (<>
96
- <Modal.Body pb="6">
97
- <Form>
98
- {React.isValidElement(form) && form}
99
-
100
- {Array.isArray(form) && <FormRenderer form={form}/>}
101
- {isFunction(form) && <FormRenderer form={form(data ?? values)}/>}
102
- {/* {Array.isArray(form) && form.map(item =>
103
- <div key={item.key} className={clsx("tab-pane fade", showTab && "show", activeTab === item.key && "active")}>
104
- {item.form}
105
- </div>
106
- )} */}
107
- </Form>
108
- </Modal.Body>
109
-
110
- <Modal.Footer dflex placeContent="end" spaceX="3">
111
- <Button disabled={mutation.isLoading} onClick={onClose} variant="borderless" me="2">
112
- {cancelLabel}
113
- </Button>
114
- <Button type="submit" disabled={!dirty || mutation.isLoading /* || !isValid*/} onClick={() => handleSubmit()}>
115
- {saveLabel ? saveLabel : (queryId ? "Update" : "Create")}
116
- </Button>
117
- </Modal.Footer>
118
- </>)}
119
- </Formik>
120
- </>)}
121
-
122
- {mutation.isLoading && <ModalLoadingOverlay />}
123
- </Modal>);
124
- }
@@ -1,100 +0,0 @@
1
- import { Table, useTableContext } from "@compill/table";
2
- import { isFunction, runIfFn } from "@soperio/react";
3
- import React from "react";
4
- import { useParams } from "react-router-dom";
5
- import { InvalidateButton } from "../../buttons/InvalidateButton";
6
- import { PageContainer } from "../../page/PageContainer";
7
- import { TableContainer } from "../../table/TableContainer";
8
- import { TableCreateButton } from "../../table/TableCreateButton";
9
- import { TableFilterButton } from "../../table/TableFilterButton";
10
- import { TableTopBar } from "../../table/TableTopBar";
11
- import { ButtonBar } from "../../layout/ButtonBar";
12
- import { TableFilters } from "../../table/TableFilters";
13
- import { TableMassActions } from "../../table/TableMassActions";
14
- import { DialogRenderer } from "../dialog/DialogRenderer";
15
- import { RefreshButton } from "./RefreshButton";
16
- import { TableViewProvider, useTableViewContext } from "./TableViewContext";
17
- import { useTableProps } from "./useTableProps";
18
- function useId(queryField) {
19
- const params = useParams();
20
- if (queryField === undefined)
21
- return undefined;
22
- const { [queryField]: id } = params;
23
- return id;
24
- }
25
- export function TableView({ queryField, title, subtitle, screen, ...props }) {
26
- const id = useId(queryField);
27
- const _screen = runIfFn(screen, id);
28
- return (<PageContainer bgColor="white" {...props}>
29
- <TableContainer columns={_screen.table.columns} initialVisibleColumns={_screen.table.initialVisibleColumns} filtersMethod={_screen.table.filtersMethod}>
30
- <TT id={id} title={title} subtitle={subtitle} screen={_screen}/>
31
- </TableContainer>
32
- </PageContainer>);
33
- }
34
- function TT({ id, title, subtitle, screen }) {
35
- const { setRowSelection } = useTableContext();
36
- const { api, table, filters, massActions, buttonBar, rowActions, createView, editView, deleteItem, breadcrumbs } = screen;
37
- const tableApi = runIfFn(api, id ?? "");
38
- return (<>
39
- {/* {breadcrumbs && <PageTopBar breadcrumbs={breadcrumbs} />} */}
40
- <TableTopBar title={title} breadcrumbs={breadcrumbs}>
41
- <TableButtonBar buttonBar={buttonBar} createView={createView} editView={editView} api={tableApi} queryKey={tableApi.queryKey}>
42
- {filters && <TableFilterButton />}
43
- </TableButtonBar>
44
- {/* <TableColumnButton /> */}
45
- </TableTopBar>
46
-
47
- {filters &&
48
- (<TableFilters form={filters.form} initialValues={filters.initialValues} schema={filters.schema} processInput={filters.processInput}/>)}
49
- {massActions && <TableMassActions actions={massActions.items}/>}
50
-
51
- <TableViewProvider queryKey={tableApi.queryKey} editView={editView} deleteItem={deleteItem}>
52
- <TableWrapper table={{ ...table, onSelectionChange: setRowSelection }} rowActions={rowActions} api={tableApi} subtitle={subtitle} queryParams={screen.queryParams}/>
53
- <TableDialogManager />
54
- </TableViewProvider>
55
- </>);
56
- }
57
- function TableButtonBar({ buttonBar, queryKey, createView, editView, api, children }) {
58
- const createDialogFn = React.useCallback((data) => {
59
- return (onClose) => {
60
- const view = runIfFn(createView, data) ?? runIfFn(editView, null);
61
- if (view.type == "customDialog")
62
- return view.render({ show: true, onClose });
63
- else
64
- return <DialogRenderer config={view} onClose={onClose} invalidateQueryKey={api.queryKey}/>;
65
- };
66
- }, [createView, editView, api]);
67
- return (<ButtonBar>
68
- <RefreshButton queryKey={queryKey}/>
69
-
70
- {buttonBar && buttonBar.map((button, index) => <React.Fragment key={index}>
71
- {button.type === "create" && editView &&
72
- (<TableCreateButton buildDialog={createDialogFn(button.data)} icon={button.icon}>
73
- {button.label}
74
- </TableCreateButton>)}
75
-
76
- {button.type === "invalidate" && <InvalidateButton pathOrPermalink={button.pathOrPermalink}/>}
77
-
78
- {button.type === "custom" && button.render()}
79
- </React.Fragment>)}
80
-
81
- {children}
82
- </ButtonBar>);
83
- }
84
- function TableWrapper({ table, subtitle, rowActions, api, queryParams }) {
85
- const tableProps = useTableProps(api, table, rowActions, queryParams);
86
- const _subtitle = React.useMemo(() => {
87
- if (!subtitle)
88
- return undefined;
89
- return (data) => {
90
- return (<div textSize="lg" textColor="#475569" fontWeight="600">
91
- {isFunction(subtitle) ? subtitle(data) : subtitle}
92
- </div>);
93
- };
94
- }, [subtitle]);
95
- return <Table {...tableProps} p="8" title={_subtitle}/>;
96
- }
97
- function TableDialogManager() {
98
- const { dialog } = useTableViewContext();
99
- return dialog;
100
- }
@@ -1,24 +0,0 @@
1
- import { useBoolean } from "@compill/hooks";
2
- import { mdiArrowLeft } from "@mdi/js";
3
- import { IconButton } from "@valerya/ui";
4
- import { useHotkeys } from "react-hotkeys-hook";
5
- import Content from "./Content";
6
- import { Sidebar } from "./Sidebar";
7
- export function AdminLayout({ color, darkMode, logo, title, menuConfig, userMenuConfig, userSettingsPath, ...props }) {
8
- return (<div w="full" h="screen" dflex flexRow bgColor={`${color}-${darkMode ? "900" : "100"}`} {...props}>
9
- <LeftPanel color={color} darkMode={darkMode} logo={logo} title={title} menuConfig={menuConfig} userMenuConfig={userMenuConfig} userSettingsPath={userSettingsPath}/>
10
-
11
- <div w="screen" py="2" pe="2">
12
- <Content bgColor="white" rounded="lg" shadow/>
13
- </div>
14
- </div>);
15
- }
16
- function LeftPanel({ color, darkMode, logo, title, menuConfig, userMenuConfig, userSettingsPath }) {
17
- const [isOpen, __, toggle] = useBoolean(true);
18
- useHotkeys('ctrl+t', () => toggle(), [toggle]);
19
- return (<div ms={isOpen ? "0" : "-14.5rem"} transition="all" duration="500" transform>
20
- <Sidebar flexShrink="0" color={color} darkMode={darkMode} logo={logo} title={title} menuConfig={menuConfig} userMenuConfig={userMenuConfig} userSettingsPath={userSettingsPath}/>
21
-
22
- <IconButton icon={mdiArrowLeft} transition="all" duration="500" transform rotate={isOpen ? "0" : "180"} position="absolute" bottom="14" end="-5" size="lg" corners="pill" onClick={toggle} z="100"/>
23
- </div>);
24
- }
@@ -1,29 +0,0 @@
1
- import { DialogButton } from "../buttons/DialogButton";
2
- import { Button, Icon } from "@valerya/ui";
3
- import { useFormikContext } from "formik";
4
- import React from "react";
5
- export function ButtonBar({ children, ...props }) {
6
- return (<div dflex border="1px" borderColor="zinc-200" divideX="1px" divideColor="zinc-200" rounded="lg" overflow="hidden" {...props}>
7
- {children}
8
- </div>);
9
- }
10
- export const ButtonBarButton = React.forwardRef(function ({ icon, children, ...props }, ref) {
11
- return (<Button scheme="dark" size="sm" aspectRatio={icon && !children ? "square" : undefined} variant="borderless" dflex alignItems="center" placeContent="center" corners="square" gap="2" {...props} ref={ref}>
12
- {icon && <Icon path={icon}/>}
13
- {children}
14
- </Button>);
15
- });
16
- export const ButtonBarSubmitButton = React.forwardRef(function ({ useDirty, disabled, icon, children, ...props }, ref) {
17
- const { dirty, handleSubmit } = useFormikContext() ?? { dirty: false, handleSubmit: undefined, values: {} };
18
- const onSubmit = React.useCallback(() => handleSubmit(), [handleSubmit]);
19
- return (<Button scheme="dark" size="sm" aspectRatio={icon && !children ? "square" : undefined} variant="borderless" dflex alignItems="center" placeContent="center" corners="square" gap="2" disabled={(useDirty && !dirty) || disabled} onClick={onSubmit} {...props} ref={ref}>
20
- {icon && <Icon path={icon}/>}
21
- {children}
22
- </Button>);
23
- });
24
- export function ButtonBarDialogButton({ icon, children, ...props }) {
25
- return (<DialogButton scheme="dark" size="sm" aspectRatio={icon && !children ? "square" : undefined} variant="borderless" dflex alignItems="center" placeContent="center" corners="square" gap="2" {...props}>
26
- {icon && <Icon path={icon}/>}
27
- {children}
28
- </DialogButton>);
29
- }
@@ -1,10 +0,0 @@
1
- import { Outlet } from "react-router-dom";
2
- /**
3
- *
4
- *
5
- */
6
- export default function Content({ ...props }) {
7
- return (<div w="100%" h="100%" overflowY="auto" {...props}>
8
- <Outlet />
9
- </div>);
10
- }
@@ -1,12 +0,0 @@
1
- export function PageTitleBar({ title, children, ...props }) {
2
- return (<div dflex flexRow alignItems="center" gap="3" p="8"
3
- // borderB="0.5"
4
- // borderBColor="--bg-2"
5
- {...props}>
6
- {title && <h2 textSize="x2" fontWeight="600" textColor="#3f4254" textTransform="capitalize">{title}</h2>}
7
-
8
- <div flexGrow>&nbsp;</div>
9
-
10
- {children}
11
- </div>);
12
- }
@@ -1,24 +0,0 @@
1
- import { FlexCenter } from "@compill/components";
2
- import { Menu } from "./menu/Menu";
3
- import { AppEnv } from "@compill/env";
4
- import Image from "next/image";
5
- import { UserBlock } from "./menu/UserBlock";
6
- export function Sidebar({ show, logo, title, menuConfig, userMenuConfig, userSettingsPath, color, darkMode, ...props }) {
7
- return (<div dflex flexCol w="full" md_w="64" minH="screen" p="0" textColor={darkMode ? "white" : "slate-800"} {...props}>
8
- <FlexCenter placeContent="start" p="4" font="title" gap="3" borderB="px" borderBColor="slate-900" borderOpacity="5">
9
- {logo ?? <Logo width={40} height={40} darkMode={darkMode}/>}
10
- <h1 textSize="md">{title || AppEnv.appName()}</h1>
11
- </FlexCenter>
12
-
13
- <Menu overflowY="auto" flexGrow="1" p="4" darkMode={darkMode} config={menuConfig}/>
14
-
15
- <div p="2">
16
- <UserBlock darkMode={darkMode} color={color} menuConfig={userMenuConfig} path={userSettingsPath}/>
17
- </div>
18
- </div>);
19
- }
20
- export default function Logo({ width, height, darkMode, ...props }) {
21
- return (<div {...props}>
22
- <Image src={`/logo_${darkMode ? "light" : "dark"}.png`} alt={AppEnv.appName() || ""} width={width} height={height} priority unoptimized/>
23
- </div>);
24
- }
@@ -1,30 +0,0 @@
1
- import { MenuItem } from "./MenuItem";
2
- import { NextMenuItem } from "./NextMenuItem";
3
- /**
4
- *
5
- *
6
- */
7
- export function Menu({ darkMode, config, useNextRouter, ...props }) {
8
- const Comp = useNextRouter ? NextMenuItem : MenuItem;
9
- return (<ul {...props}>
10
- {config.map((item, index) => {
11
- if (item.type == "divider")
12
- return <Divider key={index} title={item.label}/>;
13
- if (item.type == "item") {
14
- return (<Comp key={index} icon={item.icon} path={item.path} depth={0} darkMode={darkMode} subMenu={item.children}>
15
- {item.label}
16
- </Comp>);
17
- }
18
- })}
19
- </ul>);
20
- }
21
- function Divider({ title }) {
22
- return (<div px="2" mt="5" mb="2" opacity="75" textTransform="capitalize" letterSpacing="widest" fontWeight="700" textSize="xs">
23
- {title}
24
- </div>);
25
- }
26
- function CategoryItem({ children, ...props }) {
27
- return (<li ps="5" py="2" mt="5" textSize="sm" textColor="white" textOpacity="80" fontWeight="600" textTransform="uppercase">
28
- {children}
29
- </li>);
30
- }