Skip to content

Commit

Permalink
🐛 Exclude non-required questionnaires in assessed calculation (konvey…
Browse files Browse the repository at this point in the history
…or#1666)

Resolves https://issues.redhat.com/browse/MTA-1967

Addresses an issue where the assessed boolean for archetypes is set to
true when all questionnaires are marked as not-required. Uses the new
assessment.required boolean surfaced in
konveyor/tackle2-hub@2552233
to filter out these false positives.

---------

Signed-off-by: ibolton336 <[email protected]>
  • Loading branch information
ibolton336 authored Jan 26, 2024
1 parent 8f83736 commit 3cf032f
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 26 deletions.
5 changes: 5 additions & 0 deletions client/src/app/api/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,7 @@ export interface Assessment
confidence?: number;
stakeholders?: Ref[];
stakeholderGroups?: Ref[];
required?: boolean;
}
export interface CategorizedTag {
category: TagCategory;
Expand Down Expand Up @@ -794,3 +795,7 @@ export interface AssessmentWithArchetypeApplications
extends AssessmentWithSectionOrder {
archetypeApplications: Ref[];
}
export interface AssessmentsWithArchetype {
archetype: Archetype;
assessments: Assessment[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import { LabelsFromItems } from "@app/components/labels/labels-from-items/labels
import { RiskLabel } from "@app/components/RiskLabel";
import { ApplicationDetailFields } from "./application-detail-fields";
import { useFetchArchetypes } from "@app/queries/archetypes";
import { AssessedArchetypes } from "./components/assessed-archetypes";

export interface IApplicationDetailDrawerProps
extends Pick<IPageDrawerContentProps, "onCloseClick"> {
Expand Down Expand Up @@ -101,14 +102,6 @@ export const ApplicationDetailDrawer: React.FC<

const enableDownloadSetting = useSetting("download.html.enabled");

const assessedArchetypes =
application?.archetypes
?.map((archetypeRef) =>
archetypes.find((archetype) => archetype.id === archetypeRef.id)
)
.filter((fullArchetype) => fullArchetype?.assessed)
.filter(Boolean) || [];

const reviewedArchetypes =
application?.archetypes
?.map((archetypeRef) =>
Expand Down Expand Up @@ -211,18 +204,7 @@ export const ApplicationDetailDrawer: React.FC<
{t("terms.archetypesAssessed")}
</DescriptionListTerm>
<DescriptionListDescription>
<LabelGroup>
{assessedArchetypes?.length ? (
assessedArchetypes.map((assessedArchetype) => (
<ArchetypeItem
key={assessedArchetype?.id}
archetype={assessedArchetype}
/>
))
) : (
<EmptyTextMessage message={t("terms.none")} />
)}
</LabelGroup>
<AssessedArchetypes application={application} />
</DescriptionListDescription>
</DescriptionListGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from "react";
import { Application } from "@app/api/models";
import { Label, LabelGroup, Spinner } from "@patternfly/react-core";
import { EmptyTextMessage } from "@app/components/EmptyTextMessage";
import { useTranslation } from "react-i18next";
import { useFetchArchetypes } from "@app/queries/archetypes";
import { useFetchAllAssessmentsWithArchetypes } from "@app/queries/assessments";

interface IAssessedArchetypesProps {
application: Application | null;
}

export const AssessedArchetypes: React.FC<IAssessedArchetypesProps> = ({
application,
}) => {
const { t } = useTranslation();
const {
archetypes: applicationArchetypes,
isFetching: isFetchingArchetypes,
} = useFetchArchetypes(application);

const {
assessmentsWithArchetypes,
isLoading: isFetchingAllAssessmentsWithArchetypesLoading,
} = useFetchAllAssessmentsWithArchetypes(applicationArchetypes);

const assessedArchetypesWithARequiredAssessment = assessmentsWithArchetypes
?.filter((assessmentsWithArchetype) => {
return (
assessmentsWithArchetype.archetype.assessed &&
assessmentsWithArchetype.assessments.some(
(assessment) => assessment?.required === true
)
);
})
.map((assessmentsWithArchetype) => assessmentsWithArchetype.archetype);

if (isFetchingArchetypes || isFetchingAllAssessmentsWithArchetypesLoading) {
return <Spinner size="md" />;
}
return (
<LabelGroup>
{assessedArchetypesWithARequiredAssessment?.length ? (
assessedArchetypesWithARequiredAssessment?.map((archetype) => (
<Label key={archetype?.id}>{archetype?.name}</Label>
))
) : (
<EmptyTextMessage message={t("terms.none")} />
)}
</LabelGroup>
);
};
25 changes: 20 additions & 5 deletions client/src/app/queries/archetypes.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";

import { AxiosError } from "axios";
import { Archetype } from "@app/api/models";
import { Application, Archetype } from "@app/api/models";
import {
createArchetype,
deleteArchetype,
Expand All @@ -14,18 +14,33 @@ import {
assessmentsByItemIdQueryKey,
} from "./assessments";
import { reviewsQueryKey } from "./reviews";
import { useState } from "react";

export const ARCHETYPES_QUERY_KEY = "archetypes";
export const ARCHETYPE_QUERY_KEY = "archetype";

export const useFetchArchetypes = () => {
export const useFetchArchetypes = (forApplication?: Application | null) => {
const [filteredArchetypes, setFilteredArchetypes] = useState<Archetype[]>([]);

const queryClient = useQueryClient();
const { isLoading, isSuccess, error, refetch, data } = useQuery({
initialData: [],
queryKey: [ARCHETYPES_QUERY_KEY],
queryKey: [ARCHETYPES_QUERY_KEY, forApplication?.id],

queryFn: getArchetypes,
refetchInterval: 5000,
onSuccess: () => {
onSuccess: (fetchedArchetypes) => {
if (forApplication && forApplication.archetypes) {
const archetypeIds = forApplication.archetypes.map(
(archetype) => archetype.id
);
const filtered = fetchedArchetypes.filter((archetype) =>
archetypeIds.includes(archetype.id)
);
setFilteredArchetypes(filtered);
} else {
setFilteredArchetypes(fetchedArchetypes);
}
queryClient.invalidateQueries([reviewsQueryKey]);
queryClient.invalidateQueries([assessmentsQueryKey]);
queryClient.invalidateQueries([assessmentsByItemIdQueryKey]);
Expand All @@ -35,7 +50,7 @@ export const useFetchArchetypes = () => {
});

return {
archetypes: data || [],
archetypes: filteredArchetypes || [],
isFetching: isLoading,
isSuccess,
error,
Expand Down
34 changes: 33 additions & 1 deletion client/src/app/queries/assessments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ import {
} from "@app/api/rest";
import { AxiosError } from "axios";
import {
Archetype,
Assessment,
AssessmentWithArchetypeApplications,
AssessmentWithSectionOrder,
AssessmentsWithArchetype,
InitialAssessment,
} from "@app/api/models";
import { QuestionnairesQueryKey } from "./questionnaires";
Expand Down Expand Up @@ -214,7 +216,7 @@ const removeSectionOrderFromQuestions = (
...assessmentWithOrder,
sections: assessmentWithOrder.sections.map((section) => ({
...section,
questions: section.questions.map(({ sectionOrder, ...rest }) => rest), // Destructure out sectionOrder
questions: section.questions.map(({ sectionOrder, ...rest }) => rest),
})),
};
};
Expand Down Expand Up @@ -262,3 +264,33 @@ export const useFetchAssessmentsWithArchetypeApplications = () => {
isLoading: assessmentsLoading || isArchetypesLoading,
};
};

export const useFetchAllAssessmentsWithArchetypes = (
archetypes: Archetype[] = []
) => {
const assessmentQueries = useQueries({
queries: archetypes.map((archetype) => ({
queryKey: ["assessmentsForArchetype", archetype.id],
queryFn: () => getAssessmentsByItemId(true, archetype.id),
})),
});

const assessmentsWithArchetypes: AssessmentsWithArchetype[] =
assessmentQueries
.map((query, index) => {
if (query.isSuccess) {
return {
archetype: archetypes[index],
assessments: query.data,
};
}
return null;
})
.filter(Boolean);

return {
assessmentsWithArchetypes,
isLoading: assessmentQueries.some((query) => query.isLoading),
isError: assessmentQueries.some((query) => query.isError),
};
};

0 comments on commit 3cf032f

Please sign in to comment.