diff --git a/client/src/app/api/models.ts b/client/src/app/api/models.ts index e3107eff72..a3a3fea085 100644 --- a/client/src/app/api/models.ts +++ b/client/src/app/api/models.ts @@ -735,6 +735,7 @@ export interface Assessment confidence?: number; stakeholders?: Ref[]; stakeholderGroups?: Ref[]; + required?: boolean; } export interface CategorizedTag { category: TagCategory; @@ -794,3 +795,7 @@ export interface AssessmentWithArchetypeApplications extends AssessmentWithSectionOrder { archetypeApplications: Ref[]; } +export interface AssessmentsWithArchetype { + archetype: Archetype; + assessments: Assessment[]; +} diff --git a/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx b/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx index f3b393e913..7b4c096758 100644 --- a/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx +++ b/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx @@ -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"> { @@ -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) => @@ -211,18 +204,9 @@ 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 + archetypeRefs={application?.archetypes} + /> </DescriptionListDescription> </DescriptionListGroup> diff --git a/client/src/app/pages/applications/components/application-detail-drawer/components/assessed-archetypes.tsx b/client/src/app/pages/applications/components/application-detail-drawer/components/assessed-archetypes.tsx new file mode 100644 index 0000000000..d0d8774144 --- /dev/null +++ b/client/src/app/pages/applications/components/application-detail-drawer/components/assessed-archetypes.tsx @@ -0,0 +1,51 @@ +import React from "react"; +import { Ref } 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 { + archetypeRefs: Ref[] | undefined; +} + +export const AssessedArchetypes: React.FC<IAssessedArchetypesProps> = ({ + archetypeRefs, +}) => { + const { t } = useTranslation(); + const { archetypes, isFetching: isFetchingArchetypes } = useFetchArchetypes(); + const applicationArchetypes = archetypes.filter( + (archetype) => archetypeRefs?.some((ref) => ref.id === archetype.id) + ); + + const { + assessmentsWithArchetypes, + isLoading: isFetchingAllAssessmentsWithArchetypesLoading, + } = useFetchAllAssessmentsWithArchetypes(applicationArchetypes || []); + const filteredArchetypes = 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> + {filteredArchetypes?.length ? ( + filteredArchetypes?.map((archetype) => ( + <Label key={archetype?.id}>{archetype?.name}</Label> + )) + ) : ( + <EmptyTextMessage message={t("terms.none")} /> + )} + </LabelGroup> + ); +}; diff --git a/client/src/app/queries/assessments.ts b/client/src/app/queries/assessments.ts index 8128ba75b4..c8f54fbf08 100644 --- a/client/src/app/queries/assessments.ts +++ b/client/src/app/queries/assessments.ts @@ -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"; @@ -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), // Replace with actual API call + })), + }); + + 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), + }; +};