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:
katherinehhh 2024-03-27 12:03:24 +08:00 committed by GitHub
parent d04a60d386
commit d3bd0c71dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 156 additions and 108 deletions

View File

@ -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,21 +74,25 @@ 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': 'div',
properties: {
general: {
'x-component': 'FormV2',
'x-component-props': {
form,
@ -116,11 +104,18 @@ export const GeneralPermissions: React.FC<{
'x-decorator': 'FormItem',
'x-component': 'SnippetCheckboxGroup',
},
allowNewMenu: {
title: t('Menu permissions'),
},
},
plugins: {
'x-component': 'FormV2',
properties: {
pluginSettings: {
title: t('Plugin settings'),
'x-decorator': 'FormItem',
'x-component': 'Checkbox',
'x-content': t('New menu items are allowed to be accessed by default.'),
'x-component': 'PluginPermissions',
'x-visible': '{{pm}}',
},
},
},
},
}}

View File

@ -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,8 +110,45 @@ 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 (
<>
<SchemaComponent
schema={{
type: 'void',
name: uid(),
'x-component': 'FormV2',
'x-component-props': {
form,
},
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}
@ -153,5 +193,6 @@ export const MenuPermissions: React.FC<{
]}
dataSource={translateTitle(items)}
/>
</>
);
};

View File

@ -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} />

View File

@ -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')}
</>
),