diff --git a/epictrack-api/src/api/insights/work_staff_insight.py b/epictrack-api/src/api/insights/work_staff_insight.py index 60ca43ad1..bd36c0d78 100644 --- a/epictrack-api/src/api/insights/work_staff_insight.py +++ b/epictrack-api/src/api/insights/work_staff_insight.py @@ -21,28 +21,31 @@ class WorkStaffInsightGenerator: def generate_partition_query(self, filters: List = None, staff_id: int = None): """Generates the group by subquery.""" filter_exprs = build_insights_filters(filters, "works") if filters else [] - query = db.session.query( - StaffWorkRole.staff_id, - func.count(func.distinct(Work.id)).label("count"), - ).join(Work, StaffWorkRole.work_id == Work.id) + query = ( + db.session.query( + StaffWorkRole.staff_id, + func.count(func.distinct(Work.id)).label("count"), + ) + .join(Work, StaffWorkRole.work_id == Work.id) + .join(Staff, Staff.id == StaffWorkRole.staff_id) + ) # Join necessary tables for filters if filters: - query = query.join(WorkType, Work.work_type_id == WorkType.id) - query = query.join(Project, Work.project_id == Project.id) - query = query.join(WorkPhase, Work.current_work_phase_id == WorkPhase.id) - - query = query.join(Staff, Staff.id == StaffWorkRole.staff_id) + query = ( + query.join(WorkType, Work.work_type_id == WorkType.id) + .join(Project, Work.project_id == Project.id) + .join(WorkPhase, Work.current_work_phase_id == WorkPhase.id) + ) if staff_id: query = query.filter(Staff.id == staff_id) - query = query.filter(Staff.is_active.is_(True)) - query = query.filter(StaffWorkRole.is_active.is_(True)) query = query.filter( Work.is_active.is_(True), Work.is_deleted.is_(False), Work.is_completed.is_(False), + Staff.is_active.is_(True), StaffWorkRole.is_active.is_(True), StaffWorkRole.role_id == RoleEnum.OFFICER_ANALYST.value, *filter_exprs if filter_exprs else [], diff --git a/epictrack-api/src/api/resources/work.py b/epictrack-api/src/api/resources/work.py index 8656aea8b..7764e96e0 100644 --- a/epictrack-api/src/api/resources/work.py +++ b/epictrack-api/src/api/resources/work.py @@ -110,9 +110,13 @@ def get(): else: works = WorkService.find_all_works(is_active) + context = request_args.get("context", None) + exclude = [] if include_indigenous_nations else ['indigenous_works'] if not include_rel_staff: exclude.append('rel_staff') + if context == "insights": + exclude.extend(['ea_act', 'responsible_epd', 'eac_decision_by', 'decision_by', 'substitution_act', 'eao_team']) works_schema = res.WorkResponseSchema(many=True, exclude=exclude) diff --git a/epictrack-api/src/api/schemas/request/work_request.py b/epictrack-api/src/api/schemas/request/work_request.py index 14a3ef627..fdf5b80c1 100644 --- a/epictrack-api/src/api/schemas/request/work_request.py +++ b/epictrack-api/src/api/schemas/request/work_request.py @@ -327,6 +327,13 @@ class WorkQueryParameterSchema(RequestQueryParameterSchema): missing=None ) + context = fields.Str( + metadata={"description": "Request context; use 'insights' for a lean response excluding unused nested objects"}, + required=False, + missing=None, + allow_none=True, + ) + class WorkPhaseQueryParameterSchema(RequestQueryParameterSchema): """Work Phase Query parameters""" diff --git a/epictrack-api/src/api/services/work.py b/epictrack-api/src/api/services/work.py index fbba021e9..b6e197f76 100644 --- a/epictrack-api/src/api/services/work.py +++ b/epictrack-api/src/api/services/work.py @@ -248,7 +248,9 @@ def find_allocated_resources(cls, is_active=None): .filter( StaffWorkRole.work_id.in_(work_ids), StaffWorkRole.is_deleted.is_(False), - StaffWorkRole.is_active.is_(True) + StaffWorkRole.is_active.is_(True), + Staff.is_active.is_(True), + Staff.is_deleted.is_(False) ) .join(Role, Role.id == StaffWorkRole.role_id) .add_entity(Role) diff --git a/epictrack-web/src/components/insights/Work/Tabs/Staff/Charts/workListing.tsx b/epictrack-web/src/components/insights/Work/Tabs/Staff/Charts/workListing.tsx index 684b76f5f..acebf161b 100644 --- a/epictrack-web/src/components/insights/Work/Tabs/Staff/Charts/workListing.tsx +++ b/epictrack-web/src/components/insights/Work/Tabs/Staff/Charts/workListing.tsx @@ -1,6 +1,5 @@ import React, { useCallback, useEffect, useMemo } from "react"; import { MRT_ColumnDef } from "material-react-table"; -import { Work } from "models/work"; import { rowsPerPageOptions } from "components/shared/MasterTrackTable/utils"; import { ETGridTitle, IButton } from "components/shared"; import { searchFilter } from "components/shared/MasterTrackTable/filters"; @@ -11,7 +10,6 @@ import { useGetWorkStaffsQuery } from "services/rtkQuery/workStaffInsights"; import { exportToCsv } from "components/shared/MasterTrackTable/utils"; import { Tooltip, Box } from "@mui/material"; import { sort } from "utils"; -import { useGetWorksQuery } from "services/rtkQuery/workInsights"; import Icons from "components/icons"; import { IconProps } from "components/icons/type"; import { Role, WorkStaffRole, WorkStaffRoleNames } from "models/role"; @@ -20,57 +18,33 @@ import { useTableFilterContext } from "components/insights/TableFilterContext"; const DownloadIcon: React.FC = Icons["DownloadIcon"]; -type WorkStaffWithWork = WorkStaff & { work: Work }; - const WorkList = () => { const [pagination, setPagination] = React.useState({ pageIndex: 0, pageSize: 15, }); - const [workData, setWorkData] = React.useState([]); + const [workData, setWorkData] = React.useState([]); const { columnFilters, setColumnFilters } = useTableFilterContext(); const { isUserInsights, staffId } = useInsightsContext(); - const queryArg = useMemo(() => { - return { - is_active: true, - ...(isUserInsights && staffId ? { staffId } : {}), - }; - }, [isUserInsights, staffId]); - - const { data: works } = useGetWorksQuery(queryArg, { - refetchOnMountOrArgChange: true, - }); - const { data: workStaffs, isLoading } = useGetWorkStaffsQuery(); useEffect(() => { - if (workStaffs && works) { - const mergedData = workStaffs - .filter((workStaff) => - isUserInsights - ? workStaff.staff - .map((staff) => staff.id) - ?.includes(staffId ? staffId : -1) - : true, - ) - .map((workStaff) => { - const work = works.find( - (w) => w.eao_team_id === workStaff.eao_team.id, - ); - if (!work) { - return null; - } - return { ...workStaff, work }; - }) - .filter(Boolean) as WorkStaffWithWork[]; - setWorkData(sort(mergedData, "work.title")); + if (workStaffs) { + const filtered = workStaffs.filter((workStaff) => + isUserInsights + ? workStaff.staff + .map((staff) => staff.id) + ?.includes(staffId ? staffId : -1) + : true, + ); + setWorkData(sort(filtered, "title")); setPagination((prev) => ({ ...prev, - pageSize: workStaffs.length, + pageSize: filtered.length, })); } - }, [isUserInsights, staffId, works, workStaffs]); + }, [isUserInsights, staffId, workStaffs]); const workLeads = useMemo(() => { return Array.from( @@ -149,7 +123,7 @@ const WorkList = () => { ); useEffect(() => { - const cols: Array> = []; + const cols: Array> = []; if (workStaffs && workStaffs.length > 0) { const roles = [WorkStaffRole.TEAM_CO_LEAD, WorkStaffRole.OFFICER_ANALYST]; roles.forEach((role, index) => { @@ -191,7 +165,7 @@ const WorkList = () => { } }, [getRolefilterOptions, roleFilterFunction, workStaffs]); - const columns = React.useMemo[]>(() => { + const columns = React.useMemo[]>(() => { return [ { accessorKey: "title", diff --git a/epictrack-web/src/components/insights/Work/Tabs/Trends/charts/WorkListing.tsx b/epictrack-web/src/components/insights/Work/Tabs/Trends/charts/WorkListing.tsx index 0fa9bc0cd..9df1f25d1 100644 --- a/epictrack-web/src/components/insights/Work/Tabs/Trends/charts/WorkListing.tsx +++ b/epictrack-web/src/components/insights/Work/Tabs/Trends/charts/WorkListing.tsx @@ -9,7 +9,7 @@ import { import { searchFilter } from "components/shared/MasterTrackTable/filters"; import { TableFilter } from "components/shared/filterSelect/TableFilter"; import MasterTrackTable from "components/shared/MasterTrackTable"; -import { useGetAllWorksQuery } from "services/rtkQuery/workInsights"; +import { useGetWorksQuery } from "services/rtkQuery/workInsights"; import { exportToCsv } from "components/shared/MasterTrackTable/utils"; import { Tooltip, Box, Grid } from "@mui/material"; import { ETCaption1, ETGridTitle, IButton } from "components/shared"; @@ -40,7 +40,7 @@ const WorkList = () => { }; }, [isUserInsights, staffId]); - const { data, error, isLoading } = useGetAllWorksQuery(queryArg, { + const { data, error, isLoading } = useGetWorksQuery(queryArg, { refetchOnMountOrArgChange: true, }); diff --git a/epictrack-web/src/services/rtkQuery/workInsights.tsx b/epictrack-web/src/services/rtkQuery/workInsights.tsx index 2a6f8c970..5641ae1c3 100644 --- a/epictrack-web/src/services/rtkQuery/workInsights.tsx +++ b/epictrack-web/src/services/rtkQuery/workInsights.tsx @@ -35,7 +35,11 @@ function buildInsightBody( function buildQueryString( base: string, - { is_active, staffId }: { is_active?: boolean; staffId?: number } = {}, + { + is_active, + staffId, + context, + }: { is_active?: boolean; staffId?: number; context?: string } = {}, ): string { const params: string[] = []; @@ -45,6 +49,9 @@ function buildQueryString( if (staffId !== undefined) { params.push(`staff_id=${staffId}`); } + if (context !== undefined) { + params.push(`context=${context}`); + } return params.length ? `${base}?${params.join("&")}` : base; } @@ -92,32 +99,13 @@ export const workInsightsApi = createApi({ }, ), - getAllWorks: builder.query< - Work[], - { is_active?: boolean; staffId?: number } | void - >({ - query: ( - args: { is_active?: boolean; staffId?: number } = { is_active: true }, - ) => buildQueryString("works", args), - providesTags: (result) => - result - ? [ - ...result.map(({ id }) => ({ - type: "Works" as const, - id, - })), - { type: "Works", id: "LIST" }, - ] - : [{ type: "Works", id: "LIST" }], - }), - getWorks: builder.query< Work[], { is_active?: boolean; staffId?: number } | void >({ query: ( args: { is_active?: boolean; staffId?: number } = { is_active: true }, - ) => buildQueryString("works", args), + ) => buildQueryString("works", { ...args, context: "insights" }), providesTags: (result) => result ? [ @@ -150,8 +138,11 @@ export const workInsightsApi = createApi({ getWorksWithNations: builder.query({ query: (args) => - buildQueryString("works", { ...args, is_active: true }) + - "&include_indigenous_nations=true&include_rel_staff=true", + buildQueryString("works", { + ...args, + is_active: true, + context: "insights", + }) + "&include_indigenous_nations=true&include_rel_staff=true", providesTags: (result) => result ? [ @@ -337,5 +328,4 @@ export const { useGetWorksByYearOpenedQuery, useGetWorksByYearCompletedQuery, useGetWorkClosureBreakdownQuery, - useGetAllWorksQuery, } = workInsightsApi;