mirror of
https://github.com/nocobase/nocobase.git
synced 2026-09-24 16:02:20 +08:00
fix(ActionDrawer): improve footer schema handling (#7414)
* fix(ActionDrawer): improve footer schema handling * fix(ActionDrawer): avoid UI refresh issues by removing fieldSchema dependency * fix(MobilePicker, MobileDatePicker): remove contentEditable attribute from div elements * refactor(CreateRecordAction): optimize addNewerSchema handling
This commit is contained in:
+19
-11
@@ -7,15 +7,15 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { observer, useField, useFieldSchema } from '@formily/react';
|
||||
import React, { useState } from 'react';
|
||||
import { observer, Schema, useField, useFieldSchema } from '@formily/react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { CollectionProvider_deprecated, useCollectionManager_deprecated } from '../../../../collection-manager';
|
||||
import { NocoBaseRecursionField } from '../../../../formily/NocoBaseRecursionField';
|
||||
import { CreateAction } from '../../../../schema-initializer/components';
|
||||
import { ActionContextProvider, useActionContext } from '../../action';
|
||||
import { TabsContextProvider } from '../../tabs/context';
|
||||
import { useAssociationFieldContext, useInsertSchema } from '../hooks';
|
||||
import schema from '../schema';
|
||||
import { TabsContextProvider } from '../../tabs/context';
|
||||
|
||||
export const CreateRecordAction = observer(
|
||||
(props) => {
|
||||
@@ -31,12 +31,27 @@ export const CreateRecordAction = observer(
|
||||
const [currentDataSource, setCurrentDataSource] = useState(targetCollection?.dataSource);
|
||||
const [formValueChanged, setFormValueChanged] = useState(false);
|
||||
|
||||
const addNewerSchema = useMemo(() => {
|
||||
return fieldSchema.reduceProperties((buf, s) => {
|
||||
if (s['x-component'] === 'AssociationField.AddNewer') {
|
||||
Object.keys(s.parent.properties).forEach((key) => {
|
||||
if (key !== s.name) {
|
||||
s.parent.removeProperty(key);
|
||||
}
|
||||
});
|
||||
return s.parent;
|
||||
}
|
||||
return buf;
|
||||
}) as Schema;
|
||||
}, [fieldSchema]);
|
||||
|
||||
const addbuttonClick = (collectionData) => {
|
||||
insertAddNewer(schema.AddNewer);
|
||||
setVisibleAddNewer(true);
|
||||
setCurrentCollection(collectionData.name);
|
||||
setCurrentDataSource(collectionData.dataSource);
|
||||
};
|
||||
|
||||
return (
|
||||
<CollectionProvider_deprecated name={collectionField?.target}>
|
||||
<CreateAction {...props} onClick={(arg) => addbuttonClick(arg)} />
|
||||
@@ -51,14 +66,7 @@ export const CreateRecordAction = observer(
|
||||
>
|
||||
<CollectionProvider_deprecated name={currentCollection} dataSource={currentDataSource}>
|
||||
<TabsContextProvider>
|
||||
<NocoBaseRecursionField
|
||||
onlyRenderProperties
|
||||
basePath={field.address}
|
||||
schema={fieldSchema}
|
||||
filterProperties={(s) => {
|
||||
return s['x-component'] === 'AssociationField.AddNewer';
|
||||
}}
|
||||
/>
|
||||
<NocoBaseRecursionField basePath={field.address} schema={addNewerSchema} />
|
||||
</TabsContextProvider>
|
||||
</CollectionProvider_deprecated>
|
||||
</ActionContextProvider>
|
||||
|
||||
+19
-29
@@ -7,7 +7,7 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { ISchema, observer, useField, useFieldSchema } from '@formily/react';
|
||||
import { ISchema, observer, Schema, useField, useFieldSchema } from '@formily/react';
|
||||
import {
|
||||
Action,
|
||||
FlagProvider,
|
||||
@@ -111,6 +111,12 @@ export const ActionDrawerUsedInMobile: any = observer((props: { footerNodeName?:
|
||||
const { visible, setVisible } = useActionContext();
|
||||
const { visiblePopup } = usePopupContainer(visible);
|
||||
|
||||
// 克隆的目的是为了把底部按钮的 schema 去掉,避免重复渲染。
|
||||
// 不使用 filterProperties 的原因是防止 Iphone 中出现卡死的问题,具体原因未知。
|
||||
const clonedFieldSchema = useMemo(() => {
|
||||
return new Schema(fieldSchema.toJSON());
|
||||
}, []); // 不需要依赖 fieldSchema,不然会导致在弹窗中添加区块时不刷新 UI
|
||||
|
||||
// this schema need to add padding in the content area of the popup
|
||||
const isSpecialSchema = isChangePasswordSchema(fieldSchema) || isEditProfileSchema(fieldSchema);
|
||||
|
||||
@@ -118,19 +124,15 @@ export const ActionDrawerUsedInMobile: any = observer((props: { footerNodeName?:
|
||||
|
||||
const specialStyle = isSpecialSchema ? { backgroundColor: 'white' } : {};
|
||||
|
||||
const footerSchema = fieldSchema.reduceProperties((buf, s) => {
|
||||
if (s['x-component'] === footerNodeName) {
|
||||
return s;
|
||||
}
|
||||
return buf;
|
||||
});
|
||||
|
||||
const filterProperties = useCallback(
|
||||
(s) => {
|
||||
return s['x-component'] !== footerNodeName;
|
||||
},
|
||||
[footerNodeName],
|
||||
);
|
||||
const footerSchema = useMemo(() => {
|
||||
return clonedFieldSchema.reduceProperties((buf, s) => {
|
||||
if (s['x-component'] === footerNodeName) {
|
||||
s.parent.removeProperty(s.name); // 移除掉底部按钮区域的 schema
|
||||
return s;
|
||||
}
|
||||
return buf;
|
||||
}) as Schema;
|
||||
}, [clonedFieldSchema, footerNodeName]);
|
||||
|
||||
const title = field.title || '';
|
||||
|
||||
@@ -140,27 +142,15 @@ export const ActionDrawerUsedInMobile: any = observer((props: { footerNodeName?:
|
||||
|
||||
const popupContent = isSpecialSchema ? (
|
||||
<div style={{ padding: 12, ...specialStyle }}>
|
||||
<SchemaComponent basePath={field.address} schema={fieldSchema} filterProperties={filterProperties} />
|
||||
<SchemaComponent basePath={field.address} schema={clonedFieldSchema} />
|
||||
</div>
|
||||
) : (
|
||||
<SchemaComponent
|
||||
basePath={field.address}
|
||||
schema={fieldSchema}
|
||||
onlyRenderProperties
|
||||
filterProperties={filterProperties}
|
||||
/>
|
||||
<SchemaComponent basePath={field.address} schema={clonedFieldSchema} />
|
||||
);
|
||||
|
||||
const footerContent = footerSchema ? (
|
||||
<div className="nb-mobile-action-drawer-footer" style={isSpecialSchema ? specialStyle : null}>
|
||||
<NocoBaseRecursionField
|
||||
basePath={field.address}
|
||||
schema={fieldSchema}
|
||||
onlyRenderProperties
|
||||
filterProperties={(s) => {
|
||||
return s['x-component'] === footerNodeName;
|
||||
}}
|
||||
/>
|
||||
<NocoBaseRecursionField basePath={field.address} schema={footerSchema} />
|
||||
</div>
|
||||
) : null;
|
||||
|
||||
|
||||
+20
-20
@@ -7,25 +7,25 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import React, { useState, useCallback, useEffect, useRef } from 'react';
|
||||
import { DatePicker, Picker } from 'antd-mobile';
|
||||
import { Space, Select } from 'antd';
|
||||
import {
|
||||
mapDatePicker,
|
||||
DatePicker as NBDatePicker,
|
||||
useDatePickerContext,
|
||||
useCompile,
|
||||
inferPickerType,
|
||||
TimePicker as NBTimePicker,
|
||||
mapTimeFormat,
|
||||
useVariables,
|
||||
isVariable,
|
||||
useLocalVariables,
|
||||
} from '@nocobase/client';
|
||||
import { autorun } from '@formily/reactive';
|
||||
import dayjs from 'dayjs';
|
||||
import { connect, mapProps, mapReadPretty, useField, useFieldSchema } from '@formily/react';
|
||||
import { autorun } from '@formily/reactive';
|
||||
import {
|
||||
inferPickerType,
|
||||
isVariable,
|
||||
mapDatePicker,
|
||||
mapTimeFormat,
|
||||
DatePicker as NBDatePicker,
|
||||
TimePicker as NBTimePicker,
|
||||
useCompile,
|
||||
useDatePickerContext,
|
||||
useLocalVariables,
|
||||
useVariables,
|
||||
} from '@nocobase/client';
|
||||
import { getPickerFormat } from '@nocobase/utils/client';
|
||||
import { Select, Space } from 'antd';
|
||||
import { DatePicker, Picker } from 'antd-mobile';
|
||||
import dayjs from 'dayjs';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
function getPrecision(timeFormat: string): 'hour' | 'minute' | 'second' {
|
||||
@@ -133,7 +133,7 @@ const MobileDateTimePicker = connect(
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<div contentEditable="false" onClick={() => !disabled && setVisible(true)}>
|
||||
<div onClick={() => !disabled && setVisible(true)}>
|
||||
<NBDatePicker
|
||||
onClick={() => setVisible(true)}
|
||||
value={value}
|
||||
@@ -326,7 +326,7 @@ const MobileTimePicker: ComposedMobileTimePicker = connect(
|
||||
};
|
||||
|
||||
return (
|
||||
<div contentEditable="false" onClick={() => setVisible(true)}>
|
||||
<div onClick={() => setVisible(true)}>
|
||||
<NBTimePicker {...props} style={{ pointerEvents: 'none' }} />
|
||||
<Picker onConfirm={handleTimeChange} columns={timeData} visible={visible} />
|
||||
</div>
|
||||
@@ -342,4 +342,4 @@ MobileDateFilterWithPicker.displayName = 'MobileDateFilterWithPicker';
|
||||
MobileTimePicker.displayName = 'MobileTimePicker';
|
||||
|
||||
MobileTimePicker.RangePicker = NBTimePicker.RangePicker;
|
||||
export { MobileDateTimePicker, MobileRangePicker, MobileDateFilterWithPicker, MobileTimePicker };
|
||||
export { MobileDateFilterWithPicker, MobileDateTimePicker, MobileRangePicker, MobileTimePicker };
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ const MobilePicker = connect(
|
||||
|
||||
return (
|
||||
<>
|
||||
<div contentEditable="false" onClick={() => !disabled && setVisible(true)}>
|
||||
<div onClick={() => !disabled && setVisible(true)}>
|
||||
<Select
|
||||
disabled={disabled}
|
||||
value={value}
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ const MobileDateTimePicker = connect(
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<div contentEditable="false" onClick={() => setVisible(true)}>
|
||||
<div onClick={() => setVisible(true)}>
|
||||
<NBDatePicker
|
||||
onClick={() => setVisible(true)}
|
||||
value={value}
|
||||
|
||||
+3
-3
@@ -7,10 +7,10 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { Button, CheckList, Popup, SearchBar } from 'antd-mobile';
|
||||
import { connect, mapProps } from '@formily/react';
|
||||
import { Select } from '@nocobase/client';
|
||||
import { Button, CheckList, Popup, SearchBar } from 'antd-mobile';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const MobilePicker = connect(
|
||||
@@ -38,7 +38,7 @@ const MobilePicker = connect(
|
||||
|
||||
return (
|
||||
<>
|
||||
<div contentEditable="false" onClick={() => setVisible(true)}>
|
||||
<div onClick={() => setVisible(true)}>
|
||||
<Select
|
||||
placeholder={t('Select')}
|
||||
value={value}
|
||||
|
||||
Reference in New Issue
Block a user