feat: support other collection in popup (#916) close #838

Co-authored-by: sealday <sealday@gmail.com>
Reviewed-on: daoyoucloud/tachybase#916
This commit is contained in:
sealday 2024-05-07 01:19:24 +08:00
parent b562ab8b28
commit adfb78d936
17 changed files with 412 additions and 231 deletions

View File

@ -1,19 +1,58 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useCollection_deprecated } from '../../collection-manager'; import { useCollectionManager, useDataBlockProps } from '../../data-source';
import { useCollection } from '../../data-source/collection/CollectionProvider';
import { useCompile } from '../../schema-component';
import { SchemaToolbar } from '../../schema-settings/GeneralSchemaDesigner'; import { SchemaToolbar } from '../../schema-settings/GeneralSchemaDesigner';
import { useSchemaTemplate } from '../../schema-templates'; import { useSchemaTemplate } from '../../schema-templates';
export const BlockSchemaToolbar = (props) => { export const BlockSchemaToolbar = (props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { name, title } = useCollection_deprecated(); const cm = useCollectionManager();
let { name: currentCollectionName, title: currentCollectionTitle } = useCollection();
const template = useSchemaTemplate(); const template = useSchemaTemplate();
const { association } = useDataBlockProps() || {};
const compile = useCompile();
if (association) {
const [collectionName] = association.split('.');
const { name, title } = cm.getCollection(collectionName);
currentCollectionName = name;
currentCollectionTitle = title;
}
const associationField = cm.getCollectionField(association);
const templateName = ['FormItem', 'ReadPrettyFormItem'].includes(template?.componentName) const templateName = ['FormItem', 'ReadPrettyFormItem'].includes(template?.componentName)
? `${template?.name} ${t('(Fields only)')}` ? `${template?.name} ${t('(Fields only)')}`
: template?.name; : template?.name;
const toolbarTitle = useMemo(() => { const toolbarTitle = useMemo(() => {
return [title || name, templateName].filter(Boolean); return [
}, [name, templateName, title]); getCollectionTitle({
collectionTitle: currentCollectionTitle,
collectionName: currentCollectionName,
associationField,
compile,
}),
templateName,
].filter(Boolean);
}, [compile, currentCollectionTitle, currentCollectionName, associationField, templateName]);
return <SchemaToolbar title={toolbarTitle} {...props} />; return <SchemaToolbar title={toolbarTitle} {...props} />;
}; };
function getCollectionTitle(props: {
collectionTitle: string;
collectionName: string;
associationField: any;
compile: any;
}) {
const { collectionTitle, collectionName, associationField, compile } = props;
if (associationField) {
return `${compile(collectionTitle || collectionName)} > ${compile(
associationField.uiSchema?.title || associationField.name,
)}`;
}
return collectionTitle || collectionName;
}

View File

@ -1,7 +1,7 @@
import { TableOutlined } from '@ant-design/icons'; import { TableOutlined } from '@ant-design/icons';
import React from 'react'; import React, { useCallback } from 'react';
import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application'; import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application';
import { useCollectionManager_deprecated } from '../../../../collection-manager'; import { useCollectionManager } from '../../../../data-source';
import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer'; import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer';
import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection'; import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection';
import { createDetailsWithPaginationUISchema } from './createDetailsWithPaginationUISchema'; import { createDetailsWithPaginationUISchema } from './createDetailsWithPaginationUISchema';
@ -36,9 +36,8 @@ export const DetailsBlockInitializer = ({
showAssociationFields?: boolean; showAssociationFields?: boolean;
hideChildrenIfSingleCollection?: boolean; hideChildrenIfSingleCollection?: boolean;
}) => { }) => {
const { insert } = useSchemaInitializer();
const { getCollection } = useCollectionManager_deprecated();
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
const { createDetailsBlock } = useCreateDetailsBlock();
return ( return (
<DataBlockInitializer <DataBlockInitializer
{...itemConfig} {...itemConfig}
@ -49,18 +48,7 @@ export const DetailsBlockInitializer = ({
return createBlockSchema(options); return createBlockSchema(options);
} }
const { item } = options; createDetailsBlock(options);
const collection = getCollection(item.name, item.dataSource);
const schema = createDetailsWithPaginationUISchema({
collectionName: item.name,
dataSource: item.dataSource,
rowKey: collection.filterTargetKey || 'id',
hideActionInitializer: !(
(collection.template !== 'view' || collection?.writableView) &&
collection.template !== 'sql'
),
});
insert(schema);
}} }}
onlyCurrentDataSource={!!onlyCurrentDataSource} onlyCurrentDataSource={!!onlyCurrentDataSource}
hideSearch={hideSearch} hideSearch={hideSearch}
@ -71,3 +59,28 @@ export const DetailsBlockInitializer = ({
/> />
); );
}; };
export const useCreateDetailsBlock = () => {
const { insert } = useSchemaInitializer();
// const { getCollection } = useCollectionManager_deprecated();
const cm = useCollectionManager();
const createDetailsBlock = useCallback(
({ item }) => {
const collection = cm.getCollection(item.name);
const schema = createDetailsWithPaginationUISchema({
collectionName: item.name,
dataSource: item.dataSource,
rowKey: collection.filterTargetKey || 'id',
hideActionInitializer: !(
(collection.template !== 'view' || collection?.writableView) &&
collection.template !== 'sql'
),
});
insert(schema);
},
[cm, insert],
);
return { createDetailsBlock };
};

View File

@ -11,9 +11,10 @@ export const FormBlockInitializer = ({
hideSearch, hideSearch,
createBlockSchema, createBlockSchema,
componentType = 'FormItem', componentType = 'FormItem',
templateWrap, templateWrap: customizeTemplateWrap,
showAssociationFields, showAssociationFields,
hideChildrenIfSingleCollection, hideChildrenIfSingleCollection,
hideOtherRecordsInPopup,
}: { }: {
filterCollections: (options: { collection?: Collection; associationField?: CollectionFieldOptions }) => boolean; filterCollections: (options: { collection?: Collection; associationField?: CollectionFieldOptions }) => boolean;
onlyCurrentDataSource: boolean; onlyCurrentDataSource: boolean;
@ -33,25 +34,22 @@ export const FormBlockInitializer = ({
) => any; ) => any;
showAssociationFields?: boolean; showAssociationFields?: boolean;
hideChildrenIfSingleCollection?: boolean; hideChildrenIfSingleCollection?: boolean;
/**
* Other records
*/
hideOtherRecordsInPopup?: boolean;
}) => { }) => {
const { insert } = useSchemaInitializer();
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
const { isCusomeizeCreate } = itemConfig; const { createFormBlock, templateWrap } = useCreateFormBlock();
const onCreateFormBlockSchema = useCallback( const onCreateFormBlockSchema = useCallback(
({ item }) => { (options) => {
if (createBlockSchema) { if (createBlockSchema) {
return createBlockSchema({ item }); return createBlockSchema(options);
} }
insert( createFormBlock(options);
createCreateFormBlockUISchema({
collectionName: item.collectionName || item.name,
dataSource: item.dataSource,
isCusomeizeCreate,
}),
);
}, },
[createBlockSchema, insert, isCusomeizeCreate], [createBlockSchema, createFormBlock],
); );
return ( return (
@ -59,21 +57,12 @@ export const FormBlockInitializer = ({
{...itemConfig} {...itemConfig}
icon={<FormOutlined />} icon={<FormOutlined />}
componentType={componentType} componentType={componentType}
templateWrap={(templateSchema, { item }) => { templateWrap={(templateSchema, options) => {
if (templateWrap) { if (customizeTemplateWrap) {
return templateWrap(templateSchema, { item }); return customizeTemplateWrap(templateSchema, options);
} }
const schema = createCreateFormBlockUISchema({ return templateWrap(templateSchema, options);
isCusomeizeCreate,
dataSource: item.dataSource,
templateSchema: templateSchema,
collectionName: item.name,
});
if (item.template && item.mode === 'reference') {
schema['x-template-key'] = item.template.key;
}
return schema;
}} }}
onCreateBlockSchema={onCreateFormBlockSchema} onCreateBlockSchema={onCreateFormBlockSchema}
filter={filterCollections} filter={filterCollections}
@ -81,6 +70,41 @@ export const FormBlockInitializer = ({
hideSearch={hideSearch} hideSearch={hideSearch}
showAssociationFields={showAssociationFields} showAssociationFields={showAssociationFields}
hideChildrenIfSingleCollection={hideChildrenIfSingleCollection} hideChildrenIfSingleCollection={hideChildrenIfSingleCollection}
hideOtherRecordsInPopup={hideOtherRecordsInPopup}
/> />
); );
}; };
export const useCreateFormBlock = () => {
const { insert } = useSchemaInitializer();
const itemConfig = useSchemaInitializerItem();
const { isCusomeizeCreate: isCustomizeCreate } = itemConfig;
const createFormBlock = ({ item }) => {
insert(
createCreateFormBlockUISchema({
collectionName: item.collectionName || item.name,
dataSource: item.dataSource,
isCusomeizeCreate: isCustomizeCreate,
}),
);
};
const templateWrap = (templateSchema, { item }) => {
const schema = createCreateFormBlockUISchema({
isCusomeizeCreate: isCustomizeCreate,
dataSource: item.dataSource,
templateSchema: templateSchema,
collectionName: item.name,
});
if (item.template && item.mode === 'reference') {
schema['x-template-key'] = item.template.key;
}
return schema;
};
return {
createFormBlock,
templateWrap,
};
};

View File

@ -2,9 +2,9 @@ import { OrderedListOutlined } from '@ant-design/icons';
import React from 'react'; import React from 'react';
import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application'; import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application';
import { useCollectionManager_deprecated } from '../../../../collection-manager'; import { useCollectionManager_deprecated } from '../../../../collection-manager';
import { createGridCardBlockSchema } from './createGridCardBlockSchema';
import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer'; import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer';
import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection'; import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection';
import { createGridCardBlockUISchema } from './createGridCardBlockUISchema';
export const GridCardBlockInitializer = ({ export const GridCardBlockInitializer = ({
filterCollections, filterCollections,
@ -33,26 +33,19 @@ export const GridCardBlockInitializer = ({
) => any; ) => any;
showAssociationFields?: boolean; showAssociationFields?: boolean;
}) => { }) => {
const { insert } = useSchemaInitializer();
const { getCollection } = useCollectionManager_deprecated();
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
const { createGridCardBlock } = useCreateGridCardBlock();
return ( return (
<DataBlockInitializer <DataBlockInitializer
{...itemConfig} {...itemConfig}
icon={<OrderedListOutlined />} icon={<OrderedListOutlined />}
componentType={'GridCard'} componentType={'GridCard'}
onCreateBlockSchema={async ({ item }) => { onCreateBlockSchema={async (options) => {
if (createBlockSchema) { if (createBlockSchema) {
return createBlockSchema({ item }); return createBlockSchema(options);
} }
const collection = getCollection(item.name, item.dataSource); createGridCardBlock(options);
const schema = createGridCardBlockSchema({
collectionName: item.name,
dataSource: item.dataSource,
rowKey: collection.filterTargetKey || 'id',
});
insert(schema);
}} }}
onlyCurrentDataSource={onlyCurrentDataSource} onlyCurrentDataSource={onlyCurrentDataSource}
hideSearch={hideSearch} hideSearch={hideSearch}
@ -61,3 +54,20 @@ export const GridCardBlockInitializer = ({
/> />
); );
}; };
export const useCreateGridCardBlock = () => {
const { insert } = useSchemaInitializer();
const { getCollection } = useCollectionManager_deprecated();
const createGridCardBlock = ({ item }) => {
const collection = getCollection(item.name, item.dataSource);
const schema = createGridCardBlockUISchema({
collectionName: item.name,
dataSource: item.dataSource,
rowKey: collection.filterTargetKey || 'id',
});
insert(schema);
};
return { createGridCardBlock };
};

View File

@ -1,4 +1,4 @@
import { createGridCardBlockSchema } from '../createGridCardBlockSchema'; import { createGridCardBlockSchema } from '../createGridCardBlockUISchema';
describe('createGridCardBlockSchema', () => { describe('createGridCardBlockSchema', () => {
test('should return the correct schema', () => { test('should return the correct schema', () => {

View File

@ -1,6 +1,6 @@
import { ISchema } from '@tachybase/schema'; import { ISchema } from '@tachybase/schema';
export const createGridCardBlockSchema = (options: { export const createGridCardBlockUISchema = (options: {
dataSource: string; dataSource: string;
collectionName?: string; collectionName?: string;
association?: string; association?: string;

View File

@ -2,9 +2,9 @@ import { OrderedListOutlined } from '@ant-design/icons';
import React from 'react'; import React from 'react';
import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application'; import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application';
import { useCollectionManager_deprecated } from '../../../../collection-manager'; import { useCollectionManager_deprecated } from '../../../../collection-manager';
import { createListBlockSchema } from './createListBlockSchema';
import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer'; import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer';
import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection'; import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection';
import { createListBlockUISchema } from './createListBlockUISchema';
export const ListBlockInitializer = ({ export const ListBlockInitializer = ({
filterCollections, filterCollections,
@ -33,26 +33,20 @@ export const ListBlockInitializer = ({
) => any; ) => any;
showAssociationFields?: boolean; showAssociationFields?: boolean;
}) => { }) => {
const { getCollection } = useCollectionManager_deprecated();
const { insert } = useSchemaInitializer();
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
const { createListBlock } = useCreateListBlock();
return ( return (
<DataBlockInitializer <DataBlockInitializer
{...itemConfig} {...itemConfig}
icon={<OrderedListOutlined />} icon={<OrderedListOutlined />}
componentType={'List'} componentType={'List'}
onCreateBlockSchema={async ({ item }) => { onCreateBlockSchema={async (options) => {
if (createBlockSchema) { if (createBlockSchema) {
return createBlockSchema({ item }); return createBlockSchema(options);
} }
const collection = getCollection(item.name, item.dataSource); createListBlock(options);
const schema = createListBlockSchema({
collectionName: item.name,
dataSource: item.dataSource,
rowKey: collection.filterTargetKey || 'id',
});
insert(schema);
}} }}
onlyCurrentDataSource={onlyCurrentDataSource} onlyCurrentDataSource={onlyCurrentDataSource}
hideSearch={hideSearch} hideSearch={hideSearch}
@ -61,3 +55,20 @@ export const ListBlockInitializer = ({
/> />
); );
}; };
export const useCreateListBlock = () => {
const { getCollection } = useCollectionManager_deprecated();
const { insert } = useSchemaInitializer();
const createListBlock = ({ item }) => {
const collection = getCollection(item.name, item.dataSource);
const schema = createListBlockUISchema({
collectionName: item.name,
dataSource: item.dataSource,
rowKey: collection.filterTargetKey || 'id',
});
insert(schema);
};
return { createListBlock };
};

View File

@ -1,4 +1,4 @@
import { createListBlockSchema } from '../createListBlockSchema'; import { createListBlockSchema } from '../createListBlockUISchema';
describe('createListBlockSchema', () => { describe('createListBlockSchema', () => {
test('should return the correct schema', () => { test('should return the correct schema', () => {

View File

@ -1,6 +1,6 @@
import { ISchema } from '@tachybase/schema'; import { ISchema } from '@tachybase/schema';
export const createListBlockSchema = (options: { export const createListBlockUISchema = (options: {
dataSource: string; dataSource: string;
collectionName?: string; collectionName?: string;
association?: string; association?: string;

View File

@ -28,26 +28,19 @@ export const TableBlockInitializer = ({
) => any; ) => any;
showAssociationFields?: boolean; showAssociationFields?: boolean;
}) => { }) => {
const { insert } = useSchemaInitializer(); const { createTableBlock } = useCreateTableBlock();
const { getCollection } = useCollectionManager_deprecated();
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
return ( return (
<DataBlockInitializer <DataBlockInitializer
{...itemConfig} {...itemConfig}
icon={<TableOutlined />} icon={<TableOutlined />}
componentType={'Table'} componentType={'Table'}
onCreateBlockSchema={async ({ item }) => { onCreateBlockSchema={async (options) => {
if (createBlockSchema) { if (createBlockSchema) {
return createBlockSchema({ item }); return createBlockSchema(options);
} }
const collection = getCollection(item.name, item.dataSource); createTableBlock(options);
const schema = createTableBlockUISchema({
collectionName: item.name,
dataSource: item.dataSource,
rowKey: collection.filterTargetKey || 'id',
});
insert(schema);
}} }}
onlyCurrentDataSource={onlyCurrentDataSource} onlyCurrentDataSource={onlyCurrentDataSource}
hideSearch={hideSearch} hideSearch={hideSearch}
@ -56,3 +49,20 @@ export const TableBlockInitializer = ({
/> />
); );
}; };
export const useCreateTableBlock = () => {
const { insert } = useSchemaInitializer();
const { getCollection } = useCollectionManager_deprecated();
const createTableBlock = ({ item }) => {
const collection = getCollection(item.name, item.dataSource);
const schema = createTableBlockUISchema({
collectionName: item.name,
dataSource: item.dataSource,
rowKey: collection.filterTargetKey || 'id',
});
insert(schema);
};
return { createTableBlock };
};

View File

@ -11,10 +11,16 @@ import {
useCreateAssociationListBlock, useCreateAssociationListBlock,
useCreateAssociationTableBlock, useCreateAssociationTableBlock,
useCreateEditFormBlock, useCreateEditFormBlock,
useCreateFormBlock,
useCreateTableBlock,
} from '../..'; } from '../..';
import { CompatibleSchemaInitializer } from '../../application/schema-initializer/CompatibleSchemaInitializer'; import { CompatibleSchemaInitializer } from '../../application/schema-initializer/CompatibleSchemaInitializer';
import { useCreateDetailsBlock } from '../../modules/blocks/data-blocks/details-multi/DetailsBlockInitializer';
import { gridRowColWrap } from '../utils'; import { gridRowColWrap } from '../utils';
import { useCreateSingleDetailsSchema } from '../../modules/blocks/data-blocks/details-single/RecordReadPrettyFormBlockInitializer'; import { useCreateSingleDetailsSchema } from '../../modules/blocks/data-blocks/details-single/RecordReadPrettyFormBlockInitializer';
import { useCreateGridCardBlock } from '../../modules/blocks/data-blocks/grid-card/GridCardBlockInitializer';
import { useCreateListBlock } from '../../modules/blocks/data-blocks/list/ListBlockInitializer';
const recursiveParent = (schema: Schema) => { const recursiveParent = (schema: Schema) => {
if (!schema) return null; if (!schema) return null;
@ -52,9 +58,13 @@ function useRecordBlocks() {
createAssociationDetailsWithoutPagination, createAssociationDetailsWithoutPagination,
templateWrap: templateWrapOfAssociationDetailsWithoutPagination, templateWrap: templateWrapOfAssociationDetailsWithoutPagination,
} = useCreateAssociationDetailsWithoutPagination(); } = useCreateAssociationDetailsWithoutPagination();
const { createDetailsBlock } = useCreateDetailsBlock();
const collectionsNeedToDisplay = [currentCollection, ...collectionsWithView]; const collectionsNeedToDisplay = [currentCollection, ...collectionsWithView];
const createBlockSchema = useCallback( const createBlockSchema = useCallback(
({ item }) => { ({ item, fromOthersInPopup }) => {
if (fromOthersInPopup) {
return createDetailsBlock({ item });
}
if (item.associationField) { if (item.associationField) {
if (['hasOne', 'belongsTo'].includes(item.associationField.type)) { if (['hasOne', 'belongsTo'].includes(item.associationField.type)) {
return createAssociationDetailsWithoutPagination({ item }); return createAssociationDetailsWithoutPagination({ item });
@ -63,7 +73,12 @@ function useRecordBlocks() {
} }
return createSingleDetailsSchema({ item }); return createSingleDetailsSchema({ item });
}, },
[createAssociationDetailsBlock, createAssociationDetailsWithoutPagination, createSingleDetailsSchema], [
createAssociationDetailsBlock,
createAssociationDetailsWithoutPagination,
createDetailsBlock,
createSingleDetailsSchema,
],
); );
return { return {
filterCollections({ collection, associationField }) { filterCollections({ collection, associationField }) {
@ -103,7 +118,7 @@ function useRecordBlocks() {
dataSource: collection.dataSource, dataSource: collection.dataSource,
useComponentProps() { useComponentProps() {
const currentCollection = useCollection_deprecated(); const currentCollection = useCollection_deprecated();
const { createEditFormBlock, templateWrap } = useCreateEditFormBlock(); const { createEditFormBlock, templateWrap: templateWrapEdit } = useCreateEditFormBlock();
const collectionsNeedToDisplay = [currentCollection, ...collectionsWithView]; const collectionsNeedToDisplay = [currentCollection, ...collectionsWithView];
return { return {
@ -117,7 +132,8 @@ function useRecordBlocks() {
hideSearch: true, hideSearch: true,
componentType: 'FormItem', componentType: 'FormItem',
createBlockSchema: createEditFormBlock, createBlockSchema: createEditFormBlock,
templateWrap: templateWrap, templateWrap: templateWrapEdit,
hideOtherRecordsInPopup: true,
showAssociationFields: true, showAssociationFields: true,
}; };
}, },
@ -133,6 +149,7 @@ function useRecordBlocks() {
dataSource: collection.dataSource, dataSource: collection.dataSource,
useComponentProps() { useComponentProps() {
const { createAssociationFormBlock, templateWrap } = useCreateAssociationFormBlock(); const { createAssociationFormBlock, templateWrap } = useCreateAssociationFormBlock();
const { createFormBlock, templateWrap: templateWrapCollection } = useCreateFormBlock();
return { return {
filterCollections({ collection, associationField }) { filterCollections({ collection, associationField }) {
if (associationField) { if (associationField) {
@ -143,38 +160,29 @@ function useRecordBlocks() {
onlyCurrentDataSource: true, onlyCurrentDataSource: true,
hideSearch: true, hideSearch: true,
componentType: 'FormItem', componentType: 'FormItem',
createBlockSchema: createAssociationFormBlock, createBlockSchema: ({ item, fromOthersInPopup }) => {
templateWrap: templateWrap, if (fromOthersInPopup) {
return createFormBlock({ item });
}
createAssociationFormBlock({ item });
},
templateWrap: (templateSchema, { item, fromOthersInPopup }) => {
if (fromOthersInPopup) {
return templateWrapCollection(templateSchema, { item });
}
templateWrap(templateSchema, { item });
},
showAssociationFields: true, showAssociationFields: true,
}; };
}, },
useVisible() {
const collection = useCollection();
return useMemo(
() =>
collection.fields.some(
(field) => canMakeAssociationBlock(field) && ['hasMany', 'belongsToMany'].includes(field.type),
),
[collection.fields],
);
},
}, },
{ {
name: 'table', name: 'table',
title: '{{t("Table")}}', title: '{{t("Table")}}',
Component: 'TableBlockInitializer', Component: 'TableBlockInitializer',
useVisible() {
const collection = useCollection();
return useMemo(
() =>
collection.fields.some(
(field) => canMakeAssociationBlock(field) && ['hasMany', 'belongsToMany'].includes(field.type),
),
[collection.fields],
);
},
useComponentProps() { useComponentProps() {
const { createAssociationTableBlock } = useCreateAssociationTableBlock(); const { createAssociationTableBlock } = useCreateAssociationTableBlock();
const { createTableBlock } = useCreateTableBlock();
return { return {
hideSearch: true, hideSearch: true,
@ -185,7 +193,12 @@ function useRecordBlocks() {
} }
return false; return false;
}, },
createBlockSchema: createAssociationTableBlock, createBlockSchema: ({ item, fromOthersInPopup }) => {
if (fromOthersInPopup) {
return createTableBlock({ item });
}
createAssociationTableBlock({ item });
},
showAssociationFields: true, showAssociationFields: true,
}; };
}, },
@ -194,18 +207,9 @@ function useRecordBlocks() {
name: 'list', name: 'list',
title: '{{t("List")}}', title: '{{t("List")}}',
Component: 'ListBlockInitializer', Component: 'ListBlockInitializer',
useVisible() {
const collection = useCollection();
return useMemo(
() =>
collection.fields.some(
(field) => canMakeAssociationBlock(field) && ['hasMany', 'belongsToMany'].includes(field.type),
),
[collection.fields],
);
},
useComponentProps() { useComponentProps() {
const { createAssociationListBlock } = useCreateAssociationListBlock(); const { createAssociationListBlock } = useCreateAssociationListBlock();
const { createListBlock } = useCreateListBlock();
return { return {
hideSearch: true, hideSearch: true,
@ -216,7 +220,12 @@ function useRecordBlocks() {
} }
return false; return false;
}, },
createBlockSchema: createAssociationListBlock, createBlockSchema: ({ item, fromOthersInPopup }) => {
if (fromOthersInPopup) {
return createListBlock({ item });
}
createAssociationListBlock({ item });
},
showAssociationFields: true, showAssociationFields: true,
}; };
}, },
@ -225,18 +234,9 @@ function useRecordBlocks() {
name: 'gridCard', name: 'gridCard',
title: '{{t("Grid Card")}}', title: '{{t("Grid Card")}}',
Component: 'GridCardBlockInitializer', Component: 'GridCardBlockInitializer',
useVisible() {
const collection = useCollection();
return useMemo(
() =>
collection.fields.some(
(field) => canMakeAssociationBlock(field) && ['hasMany', 'belongsToMany'].includes(field.type),
),
[collection.fields],
);
},
useComponentProps() { useComponentProps() {
const { createAssociationGridCardBlock } = useCreateAssociationGridCardBlock(); const { createAssociationGridCardBlock } = useCreateAssociationGridCardBlock();
const { createGridCardBlock } = useCreateGridCardBlock();
return { return {
hideSearch: true, hideSearch: true,
@ -247,7 +247,12 @@ function useRecordBlocks() {
} }
return false; return false;
}, },
createBlockSchema: createAssociationGridCardBlock, createBlockSchema: ({ item, fromOthersInPopup }) => {
if (fromOthersInPopup) {
return createGridCardBlock({ item });
}
createAssociationGridCardBlock({ item });
},
showAssociationFields: true, showAssociationFields: true,
}; };
}, },

View File

@ -261,8 +261,10 @@ export interface DataBlockInitializerProps {
templateSchema: any, templateSchema: any,
{ {
item, item,
fromOthersInPopup,
}: { }: {
item: any; item: any;
fromOthersInPopup?: boolean;
}, },
) => any; ) => any;
onCreateBlockSchema?: (args: any) => void; onCreateBlockSchema?: (args: any) => void;
@ -279,6 +281,14 @@ export interface DataBlockInitializerProps {
/** 如果只有一项数据表时,不显示 children 列表 */ /** 如果只有一项数据表时,不显示 children 列表 */
hideChildrenIfSingleCollection?: boolean; hideChildrenIfSingleCollection?: boolean;
items?: ReturnType<typeof useCollectionDataSourceItems>[]; items?: ReturnType<typeof useCollectionDataSourceItems>[];
/**
* Others
*/
fromOthersInPopup?: boolean;
/**
* Other records
*/
hideOtherRecordsInPopup?: boolean;
} }
export const DataBlockInitializer = (props: DataBlockInitializerProps) => { export const DataBlockInitializer = (props: DataBlockInitializerProps) => {
@ -296,6 +306,8 @@ export const DataBlockInitializer = (props: DataBlockInitializerProps) => {
hideChildrenIfSingleCollection, hideChildrenIfSingleCollection,
filterDataSource, filterDataSource,
items: itemsFromProps, items: itemsFromProps,
fromOthersInPopup,
hideOtherRecordsInPopup,
} = props; } = props;
const { insert, setVisible } = useSchemaInitializer(); const { insert, setVisible } = useSchemaInitializer();
const compile = useCompile(); const compile = useCompile();
@ -304,15 +316,15 @@ export const DataBlockInitializer = (props: DataBlockInitializerProps) => {
async ({ item }) => { async ({ item }) => {
if (item.template) { if (item.template) {
const s = await getTemplateSchemaByMode(item); const s = await getTemplateSchemaByMode(item);
templateWrap ? insert(templateWrap(s, { item })) : insert(s); templateWrap ? insert(templateWrap(s, { item, fromOthersInPopup })) : insert(s);
} else { } else {
if (onCreateBlockSchema) { if (onCreateBlockSchema) {
onCreateBlockSchema({ item }); onCreateBlockSchema({ item, fromOthersInPopup });
} }
} }
setVisible(false); setVisible(false);
}, },
[getTemplateSchemaByMode, insert, onCreateBlockSchema, setVisible, templateWrap], [fromOthersInPopup, getTemplateSchemaByMode, insert, onCreateBlockSchema, setVisible, templateWrap],
); );
const items = const items =
itemsFromProps || itemsFromProps ||
@ -324,6 +336,7 @@ export const DataBlockInitializer = (props: DataBlockInitializerProps) => {
onlyCurrentDataSource, onlyCurrentDataSource,
showAssociationFields, showAssociationFields,
dataBlockInitializerProps: props, dataBlockInitializerProps: props,
hideOtherRecordsInPopup,
}); });
const getMenuItems = useGetSchemaInitializerMenuItems(onClick); const getMenuItems = useGetSchemaInitializerMenuItems(onClick);
const childItems = useMemo(() => { const childItems = useMemo(() => {

View File

@ -5,7 +5,7 @@ import { useCollectionManager_deprecated } from '../../collection-manager';
import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '../../application'; import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '../../application';
import { useSchemaTemplateManager } from '../../schema-templates'; import { useSchemaTemplateManager } from '../../schema-templates';
import { useRecordCollectionDataSourceItems } from '../utils'; import { useRecordCollectionDataSourceItems } from '../utils';
import { createGridCardBlockSchema } from '../../modules/blocks/data-blocks/grid-card/createGridCardBlockSchema'; import { createGridCardBlockUISchema } from '../../modules/blocks/data-blocks/grid-card/createGridCardBlockUISchema';
/** /**
* @deprecated * @deprecated
@ -30,7 +30,7 @@ export const RecordAssociationGridCardBlockInitializer = () => {
insert(s); insert(s);
} else { } else {
insert( insert(
createGridCardBlockSchema({ createGridCardBlockUISchema({
rowKey: collection.filterTargetKey, rowKey: collection.filterTargetKey,
dataSource: collection.dataSource, dataSource: collection.dataSource,
association: resource, association: resource,
@ -53,7 +53,7 @@ export function useCreateAssociationGridCardBlock() {
const collection = getCollection(field.target); const collection = getCollection(field.target);
insert( insert(
createGridCardBlockSchema({ createGridCardBlockUISchema({
rowKey: collection.filterTargetKey, rowKey: collection.filterTargetKey,
dataSource: collection.dataSource, dataSource: collection.dataSource,
association: `${field.collectionName}.${field.name}`, association: `${field.collectionName}.${field.name}`,

View File

@ -5,7 +5,7 @@ import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem }
import { useCollectionManager_deprecated } from '../../collection-manager'; import { useCollectionManager_deprecated } from '../../collection-manager';
import { useSchemaTemplateManager } from '../../schema-templates'; import { useSchemaTemplateManager } from '../../schema-templates';
import { useRecordCollectionDataSourceItems } from '../utils'; import { useRecordCollectionDataSourceItems } from '../utils';
import { createListBlockSchema } from '../../modules/blocks/data-blocks/list/createListBlockSchema'; import { createListBlockUISchema } from '../../modules/blocks/data-blocks/list/createListBlockUISchema';
export const RecordAssociationListBlockInitializer = () => { export const RecordAssociationListBlockInitializer = () => {
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
@ -27,7 +27,7 @@ export const RecordAssociationListBlockInitializer = () => {
insert(s); insert(s);
} else { } else {
insert( insert(
createListBlockSchema({ createListBlockUISchema({
rowKey: collection.filterTargetKey, rowKey: collection.filterTargetKey,
dataSource: collection.dataSource, dataSource: collection.dataSource,
association: resource, association: resource,
@ -50,7 +50,7 @@ export function useCreateAssociationListBlock() {
const collection = getCollection(field.target); const collection = getCollection(field.target);
insert( insert(
createListBlockSchema({ createListBlockUISchema({
rowKey: collection.filterTargetKey, rowKey: collection.filterTargetKey,
dataSource: collection.dataSource, dataSource: collection.dataSource,
association: `${field.collectionName}.${field.name}`, association: `${field.collectionName}.${field.name}`,

View File

@ -842,6 +842,7 @@ export const useCollectionDataSourceItems = ({
showAssociationFields, showAssociationFields,
filterDataSource, filterDataSource,
dataBlockInitializerProps, dataBlockInitializerProps,
hideOtherRecordsInPopup,
}: { }: {
componentName; componentName;
filter?: (options: { collection?: Collection; associationField?: CollectionFieldOptions }) => boolean; filter?: (options: { collection?: Collection; associationField?: CollectionFieldOptions }) => boolean;
@ -849,6 +850,10 @@ export const useCollectionDataSourceItems = ({
showAssociationFields?: boolean; showAssociationFields?: boolean;
filterDataSource?: (dataSource?: DataSource) => boolean; filterDataSource?: (dataSource?: DataSource) => boolean;
dataBlockInitializerProps?: any; dataBlockInitializerProps?: any;
/**
* Other records
*/
hideOtherRecordsInPopup?: boolean;
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const dm = useDataSourceManager(); const dm = useDataSourceManager();
@ -936,19 +941,56 @@ export const useCollectionDataSourceItems = ({
], ],
}, },
}; };
const componentTypeMap = {
ReadPrettyFormItem: 'Details',
};
const otherRecords = {
name: 'otherRecords',
Component: DataBlockInitializer,
// 目的是使点击无效
onClick() {},
componentProps: {
icon: null,
title: t('Other records'),
name: 'otherRecords',
showAssociationFields: false,
onlyCurrentDataSource: false,
hideChildrenIfSingleCollection: false,
onCreateBlockSchema: dataBlockInitializerProps.onCreateBlockSchema,
fromOthersInPopup: true,
componentType: componentTypeMap[componentName] || componentName,
filter({ collection: c, associationField }) {
return true;
},
},
};
let children; let children;
const _associationRecords = associationFields.length ? associationRecords : null;
if (noAssociationMenu[0].children.length && associationFields.length) { if (noAssociationMenu[0].children.length && associationFields.length) {
children = [currentRecord, associationRecords]; if (hideOtherRecordsInPopup) {
} else if (noAssociationMenu[0].children.length) { children = [currentRecord, _associationRecords];
// 当可选数据表只有一个时,实现只点击一次区块 menu 就能创建区块 } else {
if (noAssociationMenu[0].children.length <= 1) { children = [currentRecord, _associationRecords, otherRecords];
noAssociationMenu[0].children = (noAssociationMenu[0].children[0]?.children as any) || []; }
return noAssociationMenu; } else if (noAssociationMenu[0].children.length) {
if (hideOtherRecordsInPopup) {
// 当可选数据表只有一个时,实现只点击一次区块 menu 就能创建区块
if (noAssociationMenu[0].children.length <= 1) {
noAssociationMenu[0].children = (noAssociationMenu[0].children[0]?.children as any) || [];
return noAssociationMenu;
}
children = [currentRecord];
} else {
children = [currentRecord, otherRecords];
} }
children = [currentRecord];
} else { } else {
children = [associationRecords]; if (hideOtherRecordsInPopup) {
children = [_associationRecords];
} else {
children = [_associationRecords, otherRecords];
}
} }
return [ return [
@ -956,10 +998,19 @@ export const useCollectionDataSourceItems = ({
name: 'records', name: 'records',
label: t('Records'), label: t('Records'),
type: 'subMenu', type: 'subMenu',
children, children: children.filter(Boolean),
}, },
]; ];
}, [associationFields, collection.dataSource, collection.name, dataBlockInitializerProps, noAssociationMenu, t]); }, [
associationFields,
collection.dataSource,
collection.name,
componentName,
dataBlockInitializerProps,
hideOtherRecordsInPopup,
noAssociationMenu,
t,
]);
} }
return noAssociationMenu; return noAssociationMenu;

View File

@ -1,8 +1,9 @@
import { Plugin, canMakeAssociationBlock, useCollection } from '@nocobase/client'; import { Plugin } from '@nocobase/client';
import { generateNTemplate } from '../locale'; import { generateNTemplate } from '../locale';
import { CalendarV2 } from './calendar'; import { CalendarV2 } from './calendar';
import { calendarBlockSettings } from './calendar/Calender.Settings'; import { calendarBlockSettings } from './calendar/Calender.Settings';
import { CalendarCollectionTemplate } from './collection-templates/calendar'; import { CalendarCollectionTemplate } from './collection-templates/calendar';
import { useCalendarBlockDecoratorProps } from './hooks/useCalendarBlockDecoratorProps';
import { CalendarBlockProvider, useCalendarBlockProps } from './schema-initializer/CalendarBlockProvider'; import { CalendarBlockProvider, useCalendarBlockProps } from './schema-initializer/CalendarBlockProvider';
import { import {
CalendarActionInitializers_deprecated, CalendarActionInitializers_deprecated,
@ -14,9 +15,8 @@ import {
CalendarBlockInitializer, CalendarBlockInitializer,
RecordAssociationCalendarBlockInitializer, RecordAssociationCalendarBlockInitializer,
useCreateAssociationCalendarBlock, useCreateAssociationCalendarBlock,
useCreateCalendarBlock,
} from './schema-initializer/items'; } from './schema-initializer/items';
import { useMemo } from 'react';
import { useCalendarBlockDecoratorProps } from './hooks/useCalendarBlockDecoratorProps';
export class PluginCalendarClient extends Plugin { export class PluginCalendarClient extends Plugin {
async load() { async load() {
@ -28,18 +28,9 @@ export class PluginCalendarClient extends Plugin {
this.app.schemaInitializerManager.addItem('popup:common:addBlock', 'dataBlocks.calendar', { this.app.schemaInitializerManager.addItem('popup:common:addBlock', 'dataBlocks.calendar', {
title: generateNTemplate('Calendar'), title: generateNTemplate('Calendar'),
Component: 'CalendarBlockInitializer', Component: 'CalendarBlockInitializer',
useVisible() {
const collection = useCollection();
return useMemo(
() =>
collection.fields.some(
(field) => canMakeAssociationBlock(field) && ['hasMany', 'belongsToMany'].includes(field.type),
),
[collection.fields],
);
},
useComponentProps() { useComponentProps() {
const { createAssociationCalendarBlock } = useCreateAssociationCalendarBlock(); const { createAssociationCalendarBlock } = useCreateAssociationCalendarBlock();
const { createCalendarBlock } = useCreateCalendarBlock();
return { return {
onlyCurrentDataSource: true, onlyCurrentDataSource: true,
@ -49,7 +40,12 @@ export class PluginCalendarClient extends Plugin {
} }
return false; return false;
}, },
createBlockSchema: createAssociationCalendarBlock, createBlockSchema: ({ item, fromOthersInPopup }) => {
if (fromOthersInPopup) {
return createCalendarBlock({ item });
}
createAssociationCalendarBlock({ item });
},
showAssociationFields: true, showAssociationFields: true,
hideSearch: true, hideSearch: true,
}; };

View File

@ -30,79 +30,19 @@ export const CalendarBlockInitializer = ({
createBlockSchema?: (options: any) => any; createBlockSchema?: (options: any) => any;
showAssociationFields?: boolean; showAssociationFields?: boolean;
}) => { }) => {
const { insert } = useSchemaInitializer();
const { t } = useTranslation();
const { getCollectionField, getCollectionFieldsOptions } = useCollectionManager_deprecated();
const options = useContext(SchemaOptionsContext);
const { theme } = useGlobalTheme();
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
const { createCalendarBlock } = useCreateCalendarBlock();
return ( return (
<DataBlockInitializer <DataBlockInitializer
{...itemConfig} {...itemConfig}
componentType={'Calendar'} componentType={'Calendar'}
icon={<FormOutlined />} icon={<FormOutlined />}
onCreateBlockSchema={async ({ item }) => { onCreateBlockSchema={async (options) => {
if (createBlockSchema) { if (createBlockSchema) {
return createBlockSchema({ item }); return createBlockSchema(options);
} }
createCalendarBlock(options);
const stringFieldsOptions = getCollectionFieldsOptions(item.name, 'string', { dataSource: item.dataSource });
const dateFieldsOptions = getCollectionFieldsOptions(item.name, 'date', {
association: ['o2o', 'obo', 'oho', 'm2o'],
dataSource: item.dataSource,
});
const values = await FormDialog(
t('Create calendar block'),
() => {
return (
<SchemaComponentOptions scope={options.scope} components={{ ...options.components }}>
<FormLayout layout={'vertical'}>
<SchemaComponent
schema={{
properties: {
title: {
title: t('Title field'),
enum: stringFieldsOptions,
required: true,
'x-component': 'Select',
'x-decorator': 'FormItem',
},
start: {
title: t('Start date field'),
enum: dateFieldsOptions,
required: true,
default: getCollectionField(`${item.name}.createdAt`) ? 'createdAt' : null,
'x-component': 'Cascader',
'x-decorator': 'FormItem',
},
end: {
title: t('End date field'),
enum: dateFieldsOptions,
'x-component': 'Cascader',
'x-decorator': 'FormItem',
},
},
}}
/>
</FormLayout>
</SchemaComponentOptions>
);
},
theme,
).open({
initialValues: {},
});
insert(
createCalendarBlockUISchema({
collectionName: item.name,
dataSource: item.dataSource,
fieldNames: {
...values,
},
}),
);
}} }}
onlyCurrentDataSource={onlyCurrentDataSource} onlyCurrentDataSource={onlyCurrentDataSource}
hideSearch={hideSearch} hideSearch={hideSearch}
@ -111,3 +51,72 @@ export const CalendarBlockInitializer = ({
/> />
); );
}; };
export const useCreateCalendarBlock = () => {
const { insert } = useSchemaInitializer();
const { t } = useTranslation();
const { getCollectionField, getCollectionFieldsOptions } = useCollectionManager_deprecated();
const options = useContext(SchemaOptionsContext);
const { theme } = useGlobalTheme();
const createCalendarBlock = async ({ item }) => {
const stringFieldsOptions = getCollectionFieldsOptions(item.name, 'string', { dataSource: item.dataSource });
const dateFieldsOptions = getCollectionFieldsOptions(item.name, 'date', {
association: ['o2o', 'obo', 'oho', 'm2o'],
dataSource: item.dataSource,
});
const values = await FormDialog(
t('Create calendar block'),
() => {
return (
<SchemaComponentOptions scope={options.scope} components={{ ...options.components }}>
<FormLayout layout={'vertical'}>
<SchemaComponent
schema={{
properties: {
title: {
title: t('Title field'),
enum: stringFieldsOptions,
required: true,
'x-component': 'Select',
'x-decorator': 'FormItem',
},
start: {
title: t('Start date field'),
enum: dateFieldsOptions,
required: true,
default: getCollectionField(`${item.name}.createdAt`) ? 'createdAt' : null,
'x-component': 'Cascader',
'x-decorator': 'FormItem',
},
end: {
title: t('End date field'),
enum: dateFieldsOptions,
'x-component': 'Cascader',
'x-decorator': 'FormItem',
},
},
}}
/>
</FormLayout>
</SchemaComponentOptions>
);
},
theme,
).open({
initialValues: {},
});
insert(
createCalendarBlockUISchema({
collectionName: item.name,
dataSource: item.dataSource,
fieldNames: {
...values,
},
}),
);
};
return { createCalendarBlock };
};