diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.test.tsx
index 6f1dbc58bf9e..3fd6e78ac7d1 100644
--- a/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.test.tsx
+++ b/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.test.tsx
@@ -27,6 +27,7 @@ describe('WorkspaceCreateActionPanel', () => {
formId={formId}
formData={{ name: longName, description: formData.description }}
application={mockApplication}
+ isSubmitting={false}
/>
);
const createButton = screen.getByText('Create workspace');
@@ -40,6 +41,7 @@ describe('WorkspaceCreateActionPanel', () => {
formId={formId}
formData={{ name: formData.name, description: longDescription }}
application={mockApplication}
+ isSubmitting={false}
/>
);
const createButton = screen.getByText('Create workspace');
@@ -52,9 +54,23 @@ describe('WorkspaceCreateActionPanel', () => {
formId={formId}
formData={formData}
application={mockApplication}
+ isSubmitting={false}
/>
);
const createButton = screen.getByText('Create workspace');
expect(createButton.closest('button')).not.toBeDisabled();
});
+
+ it('should disable the "Create Workspace" and "Cancel" button when submitting', () => {
+ render(
+
+ );
+ expect(screen.getByText('Create workspace').closest('button')).toBeDisabled();
+ expect(screen.getByText('Cancel').closest('button')).toBeDisabled();
+ });
});
diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.tsx
index 26f98a24562c..5f59cbb9587b 100644
--- a/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.tsx
+++ b/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.tsx
@@ -17,12 +17,14 @@ interface WorkspaceCreateActionPanelProps {
formId: string;
formData: Pick;
application: ApplicationStart;
+ isSubmitting: boolean;
}
export const WorkspaceCreateActionPanel = ({
formId,
formData,
application,
+ isSubmitting,
}: WorkspaceCreateActionPanelProps) => {
const [isCancelModalVisible, setIsCancelModalVisible] = useState(false);
const closeCancelModal = useCallback(() => setIsCancelModalVisible(false), []);
@@ -38,6 +40,7 @@ export const WorkspaceCreateActionPanel = ({
{i18n.translate('workspace.form.right.sidebar.buttons.cancelText', {
defaultMessage: 'Cancel',
@@ -50,7 +53,8 @@ export const WorkspaceCreateActionPanel = ({
form={formId}
data-test-subj="workspaceForm-bottomBar-createButton"
fill
- disabled={createButtonDisabled}
+ disabled={createButtonDisabled || isSubmitting}
+ isLoading={isSubmitting}
>
{i18n.translate('workspace.form.right.sidebar.buttons.createWorkspaceText', {
defaultMessage: 'Create workspace',
diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx
index 760c4060de58..083c1d61c4de 100644
--- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx
+++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx
@@ -344,4 +344,33 @@ describe('WorkspaceCreator', () => {
});
expect(notificationToastsAddDanger).not.toHaveBeenCalled();
});
+
+ it('should not create workspace API when submitting', async () => {
+ workspaceClientCreate.mockImplementationOnce(
+ () =>
+ new Promise((resolve) => {
+ setTimeout(resolve, 100);
+ })
+ );
+ const { getByTestId } = render();
+ // Ensure workspace create form rendered
+ await waitFor(() => {
+ expect(getByTestId('workspaceForm-bottomBar-createButton')).toBeInTheDocument();
+ });
+ const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText');
+ fireEvent.input(nameInput, {
+ target: { value: 'test workspace name' },
+ });
+ fireEvent.click(getByTestId('workspaceUseCase-observability'));
+ fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton'));
+ expect(workspaceClientCreate).toHaveBeenCalledTimes(1);
+
+ fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton'));
+ expect(workspaceClientCreate).toHaveBeenCalledTimes(1);
+
+ await waitFor(() => {
+ fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton'));
+ expect(workspaceClientCreate).toHaveBeenCalledTimes(2);
+ });
+ });
});
diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx
index d7d763eebefe..3ba8b7850753 100644
--- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx
+++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import React, { useCallback } from 'react';
+import React, { useCallback, useState } from 'react';
import { EuiPage, EuiPageBody, EuiPageContent, euiPaletteColorBlind } from '@elastic/eui';
import { i18n } from '@osd/i18n';
import { BehaviorSubject } from 'rxjs';
@@ -43,6 +43,7 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => {
dataSourceManagement?: DataSourceManagementPluginSetup;
navigationUI: NavigationPublicPluginStart['ui'];
}>();
+ const [isFormSubmitting, setIsFormSubmitting] = useState(false);
const isPermissionEnabled = application?.capabilities.workspaces.permissionEnabled;
const { isOnlyAllowEssential, availableUseCases } = useFormAvailableUseCases({
@@ -65,6 +66,10 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => {
const handleWorkspaceFormSubmit = useCallback(
async (data: WorkspaceFormSubmitData) => {
let result;
+ if (isFormSubmitting) {
+ return;
+ }
+ setIsFormSubmitting(true);
try {
const { permissionSettings, selectedDataSources, ...attributes } = data;
const selectedDataSourceIds = (selectedDataSources ?? []).map((ds: DataSource) => {
@@ -105,9 +110,11 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => {
text: error instanceof Error ? error.message : JSON.stringify(error),
});
return;
+ } finally {
+ setIsFormSubmitting(false);
}
},
- [notifications?.toasts, http, application, workspaceClient]
+ [notifications?.toasts, http, application, workspaceClient, isFormSubmitting]
);
const isFormReadyToRender =
@@ -146,6 +153,7 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => {
dataSourceManagement={dataSourceManagement}
availableUseCases={availableUseCases}
defaultValues={defaultWorkspaceFormValues}
+ isSubmitting={isFormSubmitting}
/>
)}
diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.test.tsx
index dc0117f9e4db..95ca5bf948c5 100644
--- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.test.tsx
+++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.test.tsx
@@ -38,6 +38,7 @@ const setup = (
return render(
{
+interface WorkspaceCreatorFormProps extends WorkspaceFormProps {
+ isSubmitting: boolean;
+}
+
+export const WorkspaceCreatorForm = (props: WorkspaceCreatorFormProps) => {
const {
application,
savedObjects,
@@ -217,6 +221,7 @@ export const WorkspaceCreatorForm = (props: WorkspaceFormProps) => {
formData={formData}
formId={formId}
application={application}
+ isSubmitting={props.isSubmitting}
/>