From 9b405b4b9d1187d7dee91e6066713fb274195852 Mon Sep 17 00:00:00 2001 From: wjh Date: Wed, 27 Mar 2024 16:49:56 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=8A=8AremoteSelect=E5=92=8CSelect?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E5=90=88=E5=B9=B6=E5=88=B0=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=20(#499)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://git.daoyoucloud.com/daoyoucloud/tachycode/pulls/499 Co-authored-by: wjh Co-committed-by: wjh --- .../association-field/AssociationSelect.tsx | 5 +- .../antd/remote-select/RemoteSelect.tsx | 2 +- .../antd/select/FormulaSelect.tsx} | 121 ++------ .../schema-component/antd/select/Select.tsx | 4 + .../hooks/useFilterBlockActionProps.tsx | 1 + .../@hera/plugin-core/src/client/index.tsx | 12 +- .../src/client/schema-components/index.ts | 2 - .../remote-select/ReadPretty.tsx | 42 --- .../remote-select/RemoteSelect.tsx | 279 ------------------ .../schema-components/remote-select/index.md | 28 -- .../schema-components/remote-select/index.ts | 1 - .../schema-components/remote-select/shared.ts | 7 - .../schema-components/select/ReadPretty.tsx | 36 --- .../client/schema-components/select/index.md | 37 --- .../client/schema-components/select/index.ts | 2 - .../client/schema-components/select/utils.ts | 54 ---- .../items/CustomFilterFormItemInitializer.tsx | 8 +- .../schema-settings/SchemaSettingsRemove.tsx | 4 +- 18 files changed, 45 insertions(+), 600 deletions(-) rename packages/{plugins/@hera/plugin-core/src/client/schema-components/select/Select.tsx => core/client/src/schema-component/antd/select/FormulaSelect.tsx} (68%) delete mode 100644 packages/plugins/@hera/plugin-core/src/client/schema-components/remote-select/ReadPretty.tsx delete mode 100644 packages/plugins/@hera/plugin-core/src/client/schema-components/remote-select/RemoteSelect.tsx delete mode 100644 packages/plugins/@hera/plugin-core/src/client/schema-components/remote-select/index.md delete mode 100644 packages/plugins/@hera/plugin-core/src/client/schema-components/remote-select/index.ts delete mode 100644 packages/plugins/@hera/plugin-core/src/client/schema-components/remote-select/shared.ts delete mode 100644 packages/plugins/@hera/plugin-core/src/client/schema-components/select/ReadPretty.tsx delete mode 100644 packages/plugins/@hera/plugin-core/src/client/schema-components/select/index.md delete mode 100644 packages/plugins/@hera/plugin-core/src/client/schema-components/select/index.ts delete mode 100644 packages/plugins/@hera/plugin-core/src/client/schema-components/select/utils.ts diff --git a/packages/core/client/src/schema-component/antd/association-field/AssociationSelect.tsx b/packages/core/client/src/schema-component/antd/association-field/AssociationSelect.tsx index 250dc7432..54fdb617a 100644 --- a/packages/core/client/src/schema-component/antd/association-field/AssociationSelect.tsx +++ b/packages/core/client/src/schema-component/antd/association-field/AssociationSelect.tsx @@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next'; import { RecordProvider, useAPIClient, useApp, useCollectionRecordData } from '../../../'; import { isVariable } from '../../../variables/utils/isVariable'; import { getInnermostKeyAndValue } from '../../common/utils/uitls'; -import { RemoteSelectProps } from '../remote-select'; +import { RemoteSelectProps, RemoteSelect } from '../remote-select'; import useServiceOptions, { useAssociationFieldContext } from './hooks'; export type AssociationSelectProps

= RemoteSelectProps

& { @@ -60,8 +60,6 @@ const InternalAssociationSelect = observer( const resource = api.resource(collectionField.target); const linkageFields = filterAnalyses(field.componentProps?.service?.params?.filter); const recordData = useCollectionRecordData(); - const app = useApp(); - const RemoteSelect = useMemo(() => app.getComponent('RemoteSelect'), [app]); useEffect(() => { const initValue = isVariable(field.value) ? undefined : field.value; @@ -169,7 +167,6 @@ export const AssociationSelectReadPretty = connect( (props: any) => { const service = useServiceOptions(props); const app = useApp(); - const RemoteSelect = useMemo(() => app.getComponent('RemoteSelect'), [app]) as any; if (props.fieldNames) { return ; } diff --git a/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx b/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx index 03c0684e0..25601c2be 100644 --- a/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx +++ b/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx @@ -136,7 +136,7 @@ const InternalRemoteSelect = connect( ...service, headers, params: { - pageSize: 200, + pageSize: fieldNames['formula'] ? 9999 : 200, ...service?.params, filter: service?.params?.filter, }, diff --git a/packages/plugins/@hera/plugin-core/src/client/schema-components/select/Select.tsx b/packages/core/client/src/schema-component/antd/select/FormulaSelect.tsx similarity index 68% rename from packages/plugins/@hera/plugin-core/src/client/schema-components/select/Select.tsx rename to packages/core/client/src/schema-component/antd/select/FormulaSelect.tsx index 132205679..4b49e9d53 100644 --- a/packages/plugins/@hera/plugin-core/src/client/schema-components/select/Select.tsx +++ b/packages/core/client/src/schema-component/antd/select/FormulaSelect.tsx @@ -1,12 +1,11 @@ -import { CloseCircleFilled, CloseOutlined, LoadingOutlined } from '@ant-design/icons'; -import { connect, mapProps, mapReadPretty, useFieldSchema, useForm } from '@formily/react'; +import { CloseCircleFilled, CloseOutlined } from '@ant-design/icons'; +import { useFieldSchema, useForm } from '@formily/react'; import { isValid, toArr } from '@formily/shared'; import { isPlainObject } from '@nocobase/utils/client'; import type { SelectProps } from 'antd'; import { Select as AntdSelect, Empty, Spin, Tag } from 'antd'; import React, { useEffect, useMemo, useState } from 'react'; -import { ReadPretty } from './ReadPretty'; -import { FieldNames, defaultFieldNames, getCurrentOptions } from './utils'; +import { FieldNames, getCurrentOptions } from './utils'; import { useAPIClient, useCollection_deprecated, useRequest } from '@nocobase/client'; import { useAsyncEffect } from 'ahooks'; @@ -21,7 +20,7 @@ type Props = SelectProps & { const isEmptyObject = (val: any) => !isValid(val) || (typeof val === 'object' && Object.keys(val).length === 0); const ObjectSelect = (props: Props) => { - const { value, options, onChange, fieldNames, mode, loading, rawOptions, defaultValue, ...others } = props; + const { value, options, onChange, mode, fieldNames, loading, rawOptions, defaultValue, ...others } = props; const [defoptions, setDefOptions] = useState(); const fieldSchema = useFieldSchema(); const collectionName = fieldSchema['collectionName']; @@ -45,6 +44,12 @@ const ObjectSelect = (props: Props) => { setDefOptions(changOptions); } }, [filterField?.filter, collectionName]); + useEffect(() => { + if (collectionName && fieldSchema['name'].toString().includes('custom') && defaultValue) { + const name = fieldSchema['name'].toString().split('.')[1]; + form.values['custom'][name] = defaultValue?.[fieldNames.value]; + } + }, []); const toValue = (v: any) => { if (isEmptyObject(v)) { return; @@ -107,7 +112,7 @@ const ObjectSelect = (props: Props) => { } else { onChange?.(current.shift() || null); } - if (collectionName) { + if (collectionName && fieldSchema['name'].toString().includes('custom')) { const name = fieldSchema['name'].toString().split('.')[1]; form.values['custom'][name] = changed?.['value']; } @@ -131,8 +136,6 @@ const ObjectSelect = (props: Props) => { ); }; -const filterOption = (input, option) => (option?.label ?? '').toLowerCase().includes((input || '').toLowerCase()); - const replacePlaceholders = (inputStr, values) => { return inputStr.replace(/{{(.*?)}}/g, function (match, placeholder) { return Object.prototype.hasOwnProperty.call(values, placeholder) ? values[placeholder] : match; @@ -200,89 +203,25 @@ const useLabelOptions = (others) => { } return others; }; -const InternalSelect = connect( - (props: Props) => { - const { objectValue, loading, value, rawOptions, defaultValue, ...others } = props; - let mode: any = props.multiple ? 'multiple' : props.mode; - if (mode && !['multiple', 'tags'].includes(mode)) { - mode = undefined; - } - const modifiedProps = useLabelOptions(others); - if (objectValue) { - return ( - - ); - } - const toValue = (v) => { - if (['tags', 'multiple'].includes(props.mode) || props.multiple) { - if (v) { - return toArr(v); - } - return undefined; - } - return v; - }; - return ( - , - }} - popupMatchSelectWidth={false} - notFoundContent={loading ? : } - value={toValue(value)} - defaultValue={toValue(defaultValue)} - tagRender={(props) => { - return ( - // @ts-ignore - } - {...props} - > - {props.label} - - ); - }} - {...others} - onChange={(changed) => { - props.onChange?.(changed === undefined ? null : changed); - }} - mode={mode} - /> - ); - }, - mapProps( - { - dataSource: 'options', - }, - (props, field) => { - return { - ...props, - fieldNames: { ...defaultFieldNames, ...props.fieldNames }, - suffixIcon: field?.['loading'] || field?.['validating'] ? : props.suffixIcon, - }; - }, - ), - mapReadPretty(ReadPretty), -); -export const Select = InternalSelect as unknown as typeof InternalSelect & { - ReadPretty: typeof ReadPretty; +const FormulaSelect = (props) => { + const { objectValue, loading, value, rawOptions, defaultValue, ...others } = props; + let mode: any = props.multiple ? 'multiple' : props.mode; + if (mode && !['multiple', 'tags'].includes(mode)) { + mode = undefined; + } + const modifiedProps = useLabelOptions(others); + + return ( + + ); }; -Select.ReadPretty = ReadPretty; - -export default Select; +export default FormulaSelect; diff --git a/packages/core/client/src/schema-component/antd/select/Select.tsx b/packages/core/client/src/schema-component/antd/select/Select.tsx index 3d9784817..a1473336a 100644 --- a/packages/core/client/src/schema-component/antd/select/Select.tsx +++ b/packages/core/client/src/schema-component/antd/select/Select.tsx @@ -7,6 +7,7 @@ import { Select as AntdSelect, Empty, Spin, Tag } from 'antd'; import React from 'react'; import { ReadPretty } from './ReadPretty'; import { FieldNames, defaultFieldNames, getCurrentOptions } from './utils'; +import FormulaSelect from './FormulaSelect'; type Props = SelectProps & { objectValue?: boolean; @@ -103,6 +104,9 @@ const InternalSelect = connect( if (mode && !['multiple', 'tags'].includes(mode)) { mode = undefined; } + if ('formula' in others.fieldNames || 'collection' in props) { + return ; + } if (objectValue) { return ( { const flatValue = flat.unflatten(values); const flatFieldSchema = flat.unflatten(filterSchemaItem); flatValue['$and'] = flatValue['$and']?.filter(Boolean); + flatFieldSchema['$and'] = flatFieldSchema['$and']?.filter(Boolean); return { $and: [flatValue, flatFieldSchema], }; diff --git a/packages/plugins/@hera/plugin-core/src/client/index.tsx b/packages/plugins/@hera/plugin-core/src/client/index.tsx index e0c8b0c2f..031df1986 100644 --- a/packages/plugins/@hera/plugin-core/src/client/index.tsx +++ b/packages/plugins/@hera/plugin-core/src/client/index.tsx @@ -43,15 +43,7 @@ import { GroupBlockConfigure, SignatureInput, } from './components'; -import { - AutoComplete, - DatePicker, - GroupBlock, - InternalPDFViewer, - MenuDesigner, - RemoteSelect, - Select, -} from './schema-components'; +import { AutoComplete, DatePicker, GroupBlock, InternalPDFViewer, MenuDesigner } from './schema-components'; import { CreateSubmitActionInitializer, FilterFormItem, @@ -186,8 +178,6 @@ export class PluginCoreClient extends Plugin { PDFViewerProvider, PDFViwer: InternalPDFViewer, PageLayout, - RemoteSelect, - Select, SettingBlock: SettingBlockInitializer, SheetBlock, SheetBlockInitializer, diff --git a/packages/plugins/@hera/plugin-core/src/client/schema-components/index.ts b/packages/plugins/@hera/plugin-core/src/client/schema-components/index.ts index 5d363e12e..1547cd072 100644 --- a/packages/plugins/@hera/plugin-core/src/client/schema-components/index.ts +++ b/packages/plugins/@hera/plugin-core/src/client/schema-components/index.ts @@ -3,5 +3,3 @@ export * from './blocks/GroupBlock'; export * from './blocks/PDFViewer'; export * from './date-picker'; export * from './deprecated/ExtendedMenuDesigner'; -export * from './remote-select'; -export * from './select/Select'; diff --git a/packages/plugins/@hera/plugin-core/src/client/schema-components/remote-select/ReadPretty.tsx b/packages/plugins/@hera/plugin-core/src/client/schema-components/remote-select/ReadPretty.tsx deleted file mode 100644 index 46dafa37e..000000000 --- a/packages/plugins/@hera/plugin-core/src/client/schema-components/remote-select/ReadPretty.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { observer, useField, useFieldSchema } from '@formily/react'; -import React from 'react'; -import { getValues } from './shared'; -import { defaultFieldNames, useActionContext, useRecord, useRequest } from '@nocobase/client'; -import { Select } from '../select'; - -export const ReadPretty = observer( - (props: any) => { - const fieldNames = { ...defaultFieldNames, ...props.fieldNames }; - const field = useField(); - const fieldSchema = useFieldSchema(); - const record = useRecord(); - const { snapshot } = useActionContext(); - - const { data } = useRequest<{ - data: any[]; - }>( - snapshot - ? async () => ({ - data: record[fieldSchema.name], - }) - : { - action: 'list', - ...props.service, - params: { - paginate: false, - filter: { - [fieldNames.value]: { - $in: getValues(field.value, fieldNames), - }, - }, - }, - }, - { - refreshDeps: [props.service, field.value], - }, - ); - - return ; - }, - { displayName: 'ReadPretty' }, -); diff --git a/packages/plugins/@hera/plugin-core/src/client/schema-components/remote-select/RemoteSelect.tsx b/packages/plugins/@hera/plugin-core/src/client/schema-components/remote-select/RemoteSelect.tsx deleted file mode 100644 index 4ce9dc36b..000000000 --- a/packages/plugins/@hera/plugin-core/src/client/schema-components/remote-select/RemoteSelect.tsx +++ /dev/null @@ -1,279 +0,0 @@ -import { LoadingOutlined } from '@ant-design/icons'; -import { connect, mapProps, mapReadPretty, useFieldSchema } from '@formily/react'; -import { Divider, SelectProps, Tag } from 'antd'; -import dayjs from 'dayjs'; -import { uniqBy } from 'lodash'; -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { ReadPretty } from './ReadPretty'; -import { - defaultFieldNames, - mergeFilter, - useCollection_deprecated, - useCollectionManager_deprecated, - useCompile, - useRequest, -} from '@nocobase/client'; -import { Select } from '../select'; -const EMPTY = 'N/A'; - -export type ResourceActionOptions

= { - resource?: string; - resourceOf?: any; - action?: string; - params?: P; -}; - -export type RemoteSelectProps

= SelectProps & { - objectValue?: boolean; - onChange?: (v: any) => void; - target: string; - wait?: number; - manual?: boolean; - mapOptions?: (data: any) => RemoteSelectProps['fieldNames']; - targetField?: any; - service: ResourceActionOptions

; - CustomDropdownRender?: (v: any) => any; -}; - -const InternalRemoteSelect = connect( - (props: RemoteSelectProps) => { - const { - fieldNames = {}, - service = {}, - wait = 300, - value, - defaultValue, - objectValue, - manual = true, - mapOptions, - targetField: _targetField, - CustomDropdownRender, - ...others - } = props; - const [open, setOpen] = useState(false); - const firstRun = useRef(false); - const fieldSchema = useFieldSchema(); - const isQuickAdd = fieldSchema['x-component-props']?.addMode === 'quickAdd'; - const { getField } = useCollection_deprecated(); - const searchData = useRef(null); - const { getCollectionJoinField, getInterface } = useCollectionManager_deprecated(); - const collectionField = getField(fieldSchema.name) || getCollectionJoinField(fieldSchema.name as string); - const targetField = - _targetField || - (collectionField?.target && - fieldNames?.label && - getCollectionJoinField(`${collectionField.target}.${fieldNames.label}`)); - - const operator = useMemo(() => { - if (targetField?.interface) { - return getInterface(targetField.interface)?.filterable?.operators?.[0]?.value || '$includes'; - } - return '$includes'; - }, [targetField]); - const compile = useCompile(); - - const mapOptionsToTags = useCallback( - (options) => { - try { - return options - .filter((v) => ['number', 'string'].includes(typeof v[fieldNames.value])) - .map((option) => { - let label = compile(option[fieldNames.label]); - - if (targetField?.uiSchema?.enum) { - if (Array.isArray(label)) { - label = label - .map((item, index) => { - const option = targetField.uiSchema.enum.find((i) => i.value === item); - if (option) { - return ( - - {option?.label || item} - - ); - } else { - return ( - - {item} - - ); - } - }) - .reverse(); - } else { - const item = targetField.uiSchema.enum.find((i) => i.value === label); - if (item) { - label = ( - - {item.label} - - ); - } - } - } - if (targetField?.type === 'date') { - label = dayjs(label).format('YYYY-MM-DD'); - } - - if (mapOptions) { - return mapOptions({ - [fieldNames.label]: label || EMPTY, - [fieldNames.value]: option[fieldNames.value], - }); - } - return { - ...option, - [fieldNames.label]: label || EMPTY, - [fieldNames.value]: option[fieldNames.value], - }; - }) - .filter(Boolean); - } catch (err) { - console.error(err); - return options; - } - }, - [targetField?.uiSchema, fieldNames], - ); - const { data, run, loading } = useRequest( - { - action: 'list', - ...service, - params: { - pageSize: fieldNames['formula'] ? 9999 : 200, - ...service?.params, - filter: service?.params?.filter, - }, - }, - { - manual, - debounceWait: wait, - }, - ); - const runDep = useMemo( - () => - JSON.stringify({ - service, - fieldNames, - }), - [service, fieldNames], - ); - const CustomRenderCom = useCallback(() => { - if (searchData.current && CustomDropdownRender) { - return ( - { - searchData.current = null; - setOpen(false); - }} - /> - ); - } - return null; - }, [searchData.current]); - - useEffect(() => { - // Lazy load - if (firstRun.current) { - run(); - } - }, [runDep]); - - const onSearch = async (search) => { - run({ - filter: mergeFilter([ - search - ? { - [fieldNames.label]: { - [operator]: search, - }, - } - : {}, - service?.params?.filter, - ]), - }); - searchData.current = search; - }; - - const options = useMemo(() => { - const v = value || defaultValue; - if (!data?.data?.length) { - return v != null ? (Array.isArray(v) ? v : [v]) : []; - } - const valueOptions = - (v != null && (Array.isArray(v) ? v : [{ ...v, [fieldNames.value]: v[fieldNames.value] || v }])) || []; - return uniqBy(data?.data?.concat(valueOptions ?? []), fieldNames.value); - }, [value, defaultValue, data?.data, fieldNames.value]); - const onDropdownVisibleChange = (visible) => { - setOpen(visible); - searchData.current = null; - if (visible) { - run(); - } - firstRun.current = true; - }; - - return ( -