feat(menu): when a group is selected, the submenu items are also selected together (#1152)

This commit is contained in:
katherinehhh 2022-12-02 22:43:51 +08:00 committed by GitHub
parent 34a900820b
commit 7d32886bb0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 106 additions and 65 deletions

View File

@ -3,8 +3,8 @@ import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useAPIClient, useRequest } from '../../api-client';
import { useRecord } from '../../record-provider';
import { useCompile } from '../../schema-component';
import { useMenuItems } from './RoleTable';
import { uniq } from 'lodash';
import { useMenuItems } from './MenuItemsProvider';
const findUids = (items) => {
if (!Array.isArray(items)) {
@ -17,12 +17,31 @@ const findUids = (items) => {
}
return uids;
};
const getParentUids = (tree, func, path = []) => {
if (!tree) return [];
for (const data of tree) {
path.push(data.uid);
if (func(data)) return path;
if (data.children) {
const findChildren = getParentUids(data.children, func, path);
if (findChildren.length) return findChildren;
}
path.pop();
}
return [];
};
const getChildrenUids = (data = [], arr = []) => {
for (let item of data) {
arr.push(item.uid);
if (item.children && item.children.length) getChildrenUids(item.children, arr);
}
return arr;
};
export const MenuConfigure = () => {
const record = useRecord();
const api = useAPIClient();
const items = useMenuItems();
const compile = useCompile();
const { items } = useMenuItems();
const { t } = useTranslation();
const allUids = findUids(items);
const [uids, setUids] = useState([]);
@ -43,6 +62,28 @@ export const MenuConfigure = () => {
);
const resource = api.resource('roles.menuUiSchemas', record.name);
const allChecked = allUids.length === uids.length;
const handleChange = async (checked, schema) => {
const parentUids = getParentUids(items, (data) => data.uid === schema.uid);
const childrenUids = getChildrenUids(schema?.children, []);
if (checked) {
const totalUids = childrenUids.concat(schema.uid);
const newUids = uids.filter((v) => !totalUids.includes(v));
setUids([...newUids]);
await resource.remove({
values: totalUids,
});
} else {
const totalUids = childrenUids.concat(parentUids);
setUids((prev) => {
return uniq([...prev, ...totalUids]);
});
await resource.add({
values: totalUids,
});
}
message.success(t('Saved successfully'));
};
return (
<Table
loading={loading}
@ -75,32 +116,13 @@ export const MenuConfigure = () => {
refresh();
message.success(t('Saved successfully'));
}}
/>{' '}
/>
{t('Accessible')}
</>
),
render: (_, schema) => {
const checked = uids.includes(schema.uid);
return (
<Checkbox
checked={checked}
onChange={async (e) => {
if (checked) {
const index = uids.indexOf(schema.uid);
uids.splice(index, 1);
setUids([...uids]);
} else {
setUids((prev) => [...prev, schema.uid]);
}
await resource.toggle({
values: {
tk: schema.uid,
},
});
message.success(t('Saved successfully'));
}}
/>
);
return <Checkbox checked={checked} onChange={() => handleChange(checked, schema)} />;
},
},
]}

View File

@ -0,0 +1,50 @@
import { Spin } from 'antd';
import React, { createContext, useContext } from 'react';
import { useRequest, useAPIClient } from '../../api-client';
import { useRoute } from '../../route-switch';
const MenuItemsContext = createContext(null);
export const toItems = (properties = {}) => {
const items = [];
for (const key in properties) {
if (Object.prototype.hasOwnProperty.call(properties, key)) {
const element = properties[key];
const item = {
title: element.title,
uid: element['x-uid'],
};
if (element.properties) {
item['children'] = toItems(element.properties);
}
items.push(item);
}
}
return items;
};
export const useMenuItems = () => {
return useContext(MenuItemsContext);
};
export const MenuItemsProvider = (props) => {
const route = useRoute();
const options = {
url: `uiSchemas:getProperties/${route.uiSchemaUid}`,
};
const service = useRequest(options);
if (service.loading) {
return <Spin />;
}
const items = toItems(service.data?.data?.properties);
return (
<MenuItemsContext.Provider
value={{
service: service,
items,
}}
>
{props.children}
</MenuItemsContext.Provider>
);
};

View File

@ -1,30 +1,11 @@
import { Spin } from 'antd';
import React, { createContext, useContext } from 'react';
import { useRequest } from '../../api-client';
import { useRoute } from '../../route-switch';
import { SchemaComponent } from '../../schema-component';
import { roleSchema } from './schemas/roles';
const toItems = (properties = {}) => {
const items = [];
for (const key in properties) {
if (Object.prototype.hasOwnProperty.call(properties, key)) {
const element = properties[key];
const item = {
title: element.title,
uid: element['x-uid'],
};
if (element.properties) {
item['children'] = toItems(element.properties);
}
items.push(item);
}
}
return items;
};
import { MenuItemsProvider } from '../Configuration/MenuItemsProvider';
const AvailableActionsContext = createContext(null);
const MenuItemsContext = createContext(null);
const AvailableActionsProver: React.FC = (props) => {
const { data, loading } = useRequest({
@ -37,33 +18,15 @@ const AvailableActionsProver: React.FC = (props) => {
return <AvailableActionsContext.Provider value={data?.data}>{props.children}</AvailableActionsContext.Provider>;
};
const MenuItemsProver: React.FC = (props) => {
const route = useRoute();
const { loading, data } = useRequest({
url: `uiSchemas:getProperties/${route.uiSchemaUid}`,
});
if (loading) {
return <Spin />;
}
const items = toItems(data?.data?.properties);
return <MenuItemsContext.Provider value={items}>{props.children}</MenuItemsContext.Provider>;
};
export const useAvailableActions = () => {
return useContext(AvailableActionsContext);
};
export const useMenuItems = () => {
return useContext(MenuItemsContext);
};
export const RoleTable = () => {
return (
<div>
<AvailableActionsProver>
<MenuItemsProver>
<SchemaComponent schema={roleSchema} />
</MenuItemsProver>
<SchemaComponent schema={roleSchema} components={{ MenuItemsProvider }} />
</AvailableActionsProver>
</div>
);

View File

@ -266,6 +266,7 @@ export const roleSchema: ISchema = {
'x-component-props': {},
properties: {
menu: {
'x-decorator': 'MenuItemsProvider',
'x-component': 'MenuConfigure',
},
},

View File

@ -362,7 +362,12 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
}
async runAsCLI(argv = process.argv, options?: ParseOptions) {
await this.db.auth({ retry: 30 });
try {
await this.db.auth({ retry: 30 });
} catch (error) {
console.log(chalk.red(error.message));
process.exit(1);
}
await this.dbVersionCheck({ exit: true });
await this.load({
method: argv?.[2],