Unverified Commit 0f9eb4e7 authored by SemmyWong's avatar SemmyWong Committed by GitHub
Browse files

refactor: code splitting of the table component (#120)

parent 82ad5de8
Showing with 862 additions and 79 deletions
+862 -79
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 80,
"printWidth": 120,
"overrides": [
{
"files": ".prettierrc",
......
......@@ -11,7 +11,8 @@ import { PlusOutlined, DownOutlined } from '@ant-design/icons';
import cls from 'classnames';
import { uid, isValid, clone } from '@formily/shared';
import { Resource } from '../../../resource';
import { TableRowContext, useTable } from '../../../schemas/table';
import { TableRowContext } from '../../../schemas/table/context';
import { useTable } from '../../../schemas/table/hooks/useTable';
import { useRequest } from 'ahooks';
import { VisibleContext } from '../../../context';
import { connect, FormProvider, observer, useForm } from '@formily/react';
......
......@@ -8,7 +8,8 @@ import { LockOutlined } from '@ant-design/icons';
import cls from 'classnames';
import { uid } from '@formily/shared';
import { Resource } from '../../../resource';
import { TableRowContext, useTable } from '../../../schemas/table';
import { TableRowContext } from '../../../schemas/table/context';
import { useTable } from '../../../schemas/table/hooks/useTable';
import { useRequest } from 'ahooks';
import { VisibleContext } from '../../../context';
import { connect, ISchema, observer, useField } from '@formily/react';
......
......@@ -8,7 +8,8 @@ import { LockOutlined } from '@ant-design/icons';
import cls from 'classnames';
import { uid, isValid } from '@formily/shared';
import { Resource } from '../../../resource';
import { TableRowContext, useTable } from '../../../schemas/table';
import { TableRowContext } from '../../../schemas/table/context';
import { useTable } from '../../../schemas/table/hooks/useTable';
import { useRequest } from 'ahooks';
import { VisibleContext } from '../../../context';
import { connect, observer, useForm } from '@formily/react';
......
......@@ -52,11 +52,8 @@ import { Menu } from '../../schemas/menu';
import { Password } from '../../schemas/password';
import { Radio } from '../../schemas/radio';
import { Select } from '../../schemas/select';
import {
CollectionFieldContext,
Table,
TableRowContext,
} from '../../schemas/table';
import { Table } from '../../schemas/table';
import { CollectionFieldContext, TableRowContext } from '../../schemas/table/context';
import { Tabs } from '../../schemas/tabs';
import { TimePicker } from '../../schemas/time-picker';
import { Upload } from '../../schemas/upload';
......
......@@ -38,7 +38,7 @@ import { useEffect } from 'react';
import { uid } from '@formily/shared';
import { getSchemaPath } from '../../components/schema-renderer';
import { useCollection, useCollectionContext } from '../../constate';
import { useTable } from '../table';
import { useTable } from '../table/hooks/useTable';
import { fieldsToFilterColumns } from './';
import { set } from 'lodash';
import { DragHandle } from '../../components/Sortable';
......
......@@ -27,7 +27,7 @@ import { useEffect } from 'react';
import { uid } from '@formily/shared';
import { getSchemaPath } from '../../components/schema-renderer';
import { useCollection, useCollectionContext } from '../../constate';
import { useTable } from '../table';
import { useTable } from '../table/hooks/useTable';
import { BlockSchemaContext } from '../../context';
import { DragHandle } from '../../components/Sortable';
import { useTranslation } from 'react-i18next';
......
......@@ -44,7 +44,7 @@ import {
import { useResource as useGeneralResource } from '../../hooks/useResource';
import { Resource } from '../../resource';
import { BaseResult } from '@ahooksjs/use-request/lib/types';
import { CollectionFieldContext } from '../table';
import { CollectionFieldContext } from '../table/context';
import { useTranslation } from 'react-i18next';
export interface DescriptionsContextProps {
......
......@@ -27,7 +27,7 @@ import { useEffect } from 'react';
import { uid } from '@formily/shared';
import { getSchemaPath } from '../../components/schema-renderer';
import { useCollection, useCollectionContext } from '../../constate';
import { useTable } from '../table';
import { useTable } from '../table/hooks/useTable';
import { DragHandle } from '../../components/Sortable';
import { useCompile } from '../../hooks/useCompile';
......
......@@ -33,7 +33,7 @@ import { useEffect } from 'react';
import { uid } from '@formily/shared';
import { getSchemaPath } from '../../components/schema-renderer';
import { useCollection, useCollectionContext } from '../../constate';
import { useTable } from '../table';
import { useTable } from '../table/hooks/useTable';
import { DragHandle } from '../../components/Sortable';
import { fieldsToFilterColumns } from '../calendar';
import { useTranslation } from 'react-i18next';
......
......@@ -24,7 +24,7 @@ import { Action } from '../action';
import { BlockSchemaContext, VisibleContext } from '../../context';
import { SchemaRenderer } from '../../components/schema-renderer';
import { uid } from '@formily/shared';
import { CollectionFieldContext } from '../table';
import { CollectionFieldContext } from '../table/context';
import {
CollectionProvider,
useCollectionContext,
......
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>
);
};
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>
);
};
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>
);
}
import React, { forwardRef, useState } from 'react';
import {
SortableContext,
useSortable,
horizontalListSortingStrategy,
verticalListSortingStrategy,
sortableKeyboardCoordinates,
} from '@dnd-kit/sortable';
import React, { createContext, useContext, forwardRef, useState } from 'react';
import { SortableContext, useSortable, horizontalListSortingStrategy } from '@dnd-kit/sortable';
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 { DndContext, DragOverlay, useDroppable, useDraggable } from '@dnd-kit/core';
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 { useRef } from 'react';
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 { Schema } from '@formily/react';
import { isColumn, isColumnComponent } from '.';
import { isColumn } from './utils';
export const RowDraggableContext = createContext({});
export const ColDraggableContext = createContext(null);
......@@ -68,9 +41,7 @@ export function SortableColumn(props) {
ref={setDroppableNodeRef}
// {...attributes}
>
<ColDraggableContext.Provider
value={{ setDraggableNodeRef, attributes, listeners }}
>
<ColDraggableContext.Provider value={{ setDraggableNodeRef, attributes, listeners }}>
{props.children}
</ColDraggableContext.Provider>
{/* <span ref={setDraggableNodeRef} {...attributes} {...listeners}>
......@@ -81,22 +52,9 @@ export function SortableColumn(props) {
}
export function SortableBodyRow(props: any) {
const {
className,
style: prevStyle,
['data-row-key']: dataRowKey,
...others
} = props;
const {
isDragging,
attributes,
listeners,
setNodeRef,
setDraggableNodeRef,
overIndex,
transform,
transition,
} = useSortable({ id: dataRowKey });
const { className, style: prevStyle, ['data-row-key']: dataRowKey, ...others } = props;
const { isDragging, attributes, listeners, setNodeRef, setDraggableNodeRef, overIndex, transform, transition } =
useSortable({ id: dataRowKey });
const style = {
...prevStyle,
......@@ -105,15 +63,9 @@ export function SortableBodyRow(props: any) {
};
return (
<RowDraggableContext.Provider
value={{ listeners, setDraggableNodeRef, attributes }}
>
<RowDraggableContext.Provider value={{ listeners, setDraggableNodeRef, attributes }}>
<tr
className={cls(
{ isDragging },
props.className,
`droppable-${props['data-row-key']}`,
)}
className={cls({ isDragging }, props.className, `droppable-${props['data-row-key']}`)}
// className={cls(className)}
ref={setNodeRef}
{...others}
......@@ -127,9 +79,7 @@ export function SortableBodyRow(props: any) {
})}
>
{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>
</tr>
......@@ -264,8 +214,7 @@ export function SortableBodyCell(props) {
export function SortableRowHandle(props) {
const { className, ...others } = props;
const { setDraggableNodeRef, attributes, listeners } =
useContext<any>(RowDraggableContext);
const { setDraggableNodeRef, attributes, listeners } = useContext<any>(RowDraggableContext);
return setDraggableNodeRef ? (
<MenuOutlined
{...others}
......
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>
);
});
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')} &nbsp;&nbsp;
<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>
);
};
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>
);
});
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>
);
});
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>
);
};
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment