chore: menu permissions & plugins setting permissions (#3822)
* chore: menu permissions * chore: plugins setting permissions * chore: plugins setting permissions * chore: plugins setting permissions
This commit is contained in:
parent
d04a60d386
commit
d3bd0c71dd
@ -5,11 +5,12 @@ import { Checkbox, message } from 'antd';
|
||||
import uniq from 'lodash/uniq';
|
||||
import React, { useContext, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { uid } from '@formily/shared';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { RolesManagerContext } from '../RolesManagerProvider';
|
||||
import { StrategyActions } from './StrategyActions';
|
||||
import { useACLTranslation } from '../locale';
|
||||
import { uid } from '@formily/shared';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { PluginPermissions } from './PluginPermissions';
|
||||
|
||||
const SnippetCheckboxGroup = connect((props) => {
|
||||
const { t } = useTranslation();
|
||||
@ -61,25 +62,8 @@ export const GeneralPermissions: React.FC<{
|
||||
const { role, setRole } = useContext(RolesManagerContext);
|
||||
const { t } = useACLTranslation();
|
||||
const api = useAPIClient();
|
||||
const { data } = useRequest(
|
||||
() =>
|
||||
api
|
||||
.resource('roles')
|
||||
.get({
|
||||
filterByTk: role?.name,
|
||||
})
|
||||
.then((res) => {
|
||||
const record = res?.data?.data;
|
||||
record.snippets?.forEach((key: string) => {
|
||||
record[key] = true;
|
||||
});
|
||||
return record;
|
||||
}),
|
||||
{
|
||||
ready: active,
|
||||
refreshDeps: [role?.name],
|
||||
},
|
||||
);
|
||||
const pm = role?.snippets?.includes('pm.*');
|
||||
|
||||
const update = useMemoizedFn(async (form: Form) => {
|
||||
await api.resource('roles').update({
|
||||
filterByTk: role.name,
|
||||
@ -90,37 +74,48 @@ export const GeneralPermissions: React.FC<{
|
||||
});
|
||||
const form = useMemo(() => {
|
||||
return createForm({
|
||||
values: data,
|
||||
values: role,
|
||||
effects() {
|
||||
onFormValuesChange(async (form) => {
|
||||
await update(form);
|
||||
});
|
||||
},
|
||||
});
|
||||
}, [data, update]);
|
||||
}, [role, update]);
|
||||
|
||||
return (
|
||||
<SchemaComponent
|
||||
components={{ SnippetCheckboxGroup, StrategyActions }}
|
||||
components={{ SnippetCheckboxGroup, StrategyActions, PluginPermissions }}
|
||||
scope={{ pm }}
|
||||
schema={{
|
||||
type: 'void',
|
||||
name: uid(),
|
||||
'x-component': 'FormV2',
|
||||
'x-component-props': {
|
||||
form,
|
||||
},
|
||||
'x-component': 'div',
|
||||
properties: {
|
||||
snippets: {
|
||||
title: t('Configure permissions'),
|
||||
type: 'boolean',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'SnippetCheckboxGroup',
|
||||
general: {
|
||||
'x-component': 'FormV2',
|
||||
'x-component-props': {
|
||||
form,
|
||||
},
|
||||
properties: {
|
||||
snippets: {
|
||||
title: t('Configure permissions'),
|
||||
type: 'boolean',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'SnippetCheckboxGroup',
|
||||
},
|
||||
},
|
||||
},
|
||||
allowNewMenu: {
|
||||
title: t('Menu permissions'),
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Checkbox',
|
||||
'x-content': t('New menu items are allowed to be accessed by default.'),
|
||||
plugins: {
|
||||
'x-component': 'FormV2',
|
||||
properties: {
|
||||
pluginSettings: {
|
||||
title: t('Plugin settings'),
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'PluginPermissions',
|
||||
'x-visible': '{{pm}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
|
@ -1,9 +1,12 @@
|
||||
import { Checkbox, message, Table } from 'antd';
|
||||
import { onFormValuesChange, createForm, Form } from '@formily/core';
|
||||
import { uniq } from 'lodash';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import React, { useContext, useState, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { uid } from '@formily/shared';
|
||||
import { useAPIClient, SchemaComponent, useRequest } from '@nocobase/client';
|
||||
import { useStyles } from './style';
|
||||
import { useAPIClient, useCollectionRecord, useRequest } from '@nocobase/client';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { RolesManagerContext } from '../RolesManagerProvider';
|
||||
import { useMenuItems } from './MenuItemsProvider';
|
||||
|
||||
@ -43,7 +46,7 @@ export const MenuPermissions: React.FC<{
|
||||
active: boolean;
|
||||
}> = ({ active }) => {
|
||||
const { styles } = useStyles();
|
||||
const { role } = useContext(RolesManagerContext);
|
||||
const { role, setRole } = useContext(RolesManagerContext);
|
||||
const api = useAPIClient();
|
||||
const { items } = useMenuItems();
|
||||
const { t } = useTranslation();
|
||||
@ -107,51 +110,89 @@ export const MenuPermissions: React.FC<{
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const update = useMemoizedFn(async (form: Form) => {
|
||||
await api.resource('roles').update({
|
||||
filterByTk: role.name,
|
||||
values: form.values,
|
||||
});
|
||||
setRole({ ...role, ...form.values });
|
||||
message.success(t('Saved successfully'));
|
||||
});
|
||||
const form = useMemo(() => {
|
||||
return createForm({
|
||||
values: role,
|
||||
effects() {
|
||||
onFormValuesChange(async (form) => {
|
||||
await update(form);
|
||||
});
|
||||
},
|
||||
});
|
||||
}, [role, update]);
|
||||
return (
|
||||
<Table
|
||||
className={styles}
|
||||
loading={loading}
|
||||
rowKey={'uid'}
|
||||
pagination={false}
|
||||
expandable={{
|
||||
defaultExpandAllRows: true,
|
||||
}}
|
||||
columns={[
|
||||
{
|
||||
dataIndex: 'title',
|
||||
title: t('Menu item title'),
|
||||
},
|
||||
{
|
||||
dataIndex: 'accessible',
|
||||
title: (
|
||||
<>
|
||||
<Checkbox
|
||||
checked={allChecked}
|
||||
onChange={async (value) => {
|
||||
if (allChecked) {
|
||||
await resource.set({
|
||||
values: [],
|
||||
});
|
||||
} else {
|
||||
await resource.set({
|
||||
values: allUids,
|
||||
});
|
||||
}
|
||||
refresh();
|
||||
message.success(t('Saved successfully'));
|
||||
}}
|
||||
/>{' '}
|
||||
{t('Accessible')}
|
||||
</>
|
||||
),
|
||||
render: (_, schema) => {
|
||||
const checked = uids.includes(schema.uid);
|
||||
return <Checkbox checked={checked} onChange={() => handleChange(checked, schema)} />;
|
||||
<>
|
||||
<SchemaComponent
|
||||
schema={{
|
||||
type: 'void',
|
||||
name: uid(),
|
||||
'x-component': 'FormV2',
|
||||
'x-component-props': {
|
||||
form,
|
||||
},
|
||||
},
|
||||
]}
|
||||
dataSource={translateTitle(items)}
|
||||
/>
|
||||
properties: {
|
||||
allowNewMenu: {
|
||||
title: t('Menu permissions'),
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Checkbox',
|
||||
'x-content': t('New menu items are allowed to be accessed by default.'),
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
<Table
|
||||
className={styles}
|
||||
loading={loading}
|
||||
rowKey={'uid'}
|
||||
pagination={false}
|
||||
expandable={{
|
||||
defaultExpandAllRows: true,
|
||||
}}
|
||||
columns={[
|
||||
{
|
||||
dataIndex: 'title',
|
||||
title: t('Menu item title'),
|
||||
},
|
||||
{
|
||||
dataIndex: 'accessible',
|
||||
title: (
|
||||
<>
|
||||
<Checkbox
|
||||
checked={allChecked}
|
||||
onChange={async (value) => {
|
||||
if (allChecked) {
|
||||
await resource.set({
|
||||
values: [],
|
||||
});
|
||||
} else {
|
||||
await resource.set({
|
||||
values: allUids,
|
||||
});
|
||||
}
|
||||
refresh();
|
||||
message.success(t('Saved successfully'));
|
||||
}}
|
||||
/>{' '}
|
||||
{t('Accessible')}
|
||||
</>
|
||||
),
|
||||
render: (_, schema) => {
|
||||
const checked = uids.includes(schema.uid);
|
||||
return <Checkbox checked={checked} onChange={() => handleChange(checked, schema)} />;
|
||||
},
|
||||
},
|
||||
]}
|
||||
dataSource={translateTitle(items)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useApp } from '@nocobase/client';
|
||||
import { useApp, useRequest, useAPIClient } from '@nocobase/client';
|
||||
import { Tabs } from 'antd';
|
||||
import React, { useContext, useEffect, useMemo } from 'react';
|
||||
import { RolesManagerContext } from '../RolesManagerProvider';
|
||||
@ -7,7 +7,6 @@ import { AvailableActionsProvider } from './AvailableActions';
|
||||
import { GeneralPermissions } from './GeneralPermissions';
|
||||
import { MenuItemsProvider } from './MenuItemsProvider';
|
||||
import { MenuPermissions } from './MenuPermissions';
|
||||
import { PluginPermissions } from './PluginPermissions';
|
||||
|
||||
const TabLayout: React.FC = (props) => {
|
||||
return <div style={{ maxHeight: '60vh', overflowY: 'auto' }}>{props.children}</div>;
|
||||
@ -16,7 +15,7 @@ const TabLayout: React.FC = (props) => {
|
||||
export const Permissions: React.FC<{ active: boolean }> = ({ active }) => {
|
||||
const { t } = useACLTranslation();
|
||||
const [activeKey, setActiveKey] = React.useState('general');
|
||||
const { role } = useContext(RolesManagerContext);
|
||||
const { role, setRole } = useContext(RolesManagerContext);
|
||||
const pm = role?.snippets?.includes('pm.*');
|
||||
const app = useApp();
|
||||
const DataSourcePermissionManager = app.getComponent('DataSourcePermissionManager');
|
||||
@ -25,7 +24,7 @@ export const Permissions: React.FC<{ active: boolean }> = ({ active }) => {
|
||||
() => [
|
||||
{
|
||||
key: 'general',
|
||||
label: t('General'),
|
||||
label: t('System'),
|
||||
children: (
|
||||
<TabLayout>
|
||||
<GeneralPermissions active={activeKey === 'general' && active} />
|
||||
@ -43,19 +42,6 @@ export const Permissions: React.FC<{ active: boolean }> = ({ active }) => {
|
||||
</TabLayout>
|
||||
),
|
||||
},
|
||||
...(pm
|
||||
? [
|
||||
{
|
||||
key: 'plugin',
|
||||
label: t('Plugin settings'),
|
||||
children: (
|
||||
<TabLayout>
|
||||
<PluginPermissions active={activeKey === 'plugin' && active} />
|
||||
</TabLayout>
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(DataSourcePermissionManager
|
||||
? [
|
||||
{
|
||||
@ -74,10 +60,33 @@ export const Permissions: React.FC<{ active: boolean }> = ({ active }) => {
|
||||
],
|
||||
[pm, activeKey, active, t],
|
||||
);
|
||||
|
||||
const api = useAPIClient();
|
||||
const { data } = useRequest(
|
||||
() =>
|
||||
api
|
||||
.resource('roles')
|
||||
.get({
|
||||
filterByTk: role?.name,
|
||||
})
|
||||
.then((res) => {
|
||||
const record = res?.data?.data;
|
||||
record.snippets?.forEach((key: string) => {
|
||||
record[key] = true;
|
||||
});
|
||||
return record;
|
||||
}),
|
||||
{
|
||||
ready: active && !!role,
|
||||
refreshDeps: [role?.name],
|
||||
},
|
||||
);
|
||||
useEffect(() => {
|
||||
setActiveKey('general');
|
||||
}, [role?.name]);
|
||||
|
||||
useEffect(() => {
|
||||
setRole(data);
|
||||
}, [data]);
|
||||
return (
|
||||
<AvailableActionsProvider>
|
||||
<Tabs type="card" activeKey={activeKey} onChange={(key) => setActiveKey(key)} items={items} />
|
||||
|
@ -38,7 +38,7 @@ export const PluginPermissions: React.FC<{
|
||||
const compile = useCompile();
|
||||
const settings = app.pluginSettingsManager.getList(false);
|
||||
const allAclSnippets = app.pluginSettingsManager.getAclSnippets();
|
||||
const [snippets, setSnippets] = useState<string[]>([]);
|
||||
const [snippets, setSnippets] = useState<string[]>(role?.snippets || []);
|
||||
const flatPlugins = useMemo(() => {
|
||||
return flatMap(settings, (item) => {
|
||||
if (item.children) {
|
||||
@ -52,12 +52,11 @@ export const PluginPermissions: React.FC<{
|
||||
() => snippets.includes('pm.*') && snippets.every((item) => !item.startsWith('!pm.')),
|
||||
[snippets],
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { loading, refresh } = useRequest(
|
||||
{
|
||||
resource: 'roles.snippets',
|
||||
resourceOf: role.name,
|
||||
resourceOf: role?.name,
|
||||
action: 'list',
|
||||
params: {
|
||||
paginate: false,
|
||||
@ -66,6 +65,7 @@ export const PluginPermissions: React.FC<{
|
||||
{
|
||||
ready: !!role && active,
|
||||
refreshDeps: [role?.name],
|
||||
manual: true,
|
||||
onSuccess(data) {
|
||||
setSnippets(
|
||||
data?.data.filter((v) => {
|
||||
@ -75,7 +75,10 @@ export const PluginPermissions: React.FC<{
|
||||
},
|
||||
},
|
||||
);
|
||||
const resource = api.resource('roles.snippets', role.name);
|
||||
if (!role) {
|
||||
return;
|
||||
}
|
||||
const resource = api.resource('roles.snippets', role?.name);
|
||||
const handleChange = async (checked, record) => {
|
||||
const childrenKeys = getChildrenKeys(record?.children, []);
|
||||
const totalKeys = childrenKeys.concat(record.aclSnippet);
|
||||
@ -129,7 +132,7 @@ export const PluginPermissions: React.FC<{
|
||||
refresh();
|
||||
message.success(t('Saved successfully'));
|
||||
}}
|
||||
/>{' '}
|
||||
/>
|
||||
{t('Accessible')}
|
||||
</>
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user