stabilizing loading the resource form

There can be race conditions when the resource update is failing after a
type swtich and the form for the updated type needs to be fetched.
Sometimes, the old form is used (from the former type) which does not
have information on a custom field property.

In this case, a fallback is added to force fetching the form.

This solution is not ideal as an additional request is sent to the
server. Ideally, the changes to the table should only be rendered after
the schema (as part of the form) is present.
This commit is contained in:
ulferts
2026-06-10 11:30:06 +02:00
parent 0f9cb250dd
commit 0bdedded2c
2 changed files with 28 additions and 30 deletions
@@ -44,6 +44,7 @@ import isNewResource from 'core-app/features/hal/helpers/is-new-resource';
import { HalError } from 'core-app/features/hal/services/hal-error';
import { FormResource } from 'core-app/features/hal/resources/form-resource';
import { HalResourceEditFieldHandler } from 'core-app/shared/components/fields/edit/field-handler/hal-resource-edit-field-handler';
import { ISchemaProxy } from 'core-app/features/hal/schemas/schema-proxy';
export const activeFieldContainerClassName = 'inline-edit--active-field';
export const activeFieldClassName = 'inline-edit--field';
@@ -294,48 +295,46 @@ export abstract class EditForm<T extends HalResource = HalResource> {
* @param fieldName
*/
protected loadFieldSchema(fieldName:string, noWarnings = false):Promise<IFieldSchema> {
return new Promise((resolve, reject) => {
this.loadFormAndCheck(fieldName, noWarnings);
const fieldSchema:IFieldSchema = this.change.schema.ofProperty(fieldName);
return this.getFormFieldSchema(fieldName).then((fieldSchema) => {
if (!fieldSchema) {
this.closeEditFields([fieldName]);
throw new Error();
}
resolve(fieldSchema);
if (!fieldSchema.writable && !noWarnings) {
this.halNotification.showEditingBlockedError(fieldSchema.name || fieldName);
this.closeEditFields([fieldName]);
}
return fieldSchema;
});
}
/**
* Ensure the form gets loaded and we show an error when the field cannot be opened
* Load the form and return the field schema, reloading the form once if the schema is
* not present in the cached version (e.g. after a type change).
* Returns null if the schema is still absent after a forced reload.
* @param fieldName
* @param noWarnings
*/
private loadFormAndCheck(fieldName:string, noWarnings = false) {
// Ensure the form is being loaded if necessary
this.change
.getForm()
.then(() => {
// Look up whether we're actually editable
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const fieldSchema = this.change.schema.ofProperty(fieldName);
private getFormFieldSchema(fieldName:string):Promise<IFieldSchema|null> {
return this.change.getForm()
.then(():Promise<IFieldSchema|null> => {
const fieldSchema:IFieldSchema|null = (this.change.schema as ISchemaProxy).ofProperty(fieldName);
// If the type changed while we tried to activate the form
// silently close the field as it will no longer be writable
if (!fieldSchema) {
this.closeEditFields([fieldName]);
return;
if (fieldSchema) {
return Promise.resolve(fieldSchema);
}
if (!fieldSchema.writable && !noWarnings) {
this.halNotification.showEditingBlockedError(fieldSchema.name || fieldName);
this.closeEditFields([fieldName]);
}
// The cached form may be stale (e.g. type just changed); force a reload and retry once.
return this.change.getForm(true).then(
():IFieldSchema|null => (this.change.schema as ISchemaProxy).ofProperty(fieldName),
);
})
.catch((error:any) => {
.catch((error:unknown) => {
console.error('Failed to build edit field: %o', error);
this.halNotification.handleRawError(error, this.resource);
this.closeEditFields([fieldName]);
return null;
});
}
@@ -121,20 +121,19 @@ RSpec.describe "Switching types in work package table", :js do
# Switch type
type_field.activate!
type_field.set_value type_bug.name
type_field.set_select_field_value type_bug.name
wp_table.expect_and_dismiss_toaster(
type: :error,
message: "#{cf_req_text.name} can't be blank."
)
# Required CF requires activation
# After a failed type switch, the required CF field is auto-opened in edit mode
req_text_field.expect_active!
# Now switch back to a type without the required CF
type_field.activate!
type_field.openSelectField
type_field.set_value type_task.name
type_field.set_select_field_value type_task.name
wp_table.expect_and_dismiss_toaster(
message: "Successful update."