muffin-admin 8.5.5 → 9.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/dist/buildRA.js +5 -2
- package/dist/buttons/ActionButton.js +3 -3
- package/dist/dataprovider.js +3 -7
- package/dist/filters/DateRangeFilter.d.ts +2 -0
- package/dist/filters/DateRangeFilter.js +17 -0
- package/dist/filters/Filter.d.ts +1 -0
- package/dist/{inputs/FilterInput.js → filters/Filter.js} +1 -1
- package/dist/filters/index.d.ts +2 -0
- package/dist/filters/index.js +2 -0
- package/dist/i18n/ru.js +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/inputs/DateRangeInput.d.ts +7 -0
- package/dist/inputs/DateRangeInput.js +13 -0
- package/dist/inputs/index.d.ts +0 -1
- package/dist/inputs/index.js +0 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +6 -0
- package/package.json +5 -1
- package/src/MuffinAdmin.tsx +6 -5
- package/src/buildRA.tsx +6 -2
- package/src/buttons/ActionButton.tsx +4 -4
- package/src/dataprovider.ts +2 -9
- package/src/filters/DateRangeFilter.tsx +17 -0
- package/src/{inputs/FilterInput.tsx → filters/Filter.tsx} +1 -1
- package/src/filters/index.ts +2 -0
- package/src/i18n/ru.ts +2 -0
- package/src/index.tsx +1 -1
- package/src/inputs/DateRangeInput.tsx +29 -0
- package/src/inputs/index.ts +0 -1
- package/src/utils.tsx +9 -0
- package/dist/inputs/FilterInput.d.ts +0 -1
package/dist/utils.d.ts
CHANGED
|
@@ -25,3 +25,4 @@ export declare function makeRequest(url: string, params?: APIParams): Promise<{
|
|
|
25
25
|
export declare function findIcon(icon?: string): any;
|
|
26
26
|
export declare function buildIcon(icon?: string): import("react/jsx-runtime").JSX.Element;
|
|
27
27
|
export declare function deepMerge(target: any, ...sources: any[]): any;
|
|
28
|
+
export declare function prepareFilters(filter: any): string;
|
package/dist/utils.js
CHANGED
|
@@ -76,3 +76,9 @@ export function deepMerge(target, ...sources) {
|
|
|
76
76
|
}
|
|
77
77
|
return deepMerge(target, ...sources);
|
|
78
78
|
}
|
|
79
|
+
export function prepareFilters(filter) {
|
|
80
|
+
return JSON.stringify(Object.entries(filter).reduce((acc, [key, value]) => {
|
|
81
|
+
acc[key] = Array.isArray(value) ? { $in: value } : value;
|
|
82
|
+
return acc;
|
|
83
|
+
}, {}));
|
|
84
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "muffin-admin",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0",
|
|
4
4
|
"description": "NPM package for https://github.com/klen/muffin-admin",
|
|
5
5
|
"files": [
|
|
6
6
|
"src",
|
|
@@ -23,10 +23,12 @@
|
|
|
23
23
|
},
|
|
24
24
|
"homepage": "https://github.com/klen/muffin-admin#readme",
|
|
25
25
|
"dependencies": {
|
|
26
|
+
"date-fns": "^4.1.0",
|
|
26
27
|
"js-cookie": "^3.0.5",
|
|
27
28
|
"ra-language-russian": "^4.14.2",
|
|
28
29
|
"react": "^18.3.1",
|
|
29
30
|
"react-admin": "^5.4.0",
|
|
31
|
+
"react-datepicker": "^8.1.0",
|
|
30
32
|
"react-dom": "^18.3.1",
|
|
31
33
|
"validator": "^13.12.0"
|
|
32
34
|
},
|
|
@@ -38,6 +40,7 @@
|
|
|
38
40
|
"@types/react-window": "^1.8.8",
|
|
39
41
|
"@typescript-eslint/eslint-plugin": "^7.12.0",
|
|
40
42
|
"@typescript-eslint/parser": "^7.12.0",
|
|
43
|
+
"css-loader": "^7.1.2",
|
|
41
44
|
"dotenv": "^16.4.5",
|
|
42
45
|
"eslint": "^8",
|
|
43
46
|
"eslint-config-prettier": "^9.1.0",
|
|
@@ -47,6 +50,7 @@
|
|
|
47
50
|
"husky": "^9.0.11",
|
|
48
51
|
"prettier": "^3.2",
|
|
49
52
|
"prettier-plugin-organize-imports": "^3.2",
|
|
53
|
+
"style-loader": "^4.0.0",
|
|
50
54
|
"ts-loader": "^9.5.1",
|
|
51
55
|
"typescript": "^5.4.5",
|
|
52
56
|
"webpack": "^5.91.0",
|
package/src/MuffinAdmin.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import IconButton from "@mui/material/IconButton"
|
|
2
2
|
import SvgIcon from "@mui/material/SvgIcon"
|
|
3
3
|
import Tooltip from "@mui/material/Tooltip"
|
|
4
|
+
|
|
4
5
|
import Typography from "@mui/material/Typography"
|
|
5
6
|
import {
|
|
6
7
|
AdminContext,
|
|
@@ -27,11 +28,11 @@ export function MuffinAdmin(props: AdminProps) {
|
|
|
27
28
|
const muffinI18nProvider = buildProvider(
|
|
28
29
|
backendLocales
|
|
29
30
|
? Object.fromEntries(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
Object.entries(muffinTranslations).map(([locale, messages]) => [
|
|
32
|
+
locale,
|
|
33
|
+
deepMerge({}, messages, backendLocales[locale], buildAdmin(["locale", locale]) || {}),
|
|
34
|
+
])
|
|
35
|
+
)
|
|
35
36
|
: muffinTranslations
|
|
36
37
|
)
|
|
37
38
|
|
package/src/buildRA.tsx
CHANGED
|
@@ -36,7 +36,8 @@ import {
|
|
|
36
36
|
} from "react-admin"
|
|
37
37
|
|
|
38
38
|
import { AvatarField, CopyField, EditableBooleanField, FKField, JsonField } from "./fields"
|
|
39
|
-
import {
|
|
39
|
+
import { DateRangeFilter, Filter } from "./filters"
|
|
40
|
+
import { FKInput, JsonInput, TimestampInput } from "./inputs"
|
|
40
41
|
|
|
41
42
|
const UI: Record<string, JSX.ElementType> = {
|
|
42
43
|
// Fields
|
|
@@ -68,7 +69,6 @@ const UI: Record<string, JSX.ElementType> = {
|
|
|
68
69
|
BooleanInput,
|
|
69
70
|
CheckboxGroupInput,
|
|
70
71
|
DateInput,
|
|
71
|
-
FilterInput,
|
|
72
72
|
DateTimeInput,
|
|
73
73
|
FKInput,
|
|
74
74
|
FileInput,
|
|
@@ -84,6 +84,10 @@ const UI: Record<string, JSX.ElementType> = {
|
|
|
84
84
|
SelectInput,
|
|
85
85
|
TextInput,
|
|
86
86
|
TimestampInput,
|
|
87
|
+
|
|
88
|
+
// Filters
|
|
89
|
+
Filter,
|
|
90
|
+
DateRangeFilter,
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
export function buildRAComponent(name: string, props: any) {
|
|
@@ -17,7 +17,7 @@ import { HelpLink } from "../common/HelpLink"
|
|
|
17
17
|
import { useMuffinAdminOpts } from "../hooks"
|
|
18
18
|
import { useAction } from "../hooks/useAction"
|
|
19
19
|
import { AdminAction, AdminPayloadProps } from "../types"
|
|
20
|
-
import { buildIcon, findBuilder, requestHeaders } from "../utils"
|
|
20
|
+
import { buildIcon, findBuilder, prepareFilters, requestHeaders } from "../utils"
|
|
21
21
|
|
|
22
22
|
export type ActionPayloadProps = {
|
|
23
23
|
active: boolean
|
|
@@ -38,9 +38,9 @@ export function ActionButton({ paths, confirm, file, ...props }: AdminAction) {
|
|
|
38
38
|
const confirmMessage =
|
|
39
39
|
typeof confirm === "string" ? translate(confirm) : "Do you confirm this action?"
|
|
40
40
|
|
|
41
|
-
const onHandle = async (payload
|
|
41
|
+
const onHandle = async (payload?: any) => {
|
|
42
42
|
const process = confirm ? await confirmation.confirm({ message: confirmMessage }) : true
|
|
43
|
-
if (process)
|
|
43
|
+
if (process) mutate({ record, payload })
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
return <ActionButtonBase {...props} isPending={isPending} onHandle={onHandle} />
|
|
@@ -200,7 +200,7 @@ function FileButton({
|
|
|
200
200
|
if (record) url = url.replace("{id}", record.id as string)
|
|
201
201
|
const authorization = requestHeaders["Authorization"]
|
|
202
202
|
if (authorization) url += `&t=${authorization}`
|
|
203
|
-
if (Object.keys(filterValues).length) url += `&where=${
|
|
203
|
+
if (Object.keys(filterValues).length) url += `&where=${prepareFilters(filterValues)}`
|
|
204
204
|
|
|
205
205
|
return (
|
|
206
206
|
<Button href={url} label={label} component={Link}>
|
package/src/dataprovider.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TID } from "./types"
|
|
2
|
-
import { APIParams, makeRequest, setupAdmin } from "./utils"
|
|
2
|
+
import { APIParams, makeRequest, prepareFilters, setupAdmin } from "./utils"
|
|
3
3
|
|
|
4
4
|
export function MuffinDataprovider(apiUrl: string) {
|
|
5
5
|
async function request(url: string, options?: APIParams) {
|
|
@@ -13,14 +13,7 @@ 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)
|
|
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
|
-
}
|
|
16
|
+
if (filter) query.where = prepareFilters(filter)
|
|
24
17
|
if (pagination) {
|
|
25
18
|
const { page, perPage: limit } = pagination
|
|
26
19
|
query.limit = limit
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { InputProps, useInput } from "react-admin"
|
|
2
|
+
import { DateRangeInput } from "../inputs/DateRangeInput"
|
|
3
|
+
|
|
4
|
+
export function DateRangeFilter(props: InputProps) {
|
|
5
|
+
const { field } = useInput(props)
|
|
6
|
+
|
|
7
|
+
const onChange = (dates: [Date, Date]) => {
|
|
8
|
+
field.onChange({
|
|
9
|
+
$between: dates.map((d) => d?.toISOString() || null),
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
let filterValue = field.value.$between ?? [null, null]
|
|
13
|
+
if (!Array.isArray(filterValue)) filterValue = [null, null]
|
|
14
|
+
const value = filterValue.map((d: string) => (d ? new Date(d) : d))
|
|
15
|
+
|
|
16
|
+
return <DateRangeInput value={value} onChange={onChange} />
|
|
17
|
+
}
|
|
@@ -15,7 +15,7 @@ const OPERATORS = {
|
|
|
15
15
|
$le: "≤",
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export function
|
|
18
|
+
export function Filter({ type = "text", ...props }: any) {
|
|
19
19
|
const { field } = useInput({
|
|
20
20
|
format: (value: any) => (value ? value[Object.keys(value)[0]] : ""),
|
|
21
21
|
...props,
|
package/src/i18n/ru.ts
CHANGED
package/src/index.tsx
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import TextField from "@mui/material/TextField"
|
|
2
|
+
import { enGB, ru } from "date-fns/locale"
|
|
3
|
+
import { useLocale } from "react-admin"
|
|
4
|
+
import DatePicker, { registerLocale } from "react-datepicker"
|
|
5
|
+
import "react-datepicker/dist/react-datepicker.css"
|
|
6
|
+
|
|
7
|
+
registerLocale("ru", ru)
|
|
8
|
+
registerLocale("en", enGB)
|
|
9
|
+
|
|
10
|
+
type TProps = {
|
|
11
|
+
value: [Date, Date]
|
|
12
|
+
onChange: (value: [Date, Date]) => void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function DateRangeInput({ value, onChange }: TProps) {
|
|
16
|
+
const [startDate, endDate] = value
|
|
17
|
+
const locale = useLocale()
|
|
18
|
+
return (
|
|
19
|
+
<DatePicker
|
|
20
|
+
withPortal
|
|
21
|
+
locale={locale}
|
|
22
|
+
selectsRange
|
|
23
|
+
endDate={endDate}
|
|
24
|
+
onChange={onChange}
|
|
25
|
+
startDate={startDate}
|
|
26
|
+
customInput={<TextField variant="outlined" />}
|
|
27
|
+
/>
|
|
28
|
+
)
|
|
29
|
+
}
|
package/src/inputs/index.ts
CHANGED
package/src/utils.tsx
CHANGED
|
@@ -86,3 +86,12 @@ export function deepMerge(target: any, ...sources: any[]): any {
|
|
|
86
86
|
}
|
|
87
87
|
return deepMerge(target, ...sources)
|
|
88
88
|
}
|
|
89
|
+
|
|
90
|
+
export function prepareFilters(filter: any) {
|
|
91
|
+
return JSON.stringify(
|
|
92
|
+
Object.entries(filter).reduce((acc, [key, value]) => {
|
|
93
|
+
acc[key] = Array.isArray(value) ? { $in: value } : value
|
|
94
|
+
return acc
|
|
95
|
+
}, {})
|
|
96
|
+
)
|
|
97
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function FilterInput({ type, ...props }: any): import("react/jsx-runtime").JSX.Element;
|