Skip to content

Commit

Permalink
✨ Remove pathfinder and convert assessment wizard to use new api (kon…
Browse files Browse the repository at this point in the history
…veyor#1315)

https://github.com/konveyor/tackle2-ui/assets/11218376/a8e7162b-24e3-4262-b04d-9969041e3976

This pull request aims to start the development of the single-app
application assessment flow. It includes the addition of a full flow for
the assessment process against the new data model, updates to match the
latest Go structs from the hub PR, removal of pathfinder-specific
elements, creation of msw mocks to handle assessment initial post and
patch operations, and a few other things.

Changes Made:

- Single-App Application Assessment Flow: Added a complete flow for
single-app application assessment. This flow includes handling initial
posts and patch operations.
- Model Updates: Updated the models to align with the latest Go structs
from the hub PR.
- MSW Mocks Creation: Created msw mocks to handle assessment initial
post and patch requests.

TODO:

- Comments Feature: Comments feature is currently commented out in the
assessments flow.
- Stakeholders & Stakeholder Groups: Identified that the code related to
stakeholders and stakeholder groups is not yet added to the assessment
struct on the API. Collaboration with the hub team is needed to
incorporate this functionality, as assessments can have associated
stakeholders.
- Mock Endpoint Enhancement: Need to add support for
/applications/:id/assessments when available
- Tests Update: Need to evaluate existing tests & update to match the
new data format for assessments.
- Assessment Risks Component: Will need to wire this up depending on the
future availability of the calculatedRisk assessment field from the API
- Hub Derived Fields for Assessments: Hub-derived fields for calculated
risk not yet available. These fields are planned to be calculated by the
hub after the final assessment submission, facilitating categorization
in the reports screen.
- Old Report Cards Consideration: Although the components for report
cards still exist in the repository, their usage in reports.tsx has been
commented out.

---------

Signed-off-by: ibolton336 <[email protected]>
  • Loading branch information
ibolton336 authored Aug 31, 2023
1 parent 5757dcd commit e041fe3
Show file tree
Hide file tree
Showing 45 changed files with 1,316 additions and 1,091 deletions.
145 changes: 64 additions & 81 deletions client/src/app/api/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export interface Application {
repository?: Repository;
binary?: string;
migrationWave: Ref | null;
assessments?: Questionnaire[];
assessments?: Ref[];
}

export interface Review {
Expand Down Expand Up @@ -208,67 +208,6 @@ export interface Proxy {
enabled: boolean;
}

// Pathfinder

export type AssessmentStatus = "EMPTY" | "STARTED" | "COMPLETE";
export type Risk = "GREEN" | "AMBER" | "RED" | "UNKNOWN";

export interface Assessment {
id?: number;
applicationId: number;
status: AssessmentStatus;
stakeholders?: number[];
stakeholderGroups?: number[];
questionnaire: PathfinderQuestionnaire;
}

export interface PathfinderQuestionnaire {
categories: QuestionnaireCategory[];
}

export interface QuestionnaireCategory {
id: number;
order: number;
title?: string;
comment?: string;
questions: Question[];
}

export interface Question {
id: number;
order: number;
question: string;
description: string;
options: QuestionOption[];
}

export interface QuestionOption {
id: number;
order: number;
option: string;
checked: boolean;
risk: Risk;
}

export interface AssessmentRisk {
assessmentId: number;
applicationId: number;
risk: Risk;
}

export interface AssessmentQuestionRisk {
category: string;
question: string;
answer: string;
applications: number[];
}

export interface AssessmentConfidence {
assessmentId: number;
applicationId: number;
confidence: number;
}

export interface BulkCopyAssessment {
bulkId?: number;
fromAssessmentId: number;
Expand Down Expand Up @@ -729,35 +668,79 @@ export interface RiskMessages {
}
export interface Section {
name: string;
questions: CustomYamlAssessmentQuestion[];
questions: Question[];
order: number;
}

// TODO: Rename after removing pathfinder
export interface CustomYamlAssessmentQuestion {
export interface Question {
answers: Answer[];
text: string;
order: number;
explanation?: string;
formulation: string;
include_if_tags_present?: Tag[];
skip_if_tags_present?: Tag[];
includeFor?: CategorizedTag[];
excludeFor?: CategorizedTag[];
}

export interface Answer {
choice: string;
mitigation?: string;
rationale?: string;
order: number;
text: string;
risk: string;
autoanswer_if_tags_present?: Tag[];
autotag?: Tag[];
rationale?: string;
mitigation?: string;
applyTags?: CategorizedTag[];
autoAnswerFor?: CategorizedTag[];
selected?: boolean;
}
export interface Thresholds {
red: string;
unknown: string;
yellow: string;
red: number;
unknown: number;
yellow: number;
}
export interface YamlAssessment {
description: string;
export type AssessmentStatus = "EMPTY" | "STARTED" | "COMPLETE";
export type Risk = "GREEN" | "AMBER" | "RED" | "UNKNOWN";

export interface InitialAssessment {
application?: Ref;
archetype?: Ref;
questionnaire: Ref;
}
export interface Assessment
extends Pick<Questionnaire, "thresholds" | "sections" | "riskMessages"> {
name: string;
risk_messages: RiskMessages;
sections: Section[];
thresholds: Thresholds;
id: number;
application?: Ref;
archetype?: Ref;
questionnaire: Ref;
description: string;
status: AssessmentStatus;
risk: Risk;
}
export interface CategorizedTag {
category: TagCategory;
tag: Tag;
}

//TODO: update to use new api
export interface AssessmentRisk {
assessmentId: number;
applicationId: number;
risk: Risk;
}
export interface AssessmentRisk {
assessmentId: number;
applicationId: number;
risk: Risk;
}

export interface AssessmentQuestionRisk {
category: string;
question: string;
answer: string;
applications: number[];
}

export interface AssessmentConfidence {
assessmentId: number;
applicationId: number;
confidence: number;
}
86 changes: 39 additions & 47 deletions client/src/app/api/rest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ import {
ApplicationImport,
ApplicationImportSummary,
Assessment,
AssessmentConfidence,
AssessmentQuestionRisk,
AssessmentRisk,
BulkCopyAssessment,
BulkCopyReview,
BusinessService,
Expand Down Expand Up @@ -51,6 +48,7 @@ import {
Target,
HubFile,
Questionnaire,
InitialAssessment,
} from "./models";
import { QueryKey } from "@tanstack/react-query";
import { serializeRequestParamsForHub } from "@app/hooks/table-controls";
Expand Down Expand Up @@ -111,7 +109,7 @@ export const QUESTIONNAIRES = HUB + "/questionnaires";

// PATHFINDER
export const PATHFINDER = "/hub/pathfinder";
export const ASSESSMENTS = PATHFINDER + "/assessments";
export const ASSESSMENTS = HUB + "/assessments";

const jsonHeaders = { headers: { Accept: "application/json" } };
const formHeaders = { headers: { Accept: "multipart/form-data" } };
Expand Down Expand Up @@ -150,12 +148,6 @@ export const updateAllApplications = (
.catch((error) => error);
};

export const getApplicationById = (
id: number | string
): AxiosPromise<Application> => {
return APIClient.get(`${APPLICATIONS}/${id}`);
};

// Applications Dependencies

export const getApplicationDependencies = (): AxiosPromise<
Expand Down Expand Up @@ -214,64 +206,56 @@ export const getApplicationSummaryCSV = (id: string): AxiosPromise => {
});
};

//
//TODO: Remove this
export const getApplicationByIdPromise = (
id: number | string
): Promise<Application> => axios.get(`${APPLICATIONS}/${id}`);

//TODO: Remove this
export const getAssessmentsPromise = (filters: {
applicationId?: number | string;
}): Promise<Assessment[]> => {
const params = {
applicationId: filters.applicationId,
};

const query: string[] = buildQuery(params);
return axios.get(`${ASSESSMENTS}?${query.join("&")}`);
};

export const getAssessments = (filters: {
applicationId?: number | string;
}): AxiosPromise<Assessment[]> => {
}): Promise<Assessment[]> => {
const params = {
applicationId: filters.applicationId,
};

const query: string[] = buildQuery(params);
return APIClient.get(`${ASSESSMENTS}?${query.join("&")}`);
return axios
.get(`${ASSESSMENTS}?${query.join("&")}`)
.then((response) => response.data);
};

export const createAssessment = (obj: Assessment): AxiosPromise<Assessment> => {
return APIClient.post(`${ASSESSMENTS}`, obj);
export const createAssessment = (
obj: InitialAssessment
): Promise<Assessment> => {
return axios.post(`${ASSESSMENTS}`, obj).then((response) => response.data);
};

export const patchAssessment = (obj: Assessment): AxiosPromise<Assessment> => {
return APIClient.patch(`${ASSESSMENTS}/${obj.id}`, obj);
return axios
.patch(`${ASSESSMENTS}/${obj.id}`, obj)
.then((response) => response.data);
};

export const getAssessmentById = (
id: number | string
): AxiosPromise<Assessment> => {
return APIClient.get(`${ASSESSMENTS}/${id}`);
export const getAssessmentById = (id: number | string): Promise<Assessment> => {
return axios.get(`${ASSESSMENTS}/${id}`).then((response) => response.data);
};

export const deleteAssessment = (id: number): AxiosPromise => {
return APIClient.delete(`${ASSESSMENTS}/${id}`);
};

export const getAssessmentLandscape = (
applicationIds: number[]
): AxiosPromise<AssessmentRisk[]> => {
return APIClient.post(
`${ASSESSMENTS}/assessment-risk`,
applicationIds.map((f) => ({ applicationId: f }))
);
};

export const getAssessmentIdentifiedRisks = (
applicationIds: number[]
): AxiosPromise<AssessmentQuestionRisk[]> => {
return APIClient.post(
`${ASSESSMENTS}/risks`,
applicationIds.map((f) => ({ applicationId: f }))
);
};

export const getAssessmentConfidence = (
applicationIds: number[]
): AxiosPromise<AssessmentConfidence[]> => {
return APIClient.post(
`${ASSESSMENTS}/confidence`,
applicationIds.map((f) => ({ applicationId: f }))
);
};

export const createBulkCopyAssessment = (
bulk: BulkCopyAssessment
): AxiosPromise<BulkCopyAssessment> => {
Expand Down Expand Up @@ -320,6 +304,9 @@ export const deleteApplication = (id: number): Promise<Application> =>
export const deleteBulkApplications = (ids: number[]): Promise<Application[]> =>
axios.delete(APPLICATIONS, { data: ids });

export const getApplicationById = (id: number | string): Promise<Application> =>
axios.get(`${APPLICATIONS}/${id}`).then((response) => response.data);

export const getApplications = (): Promise<Application[]> =>
axios.get(APPLICATIONS).then((response) => response.data);

Expand Down Expand Up @@ -738,6 +725,11 @@ export const updateProxy = (obj: Proxy): Promise<Proxy> =>
export const getQuestionnaires = (): Promise<Questionnaire[]> =>
axios.get(QUESTIONNAIRES).then((response) => response.data);

export const getQuestionnaireById = (
id: number | string
): Promise<Questionnaire> =>
axios.get(`${QUESTIONNAIRES}/id/${id}`).then((response) => response.data);

// TODO: The update handlers in hub don't return any content (success is a response code
// TODO: of 204 - NoContext) ... the return type does not make sense.
export const updateQuestionnaire = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useCallback, useState } from "react";
import { AxiosError } from "axios";

import { createAssessment, getAssessments } from "@app/api/rest";
import { Application, Assessment } from "@app/api/models";
import { Application, Assessment, InitialAssessment } from "@app/api/models";

export interface IState {
inProgress: boolean;
Expand Down Expand Up @@ -34,7 +34,7 @@ export const useAssessApplication = (): IState => {

setInProgress(true);
getAssessments({ applicationId: application.id })
.then(({ data }) => {
.then((data) => {
const currentAssessment: Assessment | undefined = data[0]
? data[0]
: undefined;
Expand Down Expand Up @@ -63,12 +63,13 @@ export const useAssessApplication = (): IState => {

setInProgress(true);
getAssessments({ applicationId: application.id })
.then(({ data }) => {
.then((data) => {
const currentAssessment: Assessment | undefined = data[0];

const newAssessment = {
applicationId: application.id,
} as Assessment;
const newAssessment: InitialAssessment = {
application: { id: application.id, name: application.name },
questionnaire: { id: 1, name: "Sample Questionnaire" },
};

return Promise.all([
currentAssessment,
Expand All @@ -77,7 +78,7 @@ export const useAssessApplication = (): IState => {
})
.then(([currentAssessment, newAssessment]) => {
setInProgress(false);
onSuccess(currentAssessment || newAssessment!.data);
onSuccess(currentAssessment || newAssessment!);
})
.catch((error: AxiosError) => {
setInProgress(false);
Expand Down
Loading

0 comments on commit e041fe3

Please sign in to comment.