muffin-admin 1.36.4 → 1.36.6

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 (68) hide show
  1. package/dist/esm/admin.js +71 -0
  2. package/dist/esm/authprovider.js +191 -0
  3. package/dist/esm/buttons/ActionButton.js +81 -0
  4. package/dist/esm/buttons/LinkButton.js +23 -0
  5. package/dist/esm/dashboard.js +60 -0
  6. package/dist/esm/dataprovider.js +296 -0
  7. package/dist/esm/fields/AvatarField.js +29 -0
  8. package/dist/esm/fields/FKField.js +27 -0
  9. package/dist/esm/fields/JsonField.js +28 -0
  10. package/dist/esm/hooks/useAction.js +8 -0
  11. package/dist/esm/index.js +40 -0
  12. package/dist/esm/inputs/FKInput.js +33 -0
  13. package/dist/esm/inputs/JsonInput.js +63 -0
  14. package/dist/esm/resources.js +38 -0
  15. package/dist/esm/ui.js +71 -0
  16. package/dist/esm/utils.js +38 -0
  17. package/dist/esm/views/create.js +16 -0
  18. package/dist/esm/views/edit.js +37 -0
  19. package/dist/esm/views/list.js +64 -0
  20. package/dist/esm/views/show.js +26 -0
  21. package/dist/esm/web.js +2 -0
  22. package/package.json +7 -11
  23. package/src/admin.jsx +78 -0
  24. package/src/authprovider.js +85 -0
  25. package/src/buttons/ActionButton.jsx +99 -0
  26. package/src/buttons/LinkButton.jsx +20 -0
  27. package/src/dashboard.jsx +74 -0
  28. package/src/dataprovider.js +94 -0
  29. package/src/fields/AvatarField.jsx +33 -0
  30. package/src/fields/FKField.jsx +27 -0
  31. package/src/fields/JsonField.jsx +26 -0
  32. package/src/hooks/useAction.js +9 -0
  33. package/src/index.js +14 -0
  34. package/src/inputs/FKInput.jsx +41 -0
  35. package/src/inputs/JsonInput.jsx +62 -0
  36. package/src/resources.jsx +36 -0
  37. package/src/ui.jsx +107 -0
  38. package/src/utils.js +38 -0
  39. package/src/views/create.jsx +30 -0
  40. package/src/views/edit.jsx +41 -0
  41. package/src/views/list.jsx +86 -0
  42. package/src/views/show.jsx +42 -0
  43. package/src/web.js +3 -0
  44. package/.eslintrc.json +0 -44
  45. package/Makefile +0 -18
  46. package/jsconfig.json +0 -9
  47. package/webpack.config.js +0 -45
  48. /package/dist/{admin.js → cjs/admin.js} +0 -0
  49. /package/dist/{authprovider.js → cjs/authprovider.js} +0 -0
  50. /package/dist/{buttons → cjs/buttons}/ActionButton.js +0 -0
  51. /package/dist/{buttons → cjs/buttons}/LinkButton.js +0 -0
  52. /package/dist/{dashboard.js → cjs/dashboard.js} +0 -0
  53. /package/dist/{dataprovider.js → cjs/dataprovider.js} +0 -0
  54. /package/dist/{fields → cjs/fields}/AvatarField.js +0 -0
  55. /package/dist/{fields → cjs/fields}/FKField.js +0 -0
  56. /package/dist/{fields → cjs/fields}/JsonField.js +0 -0
  57. /package/dist/{hooks → cjs/hooks}/useAction.js +0 -0
  58. /package/dist/{index.js → cjs/index.js} +0 -0
  59. /package/dist/{inputs → cjs/inputs}/FKInput.js +0 -0
  60. /package/dist/{inputs → cjs/inputs}/JsonInput.js +0 -0
  61. /package/dist/{resources.js → cjs/resources.js} +0 -0
  62. /package/dist/{ui.js → cjs/ui.js} +0 -0
  63. /package/dist/{utils.js → cjs/utils.js} +0 -0
  64. /package/dist/{views → cjs/views}/create.js +0 -0
  65. /package/dist/{views → cjs/views}/edit.js +0 -0
  66. /package/dist/{views → cjs/views}/list.js +0 -0
  67. /package/dist/{views → cjs/views}/show.js +0 -0
  68. /package/dist/{web.js → cjs/web.js} +0 -0
@@ -0,0 +1,16 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import React from "react";
3
+ import { Create, SimpleForm, TopToolbar, ListButton } from "react-admin";
4
+ import initRAItems from "../ui";
5
+ import { checkParams, processAdmin, setupAdmin } from "../utils";
6
+
7
+ // Initialize a create component
8
+ setupAdmin("create", checkParams(function (inputs, res) {
9
+ return function MACreate(props) {
10
+ var Actions = /*#__PURE__*/React.createElement(TopToolbar, null, /*#__PURE__*/React.createElement(ListButton, null));
11
+ return /*#__PURE__*/React.createElement(Create, _extends({
12
+ actions: Actions
13
+ }, props), /*#__PURE__*/React.createElement(SimpleForm, null, processAdmin("create-inputs", inputs, res)));
14
+ };
15
+ }));
16
+ setupAdmin("create-inputs", initRAItems);
@@ -0,0 +1,37 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
+ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
4
+ var _excluded = ["basePath", "resource"];
5
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
6
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
7
+ import React from "react";
8
+ import { Edit, ListButton, ShowButton, SimpleForm, TopToolbar } from "react-admin";
9
+ import initRAItems from "../ui";
10
+ import { checkParams, processAdmin, setupAdmin } from "../utils";
11
+ import { ActionButton } from "../buttons/ActionButton";
12
+
13
+ // Initialize an edit component
14
+ setupAdmin("edit", checkParams(function (_ref, res) {
15
+ var actions = _ref.actions,
16
+ inputs = _ref.inputs;
17
+ return function MAEdit(props) {
18
+ var Actions = function Actions(_ref2) {
19
+ var basePath = _ref2.basePath,
20
+ resource = _ref2.resource,
21
+ baseProps = _objectWithoutProperties(_ref2, _excluded);
22
+ return /*#__PURE__*/React.createElement(TopToolbar, null, actions.map(function (props, idx) {
23
+ var aProps = _objectSpread(_objectSpread({
24
+ resource: resource,
25
+ basePath: basePath
26
+ }, baseProps), props);
27
+ return /*#__PURE__*/React.createElement(ActionButton, _extends({
28
+ key: idx
29
+ }, aProps));
30
+ }), /*#__PURE__*/React.createElement(ListButton, null), /*#__PURE__*/React.createElement(ShowButton, null));
31
+ };
32
+ return /*#__PURE__*/React.createElement(Edit, _extends({
33
+ actions: /*#__PURE__*/React.createElement(Actions, null)
34
+ }, props), /*#__PURE__*/React.createElement(SimpleForm, null, processAdmin("edit-inputs", inputs, res)));
35
+ };
36
+ }));
37
+ setupAdmin("edit-inputs", initRAItems);
@@ -0,0 +1,64 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
+ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
4
+ var _excluded = ["children", "filters", "edit", "pagination", "show", "limit", "limitMax", "actions"];
5
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
6
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
7
+ import React from "react";
8
+ import { BulkDeleteButton, Datagrid, EditButton, Filter, List, Pagination } from "react-admin";
9
+ import uniq from "lodash/uniq";
10
+ import sortBy from "lodash/sortBy";
11
+ import initRAItems from "../ui";
12
+ import { checkParams, processAdmin, setupAdmin } from "../utils";
13
+ import { BulkActionButton } from "../buttons/ActionButton";
14
+ var defaultPagination = /*#__PURE__*/React.createElement(Pagination, {
15
+ rowsPerPageOptions: [10, 25, 50, 100]
16
+ });
17
+
18
+ // Initiliaze a list component
19
+ setupAdmin("list", checkParams(function (props, res) {
20
+ var children = props.children,
21
+ filters = props.filters,
22
+ edit = props.edit,
23
+ pagination = props.pagination,
24
+ show = props.show,
25
+ limit = props.limit,
26
+ limitMax = props.limitMax,
27
+ actions = props.actions,
28
+ listProps = _objectWithoutProperties(props, _excluded);
29
+ children = processAdmin("list-fields", children, res);
30
+ if (edit) children.push( /*#__PURE__*/React.createElement(EditButton, {
31
+ key: "edit-button"
32
+ }));
33
+ pagination = pagination || /*#__PURE__*/React.createElement(Pagination, {
34
+ rowsPerPageOptions: sortBy(uniq([10, 25, 50, 100, limit, limitMax]))
35
+ });
36
+ return function MAList(props) {
37
+ var Filters = function Filters(props) {
38
+ return /*#__PURE__*/React.createElement(Filter, props, processAdmin("list-filters", filters, res));
39
+ };
40
+ var Actions = processAdmin("list-bulkActions", actions);
41
+ props = _objectSpread(_objectSpread({}, props), listProps);
42
+ return /*#__PURE__*/React.createElement(List, _extends({
43
+ filters: /*#__PURE__*/React.createElement(Filters, null),
44
+ bulkActionButtons: /*#__PURE__*/React.createElement(Actions, null),
45
+ perPage: limit,
46
+ pagination: pagination || defaultPagination
47
+ }, props), /*#__PURE__*/React.createElement(Datagrid, {
48
+ rowClick: show ? "show" : null
49
+ }, children));
50
+ };
51
+ }));
52
+ setupAdmin("list-bulkActions", function (actions) {
53
+ return function MABulkActions(props) {
54
+ var buttons = actions.map(function (action, idx) {
55
+ var aProps = _objectSpread(_objectSpread({}, action), props);
56
+ return /*#__PURE__*/React.createElement(BulkActionButton, _extends({
57
+ key: idx
58
+ }, aProps));
59
+ });
60
+ return /*#__PURE__*/React.createElement(React.Fragment, null, buttons, /*#__PURE__*/React.createElement(BulkDeleteButton, props));
61
+ };
62
+ });
63
+ setupAdmin("list-filters", initRAItems);
64
+ setupAdmin("list-fields", initRAItems);
@@ -0,0 +1,26 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import React from "react";
3
+ import { ListButton, EditButton, Show, SimpleShowLayout, TopToolbar } from "react-admin";
4
+ import initRAItems from "../ui";
5
+ import { checkParams, processAdmin, setupAdmin } from "../utils";
6
+ import { ActionButton } from "../buttons/ActionButton";
7
+
8
+ // Initiliaze a show component
9
+ setupAdmin("show", checkParams(function (_ref, resource) {
10
+ var actions = _ref.actions,
11
+ fields = _ref.fields;
12
+ return function MAShow(props) {
13
+ var Actions = function Actions() {
14
+ return /*#__PURE__*/React.createElement(TopToolbar, null, actions.map(function (props, idx) {
15
+ return /*#__PURE__*/React.createElement(ActionButton, _extends({
16
+ key: idx,
17
+ resource: resource
18
+ }, props));
19
+ }), /*#__PURE__*/React.createElement(ListButton, null), /*#__PURE__*/React.createElement(EditButton, null));
20
+ };
21
+ return /*#__PURE__*/React.createElement(Show, _extends({
22
+ actions: /*#__PURE__*/React.createElement(Actions, null)
23
+ }, props), /*#__PURE__*/React.createElement(SimpleShowLayout, null, processAdmin("show-fields", fields, resource)));
24
+ };
25
+ }));
26
+ setupAdmin("show-fields", initRAItems);
@@ -0,0 +1,2 @@
1
+ import { initAdmin } from ".";
2
+ global.initAdmin = initAdmin;
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "muffin-admin",
3
- "version": "1.36.4",
3
+ "version": "1.36.6",
4
4
  "description": "NPM package for https://github.com/klen/muffin-admin",
5
- "main": "dist/index.js",
5
+ "files": [
6
+ "src",
7
+ "dist"
8
+ ],
9
+ "main": "dist/cjs/index.js",
10
+ "module": "dist/esm/index.js",
6
11
  "scripts": {
7
12
  "test": "echo \"Error: no test specified\" && exit 1"
8
13
  },
@@ -35,14 +40,5 @@
35
40
  "webpack": "^5.24.4",
36
41
  "webpack-cli": "^5.0.0",
37
42
  "webpack-dev-server": "^4.3.1"
38
- },
39
- "babel": {
40
- "presets": [
41
- "@babel/preset-env",
42
- "@babel/preset-react"
43
- ],
44
- "plugins": [
45
- "@babel/plugin-transform-runtime"
46
- ]
47
43
  }
48
44
  }
package/src/admin.jsx ADDED
@@ -0,0 +1,78 @@
1
+ import React from "react"
2
+
3
+ import {
4
+ Admin,
5
+ AppBar,
6
+ Layout,
7
+ Login,
8
+ ToggleThemeButton,
9
+ defaultTheme,
10
+ } from "react-admin"
11
+ import {
12
+ IconButton,
13
+ SvgIcon,
14
+ Tooltip,
15
+ Typography,
16
+ createTheme,
17
+ } from "@mui/material"
18
+ import * as icons from "@mui/icons-material"
19
+
20
+ import authProvider from "./authprovider"
21
+ import dataProvider from "./dataprovider"
22
+ import { processAdmin, setupAdmin } from "./utils"
23
+
24
+ import "./dashboard"
25
+ import "./resources"
26
+
27
+ const darkTheme = createTheme({
28
+ palette: { mode: "dark" },
29
+ })
30
+
31
+ // Initialize the admin
32
+ setupAdmin("admin", (props) => {
33
+ const { apiUrl, auth, adminProps, appBarLinks, dashboard, resources } = props
34
+
35
+ let appBar = (props) => (
36
+ <AppBar {...props}>
37
+ <Typography
38
+ variant="h6"
39
+ color="inherit"
40
+ id="react-admin-title"
41
+ style={{
42
+ flex: 1,
43
+ textOverflow: "ellipsis",
44
+ whiteSpace: "nowrap",
45
+ overflow: "hidden",
46
+ }}
47
+ />
48
+ <ToggleThemeButton lightTheme={defaultTheme} darkTheme={darkTheme} />
49
+ {appBarLinks.map((info) => (
50
+ <Tooltip key={info.url} title={info.title}>
51
+ <IconButton color="inherit" href={info.url}>
52
+ <SvgIcon component={icons[info.icon]} />
53
+ </IconButton>
54
+ </Tooltip>
55
+ ))}
56
+ </AppBar>
57
+ )
58
+
59
+ return (
60
+ <Admin
61
+ authProvider={processAdmin("auth", auth)}
62
+ dataProvider={processAdmin("data", apiUrl)}
63
+ dashboard={processAdmin("dashboard", dashboard)}
64
+ loginPage={processAdmin("login", auth)}
65
+ layout={(props) => <Layout appBar={appBar} {...props} />}
66
+ {...adminProps}
67
+ >
68
+ {processAdmin("resources", resources)}
69
+ </Admin>
70
+ )
71
+ })
72
+
73
+ // Initialize authentication and data providers
74
+ setupAdmin("auth", authProvider)
75
+ setupAdmin("data", dataProvider)
76
+
77
+ // Initialize login page
78
+ setupAdmin("login", () => Login)
@@ -0,0 +1,85 @@
1
+ import Cookies from "js-cookie"
2
+
3
+ import { makeRequest, processAdmin, requestHeaders, setupAdmin } from "./utils"
4
+
5
+ setupAdmin(
6
+ "auth-get",
7
+ ({ storage }) =>
8
+ (name) =>
9
+ storage == "localstorage" ? localStorage.getItem(name) : Cookies.get(name)
10
+ )
11
+
12
+ setupAdmin("auth-set", ({ storage }) => (name, value) => {
13
+ if (storage == "localstorage") {
14
+ localStorage.setItem(name, value)
15
+ requestHeaders["Authorization"] = value
16
+ } else Cookies.set(name, value)
17
+ })
18
+
19
+ export default (props) => {
20
+ const { identityURL, authorizeURL, logoutURL, required, storage_name } = props
21
+
22
+ const authGet = processAdmin("auth-get", props)
23
+ const authSet = processAdmin("auth-set", props)
24
+
25
+ // Initialize request headers
26
+ authSet(storage_name, authGet(storage_name))
27
+
28
+ let getIdentity = async () => {
29
+ if (identityURL) {
30
+ let { json } = await makeRequest(identityURL)
31
+ return json
32
+ }
33
+ }
34
+
35
+ if (required)
36
+ return {
37
+ login: async (data) => {
38
+ if (!authorizeURL) throw { message: "Authorization is not supported" }
39
+
40
+ let { json } = await makeRequest(authorizeURL, { data, method: "POST" })
41
+ authSet(storage_name, json)
42
+ },
43
+
44
+ checkError: async (error) => {
45
+ const { status } = error
46
+
47
+ if (status == 401 || status == 403) {
48
+ // Clean storage
49
+ authSet(storage_name, "")
50
+
51
+ throw {
52
+ message: "Invalid authorization",
53
+ redirectTo: logoutURL,
54
+ logoutUser: !logoutURL,
55
+ }
56
+ }
57
+ },
58
+
59
+ checkAuth: async () => {
60
+ const auth = authGet(storage_name)
61
+ if (!auth) throw { message: "Authorization required" }
62
+
63
+ if (!identityURL) return auth
64
+
65
+ let user = await getIdentity()
66
+ if (!user) throw { message: "Authorization required" }
67
+
68
+ return user
69
+ },
70
+
71
+ logout: async () => {
72
+ // Clean storage
73
+ authSet(storage_name, "")
74
+
75
+ if (logoutURL) window.location = logoutURL
76
+ },
77
+
78
+ getIdentity,
79
+
80
+ getPermissions: () => {
81
+ const role = authGet(storage_name + "_role")
82
+ return role ? Promise.resolve(role) : Promise.reject()
83
+ },
84
+ }
85
+ }
@@ -0,0 +1,99 @@
1
+ import React from "react"
2
+
3
+ import {
4
+ Button,
5
+ useRefresh,
6
+ useUnselectAll,
7
+ useNotify,
8
+ useRecordContext,
9
+ } from "react-admin"
10
+ import * as icons from "@mui/icons-material"
11
+
12
+ import useAction from "../hooks/useAction"
13
+
14
+ export const BulkActionButton = ({
15
+ label,
16
+ icon,
17
+ title,
18
+ action,
19
+ resource,
20
+ selectedIds,
21
+ }) => {
22
+ const refresh = useRefresh(),
23
+ unselectAll = useUnselectAll(resource),
24
+ notify = useNotify(),
25
+ Icon = icons[icon]
26
+
27
+ const mutation = useAction(resource, action)
28
+
29
+ let onClick = () => {
30
+ mutation.mutate(
31
+ {
32
+ action,
33
+ ids: selectedIds,
34
+ },
35
+ {
36
+ onSuccess: ({ data }) => {
37
+ if (data && data.message) notify(data.message, { type: "success" })
38
+ refresh()
39
+ unselectAll()
40
+ },
41
+ onError: (err) => {
42
+ notify(typeof err === "string" ? err : err.message, { type: "error" })
43
+ },
44
+ }
45
+ )
46
+ }
47
+
48
+ return (
49
+ <Button
50
+ label={label}
51
+ title={title}
52
+ onClick={onClick}
53
+ disabled={mutation.isLoading}
54
+ >
55
+ {Icon && <Icon />}
56
+ </Button>
57
+ )
58
+ }
59
+
60
+ export const ActionButton = (props) => {
61
+ const { icon, label, title, resource, action } = props
62
+ const record = useRecordContext()
63
+ const mutation = useAction(resource, action)
64
+
65
+ const refresh = useRefresh(),
66
+ notify = useNotify(),
67
+ Icon = icons[icon]
68
+
69
+ let onClick = () => {
70
+ mutation.mutate(
71
+ { record },
72
+ {
73
+ onSuccess: ({ data }) => {
74
+ refresh()
75
+ if (data && data.redirectTo) window.location = data.redirectTo
76
+ if (data && data.message) notify(data.message, { type: "success" })
77
+ },
78
+ onError: (error) => {
79
+ notify(typeof error === "string" ? error : error.message, {
80
+ type: "error",
81
+ })
82
+ },
83
+ }
84
+ )
85
+ }
86
+
87
+ return (
88
+ <Button
89
+ label={label}
90
+ title={title}
91
+ onClick={onClick}
92
+ disabled={mutation.isLoading}
93
+ >
94
+ {Icon && <Icon />}
95
+ </Button>
96
+ )
97
+ }
98
+
99
+ export default ActionButton
@@ -0,0 +1,20 @@
1
+ import React from "react"
2
+ import { Button } from "react-admin"
3
+ import { Link } from "react-router-dom"
4
+ import * as icons from "@mui/icons-material"
5
+
6
+ const LinkButton = ({ label, icon, title, resource, filters }) => {
7
+ const Icon = icons[icon] || icon
8
+ let linkParams = {
9
+ pathname: `/${resource}`,
10
+ search: filters ? `filter=${JSON.stringify(filters)}` : undefined,
11
+ }
12
+
13
+ return (
14
+ <Button label={label} title={title} component={Link} to={linkParams}>
15
+ {Icon && <Icon />}
16
+ </Button>
17
+ )
18
+ }
19
+
20
+ export default LinkButton
@@ -0,0 +1,74 @@
1
+ import React from "react"
2
+
3
+ import {
4
+ Grid,
5
+ Card,
6
+ CardContent,
7
+ Typography,
8
+ Table,
9
+ TableBody,
10
+ TableRow,
11
+ TableCell,
12
+ } from "@mui/material"
13
+
14
+ import { setupAdmin } from "./utils"
15
+
16
+ const AdminTableView = ({ src }) => (
17
+ <Table>
18
+ <TableBody>
19
+ {src.map((row, idx) => (
20
+ <TableRow key={idx} hover>
21
+ {row.map((cell, idx) => (
22
+ <TableCell key={idx}>{cell}</TableCell>
23
+ ))}
24
+ </TableRow>
25
+ ))}
26
+ </TableBody>
27
+ </Table>
28
+ )
29
+
30
+ const AdminCard = ({ src }) => {
31
+ if (Array.isArray(src)) {
32
+ return (
33
+ <Grid container item spacing={2}>
34
+ {src.map((card, idx) => (
35
+ <AdminCard key={idx} src={card} />
36
+ ))}
37
+ </Grid>
38
+ )
39
+ }
40
+
41
+ let { title, value } = src
42
+
43
+ return (
44
+ <Grid item xs>
45
+ <Card>
46
+ <CardContent>
47
+ <Typography
48
+ variant="h5"
49
+ component="h2"
50
+ m={2}
51
+ style={{ textAlign: "center" }}
52
+ >
53
+ {title}
54
+ </Typography>
55
+ {(Array.isArray(value) && <AdminTableView src={value} />) || (
56
+ <pre>{JSON.stringify(value, null, 2)}</pre>
57
+ )}
58
+ </CardContent>
59
+ </Card>
60
+ </Grid>
61
+ )
62
+ }
63
+
64
+ // Process dashboard
65
+ setupAdmin("dashboard", (props) => {
66
+ if (!props) return
67
+
68
+ const Dashboard = () => (
69
+ <Grid container spacing={1}>
70
+ <AdminCard src={props} />
71
+ </Grid>
72
+ )
73
+ return Dashboard
74
+ })
@@ -0,0 +1,94 @@
1
+ import { makeRequest } from "./utils"
2
+
3
+ export default (apiUrl) => {
4
+ const methods = {
5
+ getList: async (resource, { filter, pagination, sort }) => {
6
+ const query = {}
7
+ if (filter) query.where = JSON.stringify(filter)
8
+ if (pagination) {
9
+ const { page, perPage: limit } = pagination
10
+ query.limit = limit
11
+ query.offset = limit * (page - 1)
12
+ }
13
+ if (sort) {
14
+ const { field, order } = sort
15
+ query.sort = order == "ASC" ? field : `-${field}`
16
+ }
17
+
18
+ const { headers, json } = await makeRequest(`${apiUrl}/${resource}`, {
19
+ query,
20
+ })
21
+ return {
22
+ data: json,
23
+ total: parseInt(headers.get("x-total"), 10),
24
+ }
25
+ },
26
+
27
+ getOne: async (resource, { id }) => {
28
+ const { json } = await makeRequest(`${apiUrl}/${resource}/${id}`)
29
+ return { data: json }
30
+ },
31
+
32
+ create: async (resource, { data }) => {
33
+ const { json } = await makeRequest(`${apiUrl}/${resource}`, {
34
+ data,
35
+ method: "POST",
36
+ })
37
+ return { data: json }
38
+ },
39
+
40
+ update: async (resource, { id, data }) => {
41
+ const { json } = await makeRequest(`${apiUrl}/${resource}/${id}`, {
42
+ data,
43
+ method: "PUT",
44
+ })
45
+ return { data: json }
46
+ },
47
+
48
+ updateMany: async (resource, { ids, data }) => {
49
+ await Promise.all(ids.map((id) => methods.update(resource, { id, data })))
50
+ return { data: ids }
51
+ },
52
+
53
+ delete: async (resource, { id }) => {
54
+ await makeRequest(`${apiUrl}/${resource}/${id}`, {
55
+ method: "DELETE",
56
+ })
57
+ return { data: { id } }
58
+ },
59
+
60
+ deleteMany: async (resource, { ids }) => {
61
+ await makeRequest(`${apiUrl}/${resource}`, {
62
+ data: ids,
63
+ method: "DELETE",
64
+ })
65
+ return { data: ids }
66
+ },
67
+
68
+ getMany: (resource, { ids }) => {
69
+ return methods.getList(resource, { filter: { id: { $in: ids } } })
70
+ },
71
+
72
+ getManyReference: async (resource, { target, id, filter, ...opts }) => {
73
+ filter = filter || {}
74
+ filter[target] = id
75
+ return await methods.getList(resource, { filter, ...opts })
76
+ },
77
+
78
+ runAction: async (resource, action, props) => {
79
+ const { payload, ids, record } = props
80
+ action = action.replace(/^\/+/, "")
81
+ if (record) {
82
+ action = action.replace(/\{([^}]+)\}/, (_, field) => record[field])
83
+ }
84
+ const { json } = await makeRequest(`${apiUrl}/${action}`, {
85
+ query: { ids },
86
+ method: "POST",
87
+ data: payload,
88
+ })
89
+ return { data: json }
90
+ },
91
+ }
92
+
93
+ return methods
94
+ }
@@ -0,0 +1,33 @@
1
+ import React from "react"
2
+ import get from "lodash/get"
3
+ import { useRecordContext } from "ra-core"
4
+ import Avatar from "@mui/material/Avatar"
5
+
6
+ const AvatarField = ({ source, alt, style, nameProp, ...props }) => {
7
+ const record = useRecordContext(props)
8
+
9
+ let value = get(record, source),
10
+ name = record[nameProp]
11
+
12
+ const letters = name
13
+ ? name
14
+ .trim(" ")
15
+ .split(/\s+/)
16
+ .slice(0, 2)
17
+ .map((n) => n[0].toUpperCase())
18
+ .join("")
19
+ : ""
20
+
21
+ return (
22
+ <Avatar src={value} alt={alt} style={style}>
23
+ {letters}
24
+ </Avatar>
25
+ )
26
+ }
27
+
28
+ AvatarField.displayName = "AvatarField"
29
+ AvatarField.defaultProps = {
30
+ addLabel: true,
31
+ }
32
+
33
+ export default AvatarField