Skip to content

Commit

Permalink
🐛 Optimize assessment fetching (#1716)
Browse files Browse the repository at this point in the history
  • Loading branch information
ibolton336 authored Feb 28, 2024
1 parent 5a30824 commit e9304fa
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React from "react";
import { useTranslation } from "react-i18next";
import { Spinner } from "@patternfly/react-core";
import { EmptyTextMessage } from "@app/components/EmptyTextMessage";
import { Application } from "@app/api/models";
import { Application, Assessment } from "@app/api/models";
import { IconedStatus, IconedStatusPreset } from "@app/components/IconedStatus";
import { useFetchAssessmentsByItemId } from "@app/queries/assessments";
import { useFetchAssessments } from "@app/queries/assessments";
import { useFetchArchetypes } from "@app/queries/archetypes";
interface ApplicationAssessmentStatusProps {
application: Application;
Expand All @@ -16,58 +16,103 @@ export const ApplicationAssessmentStatus: React.FC<
> = ({ application }) => {
const { t } = useTranslation();

const { archetypes, isFetching } = useFetchArchetypes();
const { archetypes, isFetching } = useFetchArchetypes(application);
const { assessments, fetchError } = useFetchAssessments();

const applicationArchetypes = application.archetypes?.map((archetypeRef) => {
return archetypes?.find((archetype) => archetype.id === archetypeRef.id);
});

const someArchetypesAssessed = applicationArchetypes?.some(
(archetype) => !!archetype?.assessments?.length ?? 0 > 0
const filteredAssessments = assessments?.filter(
(assessment: Assessment) => assessment.application?.id === application.id
);
const areAllArchetypesAssessed =
applicationArchetypes?.every(
(archetype) => archetype?.assessments?.length ?? 0 > 0
) ?? false;
const assessmentStatusInfo = React.useMemo(() => {
const assessmentsWithArchetypes = archetypes.map((archetype) => ({
archetype,
assessments: assessments.filter(
(assessment) => assessment.archetype?.id === archetype.id
),
}));

const {
assessments,
isFetching: isFetchingAssessmentsById,
fetchError,
} = useFetchAssessmentsByItemId(false, application.id);
const someArchetypesAssessed = assessmentsWithArchetypes.some(
({ assessments }) => assessments.length > 0
);

const allArchetypesAssessed =
assessmentsWithArchetypes.length > 0 &&
assessmentsWithArchetypes.every(({ archetype, assessments }) => {
const requiredAssessments = assessments.filter(
(assessment) => assessment.required
);
return (
archetype.assessed &&
assessments.length > 0 &&
requiredAssessments.length > 0 &&
requiredAssessments.every(
(assessment) => assessment.status === "complete"
)
);
});

const hasInProgressOrNotStartedRequiredAssessments =
assessmentsWithArchetypes.some(({ assessments }) =>
assessments.some(
(assessment) =>
assessment.required &&
["empty", "started"].includes(assessment.status)
)
);

const assessedArchetypesWithARequiredAssessment =
assessmentsWithArchetypes.filter(({ assessments, archetype }) =>
assessments.some(
(assessment) =>
assessment.required &&
assessment.status === "complete" &&
archetype.assessed
)
);
const assessedArchetypeCount =
archetypes?.filter(
(archetype) =>
archetype?.assessments?.length ?? (0 > 0 && archetype.assessed)
).length || 0;

return {
assessmentsWithArchetypes,
someArchetypesAssessed,
allArchetypesAssessed,
hasInProgressOrNotStartedRequiredAssessments,
assessedArchetypesWithARequiredAssessment,
assessedArchetypeCount,
};
}, [archetypes, assessments]);

if (fetchError) {
return <EmptyTextMessage message={t("terms.notAvailable")} />;
}

if (isFetching || isFetchingAssessmentsById) {
if (isFetching || isFetching) {
return <Spinner size="md" />;
}

let statusPreset: IconedStatusPreset = "NotStarted"; // Default status
let tooltipCount: number = 0;

const assessedArchetypeCount =
applicationArchetypes?.filter(
(archetype) => archetype?.assessments?.length ?? 0 > 0
).length || 0;

const isDirectlyAssessed =
application.assessed && (application.assessments?.length ?? 0) > 0;
const {
allArchetypesAssessed,
assessedArchetypesWithARequiredAssessment,
hasInProgressOrNotStartedRequiredAssessments,
} = assessmentStatusInfo;

if (isDirectlyAssessed) {
statusPreset = "Completed";
} else if (areAllArchetypesAssessed) {
} else if (allArchetypesAssessed) {
statusPreset = "InheritedAssessments";
tooltipCount = assessedArchetypeCount;
} else if (someArchetypesAssessed) {
tooltipCount = assessedArchetypesWithARequiredAssessment.length;
} else if (hasInProgressOrNotStartedRequiredAssessments) {
statusPreset = "InProgressInheritedAssessments";
tooltipCount = assessedArchetypeCount;
tooltipCount = assessedArchetypesWithARequiredAssessment.length;
} else if (
assessments?.some(
(assessment) =>
assessment.status === "started" || assessment.status === "complete"
)
filteredAssessments?.some((assessment) => assessment.status === "started")
) {
statusPreset = "InProgress";
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from "react";
import { Application } from "@app/api/models";
import { Application, AssessmentWithSectionOrder } 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";
import { useFetchAssessments } from "@app/queries/assessments";

interface IAssessedArchetypesProps {
application: Application | null;
Expand All @@ -14,35 +14,33 @@ export const AssessedArchetypes: React.FC<IAssessedArchetypesProps> = ({
application,
}) => {
const { t } = useTranslation();
const {
archetypes: applicationArchetypes,
isFetching: isFetchingArchetypes,
} = useFetchArchetypes(application);
const { archetypes, isFetching: isFetchingArchetypes } =
useFetchArchetypes(application);
const { assessments, isFetching: isFetchingAssessments } =
useFetchAssessments();

const {
assessmentsWithArchetypes,
isLoading: isFetchingAllAssessmentsWithArchetypesLoading,
} = useFetchAllAssessmentsWithArchetypes(applicationArchetypes);
const assessedArchetypes = React.useMemo(() => {
if (!archetypes || !assessments) return [];

const assessedArchetypesWithARequiredAssessment = assessmentsWithArchetypes
?.filter((assessmentsWithArchetype) => {
return (
assessmentsWithArchetype.archetype.assessed &&
assessmentsWithArchetype.assessments.some(
(assessment) => assessment?.required === true
)
);
})
.map((assessmentsWithArchetype) => assessmentsWithArchetype.archetype);
return archetypes.filter((archetype) =>
assessments.some(
(assessment: AssessmentWithSectionOrder) =>
assessment.archetype?.id === archetype.id &&
assessment.required &&
archetype.assessed
)
);
}, [archetypes, assessments]);

if (isFetchingArchetypes || isFetchingAllAssessmentsWithArchetypesLoading) {
if (isFetchingArchetypes || isFetchingAssessments) {
return <Spinner size="md" />;
}

return (
<LabelGroup>
{assessedArchetypesWithARequiredAssessment?.length ? (
assessedArchetypesWithARequiredAssessment?.map((archetype) => (
<Label key={archetype?.id}>{archetype?.name}</Label>
{assessedArchetypes.length ? (
assessedArchetypes.map((archetype) => (
<Label key={archetype.id}>{archetype.name}</Label>
))
) : (
<EmptyTextMessage message={t("terms.none")} />
Expand Down
2 changes: 1 addition & 1 deletion client/src/app/queries/archetypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export const useFetchArchetypes = (forApplication?: Application | null) => {
initialData: [],
queryKey: [ARCHETYPES_QUERY_KEY, forApplication?.id],
queryFn: getArchetypes,
refetchInterval: 5000,
onSuccess: (fetchedArchetypes) => {
if (!forApplication) {
setFilteredArchetypes(fetchedArchetypes);
Expand All @@ -42,6 +41,7 @@ export const useFetchArchetypes = (forApplication?: Application | null) => {
} else {
setFilteredArchetypes([]);
}

queryClient.invalidateQueries([reviewsQueryKey]);
queryClient.invalidateQueries([assessmentsQueryKey]);
queryClient.invalidateQueries([assessmentsByItemIdQueryKey]);
Expand Down
32 changes: 0 additions & 32 deletions client/src/app/queries/assessments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@ 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 @@ -264,33 +262,3 @@ 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 e9304fa

Please sign in to comment.