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:
Zeke Zhang 2025-03-26 14:37:01 +08:00 committed by GitHub
parent 27c2538d40
commit c80fbc3063
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 128 additions and 81 deletions

View File

@ -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);

View File

@ -273,7 +273,8 @@ const InternalPagePopups = (props: { paramsList?: PopupParams[] }) => {
);
});
const schemas = await Promise.all(waitList);
const clonedSchemas = schemas.map((schema, index) => {
const clonedSchemas = await Promise.all(
schemas.map(async (schema, index) => {
if (_.isEmpty(schema)) {
return get404Schema();
}
@ -284,6 +285,16 @@ const InternalPagePopups = (props: { paramsList?: PopupParams[] }) => {
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);
}
}
}
@ -297,7 +308,8 @@ const InternalPagePopups = (props: { paramsList?: PopupParams[] }) => {
result['x-read-pretty'] = true;
return result;
});
}),
);
popupPropsRef.current = clonedSchemas.map((schema, index, items) => {
const schemaContext = getPopupContextFromActionOrAssociationFieldSchema(schema);
let hidden = false;

View File

@ -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>
);
};

View File

@ -28,6 +28,7 @@ function toSchema(schema?: any) {
properties: {
[schema.name]: schema,
},
name: `p_${schema.name}`,
});
}
return new Schema(schema);
@ -52,8 +53,9 @@ 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 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(
@ -84,26 +86,32 @@ const RecursionSchemaComponent = memo((props: ISchemaFieldProps & SchemaComponen
<SchemaComponentOnChangeContext.Provider value={onChangeValue}>
<SchemaComponentContext.Provider value={value}>
<SchemaComponentOptions inherit components={components} scope={scope}>
<NocoBaseRecursionField {...others} schema={schema} isUseFormilyField />
<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 MemoizedSchemaComponent = memo(
(props: ISchemaFieldProps & SchemaComponentOnChange & DistributedProps & { parentSchema?: Schema }) => {
const { schema, parentSchema, ...others } = props;
const s = useMemoizedSchema(schema);
return <RecursionSchemaComponent {...others} schema={s} />;
});
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;

View File

@ -135,6 +135,7 @@ export const KanbanCard: any = () => {
return (
<>
<PopupContextProvider>
<Card onClick={handleCardClick} bordered={false} hoverable style={cardStyle} className={cardCss}>
<DndContext onDragStart={onDragStart} onDragEnd={onDragEnd}>
<FormLayout
@ -149,6 +150,7 @@ export const KanbanCard: any = () => {
</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;
}
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 }) {