muffin-admin 6.2.0 → 7.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": "6.2.0",
3
+ "version": "7.0.0",
4
4
  "description": "NPM package for https://github.com/klen/muffin-admin",
5
5
  "files": [
6
6
  "src",
@@ -23,10 +23,11 @@
23
23
  },
24
24
  "homepage": "https://github.com/klen/muffin-admin#readme",
25
25
  "dependencies": {
26
+ "@mui/x-date-pickers": "^7.22.3",
26
27
  "js-cookie": "^3.0.5",
27
28
  "ra-language-russian": "^4.14.2",
28
29
  "react": "^18.3.1",
29
- "react-admin": "^5.0.3",
30
+ "react-admin": "^5.4.0",
30
31
  "react-dom": "^18.3.1",
31
32
  "validator": "^13.12.0"
32
33
  },
@@ -15,25 +15,27 @@ import {
15
15
  SelectColumnsButton,
16
16
  TopToolbar,
17
17
  } from "react-admin"
18
- import { buildRA } from "./buildRA"
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
23
  import { buildAdmin, findBuilder, setupAdmin } from "./utils"
23
24
 
24
25
  export function MuffinList({ children }: PropsWithChildren) {
25
26
  const { name, list } = useMuffinResourceOpts()
26
- const { limit, limitMax, limitTotal, filters, sort } = list
27
+ const { limit, limitMax, limitTotal, sort, filters } = list
27
28
 
28
29
  const DataGrid = findBuilder(["list-grid", name])
29
30
  const Toolbar = findBuilder(["list-toolbar", name])
31
+ const raFilters = buildAdmin(["list-filters", name], filters)
30
32
 
31
33
  return limitTotal ? (
32
34
  <List
33
35
  sort={sort}
34
36
  perPage={limit}
37
+ filters={raFilters}
35
38
  actions={<Toolbar />}
36
- filters={buildAdmin(["list-filters", name], filters)}
37
39
  pagination={
38
40
  <Pagination rowsPerPageOptions={sortBy(uniq([10, 25, 50, 100, limit, limitMax]))} />
39
41
  }
@@ -42,12 +44,7 @@ export function MuffinList({ children }: PropsWithChildren) {
42
44
  <DataGrid />
43
45
  </List>
44
46
  ) : (
45
- <InfiniteList
46
- sort={sort}
47
- perPage={limit}
48
- actions={<Toolbar />}
49
- filters={buildAdmin(["list-filters", name], filters)}
50
- >
47
+ <InfiniteList sort={sort} perPage={limit} actions={<Toolbar />} filters={raFilters}>
51
48
  {children}
52
49
  <DataGrid />
53
50
  </InfiniteList>
@@ -56,7 +53,17 @@ export function MuffinList({ children }: PropsWithChildren) {
56
53
 
57
54
  setupAdmin(["list"], MuffinList)
58
55
  setupAdmin(["list-fields"], buildRA)
59
- setupAdmin(["list-filters"], buildRA)
56
+
57
+ function muffinListFilters(filters: AdminInput[]) {
58
+ return filters.map((props) => {
59
+ const [rtype, opts] = props
60
+ return buildRAComponent(rtype, {
61
+ ...opts,
62
+ variant: "outlined",
63
+ })
64
+ })
65
+ }
66
+ setupAdmin(["list-filters"], muffinListFilters)
60
67
 
61
68
  function MuffinListDatagrid() {
62
69
  const { name, list } = useMuffinResourceOpts()
@@ -125,7 +132,3 @@ function MuffinListActions() {
125
132
  }
126
133
 
127
134
  setupAdmin(["list-actions"], MuffinListActions)
128
-
129
- function MuffinPagination() {
130
- return null
131
- }
package/src/buildRA.tsx CHANGED
@@ -25,17 +25,18 @@ import {
25
25
  ReferenceField,
26
26
  ReferenceInput,
27
27
  ReferenceManyField,
28
+ required,
28
29
  RichTextField,
30
+ SelectArrayInput,
29
31
  SelectField,
30
32
  SelectInput,
31
33
  TextField,
32
34
  TextInput,
33
35
  UrlField,
34
- required,
35
36
  } from "react-admin"
36
37
 
37
38
  import { AvatarField, EditableBooleanField, FKField, JsonField } from "./fields"
38
- import { FKInput, JsonInput } from "./inputs"
39
+ import { FilterInput, FKInput, JsonInput } from "./inputs"
39
40
 
40
41
  const UI: Record<string, JSX.ElementType> = {
41
42
  // Fields
@@ -60,25 +61,27 @@ const UI: Record<string, JSX.ElementType> = {
60
61
  JsonField,
61
62
 
62
63
  // Inputs
64
+ ArrayInput,
65
+ AutocompleteArrayInput,
66
+ AutocompleteInput,
63
67
  BooleanInput,
64
- NullableBooleanInput,
68
+ CheckboxGroupInput,
65
69
  DateInput,
70
+ FilterInput,
66
71
  DateTimeInput,
67
- ImageInput,
72
+ FKInput,
68
73
  FileInput,
74
+ ImageInput,
75
+ JsonInput,
76
+ NullableBooleanInput,
69
77
  NumberInput,
70
78
  PasswordInput,
71
- TextInput,
72
- AutocompleteInput,
73
79
  RadioButtonGroupInput,
74
- SelectInput,
75
- ArrayInput,
76
- AutocompleteArrayInput,
77
- CheckboxGroupInput,
78
80
  ReferenceArrayInput,
79
81
  ReferenceInput,
80
- JsonInput,
81
- FKInput,
82
+ SelectInput,
83
+ TextInput,
84
+ SelectArrayInput,
82
85
  }
83
86
 
84
87
  export function buildRAComponent(name: string, props: any) {
@@ -13,7 +13,14 @@ export function MuffinDataprovider(apiUrl: string) {
13
13
  getList: async (resource: string, params: any) => {
14
14
  const { filter, pagination, sort } = params
15
15
  const query: APIParams["query"] = {}
16
- if (filter) query.where = JSON.stringify(filter)
16
+ if (filter) {
17
+ query.where = JSON.stringify(
18
+ Object.entries(filter).reduce((acc, [key, value]) => {
19
+ acc[key] = Array.isArray(value) ? { $in: value } : value
20
+ return acc
21
+ }, {})
22
+ )
23
+ }
17
24
  if (pagination) {
18
25
  const { page, perPage: limit } = pagination
19
26
  query.limit = limit
@@ -85,7 +92,7 @@ export function MuffinDataprovider(apiUrl: string) {
85
92
  return await methods.getList(resource, { filter, ...opts })
86
93
  },
87
94
 
88
- runAction: async (resource: string, action: string, props: TActionProps) => {
95
+ runAction: async (_: string, action: string, props: TActionProps) => {
89
96
  const { payload, ids, record } = props
90
97
  action = action.replace(/^\/+/, "")
91
98
  if (record) {
package/src/i18n/ru.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { TranslationMessages } from "ra-core"
2
2
  import raRussianMessages from "ra-language-russian"
3
3
 
4
- const muffinRussianMessages: TranslationMessages = {
4
+ const muffinRussianMessages = {
5
5
  ...raRussianMessages,
6
6
  muffin: {
7
7
  instructions: "Инструкции",
8
8
  how_to_use_admin: "Как использовать админку?",
9
9
  },
10
- }
10
+ } as unknown as TranslationMessages
11
11
 
12
12
  export default muffinRussianMessages
@@ -0,0 +1,67 @@
1
+ import Button from "@mui/material/Button"
2
+ import FormGroup from "@mui/material/FormGroup"
3
+ import Menu from "@mui/material/Menu"
4
+ import MenuItem from "@mui/material/MenuItem"
5
+ import TextField from "@mui/material/TextField"
6
+ import { useState } from "react"
7
+ import { useInput } from "react-admin"
8
+
9
+ const OPERATORS = {
10
+ $eq: "=",
11
+ $ne: "≠",
12
+ $gt: ">",
13
+ $ge: "≥",
14
+ $lt: "<",
15
+ $le: "≤",
16
+ }
17
+
18
+ export function FilterInput({ type = "text", ...props }: any) {
19
+ const { field } = useInput({
20
+ format: (value: any) => (value ? value[Object.keys(value)[0]] : ""),
21
+ ...props,
22
+ })
23
+ const [op, setOp] = useState((field.value && Object.keys(field.value)[0]) || "$eq")
24
+
25
+ const onChange = function(e: any) {
26
+ field.onChange({ [op]: e.target.value })
27
+ }
28
+
29
+ const [menuEl, setMenuEl] = useState(null)
30
+ const open = Boolean(menuEl)
31
+ return (
32
+ <>
33
+ <FormGroup row sx={{ flexWrap: "nowrap" }}>
34
+ <Button
35
+ size="small"
36
+ disableElevation
37
+ sx={{ minWidth: 30 }}
38
+ onClick={(e) => setMenuEl(e.currentTarget)}
39
+ >
40
+ <span style={{ fontSize: "1.5em" }}>{OPERATORS[op]}</span>
41
+ </Button>
42
+ <TextField
43
+ {...field}
44
+ onChange={onChange}
45
+ value={field.value}
46
+ variant="outlined"
47
+ type={type}
48
+ />
49
+ </FormGroup>
50
+ <Menu open={open} onClose={() => setMenuEl(null)} anchorEl={menuEl}>
51
+ {Object.entries(OPERATORS).map(([key, value]) => (
52
+ <MenuItem
53
+ key={key}
54
+ selected={op === value}
55
+ onClick={() => {
56
+ setOp(key)
57
+ setMenuEl(null)
58
+ field.onChange({ [key]: field.value })
59
+ }}
60
+ >
61
+ {value}
62
+ </MenuItem>
63
+ ))}
64
+ </Menu>
65
+ </>
66
+ )
67
+ }
@@ -1,2 +1,3 @@
1
+ export * from "./FilterInput"
1
2
  export * from "./FKInput"
2
3
  export * from "./JsonInput"
package/src/types.ts CHANGED
@@ -55,7 +55,7 @@ export type AdminAction = {
55
55
  }
56
56
 
57
57
  export type AdminField = [string, { source: string }]
58
- export type AdminInput = [string, { required: boolean; source: string;[key: string]: any }]
58
+ export type AdminInput = [string, { required: boolean; source: string; [key: string]: any }]
59
59
 
60
60
  export type AdminShowLink = {
61
61
  label: string
@@ -86,11 +86,11 @@ export type AdminResourceProps = {
86
86
  actions: AdminAction[]
87
87
  create: AdminInput[] | false
88
88
  edit:
89
- | {
90
- inputs: AdminInput[]
91
- remove?: boolean
92
- }
93
- | false
89
+ | {
90
+ inputs: AdminInput[]
91
+ remove?: boolean
92
+ }
93
+ | false
94
94
  list: {
95
95
  limit: number
96
96
  limitMax: number