feat: add acl components

This commit is contained in:
chenos 2022-01-30 19:28:42 +08:00
parent 15950ece05
commit fd130901be
7 changed files with 351 additions and 18 deletions

View File

@ -1,8 +1,10 @@
import React, { useState } from 'react';
import { LockOutlined } from '@ant-design/icons'; import { LockOutlined } from '@ant-design/icons';
import { SchemaComponent, useActionVisible, VisibleContext } from '../schema-component';
import { ISchema, useForm } from '@formily/react'; import { ISchema, useForm } from '@formily/react';
import { uid } from '@formily/shared';
import React, { useState } from 'react';
import { PluginManager } from '../plugin-manager'; import { PluginManager } from '../plugin-manager';
import { SchemaComponent, useActionVisible, VisibleContext } from '../schema-component';
import { RoleTable } from './RolePermissionManager';
const useCloseAction = () => { const useCloseAction = () => {
const { setVisible } = useActionVisible(); const { setVisible } = useActionVisible();
@ -20,28 +22,28 @@ const useCloseAction = () => {
const schema: ISchema = { const schema: ISchema = {
type: 'object', type: 'object',
properties: { properties: {
drawer1: { [uid()]: {
'x-component': 'Action.Drawer', 'x-component': 'Action.Drawer',
type: 'void', type: 'void',
title: 'Drawer Title', title: 'Drawer Title',
properties: { properties: {
hello1: { hello1: {
'x-content': 'Hello',
title: 'T1',
},
footer1: {
'x-component': 'Action.Drawer.Footer',
type: 'void', type: 'void',
properties: { 'x-component': 'RoleTable',
close1: {
title: 'Close',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ useCloseAction }}',
},
},
},
}, },
// footer1: {
// 'x-component': 'Action.Drawer.Footer',
// type: 'void',
// properties: {
// close1: {
// title: 'Close',
// 'x-component': 'Action',
// 'x-component-props': {
// useAction: '{{ useCloseAction }}',
// },
// },
// },
// },
}, },
}, },
}, },
@ -58,7 +60,7 @@ export const ACLShortcut = () => {
setVisible(true); setVisible(true);
}} }}
/> />
<SchemaComponent scope={{ useCloseAction }} schema={schema} /> <SchemaComponent components={{ RoleTable }} scope={{ useCloseAction }} schema={schema} />
</VisibleContext.Provider> </VisibleContext.Provider>
); );
}; };

View File

@ -1 +1,233 @@
import { Button, Checkbox, Divider, Drawer, Space, Table, Tabs, Tag, Typography } from 'antd';
import React, { useState } from 'react';
import { ScopeRecordPicker } from './ScopeRecordPicker';
export function RoleManager() {} export function RoleManager() {}
export const RoleTable = () => {
return (
<div>
<Space style={{ justifyContent: 'flex-end', width: '100%', marginBottom: 16 }}>
<Button key="destroy"></Button>
<Button type={'primary'} key="create">
</Button>
</Space>
<Table
rowSelection={{
type: 'checkbox',
}}
columns={[
{
title: '角色名称',
dataIndex: 'title',
key: 'title',
},
{
title: '角色描述',
dataIndex: 'description',
key: 'description',
},
{
title: '默认角色',
dataIndex: 'default',
key: 'default',
render: (value) => value && '是',
},
{
title: '操作',
dataIndex: 'actions',
key: 'actions',
render: () => (
<Space split={<Divider type="vertical" />}>
<ConfigurePermissions />
<Typography.Link>Edit role</Typography.Link>
<Typography.Link>Delete</Typography.Link>
</Space>
),
},
]}
dataSource={[
{
name: 'root',
title: '管理员',
description: '描述',
},
{
name: 'member',
title: '普通成员',
description: '描述',
default: true,
},
]}
/>
</div>
);
};
const ConfigurePermissions = () => {
const [visible, setVisible] = useState(false);
return (
<>
<Typography.Link onClick={() => setVisible(true)}>Configure</Typography.Link>
<Drawer width={800} title={'权限配置'} visible={visible} destroyOnClose onClose={() => setVisible(false)}>
<RolePermissions />
</Drawer>
</>
);
};
export const RolePermissions = () => {
return (
<Tabs defaultActiveKey={'actions'}>
<Tabs.TabPane key={'global'} tab={'系统全局权限'}></Tabs.TabPane>
<Tabs.TabPane key={'actions'} tab={'数据操作权限'}>
<Table
columns={[
{
title: '数据表名称',
dataIndex: 'title',
key: 'title',
},
{
title: '数据表标识',
dataIndex: 'name',
key: 'name',
},
{
title: '权限策略',
dataIndex: 'usingConfigure',
key: 'usingConfigure',
render: (value) => (value ? <Tag></Tag> : <Tag></Tag>),
},
{
title: '操作',
dataIndex: 'actions',
key: 'actions',
render: () => <ResourceActionsConfigure />,
},
]}
dataSource={[
{
title: '用户',
name: 'users',
},
]}
/>
</Tabs.TabPane>
<Tabs.TabPane key={'accessible'} tab={'菜单访问权限'}>
<Table
columns={[
{
title: '菜单页面',
dataIndex: 'title',
key: 'title',
},
{
title: (
<>
<Checkbox /> 访
</>
),
dataIndex: 'accessible',
key: 'accessible',
render: () => <Checkbox />,
},
]}
dataSource={[
{
title: '页面1',
},
{
title: '页面2',
accessible: true,
},
]}
/>
</Tabs.TabPane>
</Tabs>
);
};
const ResourceActionsConfigure = () => {
const [visible, setVisible] = useState(false);
return (
<>
<Typography.Link onClick={() => setVisible(true)}>Configure</Typography.Link>
<Drawer
width={800}
title={'权限配置'}
visible={visible}
destroyOnClose
onClose={() => setVisible(false)}
footer={
<Space style={{ justifyContent: 'flex-end', width: '100%' }}>
<Button
onClick={() => {
setVisible(false);
}}
>
Cancel
</Button>
<Button
type={'primary'}
onClick={() => {
setVisible(false);
}}
>
Submit
</Button>
</Space>
}
>
<ResourceActionsForm />
</Drawer>
</>
);
};
export const ResourceActionsForm = () => {
return (
<div>
<Table
columns={[
{
title: '操作',
dataIndex: 'title',
key: 'title',
},
{
title: '类型',
dataIndex: 'type',
key: 'type',
},
{
title: (
<>
<Checkbox />
</>
),
dataIndex: 'enable',
key: 'enable',
render: () => <Checkbox />,
},
{
title: '可操作的数据范围',
dataIndex: 'scope',
key: 'scope',
render: () => <ScopeRecordPicker />
},
]}
dataSource={[
{
title: '添加',
},
{
title: '导入',
enable: true,
},
]}
/>
</div>
);
};

View File

@ -0,0 +1,77 @@
import { createForm } from '@formily/core';
import { FormContext, ISchema } from '@formily/react';
import { Button, Space } from 'antd';
import React, { useMemo } from 'react';
import { SchemaComponent } from '../';
import { AntdSchemaComponentProvider } from '../schema-component';
const schema: ISchema = {
type: 'object',
properties: {
scope: {
type: 'array',
default: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'name2' },
],
'x-component': 'RecordPicker',
properties: {
actions: {
'x-component': 'ScopeActions',
},
rowSelection: {
'x-component': 'RowSelection',
'x-component-props': {
rowKey: 'id',
objectValue: true,
rowSelection: {
type: 'radio',
},
dataSource: [
{ id: 1, title: '全部数据' },
{ id: 2, title: '用户自己创建的数据' },
{ id: 3, title: '待审核的文章' },
],
},
properties: {
column1: {
type: 'void',
title: '数据范围',
'x-component': 'RowSelection.Column',
'x-read-pretty': true,
properties: {
title: {
type: 'string',
'x-component': 'Input',
'x-read-pretty': true,
},
},
},
},
},
},
},
},
};
const ScopeActions = () => {
return (
<Space style={{ justifyContent: 'flex-end', width: '100%', marginBottom: 16 }}>
<Button key="destroy"></Button>
<Button type={'primary'} key="create">
</Button>
</Space>
);
};
export const ScopeRecordPicker = () => {
const form = useMemo(() => createForm({}), []);
return (
<FormContext.Provider value={form}>
<AntdSchemaComponentProvider>
<SchemaComponent components={{ ScopeActions }} schema={schema} />
</AntdSchemaComponentProvider>
</FormContext.Provider>
);
};

View File

@ -0,0 +1,6 @@
import { RoleTable } from '@nocobase/client';
import React from 'react';
export default () => {
return <RoleTable />;
};

View File

@ -0,0 +1,6 @@
import { RolePermissions } from '@nocobase/client';
import React from 'react';
export default () => {
return <RolePermissions />;
};

View File

@ -0,0 +1,6 @@
import { ResourceActionsForm } from '@nocobase/client';
import React from 'react';
export default () => {
return <ResourceActionsForm />;
};

View File

@ -10,3 +10,7 @@ group:
# ACL <Badge>待定</Badge> # ACL <Badge>待定</Badge>
访问控制列表plugin-acl 的前端模块 访问控制列表plugin-acl 的前端模块
<code src="./demos/demo1.tsx" />
<code src="./demos/demo2.tsx" />
<code src="./demos/demo3.tsx" />