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

View File

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