muffin-admin 1.28.2 → 1.31.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/admin.jsx DELETED
@@ -1,56 +0,0 @@
1
- import React from "react"
2
-
3
- import { Admin, AppBar, Layout, Login } from "react-admin"
4
- import { IconButton, SvgIcon, Tooltip, Typography } from "@material-ui/core"
5
- import * as icons from "@material-ui/icons"
6
-
7
- import authProvider from "./authprovider"
8
- import dataProvider from "./dataprovider"
9
- import { processAdmin, setupAdmin } from './utils'
10
-
11
- import './dashboard.jsx';
12
- import './resources.jsx';
13
-
14
-
15
- // Initialize the admin
16
- setupAdmin('admin', props => {
17
- const { apiUrl, auth, adminProps, appBarLinks, dashboard, resources } = props;
18
-
19
- let appBar = props => (
20
- <AppBar {...props}>
21
- <Typography
22
- variant="h6"
23
- color="inherit"
24
- id="react-admin-title"
25
- style={{
26
- flex: 1,
27
- textOverflow: 'ellipsis',
28
- whiteSpace: 'nowrap',
29
- overflow: 'hidden',
30
- }}
31
- />
32
- { appBarLinks.map( info => (
33
- <Tooltip key={ info.url } title={ info.title }>
34
- <IconButton color="inherit" href={ info.url }>
35
- <SvgIcon component={ icons[info.icon] }/>
36
- </IconButton>
37
- </Tooltip>
38
- ))}
39
- </AppBar>
40
- )
41
-
42
- return <Admin authProvider={ processAdmin('auth', auth) }
43
- dataProvider={ processAdmin('data', apiUrl) }
44
- dashboard={ processAdmin('dashboard', dashboard) }
45
- loginPage={ processAdmin('login', auth) }
46
- layout={ props => <Layout appBar={appBar} {...props} /> }
47
- children={ processAdmin('resources', resources) }
48
- { ...adminProps } />
49
- });
50
-
51
- // Initialize authentication and data providers
52
- setupAdmin('auth', authProvider);
53
- setupAdmin('data', dataProvider);
54
-
55
- // Initialize login page
56
- setupAdmin('login', (params, res) => (props) => <Login {...props} />);
package/authprovider.js DELETED
@@ -1,79 +0,0 @@
1
- import Cookies from 'js-cookie'
2
- import { makeRequest, requestHeaders } from './utils';
3
-
4
-
5
- export default (props) => {
6
-
7
- const { identityURL, authorizeURL, logoutURL, required, storage, storage_name } = props;
8
-
9
- const authorize = (name, value) => {
10
- if (value === undefined) {
11
- return storage == 'localstorage' ? localStorage.getItem(name) : Cookies.get(name);
12
- }
13
-
14
- if (storage == 'localstorage') requestHeaders['Authorization'] = value;
15
- storage == 'localstorage' ? localStorage.setItem(name, value) : Cookies.set(name, value);
16
- return value;
17
- }
18
-
19
- // Initialize request headers
20
- authorize(storage_name, authorize(storage_name));
21
-
22
- let getIdentity = async () => {
23
- if (identityURL) {
24
- let {json} = await makeRequest(identityURL);
25
- return json;
26
- }
27
- }
28
-
29
- if (required) return {
30
-
31
- getIdentity,
32
-
33
- checkAuth: async (data) => {
34
- const auth = authorize(storage_name);
35
- if (!auth) throw {message: 'Authorization required'}
36
-
37
- if (!identityURL) return auth;
38
-
39
- let user = await getIdentity();
40
- if (!user) throw {message: 'Authorization required'};
41
-
42
- return user;
43
- },
44
-
45
- checkError: async (error) => {
46
- const {message, status, body} = error;
47
-
48
- if (status == 401 || status == 403) {
49
- // Clean storage
50
- authorize(storage_name, '');
51
-
52
- throw {message: 'Invalid authorization', redirectTo: logoutURL, logoutUser: !logoutURL};
53
- }
54
-
55
- },
56
-
57
- login: async (data) => {
58
- if (!authorizeURL) throw {message: 'Authorization is not supported'}
59
-
60
- let {json} = await makeRequest(authorizeURL, {data, method: 'POST'})
61
- authorize(storage_name, json);
62
- },
63
-
64
- logout: async () => {
65
-
66
- // Clean storage
67
- authorize(storage_name, '');
68
-
69
- if (logoutURL) window.location = logoutURL;
70
- },
71
-
72
- getPermissions: (data) => {
73
- const role = authorize(storage_name + '_role');
74
- return role ? Promise.resolve(role) : Promise.reject();
75
- },
76
-
77
- }
78
-
79
- }
@@ -1,68 +0,0 @@
1
- import React from 'react';
2
-
3
- import { Button, CreateButton, useRefresh, useUnselectAll, useMutation, useNotify } from 'react-admin';
4
- import * as icons from "@material-ui/icons"
5
-
6
-
7
- export const BulkActionButton = ({label, icon, title, action, resource, selectedIds, ...props}) => {
8
- const refresh = useRefresh(), unselectAll = useUnselectAll(),
9
- notify = useNotify(), [mutate, { loading }] = useMutation(),
10
- Icon = icons[icon];
11
-
12
- let onClick = event => {
13
- mutate({
14
- resource,
15
- type: 'runAction',
16
- payload: {action, ids: selectedIds},
17
- }, {
18
- onSuccess: res => {
19
- if (res && res.data && res.data.message) notify(res.data.message, 'success');
20
- refresh();
21
- unselectAll(resource);
22
- },
23
- onFailure: err => {
24
- notify(typeof err === 'string' ? err : err.message, 'error')
25
- }
26
- })
27
- }
28
-
29
- return (
30
- <Button label={ label } title={ title } onClick={ onClick } disabled={ loading }>
31
- { Icon && <Icon /> }
32
- </Button>
33
- )
34
- }
35
-
36
- export const ActionButton = ({icon, label, title, record, resource, action}) => {
37
- const refresh = useRefresh(), notify = useNotify(),
38
- [mutate, { loading }] = useMutation(), Icon = icons[icon];
39
-
40
- let onClick = event => {
41
- mutate({
42
- resource,
43
- type: 'runAction',
44
- payload: {action, record},
45
- }, {
46
- onSuccess: res => {
47
- let data = res && res.data;
48
-
49
- if (data && data.redirectTo) window.location = data.redirectTo;
50
- if (data && data.message) notify(data.message, 'success');
51
-
52
- refresh();
53
- },
54
- onFailure: err => {
55
- notify(typeof err === 'string' ? err : err.message, 'error')
56
- }
57
- })
58
- }
59
-
60
- return (
61
- <Button label={ label } title={ title } onClick={ onClick } disabled={ loading }>
62
- { Icon && <Icon /> }
63
- </Button>
64
- )
65
-
66
- }
67
-
68
- export default ActionButton
@@ -1,21 +0,0 @@
1
- import React from 'react';
2
-
3
- import { Button } from 'react-admin';
4
- import { Link } from 'react-router-dom';
5
- import * as icons from "@material-ui/icons"
6
-
7
- // import LinkButton from '../buttons/LinkButton'
8
- // <LinkButton label="Messages" icon="Message" resource="message" filters={{ user: data.id }} />
9
- //
10
- const LinkButton = ({label, icon, title, resource, filters, ...props}) => {
11
- let Icon = icons[icon] || icon, linkParams = {pathname: `/${resource}`};
12
- if (filters) linkParams.search = `filter=${JSON.stringify(filters)}`;
13
-
14
- return (
15
- <Button label={ label } title={ title } component={ Link } to={ linkParams }>
16
- { Icon && <Icon /> }
17
- </Button>
18
- )
19
- }
20
-
21
- export default LinkButton
package/dashboard.jsx DELETED
@@ -1,57 +0,0 @@
1
- import React from "react";
2
-
3
- import { Grid, Card, CardContent, Typography, Table, TableBody, TableRow, TableCell } from "@material-ui/core";
4
- import ReactJSON from "react-json-view";
5
-
6
- import { setupAdmin } from './utils';
7
-
8
-
9
- const AdminTableView = ({src}) => (
10
- <Table>
11
- <TableBody>{
12
- src.map((row, idx) =>
13
- <TableRow key={ idx } hover>{
14
- row.map((cell, idx) =>
15
- <TableCell key={ idx }>{ cell }</TableCell>
16
- )
17
- }</TableRow>
18
- )
19
- }</TableBody>
20
- </Table>
21
-
22
- )
23
-
24
- const AdminCard = ({ src }) => {
25
- if (Array.isArray(src)) {
26
- return (
27
- <Grid container item spacing={ 2 }>
28
- { src.map((card, idx) => <AdminCard key={ idx } src={ card } />) }
29
- </Grid>
30
- )
31
- }
32
-
33
- let {title, value} = src;
34
-
35
- return (
36
- <Grid item xs>
37
- <Card>
38
- <CardContent>
39
- <Typography variant="h5" component="h2" m={ 2 } style={{ textAlign: 'center' }}>{title}</Typography>
40
- {
41
- Array.isArray(value) && <AdminTableView src={ value } /> || <ReactJSON src={ value } />
42
- }
43
- </CardContent>
44
- </Card>
45
- </Grid>
46
- )
47
- }
48
-
49
- // Process dashboard
50
- setupAdmin('dashboard', props => {
51
- if (!props) return;
52
-
53
- return () =>
54
- <Grid container spacing={ 1 }>
55
- <AdminCard src={ props } />
56
- </Grid>
57
- })
package/dataprovider.js DELETED
@@ -1,81 +0,0 @@
1
- import { makeRequest } from './utils';
2
-
3
-
4
- export default (apiUrl) => {
5
-
6
- const methods = {
7
-
8
- getList: async (resource, {filter, pagination, sort}) => {
9
- const query = {};
10
- if (filter) query.where = JSON.stringify(filter);
11
- if (pagination) {
12
- const {page, perPage: limit} = pagination;
13
- query.limit = limit;
14
- query.offset = limit * (page - 1);
15
- }
16
- if (sort) {
17
- const {field, order} = sort;
18
- query.sort = order == 'ASC' ? field : `-${field}`;
19
- };
20
-
21
- const {headers, json} = await makeRequest(`${apiUrl}/${resource}`, {query});
22
- return {
23
- data: json,
24
- total: parseInt(headers.get('x-total'), 10),
25
- };
26
-
27
- },
28
-
29
- getOne: async (resource, {id}) => {
30
- const {json} = await makeRequest(`${apiUrl}/${resource}/${id}`);
31
- return {data: json};
32
- },
33
-
34
- create: async (resource, {data}) => {
35
- const {json} = await makeRequest(`${apiUrl}/${resource}`, {data, method: 'POST'});
36
- return {data: json};
37
- },
38
-
39
- update: async (resource, {id, data}) => {
40
- const {json} = await makeRequest(`${apiUrl}/${resource}/${id}`, {data, method: 'PUT'});
41
- return {data: json};
42
- },
43
-
44
- updateMany: async (resource, {ids, data}) => {
45
- await Promise.all(ids.map(id => methods.update(resource, {id, data})));
46
- return {data: ids};
47
- },
48
-
49
- delete: async (resource, {id}) => {
50
- const {json} = await makeRequest(`${apiUrl}/${resource}/${id}`, {method: 'DELETE'});
51
- return {data: {id}};
52
- },
53
-
54
- deleteMany: async (resource, {ids}) => {
55
- const {json} = await makeRequest(`${apiUrl}/${resource}`, {data: ids, method: 'DELETE'});
56
- return {data: ids};
57
- },
58
-
59
- getMany: (resource, {ids}) => {
60
- return methods.getList(resource, {filter: {id: {"$in": ids}}});
61
- },
62
-
63
- getManyReference: async (resource, {target, id, filter, ...opts}) => {
64
- filter = filter || {};
65
- filter[target] = id;
66
- return await methods.getList(resource, {filter, ...opts});
67
- },
68
-
69
- runAction: async (resource, props) => {
70
- let {action, payload, ids, record} = props;
71
- action = action.replace(/^\/+/, '')
72
- if (record) { action = action.replace(/\{([^}]+)\}/, (_, field) => record[field]) }
73
- const {json} = await makeRequest(`${apiUrl}/${action}`, {query: {ids}, method: 'POST', data: payload});
74
- return {data: json};
75
- },
76
-
77
- };
78
-
79
- return methods;
80
-
81
- }
@@ -1,25 +0,0 @@
1
- import React from 'react';
2
-
3
- import get from 'lodash/get';
4
- import { useRecordContext } from 'ra-core';
5
- import Avatar from '@material-ui/core/Avatar';
6
-
7
-
8
- const AvatarField = ({ source, record, alt, style, nameProp, ...props }) => {
9
-
10
- let sourceValue = get(record, source),
11
- letters = null,
12
- name = record[nameProp];
13
-
14
- if (name) letters = name.trim(' ').split(/\s+/).slice(0, 2).map( n => n[0].toUpperCase() ).join('');
15
-
16
- return <Avatar src={ record[source] } alt={ alt } style={ style }>{ letters }</Avatar>
17
-
18
- }
19
-
20
- AvatarField.displayName = 'AvatarField';
21
- AvatarField.defaultProps = {
22
- addLabel: true,
23
- }
24
-
25
- export default AvatarField;
@@ -1,24 +0,0 @@
1
- import React from "react";
2
-
3
- import { ReferenceField, TextField } from 'react-admin'
4
-
5
- const FKField = ({refSource, refID, link, ...props}) => {
6
- return (
7
- <ReferenceField link={ link || 'show' } { ...props }>
8
- <>
9
- <TextField source={ refSource } />
10
- { " (#" }
11
- <TextField source={ refID || 'id' } />
12
- { ")" }
13
- </>
14
- </ReferenceField>
15
- )
16
- }
17
-
18
- FKField.displayName = 'FKField';
19
- FKField.defaultProps = {
20
- addLabel: true,
21
- };
22
-
23
- export default FKField;
24
-
package/index.js DELETED
@@ -1,12 +0,0 @@
1
- import ReactDOM from 'react-dom';
2
-
3
- import { setupAdmin, processAdmin } from './utils.js'
4
-
5
- import './admin.jsx';
6
-
7
-
8
- let initAdmin = globalThis.initAdmin = (props) => ReactDOM.render(processAdmin('admin', props), document.getElementById('root'))
9
-
10
- export { setupAdmin, processAdmin }
11
-
12
- export default initAdmin
@@ -1,30 +0,0 @@
1
- import React from "react";
2
-
3
- import { ReferenceInput, AutocompleteInput } from 'react-admin'
4
-
5
-
6
- const FKInput = ({refProp, refSource, ...props}) => {
7
-
8
- let filterToQuery = search => {
9
- let filters = {};
10
- filters[refProp] = search;
11
- return filters;
12
- }
13
-
14
- refSource = refSource || 'id';
15
-
16
- let renderText = record => {
17
- let pk = record[refSource];
18
- return pk && `${record[refProp]} (#${pk})` || "";
19
- }
20
-
21
- return (
22
- <ReferenceInput { ...props } filterToQuery={ filterToQuery }>
23
- <AutocompleteInput source={ refSource } optionText={ renderText } />
24
- </ReferenceInput>
25
- )
26
-
27
-
28
- }
29
-
30
- export default FKInput;
package/resources.jsx DELETED
@@ -1,27 +0,0 @@
1
- import React from "react";
2
-
3
- import { Resource } from "react-admin";
4
- import * as icons from "@material-ui/icons"
5
-
6
- import { checkParams, processAdmin, initRAItems, setupAdmin } from './utils'
7
-
8
- import './views/list.jsx'
9
- import './views/show.jsx'
10
- import './views/edit.jsx'
11
- import './views/create.jsx'
12
-
13
-
14
- // Initialize Resources Components
15
- setupAdmin('resources', resources => resources.map(res => processAdmin('resource', res, res.name)));
16
-
17
- // Initialize a resource's component
18
- setupAdmin('resource', checkParams((props, res) => {
19
- let { create, edit, icon, list, name, show, ...resProps } = props;
20
-
21
- return <Resource key={ name } name={ name } icon={ icons[icon] }
22
- create={ processAdmin('create', create, res) }
23
- edit={ processAdmin('edit', edit, res) }
24
- list={ processAdmin('list', list, res) }
25
- show={ processAdmin('show', show, res) }
26
- { ...resProps } />;
27
- }));
package/ui.jsx DELETED
@@ -1,51 +0,0 @@
1
- import React from "react";
2
-
3
- import { required } from 'react-admin';
4
- import { BooleanField, ChipField, DateField, EmailField, ImageField, FileField, NumberField, RichTextField, TextField, UrlField, SelectField, ArrayField, ReferenceField, ReferenceManyField, ReferenceArrayField } from "react-admin";
5
- import { BooleanInput, NullableBooleanInput, DateInput, DateTimeInput, ImageInput, FileInput, NumberInput, PasswordInput, TextInput, AutocompleteInput, RadioButtonGroupInput, SelectInput, ArrayInput, AutocompleteArrayInput, CheckboxGroupInput, ReferenceArrayInput, ReferenceInput } from "react-admin";
6
- import { JsonField, JsonInput } from "react-admin-json-view";
7
-
8
- import AvatarField from "./fields/AvatarField.jsx"
9
- import FKField from "./fields/FKField.jsx"
10
- import FKInput from "./inputs/FKInput.jsx"
11
-
12
-
13
- // Fix JsonField
14
- JsonField.displayName = 'JsonField';
15
- JsonField.defaultProps = {
16
- addLabel: true,
17
- };
18
-
19
- const ui = {
20
-
21
- // Fields
22
- BooleanField, ChipField, DateField, EmailField, ImageField, FileField,
23
- NumberField, RichTextField, TextField, UrlField, SelectField, ArrayField,
24
- ReferenceField, ReferenceManyField, ReferenceArrayField, AvatarField,
25
- JsonField, FKField,
26
-
27
- // Inputs
28
- BooleanInput, NullableBooleanInput, DateInput, DateTimeInput, ImageInput,
29
- FileInput, NumberInput, PasswordInput, TextInput, AutocompleteInput,
30
- RadioButtonGroupInput, SelectInput, ArrayInput, AutocompleteArrayInput,
31
- CheckboxGroupInput, ReferenceArrayInput, ReferenceInput, JsonInput, FKInput,
32
-
33
- }
34
-
35
- const initRAItems = itemsProps => itemsProps.map((item) => {
36
- const Item = ui[item[0]],
37
- props = {...item[1]};
38
-
39
- if (props.required) {
40
- props.validate = required();
41
- delete props.required
42
- }
43
-
44
- props.fullWidth = props.fullWidth ?? true
45
-
46
- if (props.children) props.children = initRAItems(props.children)[0];
47
-
48
- return <Item key={ props.source } { ...props } />
49
- })
50
-
51
- export default initRAItems
package/utils.js DELETED
@@ -1,35 +0,0 @@
1
- import React from "react";
2
-
3
- import { fetchUtils } from 'ra-core';
4
- import { stringify } from 'query-string';
5
- import { required } from 'react-admin';
6
-
7
-
8
- const admin = globalThis.admin = globalThis.admin || {};
9
-
10
- export const setupAdmin = globalThis.setupAdmin = (type, fn) => admin[type] = fn
11
- export const checkParams = (fn) => (props, res) => {
12
- if (!props || React.isValidElement(props)) return props;
13
- return fn(props, res);
14
- }
15
- export const processAdmin = (type, props, res) => {
16
- let callbacks = [], result = props;
17
-
18
- if (process.env.NODE_ENV == 'development') console.log(`${type}${ res ? '-' + res : ''}`, props);
19
-
20
- if (admin[`${type}-${res}`]) return admin[`${type}-${res}`](props, res);
21
- if (admin[type]) return admin[type](props, res);
22
- }
23
-
24
- export const requestHeaders = {};
25
-
26
- export const makeRequest = (url, params) => {
27
- let {data, query, ...opts} = params || {};
28
-
29
- if (data) opts.body = JSON.stringify(data);
30
- if (query) url = `${url}?${stringify(query)}`;
31
-
32
- opts = {...opts, headers: new Headers({...requestHeaders, ...opts.headers})}
33
-
34
- return fetchUtils.fetchJson(url, opts);
35
- }
package/views/create.jsx DELETED
@@ -1,26 +0,0 @@
1
- import React from "react";
2
-
3
- import { Create, SimpleForm, TopToolbar, ListButton } from "react-admin";
4
-
5
- import initRAItems from '../ui.jsx'
6
- import { checkParams, processAdmin, setupAdmin } from '../utils'
7
-
8
-
9
- // Initialize a create component
10
- setupAdmin('create', checkParams((inputs, res) => props => {
11
-
12
- const Actions = ({basePath}) => (
13
- <TopToolbar>
14
- <ListButton basePath={ basePath } />
15
- </TopToolbar>
16
- )
17
-
18
- return (
19
- <Create actions={ <Actions /> } {...props}>
20
- <SimpleForm children={ processAdmin('create-inputs', inputs, res) } />
21
- </Create>
22
- )
23
- }
24
- ));
25
- setupAdmin('create-inputs', initRAItems);
26
-
package/views/edit.jsx DELETED
@@ -1,34 +0,0 @@
1
- import React from "react";
2
-
3
- import { Edit, ListButton, ShowButton, SimpleForm, TopToolbar } from "react-admin";
4
-
5
- import initRAItems from '../ui.jsx'
6
- import { checkParams, processAdmin, setupAdmin } from '../utils'
7
-
8
- import { ActionButton } from '../buttons/ActionButton.jsx'
9
-
10
-
11
- // Initialize an edit component
12
- setupAdmin('edit', checkParams(({actions, inputs}, res) => props => {
13
-
14
- const Actions = ({basePath, data, resource, ...baseProps}) => (
15
- <TopToolbar>
16
- {
17
- actions.map((props, idx) => {
18
- let aProps = {resource, basePath, ...baseProps, ...props};
19
- return <ActionButton key={ idx } {...aProps} />
20
- })
21
- }
22
- <ListButton basePath={ basePath } />
23
- <ShowButton basePath={basePath} record={data} />
24
- </TopToolbar>
25
- )
26
-
27
- return (
28
- <Edit actions={ <Actions /> } { ...props }>
29
- <SimpleForm children={ processAdmin('edit-inputs', inputs, res) } />
30
- </Edit>
31
- )
32
- }));
33
-
34
- setupAdmin('edit-inputs', initRAItems);