feat(filterForm): add 'Allow multiple selection' for association fields (#5451)

* feat(filterForm): add 'Allow multiple selection' for association fields

* test: add e2e test
This commit is contained in:
Zeke Zhang 2024-10-18 12:42:35 +08:00 committed by GitHub
parent 32b3b76172
commit 988476ea3e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 501 additions and 54 deletions

View File

@ -840,5 +840,6 @@
"is none of": "is none of",
"is any of": "is any of",
"Plugin dependency version mismatch": "Plugin dependency version mismatch",
"The current dependency version of the plugin does not match the version of the application and may not work properly. Are you sure you want to continue enabling the plugin?": "The current dependency version of the plugin does not match the version of the application and may not work properly. Are you sure you want to continue enabling the plugin?"
"The current dependency version of the plugin does not match the version of the application and may not work properly. Are you sure you want to continue enabling the plugin?": "The current dependency version of the plugin does not match the version of the application and may not work properly. Are you sure you want to continue enabling the plugin?",
"Allow multiple selection": "Allow multiple selection"
}

View File

@ -765,5 +765,6 @@
"Expand All": "Expandir todo",
"Clear default value": "Borrar valor por defecto",
"Open in new window": "Abrir en una nueva ventana",
"Sorry, the page you visited does not exist.": "Lo siento, la página que visitaste no existe."
"Sorry, the page you visited does not exist.": "Lo siento, la página que visitaste no existe.",
"Allow multiple selection": "Permitir selección múltiple"
}

View File

@ -785,5 +785,6 @@
"Expand All": "Tout déplier",
"Clear default value": "Effacer la valeur par défaut",
"Open in new window": "Ouvrir dans une nouvelle fenêtre",
"Sorry, the page you visited does not exist.": "Désolé, la page que vous avez visitée n'existe pas."
"Sorry, the page you visited does not exist.": "Désolé, la page que vous avez visitée n'existe pas.",
"Allow multiple selection": "Permettre la sélection multiple"
}

View File

@ -1006,5 +1006,6 @@
"The current user only has the UI configuration permission, but don't have view permission for collection \"{{name}}\"": "現在のユーザーにはUI設定の権限しかなく、コレクション「{{name}}」を閲覧する権限はありません。",
"NaN": "なし",
"true": "真",
"false": "偽"
}
"false": "偽",
"Allow multiple selection": "複数選択を許可"
}

View File

@ -876,5 +876,6 @@
"Expand All": "모두 펼치기",
"Clear default value": "기본값 지우기",
"Open in new window": "새 창에서 열기",
"Sorry, the page you visited does not exist.": "죄송합니다. 방문한 페이지가 존재하지 않습니다."
"Sorry, the page you visited does not exist.": "죄송합니다. 방문한 페이지가 존재하지 않습니다.",
"Allow multiple selection": "다중 선택 허용"
}

View File

@ -742,5 +742,6 @@
"Current popup record": "Registro pop-up atual",
"Clear default value": "Limpar valor padrão",
"Open in new window": "Abrir em nova janela",
"Sorry, the page you visited does not exist.": "Desculpe, a página que você visitou não existe."
"Sorry, the page you visited does not exist.": "Desculpe, a página que você visitou não existe.",
"Allow multiple selection": "Permitir seleção múltipla"
}

View File

@ -579,5 +579,6 @@
"Expand All": "Развернуть все",
"Clear default value": "Очистить значение по умолчанию",
"Open in new window": "Открыть в новом окне",
"Sorry, the page you visited does not exist.": "Извините, посещенной вами страницы не существует."
"Sorry, the page you visited does not exist.": "Извините, посещенной вами страницы не существует.",
"Allow multiple selection": "Разрешить множественный выбор"
}

View File

@ -577,5 +577,6 @@
"Expand All": "Tümünü genişlet",
"Clear default value": "Varsayılan değeri temizle",
"Open in new window": "Yeni pencerede aç",
"Sorry, the page you visited does not exist.": "Üzgünüz, ziyaret ettiğiniz sayfa mevcut değil."
"Sorry, the page you visited does not exist.": "Üzgünüz, ziyaret ettiğiniz sayfa mevcut değil.",
"Allow multiple selection": "Çoklu seçim izni"
}

View File

@ -785,5 +785,6 @@
"Expand All": "Розгорнути все",
"Clear default value": "Очистити значення за замовчуванням",
"Open in new window": "Відкрити в новому вікні",
"Sorry, the page you visited does not exist.": "Вибачте, сторінка, яку ви відвідали, не існує."
"Sorry, the page you visited does not exist.": "Вибачте, сторінка, яку ви відвідали, не існує.",
"Allow multiple selection": "Дозволити множинний вибір"
}

View File

@ -974,5 +974,6 @@
"Skip getting the total number of table records during paging to speed up loading. It is recommended to enable this option for data tables with a large amount of data": "在分页时跳过获取表记录总数,以加快加载速度,建议对有大量数据的数据表开启此选项",
"The current user only has the UI configuration permission, but don't have view permission for collection \"{{name}}\"": "当前用户只有 UI 配置权限,但没有数据表 \"{{name}}\" 查看权限。",
"Plugin dependency version mismatch": "插件依赖版本不一致",
"The current dependency version of the plugin does not match the version of the application and may not work properly. Are you sure you want to continue enabling the plugin?": "当前插件的依赖版本与应用的版本不一致,可能无法正常工作。您确定要继续激活插件吗?"
"The current dependency version of the plugin does not match the version of the application and may not work properly. Are you sure you want to continue enabling the plugin?": "当前插件的依赖版本与应用的版本不一致,可能无法正常工作。您确定要继续激活插件吗?",
"Allow multiple selection": "允许多选"
}

View File

@ -874,5 +874,6 @@
"Expand All": "展開全部",
"Clear default value": "清除預設值",
"Open in new window": "新窗口打開",
"Sorry, the page you visited does not exist.": "抱歉,你訪問的頁面不存在。"
"Sorry, the page you visited does not exist.": "抱歉,你訪問的頁面不存在。",
"Allow multiple selection": "允許多選"
}

View File

@ -16,9 +16,16 @@ import { useApp } from '../../../../application';
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
import { useCollectionManager_deprecated, useCollection_deprecated } from '../../../../collection-manager';
import { useFieldComponentName } from '../../../../common/useFieldComponentName';
import { fieldComponentSettingsItem } from '../../../../data-source/commonsSettingsItem';
import { EditOperator, useDesignable, useValidateSchema } from '../../../../schema-component';
import { SchemaSettingsDefaultValue } from '../../../../schema-settings/SchemaSettingsDefaultValue';
import { fieldComponentSettingsItem } from '../../../../data-source/commonsSettingsItem';
const fieldComponentNameMap = (name: string) => {
if (name === 'Select') {
return 'FilterSelect';
}
return name;
};
export const filterFormItemFieldSettings = new SchemaSettings({
name: 'fieldSettings:FilterFormItem',
@ -347,7 +354,9 @@ export const filterFormItemFieldSettings = new SchemaSettings({
useChildren() {
const app = useApp();
const fieldComponentName = useFieldComponentName();
const componentSettings = app.schemaSettingsManager.get(`fieldSettings:component:${fieldComponentName}`);
const componentSettings = app.schemaSettingsManager.get(
`fieldSettings:component:${fieldComponentNameMap(fieldComponentName)}`,
);
return componentSettings?.items || [];
},
},

View File

@ -15,12 +15,12 @@ import { useFieldComponentName } from '../../../../common/useFieldComponentName'
import { useDesignable, useFieldModeOptions, useIsAddNewForm } from '../../../../schema-component';
import { isSubMode } from '../../../../schema-component/antd/association-field/util';
import {
useIsFieldReadPretty,
useIsAssociationField,
useIsFieldReadPretty,
} from '../../../../schema-component/antd/form-item/FormItem.Settings';
import { useColumnSchema } from '../../../../schema-component/antd/table-v2/Table.Column.Decorator';
import { allowMultiple } from '../Select/selectComponentFieldSettings';
import { useIsShowMultipleSwitch } from '../../../../schema-settings/hooks/useIsShowMultipleSwitch';
import { getAllowMultiple } from '../Select/selectComponentFieldSettings';
const fieldComponent: any = {
name: 'fieldComponent',
@ -183,7 +183,7 @@ export const fileManagerComponentFieldSettings = new SchemaSettings({
},
},
{
...allowMultiple,
...getAllowMultiple(),
useVisible() {
const isAssociationField = useIsAssociationField();
const IsShowMultipleSwitch = useIsShowMultipleSwitch();

View File

@ -120,43 +120,42 @@ const titleField: any = {
},
};
export const allowMultiple: any = {
name: 'allowMultiple',
type: 'switch',
useVisible() {
const isFieldReadPretty = useIsFieldReadPretty();
const collectionField = useCollectionField();
return !isFieldReadPretty && ['hasMany', 'belongsToMany'].includes(collectionField?.type);
},
useComponentProps() {
const { t } = useTranslation();
const field = useField<Field>();
const { fieldSchema: tableColumnSchema } = useColumnSchema();
const schema = useFieldSchema();
const fieldSchema = tableColumnSchema || schema;
const { dn, refresh } = useDesignable();
return {
title: t('Allow multiple'),
checked:
fieldSchema['x-component-props']?.multiple === undefined ? true : fieldSchema['x-component-props'].multiple,
onChange(value) {
const schema = {
['x-uid']: fieldSchema['x-uid'],
};
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
field.componentProps = field.componentProps || {};
export const getAllowMultiple = (params?: { title: string }) => {
const title = params?.title || 'Allow multiple';
fieldSchema['x-component-props'].multiple = value;
field.componentProps.multiple = value;
return {
name: 'allowMultiple',
type: 'switch',
useComponentProps() {
const { t } = useTranslation();
const field = useField<Field>();
const { fieldSchema: tableColumnSchema } = useColumnSchema();
const schema = useFieldSchema();
const fieldSchema = tableColumnSchema || schema;
const { dn, refresh } = useDesignable();
return {
title: t(title),
checked:
fieldSchema['x-component-props']?.multiple === undefined ? true : fieldSchema['x-component-props'].multiple,
onChange(value) {
const schema = {
['x-uid']: fieldSchema['x-uid'],
};
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
field.componentProps = field.componentProps || {};
schema['x-component-props'] = fieldSchema['x-component-props'];
dn.emit('patch', {
schema,
});
refresh();
},
};
},
fieldSchema['x-component-props'].multiple = value;
field.componentProps.multiple = value;
schema['x-component-props'] = fieldSchema['x-component-props'];
dn.emit('patch', {
schema,
});
refresh();
},
};
},
};
};
const quickCreate: any = {
@ -362,7 +361,7 @@ export const selectComponentFieldSettings = new SchemaSettings({
},
},
{
...allowMultiple,
...getAllowMultiple(),
useVisible() {
const isFieldReadPretty = useIsFieldReadPretty();
const isAssociationField = useIsAssociationField();
@ -383,3 +382,50 @@ export const selectComponentFieldSettings = new SchemaSettings({
},
],
});
/**
* Used for Select fields in filter form blocks
*/
export const filterSelectComponentFieldSettings = new SchemaSettings({
name: 'fieldSettings:component:FilterSelect',
items: [
{
...fieldComponent,
useVisible: useIsAssociationField,
},
{
...setTheDataScope,
useVisible() {
const isSelectFieldMode = useIsSelectFieldMode();
const isFieldReadPretty = useIsFieldReadPretty();
return isSelectFieldMode && !isFieldReadPretty;
},
},
{
...setDefaultSortingRules,
useComponentProps() {
const { fieldSchema } = useColumnSchema();
return {
fieldSchema,
};
},
useVisible() {
const isSelectFieldMode = useIsSelectFieldMode();
const isFieldReadPretty = useIsFieldReadPretty();
return isSelectFieldMode && !isFieldReadPretty;
},
},
getAllowMultiple({ title: 'Allow multiple selection' }),
{
...titleField,
useVisible: useIsAssociationField,
},
{
...enableLink,
useVisible() {
const readPretty = useIsFieldReadPretty();
return useIsAssociationField() && readPretty;
},
},
],
});

View File

@ -58,7 +58,10 @@ import { inputNumberComponentFieldSettings } from '../modules/fields/component/I
import { subformComponentFieldSettings } from '../modules/fields/component/Nester/subformComponentFieldSettings';
import { recordPickerComponentFieldSettings } from '../modules/fields/component/Picker/recordPickerComponentFieldSettings';
import { subformPopoverComponentFieldSettings } from '../modules/fields/component/PopoverNester/subformPopoverComponentFieldSettings';
import { selectComponentFieldSettings } from '../modules/fields/component/Select/selectComponentFieldSettings';
import {
filterSelectComponentFieldSettings,
selectComponentFieldSettings,
} from '../modules/fields/component/Select/selectComponentFieldSettings';
import { subTablePopoverComponentFieldSettings } from '../modules/fields/component/SubTable/subTablePopoverComponentFieldSettings';
import { tagComponentFieldSettings } from '../modules/fields/component/Tag/tagComponentFieldSettings';
import { unixTimestampComponentFieldSettings } from '../modules/fields/component/UnixTimestamp/unixTimestampComponentFieldSettings';
@ -108,6 +111,7 @@ export class SchemaSettingsPlugin extends Plugin {
// field component settings
this.schemaSettingsManager.add(selectComponentFieldSettings);
this.schemaSettingsManager.add(filterSelectComponentFieldSettings);
this.schemaSettingsManager.add(recordPickerComponentFieldSettings);
this.schemaSettingsManager.add(subformComponentFieldSettings);
this.schemaSettingsManager.add(subformPopoverComponentFieldSettings);

View File

@ -12422,6 +12422,360 @@ export const oneFilterFormBlockWithAllAssociationFields: PageConfig = {
},
};
/**
* v1.3.33-beta
* filter form
*/
export const oneFilterFormBlockWithAllAssociationFieldsV1333Beta: PageConfig = {
collections: generalWithAssociation,
pageSchema: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Page',
'x-index': 1,
properties: {
wwjstoiggum: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer': 'page:addBlock',
'x-index': 1,
properties: {
veez0d6lmes: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '1.3.33-beta',
properties: {
aoeb96c9io9: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '1.3.33-beta',
properties: {
bddrxac1sy8: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-decorator': 'FilterFormBlockProvider',
'x-use-decorator-props': 'useFilterFormBlockDecoratorProps',
'x-decorator-props': {
dataSource: 'main',
collection: 'general',
},
'x-toolbar': 'BlockSchemaToolbar',
'x-settings': 'blockSettings:filterForm',
'x-component': 'CardItem',
'x-filter-targets': [],
'x-app-version': '1.3.33-beta',
properties: {
ia80x2ee6jk: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'FormV2',
'x-use-component-props': 'useFilterFormBlockProps',
'x-app-version': '1.3.33-beta',
properties: {
grid: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer': 'filterForm:configureFields',
'x-app-version': '1.3.33-beta',
properties: {
osddczg4sa4: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '1.3.33-beta',
properties: {
'6smjnnnol7d': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '1.3.33-beta',
properties: {
oneToOneBelongsTo: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'string',
required: false,
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'fieldSettings:FilterFormItem',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-use-decorator-props': 'useFormItemProps',
'x-collection-field': 'general.oneToOneBelongsTo',
'x-component-props': {
multiple: false,
fieldNames: {
label: 'id',
value: 'id',
},
},
'x-app-version': '1.3.33-beta',
'x-uid': 'ru1rkpoj58o',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'rn702pnhtfr',
'x-async': false,
'x-index': 1,
},
},
'x-uid': '78o33btjnxv',
'x-async': false,
'x-index': 1,
},
rui9epb6050: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '1.3.33-beta',
properties: {
'91j7vnoy7kn': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '1.3.33-beta',
properties: {
oneToOneHasOne: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'string',
required: false,
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'fieldSettings:FilterFormItem',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-use-decorator-props': 'useFormItemProps',
'x-collection-field': 'general.oneToOneHasOne',
'x-component-props': {
multiple: false,
fieldNames: {
label: 'id',
value: 'id',
},
},
'x-app-version': '1.3.33-beta',
'x-uid': 'mflntqm2g5h',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'xmo1kdyv438',
'x-async': false,
'x-index': 1,
},
},
'x-uid': '5069bfzim4k',
'x-async': false,
'x-index': 2,
},
xljcz69cnra: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '1.3.33-beta',
properties: {
yxbfetadlnk: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '1.3.33-beta',
properties: {
oneToMany: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'string',
required: false,
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'fieldSettings:FilterFormItem',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-use-decorator-props': 'useFormItemProps',
'x-collection-field': 'general.oneToMany',
'x-component-props': {
multiple: true,
fieldNames: {
label: 'id',
value: 'id',
},
},
'x-app-version': '1.3.33-beta',
'x-uid': 'hfehr0sfzvf',
'x-async': false,
'x-index': 1,
},
},
'x-uid': '3pmxr13mgiz',
'x-async': false,
'x-index': 1,
},
},
'x-uid': '0rtq29eic2v',
'x-async': false,
'x-index': 3,
},
xbd07gapqj0: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '1.3.33-beta',
properties: {
'55v9zbubqcy': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '1.3.33-beta',
properties: {
manyToOne: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'string',
required: false,
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'fieldSettings:FilterFormItem',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-use-decorator-props': 'useFormItemProps',
'x-collection-field': 'general.manyToOne',
'x-component-props': {
multiple: false,
fieldNames: {
label: 'id',
value: 'id',
},
},
'x-app-version': '1.3.33-beta',
'x-uid': 'w0ugawa0dxk',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'vpkn40vetcq',
'x-async': false,
'x-index': 1,
},
},
'x-uid': '9x163mjqgix',
'x-async': false,
'x-index': 4,
},
'6mgr3hv8s7d': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '1.3.33-beta',
properties: {
ojxf20yrv33: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '1.3.33-beta',
properties: {
manyToMany: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'string',
required: false,
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'fieldSettings:FilterFormItem',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-use-decorator-props': 'useFormItemProps',
'x-collection-field': 'general.manyToMany',
'x-component-props': {
multiple: true,
fieldNames: {
label: 'id',
value: 'id',
},
},
'x-app-version': '1.3.33-beta',
'x-uid': 'klhocltvq6v',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'frzc0g87myc',
'x-async': false,
'x-index': 1,
},
},
'x-uid': '5mm4gyqqa90',
'x-async': false,
'x-index': 5,
},
},
'x-uid': '4ky8q78hske',
'x-async': false,
'x-index': 1,
},
z51e14s05s5: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-initializer': 'filterForm:configureActions',
'x-component': 'ActionBar',
'x-component-props': {
layout: 'one-column',
style: {
float: 'right',
},
},
'x-app-version': '1.3.33-beta',
'x-uid': 'whjwk4sh4no',
'x-async': false,
'x-index': 2,
},
},
'x-uid': '4pzmjj93o9l',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'v4k9k62avgb',
'x-async': false,
'x-index': 1,
},
},
'x-uid': '4sq6xto3yu9',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'mf2few2trjl',
'x-async': false,
'x-index': 2,
},
},
'x-uid': 'xb5aal7tne6',
'x-async': false,
},
},
'x-uid': 'n6tnlu0v6ct',
'x-async': true,
},
};
/**
* 1. Table
* 2. Add new Form

View File

@ -11,6 +11,7 @@ import {
expect,
expectSettingsMenu,
oneFilterFormBlockWithAllAssociationFields,
oneFilterFormBlockWithAllAssociationFieldsV1333Beta,
oneTableBlockWithAddNewAndViewAndEditAndAssociationFields,
test,
} from '@nocobase/test/e2e';
@ -38,6 +39,28 @@ test.describe('form item & filter form', () => {
],
});
});
test('v1.3: supported options', async ({ page, mockPage }) => {
const nocoPage = await mockPage(oneFilterFormBlockWithAllAssociationFieldsV1333Beta).waitForInit();
await nocoPage.goto();
await expectSettingsMenu({
page,
showMenu: async () => {
await page.getByLabel('block-item-CollectionField-general-filter-form-general.manyToOne-manyToOne').hover();
await page.getByRole('button', { name: 'designer-schema-settings-CollectionField' }).hover();
},
supportedOptions: [
'Edit field title',
'Edit description',
'Set the data scope',
'Field component',
'Title field',
'Delete',
'Allow multiple selection',
],
});
});
});
test.describe('table column & table', () => {