feat(menu): when a group is selected, the submenu items are also selected together (#1152)
This commit is contained in:
parent
34a900820b
commit
7d32886bb0
@ -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)} />;
|
||||
},
|
||||
},
|
||||
]}
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
@ -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>
|
||||
);
|
||||
|
@ -266,6 +266,7 @@ export const roleSchema: ISchema = {
|
||||
'x-component-props': {},
|
||||
properties: {
|
||||
menu: {
|
||||
'x-decorator': 'MenuItemsProvider',
|
||||
'x-component': 'MenuConfigure',
|
||||
},
|
||||
},
|
||||
|
@ -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],
|
||||
|
Loading…
Reference in New Issue
Block a user