diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/create_integration_assistant.test.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/create_integration_assistant.test.tsx
index ca4d50958005d..133da383e4e99 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/create_integration_assistant.test.tsx
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/create_integration_assistant.test.tsx
@@ -6,11 +6,13 @@
*/
import React from 'react';
-import { render } from '@testing-library/react';
+import { render, act } from '@testing-library/react';
import { TestProvider } from '../../../mocks/test_provider';
import { CreateIntegrationAssistant } from './create_integration_assistant';
import type { State } from './state';
import { ExperimentalFeaturesService } from '../../../services';
+import { mockReportEvent } from '../../../services/telemetry/mocks/service';
+import { TelemetryEventType } from '../../../services/telemetry/types';
export const defaultInitialState: State = {
step: 1,
@@ -20,6 +22,7 @@ export const defaultInitialState: State = {
hasCelInput: false,
result: undefined,
};
+
const mockInitialState = jest.fn((): State => defaultInitialState);
jest.mock('./state', () => ({
...jest.requireActual('./state'),
@@ -39,39 +42,45 @@ const mockCelInputStep = jest.fn(() =>
const mockReviewCelStep = jest.fn(() => );
const mockDeployStep = jest.fn(() => );
-const mockIsConnectorStepReady = jest.fn();
-const mockIsIntegrationStepReady = jest.fn();
-const mockIsDataStreamStepReady = jest.fn();
-const mockIsReviewStepReady = jest.fn();
-const mockIsCelInputStepReady = jest.fn();
-const mockIsCelReviewStepReady = jest.fn();
+const mockIsConnectorStepReadyToComplete = jest.fn();
+const mockIsIntegrationStepReadyToComplete = jest.fn();
+const mockIsDataStreamStepReadyToComplete = jest.fn();
+const mockIsReviewStepReadyToComplete = jest.fn();
+const mockIsCelInputStepReadyToComplete = jest.fn();
+const mockIsCelReviewStepReadyToComplete = jest.fn();
jest.mock('./steps/connector_step', () => ({
ConnectorStep: () => mockConnectorStep(),
- isConnectorStepReady: () => mockIsConnectorStepReady(),
+ isConnectorStepReadyToComplete: () => mockIsConnectorStepReadyToComplete(),
}));
jest.mock('./steps/integration_step', () => ({
IntegrationStep: () => mockIntegrationStep(),
- isIntegrationStepReady: () => mockIsIntegrationStepReady(),
+ isIntegrationStepReadyToComplete: () => mockIsIntegrationStepReadyToComplete(),
}));
jest.mock('./steps/data_stream_step', () => ({
DataStreamStep: () => mockDataStreamStep(),
- isDataStreamStepReady: () => mockIsDataStreamStepReady(),
+ isDataStreamStepReadyToComplete: () => mockIsDataStreamStepReadyToComplete(),
}));
jest.mock('./steps/review_step', () => ({
ReviewStep: () => mockReviewStep(),
- isReviewStepReady: () => mockIsReviewStepReady(),
+ isReviewStepReadyToComplete: () => mockIsReviewStepReadyToComplete(),
}));
jest.mock('./steps/cel_input_step', () => ({
CelInputStep: () => mockCelInputStep(),
- isCelInputStepReady: () => mockIsCelInputStepReady(),
+ isCelInputStepReadyToComplete: () => mockIsCelInputStepReadyToComplete(),
}));
jest.mock('./steps/review_cel_step', () => ({
ReviewCelStep: () => mockReviewCelStep(),
- isCelReviewStepReady: () => mockIsCelReviewStepReady(),
+ isCelReviewStepReadyToComplete: () => mockIsCelReviewStepReadyToComplete(),
}));
jest.mock('./steps/deploy_step', () => ({ DeployStep: () => mockDeployStep() }));
+const mockNavigate = jest.fn();
+jest.mock('../../../common/hooks/use_navigate', () => ({
+ ...jest.requireActual('../../../common/hooks/use_navigate'),
+ useNavigate: () => mockNavigate,
+}));
+
const renderIntegrationAssistant = () =>
render(, { wrapper: TestProvider });
@@ -89,19 +98,116 @@ describe('CreateIntegration', () => {
mockInitialState.mockReturnValueOnce({ ...defaultInitialState, step: 1 });
});
- it('should render connector', () => {
+ it('shoud report telemetry for assistant open', () => {
+ renderIntegrationAssistant();
+ expect(mockReportEvent).toHaveBeenCalledWith(TelemetryEventType.IntegrationAssistantOpen, {
+ sessionId: expect.any(String),
+ });
+ });
+
+ it('should render connector step', () => {
const result = renderIntegrationAssistant();
expect(result.queryByTestId('connectorStepMock')).toBeInTheDocument();
});
- it('should call isConnectorStepReady', () => {
+ it('should call isConnectorStepReadyToComplete', () => {
renderIntegrationAssistant();
- expect(mockIsConnectorStepReady).toHaveBeenCalled();
+ expect(mockIsConnectorStepReadyToComplete).toHaveBeenCalled();
+ });
+
+ it('should show "Next" on the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toHaveTextContent('Next');
+ });
+
+ describe('when connector step is not done', () => {
+ beforeEach(() => {
+ mockIsConnectorStepReadyToComplete.mockReturnValue(false);
+ });
+
+ it('should disable the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeDisabled();
+ });
+
+ it('should still enable the back button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-backButton')).toBeEnabled();
+ });
+
+ it('should still enable the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toBeEnabled();
+ });
+ });
+
+ describe('when connector step is done', () => {
+ beforeEach(() => {
+ mockIsConnectorStepReadyToComplete.mockReturnValue(true);
+ });
+
+ it('should enable the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeEnabled();
+ });
+
+ it('should enable the back button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-backButton')).toBeEnabled();
+ });
+
+ it('should enable the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toBeEnabled();
+ });
+
+ describe('when next button is clicked', () => {
+ beforeEach(() => {
+ const result = renderIntegrationAssistant();
+ mockReportEvent.mockClear();
+ act(() => {
+ result.getByTestId('buttonsFooter-nextButton').click();
+ });
+ });
+
+ it('should report telemetry for connector step completion', () => {
+ expect(mockReportEvent).toHaveBeenCalledWith(
+ TelemetryEventType.IntegrationAssistantStepComplete,
+ {
+ sessionId: expect.any(String),
+ step: 1,
+ stepName: 'Connector Step',
+ durationMs: expect.any(Number),
+ sessionElapsedTime: expect.any(Number),
+ }
+ );
+ });
+ });
+ });
+
+ describe('when back button is clicked', () => {
+ let result: ReturnType;
+ beforeEach(() => {
+ result = renderIntegrationAssistant();
+ mockReportEvent.mockClear();
+ act(() => {
+ result.getByTestId('buttonsFooter-backButton').click();
+ });
+ });
+
+ it('should not report telemetry', () => {
+ expect(mockReportEvent).not.toHaveBeenCalled();
+ });
+
+ it('should navigate to the landing page', () => {
+ expect(mockNavigate).toHaveBeenCalledWith('landing');
+ });
});
});
describe('when step is 2', () => {
beforeEach(() => {
+ mockIsConnectorStepReadyToComplete.mockReturnValue(true);
mockInitialState.mockReturnValueOnce({ ...defaultInitialState, step: 2 });
});
@@ -110,14 +216,109 @@ describe('CreateIntegration', () => {
expect(result.queryByTestId('integrationStepMock')).toBeInTheDocument();
});
- it('should call isIntegrationStepReady', () => {
+ it('should call isIntegrationStepReadyToComplete', () => {
renderIntegrationAssistant();
- expect(mockIsIntegrationStepReady).toHaveBeenCalled();
+ expect(mockIsIntegrationStepReadyToComplete).toHaveBeenCalled();
+ });
+
+ it('should show "Next" on the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toHaveTextContent('Next');
+ });
+
+ describe('when integration step is not done', () => {
+ beforeEach(() => {
+ mockIsIntegrationStepReadyToComplete.mockReturnValue(false);
+ });
+
+ it('should disable the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeDisabled();
+ });
+
+ it('should still enable the back button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-backButton')).toBeEnabled();
+ });
+
+ it('should still enable the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toBeEnabled();
+ });
+ });
+
+ describe('when integration step is done', () => {
+ beforeEach(() => {
+ mockIsIntegrationStepReadyToComplete.mockReturnValue(true);
+ });
+
+ it('should enable the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeEnabled();
+ });
+
+ it('should enable the back button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-backButton')).toBeEnabled();
+ });
+
+ it('should enable the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toBeEnabled();
+ });
+
+ describe('when next button is clicked', () => {
+ beforeEach(() => {
+ const result = renderIntegrationAssistant();
+ mockReportEvent.mockClear();
+ act(() => {
+ result.getByTestId('buttonsFooter-nextButton').click();
+ });
+ });
+
+ it('should report telemetry for integration step completion', () => {
+ expect(mockReportEvent).toHaveBeenCalledWith(
+ TelemetryEventType.IntegrationAssistantStepComplete,
+ {
+ sessionId: expect.any(String),
+ step: 2,
+ stepName: 'Integration Step',
+ durationMs: expect.any(Number),
+ sessionElapsedTime: expect.any(Number),
+ }
+ );
+ });
+ });
+ });
+
+ describe('when back button is clicked', () => {
+ let result: ReturnType;
+ beforeEach(() => {
+ result = renderIntegrationAssistant();
+ mockReportEvent.mockClear();
+ act(() => {
+ result.getByTestId('buttonsFooter-backButton').click();
+ });
+ });
+
+ it('should not report telemetry', () => {
+ expect(mockReportEvent).not.toHaveBeenCalled();
+ });
+
+ it('should show connector step', () => {
+ expect(result.queryByTestId('connectorStepMock')).toBeInTheDocument();
+ });
+
+ it('should enable the next button', () => {
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeEnabled();
+ });
});
});
describe('when step is 3', () => {
beforeEach(() => {
+ mockIsConnectorStepReadyToComplete.mockReturnValue(true);
+ mockIsIntegrationStepReadyToComplete.mockReturnValue(true);
mockInitialState.mockReturnValueOnce({ ...defaultInitialState, step: 3 });
});
@@ -126,9 +327,116 @@ describe('CreateIntegration', () => {
expect(result.queryByTestId('dataStreamStepMock')).toBeInTheDocument();
});
- it('should call isDataStreamStepReady', () => {
+ it('should call isDataStreamStepReadyToComplete', () => {
renderIntegrationAssistant();
- expect(mockIsDataStreamStepReady).toHaveBeenCalled();
+ expect(mockIsDataStreamStepReadyToComplete).toHaveBeenCalled();
+ });
+
+ it('should show "Analyze logs" on the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toHaveTextContent('Analyze logs');
+ });
+
+ describe('when data stream step is not done', () => {
+ beforeEach(() => {
+ mockIsDataStreamStepReadyToComplete.mockReturnValue(false);
+ });
+
+ it('should disable the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeDisabled();
+ });
+
+ it('should still enable the back button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-backButton')).toBeEnabled();
+ });
+
+ it('should still enable the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toBeEnabled();
+ });
+ });
+
+ describe('when data stream step is done', () => {
+ beforeEach(() => {
+ mockIsDataStreamStepReadyToComplete.mockReturnValue(true);
+ });
+
+ it('should enable the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeEnabled();
+ });
+
+ it('should enable the back button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-backButton')).toBeEnabled();
+ });
+
+ it('should enable the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toBeEnabled();
+ });
+
+ describe('when next button is clicked', () => {
+ beforeEach(() => {
+ const result = renderIntegrationAssistant();
+ mockReportEvent.mockClear();
+ act(() => {
+ result.getByTestId('buttonsFooter-nextButton').click();
+ });
+ });
+
+ it('should report telemetry for data stream step completion', () => {
+ expect(mockReportEvent).toHaveBeenCalledWith(
+ TelemetryEventType.IntegrationAssistantStepComplete,
+ {
+ sessionId: expect.any(String),
+ step: 3,
+ stepName: 'DataStream Step',
+ durationMs: expect.any(Number),
+ sessionElapsedTime: expect.any(Number),
+ }
+ );
+ });
+
+ it('should show loader on the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('generatingLoader')).toBeInTheDocument();
+ });
+
+ it('should disable the next button', () => {
+ const result = renderIntegrationAssistant();
+ // Not sure why there are two buttons when testing.
+ const nextButton = result
+ .getAllByTestId('buttonsFooter-nextButton')
+ .filter((button) => button.textContent !== 'Next')[0];
+ expect(nextButton).toBeDisabled();
+ });
+ });
+ });
+
+ describe('when back button is clicked', () => {
+ let result: ReturnType;
+ beforeEach(() => {
+ result = renderIntegrationAssistant();
+ mockReportEvent.mockClear();
+ act(() => {
+ result.getByTestId('buttonsFooter-backButton').click();
+ });
+ });
+
+ it('should not report telemetry', () => {
+ expect(mockReportEvent).not.toHaveBeenCalled();
+ });
+
+ it('should show integration step', () => {
+ expect(result.queryByTestId('integrationStepMock')).toBeInTheDocument();
+ });
+
+ it('should enable the next button', () => {
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeEnabled();
+ });
});
});
@@ -142,9 +450,89 @@ describe('CreateIntegration', () => {
expect(result.queryByTestId('reviewStepMock')).toBeInTheDocument();
});
- it('should call isReviewStepReady', () => {
+ it('should call isReviewStepReadyToComplete', () => {
renderIntegrationAssistant();
- expect(mockIsReviewStepReady).toHaveBeenCalled();
+ expect(mockIsReviewStepReadyToComplete).toHaveBeenCalled();
+ });
+
+ it('should show the "Add to Elastic" on the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toHaveTextContent('Add to Elastic');
+ });
+
+ describe('when review step is not done', () => {
+ beforeEach(() => {
+ mockIsReviewStepReadyToComplete.mockReturnValue(false);
+ });
+
+ it('should disable the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeDisabled();
+ });
+
+ it('should still enable the back button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-backButton')).toBeEnabled();
+ });
+
+ it('should still enable the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toBeEnabled();
+ });
+ });
+
+ describe('when review step is done', () => {
+ beforeEach(() => {
+ mockIsReviewStepReadyToComplete.mockReturnValue(true);
+ });
+
+ it('should enable the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeEnabled();
+ });
+
+ it('should enable the back button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-backButton')).toBeEnabled();
+ });
+
+ it('should enable the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toBeEnabled();
+ });
+
+ describe('when next button is clicked', () => {
+ beforeEach(() => {
+ const result = renderIntegrationAssistant();
+ mockReportEvent.mockClear();
+ act(() => {
+ result.getByTestId('buttonsFooter-nextButton').click();
+ });
+ });
+
+ it('should report telemetry for review step completion', () => {
+ expect(mockReportEvent).toHaveBeenCalledWith(
+ TelemetryEventType.IntegrationAssistantStepComplete,
+ {
+ sessionId: expect.any(String),
+ step: 4,
+ stepName: 'Review Step',
+ durationMs: expect.any(Number),
+ sessionElapsedTime: expect.any(Number),
+ }
+ );
+ });
+
+ it('should show deploy step', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.queryByTestId('deployStepMock')).toBeInTheDocument();
+ });
+
+ it('should enable the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeEnabled();
+ });
+ });
});
});
@@ -157,6 +545,26 @@ describe('CreateIntegration', () => {
const result = renderIntegrationAssistant();
expect(result.queryByTestId('deployStepMock')).toBeInTheDocument();
});
+
+ it('should hide the back button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.queryByTestId('buttonsFooter-backButton')).toBe(null);
+ });
+
+ it('should hide the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.queryByTestId('buttonsFooter-backButton')).toBe(null);
+ });
+
+ it('should enable the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toBeEnabled();
+ });
+
+ it('should show "Close" on the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toHaveTextContent('Close');
+ });
});
});
@@ -179,9 +587,107 @@ describe('CreateIntegration with generateCel enabled', () => {
expect(result.queryByTestId('celInputStepMock')).toBeInTheDocument();
});
- it('should call isCelInputStepReady', () => {
+ it('should call isCelInputStepReadyToComplete', () => {
renderIntegrationAssistant();
- expect(mockIsCelInputStepReady).toHaveBeenCalled();
+ expect(mockIsCelInputStepReadyToComplete).toHaveBeenCalled();
+ });
+
+ it('should show "Generate CEL input configuration" on the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toHaveTextContent(
+ 'Generate CEL input configuration'
+ );
+ });
+
+ it('should enable the back button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-backButton')).toBeEnabled();
+ });
+
+ describe('when cel input step is not done', () => {
+ beforeEach(() => {
+ mockIsCelInputStepReadyToComplete.mockReturnValue(false);
+ });
+
+ it('should disable the next button', () => {
+ const result = renderIntegrationAssistant();
+ // Not sure why there are two buttons when testing.
+ const nextButton = result
+ .getAllByTestId('buttonsFooter-nextButton')
+ .filter((button) => button.textContent !== 'Next')[0];
+ expect(nextButton).toBeDisabled();
+ });
+ });
+
+ describe('when cel input step is done', () => {
+ beforeEach(() => {
+ mockIsCelInputStepReadyToComplete.mockReturnValue(true);
+ });
+
+ it('should enable the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeEnabled();
+ });
+
+ describe('when next button is clicked', () => {
+ beforeEach(() => {
+ const result = renderIntegrationAssistant();
+ mockReportEvent.mockClear();
+ act(() => {
+ result.getByTestId('buttonsFooter-nextButton').click();
+ });
+ });
+
+ it('should report telemetry for cel input step completion', () => {
+ expect(mockReportEvent).toHaveBeenCalledWith(
+ TelemetryEventType.IntegrationAssistantStepComplete,
+ {
+ sessionId: expect.any(String),
+ step: 5,
+ stepName: 'CEL Input Step',
+ durationMs: expect.any(Number),
+ sessionElapsedTime: expect.any(Number),
+ }
+ );
+ });
+
+ it('should show loader on the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('generatingLoader')).toBeInTheDocument();
+ });
+
+ it('should disable the next button', () => {
+ const result = renderIntegrationAssistant();
+ // Not sure why there are two buttons when testing.
+ const nextButton = result
+ .getAllByTestId('buttonsFooter-nextButton')
+ .filter((button) => button.textContent !== 'Next')[0];
+ expect(nextButton).toBeDisabled();
+ });
+ });
+ });
+
+ describe('when back button is clicked', () => {
+ let result: ReturnType;
+ beforeEach(() => {
+ result = renderIntegrationAssistant();
+ mockReportEvent.mockClear();
+ act(() => {
+ result.getByTestId('buttonsFooter-backButton').click();
+ });
+ });
+
+ it('should not report telemetry', () => {
+ expect(mockReportEvent).not.toHaveBeenCalled();
+ });
+
+ it('should show review step', () => {
+ expect(result.queryByTestId('reviewStepMock')).toBeInTheDocument();
+ });
+
+ it('should enable the next button', () => {
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeEnabled();
+ });
});
});
@@ -194,6 +700,26 @@ describe('CreateIntegration with generateCel enabled', () => {
const result = renderIntegrationAssistant();
expect(result.queryByTestId('deployStepMock')).toBeInTheDocument();
});
+
+ it('should hide the back button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.queryByTestId('buttonsFooter-backButton')).toBe(null);
+ });
+
+ it('should hide the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.queryByTestId('buttonsFooter-backButton')).toBe(null);
+ });
+
+ it('should enable the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toBeEnabled();
+ });
+
+ it('should show "Close" on the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toHaveTextContent('Close');
+ });
});
describe('when step is 6', () => {
@@ -210,9 +736,89 @@ describe('CreateIntegration with generateCel enabled', () => {
expect(result.queryByTestId('reviewCelStepMock')).toBeInTheDocument();
});
- it('should call isReviewCelStepReady', () => {
+ it('should call isReviewCelStepReadyToComplete', () => {
renderIntegrationAssistant();
- expect(mockIsCelReviewStepReady).toHaveBeenCalled();
+ expect(mockIsCelReviewStepReadyToComplete).toHaveBeenCalled();
+ });
+
+ it('should show the "Add to Elastic" on the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toHaveTextContent('Add to Elastic');
+ });
+
+ describe('when cel review step is not done', () => {
+ beforeEach(() => {
+ mockIsCelReviewStepReadyToComplete.mockReturnValue(false);
+ });
+
+ it('should disable the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeDisabled();
+ });
+
+ it('should still enable the back button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-backButton')).toBeEnabled();
+ });
+
+ it('should still enable the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toBeEnabled();
+ });
+ });
+
+ describe('when cel review step is done', () => {
+ beforeEach(() => {
+ mockIsCelReviewStepReadyToComplete.mockReturnValue(true);
+ });
+
+ it('should enable the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeEnabled();
+ });
+
+ it('should enable the back button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-backButton')).toBeEnabled();
+ });
+
+ it('should enable the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toBeEnabled();
+ });
+
+ describe('when next button is clicked', () => {
+ beforeEach(() => {
+ const result = renderIntegrationAssistant();
+ mockReportEvent.mockClear();
+ act(() => {
+ result.getByTestId('buttonsFooter-nextButton').click();
+ });
+ });
+
+ it('should report telemetry for review step completion', () => {
+ expect(mockReportEvent).toHaveBeenCalledWith(
+ TelemetryEventType.IntegrationAssistantStepComplete,
+ {
+ sessionId: expect.any(String),
+ step: 6,
+ stepName: 'CEL Review Step',
+ durationMs: expect.any(Number),
+ sessionElapsedTime: expect.any(Number),
+ }
+ );
+ });
+
+ it('should show deploy step', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.queryByTestId('deployStepMock')).toBeInTheDocument();
+ });
+
+ it('should enable the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-nextButton')).toBeEnabled();
+ });
+ });
});
});
@@ -225,5 +831,25 @@ describe('CreateIntegration with generateCel enabled', () => {
const result = renderIntegrationAssistant();
expect(result.queryByTestId('deployStepMock')).toBeInTheDocument();
});
+
+ it('should hide the back button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.queryByTestId('buttonsFooter-backButton')).toBe(null);
+ });
+
+ it('should hide the next button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.queryByTestId('buttonsFooter-backButton')).toBe(null);
+ });
+
+ it('should enable the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toBeEnabled();
+ });
+
+ it('should show "Close" on the cancel button', () => {
+ const result = renderIntegrationAssistant();
+ expect(result.getByTestId('buttonsFooter-cancelButton')).toHaveTextContent('Close');
+ });
});
});
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/create_integration_assistant.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/create_integration_assistant.tsx
index 72e085e19920a..81cb5a9b3b137 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/create_integration_assistant.tsx
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/create_integration_assistant.tsx
@@ -5,31 +5,96 @@
* 2.0.
*/
-import React, { useReducer, useMemo, useEffect } from 'react';
+import React, { useReducer, useMemo, useEffect, useCallback } from 'react';
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
import { Header } from './header';
import { Footer } from './footer';
-import { ConnectorStep, isConnectorStepReady } from './steps/connector_step';
-import { IntegrationStep, isIntegrationStepReady } from './steps/integration_step';
-import { DataStreamStep, isDataStreamStepReady } from './steps/data_stream_step';
-import { ReviewStep, isReviewStepReady } from './steps/review_step';
-import { CelInputStep, isCelInputStepReady } from './steps/cel_input_step';
-import { ReviewCelStep, isCelReviewStepReady } from './steps/review_cel_step';
+import { useNavigate, Page } from '../../../common/hooks/use_navigate';
+import { ConnectorStep, isConnectorStepReadyToComplete } from './steps/connector_step';
+import { IntegrationStep, isIntegrationStepReadyToComplete } from './steps/integration_step';
+import { DataStreamStep, isDataStreamStepReadyToComplete } from './steps/data_stream_step';
+import { ReviewStep, isReviewStepReadyToComplete } from './steps/review_step';
+import { CelInputStep, isCelInputStepReadyToComplete } from './steps/cel_input_step';
+import { ReviewCelStep, isCelReviewStepReadyToComplete } from './steps/review_cel_step';
import { DeployStep } from './steps/deploy_step';
import { reducer, initialState, ActionsProvider, type Actions } from './state';
import { useTelemetry } from '../telemetry';
import { ExperimentalFeaturesService } from '../../../services';
+const stepNames: Record = {
+ 1: 'Connector Step',
+ 2: 'Integration Step',
+ 3: 'DataStream Step',
+ 4: 'Review Step',
+ cel_input: 'CEL Input Step',
+ cel_review: 'CEL Review Step',
+ deploy: 'Deploy Step',
+};
+
export const CreateIntegrationAssistant = React.memo(() => {
const [state, dispatch] = useReducer(reducer, initialState);
-
+ const navigate = useNavigate();
const { generateCel: isGenerateCelEnabled } = ExperimentalFeaturesService.get();
+ const celInputStepIndex = isGenerateCelEnabled && state.hasCelInput ? 5 : null;
+ const celReviewStepIndex = isGenerateCelEnabled && state.celInputResult ? 6 : null;
+ const deployStepIndex =
+ celInputStepIndex !== null || celReviewStepIndex !== null || state.step === 7 ? 7 : 5;
+
+ const stepName =
+ state.step === deployStepIndex
+ ? stepNames.deploy
+ : state.step === celReviewStepIndex
+ ? stepNames.cel_review
+ : state.step === celInputStepIndex
+ ? stepNames.cel_input
+ : state.step in stepNames
+ ? stepNames[state.step]
+ : 'Unknown Step';
+
const telemetry = useTelemetry();
useEffect(() => {
telemetry.reportAssistantOpen();
}, [telemetry]);
+ const isThisStepReadyToComplete = useMemo(() => {
+ if (state.step === 1) {
+ return isConnectorStepReadyToComplete(state);
+ } else if (state.step === 2) {
+ return isIntegrationStepReadyToComplete(state);
+ } else if (state.step === 3) {
+ return isDataStreamStepReadyToComplete(state);
+ } else if (state.step === 4) {
+ return isReviewStepReadyToComplete(state);
+ } else if (isGenerateCelEnabled && state.step === 5) {
+ return isCelInputStepReadyToComplete(state);
+ } else if (isGenerateCelEnabled && state.step === 6) {
+ return isCelReviewStepReadyToComplete(state);
+ }
+ return false;
+ }, [state, isGenerateCelEnabled]);
+
+ const goBackStep = useCallback(() => {
+ if (state.step === 1) {
+ navigate(Page.landing);
+ } else {
+ dispatch({ type: 'SET_STEP', payload: state.step - 1 });
+ }
+ }, [navigate, dispatch, state.step]);
+
+ const completeStep = useCallback(() => {
+ if (!isThisStepReadyToComplete) {
+ // If the user tries to navigate to the next step without completing the current step.
+ return;
+ }
+ telemetry.reportAssistantStepComplete({ step: state.step, stepName });
+ if (state.step === 3 || state.step === celInputStepIndex) {
+ dispatch({ type: 'SET_IS_GENERATING', payload: true });
+ } else {
+ dispatch({ type: 'SET_STEP', payload: state.step + 1 });
+ }
+ }, [telemetry, state.step, stepName, celInputStepIndex, isThisStepReadyToComplete]);
+
const actions = useMemo(
() => ({
setStep: (payload) => {
@@ -53,27 +118,11 @@ export const CreateIntegrationAssistant = React.memo(() => {
setCelInputResult: (payload) => {
dispatch({ type: 'SET_CEL_INPUT_RESULT', payload });
},
+ completeStep,
}),
- []
+ [completeStep]
);
- const isNextStepEnabled = useMemo(() => {
- if (state.step === 1) {
- return isConnectorStepReady(state);
- } else if (state.step === 2) {
- return isIntegrationStepReady(state);
- } else if (state.step === 3) {
- return isDataStreamStepReady(state);
- } else if (state.step === 4) {
- return isReviewStepReady(state);
- } else if (isGenerateCelEnabled && state.step === 5) {
- return isCelInputStepReady(state);
- } else if (isGenerateCelEnabled && state.step === 6) {
- return isCelReviewStepReady(state);
- }
- return false;
- }, [state, isGenerateCelEnabled]);
-
return (
@@ -95,28 +144,21 @@ export const CreateIntegrationAssistant = React.memo(() => {
result={state.result}
/>
)}
- {state.step === 5 &&
- (isGenerateCelEnabled && state.hasCelInput ? (
-
- ) : (
-
- ))}
-
- {isGenerateCelEnabled && state.celInputResult && state.step === 6 && (
+ {state.step === celInputStepIndex && (
+
+ )}
+ {state.step === celReviewStepIndex && (
)}
- {isGenerateCelEnabled && state.step === 7 && (
+
+ {state.step === deployStepIndex && (
{
)}
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/footer/footer.test.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/footer/footer.test.tsx
index 1ca79210bb19f..1291507e3f62b 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/footer/footer.test.tsx
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/footer/footer.test.tsx
@@ -6,13 +6,11 @@
*/
import React from 'react';
-import { render, act, type RenderResult } from '@testing-library/react';
+import { render, type RenderResult } from '@testing-library/react';
import { TestProvider } from '../../../../mocks/test_provider';
import { Footer } from './footer';
import { ActionsProvider } from '../state';
import { mockActions } from '../mocks/state';
-import { mockReportEvent } from '../../../../services/telemetry/mocks/service';
-import { TelemetryEventType } from '../../../../services/telemetry/types';
import { ExperimentalFeaturesService } from '../../../../services';
const mockNavigate = jest.fn();
@@ -39,15 +37,12 @@ describe('Footer', () => {
} as never);
});
- describe('when rendered', () => {
+ describe('when rendered for the most common case', () => {
let result: RenderResult;
beforeEach(() => {
- result = render(
- ,
- {
- wrapper,
- }
- );
+ result = render(, {
+ wrapper,
+ });
});
it('should render footer buttons component', () => {
expect(result.queryByTestId('buttonsFooter')).toBeInTheDocument();
@@ -65,230 +60,4 @@ describe('Footer', () => {
expect(result.queryByTestId('buttonsFooter-nextButton')).toBeInTheDocument();
});
});
-
- describe('when step is 1', () => {
- let result: RenderResult;
- beforeEach(() => {
- result = render(
- ,
- {
- wrapper,
- }
- );
- });
-
- describe('when next button is clicked', () => {
- beforeEach(() => {
- act(() => {
- result.getByTestId('buttonsFooter-nextButton').click();
- });
- });
-
- it('should set step 2', () => {
- expect(mockActions.setStep).toHaveBeenCalledWith(2);
- });
-
- it('should report telemetry', () => {
- expect(mockReportEvent).toHaveBeenCalledWith(
- TelemetryEventType.IntegrationAssistantStepComplete,
- {
- sessionId: expect.any(String),
- step: 1,
- stepName: 'Connector Step',
- durationMs: expect.any(Number),
- sessionElapsedTime: expect.any(Number),
- }
- );
- });
- });
-
- describe('when back button is clicked', () => {
- beforeEach(() => {
- act(() => {
- result.getByTestId('buttonsFooter-backButton').click();
- });
- });
-
- it('should navigate to landing', () => {
- expect(mockNavigate).toHaveBeenCalledWith('landing');
- });
- });
- });
-
- describe('when step is 2', () => {
- let result: RenderResult;
- beforeEach(() => {
- result = render(
- ,
- {
- wrapper,
- }
- );
- });
-
- describe('when next button is clicked', () => {
- beforeEach(() => {
- act(() => {
- result.getByTestId('buttonsFooter-nextButton').click();
- });
- });
-
- it('should set step 3', () => {
- expect(mockActions.setStep).toHaveBeenCalledWith(3);
- });
-
- it('should report telemetry', () => {
- expect(mockReportEvent).toHaveBeenCalledWith(
- TelemetryEventType.IntegrationAssistantStepComplete,
- {
- sessionId: expect.any(String),
- step: 2,
- stepName: 'Integration Step',
- durationMs: expect.any(Number),
- sessionElapsedTime: expect.any(Number),
- }
- );
- });
- });
-
- describe('when back button is clicked', () => {
- beforeEach(() => {
- act(() => {
- result.getByTestId('buttonsFooter-backButton').click();
- });
- });
-
- it('should set step 1', () => {
- expect(mockActions.setStep).toHaveBeenCalledWith(1);
- });
- });
- });
-
- describe('when step is 3', () => {
- describe('when it is not generating', () => {
- let result: RenderResult;
- beforeEach(() => {
- result = render(
- ,
- {
- wrapper,
- }
- );
- });
-
- describe('when next button is clicked', () => {
- beforeEach(() => {
- act(() => {
- result.getByTestId('buttonsFooter-nextButton').click();
- });
- });
-
- it('should set step 4', () => {
- expect(mockActions.setIsGenerating).toHaveBeenCalledWith(true);
- });
-
- it('should report telemetry', () => {
- expect(mockReportEvent).toHaveBeenCalledWith(
- TelemetryEventType.IntegrationAssistantStepComplete,
- {
- sessionId: expect.any(String),
- step: 3,
- stepName: 'DataStream Step',
- durationMs: expect.any(Number),
- sessionElapsedTime: expect.any(Number),
- }
- );
- });
- });
-
- describe('when back button is clicked', () => {
- beforeEach(() => {
- act(() => {
- result.getByTestId('buttonsFooter-backButton').click();
- });
- });
-
- it('should set step 2', () => {
- expect(mockActions.setStep).toHaveBeenCalledWith(2);
- });
- });
- });
-
- describe('when it is generating', () => {
- let result: RenderResult;
- beforeEach(() => {
- result = render(
- ,
- {
- wrapper,
- }
- );
- });
-
- it('should render the loader', () => {
- expect(result.queryByTestId('generatingLoader')).toBeInTheDocument();
- });
- });
- });
-
- describe('when step is 4', () => {
- let result: RenderResult;
- beforeEach(() => {
- result = render(
- ,
- {
- wrapper,
- }
- );
- });
-
- describe('when next button is clicked', () => {
- beforeEach(() => {
- act(() => {
- result.getByTestId('buttonsFooter-nextButton').click();
- });
- });
-
- it('should set step 5', () => {
- expect(mockActions.setStep).toHaveBeenCalledWith(5);
- });
-
- it('should report telemetry', () => {
- expect(mockReportEvent).toHaveBeenCalledWith(
- TelemetryEventType.IntegrationAssistantStepComplete,
- {
- sessionId: expect.any(String),
- step: 4,
- stepName: 'Review Step',
- durationMs: expect.any(Number),
- sessionElapsedTime: expect.any(Number),
- }
- );
- });
- });
-
- describe('when back button is clicked', () => {
- beforeEach(() => {
- act(() => {
- result.getByTestId('buttonsFooter-backButton').click();
- });
- });
-
- it('should set step 3', () => {
- expect(mockActions.setStep).toHaveBeenCalledWith(3);
- });
- });
- });
-
- describe('when next step is disabled', () => {
- let result: RenderResult;
- beforeEach(() => {
- result = render(, {
- wrapper,
- });
- });
- it('should render next button disabled', () => {
- expect(result.queryByTestId('buttonsFooter-nextButton')).toBeDisabled();
- });
- });
});
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/footer/footer.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/footer/footer.tsx
index 839d751e6f380..dfd38517e1609 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/footer/footer.tsx
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/footer/footer.tsx
@@ -6,13 +6,10 @@
*/
import { EuiLoadingSpinner } from '@elastic/eui';
-import React, { useCallback, useMemo } from 'react';
+import React, { useMemo } from 'react';
import { ButtonsFooter } from '../../../../common/components/buttons_footer';
-import { useNavigate, Page } from '../../../../common/hooks/use_navigate';
-import { useTelemetry } from '../../telemetry';
-import { useActions, type State } from '../state';
+import { type State } from '../state';
import * as i18n from './translations';
-import { ExperimentalFeaturesService } from '../../../../services';
// Generation button for Step 3
const AnalyzeButtonText = React.memo<{ isGenerating: boolean }>(({ isGenerating }) => {
@@ -43,61 +40,47 @@ const AnalyzeCelButtonText = React.memo<{ isGenerating: boolean }>(({ isGenerati
AnalyzeCelButtonText.displayName = 'AnalyzeCelButtonText';
interface FooterProps {
- currentStep: State['step'];
- isGenerating: State['isGenerating'];
- hasCelInput: State['hasCelInput'];
+ isGenerating?: State['isGenerating'];
+ isAnalyzeStep?: boolean;
+ isAnalyzeCelStep?: boolean;
+ isLastStep?: boolean;
isNextStepEnabled?: boolean;
+ isNextAddingToElastic?: boolean;
+ onBack?: () => void;
+ onNext?: () => void;
}
export const Footer = React.memo(
- ({ currentStep, isGenerating, hasCelInput, isNextStepEnabled = false }) => {
- const telemetry = useTelemetry();
- const { setStep, setIsGenerating } = useActions();
- const navigate = useNavigate();
-
- const { generateCel: isGenerateCelEnabled } = ExperimentalFeaturesService.get();
-
- const onBack = useCallback(() => {
- if (currentStep === 1) {
- navigate(Page.landing);
- } else {
- setStep(currentStep - 1);
- }
- }, [currentStep, navigate, setStep]);
-
- const onNext = useCallback(() => {
- telemetry.reportAssistantStepComplete({ step: currentStep });
- if (currentStep === 3 || currentStep === 5) {
- setIsGenerating(true);
- } else {
- setStep(currentStep + 1);
- }
- }, [currentStep, setIsGenerating, setStep, telemetry]);
-
- const nextButtonText = useMemo(() => {
- if (currentStep === 3) {
- return ;
- }
- if (currentStep === 4 && (!isGenerateCelEnabled || !hasCelInput)) {
- return i18n.ADD_TO_ELASTIC;
- }
- if (currentStep === 5 && isGenerateCelEnabled && hasCelInput) {
- return ;
- }
- if (currentStep === 6 && isGenerateCelEnabled) {
- return i18n.ADD_TO_ELASTIC;
- }
- }, [currentStep, isGenerating, hasCelInput, isGenerateCelEnabled]);
+ ({
+ isGenerating = false,
+ isAnalyzeStep = false,
+ isAnalyzeCelStep = false,
+ isLastStep = false,
+ isNextStepEnabled = false,
+ isNextAddingToElastic = false,
+ onBack = () => {},
+ onNext = () => {},
+ }) => {
+ const nextButtonText = useMemo(
+ () =>
+ isNextAddingToElastic ? (
+ i18n.ADD_TO_ELASTIC
+ ) : isAnalyzeStep ? (
+
+ ) : isAnalyzeCelStep ? (
+
+ ) : null,
+ [isNextAddingToElastic, isAnalyzeStep, isGenerating, isAnalyzeCelStep]
+ );
- if (currentStep === 7 || (currentStep === 5 && (!isGenerateCelEnabled || !hasCelInput))) {
- return ;
- }
- return (
+ return isLastStep ? (
+
+ ) : (
);
}
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/mocks/state.ts b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/mocks/state.ts
index c25a78a35416e..bdae762e83c2b 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/mocks/state.ts
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/mocks/state.ts
@@ -435,4 +435,5 @@ export const mockActions: Actions = {
setHasCelInput: jest.fn(),
setResult: jest.fn(),
setCelInputResult: jest.fn(),
+ completeStep: jest.fn(),
};
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/state.ts b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/state.ts
index 1e7b22128843b..17ac3bdd9f90f 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/state.ts
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/state.ts
@@ -78,6 +78,7 @@ export interface Actions {
setHasCelInput: (payload: State['hasCelInput']) => void;
setResult: (payload: State['result']) => void;
setCelInputResult: (payload: State['celInputResult']) => void;
+ completeStep: () => void;
}
const ActionsContext = createContext(undefined);
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/cel_input_step/cel_input_step.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/cel_input_step/cel_input_step.tsx
index b0a0b3194ec33..851ea3f7e6a21 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/cel_input_step/cel_input_step.tsx
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/cel_input_step/cel_input_step.tsx
@@ -22,7 +22,7 @@ interface CelInputStepProps {
export const CelInputStep = React.memo(
({ integrationSettings, connector, isGenerating }) => {
- const { setIsGenerating, setStep, setCelInputResult } = useActions();
+ const { setIsGenerating, setStep, setCelInputResult, completeStep } = useActions();
const onGenerationCompleted = useCallback(
(result: State['celInputResult']) => {
@@ -43,7 +43,14 @@ export const CelInputStep = React.memo(
-
+ {
+ e.preventDefault();
+ completeStep();
+ }}
+ >
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/cel_input_step/is_step_ready.ts b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/cel_input_step/is_step_ready.ts
index 594f4230164ce..fa89ccc3882db 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/cel_input_step/is_step_ready.ts
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/cel_input_step/is_step_ready.ts
@@ -6,7 +6,7 @@
*/
import type { State } from '../../state';
-export const isCelInputStepReady = ({ integrationSettings }: State) =>
+export const isCelInputStepReadyToComplete = ({ integrationSettings }: State) =>
Boolean(
integrationSettings?.name &&
integrationSettings?.dataStreamTitle &&
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_selector.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_selector.tsx
index 4ea33cc8668e3..509a9a3058cf0 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_selector.tsx
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_selector.tsx
@@ -6,12 +6,18 @@
*/
import React from 'react';
-import { useEuiTheme, EuiBadge, EuiFlexGroup, EuiFlexItem, EuiPanel, EuiRadio } from '@elastic/eui';
-import { noop } from 'lodash/fp';
+import {
+ useEuiTheme,
+ EuiBadge,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiPanel,
+ EuiRadio,
+ EuiFormFieldset,
+} from '@elastic/eui';
import { css } from '@emotion/react';
import { useKibana } from '../../../../../common/hooks/use_kibana';
import type { AIConnector } from '../../types';
-import { useActions } from '../../state';
const useRowCss = () => {
const { euiTheme } = useEuiTheme();
@@ -36,54 +42,60 @@ const useRowCss = () => {
interface ConnectorSelectorProps {
connectors: AIConnector[];
selectedConnectorId: string | undefined;
+ setConnector: (connector: AIConnector | undefined) => void;
}
export const ConnectorSelector = React.memo(
- ({ connectors, selectedConnectorId }) => {
+ ({ connectors, setConnector, selectedConnectorId }) => {
const {
triggersActionsUi: { actionTypeRegistry },
} = useKibana().services;
- const { setConnector } = useActions();
const rowCss = useRowCss();
return (
-
- {connectors.map((connector) => (
-
- setConnector(connector)}
- hasShadow={false}
- hasBorder
- paddingSize="l"
- css={rowCss}
- data-test-subj={`connectorSelector-${connector.id}`}
- >
-
-
-
-
-
-
- {actionTypeRegistry.get(connector.actionTypeId).actionTypeTitle}
-
-
-
-
-
- ))}
-
+
+
+ {connectors.map((connector) => (
+
+ setConnector(connector)}
+ hasShadow={false}
+ hasBorder
+ paddingSize="l"
+ css={rowCss}
+ data-test-subj={`connectorSelector-${connector.id}`}
+ >
+
+
+ setConnector(connector)}
+ data-test-subj={`connectorSelectorRadio-${connector.id}${
+ selectedConnectorId === connector.id ? '-selected' : ''
+ }`}
+ />
+
+
+
+ {actionTypeRegistry.get(connector.actionTypeId).actionTypeTitle}
+
+
+
+
+
+ ))}
+
+
);
}
);
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_step.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_step.tsx
index c2643ffa9e92c..8c7fa66795c81 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_step.tsx
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_step.tsx
@@ -8,6 +8,7 @@
import React, { useCallback, useEffect, useState } from 'react';
import { useLoadConnectors } from '@kbn/elastic-assistant';
import {
+ EuiForm,
EuiFlexGroup,
EuiFlexItem,
EuiLoadingSpinner,
@@ -42,7 +43,8 @@ interface ConnectorStepProps {
export const ConnectorStep = React.memo(({ connector }) => {
const { euiTheme } = useEuiTheme();
const { http, notifications } = useKibana().services;
- const { setConnector } = useActions();
+ const { setConnector, completeStep } = useActions();
+
const [connectors, setConnectors] = useState();
const {
isLoading,
@@ -69,41 +71,56 @@ export const ConnectorStep = React.memo(({ connector }) => {
const hasConnectors = !isLoading && connectors?.length;
return (
- : null}
+ {
+ e.preventDefault();
+ completeStep();
+ }}
>
-
-
- {isLoading ? (
-
- ) : (
- <>
- {hasConnectors ? (
-
- ) : (
-
- : null
+ }
+ >
+
+
+ {isLoading ? (
+
+ ) : (
+ <>
+ {hasConnectors ? (
+
-
- )}
- >
- )}
-
-
-
-
-
-
-
+ ) : (
+
+
+
+ )}
+ >
+ )}
- {i18n.SUPPORTED_MODELS_INFO}
-
-
+
+
+
+
+
+
+ {i18n.SUPPORTED_MODELS_INFO}
+
+
+
+
);
});
ConnectorStep.displayName = 'ConnectorStep';
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/is_step_ready.ts b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/is_step_ready.ts
index 5b425b0940094..cc09cd2a6c87b 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/is_step_ready.ts
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/is_step_ready.ts
@@ -7,4 +7,4 @@
import type { State } from '../../state';
-export const isConnectorStepReady = ({ connector }: State) => connector != null;
+export const isConnectorStepReadyToComplete = ({ connector }: State) => connector != null;
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/data_stream_step.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/data_stream_step.tsx
index 4b505fb7062d6..1bd7b92b2e0cb 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/data_stream_step.tsx
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/data_stream_step.tsx
@@ -53,8 +53,14 @@ interface DataStreamStepProps {
}
export const DataStreamStep = React.memo(
({ integrationSettings, connector, isGenerating }) => {
- const { setIntegrationSettings, setIsGenerating, setHasCelInput, setStep, setResult } =
- useActions();
+ const {
+ setIntegrationSettings,
+ setIsGenerating,
+ setHasCelInput,
+ setStep,
+ setResult,
+ completeStep,
+ } = useActions();
const { isLoading: isLoadingPackageNames, packageNames } = useLoadPackageNames(); // this is used to avoid duplicate names
const [name, setName] = useState(integrationSettings?.name ?? '');
@@ -150,14 +156,21 @@ export const DataStreamStep = React.memo(
);
return (
-
-
-
-
-
+ {
+ e.preventDefault();
+ completeStep();
+ }}
+ >
+
+
+
+
(
disabled={isLoadingPackageNames}
/>
-
-
-
-
+
+
+
-
-
-
-
+
+
+
(
/>
-
-
-
- {isGenerating && (
-
- )}
-
-
+
+
+ {isGenerating && (
+
+ )}
+
+
+
);
}
);
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/is_step_ready.ts b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/is_step_ready.ts
index 4a40334a72ab2..509ee99b4122f 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/is_step_ready.ts
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/is_step_ready.ts
@@ -6,7 +6,7 @@
*/
import type { State } from '../../state';
-export const isDataStreamStepReady = ({ integrationSettings }: State) =>
+export const isDataStreamStepReadyToComplete = ({ integrationSettings }: State) =>
Boolean(
integrationSettings?.name &&
integrationSettings?.dataStreamTitle &&
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/integration_step/integration_step.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/integration_step/integration_step.tsx
index dc27abd9529cd..928f4db5f065f 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/integration_step/integration_step.tsx
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/integration_step/integration_step.tsx
@@ -51,7 +51,7 @@ interface IntegrationStepProps {
export const IntegrationStep = React.memo(({ integrationSettings }) => {
const styles = useLayoutStyles();
- const { setIntegrationSettings } = useActions();
+ const { setIntegrationSettings, completeStep } = useActions();
const [logoError, setLogoError] = React.useState();
const setIntegrationValues = useCallback(
@@ -95,7 +95,14 @@ export const IntegrationStep = React.memo(({ integrationSe
-
+ {
+ e.preventDefault();
+ completeStep();
+ }}
+ >
+export const isIntegrationStepReadyToComplete = ({ integrationSettings }: State) =>
Boolean(integrationSettings?.title && integrationSettings?.description);
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/review_cel_step/is_step_ready.ts b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/review_cel_step/is_step_ready.ts
index 166c40e8e2614..902cdea32d5e0 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/review_cel_step/is_step_ready.ts
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/review_cel_step/is_step_ready.ts
@@ -7,5 +7,5 @@
import type { State } from '../../state';
-export const isCelReviewStepReady = ({ isGenerating, celInputResult }: State) =>
+export const isCelReviewStepReadyToComplete = ({ isGenerating, celInputResult }: State) =>
isGenerating === false && celInputResult != null;
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/review_cel_step/review_cel_step.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/review_cel_step/review_cel_step.tsx
index a40fec082894e..85b9980a4a5de 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/review_cel_step/review_cel_step.tsx
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/review_cel_step/review_cel_step.tsx
@@ -4,9 +4,9 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
-import { EuiLoadingSpinner, EuiPanel } from '@elastic/eui';
+import { EuiForm, EuiLoadingSpinner, EuiPanel } from '@elastic/eui';
import React from 'react';
-import type { State } from '../../state';
+import { useActions, type State } from '../../state';
import { StepContentWrapper } from '../step_content_wrapper';
import * as i18n from './translations';
import { CelConfigResults } from './cel_config_results';
@@ -17,15 +17,24 @@ interface ReviewCelStepProps {
}
export const ReviewCelStep = React.memo(({ isGenerating, celInputResult }) => {
+ const { completeStep } = useActions();
+
return (
{isGenerating ? (
) : (
- <>
+ {
+ e.preventDefault();
+ completeStep();
+ }}
+ >
- >
+
)}
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/review_step/is_step_ready.ts b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/review_step/is_step_ready.ts
index b03215c5e8255..91b9726e03a3e 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/review_step/is_step_ready.ts
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/review_step/is_step_ready.ts
@@ -7,5 +7,5 @@
import type { State } from '../../state';
-export const isReviewStepReady = ({ isGenerating, result }: State) =>
+export const isReviewStepReadyToComplete = ({ isGenerating, result }: State) =>
isGenerating === false && result != null;
diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/telemetry.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/telemetry.tsx
index 39076726b7f9d..04d8a07cd1288 100644
--- a/x-pack/plugins/integration_assistant/public/components/create_integration/telemetry.tsx
+++ b/x-pack/plugins/integration_assistant/public/components/create_integration/telemetry.tsx
@@ -15,20 +15,12 @@ import type {
IntegrationSettings,
} from './create_integration_assistant/types';
-const stepNames: Record = {
- '1': 'Connector Step',
- '2': 'Integration Step',
- '3': 'DataStream Step',
- '4': 'Review Step',
- '5': 'Deploy Step',
-};
-
type ReportUploadZipIntegrationComplete = (params: {
integrationName?: string;
error?: string;
}) => void;
type ReportAssistantOpen = () => void;
-type ReportAssistantStepComplete = (params: { step: number }) => void;
+type ReportAssistantStepComplete = (params: { step: number; stepName: string }) => void;
type ReportGenerationComplete = (params: {
connector: AIConnector;
integrationSettings: IntegrationSettings;
@@ -92,11 +84,11 @@ export const TelemetryContextProvider = React.memo>(({ chi
}, [telemetry]);
const reportAssistantStepComplete = useCallback(
- ({ step }) => {
+ ({ step, stepName }) => {
telemetry.reportEvent(TelemetryEventType.IntegrationAssistantStepComplete, {
sessionId: sessionData.current.sessionId,
step,
- stepName: stepNames[step.toString()] ?? 'Unknown Step',
+ stepName,
durationMs: Date.now() - stepsData.current.startedAt,
sessionElapsedTime: Date.now() - sessionData.current.startedAt,
});