mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 05:29:26 +08:00
fix(kanban): unable to open popup (#6535)
* fix: handle potential errors when retrieving card schema in Kanban * fix(kanban): unable to open popup * fix(Link): cannot use 'current user' variable * fix(PagePopups): improve schema fetching and cloning logic for popups * fix(Kanban): clicking cards repeatedly opens multiple popups
This commit is contained in:
parent
27c2538d40
commit
c80fbc3063
@ -48,6 +48,7 @@ interface INocoBaseRecursionFieldProps extends IRecursionFieldProps {
|
||||
* Whether to use Formily Field class - performance will be reduced but provides better compatibility with Formily
|
||||
*/
|
||||
isUseFormilyField?: boolean;
|
||||
parentSchema?: Schema;
|
||||
}
|
||||
|
||||
const CollectionFieldUISchemaContext = React.createContext<CollectionFieldOptions>({});
|
||||
@ -266,6 +267,7 @@ export const NocoBaseRecursionField: ReactFC<INocoBaseRecursionFieldProps> = Rea
|
||||
values,
|
||||
isUseFormilyField = true,
|
||||
uiSchema,
|
||||
parentSchema,
|
||||
} = props;
|
||||
const basePath = useBasePath(props);
|
||||
const newFieldSchemaRef = useRef(null);
|
||||
@ -279,6 +281,14 @@ export const NocoBaseRecursionField: ReactFC<INocoBaseRecursionFieldProps> = Rea
|
||||
|
||||
const fieldSchema: Schema = newFieldSchemaRef.current || oldFieldSchema;
|
||||
|
||||
// Establish connection with the Schema tree
|
||||
if (!fieldSchema.parent && parentSchema) {
|
||||
fieldSchema.parent = parentSchema;
|
||||
if (!fieldSchema.parent?.properties?.[fieldSchema.name] && fieldSchema.name) {
|
||||
_.set(fieldSchema.parent, `properties.${fieldSchema.name}`, fieldSchema);
|
||||
}
|
||||
}
|
||||
|
||||
const refresh = useCallback(() => {
|
||||
const parent = fieldSchema.parent;
|
||||
newFieldSchemaRef.current = new Schema(fieldSchema.toJSON(), parent);
|
||||
|
@ -273,31 +273,43 @@ const InternalPagePopups = (props: { paramsList?: PopupParams[] }) => {
|
||||
);
|
||||
});
|
||||
const schemas = await Promise.all(waitList);
|
||||
const clonedSchemas = schemas.map((schema, index) => {
|
||||
if (_.isEmpty(schema)) {
|
||||
return get404Schema();
|
||||
}
|
||||
|
||||
const params = popupParams[index];
|
||||
|
||||
if (params.puid) {
|
||||
const popupSchema = findSchemaByUid(params.puid, fieldSchema?.root);
|
||||
if (popupSchema) {
|
||||
savePopupSchemaToSchema(_.omit(popupSchema, 'parent'), schema);
|
||||
const clonedSchemas = await Promise.all(
|
||||
schemas.map(async (schema, index) => {
|
||||
if (_.isEmpty(schema)) {
|
||||
return get404Schema();
|
||||
}
|
||||
}
|
||||
|
||||
// Using toJSON for deep clone, faster than lodash's cloneDeep
|
||||
const result = _.cloneDeepWith(_.omit(schema, 'parent'), (value) => {
|
||||
// If we clone the Tabs component, it will cause the configuration to be lost when reopening the popup after modifying its settings
|
||||
if (value?.['x-component'] === 'Tabs') {
|
||||
return value;
|
||||
const params = popupParams[index];
|
||||
|
||||
if (params.puid) {
|
||||
const popupSchema = findSchemaByUid(params.puid, fieldSchema?.root);
|
||||
if (popupSchema) {
|
||||
savePopupSchemaToSchema(_.omit(popupSchema, 'parent'), schema);
|
||||
} else {
|
||||
// 当本地找不到 popupSchema 时,通过接口请求 puid 对应的 schema
|
||||
try {
|
||||
const remoteSchema = await requestSchema(params.puid);
|
||||
if (remoteSchema) {
|
||||
savePopupSchemaToSchema(remoteSchema, schema);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch schema for puid:', params.puid, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
result['x-read-pretty'] = true;
|
||||
|
||||
return result;
|
||||
});
|
||||
// Using toJSON for deep clone, faster than lodash's cloneDeep
|
||||
const result = _.cloneDeepWith(_.omit(schema, 'parent'), (value) => {
|
||||
// If we clone the Tabs component, it will cause the configuration to be lost when reopening the popup after modifying its settings
|
||||
if (value?.['x-component'] === 'Tabs') {
|
||||
return value;
|
||||
}
|
||||
});
|
||||
result['x-read-pretty'] = true;
|
||||
|
||||
return result;
|
||||
}),
|
||||
);
|
||||
popupPropsRef.current = clonedSchemas.map((schema, index, items) => {
|
||||
const schemaContext = getPopupContextFromActionOrAssociationFieldSchema(schema);
|
||||
let hidden = false;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
import { createForm } from '@formily/core';
|
||||
import { Schema } from '@formily/react';
|
||||
import { Schema, useFieldSchema } from '@formily/react';
|
||||
import { Spin } from 'antd';
|
||||
import React, { memo, useMemo } from 'react';
|
||||
import { useRemoteCollectionManagerLoading } from '../../collection-manager/CollectionManagerProvider';
|
||||
@ -62,6 +62,7 @@ const RequestSchemaComponent: React.FC<RemoteSchemaComponentProps> = (props) =>
|
||||
});
|
||||
const NotFoundComponent = useComponent(NotFoundPage);
|
||||
const collectionManagerLoading = useRemoteCollectionManagerLoading();
|
||||
const parentSchema = useFieldSchema();
|
||||
|
||||
if (collectionManagerLoading || loading || hidden) {
|
||||
return <Spin style={{ width: '100%', marginTop: 20 }} delay={LOADING_DELAY} />;
|
||||
@ -73,10 +74,20 @@ const RequestSchemaComponent: React.FC<RemoteSchemaComponentProps> = (props) =>
|
||||
}
|
||||
|
||||
return noForm ? (
|
||||
<SchemaComponent components={components} scope={scope} schema={schemaTransform(schema || {})} />
|
||||
<SchemaComponent
|
||||
components={components}
|
||||
scope={scope}
|
||||
schema={schemaTransform(schema || {})}
|
||||
parentSchema={parentSchema}
|
||||
/>
|
||||
) : (
|
||||
<FormProvider form={form}>
|
||||
<SchemaComponent components={components} scope={scope} schema={schemaTransform(schema || {})} />
|
||||
<SchemaComponent
|
||||
components={components}
|
||||
scope={scope}
|
||||
schema={schemaTransform(schema || {})}
|
||||
parentSchema={parentSchema}
|
||||
/>
|
||||
</FormProvider>
|
||||
);
|
||||
};
|
||||
|
@ -28,6 +28,7 @@ function toSchema(schema?: any) {
|
||||
properties: {
|
||||
[schema.name]: schema,
|
||||
},
|
||||
name: `p_${schema.name}`,
|
||||
});
|
||||
}
|
||||
return new Schema(schema);
|
||||
@ -52,58 +53,65 @@ interface DistributedProps {
|
||||
*/
|
||||
export const SchemaComponentOnChangeContext = createContext<SchemaComponentOnChange>({ onChange: _.noop });
|
||||
|
||||
const RecursionSchemaComponent = memo((props: ISchemaFieldProps & SchemaComponentOnChange & DistributedProps) => {
|
||||
const { components, scope, schema: _schema, distributed, onChange: _onChange, ...others } = props;
|
||||
const ctx = useContext(SchemaComponentContext);
|
||||
const schema = useMemo(() => toSchema(_schema), [_schema]);
|
||||
const value = useMemo(
|
||||
() => ({
|
||||
...ctx,
|
||||
distributed: ctx.distributed == false ? false : distributed,
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
refresh: ctx.refresh || _.noop,
|
||||
}),
|
||||
[ctx, distributed],
|
||||
);
|
||||
const RecursionSchemaComponent = memo(
|
||||
(props: ISchemaFieldProps & SchemaComponentOnChange & DistributedProps & { parentSchema?: Schema }) => {
|
||||
const { components, scope, schema: _schema, distributed, onChange: _onChange, parentSchema, ...others } = props;
|
||||
const ctx = useContext(SchemaComponentContext);
|
||||
const schema = useMemo(() => toSchema(_schema), [_schema]);
|
||||
const value = useMemo(
|
||||
() => ({
|
||||
...ctx,
|
||||
distributed: ctx.distributed == false ? false : distributed,
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
refresh: ctx.refresh || _.noop,
|
||||
}),
|
||||
[ctx, distributed],
|
||||
);
|
||||
|
||||
const { onChange: onChangeFromContext } = useContext(SchemaComponentOnChangeContext);
|
||||
const { onChange: onChangeFromContext } = useContext(SchemaComponentOnChangeContext);
|
||||
|
||||
const onChangeValue = useMemo(
|
||||
() => ({
|
||||
onChange: () => {
|
||||
_onChange?.(schema);
|
||||
onChangeFromContext?.();
|
||||
},
|
||||
}),
|
||||
[_onChange, onChangeFromContext, schema],
|
||||
);
|
||||
const onChangeValue = useMemo(
|
||||
() => ({
|
||||
onChange: () => {
|
||||
_onChange?.(schema);
|
||||
onChangeFromContext?.();
|
||||
},
|
||||
}),
|
||||
[_onChange, onChangeFromContext, schema],
|
||||
);
|
||||
|
||||
return (
|
||||
<SchemaComponentOnChangeContext.Provider value={onChangeValue}>
|
||||
<SchemaComponentContext.Provider value={value}>
|
||||
<SchemaComponentOptions inherit components={components} scope={scope}>
|
||||
<NocoBaseRecursionField {...others} schema={schema} isUseFormilyField />
|
||||
</SchemaComponentOptions>
|
||||
</SchemaComponentContext.Provider>
|
||||
</SchemaComponentOnChangeContext.Provider>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<SchemaComponentOnChangeContext.Provider value={onChangeValue}>
|
||||
<SchemaComponentContext.Provider value={value}>
|
||||
<SchemaComponentOptions inherit components={components} scope={scope}>
|
||||
<NocoBaseRecursionField {...others} schema={schema} isUseFormilyField parentSchema={parentSchema} />
|
||||
</SchemaComponentOptions>
|
||||
</SchemaComponentContext.Provider>
|
||||
</SchemaComponentOnChangeContext.Provider>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
RecursionSchemaComponent.displayName = 'RecursionSchemaComponent';
|
||||
|
||||
const MemoizedSchemaComponent = memo((props: ISchemaFieldProps & SchemaComponentOnChange & DistributedProps) => {
|
||||
const { schema, ...others } = props;
|
||||
const s = useMemoizedSchema(schema);
|
||||
return <RecursionSchemaComponent {...others} schema={s} />;
|
||||
});
|
||||
const MemoizedSchemaComponent = memo(
|
||||
(props: ISchemaFieldProps & SchemaComponentOnChange & DistributedProps & { parentSchema?: Schema }) => {
|
||||
const { schema, parentSchema, ...others } = props;
|
||||
const s = useMemoizedSchema(schema);
|
||||
return <RecursionSchemaComponent {...others} schema={s} parentSchema={parentSchema} />;
|
||||
},
|
||||
);
|
||||
|
||||
MemoizedSchemaComponent.displayName = 'MemoizedSchemaComponent';
|
||||
|
||||
export const SchemaComponent = memo(
|
||||
(
|
||||
props: (ISchemaFieldProps | IRecursionFieldProps) & { memoized?: boolean } & SchemaComponentOnChange &
|
||||
props: (ISchemaFieldProps | IRecursionFieldProps) & {
|
||||
memoized?: boolean;
|
||||
parentSchema?: Schema;
|
||||
} & SchemaComponentOnChange &
|
||||
DistributedProps,
|
||||
) => {
|
||||
const { memoized, ...others } = props;
|
||||
|
@ -135,20 +135,22 @@ export const KanbanCard: any = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card onClick={handleCardClick} bordered={false} hoverable style={cardStyle} className={cardCss}>
|
||||
<DndContext onDragStart={onDragStart} onDragEnd={onDragEnd}>
|
||||
<FormLayout
|
||||
layout={layout}
|
||||
labelAlign={labelAlign}
|
||||
labelWidth={layout === 'horizontal' ? labelWidth : null}
|
||||
labelWrap={labelWrap}
|
||||
>
|
||||
<FormProvider form={form}>
|
||||
<MemorizedRecursionField schema={fieldSchema} onlyRenderProperties />
|
||||
</FormProvider>
|
||||
</FormLayout>
|
||||
</DndContext>
|
||||
</Card>
|
||||
<PopupContextProvider>
|
||||
<Card onClick={handleCardClick} bordered={false} hoverable style={cardStyle} className={cardCss}>
|
||||
<DndContext onDragStart={onDragStart} onDragEnd={onDragEnd}>
|
||||
<FormLayout
|
||||
layout={layout}
|
||||
labelAlign={labelAlign}
|
||||
labelWidth={layout === 'horizontal' ? labelWidth : null}
|
||||
labelWrap={labelWrap}
|
||||
>
|
||||
<FormProvider form={form}>
|
||||
<MemorizedRecursionField schema={fieldSchema} onlyRenderProperties />
|
||||
</FormProvider>
|
||||
</FormLayout>
|
||||
</DndContext>
|
||||
</Card>
|
||||
</PopupContextProvider>
|
||||
<PopupContextProvider visible={visible} setVisible={setVisible}>
|
||||
<VariablePopupRecordProvider recordData={recordData} collection={collection}>
|
||||
<MemorizedRecursionField schema={wrappedPopupSchema} />
|
||||
@ -163,8 +165,12 @@ function getPopupSchemaFromParent(fieldSchema: Schema) {
|
||||
return fieldSchema.parent.properties.cardViewer.properties.drawer;
|
||||
}
|
||||
|
||||
const cardSchema = findSchemaByUid(fieldSchema['x-uid'], fieldSchema.root);
|
||||
return cardSchema.parent.properties.cardViewer.properties.drawer;
|
||||
try {
|
||||
const cardSchema = findSchemaByUid(fieldSchema['x-uid'], fieldSchema.root);
|
||||
return cardSchema.parent.properties.cardViewer.properties.drawer;
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
function findSchemaByUid(uid: string, rootSchema: Schema, resultRef: { value: Schema } = { value: null }) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user