Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Remove pathfinder and convert assessment wizard to use new api #1315

Merged
merged 2 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 = (
sjd78 marked this conversation as resolved.
Show resolved Hide resolved
id: number | string
): Promise<Application> => axios.get(`${APPLICATIONS}/${id}`);

//TODO: Remove this
export const getAssessmentsPromise = (filters: {
sjd78 marked this conversation as resolved.
Show resolved Hide resolved
applicationId?: number | string;
}): Promise<Assessment[]> => {
Comment on lines +215 to +217
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYT about just using destructuring (also kinda a nit-pick):

Suggested change
export const getAssessmentsPromise = (filters: {
applicationId?: number | string;
}): Promise<Assessment[]> => {
export const getAssessmentsPromise = ({ applicationId }: {
applicationId?: number | string;
}): Promise<Assessment[]> => {

and then just using applicationId later?

Not that it is applicable here, but default values are pretty easy this way. For example:

export const getAssessments = ({
  applicationId = 1,
}: { applicationId?: number | string } = {}) => {
  const query: string[] = buildQuery({ applicationId });
  return axios.get(`${ASSESSMENTS}?${query.join("&")}`);
};

(the extra default param = {} takes care of calls like getAssessments() or getAssessments(null))

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that is a good idea. All of this code is also going to be deleted as soon as the back end guys finish the /applications/:id/assessments endpoint. This query param will go away entirely.

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