Revert "refactor: code splitting of the table component (#120)"
This reverts commit 0f9eb4e7f2
.
This commit is contained in:
parent
0f9eb4e7f2
commit
1072e03c5a
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"trailingComma": "all",
|
"trailingComma": "all",
|
||||||
"printWidth": 120,
|
"printWidth": 80,
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": ".prettierrc",
|
"files": ".prettierrc",
|
||||||
|
@ -11,8 +11,7 @@ import { PlusOutlined, DownOutlined } from '@ant-design/icons';
|
|||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { uid, isValid, clone } from '@formily/shared';
|
import { uid, isValid, clone } from '@formily/shared';
|
||||||
import { Resource } from '../../../resource';
|
import { Resource } from '../../../resource';
|
||||||
import { TableRowContext } from '../../../schemas/table/context';
|
import { TableRowContext, useTable } from '../../../schemas/table';
|
||||||
import { useTable } from '../../../schemas/table/hooks/useTable';
|
|
||||||
import { useRequest } from 'ahooks';
|
import { useRequest } from 'ahooks';
|
||||||
import { VisibleContext } from '../../../context';
|
import { VisibleContext } from '../../../context';
|
||||||
import { connect, FormProvider, observer, useForm } from '@formily/react';
|
import { connect, FormProvider, observer, useForm } from '@formily/react';
|
||||||
|
@ -8,8 +8,7 @@ import { LockOutlined } from '@ant-design/icons';
|
|||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { Resource } from '../../../resource';
|
import { Resource } from '../../../resource';
|
||||||
import { TableRowContext } from '../../../schemas/table/context';
|
import { TableRowContext, useTable } from '../../../schemas/table';
|
||||||
import { useTable } from '../../../schemas/table/hooks/useTable';
|
|
||||||
import { useRequest } from 'ahooks';
|
import { useRequest } from 'ahooks';
|
||||||
import { VisibleContext } from '../../../context';
|
import { VisibleContext } from '../../../context';
|
||||||
import { connect, ISchema, observer, useField } from '@formily/react';
|
import { connect, ISchema, observer, useField } from '@formily/react';
|
||||||
|
@ -8,8 +8,7 @@ import { LockOutlined } from '@ant-design/icons';
|
|||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { uid, isValid } from '@formily/shared';
|
import { uid, isValid } from '@formily/shared';
|
||||||
import { Resource } from '../../../resource';
|
import { Resource } from '../../../resource';
|
||||||
import { TableRowContext } from '../../../schemas/table/context';
|
import { TableRowContext, useTable } from '../../../schemas/table';
|
||||||
import { useTable } from '../../../schemas/table/hooks/useTable';
|
|
||||||
import { useRequest } from 'ahooks';
|
import { useRequest } from 'ahooks';
|
||||||
import { VisibleContext } from '../../../context';
|
import { VisibleContext } from '../../../context';
|
||||||
import { connect, observer, useForm } from '@formily/react';
|
import { connect, observer, useForm } from '@formily/react';
|
||||||
|
@ -52,8 +52,11 @@ import { Menu } from '../../schemas/menu';
|
|||||||
import { Password } from '../../schemas/password';
|
import { Password } from '../../schemas/password';
|
||||||
import { Radio } from '../../schemas/radio';
|
import { Radio } from '../../schemas/radio';
|
||||||
import { Select } from '../../schemas/select';
|
import { Select } from '../../schemas/select';
|
||||||
import { Table } from '../../schemas/table';
|
import {
|
||||||
import { CollectionFieldContext, TableRowContext } from '../../schemas/table/context';
|
CollectionFieldContext,
|
||||||
|
Table,
|
||||||
|
TableRowContext,
|
||||||
|
} from '../../schemas/table';
|
||||||
import { Tabs } from '../../schemas/tabs';
|
import { Tabs } from '../../schemas/tabs';
|
||||||
import { TimePicker } from '../../schemas/time-picker';
|
import { TimePicker } from '../../schemas/time-picker';
|
||||||
import { Upload } from '../../schemas/upload';
|
import { Upload } from '../../schemas/upload';
|
||||||
|
@ -38,7 +38,7 @@ import { useEffect } from 'react';
|
|||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { getSchemaPath } from '../../components/schema-renderer';
|
import { getSchemaPath } from '../../components/schema-renderer';
|
||||||
import { useCollection, useCollectionContext } from '../../constate';
|
import { useCollection, useCollectionContext } from '../../constate';
|
||||||
import { useTable } from '../table/hooks/useTable';
|
import { useTable } from '../table';
|
||||||
import { fieldsToFilterColumns } from './';
|
import { fieldsToFilterColumns } from './';
|
||||||
import { set } from 'lodash';
|
import { set } from 'lodash';
|
||||||
import { DragHandle } from '../../components/Sortable';
|
import { DragHandle } from '../../components/Sortable';
|
||||||
|
@ -27,7 +27,7 @@ import { useEffect } from 'react';
|
|||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { getSchemaPath } from '../../components/schema-renderer';
|
import { getSchemaPath } from '../../components/schema-renderer';
|
||||||
import { useCollection, useCollectionContext } from '../../constate';
|
import { useCollection, useCollectionContext } from '../../constate';
|
||||||
import { useTable } from '../table/hooks/useTable';
|
import { useTable } from '../table';
|
||||||
import { BlockSchemaContext } from '../../context';
|
import { BlockSchemaContext } from '../../context';
|
||||||
import { DragHandle } from '../../components/Sortable';
|
import { DragHandle } from '../../components/Sortable';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
@ -44,7 +44,7 @@ import {
|
|||||||
import { useResource as useGeneralResource } from '../../hooks/useResource';
|
import { useResource as useGeneralResource } from '../../hooks/useResource';
|
||||||
import { Resource } from '../../resource';
|
import { Resource } from '../../resource';
|
||||||
import { BaseResult } from '@ahooksjs/use-request/lib/types';
|
import { BaseResult } from '@ahooksjs/use-request/lib/types';
|
||||||
import { CollectionFieldContext } from '../table/context';
|
import { CollectionFieldContext } from '../table';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export interface DescriptionsContextProps {
|
export interface DescriptionsContextProps {
|
||||||
|
@ -27,7 +27,7 @@ import { useEffect } from 'react';
|
|||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { getSchemaPath } from '../../components/schema-renderer';
|
import { getSchemaPath } from '../../components/schema-renderer';
|
||||||
import { useCollection, useCollectionContext } from '../../constate';
|
import { useCollection, useCollectionContext } from '../../constate';
|
||||||
import { useTable } from '../table/hooks/useTable';
|
import { useTable } from '../table';
|
||||||
import { DragHandle } from '../../components/Sortable';
|
import { DragHandle } from '../../components/Sortable';
|
||||||
import { useCompile } from '../../hooks/useCompile';
|
import { useCompile } from '../../hooks/useCompile';
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ import { useEffect } from 'react';
|
|||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { getSchemaPath } from '../../components/schema-renderer';
|
import { getSchemaPath } from '../../components/schema-renderer';
|
||||||
import { useCollection, useCollectionContext } from '../../constate';
|
import { useCollection, useCollectionContext } from '../../constate';
|
||||||
import { useTable } from '../table/hooks/useTable';
|
import { useTable } from '../table';
|
||||||
import { DragHandle } from '../../components/Sortable';
|
import { DragHandle } from '../../components/Sortable';
|
||||||
import { fieldsToFilterColumns } from '../calendar';
|
import { fieldsToFilterColumns } from '../calendar';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
@ -24,7 +24,7 @@ import { Action } from '../action';
|
|||||||
import { BlockSchemaContext, VisibleContext } from '../../context';
|
import { BlockSchemaContext, VisibleContext } from '../../context';
|
||||||
import { SchemaRenderer } from '../../components/schema-renderer';
|
import { SchemaRenderer } from '../../components/schema-renderer';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { CollectionFieldContext } from '../table/context';
|
import { CollectionFieldContext } from '../table';
|
||||||
import {
|
import {
|
||||||
CollectionProvider,
|
CollectionProvider,
|
||||||
useCollectionContext,
|
useCollectionContext,
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Space } from 'antd';
|
|
||||||
import { RecursionField } from '@formily/react';
|
|
||||||
import { useDesignable } from '..';
|
|
||||||
import { Droppable, SortableItem } from '../../components/Sortable';
|
|
||||||
import { getSchemaPath } from '../../components/schema-renderer';
|
|
||||||
|
|
||||||
export const Actions = (props: any) => {
|
|
||||||
const { align = 'left' } = props;
|
|
||||||
const { schema, designable } = useDesignable();
|
|
||||||
return (
|
|
||||||
<Droppable
|
|
||||||
id={`${schema.name}-${align}`}
|
|
||||||
className={`action-bar-align-${align}`}
|
|
||||||
data={{ align, path: getSchemaPath(schema) }}
|
|
||||||
>
|
|
||||||
<Space>
|
|
||||||
{schema.mapProperties((s) => {
|
|
||||||
const currentAlign = s['x-align'] || 'left';
|
|
||||||
if (currentAlign !== align) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<SortableItem
|
|
||||||
id={s.name}
|
|
||||||
data={{
|
|
||||||
align,
|
|
||||||
draggable: true,
|
|
||||||
title: s.title,
|
|
||||||
path: getSchemaPath(s),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<RecursionField name={s.name} schema={s} />
|
|
||||||
</SortableItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Space>
|
|
||||||
</Droppable>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,77 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { Dropdown, Menu, Button } from 'antd';
|
|
||||||
import { SettingOutlined } from '@ant-design/icons';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { Schema } from '@formily/react';
|
|
||||||
import { useDesignable, ISchema } from '..';
|
|
||||||
import { useDisplayedMapContext, useClient } from '../../constate';
|
|
||||||
import SwitchMenuItem from '../../components/SwitchMenuItem';
|
|
||||||
import { getSchemaPath } from '../../components/schema-renderer';
|
|
||||||
import {generateActionSchema} from './utils';
|
|
||||||
|
|
||||||
export const AddActionButton = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const displayed = useDisplayedMapContext();
|
|
||||||
const { appendChild, remove } = useDesignable();
|
|
||||||
const { schema, designable } = useDesignable();
|
|
||||||
const { createSchema, removeSchema, updateSchema } = useClient();
|
|
||||||
|
|
||||||
if (!designable || !schema['x-designable-bar']) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Dropdown
|
|
||||||
trigger={['hover']}
|
|
||||||
visible={visible}
|
|
||||||
onVisibleChange={setVisible}
|
|
||||||
overlay={
|
|
||||||
<Menu>
|
|
||||||
<Menu.ItemGroup title={t('Enable actions')}>
|
|
||||||
{[
|
|
||||||
{ title: t('Filter'), name: 'filter' },
|
|
||||||
{ title: t('Export'), name: 'export' },
|
|
||||||
{ title: t('Add new'), name: 'create' },
|
|
||||||
{ title: t('Delete'), name: 'destroy' },
|
|
||||||
].map((item) => (
|
|
||||||
<SwitchMenuItem
|
|
||||||
key={item.name}
|
|
||||||
checked={displayed.has(item.name)}
|
|
||||||
title={item.title}
|
|
||||||
onChange={async (checked) => {
|
|
||||||
if (!checked) {
|
|
||||||
const s = displayed.get(item.name) as Schema;
|
|
||||||
const path = getSchemaPath(s);
|
|
||||||
displayed.remove(item.name);
|
|
||||||
const removed = remove(path);
|
|
||||||
await removeSchema(removed);
|
|
||||||
} else {
|
|
||||||
const s = generateActionSchema(item.name);
|
|
||||||
const data = appendChild(s);
|
|
||||||
await createSchema(data);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Menu.ItemGroup>
|
|
||||||
<Menu.Divider />
|
|
||||||
<Menu.SubMenu disabled title={t('Customize')}>
|
|
||||||
<Menu.Item style={{ minWidth: 120 }}>{t('Function')}</Menu.Item>
|
|
||||||
<Menu.Item>{t('Popup form')}</Menu.Item>
|
|
||||||
<Menu.Item>{t('Flexible popup')}</Menu.Item>
|
|
||||||
</Menu.SubMenu>
|
|
||||||
</Menu>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
className={'designable-btn designable-btn-dash'}
|
|
||||||
style={{ marginLeft: 8 }}
|
|
||||||
type={'dashed'}
|
|
||||||
icon={<SettingOutlined />}
|
|
||||||
>
|
|
||||||
{t('Configure actions')}
|
|
||||||
</Button>
|
|
||||||
</Dropdown>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -1,232 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { Dropdown, Menu, Button } from 'antd';
|
|
||||||
import { SettingOutlined } from '@ant-design/icons';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { uid } from '@formily/shared';
|
|
||||||
import { FormDialog, FormLayout } from '@formily/antd';
|
|
||||||
import { useDesignable, createCollectionField, ISchema } from '..';
|
|
||||||
import { useCollectionContext, useCollectionsContext, useDisplayedMapContext, useClient } from '../../constate';
|
|
||||||
import { useTable } from './hooks/useTable';
|
|
||||||
import SwitchMenuItem from '../../components/SwitchMenuItem';
|
|
||||||
import { isAssociation, options } from '../database-field/interfaces';
|
|
||||||
import { getSchemaPath, SchemaField } from '../../components/schema-renderer';
|
|
||||||
|
|
||||||
export function AddColumn() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const { appendChild, remove } = useDesignable();
|
|
||||||
const { loadCollections } = useCollectionsContext();
|
|
||||||
const { collection, fields, refresh } = useCollectionContext();
|
|
||||||
const displayed = useDisplayedMapContext();
|
|
||||||
const { service } = useTable();
|
|
||||||
const { createSchema, removeSchema, updateSchema } = useClient();
|
|
||||||
return (
|
|
||||||
<Dropdown
|
|
||||||
trigger={['hover']}
|
|
||||||
visible={visible}
|
|
||||||
onVisibleChange={setVisible}
|
|
||||||
overlay={
|
|
||||||
<Menu>
|
|
||||||
<Menu.ItemGroup className={'display-fields'} title={t('Display fields')}>
|
|
||||||
{fields.map((field) => (
|
|
||||||
<SwitchMenuItem
|
|
||||||
title={field?.uiSchema?.title}
|
|
||||||
checked={displayed.has(field.name)}
|
|
||||||
onChange={async (checked) => {
|
|
||||||
if (checked) {
|
|
||||||
console.log('SwitchMenuItem.field.name', field.dataType, service.params[0]);
|
|
||||||
const columnSchema: ISchema = {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Table.Column',
|
|
||||||
'x-component-props': {
|
|
||||||
fieldName: field.name,
|
|
||||||
},
|
|
||||||
'x-designable-bar': 'Table.Column.DesignableBar',
|
|
||||||
};
|
|
||||||
if (field.interface === 'linkTo') {
|
|
||||||
columnSchema.properties = {
|
|
||||||
options: {
|
|
||||||
type: 'void',
|
|
||||||
'x-decorator': 'Form',
|
|
||||||
'x-component': 'Select.Options.Drawer',
|
|
||||||
'x-component-props': {
|
|
||||||
useOkAction: '{{ Select.useOkAction }}',
|
|
||||||
},
|
|
||||||
title: "{{t('Select record')}}",
|
|
||||||
properties: {
|
|
||||||
table: {
|
|
||||||
type: 'array',
|
|
||||||
'x-designable-bar': 'Table.DesignableBar',
|
|
||||||
'x-decorator': 'BlockItem',
|
|
||||||
'x-decorator-props': {
|
|
||||||
draggable: false,
|
|
||||||
},
|
|
||||||
'x-component': 'Table',
|
|
||||||
default: [],
|
|
||||||
'x-component-props': {
|
|
||||||
rowKey: 'id',
|
|
||||||
useRowSelection: '{{ Select.useRowSelection }}',
|
|
||||||
useSelectedRowKeys: '{{ Select.useSelectedRowKeys }}',
|
|
||||||
onSelect: '{{ Select.useSelect() }}',
|
|
||||||
collectionName: field.target,
|
|
||||||
// dragSort: true,
|
|
||||||
// showIndex: true,
|
|
||||||
refreshRequestOnChange: true,
|
|
||||||
pagination: {
|
|
||||||
pageSize: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Table.ActionBar',
|
|
||||||
'x-designable-bar': 'Table.ActionBar.DesignableBar',
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
title: "{{t('Filter')}}",
|
|
||||||
'x-decorator': 'AddNew.Displayed',
|
|
||||||
'x-decorator-props': {
|
|
||||||
displayName: 'filter',
|
|
||||||
},
|
|
||||||
'x-align': 'left',
|
|
||||||
'x-component': 'Table.Filter',
|
|
||||||
'x-designable-bar': 'Table.Filter.DesignableBar',
|
|
||||||
'x-component-props': {
|
|
||||||
fieldNames: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
option: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Select.OptionTag',
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
title: "{{t('View record')}}",
|
|
||||||
'x-component': 'Action.Drawer',
|
|
||||||
'x-component-props': {
|
|
||||||
bodyStyle: {
|
|
||||||
background: '#f0f2f5',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Tabs',
|
|
||||||
'x-designable-bar': 'Tabs.DesignableBar',
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
title: "{{t('Details')}}",
|
|
||||||
'x-designable-bar': 'Tabs.TabPane.DesignableBar',
|
|
||||||
'x-component': 'Tabs.TabPane',
|
|
||||||
'x-component-props': {},
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Grid',
|
|
||||||
'x-component-props': {
|
|
||||||
addNewComponent: 'AddNew.PaneItem',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const data = appendChild(columnSchema);
|
|
||||||
await createSchema(data);
|
|
||||||
if (isAssociation(field)) {
|
|
||||||
const defaultAppends = service.params[0]?.defaultAppends || [];
|
|
||||||
defaultAppends.push(field.name);
|
|
||||||
await service.run({
|
|
||||||
...service.params[0],
|
|
||||||
defaultAppends,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const s: any = displayed.get(field.name);
|
|
||||||
const p = getSchemaPath(s);
|
|
||||||
const removed = remove(p);
|
|
||||||
await removeSchema(removed);
|
|
||||||
displayed.remove(field.name);
|
|
||||||
if (isAssociation(field)) {
|
|
||||||
const defaultAppends = service.params[0]?.defaultAppends || [];
|
|
||||||
const index = defaultAppends.indexOf(field.name);
|
|
||||||
if (index > -1) {
|
|
||||||
defaultAppends.splice(index, 1);
|
|
||||||
}
|
|
||||||
await service.run({
|
|
||||||
...service.params[0],
|
|
||||||
defaultAppends,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// service.refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Menu.ItemGroup>
|
|
||||||
<Menu.Divider />
|
|
||||||
<Menu.SubMenu disabled popupClassName={'add-new-fields-popup'} title={t('Add field')}>
|
|
||||||
{options.map((option) => (
|
|
||||||
<Menu.ItemGroup title={option.label}>
|
|
||||||
{option.children.map((item) => (
|
|
||||||
<Menu.Item
|
|
||||||
style={{ minWidth: 150 }}
|
|
||||||
key={item.name}
|
|
||||||
onClick={async () => {
|
|
||||||
setVisible(false);
|
|
||||||
const values = await FormDialog(t('Add field'), () => {
|
|
||||||
return (
|
|
||||||
<FormLayout layout={'vertical'}>
|
|
||||||
<SchemaField scope={{ loadCollections }} schema={item} />
|
|
||||||
</FormLayout>
|
|
||||||
);
|
|
||||||
}).open({
|
|
||||||
initialValues: {
|
|
||||||
interface: item.name,
|
|
||||||
...item.default,
|
|
||||||
key: uid(),
|
|
||||||
name: `f_${uid()}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await createCollectionField(collection?.name, values);
|
|
||||||
const data = appendChild({
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Table.Column',
|
|
||||||
'x-component-props': {
|
|
||||||
fieldName: values.name,
|
|
||||||
},
|
|
||||||
'x-designable-bar': 'Table.Column.DesignableBar',
|
|
||||||
});
|
|
||||||
await createSchema(data);
|
|
||||||
await refresh();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item.title}
|
|
||||||
</Menu.Item>
|
|
||||||
))}
|
|
||||||
</Menu.ItemGroup>
|
|
||||||
))}
|
|
||||||
</Menu.SubMenu>
|
|
||||||
</Menu>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Button type={'dashed'} className={'designable-btn designable-btn-dash'} icon={<SettingOutlined />}>
|
|
||||||
{t('Configure fields')}
|
|
||||||
</Button>
|
|
||||||
</Dropdown>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,15 +1,42 @@
|
|||||||
import React, { createContext, useContext, forwardRef, useState } from 'react';
|
import React, { forwardRef, useState } from 'react';
|
||||||
import { SortableContext, useSortable, horizontalListSortingStrategy } from '@dnd-kit/sortable';
|
import {
|
||||||
|
SortableContext,
|
||||||
|
useSortable,
|
||||||
|
horizontalListSortingStrategy,
|
||||||
|
verticalListSortingStrategy,
|
||||||
|
sortableKeyboardCoordinates,
|
||||||
|
} from '@dnd-kit/sortable';
|
||||||
import { CSS } from '@dnd-kit/utilities';
|
import { CSS } from '@dnd-kit/utilities';
|
||||||
|
import { Table } from 'antd';
|
||||||
|
import { createContext } from 'react';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { range } from 'lodash';
|
||||||
|
import parse from 'html-react-parser';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { DndContext, DragOverlay, useDroppable, useDraggable } from '@dnd-kit/core';
|
|
||||||
import { MenuOutlined } from '@ant-design/icons';
|
import { MenuOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
|
import {
|
||||||
|
DndContext,
|
||||||
|
DragOverlay,
|
||||||
|
closestCenter,
|
||||||
|
KeyboardSensor,
|
||||||
|
PointerSensor,
|
||||||
|
useSensor,
|
||||||
|
useSensors,
|
||||||
|
useDroppable,
|
||||||
|
useDraggable,
|
||||||
|
} from '@dnd-kit/core';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
|
import { useRef } from 'react';
|
||||||
import { SortableItem } from '../../components/Sortable';
|
import { SortableItem } from '../../components/Sortable';
|
||||||
import { findPropertyByPath, getSchemaPath, useDesignable } from '../../components/schema-renderer';
|
import {
|
||||||
|
findPropertyByPath,
|
||||||
|
getSchemaPath,
|
||||||
|
useDesignable,
|
||||||
|
} from '../../components/schema-renderer';
|
||||||
import { updateSchema } from '..';
|
import { updateSchema } from '..';
|
||||||
import { Schema } from '@formily/react';
|
import { Schema } from '@formily/react';
|
||||||
import { isColumn } from './utils';
|
import { isColumn, isColumnComponent } from '.';
|
||||||
|
|
||||||
export const RowDraggableContext = createContext({});
|
export const RowDraggableContext = createContext({});
|
||||||
export const ColDraggableContext = createContext(null);
|
export const ColDraggableContext = createContext(null);
|
||||||
@ -41,7 +68,9 @@ export function SortableColumn(props) {
|
|||||||
ref={setDroppableNodeRef}
|
ref={setDroppableNodeRef}
|
||||||
// {...attributes}
|
// {...attributes}
|
||||||
>
|
>
|
||||||
<ColDraggableContext.Provider value={{ setDraggableNodeRef, attributes, listeners }}>
|
<ColDraggableContext.Provider
|
||||||
|
value={{ setDraggableNodeRef, attributes, listeners }}
|
||||||
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
</ColDraggableContext.Provider>
|
</ColDraggableContext.Provider>
|
||||||
{/* <span ref={setDraggableNodeRef} {...attributes} {...listeners}>
|
{/* <span ref={setDraggableNodeRef} {...attributes} {...listeners}>
|
||||||
@ -52,9 +81,22 @@ export function SortableColumn(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function SortableBodyRow(props: any) {
|
export function SortableBodyRow(props: any) {
|
||||||
const { className, style: prevStyle, ['data-row-key']: dataRowKey, ...others } = props;
|
const {
|
||||||
const { isDragging, attributes, listeners, setNodeRef, setDraggableNodeRef, overIndex, transform, transition } =
|
className,
|
||||||
useSortable({ id: dataRowKey });
|
style: prevStyle,
|
||||||
|
['data-row-key']: dataRowKey,
|
||||||
|
...others
|
||||||
|
} = props;
|
||||||
|
const {
|
||||||
|
isDragging,
|
||||||
|
attributes,
|
||||||
|
listeners,
|
||||||
|
setNodeRef,
|
||||||
|
setDraggableNodeRef,
|
||||||
|
overIndex,
|
||||||
|
transform,
|
||||||
|
transition,
|
||||||
|
} = useSortable({ id: dataRowKey });
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
...prevStyle,
|
...prevStyle,
|
||||||
@ -63,9 +105,15 @@ export function SortableBodyRow(props: any) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RowDraggableContext.Provider value={{ listeners, setDraggableNodeRef, attributes }}>
|
<RowDraggableContext.Provider
|
||||||
|
value={{ listeners, setDraggableNodeRef, attributes }}
|
||||||
|
>
|
||||||
<tr
|
<tr
|
||||||
className={cls({ isDragging }, props.className, `droppable-${props['data-row-key']}`)}
|
className={cls(
|
||||||
|
{ isDragging },
|
||||||
|
props.className,
|
||||||
|
`droppable-${props['data-row-key']}`,
|
||||||
|
)}
|
||||||
// className={cls(className)}
|
// className={cls(className)}
|
||||||
ref={setNodeRef}
|
ref={setNodeRef}
|
||||||
{...others}
|
{...others}
|
||||||
@ -79,7 +127,9 @@ export function SortableBodyRow(props: any) {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{React.Children.map(props.children, (child, index) => (
|
{React.Children.map(props.children, (child, index) => (
|
||||||
<CellContext.Provider value={`td${child.key}`}>{child}</CellContext.Provider>
|
<CellContext.Provider value={`td${child.key}`}>
|
||||||
|
{child}
|
||||||
|
</CellContext.Provider>
|
||||||
))}
|
))}
|
||||||
</SortableContext>
|
</SortableContext>
|
||||||
</tr>
|
</tr>
|
||||||
@ -214,7 +264,8 @@ export function SortableBodyCell(props) {
|
|||||||
|
|
||||||
export function SortableRowHandle(props) {
|
export function SortableRowHandle(props) {
|
||||||
const { className, ...others } = props;
|
const { className, ...others } = props;
|
||||||
const { setDraggableNodeRef, attributes, listeners } = useContext<any>(RowDraggableContext);
|
const { setDraggableNodeRef, attributes, listeners } =
|
||||||
|
useContext<any>(RowDraggableContext);
|
||||||
return setDraggableNodeRef ? (
|
return setDraggableNodeRef ? (
|
||||||
<MenuOutlined
|
<MenuOutlined
|
||||||
{...others}
|
{...others}
|
||||||
|
@ -1,106 +0,0 @@
|
|||||||
import React, { useContext, useState } from 'react';
|
|
||||||
import { observer } from '@formily/react';
|
|
||||||
import cls from 'classnames';
|
|
||||||
import { DndContext, DragOverlay } from '@dnd-kit/core';
|
|
||||||
import { useDesignable } from '..';
|
|
||||||
import { DisplayedMapProvider, useClient } from '../../constate';
|
|
||||||
import { AddActionButton } from './AddActionButton';
|
|
||||||
import { Actions } from './Actions';
|
|
||||||
import { findPropertyByPath } from '../../components/schema-renderer';
|
|
||||||
|
|
||||||
export const TableActionBar = observer((props: any) => {
|
|
||||||
const { align = 'top' } = props;
|
|
||||||
// const { schema, designable } = useDesignable();
|
|
||||||
const { root, schema, insertAfter, remove, appendChild } = useDesignable();
|
|
||||||
const moveToAfter = (path1, path2, extra = {}) => {
|
|
||||||
if (!path1 || !path2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (path1.join('.') === path2.join('.')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const data = findPropertyByPath(root, path1);
|
|
||||||
if (!data) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
remove(path1);
|
|
||||||
return insertAfter(
|
|
||||||
{
|
|
||||||
...data.toJSON(),
|
|
||||||
...extra,
|
|
||||||
},
|
|
||||||
path2,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const { createSchema, removeSchema, updateSchema } = useClient();
|
|
||||||
|
|
||||||
const [dragOverlayContent, setDragOverlayContent] = useState('');
|
|
||||||
return (
|
|
||||||
<DndContext
|
|
||||||
onDragStart={(event) => {
|
|
||||||
setDragOverlayContent(event.active.data?.current?.title || '');
|
|
||||||
// const previewRef = event.active.data?.current?.previewRef;
|
|
||||||
// if (previewRef) {
|
|
||||||
// setDragOverlayContent(previewRef?.current?.innerHTML);
|
|
||||||
// } else {
|
|
||||||
// setDragOverlayContent('');
|
|
||||||
// }
|
|
||||||
}}
|
|
||||||
onDragEnd={async (event) => {
|
|
||||||
const path1 = event.active?.data?.current?.path;
|
|
||||||
const path2 = event.over?.data?.current?.path;
|
|
||||||
const align = event.over?.data?.current?.align;
|
|
||||||
const draggable = event.over?.data?.current?.draggable;
|
|
||||||
if (!path1 || !path2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (path1.join('.') === path2.join('.')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!draggable) {
|
|
||||||
console.log('alignalignalignalign', align);
|
|
||||||
const p = findPropertyByPath(root, path1);
|
|
||||||
if (!p) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
remove(path1);
|
|
||||||
const data = appendChild(
|
|
||||||
{
|
|
||||||
...p.toJSON(),
|
|
||||||
'x-align': align,
|
|
||||||
},
|
|
||||||
path2,
|
|
||||||
);
|
|
||||||
await updateSchema(data);
|
|
||||||
} else {
|
|
||||||
const data = moveToAfter(path1, path2, {
|
|
||||||
'x-align': align,
|
|
||||||
});
|
|
||||||
await updateSchema(data);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DragOverlay
|
|
||||||
dropAnimation={{
|
|
||||||
duration: 10,
|
|
||||||
easing: 'cubic-bezier(0.18, 0.67, 0.6, 1.22)',
|
|
||||||
}}
|
|
||||||
style={{ pointerEvents: 'none', whiteSpace: 'nowrap' }}
|
|
||||||
>
|
|
||||||
{dragOverlayContent}
|
|
||||||
{/* <div style={{ transform: 'translateX(-100%)' }} dangerouslySetInnerHTML={{__html: dragOverlayContent}}></div> */}
|
|
||||||
</DragOverlay>
|
|
||||||
<DisplayedMapProvider>
|
|
||||||
<div className={cls('nb-action-bar', `align-${align}`)}>
|
|
||||||
<div style={{ width: '50%' }}>
|
|
||||||
<Actions align={'left'} />
|
|
||||||
</div>
|
|
||||||
<div style={{ marginLeft: 'auto', width: '50%', textAlign: 'right' }}>
|
|
||||||
<Actions align={'right'} />
|
|
||||||
</div>
|
|
||||||
<AddActionButton />
|
|
||||||
</div>
|
|
||||||
</DisplayedMapProvider>
|
|
||||||
</DndContext>
|
|
||||||
);
|
|
||||||
});
|
|
@ -1,143 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { Select, Dropdown, Menu, Switch, Space } from 'antd';
|
|
||||||
import { MenuOutlined } from '@ant-design/icons';
|
|
||||||
import { useField } from '@formily/react';
|
|
||||||
import { FormDialog, FormLayout } from '@formily/antd';
|
|
||||||
import cls from 'classnames';
|
|
||||||
import { Trans, useTranslation } from 'react-i18next';
|
|
||||||
import { useDesignable } from '..';
|
|
||||||
import { useDisplayedMapContext, useClient } from '../../constate';
|
|
||||||
import { DragHandle } from '../../components/Sortable';
|
|
||||||
import { SchemaField } from '../../components/schema-renderer';
|
|
||||||
|
|
||||||
export const TableActionDesignableBar = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { schema, remove, refresh, insertAfter } = useDesignable();
|
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const isPopup = Object.keys(schema.properties || {}).length > 0;
|
|
||||||
const popupSchema = Object.values(schema.properties || {}).shift();
|
|
||||||
const inActionBar = schema.parent['x-component'] === 'Table.ActionBar';
|
|
||||||
const displayed = useDisplayedMapContext();
|
|
||||||
const field = useField();
|
|
||||||
const { createSchema, removeSchema, updateSchema } = useClient();
|
|
||||||
const popupComponent = popupSchema?.['x-component'] || 'Action.Drawer';
|
|
||||||
return (
|
|
||||||
<div className={cls('designable-bar', { active: visible })}>
|
|
||||||
<span
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
}}
|
|
||||||
className={cls('designable-bar-actions', { active: visible })}
|
|
||||||
>
|
|
||||||
<Space>
|
|
||||||
<DragHandle />
|
|
||||||
<Dropdown
|
|
||||||
trigger={['hover']}
|
|
||||||
visible={visible}
|
|
||||||
onVisibleChange={(visible) => {
|
|
||||||
setVisible(visible);
|
|
||||||
}}
|
|
||||||
overlay={
|
|
||||||
<Menu>
|
|
||||||
<Menu.Item
|
|
||||||
onClick={async (e) => {
|
|
||||||
setVisible(false);
|
|
||||||
const values = await FormDialog(t('Edit button'), () => {
|
|
||||||
return (
|
|
||||||
<FormLayout layout={'vertical'}>
|
|
||||||
<SchemaField
|
|
||||||
schema={{
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
title: {
|
|
||||||
type: 'string',
|
|
||||||
title: t('Display name'),
|
|
||||||
required: true,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
icon: {
|
|
||||||
type: 'string',
|
|
||||||
title: t('Icon'),
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'IconPicker',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</FormLayout>
|
|
||||||
);
|
|
||||||
}).open({
|
|
||||||
initialValues: {
|
|
||||||
title: schema['title'],
|
|
||||||
icon: schema['x-component-props']?.['icon'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
schema['title'] = values.title;
|
|
||||||
schema['x-component-props']['icon'] = values.icon;
|
|
||||||
field.componentProps.icon = values.icon;
|
|
||||||
field.title = values.title;
|
|
||||||
updateSchema(schema);
|
|
||||||
refresh();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Edit button')}
|
|
||||||
</Menu.Item>
|
|
||||||
{isPopup && (
|
|
||||||
<Menu.Item>
|
|
||||||
<Trans t={t}>
|
|
||||||
Open in
|
|
||||||
<Select
|
|
||||||
bordered={false}
|
|
||||||
size={'small'}
|
|
||||||
defaultValue={popupComponent}
|
|
||||||
style={{ width: 100 }}
|
|
||||||
onChange={async (value) => {
|
|
||||||
const s = Object.values(schema.properties).shift();
|
|
||||||
s['x-component'] = value;
|
|
||||||
refresh();
|
|
||||||
await updateSchema(s);
|
|
||||||
window.location.reload();
|
|
||||||
// const f = field.query(getSchemaPath(s)).take()
|
|
||||||
// console.log('fffffff', { schema, f });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Select.Option value={'Action.Modal'}>Modal</Select.Option>
|
|
||||||
<Select.Option value={'Action.Drawer'}>Drawer</Select.Option>
|
|
||||||
<Select.Option disabled value={'Action.Window'}>
|
|
||||||
Window
|
|
||||||
</Select.Option>
|
|
||||||
</Select>
|
|
||||||
</Trans>
|
|
||||||
</Menu.Item>
|
|
||||||
)}
|
|
||||||
{!inActionBar && (
|
|
||||||
<Menu.Item>
|
|
||||||
{t('Triggered when the row is clicked')}
|
|
||||||
<Switch size={'small'} defaultChecked />
|
|
||||||
</Menu.Item>
|
|
||||||
)}
|
|
||||||
<Menu.Divider />
|
|
||||||
<Menu.Item
|
|
||||||
onClick={async () => {
|
|
||||||
const displayName = schema?.['x-decorator-props']?.['displayName'];
|
|
||||||
const data = remove();
|
|
||||||
await removeSchema(data);
|
|
||||||
if (displayName) {
|
|
||||||
displayed.remove(displayName);
|
|
||||||
}
|
|
||||||
setVisible(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Hide')}
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<MenuOutlined />
|
|
||||||
</Dropdown>
|
|
||||||
</Space>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,54 +0,0 @@
|
|||||||
import React, { useContext } from 'react';
|
|
||||||
import { observer, RecursionField, Schema } from '@formily/react';
|
|
||||||
import { cloneDeepWith, set } from 'lodash';
|
|
||||||
import { uid, merge } from '@formily/shared';
|
|
||||||
import { CollectionFieldContext,TableRowContext } from './context';
|
|
||||||
import { Table } from '.';
|
|
||||||
|
|
||||||
export const TableCell = observer((props: any) => {
|
|
||||||
const ctx = useContext(TableRowContext);
|
|
||||||
const schema = props.schema;
|
|
||||||
const collectionField = useContext(CollectionFieldContext);
|
|
||||||
if (schema['x-component'] === 'Table.Operation') {
|
|
||||||
return <Table.Operation.Cell {...props} />;
|
|
||||||
}
|
|
||||||
let uiSchema = collectionField?.uiSchema as Schema;
|
|
||||||
if (uiSchema?.['x-component'] === 'Upload.Attachment') {
|
|
||||||
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
|
|
||||||
schema={
|
|
||||||
!collectionField
|
|
||||||
? schema
|
|
||||||
: new Schema({
|
|
||||||
type: 'void',
|
|
||||||
properties: {
|
|
||||||
[collectionField.name]: {
|
|
||||||
...uiSchema,
|
|
||||||
title: undefined,
|
|
||||||
'x-read-pretty': true,
|
|
||||||
'x-decorator-props': {
|
|
||||||
feedbackLayout: 'popover',
|
|
||||||
},
|
|
||||||
'x-decorator': 'FormilyFormItem',
|
|
||||||
'x-component-props': componentProps,
|
|
||||||
properties: {
|
|
||||||
...schema?.properties,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
name={ctx.index}
|
|
||||||
onlyRenderProperties
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
@ -1,24 +0,0 @@
|
|||||||
import React, { useContext, useEffect } from 'react';
|
|
||||||
import { observer } from '@formily/react';
|
|
||||||
import { useDesignable } from '..';
|
|
||||||
import { useDisplayedMapContext } from '../../constate';
|
|
||||||
import { useCompile } from '../../hooks/useCompile';
|
|
||||||
import { CollectionFieldContext } from './context';
|
|
||||||
|
|
||||||
export const TableColumn = observer((props: any) => {
|
|
||||||
const collectionField = useContext(CollectionFieldContext);
|
|
||||||
const { schema, DesignableBar } = useDesignable();
|
|
||||||
const compile = useCompile();
|
|
||||||
const displayed = useDisplayedMapContext();
|
|
||||||
useEffect(() => {
|
|
||||||
if (collectionField?.name) {
|
|
||||||
displayed.set(collectionField.name, schema);
|
|
||||||
}
|
|
||||||
}, [collectionField, schema]);
|
|
||||||
return (
|
|
||||||
<div className={'nb-table-column'}>
|
|
||||||
{compile(schema.title || collectionField?.uiSchema?.title)}
|
|
||||||
<DesignableBar />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
@ -1,158 +0,0 @@
|
|||||||
import React, { useContext, useState } from 'react';
|
|
||||||
import { useField } from '@formily/react';
|
|
||||||
import { Select, Dropdown, Menu, Space } from 'antd';
|
|
||||||
import { set } from 'lodash';
|
|
||||||
import cls from 'classnames';
|
|
||||||
import { MenuOutlined } from '@ant-design/icons';
|
|
||||||
import { FormDialog, FormLayout, Submit } from '@formily/antd';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { SchemaField } from '../../components/schema-renderer';
|
|
||||||
import { useCollectionsContext, useDisplayedMapContext, useClient } from '../../constate';
|
|
||||||
import { DragHandle } from '../../components/Sortable';
|
|
||||||
import { useDesignable } from '..';
|
|
||||||
import { useCompile } from '../../hooks/useCompile';
|
|
||||||
import { useTable } from './hooks/useTable';
|
|
||||||
import { CollectionFieldContext } from './hooks/useTableColumns';
|
|
||||||
|
|
||||||
export const TableColumnDesignableBar = () => {
|
|
||||||
const field = useField();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const compile = useCompile();
|
|
||||||
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);
|
|
||||||
const { createSchema, removeSchema, updateSchema } = useClient();
|
|
||||||
console.log('displayed.map', displayed.map);
|
|
||||||
return (
|
|
||||||
<div className={cls('designable-bar', { active: visible })}>
|
|
||||||
<span
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
}}
|
|
||||||
className={cls('designable-bar-actions', { active: visible })}
|
|
||||||
>
|
|
||||||
<Space>
|
|
||||||
<DragHandle />
|
|
||||||
<Dropdown
|
|
||||||
trigger={['hover']}
|
|
||||||
visible={visible}
|
|
||||||
onVisibleChange={(visible) => {
|
|
||||||
setVisible(visible);
|
|
||||||
}}
|
|
||||||
overlay={
|
|
||||||
<Menu>
|
|
||||||
<Menu.Item
|
|
||||||
onClick={async (e) => {
|
|
||||||
setVisible(false);
|
|
||||||
const values = await FormDialog(t('Custom name'), () => {
|
|
||||||
return (
|
|
||||||
<FormLayout layout={'vertical'}>
|
|
||||||
<SchemaField
|
|
||||||
schema={{
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
fieldName: {
|
|
||||||
type: 'string',
|
|
||||||
title: t('Original name'),
|
|
||||||
'x-read-pretty': true,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: 'string',
|
|
||||||
title: t('Custom name'),
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</FormLayout>
|
|
||||||
);
|
|
||||||
}).open({
|
|
||||||
initialValues: {
|
|
||||||
fieldName: collectionField?.uiSchema?.title,
|
|
||||||
title: schema['title'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const title = values.title || null;
|
|
||||||
field.title = title;
|
|
||||||
schema.title = title;
|
|
||||||
refresh();
|
|
||||||
await updateSchema({
|
|
||||||
key: schema['key'],
|
|
||||||
title: title,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Custom column name')}
|
|
||||||
</Menu.Item>
|
|
||||||
{collectionField?.interface === 'linkTo' && (
|
|
||||||
<Menu.Item>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Label field')}{' '}
|
|
||||||
<Select
|
|
||||||
value={schema?.['x-component-props']?.['fieldNames']?.['label']}
|
|
||||||
placeholder={t('Default is the ID field')}
|
|
||||||
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: compile(field?.uiSchema?.title || field.name),
|
|
||||||
value: field.name,
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Menu.Item>
|
|
||||||
)}
|
|
||||||
<Menu.Divider />
|
|
||||||
<Menu.Item
|
|
||||||
onClick={async () => {
|
|
||||||
const fieldName = schema['x-component-props']?.['fieldName'];
|
|
||||||
displayed.remove(fieldName);
|
|
||||||
schema['x-hidden'] = true;
|
|
||||||
refresh();
|
|
||||||
await updateSchema({
|
|
||||||
key: schema['key'],
|
|
||||||
['x-hidden']: true,
|
|
||||||
});
|
|
||||||
// const s = remove();
|
|
||||||
// await removeSchema(s);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Hide')}
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<MenuOutlined />
|
|
||||||
</Dropdown>
|
|
||||||
</Space>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,275 +0,0 @@
|
|||||||
import React, { useContext, useState } from 'react';
|
|
||||||
import { Modal, Select, Dropdown, Menu, Switch, Space } from 'antd';
|
|
||||||
import { MenuOutlined } from '@ant-design/icons';
|
|
||||||
import { set } from 'lodash';
|
|
||||||
import { observer, useField } from '@formily/react';
|
|
||||||
import { FormDialog, FormLayout } from '@formily/antd';
|
|
||||||
import cls from 'classnames';
|
|
||||||
import { Trans, useTranslation } from 'react-i18next';
|
|
||||||
import { useCompile } from '../../hooks/useCompile';
|
|
||||||
import { useDesignable } from '..';
|
|
||||||
import { DraggableBlockContext } from '../../components/drag-and-drop';
|
|
||||||
import { useCollection, useClient } from '../../constate';
|
|
||||||
import AddNew from '../add-new';
|
|
||||||
import { SchemaField } from '../../components/schema-renderer';
|
|
||||||
import { DragHandle } from '../../components/Sortable';
|
|
||||||
import { fieldsToSortColumns, fieldsToFilterColumns } from './utils';
|
|
||||||
|
|
||||||
export const TableDesignableBar = observer((props) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const compile = useCompile();
|
|
||||||
const field = useField();
|
|
||||||
const { schema, refresh, deepRemove } = useDesignable();
|
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const { dragRef } = useContext(DraggableBlockContext);
|
|
||||||
const defaultPageSize = field?.componentProps?.pagination?.defaultPageSize || 10;
|
|
||||||
const collectionName = field?.componentProps?.collectionName;
|
|
||||||
const { collection, fields } = useCollection({ collectionName });
|
|
||||||
const { createSchema, removeSchema, updateSchema } = useClient();
|
|
||||||
console.log({ collectionName });
|
|
||||||
return (
|
|
||||||
<div className={cls('designable-bar', { active: visible })}>
|
|
||||||
<div className={'designable-info'}>{compile(collection?.title || collection?.name)}</div>
|
|
||||||
<span
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
}}
|
|
||||||
className={cls('designable-bar-actions', { active: visible })}
|
|
||||||
>
|
|
||||||
<Space size={2}>
|
|
||||||
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
|
||||||
<DragHandle />
|
|
||||||
<Dropdown
|
|
||||||
trigger={['hover']}
|
|
||||||
visible={visible}
|
|
||||||
onVisibleChange={(visible) => {
|
|
||||||
setVisible(visible);
|
|
||||||
}}
|
|
||||||
overlay={
|
|
||||||
<Menu>
|
|
||||||
<Menu.Item
|
|
||||||
key={'showIndex'}
|
|
||||||
onClick={() => {
|
|
||||||
const bool = !field.componentProps.showIndex;
|
|
||||||
schema['x-component-props']['showIndex'] = bool;
|
|
||||||
field.componentProps.showIndex = bool;
|
|
||||||
updateSchema(schema);
|
|
||||||
setVisible(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className={'nb-space-between'}>
|
|
||||||
{t('Display order number')} <Switch size={'small'} checked={field.componentProps.showIndex} />
|
|
||||||
</div>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item
|
|
||||||
key={'dragSort'}
|
|
||||||
onClick={() => {
|
|
||||||
const dragSort = field.componentProps.dragSort ? false : 'sort';
|
|
||||||
schema['x-component-props']['dragSort'] = dragSort;
|
|
||||||
field.componentProps.dragSort = dragSort;
|
|
||||||
updateSchema(schema);
|
|
||||||
setVisible(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className={'nb-space-between'}>
|
|
||||||
{t('Enable drag and drop sorting')}
|
|
||||||
|
|
||||||
<Switch size={'small'} checked={field.componentProps.dragSort} />
|
|
||||||
</div>
|
|
||||||
</Menu.Item>
|
|
||||||
{!field.componentProps.dragSort && (
|
|
||||||
<Menu.Item
|
|
||||||
key={'defaultSort'}
|
|
||||||
onClick={async () => {
|
|
||||||
const defaultSort = field.componentProps?.defaultSort?.map((item: string) => {
|
|
||||||
return item.startsWith('-')
|
|
||||||
? {
|
|
||||||
field: item.substring(1),
|
|
||||||
direction: 'desc',
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
field: item,
|
|
||||||
direction: 'asc',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
const values = await FormDialog(t('Set default sorting rules'), () => {
|
|
||||||
return (
|
|
||||||
<FormLayout layout={'vertical'}>
|
|
||||||
<SchemaField
|
|
||||||
schema={{
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
defaultSort: {
|
|
||||||
type: 'array',
|
|
||||||
'x-component': 'ArrayItems',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
items: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
space: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Space',
|
|
||||||
properties: {
|
|
||||||
sort: {
|
|
||||||
type: 'void',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'ArrayItems.SortHandle',
|
|
||||||
},
|
|
||||||
field: {
|
|
||||||
type: 'string',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Select',
|
|
||||||
enum: fieldsToSortColumns(fields),
|
|
||||||
'x-component-props': {
|
|
||||||
style: {
|
|
||||||
width: 260,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
direction: {
|
|
||||||
type: 'string',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Radio.Group',
|
|
||||||
'x-component-props': {
|
|
||||||
optionType: 'button',
|
|
||||||
},
|
|
||||||
enum: [
|
|
||||||
{
|
|
||||||
label: t('ASC'),
|
|
||||||
value: 'asc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('DESC'),
|
|
||||||
value: 'desc',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
remove: {
|
|
||||||
type: 'void',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'ArrayItems.Remove',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
add: {
|
|
||||||
type: 'void',
|
|
||||||
title: t('Add sort field'),
|
|
||||||
'x-component': 'ArrayItems.Addition',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</FormLayout>
|
|
||||||
);
|
|
||||||
}).open({
|
|
||||||
initialValues: {
|
|
||||||
defaultSort,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const sort = values.defaultSort.map((item) => {
|
|
||||||
return item.direction === 'desc' ? `-${item.field}` : item.field;
|
|
||||||
});
|
|
||||||
schema['x-component-props']['defaultSort'] = sort;
|
|
||||||
field.componentProps.defaultSort = sort;
|
|
||||||
await updateSchema(schema);
|
|
||||||
setVisible(false);
|
|
||||||
console.log('defaultSort', sort);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Set default sorting rules')}
|
|
||||||
</Menu.Item>
|
|
||||||
)}
|
|
||||||
<Menu.Item
|
|
||||||
key={'defaultFilter'}
|
|
||||||
onClick={async () => {
|
|
||||||
const { defaultFilter } = await FormDialog(t('Set the data scope'), () => {
|
|
||||||
return (
|
|
||||||
<FormLayout layout={'vertical'}>
|
|
||||||
<SchemaField
|
|
||||||
schema={{
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
defaultFilter: {
|
|
||||||
type: 'object',
|
|
||||||
'x-component': 'Filter',
|
|
||||||
properties: fieldsToFilterColumns(fields),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</FormLayout>
|
|
||||||
);
|
|
||||||
}).open({
|
|
||||||
initialValues: {
|
|
||||||
defaultFilter: field?.componentProps?.defaultFilter || {},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
schema['x-component-props']['defaultFilter'] = defaultFilter;
|
|
||||||
field.componentProps.defaultFilter = defaultFilter;
|
|
||||||
await updateSchema(schema);
|
|
||||||
setVisible(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Set the data scope')}
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key={'defaultPageSize'}>
|
|
||||||
<Trans>
|
|
||||||
{'Display '}
|
|
||||||
<Select
|
|
||||||
bordered={false}
|
|
||||||
size={'small'}
|
|
||||||
onChange={(value) => {
|
|
||||||
const componentProps = schema['x-component-props'] || {};
|
|
||||||
set(componentProps, 'pagination.defaultPageSize', value);
|
|
||||||
set(componentProps, 'pagination.pageSize', value);
|
|
||||||
schema['x-component-props'] = componentProps;
|
|
||||||
field.componentProps.pagination.pageSize = value;
|
|
||||||
field.componentProps.pagination.defaultPageSize = value;
|
|
||||||
refresh();
|
|
||||||
updateSchema(schema);
|
|
||||||
setVisible(false);
|
|
||||||
}}
|
|
||||||
defaultValue={defaultPageSize}
|
|
||||||
>
|
|
||||||
<Select.Option value={10}>10</Select.Option>
|
|
||||||
<Select.Option value={20}>20</Select.Option>
|
|
||||||
<Select.Option value={50}>50</Select.Option>
|
|
||||||
<Select.Option value={100}>100</Select.Option>
|
|
||||||
</Select>
|
|
||||||
{' items per page'}
|
|
||||||
</Trans>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Divider />
|
|
||||||
<Menu.Item
|
|
||||||
key={'delete'}
|
|
||||||
onClick={async () => {
|
|
||||||
Modal.confirm({
|
|
||||||
title: t('Delete block'),
|
|
||||||
content: t('Are you sure you want to delete it?'),
|
|
||||||
onOk: async () => {
|
|
||||||
const removed = deepRemove();
|
|
||||||
// console.log({ removed })
|
|
||||||
const last = removed.pop();
|
|
||||||
await removeSchema(last);
|
|
||||||
setVisible(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Delete')}
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<MenuOutlined />
|
|
||||||
</Dropdown>
|
|
||||||
</Space>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
@ -1,134 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { Dropdown, Menu, Space } from 'antd';
|
|
||||||
import { useField } from '@formily/react';
|
|
||||||
import { FormDialog, FormLayout } from '@formily/antd';
|
|
||||||
import { MenuOutlined } from '@ant-design/icons';
|
|
||||||
import cls from 'classnames';
|
|
||||||
import { Trans, useTranslation } from 'react-i18next';
|
|
||||||
import { DragHandle } from '../../components/Sortable';
|
|
||||||
import { useDesignable } from '..';
|
|
||||||
import { useCollectionContext, useDisplayedMapContext, useClient } from '../../constate';
|
|
||||||
import SwitchMenuItem from '../../components/SwitchMenuItem';
|
|
||||||
import { SchemaField } from '../../components/schema-renderer';
|
|
||||||
|
|
||||||
export const TableExportActionDesignableBar = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { schema, remove, refresh, insertAfter } = useDesignable();
|
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const displayed = useDisplayedMapContext();
|
|
||||||
const { fields } = useCollectionContext();
|
|
||||||
const field = useField();
|
|
||||||
const { createSchema, removeSchema, updateSchema } = useClient();
|
|
||||||
let fieldNames = field.componentProps.fieldNames || [];
|
|
||||||
if (fieldNames.length === 0) {
|
|
||||||
fieldNames = fields.map((field) => field.name);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className={cls('designable-bar', { active: visible })}>
|
|
||||||
<span
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
}}
|
|
||||||
className={cls('designable-bar-actions', { active: visible })}
|
|
||||||
>
|
|
||||||
<Space>
|
|
||||||
<DragHandle />
|
|
||||||
<Dropdown
|
|
||||||
trigger={['hover']}
|
|
||||||
visible={visible}
|
|
||||||
onVisibleChange={(visible) => {
|
|
||||||
setVisible(visible);
|
|
||||||
}}
|
|
||||||
overlay={
|
|
||||||
<Menu>
|
|
||||||
<Menu.ItemGroup title={t('Export fields')}>
|
|
||||||
{fields.map((collectionField) => (
|
|
||||||
<SwitchMenuItem
|
|
||||||
title={collectionField?.uiSchema?.title}
|
|
||||||
checked={fieldNames.includes(collectionField.name)}
|
|
||||||
onChange={async (checked) => {
|
|
||||||
if (checked) {
|
|
||||||
fieldNames.push(collectionField.name);
|
|
||||||
} else {
|
|
||||||
const index = fieldNames.indexOf(collectionField.name);
|
|
||||||
if (index > -1) {
|
|
||||||
fieldNames.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log({ fieldNames, field });
|
|
||||||
schema['x-component-props']['fieldNames'] = fieldNames;
|
|
||||||
field.componentProps.fieldNames = fieldNames;
|
|
||||||
updateSchema(schema);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Menu.ItemGroup>
|
|
||||||
<Menu.Divider />
|
|
||||||
<Menu.Item
|
|
||||||
onClick={async (e) => {
|
|
||||||
setVisible(false);
|
|
||||||
const values = await FormDialog(t('Edit button'), () => {
|
|
||||||
return (
|
|
||||||
<FormLayout layout={'vertical'}>
|
|
||||||
<SchemaField
|
|
||||||
schema={{
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
title: {
|
|
||||||
type: 'string',
|
|
||||||
title: t('Display name'),
|
|
||||||
required: true,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
icon: {
|
|
||||||
type: 'string',
|
|
||||||
title: t('Icon'),
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'IconPicker',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</FormLayout>
|
|
||||||
);
|
|
||||||
}).open({
|
|
||||||
initialValues: {
|
|
||||||
title: schema['title'],
|
|
||||||
icon: schema['x-component-props']?.['icon'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
schema['title'] = values.title;
|
|
||||||
schema['x-component-props']['icon'] = values.icon;
|
|
||||||
field.componentProps.icon = values.icon;
|
|
||||||
field.title = values.title;
|
|
||||||
updateSchema(schema);
|
|
||||||
refresh();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Edit button')}
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Divider />
|
|
||||||
<Menu.Item
|
|
||||||
onClick={async () => {
|
|
||||||
const displayName = schema?.['x-decorator-props']?.['displayName'];
|
|
||||||
const data = remove();
|
|
||||||
await removeSchema(data);
|
|
||||||
if (displayName) {
|
|
||||||
displayed.remove(displayName);
|
|
||||||
}
|
|
||||||
setVisible(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Hide')}
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<MenuOutlined />
|
|
||||||
</Dropdown>
|
|
||||||
</Space>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,92 +0,0 @@
|
|||||||
import React, { useMemo, useState } from 'react';
|
|
||||||
import { Popover, Button, } from 'antd';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import flatten from 'flat';
|
|
||||||
import { createForm } from '@formily/core';
|
|
||||||
import { FormProvider, observer } from '@formily/react';
|
|
||||||
import { FormButtonGroup, Submit } from '@formily/antd';
|
|
||||||
import { interfaces } from '../database-field/interfaces';
|
|
||||||
import { useDesignable } from '..';
|
|
||||||
import { useCollectionContext, } from '../../constate';
|
|
||||||
import { SchemaField } from '../../components/schema-renderer';
|
|
||||||
import { useTable } from './hooks/useTable';
|
|
||||||
import { useCompile } from '../../hooks/useCompile';
|
|
||||||
import IconPicker from '../../components/icon-picker';
|
|
||||||
|
|
||||||
export const TableFilter = observer((props: any) => {
|
|
||||||
const { service } = useTable();
|
|
||||||
const { fieldNames = [] } = props;
|
|
||||||
const compile = useCompile();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { schema, DesignableBar } = useDesignable();
|
|
||||||
const form = useMemo(() => createForm(), []);
|
|
||||||
const { fields = [] } = useCollectionContext();
|
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const obj = flatten(form.values.filter || {});
|
|
||||||
console.log('flatten', obj, Object.values(obj));
|
|
||||||
const count = Object.values(obj).filter((i) => (Array.isArray(i) ? i.length : i)).length;
|
|
||||||
const icon = props.icon || 'FilterOutlined';
|
|
||||||
const properties = fieldsToFilterColumns(fields, { fieldNames });
|
|
||||||
schema.mapProperties((p) => {
|
|
||||||
properties[p.name] = p;
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<Popover
|
|
||||||
trigger={['click']}
|
|
||||||
placement={'bottomLeft'}
|
|
||||||
visible={visible}
|
|
||||||
onVisibleChange={setVisible}
|
|
||||||
content={
|
|
||||||
<div>
|
|
||||||
<FormProvider form={form}>
|
|
||||||
<SchemaField
|
|
||||||
schema={{
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
filter: {
|
|
||||||
type: 'object',
|
|
||||||
'x-component': 'Filter',
|
|
||||||
properties,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<FormButtonGroup align={'right'}>
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
setVisible(false);
|
|
||||||
form.reset();
|
|
||||||
const { filter } = form.values;
|
|
||||||
return service.run({
|
|
||||||
...service.params[0],
|
|
||||||
filter,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Reset')}
|
|
||||||
</Button>
|
|
||||||
<Submit
|
|
||||||
onSubmit={() => {
|
|
||||||
const { filter } = form.values;
|
|
||||||
console.log('Table.Filter', form.values);
|
|
||||||
setVisible(false);
|
|
||||||
return service.run({
|
|
||||||
...service.params[0],
|
|
||||||
filter,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Submit')}
|
|
||||||
</Submit>
|
|
||||||
</FormButtonGroup>
|
|
||||||
</FormProvider>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Button icon={<IconPicker type={icon} />}>
|
|
||||||
{count > 0 ? t('{{count}} filter items', { count }) : compile(schema.title)}
|
|
||||||
<DesignableBar />
|
|
||||||
</Button>
|
|
||||||
</Popover>
|
|
||||||
);
|
|
||||||
});
|
|
@ -1,140 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { Dropdown, Menu, Space } from 'antd';
|
|
||||||
import { useField } from '@formily/react';
|
|
||||||
import { FormDialog, FormLayout } from '@formily/antd';
|
|
||||||
import { MenuOutlined } from '@ant-design/icons';
|
|
||||||
import cls from 'classnames';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { DragHandle } from '../../components/Sortable';
|
|
||||||
import { interfaces } from '../database-field/interfaces';
|
|
||||||
import { useDesignable } from '..';
|
|
||||||
import { useCollectionContext, useDisplayedMapContext, useClient } from '../../constate';
|
|
||||||
import SwitchMenuItem from '../../components/SwitchMenuItem';
|
|
||||||
import { SchemaField } from '../../components/schema-renderer';
|
|
||||||
|
|
||||||
export const TableFilterDesignableBar = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { schema, remove, refresh, insertAfter } = useDesignable();
|
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const displayed = useDisplayedMapContext();
|
|
||||||
const { fields } = useCollectionContext();
|
|
||||||
const field = useField();
|
|
||||||
const { createSchema, removeSchema, updateSchema } = useClient();
|
|
||||||
let fieldNames = field.componentProps.fieldNames || [];
|
|
||||||
if (fieldNames.length === 0) {
|
|
||||||
fieldNames = fields.map((field) => field.name);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className={cls('designable-bar', { active: visible })}>
|
|
||||||
<span
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
}}
|
|
||||||
className={cls('designable-bar-actions', { active: visible })}
|
|
||||||
>
|
|
||||||
<Space>
|
|
||||||
<DragHandle />
|
|
||||||
<Dropdown
|
|
||||||
trigger={['hover']}
|
|
||||||
visible={visible}
|
|
||||||
onVisibleChange={(visible) => {
|
|
||||||
setVisible(visible);
|
|
||||||
}}
|
|
||||||
overlay={
|
|
||||||
<Menu>
|
|
||||||
<Menu.ItemGroup title={t('Filterable fields')}>
|
|
||||||
{fields
|
|
||||||
.filter((collectionField) => {
|
|
||||||
const option = interfaces.get(collectionField.interface);
|
|
||||||
return option?.operations?.length;
|
|
||||||
})
|
|
||||||
.map((collectionField) => (
|
|
||||||
<SwitchMenuItem
|
|
||||||
title={collectionField?.uiSchema?.title}
|
|
||||||
checked={fieldNames.includes(collectionField.name)}
|
|
||||||
onChange={async (checked) => {
|
|
||||||
if (checked) {
|
|
||||||
fieldNames.push(collectionField.name);
|
|
||||||
} else {
|
|
||||||
const index = fieldNames.indexOf(collectionField.name);
|
|
||||||
if (index > -1) {
|
|
||||||
fieldNames.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log({ fieldNames, field });
|
|
||||||
schema['x-component-props']['fieldNames'] = fieldNames;
|
|
||||||
field.componentProps.fieldNames = fieldNames;
|
|
||||||
updateSchema(schema);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Menu.ItemGroup>
|
|
||||||
<Menu.Divider />
|
|
||||||
<Menu.Item
|
|
||||||
onClick={async (e) => {
|
|
||||||
setVisible(false);
|
|
||||||
const values = await FormDialog(t('Edit button'), () => {
|
|
||||||
return (
|
|
||||||
<FormLayout layout={'vertical'}>
|
|
||||||
<SchemaField
|
|
||||||
schema={{
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
title: {
|
|
||||||
type: 'string',
|
|
||||||
title: t('Display name'),
|
|
||||||
required: true,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
icon: {
|
|
||||||
type: 'string',
|
|
||||||
title: t('Icon'),
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'IconPicker',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</FormLayout>
|
|
||||||
);
|
|
||||||
}).open({
|
|
||||||
initialValues: {
|
|
||||||
title: schema['title'],
|
|
||||||
icon: schema['x-component-props']?.['icon'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
schema['title'] = values.title;
|
|
||||||
schema['x-component-props']['icon'] = values.icon;
|
|
||||||
field.componentProps.icon = values.icon;
|
|
||||||
field.title = values.title;
|
|
||||||
updateSchema(schema);
|
|
||||||
refresh();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Edit button')}
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Divider />
|
|
||||||
<Menu.Item
|
|
||||||
onClick={async () => {
|
|
||||||
const displayName = schema?.['x-decorator-props']?.['displayName'];
|
|
||||||
const data = remove();
|
|
||||||
await removeSchema(data);
|
|
||||||
if (displayName) {
|
|
||||||
displayed.remove(displayName);
|
|
||||||
}
|
|
||||||
setVisible(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Hide')}
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<MenuOutlined />
|
|
||||||
</Dropdown>
|
|
||||||
</Space>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,8 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { observer } from '@formily/react';
|
|
||||||
import { useTableIndex } from './hooks/useTableIndex';
|
|
||||||
|
|
||||||
export const TableIndex = observer(() => {
|
|
||||||
const index = useTableIndex();
|
|
||||||
return <span className={'nb-table-index'}>{index + 1}</span>;
|
|
||||||
});
|
|
@ -1,139 +0,0 @@
|
|||||||
import React, { DndContext } from '@dnd-kit/core';
|
|
||||||
import { useState } from 'react';
|
|
||||||
import { Table as AntdTable } from 'antd';
|
|
||||||
import { findIndex } from 'lodash';
|
|
||||||
import cls from 'classnames';
|
|
||||||
import { RecursionField, Schema } from '@formily/react';
|
|
||||||
import { isValid } from '@formily/shared';
|
|
||||||
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
|
||||||
import { SortableBodyRow, SortableHeaderCell, SortableHeaderRow } from './Sortable';
|
|
||||||
import { TableRowContext } from './context';
|
|
||||||
import { useDataSource } from './hooks/useDataSource';
|
|
||||||
import { useDefaultRowSelection } from './hooks/useDefaultRowSelection';
|
|
||||||
import { useTable } from './hooks/useTable';
|
|
||||||
import { useTableActionBars } from './hooks/useTableActionBars';
|
|
||||||
import { useTableColumns } from './hooks/useTableColumns';
|
|
||||||
import { Table } from '.';
|
|
||||||
|
|
||||||
export const TableMain = () => {
|
|
||||||
const {
|
|
||||||
resource,
|
|
||||||
selectedRowKeys,
|
|
||||||
setSelectedRowKeys,
|
|
||||||
service,
|
|
||||||
field,
|
|
||||||
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
|
|
||||||
onDragEnd={async (event) => {
|
|
||||||
const fromId = event.active?.id as any;
|
|
||||||
const toId = event.over?.id as any;
|
|
||||||
if (isValid(fromId) && isValid(toId)) {
|
|
||||||
const fromIndex = findIndex(field.value, (item) => item[rowKey] === fromId);
|
|
||||||
const toIndex = findIndex(field.value, (item) => item[rowKey] === toId);
|
|
||||||
console.log({ fromId, toId, fromIndex, toIndex });
|
|
||||||
field.move(fromIndex, toIndex);
|
|
||||||
refresh();
|
|
||||||
await resource.sort({
|
|
||||||
resourceKey: fromId,
|
|
||||||
target: {
|
|
||||||
[rowKey]: toId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await service.refresh();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{actionBars.map((actionBar) => (
|
|
||||||
<RecursionField
|
|
||||||
schema={
|
|
||||||
new Schema({
|
|
||||||
type: 'void',
|
|
||||||
properties: {
|
|
||||||
[actionBar.name]: actionBar,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
<SortableContext items={dataSource || []} strategy={verticalListSortingStrategy}>
|
|
||||||
<AntdTable
|
|
||||||
pagination={false}
|
|
||||||
onChange={(pagination) => {}}
|
|
||||||
loading={service?.loading}
|
|
||||||
rowKey={rowKey}
|
|
||||||
dataSource={dataSource}
|
|
||||||
columns={columns}
|
|
||||||
// components={{
|
|
||||||
// body: {
|
|
||||||
// row: DragableBodyRow,
|
|
||||||
// },
|
|
||||||
// }}
|
|
||||||
components={{
|
|
||||||
header: {
|
|
||||||
row: SortableHeaderRow,
|
|
||||||
cell: SortableHeaderCell,
|
|
||||||
},
|
|
||||||
body: {
|
|
||||||
// wrapper: (props) => {
|
|
||||||
// return (
|
|
||||||
// <tbody {...props}>
|
|
||||||
// <DragOverlay
|
|
||||||
// className={'ant-table-row'}
|
|
||||||
// wrapperElement={'tr'}
|
|
||||||
// >
|
|
||||||
// <div />
|
|
||||||
// </DragOverlay>
|
|
||||||
// {props.children}
|
|
||||||
// </tbody>
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
row: SortableBodyRow,
|
|
||||||
// cell: SortableBodyCell,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
rowSelection={{
|
|
||||||
type: type || 'checkbox',
|
|
||||||
selectedRowKeys,
|
|
||||||
onChange: (rowKeys, rows) => {
|
|
||||||
setSelectedRowKeys(rowKeys);
|
|
||||||
onSelect && onSelect(rowKeys, rows);
|
|
||||||
},
|
|
||||||
renderCell: (checked, record, _, originNode) => {
|
|
||||||
const index = findIndex(field.value, (item) => item[rowKey] === record[rowKey]);
|
|
||||||
return (
|
|
||||||
<TableRowContext.Provider
|
|
||||||
value={{
|
|
||||||
index,
|
|
||||||
record,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={cls('nb-table-selection', {
|
|
||||||
dragSort,
|
|
||||||
showIndex,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{dragSort && <Table.SortHandle />}
|
|
||||||
{showIndex && <Table.Index />}
|
|
||||||
{originNode}
|
|
||||||
</div>
|
|
||||||
</TableRowContext.Provider>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</SortableContext>
|
|
||||||
</DndContext>
|
|
||||||
<Table.Pagination />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,16 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { observer } from '@formily/react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useDesignable } from '..';
|
|
||||||
import { Table } from '.';
|
|
||||||
|
|
||||||
export const TableOperation = observer((props: any) => {
|
|
||||||
const { designable, schema } = useDesignable();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
return (
|
|
||||||
<div className={'nb-table-column'}>
|
|
||||||
{t('Operations')}
|
|
||||||
<Table.Operation.DesignableBar path={props.path} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
@ -1,13 +0,0 @@
|
|||||||
import React, { useContext } from 'react';
|
|
||||||
import { observer, RecursionField } from '@formily/react';
|
|
||||||
import { TableRowContext } from './context';
|
|
||||||
|
|
||||||
export const TableOperationCell = observer((props: any) => {
|
|
||||||
const ctx = useContext(TableRowContext);
|
|
||||||
const schema = props.schema;
|
|
||||||
return (
|
|
||||||
<div className={'nb-table-column'}>
|
|
||||||
<RecursionField schema={schema} name={ctx.index} onlyRenderProperties />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
@ -1,194 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { Dropdown, Menu, Space } from 'antd';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { uid, merge } from '@formily/shared';
|
|
||||||
import cls from 'classnames';
|
|
||||||
import { MenuOutlined } from '@ant-design/icons';
|
|
||||||
import { useDesignable, ISchema } from '..';
|
|
||||||
import { getSchemaPath } from '../../components/schema-renderer';
|
|
||||||
import { useClient } from '../../constate';
|
|
||||||
import SwitchMenuItem from '../../components/SwitchMenuItem';
|
|
||||||
import { DragHandle } from '../../components/Sortable';
|
|
||||||
|
|
||||||
export const TableOperationDesignableBar = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { schema: columnSchema } = useDesignable();
|
|
||||||
const groupSchema = Object.values(columnSchema.properties || {}).shift();
|
|
||||||
const groupPath = getSchemaPath(groupSchema);
|
|
||||||
const { schema, remove, refresh, appendChild } = useDesignable(groupPath);
|
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const { createSchema, removeSchema, updateSchema } = useClient();
|
|
||||||
|
|
||||||
const map = new Map();
|
|
||||||
schema.mapProperties((s) => {
|
|
||||||
if (!s['x-action-type']) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
map.set(s['x-action-type'], s.name);
|
|
||||||
});
|
|
||||||
const path = getSchemaPath(schema);
|
|
||||||
return (
|
|
||||||
<div className={cls('designable-bar', { active: visible })}>
|
|
||||||
<span
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
}}
|
|
||||||
className={cls('designable-bar-actions', { active: visible })}
|
|
||||||
>
|
|
||||||
<Space>
|
|
||||||
<DragHandle />
|
|
||||||
<Dropdown
|
|
||||||
trigger={['hover']}
|
|
||||||
visible={visible}
|
|
||||||
onVisibleChange={(visible) => {
|
|
||||||
setVisible(visible);
|
|
||||||
}}
|
|
||||||
overlay={
|
|
||||||
<Menu>
|
|
||||||
<Menu.ItemGroup title={t('Enable actions')}>
|
|
||||||
{[
|
|
||||||
{ title: t('View'), name: 'view' },
|
|
||||||
{ title: t('Edit'), name: 'update' },
|
|
||||||
{ title: t('Delete'), name: 'destroy' },
|
|
||||||
].map((item) => (
|
|
||||||
<SwitchMenuItem
|
|
||||||
key={item.name}
|
|
||||||
title={item.title}
|
|
||||||
checked={map.has(item.name)}
|
|
||||||
onChange={async (checked) => {
|
|
||||||
if (checked) {
|
|
||||||
const s = generateMenuActionSchema(item.name);
|
|
||||||
const data = appendChild(s);
|
|
||||||
await createSchema(data);
|
|
||||||
} else if (map.get(item.name)) {
|
|
||||||
const removed = remove([...path, map.get(item.name)]);
|
|
||||||
await removeSchema(removed);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Menu.ItemGroup>
|
|
||||||
<Menu.Divider />
|
|
||||||
<Menu.SubMenu disabled title={t('Customize')}>
|
|
||||||
<Menu.Item style={{ minWidth: 120 }}>{t('Function')}</Menu.Item>
|
|
||||||
<Menu.Item>{t('Popup form')}</Menu.Item>
|
|
||||||
<Menu.Item>{t('Flexible popup')}</Menu.Item>
|
|
||||||
</Menu.SubMenu>
|
|
||||||
</Menu>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<MenuOutlined />
|
|
||||||
</Dropdown>
|
|
||||||
</Space>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
function generateMenuActionSchema(type) {
|
|
||||||
const actions: { [key: string]: ISchema } = {
|
|
||||||
view: {
|
|
||||||
key: uid(),
|
|
||||||
name: uid(),
|
|
||||||
type: 'void',
|
|
||||||
title: "{{ t('View') }}",
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': {
|
|
||||||
type: 'link',
|
|
||||||
},
|
|
||||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
|
||||||
'x-action-type': 'view',
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
title: "{{ t('View record') }}",
|
|
||||||
'x-component': 'Action.Drawer',
|
|
||||||
'x-component-props': {
|
|
||||||
bodyStyle: {
|
|
||||||
background: '#f0f2f5',
|
|
||||||
// paddingTop: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Tabs',
|
|
||||||
'x-designable-bar': 'Tabs.DesignableBar',
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
title: "{{ t('Details') }}",
|
|
||||||
'x-designable-bar': 'Tabs.TabPane.DesignableBar',
|
|
||||||
'x-component': 'Tabs.TabPane',
|
|
||||||
'x-component-props': {},
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Grid',
|
|
||||||
'x-component-props': {
|
|
||||||
addNewComponent: 'AddNew.PaneItem',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
update: {
|
|
||||||
key: uid(),
|
|
||||||
name: uid(),
|
|
||||||
type: 'void',
|
|
||||||
title: "{{ t('Edit') }}",
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': {
|
|
||||||
type: 'link',
|
|
||||||
},
|
|
||||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
|
||||||
'x-action-type': 'update',
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
title: "{{ t('Edit record') }}",
|
|
||||||
'x-decorator': 'Form',
|
|
||||||
'x-decorator-props': {
|
|
||||||
useResource: '{{ Table.useResource }}',
|
|
||||||
useValues: '{{ Table.useTableRowRecord }}',
|
|
||||||
},
|
|
||||||
'x-component': 'Action.Drawer',
|
|
||||||
'x-component-props': {
|
|
||||||
useOkAction: '{{ Table.useTableUpdateAction }}',
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Grid',
|
|
||||||
'x-component-props': {
|
|
||||||
addNewComponent: 'AddNew.FormItem',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
destroy: {
|
|
||||||
key: uid(),
|
|
||||||
name: uid(),
|
|
||||||
type: 'void',
|
|
||||||
title: "{{ t('Delete') }}",
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
|
||||||
'x-action-type': 'destroy',
|
|
||||||
'x-component-props': {
|
|
||||||
useAction: '{{ Table.useTableDestroyAction }}',
|
|
||||||
type: 'link',
|
|
||||||
confirm: {
|
|
||||||
title: "{{ t('Delete record') }}",
|
|
||||||
content: "{{ t('Are you sure you want to delete it?') }}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return actions[type];
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Pagination } from 'antd';
|
|
||||||
import { observer } from '@formily/react';
|
|
||||||
import { useTable } from './hooks/useTable';
|
|
||||||
import { useTotal } from './hooks/useTotal';
|
|
||||||
|
|
||||||
export const TablePagination = observer(() => {
|
|
||||||
const { service, pagination, setPagination, props } = useTable();
|
|
||||||
if (!pagination || Object.keys(pagination).length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const { clientSidePagination } = props;
|
|
||||||
const total = useTotal();
|
|
||||||
const { page = 1 } = pagination;
|
|
||||||
return (
|
|
||||||
<div style={{ marginTop: 16 }}>
|
|
||||||
<Pagination
|
|
||||||
{...pagination}
|
|
||||||
showSizeChanger
|
|
||||||
current={page}
|
|
||||||
total={total}
|
|
||||||
onChange={(current, pageSize) => {
|
|
||||||
const page = pagination.pageSize !== pageSize ? 1 : current;
|
|
||||||
setPagination({
|
|
||||||
page,
|
|
||||||
pageSize,
|
|
||||||
});
|
|
||||||
// if (clientSidePagination) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// service.run({
|
|
||||||
// ...service.params[0],
|
|
||||||
// page,
|
|
||||||
// pageSize,
|
|
||||||
// });
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
@ -1,103 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { ArrayField } from '@formily/core';
|
|
||||||
import { useField } from '@formily/react';
|
|
||||||
import { uid } from '@formily/shared';
|
|
||||||
import useRequest from '@ahooksjs/use-request';
|
|
||||||
import { useDeepCompareEffectNoCheck } from 'use-deep-compare-effect';
|
|
||||||
import { useResource as useGeneralResource } from '../../hooks/useResource';
|
|
||||||
import { useDesignable } from '..';
|
|
||||||
import { useCollectionContext } from '../../constate';
|
|
||||||
import { useDefaultSelectedRowKeys } from './hooks/useDefaultSelectedRowKeys';
|
|
||||||
import { usePagination } from './hooks/usePagination';
|
|
||||||
import { useCollectionFields } from './hooks/useCollectionFields';
|
|
||||||
import {TableContext} from './context';
|
|
||||||
import {TableMain} from './TableMain';
|
|
||||||
|
|
||||||
export const TableProvider = (props: any) => {
|
|
||||||
const {
|
|
||||||
rowKey = 'id',
|
|
||||||
dataRequest,
|
|
||||||
useResource = useGeneralResource,
|
|
||||||
defaultSelectedRowKeys,
|
|
||||||
useSelectedRowKeys = useDefaultSelectedRowKeys,
|
|
||||||
...others
|
|
||||||
} = props;
|
|
||||||
const { schema } = useDesignable();
|
|
||||||
const field = useField<ArrayField>();
|
|
||||||
const [pagination, setPagination] = usePagination();
|
|
||||||
const { selectedRowKeys, setSelectedRowKeys } = useSelectedRowKeys();
|
|
||||||
console.log('props.useSelectedRowKeys', selectedRowKeys);
|
|
||||||
const [, refresh] = useState(uid());
|
|
||||||
const { resource } = useResource();
|
|
||||||
const { sortableField } = useCollectionContext();
|
|
||||||
const dragSort = props.dragSort;
|
|
||||||
const collectionFields = useCollectionFields(schema);
|
|
||||||
// console.log({ collectionFields, pagination });
|
|
||||||
const getDefaultParams = () => {
|
|
||||||
const defaultParams = { ...pagination };
|
|
||||||
if (dragSort) {
|
|
||||||
defaultParams['sort'] = [sortableField || 'sort'];
|
|
||||||
} else {
|
|
||||||
defaultParams['sort'] = (props.defaultSort || []).join(',');
|
|
||||||
}
|
|
||||||
defaultParams['defaultAppends'] = [...(props.defaultAppends || []), ...collectionFields];
|
|
||||||
if (props.defaultFilter) {
|
|
||||||
defaultParams['defaultFilter'] = props.defaultFilter;
|
|
||||||
}
|
|
||||||
console.log({ defaultParams });
|
|
||||||
return defaultParams;
|
|
||||||
};
|
|
||||||
const service = useRequest(
|
|
||||||
(params?: any) => {
|
|
||||||
if (!resource) {
|
|
||||||
return Promise.resolve({
|
|
||||||
list: field.value,
|
|
||||||
total: field?.value?.length,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return resource.list(params).then((res) => {
|
|
||||||
return {
|
|
||||||
list: res?.data || [],
|
|
||||||
total: res?.meta?.count || res?.data?.length,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{
|
|
||||||
onSuccess(data: any) {
|
|
||||||
field.setValue(data?.list || []);
|
|
||||||
},
|
|
||||||
manual: true,
|
|
||||||
// defaultParams: [getDefaultParams()],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
useDeepCompareEffectNoCheck(() => {
|
|
||||||
service.run(getDefaultParams());
|
|
||||||
}, [pagination?.pageSize, pagination?.page, props.dragSort, props.defaultSort, props.defaultFilter]);
|
|
||||||
return (
|
|
||||||
<TableContext.Provider
|
|
||||||
value={{
|
|
||||||
resource,
|
|
||||||
refresh: () => {
|
|
||||||
const { page = 1, pageSize } = pagination;
|
|
||||||
const total = props.clientSidePagination ? field?.value?.length : service?.data?.total;
|
|
||||||
const maxPage = Math.ceil(total / pageSize);
|
|
||||||
if (page > maxPage) {
|
|
||||||
setPagination({ page: maxPage });
|
|
||||||
} else {
|
|
||||||
refresh(uid());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selectedRowKeys,
|
|
||||||
setSelectedRowKeys,
|
|
||||||
pagination,
|
|
||||||
setPagination,
|
|
||||||
service,
|
|
||||||
field,
|
|
||||||
schema,
|
|
||||||
props: { ...others, rowKey, dataRequest },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<TableMain />
|
|
||||||
</TableContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,7 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { observer } from '@formily/react';
|
|
||||||
import { SortableRowHandle } from './Sortable';
|
|
||||||
|
|
||||||
export const TableSortHandle = observer((props: any) => {
|
|
||||||
return <SortableRowHandle {...props} />;
|
|
||||||
});
|
|
@ -1,6 +0,0 @@
|
|||||||
import {createContext} from 'react';
|
|
||||||
import {ITableContext,ITableRowContext} from './types';
|
|
||||||
|
|
||||||
export const TableContext = createContext<ITableContext>({} as any);
|
|
||||||
export const CollectionFieldContext = createContext(null);
|
|
||||||
export const TableRowContext = createContext<ITableRowContext>(null);
|
|
@ -1,38 +0,0 @@
|
|||||||
import { useContext, useEffect } from 'react';
|
|
||||||
import { useTable } from './useTable';
|
|
||||||
import useRequest from '@ahooksjs/use-request';
|
|
||||||
import { useCollectionContext, useResourceRequest } from '../../../constate';
|
|
||||||
import { VisibleContext } from '../../../context';
|
|
||||||
import { TableRowContext } from '../context';
|
|
||||||
|
|
||||||
export const useActionLogDetailsResource = ({ onSuccess }) => {
|
|
||||||
const { props } = useTable();
|
|
||||||
const { collection } = useCollectionContext();
|
|
||||||
const ctx = useContext(TableRowContext);
|
|
||||||
const resource = useResourceRequest({
|
|
||||||
resourceName: 'action_logs',
|
|
||||||
resourceKey: ctx.record[props.rowKey],
|
|
||||||
});
|
|
||||||
const service = useRequest(
|
|
||||||
(params?: any) => {
|
|
||||||
return resource.get({
|
|
||||||
...params,
|
|
||||||
appends: ['changes', 'user', 'collection'],
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{
|
|
||||||
formatResult: (result) => result?.data,
|
|
||||||
onSuccess,
|
|
||||||
manual: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
const [visible] = useContext(VisibleContext);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (visible) {
|
|
||||||
service.run({});
|
|
||||||
}
|
|
||||||
}, [visible]);
|
|
||||||
|
|
||||||
return { resource, service, initialValues: service.data, ...service };
|
|
||||||
};
|
|
@ -1,35 +0,0 @@
|
|||||||
import React, { useContext, createContext, useEffect, useState } from 'react';
|
|
||||||
import { useTable } from './useTable';
|
|
||||||
import { ListOptions, Resource } from '../../../resource';
|
|
||||||
import { TableRowContext } from '../context';
|
|
||||||
import { useResourceRequest } from '../../../constate';
|
|
||||||
|
|
||||||
export const useActionLogsResource = (options: any = {}) => {
|
|
||||||
const { props } = useTable();
|
|
||||||
const ctx = useContext(TableRowContext);
|
|
||||||
|
|
||||||
class ActionLogoResource extends Resource {
|
|
||||||
list(options?: ListOptions) {
|
|
||||||
console.log({ options });
|
|
||||||
let defaultFilter = options?.defaultFilter;
|
|
||||||
if (ctx?.record) {
|
|
||||||
const extra = {
|
|
||||||
index: ctx?.record?.id,
|
|
||||||
collection_name: props.collectionName,
|
|
||||||
};
|
|
||||||
if (defaultFilter) {
|
|
||||||
defaultFilter = { and: [defaultFilter, extra] };
|
|
||||||
} else {
|
|
||||||
defaultFilter = extra;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.list({ ...options, defaultFilter });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const resource = useResourceRequest('action_logs', ActionLogoResource);
|
|
||||||
|
|
||||||
return {
|
|
||||||
resource,
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,24 +0,0 @@
|
|||||||
import { Schema } from '@formily/react';
|
|
||||||
import { isColumn } from '../utils';
|
|
||||||
|
|
||||||
export const useCollectionFields = (schema: Schema) => {
|
|
||||||
const columns = schema.reduceProperties((columns, current) => {
|
|
||||||
if (isColumn(current)) {
|
|
||||||
if (current['x-hidden']) {
|
|
||||||
return columns;
|
|
||||||
}
|
|
||||||
if (current['x-display'] && current['x-display'] !== 'visible') {
|
|
||||||
return columns;
|
|
||||||
}
|
|
||||||
return [...columns, current];
|
|
||||||
}
|
|
||||||
return [...columns];
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return columns
|
|
||||||
.map((column) => {
|
|
||||||
const columnProps = column['x-component-props'] || {};
|
|
||||||
return columnProps.fieldName;
|
|
||||||
})
|
|
||||||
.filter(Boolean);
|
|
||||||
};
|
|
@ -1,17 +0,0 @@
|
|||||||
import { useTable } from './useTable';
|
|
||||||
|
|
||||||
export const useDataSource = () => {
|
|
||||||
const {
|
|
||||||
pagination,
|
|
||||||
field,
|
|
||||||
props: { clientSidePagination, dataRequest },
|
|
||||||
} = useTable();
|
|
||||||
let dataSource = field.value;
|
|
||||||
// if (pagination && (clientSidePagination || !dataRequest)) {
|
|
||||||
// const { page = 1, pageSize } = pagination;
|
|
||||||
// const startIndex = (page - 1) * pageSize;
|
|
||||||
// const endIndex = startIndex + pageSize - 1;
|
|
||||||
// dataSource = field.value?.slice(startIndex, endIndex + 1);
|
|
||||||
// }
|
|
||||||
return dataSource;
|
|
||||||
};
|
|
@ -1,5 +0,0 @@
|
|||||||
export const useDefaultRowSelection = () => {
|
|
||||||
return {
|
|
||||||
type: 'checkbox',
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,6 +0,0 @@
|
|||||||
import { useState } from "react";
|
|
||||||
|
|
||||||
export const useDefaultSelectedRowKeys = () => {
|
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]);
|
|
||||||
return { selectedRowKeys, setSelectedRowKeys };
|
|
||||||
};
|
|
@ -1,33 +0,0 @@
|
|||||||
import { ArrayField } from '@formily/core';
|
|
||||||
import { useField } from '@formily/react';
|
|
||||||
|
|
||||||
export const usePagination = () => {
|
|
||||||
const field = useField<ArrayField>();
|
|
||||||
const paginationProps = field.componentProps.pagination;
|
|
||||||
|
|
||||||
let pagination = paginationProps;
|
|
||||||
|
|
||||||
// const [pagination, setPagination] = useState(() => {
|
|
||||||
// if (!paginationProps) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// const { defaultPageSize = 10, ...others } = paginationProps;
|
|
||||||
// return { page: 1, pageSize: defaultPageSize, ...others };
|
|
||||||
// });
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (!paginationProps) {
|
|
||||||
// return setPagination(false);
|
|
||||||
// }
|
|
||||||
// const { defaultPageSize = 10, ...others } = paginationProps;
|
|
||||||
// setPagination({ page: 1, pageSize: defaultPageSize, ...others });
|
|
||||||
// }, [paginationProps]);
|
|
||||||
|
|
||||||
return [
|
|
||||||
pagination,
|
|
||||||
(params) => {
|
|
||||||
const defaults = field.componentProps.pagination;
|
|
||||||
field.componentProps.pagination = { ...defaults, ...params };
|
|
||||||
},
|
|
||||||
];
|
|
||||||
};
|
|
@ -1,51 +0,0 @@
|
|||||||
import { useContext } from 'react';
|
|
||||||
import { Schema } from '@formily/react';
|
|
||||||
import { useTable } from './useTable';
|
|
||||||
import { TableRowContext } from '../context';
|
|
||||||
import useRequest from '@ahooksjs/use-request';
|
|
||||||
import { useCollectionContext, useResourceRequest } from '../../../constate';
|
|
||||||
import { useDesignable } from '../..';
|
|
||||||
|
|
||||||
export const useResource = ({ onSuccess, manual = true }) => {
|
|
||||||
const { props } = useTable();
|
|
||||||
const { collection } = useCollectionContext();
|
|
||||||
const ctx = useContext(TableRowContext);
|
|
||||||
const resource = useResourceRequest({
|
|
||||||
resourceName: collection?.name || props.collectionName,
|
|
||||||
resourceKey: ctx.record[props.rowKey],
|
|
||||||
});
|
|
||||||
const { schema } = useDesignable();
|
|
||||||
const fieldFields = (schema: Schema) => {
|
|
||||||
const names = [];
|
|
||||||
schema.reduceProperties((buf, current) => {
|
|
||||||
if (current['x-component'] === 'Form.Field') {
|
|
||||||
const fieldName = current['x-component-props']?.['fieldName'];
|
|
||||||
if (fieldName) {
|
|
||||||
buf.push(fieldName);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const fieldNames = fieldFields(current);
|
|
||||||
buf.push(...fieldNames);
|
|
||||||
}
|
|
||||||
return buf;
|
|
||||||
}, names);
|
|
||||||
return names;
|
|
||||||
};
|
|
||||||
console.log(
|
|
||||||
'collection?.name || props.collectionName',
|
|
||||||
collection?.name || props.collectionName,
|
|
||||||
// fieldFields(schema),
|
|
||||||
);
|
|
||||||
const service = useRequest(
|
|
||||||
(params?: any) => {
|
|
||||||
console.log('Table.useResource', params);
|
|
||||||
return resource.get({ ...params, appends: fieldFields(schema) });
|
|
||||||
},
|
|
||||||
{
|
|
||||||
formatResult: (result) => result?.data,
|
|
||||||
onSuccess,
|
|
||||||
manual,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return { resource, service, initialValues: service.data, ...service };
|
|
||||||
};
|
|
@ -1,6 +0,0 @@
|
|||||||
import React, { useContext,createContext, useEffect, useState } from 'react';
|
|
||||||
import {TableContext} from '../context';
|
|
||||||
|
|
||||||
export const useTable = () => {
|
|
||||||
return useContext(TableContext);
|
|
||||||
};
|
|
@ -1,18 +0,0 @@
|
|||||||
import { useTable } from './useTable';
|
|
||||||
|
|
||||||
export const useTableActionBars = () => {
|
|
||||||
const {
|
|
||||||
field,
|
|
||||||
schema,
|
|
||||||
props: { rowKey },
|
|
||||||
} = useTable();
|
|
||||||
|
|
||||||
const bars = schema.reduceProperties((bars, current) => {
|
|
||||||
if (current['x-component'] === 'Table.ActionBar') {
|
|
||||||
return [...bars, current];
|
|
||||||
}
|
|
||||||
return [...bars];
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return bars;
|
|
||||||
};
|
|
@ -1,69 +0,0 @@
|
|||||||
import React,{ createContext } from 'react';
|
|
||||||
import { findIndex } from 'lodash';
|
|
||||||
import { RecursionField, Schema } from '@formily/react';
|
|
||||||
import { useDesignable } from '../..';
|
|
||||||
import { useTable } from './useTable';
|
|
||||||
import {TableRowContext} from '../context';
|
|
||||||
import { useCollectionContext } from '../../../constate';
|
|
||||||
import {Table, } from '..';
|
|
||||||
import {isColumn} from '../utils'
|
|
||||||
import {AddColumn } from '../AddColumn';
|
|
||||||
import {CollectionFieldContext}from '../context';
|
|
||||||
|
|
||||||
export const useTableColumns = () => {
|
|
||||||
const {
|
|
||||||
field,
|
|
||||||
schema,
|
|
||||||
props: { rowKey },
|
|
||||||
} = useTable();
|
|
||||||
const { designable } = useDesignable();
|
|
||||||
|
|
||||||
const { getField } = useCollectionContext();
|
|
||||||
|
|
||||||
const columnSchemas = schema.reduceProperties((columns, current) => {
|
|
||||||
if (isColumn(current)) {
|
|
||||||
if (current['x-hidden']) {
|
|
||||||
return columns;
|
|
||||||
}
|
|
||||||
if (current['x-display'] && current['x-display'] !== 'visible') {
|
|
||||||
return columns;
|
|
||||||
}
|
|
||||||
return [...columns, current];
|
|
||||||
}
|
|
||||||
return [...columns];
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const columns: any[] = [].concat(
|
|
||||||
columnSchemas.map((column: Schema) => {
|
|
||||||
const columnProps = column['x-component-props'] || {};
|
|
||||||
const collectionField = getField(columnProps.fieldName);
|
|
||||||
return {
|
|
||||||
title: (
|
|
||||||
<CollectionFieldContext.Provider value={collectionField}>
|
|
||||||
<RecursionField name={column.name} schema={column} onlyRenderSelf />
|
|
||||||
</CollectionFieldContext.Provider>
|
|
||||||
),
|
|
||||||
dataIndex: column.name,
|
|
||||||
...columnProps,
|
|
||||||
render: (_: any, record: any) => {
|
|
||||||
const index = findIndex(field.value, (item) => item[rowKey] === record[rowKey]);
|
|
||||||
return (
|
|
||||||
<CollectionFieldContext.Provider value={collectionField}>
|
|
||||||
<TableRowContext.Provider value={{ index, record }}>
|
|
||||||
<Table.Cell schema={column} />
|
|
||||||
</TableRowContext.Provider>
|
|
||||||
</CollectionFieldContext.Provider>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (designable && schema['x-designable-bar'] && schema['x-designable-bar'] !== 'Table.SimpleDesignableBar') {
|
|
||||||
columns.push({
|
|
||||||
title: <AddColumn />,
|
|
||||||
dataIndex: 'addnew',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return columns;
|
|
||||||
};
|
|
@ -1,24 +0,0 @@
|
|||||||
import { useForm } from '@formily/react';
|
|
||||||
import { useTable } from './useTable';
|
|
||||||
|
|
||||||
export function useTableCreateAction() {
|
|
||||||
const {
|
|
||||||
field,
|
|
||||||
service,
|
|
||||||
resource,
|
|
||||||
refresh,
|
|
||||||
props: { refreshRequestOnChange },
|
|
||||||
} = useTable();
|
|
||||||
const form = useForm();
|
|
||||||
return {
|
|
||||||
async run() {
|
|
||||||
console.log('refreshRequestOnChange', refreshRequestOnChange);
|
|
||||||
if (refreshRequestOnChange) {
|
|
||||||
await resource.create(form.values);
|
|
||||||
await form.reset();
|
|
||||||
return service.refresh();
|
|
||||||
}
|
|
||||||
field.unshift(form.values);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
import { useContext } from "react";
|
|
||||||
import { useTable } from "./useTable";
|
|
||||||
import { TableRowContext } from "../context";
|
|
||||||
import { VisibleContext } from '../../../context';
|
|
||||||
import { findIndex } from 'lodash';
|
|
||||||
|
|
||||||
export const useTableDestroyAction = () => {
|
|
||||||
const {
|
|
||||||
resource,
|
|
||||||
field,
|
|
||||||
service,
|
|
||||||
selectedRowKeys,
|
|
||||||
setSelectedRowKeys,
|
|
||||||
refresh,
|
|
||||||
props: { refreshRequestOnChange, rowKey },
|
|
||||||
} = useTable();
|
|
||||||
const ctx = useContext(TableRowContext);
|
|
||||||
const [, setVisible] = useContext(VisibleContext);
|
|
||||||
return {
|
|
||||||
async run() {
|
|
||||||
if (refreshRequestOnChange) {
|
|
||||||
const rowKeys = selectedRowKeys || [];
|
|
||||||
if (ctx) {
|
|
||||||
rowKeys.push(ctx.record[rowKey]);
|
|
||||||
}
|
|
||||||
await resource.destroy({
|
|
||||||
[`${rowKey}.in`]: rowKeys,
|
|
||||||
});
|
|
||||||
setSelectedRowKeys([]);
|
|
||||||
setVisible && setVisible(false);
|
|
||||||
return service.refresh();
|
|
||||||
}
|
|
||||||
if (ctx) {
|
|
||||||
console.log('ctx.index', ctx.index);
|
|
||||||
field.remove(ctx.index);
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
const rowKeys = [...selectedRowKeys];
|
|
||||||
while (rowKeys.length) {
|
|
||||||
const key = rowKeys.shift();
|
|
||||||
const index = findIndex(field.value, (item) => item[rowKey] === key);
|
|
||||||
field.remove(index);
|
|
||||||
}
|
|
||||||
setSelectedRowKeys([]);
|
|
||||||
refresh();
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,51 +0,0 @@
|
|||||||
import { useField } from '@formily/react';
|
|
||||||
import { useContext } from 'react';
|
|
||||||
import { useTable } from './useTable';
|
|
||||||
import { TableRowContext } from '../context';
|
|
||||||
import { useCollectionContext } from '../../../constate';
|
|
||||||
|
|
||||||
export const useTableExportAction = () => {
|
|
||||||
const {
|
|
||||||
resource,
|
|
||||||
field,
|
|
||||||
service,
|
|
||||||
selectedRowKeys,
|
|
||||||
setSelectedRowKeys,
|
|
||||||
refresh,
|
|
||||||
schema,
|
|
||||||
props: { refreshRequestOnChange, rowKey },
|
|
||||||
} = useTable();
|
|
||||||
const ctx = useContext(TableRowContext);
|
|
||||||
|
|
||||||
const actionField = useField();
|
|
||||||
const fieldNames = actionField.componentProps.fieldNames || [];
|
|
||||||
const { getField } = useCollectionContext();
|
|
||||||
|
|
||||||
const columns = fieldNames
|
|
||||||
.map((name) => {
|
|
||||||
const f = getField(name);
|
|
||||||
return {
|
|
||||||
title: f?.uiSchema.title,
|
|
||||||
name,
|
|
||||||
sort: f?.sort,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.sort((a, b) => a.sort - b.sort);
|
|
||||||
|
|
||||||
return {
|
|
||||||
async run() {
|
|
||||||
const rowKeys = selectedRowKeys || [];
|
|
||||||
const { filter = {}, ...others } = service.params[0];
|
|
||||||
if (rowKeys.length) {
|
|
||||||
filter[`${rowKey}.in`] = rowKeys;
|
|
||||||
}
|
|
||||||
await resource.export({
|
|
||||||
...others,
|
|
||||||
columns,
|
|
||||||
perPage: -1,
|
|
||||||
page: 1,
|
|
||||||
filter,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,23 +0,0 @@
|
|||||||
import { useTable } from './useTable';
|
|
||||||
import { useForm } from '@formily/react';
|
|
||||||
|
|
||||||
export function useTableFilterAction() {
|
|
||||||
const {
|
|
||||||
field,
|
|
||||||
service,
|
|
||||||
refresh,
|
|
||||||
props: { refreshRequestOnChange },
|
|
||||||
} = useTable();
|
|
||||||
const form = useForm();
|
|
||||||
return {
|
|
||||||
async run() {
|
|
||||||
console.log('useTableFilterAction', form.values);
|
|
||||||
if (refreshRequestOnChange) {
|
|
||||||
return service.run({
|
|
||||||
...service.params[0],
|
|
||||||
// filter,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
import { useContext } from 'react';
|
|
||||||
import { useTable } from './useTable';
|
|
||||||
import { TableRowContext } from '../context';
|
|
||||||
|
|
||||||
export const useTableIndex = () => {
|
|
||||||
const { pagination, props } = useTable();
|
|
||||||
const ctx = useContext(TableRowContext);
|
|
||||||
const { pageSize, page = 1 } = pagination;
|
|
||||||
console.log({ pageSize, page }, ctx.index);
|
|
||||||
return ctx.index + (page - 1) * pageSize;
|
|
||||||
if (pagination && !props.clientSidePagination) {
|
|
||||||
const { pageSize, page = 1 } = pagination;
|
|
||||||
return ctx.index + (page - 1) * pageSize;
|
|
||||||
}
|
|
||||||
return ctx.index;
|
|
||||||
};
|
|
@ -1,7 +0,0 @@
|
|||||||
import React, { useContext } from 'react';
|
|
||||||
import {TableRowContext} from '../context';
|
|
||||||
|
|
||||||
|
|
||||||
export const useTableRow = () => {
|
|
||||||
return useContext(TableRowContext);
|
|
||||||
};
|
|
@ -1,7 +0,0 @@
|
|||||||
import { useContext } from "react";
|
|
||||||
import { TableRowContext } from "../context";
|
|
||||||
|
|
||||||
export const useTableRowRecord = () => {
|
|
||||||
const ctx = useContext(TableRowContext);
|
|
||||||
return ctx.record;
|
|
||||||
};
|
|
@ -1,35 +0,0 @@
|
|||||||
import { useForm } from "@formily/react";
|
|
||||||
import { useContext } from "react";
|
|
||||||
import { useTable } from "./useTable";
|
|
||||||
import { TableRowContext } from "../context";
|
|
||||||
import { DescriptionsContext } from '../../form';
|
|
||||||
|
|
||||||
export const useTableUpdateAction = () => {
|
|
||||||
const {
|
|
||||||
resource,
|
|
||||||
field,
|
|
||||||
service,
|
|
||||||
refresh,
|
|
||||||
props: { refreshRequestOnChange, rowKey },
|
|
||||||
} = useTable();
|
|
||||||
const ctx = useContext(TableRowContext);
|
|
||||||
const form = useForm();
|
|
||||||
const { service: formService } = useContext(DescriptionsContext);
|
|
||||||
|
|
||||||
return {
|
|
||||||
async run() {
|
|
||||||
if (refreshRequestOnChange) {
|
|
||||||
await resource.save(form.values, {
|
|
||||||
resourceKey: ctx.record[rowKey],
|
|
||||||
});
|
|
||||||
if (formService) {
|
|
||||||
await formService.refresh();
|
|
||||||
}
|
|
||||||
await service.refresh();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
field.value[ctx.index] = form.values;
|
|
||||||
// refresh();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,10 +0,0 @@
|
|||||||
import { useTable } from './useTable';
|
|
||||||
|
|
||||||
export const useTotal = () => {
|
|
||||||
const {
|
|
||||||
field,
|
|
||||||
service,
|
|
||||||
props: { clientSidePagination },
|
|
||||||
} = useTable();
|
|
||||||
return clientSidePagination ? field?.value?.length : service?.data?.total;
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load Diff
@ -1,22 +0,0 @@
|
|||||||
import { ArrayField } from '@formily/core';
|
|
||||||
import { FormProvider, observer, RecursionField, Schema, useField, useForm } from '@formily/react';
|
|
||||||
import { BaseResult } from '@ahooksjs/use-request/lib/types';
|
|
||||||
import { ListOptions, Resource } from '../../resource';
|
|
||||||
|
|
||||||
export interface ITableContext {
|
|
||||||
props: any;
|
|
||||||
field: ArrayField;
|
|
||||||
schema: Schema;
|
|
||||||
service: BaseResult<any, any>;
|
|
||||||
selectedRowKeys?: any;
|
|
||||||
setSelectedRowKeys?: any;
|
|
||||||
pagination?: any;
|
|
||||||
setPagination?: any;
|
|
||||||
refresh?: any;
|
|
||||||
resource?: Resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ITableRowContext {
|
|
||||||
index: number;
|
|
||||||
record: any;
|
|
||||||
}
|
|
@ -1,164 +0,0 @@
|
|||||||
import { Schema } from '@formily/react';
|
|
||||||
import { uid } from '@formily/shared';
|
|
||||||
import { interfaces } from '../database-field/interfaces';
|
|
||||||
import { ISchema } from '..';
|
|
||||||
|
|
||||||
export const fieldsToSortColumns = (fields: any[]) => {
|
|
||||||
const dataSource = [];
|
|
||||||
|
|
||||||
fields.forEach((field) => {
|
|
||||||
const fieldOption = interfaces.get(field.interface);
|
|
||||||
if (!fieldOption?.sortable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dataSource.push({
|
|
||||||
value: field.name,
|
|
||||||
label: field?.uiSchema?.title,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return dataSource;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fieldsToFilterColumns = (fields: any[], options: any = {}) => {
|
|
||||||
const { fieldNames = [] } = options;
|
|
||||||
const properties = {};
|
|
||||||
fields.forEach((field, index) => {
|
|
||||||
if (fieldNames?.length && !fieldNames.includes(field.name)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const fieldOption = interfaces.get(field.interface);
|
|
||||||
if (!fieldOption?.operations) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
properties[`column${index}`] = {
|
|
||||||
type: 'void',
|
|
||||||
title: field?.uiSchema?.title,
|
|
||||||
'x-component': 'Filter.Column',
|
|
||||||
'x-component-props': {
|
|
||||||
operations: fieldOption.operations,
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
[field.name]: {
|
|
||||||
...field.uiSchema,
|
|
||||||
'x-decorator': 'FormilyFormItem',
|
|
||||||
title: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return properties;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const generateActionSchema = (type) => {
|
|
||||||
const actions: { [key: string]: ISchema } = {
|
|
||||||
filter: {
|
|
||||||
key: uid(),
|
|
||||||
name: uid(),
|
|
||||||
type: 'void',
|
|
||||||
title: "{{ t('Filter') }}",
|
|
||||||
'x-align': 'left',
|
|
||||||
'x-decorator': 'AddNew.Displayed',
|
|
||||||
'x-decorator-props': {
|
|
||||||
displayName: 'filter',
|
|
||||||
},
|
|
||||||
'x-component': 'Table.Filter',
|
|
||||||
'x-designable-bar': 'Table.Filter.DesignableBar',
|
|
||||||
'x-component-props': {
|
|
||||||
fieldNames: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
export: {
|
|
||||||
key: uid(),
|
|
||||||
type: 'void',
|
|
||||||
name: uid(),
|
|
||||||
title: "{{ t('Export') }}",
|
|
||||||
'x-align': 'right',
|
|
||||||
'x-decorator': 'AddNew.Displayed',
|
|
||||||
'x-decorator-props': {
|
|
||||||
displayName: 'export',
|
|
||||||
},
|
|
||||||
'x-action-type': 'export',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-designable-bar': 'Table.ExportActionDesignableBar',
|
|
||||||
'x-component-props': {
|
|
||||||
fieldNames: [],
|
|
||||||
icon: 'ExportOutlined',
|
|
||||||
useAction: '{{ Table.useTableExportAction }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
key: uid(),
|
|
||||||
type: 'void',
|
|
||||||
name: uid(),
|
|
||||||
title: "{{ t('Add new') }}",
|
|
||||||
'x-align': 'right',
|
|
||||||
'x-decorator': 'AddNew.Displayed',
|
|
||||||
'x-decorator-props': {
|
|
||||||
displayName: 'create',
|
|
||||||
},
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': {
|
|
||||||
type: 'primary',
|
|
||||||
icon: 'PlusOutlined',
|
|
||||||
},
|
|
||||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
|
||||||
properties: {
|
|
||||||
modal: {
|
|
||||||
type: 'void',
|
|
||||||
title: "{{ t('Add record') }}",
|
|
||||||
'x-decorator': 'Form',
|
|
||||||
'x-component': 'Action.Drawer',
|
|
||||||
'x-component-props': {
|
|
||||||
useOkAction: '{{ Table.useTableCreateAction }}',
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Grid',
|
|
||||||
'x-component-props': {
|
|
||||||
addNewComponent: 'AddNew.FormItem',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
destroy: {
|
|
||||||
key: uid(),
|
|
||||||
type: 'void',
|
|
||||||
name: uid(),
|
|
||||||
title: "{{ t('Delete') }}",
|
|
||||||
'x-align': 'right',
|
|
||||||
'x-decorator': 'AddNew.Displayed',
|
|
||||||
'x-decorator-props': {
|
|
||||||
displayName: 'destroy',
|
|
||||||
},
|
|
||||||
'x-action-type': 'destroy',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
|
||||||
'x-component-props': {
|
|
||||||
confirm: {
|
|
||||||
title: "{{ t('Delete record') }}",
|
|
||||||
content: "{{ t('Are you sure you want to delete it?') }}",
|
|
||||||
},
|
|
||||||
useAction: '{{ Table.useTableDestroyAction }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
view: {},
|
|
||||||
update: {},
|
|
||||||
};
|
|
||||||
return actions[type];
|
|
||||||
};
|
|
||||||
|
|
||||||
export function isColumn(schema: Schema) {
|
|
||||||
return ['Table.Column'].includes(schema['x-component']);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isColumnComponent(component: string) {
|
|
||||||
return ['Table.Operation', 'Table.Column'].includes(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isOperationColumn(schema: Schema) {
|
|
||||||
return ['Table.Operation'].includes(schema['x-component']);
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user