mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 10:37:01 +00:00
feat: add acl components
This commit is contained in:
parent
15950ece05
commit
fd130901be
@ -1,8 +1,10 @@
|
||||
import React, { useState } from 'react';
|
||||
import { LockOutlined } from '@ant-design/icons';
|
||||
import { SchemaComponent, useActionVisible, VisibleContext } from '../schema-component';
|
||||
import { ISchema, useForm } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
import React, { useState } from 'react';
|
||||
import { PluginManager } from '../plugin-manager';
|
||||
import { SchemaComponent, useActionVisible, VisibleContext } from '../schema-component';
|
||||
import { RoleTable } from './RolePermissionManager';
|
||||
|
||||
const useCloseAction = () => {
|
||||
const { setVisible } = useActionVisible();
|
||||
@ -20,28 +22,28 @@ const useCloseAction = () => {
|
||||
const schema: ISchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
drawer1: {
|
||||
[uid()]: {
|
||||
'x-component': 'Action.Drawer',
|
||||
type: 'void',
|
||||
title: 'Drawer Title',
|
||||
properties: {
|
||||
hello1: {
|
||||
'x-content': 'Hello',
|
||||
title: 'T1',
|
||||
},
|
||||
footer1: {
|
||||
'x-component': 'Action.Drawer.Footer',
|
||||
type: 'void',
|
||||
properties: {
|
||||
close1: {
|
||||
title: 'Close',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction: '{{ useCloseAction }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
'x-component': 'RoleTable',
|
||||
},
|
||||
// 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);
|
||||
}}
|
||||
/>
|
||||
<SchemaComponent scope={{ useCloseAction }} schema={schema} />
|
||||
<SchemaComponent components={{ RoleTable }} scope={{ useCloseAction }} schema={schema} />
|
||||
</VisibleContext.Provider>
|
||||
);
|
||||
};
|
||||
|
@ -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 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>
|
||||
);
|
||||
};
|
||||
|
77
packages/client/src/acl/ScopeRecordPicker.tsx
Normal file
77
packages/client/src/acl/ScopeRecordPicker.tsx
Normal 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>
|
||||
);
|
||||
};
|
6
packages/client/src/acl/demos/demo1.tsx
Normal file
6
packages/client/src/acl/demos/demo1.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
import { RoleTable } from '@nocobase/client';
|
||||
import React from 'react';
|
||||
|
||||
export default () => {
|
||||
return <RoleTable />;
|
||||
};
|
6
packages/client/src/acl/demos/demo2.tsx
Normal file
6
packages/client/src/acl/demos/demo2.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
import { RolePermissions } from '@nocobase/client';
|
||||
import React from 'react';
|
||||
|
||||
export default () => {
|
||||
return <RolePermissions />;
|
||||
};
|
6
packages/client/src/acl/demos/demo3.tsx
Normal file
6
packages/client/src/acl/demos/demo3.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
import { ResourceActionsForm } from '@nocobase/client';
|
||||
import React from 'react';
|
||||
|
||||
export default () => {
|
||||
return <ResourceActionsForm />;
|
||||
};
|
@ -10,3 +10,7 @@ group:
|
||||
# ACL <Badge>待定</Badge>
|
||||
|
||||
访问控制列表,plugin-acl 的前端模块
|
||||
|
||||
<code src="./demos/demo1.tsx" />
|
||||
<code src="./demos/demo2.tsx" />
|
||||
<code src="./demos/demo3.tsx" />
|
||||
|
Loading…
Reference in New Issue
Block a user