feat: improve code
This commit is contained in:
parent
10861d3c1c
commit
3c8c2d71e3
@ -3,8 +3,10 @@ import React from 'react';
|
||||
import { FormItem } from '@formily/antd';
|
||||
import { action } from '@formily/reactive';
|
||||
import { useCollectionsContext } from '../../constate/Collections';
|
||||
import { Field } from '@formily/core';
|
||||
|
||||
export const useAsyncDataSource = (service: any) => (field: any) => {
|
||||
console.log('loadCollectionFields');
|
||||
field.loading = true;
|
||||
service(field).then(
|
||||
action.bound((data: any) => {
|
||||
@ -24,6 +26,22 @@ export default () => {
|
||||
}));
|
||||
};
|
||||
|
||||
const loadCollectionFields = async (field: Field) => {
|
||||
const target = field.query('....target').get('value');
|
||||
const f = field.query('....target').take();
|
||||
console.log('loadCollectionFields', f, field);
|
||||
const collection = collections?.find((item) => item.name === target);
|
||||
if (!collection) {
|
||||
return [];
|
||||
}
|
||||
return collection?.generalFields
|
||||
?.filter((item) => item?.uiSchema?.title)
|
||||
?.map((item) => ({
|
||||
label: item?.uiSchema?.title || item.name,
|
||||
value: item.name,
|
||||
}));
|
||||
};
|
||||
|
||||
const schema = {
|
||||
type: 'array',
|
||||
name: 'collections',
|
||||
@ -56,7 +74,7 @@ export default () => {
|
||||
};
|
||||
return (
|
||||
<SchemaRenderer
|
||||
scope={{ loadCollections, useAsyncDataSource }}
|
||||
scope={{ loadCollections, loadCollectionFields, useAsyncDataSource }}
|
||||
components={{ FormItem }}
|
||||
schema={schema}
|
||||
/>
|
||||
|
@ -6,9 +6,14 @@ const [CollectionsProvider, useCollectionsContext] = constate(() => {
|
||||
formatResult: (result) => result?.data,
|
||||
});
|
||||
return {
|
||||
...result, collections: result.data || [], findCollection(name) {
|
||||
...result, collections: result.data || [],
|
||||
findCollection(name) {
|
||||
return result?.data?.find((item) => item.name === name);
|
||||
}
|
||||
},
|
||||
getFieldsByCollection(collectionName) {
|
||||
const collection = result?.data?.find((item) => item.name === collectionName);
|
||||
return collection?.generalFields;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -1437,12 +1437,13 @@ AddNew.FormItem = observer((props: any) => {
|
||||
default: [],
|
||||
'x-component-props': {
|
||||
rowKey: 'id',
|
||||
defaultSelectedRowKeys:
|
||||
'{{ Select.useSelectedRowKeys() }}',
|
||||
useSelectedRowKeys:
|
||||
'{{ Select.useSelectedRowKeys }}',
|
||||
onSelect: '{{ Select.useSelect() }}',
|
||||
useRowSelection: '{{ Select.useRowSelection }}',
|
||||
collectionName: field.target,
|
||||
// dragSort: true,
|
||||
showIndex: true,
|
||||
// showIndex: true,
|
||||
refreshRequestOnChange: true,
|
||||
pagination: {
|
||||
pageSize: 10,
|
||||
|
@ -20,7 +20,7 @@ import {
|
||||
updateSchema,
|
||||
} from '../';
|
||||
import get from 'lodash/get';
|
||||
import { Button, Dropdown, Menu, Modal, Space, Switch } from 'antd';
|
||||
import { Button, Dropdown, Menu, Modal, Select, Space, Switch } from 'antd';
|
||||
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
||||
import cls from 'classnames';
|
||||
import { FormDialog, FormLayout } from '@formily/antd';
|
||||
@ -33,19 +33,25 @@ import { useEffect } from 'react';
|
||||
import { uid } from '@formily/shared';
|
||||
import { getSchemaPath } from '../../components/schema-renderer';
|
||||
import { RandomNameContext } from '.';
|
||||
import { useCollectionContext, useDisplayedMapContext } from '../../constate';
|
||||
import {
|
||||
useCollectionContext,
|
||||
useCollectionsContext,
|
||||
useDisplayedMapContext,
|
||||
} from '../../constate';
|
||||
import SwitchMenuItem from '../../components/SwitchMenuItem';
|
||||
import { DragHandle } from '../../components/Sortable';
|
||||
import { set } from 'lodash';
|
||||
|
||||
export const FieldDesignableBar = observer((props) => {
|
||||
const field = useField();
|
||||
const { schema, deepRemove } = useDesignable();
|
||||
const { schema, deepRemove, refresh } = useDesignable();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { dragRef } = useContext(DraggableBlockContext);
|
||||
const randomName = useContext(RandomNameContext);
|
||||
const displayed = useDisplayedMapContext();
|
||||
const fieldName = schema['x-component-props']?.['fieldName'];
|
||||
const { getField } = useCollectionContext();
|
||||
const { getFieldsByCollection } = useCollectionsContext();
|
||||
|
||||
const collectionField = getField(fieldName);
|
||||
|
||||
@ -124,6 +130,59 @@ export const FieldDesignableBar = observer((props) => {
|
||||
>
|
||||
自定义字段名称
|
||||
</Menu.Item>
|
||||
{collectionField.interface === 'linkTo' && (
|
||||
<Menu.Item>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
标签字段{' '}
|
||||
<Select
|
||||
value={
|
||||
schema?.['x-component-props']?.['fieldNames']?.[
|
||||
'label'
|
||||
]
|
||||
}
|
||||
placeholder={'默认为 ID 字段'}
|
||||
onChange={async (value) => {
|
||||
set(
|
||||
schema['x-component-props'],
|
||||
'fieldNames.label',
|
||||
value,
|
||||
);
|
||||
refresh();
|
||||
const fieldNames = {
|
||||
label: value,
|
||||
value:
|
||||
get(
|
||||
schema['x-component-props'],
|
||||
'fieldNames.value',
|
||||
) || 'id',
|
||||
};
|
||||
// realField.componentProps.fieldNames = fieldNames;
|
||||
await updateSchema({
|
||||
key: schema['key'],
|
||||
'x-component-props': {
|
||||
fieldNames,
|
||||
},
|
||||
});
|
||||
// await service.refresh();
|
||||
}}
|
||||
bordered={false}
|
||||
size={'small'}
|
||||
style={{ marginLeft: 16, minWidth: 120 }}
|
||||
options={getFieldsByCollection(collectionField.target)
|
||||
.filter((f) => f?.uiSchema?.title)
|
||||
.map((field) => ({
|
||||
label: field?.uiSchema?.title || field.name,
|
||||
value: field.name,
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
</Menu.Item>
|
||||
)}
|
||||
<Menu.Item
|
||||
style={{ minWidth: 150 }}
|
||||
onClick={async () => {
|
||||
|
@ -29,7 +29,7 @@ import { DraggableBlockContext } from '../../components/drag-and-drop';
|
||||
import { isGridRowOrCol } from '../grid';
|
||||
import constate from 'constate';
|
||||
import { useEffect } from 'react';
|
||||
import { uid } from '@formily/shared';
|
||||
import { uid, merge } from '@formily/shared';
|
||||
import { getSchemaPath } from '../../components/schema-renderer';
|
||||
import { DesignableBar } from './DesignableBar';
|
||||
import { FieldDesignableBar } from './Field.DesignableBar';
|
||||
@ -183,7 +183,15 @@ Form.Field = observer((props: any) => {
|
||||
const required = schema['required'] || collectionField?.uiSchema?.required;
|
||||
const description =
|
||||
schema['description'] || collectionField?.uiSchema?.description;
|
||||
console.log('schema.properties', schema.properties)
|
||||
console.log('schema.properties', schema.properties);
|
||||
|
||||
const componentProps = merge(
|
||||
collectionField?.uiSchema?.['x-component-props'] || {},
|
||||
schema?.['x-component-props'] || {},
|
||||
{
|
||||
arrayMerge: (t, s) => s,
|
||||
},
|
||||
);
|
||||
return (
|
||||
<CollectionFieldContext.Provider value={collectionField}>
|
||||
<RecursionField
|
||||
@ -199,6 +207,7 @@ Form.Field = observer((props: any) => {
|
||||
required,
|
||||
description,
|
||||
'x-decorator': 'FormilyFormItem',
|
||||
'x-component-props': componentProps,
|
||||
properties: {
|
||||
...schema.properties,
|
||||
},
|
||||
|
@ -18,7 +18,7 @@ import { useState } from 'react';
|
||||
import { useDesignable } from '../';
|
||||
import { createContext } from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { get, isEmpty } from 'lodash';
|
||||
import { Field, isArrayField, isField } from '@formily/core';
|
||||
import { Action } from '../action';
|
||||
import { BlockSchemaContext, VisibleContext } from '../../context';
|
||||
@ -28,6 +28,7 @@ import { CollectionFieldContext } from '../table';
|
||||
import { CollectionProvider, useCollectionContext } from '../../constate';
|
||||
import { Resource } from '../../resource';
|
||||
import { useRequest } from 'ahooks';
|
||||
import constate from 'constate';
|
||||
|
||||
export const Select: any = connect(
|
||||
(props) => {
|
||||
@ -236,11 +237,11 @@ Select.Object = connect(
|
||||
|
||||
const OptionTagContext = createContext(null);
|
||||
|
||||
const SelectedRowKeysContext = createContext([]);
|
||||
const SelectedRowsContext = createContext<any>(null);
|
||||
|
||||
Select.useOkAction = () => {
|
||||
const { props } = useContext(SelectContext);
|
||||
const [selectedRows] = useContext(SelectedRowKeysContext);
|
||||
const { selectedRows } = useContext(SelectedRowsContext);
|
||||
return {
|
||||
async run() {
|
||||
props.onChange(selectedRows);
|
||||
@ -249,38 +250,63 @@ Select.useOkAction = () => {
|
||||
};
|
||||
};
|
||||
|
||||
Select.useRowSelection = () => {
|
||||
const { props } = useContext(SelectContext);
|
||||
return {
|
||||
type: props.multiple ? 'checkbox' : 'radio',
|
||||
};
|
||||
};
|
||||
|
||||
Select.useSelect = () => {
|
||||
const [, setSelectedRows] = useContext(SelectedRowKeysContext);
|
||||
const { setSelectedRows } = useContext(SelectedRowsContext);
|
||||
return (keys, rows) => {
|
||||
setSelectedRows(rows);
|
||||
console.log('Select.onSelect', keys, rows);
|
||||
};
|
||||
};
|
||||
|
||||
Select.useSelectedRowKeys = () => {
|
||||
const [selectedRows] = useContext(SelectedRowKeysContext);
|
||||
return selectedRows?.map((row) => row.id) || [];
|
||||
export const useSelectedRowKeys = () => {
|
||||
const { selectedRows } = useContext(SelectedRowsContext);
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]);
|
||||
useEffect(() => {
|
||||
setSelectedRowKeys(selectedRows.map((row) => row.id));
|
||||
}, [selectedRows]);
|
||||
return { selectedRowKeys, setSelectedRowKeys };
|
||||
};
|
||||
|
||||
Select.useSelectedRowKeys = useSelectedRowKeys;
|
||||
|
||||
const SelectContext = createContext(null);
|
||||
|
||||
Select.Drawer = connect(
|
||||
(props) => {
|
||||
const field = useField<Field>();
|
||||
const {
|
||||
value,
|
||||
onChange,
|
||||
fieldNames = {
|
||||
label: 'id',
|
||||
value: 'id',
|
||||
},
|
||||
// fieldNames = {
|
||||
// label: 'id',
|
||||
// value: 'id',
|
||||
// },
|
||||
...others
|
||||
} = props;
|
||||
let value = props.value;
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { schema } = useDesignable();
|
||||
const fieldNames = {
|
||||
label: 'id',
|
||||
value: 'id',
|
||||
...(get(schema['x-component-props'], 'fieldNames') || {}),
|
||||
};
|
||||
const options = field?.['dataSource'] || props.options || [];
|
||||
|
||||
if (props.multiple) {
|
||||
Object.assign(others, {
|
||||
mode: 'multiple',
|
||||
});
|
||||
}
|
||||
let optionValue = undefined;
|
||||
if (props.multiple) {
|
||||
value = toArr(value);
|
||||
}
|
||||
if (isArr(value)) {
|
||||
optionValue = value.map((val) => {
|
||||
return {
|
||||
@ -294,6 +320,7 @@ Select.Drawer = connect(
|
||||
value: value[fieldNames.value],
|
||||
};
|
||||
}
|
||||
const [selectedRows, setSelectedRows] = useState(toArr(field.value));
|
||||
|
||||
const onFieldChange = (selectValue) => {
|
||||
if (!isValid(selectValue)) {
|
||||
@ -323,9 +350,9 @@ Select.Drawer = connect(
|
||||
options.find((option) => option[fieldNames.value] === selectValue),
|
||||
);
|
||||
}
|
||||
setSelectedRows(toArr(field.value));
|
||||
};
|
||||
// const selectedKeys = toArr(optionValue).map((item) => item.value);
|
||||
const [selectedRows, setSelectedRows] = useState(toArr(field.value));
|
||||
console.log({ optionValue, value });
|
||||
const collectionField = useContext(CollectionFieldContext);
|
||||
return (
|
||||
@ -352,8 +379,8 @@ Select.Drawer = connect(
|
||||
}
|
||||
}}
|
||||
></AntdSelect>
|
||||
<SelectedRowKeysContext.Provider
|
||||
value={[selectedRows, setSelectedRows]}
|
||||
<SelectedRowsContext.Provider
|
||||
value={{ selectedRows, setSelectedRows }}
|
||||
>
|
||||
<CollectionProvider collectionName={collectionField?.target}>
|
||||
<RecursionField
|
||||
@ -364,7 +391,7 @@ Select.Drawer = connect(
|
||||
}}
|
||||
/>
|
||||
</CollectionProvider>
|
||||
</SelectedRowKeysContext.Provider>
|
||||
</SelectedRowsContext.Provider>
|
||||
</VisibleContext.Provider>
|
||||
</SelectContext.Provider>
|
||||
);
|
||||
@ -391,9 +418,14 @@ Select.Drawer = connect(
|
||||
observer((props: any) => {
|
||||
const collectionField = useContext(CollectionFieldContext);
|
||||
const field = useField<Formily.Core.Models.Field>();
|
||||
const { fieldNames = { label: 'id' }, ...others } = props;
|
||||
const { ...others } = props;
|
||||
const value = field.value || field.initialValue;
|
||||
const { schema } = useDesignable();
|
||||
const fieldNames = {
|
||||
label: 'id',
|
||||
value: 'id',
|
||||
...(get(schema['x-component-props'], 'fieldNames') || {}),
|
||||
};
|
||||
console.log({ fieldNames, field, value });
|
||||
if (!value) {
|
||||
return null;
|
||||
@ -437,7 +469,7 @@ Select.Drawer.useResource = ({ onSuccess }) => {
|
||||
resourceName: collection?.name,
|
||||
resourceKey: ctx.data.id,
|
||||
});
|
||||
console.log('OptionTagContext', ctx.data.id)
|
||||
console.log('OptionTagContext', ctx.data.id);
|
||||
const { schema } = useDesignable();
|
||||
const fieldFields = (schema: Schema) => {
|
||||
const names = [];
|
||||
@ -473,7 +505,7 @@ Select.Drawer.useResource = ({ onSuccess }) => {
|
||||
}
|
||||
}, [visible]);
|
||||
return { resource, service, initialValues: service.data, ...service };
|
||||
}
|
||||
};
|
||||
|
||||
Select.Options = observer((props) => {
|
||||
return <>{props.children}</>;
|
||||
|
@ -19,7 +19,7 @@ import {
|
||||
createCollectionField,
|
||||
ISchema,
|
||||
} from '..';
|
||||
import { uid } from '@formily/shared';
|
||||
import { uid, merge } from '@formily/shared';
|
||||
import useRequest from '@ahooksjs/use-request';
|
||||
import { BaseResult } from '@ahooksjs/use-request/lib/types';
|
||||
import cls from 'classnames';
|
||||
@ -30,7 +30,6 @@ import {
|
||||
useSortable,
|
||||
verticalListSortingStrategy,
|
||||
} from '@dnd-kit/sortable';
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
import { Select, Dropdown, Menu, Switch, Button, Space } from 'antd';
|
||||
import { PlusOutlined, SettingOutlined } from '@ant-design/icons';
|
||||
import './style.less';
|
||||
@ -54,6 +53,7 @@ import {
|
||||
DisplayedMapProvider,
|
||||
useCollection,
|
||||
useCollectionContext,
|
||||
useCollectionsContext,
|
||||
useDisplayedMapContext,
|
||||
} from '../../constate';
|
||||
import { useResource as useGeneralResource } from '../../hooks/useResource';
|
||||
@ -140,7 +140,7 @@ function useTableCreateAction() {
|
||||
const form = useForm();
|
||||
return {
|
||||
async run() {
|
||||
console.log('useTableCreateAction', resource)
|
||||
console.log('useTableCreateAction', resource);
|
||||
if (refreshRequestOnChange) {
|
||||
await resource.create(form.values);
|
||||
await form.reset();
|
||||
@ -457,11 +457,13 @@ function AddColumn() {
|
||||
default: [],
|
||||
'x-component-props': {
|
||||
rowKey: 'id',
|
||||
defaultSelectedRowKeys: '{{ Select.useSelectedRowKeys() }}',
|
||||
useRowSelection: '{{ Select.useRowSelection }}',
|
||||
useSelectedRowKeys:
|
||||
'{{ Select.useSelectedRowKeys }}',
|
||||
onSelect: '{{ Select.useSelect() }}',
|
||||
collectionName: field.target,
|
||||
// dragSort: true,
|
||||
showIndex: true,
|
||||
// showIndex: true,
|
||||
refreshRequestOnChange: true,
|
||||
pagination: {
|
||||
pageSize: 10,
|
||||
@ -634,6 +636,12 @@ function AddColumn() {
|
||||
);
|
||||
}
|
||||
|
||||
const useDefaultRowSelection = () => {
|
||||
return {
|
||||
type: 'checkbox',
|
||||
};
|
||||
};
|
||||
|
||||
const useDataSource = () => {
|
||||
const {
|
||||
pagination,
|
||||
@ -657,13 +665,20 @@ const TableMain = () => {
|
||||
setSelectedRowKeys,
|
||||
service,
|
||||
field,
|
||||
props: { rowKey, dragSort, showIndex, onSelect },
|
||||
props: {
|
||||
rowKey,
|
||||
dragSort,
|
||||
showIndex,
|
||||
onSelect,
|
||||
useRowSelection = useDefaultRowSelection,
|
||||
},
|
||||
refresh,
|
||||
} = useTable();
|
||||
const columns = useTableColumns();
|
||||
const dataSource = useDataSource();
|
||||
const actionBars = useTableActionBars();
|
||||
const [html, setHtml] = useState('');
|
||||
const { type } = useRowSelection();
|
||||
return (
|
||||
<div className={'nb-table'}>
|
||||
<DndContext
|
||||
@ -744,7 +759,7 @@ const TableMain = () => {
|
||||
},
|
||||
}}
|
||||
rowSelection={{
|
||||
type: 'checkbox',
|
||||
type: type || 'checkbox',
|
||||
selectedRowKeys,
|
||||
onChange: (rowKeys, rows) => {
|
||||
setSelectedRowKeys(rowKeys);
|
||||
@ -815,20 +830,25 @@ const usePagination = () => {
|
||||
];
|
||||
};
|
||||
|
||||
const useDefaultSelectedRowKeys = () => {
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]);
|
||||
return { selectedRowKeys, setSelectedRowKeys };
|
||||
};
|
||||
|
||||
const TableProvider = (props: any) => {
|
||||
const {
|
||||
rowKey = 'id',
|
||||
dataRequest,
|
||||
useResource = useGeneralResource,
|
||||
defaultSelectedRowKeys,
|
||||
useSelectedRowKeys = useDefaultSelectedRowKeys,
|
||||
...others
|
||||
} = props;
|
||||
const { schema } = useDesignable();
|
||||
const field = useField<Formily.Core.Models.ArrayField>();
|
||||
const [pagination, setPagination] = usePagination();
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<any>(
|
||||
defaultSelectedRowKeys || [],
|
||||
);
|
||||
const { selectedRowKeys, setSelectedRowKeys } = useSelectedRowKeys();
|
||||
console.log('props.useSelectedRowKeys', selectedRowKeys);
|
||||
const [, refresh] = useState(uid());
|
||||
const { resource } = useResource();
|
||||
const { sortableField } = useCollectionContext();
|
||||
@ -1968,6 +1988,14 @@ Table.Cell = observer((props: any) => {
|
||||
uiSchema = cloneDeepWith(uiSchema);
|
||||
set(uiSchema, 'x-component-props.size', 'small');
|
||||
}
|
||||
const componentProps = merge(
|
||||
uiSchema?.['x-component-props'] || {},
|
||||
schema?.['x-component-props'] || {},
|
||||
{
|
||||
arrayMerge: (t, s) => s,
|
||||
},
|
||||
);
|
||||
console.log('Table.Cell', collectionField?.interface, componentProps);
|
||||
return (
|
||||
<div className={`field-interface-${collectionField?.interface}`}>
|
||||
<RecursionField
|
||||
@ -1985,6 +2013,7 @@ Table.Cell = observer((props: any) => {
|
||||
feedbackLayout: 'popover',
|
||||
},
|
||||
'x-decorator': 'FormilyFormItem',
|
||||
'x-component-props': componentProps,
|
||||
properties: {
|
||||
...schema?.properties,
|
||||
},
|
||||
@ -2018,10 +2047,12 @@ Table.Column = observer((props: any) => {
|
||||
|
||||
Table.Column.DesignableBar = () => {
|
||||
const field = useField();
|
||||
const { service, refresh: refreshTable } = useTable();
|
||||
// const fieldSchema = useFieldSchema();
|
||||
const { schema, remove, refresh, insertAfter } = useDesignable();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const displayed = useDisplayedMapContext();
|
||||
const { getFieldsByCollection } = useCollectionsContext();
|
||||
const collectionField = useContext(CollectionFieldContext);
|
||||
console.log('displayed.map', displayed.map);
|
||||
return (
|
||||
@ -2088,6 +2119,52 @@ Table.Column.DesignableBar = () => {
|
||||
>
|
||||
自定义列名称
|
||||
</Menu.Item>
|
||||
{collectionField.interface === 'linkTo' && (
|
||||
<Menu.Item>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
标签字段{' '}
|
||||
<Select
|
||||
value={
|
||||
schema?.['x-component-props']?.['fieldNames']?.[
|
||||
'label'
|
||||
]
|
||||
}
|
||||
placeholder={'默认为 ID 字段'}
|
||||
onChange={async (value) => {
|
||||
set(
|
||||
schema['x-component-props'],
|
||||
'fieldNames.label',
|
||||
value,
|
||||
);
|
||||
await updateSchema({
|
||||
key: schema['key'],
|
||||
'x-component-props': {
|
||||
fieldNames: {
|
||||
label: value,
|
||||
},
|
||||
},
|
||||
});
|
||||
refreshTable();
|
||||
// await service.refresh();
|
||||
}}
|
||||
bordered={false}
|
||||
size={'small'}
|
||||
style={{ marginLeft: 16, minWidth: 120 }}
|
||||
options={getFieldsByCollection(collectionField.target)
|
||||
.filter((f) => f?.uiSchema?.title)
|
||||
.map((field) => ({
|
||||
label: field?.uiSchema?.title || field.name,
|
||||
value: field.name,
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
</Menu.Item>
|
||||
)}
|
||||
<Menu.Divider />
|
||||
<Menu.Item
|
||||
onClick={async () => {
|
||||
|
Loading…
Reference in New Issue
Block a user