mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 01:36:52 +00:00
refactor(plugin-acl): extensible support for role permissions configuration UI (#5216)
This commit is contained in:
parent
2459991fbb
commit
44275b5cd7
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* This file is part of the NocoBase (R) project.
|
||||
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||
* Authors: NocoBase Team.
|
||||
*
|
||||
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { TabsProps } from 'antd/es/tabs/index';
|
||||
import React from 'react';
|
||||
import { GeneralPermissions } from './permissions/GeneralPermissions';
|
||||
import { MenuItemsProvider } from './permissions/MenuItemsProvider';
|
||||
import { MenuPermissions } from './permissions/MenuPermissions';
|
||||
import { Role } from './RolesManagerProvider';
|
||||
|
||||
interface PermissionsTabsProps {
|
||||
/**
|
||||
* the key of the currently active tab panel
|
||||
*/
|
||||
activeKey: string;
|
||||
/**
|
||||
* the currently selected role
|
||||
*/
|
||||
role: Role;
|
||||
/**
|
||||
* translation function
|
||||
*/
|
||||
t: (key: string) => string;
|
||||
/**
|
||||
* used to constrain the size of the container in the Tab
|
||||
*/
|
||||
TabLayout: React.FC;
|
||||
}
|
||||
|
||||
type Tab = TabsProps['items'][0];
|
||||
|
||||
type TabCallback = (props: PermissionsTabsProps) => Tab;
|
||||
|
||||
/**
|
||||
* the extension API for ACL settings page
|
||||
*/
|
||||
export class ACLSettingsUI {
|
||||
private permissionsTabs: (Tab | TabCallback)[] = [
|
||||
({ t, TabLayout }) => ({
|
||||
key: 'general',
|
||||
label: t('System'),
|
||||
children: (
|
||||
<TabLayout>
|
||||
<GeneralPermissions />
|
||||
</TabLayout>
|
||||
),
|
||||
}),
|
||||
({ activeKey, t, TabLayout }) => ({
|
||||
key: 'menu',
|
||||
label: t('Menu'),
|
||||
children: (
|
||||
<TabLayout>
|
||||
<MenuItemsProvider>
|
||||
<MenuPermissions active={activeKey === 'menu'} />
|
||||
</MenuItemsProvider>
|
||||
</TabLayout>
|
||||
),
|
||||
}),
|
||||
];
|
||||
|
||||
addPermissionsTab(tab: Tab | TabCallback): void {
|
||||
this.permissionsTabs.push(tab);
|
||||
}
|
||||
|
||||
getPermissionsTabs(props: PermissionsTabsProps): Tab[] {
|
||||
return this.permissionsTabs.map((tab) => {
|
||||
if (typeof tab === 'function') {
|
||||
return tab(props);
|
||||
}
|
||||
return tab;
|
||||
});
|
||||
}
|
||||
}
|
@ -9,9 +9,25 @@
|
||||
|
||||
import { createContext } from 'react';
|
||||
|
||||
export interface Role {
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
name: string;
|
||||
title: string;
|
||||
description: string;
|
||||
strategy: {
|
||||
actions: string[];
|
||||
};
|
||||
default: boolean;
|
||||
hidden: boolean;
|
||||
allowConfigure: boolean;
|
||||
allowNewMenu: boolean;
|
||||
snippets: string[];
|
||||
}
|
||||
|
||||
export const RolesManagerContext = createContext<{
|
||||
role: any;
|
||||
setRole: (role: any) => void;
|
||||
role: Role;
|
||||
setRole: (role: Role) => void;
|
||||
}>({
|
||||
role: null,
|
||||
} as any);
|
||||
|
@ -8,11 +8,13 @@
|
||||
*/
|
||||
|
||||
import { Plugin } from '@nocobase/client';
|
||||
import { ACLSettingsUI } from './ACLSettingsUI';
|
||||
import { RolesManagement } from './RolesManagement';
|
||||
import { RolesManager } from './roles-manager';
|
||||
|
||||
export class PluginACLClient extends Plugin {
|
||||
rolesManager = new RolesManager();
|
||||
settingsUI = new ACLSettingsUI();
|
||||
|
||||
async load() {
|
||||
this.pluginSettingsManager.add('users-permissions.roles', {
|
||||
|
@ -7,19 +7,19 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { onFormValuesChange, createForm, Form, onFieldChange } from '@formily/core';
|
||||
import { createForm, Form, onFormValuesChange } from '@formily/core';
|
||||
import { connect } from '@formily/react';
|
||||
import { SchemaComponent, useAPIClient, useRequest } from '@nocobase/client';
|
||||
import { uid } from '@formily/shared';
|
||||
import { SchemaComponent, useAPIClient } from '@nocobase/client';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
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 { RolesManagerContext } from '../RolesManagerProvider';
|
||||
import { PluginPermissions } from './PluginPermissions';
|
||||
import { StrategyActions } from './StrategyActions';
|
||||
|
||||
const SnippetCheckboxGroup = connect((props) => {
|
||||
const { t } = useTranslation();
|
||||
@ -65,9 +65,7 @@ const SnippetCheckboxGroup = connect((props) => {
|
||||
);
|
||||
});
|
||||
|
||||
export const GeneralPermissions: React.FC<{
|
||||
active: boolean;
|
||||
}> = ({ active }) => {
|
||||
export const GeneralPermissions: React.FC = () => {
|
||||
const { role, setRole } = useContext(RolesManagerContext);
|
||||
const { t } = useACLTranslation();
|
||||
const api = useAPIClient();
|
||||
|
@ -7,17 +7,17 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { Checkbox, message, Table } from 'antd';
|
||||
import { onFormValuesChange, createForm, Form } from '@formily/core';
|
||||
import { uniq } from 'lodash';
|
||||
import React, { useContext, useState, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { createForm, Form, onFormValuesChange } from '@formily/core';
|
||||
import { uid } from '@formily/shared';
|
||||
import { useAPIClient, SchemaComponent, useRequest } from '@nocobase/client';
|
||||
import { useStyles } from './style';
|
||||
import { SchemaComponent, useAPIClient, useRequest } from '@nocobase/client';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { Checkbox, message, Table } from 'antd';
|
||||
import { uniq } from 'lodash';
|
||||
import React, { useContext, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { RolesManagerContext } from '../RolesManagerProvider';
|
||||
import { useMenuItems } from './MenuItemsProvider';
|
||||
import { useStyles } from './style';
|
||||
|
||||
const findUids = (items) => {
|
||||
if (!Array.isArray(items)) {
|
||||
|
@ -7,15 +7,13 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { useApp, useRequest, useAPIClient } from '@nocobase/client';
|
||||
import { useAPIClient, usePlugin, useRequest } from '@nocobase/client';
|
||||
import { Tabs } from 'antd';
|
||||
import React, { useContext, useEffect, useMemo } from 'react';
|
||||
import { RolesManagerContext } from '../RolesManagerProvider';
|
||||
import PluginACLClient from '..';
|
||||
import { Role, RolesManagerContext } from '../RolesManagerProvider';
|
||||
import { useACLTranslation } from '../locale';
|
||||
import { AvailableActionsProvider } from './AvailableActions';
|
||||
import { GeneralPermissions } from './GeneralPermissions';
|
||||
import { MenuItemsProvider } from './MenuItemsProvider';
|
||||
import { MenuPermissions } from './MenuPermissions';
|
||||
|
||||
const TabLayout: React.FC = (props) => {
|
||||
return <div style={{ maxHeight: '60vh', overflowY: 'auto' }}>{props.children}</div>;
|
||||
@ -25,52 +23,15 @@ export const Permissions: React.FC<{ active: boolean }> = ({ active }) => {
|
||||
const { t } = useACLTranslation();
|
||||
const [activeKey, setActiveKey] = React.useState('general');
|
||||
const { role, setRole } = useContext(RolesManagerContext);
|
||||
const pm = role?.snippets?.includes('pm.*');
|
||||
const app = useApp();
|
||||
const DataSourcePermissionManager = app.getComponent('DataSourcePermissionManager');
|
||||
const pluginACLClient = usePlugin(PluginACLClient);
|
||||
|
||||
const items = useMemo(
|
||||
() => [
|
||||
{
|
||||
key: 'general',
|
||||
label: t('System'),
|
||||
children: (
|
||||
<TabLayout>
|
||||
<GeneralPermissions active={activeKey === 'general' && active} />
|
||||
</TabLayout>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'menu',
|
||||
label: t('Menu'),
|
||||
children: (
|
||||
<TabLayout>
|
||||
<MenuItemsProvider>
|
||||
<MenuPermissions active={activeKey === 'menu' && active} />
|
||||
</MenuItemsProvider>
|
||||
</TabLayout>
|
||||
),
|
||||
},
|
||||
...(DataSourcePermissionManager
|
||||
? [
|
||||
{
|
||||
key: 'dataSource',
|
||||
label: t('Data sources'),
|
||||
children: (
|
||||
<TabLayout>
|
||||
<MenuItemsProvider>
|
||||
<DataSourcePermissionManager role={role} active={activeKey === 'dataSource' && active} />
|
||||
</MenuItemsProvider>
|
||||
</TabLayout>
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
[pm, activeKey, active, t],
|
||||
() => pluginACLClient.settingsUI.getPermissionsTabs({ t, activeKey, TabLayout, role }),
|
||||
[activeKey, pluginACLClient.settingsUI, role, t],
|
||||
);
|
||||
|
||||
const api = useAPIClient();
|
||||
const { data } = useRequest(
|
||||
const { data } = useRequest<Role>(
|
||||
() =>
|
||||
api
|
||||
.resource('roles')
|
||||
@ -89,13 +50,15 @@ export const Permissions: React.FC<{ active: boolean }> = ({ active }) => {
|
||||
refreshDeps: [role?.name],
|
||||
},
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setActiveKey('general');
|
||||
}, [role?.name]);
|
||||
|
||||
useEffect(() => {
|
||||
setRole(data);
|
||||
}, [data]);
|
||||
}, [data, setRole]);
|
||||
|
||||
return (
|
||||
<AvailableActionsProvider>
|
||||
<Tabs type="card" activeKey={activeKey} onChange={(key) => setActiveKey(key)} items={items} />
|
||||
|
@ -11,7 +11,8 @@
|
||||
"peerDependencies": {
|
||||
"@nocobase/client": "1.x",
|
||||
"@nocobase/server": "1.x",
|
||||
"@nocobase/test": "1.x"
|
||||
"@nocobase/test": "1.x",
|
||||
"@nocobase/plugin-acl": "1.x"
|
||||
},
|
||||
"keywords": [
|
||||
"Data model tools"
|
||||
|
@ -9,20 +9,20 @@
|
||||
|
||||
import { ISchema } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
import {
|
||||
MenuConfigure,
|
||||
ResourceActionProvider,
|
||||
SchemaComponent,
|
||||
SettingCenterProvider,
|
||||
SettingsCenterConfigure,
|
||||
} from '@nocobase/client';
|
||||
import { Card } from 'antd';
|
||||
import React, { createContext } from 'react';
|
||||
import {
|
||||
SchemaComponent,
|
||||
MenuConfigure,
|
||||
SettingsCenterConfigure,
|
||||
SettingCenterProvider,
|
||||
ResourceActionProvider,
|
||||
} from '@nocobase/client';
|
||||
import { DataSourceTable } from './DataSourceTable';
|
||||
import { RoleConfigure } from './RoleConfigure';
|
||||
import { StrategyActions } from './StrategyActions';
|
||||
import { RolesResourcesActions } from './RolesResourcesActions';
|
||||
import { RoleRecordProvider } from './PermisionProvider';
|
||||
import { RoleConfigure } from './RoleConfigure';
|
||||
import { RolesResourcesActions } from './RolesResourcesActions';
|
||||
import { StrategyActions } from './StrategyActions';
|
||||
|
||||
const schema2: ISchema = {
|
||||
type: 'object',
|
||||
@ -36,7 +36,7 @@ const schema2: ISchema = {
|
||||
export const CurrentRolesContext = createContext<any>({} as any);
|
||||
CurrentRolesContext.displayName = 'CurrentRolesContext';
|
||||
|
||||
export const DataSourcePermissionManager = ({ role }: any) => {
|
||||
export const DataSourcePermissionManager = ({ role }) => {
|
||||
return (
|
||||
<Card data-testid="acl-pane-card" bordered={false}>
|
||||
<CurrentRolesContext.Provider value={role}>
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
import { Plugin } from '@nocobase/client';
|
||||
import PluginACLClient from '@nocobase/plugin-acl/client';
|
||||
import React from 'react';
|
||||
import { DatabaseConnectionProvider } from './DatabaseConnectionProvider';
|
||||
import { ThirdDataSource } from './ThridDataSource';
|
||||
@ -21,10 +22,17 @@ import { NAMESPACE } from './locale';
|
||||
export class PluginDataSourceManagerClient extends Plugin {
|
||||
types = new Map();
|
||||
async load() {
|
||||
// 注册组件
|
||||
this.app.addComponents({
|
||||
DataSourcePermissionManager,
|
||||
});
|
||||
// register a configuration item in the Users & Permissions management page
|
||||
this.app.pm.get(PluginACLClient).settingsUI.addPermissionsTab(({ t, TabLayout, role }) => ({
|
||||
key: 'dataSource',
|
||||
label: t('Data sources'),
|
||||
children: (
|
||||
<TabLayout>
|
||||
<DataSourcePermissionManager role={role} />
|
||||
</TabLayout>
|
||||
),
|
||||
}));
|
||||
|
||||
this.app.use(DatabaseConnectionProvider);
|
||||
this.app.pluginSettingsManager.add(NAMESPACE, {
|
||||
title: `{{t("Data sources", { ns: "${NAMESPACE}" })}}`,
|
||||
|
Loading…
Reference in New Issue
Block a user