feat(scaffolder): disable the submit button on creating
close #29054 Signed-off-by: JounQin <admin@1stg.me>
This commit is contained in:
@@ -15,17 +15,16 @@
|
||||
*/
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import type { RJSFValidationError } from '@rjsf/utils';
|
||||
import { act, fireEvent, waitFor } from '@testing-library/react';
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import { FieldExtensionComponentProps } from '../../../extensions';
|
||||
import { LayoutTemplate } from '../../../layouts';
|
||||
import { SecretsContextProvider } from '../../../secrets';
|
||||
import { TemplateParameterSchema } from '../../../types';
|
||||
import { Stepper } from './Stepper';
|
||||
|
||||
import type { RJSFValidationError } from '@rjsf/utils';
|
||||
import { FieldExtensionComponentProps } from '../../../extensions';
|
||||
|
||||
describe('Stepper', () => {
|
||||
it('should render the step titles for each step of the manifest', async () => {
|
||||
const manifest: TemplateParameterSchema = {
|
||||
@@ -762,7 +761,10 @@ describe('Stepper', () => {
|
||||
],
|
||||
};
|
||||
|
||||
const onCreate = jest.fn();
|
||||
// `onCreate` must be async to mock the submit button disabled behavior
|
||||
const onCreate = jest.fn(
|
||||
() => new Promise<void>(resolve => setTimeout(resolve, 0)),
|
||||
);
|
||||
|
||||
const { getByRole } = await renderInTestApp(
|
||||
<SecretsContextProvider>
|
||||
@@ -783,10 +785,18 @@ describe('Stepper', () => {
|
||||
fireEvent.click(getByRole('button', { name: 'Review' }));
|
||||
});
|
||||
|
||||
fireEvent.click(getByRole('button', { name: 'Create' }));
|
||||
|
||||
await waitFor(() =>
|
||||
expect(getByRole('button', { name: 'Create' })).toBeDisabled(),
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(getByRole('button', { name: 'Create' }));
|
||||
});
|
||||
|
||||
expect(onCreate).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(onCreate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
thing: { repoOrg: 'backstage' },
|
||||
|
||||
@@ -115,7 +115,7 @@ export type StepperProps = {
|
||||
*/
|
||||
export const Stepper = (stepperProps: StepperProps) => {
|
||||
const { t } = useTranslationRef(scaffolderReactTranslationRef);
|
||||
const { layouts = [], components = {}, ...props } = stepperProps;
|
||||
const { layouts = [], components = {}, onCreate, ...props } = stepperProps;
|
||||
const {
|
||||
ReviewStateComponent = ReviewState,
|
||||
ReviewStepComponent,
|
||||
@@ -220,10 +220,17 @@ export const Stepper = (stepperProps: StepperProps) => {
|
||||
|
||||
const mergedUiSchema = merge({}, propUiSchema, currentStep?.uiSchema);
|
||||
|
||||
const handleCreate = useCallback(() => {
|
||||
props.onCreate(stepsState);
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
|
||||
const handleCreate = useCallback(async () => {
|
||||
setIsCreating(true);
|
||||
analytics.captureEvent('click', `${createLabel}`);
|
||||
}, [props, stepsState, analytics, createLabel]);
|
||||
try {
|
||||
await onCreate(stepsState);
|
||||
} finally {
|
||||
setIsCreating(false);
|
||||
}
|
||||
}, [analytics, createLabel, onCreate, stepsState]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -318,6 +325,7 @@ export const Stepper = (stepperProps: StepperProps) => {
|
||||
{backLabel}
|
||||
</Button>
|
||||
<Button
|
||||
disabled={isCreating}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleCreate}
|
||||
|
||||
@@ -95,7 +95,7 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => {
|
||||
|
||||
const workflowOnCreate = useCallback(
|
||||
async (formState: Record<string, JsonValue>) => {
|
||||
onCreate(formState);
|
||||
await onCreate(formState);
|
||||
|
||||
const name =
|
||||
typeof formState.name === 'string' ? formState.name : undefined;
|
||||
|
||||
Reference in New Issue
Block a user