From e5389f9f9d7d6463100d742c72a9dff1e1f9c828 Mon Sep 17 00:00:00 2001 From: Dinesh <97143739+dinesh-aot@users.noreply.github.com> Date: Mon, 6 May 2024 13:22:42 -0700 Subject: [PATCH] lined work creation (#2196) --- .../b724615d3fdf_create_linked_work_table.py | 43 +++++++++++++++++++ epictrack-api/src/api/actions/create_work.py | 12 +++++- epictrack-api/src/api/models/__init__.py | 1 + epictrack-api/src/api/models/linked_work.py | 33 ++++++++++++++ epictrack-api/src/api/services/work.py | 3 ++ .../components/myWorkplans/Card/CardBody.tsx | 27 ++++++++---- epictrack-web/src/models/workplan.tsx | 3 ++ 7 files changed, 112 insertions(+), 10 deletions(-) create mode 100644 epictrack-api/migrations/versions/b724615d3fdf_create_linked_work_table.py create mode 100644 epictrack-api/src/api/models/linked_work.py diff --git a/epictrack-api/migrations/versions/b724615d3fdf_create_linked_work_table.py b/epictrack-api/migrations/versions/b724615d3fdf_create_linked_work_table.py new file mode 100644 index 000000000..c723989c6 --- /dev/null +++ b/epictrack-api/migrations/versions/b724615d3fdf_create_linked_work_table.py @@ -0,0 +1,43 @@ +"""create linked_work table + +Revision ID: b724615d3fdf +Revises: c64aaa268112 +Create Date: 2024-05-05 10:45:18.936600 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'b724615d3fdf' +down_revision = 'c64aaa268112' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('LinkedWorks', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('source_work_id', sa.Integer(), nullable=False), + sa.Column('linked_work_id', sa.Integer(), nullable=False), + sa.Column('source_event_id', sa.Integer(), nullable=False), + sa.Column('created_by', sa.String(length=255), nullable=True), + sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"), nullable=True), + sa.Column('updated_by', sa.String(length=255), nullable=True), + sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True), + sa.Column('is_active', sa.Boolean(), server_default='t', nullable=False), + sa.Column('is_deleted', sa.Boolean(), server_default='f', nullable=False), + sa.ForeignKeyConstraint(['linked_work_id'], ['works.id'], ), + sa.ForeignKeyConstraint(['source_event_id'], ['events.id'], ), + sa.ForeignKeyConstraint(['source_work_id'], ['works.id'], ), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('LinkedWorks') + # ### end Alembic commands ### diff --git a/epictrack-api/src/api/actions/create_work.py b/epictrack-api/src/api/actions/create_work.py index 9c0ab29a1..a50c2dfbb 100644 --- a/epictrack-api/src/api/actions/create_work.py +++ b/epictrack-api/src/api/actions/create_work.py @@ -4,6 +4,7 @@ from pytz import timezone from api.actions.base import ActionFactory +from api.models.linked_work import LinkedWork class CreateWork(ActionFactory): @@ -31,4 +32,13 @@ def run(self, source_event, params) -> None: "eao_team_id": source_event.work.eao_team_id, "decision_by_id": source_event.work.decision_by_id, } - WorkService.create_work(new_work) + work = WorkService.create_work(new_work) + linked_work = LinkedWork( + **{ + "source_work_id": source_event.work_id, + "linked_work_id": work.id, + "source_event_id": source_event.id, + "is_active": True, + } + ) + linked_work.flush() diff --git a/epictrack-api/src/api/models/__init__.py b/epictrack-api/src/api/models/__init__.py index 9ae02c6a0..fb3901f36 100644 --- a/epictrack-api/src/api/models/__init__.py +++ b/epictrack-api/src/api/models/__init__.py @@ -73,3 +73,4 @@ from .work_status import WorkStatus from .work_type import WorkType from .indigenous_consultation_levels import IndigenousConsultationLevel +from .linked_work import LinkedWork diff --git a/epictrack-api/src/api/models/linked_work.py b/epictrack-api/src/api/models/linked_work.py new file mode 100644 index 000000000..d0b00e891 --- /dev/null +++ b/epictrack-api/src/api/models/linked_work.py @@ -0,0 +1,33 @@ +# Copyright © 2019 Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Model for linked works""" + +from sqlalchemy import Column, ForeignKey, Integer +from sqlalchemy.orm import relationship +from .base_model import BaseModel + + +class LinkedWork(BaseModel): + """Model for linked works""" + + __tablename__ = "LinkedWorks" + + id = Column(Integer, primary_key=True, autoincrement=True) + source_work_id = Column(ForeignKey("works.id"), nullable=False) + linked_work_id = Column(ForeignKey("works.id"), nullable=False) + source_event_id = Column(ForeignKey("events.id"), nullable=False) + + source_work = relationship('Work', foreign_keys=[source_work_id], lazy="select") + linked_work = relationship('Work', foreign_keys=[linked_work_id], lazy="select") + event = relationship('Event', foreign_keys=[source_event_id], lazy="select") diff --git a/epictrack-api/src/api/services/work.py b/epictrack-api/src/api/services/work.py index 6f2b1bb8c..846ace63d 100644 --- a/epictrack-api/src/api/services/work.py +++ b/epictrack-api/src/api/services/work.py @@ -84,6 +84,7 @@ from api.utils.roles import Role as KeycloakRole +# pylint: disable=too-many-lines class WorkService: # pylint: disable=too-many-public-methods """Service to manage work related operations.""" @@ -137,6 +138,7 @@ def _serialize_work(work, work_staffs, works_statuses, work_phase): "id", "work_state", "work_type", + "current_work_phase_id", "federal_involvement", "eao_team", "title", @@ -153,6 +155,7 @@ def _serialize_work(work, work_staffs, works_statuses, work_phase): "next_milestone", "milestone_progress", "days_left", + "work_phase.id", "work_phase.phase.color", "work_phase.start_date", "work_phase.end_date", diff --git a/epictrack-web/src/components/myWorkplans/Card/CardBody.tsx b/epictrack-web/src/components/myWorkplans/Card/CardBody.tsx index 8d8d54c45..c4ef67aa2 100644 --- a/epictrack-web/src/components/myWorkplans/Card/CardBody.tsx +++ b/epictrack-web/src/components/myWorkplans/Card/CardBody.tsx @@ -1,3 +1,4 @@ +import { useMemo } from "react"; import { Grid, Stack } from "@mui/material"; import { Palette } from "../../../styles/theme"; import { ETCaption1, ETCaption2, ETHeading4, ETParagraph } from "../../shared"; @@ -28,6 +29,14 @@ const CardBody = ({ workplan }: CardProps) => { workplan.simple_title ? ` - ${workplan.simple_title}` : "" }`; + const currentWorkPhaseInfo = useMemo(() => { + const currentPhaseInfo = workplan.phase_info.filter( + (p) => p.work_phase.id === workplan.current_work_phase_id + ); + return currentPhaseInfo[0]; + }, [workplan]); + console.log("CURRENT WORKPHASE INFO", currentWorkPhaseInfo); + return ( { - + { textOverflow: "ellipsis", }} > - {workplan?.phase_info[0]?.work_phase.name} + {currentWorkPhaseInfo.work_phase.name} 0 + currentWorkPhaseInfo?.days_left > 0 ? Palette.neutral.main : Palette.error.main } @@ -98,7 +107,7 @@ const CardBody = ({ workplan }: CardProps) => { bold enableEllipsis color={ - workplan?.phase_info[0]?.days_left > 0 + currentWorkPhaseInfo?.days_left > 0 ? Palette.neutral.main : Palette.error.main } @@ -108,8 +117,8 @@ const CardBody = ({ workplan }: CardProps) => { }} > {daysLeft( - workplan?.phase_info[0]?.days_left, - workplan?.phase_info[0]?.total_number_of_days + currentWorkPhaseInfo?.days_left, + currentWorkPhaseInfo?.total_number_of_days )} @@ -117,7 +126,7 @@ const CardBody = ({ workplan }: CardProps) => { - + { > {`UPCOMING MILESTONE ${dayjs(new Date()) - .add(workplan?.phase_info[0]?.days_left, "days") + .add(currentWorkPhaseInfo?.days_left, "days") .format(MONTH_DAY_YEAR) .toUpperCase()}`} @@ -146,7 +155,7 @@ const CardBody = ({ workplan }: CardProps) => { whiteSpace: "nowrap", }} > - {workplan.phase_info[0]?.next_milestone} + {currentWorkPhaseInfo?.next_milestone} diff --git a/epictrack-web/src/models/workplan.tsx b/epictrack-web/src/models/workplan.tsx index b2c97a90b..a1213052a 100644 --- a/epictrack-web/src/models/workplan.tsx +++ b/epictrack-web/src/models/workplan.tsx @@ -1,3 +1,4 @@ +import { WorkPhase } from "./work"; import { WorkType } from "./workType"; export interface WorkPlan { @@ -5,6 +6,7 @@ export interface WorkPlan { title: string; simple_title: string; is_active: boolean; + current_work_phase_id: number; work_type: WorkType; work_state: string; @@ -19,6 +21,7 @@ export interface WorkPlan { total_number_of_days: number; work_phase: { name: string; + id: number; phase: { color: string; };