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 { 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 { useSchemaTemplate } from '../../schema-templates';
export const BlockSchemaToolbar = (props) => {
const { t } = useTranslation();
const { name, title } = useCollection_deprecated();
const cm = useCollectionManager();
let { name: currentCollectionName, title: currentCollectionTitle } = useCollection();
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)
? `${template?.name} ${t('(Fields only)')}`
: template?.name;
const toolbarTitle = useMemo(() => {
return [title || name, templateName].filter(Boolean);
}, [name, templateName, title]);
return [
getCollectionTitle({
collectionTitle: currentCollectionTitle,
collectionName: currentCollectionName,
associationField,
compile,
}),
templateName,
].filter(Boolean);
}, [compile, currentCollectionTitle, currentCollectionName, associationField, templateName]);
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 React from 'react';
import React, { useCallback } from 'react';
import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application';
import { useCollectionManager_deprecated } from '../../../../collection-manager';
import { useCollectionManager } from '../../../../data-source';
import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer';
import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection';
import { createDetailsWithPaginationUISchema } from './createDetailsWithPaginationUISchema';
@ -36,9 +36,8 @@ export const DetailsBlockInitializer = ({
showAssociationFields?: boolean;
hideChildrenIfSingleCollection?: boolean;
}) => {
const { insert } = useSchemaInitializer();
const { getCollection } = useCollectionManager_deprecated();
const itemConfig = useSchemaInitializerItem();
const { createDetailsBlock } = useCreateDetailsBlock();
return (
<DataBlockInitializer
{...itemConfig}
@ -49,18 +48,7 @@ export const DetailsBlockInitializer = ({
return createBlockSchema(options);
}
const { item } = 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);
createDetailsBlock(options);
}}
onlyCurrentDataSource={!!onlyCurrentDataSource}
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,
createBlockSchema,
componentType = 'FormItem',
templateWrap,
templateWrap: customizeTemplateWrap,
showAssociationFields,
hideChildrenIfSingleCollection,
hideOtherRecordsInPopup,
}: {
filterCollections: (options: { collection?: Collection; associationField?: CollectionFieldOptions }) => boolean;
onlyCurrentDataSource: boolean;
@ -33,25 +34,22 @@ export const FormBlockInitializer = ({
) => any;
showAssociationFields?: boolean;
hideChildrenIfSingleCollection?: boolean;
/**
* Other records
*/
hideOtherRecordsInPopup?: boolean;
}) => {
const { insert } = useSchemaInitializer();
const itemConfig = useSchemaInitializerItem();
const { isCusomeizeCreate } = itemConfig;
const { createFormBlock, templateWrap } = useCreateFormBlock();
const onCreateFormBlockSchema = useCallback(
({ item }) => {
(options) => {
if (createBlockSchema) {
return createBlockSchema({ item });
return createBlockSchema(options);
}
insert(
createCreateFormBlockUISchema({
collectionName: item.collectionName || item.name,
dataSource: item.dataSource,
isCusomeizeCreate,
}),
);
createFormBlock(options);
},
[createBlockSchema, insert, isCusomeizeCreate],
[createBlockSchema, createFormBlock],
);
return (
@ -59,21 +57,12 @@ export const FormBlockInitializer = ({
{...itemConfig}
icon={<FormOutlined />}
componentType={componentType}
templateWrap={(templateSchema, { item }) => {
if (templateWrap) {
return templateWrap(templateSchema, { item });
templateWrap={(templateSchema, options) => {
if (customizeTemplateWrap) {
return customizeTemplateWrap(templateSchema, options);
}
const schema = createCreateFormBlockUISchema({
isCusomeizeCreate,
dataSource: item.dataSource,
templateSchema: templateSchema,
collectionName: item.name,
});
if (item.template && item.mode === 'reference') {
schema['x-template-key'] = item.template.key;
}
return schema;
return templateWrap(templateSchema, options);
}}
onCreateBlockSchema={onCreateFormBlockSchema}
filter={filterCollections}
@ -81,6 +70,41 @@ export const FormBlockInitializer = ({
hideSearch={hideSearch}
showAssociationFields={showAssociationFields}
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 { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application';
import { useCollectionManager_deprecated } from '../../../../collection-manager';
import { createGridCardBlockSchema } from './createGridCardBlockSchema';
import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer';
import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection';
import { createGridCardBlockUISchema } from './createGridCardBlockUISchema';
export const GridCardBlockInitializer = ({
filterCollections,
@ -33,26 +33,19 @@ export const GridCardBlockInitializer = ({
) => any;
showAssociationFields?: boolean;
}) => {
const { insert } = useSchemaInitializer();
const { getCollection } = useCollectionManager_deprecated();
const itemConfig = useSchemaInitializerItem();
const { createGridCardBlock } = useCreateGridCardBlock();
return (
<DataBlockInitializer
{...itemConfig}
icon={<OrderedListOutlined />}
componentType={'GridCard'}
onCreateBlockSchema={async ({ item }) => {
onCreateBlockSchema={async (options) => {
if (createBlockSchema) {
return createBlockSchema({ item });
return createBlockSchema(options);
}
const collection = getCollection(item.name, item.dataSource);
const schema = createGridCardBlockSchema({
collectionName: item.name,
dataSource: item.dataSource,
rowKey: collection.filterTargetKey || 'id',
});
insert(schema);
createGridCardBlock(options);
}}
onlyCurrentDataSource={onlyCurrentDataSource}
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', () => {
test('should return the correct schema', () => {

View File

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

View File

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

View File

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

View File

@ -28,26 +28,19 @@ export const TableBlockInitializer = ({
) => any;
showAssociationFields?: boolean;
}) => {
const { insert } = useSchemaInitializer();
const { getCollection } = useCollectionManager_deprecated();
const { createTableBlock } = useCreateTableBlock();
const itemConfig = useSchemaInitializerItem();
return (
<DataBlockInitializer
{...itemConfig}
icon={<TableOutlined />}
componentType={'Table'}
onCreateBlockSchema={async ({ item }) => {
onCreateBlockSchema={async (options) => {
if (createBlockSchema) {
return createBlockSchema({ item });
return createBlockSchema(options);
}
const collection = getCollection(item.name, item.dataSource);
const schema = createTableBlockUISchema({
collectionName: item.name,
dataSource: item.dataSource,
rowKey: collection.filterTargetKey || 'id',
});
insert(schema);
createTableBlock(options);
}}
onlyCurrentDataSource={onlyCurrentDataSource}
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,
useCreateAssociationTableBlock,
useCreateEditFormBlock,
useCreateFormBlock,
useCreateTableBlock,
} from '../..';
import { CompatibleSchemaInitializer } from '../../application/schema-initializer/CompatibleSchemaInitializer';
import { useCreateDetailsBlock } from '../../modules/blocks/data-blocks/details-multi/DetailsBlockInitializer';
import { gridRowColWrap } from '../utils';
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) => {
if (!schema) return null;
@ -52,9 +58,13 @@ function useRecordBlocks() {
createAssociationDetailsWithoutPagination,
templateWrap: templateWrapOfAssociationDetailsWithoutPagination,
} = useCreateAssociationDetailsWithoutPagination();
const { createDetailsBlock } = useCreateDetailsBlock();
const collectionsNeedToDisplay = [currentCollection, ...collectionsWithView];
const createBlockSchema = useCallback(
({ item }) => {
({ item, fromOthersInPopup }) => {
if (fromOthersInPopup) {
return createDetailsBlock({ item });
}
if (item.associationField) {
if (['hasOne', 'belongsTo'].includes(item.associationField.type)) {
return createAssociationDetailsWithoutPagination({ item });
@ -63,7 +73,12 @@ function useRecordBlocks() {
}
return createSingleDetailsSchema({ item });
},
[createAssociationDetailsBlock, createAssociationDetailsWithoutPagination, createSingleDetailsSchema],
[
createAssociationDetailsBlock,
createAssociationDetailsWithoutPagination,
createDetailsBlock,
createSingleDetailsSchema,
],
);
return {
filterCollections({ collection, associationField }) {
@ -103,7 +118,7 @@ function useRecordBlocks() {
dataSource: collection.dataSource,
useComponentProps() {
const currentCollection = useCollection_deprecated();
const { createEditFormBlock, templateWrap } = useCreateEditFormBlock();
const { createEditFormBlock, templateWrap: templateWrapEdit } = useCreateEditFormBlock();
const collectionsNeedToDisplay = [currentCollection, ...collectionsWithView];
return {
@ -117,7 +132,8 @@ function useRecordBlocks() {
hideSearch: true,
componentType: 'FormItem',
createBlockSchema: createEditFormBlock,
templateWrap: templateWrap,
templateWrap: templateWrapEdit,
hideOtherRecordsInPopup: true,
showAssociationFields: true,
};
},
@ -133,6 +149,7 @@ function useRecordBlocks() {
dataSource: collection.dataSource,
useComponentProps() {
const { createAssociationFormBlock, templateWrap } = useCreateAssociationFormBlock();
const { createFormBlock, templateWrap: templateWrapCollection } = useCreateFormBlock();
return {
filterCollections({ collection, associationField }) {
if (associationField) {
@ -143,38 +160,29 @@ function useRecordBlocks() {
onlyCurrentDataSource: true,
hideSearch: true,
componentType: 'FormItem',
createBlockSchema: createAssociationFormBlock,
templateWrap: templateWrap,
createBlockSchema: ({ item, fromOthersInPopup }) => {
if (fromOthersInPopup) {
return createFormBlock({ item });
}
createAssociationFormBlock({ item });
},
templateWrap: (templateSchema, { item, fromOthersInPopup }) => {
if (fromOthersInPopup) {
return templateWrapCollection(templateSchema, { item });
}
templateWrap(templateSchema, { item });
},
showAssociationFields: true,
};
},
useVisible() {
const collection = useCollection();
return useMemo(
() =>
collection.fields.some(
(field) => canMakeAssociationBlock(field) && ['hasMany', 'belongsToMany'].includes(field.type),
),
[collection.fields],
);
},
},
{
name: 'table',
title: '{{t("Table")}}',
Component: 'TableBlockInitializer',
useVisible() {
const collection = useCollection();
return useMemo(
() =>
collection.fields.some(
(field) => canMakeAssociationBlock(field) && ['hasMany', 'belongsToMany'].includes(field.type),
),
[collection.fields],
);
},
useComponentProps() {
const { createAssociationTableBlock } = useCreateAssociationTableBlock();
const { createTableBlock } = useCreateTableBlock();
return {
hideSearch: true,
@ -185,7 +193,12 @@ function useRecordBlocks() {
}
return false;
},
createBlockSchema: createAssociationTableBlock,
createBlockSchema: ({ item, fromOthersInPopup }) => {
if (fromOthersInPopup) {
return createTableBlock({ item });
}
createAssociationTableBlock({ item });
},
showAssociationFields: true,
};
},
@ -194,18 +207,9 @@ function useRecordBlocks() {
name: 'list',
title: '{{t("List")}}',
Component: 'ListBlockInitializer',
useVisible() {
const collection = useCollection();
return useMemo(
() =>
collection.fields.some(
(field) => canMakeAssociationBlock(field) && ['hasMany', 'belongsToMany'].includes(field.type),
),
[collection.fields],
);
},
useComponentProps() {
const { createAssociationListBlock } = useCreateAssociationListBlock();
const { createListBlock } = useCreateListBlock();
return {
hideSearch: true,
@ -216,7 +220,12 @@ function useRecordBlocks() {
}
return false;
},
createBlockSchema: createAssociationListBlock,
createBlockSchema: ({ item, fromOthersInPopup }) => {
if (fromOthersInPopup) {
return createListBlock({ item });
}
createAssociationListBlock({ item });
},
showAssociationFields: true,
};
},
@ -225,18 +234,9 @@ function useRecordBlocks() {
name: 'gridCard',
title: '{{t("Grid Card")}}',
Component: 'GridCardBlockInitializer',
useVisible() {
const collection = useCollection();
return useMemo(
() =>
collection.fields.some(
(field) => canMakeAssociationBlock(field) && ['hasMany', 'belongsToMany'].includes(field.type),
),
[collection.fields],
);
},
useComponentProps() {
const { createAssociationGridCardBlock } = useCreateAssociationGridCardBlock();
const { createGridCardBlock } = useCreateGridCardBlock();
return {
hideSearch: true,
@ -247,7 +247,12 @@ function useRecordBlocks() {
}
return false;
},
createBlockSchema: createAssociationGridCardBlock,
createBlockSchema: ({ item, fromOthersInPopup }) => {
if (fromOthersInPopup) {
return createGridCardBlock({ item });
}
createAssociationGridCardBlock({ item });
},
showAssociationFields: true,
};
},

View File

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

View File

@ -5,7 +5,7 @@ import { useCollectionManager_deprecated } from '../../collection-manager';
import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '../../application';
import { useSchemaTemplateManager } from '../../schema-templates';
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
@ -30,7 +30,7 @@ export const RecordAssociationGridCardBlockInitializer = () => {
insert(s);
} else {
insert(
createGridCardBlockSchema({
createGridCardBlockUISchema({
rowKey: collection.filterTargetKey,
dataSource: collection.dataSource,
association: resource,
@ -53,7 +53,7 @@ export function useCreateAssociationGridCardBlock() {
const collection = getCollection(field.target);
insert(
createGridCardBlockSchema({
createGridCardBlockUISchema({
rowKey: collection.filterTargetKey,
dataSource: collection.dataSource,
association: `${field.collectionName}.${field.name}`,

View File

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

View File

@ -842,6 +842,7 @@ export const useCollectionDataSourceItems = ({
showAssociationFields,
filterDataSource,
dataBlockInitializerProps,
hideOtherRecordsInPopup,
}: {
componentName;
filter?: (options: { collection?: Collection; associationField?: CollectionFieldOptions }) => boolean;
@ -849,6 +850,10 @@ export const useCollectionDataSourceItems = ({
showAssociationFields?: boolean;
filterDataSource?: (dataSource?: DataSource) => boolean;
dataBlockInitializerProps?: any;
/**
* Other records
*/
hideOtherRecordsInPopup?: boolean;
}) => {
const { t } = useTranslation();
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;
const _associationRecords = associationFields.length ? associationRecords : null;
if (noAssociationMenu[0].children.length && associationFields.length) {
children = [currentRecord, associationRecords];
} else if (noAssociationMenu[0].children.length) {
// 当可选数据表只有一个时,实现只点击一次区块 menu 就能创建区块
if (noAssociationMenu[0].children.length <= 1) {
noAssociationMenu[0].children = (noAssociationMenu[0].children[0]?.children as any) || [];
return noAssociationMenu;
if (hideOtherRecordsInPopup) {
children = [currentRecord, _associationRecords];
} else {
children = [currentRecord, _associationRecords, otherRecords];
}
} 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 {
children = [associationRecords];
if (hideOtherRecordsInPopup) {
children = [_associationRecords];
} else {
children = [_associationRecords, otherRecords];
}
}
return [
@ -956,10 +998,19 @@ export const useCollectionDataSourceItems = ({
name: 'records',
label: t('Records'),
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;

View File

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

View File

@ -30,79 +30,19 @@ export const CalendarBlockInitializer = ({
createBlockSchema?: (options: any) => any;
showAssociationFields?: boolean;
}) => {
const { insert } = useSchemaInitializer();
const { t } = useTranslation();
const { getCollectionField, getCollectionFieldsOptions } = useCollectionManager_deprecated();
const options = useContext(SchemaOptionsContext);
const { theme } = useGlobalTheme();
const itemConfig = useSchemaInitializerItem();
const { createCalendarBlock } = useCreateCalendarBlock();
return (
<DataBlockInitializer
{...itemConfig}
componentType={'Calendar'}
icon={<FormOutlined />}
onCreateBlockSchema={async ({ item }) => {
onCreateBlockSchema={async (options) => {
if (createBlockSchema) {
return createBlockSchema({ item });
return createBlockSchema(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,
},
}),
);
createCalendarBlock(options);
}}
onlyCurrentDataSource={onlyCurrentDataSource}
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 };
};