refactor(client): schema initializer
This commit is contained in:
		
							parent
							
								
									d486768eda
								
							
						
					
					
						commit
						f45b08af38
					
				@ -10,6 +10,7 @@ import {
 | 
			
		||||
  DesignableSwitch,
 | 
			
		||||
  DocumentTitleProvider,
 | 
			
		||||
  i18n,
 | 
			
		||||
  MenuItemInitializers,
 | 
			
		||||
  PluginManagerProvider,
 | 
			
		||||
  RemoteCollectionManagerProvider,
 | 
			
		||||
  RouteSchemaComponent,
 | 
			
		||||
@ -50,7 +51,7 @@ const providers = [
 | 
			
		||||
  ],
 | 
			
		||||
  [SchemaComponentProvider, { components: { Link, NavLink } }],
 | 
			
		||||
  RemoteCollectionManagerProvider,
 | 
			
		||||
  SchemaInitializerProvider,
 | 
			
		||||
  [SchemaInitializerProvider, { initializers: { MenuItemInitializers } }],
 | 
			
		||||
  AntdSchemaComponentProvider,
 | 
			
		||||
  [DocumentTitleProvider, { addonAfter: 'NocoBase' }],
 | 
			
		||||
  [
 | 
			
		||||
 | 
			
		||||
@ -125,7 +125,7 @@ export default (apiClient: APIClient) => {
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            name: 'grid1',
 | 
			
		||||
            'x-component': 'Grid',
 | 
			
		||||
            'x-item-initializer': 'Grid.AddBlockItem',
 | 
			
		||||
            'x-initializer': 'Grid.AddBlockItem',
 | 
			
		||||
            'x-uid': uid(),
 | 
			
		||||
            properties: {},
 | 
			
		||||
          },
 | 
			
		||||
@ -152,7 +152,7 @@ export default (apiClient: APIClient) => {
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            name: 'grid1',
 | 
			
		||||
            'x-component': 'Grid',
 | 
			
		||||
            'x-item-initializer': 'Grid.AddBlockItem',
 | 
			
		||||
            'x-initializer': 'Grid.AddBlockItem',
 | 
			
		||||
            'x-uid': uid(),
 | 
			
		||||
            properties: {},
 | 
			
		||||
          },
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,18 @@
 | 
			
		||||
import { observer, RecursionField, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { Space } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useSchemaInitializer } from '../../../schema-initializer';
 | 
			
		||||
import { DndContext } from '../../common';
 | 
			
		||||
import { useComponent } from '../../hooks';
 | 
			
		||||
 | 
			
		||||
export const ActionBar = observer((props: any) => {
 | 
			
		||||
  const { layout = 'tow-columns', style, ...others } = props;
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const ActionInitializer = useComponent(fieldSchema['x-action-initializer']);
 | 
			
		||||
  const { render } = useSchemaInitializer(fieldSchema['x-initializer']);
 | 
			
		||||
  if (layout === 'one-column') {
 | 
			
		||||
    return (
 | 
			
		||||
      <div style={{ display: 'flex', ...style }} {...others}>
 | 
			
		||||
        {props.children && <div style={{ marginRight: 8 }}>{props.children}</div>}
 | 
			
		||||
        {ActionInitializer && <ActionInitializer />}
 | 
			
		||||
        {render()}
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
@ -38,7 +38,7 @@ export const ActionBar = observer((props: any) => {
 | 
			
		||||
          </Space>
 | 
			
		||||
        </DndContext>
 | 
			
		||||
      </div>
 | 
			
		||||
      {ActionInitializer && <ActionInitializer />}
 | 
			
		||||
      {render()}
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -5,8 +5,7 @@ import { Table, TableColumnProps } from 'antd';
 | 
			
		||||
import cls from 'classnames';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { DndContext } from '../..';
 | 
			
		||||
import { RecordProvider } from '../../../';
 | 
			
		||||
import { useComponent } from '../../hooks';
 | 
			
		||||
import { RecordProvider, useSchemaInitializer } from '../../../';
 | 
			
		||||
 | 
			
		||||
const isColumnComponent = (schema: Schema) => {
 | 
			
		||||
  return schema['x-component']?.endsWith('.Column') > -1;
 | 
			
		||||
@ -15,7 +14,7 @@ const isColumnComponent = (schema: Schema) => {
 | 
			
		||||
const useTableColumns = () => {
 | 
			
		||||
  const field = useField<ArrayField>();
 | 
			
		||||
  const schema = useFieldSchema();
 | 
			
		||||
  const Initializer = useComponent(schema['x-column-initializer']);
 | 
			
		||||
  const { exists, render } = useSchemaInitializer(schema['x-initializer']);
 | 
			
		||||
  const columns = schema
 | 
			
		||||
    .reduceProperties((buf, s) => {
 | 
			
		||||
      if (isColumnComponent(s)) {
 | 
			
		||||
@ -38,11 +37,11 @@ const useTableColumns = () => {
 | 
			
		||||
      } as TableColumnProps<any>;
 | 
			
		||||
    });
 | 
			
		||||
  console.log(columns);
 | 
			
		||||
  if (!Initializer) {
 | 
			
		||||
  if (!exists) {
 | 
			
		||||
    return columns;
 | 
			
		||||
  }
 | 
			
		||||
  return columns.concat({
 | 
			
		||||
    title: <Initializer />,
 | 
			
		||||
    title: render(),
 | 
			
		||||
    dataIndex: 'TABLE_COLUMN_INITIALIZER',
 | 
			
		||||
    key: 'TABLE_COLUMN_INITIALIZER',
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ export const useColumnSchema = () => {
 | 
			
		||||
    return buf;
 | 
			
		||||
  }, null);
 | 
			
		||||
  if (!fieldSchema) {
 | 
			
		||||
    return;
 | 
			
		||||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
  const collectionField = getField(fieldSchema.name);
 | 
			
		||||
  return { columnSchema, fieldSchema, collectionField };
 | 
			
		||||
@ -21,7 +21,7 @@ export const useColumnSchema = () => {
 | 
			
		||||
export const TableColumnDecorator = (props) => {
 | 
			
		||||
  const Designer = useDesigner();
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const { columnSchema, fieldSchema, collectionField } = useColumnSchema();
 | 
			
		||||
  const { fieldSchema, collectionField } = useColumnSchema();
 | 
			
		||||
  const { refresh } = useDesignable();
 | 
			
		||||
  useLayoutEffect(() => {
 | 
			
		||||
    if (field.title) {
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,14 @@
 | 
			
		||||
import { DragOutlined } from '@ant-design/icons';
 | 
			
		||||
import { useFieldSchema } from '@formily/react';
 | 
			
		||||
import { useSchemaInitializer } from '@nocobase/client';
 | 
			
		||||
import { Space } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { DragHandler, useComponent } from '../../../schema-component';
 | 
			
		||||
import { DragHandler } from '../../../schema-component';
 | 
			
		||||
 | 
			
		||||
export const TableRecordActionDesigner = (props: any) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const ActionInitializer = useComponent(fieldSchema['x-action-initializer']);
 | 
			
		||||
  const { render } = useSchemaInitializer(fieldSchema['x-initializer']);
 | 
			
		||||
  console.log("fieldSchema['x-initializer']", fieldSchema['x-initializer'])
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={'general-schema-designer'}>
 | 
			
		||||
      <div className={'general-schema-designer-icons'}>
 | 
			
		||||
@ -14,7 +16,7 @@ export const TableRecordActionDesigner = (props: any) => {
 | 
			
		||||
          <DragHandler>
 | 
			
		||||
            <DragOutlined />
 | 
			
		||||
          </DragHandler>
 | 
			
		||||
          <ActionInitializer />
 | 
			
		||||
          {render()}
 | 
			
		||||
        </Space>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@ import { observer, RecursionField, Schema, useField, useFieldSchema } from '@for
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
import cls from 'classnames';
 | 
			
		||||
import React, { createContext, useContext, useState } from 'react';
 | 
			
		||||
import { useComponent } from '../..';
 | 
			
		||||
import { useSchemaInitializer } from '../../../';
 | 
			
		||||
import { DndContext } from '../../common/dnd-context';
 | 
			
		||||
 | 
			
		||||
const GridRowContext = createContext(null);
 | 
			
		||||
@ -123,7 +123,7 @@ const useColProperties = () => {
 | 
			
		||||
export const Grid: any = observer((props) => {
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const ItemInitializer = useComponent(fieldSchema['x-item-initializer']);
 | 
			
		||||
  const { render } = useSchemaInitializer(fieldSchema['x-initializer']);
 | 
			
		||||
  const addr = field.address.toString();
 | 
			
		||||
  const rows = useRowProperties();
 | 
			
		||||
  return (
 | 
			
		||||
@ -145,7 +145,7 @@ export const Grid: any = observer((props) => {
 | 
			
		||||
          );
 | 
			
		||||
        })}
 | 
			
		||||
      </DndContext>
 | 
			
		||||
      <div>{ItemInitializer && <ItemInitializer />}</div>
 | 
			
		||||
      <div>{render()}</div>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -10,8 +10,8 @@ import {
 | 
			
		||||
import { Menu as AntdMenu } from 'antd';
 | 
			
		||||
import React, { createContext, useContext, useEffect, useState } from 'react';
 | 
			
		||||
import { createPortal } from 'react-dom';
 | 
			
		||||
import { createDesignable, DndContext, SortableItem, useComponent, useDesignable, useDesigner } from '../..';
 | 
			
		||||
import { Icon, useAPIClient } from '../../../';
 | 
			
		||||
import { createDesignable, DndContext, SortableItem, useDesignable, useDesigner } from '../..';
 | 
			
		||||
import { Icon, useAPIClient, useSchemaInitializer } from '../../../';
 | 
			
		||||
import { MenuDesigner } from './Menu.Designer';
 | 
			
		||||
import { findKeysByUid, findMenuItem } from './util';
 | 
			
		||||
 | 
			
		||||
@ -146,7 +146,7 @@ export const Menu: ComposedMenu = observer((props) => {
 | 
			
		||||
  const schema = useFieldSchema();
 | 
			
		||||
  const { refresh } = useDesignable();
 | 
			
		||||
  const api = useAPIClient();
 | 
			
		||||
  const Initializer = useComponent(schema['x-initializer']);
 | 
			
		||||
  const { render } = useSchemaInitializer(schema['x-initializer']);
 | 
			
		||||
  const sideMenuRef = useSideMenuRef();
 | 
			
		||||
  const [defaultSelectedKeys, setDefaultSelectedKeys] = useState(() => {
 | 
			
		||||
    if (dSelectedKeys) {
 | 
			
		||||
@ -241,7 +241,7 @@ export const Menu: ComposedMenu = observer((props) => {
 | 
			
		||||
            defaultSelectedKeys={defaultSelectedKeys}
 | 
			
		||||
          >
 | 
			
		||||
            <RecursionField schema={schema} onlyRenderProperties />
 | 
			
		||||
            {Initializer && <Initializer style={{ background: 'none', marginTop: 7, marginLeft: 8 }} />}
 | 
			
		||||
            {render({ style: { background: 'none', marginTop: 7, marginLeft: 8 } })}
 | 
			
		||||
          </AntdMenu>
 | 
			
		||||
          {loading
 | 
			
		||||
            ? null
 | 
			
		||||
@ -285,21 +285,19 @@ export const Menu: ComposedMenu = observer((props) => {
 | 
			
		||||
                    `}
 | 
			
		||||
                  >
 | 
			
		||||
                    <RecursionField schema={sideMenuSchema} onlyRenderProperties />
 | 
			
		||||
                    {Initializer && (
 | 
			
		||||
                      <Initializer
 | 
			
		||||
                        style={{ margin: 8 }}
 | 
			
		||||
                        insert={(s) => {
 | 
			
		||||
                          console.log('createDesignable', s);
 | 
			
		||||
                          const dn = createDesignable({
 | 
			
		||||
                            api,
 | 
			
		||||
                            refresh,
 | 
			
		||||
                            current: sideMenuSchema,
 | 
			
		||||
                          });
 | 
			
		||||
                          dn.loadAPIClientEvents();
 | 
			
		||||
                          dn.insertAdjacent('beforeEnd', s);
 | 
			
		||||
                        }}
 | 
			
		||||
                      />
 | 
			
		||||
                    )}
 | 
			
		||||
                    {render({
 | 
			
		||||
                      style: { margin: 8 },
 | 
			
		||||
                      insert: (s) => {
 | 
			
		||||
                        console.log('createDesignable', s);
 | 
			
		||||
                        const dn = createDesignable({
 | 
			
		||||
                          api,
 | 
			
		||||
                          refresh,
 | 
			
		||||
                          current: sideMenuSchema,
 | 
			
		||||
                        });
 | 
			
		||||
                        dn.loadAPIClientEvents();
 | 
			
		||||
                        dn.insertAdjacent('beforeEnd', s);
 | 
			
		||||
                      },
 | 
			
		||||
                    })}
 | 
			
		||||
                  </AntdMenu>
 | 
			
		||||
                </MenuModeContext.Provider>,
 | 
			
		||||
                sideMenuRef.current.firstChild,
 | 
			
		||||
@ -331,9 +329,15 @@ Menu.URL = observer((props) => {
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const Designer = useContext(MenuItemDesignerContext);
 | 
			
		||||
  return (
 | 
			
		||||
    <AntdMenu.Item {...others} key={schema.name} eventKey={schema.name} schema={schema} onClick={() => {
 | 
			
		||||
      window.open(props.href, '_blank');
 | 
			
		||||
    }}>
 | 
			
		||||
    <AntdMenu.Item
 | 
			
		||||
      {...others}
 | 
			
		||||
      key={schema.name}
 | 
			
		||||
      eventKey={schema.name}
 | 
			
		||||
      schema={schema}
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        window.open(props.href, '_blank');
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <SortableItem className={designerCss}>
 | 
			
		||||
        <Icon style={{ marginRight: 5 }} type={icon} />
 | 
			
		||||
        {schema.title}
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,11 @@
 | 
			
		||||
import { FormDialog, FormLayout } from '@formily/antd';
 | 
			
		||||
import { observer, SchemaOptionsContext } from '@formily/react';
 | 
			
		||||
import { SchemaOptionsContext } from '@formily/react';
 | 
			
		||||
import React, { useContext } from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { SchemaComponent, SchemaComponentOptions } from '../../..';
 | 
			
		||||
import { SchemaInitializer } from '../../../../schema-initializer';
 | 
			
		||||
 | 
			
		||||
export const MenuItemInitializer = observer((props: any) => {
 | 
			
		||||
export const MenuItemInitializers = (props: any) => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
@ -34,7 +34,7 @@ export const MenuItemInitializer = observer((props: any) => {
 | 
			
		||||
      {t('Add menu item')}
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const itemWrap = SchemaInitializer.itemWrap;
 | 
			
		||||
 | 
			
		||||
@ -137,7 +137,7 @@ export const PageMenuItem = itemWrap((props) => {
 | 
			
		||||
                grid: {
 | 
			
		||||
                  type: 'void',
 | 
			
		||||
                  'x-component': 'Grid',
 | 
			
		||||
                  'x-item-initializer': 'BlockInitializer',
 | 
			
		||||
                  'x-initializer': 'BlockInitializers',
 | 
			
		||||
                  properties: {},
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
export * from './Menu';
 | 
			
		||||
export * from './MenuItemInitializer';
 | 
			
		||||
export * from './MenuItemInitializers';
 | 
			
		||||
export * from './util';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,71 +0,0 @@
 | 
			
		||||
import { ISchema, observer } from '@formily/react';
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { SchemaInitializer } from '../..';
 | 
			
		||||
import { CalendarBlock } from './CalendarBlock';
 | 
			
		||||
import { FormBlock } from './FormBlock';
 | 
			
		||||
import { MarkdownBlock } from './MarkdownBlock';
 | 
			
		||||
import { TableBlock } from './TableBlock';
 | 
			
		||||
 | 
			
		||||
const gridRowColWrap = (schema: ISchema) => {
 | 
			
		||||
  return {
 | 
			
		||||
    type: 'void',
 | 
			
		||||
    'x-component': 'Grid.Row',
 | 
			
		||||
    properties: {
 | 
			
		||||
      [uid()]: {
 | 
			
		||||
        type: 'void',
 | 
			
		||||
        'x-component': 'Grid.Col',
 | 
			
		||||
        properties: {
 | 
			
		||||
          [schema.name || uid()]: schema,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const BlockInitializer = observer((props: any) => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      wrap={gridRowColWrap}
 | 
			
		||||
      insertPosition={'beforeEnd'}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: t('Data blocks'),
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Table'),
 | 
			
		||||
              component: TableBlock,
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Form'),
 | 
			
		||||
              component: FormBlock,
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Calendar'),
 | 
			
		||||
              component: CalendarBlock,
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: t('Media'),
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Markdown'),
 | 
			
		||||
              component: MarkdownBlock,
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      {t('Add block')}
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -0,0 +1,41 @@
 | 
			
		||||
import { gridRowColWrap } from './utils';
 | 
			
		||||
 | 
			
		||||
// 页面里添加区块
 | 
			
		||||
export const BlockInitializers = {
 | 
			
		||||
  title: '{{t("Add block")}}',
 | 
			
		||||
  wrap: gridRowColWrap,
 | 
			
		||||
  items: [
 | 
			
		||||
    {
 | 
			
		||||
      type: 'itemGroup',
 | 
			
		||||
      title: 'Data blocks',
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: 'Table',
 | 
			
		||||
          component: 'TableBlockInitializer',
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: 'Form',
 | 
			
		||||
          component: 'FormBlockInitializer',
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: 'Calendar',
 | 
			
		||||
          component: 'CalendarBlockInitializer',
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      type: 'itemGroup',
 | 
			
		||||
      title: 'Media',
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: 'Markdown',
 | 
			
		||||
          component: 'MarkdownBlockInitializer',
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
};
 | 
			
		||||
@ -1,187 +0,0 @@
 | 
			
		||||
import { observer, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { Switch } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { SchemaInitializer } from '../..';
 | 
			
		||||
import { useDesignable } from '../../../schema-component';
 | 
			
		||||
 | 
			
		||||
const useCurrentActionSchema = (action: string) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const { remove } = useDesignable();
 | 
			
		||||
  const schema = fieldSchema.reduceProperties((buf, s) => {
 | 
			
		||||
    if (s['x-action'] === action) {
 | 
			
		||||
      return s;
 | 
			
		||||
    }
 | 
			
		||||
    return buf;
 | 
			
		||||
  });
 | 
			
		||||
  return {
 | 
			
		||||
    schema,
 | 
			
		||||
    exists: !!schema,
 | 
			
		||||
    remove() {
 | 
			
		||||
      schema && remove(schema);
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const InitializeAction = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { exists, remove } = useCurrentActionSchema(item.schema['x-action']);
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          'x-designer': 'Action.Designer',
 | 
			
		||||
          'x-component': 'Action',
 | 
			
		||||
          ...item.schema,
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title}
 | 
			
		||||
        <Switch style={{ marginLeft: 20 }} size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const CalendarActionInitializer = observer((props: any) => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      insertPosition={'beforeEnd'}
 | 
			
		||||
      style={{ marginLeft: 8 }}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: t('Enable actions'),
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Today'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: t('Today'),
 | 
			
		||||
                'x-component': 'Calendar.Today',
 | 
			
		||||
                'x-action': `calendar:today`,
 | 
			
		||||
                'x-align': 'left',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Turn page'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: t('Turn page'),
 | 
			
		||||
                'x-component': 'Calendar.Nav',
 | 
			
		||||
                'x-action': `calendar:nav`,
 | 
			
		||||
                'x-align': 'left',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Title'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: t('Title'),
 | 
			
		||||
                'x-component': 'Calendar.Title',
 | 
			
		||||
                'x-action': `calendar:title`,
 | 
			
		||||
                'x-align': 'left',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Select view'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: t('Select view'),
 | 
			
		||||
                'x-component': 'Calendar.ViewSelect',
 | 
			
		||||
                'x-action': `calendar:viewSelect`,
 | 
			
		||||
                'x-align': 'left',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Filter'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: '{{ t("Filter") }}',
 | 
			
		||||
                'x-action': 'filter',
 | 
			
		||||
                'x-align': 'left',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Add new'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                title: '{{ t("Add new") }}',
 | 
			
		||||
                'x-action': 'create',
 | 
			
		||||
                'x-component': 'Action',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  type: 'primary',
 | 
			
		||||
                  openMode: 'drawer',
 | 
			
		||||
                },
 | 
			
		||||
                properties: {
 | 
			
		||||
                  drawer: {
 | 
			
		||||
                    type: 'void',
 | 
			
		||||
                    title: '{{ t("Add new record") }}',
 | 
			
		||||
                    'x-component': 'Action.Container',
 | 
			
		||||
                    'x-component-props': {},
 | 
			
		||||
                    'x-decorator': 'Form',
 | 
			
		||||
                    properties: {
 | 
			
		||||
                      grid: {
 | 
			
		||||
                        type: 'void',
 | 
			
		||||
                        'x-component': 'Grid',
 | 
			
		||||
                        'x-item-initializer': 'FormItemInitializer',
 | 
			
		||||
                        properties: {},
 | 
			
		||||
                      },
 | 
			
		||||
                      footer: {
 | 
			
		||||
                        type: 'void',
 | 
			
		||||
                        'x-component': 'Action.Container.Footer',
 | 
			
		||||
                        properties: {
 | 
			
		||||
                          actions: {
 | 
			
		||||
                            type: 'void',
 | 
			
		||||
                            'x-action-initializer': 'PopupFormActionInitializer',
 | 
			
		||||
                            'x-decorator': 'DndContext',
 | 
			
		||||
                            'x-component': 'ActionBar',
 | 
			
		||||
                            'x-component-props': {
 | 
			
		||||
                              layout: 'one-column',
 | 
			
		||||
                            },
 | 
			
		||||
                            properties: {},
 | 
			
		||||
                          },
 | 
			
		||||
                        },
 | 
			
		||||
                      },
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Delete'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: '{{ t("Delete") }}',
 | 
			
		||||
                'x-action': 'destroy',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  confirm: {
 | 
			
		||||
                    title: "{{t('Delete record')}}",
 | 
			
		||||
                    content: "{{t('Are you sure you want to delete it?')}}",
 | 
			
		||||
                  },
 | 
			
		||||
                  useAction: '{{ cm.useBulkDestroyAction }}',
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      {t('Configure actions')}
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -0,0 +1,75 @@
 | 
			
		||||
// 日历的操作配置
 | 
			
		||||
export const CalendarActionInitializers = {
 | 
			
		||||
  title: 'Configure actions',
 | 
			
		||||
  style: { marginLeft: 8 },
 | 
			
		||||
  items: [
 | 
			
		||||
    {
 | 
			
		||||
      type: 'itemGroup',
 | 
			
		||||
      title: 'Enable actions',
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: 'Today',
 | 
			
		||||
          component: 'ActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: 'Today',
 | 
			
		||||
            'x-component': 'Calendar.Today',
 | 
			
		||||
            'x-action': `calendar:today`,
 | 
			
		||||
            'x-align': 'left',
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: 'Turn pages',
 | 
			
		||||
          component: 'ActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: 'Turn page',
 | 
			
		||||
            'x-component': 'Calendar.Nav',
 | 
			
		||||
            'x-action': `calendar:nav`,
 | 
			
		||||
            'x-align': 'left',
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: 'Title',
 | 
			
		||||
          component: 'ActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: 'Title',
 | 
			
		||||
            'x-component': 'Calendar.Title',
 | 
			
		||||
            'x-action': `calendar:title`,
 | 
			
		||||
            'x-align': 'left',
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: 'Select view',
 | 
			
		||||
          component: 'ActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: 'Select view',
 | 
			
		||||
            'x-component': 'Calendar.ViewSelect',
 | 
			
		||||
            'x-action': `calendar:viewSelect`,
 | 
			
		||||
            'x-align': 'right',
 | 
			
		||||
            'x-designer': 'Action.Designer',
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: 'Filter',
 | 
			
		||||
          component: 'ActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: '{{ t("Filter") }}',
 | 
			
		||||
            'x-action': 'filter',
 | 
			
		||||
            'x-align': 'right',
 | 
			
		||||
            'x-component': 'Action',
 | 
			
		||||
            'x-designer': 'Action.Designer',
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: '{{ t("Add new") }}',
 | 
			
		||||
          component: 'AddNewActionInitializer',
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
};
 | 
			
		||||
@ -1,84 +0,0 @@
 | 
			
		||||
import { observer, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { Switch } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { SchemaInitializer } from '../..';
 | 
			
		||||
import { useDesignable } from '../../../schema-component';
 | 
			
		||||
 | 
			
		||||
const useCurrentActionSchema = (action: string) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const { remove } = useDesignable();
 | 
			
		||||
  const schema = fieldSchema.reduceProperties((buf, s) => {
 | 
			
		||||
    if (s['x-action'] === action) {
 | 
			
		||||
      return s;
 | 
			
		||||
    }
 | 
			
		||||
    return buf;
 | 
			
		||||
  });
 | 
			
		||||
  return {
 | 
			
		||||
    schema,
 | 
			
		||||
    exists: !!schema,
 | 
			
		||||
    remove() {
 | 
			
		||||
      schema && remove(schema);
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const InitializeAction = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { exists, remove } = useCurrentActionSchema(item.schema['x-action']);
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          'x-designer': 'TestDesigner',
 | 
			
		||||
          'x-component': 'Action',
 | 
			
		||||
          ...item.schema,
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title} <Switch size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const DetailsActionInitializer = observer((props: any) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      insertPosition={'beforeEnd'}
 | 
			
		||||
      style={{ marginLeft: 8 }}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: 'Enable actions',
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: 'Edit',
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: 'Edit',
 | 
			
		||||
                'x-action': 'update',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: 'Delete',
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: 'Delete',
 | 
			
		||||
                'x-action': 'delete',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      Configure actions
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -0,0 +1,30 @@
 | 
			
		||||
// 详情的操作配置
 | 
			
		||||
export const DetailsActionInitializers = {
 | 
			
		||||
  title: 'Configure actions',
 | 
			
		||||
  items: [
 | 
			
		||||
    {
 | 
			
		||||
      type: 'itemGroup',
 | 
			
		||||
      title: 'Enable actions',
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: 'Edit',
 | 
			
		||||
          component: 'ActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: 'Edit',
 | 
			
		||||
            'x-action': 'update',
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: 'Delete',
 | 
			
		||||
          component: 'ActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: 'Delete',
 | 
			
		||||
            'x-action': 'delete',
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
};
 | 
			
		||||
@ -1,83 +0,0 @@
 | 
			
		||||
import { observer, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { Switch } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { SchemaInitializer } from '../..';
 | 
			
		||||
import { useDesignable } from '../../../schema-component';
 | 
			
		||||
 | 
			
		||||
const useCurrentActionSchema = (action: string) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const { remove } = useDesignable();
 | 
			
		||||
  const schema = fieldSchema.reduceProperties((buf, s) => {
 | 
			
		||||
    if (s['x-action'] === action) {
 | 
			
		||||
      return s;
 | 
			
		||||
    }
 | 
			
		||||
    return buf;
 | 
			
		||||
  });
 | 
			
		||||
  return {
 | 
			
		||||
    schema,
 | 
			
		||||
    exists: !!schema,
 | 
			
		||||
    remove() {
 | 
			
		||||
      schema && remove(schema);
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const InitializeAction = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { exists, remove } = useCurrentActionSchema(item.schema['x-action']);
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          'x-designer': 'Action.Designer',
 | 
			
		||||
          'x-component': 'Action',
 | 
			
		||||
          ...item.schema,
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title}
 | 
			
		||||
        <Switch style={{ marginLeft: 20 }} size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const FormActionInitializer = observer((props: any) => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      insertPosition={'beforeEnd'}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: t('Enable actions'),
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Submit'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: '{{ t("Submit") }}',
 | 
			
		||||
                'x-action': 'submit',
 | 
			
		||||
                'x-align': 'left',
 | 
			
		||||
                'x-component': 'Action',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  type: 'primary',
 | 
			
		||||
                  useAction: '{{ cm.useCreateActionWithoutRefresh }}',
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      {t('Configure actions')}
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -0,0 +1,27 @@
 | 
			
		||||
// 普通表单的操作配置
 | 
			
		||||
export const FormActionInitializers = {
 | 
			
		||||
  title: 'Configure actions',
 | 
			
		||||
  items: [
 | 
			
		||||
    {
 | 
			
		||||
      type: 'itemGroup',
 | 
			
		||||
      title: 'Enable actions',
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: '{{ t("Submit") }}',
 | 
			
		||||
          component: 'ActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: '{{ t("Submit") }}',
 | 
			
		||||
            'x-action': 'submit',
 | 
			
		||||
            'x-align': 'left',
 | 
			
		||||
            'x-component': 'Action',
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              type: 'primary',
 | 
			
		||||
              useAction: '{{ cm.useCreateActionWithoutRefresh }}',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
};
 | 
			
		||||
@ -1,145 +0,0 @@
 | 
			
		||||
import { ISchema, observer, Schema, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
import { Switch } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { SchemaInitializer, SchemaInitializerItemOptions } from '../..';
 | 
			
		||||
import { useCollection } from '../../../collection-manager';
 | 
			
		||||
import { useDesignable } from '../../../schema-component';
 | 
			
		||||
 | 
			
		||||
const useFormItemInitializerFields = () => {
 | 
			
		||||
  const { name, fields } = useCollection();
 | 
			
		||||
  return fields?.map((field) => {
 | 
			
		||||
    return {
 | 
			
		||||
      type: 'item',
 | 
			
		||||
      title: field?.uiSchema?.title || field.name,
 | 
			
		||||
      component: FormItem,
 | 
			
		||||
      schema: {
 | 
			
		||||
        name: field.name,
 | 
			
		||||
        'x-designer': 'FormItem.Designer',
 | 
			
		||||
        'x-component': 'CollectionField',
 | 
			
		||||
        'x-decorator': 'FormItem',
 | 
			
		||||
        'x-collection-field': `${name}.${field.name}`,
 | 
			
		||||
      },
 | 
			
		||||
    } as SchemaInitializerItemOptions;
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const gridRowColWrap = (schema: ISchema) => {
 | 
			
		||||
  return {
 | 
			
		||||
    type: 'void',
 | 
			
		||||
    'x-component': 'Grid.Row',
 | 
			
		||||
    properties: {
 | 
			
		||||
      [uid()]: {
 | 
			
		||||
        type: 'void',
 | 
			
		||||
        'x-component': 'Grid.Col',
 | 
			
		||||
        properties: {
 | 
			
		||||
          [schema.name || uid()]: schema,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const useCurrentFieldSchema = (path: string) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const { remove } = useDesignable();
 | 
			
		||||
  const findFieldSchema = (schema: Schema) => {
 | 
			
		||||
    return schema.reduceProperties((buf, s) => {
 | 
			
		||||
      if (s['x-collection-field'] === path) {
 | 
			
		||||
        return s;
 | 
			
		||||
      }
 | 
			
		||||
      const child = findFieldSchema(s);
 | 
			
		||||
      if (child) {
 | 
			
		||||
        return child;
 | 
			
		||||
      }
 | 
			
		||||
      return buf;
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
  const schema = findFieldSchema(fieldSchema);
 | 
			
		||||
  return {
 | 
			
		||||
    schema,
 | 
			
		||||
    exists: !!schema,
 | 
			
		||||
    remove() {
 | 
			
		||||
      schema &&
 | 
			
		||||
        remove(schema, {
 | 
			
		||||
          removeParentsIfNoChildren: true,
 | 
			
		||||
          breakRemoveOn: (s) => {
 | 
			
		||||
            return s['x-component'] === 'Grid';
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const itemWrap = SchemaInitializer.itemWrap;
 | 
			
		||||
 | 
			
		||||
const FormItem = itemWrap((props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { schema, exists, remove } = useCurrentFieldSchema(item.schema['x-collection-field']);
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          ...item.schema,
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title} <Switch size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const TextItem = itemWrap((props) => {
 | 
			
		||||
  const { insert } = props;
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        insert({
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          'x-editable': false,
 | 
			
		||||
          'x-decorator': 'FormItem',
 | 
			
		||||
          'x-designer': 'Markdown.Void.Designer',
 | 
			
		||||
          'x-component': 'Markdown.Void',
 | 
			
		||||
          'x-component-props': {
 | 
			
		||||
            content: t('This is a demo text, **supports Markdown syntax**.'),
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const FormItemInitializer = observer((props: any) => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      wrap={gridRowColWrap}
 | 
			
		||||
      insertPosition={'beforeEnd'}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: t('Display fields'),
 | 
			
		||||
          children: useFormItemInitializerFields(),
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'divider',
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: t('Add text'),
 | 
			
		||||
          component: TextItem,
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      {t('Configure fields')}
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -0,0 +1,41 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { SchemaInitializer } from '../SchemaInitializer';
 | 
			
		||||
import { gridRowColWrap, useFormItemInitializerFields } from './utils';
 | 
			
		||||
 | 
			
		||||
// Grid 组件里配置字段
 | 
			
		||||
export const GridFormItemInitializers = (props: any) => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      wrap={gridRowColWrap}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: 'Display fields',
 | 
			
		||||
          children: useFormItemInitializerFields(),
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'divider',
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: 'Add text',
 | 
			
		||||
          component: 'GeneralInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            'x-editable': false,
 | 
			
		||||
            'x-decorator': 'FormItem',
 | 
			
		||||
            'x-designer': 'Markdown.Void.Designer',
 | 
			
		||||
            'x-component': 'Markdown.Void',
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              content: t('This is a demo text, **supports Markdown syntax**.'),
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      {t('Configure fields')}
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,26 @@
 | 
			
		||||
import { Switch } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { SchemaInitializer } from '../../SchemaInitializer';
 | 
			
		||||
import { useCurrentSchema } from '../utils';
 | 
			
		||||
 | 
			
		||||
export const ActionInitializer = (props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { exists, remove } = useCurrentSchema(item.schema['x-action'], 'x-action', item.find);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          ...item.schema,
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title} <Switch style={{ marginLeft: 20 }} size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,67 @@
 | 
			
		||||
import { Switch } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { SchemaInitializer } from '../../SchemaInitializer';
 | 
			
		||||
import { useCurrentSchema } from '../utils';
 | 
			
		||||
 | 
			
		||||
export const AddNewActionInitializer = (props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { exists, remove } = useCurrentSchema(item?.schema?.['x-action'] || 'create', 'x-action', item.find);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          title: '{{ t("Add new") }}',
 | 
			
		||||
          'x-action': 'create',
 | 
			
		||||
          'x-component': 'Action',
 | 
			
		||||
          'x-component-props': {
 | 
			
		||||
            type: 'primary',
 | 
			
		||||
            openMode: 'drawer',
 | 
			
		||||
          },
 | 
			
		||||
          properties: {
 | 
			
		||||
            drawer: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              title: '{{ t("Add new record") }}',
 | 
			
		||||
              'x-component': 'Action.Container',
 | 
			
		||||
              'x-component-props': {},
 | 
			
		||||
              'x-decorator': 'Form',
 | 
			
		||||
              properties: {
 | 
			
		||||
                grid: {
 | 
			
		||||
                  type: 'void',
 | 
			
		||||
                  'x-component': 'Grid',
 | 
			
		||||
                  'x-initializer': 'GridFormItemInitializers',
 | 
			
		||||
                  properties: {},
 | 
			
		||||
                },
 | 
			
		||||
                footer: {
 | 
			
		||||
                  type: 'void',
 | 
			
		||||
                  'x-component': 'Action.Container.Footer',
 | 
			
		||||
                  properties: {
 | 
			
		||||
                    actions: {
 | 
			
		||||
                      type: 'void',
 | 
			
		||||
                      'x-initializer': 'PopupFormActionInitializers',
 | 
			
		||||
                      'x-decorator': 'DndContext',
 | 
			
		||||
                      'x-component': 'ActionBar',
 | 
			
		||||
                      'x-component-props': {
 | 
			
		||||
                        layout: 'one-column',
 | 
			
		||||
                      },
 | 
			
		||||
                      properties: {},
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          ...item.schema,
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title} <Switch style={{ marginLeft: 20 }} size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -3,9 +3,9 @@ import { FormDialog, FormLayout } from '@formily/antd';
 | 
			
		||||
import { ISchema, SchemaOptionsContext } from '@formily/react';
 | 
			
		||||
import React, { useContext } from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { SchemaInitializer } from '../..';
 | 
			
		||||
import { useCollectionManager } from '../../../collection-manager';
 | 
			
		||||
import { SchemaComponent, SchemaComponentOptions } from '../../../schema-component';
 | 
			
		||||
import { SchemaInitializer } from '../../SchemaInitializer';
 | 
			
		||||
 | 
			
		||||
const createSchema = (collectionName, { title, start, end }) => {
 | 
			
		||||
  const schema: ISchema = {
 | 
			
		||||
@ -38,7 +38,12 @@ const createSchema = (collectionName, { title, start, end }) => {
 | 
			
		||||
          toolBar: {
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            'x-component': 'Calendar.ActionBar',
 | 
			
		||||
            'x-action-initializer': 'CalendarActionInitializer',
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              style: {
 | 
			
		||||
                marginBottom: 24,
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            'x-initializer': 'CalendarActionInitializers',
 | 
			
		||||
            properties: {},
 | 
			
		||||
          },
 | 
			
		||||
          event: {
 | 
			
		||||
@ -58,7 +63,7 @@ const createSchema = (collectionName, { title, start, end }) => {
 | 
			
		||||
                  grid: {
 | 
			
		||||
                    type: 'void',
 | 
			
		||||
                    'x-component': 'Grid',
 | 
			
		||||
                    'x-item-initializer': 'FormItemInitializer',
 | 
			
		||||
                    'x-initializer': 'GridFormItemInitializers',
 | 
			
		||||
                    properties: {},
 | 
			
		||||
                  },
 | 
			
		||||
                  footer: {
 | 
			
		||||
@ -67,7 +72,7 @@ const createSchema = (collectionName, { title, start, end }) => {
 | 
			
		||||
                    properties: {
 | 
			
		||||
                      actions: {
 | 
			
		||||
                        type: 'void',
 | 
			
		||||
                        'x-action-initializer': 'PopupFormActionInitializer',
 | 
			
		||||
                        'x-initializer': 'PopupFormActionInitializers',
 | 
			
		||||
                        'x-decorator': 'DndContext',
 | 
			
		||||
                        'x-component': 'ActionBar',
 | 
			
		||||
                        'x-component-props': {
 | 
			
		||||
@ -88,9 +93,7 @@ const createSchema = (collectionName, { title, start, end }) => {
 | 
			
		||||
  return schema;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const itemWrap = SchemaInitializer.itemWrap;
 | 
			
		||||
 | 
			
		||||
export const CalendarBlock = itemWrap((props) => {
 | 
			
		||||
export const CalendarBlockInitializer = (props) => {
 | 
			
		||||
  const { insert } = props;
 | 
			
		||||
  const { collections, getCollection } = useCollectionManager();
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
@ -160,4 +163,4 @@ export const CalendarBlock = itemWrap((props) => {
 | 
			
		||||
      ]}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,31 @@
 | 
			
		||||
import { Switch } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { SchemaInitializer } from '../../SchemaInitializer';
 | 
			
		||||
import { useCurrentSchema } from '../utils';
 | 
			
		||||
 | 
			
		||||
export const CollectionFieldInitializer = (props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { exists, remove } = useCurrentSchema(
 | 
			
		||||
    item.schema['x-collection-field'],
 | 
			
		||||
    'x-collection-field',
 | 
			
		||||
    item.find,
 | 
			
		||||
    item.remove,
 | 
			
		||||
  );
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        console.log(item, exists);
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          ...item.schema,
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title} <Switch style={{ marginLeft: 20 }} size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -29,12 +29,12 @@ const createSchema = (collectionName) => {
 | 
			
		||||
          grid: {
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            'x-component': 'Grid',
 | 
			
		||||
            'x-item-initializer': 'FormItemInitializer',
 | 
			
		||||
            'x-initializer': 'GridFormItemInitializers',
 | 
			
		||||
            properties: {},
 | 
			
		||||
          },
 | 
			
		||||
          actions: {
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            'x-action-initializer': 'FormActionInitializer',
 | 
			
		||||
            'x-initializer': 'FormActionInitializers',
 | 
			
		||||
            'x-component': 'ActionBar',
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              layout: 'one-column',
 | 
			
		||||
@ -51,9 +51,7 @@ const createSchema = (collectionName) => {
 | 
			
		||||
  return schema;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const itemWrap = SchemaInitializer.itemWrap;
 | 
			
		||||
 | 
			
		||||
export const FormBlock = itemWrap((props) => {
 | 
			
		||||
export const FormBlockInitializer = (props) => {
 | 
			
		||||
  const { insert } = props;
 | 
			
		||||
  const { collections } = useCollectionManager();
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
@ -79,4 +77,4 @@ export const FormBlock = itemWrap((props) => {
 | 
			
		||||
      ]}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,15 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { SchemaInitializer } from '../../SchemaInitializer';
 | 
			
		||||
 | 
			
		||||
export const GeneralInitializer = (props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        insert({
 | 
			
		||||
          ...item.schema,
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -3,9 +3,7 @@ import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { SchemaInitializer } from '../..';
 | 
			
		||||
 | 
			
		||||
const itemWrap = SchemaInitializer.itemWrap;
 | 
			
		||||
 | 
			
		||||
export const MarkdownBlock = itemWrap((props) => {
 | 
			
		||||
export const MarkdownBlockInitializer = (props) => {
 | 
			
		||||
  const { insert } = props;
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  return (
 | 
			
		||||
@ -26,4 +24,4 @@ export const MarkdownBlock = itemWrap((props) => {
 | 
			
		||||
      }}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
};
 | 
			
		||||
@ -28,7 +28,7 @@ const createSchema = (collectionName) => {
 | 
			
		||||
    properties: {
 | 
			
		||||
      actions: {
 | 
			
		||||
        type: 'void',
 | 
			
		||||
        'x-action-initializer': 'TableActionInitializer',
 | 
			
		||||
        'x-initializer': 'TableActionInitializers',
 | 
			
		||||
        'x-component': 'ActionBar',
 | 
			
		||||
        'x-component-props': {
 | 
			
		||||
          style: {
 | 
			
		||||
@ -47,7 +47,7 @@ const createSchema = (collectionName) => {
 | 
			
		||||
          },
 | 
			
		||||
          useDataSource: '{{ cm.useDataSourceFromRAC }}',
 | 
			
		||||
        },
 | 
			
		||||
        'x-column-initializer': 'TableColumnInitializer',
 | 
			
		||||
        'x-initializer': 'TableColumnInitializers',
 | 
			
		||||
        properties: {
 | 
			
		||||
          actions: {
 | 
			
		||||
            type: 'void',
 | 
			
		||||
@ -55,7 +55,7 @@ const createSchema = (collectionName) => {
 | 
			
		||||
            'x-decorator': 'TableColumnActionBar',
 | 
			
		||||
            'x-component': 'VoidTable.Column',
 | 
			
		||||
            'x-designer': 'TableRecordActionDesigner',
 | 
			
		||||
            'x-action-initializer': 'TableRecordActionInitializer',
 | 
			
		||||
            'x-initializer': 'TableRecordActionInitializers',
 | 
			
		||||
            properties: {
 | 
			
		||||
              actions: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
@ -75,9 +75,7 @@ const createSchema = (collectionName) => {
 | 
			
		||||
  return schema;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const itemWrap = SchemaInitializer.itemWrap;
 | 
			
		||||
 | 
			
		||||
export const TableBlock = itemWrap((props) => {
 | 
			
		||||
export const TableBlockInitializer = (props) => {
 | 
			
		||||
  const { insert } = props;
 | 
			
		||||
  const { collections } = useCollectionManager();
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
@ -103,4 +101,4 @@ export const TableBlock = itemWrap((props) => {
 | 
			
		||||
      ]}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,9 @@
 | 
			
		||||
export * from './ActionInitializer';
 | 
			
		||||
export * from './AddNewActionInitializer';
 | 
			
		||||
export * from './CalendarBlockInitializer';
 | 
			
		||||
export * from './CollectionFieldInitializer';
 | 
			
		||||
export * from './FormBlockInitializer';
 | 
			
		||||
export * from './GeneralInitializer';
 | 
			
		||||
export * from './MarkdownBlockInitializer';
 | 
			
		||||
export * from './TableBlockInitializer';
 | 
			
		||||
 | 
			
		||||
@ -1,95 +0,0 @@
 | 
			
		||||
import { observer, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { Switch } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { SchemaInitializer } from '../..';
 | 
			
		||||
import { useDesignable } from '../../../schema-component';
 | 
			
		||||
 | 
			
		||||
const useCurrentActionSchema = (action: string) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const { remove } = useDesignable();
 | 
			
		||||
  const schema = fieldSchema.reduceProperties((buf, s) => {
 | 
			
		||||
    if (s['x-action'] === action) {
 | 
			
		||||
      return s;
 | 
			
		||||
    }
 | 
			
		||||
    return buf;
 | 
			
		||||
  });
 | 
			
		||||
  return {
 | 
			
		||||
    schema,
 | 
			
		||||
    exists: !!schema,
 | 
			
		||||
    remove() {
 | 
			
		||||
      schema && remove(schema);
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const InitializeAction = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { exists, remove } = useCurrentActionSchema(item.schema['x-action']);
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          'x-designer': 'Action.Designer',
 | 
			
		||||
          'x-component': 'Action',
 | 
			
		||||
          ...item.schema,
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title}
 | 
			
		||||
        <Switch style={{ marginLeft: 20 }} size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const PopupFormActionInitializer = observer((props: any) => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      insertPosition={'beforeEnd'}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: t('Enable actions'),
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Submit'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: '{{ t("Submit") }}',
 | 
			
		||||
                'x-action': 'submit',
 | 
			
		||||
                'x-component': 'Action',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  type: 'primary',
 | 
			
		||||
                  useAction: '{{ cm.useCreateAction }}',
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Cancel'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: '{{ t("Cancel") }}',
 | 
			
		||||
                'x-action': 'cancel',
 | 
			
		||||
                'x-component': 'Action',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  useAction: '{{ cm.useCancelAction }}',
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      {t('Configure actions')}
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -0,0 +1,39 @@
 | 
			
		||||
// 弹窗表单的操作配置
 | 
			
		||||
export const PopupFormActionInitializers = {
 | 
			
		||||
  title: "{{t('Configure actions')}}",
 | 
			
		||||
  items: [
 | 
			
		||||
    {
 | 
			
		||||
      type: 'itemGroup',
 | 
			
		||||
      title: "{{t('Enable actions')}}",
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: "{{t('Submit')}}",
 | 
			
		||||
          component: 'ActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: '{{ t("Submit") }}',
 | 
			
		||||
            'x-action': 'submit',
 | 
			
		||||
            'x-component': 'Action',
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              type: 'primary',
 | 
			
		||||
              useAction: '{{ cm.useCreateAction }}',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: "{{t('Cancel')}}",
 | 
			
		||||
          component: 'ActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: '{{ t("Cancel") }}',
 | 
			
		||||
            'x-action': 'cancel',
 | 
			
		||||
            'x-component': 'Action',
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              useAction: '{{ cm.useCancelAction }}',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
};
 | 
			
		||||
@ -1,64 +0,0 @@
 | 
			
		||||
import { FormOutlined } from '@ant-design/icons';
 | 
			
		||||
import { ISchema, observer } from '@formily/react';
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { SchemaInitializer } from '../..';
 | 
			
		||||
 | 
			
		||||
const gridRowColWrap = (schema: ISchema) => {
 | 
			
		||||
  return {
 | 
			
		||||
    type: 'void',
 | 
			
		||||
    'x-component': 'Grid.Row',
 | 
			
		||||
    properties: {
 | 
			
		||||
      [uid()]: {
 | 
			
		||||
        type: 'void',
 | 
			
		||||
        'x-component': 'Grid.Col',
 | 
			
		||||
        properties: {
 | 
			
		||||
          [schema.name || uid()]: schema,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const itemWrap = SchemaInitializer.itemWrap;
 | 
			
		||||
 | 
			
		||||
const FormBlock = itemWrap((props) => {
 | 
			
		||||
  const { insert } = props;
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      icon={<FormOutlined />}
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        insert({});
 | 
			
		||||
      }}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const RecordBlockInitializer = observer((props: any) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      wrap={gridRowColWrap}
 | 
			
		||||
      insertPosition={'beforeEnd'}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: 'Data blocks',
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: 'Form',
 | 
			
		||||
              component: FormBlock,
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: 'Details',
 | 
			
		||||
              component: FormBlock,
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      Add block
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
import { gridRowColWrap } from './utils';
 | 
			
		||||
 | 
			
		||||
// 当前行记录所在面板的添加区块
 | 
			
		||||
export const RecordBlockInitializers = {
 | 
			
		||||
  wrap: gridRowColWrap,
 | 
			
		||||
  title: "{{t('Add block')}}",
 | 
			
		||||
  items: [],
 | 
			
		||||
};
 | 
			
		||||
@ -1,143 +0,0 @@
 | 
			
		||||
import { observer, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { Switch } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { SchemaInitializer } from '../..';
 | 
			
		||||
import { useDesignable } from '../../../schema-component';
 | 
			
		||||
 | 
			
		||||
const useCurrentActionSchema = (action: string) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const { remove } = useDesignable();
 | 
			
		||||
  const schema = fieldSchema.reduceProperties((buf, s) => {
 | 
			
		||||
    if (s['x-action'] === action) {
 | 
			
		||||
      return s;
 | 
			
		||||
    }
 | 
			
		||||
    return buf;
 | 
			
		||||
  });
 | 
			
		||||
  return {
 | 
			
		||||
    schema,
 | 
			
		||||
    exists: !!schema,
 | 
			
		||||
    remove() {
 | 
			
		||||
      schema && remove(schema);
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const InitializeAction = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { exists, remove } = useCurrentActionSchema(item.schema['x-action']);
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          'x-designer': 'Action.Designer',
 | 
			
		||||
          'x-component': 'Action',
 | 
			
		||||
          ...item.schema,
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title}
 | 
			
		||||
        <Switch style={{ marginLeft: 20 }} size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const TableActionInitializer = observer((props: any) => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      insertPosition={'beforeEnd'}
 | 
			
		||||
      style={{ marginLeft: 8 }}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: t('Enable actions'),
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Filter'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: '{{ t("Filter") }}',
 | 
			
		||||
                'x-action': 'filter',
 | 
			
		||||
                'x-align': 'left',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Add new'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                title: '{{ t("Add new") }}',
 | 
			
		||||
                'x-action': 'create',
 | 
			
		||||
                'x-component': 'Action',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  type: 'primary',
 | 
			
		||||
                  openMode: 'drawer',
 | 
			
		||||
                },
 | 
			
		||||
                properties: {
 | 
			
		||||
                  drawer: {
 | 
			
		||||
                    type: 'void',
 | 
			
		||||
                    title: '{{ t("Add new record") }}',
 | 
			
		||||
                    'x-component': 'Action.Container',
 | 
			
		||||
                    'x-component-props': {},
 | 
			
		||||
                    'x-decorator': 'Form',
 | 
			
		||||
                    properties: {
 | 
			
		||||
                      grid: {
 | 
			
		||||
                        type: 'void',
 | 
			
		||||
                        'x-component': 'Grid',
 | 
			
		||||
                        'x-item-initializer': 'FormItemInitializer',
 | 
			
		||||
                        properties: {},
 | 
			
		||||
                      },
 | 
			
		||||
                      footer: {
 | 
			
		||||
                        type: 'void',
 | 
			
		||||
                        'x-component': 'Action.Container.Footer',
 | 
			
		||||
                        properties: {
 | 
			
		||||
                          actions: {
 | 
			
		||||
                            type: 'void',
 | 
			
		||||
                            'x-action-initializer': 'PopupFormActionInitializer',
 | 
			
		||||
                            'x-decorator': 'DndContext',
 | 
			
		||||
                            'x-component': 'ActionBar',
 | 
			
		||||
                            'x-component-props': {
 | 
			
		||||
                              layout: 'one-column',
 | 
			
		||||
                            },
 | 
			
		||||
                            properties: {},
 | 
			
		||||
                          },
 | 
			
		||||
                        },
 | 
			
		||||
                      },
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Delete'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: '{{ t("Delete") }}',
 | 
			
		||||
                'x-action': 'destroy',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  confirm: {
 | 
			
		||||
                    title: "{{t('Delete record')}}",
 | 
			
		||||
                    content: "{{t('Are you sure you want to delete it?')}}",
 | 
			
		||||
                  },
 | 
			
		||||
                  useAction: '{{ cm.useBulkDestroyAction }}',
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      {t('Configure actions')}
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -0,0 +1,50 @@
 | 
			
		||||
// 表格操作配置
 | 
			
		||||
export const TableActionInitializers = {
 | 
			
		||||
  title: "{{t('Configure actions')}}",
 | 
			
		||||
  style: {
 | 
			
		||||
    marginLeft: 8,
 | 
			
		||||
  },
 | 
			
		||||
  items: [
 | 
			
		||||
    {
 | 
			
		||||
      type: 'itemGroup',
 | 
			
		||||
      title: "{{t('Enable actions')}}",
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: "{{t('Filter')}}",
 | 
			
		||||
          component: 'ActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: '{{ t("Filter") }}',
 | 
			
		||||
            'x-action': 'filter',
 | 
			
		||||
            'x-align': 'left',
 | 
			
		||||
            'x-component': 'Action',
 | 
			
		||||
            'x-designer': 'Action.Designer',
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: "{{t('Add new')}}",
 | 
			
		||||
          component: 'AddNewActionInitializer',
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: "{{t('Delete')}}",
 | 
			
		||||
          component: 'ActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: '{{ t("Delete") }}',
 | 
			
		||||
            'x-action': 'destroy',
 | 
			
		||||
            'x-component': 'Action',
 | 
			
		||||
            'x-designer': 'Action.Designer',
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              confirm: {
 | 
			
		||||
                title: "{{t('Delete record')}}",
 | 
			
		||||
                content: "{{t('Are you sure you want to delete it?')}}",
 | 
			
		||||
              },
 | 
			
		||||
              useAction: '{{ cm.useBulkDestroyAction }}',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
};
 | 
			
		||||
@ -1,102 +0,0 @@
 | 
			
		||||
import { observer, Schema, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { Switch } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { SchemaInitializer, SchemaInitializerItemOptions } from '../..';
 | 
			
		||||
import { useCollection, useDesignable } from '../../..';
 | 
			
		||||
 | 
			
		||||
const useTableColumnInitializerFields = () => {
 | 
			
		||||
  const { name, fields } = useCollection();
 | 
			
		||||
  return (
 | 
			
		||||
    fields
 | 
			
		||||
      // .filter((field) => field?.uiSchema?.title)
 | 
			
		||||
      .map((field) => {
 | 
			
		||||
        return {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: field?.uiSchema?.title || field.name,
 | 
			
		||||
          schema: {
 | 
			
		||||
            name: field.name,
 | 
			
		||||
            'x-collection-field': `${name}.${field.name}`,
 | 
			
		||||
            'x-component': 'CollectionField',
 | 
			
		||||
          },
 | 
			
		||||
          component: ColumnInitializerItem,
 | 
			
		||||
        } as SchemaInitializerItemOptions;
 | 
			
		||||
      })
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const useCurrentColumnSchema = (path: string) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const { remove } = useDesignable();
 | 
			
		||||
  const findFieldSchema = (schema: Schema) => {
 | 
			
		||||
    return schema.reduceProperties((buf, s) => {
 | 
			
		||||
      if (s['x-collection-field'] === path) {
 | 
			
		||||
        return s;
 | 
			
		||||
      }
 | 
			
		||||
      const child = findFieldSchema(s);
 | 
			
		||||
      if (child) {
 | 
			
		||||
        return child;
 | 
			
		||||
      }
 | 
			
		||||
      return buf;
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
  const schema = findFieldSchema(fieldSchema);
 | 
			
		||||
  return {
 | 
			
		||||
    schema,
 | 
			
		||||
    exists: !!schema,
 | 
			
		||||
    remove() {
 | 
			
		||||
      schema && remove(schema.parent);
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const ColumnInitializerItem = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { exists, remove } = useCurrentColumnSchema(item.schema['x-collection-field']);
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          'x-decorator': 'TableColumnDecorator',
 | 
			
		||||
          'x-designer': 'TableColumnDeigner',
 | 
			
		||||
          'x-component': 'VoidTable.Column',
 | 
			
		||||
          properties: {
 | 
			
		||||
            [item.schema.name]: {
 | 
			
		||||
              'x-read-pretty': true,
 | 
			
		||||
              ...item.schema,
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title} <Switch style={{ marginLeft: 20 }} size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 表格列配置器
 | 
			
		||||
 */
 | 
			
		||||
export const TableColumnInitializer = observer((props: any) => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      insertPosition={'beforeEnd'}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: t('Display fields'),
 | 
			
		||||
          children: useTableColumnInitializerFields(),
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      {t('Configure columns')}
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -0,0 +1,37 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { SchemaInitializer } from '../SchemaInitializer';
 | 
			
		||||
import { useTableColumnInitializerFields } from './utils';
 | 
			
		||||
 | 
			
		||||
// 表格列配置
 | 
			
		||||
export const TableColumnInitializers = (props: any) => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      insertPosition={'beforeEnd'}
 | 
			
		||||
      wrap={(s) => {
 | 
			
		||||
        return {
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          'x-decorator': 'TableColumnDecorator',
 | 
			
		||||
          'x-designer': 'TableColumnDeigner',
 | 
			
		||||
          'x-component': 'VoidTable.Column',
 | 
			
		||||
          properties: {
 | 
			
		||||
            [s.name]: {
 | 
			
		||||
              'x-read-pretty': true,
 | 
			
		||||
              ...s,
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        };
 | 
			
		||||
      }}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: t('Display fields'),
 | 
			
		||||
          children: useTableColumnInitializerFields(),
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      {t('Configure columns')}
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -1,92 +1,18 @@
 | 
			
		||||
import { MenuOutlined } from '@ant-design/icons';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { observer, Schema, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { Switch } from 'antd';
 | 
			
		||||
import { useFieldSchema } from '@formily/react';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { SchemaInitializer } from '../..';
 | 
			
		||||
import { useAPIClient } from '../../../api-client';
 | 
			
		||||
import { createDesignable, useDesignable } from '../../../schema-component';
 | 
			
		||||
import { useAPIClient } from '../../api-client';
 | 
			
		||||
import { createDesignable, useDesignable } from '../../schema-component';
 | 
			
		||||
 | 
			
		||||
const useCurrentActionSchema = (action: string) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const { remove } = useDesignable();
 | 
			
		||||
  const findActionSchema = (schema: Schema) => {
 | 
			
		||||
    return schema.reduceProperties((buf, s) => {
 | 
			
		||||
      if (s['x-action'] === action) {
 | 
			
		||||
        return s;
 | 
			
		||||
      }
 | 
			
		||||
      const c = findActionSchema(s);
 | 
			
		||||
      if (c) {
 | 
			
		||||
        return c;
 | 
			
		||||
      }
 | 
			
		||||
      return buf;
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
  const schema = findActionSchema(fieldSchema);
 | 
			
		||||
  return {
 | 
			
		||||
    schema,
 | 
			
		||||
    exists: !!schema,
 | 
			
		||||
    remove() {
 | 
			
		||||
      schema && remove(schema);
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const InitializeViewAction = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { exists, remove } = useCurrentActionSchema(item.schema['x-action']);
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        console.log('InitializeAction', insert);
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          'x-component': 'Action.Link',
 | 
			
		||||
          ...item.schema,
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title} <Switch style={{ marginLeft: 20 }} size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const InitializeAction = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { exists, remove } = useCurrentActionSchema(item.schema['x-action']);
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        console.log('InitializeAction', insert);
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          'x-designer': 'Action.Designer',
 | 
			
		||||
          'x-component': 'Action.Link',
 | 
			
		||||
          ...item.schema,
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title} <Switch style={{ marginLeft: 20 }} size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const TableRecordActionInitializer = observer((props: any) => {
 | 
			
		||||
export const TableRecordActionInitializers = (props: any) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const api = useAPIClient();
 | 
			
		||||
  const { refresh } = useDesignable();
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  console.log('TableRecordActionInitializers');
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      className={css`
 | 
			
		||||
@ -126,7 +52,7 @@ export const TableRecordActionInitializer = observer((props: any) => {
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('View'),
 | 
			
		||||
              component: InitializeViewAction,
 | 
			
		||||
              component: 'ActionInitializer',
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: '{{ t("View") }}',
 | 
			
		||||
                type: 'void',
 | 
			
		||||
@ -171,11 +97,12 @@ export const TableRecordActionInitializer = observer((props: any) => {
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Edit'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              component: 'ActionInitializer',
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: '{{ t("Edit") }}',
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                'x-action': 'update',
 | 
			
		||||
                'x-designer': 'Action.Designer',
 | 
			
		||||
                'x-component': 'Action.Link',
 | 
			
		||||
                'x-component-props': {},
 | 
			
		||||
                properties: {
 | 
			
		||||
@ -218,10 +145,12 @@ export const TableRecordActionInitializer = observer((props: any) => {
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: t('Delete'),
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              component: 'ActionInitializer',
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: '{{ t("Delete") }}',
 | 
			
		||||
                'x-action': 'destroy',
 | 
			
		||||
                'x-designer': 'Action.Designer',
 | 
			
		||||
                'x-component': 'Action.Link',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  confirm: {
 | 
			
		||||
                    title: "{{t('Delete record')}}",
 | 
			
		||||
@ -238,4 +167,4 @@ export const TableRecordActionInitializer = observer((props: any) => {
 | 
			
		||||
      <MenuOutlined />
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
};
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
export * from './BlockInitializer';
 | 
			
		||||
export * from './CalendarActionInitializer';
 | 
			
		||||
export * from './DetailsActionInitializer';
 | 
			
		||||
export * from './FormActionInitializer';
 | 
			
		||||
export * from './FormItemInitializer';
 | 
			
		||||
export * from './PopupFormActionInitializer';
 | 
			
		||||
export * from './RecordBlockInitializer';
 | 
			
		||||
export * from './TableActionInitializer';
 | 
			
		||||
export * from './TableColumnInitializer';
 | 
			
		||||
export * from './TableRecordActionInitializer';
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,36 @@
 | 
			
		||||
import { BlockInitializers } from './BlockInitializers';
 | 
			
		||||
import { CalendarActionInitializers } from './CalendarActionInitializers';
 | 
			
		||||
import { DetailsActionInitializers } from './DetailsActionInitializers';
 | 
			
		||||
import { FormActionInitializers } from './FormActionInitializers';
 | 
			
		||||
import { GridFormItemInitializers } from './GridFormItemInitializers';
 | 
			
		||||
import * as Items from './Items';
 | 
			
		||||
import { PopupFormActionInitializers } from './PopupFormActionInitializers';
 | 
			
		||||
import { RecordBlockInitializers } from './RecordBlockInitializers';
 | 
			
		||||
import { TableActionInitializers } from './TableActionInitializers';
 | 
			
		||||
import { TableColumnInitializers } from './TableColumnInitializers';
 | 
			
		||||
import { TableRecordActionInitializers } from './TableRecordActionInitializers';
 | 
			
		||||
 | 
			
		||||
export const items = { ...Items };
 | 
			
		||||
 | 
			
		||||
export const initializes = {
 | 
			
		||||
  // 页面里的「添加区块」
 | 
			
		||||
  BlockInitializers,
 | 
			
		||||
  // 日历的「操作配置」
 | 
			
		||||
  CalendarActionInitializers,
 | 
			
		||||
  // 详情的「操作配置」
 | 
			
		||||
  DetailsActionInitializers,
 | 
			
		||||
  // 普通表单的「操作配置」
 | 
			
		||||
  FormActionInitializers,
 | 
			
		||||
  // Grid 组件里「配置字段」
 | 
			
		||||
  GridFormItemInitializers,
 | 
			
		||||
  // 弹窗表单的「操作配置」
 | 
			
		||||
  PopupFormActionInitializers,
 | 
			
		||||
  // 当前行记录所在面板的「添加区块」
 | 
			
		||||
  RecordBlockInitializers,
 | 
			
		||||
  // 表格「操作配置」
 | 
			
		||||
  TableActionInitializers,
 | 
			
		||||
  // 表格「列配置」
 | 
			
		||||
  TableColumnInitializers,
 | 
			
		||||
  // 表格当前行记录的「操作配置」
 | 
			
		||||
  TableRecordActionInitializers,
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										109
									
								
								packages/client/src/schema-initializer/Initializers/utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								packages/client/src/schema-initializer/Initializers/utils.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,109 @@
 | 
			
		||||
import { ISchema, Schema, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
import { SchemaInitializerItemOptions } from '../';
 | 
			
		||||
import { useCollection } from '../../collection-manager';
 | 
			
		||||
import { useDesignable } from '../../schema-component';
 | 
			
		||||
 | 
			
		||||
export const gridRowColWrap = (schema: ISchema) => {
 | 
			
		||||
  return {
 | 
			
		||||
    type: 'void',
 | 
			
		||||
    'x-component': 'Grid.Row',
 | 
			
		||||
    properties: {
 | 
			
		||||
      [uid()]: {
 | 
			
		||||
        type: 'void',
 | 
			
		||||
        'x-component': 'Grid.Col',
 | 
			
		||||
        properties: {
 | 
			
		||||
          [schema.name || uid()]: schema,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const removeTableColumn = (schema, cb) => {
 | 
			
		||||
  cb(schema, {
 | 
			
		||||
    removeParentsIfNoChildren: true,
 | 
			
		||||
    breakRemoveOn: {
 | 
			
		||||
      'x-component': 'ArrayTable',
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const removeGridFormItem = (schema, cb) => {
 | 
			
		||||
  cb(schema, {
 | 
			
		||||
    removeParentsIfNoChildren: true,
 | 
			
		||||
    breakRemoveOn: {
 | 
			
		||||
      'x-component': 'Grid',
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const useTableColumnInitializerFields = () => {
 | 
			
		||||
  const { name, fields } = useCollection();
 | 
			
		||||
  return (
 | 
			
		||||
    fields
 | 
			
		||||
      // .filter((field) => field?.uiSchema?.title)
 | 
			
		||||
      .map((field) => {
 | 
			
		||||
        return {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: field?.uiSchema?.title || field.name,
 | 
			
		||||
          schema: {
 | 
			
		||||
            name: field.name,
 | 
			
		||||
            'x-collection-field': `${name}.${field.name}`,
 | 
			
		||||
            'x-component': 'CollectionField',
 | 
			
		||||
          },
 | 
			
		||||
          component: 'CollectionFieldInitializer',
 | 
			
		||||
          remove: removeTableColumn,
 | 
			
		||||
        } as SchemaInitializerItemOptions;
 | 
			
		||||
      })
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const useFormItemInitializerFields = () => {
 | 
			
		||||
  const { name, fields } = useCollection();
 | 
			
		||||
  return fields?.map((field) => {
 | 
			
		||||
    return {
 | 
			
		||||
      type: 'item',
 | 
			
		||||
      title: field?.uiSchema?.title || field.name,
 | 
			
		||||
      component: 'CollectionFieldInitializer',
 | 
			
		||||
      remove: removeGridFormItem,
 | 
			
		||||
      schema: {
 | 
			
		||||
        name: field.name,
 | 
			
		||||
        'x-designer': 'FormItem.Designer',
 | 
			
		||||
        'x-component': 'CollectionField',
 | 
			
		||||
        'x-decorator': 'FormItem',
 | 
			
		||||
        'x-collection-field': `${name}.${field.name}`,
 | 
			
		||||
      },
 | 
			
		||||
    } as SchemaInitializerItemOptions;
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const findSchema = (schema: Schema, key: string, action: string) => {
 | 
			
		||||
  return schema.reduceProperties((buf, s) => {
 | 
			
		||||
    if (s[key] === action) {
 | 
			
		||||
      return s;
 | 
			
		||||
    }
 | 
			
		||||
    const c = findSchema(s, key, action);
 | 
			
		||||
    if (c) {
 | 
			
		||||
      return c;
 | 
			
		||||
    }
 | 
			
		||||
    return buf;
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const removeSchema = (schema, cb) => {
 | 
			
		||||
  return cb(schema);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const useCurrentSchema = (action: string, key: string, find = findSchema, rm = removeSchema) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const { remove } = useDesignable();
 | 
			
		||||
  const schema = find(fieldSchema, key, action);
 | 
			
		||||
  return {
 | 
			
		||||
    schema,
 | 
			
		||||
    exists: !!schema,
 | 
			
		||||
    remove() {
 | 
			
		||||
      schema && rm(schema, remove);
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
@ -2,6 +2,7 @@ import { ISchema, observer } from '@formily/react';
 | 
			
		||||
import { Button, Dropdown, Menu } from 'antd';
 | 
			
		||||
import React, { createContext, useContext, useState } from 'react';
 | 
			
		||||
import { useDesignable } from '../schema-component/hooks';
 | 
			
		||||
import { initializes, items } from './Initializers';
 | 
			
		||||
import {
 | 
			
		||||
  SchemaInitializerButtonProps,
 | 
			
		||||
  SchemaInitializerItemComponent,
 | 
			
		||||
@ -15,8 +16,21 @@ export const SchemaInitializerItemContext = createContext(null);
 | 
			
		||||
 | 
			
		||||
export const SchemaInitializer = () => null;
 | 
			
		||||
 | 
			
		||||
SchemaInitializer.items = items;
 | 
			
		||||
 | 
			
		||||
SchemaInitializer.initializes = initializes;
 | 
			
		||||
 | 
			
		||||
SchemaInitializer.Button = observer((props: SchemaInitializerButtonProps) => {
 | 
			
		||||
  const { insert, wrap = defaultWrap, items = [], insertPosition, dropdown, style, ...others } = props;
 | 
			
		||||
  const {
 | 
			
		||||
    title,
 | 
			
		||||
    insert,
 | 
			
		||||
    wrap = defaultWrap,
 | 
			
		||||
    items = [],
 | 
			
		||||
    insertPosition = 'beforeEnd',
 | 
			
		||||
    dropdown,
 | 
			
		||||
    style,
 | 
			
		||||
    ...others
 | 
			
		||||
  } = props;
 | 
			
		||||
  let { insertAdjacent, findComponent, designable } = useDesignable();
 | 
			
		||||
  const [visible, setVisible] = useState(false);
 | 
			
		||||
  const insertSchema = (schema) => {
 | 
			
		||||
@ -102,7 +116,9 @@ SchemaInitializer.Button = observer((props: SchemaInitializerButtonProps) => {
 | 
			
		||||
          borderColor: '#f18b62',
 | 
			
		||||
          color: '#f18b62',
 | 
			
		||||
        }}
 | 
			
		||||
      />
 | 
			
		||||
      >
 | 
			
		||||
        {props.children || props.title}
 | 
			
		||||
      </Button>
 | 
			
		||||
    </Dropdown>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,54 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { isPlainObj } from '@formily/shared';
 | 
			
		||||
import React, { createContext, useContext } from 'react';
 | 
			
		||||
import { SchemaComponentOptions } from '../schema-component';
 | 
			
		||||
import * as initializers from './Initializers';
 | 
			
		||||
import { initializes as globals, items } from './Initializers';
 | 
			
		||||
import { SchemaInitializer } from './SchemaInitializer';
 | 
			
		||||
 | 
			
		||||
export const SchemaInitializerProvider: React.FC = (props) => {
 | 
			
		||||
  return <SchemaComponentOptions components={initializers}>{props.children}</SchemaComponentOptions>;
 | 
			
		||||
const SchemaInitializerContext = createContext(null);
 | 
			
		||||
 | 
			
		||||
export interface SchemaInitializerProviderProps {
 | 
			
		||||
  initializers?: Record<string, any>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const useSchemaInitializer = (name: string) => {
 | 
			
		||||
  const initializers = useContext(SchemaInitializerContext);
 | 
			
		||||
 | 
			
		||||
  const render = (component?: any, props?: any) => {
 | 
			
		||||
    return component && React.createElement(component, props);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (!name) {
 | 
			
		||||
    return { exists: false, render };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const initializer = initializers?.[name];
 | 
			
		||||
 | 
			
		||||
  if (!initializer) {
 | 
			
		||||
    return { exists: false, render };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (isPlainObj(initializer)) {
 | 
			
		||||
    return {
 | 
			
		||||
      exists: true,
 | 
			
		||||
      render: (props?: any) => {
 | 
			
		||||
        const component = (initializer as any).component || SchemaInitializer.Button;
 | 
			
		||||
        return render(component, { ...initializer, ...props });
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    exists: true,
 | 
			
		||||
    render: (props?: any) => render(initializer, props),
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const SchemaInitializerProvider: React.FC<SchemaInitializerProviderProps> = (props) => {
 | 
			
		||||
  const { initializers, children } = props;
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializerContext.Provider value={{ ...globals, ...initializers }}>
 | 
			
		||||
      <SchemaComponentOptions components={{ ...items }}>{children}</SchemaComponentOptions>
 | 
			
		||||
    </SchemaInitializerContext.Provider>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,13 @@
 | 
			
		||||
import { FormOutlined, TableOutlined } from '@ant-design/icons';
 | 
			
		||||
import { TableOutlined } from '@ant-design/icons';
 | 
			
		||||
import { Field } from '@formily/core';
 | 
			
		||||
import { observer, useField } from '@formily/react';
 | 
			
		||||
import { SchemaComponent, SchemaComponentProvider, SchemaInitializer } from '@nocobase/client';
 | 
			
		||||
import {
 | 
			
		||||
  SchemaComponent,
 | 
			
		||||
  SchemaComponentProvider,
 | 
			
		||||
  SchemaInitializer,
 | 
			
		||||
  SchemaInitializerProvider,
 | 
			
		||||
  useSchemaInitializer
 | 
			
		||||
} from '@nocobase/client';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
const Hello = observer((props) => {
 | 
			
		||||
@ -13,36 +19,7 @@ const Hello = observer((props) => {
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AddBlockButton = observer((props: any) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      wrap={(schema) => schema}
 | 
			
		||||
      insertPosition={'beforeBegin'}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: 'Data blocks',
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: 'Table',
 | 
			
		||||
              component: TableBlockInitializerItem,
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: 'Form',
 | 
			
		||||
              component: FormBlockInitializerItem,
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      Add block
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const TableBlockInitializerItem = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
const TableBlockInitializer = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  const { insert } = props;
 | 
			
		||||
  const items: any = [
 | 
			
		||||
    {
 | 
			
		||||
@ -77,48 +54,69 @@ const TableBlockInitializerItem = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const FormBlockInitializerItem = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  const { insert } = props;
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      icon={<FormOutlined />}
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        insert({
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          title: 'Form',
 | 
			
		||||
          'x-component': 'Hello',
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
const initializers = {
 | 
			
		||||
  AddBlock: {
 | 
			
		||||
    title: 'Add block',
 | 
			
		||||
    insertPosition: 'beforeBegin',
 | 
			
		||||
    items: [
 | 
			
		||||
      {
 | 
			
		||||
        type: 'itemGroup',
 | 
			
		||||
        title: 'Data blocks',
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            type: 'item',
 | 
			
		||||
            title: 'Table',
 | 
			
		||||
            component: 'TableBlockInitializer',
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            type: 'item',
 | 
			
		||||
            title: 'Form',
 | 
			
		||||
            component: 'GeneralInitializer',
 | 
			
		||||
            schema: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              title: 'Form',
 | 
			
		||||
              'x-component': 'Hello',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const AddBlockButton = observer((props: any) => {
 | 
			
		||||
  const { render } = useSchemaInitializer('AddBlock');
 | 
			
		||||
  return <>{render()}</>;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default function App() {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaComponentProvider components={{ Hello, AddBlockButton }}>
 | 
			
		||||
      <SchemaComponent
 | 
			
		||||
        schema={{
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          name: 'page',
 | 
			
		||||
          'x-component': 'div',
 | 
			
		||||
          properties: {
 | 
			
		||||
            hello1: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              title: 'Test1',
 | 
			
		||||
              'x-component': 'Hello',
 | 
			
		||||
    <SchemaComponentProvider components={{ TableBlockInitializer, Hello, AddBlockButton }}>
 | 
			
		||||
      <SchemaInitializerProvider initializers={initializers}>
 | 
			
		||||
        <SchemaComponent
 | 
			
		||||
          schema={{
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            name: 'page',
 | 
			
		||||
            'x-component': 'div',
 | 
			
		||||
            properties: {
 | 
			
		||||
              hello1: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                title: 'Test1',
 | 
			
		||||
                'x-component': 'Hello',
 | 
			
		||||
              },
 | 
			
		||||
              hello2: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                title: 'Test2',
 | 
			
		||||
                'x-component': 'Hello',
 | 
			
		||||
              },
 | 
			
		||||
              initializer: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                'x-component': 'AddBlockButton',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            hello2: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              title: 'Test2',
 | 
			
		||||
              'x-component': 'Hello',
 | 
			
		||||
            },
 | 
			
		||||
            initializer: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              'x-component': 'AddBlockButton',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        }}
 | 
			
		||||
      />
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      </SchemaInitializerProvider>
 | 
			
		||||
    </SchemaComponentProvider>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,117 +1,77 @@
 | 
			
		||||
import { observer, useFieldSchema } from '@formily/react';
 | 
			
		||||
import {
 | 
			
		||||
  Action,
 | 
			
		||||
  ActionBar,
 | 
			
		||||
  SchemaComponent,
 | 
			
		||||
  SchemaComponentProvider,
 | 
			
		||||
  SchemaInitializer,
 | 
			
		||||
  useDesignable
 | 
			
		||||
  SchemaInitializerProvider
 | 
			
		||||
} from '@nocobase/client';
 | 
			
		||||
import { Switch } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
const AddActionButton = observer((props: any) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      insertPosition={'beforeEnd'}
 | 
			
		||||
      style={{ marginLeft: 8 }}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: 'Enable actions',
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
const initializers = {
 | 
			
		||||
  AddAction: {
 | 
			
		||||
    title: 'Configure actions',
 | 
			
		||||
    insertPosition: 'beforeEnd',
 | 
			
		||||
    style: { marginLeft: 8 },
 | 
			
		||||
    items: [
 | 
			
		||||
      {
 | 
			
		||||
        type: 'itemGroup',
 | 
			
		||||
        title: 'Enable actions',
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            type: 'item',
 | 
			
		||||
            title: 'Create',
 | 
			
		||||
            component: 'ActionInitializer',
 | 
			
		||||
            schema: {
 | 
			
		||||
              title: 'Create',
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: 'Create',
 | 
			
		||||
                'x-action': 'posts:create',
 | 
			
		||||
                'x-align': 'left',
 | 
			
		||||
              },
 | 
			
		||||
              'x-action': 'posts:create',
 | 
			
		||||
              'x-component': 'Action',
 | 
			
		||||
              'x-designer': 'Action.Designer',
 | 
			
		||||
              'x-align': 'left',
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            type: 'item',
 | 
			
		||||
            title: 'Update',
 | 
			
		||||
            component: 'ActionInitializer',
 | 
			
		||||
            schema: {
 | 
			
		||||
              title: 'Update',
 | 
			
		||||
              component: InitializeAction,
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: 'Update',
 | 
			
		||||
                'x-action': 'posts:update',
 | 
			
		||||
              },
 | 
			
		||||
              'x-action': 'posts:update',
 | 
			
		||||
              'x-component': 'Action',
 | 
			
		||||
              'x-designer': 'Action.Designer',
 | 
			
		||||
              'x-align': 'right',
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      Configure actions
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const useCurrentActionSchema = (action: string) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const { remove } = useDesignable();
 | 
			
		||||
  const schema = fieldSchema.reduceProperties((buf, s) => {
 | 
			
		||||
    if (s['x-action'] === action) {
 | 
			
		||||
      return s;
 | 
			
		||||
    }
 | 
			
		||||
    return buf;
 | 
			
		||||
  });
 | 
			
		||||
  return {
 | 
			
		||||
    schema,
 | 
			
		||||
    exists: !!schema,
 | 
			
		||||
    remove() {
 | 
			
		||||
      schema && remove(schema);
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const InitializeAction = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { exists, remove } = useCurrentActionSchema(item.schema['x-action']);
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          'x-component': 'Action',
 | 
			
		||||
          ...item.schema,
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title} <Switch size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default function App() {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaComponentProvider components={{ ActionBar, Action, AddActionButton }}>
 | 
			
		||||
      <SchemaComponent
 | 
			
		||||
        schema={{
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          name: 'page',
 | 
			
		||||
          'x-component': 'ActionBar',
 | 
			
		||||
          // 指定初始化的按钮组件,
 | 
			
		||||
          // Table、Form、Details、Calendar、Kanban 等等不同区块
 | 
			
		||||
          // 可以根据情况组装自己的 initializer
 | 
			
		||||
          'x-action-initializer': 'AddActionButton',
 | 
			
		||||
          properties: {
 | 
			
		||||
            action1: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              title: 'Update',
 | 
			
		||||
              // 使用 x-action 来标记 action schema
 | 
			
		||||
              'x-action': 'posts:update',
 | 
			
		||||
              'x-component': 'Action',
 | 
			
		||||
    <SchemaComponentProvider components={{ ActionBar, Action }}>
 | 
			
		||||
      <SchemaInitializerProvider initializers={initializers}>
 | 
			
		||||
        <SchemaComponent
 | 
			
		||||
          schema={{
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            name: 'page',
 | 
			
		||||
            'x-component': 'ActionBar',
 | 
			
		||||
            // 指定初始化的按钮组件,
 | 
			
		||||
            // Table、Form、Details、Calendar、Kanban 等等不同区块
 | 
			
		||||
            // 可以根据情况组装自己的 initializer
 | 
			
		||||
            'x-initializer': 'AddAction',
 | 
			
		||||
            properties: {
 | 
			
		||||
              action1: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                title: 'Update',
 | 
			
		||||
                // 使用 x-action 来标记 action schema
 | 
			
		||||
                'x-action': 'posts:update',
 | 
			
		||||
                'x-component': 'Action',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        }}
 | 
			
		||||
      />
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      </SchemaInitializerProvider>
 | 
			
		||||
    </SchemaComponentProvider>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
import { observer, Schema, useFieldSchema } from '@formily/react';
 | 
			
		||||
import {
 | 
			
		||||
  Form,
 | 
			
		||||
  FormItem,
 | 
			
		||||
@ -6,18 +5,18 @@ import {
 | 
			
		||||
  SchemaComponent,
 | 
			
		||||
  SchemaComponentProvider,
 | 
			
		||||
  SchemaInitializer,
 | 
			
		||||
  SchemaInitializerItemOptions,
 | 
			
		||||
  useDesignable
 | 
			
		||||
  SchemaInitializerItemOptions
 | 
			
		||||
} from '@nocobase/client';
 | 
			
		||||
import { Input, Switch } from 'antd';
 | 
			
		||||
import { Input } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { SchemaInitializerProvider, useSchemaInitializer } from '..';
 | 
			
		||||
 | 
			
		||||
const useFormItemInitializerFields = () => {
 | 
			
		||||
  return [
 | 
			
		||||
    {
 | 
			
		||||
      type: 'item',
 | 
			
		||||
      title: 'Name',
 | 
			
		||||
      component: InitializeFormItem,
 | 
			
		||||
      component: 'CollectionFieldInitializer',
 | 
			
		||||
      schema: {
 | 
			
		||||
        type: 'string',
 | 
			
		||||
        title: 'Name',
 | 
			
		||||
@ -30,7 +29,7 @@ const useFormItemInitializerFields = () => {
 | 
			
		||||
    {
 | 
			
		||||
      type: 'item',
 | 
			
		||||
      title: 'Title',
 | 
			
		||||
      component: InitializeFormItem,
 | 
			
		||||
      component: 'CollectionFieldInitializer',
 | 
			
		||||
      schema: {
 | 
			
		||||
        type: 'string',
 | 
			
		||||
        title: 'Title',
 | 
			
		||||
@ -43,79 +42,7 @@ const useFormItemInitializerFields = () => {
 | 
			
		||||
  ] as SchemaInitializerItemOptions[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const AddFormItemButton = observer((props: any) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      wrap={(schema) => schema}
 | 
			
		||||
      insertPosition={'beforeEnd'}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: 'Display fields',
 | 
			
		||||
          children: useFormItemInitializerFields(),
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'divider',
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: 'Add text',
 | 
			
		||||
          component: InitializeTextFormItem,
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      Configure fields
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const useCurrentFieldSchema = (path: string) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const { remove } = useDesignable();
 | 
			
		||||
  const findFieldSchema = (schema: Schema) => {
 | 
			
		||||
    return schema.reduceProperties((buf, s) => {
 | 
			
		||||
      if (s['x-collection-field'] === path) {
 | 
			
		||||
        return s;
 | 
			
		||||
      }
 | 
			
		||||
      const child = findFieldSchema(s);
 | 
			
		||||
      if (child) {
 | 
			
		||||
        return child;
 | 
			
		||||
      }
 | 
			
		||||
      return buf;
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
  const schema = findFieldSchema(fieldSchema);
 | 
			
		||||
  return {
 | 
			
		||||
    schema,
 | 
			
		||||
    exists: !!schema,
 | 
			
		||||
    remove() {
 | 
			
		||||
      schema && remove(schema);
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const InitializeFormItem = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { exists, remove } = useCurrentFieldSchema(item.schema['x-collection-field']);
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          ...item.schema,
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title} <Switch size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const InitializeTextFormItem = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
const TextInitializer = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  const { insert } = props;
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
@ -132,41 +59,66 @@ const InitializeTextFormItem = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const Page = (props) => {
 | 
			
		||||
  const { render } = useSchemaInitializer('AddFormItem');
 | 
			
		||||
  return (
 | 
			
		||||
    <div>
 | 
			
		||||
      {props.children}
 | 
			
		||||
      <AddFormItemButton />
 | 
			
		||||
      {render()}
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default function App() {
 | 
			
		||||
  const initializers = {
 | 
			
		||||
    AddFormItem: {
 | 
			
		||||
      title: 'Configure fields',
 | 
			
		||||
      insertPosition: 'beforeEnd',
 | 
			
		||||
      items: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: 'Display fields',
 | 
			
		||||
          // 从 hook 动态加载字段
 | 
			
		||||
          children: useFormItemInitializerFields(),
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'divider',
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: 'Add text',
 | 
			
		||||
          component: 'TextInitializer',
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaComponentProvider components={{ Page, Form, Input, FormItem, Markdown }}>
 | 
			
		||||
      <SchemaComponent
 | 
			
		||||
        schema={{
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          name: 'page',
 | 
			
		||||
          'x-decorator': 'Form',
 | 
			
		||||
          'x-component': 'Page',
 | 
			
		||||
          properties: {
 | 
			
		||||
            title: {
 | 
			
		||||
              type: 'string',
 | 
			
		||||
              title: 'Title',
 | 
			
		||||
              'x-component': 'Input',
 | 
			
		||||
              'x-decorator': 'FormItem',
 | 
			
		||||
              'x-collection-field': 'posts.title',
 | 
			
		||||
    <SchemaComponentProvider components={{ TextInitializer, Page, Form, Input, FormItem, Markdown }}>
 | 
			
		||||
      <SchemaInitializerProvider initializers={initializers}>
 | 
			
		||||
        <SchemaComponent
 | 
			
		||||
          schema={{
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            name: 'page',
 | 
			
		||||
            'x-decorator': 'Form',
 | 
			
		||||
            'x-component': 'Page',
 | 
			
		||||
            properties: {
 | 
			
		||||
              title: {
 | 
			
		||||
                type: 'string',
 | 
			
		||||
                title: 'Title',
 | 
			
		||||
                'x-component': 'Input',
 | 
			
		||||
                'x-decorator': 'FormItem',
 | 
			
		||||
                'x-collection-field': 'posts.title',
 | 
			
		||||
              },
 | 
			
		||||
              name: {
 | 
			
		||||
                type: 'string',
 | 
			
		||||
                title: 'Name',
 | 
			
		||||
                'x-component': 'Input',
 | 
			
		||||
                'x-decorator': 'FormItem',
 | 
			
		||||
                'x-collection-field': 'posts.name',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            name: {
 | 
			
		||||
              type: 'string',
 | 
			
		||||
              title: 'Name',
 | 
			
		||||
              'x-component': 'Input',
 | 
			
		||||
              'x-decorator': 'FormItem',
 | 
			
		||||
              'x-collection-field': 'posts.name',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        }}
 | 
			
		||||
      />
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      </SchemaInitializerProvider>
 | 
			
		||||
    </SchemaComponentProvider>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,116 +1,90 @@
 | 
			
		||||
import { observer, Schema, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
import {
 | 
			
		||||
  ArrayTable,
 | 
			
		||||
  Input,
 | 
			
		||||
  SchemaComponent,
 | 
			
		||||
  SchemaComponentProvider,
 | 
			
		||||
  SchemaInitializer,
 | 
			
		||||
  SchemaInitializerItemOptions,
 | 
			
		||||
  useDesignable
 | 
			
		||||
  SchemaInitializerProvider
 | 
			
		||||
} from '@nocobase/client';
 | 
			
		||||
import { Switch } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
const removeColumn = (schema, cb) => {
 | 
			
		||||
  cb(schema, {
 | 
			
		||||
    removeParentsIfNoChildren: true,
 | 
			
		||||
    breakRemoveOn: {
 | 
			
		||||
      'x-component': 'ArrayTable',
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const useTableColumnInitializerFields = () => {
 | 
			
		||||
  const fields: SchemaInitializerItemOptions[] = [
 | 
			
		||||
    {
 | 
			
		||||
      type: 'item',
 | 
			
		||||
      title: 'Name',
 | 
			
		||||
      remove: removeColumn,
 | 
			
		||||
      schema: {
 | 
			
		||||
        type: 'string',
 | 
			
		||||
        name: 'name',
 | 
			
		||||
        type: 'string',
 | 
			
		||||
        title: 'Name',
 | 
			
		||||
        'x-collection-field': 'posts.name',
 | 
			
		||||
        'x-component': 'Input',
 | 
			
		||||
        'x-read-pretty': true,
 | 
			
		||||
      },
 | 
			
		||||
      component: ColumnInitializerItem,
 | 
			
		||||
      component: 'CollectionFieldInitializer',
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      type: 'item',
 | 
			
		||||
      title: 'Title',
 | 
			
		||||
      remove: removeColumn,
 | 
			
		||||
      schema: {
 | 
			
		||||
        type: 'string',
 | 
			
		||||
        name: 'title',
 | 
			
		||||
        type: 'string',
 | 
			
		||||
        title: 'Title',
 | 
			
		||||
        'x-collection-field': 'posts.title',
 | 
			
		||||
        'x-component': 'Input',
 | 
			
		||||
        'x-read-pretty': true,
 | 
			
		||||
      },
 | 
			
		||||
      component: ColumnInitializerItem,
 | 
			
		||||
      component: 'CollectionFieldInitializer',
 | 
			
		||||
    },
 | 
			
		||||
  ];
 | 
			
		||||
  return fields;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const AddTableColumn = observer((props: any) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      wrap={(schema) => schema}
 | 
			
		||||
      insertPosition={'beforeEnd'}
 | 
			
		||||
      items={[
 | 
			
		||||
const columnWrap = (s) => {
 | 
			
		||||
  return {
 | 
			
		||||
    name: [uid()],
 | 
			
		||||
    type: 'void',
 | 
			
		||||
    title: s.title,
 | 
			
		||||
    'x-component': 'ArrayTable.Column',
 | 
			
		||||
    properties: {
 | 
			
		||||
      [s.name]: {
 | 
			
		||||
        ...s,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 因为有个动态获取字段的 hook,所以这里将 SchemaInitializerProvider 自定义的处理了一下
 | 
			
		||||
const CustomSchemaInitializerProvider: React.FC = (props) => {
 | 
			
		||||
  const initializers = {
 | 
			
		||||
    AddColumn: {
 | 
			
		||||
      insertPosition: 'beforeEnd',
 | 
			
		||||
      title: 'Configure columns',
 | 
			
		||||
      wrap: columnWrap,
 | 
			
		||||
      items: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: 'Display fields',
 | 
			
		||||
          children: useTableColumnInitializerFields(),
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
    >
 | 
			
		||||
      Configure columns
 | 
			
		||||
    </SchemaInitializer.Button>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const useCurrentColumnSchema = (path: string) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const { remove } = useDesignable();
 | 
			
		||||
  const findFieldSchema = (schema: Schema) => {
 | 
			
		||||
    return schema.reduceProperties((buf, s) => {
 | 
			
		||||
      if (s['x-collection-field'] === path) {
 | 
			
		||||
        return s;
 | 
			
		||||
      }
 | 
			
		||||
      const child = findFieldSchema(s);
 | 
			
		||||
      if (child) {
 | 
			
		||||
        return child;
 | 
			
		||||
      }
 | 
			
		||||
      return buf;
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
  const schema = findFieldSchema(fieldSchema);
 | 
			
		||||
  return {
 | 
			
		||||
    schema,
 | 
			
		||||
    exists: !!schema,
 | 
			
		||||
    remove() {
 | 
			
		||||
      schema && remove(schema.parent);
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
  return <SchemaInitializerProvider initializers={initializers}>{props.children}</SchemaInitializerProvider>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const ColumnInitializerItem = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
  const { item, insert } = props;
 | 
			
		||||
  const { exists, remove } = useCurrentColumnSchema(item.schema['x-collection-field']);
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Item
 | 
			
		||||
      onClick={() => {
 | 
			
		||||
        if (exists) {
 | 
			
		||||
          return remove();
 | 
			
		||||
        }
 | 
			
		||||
        insert({
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          title: item.schema.name,
 | 
			
		||||
          'x-component': 'ArrayTable.Column',
 | 
			
		||||
          properties: {
 | 
			
		||||
            [item.schema.name]: {
 | 
			
		||||
              'x-read-pretty': true,
 | 
			
		||||
              ...item.schema,
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
 | 
			
		||||
        {item.title} <Switch size={'small'} checked={exists} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SchemaInitializer.Item>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const schema = {
 | 
			
		||||
  type: 'object',
 | 
			
		||||
  properties: {
 | 
			
		||||
@ -122,7 +96,7 @@ const schema = {
 | 
			
		||||
        { id: 3, name: 'Name3' },
 | 
			
		||||
      ],
 | 
			
		||||
      'x-component': 'ArrayTable',
 | 
			
		||||
      'x-column-initializer': 'AddTableColumn',
 | 
			
		||||
      'x-initializer': 'AddColumn',
 | 
			
		||||
      'x-component-props': {
 | 
			
		||||
        rowKey: 'id',
 | 
			
		||||
      },
 | 
			
		||||
@ -147,8 +121,10 @@ const schema = {
 | 
			
		||||
 | 
			
		||||
export default function App() {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaComponentProvider components={{ AddTableColumn, Input, ArrayTable }}>
 | 
			
		||||
      <SchemaComponent schema={schema} />
 | 
			
		||||
    <SchemaComponentProvider components={{ Input, ArrayTable }}>
 | 
			
		||||
      <CustomSchemaInitializerProvider>
 | 
			
		||||
        <SchemaComponent schema={schema} />
 | 
			
		||||
      </CustomSchemaInitializerProvider>
 | 
			
		||||
    </SchemaComponentProvider>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -150,3 +150,70 @@ const TableBlockInitializerItem = SchemaInitializer.itemWrap((props) => {
 | 
			
		||||
### Table.Column
 | 
			
		||||
 | 
			
		||||
<code src="./demos/demo4.tsx" />
 | 
			
		||||
 | 
			
		||||
## 配置
 | 
			
		||||
 | 
			
		||||
核心的参数
 | 
			
		||||
 | 
			
		||||
```tsx | pure
 | 
			
		||||
const initializers = {
 | 
			
		||||
  xxx: {
 | 
			
		||||
    title: '{{t("Add block")}}',
 | 
			
		||||
    insertPosition: 'beforeEnd',
 | 
			
		||||
    items: [], // 在这里配置
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
<SchemaInitializerProvider initializers={initializers}>
 | 
			
		||||
  {/* children */}
 | 
			
		||||
</SchemaInitializerProvider>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
items 例子:
 | 
			
		||||
 | 
			
		||||
- Initializer.Item 只有添加的逻辑
 | 
			
		||||
- Initializer.SwitchItem 可以添加或移除
 | 
			
		||||
 | 
			
		||||
```ts
 | 
			
		||||
{
 | 
			
		||||
  BlockInitializer: {
 | 
			
		||||
    insertPosition: 'beforeEnd',
 | 
			
		||||
    items: [
 | 
			
		||||
      {
 | 
			
		||||
        type: 'itemGroup',
 | 
			
		||||
        title: "{{t('Enable actions')}}",
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            type: 'item',
 | 
			
		||||
            title: "{{t('Tody')}}",
 | 
			
		||||
            component: 'Initializer.SwitchItem',
 | 
			
		||||
            schema: {
 | 
			
		||||
              title: "{{t('Tody')}}",
 | 
			
		||||
              'x-component': 'Calendar.Today',
 | 
			
		||||
              'x-action': `calendar:today`,
 | 
			
		||||
              'x-align': 'left',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            type: 'item',
 | 
			
		||||
            title: "{{t('Tody')}}",
 | 
			
		||||
            component: 'Initializer.Item',
 | 
			
		||||
            schema: {
 | 
			
		||||
              title: "{{t('Tody')}}",
 | 
			
		||||
              'x-component': 'Calendar.Today',
 | 
			
		||||
              'x-action': `calendar:today`,
 | 
			
		||||
              'x-align': 'left',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
内置的 Initializer 有:
 | 
			
		||||
 | 
			
		||||
- `GeneralInitializer` 通用的配置项,只有插入的逻辑
 | 
			
		||||
- `ActionInitializer` 用于配置操作按钮,有插入和移除的逻辑
 | 
			
		||||
- `CollectionFieldInitializer` 用于配置数据表字段,有插入和移除的逻辑
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,4 @@
 | 
			
		||||
export * from './SchemaInitializer';
 | 
			
		||||
export * from './SchemaInitializerProvider';
 | 
			
		||||
export * from './types';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import { ISchema } from '@formily/react';
 | 
			
		||||
import { ISchema, Schema } from '@formily/react';
 | 
			
		||||
import { ButtonProps, DropDownProps, MenuItemProps } from 'antd';
 | 
			
		||||
 | 
			
		||||
export interface SchemaInitializerButtonProps extends ButtonProps {
 | 
			
		||||
@ -25,10 +25,21 @@ interface SubMenuOptions extends ItemCommonOptions {
 | 
			
		||||
  children?: SchemaInitializerItemOptions[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type BreakFn = (s: ISchema) => boolean;
 | 
			
		||||
 | 
			
		||||
interface RemoveOptions {
 | 
			
		||||
  removeParentsIfNoChildren?: boolean;
 | 
			
		||||
  breakRemoveOn?: ISchema | BreakFn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RemoveCallback = (s: Schema, options?: RemoveOptions) => void;
 | 
			
		||||
 | 
			
		||||
interface ItemOptions extends ItemCommonOptions {
 | 
			
		||||
  type: 'item';
 | 
			
		||||
  component?: any;
 | 
			
		||||
  schema?: ISchema;
 | 
			
		||||
  remove?: (schema: Schema, cb: RemoveCallback) => void;
 | 
			
		||||
  find?: (schema: Schema, current: string) => Schema | null | undefined;
 | 
			
		||||
  [key: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ export class UiRoutesStoragePlugin extends Plugin {
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            'x-component': 'Menu',
 | 
			
		||||
            'x-designer': 'Menu.Designer',
 | 
			
		||||
            'x-initializer': 'MenuItemInitializer',
 | 
			
		||||
            'x-initializer': 'MenuItemInitializers',
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              mode: 'mix',
 | 
			
		||||
              theme: 'dark',
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user