feat: scope select for acl resource actions
This commit is contained in:
parent
1859879978
commit
adea10a4d8
@ -2,7 +2,7 @@ import { FormItem, FormLayout } from '@formily/antd';
|
|||||||
import { ArrayField } from '@formily/core';
|
import { ArrayField } from '@formily/core';
|
||||||
import { connect, useField, useForm } from '@formily/react';
|
import { connect, useField, useForm } from '@formily/react';
|
||||||
import { Checkbox, Table, Tag } from 'antd';
|
import { Checkbox, Table, Tag } from 'antd';
|
||||||
import React from 'react';
|
import React, { createContext } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useAvailableActions } from '.';
|
import { useAvailableActions } from '.';
|
||||||
import { useCollectionManager, useCompile, useRecord } from '../..';
|
import { useCollectionManager, useCompile, useRecord } from '../..';
|
||||||
@ -18,6 +18,8 @@ const toActionMap = (arr: any[]) => {
|
|||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const RoleResourceCollectionContext = createContext<any>({});
|
||||||
|
|
||||||
export const RolesResourcesActions = connect((props) => {
|
export const RolesResourcesActions = connect((props) => {
|
||||||
const { onChange } = props;
|
const { onChange } = props;
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
@ -67,6 +69,7 @@ export const RolesResourcesActions = connect((props) => {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<RoleResourceCollectionContext.Provider value={collection}>
|
||||||
<FormLayout layout={'vertical'}>
|
<FormLayout layout={'vertical'}>
|
||||||
<FormItem label={'操作权限'}>
|
<FormItem label={'操作权限'}>
|
||||||
<Table
|
<Table
|
||||||
@ -189,6 +192,7 @@ export const RolesResourcesActions = connect((props) => {
|
|||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</FormLayout>
|
</FormLayout>
|
||||||
|
</RoleResourceCollectionContext.Provider>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
import { ISchema, useForm } from '@formily/react';
|
import { ISchema } from '@formily/react';
|
||||||
import { useActionContext } from '../../../';
|
import { useContext, useEffect } from 'react';
|
||||||
import { useAPIClient, useRequest } from '../../../api-client';
|
import { useFormBlockContext } from '../../../block-provider';
|
||||||
import { useRecord } from '../../../record-provider';
|
import { useFilterOptions } from '../../../schema-component';
|
||||||
|
import { RoleResourceCollectionContext } from '../RolesResourcesActions';
|
||||||
|
|
||||||
const collection = {
|
export const rolesResourcesScopesCollection = {
|
||||||
name: 'rolesResourcesScopes',
|
name: 'rolesResourcesScopes',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
name: 'title',
|
name: 'name',
|
||||||
interface: 'input',
|
interface: 'input',
|
||||||
uiSchema: {
|
uiSchema: {
|
||||||
title: '名称',
|
title: '名称',
|
||||||
@ -20,6 +21,19 @@ const collection = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const useFormBlockProps = () => {
|
||||||
|
const { name } = useContext(RoleResourceCollectionContext);
|
||||||
|
const ctx = useFormBlockContext();
|
||||||
|
useEffect(() => {
|
||||||
|
ctx.form.setInitialValues({
|
||||||
|
resourceName: name,
|
||||||
|
});
|
||||||
|
}, [name]);
|
||||||
|
return {
|
||||||
|
form: ctx.form,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const scopesSchema: ISchema = {
|
export const scopesSchema: ISchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@ -31,14 +45,41 @@ export const scopesSchema: ISchema = {
|
|||||||
label: 'name',
|
label: 'name',
|
||||||
value: 'id',
|
value: 'id',
|
||||||
},
|
},
|
||||||
|
association: {
|
||||||
|
target: 'rolesResourcesScopes',
|
||||||
|
},
|
||||||
onChange: '{{ onChange }}',
|
onChange: '{{ onChange }}',
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
options: {
|
selector: {
|
||||||
'x-decorator': 'RolesResourcesScopesSelectedRowKeysProvider',
|
|
||||||
'x-component': 'RecordPicker.Options',
|
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '可操作的数据范围',
|
title: '{{ t("Select record") }}',
|
||||||
|
'x-component': 'RecordPicker.Selector',
|
||||||
|
'x-component-props': {
|
||||||
|
className: 'nb-record-picker-selector',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
tableBlock: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'TableSelectorProvider',
|
||||||
|
'x-decorator-props': {
|
||||||
|
collection: rolesResourcesScopesCollection,
|
||||||
|
resource: 'rolesResourcesScopes',
|
||||||
|
action: 'list',
|
||||||
|
params: {
|
||||||
|
pageSize: 20,
|
||||||
|
},
|
||||||
|
useParams() {
|
||||||
|
const ctx = useContext(RoleResourceCollectionContext);
|
||||||
|
return {
|
||||||
|
filter: {
|
||||||
|
$or: [{ resourceName: ctx.name }, { resourceName: null }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
rowKey: 'id',
|
||||||
|
},
|
||||||
|
'x-component': 'BlockItem',
|
||||||
properties: {
|
properties: {
|
||||||
actions: {
|
actions: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
@ -49,70 +90,82 @@ export const scopesSchema: ISchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
// delete: {
|
|
||||||
// type: 'void',
|
|
||||||
// title: '删除',
|
|
||||||
// 'x-component': 'Action',
|
|
||||||
// },
|
|
||||||
create: {
|
create: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '添加数据范围',
|
title: '{{ t("Add new") }}',
|
||||||
|
'x-action': 'create',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
|
icon: 'PlusOutlined',
|
||||||
|
openMode: 'drawer',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
drawer: {
|
drawer: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Action.Drawer',
|
title: '{{ t("Add record") }}',
|
||||||
'x-decorator': 'Form',
|
'x-component': 'Action.Container',
|
||||||
title: '添加数据范围',
|
'x-component-props': {
|
||||||
|
className: 'nb-action-popup',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
formBlock: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'FormBlockProvider',
|
||||||
|
'x-decorator-props': {
|
||||||
|
resource: 'rolesResourcesScopes',
|
||||||
|
collection: rolesResourcesScopesCollection,
|
||||||
|
// useParams: '{{ useParamsFromRecord }}',
|
||||||
|
},
|
||||||
|
'x-component': 'CardItem',
|
||||||
|
properties: {
|
||||||
|
form: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'FormV2',
|
||||||
|
'x-component-props': {
|
||||||
|
useProps: useFormBlockProps,
|
||||||
|
},
|
||||||
properties: {
|
properties: {
|
||||||
name: {
|
name: {
|
||||||
title: '数据范围名称',
|
type: 'string',
|
||||||
'x-component': 'Input',
|
'x-component': 'CollectionField',
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
},
|
},
|
||||||
// scope: {
|
scope: {
|
||||||
// 'x-component': 'Input',
|
type: 'object',
|
||||||
// 'x-decorator': 'FormItem',
|
title: 'Data scope',
|
||||||
// },
|
name: 'filter',
|
||||||
footer: {
|
'x-decorator': 'FormItem',
|
||||||
type: 'void',
|
'x-component': 'Filter',
|
||||||
'x-component': 'Action.Drawer.Footer',
|
|
||||||
properties: {
|
|
||||||
action1: {
|
|
||||||
title: 'Cancel',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
useAction: '{{ cm.useCancelAction }}',
|
useProps() {
|
||||||
},
|
const ctx = useContext(RoleResourceCollectionContext);
|
||||||
},
|
const options = useFilterOptions(ctx.name);
|
||||||
action2: {
|
console.log('ctx.name', ctx.name, options);
|
||||||
title: 'Submit',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': {
|
|
||||||
type: 'primary',
|
|
||||||
useAction() {
|
|
||||||
const api = useAPIClient();
|
|
||||||
const ctx = useActionContext();
|
|
||||||
const form = useForm();
|
|
||||||
const record = useRecord();
|
|
||||||
return {
|
return {
|
||||||
async run() {
|
options,
|
||||||
await api.resource('rolesResourcesScopes').create({
|
|
||||||
values: {
|
|
||||||
...form.values,
|
|
||||||
resourceName: record.name,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
ctx.setVisible(false);
|
|
||||||
api.service('rolesResourcesScopesList')?.refresh?.();
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
layout: 'one-column',
|
||||||
|
style: {
|
||||||
|
marginTop: 24,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
create: {
|
||||||
|
title: '{{ t("Submit") }}',
|
||||||
|
'x-action': 'submit',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
htmlType: 'submit',
|
||||||
|
useProps: '{{ useCreateActionProps }}',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -121,75 +174,179 @@ export const scopesSchema: ISchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input: {
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
value: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
'x-component': 'Table.RowSelection',
|
'x-component': 'TableV2.Selector',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
rowKey: 'id',
|
rowKey: 'id',
|
||||||
objectValue: true,
|
|
||||||
rowSelection: {
|
rowSelection: {
|
||||||
type: 'radio',
|
type: 'checkbox',
|
||||||
},
|
},
|
||||||
// useSelectedRowKeys() {
|
useProps: '{{ useTableSelectorProps }}',
|
||||||
// const [selectedRowKeys, setSelectedRowKeys] = useRolesResourcesScopesSelectedRowKeys();
|
|
||||||
// return [selectedRowKeys, setSelectedRowKeys];
|
|
||||||
// },
|
|
||||||
useDataSource(options) {
|
|
||||||
const record = useRecord();
|
|
||||||
return useRequest(
|
|
||||||
{
|
|
||||||
resource: 'rolesResourcesScopes',
|
|
||||||
action: 'list',
|
|
||||||
params: {
|
|
||||||
sort: 'id',
|
|
||||||
filter: JSON.stringify({
|
|
||||||
$or: [
|
|
||||||
{
|
|
||||||
'resourceName.$eq': record.name,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'resourceName.$eq': '*',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
...options,
|
|
||||||
uid: 'rolesResourcesScopesList',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// dataSource: [
|
|
||||||
// { id: 1, name: 'Name1' },
|
|
||||||
// { id: 2, name: 'Name2' },
|
|
||||||
// { id: 3, name: 'Name3' },
|
|
||||||
// ],
|
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
column1: {
|
column1: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: 'Name',
|
'x-decorator': 'TableV2.Column.Decorator',
|
||||||
'x-component': 'Table.Column',
|
'x-component': 'TableV2.Column',
|
||||||
properties: {
|
properties: {
|
||||||
name: {
|
name: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
'x-component': 'Input',
|
'x-component': 'CollectionField',
|
||||||
'x-read-pretty': true,
|
'x-read-pretty': true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
column2: {
|
actions: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: 'Actions',
|
title: '{{ t("Actions") }}',
|
||||||
'x-component': 'Table.Column',
|
'x-action-column': 'actions',
|
||||||
// properties: {
|
'x-component': 'TableV2.Column',
|
||||||
// delete: {
|
properties: {
|
||||||
// type: 'void',
|
actions: {
|
||||||
// title: '删除',
|
type: 'void',
|
||||||
// 'x-component': 'Action.Link',
|
'x-decorator': 'DndContext',
|
||||||
// },
|
'x-component': 'Space',
|
||||||
// },
|
'x-component-props': {
|
||||||
|
split: '|',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
edit: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Edit") }}',
|
||||||
|
'x-action': 'update',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-component-props': {
|
||||||
|
openMode: 'drawer',
|
||||||
|
icon: 'EditOutlined',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
drawer: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Edit record") }}',
|
||||||
|
'x-component': 'Action.Container',
|
||||||
|
'x-component-props': {
|
||||||
|
className: 'nb-action-popup',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
formBlock: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'FormBlockProvider',
|
||||||
|
'x-decorator-props': {
|
||||||
|
resource: 'rolesResourcesScopes',
|
||||||
|
collection: rolesResourcesScopesCollection,
|
||||||
|
action: 'get',
|
||||||
|
useParams: '{{ useParamsFromRecord }}',
|
||||||
|
},
|
||||||
|
'x-component': 'CardItem',
|
||||||
|
properties: {
|
||||||
|
form: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'FormV2',
|
||||||
|
'x-component-props': {
|
||||||
|
useProps: '{{ useFormBlockProps }}',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
scope: {
|
||||||
|
type: 'object',
|
||||||
|
title: 'Data scope',
|
||||||
|
name: 'filter',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Filter',
|
||||||
|
'x-component-props': {
|
||||||
|
useProps() {
|
||||||
|
const ctx = useContext(RoleResourceCollectionContext);
|
||||||
|
const options = useFilterOptions(ctx.name);
|
||||||
|
return {
|
||||||
|
options,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
layout: 'one-column',
|
||||||
|
style: {
|
||||||
|
marginTop: 24,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
update: {
|
||||||
|
title: '{{ t("Submit") }}',
|
||||||
|
'x-action': 'submit',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
htmlType: 'submit',
|
||||||
|
useProps: '{{ useUpdateActionProps }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
destroy: {
|
||||||
|
title: '{{ t("Delete") }}',
|
||||||
|
'x-action': 'destroy',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-designer': 'Action.Designer',
|
||||||
|
'x-component-props': {
|
||||||
|
icon: 'DeleteOutlined',
|
||||||
|
confirm: {
|
||||||
|
title: "{{t('Delete record')}}",
|
||||||
|
content: "{{t('Are you sure you want to delete it?')}}",
|
||||||
|
},
|
||||||
|
useProps: '{{ useDestroyActionProps }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
'x-component': 'Action.Container.Footer',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
submit: {
|
||||||
|
title: '{{ t("Submit") }}',
|
||||||
|
'x-action': 'submit',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-designer': 'Action.Designer',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
htmlType: 'submit',
|
||||||
|
useProps: '{{ usePickActionProps }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -49,6 +49,7 @@ export const FilterGroup = connect((props) => {
|
|||||||
<Trans>
|
<Trans>
|
||||||
{'Meet '}
|
{'Meet '}
|
||||||
<Select
|
<Select
|
||||||
|
style={{ width: 'auto' }}
|
||||||
value={logic}
|
value={logic}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
setLogic(value);
|
setLogic(value);
|
||||||
|
@ -41,13 +41,22 @@ const usePickActionProps = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const useAssociation = (props) => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { association } = props;
|
||||||
|
const { getField } = useCollection();
|
||||||
|
if (association) {
|
||||||
|
return association;
|
||||||
|
}
|
||||||
|
return getField(fieldSchema.name);
|
||||||
|
}
|
||||||
|
|
||||||
export const InputRecordPicker: React.FC<any> = (props) => {
|
export const InputRecordPicker: React.FC<any> = (props) => {
|
||||||
const { value, multiple, onChange } = props;
|
const { value, multiple, onChange } = props;
|
||||||
const fieldNames = useFieldNames(props);
|
const fieldNames = useFieldNames(props);
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { getField } = useCollection();
|
const collectionField = useAssociation(props);
|
||||||
const collectionField = getField(fieldSchema.name);
|
|
||||||
const options = Array.isArray(value) ? value : value ? [value] : [];
|
const options = Array.isArray(value) ? value : value ? [value] : [];
|
||||||
const [selectedRows, setSelectedRows] = useState(options);
|
const [selectedRows, setSelectedRows] = useState(options);
|
||||||
const values = options?.map((option) => option[fieldNames.value]);
|
const values = options?.map((option) => option[fieldNames.value]);
|
||||||
|
Loading…
Reference in New Issue
Block a user