fix(kanban): fix incorrect appends parameter issue (#5592)

* refactor(kanban): optimize get appends function

* fix(kanban): fix incorrect appends parameter issue

* chore: remove useless code
This commit is contained in:
Zeke Zhang 2024-11-06 09:28:20 +08:00 committed by GitHub
parent ee1dd2375f
commit a6f16acf1c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 458 additions and 166 deletions

View File

@ -0,0 +1,248 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Schema } from '@formily/json-schema';
import { describe, expect, it } from 'vitest';
import { getAppends } from '../../hooks/index';
describe('getAppends', () => {
const mockGetCollectionJoinField = (name: string) => {
const fields = {
'users.profile': {
type: 'hasOne',
target: 'profiles',
},
'users.posts': {
type: 'hasMany',
target: 'posts',
},
'posts.author': {
type: 'belongsTo',
target: 'users',
},
'users.roles': {
type: 'belongsToMany',
target: 'roles',
},
'users.categories': {
type: 'belongsToArray',
target: 'categories',
},
};
return fields[name];
};
const mockGetCollection = (name: string) => {
const collections = {
categories: {
template: 'tree',
},
users: {
template: 'general',
},
};
return collections[name];
};
const createSchema = (properties) => {
return new Schema({
properties,
});
};
it('should handle basic association fields', () => {
const schema = createSchema({
profile: {
'x-component': 'Input',
'x-collection-field': 'users.profile',
name: 'profile',
},
});
const updateAssociationValues = new Set<string>();
const appends = new Set<string>();
getAppends({
schema,
prefix: '',
updateAssociationValues,
appends,
getCollectionJoinField: mockGetCollectionJoinField,
getCollection: mockGetCollection,
dataSource: 'main',
});
expect(Array.from(appends)).toEqual(['profile']);
expect(Array.from(updateAssociationValues)).toEqual([]);
});
it('should handle tree collection fields', () => {
const schema = createSchema({
categories: {
'x-component': 'Input',
'x-collection-field': 'users.categories',
name: 'categories',
},
});
const updateAssociationValues = new Set<string>();
const appends = new Set<string>();
getAppends({
schema,
prefix: '',
updateAssociationValues,
appends,
getCollectionJoinField: mockGetCollectionJoinField,
getCollection: mockGetCollection,
dataSource: 'main',
});
expect(Array.from(appends)).toEqual(['categories', 'categories.parent(recursively=true)']);
});
it('should handle nested fields with sorting', () => {
const schema = createSchema({
posts: {
'x-component': 'Input',
'x-collection-field': 'users.posts',
'x-component-props': {
sortArr: 'createdAt',
},
name: 'posts',
},
});
const updateAssociationValues = new Set<string>();
const appends = new Set<string>();
getAppends({
schema,
prefix: '',
updateAssociationValues,
appends,
getCollectionJoinField: mockGetCollectionJoinField,
getCollection: mockGetCollection,
dataSource: 'main',
});
expect(Array.from(appends)).toEqual(['posts(sort=createdAt)']);
});
it('should handle nested SubTable mode', () => {
const schema = createSchema({
posts: {
'x-component': 'Input',
'x-collection-field': 'users.posts',
'x-component-props': {
mode: 'SubTable',
},
name: 'posts',
properties: {
author: {
'x-component': 'Input',
'x-collection-field': 'posts.author',
name: 'author',
},
},
},
});
const updateAssociationValues = new Set<string>();
const appends = new Set<string>();
getAppends({
schema,
prefix: '',
updateAssociationValues,
appends,
getCollectionJoinField: mockGetCollectionJoinField,
getCollection: mockGetCollection,
dataSource: 'main',
});
expect(Array.from(appends)).toEqual(['posts', 'posts.author']);
expect(Array.from(updateAssociationValues)).toEqual(['posts']);
});
it('should ignore TableField components', () => {
const schema = createSchema({
posts: {
'x-component': 'TableField',
'x-collection-field': 'users.posts',
name: 'posts',
},
});
const updateAssociationValues = new Set<string>();
const appends = new Set<string>();
getAppends({
schema,
prefix: '',
updateAssociationValues,
appends,
getCollectionJoinField: mockGetCollectionJoinField,
getCollection: mockGetCollection,
dataSource: 'main',
});
expect(Array.from(appends)).toEqual([]);
expect(Array.from(updateAssociationValues)).toEqual([]);
});
it('should ignore Kanban.CardViewer components', () => {
const schema = createSchema({
cardViewer: {
'x-component': 'Kanban.CardViewer',
name: 'cardViewer',
properties: {
drawer: {
name: 'drawer',
type: 'void',
properties: {
grid: {
name: 'grid',
type: 'void',
properties: {
field1: {
'x-component': 'Input',
'x-collection-field': 'users.posts',
name: 'field1',
},
field2: {
'x-component': 'Input',
'x-collection-field': 'posts.author',
name: 'field2',
},
},
},
},
},
},
},
});
const updateAssociationValues = new Set<string>();
const appends = new Set<string>();
getAppends({
schema,
prefix: '',
updateAssociationValues,
appends,
getCollectionJoinField: mockGetCollectionJoinField,
getCollection: mockGetCollection,
dataSource: 'main',
});
expect(Array.from(appends)).toEqual([]);
expect(Array.from(updateAssociationValues)).toEqual([]);
});
});

View File

@ -35,7 +35,7 @@ import {
import { useAPIClient, useRequest } from '../../api-client'; import { useAPIClient, useRequest } from '../../api-client';
import { useNavigateNoUpdate } from '../../application/CustomRouterContextProvider'; import { useNavigateNoUpdate } from '../../application/CustomRouterContextProvider';
import { useFormBlockContext } from '../../block-provider/FormBlockProvider'; import { useFormBlockContext } from '../../block-provider/FormBlockProvider';
import { useCollectionManager_deprecated, useCollection_deprecated } from '../../collection-manager'; import { CollectionOptions, useCollectionManager_deprecated, useCollection_deprecated } from '../../collection-manager';
import { DataBlock, useFilterBlock } from '../../filter-provider/FilterProvider'; import { DataBlock, useFilterBlock } from '../../filter-provider/FilterProvider';
import { mergeFilter, transformToFilter } from '../../filter-provider/utils'; import { mergeFilter, transformToFilter } from '../../filter-provider/utils';
import { useTreeParentRecord } from '../../modules/blocks/data-blocks/table/TreeRecordProvider'; import { useTreeParentRecord } from '../../modules/blocks/data-blocks/table/TreeRecordProvider';
@ -1494,14 +1494,25 @@ export function getAssociationPath(str) {
return str; return str;
} }
export const useAssociationNames = (dataSource?: string) => { export const getAppends = ({
let updateAssociationValues = new Set([]); schema,
let appends = new Set([]); prefix: defaultPrefix,
const { getCollectionJoinField, getCollection } = useCollectionManager_deprecated(dataSource); updateAssociationValues,
const fieldSchema = useFieldSchema(); appends,
const _getAssociationAppends = (schema, str) => { getCollectionJoinField,
getCollection,
dataSource,
}: {
schema: any;
prefix: string;
updateAssociationValues: Set<string>;
appends: Set<string>;
getCollectionJoinField: (name: string, dataSource: string) => any;
getCollection: (name: any, customDataSource?: string) => CollectionOptions;
dataSource: string;
}) => {
schema.reduceProperties((pre, s) => { schema.reduceProperties((pre, s) => {
const prefix = pre || str; const prefix = pre || defaultPrefix;
const collectionField = s['x-collection-field'] && getCollectionJoinField(s['x-collection-field'], dataSource); const collectionField = s['x-collection-field'] && getCollectionJoinField(s['x-collection-field'], dataSource);
const isAssociationSubfield = s.name.includes('.'); const isAssociationSubfield = s.name.includes('.');
const isAssociationField = const isAssociationField =
@ -1534,8 +1545,10 @@ export const useAssociationNames = (dataSource?: string) => {
collectAppends(condition); collectAppends(condition);
}); });
} }
const isTreeCollection = const isTreeCollection =
isAssociationField && getCollection(collectionField.target, dataSource)?.template === 'tree'; isAssociationField && getCollection(collectionField.target, dataSource)?.template === 'tree';
if (collectionField && (isAssociationField || isAssociationSubfield) && s['x-component'] !== 'TableField') { if (collectionField && (isAssociationField || isAssociationSubfield) && s['x-component'] !== 'TableField') {
const fieldPath = !isAssociationField && isAssociationSubfield ? getAssociationPath(s.name) : s.name; const fieldPath = !isAssociationField && isAssociationSubfield ? getAssociationPath(s.name) : s.name;
const path = prefix === '' || !prefix ? fieldPath : prefix + '.' + fieldPath; const path = prefix === '' || !prefix ? fieldPath : prefix + '.' + fieldPath;
@ -1550,10 +1563,18 @@ export const useAssociationNames = (dataSource?: string) => {
appends.add(path); appends.add(path);
} }
} }
if (['Nester', 'SubTable', 'PopoverNester'].includes(s['x-component-props']?.mode)) { if (isSubMode(s)) {
updateAssociationValues.add(path); updateAssociationValues.add(path);
const bufPrefix = prefix && prefix !== '' ? prefix + '.' + s.name : s.name; const bufPrefix = prefix && prefix !== '' ? prefix + '.' + s.name : s.name;
_getAssociationAppends(s, bufPrefix); getAppends({
schema: s,
prefix: bufPrefix,
updateAssociationValues,
appends,
getCollectionJoinField,
getCollection,
dataSource,
});
} }
} else if ( } else if (
![ ![
@ -1567,17 +1588,43 @@ export const useAssociationNames = (dataSource?: string) => {
'AssociationField.Selector', 'AssociationField.Selector',
'AssociationField.AddNewer', 'AssociationField.AddNewer',
'TableField', 'TableField',
'Kanban.CardViewer',
].includes(s['x-component']) ].includes(s['x-component'])
) { ) {
_getAssociationAppends(s, str); getAppends({
schema: s,
prefix: defaultPrefix,
updateAssociationValues,
appends,
getCollectionJoinField,
getCollection,
dataSource,
});
} }
}, str); }, defaultPrefix);
}; };
export const useAssociationNames = (dataSource?: string) => {
const { getCollectionJoinField, getCollection } = useCollectionManager_deprecated(dataSource);
const fieldSchema = useFieldSchema();
const getAssociationAppends = () => { const getAssociationAppends = () => {
updateAssociationValues = new Set([]); const updateAssociationValues = new Set([]);
appends = new Set([]); let appends = new Set([]);
_getAssociationAppends(fieldSchema, '');
getAppends({
schema: fieldSchema,
prefix: '',
updateAssociationValues,
appends,
getCollectionJoinField,
getCollection,
dataSource,
});
appends = fillParentFields(appends); appends = fillParentFields(appends);
console.log('appends', appends);
return { appends: [...appends], updateAssociationValues: [...updateAssociationValues] }; return { appends: [...appends], updateAssociationValues: [...updateAssociationValues] };
}; };

View File

@ -10,17 +10,17 @@
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { FormLayout } from '@formily/antd-v5'; import { FormLayout } from '@formily/antd-v5';
import { createForm } from '@formily/core'; import { createForm } from '@formily/core';
import { observer, RecursionField, useFieldSchema } from '@formily/react'; import { RecursionField, useFieldSchema } from '@formily/react';
import { import {
DndContext, DndContext,
FormProvider, FormProvider,
getCardItemSchema,
PopupContextProvider, PopupContextProvider,
useCollection, useCollection,
useCollectionRecordData, useCollectionRecordData,
usePopupSettings, usePopupSettings,
usePopupUtils, usePopupUtils,
VariablePopupRecordProvider, VariablePopupRecordProvider,
getCardItemSchema,
} from '@nocobase/client'; } from '@nocobase/client';
import { Schema } from '@nocobase/utils'; import { Schema } from '@nocobase/utils';
import { Card } from 'antd'; import { Card } from 'antd';
@ -68,8 +68,7 @@ const cardCss = css`
const MemorizedRecursionField = React.memo(RecursionField); const MemorizedRecursionField = React.memo(RecursionField);
MemorizedRecursionField.displayName = 'MemorizedRecursionField'; MemorizedRecursionField.displayName = 'MemorizedRecursionField';
export const KanbanCard: any = observer( export const KanbanCard: any = () => {
() => {
const collection = useCollection(); const collection = useCollection();
const { setDisableCardDrag } = useContext(KanbanCardContext) || {}; const { setDisableCardDrag } = useContext(KanbanCardContext) || {};
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
@ -157,9 +156,7 @@ export const KanbanCard: any = observer(
</PopupContextProvider> </PopupContextProvider>
</> </>
); );
}, };
{ displayName: 'KanbanCard' },
);
function getPopupSchemaFromParent(fieldSchema: Schema) { function getPopupSchemaFromParent(fieldSchema: Schema) {
if (fieldSchema.parent?.properties?.cardViewer?.properties?.drawer) { if (fieldSchema.parent?.properties?.cardViewer?.properties?.drawer) {