muffin-admin 11.8.0 → 13.0.0

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 (99) hide show
  1. package/dist/MuffinAdmin.d.ts +5 -5
  2. package/dist/MuffinAdmin.js +1 -1
  3. package/dist/MuffinDashboard.d.ts +1 -1
  4. package/dist/MuffinDashboard.js +3 -3
  5. package/dist/MuffinMenu.d.ts +2 -2
  6. package/dist/MuffinMenu.js +2 -2
  7. package/dist/MuffinRecordList.d.ts +2 -2
  8. package/dist/MuffinRecordList.js +1 -1
  9. package/dist/MuffinResource.d.ts +2 -2
  10. package/dist/MuffinResourceCreate.d.ts +3 -3
  11. package/dist/MuffinResourceEdit.d.ts +6 -6
  12. package/dist/MuffinResourceEdit.js +36 -4
  13. package/dist/MuffinResourceList.d.ts +2 -2
  14. package/dist/MuffinResourceList.js +10 -5
  15. package/dist/MuffinResourceShow.d.ts +5 -5
  16. package/dist/MuffinResourceShow.js +43 -6
  17. package/dist/actions/LinkAction.d.ts +2 -2
  18. package/dist/authprovider.js +7 -9
  19. package/dist/buildRA.d.ts +4 -3
  20. package/dist/buildRA.js +1 -1
  21. package/dist/buttons/ActionButton.d.ts +5 -5
  22. package/dist/buttons/ActionButton.js +5 -5
  23. package/dist/buttons/CopyButton.d.ts +1 -1
  24. package/dist/buttons/LinkButton.d.ts +2 -2
  25. package/dist/buttons/LinkButton.js +8 -2
  26. package/dist/common/AdminModal.d.ts +6 -4
  27. package/dist/common/AdminModal.js +2 -2
  28. package/dist/common/ConfirmationProvider.d.ts +2 -2
  29. package/dist/common/ConfirmationProvider.js +1 -1
  30. package/dist/common/HelpLink.d.ts +1 -1
  31. package/dist/common/PayloadButtons.d.ts +1 -1
  32. package/dist/common/PayloadButtons.js +1 -1
  33. package/dist/context.d.ts +1 -1
  34. package/dist/dataprovider.d.ts +7 -7
  35. package/dist/fields/AvatarField.d.ts +3 -3
  36. package/dist/fields/AvatarField.js +2 -2
  37. package/dist/fields/CopyField.d.ts +1 -1
  38. package/dist/fields/EditableBooleanField.d.ts +1 -1
  39. package/dist/fields/FKField.d.ts +4 -4
  40. package/dist/fields/FKField.js +12 -2
  41. package/dist/fields/JsonField.d.ts +1 -1
  42. package/dist/filters/DateRangeFilter.d.ts +1 -1
  43. package/dist/filters/Filter.d.ts +2 -2
  44. package/dist/filters/Filter.js +2 -2
  45. package/dist/filters/SearchFilter.d.ts +2 -2
  46. package/dist/filters/SearchFilter.js +6 -4
  47. package/dist/hooks/useAction.d.ts +2 -2
  48. package/dist/hooks/useAction.js +2 -2
  49. package/dist/i18n/en.d.ts +1 -1
  50. package/dist/i18n/provider.d.ts +3 -3
  51. package/dist/i18n/ru.d.ts +1 -1
  52. package/dist/index.d.ts +11 -11
  53. package/dist/index.js +12 -12
  54. package/dist/inputs/DateRangeInput.d.ts +2 -2
  55. package/dist/inputs/FKInput.d.ts +2 -2
  56. package/dist/inputs/ImgInput.d.ts +2 -2
  57. package/dist/inputs/JsonInput.d.ts +1 -1
  58. package/dist/inputs/JsonInput.js +1 -1
  59. package/dist/inputs/TimestampInput.d.ts +2 -2
  60. package/dist/utils.d.ts +2 -2
  61. package/dist/utils.js +1 -0
  62. package/dist/version.d.ts +1 -0
  63. package/dist/version.js +1 -0
  64. package/dist/web.js +0 -1
  65. package/package.json +15 -29
  66. package/src/MuffinAdmin.tsx +6 -7
  67. package/src/MuffinDashboard.tsx +6 -6
  68. package/src/MuffinMenu.tsx +3 -5
  69. package/src/MuffinRecordList.tsx +2 -2
  70. package/src/MuffinResource.tsx +1 -1
  71. package/src/MuffinResourceCreate.tsx +1 -1
  72. package/src/MuffinResourceEdit.tsx +73 -12
  73. package/src/MuffinResourceList.tsx +17 -6
  74. package/src/MuffinResourceShow.tsx +93 -15
  75. package/src/actions/LinkAction.tsx +1 -1
  76. package/src/authprovider.ts +88 -101
  77. package/src/buildRA.tsx +4 -3
  78. package/src/buttons/ActionButton.tsx +9 -10
  79. package/src/buttons/LinkButton.tsx +11 -3
  80. package/src/common/AdminModal.tsx +8 -5
  81. package/src/common/ConfirmationProvider.tsx +1 -1
  82. package/src/common/PayloadButtons.tsx +1 -1
  83. package/src/context.ts +1 -1
  84. package/src/dataprovider.ts +2 -2
  85. package/src/fields/AvatarField.tsx +8 -10
  86. package/src/fields/FKField.tsx +14 -2
  87. package/src/filters/Filter.tsx +2 -2
  88. package/src/filters/SearchFilter.tsx +14 -7
  89. package/src/globals.d.ts +1 -0
  90. package/src/hooks/useAction.ts +4 -4
  91. package/src/i18n/en.ts +1 -1
  92. package/src/i18n/ru.ts +1 -1
  93. package/src/index.tsx +12 -13
  94. package/src/inputs/DateRangeInput.tsx +1 -1
  95. package/src/inputs/JsonInput.tsx +1 -1
  96. package/src/utils.tsx +2 -1
  97. package/src/version.ts +1 -0
  98. package/src/web.ts +0 -1
  99. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -1,4 +1,5 @@
1
- import { PropsWithChildren } from "react"
1
+ import { Box, Typography } from "@mui/material"
2
+ import type { PropsWithChildren } from "react"
2
3
  import {
3
4
  DeleteButton,
4
5
  Edit,
@@ -8,10 +9,14 @@ import {
8
9
  SimpleForm,
9
10
  Toolbar,
10
11
  TopToolbar,
12
+ useRecordContext,
11
13
  useResourceContext,
14
+ useTranslate,
12
15
  } from "react-admin"
16
+ import { useLocation, useNavigate } from "react-router-dom"
13
17
  import { buildRA } from "./buildRA"
14
18
  import { ActionButton } from "./buttons"
19
+ import { AdminModal } from "./common"
15
20
  import { useMuffinAdminOpts, useMuffinResourceOpts } from "./hooks"
16
21
  import { findBuilder, setupAdmin } from "./utils"
17
22
 
@@ -21,18 +26,64 @@ export function MuffinEdit({ children }: PropsWithChildren) {
21
26
  } = useMuffinAdminOpts()
22
27
 
23
28
  const { edit, name, key } = useMuffinResourceOpts()
29
+ const location = useLocation()
30
+ const navigate = useNavigate()
31
+ const returnTo = new URLSearchParams(location.search).get("returnTo")
24
32
  if (!edit) return null
25
33
 
34
+ const handleClose = () => {
35
+ if (returnTo) {
36
+ navigate(returnTo)
37
+ return
38
+ }
39
+
40
+ if (window.history.length > 1) {
41
+ navigate(-1)
42
+ return
43
+ }
44
+
45
+ navigate(`/${name}`)
46
+ }
47
+
26
48
  const Actions = findBuilder(["edit-toolbar", name])
27
49
  const Inputs = findBuilder(["edit-inputs", name])
28
50
  const FormToolbar = findBuilder(["edit-form-toolbar", name])
29
51
 
30
52
  return (
31
- <Edit actions={<Actions />} mutationMode={mutationMode} queryOptions={{ meta: { key } }}>
32
- {children}
33
- <SimpleForm toolbar={<FormToolbar />}>
34
- <Inputs />
35
- </SimpleForm>
53
+ <Edit
54
+ actions={false}
55
+ title={false}
56
+ component="div"
57
+ mutationMode={mutationMode}
58
+ queryOptions={{ meta: { key } }}
59
+ sx={{
60
+ "& .RaEdit-main": {
61
+ padding: 0,
62
+ },
63
+ }}
64
+ >
65
+ <AdminModal
66
+ open={true}
67
+ onClose={handleClose}
68
+ title={<Actions />}
69
+ maxWidth="xl"
70
+ contentSx={{
71
+ paddingTop: "8px !important",
72
+ paddingBottom: "12px !important",
73
+ paddingLeft: "16px !important",
74
+ paddingRight: "16px !important",
75
+ }}
76
+ sx={{
77
+ "& .MuiDialog-paper": {
78
+ width: "min(1400px, 96vw)",
79
+ },
80
+ }}
81
+ >
82
+ {children}
83
+ <SimpleForm toolbar={<FormToolbar />}>
84
+ <Inputs />
85
+ </SimpleForm>
86
+ </AdminModal>
36
87
  </Edit>
37
88
  )
38
89
  }
@@ -66,14 +117,24 @@ setupAdmin(["edit-inputs"], MuffinEditInputs)
66
117
 
67
118
  export function MuffinEditToolbar({ children }: PropsWithChildren) {
68
119
  const resource = useResourceContext()
120
+ const record = useRecordContext()
121
+ const translate = useTranslate()
69
122
  const Actions = findBuilder(["edit-actions", resource])
70
123
  return (
71
- <TopToolbar>
72
- <Actions />
73
- {children}
74
- <ListButton />
75
- <ShowButton />
76
- </TopToolbar>
124
+ <Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>
125
+ <TopToolbar sx={{ pl: 0, pr: 0, width: "100%", justifyContent: "space-between" }}>
126
+ <Typography variant="h6" sx={{ mr: 2 }}>
127
+ {translate(`resources.${resource}.name`, { smart_count: 1, _: resource })}
128
+ {record?.id ? ` #${record.id}` : ""}
129
+ </Typography>
130
+ <Box sx={{ display: "flex", alignItems: "center" }}>
131
+ <Actions />
132
+ {children}
133
+ <ShowButton />
134
+ <ListButton />
135
+ </Box>
136
+ </TopToolbar>
137
+ </Box>
77
138
  )
78
139
  }
79
140
 
@@ -1,25 +1,25 @@
1
1
  import sortBy from "lodash/sortBy"
2
2
  import uniq from "lodash/uniq"
3
- import { PropsWithChildren } from "react"
3
+ import type { PropsWithChildren } from "react"
4
4
  import {
5
5
  BulkDeleteButton,
6
6
  BulkExportButton,
7
7
  CreateButton,
8
8
  DatagridConfigurable,
9
9
  EditButton,
10
- ExportButton,
11
10
  FilterButton,
12
11
  InfiniteList,
13
12
  List,
14
13
  Pagination,
15
14
  SelectColumnsButton,
16
15
  TopToolbar,
16
+ useTranslate,
17
17
  } from "react-admin"
18
18
  import { buildRA, buildRAComponent } from "./buildRA"
19
19
  import { BulkActionButton, ListActionButton } from "./buttons"
20
20
  import { HelpLink } from "./common/HelpLink"
21
21
  import { useMuffinResourceOpts } from "./hooks"
22
- import { AdminInput } from "./types"
22
+ import type { AdminInput } from "./types"
23
23
  import { buildAdmin, findBuilder, setupAdmin } from "./utils"
24
24
 
25
25
  export function MuffinList({ children }: PropsWithChildren) {
@@ -76,6 +76,7 @@ function MuffinListDatagrid() {
76
76
  const { name, list } = useMuffinResourceOpts()
77
77
  const { fields, edit, show } = list
78
78
  const BulkActions = findBuilder(["list-actions", name])
79
+
79
80
  return (
80
81
  <DatagridConfigurable
81
82
  rowClick={show ? "show" : edit ? "edit" : false}
@@ -91,9 +92,21 @@ setupAdmin(["list-grid"], MuffinListDatagrid)
91
92
 
92
93
  function MuffinListGridButtons() {
93
94
  const { list } = useMuffinResourceOpts()
95
+ const translate = useTranslate()
94
96
  const { edit } = list
95
97
  if (!edit) return null
96
- return <EditButton />
98
+ return (
99
+ <EditButton
100
+ label=""
101
+ title={translate("ra.action.edit", { _: "Edit" })}
102
+ sx={{
103
+ minWidth: "auto",
104
+ width: "100%",
105
+ justifyContent: "flex-end",
106
+ "& .MuiButton-startIcon": { margin: 0 },
107
+ }}
108
+ />
109
+ )
97
110
  }
98
111
 
99
112
  setupAdmin(["list-grid-buttons"], MuffinListGridButtons)
@@ -105,7 +118,6 @@ function MuffinListToolbar() {
105
118
  list: { create },
106
119
  } = useMuffinResourceOpts()
107
120
  const actions = baseActions.filter((a) => a.view?.includes("list"))
108
- const hasExport = actions.some((a) => a.id === "export")
109
121
  return (
110
122
  <TopToolbar>
111
123
  {help && <HelpLink href={help} />}
@@ -115,7 +127,6 @@ function MuffinListToolbar() {
115
127
  {actions.length
116
128
  ? actions.map((props) => <ListActionButton key={props.id} {...props} />)
117
129
  : null}
118
- {!hasExport && <ExportButton />}
119
130
  </TopToolbar>
120
131
  )
121
132
  }
@@ -1,19 +1,86 @@
1
- import { PropsWithChildren } from "react"
2
- import { EditButton, ListButton, Show, SimpleShowLayout, TopToolbar } from "react-admin"
1
+ import { Box, Typography } from "@mui/material"
2
+ import type { PropsWithChildren } from "react"
3
+ import {
4
+ EditButton,
5
+ ListButton,
6
+ Show,
7
+ SimpleShowLayout,
8
+ TopToolbar,
9
+ useRecordContext,
10
+ useTranslate,
11
+ } from "react-admin"
12
+ import { useLocation, useNavigate } from "react-router-dom"
3
13
  import { LinkAction } from "./actions"
4
14
  import { buildRA } from "./buildRA"
5
15
  import { ActionButton } from "./buttons"
16
+ import { AdminModal } from "./common"
6
17
  import { useMuffinResourceOpts } from "./hooks"
7
18
  import { buildAdmin, findBuilder, setupAdmin } from "./utils"
8
19
 
9
20
  export function MuffinShow({ children }: PropsWithChildren) {
10
21
  const { show, name, key } = useMuffinResourceOpts()
22
+ const location = useLocation()
23
+ const navigate = useNavigate()
11
24
  const ShowToolbar = findBuilder(["show-toolbar", name])
25
+ const returnTo = new URLSearchParams(location.search).get("returnTo")
26
+
27
+ const handleClose = () => {
28
+ if (returnTo) {
29
+ navigate(returnTo)
30
+ return
31
+ }
32
+
33
+ if (window.history.length > 1) {
34
+ navigate(-1)
35
+ return
36
+ }
37
+
38
+ navigate(`/${name}`)
39
+ }
12
40
 
13
41
  return (
14
- <Show actions={<ShowToolbar />} queryOptions={{ meta: { key } }}>
15
- <SimpleShowLayout>{buildAdmin(["show-fields", name], show)}</SimpleShowLayout>
16
- {children}
42
+ <Show
43
+ actions={false}
44
+ title={false}
45
+ component="div"
46
+ queryOptions={{ meta: { key } }}
47
+ sx={{
48
+ "& .RaShow-main": {
49
+ padding: 0,
50
+ },
51
+ }}
52
+ >
53
+ <AdminModal
54
+ open={true}
55
+ onClose={handleClose}
56
+ title={<ShowToolbar />}
57
+ maxWidth="xl"
58
+ hideBackdrop
59
+ disableScrollLock
60
+ contentSx={{
61
+ paddingTop: "8px !important",
62
+ paddingBottom: "12px !important",
63
+ paddingLeft: "16px !important",
64
+ paddingRight: "16px !important",
65
+ }}
66
+ sx={{
67
+ "& .MuiDialog-paper": {
68
+ width: "min(1400px, 96vw)",
69
+ },
70
+ }}
71
+ >
72
+ <SimpleShowLayout
73
+ sx={{
74
+ padding: 0,
75
+ "& .RaSimpleShowLayout-stack": {
76
+ rowGap: 1,
77
+ },
78
+ }}
79
+ >
80
+ {buildAdmin(["show-fields", name], show)}
81
+ </SimpleShowLayout>
82
+ {children}
83
+ </AdminModal>
17
84
  </Show>
18
85
  )
19
86
  }
@@ -21,21 +88,32 @@ export function MuffinShow({ children }: PropsWithChildren) {
21
88
  setupAdmin(["show"], MuffinShow)
22
89
  setupAdmin(["show-fields"], ({ fields }) => buildRA(fields))
23
90
 
24
- export function MuffinShowToolbar({ children }: PropsWithChildren) {
91
+ export function MuffinShowToolbar() {
25
92
  const { show, name } = useMuffinResourceOpts()
93
+ const record = useRecordContext()
94
+ const translate = useTranslate()
26
95
  const { edit } = show
27
96
 
28
97
  const Links = findBuilder(["show-links", name])
29
98
  const Actions = findBuilder(["show-actions", name])
30
99
 
31
100
  return (
32
- <TopToolbar>
33
- <Links />
34
- <Actions />
35
- {children}
36
- <ListButton />
37
- {edit && <EditButton />}
38
- </TopToolbar>
101
+ <Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>
102
+ <TopToolbar sx={{ pl: 0, pr: 0, width: "100%", justifyContent: "space-between" }}>
103
+ <Typography variant="h6" sx={{ mr: 2 }}>
104
+ {translate(`resources.${name}.name`, { smart_count: 1, _: name })}
105
+ {record?.id ? ` #${record.id}` : ""}
106
+ </Typography>
107
+ <Box sx={{ display: "flex", alignItems: "center" }}>
108
+ <Actions />
109
+ {edit && <EditButton />}
110
+ <ListButton />
111
+ </Box>
112
+ </TopToolbar>
113
+ <Box sx={{ mt: 0.5 }}>
114
+ <Links />
115
+ </Box>
116
+ </Box>
39
117
  )
40
118
  }
41
119
 
@@ -60,12 +138,12 @@ export function MuffinShowLinks({ children }: PropsWithChildren) {
60
138
  const { show } = useMuffinResourceOpts()
61
139
  const { links } = show
62
140
  return (
63
- <div style={{ marginRight: "auto" }}>
141
+ <Box sx={{ display: "flex", flexWrap: "wrap", gap: 1 }}>
64
142
  {links.map(([key, props]) => (
65
143
  <LinkAction key={key} resource={key} {...props} />
66
144
  ))}
67
145
  {children}
68
- </div>
146
+ </Box>
69
147
  )
70
148
  }
71
149
 
@@ -1,7 +1,7 @@
1
1
  import { useRecordContext, useResourceContext } from "react-admin"
2
2
  import LinkButton from "../buttons/LinkButton"
3
3
  import { useMuffinAdminOpts } from "../hooks"
4
- import { AdminShowLink } from "../types"
4
+ import type { AdminShowLink } from "../types"
5
5
 
6
6
  export function LinkAction({
7
7
  field,
@@ -1,107 +1,94 @@
1
- import Cookies from "js-cookie";
2
- import { findBuilder, makeRequest, requestHeaders, setupAdmin } from ".";
3
- import type { AdminOpts } from "./types";
1
+ import Cookies from "js-cookie"
2
+ import type { AdminOpts } from "./types"
3
+ import { findBuilder, makeRequest, requestHeaders, setupAdmin } from "./utils"
4
4
 
5
5
  setupAdmin(
6
- ["auth-storage-get"],
7
- ({ storage, storageName }: AdminOpts["auth"]) =>
8
- () =>
9
- storage == "localstorage"
10
- ? localStorage.getItem(storageName)
11
- : Cookies.get(storageName),
12
- );
13
-
14
- setupAdmin(
15
- ["auth-storage-set"],
16
- ({ storage }) =>
17
- (name, value, requestOnly) => {
18
- if (storage == "localstorage") {
19
- localStorage.setItem(name, value);
20
- requestHeaders["Authorization"] = value;
21
- } else Cookies.set(name, value);
22
- },
23
- );
6
+ ["auth-storage-get"],
7
+ ({ storage, storageName }: AdminOpts["auth"]) =>
8
+ () =>
9
+ storage == "localstorage" ? localStorage.getItem(storageName) : Cookies.get(storageName)
10
+ )
11
+
12
+ setupAdmin(["auth-storage-set"], ({ storage }) => (name, value, _requestOnly) => {
13
+ if (storage == "localstorage") {
14
+ localStorage.setItem(name, value)
15
+ requestHeaders.Authorization = value
16
+ } else Cookies.set(name, value)
17
+ })
24
18
 
25
19
  export function MuffinAuthProvider(props: AdminOpts["auth"]) {
26
- const {
27
- identityURL,
28
- authorizeURL,
29
- logoutURL,
30
- required,
31
- storageName,
32
- storage,
33
- } = props;
34
-
35
- const authGet = findBuilder(["auth-storage-get"])(props);
36
- const authSet = findBuilder(["auth-storage-set"])(props);
37
-
38
- // Initialize request headers
39
- if (storage == "localstorage") {
40
- const token = authGet(storageName);
41
- if (token) requestHeaders["Authorization"] = token;
42
- }
43
-
44
- const getIdentity = async () => {
45
- if (identityURL) {
46
- const { json } = await makeRequest(identityURL);
47
- return json;
48
- }
49
- };
50
-
51
- if (required)
52
- return {
53
- login: async (data) => {
54
- if (!authorizeURL) throw { message: "Authorization is not supported" };
55
-
56
- const { json } = await makeRequest(authorizeURL, {
57
- data,
58
- method: "POST",
59
- });
60
- authSet(storageName, json);
61
- },
62
-
63
- checkError: async (error) => {
64
- const { status } = error || {};
65
-
66
- if (status == 401 || status == 403) {
67
- // Clean storage
68
- authSet(storageName, "");
69
-
70
- throw {
71
- message: "Invalid authorization",
72
- redirectTo: logoutURL,
73
- logoutUser: !logoutURL,
74
- };
75
- }
76
- },
77
-
78
- checkAuth: async () => {
79
- const auth = authGet(storageName);
80
- if (!auth) throw { message: "Authorization required" };
81
-
82
- if (!identityURL) return auth;
83
-
84
- const user = await getIdentity();
85
- if (!user) throw { message: "Authorization required" };
86
-
87
- return user;
88
- },
89
-
90
- getAuthorization: () => authGet(storageName),
91
-
92
- logout: async () => {
93
- // Clean storage
94
- authSet(storageName, "");
95
- if (logoutURL) window.location.href = logoutURL;
96
- },
97
-
98
- getIdentity,
99
-
100
- getPermissions: async () => {
101
- const role = authGet(storageName + "_role");
102
- return role || "";
103
- },
104
- };
20
+ const { identityURL, authorizeURL, logoutURL, required, storageName, storage } = props
21
+
22
+ const authGet = findBuilder(["auth-storage-get"])(props)
23
+ const authSet = findBuilder(["auth-storage-set"])(props)
24
+
25
+ // Initialize request headers
26
+ if (storage == "localstorage") {
27
+ const token = authGet(storageName)
28
+ if (token) requestHeaders.Authorization = token
29
+ }
30
+
31
+ const getIdentity = async () => {
32
+ if (identityURL) {
33
+ const { json } = await makeRequest(identityURL)
34
+ return json
35
+ }
36
+ }
37
+
38
+ if (required)
39
+ return {
40
+ login: async (data) => {
41
+ if (!authorizeURL) throw { message: "Authorization is not supported" }
42
+
43
+ const { json } = await makeRequest(authorizeURL, {
44
+ data,
45
+ method: "POST",
46
+ })
47
+ authSet(storageName, json)
48
+ },
49
+
50
+ checkError: async (error) => {
51
+ const { status } = error || {}
52
+
53
+ if (status == 401 || status == 403) {
54
+ // Clean storage
55
+ authSet(storageName, "")
56
+
57
+ throw {
58
+ message: "Invalid authorization",
59
+ redirectTo: logoutURL,
60
+ logoutUser: !logoutURL,
61
+ }
62
+ }
63
+ },
64
+
65
+ checkAuth: async () => {
66
+ const auth = authGet(storageName)
67
+ if (!auth) throw { message: "Authorization required" }
68
+
69
+ if (!identityURL) return auth
70
+
71
+ const user = await getIdentity()
72
+ if (!user) throw { message: "Authorization required" }
73
+
74
+ return user
75
+ },
76
+
77
+ getAuthorization: () => authGet(storageName),
78
+
79
+ logout: async () => {
80
+ // Clean storage
81
+ authSet(storageName, "")
82
+ if (logoutURL) window.location.href = logoutURL
83
+ },
84
+
85
+ getIdentity,
86
+
87
+ getPermissions: async () => {
88
+ const role = authGet(`${storageName}_role`)
89
+ return role || ""
90
+ },
91
+ }
105
92
  }
106
93
 
107
- setupAdmin(["auth-provider"], MuffinAuthProvider);
94
+ setupAdmin(["auth-provider"], MuffinAuthProvider)
package/src/buildRA.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ import type { ElementType } from "react"
1
2
  import {
2
3
  ArrayField,
3
4
  ArrayInput,
@@ -25,8 +26,8 @@ import {
25
26
  ReferenceField,
26
27
  ReferenceInput,
27
28
  ReferenceManyField,
28
- required,
29
29
  RichTextField,
30
+ required,
30
31
  SearchInput,
31
32
  SelectArrayInput,
32
33
  SelectField,
@@ -40,7 +41,7 @@ import { AvatarField, CopyField, EditableBooleanField, FKField, JsonField } from
40
41
  import { DateRangeFilter, Filter, SearchFilter } from "./filters"
41
42
  import { FKInput, ImgInput, JsonInput, TimestampInput } from "./inputs"
42
43
 
43
- const UI: Record<string, JSX.ElementType> = {
44
+ const UI: Record<string, ElementType> = {
44
45
  // Fields
45
46
  BooleanField,
46
47
  ChipField,
@@ -112,6 +113,6 @@ export function buildRA(items: [string, Record<string, any>][]) {
112
113
  return items.map((item) => buildRAComponent(item[0], item[1]))
113
114
  }
114
115
 
115
- export function registerUI(name: string, component: JSX.ElementType) {
116
+ export function registerUI(name: string, component: ElementType) {
116
117
  UI[name] = component
117
118
  }
@@ -1,3 +1,5 @@
1
+ import { Link, Stack } from "@mui/material"
2
+ import { useState } from "react"
1
3
  import {
2
4
  Button,
3
5
  FormGroupsProvider,
@@ -8,15 +10,12 @@ import {
8
10
  useTranslate,
9
11
  } from "react-admin"
10
12
  import { FormProvider } from "react-hook-form"
11
-
12
- import { Link, Stack } from "@mui/material"
13
- import { useState } from "react"
14
13
  import { buildRA } from "../buildRA"
15
14
  import { AdminModal, PayloadButtons, useConfirmation } from "../common"
16
15
  import { HelpLink } from "../common/HelpLink"
17
16
  import { useMuffinAdminOpts } from "../hooks"
18
17
  import { useAction } from "../hooks/useAction"
19
- import { AdminAction, AdminPayloadProps } from "../types"
18
+ import type { AdminAction, AdminPayloadProps } from "../types"
20
19
  import { buildIcon, findBuilder, prepareFilters, requestHeaders } from "../utils"
21
20
 
22
21
  export type ActionPayloadProps = {
@@ -160,11 +159,11 @@ export function CommonPayload({
160
159
  title={
161
160
  help
162
161
  ? ((
163
- <Stack alignItems="flex-start">
164
- <span>{translate(title, { _: title })}</span>
165
- <HelpLink href={help} style={{ alignSelf: "flex-end" }} />
166
- </Stack>
167
- ) as any)
162
+ <Stack sx={{ alignItems: "flex-start" }}>
163
+ <span>{translate(title, { _: title })}</span>
164
+ <HelpLink href={help} style={{ alignSelf: "flex-end" }} />
165
+ </Stack>
166
+ ) as any)
168
167
  : translate(title, { _: title })
169
168
  }
170
169
  actions={
@@ -198,7 +197,7 @@ function FileButton({
198
197
  const { apiUrl } = useMuffinAdminOpts()
199
198
  let url = `${apiUrl}${path}?f`
200
199
  if (record) url = url.replace("{id}", record.id as string)
201
- const authorization = requestHeaders["Authorization"]
200
+ const authorization = requestHeaders.Authorization
202
201
  if (authorization) url += `&t=${authorization}`
203
202
  if (Object.keys(filterValues).length) url += `&where=${prepareFilters(filterValues)}`
204
203
 
@@ -1,6 +1,6 @@
1
1
  import { Button } from "react-admin"
2
- import { Link } from "react-router-dom"
3
- import { AdminShowLink } from "../types"
2
+ import { Link, useLocation } from "react-router-dom"
3
+ import type { AdminShowLink } from "../types"
4
4
  import { buildIcon } from "../utils"
5
5
 
6
6
  const LinkButton = ({
@@ -11,9 +11,17 @@ const LinkButton = ({
11
11
  id,
12
12
  title,
13
13
  }: AdminShowLink & { resource: string; filters?: any; id?: string }) => {
14
+ const location = useLocation()
15
+ const searchParams = new URLSearchParams()
16
+ searchParams.set("returnTo", `${location.pathname}${location.search}`)
17
+
18
+ if (filters) {
19
+ searchParams.set("filter", JSON.stringify(filters))
20
+ }
21
+
14
22
  const linkParams = {
15
23
  pathname: `/${resource}`,
16
- search: filters ? `filter=${JSON.stringify(filters)}` : undefined,
24
+ search: `?${searchParams.toString()}`,
17
25
  }
18
26
 
19
27
  if (id) linkParams.pathname += `/${id}/show`