muffin-admin 11.7.2 → 12.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muffin-admin",
3
- "version": "11.7.2",
3
+ "version": "12.0.0",
4
4
  "description": "NPM package for https://github.com/klen/muffin-admin",
5
5
  "files": [
6
6
  "src",
@@ -1,3 +1,4 @@
1
+ import { Box, Typography } from "@mui/material"
1
2
  import { PropsWithChildren } from "react"
2
3
  import {
3
4
  DeleteButton,
@@ -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
 
@@ -14,6 +14,7 @@ import {
14
14
  Pagination,
15
15
  SelectColumnsButton,
16
16
  TopToolbar,
17
+ useTranslate,
17
18
  } from "react-admin"
18
19
  import { buildRA, buildRAComponent } from "./buildRA"
19
20
  import { BulkActionButton, ListActionButton } from "./buttons"
@@ -76,6 +77,7 @@ function MuffinListDatagrid() {
76
77
  const { name, list } = useMuffinResourceOpts()
77
78
  const { fields, edit, show } = list
78
79
  const BulkActions = findBuilder(["list-actions", name])
80
+
79
81
  return (
80
82
  <DatagridConfigurable
81
83
  rowClick={show ? "show" : edit ? "edit" : false}
@@ -91,9 +93,21 @@ setupAdmin(["list-grid"], MuffinListDatagrid)
91
93
 
92
94
  function MuffinListGridButtons() {
93
95
  const { list } = useMuffinResourceOpts()
96
+ const translate = useTranslate()
94
97
  const { edit } = list
95
98
  if (!edit) return null
96
- return <EditButton />
99
+ return (
100
+ <EditButton
101
+ label=""
102
+ title={translate("ra.action.edit", { _: "Edit" })}
103
+ sx={{
104
+ minWidth: "auto",
105
+ width: "100%",
106
+ justifyContent: "flex-end",
107
+ "& .MuiButton-startIcon": { margin: 0 },
108
+ }}
109
+ />
110
+ )
97
111
  }
98
112
 
99
113
  setupAdmin(["list-grid-buttons"], MuffinListGridButtons)
@@ -1,19 +1,86 @@
1
+ import { Box, Typography } from "@mui/material"
1
2
  import { PropsWithChildren } from "react"
2
- import { EditButton, ListButton, Show, SimpleShowLayout, TopToolbar } from "react-admin"
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,5 +1,5 @@
1
1
  import { Button } from "react-admin"
2
- import { Link } from "react-router-dom"
2
+ import { Link, useLocation } from "react-router-dom"
3
3
  import { AdminShowLink } from "../types"
4
4
  import { buildIcon } from "../utils"
5
5
 
@@ -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`
@@ -1,11 +1,13 @@
1
1
  import { Dialog, DialogActions, DialogContent, DialogProps, DialogTitle } from "@mui/material"
2
2
  import { PropsWithChildren } from "react"
3
+ import { SxProps, Theme } from "@mui/material/styles"
3
4
 
4
- interface IProps {
5
+ interface IProps extends Omit<DialogProps, "title" | "open" | "onClose"> {
5
6
  open: boolean
6
7
  onClose: () => void
7
8
  title?: React.ReactNode
8
9
  actions?: React.ReactNode
10
+ contentSx?: SxProps<Theme>
9
11
  }
10
12
 
11
13
  export function AdminModal({
@@ -14,12 +16,13 @@ export function AdminModal({
14
16
  children,
15
17
  title,
16
18
  actions,
19
+ contentSx,
17
20
  ...props
18
- }: PropsWithChildren<IProps & DialogProps>) {
21
+ }: PropsWithChildren<IProps>) {
19
22
  return (
20
23
  <Dialog open={open} onClose={onClose} fullWidth maxWidth="md" {...props}>
21
24
  {title && <DialogTitle>{title}</DialogTitle>}
22
- <DialogContent>{children}</DialogContent>
25
+ <DialogContent sx={contentSx}>{children}</DialogContent>
23
26
  {actions && <DialogActions>{actions}</DialogActions>}
24
27
  </Dialog>
25
28
  )
@@ -1,11 +1,23 @@
1
1
  import { ReferenceField, TextField, useFieldValue, UseFieldValueOptions } from "react-admin"
2
+ import { useLocation } from "react-router-dom"
2
3
 
3
4
  export function FKField({ reference, refSource, refKey, link, source, ...props }) {
5
+ const location = useLocation()
4
6
  refKey = refKey || "id"
7
+ const returnTo = `${location.pathname}${location.search}`
8
+
9
+ const resolveLink =
10
+ link ||
11
+ ((record) => {
12
+ const id = record?.[refKey]
13
+ if (id === undefined || id === null) return false
14
+ return `/${reference}/${id}/show?returnTo=${encodeURIComponent(returnTo)}`
15
+ })
16
+
5
17
  return (
6
18
  <ReferenceField
7
19
  source={source}
8
- link={link || "show"}
20
+ link={resolveLink}
9
21
  reference={reference}
10
22
  queryOptions={{ meta: { key: refKey } }}
11
23
  {...props}
package/src/index.tsx CHANGED
@@ -37,4 +37,4 @@ export async function initAdmin(prefix = "", containerId: string = "root") {
37
37
  )
38
38
  }
39
39
 
40
- export const VERSION = "11.7.2"
40
+ export const VERSION = "12.0.0"