@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.
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
@@ -0,0 +1,37 @@
1
+ import { useApiMutation, useInvalidateParentMutation, useMutate } from "@compill/api";
2
+ import { ModalLoadingOverlay } from "@compill/components";
3
+ import { Button, Icon, Modal, ModalBody, ModalFooter, ModalHeader } from "@valerya/ui";
4
+ export function ConfirmationActionButton({ label, buttonProps, icon, queryKey, queryFn, successMsg, errorMsg, invalidateParent }) {
5
+ const mutation = invalidateParent ? useInvalidateParentMutation(queryFn, queryKey) : useApiMutation(queryFn, queryKey);
6
+ const mutate = useMutate(mutation, {
7
+ successMsg,
8
+ errorMsg
9
+ });
10
+ return (<Button display="flex" alignItems="center" gap="3" {...buttonProps} onClick={mutate} disabled={mutation.isLoading}>
11
+ {icon && <Icon path={icon}/>}
12
+ {label}
13
+ </Button>);
14
+ }
15
+ export function ConfirmationDialog({ title, text, positiveButtonLabel, negativeButtonLabel, queryKey, queryFn, successMsg, errorMsg, invalidateParent, show, onClose }) {
16
+ const mutation = invalidateParent ? useInvalidateParentMutation(queryFn, queryKey) : useApiMutation(queryFn, queryKey);
17
+ const mutate = useMutate(mutation, {
18
+ successMsg,
19
+ errorMsg
20
+ });
21
+ return (<Modal show={show} onClose={onClose}>
22
+ <ModalHeader>
23
+ <div textSize="xl" fontWeight="600">{title}</div>
24
+ </ModalHeader>
25
+
26
+ <ModalBody>
27
+ {text}
28
+ </ModalBody>
29
+
30
+ <ModalFooter dflex gap="3" alignItems="center" placeContent="end">
31
+ <Button>{negativeButtonLabel || "Cancel"}</Button>
32
+ <Button onClick={mutate}>{positiveButtonLabel || "OK"}</Button>
33
+ </ModalFooter>
34
+
35
+ {mutation.isLoading && <ModalLoadingOverlay />}
36
+ </Modal>);
37
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { EditItemDialogConfig } from "../types/EditItemDialog";
3
2
  import { QueryWrapperDialogConfig } from "../types/QueryWrapperDialog";
4
3
  import { MultiQueryWrapperDialogConfig } from "../types/MultiQueryWrapperDialog";
@@ -0,0 +1,13 @@
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
+ }
@@ -0,0 +1,36 @@
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
+ }
@@ -0,0 +1,124 @@
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,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { MultiQueryWrapperDialogConfig } from "../types/MultiQueryWrapperDialog";
3
2
  export type MultiQueryWrapperDialogProps = Omit<MultiQueryWrapperDialogConfig, "type"> & {
4
3
  queryId?: string;
@@ -0,0 +1,22 @@
1
+ import { useApiQueries } from "@compill/api";
2
+ import React from "react";
3
+ import { ItemEditDialog } from "./ItemEditDialog";
4
+ export function MultiQueryWrapperDialog({ queries, config, onClose, queryId, invalidateQueryKey }) {
5
+ const { data, isFetching, isError } = useApiQueries(queries.map(q => ({
6
+ queryKey: q.api.queryKey,
7
+ queryFn: q.fn == "get" ? q.api.get : q.api.getAll,
8
+ queryOptions: {
9
+ cacheTime: q.cache === false ? 0 : undefined,
10
+ staleTime: q.cache === false ? 0 : undefined
11
+ }
12
+ })));
13
+ const transformedData = React.useMemo(() => {
14
+ return data?.map((d, index) => queries[index]?.transformFn ? queries[index]?.transformFn?.(d) : d);
15
+ }, [data, queries]);
16
+ // TODO This is not really good
17
+ // So instead, add a isPreloading and isPreloadingError to ItemEditDialog to handle the cases
18
+ // if (isFetching)
19
+ // return null
20
+ // @ts-ignore
21
+ return <ItemEditDialog isPreloading={isFetching} {...config(...transformedData)} queryId={queryId} invalidateQueryKey={invalidateQueryKey} show onClose={onClose}/>;
22
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { CRUDAPI, CRUD_MODEL } from "@compill/api";
3
2
  import { QueryWrapperDialogConfig } from "../types/QueryWrapperDialog";
4
3
  import { EditItemDialogConfig } from "../types/EditItemDialog";
@@ -0,0 +1,19 @@
1
+ import { useApiQuery } from "@compill/api";
2
+ import React from "react";
3
+ import { ItemEditDialog } from "./ItemEditDialog";
4
+ export function QueryWrapperDialog({ api, fn, transformFn, config, onClose, queryId, invalidateQueryKey }) {
5
+ const { data, isFetching } = useApiQuery(api.queryKey, fn === "get" || fn === "getTransformed" ? api.get : api.getAll, undefined, { retryOnMount: false, refetchOnMount: false, refetchOnWindowFocus: false });
6
+ const transformedData = React.useMemo(() => {
7
+ if (data && (fn === "getTransformed" || fn === "getAllTransformed")) {
8
+ if (!transformFn)
9
+ console.warn(`QueryWrapperDialog: you forgot to pass transformFn as parameter for fn ${fn}`);
10
+ // @ts-ignore
11
+ return transformFn?.(data);
12
+ }
13
+ return data;
14
+ }, [data, fn, transformFn]);
15
+ if (isFetching)
16
+ return null;
17
+ // @ts-ignore
18
+ return <ItemEditDialog {...config(transformedData)} queryId={queryId} invalidateQueryKey={invalidateQueryKey} show onClose={onClose}/>;
19
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  export declare function RefreshButton({ queryKey }: {
3
2
  queryKey: string[];
4
3
  }): JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { useInvalidateQuery } from "@compill/api";
2
+ import { mdiRefresh } from "@mdi/js";
3
+ import { Icon } from "@valerya/ui";
4
+ import { ButtonBarButton } from "../../layout/ButtonBar";
5
+ import { useHotkeys } from "react-hotkeys-hook";
6
+ export function RefreshButton({ queryKey }) {
7
+ const invalidate = useInvalidateQuery(queryKey);
8
+ useHotkeys('ctrl+r', () => invalidate(), { preventDefault: true }, [invalidate]);
9
+ return (<ButtonBarButton scheme="dark" size="sm" aspectRatio="square" variant="borderless" onClick={invalidate}>
10
+ <Icon path={mdiRefresh}/>
11
+ </ButtonBarButton>);
12
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { TableRowAction } from "../types/TableView";
3
2
  import { API } from "@compill/admin-api";
4
3
  interface TableRowActionViewProps {
@@ -0,0 +1,45 @@
1
+ import { mdiDelete, mdiEye, mdiOpenInNew, mdiPencil } from "@mdi/js";
2
+ import { Icon } from "@valerya/ui";
3
+ import { TableRowPublishPostButton } from "./TableRowPublishPostButton";
4
+ import React from "react";
5
+ import { TableRowActionButton } from "@compill/admin";
6
+ import { runIfFn } from "@soperio/react";
7
+ export function TableRowActionsView({ row, onAction, rowActions, api, queryKey }) {
8
+ const item = row.original;
9
+ return (<div dflex w="full" alignItems="stretch" placeContent="end" h="full">
10
+ {runIfFn(rowActions, item)?.map((action, index) => (<React.Fragment key={index}>
11
+ {action.type === "publish" && <TableRowPublishPostButton id={item.id} api={action.api ?? api} status={item.status} invalidateQueryKey={queryKey}/>}
12
+
13
+ {action.type == "custom" && <>{action.component(item, queryKey, action.icon, action.label)}</>}
14
+
15
+ {!["publish", "custom"].includes(action.type) &&
16
+ (<ActionButton onClick={() => onAction(action, item)} scheme={schemes[action.type]}>
17
+ <Icon path={icons[action.type]} size="sm"/>
18
+ </ActionButton>)}
19
+ </React.Fragment>))}
20
+ </div>);
21
+ }
22
+ function ActionButton({ onClick, ...props }) {
23
+ const handleClick = React.useCallback((event) => {
24
+ event?.preventDefault();
25
+ event?.stopPropagation();
26
+ onClick?.(event);
27
+ }, [onClick]);
28
+ return (<TableRowActionButton onClick={handleClick} {...props}/>);
29
+ }
30
+ const icons = {
31
+ "link": mdiOpenInNew,
32
+ "view": mdiEye,
33
+ "edit": mdiPencil,
34
+ "delete": mdiDelete,
35
+ "publish": mdiDelete,
36
+ "custom": ""
37
+ };
38
+ const schemes = {
39
+ "link": "dark",
40
+ "view": "dark",
41
+ "edit": "dark",
42
+ "delete": "dark",
43
+ "publish": "dark",
44
+ "custom": "dark"
45
+ };
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { ButtonProps } from "@valerya/ui";
3
2
  import { API } from "@compill/admin-api";
4
3
  export declare function TableRowPublishPostButton({ id, api, status, invalidateQueryKey, ...props }: {
@@ -0,0 +1,21 @@
1
+ import { Icon } from "@valerya/ui";
2
+ import { mdiPublish, mdiPublishOff } from "@mdi/js";
3
+ import { Button } from "@valerya/ui";
4
+ import React from "react";
5
+ import { useInvalidateParentMutation } from "@compill/api";
6
+ import { toast } from "react-toastify";
7
+ export function TableRowPublishPostButton({ id, api, status, invalidateQueryKey, ...props }) {
8
+ const isDraft = status == "draft";
9
+ const mutation = useInvalidateParentMutation(isDraft ? api.publish : api.unpublish, invalidateQueryKey ?? api.queryKey, { networkMode: "always" });
10
+ const publish = React.useCallback((event) => {
11
+ event?.preventDefault();
12
+ event?.stopPropagation();
13
+ mutation.reset();
14
+ mutation.mutateAsync(id)
15
+ .then(() => toast.success(isDraft ? "Published!" : "Unpublished!"))
16
+ .catch(error => toast.error(`Error: ${error}`));
17
+ }, [mutation, id]);
18
+ return (<Button variant="borderless" corners="square" scheme="dark" onClick={publish} {...props}>
19
+ <Icon path={isDraft ? mdiPublish : mdiPublishOff} size="sm"/>
20
+ </Button>);
21
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { SoperioComponent } from "@soperio/react";
3
2
  import { TableViewConfig } from "../types/TableView";
4
3
  export declare function TableView({ queryField, title, subtitle, screen, ...props }: Omit<TableViewConfig, "type"> & SoperioComponent): JSX.Element;
@@ -0,0 +1,100 @@
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
+ }
@@ -0,0 +1,57 @@
1
+ import { useOpenLink } from "@compill/hooks";
2
+ import { createContext, runIfFn } from "@soperio/react";
3
+ import React from "react";
4
+ import { useNavigate } from "react-router-dom";
5
+ import { DialogRenderer } from "../dialog/DialogRenderer";
6
+ import { ItemDeleteDialog } from "../dialog/ItemDeleteDialog";
7
+ import { AppEnv } from "@compill/env";
8
+ const [provider, useContext] = createContext();
9
+ function TableViewProvider({ editView, deleteItem, queryKey, children }) {
10
+ const openLink = useOpenLink();
11
+ const navigate = useNavigate();
12
+ const [dialog, setDialog] = React.useState(null);
13
+ const onCloseDialog = React.useCallback(() => setDialog(null), [setDialog]);
14
+ const onAction = React.useCallback((action, item) => {
15
+ switch (action.type) {
16
+ case "view":
17
+ {
18
+ navigate(runIfFn(action.path, item));
19
+ break;
20
+ }
21
+ case "link":
22
+ {
23
+ openLink(`${AppEnv.websiteUrl()}/${runIfFn(action.path, item)}`);
24
+ break;
25
+ }
26
+ case "edit":
27
+ {
28
+ const editConfig = runIfFn(editView, item);
29
+ if (editConfig) {
30
+ if (editConfig.type == "customDialog") {
31
+ setDialog(editConfig.render({ show: true, onClose: onCloseDialog }));
32
+ }
33
+ else {
34
+ setDialog(<DialogRenderer onClose={onCloseDialog} config={editConfig} queryId={item.id} invalidateQueryKey={queryKey}/>);
35
+ }
36
+ }
37
+ break;
38
+ }
39
+ case "delete":
40
+ {
41
+ const deleteConfig = runIfFn(deleteItem, item);
42
+ setDialog(<ItemDeleteDialog show onClose={onCloseDialog} queryId={item.id} invalidateQueryKey={queryKey} msg={item.msg} {...deleteConfig} itemLabel={runIfFn(deleteConfig.itemLabel, item)}/>);
43
+ // TODO
44
+ // const { initialValues, ...props } = editItem!!
45
+ // setDialog(<ItemEditDialog {...props} initialValues={runIfFn(initialValues, item)} show queryId={item?.id} onClose={onCloseDialog} />)
46
+ break;
47
+ }
48
+ }
49
+ }, [navigate, editView, deleteItem]);
50
+ const Provider = provider;
51
+ const value = {
52
+ dialog,
53
+ onAction
54
+ };
55
+ return <Provider value={value}>{children}</Provider>;
56
+ }
57
+ export { TableViewProvider, useContext as useTableViewContext };
@@ -0,0 +1,56 @@
1
+ import { useOpenLink } from "@compill/hooks";
2
+ import { runIfFn } from "@soperio/react";
3
+ import { createColumnHelper } from "@tanstack/react-table";
4
+ import React from "react";
5
+ import { useNavigate } from "react-router-dom";
6
+ import { TableRowActionsView } from "./TableRowActionsView";
7
+ import { useTableViewContext } from "./TableViewContext";
8
+ import { useRouter } from "next/router";
9
+ import { AppEnv } from "@compill/env";
10
+ export function useTableProps(api, table, rowActions, queryParams) {
11
+ const navigate = useNavigate();
12
+ const nextRouter = useRouter();
13
+ const openLink = useOpenLink();
14
+ const { onAction } = useTableViewContext();
15
+ const { onRowClick, columns: c, ...props } = table;
16
+ const onRowClickHandler = React.useCallback((item) => {
17
+ const config = runIfFn(onRowClick, item);
18
+ if (config) {
19
+ switch (config.type) {
20
+ case "navigate":
21
+ {
22
+ navigate(runIfFn(config.path, item) ?? "");
23
+ break;
24
+ }
25
+ case "nextpush":
26
+ {
27
+ nextRouter.push(runIfFn(config.path, item));
28
+ break;
29
+ }
30
+ case "link":
31
+ {
32
+ openLink(`${AppEnv.websiteUrl()}/${runIfFn(config.path, item)}`);
33
+ break;
34
+ }
35
+ }
36
+ }
37
+ }, [navigate, onRowClick]);
38
+ const columns = React.useMemo(() => {
39
+ const columns = table.columns.concat([]);
40
+ if (rowActions) {
41
+ columns.push(createColumnHelper().display({
42
+ id: "actions",
43
+ header: "Actions",
44
+ cell: props => <TableRowActionsView row={props.row} onAction={onAction} rowActions={rowActions} api={api} queryKey={api.queryKey}/>
45
+ }));
46
+ }
47
+ return columns;
48
+ }, [table, onAction, rowActions, api]);
49
+ const tableProps = { ...props };
50
+ tableProps.columns = columns;
51
+ tableProps.onRowClick = onRowClickHandler;
52
+ tableProps.queryKey = api.queryKey;
53
+ tableProps.queryFilters = queryParams;
54
+ tableProps.queryFn = api.search;
55
+ return tableProps;
56
+ }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { API } from "@compill/admin-api";
3
2
  import * as Yup from "yup";
4
3
  import { Breadcrumb } from "../../breadcrumbs/BreadCrumbs";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { CRUDAPI } from "@compill/api";
3
2
  import { Breadcrumb } from "../../breadcrumbs/BreadCrumbs";
4
3
  import { DetailsViewConfig } from "./DetailsView";
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { API } from "@compill/admin-api";
3
2
  import { FormRendererConfig } from "@compill/form";
4
3
  import { TableProps } from "@compill/table";