[Guided onboarding] Fix "done" state showing before last step is marked as completed (#144221)

Fixes https://github.com/elastic/kibana/issues/144165

### Summary
This PR addresses the issue with the "done" state being shown before the
last step is marked as completed when the last step is a manual
completion step



https://user-images.githubusercontent.com/53621505/198980758-dba2d763-76ff-40a7-97ba-765333f20524.mov

Co-authored-by: Muhammad Ibragimov <muhammad.ibragimov@elastic.co>
This commit is contained in:
Muhammad Ibragimov 2022-11-11 14:53:10 +05:00 committed by GitHub
parent 3293aefc97
commit d077a51d15
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 117 additions and 3 deletions

View file

@ -235,6 +235,36 @@ describe('Guided setup', () => {
expect(exists('onboarding--completeGuideButton--testGuide')).toBe(true);
});
test('should not show the completed state when the last step is not marked as complete', async () => {
const { component, exists, find } = testBed;
const mockCompleteTestGuideState: GuideState = {
...mockActiveTestGuideState,
steps: [
{
id: mockActiveTestGuideState.steps[0].id,
status: 'complete',
},
{
id: mockActiveTestGuideState.steps[1].id,
status: 'complete',
},
{
id: mockActiveTestGuideState.steps[2].id,
status: 'complete',
},
],
};
await updateComponentWithState(component, mockCompleteTestGuideState, true);
expect(find('guideTitle').text()).not.toContain('Well done');
expect(find('guideDescription').text()).not.toContain(
`You've completed the Elastic Testing example guide`
);
expect(exists('useElasticButton')).toBe(false);
});
describe('Steps', () => {
const clickStepButton = async ({
telemetryGuideId,

View file

@ -17,6 +17,7 @@ import { ApiService } from './api';
import {
testGuide,
testGuideFirstStep,
testGuideLastStep,
testGuideManualCompletionStep,
testGuideStep1ActiveState,
testGuideStep1InProgressState,
@ -359,6 +360,59 @@ describe('GuidedOnboarding ApiService', () => {
await apiService.completeGuideStep(testGuide, testGuideFirstStep);
expect(httpClient.put).toHaveBeenCalledTimes(0);
});
it('marks the guide as "ready_to_complete" if the current step is the last step in the guide and configured for manual completion', async () => {
const testGuideStep3InProgressState: GuideState = {
...testGuideStep2ActiveState,
steps: [
testGuideStep2ActiveState.steps[0],
{ ...testGuideStep2ActiveState.steps[1], status: 'complete' },
{ ...testGuideStep2ActiveState.steps[2], status: 'ready_to_complete' },
],
};
httpClient.get.mockResolvedValue({
state: [testGuideStep3InProgressState],
});
apiService.setup(httpClient);
await apiService.completeGuideStep(testGuide, testGuideLastStep);
expect(httpClient.put).toHaveBeenCalledTimes(1);
// Verify the guide now has a "ready_to_complete" status and the last step is "complete"
expect(httpClient.put).toHaveBeenCalledWith(`${API_BASE_PATH}/state`, {
body: JSON.stringify({
...testGuideStep3InProgressState,
steps: [
...testGuideStep3InProgressState.steps.slice(0, 2),
{ ...testGuideStep3InProgressState.steps[2], status: 'complete' },
],
status: 'ready_to_complete',
}),
});
});
it('marks the guide as "in_progress" if the current step is not the last step in the guide', async () => {
httpClient.get.mockResolvedValue({
state: [testGuideStep1InProgressState],
});
apiService.setup(httpClient);
await apiService.completeGuideStep(testGuide, testGuideFirstStep);
expect(httpClient.put).toHaveBeenCalledTimes(1);
// Verify the guide now has a "in_progress" status and the second step is "active"
expect(httpClient.put).toHaveBeenCalledWith(`${API_BASE_PATH}/state`, {
body: JSON.stringify({
...testGuideStep2ActiveState,
steps: [
testGuideStep2ActiveState.steps[0],
{ ...testGuideStep2ActiveState.steps[1], status: 'active' },
testGuideStep2ActiveState.steps[2],
],
status: 'in_progress',
}),
});
});
});
describe('isGuidedOnboardingActiveForIntegration$', () => {

View file

@ -16,8 +16,8 @@ import {
getInProgressStepId,
getStepConfig,
getUpdatedSteps,
getGuideStatusOnStepCompletion,
isIntegrationInGuideStep,
isLastStep,
isStepInProgress,
isStepReadyToComplete,
} from './helpers';
@ -319,7 +319,7 @@ export class ApiService implements GuidedOnboardingApi {
const currentGuide: GuideState = {
guideId,
isActive: true,
status: isLastStep(guideId, stepId) ? 'ready_to_complete' : 'in_progress',
status: getGuideStatusOnStepCompletion(guideState, guideId, stepId),
steps: updatedSteps,
};

View file

@ -6,7 +6,13 @@
* Side Public License, v 1.
*/
import type { GuideId, GuideStepIds, GuideState, GuideStep } from '@kbn/guided-onboarding';
import type {
GuideId,
GuideStepIds,
GuideState,
GuideStep,
GuideStatus,
} from '@kbn/guided-onboarding';
import { guidesConfig } from '../constants/guides_config';
import { GuideConfig, StepConfig } from '../types';
@ -128,3 +134,27 @@ export const getUpdatedSteps = (
return step;
});
};
export const getGuideStatusOnStepCompletion = (
guideState: GuideState,
guideId: GuideId,
stepId: GuideStepIds
): GuideStatus => {
const stepConfig = getStepConfig(guideId, stepId);
const isManualCompletion = stepConfig?.manualCompletion || false;
const isLastStepInGuide = isLastStep(guideId, stepId);
const isCurrentStepReadyToComplete = isStepReadyToComplete(guideState, guideId, stepId);
// We want to set the guide status to 'ready_to_complete' if the current step is the last step in the guide
// and the step is not configured for manual completion
// or if the current step is configured for manual completion and the last step is ready to complete
if (
(isLastStepInGuide && !isManualCompletion) ||
(isLastStepInGuide && isManualCompletion && isCurrentStepReadyToComplete)
) {
return 'ready_to_complete';
}
// Otherwise the guide is still in progress
return 'in_progress';
};