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;
};