muffin-admin 1.44.4 → 1.45.1
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/MuffinAdmin.d.ts +2 -0
- package/dist/MuffinAdmin.js +25 -0
- package/dist/MuffinDashboard.d.ts +2 -0
- package/dist/MuffinDashboard.js +16 -0
- package/dist/MuffinResource.d.ts +2 -0
- package/dist/MuffinResource.js +19 -0
- package/dist/MuffinResourceCreate.d.ts +4 -0
- package/dist/MuffinResourceCreate.js +11 -0
- package/dist/MuffinResourceEdit.d.ts +2 -0
- package/dist/MuffinResourceEdit.js +26 -0
- package/dist/MuffinResourceList.d.ts +2 -0
- package/dist/MuffinResourceList.js +16 -0
- package/dist/MuffinResourceShow.d.ts +2 -0
- package/dist/MuffinResourceShow.js +13 -0
- package/dist/actions/LinkAction.d.ts +4 -0
- package/dist/actions/LinkAction.js +10 -0
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/index.js +1 -0
- package/dist/authprovider.d.ts +9 -0
- package/dist/authprovider.js +80 -0
- package/dist/buildRA.d.ts +2 -0
- package/dist/buildRA.js +63 -0
- package/dist/buttons/ActionButton.d.ts +7 -0
- package/dist/buttons/ActionButton.js +51 -0
- package/dist/buttons/LinkButton.d.ts +6 -0
- package/dist/buttons/LinkButton.js +12 -0
- package/dist/buttons/index.d.ts +2 -0
- package/dist/buttons/index.js +2 -0
- package/dist/dataprovider.d.ts +59 -0
- package/dist/dataprovider.js +106 -0
- package/dist/fields/AvatarField.d.ts +13 -0
- package/dist/fields/AvatarField.js +33 -0
- package/dist/fields/EditableBooleanField.d.ts +3 -0
- package/dist/fields/EditableBooleanField.js +5 -0
- package/dist/fields/FKField.d.ts +14 -0
- package/dist/fields/FKField.js +21 -0
- package/dist/fields/JsonField.d.ts +4 -0
- package/dist/fields/JsonField.js +11 -0
- package/dist/fields/index.d.ts +4 -0
- package/dist/fields/index.js +4 -0
- package/dist/hooks/useAction.d.ts +5 -0
- package/dist/hooks/useAction.js +6 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +35 -0
- package/dist/inputs/FKInput.d.ts +8 -0
- package/dist/inputs/FKInput.js +27 -0
- package/dist/inputs/JsonInput.d.ts +19 -0
- package/dist/inputs/JsonInput.js +69 -0
- package/dist/inputs/index.d.ts +2 -0
- package/dist/inputs/index.js +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +28 -0
- package/dist/utils.js +57 -0
- package/dist/web.d.ts +1 -0
- package/dist/web.js +3 -0
- package/package.json +31 -14
- package/src/MuffinAdmin.tsx +73 -0
- package/src/MuffinDashboard.tsx +52 -0
- package/src/MuffinResource.tsx +27 -0
- package/src/MuffinResourceCreate.tsx +24 -0
- package/src/MuffinResourceEdit.tsx +42 -0
- package/src/MuffinResourceList.tsx +46 -0
- package/src/MuffinResourceShow.tsx +39 -0
- package/src/actions/LinkAction.tsx +10 -0
- package/src/actions/index.ts +1 -0
- package/src/{authprovider.js → authprovider.ts} +27 -22
- package/src/{ui.jsx → buildRA.tsx} +30 -35
- package/src/buttons/{ActionButton.jsx → ActionButton.tsx} +18 -30
- package/src/buttons/{LinkButton.jsx → LinkButton.tsx} +11 -6
- package/src/buttons/index.ts +2 -0
- package/src/{dataprovider.js → dataprovider.ts} +8 -6
- package/src/fields/{AvatarField.jsx → AvatarField.tsx} +3 -7
- package/src/fields/EditableBooleanField.tsx +5 -0
- package/src/fields/{FKField.jsx → FKField.tsx} +2 -10
- package/src/fields/{JsonField.jsx → JsonField.tsx} +2 -3
- package/src/fields/index.ts +4 -0
- package/src/hooks/{useAction.js → useAction.ts} +2 -2
- package/src/index.tsx +25 -0
- package/src/inputs/FKInput.tsx +27 -0
- package/src/inputs/{JsonInput.jsx → JsonInput.tsx} +3 -4
- package/src/inputs/index.ts +2 -0
- package/src/types.ts +73 -0
- package/src/utils.tsx +69 -0
- package/src/web.ts +4 -0
- package/dist/cjs/admin.js +0 -80
- package/dist/cjs/authprovider.js +0 -214
- package/dist/cjs/buttons/ActionButton.js +0 -96
- package/dist/cjs/buttons/LinkButton.js +0 -34
- package/dist/cjs/dashboard.js +0 -63
- package/dist/cjs/dataprovider.js +0 -304
- package/dist/cjs/fields/AvatarField.js +0 -37
- package/dist/cjs/fields/EditableBooleanField.js +0 -25
- package/dist/cjs/fields/FKField.js +0 -35
- package/dist/cjs/fields/JsonField.js +0 -38
- package/dist/cjs/hooks/useAction.js +0 -14
- package/dist/cjs/index.js +0 -76
- package/dist/cjs/inputs/FKInput.js +0 -41
- package/dist/cjs/inputs/JsonInput.js +0 -70
- package/dist/cjs/resources.js +0 -52
- package/dist/cjs/ui.js +0 -76
- package/dist/cjs/utils.js +0 -49
- package/dist/cjs/views/create.js +0 -18
- package/dist/cjs/views/edit.js +0 -31
- package/dist/cjs/views/list.js +0 -67
- package/dist/cjs/views/show.js +0 -37
- package/dist/cjs/web.js +0 -4
- package/dist/esm/admin.js +0 -74
- package/dist/esm/authprovider.js +0 -206
- package/dist/esm/buttons/ActionButton.js +0 -83
- package/dist/esm/buttons/LinkButton.js +0 -23
- package/dist/esm/dashboard.js +0 -60
- package/dist/esm/dataprovider.js +0 -296
- package/dist/esm/fields/AvatarField.js +0 -29
- package/dist/esm/fields/EditableBooleanField.js +0 -17
- package/dist/esm/fields/FKField.js +0 -27
- package/dist/esm/fields/JsonField.js +0 -28
- package/dist/esm/hooks/useAction.js +0 -8
- package/dist/esm/index.js +0 -42
- package/dist/esm/inputs/FKInput.js +0 -33
- package/dist/esm/inputs/JsonInput.js +0 -63
- package/dist/esm/resources.js +0 -47
- package/dist/esm/ui.js +0 -70
- package/dist/esm/utils.js +0 -38
- package/dist/esm/views/create.js +0 -16
- package/dist/esm/views/edit.js +0 -29
- package/dist/esm/views/list.js +0 -64
- package/dist/esm/views/show.js +0 -35
- package/dist/esm/web.js +0 -2
- package/src/admin.jsx +0 -78
- package/src/dashboard.jsx +0 -74
- package/src/fields/EditableBooleanField.jsx +0 -11
- package/src/index.js +0 -16
- package/src/inputs/FKInput.jsx +0 -42
- package/src/resources.jsx +0 -39
- package/src/utils.js +0 -38
- package/src/views/create.jsx +0 -30
- package/src/views/edit.jsx +0 -48
- package/src/views/list.jsx +0 -86
- package/src/views/show.jsx +0 -51
- package/src/web.js +0 -3
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export type TProps = {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
};
|
|
4
|
+
export type AdminAction = {
|
|
5
|
+
view: string;
|
|
6
|
+
icon: string;
|
|
7
|
+
action: string;
|
|
8
|
+
title: string;
|
|
9
|
+
label: string;
|
|
10
|
+
};
|
|
11
|
+
export type AdminField = [string, {
|
|
12
|
+
source: string;
|
|
13
|
+
}];
|
|
14
|
+
export type AdminInput = [string, {
|
|
15
|
+
required: boolean;
|
|
16
|
+
source: string;
|
|
17
|
+
}];
|
|
18
|
+
export type AdminShowLink = {
|
|
19
|
+
label: string;
|
|
20
|
+
title?: string;
|
|
21
|
+
icon?: string;
|
|
22
|
+
};
|
|
23
|
+
export type AdminShowProps = {
|
|
24
|
+
actions: AdminAction[];
|
|
25
|
+
fields: AdminField[];
|
|
26
|
+
links: Record<string, AdminShowLink>;
|
|
27
|
+
};
|
|
28
|
+
export type AdminResourceProps = {
|
|
29
|
+
name: string;
|
|
30
|
+
icon?: string;
|
|
31
|
+
label: string;
|
|
32
|
+
create: AdminInput[];
|
|
33
|
+
edit: {
|
|
34
|
+
actions: AdminAction[];
|
|
35
|
+
inputs: AdminInput[];
|
|
36
|
+
};
|
|
37
|
+
list: {
|
|
38
|
+
limit: number;
|
|
39
|
+
limitMax: number;
|
|
40
|
+
actions: AdminAction[];
|
|
41
|
+
fields: AdminField[];
|
|
42
|
+
filters: AdminInput[];
|
|
43
|
+
show: boolean;
|
|
44
|
+
edit?: boolean;
|
|
45
|
+
};
|
|
46
|
+
show: AdminShowProps;
|
|
47
|
+
};
|
|
48
|
+
export type AdminDashboardBlock = {
|
|
49
|
+
title: string;
|
|
50
|
+
value: any;
|
|
51
|
+
};
|
|
52
|
+
export type AdminOpts = {
|
|
53
|
+
adminProps: {
|
|
54
|
+
title: string;
|
|
55
|
+
disableTelemetry?: boolean;
|
|
56
|
+
mutationMode?: "optimistic" | "pessimistic" | "undoable";
|
|
57
|
+
};
|
|
58
|
+
apiUrl: string;
|
|
59
|
+
appBarLinks: [{
|
|
60
|
+
ulr: string;
|
|
61
|
+
title: string;
|
|
62
|
+
icon?: string;
|
|
63
|
+
}];
|
|
64
|
+
auth: {
|
|
65
|
+
identityURL: string;
|
|
66
|
+
authorizeURL: string;
|
|
67
|
+
loginURL?: string;
|
|
68
|
+
logoutURL?: string;
|
|
69
|
+
required: boolean;
|
|
70
|
+
storage: "localstorage" | "cookie";
|
|
71
|
+
storageName: string;
|
|
72
|
+
};
|
|
73
|
+
dashboard: AdminDashboardBlock[] | AdminDashboardBlock;
|
|
74
|
+
resources: AdminResourceProps[];
|
|
75
|
+
version: string;
|
|
76
|
+
};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { AdminOpts } from "./types";
|
|
3
|
+
export declare function setupAdmin<T>(adminType: string[], fc: (props: any) => T): void;
|
|
4
|
+
export declare function buildAdmin(adminType: string[], props?: {}): any;
|
|
5
|
+
export declare function findBuilder(adminType: string[]): (props: any) => any;
|
|
6
|
+
export declare const AdminPropsContext: import("react").Context<AdminOpts>;
|
|
7
|
+
export type APIParams = {
|
|
8
|
+
method?: string;
|
|
9
|
+
query?: {
|
|
10
|
+
where?: string;
|
|
11
|
+
limit?: number;
|
|
12
|
+
offset?: number;
|
|
13
|
+
sort?: string;
|
|
14
|
+
ids?: string[];
|
|
15
|
+
};
|
|
16
|
+
data?: any;
|
|
17
|
+
headers?: any;
|
|
18
|
+
body?: string;
|
|
19
|
+
};
|
|
20
|
+
export declare const requestHeaders: {};
|
|
21
|
+
export declare function makeRequest(url: string, params?: APIParams): Promise<{
|
|
22
|
+
status: number;
|
|
23
|
+
headers: Headers;
|
|
24
|
+
body: string;
|
|
25
|
+
json: any;
|
|
26
|
+
}>;
|
|
27
|
+
export declare function findIcon(icon?: string): any;
|
|
28
|
+
export declare function buildIcon(icon?: string): import("react/jsx-runtime").JSX.Element;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
+
import * as icons from "@mui/icons-material";
|
|
14
|
+
import { stringify } from "query-string";
|
|
15
|
+
import { fetchUtils } from "ra-core";
|
|
16
|
+
import { createContext } from "react";
|
|
17
|
+
const builders = new Map();
|
|
18
|
+
export function setupAdmin(adminType, fc) {
|
|
19
|
+
const key = adminType.join("/");
|
|
20
|
+
builders.set(key, fc);
|
|
21
|
+
}
|
|
22
|
+
export function buildAdmin(adminType, props = {}) {
|
|
23
|
+
if (process.env.NODE_ENV == "development")
|
|
24
|
+
console.log(adminType, props);
|
|
25
|
+
const builder = findBuilder(adminType);
|
|
26
|
+
if (builder)
|
|
27
|
+
return builder(props);
|
|
28
|
+
console.warn(`No admin renderer found for ${adminType.join("/")}`);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
export function findBuilder(adminType) {
|
|
32
|
+
const key = [...adminType];
|
|
33
|
+
while (key.length) {
|
|
34
|
+
const render = builders.get(key.join("/"));
|
|
35
|
+
if (render)
|
|
36
|
+
return render;
|
|
37
|
+
key.pop();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export const AdminPropsContext = createContext(null);
|
|
41
|
+
export const requestHeaders = {};
|
|
42
|
+
export function makeRequest(url, params = {}) {
|
|
43
|
+
const _a = params || {}, { data, query } = _a, opts = __rest(_a, ["data", "query"]);
|
|
44
|
+
if (data)
|
|
45
|
+
opts.body = JSON.stringify(data);
|
|
46
|
+
if (query)
|
|
47
|
+
url = `${url}?${stringify(query)}`;
|
|
48
|
+
return fetchUtils.fetchJson(url, Object.assign(Object.assign({}, opts), { headers: new Headers(Object.assign(Object.assign({}, requestHeaders), opts.headers)) }));
|
|
49
|
+
}
|
|
50
|
+
export function findIcon(icon) {
|
|
51
|
+
return icon ? icons[icon] : undefined;
|
|
52
|
+
}
|
|
53
|
+
export function buildIcon(icon) {
|
|
54
|
+
const Icon = findIcon(icon);
|
|
55
|
+
if (Icon)
|
|
56
|
+
return _jsx(Icon, {});
|
|
57
|
+
}
|
package/dist/web.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/web.js
ADDED
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "muffin-admin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.45.1",
|
|
4
4
|
"description": "NPM package for https://github.com/klen/muffin-admin",
|
|
5
5
|
"files": [
|
|
6
6
|
"src",
|
|
7
7
|
"dist"
|
|
8
8
|
],
|
|
9
|
-
"main": "dist/
|
|
10
|
-
"
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"types": "dist/index.d.js",
|
|
11
11
|
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
12
13
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
13
14
|
},
|
|
14
15
|
"repository": {
|
|
@@ -22,26 +23,42 @@
|
|
|
22
23
|
},
|
|
23
24
|
"homepage": "https://github.com/klen/muffin-admin#readme",
|
|
24
25
|
"dependencies": {
|
|
25
|
-
"@mui/icons-material": "^5.14.1",
|
|
26
|
-
"@mui/material": "^5.14.2",
|
|
27
26
|
"js-cookie": "^3.0.5",
|
|
28
|
-
"ra-ui-materialui": "^4.12.2",
|
|
29
27
|
"react": "^18.2.0",
|
|
30
28
|
"react-admin": "^4.12.2",
|
|
31
29
|
"react-dom": "^18.2.0",
|
|
32
30
|
"validator": "^13.9.0"
|
|
33
31
|
},
|
|
34
32
|
"devDependencies": {
|
|
35
|
-
"@
|
|
36
|
-
"@
|
|
37
|
-
"@
|
|
38
|
-
"@
|
|
39
|
-
"@
|
|
40
|
-
"@
|
|
41
|
-
"
|
|
42
|
-
"eslint
|
|
33
|
+
"@types/node": "20.3.2",
|
|
34
|
+
"@types/react": "18.2.14",
|
|
35
|
+
"@types/react-dom": "18.2.6",
|
|
36
|
+
"@types/react-window": "^1.8.5",
|
|
37
|
+
"@typescript-eslint/eslint-plugin": "^6.3.0",
|
|
38
|
+
"@typescript-eslint/parser": "^6.3.0",
|
|
39
|
+
"dotenv": "^16.3.1",
|
|
40
|
+
"eslint": "8.46.0",
|
|
41
|
+
"eslint-config-prettier": "^9.0.0",
|
|
42
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
43
|
+
"html-webpack-plugin": "^5.5.3",
|
|
44
|
+
"husky": "^8.0.1",
|
|
45
|
+
"prettier": "^3.0.1",
|
|
46
|
+
"prettier-plugin-organize-imports": "^3.2.3",
|
|
47
|
+
"ts-loader": "^9.4.4",
|
|
48
|
+
"typescript": "^5.1.6",
|
|
43
49
|
"webpack": "^5.88.2",
|
|
44
50
|
"webpack-cli": "^5.1.4",
|
|
45
51
|
"webpack-dev-server": "^4.15.1"
|
|
52
|
+
},
|
|
53
|
+
"prettier": {
|
|
54
|
+
"arrowParens": "always",
|
|
55
|
+
"plugins": [
|
|
56
|
+
"prettier-plugin-organize-imports"
|
|
57
|
+
],
|
|
58
|
+
"printWidth": 100,
|
|
59
|
+
"semi": false,
|
|
60
|
+
"tabWidth": 2,
|
|
61
|
+
"trailingComma": "es5",
|
|
62
|
+
"useTabs": false
|
|
46
63
|
}
|
|
47
64
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import IconButton from "@mui/material/IconButton"
|
|
2
|
+
import SvgIcon from "@mui/material/SvgIcon"
|
|
3
|
+
import Tooltip from "@mui/material/Tooltip"
|
|
4
|
+
import Typography from "@mui/material/Typography"
|
|
5
|
+
import createTheme from "@mui/material/styles/createTheme"
|
|
6
|
+
import {
|
|
7
|
+
Admin,
|
|
8
|
+
AppBar,
|
|
9
|
+
DataProvider,
|
|
10
|
+
Layout,
|
|
11
|
+
Login,
|
|
12
|
+
ToggleThemeButton,
|
|
13
|
+
defaultTheme,
|
|
14
|
+
} from "react-admin"
|
|
15
|
+
import { AdminOpts } from "./types"
|
|
16
|
+
import { AdminPropsContext, buildAdmin, findBuilder, findIcon, setupAdmin } from "./utils"
|
|
17
|
+
|
|
18
|
+
const darkTheme = createTheme({
|
|
19
|
+
palette: { mode: "dark" },
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export function MuffinAdmin(props: AdminOpts) {
|
|
23
|
+
const { resources, auth } = props
|
|
24
|
+
const children = resources.map((resource) =>
|
|
25
|
+
buildAdmin(["resource", resource.name], {
|
|
26
|
+
...resource,
|
|
27
|
+
key: resource.name,
|
|
28
|
+
})
|
|
29
|
+
)
|
|
30
|
+
const appBar = (props) => (
|
|
31
|
+
<AppBar {...props}>
|
|
32
|
+
<Typography
|
|
33
|
+
variant="h6"
|
|
34
|
+
color="inherit"
|
|
35
|
+
id="react-admin-title"
|
|
36
|
+
style={{
|
|
37
|
+
flex: 1,
|
|
38
|
+
textOverflow: "ellipsis",
|
|
39
|
+
whiteSpace: "nowrap",
|
|
40
|
+
overflow: "hidden",
|
|
41
|
+
}}
|
|
42
|
+
/>
|
|
43
|
+
<ToggleThemeButton lightTheme={defaultTheme} darkTheme={darkTheme} />
|
|
44
|
+
{props.appBarLinks.map((info) => (
|
|
45
|
+
<Tooltip key={info.url} title={info.title}>
|
|
46
|
+
<IconButton color="inherit" href={info.url}>
|
|
47
|
+
<SvgIcon component={findIcon(info.icon)} />
|
|
48
|
+
</IconButton>
|
|
49
|
+
</Tooltip>
|
|
50
|
+
))}
|
|
51
|
+
</AppBar>
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<AdminPropsContext.Provider value={props}>
|
|
56
|
+
<Admin
|
|
57
|
+
requireAuth={auth.required}
|
|
58
|
+
dashboard={buildAdmin(["dashboard"])}
|
|
59
|
+
loginPage={findBuilder(["loginpage"])}
|
|
60
|
+
authProvider={buildAdmin(["authprovider"], auth)}
|
|
61
|
+
layout={(props) => <Layout {...props} appBar={appBar} />}
|
|
62
|
+
dataProvider={buildAdmin(["dataprovider"], props) as unknown as DataProvider}
|
|
63
|
+
>
|
|
64
|
+
{children}
|
|
65
|
+
</Admin>
|
|
66
|
+
</AdminPropsContext.Provider>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
setupAdmin(["admin"], MuffinAdmin)
|
|
71
|
+
|
|
72
|
+
// Initialize login page
|
|
73
|
+
setupAdmin(["loginpage"], Login)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import Card from "@mui/material/Card"
|
|
2
|
+
import CardContent from "@mui/material/CardContent"
|
|
3
|
+
import Grid from "@mui/material/Grid"
|
|
4
|
+
import Table from "@mui/material/Table"
|
|
5
|
+
import TableBody from "@mui/material/TableBody"
|
|
6
|
+
import TableCell from "@mui/material/TableCell"
|
|
7
|
+
import TableRow from "@mui/material/TableRow"
|
|
8
|
+
import Typography from "@mui/material/Typography"
|
|
9
|
+
import { AdminDashboardBlock, AdminOpts } from "./types"
|
|
10
|
+
|
|
11
|
+
export function MuffinDashboard(props: AdminOpts["dashboard"]) {
|
|
12
|
+
return (
|
|
13
|
+
<Grid container spacing={1}>
|
|
14
|
+
{Array.isArray(props) ? (
|
|
15
|
+
props.map((card, idx) => <DashboardCard key={idx} {...card} />)
|
|
16
|
+
) : (
|
|
17
|
+
<DashboardCard {...props} />
|
|
18
|
+
)}
|
|
19
|
+
</Grid>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function DashboardCard(title, value: AdminDashboardBlock) {
|
|
24
|
+
return (
|
|
25
|
+
<Grid item xs>
|
|
26
|
+
<Card>
|
|
27
|
+
<CardContent>
|
|
28
|
+
<Typography variant="h5" component="h2" m={2} style={{ textAlign: "center" }}>
|
|
29
|
+
{title}
|
|
30
|
+
</Typography>
|
|
31
|
+
{(Array.isArray(value) && <AdminTableView src={value} />) || (
|
|
32
|
+
<pre>{JSON.stringify(value, null, 2)}</pre>
|
|
33
|
+
)}
|
|
34
|
+
</CardContent>
|
|
35
|
+
</Card>
|
|
36
|
+
</Grid>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const AdminTableView = ({ src }) => (
|
|
41
|
+
<Table>
|
|
42
|
+
<TableBody>
|
|
43
|
+
{src.map((row, idx) => (
|
|
44
|
+
<TableRow key={idx} hover>
|
|
45
|
+
{row.map((cell, idx) => (
|
|
46
|
+
<TableCell key={idx}>{cell}</TableCell>
|
|
47
|
+
))}
|
|
48
|
+
</TableRow>
|
|
49
|
+
))}
|
|
50
|
+
</TableBody>
|
|
51
|
+
</Table>
|
|
52
|
+
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Resource } from "react-admin"
|
|
2
|
+
import { AdminResourceProps } from "./types"
|
|
3
|
+
import { buildAdmin, findIcon, setupAdmin } from "./utils"
|
|
4
|
+
|
|
5
|
+
export function MuffinResource({
|
|
6
|
+
name,
|
|
7
|
+
create: createProps,
|
|
8
|
+
edit: editProps,
|
|
9
|
+
list: listProps,
|
|
10
|
+
show: showProps,
|
|
11
|
+
icon,
|
|
12
|
+
...props
|
|
13
|
+
}: AdminResourceProps) {
|
|
14
|
+
return (
|
|
15
|
+
<Resource
|
|
16
|
+
name={name}
|
|
17
|
+
icon={findIcon(icon)}
|
|
18
|
+
create={buildAdmin(["create", name], createProps)}
|
|
19
|
+
edit={buildAdmin(["edit", name], editProps)}
|
|
20
|
+
list={buildAdmin(["list", name], listProps)}
|
|
21
|
+
show={buildAdmin(["show", name], showProps)}
|
|
22
|
+
{...props}
|
|
23
|
+
/>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
setupAdmin(["resource"], MuffinResource)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Create, ListButton, SimpleForm, TopToolbar, useResourceContext } from "react-admin"
|
|
2
|
+
import { buildRA } from "./buildRA"
|
|
3
|
+
import { AdminResourceProps } from "./types"
|
|
4
|
+
import { buildAdmin, setupAdmin } from "./utils"
|
|
5
|
+
|
|
6
|
+
export function MuffinResourceCreate({ inputs }: { inputs: AdminResourceProps["create"] }) {
|
|
7
|
+
const resourceName = useResourceContext()
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<Create actions={buildAdmin(["create-actions", resourceName])}>
|
|
11
|
+
<SimpleForm>{buildAdmin(["create-inputs", resourceName], inputs)}</SimpleForm>
|
|
12
|
+
</Create>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
setupAdmin(["create"], (inputs) => <MuffinResourceCreate inputs={inputs} />)
|
|
17
|
+
|
|
18
|
+
setupAdmin(["create-actions"], () => (
|
|
19
|
+
<TopToolbar>
|
|
20
|
+
<ListButton />
|
|
21
|
+
</TopToolbar>
|
|
22
|
+
))
|
|
23
|
+
|
|
24
|
+
setupAdmin(["create-inputs"], buildRA)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { useContext } from "react"
|
|
2
|
+
import {
|
|
3
|
+
Edit,
|
|
4
|
+
ListButton,
|
|
5
|
+
ShowButton,
|
|
6
|
+
SimpleForm,
|
|
7
|
+
TopToolbar,
|
|
8
|
+
useResourceContext,
|
|
9
|
+
} from "react-admin"
|
|
10
|
+
import { buildRA } from "./buildRA"
|
|
11
|
+
import { ActionButton } from "./buttons"
|
|
12
|
+
import { AdminAction, AdminOpts, AdminResourceProps } from "./types"
|
|
13
|
+
import { AdminPropsContext, buildAdmin, setupAdmin } from "./utils"
|
|
14
|
+
|
|
15
|
+
export function MuffinResourceEdit({ actions, inputs, ...props }: AdminResourceProps["edit"]) {
|
|
16
|
+
const resourceName = useResourceContext()
|
|
17
|
+
const {
|
|
18
|
+
adminProps: { mutationMode },
|
|
19
|
+
} = useContext(AdminPropsContext) as AdminOpts
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<Edit
|
|
23
|
+
actions={buildAdmin(["edit-actions", resourceName], actions)}
|
|
24
|
+
mutationMode={mutationMode || "optimistic"}
|
|
25
|
+
{...props}
|
|
26
|
+
>
|
|
27
|
+
<SimpleForm>{buildAdmin(["edit-inputs", resourceName], inputs)}</SimpleForm>
|
|
28
|
+
</Edit>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
setupAdmin(["edit"], (props) => <MuffinResourceEdit {...props} />)
|
|
33
|
+
setupAdmin(["edit-actions"], (actions: AdminAction[]) => (
|
|
34
|
+
<TopToolbar>
|
|
35
|
+
{actions.map((props, idx) => (
|
|
36
|
+
<ActionButton key={idx} {...props} />
|
|
37
|
+
))}
|
|
38
|
+
<ListButton />
|
|
39
|
+
<ShowButton />
|
|
40
|
+
</TopToolbar>
|
|
41
|
+
))
|
|
42
|
+
setupAdmin(["edit-inputs"], buildRA)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import sortBy from "lodash/sortBy"
|
|
2
|
+
import uniq from "lodash/uniq"
|
|
3
|
+
import {
|
|
4
|
+
BulkDeleteButton,
|
|
5
|
+
Datagrid,
|
|
6
|
+
EditButton,
|
|
7
|
+
List,
|
|
8
|
+
Pagination,
|
|
9
|
+
useResourceContext,
|
|
10
|
+
} from "react-admin"
|
|
11
|
+
import { buildRA } from "./buildRA"
|
|
12
|
+
import { BulkActionButton } from "./buttons"
|
|
13
|
+
import { AdminAction, AdminResourceProps } from "./types"
|
|
14
|
+
import { buildAdmin, setupAdmin } from "./utils"
|
|
15
|
+
|
|
16
|
+
export function MuffinResourceList(props: AdminResourceProps["list"]) {
|
|
17
|
+
const resourceName = useResourceContext()
|
|
18
|
+
const { fields, edit, show, limit, limitMax, filters, actions } = props
|
|
19
|
+
return (
|
|
20
|
+
<List
|
|
21
|
+
bulkActionButtons={buildAdmin(["list-actions", resourceName], actions)}
|
|
22
|
+
filters={buildAdmin(["list-filters", resourceName], filters) || undefined}
|
|
23
|
+
perPage={limit}
|
|
24
|
+
pagination={
|
|
25
|
+
<Pagination rowsPerPageOptions={sortBy(uniq([10, 25, 50, 100, limit, limitMax]))} />
|
|
26
|
+
}
|
|
27
|
+
>
|
|
28
|
+
<Datagrid rowClick={show ? "show" : edit ? "edit" : false}>
|
|
29
|
+
{buildAdmin(["list-fields", resourceName], fields)}
|
|
30
|
+
{edit && <EditButton />}
|
|
31
|
+
</Datagrid>
|
|
32
|
+
</List>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
setupAdmin(["list"], (props) => <MuffinResourceList {...props} />)
|
|
37
|
+
setupAdmin(["list-fields"], buildRA)
|
|
38
|
+
setupAdmin(["list-filters"], buildRA)
|
|
39
|
+
setupAdmin(["list-actions"], (actions: AdminAction[]) => (
|
|
40
|
+
<>
|
|
41
|
+
{actions.map((props, idx) => (
|
|
42
|
+
<BulkActionButton key={idx} {...props} />
|
|
43
|
+
))}
|
|
44
|
+
<BulkDeleteButton />
|
|
45
|
+
</>
|
|
46
|
+
))
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EditButton,
|
|
3
|
+
ListButton,
|
|
4
|
+
Show,
|
|
5
|
+
SimpleShowLayout,
|
|
6
|
+
TopToolbar,
|
|
7
|
+
useResourceContext,
|
|
8
|
+
} from "react-admin"
|
|
9
|
+
import { LinkAction } from "./actions"
|
|
10
|
+
import { buildRA } from "./buildRA"
|
|
11
|
+
import { ActionButton } from "./buttons"
|
|
12
|
+
import { AdminShowProps } from "./types"
|
|
13
|
+
import { buildAdmin, setupAdmin } from "./utils"
|
|
14
|
+
|
|
15
|
+
export function MuffinResourceShow(props: AdminShowProps) {
|
|
16
|
+
const resourceName = useResourceContext()
|
|
17
|
+
return (
|
|
18
|
+
<Show actions={buildAdmin(["show-actions", resourceName], props)}>
|
|
19
|
+
<SimpleShowLayout>{buildAdmin(["show-fields", resourceName], props)}</SimpleShowLayout>
|
|
20
|
+
</Show>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
setupAdmin(["show"], (props) => <MuffinResourceShow {...props} />)
|
|
25
|
+
setupAdmin(["show-fields"], ({ fields }) => buildRA(fields))
|
|
26
|
+
setupAdmin(["show-actions"], ({ actions, links }) => (
|
|
27
|
+
<TopToolbar>
|
|
28
|
+
<div style={{ marginRight: "auto" }}>
|
|
29
|
+
{Object.keys(links).map((key) => (
|
|
30
|
+
<LinkAction key={key} resource={key} {...links[key]} />
|
|
31
|
+
))}
|
|
32
|
+
</div>
|
|
33
|
+
{actions.map((props, idx) => (
|
|
34
|
+
<ActionButton key={idx} {...props} />
|
|
35
|
+
))}
|
|
36
|
+
<ListButton />
|
|
37
|
+
<EditButton />
|
|
38
|
+
</TopToolbar>
|
|
39
|
+
))
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useRecordContext, useResourceContext } from "react-admin"
|
|
2
|
+
import LinkButton from "../buttons/LinkButton"
|
|
3
|
+
import { AdminShowLink } from "../types"
|
|
4
|
+
|
|
5
|
+
export function LinkAction(props: AdminShowLink & { resource: string }) {
|
|
6
|
+
const record = useRecordContext()
|
|
7
|
+
const currentResource = useResourceContext()
|
|
8
|
+
if (!record) return null
|
|
9
|
+
return <LinkButton {...props} filters={{ [currentResource]: record.id }} />
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./LinkAction"
|
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
import Cookies from "js-cookie"
|
|
2
|
-
|
|
3
|
-
import {
|
|
2
|
+
import { buildAdmin, makeRequest, requestHeaders, setupAdmin } from "."
|
|
3
|
+
import { AdminOpts } from "./types"
|
|
4
4
|
|
|
5
5
|
setupAdmin(
|
|
6
|
-
"auth-get",
|
|
7
|
-
({ storage }) =>
|
|
8
|
-
(
|
|
9
|
-
storage == "localstorage" ? localStorage.getItem(
|
|
6
|
+
["auth-storage-get"],
|
|
7
|
+
({ storage, storageName }: AdminOpts["auth"]) =>
|
|
8
|
+
() =>
|
|
9
|
+
storage == "localstorage" ? localStorage.getItem(storageName) : Cookies.get(storageName)
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
-
setupAdmin("auth-set", ({ storage }) => (name, value) => {
|
|
12
|
+
setupAdmin(["auth-storage-set"], ({ storage }) => (name, value) => {
|
|
13
13
|
if (storage == "localstorage") {
|
|
14
14
|
localStorage.setItem(name, value)
|
|
15
15
|
requestHeaders["Authorization"] = value
|
|
16
16
|
} else Cookies.set(name, value)
|
|
17
17
|
})
|
|
18
18
|
|
|
19
|
-
export
|
|
20
|
-
const { identityURL, authorizeURL, logoutURL, required,
|
|
19
|
+
export function MuffinAuthProvider(props: AdminOpts["auth"]) {
|
|
20
|
+
const { identityURL, authorizeURL, logoutURL, required, storageName } = props
|
|
21
21
|
|
|
22
|
-
const authGet =
|
|
23
|
-
const authSet =
|
|
22
|
+
const authGet = buildAdmin(["auth-storage-get"], props)
|
|
23
|
+
const authSet = buildAdmin(["auth-storage-set"], props)
|
|
24
24
|
|
|
25
25
|
// Initialize request headers
|
|
26
|
-
authSet(
|
|
26
|
+
authSet(storageName, authGet(storageName))
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
const getIdentity = async () => {
|
|
29
29
|
if (identityURL) {
|
|
30
|
-
|
|
30
|
+
const { json } = await makeRequest(identityURL)
|
|
31
31
|
return json
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -37,8 +37,11 @@ export default (props) => {
|
|
|
37
37
|
login: async (data) => {
|
|
38
38
|
if (!authorizeURL) throw { message: "Authorization is not supported" }
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
const { json } = await makeRequest(authorizeURL, {
|
|
41
|
+
data,
|
|
42
|
+
method: "POST",
|
|
43
|
+
})
|
|
44
|
+
authSet(storageName, json)
|
|
42
45
|
},
|
|
43
46
|
|
|
44
47
|
checkError: async (error) => {
|
|
@@ -46,7 +49,7 @@ export default (props) => {
|
|
|
46
49
|
|
|
47
50
|
if (status == 401 || status == 403) {
|
|
48
51
|
// Clean storage
|
|
49
|
-
authSet(
|
|
52
|
+
authSet(storageName, "")
|
|
50
53
|
|
|
51
54
|
throw {
|
|
52
55
|
message: "Invalid authorization",
|
|
@@ -57,12 +60,12 @@ export default (props) => {
|
|
|
57
60
|
},
|
|
58
61
|
|
|
59
62
|
checkAuth: async () => {
|
|
60
|
-
const auth = authGet(
|
|
63
|
+
const auth = authGet(storageName)
|
|
61
64
|
if (!auth) throw { message: "Authorization required" }
|
|
62
65
|
|
|
63
66
|
if (!identityURL) return auth
|
|
64
67
|
|
|
65
|
-
|
|
68
|
+
const user = await getIdentity()
|
|
66
69
|
if (!user) throw { message: "Authorization required" }
|
|
67
70
|
|
|
68
71
|
return user
|
|
@@ -70,16 +73,18 @@ export default (props) => {
|
|
|
70
73
|
|
|
71
74
|
logout: async () => {
|
|
72
75
|
// Clean storage
|
|
73
|
-
authSet(
|
|
76
|
+
authSet(storageName, "")
|
|
74
77
|
|
|
75
|
-
if (logoutURL) window.location = logoutURL
|
|
78
|
+
if (logoutURL) window.location.href = logoutURL
|
|
76
79
|
},
|
|
77
80
|
|
|
78
81
|
getIdentity,
|
|
79
82
|
|
|
80
83
|
getPermissions: async () => {
|
|
81
|
-
const role = authGet(
|
|
84
|
+
const role = authGet(storageName + "_role")
|
|
82
85
|
return role || ""
|
|
83
86
|
},
|
|
84
87
|
}
|
|
85
88
|
}
|
|
89
|
+
|
|
90
|
+
setupAdmin(["authprovider"], MuffinAuthProvider)
|