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';
|
import { CollectionManagerOptions } from './types';
|
||||||
|
|
||||||
export const CollectionManagerProvider: React.FC<CollectionManagerOptions> = (props) => {
|
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 defaultTemplates = keyBy(templateOptions(), (item) => item.name);
|
||||||
const ctx = useContext(CollectionManagerContext);
|
const ctx = useContext(CollectionManagerContext);
|
||||||
return (
|
return (
|
||||||
@ -22,6 +22,7 @@ export const CollectionManagerProvider: React.FC<CollectionManagerOptions> = (pr
|
|||||||
templates: { ...defaultTemplates, ...templates },
|
templates: { ...defaultTemplates, ...templates },
|
||||||
collections: [...ctx.collections, ...collections],
|
collections: [...ctx.collections, ...collections],
|
||||||
refreshCM,
|
refreshCM,
|
||||||
|
updateCollection,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CollectionManagerSchemaComponentProvider>{props.children}</CollectionManagerSchemaComponentProvider>
|
<CollectionManagerSchemaComponentProvider>{props.children}</CollectionManagerSchemaComponentProvider>
|
||||||
@ -76,12 +77,17 @@ export const RemoteCollectionManagerProvider = (props: any) => {
|
|||||||
return data?.data || [];
|
return data?.data || [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateCollection = (collection) => {
|
||||||
|
service.mutate({ data: collection });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CollectionCategroriesProvider service={{ ...result }} refreshCategory={refreshCategory}>
|
<CollectionCategroriesProvider service={{ ...result }} refreshCategory={refreshCategory}>
|
||||||
<CollectionManagerProvider
|
<CollectionManagerProvider
|
||||||
service={{ ...service, contentLoading, setContentLoading }}
|
service={{ ...service, contentLoading, setContentLoading }}
|
||||||
collections={service?.data?.data}
|
collections={service?.data?.data}
|
||||||
refreshCM={refreshCM}
|
refreshCM={refreshCM}
|
||||||
|
updateCollection={updateCollection}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</CollectionCategroriesProvider>
|
</CollectionCategroriesProvider>
|
||||||
@ -95,7 +101,7 @@ export const CollectionCategroriesProvider = (props) => {
|
|||||||
value={{
|
value={{
|
||||||
data: service?.data?.data,
|
data: service?.data?.data,
|
||||||
refresh: refreshCategory,
|
refresh: refreshCategory,
|
||||||
...props
|
...props,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.children}
|
{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,
|
useCompile,
|
||||||
useRecord,
|
useRecord,
|
||||||
useRequest,
|
useRequest,
|
||||||
useSchemaInitializer
|
useSchemaInitializer,
|
||||||
} from '../..';
|
} from '../..';
|
||||||
import { overridingSchema } from '../Configuration/schemas/collectionFields';
|
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) => {
|
||||||
const expandedRowRender = (record: CategorizeDataItem, index, indent, expanded) => {
|
const columns = useTableColumns();
|
||||||
if(!props.loading){
|
if (!props.loading) {
|
||||||
const columns = useTableColumns();
|
|
||||||
if (inherits.includes(record.key)) {
|
if (inherits.includes(record.key)) {
|
||||||
columns.pop();
|
columns.pop();
|
||||||
columns.push({
|
columns.push({
|
||||||
@ -244,7 +243,6 @@ export const CollectionFieldsTableArray: React.FC<any> = observer((props) => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -262,7 +260,7 @@ export const CollectionFieldsTableArray: React.FC<any> = observer((props) => {
|
|||||||
dataSource={categorizeData}
|
dataSource={categorizeData}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
expandable={{
|
expandable={{
|
||||||
expandedRowRender,
|
expandedRowRender: ExpandedRowRender,
|
||||||
expandedRowKeys: expandedKeys,
|
expandedRowKeys: expandedKeys,
|
||||||
}}
|
}}
|
||||||
onExpand={(expanded, record) => {
|
onExpand={(expanded, record) => {
|
||||||
|
@ -12,10 +12,11 @@ import { CollectionCategroriesContext } from '../context';
|
|||||||
import { useCollectionManager } from '../hooks/useCollectionManager';
|
import { useCollectionManager } from '../hooks/useCollectionManager';
|
||||||
import { DataSourceContext } from '../sub-table';
|
import { DataSourceContext } from '../sub-table';
|
||||||
import { AddSubFieldAction } from './AddSubFieldAction';
|
import { AddSubFieldAction } from './AddSubFieldAction';
|
||||||
|
import { CollectionFields } from './CollectionFields';
|
||||||
import { EditSubFieldAction } from './EditSubFieldAction';
|
import { EditSubFieldAction } from './EditSubFieldAction';
|
||||||
import { FieldSummary } from './components/FieldSummary';
|
import { FieldSummary } from './components/FieldSummary';
|
||||||
|
import { TemplateSummay } from './components/TemplateSummay';
|
||||||
import { collectionSchema } from './schemas/collections';
|
import { collectionSchema } from './schemas/collections';
|
||||||
import {TemplateSummay} from './components/TemplateSummay';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param service
|
* @param service
|
||||||
@ -166,6 +167,7 @@ export const ConfigurationTable = () => {
|
|||||||
FieldSummary,
|
FieldSummary,
|
||||||
TemplateSummay,
|
TemplateSummay,
|
||||||
CollectionFieldsTable,
|
CollectionFieldsTable,
|
||||||
|
CollectionFields,
|
||||||
}}
|
}}
|
||||||
scope={{
|
scope={{
|
||||||
useDestroySubField,
|
useDestroySubField,
|
||||||
|
@ -9,14 +9,15 @@ import {
|
|||||||
useSensor,
|
useSensor,
|
||||||
useSensors
|
useSensors
|
||||||
} from '@dnd-kit/core';
|
} from '@dnd-kit/core';
|
||||||
import { observer, RecursionField } from '@formily/react';
|
import { RecursionField, observer } from '@formily/react';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { Badge, Card, Dropdown, Menu, Modal, Tabs } from 'antd';
|
import { Badge, Card, Dropdown, Menu, Modal, Tabs } from 'antd';
|
||||||
import React, { useContext, useState } from 'react';
|
import React, { useContext, useState } from 'react';
|
||||||
import { useAPIClient } from '../../api-client';
|
import { useAPIClient } from '../../api-client';
|
||||||
import { SchemaComponent, SchemaComponentOptions, useCompile } from '../../schema-component';
|
import { SchemaComponent, SchemaComponentOptions, useCompile } from '../../schema-component';
|
||||||
import { CollectionCategroriesContext } from '../context';
|
|
||||||
import { useResourceActionContext } from '../ResourceActionProvider';
|
import { useResourceActionContext } from '../ResourceActionProvider';
|
||||||
|
import { CollectionCategroriesContext } from '../context';
|
||||||
|
import { CollectionFields } from './CollectionFields';
|
||||||
import { collectionTableSchema } from './schemas/collections';
|
import { collectionTableSchema } from './schemas/collections';
|
||||||
|
|
||||||
function Draggable(props) {
|
function Draggable(props) {
|
||||||
@ -240,6 +241,7 @@ export const ConfigurationTabs = () => {
|
|||||||
>
|
>
|
||||||
<Card bordered={false}>
|
<Card bordered={false}>
|
||||||
<SchemaComponentOptions
|
<SchemaComponentOptions
|
||||||
|
components={{ CollectionFields }}
|
||||||
inherit
|
inherit
|
||||||
scope={{ loadCategories, categoryVisible: item.id === 'all', categoryId: item.id }}
|
scope={{ loadCategories, categoryVisible: item.id === 'all', categoryId: item.id }}
|
||||||
>
|
>
|
||||||
|
@ -8,10 +8,10 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { useRequest } from '../../api-client';
|
import { useRequest } from '../../api-client';
|
||||||
import { RecordProvider, useRecord } from '../../record-provider';
|
import { RecordProvider, useRecord } from '../../record-provider';
|
||||||
import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component';
|
import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component';
|
||||||
|
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
|
||||||
import { useCancelAction } from '../action-hooks';
|
import { useCancelAction } from '../action-hooks';
|
||||||
import { useCollectionManager } from '../hooks';
|
import { useCollectionManager } from '../hooks';
|
||||||
import { IField } from '../interfaces/types';
|
import { IField } from '../interfaces/types';
|
||||||
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
|
|
||||||
import * as components from './components';
|
import * as components from './components';
|
||||||
|
|
||||||
const getSchema = (schema: IField, record: any, compile, getContainer): ISchema => {
|
const getSchema = (schema: IField, record: any, compile, getContainer): ISchema => {
|
||||||
@ -26,10 +26,10 @@ const getSchema = (schema: IField, record: any, compile, getContainer): ISchema
|
|||||||
name: {
|
name: {
|
||||||
'x-component': 'CollectionField',
|
'x-component': 'CollectionField',
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-disabled': true,
|
// 'x-disabled': true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
properties.name['x-disabled'] = true;
|
// properties.name['x-disabled'] = true;
|
||||||
if (schema.hasDefaultValue === true) {
|
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']['title'] = compile('{{ t("Default value") }}');
|
||||||
|
@ -8,10 +8,10 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { useAPIClient, useRequest } from '../../api-client';
|
import { useAPIClient, useRequest } from '../../api-client';
|
||||||
import { RecordProvider, useRecord } from '../../record-provider';
|
import { RecordProvider, useRecord } from '../../record-provider';
|
||||||
import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component';
|
import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component';
|
||||||
|
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
|
||||||
import { useCancelAction, useUpdateAction } from '../action-hooks';
|
import { useCancelAction, useUpdateAction } from '../action-hooks';
|
||||||
import { useCollectionManager } from '../hooks';
|
import { useCollectionManager } from '../hooks';
|
||||||
import { IField } from '../interfaces/types';
|
import { IField } from '../interfaces/types';
|
||||||
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
|
|
||||||
import * as components from './components';
|
import * as components from './components';
|
||||||
|
|
||||||
const getSchema = (schema: IField, record: any, compile, getContainer): ISchema => {
|
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) {
|
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']['title'] = compile('{{ t("Default value") }}');
|
||||||
properties['defaultValue']['x-decorator'] = 'FormItem';
|
properties['defaultValue']['x-decorator'] = 'FormItem';
|
||||||
properties['defaultValue']['x-reactions'] = {
|
properties['defaultValue']['x-reactions'] = {
|
||||||
|
@ -8,10 +8,10 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { useAPIClient, useRequest } from '../../api-client';
|
import { useAPIClient, useRequest } from '../../api-client';
|
||||||
import { RecordProvider, useRecord } from '../../record-provider';
|
import { RecordProvider, useRecord } from '../../record-provider';
|
||||||
import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component';
|
import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component';
|
||||||
|
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
|
||||||
import { useCancelAction } from '../action-hooks';
|
import { useCancelAction } from '../action-hooks';
|
||||||
import { useCollectionManager } from '../hooks';
|
import { useCollectionManager } from '../hooks';
|
||||||
import { IField } from '../interfaces/types';
|
import { IField } from '../interfaces/types';
|
||||||
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
|
|
||||||
import * as components from './components';
|
import * as components from './components';
|
||||||
|
|
||||||
const getSchema = (schema: IField, record: any, compile, getContainer): ISchema => {
|
const getSchema = (schema: IField, record: any, compile, getContainer): ISchema => {
|
||||||
|
@ -2,7 +2,7 @@ import { ISchema } from '@formily/react';
|
|||||||
import { CollectionOptions } from '../../types';
|
import { CollectionOptions } from '../../types';
|
||||||
import { CollectionFieldInterface } from '../components/CollectionFieldInterface';
|
import { CollectionFieldInterface } from '../components/CollectionFieldInterface';
|
||||||
|
|
||||||
const collection: CollectionOptions = {
|
export const collection: CollectionOptions = {
|
||||||
name: 'fields',
|
name: 'fields',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
import { ISchema, Schema } from '@formily/react';
|
import { ISchema, Schema } from '@formily/react';
|
||||||
import { message } from 'antd';
|
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
|
import { message } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useAPIClient } from '../../../api-client';
|
import { useAPIClient } from '../../../api-client';
|
||||||
import { i18n } from '../../../i18n';
|
import { i18n } from '../../../i18n';
|
||||||
import { CollectionOptions } from '../../types';
|
import { CollectionOptions } from '../../types';
|
||||||
import { CollectionTemplate } from '../components/CollectionTemplate';
|
|
||||||
import { CollectionCategory } from '../components/CollectionCategory';
|
import { CollectionCategory } from '../components/CollectionCategory';
|
||||||
import { collectionFieldSchema } from './collectionFields';
|
import { CollectionTemplate } from '../components/CollectionTemplate';
|
||||||
|
|
||||||
const compile = (source) => {
|
const compile = (source) => {
|
||||||
return Schema.compile(source, { t: i18n.t });
|
return Schema.compile(source, { t: i18n.t });
|
||||||
};
|
};
|
||||||
@ -255,6 +253,7 @@ export const collectionTableSchema: ISchema = {
|
|||||||
'x-component': 'Action.Drawer',
|
'x-component': 'Action.Drawer',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
destroyOnClose: true,
|
destroyOnClose: true,
|
||||||
|
width: '70%',
|
||||||
},
|
},
|
||||||
'x-reactions': (field) => {
|
'x-reactions': (field) => {
|
||||||
const i = field.path.segments[1];
|
const i = field.path.segments[1];
|
||||||
@ -265,7 +264,10 @@ export const collectionTableSchema: ISchema = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
collectionFieldSchema,
|
collectionFieldSchema: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'CollectionFields',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -202,7 +202,7 @@ export const useCollectionFilterOptions = (collectionName: string) => {
|
|||||||
|
|
||||||
export const useLinkageCollectionFilterOptions = (collectionName: string) => {
|
export const useLinkageCollectionFilterOptions = (collectionName: string) => {
|
||||||
const { getCollectionFields, getInterface } = useCollectionManager();
|
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) => {
|
const field2option = (field, depth) => {
|
||||||
if (!field.interface) {
|
if (!field.interface) {
|
||||||
return;
|
return;
|
||||||
@ -232,7 +232,7 @@ export const useLinkageCollectionFilterOptions = (collectionName: string) => {
|
|||||||
option['children'] = children;
|
option['children'] = children;
|
||||||
}
|
}
|
||||||
if (nested) {
|
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);
|
const options = getOptions(targetFields, depth + 1).filter(Boolean);
|
||||||
option['children'] = option['children'] || [];
|
option['children'] = option['children'] || [];
|
||||||
option['children'].push(...options);
|
option['children'].push(...options);
|
||||||
@ -253,7 +253,6 @@ export const useLinkageCollectionFilterOptions = (collectionName: string) => {
|
|||||||
return options;
|
return options;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const useFilterDataSource = (options) => {
|
export const useFilterDataSource = (options) => {
|
||||||
const { name } = useCollection();
|
const { name } = useCollection();
|
||||||
const data = useCollectionFilterOptions(name);
|
const data = useCollectionFilterOptions(name);
|
||||||
@ -378,7 +377,7 @@ export const useDestroyAction = () => {
|
|||||||
|
|
||||||
export const useBulkDestroyAction = () => {
|
export const useBulkDestroyAction = () => {
|
||||||
const { state, setState, refresh } = useResourceActionContext();
|
const { state, setState, refresh } = useResourceActionContext();
|
||||||
const { resource, targetKey } = useResourceContext();
|
const { resource } = useResourceContext();
|
||||||
return {
|
return {
|
||||||
async run() {
|
async run() {
|
||||||
await resource.destroy({
|
await resource.destroy({
|
||||||
@ -431,8 +430,13 @@ export const useDestroyActionAndRefreshCM = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useDeleteButtonDisabled = () => {
|
export const useDeleteButtonDisabled = (record?: any) => {
|
||||||
const { interface: i, deletable = true } = useRecord();
|
const recordFromProvider = useRecord();
|
||||||
|
return isDeleteButtonDisabled(record || recordFromProvider);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isDeleteButtonDisabled = (record?: any) => {
|
||||||
|
const { interface: i, deletable = true } = record || {};
|
||||||
|
|
||||||
return !deletable || i === 'id';
|
return !deletable || i === 'id';
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,8 @@ import { CollectionManagerContext } from '../context';
|
|||||||
import { CollectionFieldOptions } from '../types';
|
import { CollectionFieldOptions } from '../types';
|
||||||
|
|
||||||
export const useCollectionManager = () => {
|
export const useCollectionManager = () => {
|
||||||
const { refreshCM, service, interfaces, collections, templates } = useContext(CollectionManagerContext);
|
const { refreshCM, updateCollection, service, interfaces, collections, templates } =
|
||||||
|
useContext(CollectionManagerContext);
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const getInheritedFields = (name) => {
|
const getInheritedFields = (name) => {
|
||||||
const inheritKeys = getInheritCollections(name);
|
const inheritKeys = getInheritCollections(name);
|
||||||
@ -241,6 +242,7 @@ export const useCollectionManager = () => {
|
|||||||
getInheritCollections,
|
getInheritCollections,
|
||||||
getChildrenCollections,
|
getChildrenCollections,
|
||||||
refreshCM: () => refreshCM?.(),
|
refreshCM: () => refreshCM?.(),
|
||||||
|
updateCollection,
|
||||||
get(name: string) {
|
get(name: string) {
|
||||||
return collections?.find((collection) => collection.name === name);
|
return collections?.find((collection) => collection.name === name);
|
||||||
},
|
},
|
||||||
|
@ -6,6 +6,7 @@ export interface CollectionManagerOptions {
|
|||||||
collections?: any[];
|
collections?: any[];
|
||||||
templates?: any;
|
templates?: any;
|
||||||
refreshCM?: () => Promise<void>;
|
refreshCM?: () => Promise<void>;
|
||||||
|
updateCollection?: (collection: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FieldOptions {
|
export interface FieldOptions {
|
||||||
|
@ -213,6 +213,7 @@ export default {
|
|||||||
"Optional fields": "Optional fields",
|
"Optional fields": "Optional fields",
|
||||||
"System fields": "System fields",
|
"System fields": "System fields",
|
||||||
"General fields": "General fields",
|
"General fields": "General fields",
|
||||||
|
"Inherited fields": "Inherited fields",
|
||||||
"Parent collection fields": "Parent collection fields",
|
"Parent collection fields": "Parent collection fields",
|
||||||
"Basic": "Basic",
|
"Basic": "Basic",
|
||||||
"Single line text": "Single line text",
|
"Single line text": "Single line text",
|
||||||
|
@ -595,4 +595,14 @@ export default {
|
|||||||
|
|
||||||
'Click or drag file to this area to upload': 'クリックまたはドラッグしてファイルをアップロード',
|
'Click or drag file to this area to upload': 'クリックまたはドラッグしてファイルをアップロード',
|
||||||
'Support for a single or bulk upload, file size should not exceed': '単一または複数のファイルをアップロードできます。ファイルサイズは',
|
'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",
|
"Optional fields": "Campos opcionais",
|
||||||
"System fields": "Campos do sistema",
|
"System fields": "Campos do sistema",
|
||||||
"General fields": "Campos gerais",
|
"General fields": "Campos gerais",
|
||||||
|
"Inherited fields": "Campos herdados",
|
||||||
"Parent collection fields": "Campos da coleção pai",
|
"Parent collection fields": "Campos da coleção pai",
|
||||||
"Basic": "Básico",
|
"Basic": "Básico",
|
||||||
"Single line text": "Texto de uma linha",
|
"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',
|
'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',
|
'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': "Нажмите или перетащите файл в эту область, чтобы загрузить",
|
'Click or drag file to this area to upload': "Нажмите или перетащите файл в эту область, чтобы загрузить",
|
||||||
'Support for a single or bulk upload, file size should not exceed': "Поддержка одиночной или массовой загрузки, размер файла не должен превышать",
|
'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 display name": "Alan görünen adı",
|
||||||
"Field type": "Alan türü",
|
"Field type": "Alan türü",
|
||||||
"Field interface": "Alan arayüzü",
|
"Field interface": "Alan arayüzü",
|
||||||
|
"Title field": "Başlık alanı",
|
||||||
"Date format": "Tarih formatı",
|
"Date format": "Tarih formatı",
|
||||||
"Year/Month/Day": "Yıl/Ay/Gün",
|
"Year/Month/Day": "Yıl/Ay/Gün",
|
||||||
"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 linking to multiple records": "Birden çok kayda bağlanmaya izin ver",
|
||||||
"Allow uploading multiple files": "Birden çok dosya yüklemeye izin ver",
|
"Allow uploading multiple files": "Birden çok dosya yüklemeye izin ver",
|
||||||
"Configure calendar": "Takvimi yapılandır",
|
"Configure calendar": "Takvimi yapılandır",
|
||||||
"Title field": "Başlık alanı",
|
|
||||||
"Start date field": "Başlangıç tarihi alanı",
|
"Start date field": "Başlangıç tarihi alanı",
|
||||||
"End date field": "Bitiş tarihi alanı",
|
"End date field": "Bitiş tarihi alanı",
|
||||||
"Navigate": "Navigate",
|
"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",
|
'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",
|
'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": "可选字段",
|
"Optional fields": "可选字段",
|
||||||
"System fields": "系统字段",
|
"System fields": "系统字段",
|
||||||
"General fields": "普通字段",
|
"General fields": "普通字段",
|
||||||
|
"Inherited fields": "继承字段",
|
||||||
"Parent collection fields": "父表字段",
|
"Parent collection fields": "父表字段",
|
||||||
"Basic": "基本类型",
|
"Basic": "基本类型",
|
||||||
"Single line text": "单行文本",
|
"Single line text": "单行文本",
|
||||||
@ -743,4 +744,14 @@ export default {
|
|||||||
|
|
||||||
'Click or drag file to this area to upload': '点击或拖拽文件到此区域上传',
|
'Click or drag file to this area to upload': '点击或拖拽文件到此区域上传',
|
||||||
'Support for a single or bulk upload, file size should not exceed': '支持单个或批量上传,文件大小不能超过',
|
'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 values = useRecord();
|
||||||
const designerProps = fieldSchema['x-designer-props'];
|
const designerProps = fieldSchema['x-designer-props'];
|
||||||
const openMode = fieldSchema?.['x-component-props']?.['openMode'];
|
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 openSize = fieldSchema?.['x-component-props']?.['openSize'];
|
||||||
const linkageRules = fieldSchema?.['x-linkage-rules'] || [];
|
const linkageRules = fieldSchema?.['x-linkage-rules'] || [];
|
||||||
const { designable } = useDesignable();
|
const { designable } = useDesignable();
|
||||||
|
@ -2,16 +2,16 @@ import { MenuOutlined } from '@ant-design/icons';
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { ArrayField, Field } from '@formily/core';
|
import { ArrayField, Field } from '@formily/core';
|
||||||
import {
|
import {
|
||||||
observer,
|
|
||||||
RecursionField,
|
RecursionField,
|
||||||
Schema,
|
Schema,
|
||||||
|
SchemaExpressionScopeContext,
|
||||||
|
observer,
|
||||||
useField,
|
useField,
|
||||||
useFieldSchema,
|
useFieldSchema,
|
||||||
SchemaExpressionScopeContext,
|
|
||||||
} from '@formily/react';
|
} from '@formily/react';
|
||||||
import { Table, TableColumnProps } from 'antd';
|
import { Table, TableColumnProps } from 'antd';
|
||||||
import { default as classNames, default as cls } from 'classnames';
|
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 ReactDragListView from 'react-drag-listview';
|
||||||
import { DndContext } from '../..';
|
import { DndContext } from '../..';
|
||||||
import { RecordIndexProvider, RecordProvider, useRequest, useSchemaInitializer } from '../../../';
|
import { RecordIndexProvider, RecordProvider, useRequest, useSchemaInitializer } from '../../../';
|
||||||
@ -35,7 +35,7 @@ const useTableColumns = () => {
|
|||||||
if (isColumnComponent(s) && useScope(s['x-visible'])) {
|
if (isColumnComponent(s) && useScope(s['x-visible'])) {
|
||||||
return buf.concat([s]);
|
return buf.concat([s]);
|
||||||
}
|
}
|
||||||
return buf
|
return buf;
|
||||||
}, [])
|
}, [])
|
||||||
.map((s: Schema) => {
|
.map((s: Schema) => {
|
||||||
return {
|
return {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { connect, mapProps, observer } from '@formily/react';
|
import { connect, mapProps, observer } from '@formily/react';
|
||||||
import { Tree as AntdTree } from 'antd';
|
import { Tree as AntdTree } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useCollectionManager } from '../../collection-manager';
|
||||||
import { AssociationSelect, SchemaComponent } from '../../schema-component';
|
import { AssociationSelect, SchemaComponent } from '../../schema-component';
|
||||||
import { AsDefaultTemplate } from './components/AsDefaultTemplate';
|
import { AsDefaultTemplate } from './components/AsDefaultTemplate';
|
||||||
import { ArrayCollapse } from './components/DataTemplateTitle';
|
import { ArrayCollapse } from './components/DataTemplateTitle';
|
||||||
@ -19,6 +21,9 @@ export const FormDataTemplates = observer((props: any) => {
|
|||||||
const { useProps } = props;
|
const { useProps } = props;
|
||||||
const { defaultValues, collectionName } = useProps();
|
const { defaultValues, collectionName } = useProps();
|
||||||
const { collectionList, getEnableFieldTree } = useCollectionState(collectionName);
|
const { collectionList, getEnableFieldTree } = useCollectionState(collectionName);
|
||||||
|
const { getCollection } = useCollectionManager();
|
||||||
|
const collection = getCollection(collectionName);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SchemaComponent
|
<SchemaComponent
|
||||||
@ -54,7 +59,7 @@ export const FormDataTemplates = observer((props: any) => {
|
|||||||
type: 'string',
|
type: 'string',
|
||||||
title: '{{ t("Collection") }}',
|
title: '{{ t("Collection") }}',
|
||||||
required: true,
|
required: true,
|
||||||
description: '当前表有继承关系时,可选择继承链路上的表作为模板来源',
|
description: t('If collection inherits, choose inherited collections as templates'),
|
||||||
default: collectionName,
|
default: collectionName,
|
||||||
'x-display': collectionList.length > 1 ? 'visible' : 'hidden',
|
'x-display': collectionList.length > 1 ? 'visible' : 'hidden',
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
@ -67,7 +72,7 @@ export const FormDataTemplates = observer((props: any) => {
|
|||||||
type: 'number',
|
type: 'number',
|
||||||
title: '{{ t("Template Data") }}',
|
title: '{{ t("Template Data") }}',
|
||||||
required: true,
|
required: true,
|
||||||
description: '选择一条已有的数据作为表单的初始化数据',
|
description: t('Select an existing piece of data as the initialization data for the form'),
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': AssociationSelect,
|
'x-component': AssociationSelect,
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
@ -79,14 +84,14 @@ export const FormDataTemplates = observer((props: any) => {
|
|||||||
objectValue: false,
|
objectValue: false,
|
||||||
manual: false,
|
manual: false,
|
||||||
mapOptions: (item) => {
|
mapOptions: (item) => {
|
||||||
// TODO: 应该使用 item.title 字段的值作为 label
|
|
||||||
return {
|
return {
|
||||||
label: item.id,
|
...item,
|
||||||
|
[collection.titleField || 'label']: `#${item.id} ${item[collection.titleField] || ''}`,
|
||||||
value: item.id,
|
value: item.id,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
fieldNames: {
|
fieldNames: {
|
||||||
label: 'label',
|
label: collection.titleField || 'label',
|
||||||
value: 'value',
|
value: 'value',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -110,7 +115,7 @@ export const FormDataTemplates = observer((props: any) => {
|
|||||||
type: 'array',
|
type: 'array',
|
||||||
title: '{{ t("Data fields") }}',
|
title: '{{ t("Data fields") }}',
|
||||||
required: true,
|
required: true,
|
||||||
description: '仅选择的字段才会作为表单的初始化数据',
|
description: t('Only the selected fields will be used as the initialization data for the form'),
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': Tree,
|
'x-component': Tree,
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
|
@ -164,6 +164,7 @@
|
|||||||
"Optional fields": "Optional fields",
|
"Optional fields": "Optional fields",
|
||||||
"System fields": "System fields",
|
"System fields": "System fields",
|
||||||
"General fields": "General fields",
|
"General fields": "General fields",
|
||||||
|
"Inherited fields": "Inherited fields",
|
||||||
"Parent collection fields": "Parent collection fields",
|
"Parent collection fields": "Parent collection fields",
|
||||||
"Basic": "Basic",
|
"Basic": "Basic",
|
||||||
"Single line text": "Single line text",
|
"Single line text": "Single line text",
|
||||||
|
@ -149,6 +149,7 @@
|
|||||||
"Optional fields": "Campos opcionais",
|
"Optional fields": "Campos opcionais",
|
||||||
"System fields": "Campos do sistema",
|
"System fields": "Campos do sistema",
|
||||||
"General fields": "Campos gerais",
|
"General fields": "Campos gerais",
|
||||||
|
"Inherited fields": "Campos herdados",
|
||||||
"Parent collection fields": "Campos da coleção pai",
|
"Parent collection fields": "Campos da coleção pai",
|
||||||
"Basic": "Básico",
|
"Basic": "Básico",
|
||||||
"Single line text": "Texto de linha única",
|
"Single line text": "Texto de linha única",
|
||||||
|
@ -164,6 +164,7 @@
|
|||||||
"Optional fields": "可选字段",
|
"Optional fields": "可选字段",
|
||||||
"System fields": "系统字段",
|
"System fields": "系统字段",
|
||||||
"General fields": "普通字段",
|
"General fields": "普通字段",
|
||||||
|
"Inherited fields": "继承字段",
|
||||||
"Parent collection fields": "父表字段",
|
"Parent collection fields": "父表字段",
|
||||||
"Basic": "基本类型",
|
"Basic": "基本类型",
|
||||||
"Single line text": "单行文本",
|
"Single line text": "单行文本",
|
||||||
|
Loading…
Reference in New Issue
Block a user