Merge pull request #27230 from backstage/blam/fix-stepper

Fix issue with state tracking in the scaffolder
This commit is contained in:
Ben Lambert
2024-10-17 17:00:30 +02:00
committed by GitHub
2 changed files with 37 additions and 36 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-react': patch
---
Fix issue with form state not refreshing when updating
@@ -124,16 +124,15 @@ export const Stepper = (stepperProps: StepperProps) => {
const apiHolder = useApiHolder();
const [activeStep, setActiveStep] = useState(0);
const [isValidating, setIsValidating] = useState(false);
const [initialState] = useFormDataFromQuery(props.initialState);
const [formState, setFormState] = useState<{
[step: string]: Record<string, JsonValue>;
}>();
const [stepsState, setStepsState] = useState<Record<string, JsonValue>[]>(
steps.map(() => initialState),
);
const [errors, setErrors] = useState<undefined | FormValidation>();
const styles = useStyles();
const makeStepKey = (step: string | number) => `step-${step}`;
const backLabel =
presentation?.buttonLabels?.backButtonText ?? backButtonText;
const createLabel =
@@ -168,15 +167,15 @@ export const Stepper = (stepperProps: StepperProps) => {
setActiveStep(prevActiveStep => prevActiveStep - 1);
};
const handleChange = useCallback(
(e: IChangeEvent) => {
setFormState(current => ({
...current,
[makeStepKey(activeStep)]: e.formData,
}));
},
[setFormState, activeStep],
);
const handleChange = (e: IChangeEvent) => {
setStepsState(current => {
const newState = [...current];
newState[activeStep] = {
...e.formData,
};
return newState;
});
};
const currentStep = useTransformSchemaToProps(steps[activeStep], { layouts });
@@ -197,6 +196,13 @@ export const Stepper = (stepperProps: StepperProps) => {
if (hasErrors(returnedValidation)) {
setErrors(returnedValidation);
} else {
setStepsState(current => {
const newState = [...current];
newState[activeStep] = {
...formData,
};
return newState;
});
setErrors(undefined);
setActiveStep(prevActiveStep => {
const stepNum = prevActiveStep + 1;
@@ -204,10 +210,6 @@ export const Stepper = (stepperProps: StepperProps) => {
return stepNum;
});
}
setFormState(current => ({
...current,
[makeStepKey(activeStep)]: formData,
}));
};
const {
@@ -218,23 +220,14 @@ export const Stepper = (stepperProps: StepperProps) => {
const mergedUiSchema = merge({}, propUiSchema, currentStep?.uiSchema);
const mergedState = useMemo(() => {
if (!formState) {
return initialState;
}
const { [makeStepKey(activeStep)]: activeState, ...historicalState } =
formState;
const chronologicalState = {
...historicalState,
[makeStepKey(activeStep)]: activeState,
};
return merge({}, ...Object.values(chronologicalState));
}, [formState, activeStep, initialState]);
const formState = stepsState.reduce((acc, step) => {
return { ...acc, ...step };
}, {});
const handleCreate = useCallback(() => {
props.onCreate(mergedState);
props.onCreate(formState);
analytics.captureEvent('click', `${createLabel}`);
}, [props, mergedState, analytics, createLabel]);
}, [props, formState, analytics, createLabel]);
return (
<>
@@ -269,12 +262,15 @@ export const Stepper = (stepperProps: StepperProps) => {
{/* eslint-disable-next-line no-nested-ternary */}
{activeStep < steps.length ? (
<Form
key={activeStep}
validator={validator}
extraErrors={errors as unknown as ErrorSchema}
formData={mergedState}
formContext={{ ...propFormContext, formData: mergedState }}
formData={{ ...stepsState[activeStep] }}
formContext={{ ...propFormContext, formData: formState }}
schema={currentStep.schema}
uiSchema={mergedUiSchema}
omitExtraData
liveOmit
onSubmit={handleNext}
fields={fields}
showErrorList="top"
@@ -308,7 +304,7 @@ export const Stepper = (stepperProps: StepperProps) => {
ReviewStepComponent ? (
<ReviewStepComponent
disableButtons={isValidating}
formData={mergedState}
formData={formState}
handleBack={handleBack}
handleReset={() => {}}
steps={steps}
@@ -316,7 +312,7 @@ export const Stepper = (stepperProps: StepperProps) => {
/>
) : (
<>
<ReviewStateComponent formState={mergedState} schemas={steps} />
<ReviewStateComponent formState={formState} schemas={steps} />
<div className={styles.footer}>
<Button
onClick={handleBack}