feat(collection-manager): support for setting the title field (#1729)
* feat: configure fields * feat: edit * feat: enable delete action * style: indent style * feat: support to override and view inherited fields * feat: support to delete and add field and sync * fix: should delete the seleted option * feat: support to setting title field * feat: avoid infinite loops and add default title field * feat(data-templates): use titleField to display title * fix: fix the pagination of collection manager * feat: add prompt for title field switch * feat: filter field types * feat: not use title switch when field interface is icon * feat: translate * fix: sync update collections data * feat: translate * fix: fix build error --------- Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
		
							parent
							
								
									5930218811
								
							
						
					
					
						commit
						3c884cdd36
					
				@ -10,7 +10,7 @@ import * as defaultInterfaces from './interfaces';
 | 
			
		||||
import { CollectionManagerOptions } from './types';
 | 
			
		||||
 | 
			
		||||
export const CollectionManagerProvider: React.FC<CollectionManagerOptions> = (props) => {
 | 
			
		||||
  const { service, interfaces, collections = [], refreshCM, templates } = props;
 | 
			
		||||
  const { service, interfaces, collections = [], refreshCM, updateCollection, templates } = props;
 | 
			
		||||
  const defaultTemplates = keyBy(templateOptions(), (item) => item.name);
 | 
			
		||||
  const ctx = useContext(CollectionManagerContext);
 | 
			
		||||
  return (
 | 
			
		||||
@ -22,6 +22,7 @@ export const CollectionManagerProvider: React.FC<CollectionManagerOptions> = (pr
 | 
			
		||||
        templates: { ...defaultTemplates, ...templates },
 | 
			
		||||
        collections: [...ctx.collections, ...collections],
 | 
			
		||||
        refreshCM,
 | 
			
		||||
        updateCollection,
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <CollectionManagerSchemaComponentProvider>{props.children}</CollectionManagerSchemaComponentProvider>
 | 
			
		||||
@ -76,12 +77,17 @@ export const RemoteCollectionManagerProvider = (props: any) => {
 | 
			
		||||
    return data?.data || [];
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const updateCollection = (collection) => {
 | 
			
		||||
    service.mutate({ data: collection });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <CollectionCategroriesProvider service={{ ...result }} refreshCategory={refreshCategory}>
 | 
			
		||||
      <CollectionManagerProvider
 | 
			
		||||
        service={{ ...service, contentLoading, setContentLoading }}
 | 
			
		||||
        collections={service?.data?.data}
 | 
			
		||||
        refreshCM={refreshCM}
 | 
			
		||||
        updateCollection={updateCollection}
 | 
			
		||||
        {...props}
 | 
			
		||||
      />
 | 
			
		||||
    </CollectionCategroriesProvider>
 | 
			
		||||
@ -95,7 +101,7 @@ export const CollectionCategroriesProvider = (props) => {
 | 
			
		||||
      value={{
 | 
			
		||||
        data: service?.data?.data,
 | 
			
		||||
        refresh: refreshCategory,
 | 
			
		||||
        ...props
 | 
			
		||||
        ...props,
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      {props.children}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,440 @@
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { Field, createForm } from '@formily/core';
 | 
			
		||||
import { FieldContext, FormContext, useField } from '@formily/react';
 | 
			
		||||
import { Space, Switch, Table, TableColumnProps, Tag, Tooltip } from 'antd';
 | 
			
		||||
import React, { useContext, useMemo } from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { RecordProvider, useRecord } from '../../record-provider';
 | 
			
		||||
import { Action, useAttach, useCompile } from '../../schema-component';
 | 
			
		||||
import {
 | 
			
		||||
  ResourceActionContext,
 | 
			
		||||
  ResourceActionProvider,
 | 
			
		||||
  useResourceActionContext,
 | 
			
		||||
  useResourceContext,
 | 
			
		||||
} from '../ResourceActionProvider';
 | 
			
		||||
import {
 | 
			
		||||
  isDeleteButtonDisabled,
 | 
			
		||||
  useBulkDestroyActionAndRefreshCM,
 | 
			
		||||
  useDestroyActionAndRefreshCM,
 | 
			
		||||
} from '../action-hooks';
 | 
			
		||||
import { useCollectionManager } from '../hooks/useCollectionManager';
 | 
			
		||||
import { AddCollectionField } from './AddFieldAction';
 | 
			
		||||
import { EditCollectionField } from './EditFieldAction';
 | 
			
		||||
import { OverridingCollectionField } from './OverridingCollectionField';
 | 
			
		||||
import { SyncFieldsAction } from './SyncFieldsAction';
 | 
			
		||||
import { ViewCollectionField } from './ViewInheritedField';
 | 
			
		||||
import { collection } from './schemas/collectionFields';
 | 
			
		||||
const CELL_WIDTH = 200;
 | 
			
		||||
 | 
			
		||||
const indentStyle = css`
 | 
			
		||||
  .ant-table {
 | 
			
		||||
    margin-left: -7px !important;
 | 
			
		||||
  }
 | 
			
		||||
`;
 | 
			
		||||
const rowStyle = css`
 | 
			
		||||
  .ant-table-cell {
 | 
			
		||||
    background-color: white;
 | 
			
		||||
  }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
const titlePrompt = 'Default title for each record';
 | 
			
		||||
// 只有下面类型的字段才可以设置为标题字段
 | 
			
		||||
const expectTypes = ['string', 'integer', 'bigInt', 'float', 'double', 'decimal', 'date', 'dateonly', 'time'];
 | 
			
		||||
const excludeInterfaces = ['icon'];
 | 
			
		||||
 | 
			
		||||
const CurrentFields = (props) => {
 | 
			
		||||
  const compile = useCompile();
 | 
			
		||||
  const { getInterface } = useCollectionManager();
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const { setState } = useResourceActionContext();
 | 
			
		||||
  const { resource, targetKey } = props.collectionResource || {};
 | 
			
		||||
  const { [targetKey]: filterByTk, titleField } = useRecord();
 | 
			
		||||
  const [loadingRecord, setLoadingRecord] = React.useState<any>(null);
 | 
			
		||||
  const { updateCollection } = useCollectionManager();
 | 
			
		||||
 | 
			
		||||
  const columns: TableColumnProps<any>[] = [
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: ['uiSchema', 'title'],
 | 
			
		||||
      title: t('Field display name'),
 | 
			
		||||
      render: (value) => <div style={{ marginLeft: 7 }}>{compile(value)}</div>,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: 'name',
 | 
			
		||||
      title: t('Field name'),
 | 
			
		||||
      width: CELL_WIDTH + 20,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: 'interface',
 | 
			
		||||
      title: t('Field interface'),
 | 
			
		||||
      width: CELL_WIDTH,
 | 
			
		||||
      render: (value) => <Tag>{compile(getInterface(value)?.title)}</Tag>,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: 'titleField',
 | 
			
		||||
      title: t('Title field'),
 | 
			
		||||
      width: CELL_WIDTH,
 | 
			
		||||
      render: function Render(_, record) {
 | 
			
		||||
        const handleChange = (checked) => {
 | 
			
		||||
          setLoadingRecord(record);
 | 
			
		||||
          resource
 | 
			
		||||
            .update({ filterByTk, values: { titleField: checked ? record.name : 'id' } })
 | 
			
		||||
            .then(async () => {
 | 
			
		||||
              const data = await props.refreshAsync();
 | 
			
		||||
              if (data?.data) {
 | 
			
		||||
                updateCollection(data.data);
 | 
			
		||||
              }
 | 
			
		||||
              setLoadingRecord(null);
 | 
			
		||||
            })
 | 
			
		||||
            .catch((err) => {
 | 
			
		||||
              setLoadingRecord(null);
 | 
			
		||||
              console.error(err);
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return expectTypes.includes(record.type) && !excludeInterfaces.includes(record.interface) ? (
 | 
			
		||||
          <Tooltip title={t(titlePrompt)} placement="right" overlayInnerStyle={{ textAlign: 'center' }}>
 | 
			
		||||
            <Switch
 | 
			
		||||
              size="small"
 | 
			
		||||
              loading={record.name === loadingRecord?.name}
 | 
			
		||||
              checked={record.name === (titleField || 'id')}
 | 
			
		||||
              onChange={handleChange}
 | 
			
		||||
            />
 | 
			
		||||
          </Tooltip>
 | 
			
		||||
        ) : null;
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: 'actions',
 | 
			
		||||
      title: t('Actions'),
 | 
			
		||||
      width: CELL_WIDTH,
 | 
			
		||||
      render: (_, record) => {
 | 
			
		||||
        const deleteProps = {
 | 
			
		||||
          confirm: {
 | 
			
		||||
            title: t('Delete record'),
 | 
			
		||||
            content: t('Are you sure you want to delete it?'),
 | 
			
		||||
          },
 | 
			
		||||
          useAction: useDestroyActionAndRefreshCM,
 | 
			
		||||
          disabled: isDeleteButtonDisabled(record),
 | 
			
		||||
          title: t('Delete'),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
          <RecordProvider record={record}>
 | 
			
		||||
            <Space>
 | 
			
		||||
              <EditCollectionField type="primary" />
 | 
			
		||||
              <Action.Link {...deleteProps} />
 | 
			
		||||
            </Space>
 | 
			
		||||
          </RecordProvider>
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  ];
 | 
			
		||||
  return (
 | 
			
		||||
    <Table
 | 
			
		||||
      rowKey={'name'}
 | 
			
		||||
      columns={columns}
 | 
			
		||||
      showHeader={false}
 | 
			
		||||
      pagination={false}
 | 
			
		||||
      dataSource={props.fields}
 | 
			
		||||
      rowSelection={{
 | 
			
		||||
        type: 'checkbox',
 | 
			
		||||
        onChange: (selectedRowKeys) => {
 | 
			
		||||
          setState((state) => {
 | 
			
		||||
            const result = [...(state.selectedRowKeys || []), ...selectedRowKeys];
 | 
			
		||||
            return {
 | 
			
		||||
              ...state,
 | 
			
		||||
              selectedRowKeys: result,
 | 
			
		||||
            };
 | 
			
		||||
          });
 | 
			
		||||
        },
 | 
			
		||||
      }}
 | 
			
		||||
      className={indentStyle}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const InheritFields = (props) => {
 | 
			
		||||
  const compile = useCompile();
 | 
			
		||||
  const { getInterface } = useCollectionManager();
 | 
			
		||||
  const { resource, targetKey } = props.collectionResource || {};
 | 
			
		||||
  const { [targetKey]: filterByTk, titleField, name } = useRecord();
 | 
			
		||||
  const [loadingRecord, setLoadingRecord] = React.useState(null);
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const { updateCollection } = useCollectionManager();
 | 
			
		||||
 | 
			
		||||
  const columns: TableColumnProps<any>[] = [
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: ['uiSchema', 'title'],
 | 
			
		||||
      title: t('Field display name'),
 | 
			
		||||
      render: (value) => <div style={{ marginLeft: 1 }}>{compile(value)}</div>,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: 'name',
 | 
			
		||||
      title: t('Field name'),
 | 
			
		||||
      width: CELL_WIDTH + 20,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: 'interface',
 | 
			
		||||
      title: t('Field interface'),
 | 
			
		||||
      width: CELL_WIDTH,
 | 
			
		||||
      render: (value) => <Tag>{compile(getInterface(value)?.title)}</Tag>,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: 'titleField',
 | 
			
		||||
      title: t('Title field'),
 | 
			
		||||
      width: CELL_WIDTH,
 | 
			
		||||
      render(_, record) {
 | 
			
		||||
        const handleChange = (checked) => {
 | 
			
		||||
          setLoadingRecord(record);
 | 
			
		||||
          resource
 | 
			
		||||
            .update({ filterByTk, values: { titleField: checked ? record.name : 'id' } })
 | 
			
		||||
            .then(async () => {
 | 
			
		||||
              const data = await props.refreshAsync();
 | 
			
		||||
              if (data?.data) {
 | 
			
		||||
                updateCollection(data.data);
 | 
			
		||||
              }
 | 
			
		||||
              setLoadingRecord(null);
 | 
			
		||||
            })
 | 
			
		||||
            .catch((err) => {
 | 
			
		||||
              setLoadingRecord(null);
 | 
			
		||||
              console.error(err);
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return expectTypes.includes(record.type) && !excludeInterfaces.includes(record.interface) ? (
 | 
			
		||||
          <Tooltip title={t(titlePrompt)} placement="right" overlayInnerStyle={{ textAlign: 'center' }}>
 | 
			
		||||
            <Switch
 | 
			
		||||
              size="small"
 | 
			
		||||
              loading={record.name === loadingRecord?.name}
 | 
			
		||||
              checked={record.name === (titleField || 'id')}
 | 
			
		||||
              onChange={handleChange}
 | 
			
		||||
            />
 | 
			
		||||
          </Tooltip>
 | 
			
		||||
        ) : null;
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: 'actions',
 | 
			
		||||
      title: t('Actions'),
 | 
			
		||||
      width: CELL_WIDTH,
 | 
			
		||||
      render: function Render(_, record) {
 | 
			
		||||
        const overrideProps = {
 | 
			
		||||
          type: 'primary',
 | 
			
		||||
          currentCollection: name,
 | 
			
		||||
        };
 | 
			
		||||
        const viewCollectionProps = {
 | 
			
		||||
          type: 'primary',
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
          <RecordProvider record={record}>
 | 
			
		||||
            <Space>
 | 
			
		||||
              <OverridingCollectionField {...overrideProps} />
 | 
			
		||||
              <ViewCollectionField {...viewCollectionProps} />
 | 
			
		||||
            </Space>
 | 
			
		||||
          </RecordProvider>
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  ];
 | 
			
		||||
  return (
 | 
			
		||||
    <Table
 | 
			
		||||
      rowKey={'name'}
 | 
			
		||||
      columns={columns}
 | 
			
		||||
      showHeader={false}
 | 
			
		||||
      pagination={false}
 | 
			
		||||
      dataSource={props.fields.filter((field) => field.interface)}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const CollectionFields = (props) => {
 | 
			
		||||
  const compile = useCompile();
 | 
			
		||||
  const field = useField<Field>();
 | 
			
		||||
  const { name } = useRecord();
 | 
			
		||||
  const { getInterface, getInheritCollections, getCollection, getCurrentCollectionFields } = useCollectionManager();
 | 
			
		||||
  const form = useMemo(() => createForm(), []);
 | 
			
		||||
  const f = useAttach(form.createArrayField({ ...field.props, basePath: '' }));
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const collectionResource = useResourceContext();
 | 
			
		||||
  const { refreshAsync } = useContext(ResourceActionContext);
 | 
			
		||||
 | 
			
		||||
  const inherits = getInheritCollections(name);
 | 
			
		||||
 | 
			
		||||
  const columns: TableColumnProps<any>[] = [
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: 'title',
 | 
			
		||||
      title: t('Field display name'),
 | 
			
		||||
      render: (value) => (
 | 
			
		||||
        <div
 | 
			
		||||
          className={css`
 | 
			
		||||
            font-weight: 500;
 | 
			
		||||
            white-space: nowrap;
 | 
			
		||||
            width: 100px;
 | 
			
		||||
          `}
 | 
			
		||||
        >
 | 
			
		||||
          {value}
 | 
			
		||||
        </div>
 | 
			
		||||
      ),
 | 
			
		||||
      // width: CELL_WIDTH,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: 'name',
 | 
			
		||||
      title: t('Field name'),
 | 
			
		||||
      width: CELL_WIDTH + 20,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: 'interface',
 | 
			
		||||
      title: t('Field interface'),
 | 
			
		||||
      width: CELL_WIDTH,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: 'titleField',
 | 
			
		||||
      title: t('Title field'),
 | 
			
		||||
      width: CELL_WIDTH,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      dataIndex: 'actions',
 | 
			
		||||
      title: t('Actions'),
 | 
			
		||||
      width: CELL_WIDTH,
 | 
			
		||||
    },
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  const fields = getCurrentCollectionFields(name);
 | 
			
		||||
 | 
			
		||||
  const groups = {
 | 
			
		||||
    pf: [],
 | 
			
		||||
    association: [],
 | 
			
		||||
    general: [],
 | 
			
		||||
    system: [],
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  fields.forEach((field) => {
 | 
			
		||||
    if (field.primaryKey || field.isForeignKey) {
 | 
			
		||||
      groups.pf.push(field);
 | 
			
		||||
    } else if (field.interface) {
 | 
			
		||||
      const conf = getInterface(field.interface);
 | 
			
		||||
      if (conf.group === 'systemInfo') {
 | 
			
		||||
        groups.system.push(field);
 | 
			
		||||
      } else if (['m2m', 'm2o', 'o2b', 'o2m', 'linkTo'].includes(field.interface)) {
 | 
			
		||||
        groups.association.push(field);
 | 
			
		||||
      } else {
 | 
			
		||||
        groups.general.push(field);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const dataSource = [
 | 
			
		||||
    {
 | 
			
		||||
      key: 'pf',
 | 
			
		||||
      title: t('PK & FK fields'),
 | 
			
		||||
      fields: groups.pf,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      key: 'association',
 | 
			
		||||
      title: t('Association fields'),
 | 
			
		||||
      fields: groups.association,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      key: 'general',
 | 
			
		||||
      title: t('General fields'),
 | 
			
		||||
      fields: groups.general,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      key: 'system',
 | 
			
		||||
      title: t('System fields'),
 | 
			
		||||
      fields: groups.system,
 | 
			
		||||
    },
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  dataSource.push(
 | 
			
		||||
    ...inherits.map((key) => {
 | 
			
		||||
      const collection = getCollection(key);
 | 
			
		||||
      return {
 | 
			
		||||
        key,
 | 
			
		||||
        title: `${t('Inherited fields')} - ` + compile(collection.title),
 | 
			
		||||
        inherit: true,
 | 
			
		||||
        fields: collection.fields,
 | 
			
		||||
      };
 | 
			
		||||
    }),
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const resourceActionProps = {
 | 
			
		||||
    association: {
 | 
			
		||||
      sourceKey: 'name',
 | 
			
		||||
      targetKey: 'name',
 | 
			
		||||
    },
 | 
			
		||||
    collection,
 | 
			
		||||
    request: {
 | 
			
		||||
      resource: 'collections.fields',
 | 
			
		||||
      action: 'list',
 | 
			
		||||
      params: {
 | 
			
		||||
        paginate: false,
 | 
			
		||||
        filter: {
 | 
			
		||||
          $or: [{ 'interface.$not': null }, { 'options.source.$notEmpty': true }],
 | 
			
		||||
        },
 | 
			
		||||
        sort: ['sort'],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const deleteProps = useMemo(
 | 
			
		||||
    () => ({
 | 
			
		||||
      useAction: useBulkDestroyActionAndRefreshCM,
 | 
			
		||||
      title: t('Delete'),
 | 
			
		||||
      icon: 'DeleteOutlined',
 | 
			
		||||
      confirm: {
 | 
			
		||||
        title: t('Delete record'),
 | 
			
		||||
        content: t('Are you sure you want to delete it?'),
 | 
			
		||||
      },
 | 
			
		||||
    }),
 | 
			
		||||
    [t],
 | 
			
		||||
  );
 | 
			
		||||
  const addProps = { type: 'primary' };
 | 
			
		||||
  const syncProps = { type: 'primary' };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <ResourceActionProvider {...resourceActionProps}>
 | 
			
		||||
      <FormContext.Provider value={form}>
 | 
			
		||||
        <FieldContext.Provider value={f}>
 | 
			
		||||
          <Space
 | 
			
		||||
            align={'end'}
 | 
			
		||||
            className={css`
 | 
			
		||||
              justify-content: flex-end;
 | 
			
		||||
              display: flex;
 | 
			
		||||
              margin-bottom: 16px;
 | 
			
		||||
            `}
 | 
			
		||||
          >
 | 
			
		||||
            <Action {...deleteProps} />
 | 
			
		||||
            <SyncFieldsAction {...syncProps} />
 | 
			
		||||
            <AddCollectionField {...addProps} />
 | 
			
		||||
          </Space>
 | 
			
		||||
          <Table
 | 
			
		||||
            rowKey={'key'}
 | 
			
		||||
            columns={columns}
 | 
			
		||||
            dataSource={dataSource.filter((d) => d.fields.length)}
 | 
			
		||||
            pagination={false}
 | 
			
		||||
            expandable={{
 | 
			
		||||
              defaultExpandAllRows: true,
 | 
			
		||||
              expandedRowClassName: () => rowStyle,
 | 
			
		||||
              expandedRowRender: (record) =>
 | 
			
		||||
                record.inherit ? (
 | 
			
		||||
                  <InheritFields
 | 
			
		||||
                    fields={record.fields}
 | 
			
		||||
                    collectionResource={collectionResource}
 | 
			
		||||
                    refreshAsync={refreshAsync}
 | 
			
		||||
                  />
 | 
			
		||||
                ) : (
 | 
			
		||||
                  <CurrentFields
 | 
			
		||||
                    fields={record.fields}
 | 
			
		||||
                    collectionResource={collectionResource}
 | 
			
		||||
                    refreshAsync={refreshAsync}
 | 
			
		||||
                  />
 | 
			
		||||
                ),
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        </FieldContext.Provider>
 | 
			
		||||
      </FormContext.Provider>
 | 
			
		||||
    </ResourceActionProvider>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -14,7 +14,7 @@ import {
 | 
			
		||||
  useCompile,
 | 
			
		||||
  useRecord,
 | 
			
		||||
  useRequest,
 | 
			
		||||
  useSchemaInitializer
 | 
			
		||||
  useSchemaInitializer,
 | 
			
		||||
} from '../..';
 | 
			
		||||
import { overridingSchema } from '../Configuration/schemas/collectionFields';
 | 
			
		||||
 | 
			
		||||
@ -192,10 +192,9 @@ export const CollectionFieldsTableArray: React.FC<any> = observer((props) => {
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  const expandedRowRender = (record: CategorizeDataItem, index, indent, expanded) => {
 | 
			
		||||
    if(!props.loading){
 | 
			
		||||
      const columns = useTableColumns();
 | 
			
		||||
  const ExpandedRowRender = (record: CategorizeDataItem, index, indent, expanded) => {
 | 
			
		||||
    const columns = useTableColumns();
 | 
			
		||||
    if (!props.loading) {
 | 
			
		||||
      if (inherits.includes(record.key)) {
 | 
			
		||||
        columns.pop();
 | 
			
		||||
        columns.push({
 | 
			
		||||
@ -244,7 +243,6 @@ export const CollectionFieldsTableArray: React.FC<any> = observer((props) => {
 | 
			
		||||
        />
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  };
 | 
			
		||||
  return (
 | 
			
		||||
    <div
 | 
			
		||||
@ -262,7 +260,7 @@ export const CollectionFieldsTableArray: React.FC<any> = observer((props) => {
 | 
			
		||||
        dataSource={categorizeData}
 | 
			
		||||
        pagination={false}
 | 
			
		||||
        expandable={{
 | 
			
		||||
          expandedRowRender,
 | 
			
		||||
          expandedRowRender: ExpandedRowRender,
 | 
			
		||||
          expandedRowKeys: expandedKeys,
 | 
			
		||||
        }}
 | 
			
		||||
        onExpand={(expanded, record) => {
 | 
			
		||||
 | 
			
		||||
@ -12,10 +12,11 @@ import { CollectionCategroriesContext } from '../context';
 | 
			
		||||
import { useCollectionManager } from '../hooks/useCollectionManager';
 | 
			
		||||
import { DataSourceContext } from '../sub-table';
 | 
			
		||||
import { AddSubFieldAction } from './AddSubFieldAction';
 | 
			
		||||
import { CollectionFields } from './CollectionFields';
 | 
			
		||||
import { EditSubFieldAction } from './EditSubFieldAction';
 | 
			
		||||
import { FieldSummary } from './components/FieldSummary';
 | 
			
		||||
import { TemplateSummay } from './components/TemplateSummay';
 | 
			
		||||
import { collectionSchema } from './schemas/collections';
 | 
			
		||||
import {TemplateSummay} from './components/TemplateSummay';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param service
 | 
			
		||||
@ -166,6 +167,7 @@ export const ConfigurationTable = () => {
 | 
			
		||||
          FieldSummary,
 | 
			
		||||
          TemplateSummay,
 | 
			
		||||
          CollectionFieldsTable,
 | 
			
		||||
          CollectionFields,
 | 
			
		||||
        }}
 | 
			
		||||
        scope={{
 | 
			
		||||
          useDestroySubField,
 | 
			
		||||
 | 
			
		||||
@ -9,14 +9,15 @@ import {
 | 
			
		||||
  useSensor,
 | 
			
		||||
  useSensors
 | 
			
		||||
} from '@dnd-kit/core';
 | 
			
		||||
import { observer, RecursionField } from '@formily/react';
 | 
			
		||||
import { RecursionField, observer } from '@formily/react';
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
import { Badge, Card, Dropdown, Menu, Modal, Tabs } from 'antd';
 | 
			
		||||
import React, { useContext, useState } from 'react';
 | 
			
		||||
import { useAPIClient } from '../../api-client';
 | 
			
		||||
import { SchemaComponent, SchemaComponentOptions, useCompile } from '../../schema-component';
 | 
			
		||||
import { CollectionCategroriesContext } from '../context';
 | 
			
		||||
import { useResourceActionContext } from '../ResourceActionProvider';
 | 
			
		||||
import { CollectionCategroriesContext } from '../context';
 | 
			
		||||
import { CollectionFields } from './CollectionFields';
 | 
			
		||||
import { collectionTableSchema } from './schemas/collections';
 | 
			
		||||
 | 
			
		||||
function Draggable(props) {
 | 
			
		||||
@ -240,6 +241,7 @@ export const ConfigurationTabs = () => {
 | 
			
		||||
            >
 | 
			
		||||
              <Card bordered={false}>
 | 
			
		||||
                <SchemaComponentOptions
 | 
			
		||||
                  components={{ CollectionFields }}
 | 
			
		||||
                  inherit
 | 
			
		||||
                  scope={{ loadCategories, categoryVisible: item.id === 'all', categoryId: item.id }}
 | 
			
		||||
                >
 | 
			
		||||
 | 
			
		||||
@ -8,10 +8,10 @@ import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { useRequest } from '../../api-client';
 | 
			
		||||
import { RecordProvider, useRecord } from '../../record-provider';
 | 
			
		||||
import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component';
 | 
			
		||||
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
 | 
			
		||||
import { useCancelAction } from '../action-hooks';
 | 
			
		||||
import { useCollectionManager } from '../hooks';
 | 
			
		||||
import { IField } from '../interfaces/types';
 | 
			
		||||
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
 | 
			
		||||
import * as components from './components';
 | 
			
		||||
 | 
			
		||||
const getSchema = (schema: IField, record: any, compile, getContainer): ISchema => {
 | 
			
		||||
@ -26,10 +26,10 @@ const getSchema = (schema: IField, record: any, compile, getContainer): ISchema
 | 
			
		||||
    name: {
 | 
			
		||||
      'x-component': 'CollectionField',
 | 
			
		||||
      'x-decorator': 'FormItem',
 | 
			
		||||
      'x-disabled': true,
 | 
			
		||||
      // 'x-disabled': true,
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
  properties.name['x-disabled'] = true;
 | 
			
		||||
  // properties.name['x-disabled'] = true;
 | 
			
		||||
  if (schema.hasDefaultValue === true) {
 | 
			
		||||
    properties['defaultValue'] = cloneDeep(schema.default.uiSchema);
 | 
			
		||||
    properties['defaultValue']['title'] = compile('{{ t("Default value") }}');
 | 
			
		||||
 | 
			
		||||
@ -8,10 +8,10 @@ import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { useAPIClient, useRequest } from '../../api-client';
 | 
			
		||||
import { RecordProvider, useRecord } from '../../record-provider';
 | 
			
		||||
import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component';
 | 
			
		||||
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
 | 
			
		||||
import { useCancelAction, useUpdateAction } from '../action-hooks';
 | 
			
		||||
import { useCollectionManager } from '../hooks';
 | 
			
		||||
import { IField } from '../interfaces/types';
 | 
			
		||||
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
 | 
			
		||||
import * as components from './components';
 | 
			
		||||
 | 
			
		||||
const getSchema = (schema: IField, record: any, compile, getContainer): ISchema => {
 | 
			
		||||
@ -24,7 +24,7 @@ const getSchema = (schema: IField, record: any, compile, getContainer): ISchema
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (schema.hasDefaultValue === true) {
 | 
			
		||||
    properties['defaultValue'] = cloneDeep(schema.default.uiSchema)||{};
 | 
			
		||||
    properties['defaultValue'] = cloneDeep(schema.default.uiSchema) || {};
 | 
			
		||||
    properties['defaultValue']['title'] = compile('{{ t("Default value") }}');
 | 
			
		||||
    properties['defaultValue']['x-decorator'] = 'FormItem';
 | 
			
		||||
    properties['defaultValue']['x-reactions'] = {
 | 
			
		||||
 | 
			
		||||
@ -8,10 +8,10 @@ import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { useAPIClient, useRequest } from '../../api-client';
 | 
			
		||||
import { RecordProvider, useRecord } from '../../record-provider';
 | 
			
		||||
import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component';
 | 
			
		||||
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
 | 
			
		||||
import { useCancelAction } from '../action-hooks';
 | 
			
		||||
import { useCollectionManager } from '../hooks';
 | 
			
		||||
import { IField } from '../interfaces/types';
 | 
			
		||||
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
 | 
			
		||||
import * as components from './components';
 | 
			
		||||
 | 
			
		||||
const getSchema = (schema: IField, record: any, compile, getContainer): ISchema => {
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ import { ISchema } from '@formily/react';
 | 
			
		||||
import { CollectionOptions } from '../../types';
 | 
			
		||||
import { CollectionFieldInterface } from '../components/CollectionFieldInterface';
 | 
			
		||||
 | 
			
		||||
const collection: CollectionOptions = {
 | 
			
		||||
export const collection: CollectionOptions = {
 | 
			
		||||
  name: 'fields',
 | 
			
		||||
  fields: [
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -1,14 +1,12 @@
 | 
			
		||||
import { ISchema, Schema } from '@formily/react';
 | 
			
		||||
import { message } from 'antd';
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
import { message } from 'antd';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { useAPIClient } from '../../../api-client';
 | 
			
		||||
import { i18n } from '../../../i18n';
 | 
			
		||||
import { CollectionOptions } from '../../types';
 | 
			
		||||
import { CollectionTemplate } from '../components/CollectionTemplate';
 | 
			
		||||
import { CollectionCategory } from '../components/CollectionCategory';
 | 
			
		||||
import { collectionFieldSchema } from './collectionFields';
 | 
			
		||||
 | 
			
		||||
import { CollectionTemplate } from '../components/CollectionTemplate';
 | 
			
		||||
const compile = (source) => {
 | 
			
		||||
  return Schema.compile(source, { t: i18n.t });
 | 
			
		||||
};
 | 
			
		||||
@ -255,6 +253,7 @@ export const collectionTableSchema: ISchema = {
 | 
			
		||||
                      'x-component': 'Action.Drawer',
 | 
			
		||||
                      'x-component-props': {
 | 
			
		||||
                        destroyOnClose: true,
 | 
			
		||||
                        width: '70%',
 | 
			
		||||
                      },
 | 
			
		||||
                      'x-reactions': (field) => {
 | 
			
		||||
                        const i = field.path.segments[1];
 | 
			
		||||
@ -265,7 +264,10 @@ export const collectionTableSchema: ISchema = {
 | 
			
		||||
                        }
 | 
			
		||||
                      },
 | 
			
		||||
                      properties: {
 | 
			
		||||
                        collectionFieldSchema,
 | 
			
		||||
                        collectionFieldSchema: {
 | 
			
		||||
                          type: 'void',
 | 
			
		||||
                          'x-component': 'CollectionFields',
 | 
			
		||||
                        },
 | 
			
		||||
                      },
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
 | 
			
		||||
@ -202,7 +202,7 @@ export const useCollectionFilterOptions = (collectionName: string) => {
 | 
			
		||||
 | 
			
		||||
export const useLinkageCollectionFilterOptions = (collectionName: string) => {
 | 
			
		||||
  const { getCollectionFields, getInterface } = useCollectionManager();
 | 
			
		||||
  const fields = getCollectionFields(collectionName).filter((v)=>!['o2m', 'm2m'].includes(v.interface))
 | 
			
		||||
  const fields = getCollectionFields(collectionName).filter((v) => !['o2m', 'm2m'].includes(v.interface));
 | 
			
		||||
  const field2option = (field, depth) => {
 | 
			
		||||
    if (!field.interface) {
 | 
			
		||||
      return;
 | 
			
		||||
@ -232,7 +232,7 @@ export const useLinkageCollectionFilterOptions = (collectionName: string) => {
 | 
			
		||||
      option['children'] = children;
 | 
			
		||||
    }
 | 
			
		||||
    if (nested) {
 | 
			
		||||
      const targetFields = getCollectionFields(field.target).filter((v)=>!['o2m', 'm2m'].includes(v.interface))
 | 
			
		||||
      const targetFields = getCollectionFields(field.target).filter((v) => !['o2m', 'm2m'].includes(v.interface));
 | 
			
		||||
      const options = getOptions(targetFields, depth + 1).filter(Boolean);
 | 
			
		||||
      option['children'] = option['children'] || [];
 | 
			
		||||
      option['children'].push(...options);
 | 
			
		||||
@ -253,7 +253,6 @@ export const useLinkageCollectionFilterOptions = (collectionName: string) => {
 | 
			
		||||
  return options;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export const useFilterDataSource = (options) => {
 | 
			
		||||
  const { name } = useCollection();
 | 
			
		||||
  const data = useCollectionFilterOptions(name);
 | 
			
		||||
@ -378,7 +377,7 @@ export const useDestroyAction = () => {
 | 
			
		||||
 | 
			
		||||
export const useBulkDestroyAction = () => {
 | 
			
		||||
  const { state, setState, refresh } = useResourceActionContext();
 | 
			
		||||
  const { resource, targetKey } = useResourceContext();
 | 
			
		||||
  const { resource } = useResourceContext();
 | 
			
		||||
  return {
 | 
			
		||||
    async run() {
 | 
			
		||||
      await resource.destroy({
 | 
			
		||||
@ -431,8 +430,13 @@ export const useDestroyActionAndRefreshCM = () => {
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const useDeleteButtonDisabled = () => {
 | 
			
		||||
  const { interface: i, deletable = true } = useRecord();
 | 
			
		||||
export const useDeleteButtonDisabled = (record?: any) => {
 | 
			
		||||
  const recordFromProvider = useRecord();
 | 
			
		||||
  return isDeleteButtonDisabled(record || recordFromProvider);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const isDeleteButtonDisabled = (record?: any) => {
 | 
			
		||||
  const { interface: i, deletable = true } = record || {};
 | 
			
		||||
 | 
			
		||||
  return !deletable || i === 'id';
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,8 @@ import { CollectionManagerContext } from '../context';
 | 
			
		||||
import { CollectionFieldOptions } from '../types';
 | 
			
		||||
 | 
			
		||||
export const useCollectionManager = () => {
 | 
			
		||||
  const { refreshCM, service, interfaces, collections, templates } = useContext(CollectionManagerContext);
 | 
			
		||||
  const { refreshCM, updateCollection, service, interfaces, collections, templates } =
 | 
			
		||||
    useContext(CollectionManagerContext);
 | 
			
		||||
  const compile = useCompile();
 | 
			
		||||
  const getInheritedFields = (name) => {
 | 
			
		||||
    const inheritKeys = getInheritCollections(name);
 | 
			
		||||
@ -241,6 +242,7 @@ export const useCollectionManager = () => {
 | 
			
		||||
    getInheritCollections,
 | 
			
		||||
    getChildrenCollections,
 | 
			
		||||
    refreshCM: () => refreshCM?.(),
 | 
			
		||||
    updateCollection,
 | 
			
		||||
    get(name: string) {
 | 
			
		||||
      return collections?.find((collection) => collection.name === name);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ export interface CollectionManagerOptions {
 | 
			
		||||
  collections?: any[];
 | 
			
		||||
  templates?: any;
 | 
			
		||||
  refreshCM?: () => Promise<void>;
 | 
			
		||||
  updateCollection?: (collection: any) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FieldOptions {
 | 
			
		||||
 | 
			
		||||
@ -213,6 +213,7 @@ export default {
 | 
			
		||||
  "Optional fields": "Optional fields",
 | 
			
		||||
  "System fields": "System fields",
 | 
			
		||||
  "General fields": "General fields",
 | 
			
		||||
  "Inherited fields": "Inherited fields",
 | 
			
		||||
  "Parent collection fields": "Parent collection fields",
 | 
			
		||||
  "Basic": "Basic",
 | 
			
		||||
  "Single line text": "Single line text",
 | 
			
		||||
 | 
			
		||||
@ -595,4 +595,14 @@ export default {
 | 
			
		||||
 | 
			
		||||
  'Click or drag file to this area to upload': 'クリックまたはドラッグしてファイルをアップロード',
 | 
			
		||||
  'Support for a single or bulk upload, file size should not exceed': '単一または複数のファイルをアップロードできます。ファイルサイズは',
 | 
			
		||||
  'Default title for each record': '各レコードのデフォルトタイトル',
 | 
			
		||||
 | 
			
		||||
  'If collection inherits, choose inherited collections as templates': 'コレクションが継承されている場合、継承されたコレクションをテンプレートとして選択してください',
 | 
			
		||||
  'Select an existing piece of data as the initialization data for the form': '既存のデータを選択して、フォームの初期化データとして使用します',
 | 
			
		||||
  'Only the selected fields will be used as the initialization data for the form': '選択したフィールドのみがフォームの初期化データとして使用されます',
 | 
			
		||||
  'Template Data': 'テンプレートデータ',
 | 
			
		||||
  'Data fields': 'データフィールド',
 | 
			
		||||
  'Add template': 'テンプレートを追加',
 | 
			
		||||
  'Display data template selector': 'データテンプレートセレクターを表示',
 | 
			
		||||
  'Form data templates': 'フォームデータテンプレート',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -173,6 +173,7 @@ export default {
 | 
			
		||||
  "Optional fields": "Campos opcionais",
 | 
			
		||||
  "System fields": "Campos do sistema",
 | 
			
		||||
  "General fields": "Campos gerais",
 | 
			
		||||
  "Inherited fields": "Campos herdados",
 | 
			
		||||
  "Parent collection fields": "Campos da coleção pai",
 | 
			
		||||
  "Basic": "Básico",
 | 
			
		||||
  "Single line text": "Texto de uma linha",
 | 
			
		||||
@ -647,4 +648,14 @@ export default {
 | 
			
		||||
 | 
			
		||||
  'Click or drag file to this area to upload': 'Clique ou arraste o arquivo para esta área para fazer o upload',
 | 
			
		||||
  'Support for a single or bulk upload, file size should not exceed': 'Suporte para upload único ou em massa, o tamanho do arquivo não deve exceder',
 | 
			
		||||
  'Default title for each record': 'Título padrão para cada registro',
 | 
			
		||||
 | 
			
		||||
  'If collection inherits, choose inherited collections as templates': 'Se a coleção herda, escolha as coleções herdadas como modelos',
 | 
			
		||||
  'Select an existing piece of data as the initialization data for the form': 'Selecione um pedaço de dados existente como os dados de inicialização para o formulário',
 | 
			
		||||
  'Only the selected fields will be used as the initialization data for the form': 'Somente os campos selecionados serão usados como dados de inicialização para o formulário',
 | 
			
		||||
  'Template Data': 'Dados do modelo',
 | 
			
		||||
  'Data fields': 'Campos de dados',
 | 
			
		||||
  'Add template': 'Adicionar modelo',
 | 
			
		||||
  'Display data template selector': 'Exibir seletor de modelo de dados',
 | 
			
		||||
  'Form data templates': 'Modelos de dados do formulário',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -502,4 +502,14 @@ export default {
 | 
			
		||||
 | 
			
		||||
  'Click or drag file to this area to upload': "Нажмите или перетащите файл в эту область, чтобы загрузить",
 | 
			
		||||
  'Support for a single or bulk upload, file size should not exceed': "Поддержка одиночной или массовой загрузки, размер файла не должен превышать",
 | 
			
		||||
  'Default title for each record': "Заголовок по умолчанию для каждой записи",
 | 
			
		||||
 | 
			
		||||
  'If collection inherits, choose inherited collections as templates': "Если коллекция наследуется, выберите наследуемые коллекции в качестве шаблонов",
 | 
			
		||||
  'Select an existing piece of data as the initialization data for the form': "Выберите существующие данные в качестве исходных данных для формы",
 | 
			
		||||
  'Only the selected fields will be used as the initialization data for the form': "Только выбранные поля будут использоваться в качестве исходных данных для формы",
 | 
			
		||||
  'Template Data': "Шаблон данных",
 | 
			
		||||
  'Data fields': "Поля данных",
 | 
			
		||||
  'Add template': "Добавить шаблон",
 | 
			
		||||
  'Display data template selector': "Отображать селектор шаблона данных",
 | 
			
		||||
  'Form data templates': "Шаблоны данных формы",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -174,6 +174,7 @@ export default {
 | 
			
		||||
  "Field display name": "Alan görünen adı",
 | 
			
		||||
  "Field type": "Alan türü",
 | 
			
		||||
  "Field interface": "Alan arayüzü",
 | 
			
		||||
  "Title field": "Başlık alanı",
 | 
			
		||||
  "Date format": "Tarih formatı",
 | 
			
		||||
  "Year/Month/Day": "Yıl/Ay/Gün",
 | 
			
		||||
  "Year-Month-Day": "Yıl-Ay-Gün",
 | 
			
		||||
@ -273,7 +274,6 @@ export default {
 | 
			
		||||
  "Allow linking to multiple records": "Birden çok kayda bağlanmaya izin ver",
 | 
			
		||||
  "Allow uploading multiple files": "Birden çok dosya yüklemeye izin ver",
 | 
			
		||||
  "Configure calendar": "Takvimi yapılandır",
 | 
			
		||||
  "Title field": "Başlık alanı",
 | 
			
		||||
  "Start date field": "Başlangıç tarihi alanı",
 | 
			
		||||
  "End date field": "Bitiş tarihi alanı",
 | 
			
		||||
  "Navigate": "Navigate",
 | 
			
		||||
@ -501,4 +501,14 @@ export default {
 | 
			
		||||
 | 
			
		||||
  'Click or drag file to this area to upload': "Dosyayı yüklemek için buraya tıklayın veya sürükleyin",
 | 
			
		||||
  'Support for a single or bulk upload, file size should not exceed': "Tek veya toplu yükleme destekler, dosya boyutu aşmamalıdır",
 | 
			
		||||
  'Default title for each record': "Her kayıt için varsayılan başlık",
 | 
			
		||||
 | 
			
		||||
  'If collection inherits, choose inherited collections as templates': "Koleksiyon miras alırsa, kalıtılan koleksiyonları şablon olarak seçin",
 | 
			
		||||
  'Select an existing piece of data as the initialization data for the form': 'Formun başlangıç verileri olarak mevcut bir veri parçasını seçin',
 | 
			
		||||
  'Only the selected fields will be used as the initialization data for the form': 'Yalnızca seçilen alanlar, formun başlangıç verileri olarak kullanılacaktır',
 | 
			
		||||
  'Template Data': 'Şablon Verisi',
 | 
			
		||||
  'Data fields': 'Veri alanları',
 | 
			
		||||
  'Add template': 'Şablon ekle',
 | 
			
		||||
  'Display data template selector': 'Veri şablonu seçicisini görüntüle',
 | 
			
		||||
  'Form data templates': 'Form veri şablonları',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -227,6 +227,7 @@ export default {
 | 
			
		||||
  "Optional fields": "可选字段",
 | 
			
		||||
  "System fields": "系统字段",
 | 
			
		||||
  "General fields": "普通字段",
 | 
			
		||||
  "Inherited fields": "继承字段",
 | 
			
		||||
  "Parent collection fields": "父表字段",
 | 
			
		||||
  "Basic": "基本类型",
 | 
			
		||||
  "Single line text": "单行文本",
 | 
			
		||||
@ -743,4 +744,14 @@ export default {
 | 
			
		||||
 | 
			
		||||
  'Click or drag file to this area to upload': '点击或拖拽文件到此区域上传',
 | 
			
		||||
  'Support for a single or bulk upload, file size should not exceed': '支持单个或批量上传,文件大小不能超过',
 | 
			
		||||
  'Default title for each record': '用作数据的默认标题',
 | 
			
		||||
 | 
			
		||||
  'If collection inherits, choose inherited collections as templates': '当前表有继承关系时,可选择继承链路上的表作为模板来源',
 | 
			
		||||
  'Select an existing piece of data as the initialization data for the form': '选择一条已有的数据作为表单的初始化数据',
 | 
			
		||||
  'Only the selected fields will be used as the initialization data for the form': '仅选择的字段才会作为表单的初始化数据',
 | 
			
		||||
  'Template Data': '模板数据',
 | 
			
		||||
  'Data fields': '数据字段',
 | 
			
		||||
  'Add template': '添加模板',
 | 
			
		||||
  'Display data template selector': '显示数据模板选择框',
 | 
			
		||||
  'Form data templates': '表单数据模板',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -89,7 +89,7 @@ export const Action: ComposedAction = observer((props: any) => {
 | 
			
		||||
  const values = useRecord();
 | 
			
		||||
  const designerProps = fieldSchema['x-designer-props'];
 | 
			
		||||
  const openMode = fieldSchema?.['x-component-props']?.['openMode'];
 | 
			
		||||
  const disabled = form.disabled || field.disabled;
 | 
			
		||||
  const disabled = form.disabled || field.disabled || props.disabled;
 | 
			
		||||
  const openSize = fieldSchema?.['x-component-props']?.['openSize'];
 | 
			
		||||
  const linkageRules = fieldSchema?.['x-linkage-rules'] || [];
 | 
			
		||||
  const { designable } = useDesignable();
 | 
			
		||||
 | 
			
		||||
@ -2,16 +2,16 @@ import { MenuOutlined } from '@ant-design/icons';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { ArrayField, Field } from '@formily/core';
 | 
			
		||||
import {
 | 
			
		||||
  observer,
 | 
			
		||||
  RecursionField,
 | 
			
		||||
  Schema,
 | 
			
		||||
  SchemaExpressionScopeContext,
 | 
			
		||||
  observer,
 | 
			
		||||
  useField,
 | 
			
		||||
  useFieldSchema,
 | 
			
		||||
  SchemaExpressionScopeContext,
 | 
			
		||||
} from '@formily/react';
 | 
			
		||||
import { Table, TableColumnProps } from 'antd';
 | 
			
		||||
import { default as classNames, default as cls } from 'classnames';
 | 
			
		||||
import React, { useState, useContext } from 'react';
 | 
			
		||||
import React, { useContext, useState } from 'react';
 | 
			
		||||
import ReactDragListView from 'react-drag-listview';
 | 
			
		||||
import { DndContext } from '../..';
 | 
			
		||||
import { RecordIndexProvider, RecordProvider, useRequest, useSchemaInitializer } from '../../../';
 | 
			
		||||
@ -35,7 +35,7 @@ const useTableColumns = () => {
 | 
			
		||||
      if (isColumnComponent(s) && useScope(s['x-visible'])) {
 | 
			
		||||
        return buf.concat([s]);
 | 
			
		||||
      }
 | 
			
		||||
      return buf
 | 
			
		||||
      return buf;
 | 
			
		||||
    }, [])
 | 
			
		||||
    .map((s: Schema) => {
 | 
			
		||||
      return {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,8 @@
 | 
			
		||||
import { connect, mapProps, observer } from '@formily/react';
 | 
			
		||||
import { Tree as AntdTree } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { useCollectionManager } from '../../collection-manager';
 | 
			
		||||
import { AssociationSelect, SchemaComponent } from '../../schema-component';
 | 
			
		||||
import { AsDefaultTemplate } from './components/AsDefaultTemplate';
 | 
			
		||||
import { ArrayCollapse } from './components/DataTemplateTitle';
 | 
			
		||||
@ -19,6 +21,9 @@ export const FormDataTemplates = observer((props: any) => {
 | 
			
		||||
  const { useProps } = props;
 | 
			
		||||
  const { defaultValues, collectionName } = useProps();
 | 
			
		||||
  const { collectionList, getEnableFieldTree } = useCollectionState(collectionName);
 | 
			
		||||
  const { getCollection } = useCollectionManager();
 | 
			
		||||
  const collection = getCollection(collectionName);
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaComponent
 | 
			
		||||
@ -54,7 +59,7 @@ export const FormDataTemplates = observer((props: any) => {
 | 
			
		||||
                      type: 'string',
 | 
			
		||||
                      title: '{{ t("Collection") }}',
 | 
			
		||||
                      required: true,
 | 
			
		||||
                      description: '当前表有继承关系时,可选择继承链路上的表作为模板来源',
 | 
			
		||||
                      description: t('If collection inherits, choose inherited collections as templates'),
 | 
			
		||||
                      default: collectionName,
 | 
			
		||||
                      'x-display': collectionList.length > 1 ? 'visible' : 'hidden',
 | 
			
		||||
                      'x-decorator': 'FormItem',
 | 
			
		||||
@ -67,7 +72,7 @@ export const FormDataTemplates = observer((props: any) => {
 | 
			
		||||
                      type: 'number',
 | 
			
		||||
                      title: '{{ t("Template Data") }}',
 | 
			
		||||
                      required: true,
 | 
			
		||||
                      description: '选择一条已有的数据作为表单的初始化数据',
 | 
			
		||||
                      description: t('Select an existing piece of data as the initialization data for the form'),
 | 
			
		||||
                      'x-decorator': 'FormItem',
 | 
			
		||||
                      'x-component': AssociationSelect,
 | 
			
		||||
                      'x-component-props': {
 | 
			
		||||
@ -79,14 +84,14 @@ export const FormDataTemplates = observer((props: any) => {
 | 
			
		||||
                        objectValue: false,
 | 
			
		||||
                        manual: false,
 | 
			
		||||
                        mapOptions: (item) => {
 | 
			
		||||
                          // TODO: 应该使用 item.title 字段的值作为 label
 | 
			
		||||
                          return {
 | 
			
		||||
                            label: item.id,
 | 
			
		||||
                            ...item,
 | 
			
		||||
                            [collection.titleField || 'label']: `#${item.id} ${item[collection.titleField] || ''}`,
 | 
			
		||||
                            value: item.id,
 | 
			
		||||
                          };
 | 
			
		||||
                        },
 | 
			
		||||
                        fieldNames: {
 | 
			
		||||
                          label: 'label',
 | 
			
		||||
                          label: collection.titleField || 'label',
 | 
			
		||||
                          value: 'value',
 | 
			
		||||
                        },
 | 
			
		||||
                      },
 | 
			
		||||
@ -110,7 +115,7 @@ export const FormDataTemplates = observer((props: any) => {
 | 
			
		||||
                      type: 'array',
 | 
			
		||||
                      title: '{{ t("Data fields") }}',
 | 
			
		||||
                      required: true,
 | 
			
		||||
                      description: '仅选择的字段才会作为表单的初始化数据',
 | 
			
		||||
                      description: t('Only the selected fields will be used as the initialization data for the form'),
 | 
			
		||||
                      'x-decorator': 'FormItem',
 | 
			
		||||
                      'x-component': Tree,
 | 
			
		||||
                      'x-component-props': {
 | 
			
		||||
 | 
			
		||||
@ -164,6 +164,7 @@
 | 
			
		||||
      "Optional fields": "Optional fields",
 | 
			
		||||
      "System fields": "System fields",
 | 
			
		||||
      "General fields": "General fields",
 | 
			
		||||
      "Inherited fields": "Inherited fields",
 | 
			
		||||
      "Parent collection fields": "Parent collection fields",
 | 
			
		||||
      "Basic": "Basic",
 | 
			
		||||
      "Single line text": "Single line text",
 | 
			
		||||
 | 
			
		||||
@ -149,6 +149,7 @@
 | 
			
		||||
      "Optional fields": "Campos opcionais",
 | 
			
		||||
      "System fields": "Campos do sistema",
 | 
			
		||||
      "General fields": "Campos gerais",
 | 
			
		||||
      "Inherited fields": "Campos herdados",
 | 
			
		||||
      "Parent collection fields": "Campos da coleção pai",
 | 
			
		||||
      "Basic": "Básico",
 | 
			
		||||
      "Single line text": "Texto de linha única",
 | 
			
		||||
 | 
			
		||||
@ -164,6 +164,7 @@
 | 
			
		||||
      "Optional fields": "可选字段",
 | 
			
		||||
      "System fields": "系统字段",
 | 
			
		||||
      "General fields": "普通字段",
 | 
			
		||||
      "Inherited fields": "继承字段",
 | 
			
		||||
      "Parent collection fields": "父表字段",
 | 
			
		||||
      "Basic": "基本类型",
 | 
			
		||||
      "Single line text": "单行文本",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user