@compill/admin 1.0.101 → 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.
Files changed (169) hide show
  1. package/dist/index.js +50 -0
  2. package/{src → dist}/lib/SectionTitle.d.ts +0 -1
  3. package/dist/lib/SectionTitle.jsx +3 -0
  4. package/{src → dist}/lib/breadcrumbs/BreadCrumbs.d.ts +0 -1
  5. package/dist/lib/breadcrumbs/BreadCrumbs.jsx +43 -0
  6. package/dist/lib/buttons/DialogButton.jsx +17 -0
  7. package/{src → dist}/lib/buttons/InvalidateButton.d.ts +0 -1
  8. package/dist/lib/buttons/InvalidateButton.jsx +10 -0
  9. package/{src → dist}/lib/buttons/NavigateButton.d.ts +0 -1
  10. package/dist/lib/buttons/NavigateButton.jsx +13 -0
  11. package/{src → dist}/lib/buttons/PublishButton.d.ts +0 -1
  12. package/dist/lib/buttons/PublishButton.jsx +18 -0
  13. package/{src → dist}/lib/buttons/UpdateButton.d.ts +0 -1
  14. package/dist/lib/buttons/UpdateButton.jsx +12 -0
  15. package/{src → dist}/lib/buttons/ViewButton.d.ts +1 -2
  16. package/dist/lib/buttons/ViewButton.jsx +14 -0
  17. package/{src → dist}/lib/cells/OrderCell.d.ts +0 -1
  18. package/dist/lib/cells/OrderCell.jsx +35 -0
  19. package/{src → dist}/lib/json/DetailsView.d.ts +0 -1
  20. package/dist/lib/json/DetailsView.jsx +96 -0
  21. package/{src → dist}/lib/json/EditItemView.d.ts +0 -1
  22. package/dist/lib/json/EditItemView.jsx +5 -0
  23. package/{src → dist}/lib/json/MultiQueryWrapper.d.ts +0 -1
  24. package/dist/lib/json/MultiQueryWrapper.jsx +60 -0
  25. package/{src → dist}/lib/json/QueryWrapper.d.ts +0 -1
  26. package/dist/lib/json/QueryWrapper.jsx +28 -0
  27. package/{src → dist}/lib/json/ScreenRenderer.d.ts +0 -1
  28. package/dist/lib/json/ScreenRenderer.jsx +18 -0
  29. package/{src → dist}/lib/json/ScreenTopBar.d.ts +0 -1
  30. package/dist/lib/json/ScreenTopBar.jsx +39 -0
  31. package/{src → dist}/lib/json/TabbedView.d.ts +0 -1
  32. package/dist/lib/json/TabbedView.jsx +28 -0
  33. package/{src → dist}/lib/json/buttons/ActionButton.d.ts +0 -1
  34. package/dist/lib/json/buttons/ActionButton.jsx +13 -0
  35. package/{src → dist}/lib/json/buttons/ConfirmationActionButton.d.ts +0 -1
  36. package/dist/lib/json/buttons/ConfirmationActionButton.jsx +37 -0
  37. package/{src → dist}/lib/json/dialog/DialogRenderer.d.ts +0 -1
  38. package/dist/lib/json/dialog/DialogRenderer.jsx +13 -0
  39. package/dist/lib/json/dialog/ItemDeleteDialog.jsx +36 -0
  40. package/dist/lib/json/dialog/ItemEditDialog.jsx +124 -0
  41. package/{src → dist}/lib/json/dialog/MultiQueryWrapperDialog.d.ts +0 -1
  42. package/dist/lib/json/dialog/MultiQueryWrapperDialog.jsx +22 -0
  43. package/{src → dist}/lib/json/dialog/QueryWrapperDialog.d.ts +0 -1
  44. package/dist/lib/json/dialog/QueryWrapperDialog.jsx +19 -0
  45. package/{src → dist}/lib/json/table/RefreshButton.d.ts +0 -1
  46. package/dist/lib/json/table/RefreshButton.jsx +12 -0
  47. package/{src → dist}/lib/json/table/TableRowActionsView.d.ts +0 -1
  48. package/dist/lib/json/table/TableRowActionsView.jsx +45 -0
  49. package/{src → dist}/lib/json/table/TableRowPublishPostButton.d.ts +0 -1
  50. package/dist/lib/json/table/TableRowPublishPostButton.jsx +21 -0
  51. package/{src → dist}/lib/json/table/TableView.d.ts +0 -1
  52. package/dist/lib/json/table/TableView.jsx +100 -0
  53. package/dist/lib/json/table/TableViewContext.jsx +57 -0
  54. package/dist/lib/json/table/useTableProps.jsx +56 -0
  55. package/{src → dist}/lib/json/types/DetailsView.d.ts +0 -1
  56. package/dist/lib/json/types/DetailsView.js +1 -0
  57. package/dist/lib/json/types/EditItemDialog.js +1 -0
  58. package/dist/lib/json/types/MultiQueryWrapper.js +1 -0
  59. package/dist/lib/json/types/MultiQueryWrapperDialog.js +1 -0
  60. package/dist/lib/json/types/QueryWrapper.js +1 -0
  61. package/dist/lib/json/types/QueryWrapperDialog.js +1 -0
  62. package/dist/lib/json/types/ScreenConfig.js +1 -0
  63. package/{src → dist}/lib/json/types/TabbedView.d.ts +0 -1
  64. package/dist/lib/json/types/TabbedView.js +1 -0
  65. package/{src → dist}/lib/json/types/TableView.d.ts +0 -1
  66. package/dist/lib/json/types/TableView.js +1 -0
  67. package/{src → dist}/lib/layout/AdminLayout.d.ts +0 -1
  68. package/dist/lib/layout/AdminLayout.jsx +24 -0
  69. package/{src → dist}/lib/layout/ButtonBar.d.ts +1 -1
  70. package/dist/lib/layout/ButtonBar.jsx +29 -0
  71. package/{src → dist}/lib/layout/Content.d.ts +0 -1
  72. package/dist/lib/layout/Content.jsx +10 -0
  73. package/{src → dist}/lib/layout/PageTitleBar.d.ts +0 -1
  74. package/dist/lib/layout/PageTitleBar.jsx +12 -0
  75. package/{src → dist}/lib/layout/Sidebar.d.ts +0 -1
  76. package/dist/lib/layout/Sidebar.jsx +24 -0
  77. package/{src → dist}/lib/layout/menu/Menu.d.ts +0 -1
  78. package/dist/lib/layout/menu/Menu.jsx +30 -0
  79. package/{src → dist}/lib/layout/menu/MenuButton.d.ts +0 -1
  80. package/dist/lib/layout/menu/MenuButton.jsx +7 -0
  81. package/dist/lib/layout/menu/MenuConfig.js +1 -0
  82. package/{src → dist}/lib/layout/menu/MenuItem.d.ts +0 -1
  83. package/dist/lib/layout/menu/MenuItem.jsx +20 -0
  84. package/{src → dist}/lib/layout/menu/NextMenuItem.d.ts +0 -1
  85. package/dist/lib/layout/menu/NextMenuItem.jsx +20 -0
  86. package/{src → dist}/lib/layout/menu/SelectedIndicator.d.ts +0 -1
  87. package/dist/lib/layout/menu/SelectedIndicator.jsx +3 -0
  88. package/{src → dist}/lib/layout/menu/UserBlock.d.ts +1 -2
  89. package/dist/lib/layout/menu/UserBlock.jsx +55 -0
  90. package/{src → dist}/lib/modal/AttachDialog.d.ts +0 -1
  91. package/dist/lib/modal/AttachDialog.jsx +109 -0
  92. package/dist/lib/modal/FormActionDialog.jsx +46 -0
  93. package/{src → dist}/lib/page/PageContainer.d.ts +0 -1
  94. package/dist/lib/page/PageContainer.jsx +4 -0
  95. package/{src → dist}/lib/page/PageContentEditor.d.ts +0 -1
  96. package/dist/lib/page/PageContentEditor.jsx +11 -0
  97. package/{src → dist}/lib/page/PageMain.d.ts +0 -1
  98. package/dist/lib/page/PageMain.jsx +4 -0
  99. package/dist/lib/page/PageQueryStateContainer.jsx +15 -0
  100. package/{src → dist}/lib/page/PageSectionTitle.d.ts +0 -1
  101. package/dist/lib/page/PageSectionTitle.jsx +3 -0
  102. package/{src → dist}/lib/page/PageSidebar.d.ts +0 -1
  103. package/dist/lib/page/PageSidebar.jsx +3 -0
  104. package/{src → dist}/lib/page/PageSidebarSection.d.ts +0 -1
  105. package/dist/lib/page/PageSidebarSection.jsx +7 -0
  106. package/dist/lib/page/PageStateContainer.jsx +9 -0
  107. package/{src → dist}/lib/page/PageSubSectionTitle.d.ts +0 -1
  108. package/dist/lib/page/PageSubSectionTitle.jsx +3 -0
  109. package/{src → dist}/lib/page/PageTitle.d.ts +0 -1
  110. package/dist/lib/page/PageTitle.jsx +3 -0
  111. package/dist/lib/page/PageTopBar.jsx +92 -0
  112. package/{src → dist}/lib/status/StatusBadge.d.ts +0 -1
  113. package/dist/lib/status/StatusBadge.jsx +20 -0
  114. package/dist/lib/table/TableColumnButton.d.ts +1 -0
  115. package/dist/lib/table/TableColumnButton.jsx +53 -0
  116. package/{src → dist}/lib/table/TableContainer.d.ts +0 -1
  117. package/dist/lib/table/TableContainer.jsx +11 -0
  118. package/dist/lib/table/TableContainerContext.jsx +39 -0
  119. package/{src → dist}/lib/table/TableCreateButton.d.ts +0 -1
  120. package/dist/lib/table/TableCreateButton.jsx +9 -0
  121. package/{src → dist}/lib/table/TableFilterButton.d.ts +0 -1
  122. package/dist/lib/table/TableFilterButton.jsx +16 -0
  123. package/{src → dist}/lib/table/TableFilters.d.ts +0 -1
  124. package/dist/lib/table/TableFilters.jsx +46 -0
  125. package/{src → dist}/lib/table/TableMassActions.d.ts +0 -1
  126. package/dist/lib/table/TableMassActions.jsx +15 -0
  127. package/{src → dist}/lib/table/TableRowActionBar.d.ts +0 -1
  128. package/dist/lib/table/TableRowActionBar.jsx +14 -0
  129. package/{src → dist}/lib/table/TableRowActionButton.d.ts +0 -1
  130. package/dist/lib/table/TableRowActionButton.jsx +7 -0
  131. package/{src → dist}/lib/table/TableRowActionDialogButton.d.ts +1 -2
  132. package/dist/lib/table/TableRowActionDialogButton.jsx +8 -0
  133. package/{src → dist}/lib/table/TableRowDeleteButton.d.ts +0 -1
  134. package/dist/lib/table/TableRowDeleteButton.jsx +5 -0
  135. package/{src → dist}/lib/table/TableRowEditButton.d.ts +0 -1
  136. package/dist/lib/table/TableRowEditButton.jsx +7 -0
  137. package/{src → dist}/lib/table/TableRowNavigateButton.d.ts +0 -1
  138. package/dist/lib/table/TableRowNavigateButton.jsx +13 -0
  139. package/{src → dist}/lib/table/TableRowPublishPostButton.d.ts +0 -1
  140. package/dist/lib/table/TableRowPublishPostButton.jsx +18 -0
  141. package/{src → dist}/lib/table/TableRowViewButton.d.ts +0 -1
  142. package/dist/lib/table/TableRowViewButton.jsx +12 -0
  143. package/{src → dist}/lib/table/TableTopBar.d.ts +1 -2
  144. package/dist/lib/table/TableTopBar.jsx +17 -0
  145. package/package.json +60 -4
  146. package/README.md +0 -7
  147. package/index.cjs.d.ts +0 -1
  148. package/index.cjs.js +0 -3710
  149. package/index.esm.d.ts +0 -1
  150. package/index.esm.js +0 -3662
  151. package/src/lib/table/TableColumnButton.d.ts +0 -0
  152. /package/{src → dist}/index.d.ts +0 -0
  153. /package/{src → dist}/lib/buttons/DialogButton.d.ts +0 -0
  154. /package/{src → dist}/lib/json/dialog/ItemDeleteDialog.d.ts +0 -0
  155. /package/{src → dist}/lib/json/dialog/ItemEditDialog.d.ts +0 -0
  156. /package/{src → dist}/lib/json/table/TableViewContext.d.ts +0 -0
  157. /package/{src → dist}/lib/json/table/useTableProps.d.ts +0 -0
  158. /package/{src → dist}/lib/json/types/EditItemDialog.d.ts +0 -0
  159. /package/{src → dist}/lib/json/types/MultiQueryWrapper.d.ts +0 -0
  160. /package/{src → dist}/lib/json/types/MultiQueryWrapperDialog.d.ts +0 -0
  161. /package/{src → dist}/lib/json/types/QueryWrapper.d.ts +0 -0
  162. /package/{src → dist}/lib/json/types/QueryWrapperDialog.d.ts +0 -0
  163. /package/{src → dist}/lib/json/types/ScreenConfig.d.ts +0 -0
  164. /package/{src → dist}/lib/layout/menu/MenuConfig.d.ts +0 -0
  165. /package/{src → dist}/lib/modal/FormActionDialog.d.ts +0 -0
  166. /package/{src → dist}/lib/page/PageQueryStateContainer.d.ts +0 -0
  167. /package/{src → dist}/lib/page/PageStateContainer.d.ts +0 -0
  168. /package/{src → dist}/lib/page/PageTopBar.d.ts +0 -0
  169. /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";
@@ -1,3 +1,2 @@
1
- /// <reference types="react" />
2
1
  import { ParentComponent, SoperioComponent } from "@soperio/react";
3
2
  export declare function SectionTitle({ children, ...props }: SoperioComponent & ParentComponent): JSX.Element;
@@ -0,0 +1,3 @@
1
+ export function SectionTitle({ children, ...props }) {
2
+ return <h2 textSize="xl" fontWeight="600" textColor="slate-800" {...props}>{children}</h2>;
3
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { SoperioComponent } from "@soperio/react";
3
2
  export interface Breadcrumb {
4
3
  label: string;
@@ -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
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { ButtonBarButtonProps } from "../layout/ButtonBar";
3
2
  interface InvalidateButtonProps extends ButtonBarButtonProps {
4
3
  pathOrPermalink: string;
@@ -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
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { ButtonProps } from "@valerya/ui";
3
2
  export declare function NavigateButton({ path, ...props }: {
4
3
  path: string;
@@ -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
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { API } from "@compill/admin-api";
3
2
  import { ButtonProps } from "@valerya/ui";
4
3
  interface PublishButtonProps extends ButtonProps {
@@ -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
+ }
@@ -1,3 +1,2 @@
1
- /// <reference types="react" />
2
1
  import { ButtonProps } from "@valerya/ui";
3
2
  export declare function UpdateButton({ ...props }: ButtonProps): JSX.Element;
@@ -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
- /// <reference types="react" />
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
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  interface OrderApi {
3
2
  moveUp: (id: string) => Promise<any>;
4
3
  moveDown: (id: string) => Promise<any>;
@@ -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,3 +1,2 @@
1
- /// <reference types="react" />
2
1
  import { ItemEditDialogProps } from "./dialog/ItemEditDialog";
3
2
  export declare function EditItemView({ initialValues, ...props }: Omit<ItemEditDialogProps, "show">): JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { runIfFn } from "@soperio/react";
2
+ import { ItemEditDialog } from "./dialog/ItemEditDialog";
3
+ export function EditItemView({ initialValues, ...props }) {
4
+ return (<ItemEditDialog {...props} initialValues={runIfFn(initialValues, null)} show/>);
5
+ }
@@ -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
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { QueryWrapperConfig } from "./types/QueryWrapper";
3
2
  import { SoperioComponent } from "@soperio/react";
4
3
  import { CRUD_MODEL } from "@compill/api";
@@ -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
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { ScreenConfig } from "./types/ScreenConfig";
3
2
  import { SoperioComponent } from "@soperio/react";
4
3
  export declare function ScreenRenderer({ config, tabbed, ...props }: {
@@ -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
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { API } from "@compill/admin-api";
3
2
  import { Breadcrumb } from "../breadcrumbs/BreadCrumbs";
4
3
  import { DetailViewButton } from "./types/DetailsView";
@@ -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
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { TabbedViewConfig } from "./types/TabbedView";
3
2
  import { SoperioComponent } from "@soperio/react";
4
3
  export declare function TabbedView({ queryField, api, screen, ...props }: TabbedViewConfig & SoperioComponent): JSX.Element;
@@ -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
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { MutationQueryFn, MutationQueryKey } from "@compill/api";
3
2
  import { ButtonProps } from "@valerya/ui";
4
3
  interface ActionButtonProps {
@@ -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
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { MutationQueryFn, MutationQueryKey } from "@compill/api";
3
2
  import { ButtonProps, ModalProps } from "@valerya/ui";
4
3
  interface ConfirmationActionButtonProps {