diff --git a/packages/client/src/collection-manager/action-hooks.ts b/packages/client/src/collection-manager/action-hooks.ts index 824129f87..9e349f338 100644 --- a/packages/client/src/collection-manager/action-hooks.ts +++ b/packages/client/src/collection-manager/action-hooks.ts @@ -27,33 +27,45 @@ export const useCancelFilterAction = () => { }; export const useCollectionFilterOptions = (collectionName: string) => { - const { getCollection, getInterface } = useCollectionManager(); - const options = []; - const collection = getCollection(collectionName); - const fields = collection?.fields || []; + const { getCollectionFields, getInterface } = useCollectionManager(); + const fields = getCollectionFields(collectionName); const field2option = (field) => { if (!field.interface) { return; } const fieldInterface = getInterface(field.interface); - if (!fieldInterface.operators) { + if (!fieldInterface.filterable) { return; } + const { nested, children, operators } = fieldInterface.filterable; const option = { name: field.name, title: field?.uiSchema?.title || field.name, schema: field?.uiSchema, - operators: fieldInterface.operators || [], + operators: operators || [], }; + if (children?.length) { + option['children'] = children; + } + if (nested) { + const targetFields = getCollectionFields(field.target); + const options = getOptions(targetFields); + option['children'] = option['children'] || []; + option['children'].push(...options); + } return option; }; - fields.forEach((field) => { - const option = field2option(field); - if (option) { - options.push(option); - } - }); - return options; + const getOptions = (fields) => { + const options = []; + fields.forEach((field) => { + const option = field2option(field); + if (option) { + options.push(option); + } + }); + return options; + }; + return getOptions(fields); }; export const useFilterDataSource = (options) => { diff --git a/packages/client/src/collection-manager/hooks/useCollectionManager.ts b/packages/client/src/collection-manager/hooks/useCollectionManager.ts index 3471912b4..2c759ed85 100644 --- a/packages/client/src/collection-manager/hooks/useCollectionManager.ts +++ b/packages/client/src/collection-manager/hooks/useCollectionManager.ts @@ -15,6 +15,10 @@ export const useCollectionManager = () => { getCollection(name: string) { return collections?.find((collection) => collection.name === name); }, + getCollectionFields(name: string) { + const collection = collections?.find((collection) => collection.name === name); + return collection?.fields || []; + }, getInterface(name: string) { return interfaces[name] ? clone(interfaces[name]) : null; }, diff --git a/packages/client/src/collection-manager/interfaces/attachment.ts b/packages/client/src/collection-manager/interfaces/attachment.ts index 7b76dfc7d..5f227b137 100644 --- a/packages/client/src/collection-manager/interfaces/attachment.ts +++ b/packages/client/src/collection-manager/interfaces/attachment.ts @@ -48,4 +48,21 @@ export const attachment: IField = { default: true, }, }, + filterable: { + children: [ + { + name: 'filename', + title: '{{t("Filename")}}', + operators: [ + { label: 'empty', value: '$empty' }, + { label: 'notEmpty', value: '$notEmpty' }, + ], + schema: { + title: '{{t("Filename")}}', + type: 'string', + 'x-component': 'Input', + }, + }, + ], + }, }; diff --git a/packages/client/src/collection-manager/interfaces/checkbox.ts b/packages/client/src/collection-manager/interfaces/checkbox.ts index 1745b13cd..bc5480148 100644 --- a/packages/client/src/collection-manager/interfaces/checkbox.ts +++ b/packages/client/src/collection-manager/interfaces/checkbox.ts @@ -1,4 +1,4 @@ -import { defaultProps } from './properties'; +import { defaultProps, operators } from './properties'; import { IField } from './types'; export const checkbox: IField = { @@ -18,8 +18,7 @@ export const checkbox: IField = { properties: { ...defaultProps, }, - operators: [ - { label: '{{t("Yes")}}', value: '$isTruly', selected: true, noValue: true }, - { label: '{{t("No")}}', value: '$isFalsy', noValue: true }, - ], + filterable: { + operators: operators.boolean, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/checkboxGroup.ts b/packages/client/src/collection-manager/interfaces/checkboxGroup.ts index e90c10288..c652f7f5d 100644 --- a/packages/client/src/collection-manager/interfaces/checkboxGroup.ts +++ b/packages/client/src/collection-manager/interfaces/checkboxGroup.ts @@ -1,4 +1,4 @@ -import { dataSource, defaultProps } from './properties'; +import { dataSource, defaultProps, operators } from './properties'; import { IField } from './types'; export const checkboxGroup: IField = { @@ -20,4 +20,7 @@ export const checkboxGroup: IField = { ...defaultProps, 'uiSchema.enum': dataSource, }, + filterable: { + operators: operators.array, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/chinaRegion.ts b/packages/client/src/collection-manager/interfaces/chinaRegion.ts index 9c893a566..bef27a042 100644 --- a/packages/client/src/collection-manager/interfaces/chinaRegion.ts +++ b/packages/client/src/collection-manager/interfaces/chinaRegion.ts @@ -1,5 +1,5 @@ import { uid } from '@formily/shared'; -import { defaultProps } from './properties'; +import { defaultProps, operators } from './properties'; import { IField } from './types'; export const chinaRegion: IField = { @@ -74,5 +74,18 @@ export const chinaRegion: IField = { 'x-decorator': 'FormItem', }, }, - operators: [{ label: '{{t("is")}}', value: 'code.$in' }], + filterable: { + children: [ + { + name: 'name', + title: '名称', + operators: operators.string, + schema: { + title: '名称', + type: 'string', + 'x-component': 'Input', + }, + }, + ], + }, }; diff --git a/packages/client/src/collection-manager/interfaces/createdAt.ts b/packages/client/src/collection-manager/interfaces/createdAt.ts index 32ea73110..8d622cece 100644 --- a/packages/client/src/collection-manager/interfaces/createdAt.ts +++ b/packages/client/src/collection-manager/interfaces/createdAt.ts @@ -1,4 +1,4 @@ -import { dateTimeProps, defaultProps } from './properties'; +import { dateTimeProps, defaultProps, operators } from './properties'; import { IField } from './types'; export const createdAt: IField = { @@ -24,4 +24,7 @@ export const createdAt: IField = { ...defaultProps, ...dateTimeProps, }, + filterable: { + operators: operators.datetime, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/createdBy.ts b/packages/client/src/collection-manager/interfaces/createdBy.ts index f8446ddbc..55fdd592d 100644 --- a/packages/client/src/collection-manager/interfaces/createdBy.ts +++ b/packages/client/src/collection-manager/interfaces/createdBy.ts @@ -1,4 +1,4 @@ -import { defaultProps } from './properties'; +import { defaultProps, operators } from './properties'; import { IField } from './types'; export const createdBy: IField = { @@ -29,4 +29,18 @@ export const createdBy: IField = { properties: { ...defaultProps, }, + filterable: { + children: [ + { + name: 'nickname', + title: '{{t("Nickname")}}', + operators: operators.string, + schema: { + title: '{{t("Nickname")}}', + type: 'string', + 'x-component': 'Input', + }, + }, + ], + }, }; diff --git a/packages/client/src/collection-manager/interfaces/datetime.ts b/packages/client/src/collection-manager/interfaces/datetime.ts index 1c1edf2c5..8cc3d8b1a 100644 --- a/packages/client/src/collection-manager/interfaces/datetime.ts +++ b/packages/client/src/collection-manager/interfaces/datetime.ts @@ -1,4 +1,4 @@ -import { dateTimeProps, defaultProps } from './properties'; +import { dateTimeProps, defaultProps, operators } from './properties'; import { IField } from './types'; export const datetime: IField = { @@ -24,14 +24,7 @@ export const datetime: IField = { ...defaultProps, ...dateTimeProps, }, - operators: [ - { label: "{{ t('is') }}", value: '$dateOn', selected: true }, - { label: "{{ t('is not') }}", value: '$dateNotOn' }, - { label: "{{ t('is before') }}", value: '$dateBefore' }, - { label: "{{ t('is after') }}", value: '$dateAfter' }, - { label: "{{ t('is on or after') }}", value: '$dateNotBefore' }, - { label: "{{ t('is on or before') }}", value: '$dateNotAfter' }, - { label: "{{ t('is empty') }}", value: '$null', noValue: true }, - { label: "{{ t('is not empty') }}", value: '$notNull', noValue: true }, - ], + filterable: { + operators: operators.datetime, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/email.ts b/packages/client/src/collection-manager/interfaces/email.ts index 7cfe1dbd6..25c4ef687 100644 --- a/packages/client/src/collection-manager/interfaces/email.ts +++ b/packages/client/src/collection-manager/interfaces/email.ts @@ -1,5 +1,4 @@ -import { input } from './input'; -import { defaultProps } from './properties'; +import { defaultProps, operators } from './properties'; import { IField } from './types'; export const email: IField = { @@ -22,5 +21,7 @@ export const email: IField = { properties: { ...defaultProps, }, - operators: input.operators, + filterable: { + operators: operators.string, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/input.ts b/packages/client/src/collection-manager/interfaces/input.ts index feedabecb..b43999dd1 100644 --- a/packages/client/src/collection-manager/interfaces/input.ts +++ b/packages/client/src/collection-manager/interfaces/input.ts @@ -1,4 +1,4 @@ -import { defaultProps } from './properties'; +import { defaultProps, operators } from './properties'; import { IField } from './types'; export const input: IField = { @@ -19,12 +19,7 @@ export const input: IField = { properties: { ...defaultProps, }, - operators: [ - { label: '{{t("contains")}}', value: '$includes', selected: true }, - { label: '{{t("does not contain")}}', value: '$notIncludes' }, - { label: '{{t("is")}}', value: '$eq' }, - { label: '{{t("is not")}}', value: '$ne' }, - { label: '{{t("is empty")}}', value: '$empty', noValue: true }, - { label: '{{t("is not empty")}}', value: '$notEmpty', noValue: true }, - ], + filterable: { + operators: operators.string, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/linkTo.ts b/packages/client/src/collection-manager/interfaces/linkTo.ts index ff95b28e8..3dc3ee31f 100644 --- a/packages/client/src/collection-manager/interfaces/linkTo.ts +++ b/packages/client/src/collection-manager/interfaces/linkTo.ts @@ -69,4 +69,7 @@ export const linkTo: IField = { 'x-component': 'Checkbox', }, }, + filterable: { + nested: true, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/multipleSelect.ts b/packages/client/src/collection-manager/interfaces/multipleSelect.ts index 703423d07..8b99a8e69 100644 --- a/packages/client/src/collection-manager/interfaces/multipleSelect.ts +++ b/packages/client/src/collection-manager/interfaces/multipleSelect.ts @@ -1,4 +1,4 @@ -import { dataSource, defaultProps } from './properties'; +import { dataSource, defaultProps, operators } from './properties'; import { IField } from './types'; export const multipleSelect: IField = { @@ -26,29 +26,7 @@ export const multipleSelect: IField = { ...defaultProps, 'uiSchema.enum': dataSource, }, - operators: [ - { - label: '{{t("is")}}', - value: '$match', - selected: true, - schema: { 'x-component': 'Select' }, - }, - { - label: '{{t("is not")}}', - value: '$notMatch', - schema: { 'x-component': 'Select' }, - }, - { - label: '{{t("contains")}}', - value: '$anyOf', - schema: { 'x-component': 'Select' }, - }, - { - label: '{{t("does not contain")}}', - value: '$noneOf', - schema: { 'x-component': 'Select' }, - }, - { label: '{{t("is empty")}}', value: '$empty', noValue: true }, - { label: '{{t("is not empty")}}', value: '$notEmpty', noValue: true }, - ], + filterable: { + operators: operators.array, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/number.ts b/packages/client/src/collection-manager/interfaces/number.ts index 1b58d7064..eb5528bd2 100644 --- a/packages/client/src/collection-manager/interfaces/number.ts +++ b/packages/client/src/collection-manager/interfaces/number.ts @@ -1,4 +1,4 @@ -import { defaultProps } from './properties'; +import { defaultProps, operators } from './properties'; import { IField } from './types'; export const number: IField = { @@ -39,14 +39,7 @@ export const number: IField = { ], }, }, - operations: [ - { label: '{{t("=")}}', value: '$eq', selected: true }, - { label: '{{t("≠")}}', value: '$ne' }, - { label: '{{t(">")}}', value: '$gt' }, - { label: '{{t("≥")}}', value: '$gte' }, - { label: '{{t("<")}}', value: '$lt' }, - { label: '{{t("≤")}}', value: '$lte' }, - { label: '{{t("is empty")}}', value: '$null', noValue: true }, - { label: '{{t("is not empty")}}', value: '$notNull', noValue: true }, - ], + filterable: { + operators: operators.number, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/percent.ts b/packages/client/src/collection-manager/interfaces/percent.ts index feff8bc2e..1b1638017 100644 --- a/packages/client/src/collection-manager/interfaces/percent.ts +++ b/packages/client/src/collection-manager/interfaces/percent.ts @@ -1,5 +1,4 @@ -import { number } from './number'; -import { defaultProps } from './properties'; +import { defaultProps, operators } from './properties'; import { IField } from './types'; export const percent: IField = { @@ -43,5 +42,7 @@ export const percent: IField = { ], }, }, - operators: number.operators, + filterable: { + operators: operators.number, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/phone.ts b/packages/client/src/collection-manager/interfaces/phone.ts index 88b860494..b7aed25ba 100644 --- a/packages/client/src/collection-manager/interfaces/phone.ts +++ b/packages/client/src/collection-manager/interfaces/phone.ts @@ -1,5 +1,4 @@ -import { input } from './input'; -import { defaultProps } from './properties'; +import { defaultProps, operators } from './properties'; import { IField } from './types'; export const phone: IField = { @@ -24,5 +23,7 @@ export const phone: IField = { properties: { ...defaultProps, }, - operators: input.operators, + filterable: { + operators: operators.string, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/properties/index.ts b/packages/client/src/collection-manager/interfaces/properties/index.ts index e59cbf3af..c6713a578 100644 --- a/packages/client/src/collection-manager/interfaces/properties/index.ts +++ b/packages/client/src/collection-manager/interfaces/properties/index.ts @@ -196,3 +196,6 @@ export const defaultProps = { }, type, }; + + +export * as operators from './operators'; diff --git a/packages/client/src/collection-manager/interfaces/properties/operators.ts b/packages/client/src/collection-manager/interfaces/properties/operators.ts new file mode 100644 index 000000000..15c23e300 --- /dev/null +++ b/packages/client/src/collection-manager/interfaces/properties/operators.ts @@ -0,0 +1,100 @@ +export const string = [ + { label: '{{t("contains")}}', value: '$includes', selected: true }, + { label: '{{t("does not contain")}}', value: '$notIncludes' }, + { label: '{{t("is")}}', value: '$eq' }, + { label: '{{t("is not")}}', value: '$ne' }, + { label: '{{t("is empty")}}', value: '$empty', noValue: true }, + { label: '{{t("is not empty")}}', value: '$notEmpty', noValue: true }, +]; + +export const array = [ + { + label: '{{t("is")}}', + value: '$match', + selected: true, + schema: { 'x-component': 'Select' }, + }, + { + label: '{{t("is not")}}', + value: '$notMatch', + schema: { 'x-component': 'Select' }, + }, + { + label: '{{t("contains")}}', + value: '$anyOf', + schema: { 'x-component': 'Select' }, + }, + { + label: '{{t("does not contain")}}', + value: '$noneOf', + schema: { 'x-component': 'Select' }, + }, + { label: '{{t("is empty")}}', value: '$empty', noValue: true }, + { label: '{{t("is not empty")}}', value: '$notEmpty', noValue: true }, +]; + +export const datetime = [ + { label: "{{ t('is') }}", value: '$dateOn', selected: true }, + { label: "{{ t('is not') }}", value: '$dateNotOn' }, + { label: "{{ t('is before') }}", value: '$dateBefore' }, + { label: "{{ t('is after') }}", value: '$dateAfter' }, + { label: "{{ t('is on or after') }}", value: '$dateNotBefore' }, + { label: "{{ t('is on or before') }}", value: '$dateNotAfter' }, + { label: "{{ t('is empty') }}", value: '$null', noValue: true }, + { label: "{{ t('is not empty') }}", value: '$notNull', noValue: true }, +]; + +export const number = [ + { label: '{{t("=")}}', value: '$eq', selected: true }, + { label: '{{t("≠")}}', value: '$ne' }, + { label: '{{t(">")}}', value: '$gt' }, + { label: '{{t("≥")}}', value: '$gte' }, + { label: '{{t("<")}}', value: '$lt' }, + { label: '{{t("≤")}}', value: '$lte' }, + { label: '{{t("is empty")}}', value: '$empty', noValue: true }, + { label: '{{t("is not empty")}}', value: '$notEmpty', noValue: true }, +]; + +export const enumType = [ + { + label: '{{t("is")}}', + value: '$eq', + selected: true, + schema: { 'x-component': 'Select' }, + }, + { + label: '{{t("is not")}}', + value: '$ne', + schema: { 'x-component': 'Select' }, + }, + { + label: '{{t("contains")}}', + value: '$in', + schema: { + 'x-component': 'Select', + 'x-component-props': { mode: 'tags' }, + }, + }, + { + label: '{{t("does not contain")}}', + value: '$notIn', + schema: { + 'x-component': 'Select', + 'x-component-props': { mode: 'tags' }, + }, + }, + { label: '{{t("is empty")}}', value: '$empty', noValue: true }, + { label: '{{t("is not empty")}}', value: '$notEmpty', noValue: true }, +]; + +export const time = [ + { label: '{{t("is")}}', value: '$eq', selected: true }, + { label: '{{t("is not")}}', value: '$neq' }, + { label: '{{t("is empty")}}', value: '$null', noValue: true }, + { label: '{{t("is not empty")}}', value: '$notNull', noValue: true }, +]; + +export const boolean = [ + { label: '{{t("Yes")}}', value: '$isTruly', selected: true, noValue: true }, + { label: '{{t("No")}}', value: '$isFalsy', noValue: true }, +]; diff --git a/packages/client/src/collection-manager/interfaces/radioGroup.ts b/packages/client/src/collection-manager/interfaces/radioGroup.ts index 701981e96..ea784f853 100644 --- a/packages/client/src/collection-manager/interfaces/radioGroup.ts +++ b/packages/client/src/collection-manager/interfaces/radioGroup.ts @@ -1,5 +1,4 @@ -import { dataSource, defaultProps } from './properties'; -import { select } from './select'; +import { dataSource, defaultProps, operators } from './properties'; import { IField } from './types'; export const radioGroup: IField = { @@ -21,5 +20,7 @@ export const radioGroup: IField = { ...defaultProps, 'uiSchema.enum': dataSource, }, - operators: select.operators, + filterable: { + operators: operators.enumType, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/select.ts b/packages/client/src/collection-manager/interfaces/select.ts index 05d945976..a64a92d6b 100644 --- a/packages/client/src/collection-manager/interfaces/select.ts +++ b/packages/client/src/collection-manager/interfaces/select.ts @@ -1,4 +1,4 @@ -import { dataSource, defaultProps } from './properties'; +import { dataSource, defaultProps, operators } from './properties'; import { IField } from './types'; export const select: IField = { @@ -21,35 +21,7 @@ export const select: IField = { ...defaultProps, 'uiSchema.enum': dataSource, }, - operators: [ - { - label: '{{t("is")}}', - value: '$eq', - selected: true, - schema: { 'x-component': 'Select' }, - }, - { - label: '{{t("is not")}}', - value: '$ne', - schema: { 'x-component': 'Select' }, - }, - { - label: '{{t("contains")}}', - value: '$in', - schema: { - 'x-component': 'Select', - 'x-component-props': { mode: 'tags' }, - }, - }, - { - label: '{{t("does not contain")}}', - value: '$notIn', - schema: { - 'x-component': 'Select', - 'x-component-props': { mode: 'tags' }, - }, - }, - { label: '{{t("is empty")}}', value: '$empty', noValue: true }, - { label: '{{t("is not empty")}}', value: '$notEmpty', noValue: true }, - ], + filterable: { + operators: operators.enumType, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/subTable.ts b/packages/client/src/collection-manager/interfaces/subTable.ts index 645ec3762..6bc8813e3 100644 --- a/packages/client/src/collection-manager/interfaces/subTable.ts +++ b/packages/client/src/collection-manager/interfaces/subTable.ts @@ -9,7 +9,6 @@ export const subTable: IField = { order: 2, title: '{{t("Sub-table")}}', isAssociation: true, - disabled: true, default: { type: 'hasMany', // name, diff --git a/packages/client/src/collection-manager/interfaces/time.ts b/packages/client/src/collection-manager/interfaces/time.ts index 32cdde755..dfb91af5c 100644 --- a/packages/client/src/collection-manager/interfaces/time.ts +++ b/packages/client/src/collection-manager/interfaces/time.ts @@ -1,4 +1,4 @@ -import { defaultProps } from './properties'; +import { defaultProps, operators } from './properties'; import { IField } from './types'; export const time: IField = { @@ -36,10 +36,7 @@ export const time: IField = { ], }, }, - operators: [ - { label: '{{t("is")}}', value: '$eq', selected: true }, - { label: '{{t("is not")}}', value: '$neq' }, - { label: '{{t("is empty")}}', value: '$null', noValue: true }, - { label: '{{t("is not empty")}}', value: '$notNull', noValue: true }, - ], + filterable: { + operators: operators.time, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/types.ts b/packages/client/src/collection-manager/interfaces/types.ts index da7a83869..f0d8664af 100644 --- a/packages/client/src/collection-manager/interfaces/types.ts +++ b/packages/client/src/collection-manager/interfaces/types.ts @@ -9,5 +9,6 @@ interface IDefault { export interface IField extends ISchema { default?: IDefault; operators?: any[]; + filterable?: any, [key: string]: any; } diff --git a/packages/client/src/collection-manager/interfaces/updatedAt.ts b/packages/client/src/collection-manager/interfaces/updatedAt.ts index 57b237e60..5eb008706 100644 --- a/packages/client/src/collection-manager/interfaces/updatedAt.ts +++ b/packages/client/src/collection-manager/interfaces/updatedAt.ts @@ -1,5 +1,4 @@ -import { datetime } from './datetime'; -import { dateTimeProps, defaultProps } from './properties'; +import { dateTimeProps, defaultProps, operators } from './properties'; import { IField } from './types'; export const updatedAt: IField = { @@ -25,5 +24,7 @@ export const updatedAt: IField = { ...defaultProps, ...dateTimeProps, }, - operators: datetime.operators, + filterable: { + operators: operators.datetime, + }, }; diff --git a/packages/client/src/collection-manager/interfaces/updatedBy.ts b/packages/client/src/collection-manager/interfaces/updatedBy.ts index 11b587dd6..282103a26 100644 --- a/packages/client/src/collection-manager/interfaces/updatedBy.ts +++ b/packages/client/src/collection-manager/interfaces/updatedBy.ts @@ -1,4 +1,4 @@ -import { defaultProps } from './properties'; +import { defaultProps, operators } from './properties'; import { IField } from './types'; export const updatedBy: IField = { @@ -28,4 +28,18 @@ export const updatedBy: IField = { properties: { ...defaultProps, }, + filterable: { + children: [ + { + name: 'nickname', + title: '{{t("Nickname")}}', + operators: operators.string, + schema: { + title: '{{t("Nickname")}}', + type: 'string', + 'x-component': 'Input', + }, + }, + ], + }, };