From 97dea3fff52279e990d8f05308200a5c4c1373ef Mon Sep 17 00:00:00 2001 From: Jad Date: Wed, 16 Oct 2024 11:50:54 -0700 Subject: [PATCH 1/4] handle package status list in UI --- .../versions/e1e1b81ad5c8_rename_status.py | 55 +++++++++++++++++++ submit-api/src/submit_api/models/package.py | 9 +-- submit-api/src/submit_api/schemas/package.py | 3 +- submit-api/src/submit_api/schemas/project.py | 3 +- .../PackageStatusChipStack.tsx | 18 ++++++ .../index.tsx} | 0 .../src/components/Projects/Project.tsx | 7 ++- .../components/Projects/ProjectTableRow.tsx | 4 +- submit-web/src/models/Package.ts | 4 +- .../_submissionLayout/index.tsx | 18 +++--- 10 files changed, 93 insertions(+), 28 deletions(-) create mode 100644 submit-api/migrations/versions/e1e1b81ad5c8_rename_status.py create mode 100644 submit-web/src/components/PackageStatusChip/PackageStatusChipStack.tsx rename submit-web/src/components/{Projects/ProjectStatusChip.tsx => PackageStatusChip/index.tsx} (100%) diff --git a/submit-api/migrations/versions/e1e1b81ad5c8_rename_status.py b/submit-api/migrations/versions/e1e1b81ad5c8_rename_status.py new file mode 100644 index 00000000..e5712abb --- /dev/null +++ b/submit-api/migrations/versions/e1e1b81ad5c8_rename_status.py @@ -0,0 +1,55 @@ +""" Rename aggregated_item_statuses to status + +Revision ID: e1e1b81ad5c8 +Revises: 8dff03f931d7 +Create Date: 2024-10-16 11:09:18.732646 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM, ARRAY + +# revision identifiers, used by Alembic. +revision = 'e1e1b81ad5c8' +down_revision = '8dff03f931d7' +branch_labels = None +depends_on = None + + +def upgrade(): + # Remove the existing status column + op.drop_column('packages', 'status') + + # Rename aggregated_item_statuses to status + op.alter_column( + 'packages', + 'aggregated_item_statuses', + new_column_name='status', + existing_type=ARRAY( + ENUM('NEW_SUBMISSION', 'IN_REVIEW', 'APPROVED', 'REJECTED', 'SUBMITTED', name='packagestatus')), + nullable=False + ) + + +def downgrade(): + # Add the status column back + + # Rename status back to aggregated_item_statuses + op.alter_column( + 'packages', + 'status', + new_column_name='aggregated_item_statuses', + existing_type=ARRAY(ENUM('NEW_SUBMISSION', 'IN_REVIEW', 'APPROVED', 'REJECTED', 'SUBMITTED', name='packagestatus')), + nullable=False + ) + op.add_column( + 'packages', + sa.Column('status', ENUM('NEW_SUBMISSION', 'IN_REVIEW', 'APPROVED', 'REJECTED', 'SUBMITTED', name='packagestatus'), nullable=True) + ) + # populate status column with the first member of the existing aggregated_item_statuses or 'NEW_SUBMISSION' if empty + op.execute( + "UPDATE packages SET status = COALESCE(aggregated_item_statuses[1], 'NEW_SUBMISSION')" + ) + # make status column not nullable + op.alter_column('packages', 'status', nullable=False) + # ### end Alembic commands ### diff --git a/submit-api/src/submit_api/models/package.py b/submit-api/src/submit_api/models/package.py index b707404f..cfd327dd 100644 --- a/submit-api/src/submit_api/models/package.py +++ b/submit-api/src/submit_api/models/package.py @@ -35,7 +35,6 @@ class Package(BaseModel): name = Column(db.String(255), nullable=False) type_id = Column(db.Integer, ForeignKey('package_types.id'), nullable=False) type = db.relationship('PackageType', foreign_keys=[type_id], lazy='joined') - status = Column(Enum(PackageStatus), nullable=False, default=PackageStatus.NEW_SUBMISSION.value) submitted_on = Column(db.DateTime, nullable=True) submitted_by = Column(db.String(255), nullable=True) submitted_by_account_user = db.relationship( @@ -45,13 +44,7 @@ class Package(BaseModel): ) meta = db.relationship('PackageMetadata', backref='package', lazy='select') items = db.relationship('Item', backref='package', lazy='joined', order_by='Item.sort_order') - aggregated_item_statuses = Column(db.ARRAY(Enum(PackageStatus)), nullable=False, default=list) - - # @hybrid_property - # def aggregated_item_statuses(self): - # """Aggregate item statuses.""" - # aggregated_statuses = PackageQueries.aggregate_item_statuses(self.items) - # return aggregated_statuses + status = Column(db.ARRAY(Enum(PackageStatus)), nullable=False, default=[PackageStatus.NEW_SUBMISSION.value]) @classmethod def get_package_by_id_with_items(cls, package_id: int): diff --git a/submit-api/src/submit_api/schemas/package.py b/submit-api/src/submit_api/schemas/package.py index cd8571f6..17cff70b 100644 --- a/submit-api/src/submit_api/schemas/package.py +++ b/submit-api/src/submit_api/schemas/package.py @@ -61,9 +61,8 @@ class Meta: # pylint: disable=too-few-public-methods name = fields.Str(data_key="name") type = fields.Nested(PackageTypeSchema, data_key="type") type_id = fields.Int(data_key="type_id") - status = fields.Enum(data_key="status", enum=PackageStatus) + status = fields.List(fields.Enum(enum=PackageStatus), enum=PackageStatus ,data_key="status") submitted_on = fields.DateTime(data_key="submitted_on") submitted_by_account_user = fields.Pluck(AccountUserSchema, "full_name", data_key="submitted_by") meta = fields.Nested(PackageMetadataSchema, data_key="meta", many=True) items = fields.Nested(ItemSchema, data_key="items", many=True) - aggregated_item_statuses = fields.List(fields.Enum(enum=PackageStatus), data_key="aggregated_item_statuses") diff --git a/submit-api/src/submit_api/schemas/project.py b/submit-api/src/submit_api/schemas/project.py index e1b50858..2770de73 100644 --- a/submit-api/src/submit_api/schemas/project.py +++ b/submit-api/src/submit_api/schemas/project.py @@ -47,11 +47,10 @@ class Meta: # pylint: disable=too-few-public-methods id = fields.Int(data_key="id") name = fields.Str(data_key="name") type = fields.Nested(PackageTypeSchema, data_key="type") - status = fields.Enum(data_key="status", enum=PackageStatus) + status = fields.List(fields.Enum(enum=PackageStatus), data_key="status") submitted_on = fields.DateTime(data_key="submitted_on") submitted_by_account_user = fields.Pluck(AccountUserSchema, "full_name", data_key="submitted_by") items = fields.Function(lambda obj: []) - aggregated_item_statuses = fields.List(fields.Enum(enum=PackageStatus), data_key="aggregated_item_statuses") class AccountProjectSchema(Schema): diff --git a/submit-web/src/components/PackageStatusChip/PackageStatusChipStack.tsx b/submit-web/src/components/PackageStatusChip/PackageStatusChipStack.tsx new file mode 100644 index 00000000..fcbcd093 --- /dev/null +++ b/submit-web/src/components/PackageStatusChip/PackageStatusChipStack.tsx @@ -0,0 +1,18 @@ +import { PackageStatus } from "@/models/Package"; +import { Stack } from "@mui/material"; +import PackageStatusChip from "."; + +type PackageStatusChipStackProps = { + status: PackageStatus[]; +}; +export const PackageStatusChipStack = ({ + status, +}: PackageStatusChipStackProps) => { + return ( + + {status.map((value) => ( + + ))} + + ); +}; diff --git a/submit-web/src/components/Projects/ProjectStatusChip.tsx b/submit-web/src/components/PackageStatusChip/index.tsx similarity index 100% rename from submit-web/src/components/Projects/ProjectStatusChip.tsx rename to submit-web/src/components/PackageStatusChip/index.tsx diff --git a/submit-web/src/components/Projects/Project.tsx b/submit-web/src/components/Projects/Project.tsx index 1010a744..4f6a1a25 100644 --- a/submit-web/src/components/Projects/Project.tsx +++ b/submit-web/src/components/Projects/Project.tsx @@ -26,10 +26,13 @@ export const Project = ({ accountProject }: ProjectParam) => { const navigate = useNavigate(); const activeSubmissionPackages = accountProject.packages.filter( - (subPackage) => subPackage.status === PACKAGE_STATUS.IN_REVIEW.value + (subPackage) => subPackage.status.includes(PACKAGE_STATUS.IN_REVIEW.value), ); const pastSubmissionPackages = accountProject.packages.filter( - (subPackage) => subPackage.status !== PACKAGE_STATUS.IN_REVIEW.value + (subPackage) => + // check if the package status includes approved or rejected + subPackage.status.includes(PACKAGE_STATUS.APPROVED.value) || + subPackage.status.includes(PACKAGE_STATUS.REJECTED.value), ); const { name, ea_certificate } = accountProject.project; diff --git a/submit-web/src/components/Projects/ProjectTableRow.tsx b/submit-web/src/components/Projects/ProjectTableRow.tsx index 01ff2e68..38353c7c 100644 --- a/submit-web/src/components/Projects/ProjectTableRow.tsx +++ b/submit-web/src/components/Projects/ProjectTableRow.tsx @@ -1,9 +1,9 @@ import { ArrowForwardIos } from "@mui/icons-material"; import { Link, TableCell, TableRow, Typography } from "@mui/material"; import { BCDesignTokens } from "epic.theme"; -import PackageStatusChip from "./ProjectStatusChip"; import { SubmissionPackage } from "@/models/Package"; import dayjs from "dayjs"; +import { PackageStatusChipStack } from "../PackageStatusChip/PackageStatusChipStack"; interface ProjectRowProps { subPackage: SubmissionPackage; @@ -94,7 +94,7 @@ export default function ProjectTableRow({ py: BCDesignTokens.layoutPaddingXsmall, }} > - + diff --git a/submit-web/src/models/Package.ts b/submit-web/src/models/Package.ts index 6646c111..f459aa3a 100644 --- a/submit-web/src/models/Package.ts +++ b/submit-web/src/models/Package.ts @@ -40,7 +40,7 @@ export const PACKAGE_STATUS: Record< export type SubmissionPackage = { id: number; name: string; - status: PackageStatus; + status: PackageStatus[]; submitted_on?: string; submitted_by?: string; type_id: number; @@ -51,7 +51,7 @@ export type SubmissionPackage = { export const createDefaultSubmissionPackage = (): SubmissionPackage => ({ id: 0, name: "", - status: PACKAGE_STATUS.IN_REVIEW.value, + status: [PACKAGE_STATUS.IN_REVIEW.value], type_id: 0, type: { id: 0, diff --git a/submit-web/src/routes/_authenticated/_dashboard/projects/$projectId/_projectLayout/submission-packages/$submissionPackageId/_submissionLayout/index.tsx b/submit-web/src/routes/_authenticated/_dashboard/projects/$projectId/_projectLayout/submission-packages/$submissionPackageId/_submissionLayout/index.tsx index 460651ec..eb8a62fa 100644 --- a/submit-web/src/routes/_authenticated/_dashboard/projects/$projectId/_projectLayout/submission-packages/$submissionPackageId/_submissionLayout/index.tsx +++ b/submit-web/src/routes/_authenticated/_dashboard/projects/$projectId/_projectLayout/submission-packages/$submissionPackageId/_submissionLayout/index.tsx @@ -24,9 +24,9 @@ import { useEffect } from "react"; import { PACKAGE_STATUS } from "@/models/Package"; import { LoadingButton as Button } from "@/components/Shared/LoadingButton"; import { notify } from "@/components/Shared/Snackbar/snackbarStore"; -import PackageStatusChip from "@/components/Projects/ProjectStatusChip"; import { SuccessBox } from "@/components/Submission/SuccessBox"; import { When } from "react-if"; +import { PackageStatusChipStack } from "@/components/PackageStatusChip/PackageStatusChipStack"; export const Route = createFileRoute( "/_authenticated/_dashboard/projects/$projectId/_projectLayout/submission-packages/$submissionPackageId/_submissionLayout/", @@ -97,6 +97,10 @@ export default function SubmissionPage() { return ; } + const isPackageSubmitted = submissionPackage.status.includes( + PACKAGE_STATUS.SUBMITTED.value, + ); + return ( @@ -155,7 +159,7 @@ export default function SubmissionPage() { > Submission Status: - + @@ -167,11 +171,7 @@ export default function SubmissionPage() { > - + @@ -193,9 +193,7 @@ export default function SubmissionPage() { From cf803551c0fe18879f787f7b131d5f27bff2631c Mon Sep 17 00:00:00 2001 From: Jad Date: Wed, 16 Oct 2024 16:18:22 -0700 Subject: [PATCH 2/4] Display package statuses --- .../src/submit_api/models/queries/package.py | 4 ++-- .../PackageStatusChipStack.tsx | 14 ++++++++------ submit-web/src/components/Projects/Project.tsx | 18 ++++++++++++------ .../src/components/Projects/ProjectTable.tsx | 12 ++++-------- .../components/Projects/ProjectTableRow.tsx | 8 ++------ 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/submit-api/src/submit_api/models/queries/package.py b/submit-api/src/submit_api/models/queries/package.py index c80216d6..0863ad69 100644 --- a/submit-api/src/submit_api/models/queries/package.py +++ b/submit-api/src/submit_api/models/queries/package.py @@ -60,6 +60,6 @@ def update_package_status(package_id, session): package = session.query(PackageModel).filter_by(id=package_id).one() # Determine new package statuses based on item statuses new_statuses = PackageQueries.aggregate_item_statuses(package.items) - if set(package.aggregated_item_statuses) != set(new_statuses): - package.aggregated_item_statuses = list(new_statuses) + if set(package.status) != set(new_statuses): + package.status = list(new_statuses) session.add(package) diff --git a/submit-web/src/components/PackageStatusChip/PackageStatusChipStack.tsx b/submit-web/src/components/PackageStatusChip/PackageStatusChipStack.tsx index fcbcd093..ec9bc91b 100644 --- a/submit-web/src/components/PackageStatusChip/PackageStatusChipStack.tsx +++ b/submit-web/src/components/PackageStatusChip/PackageStatusChipStack.tsx @@ -1,5 +1,5 @@ import { PackageStatus } from "@/models/Package"; -import { Stack } from "@mui/material"; +import { Box, Stack } from "@mui/material"; import PackageStatusChip from "."; type PackageStatusChipStackProps = { @@ -9,10 +9,12 @@ export const PackageStatusChipStack = ({ status, }: PackageStatusChipStackProps) => { return ( - - {status.map((value) => ( - - ))} - + + + {status.map((value) => ( + + ))} + + ); }; diff --git a/submit-web/src/components/Projects/Project.tsx b/submit-web/src/components/Projects/Project.tsx index 4f6a1a25..b0313752 100644 --- a/submit-web/src/components/Projects/Project.tsx +++ b/submit-web/src/components/Projects/Project.tsx @@ -26,13 +26,19 @@ export const Project = ({ accountProject }: ProjectParam) => { const navigate = useNavigate(); const activeSubmissionPackages = accountProject.packages.filter( - (subPackage) => subPackage.status.includes(PACKAGE_STATUS.IN_REVIEW.value), - ); - const pastSubmissionPackages = accountProject.packages.filter( (subPackage) => - // check if the package status includes approved or rejected - subPackage.status.includes(PACKAGE_STATUS.APPROVED.value) || - subPackage.status.includes(PACKAGE_STATUS.REJECTED.value), + !subPackage.status.some( + (status) => + status === PACKAGE_STATUS.APPROVED.value || + status === PACKAGE_STATUS.REJECTED.value, + ), + ); + const pastSubmissionPackages = accountProject.packages.filter((subPackage) => + subPackage.status.some( + (status) => + status === PACKAGE_STATUS.APPROVED.value || + status === PACKAGE_STATUS.REJECTED.value, + ), ); const { name, ea_certificate } = accountProject.project; diff --git a/submit-web/src/components/Projects/ProjectTable.tsx b/submit-web/src/components/Projects/ProjectTable.tsx index e9e730ac..2399b89a 100644 --- a/submit-web/src/components/Projects/ProjectTable.tsx +++ b/submit-web/src/components/Projects/ProjectTable.tsx @@ -33,18 +33,14 @@ export default function SubmissionPackageTable({ }} > - - Submission Name - - + Submission Name + Date Submitted - + Submitted By - - Status - + Status )} diff --git a/submit-web/src/components/Projects/ProjectTableRow.tsx b/submit-web/src/components/Projects/ProjectTableRow.tsx index 38353c7c..d1757796 100644 --- a/submit-web/src/components/Projects/ProjectTableRow.tsx +++ b/submit-web/src/components/Projects/ProjectTableRow.tsx @@ -27,7 +27,6 @@ export default function ProjectTableRow({ }} > Date: Wed, 16 Oct 2024 17:46:25 -0700 Subject: [PATCH 3/4] Update submit package and add missing package statuses in UI --- .../src/submit_api/models/queries/package.py | 5 +++-- submit-api/src/submit_api/services/package.py | 10 ++++++++-- .../components/PackageStatusChip/index.tsx | 20 ++++++++++++++++++- submit-web/src/models/Package.ts | 13 +++++++++++- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/submit-api/src/submit_api/models/queries/package.py b/submit-api/src/submit_api/models/queries/package.py index 0863ad69..99d3fa9a 100644 --- a/submit-api/src/submit_api/models/queries/package.py +++ b/submit-api/src/submit_api/models/queries/package.py @@ -55,9 +55,10 @@ def aggregate_item_statuses(cls, items: list): return aggregated_statuses_list @staticmethod - def update_package_status(package_id, session): + def update_package_status(package_id, session, package=None): """Update the status of the package based on the statuses of its items.""" - package = session.query(PackageModel).filter_by(id=package_id).one() + if not package: + package = session.query(PackageModel).filter_by(id=package_id).one() # Determine new package statuses based on item statuses new_statuses = PackageQueries.aggregate_item_statuses(package.items) if set(package.status) != set(new_statuses): diff --git a/submit-api/src/submit_api/services/package.py b/submit-api/src/submit_api/services/package.py index 845572b8..78d1ea4d 100644 --- a/submit-api/src/submit_api/services/package.py +++ b/submit-api/src/submit_api/services/package.py @@ -13,6 +13,7 @@ from submit_api.models.package import PackageStatus from submit_api.models.package_metadata import PackageMetadata as PackageMetadataModel from submit_api.models.package_item_type import PackageItemType as PackageItemTypeModel +from submit_api.models.queries.package import PackageQueries from submit_api.utils.token_info import TokenInfo @@ -91,6 +92,11 @@ def _get_and_validate_complete_package(package_id) -> PackageModel: raise BadRequestError("All items must be completed before completing the package") return package + @staticmethod + def _update_package_status(package_id, session, package=None): + """Update the status of the package based on the statuses of its items.""" + PackageQueries.update_package_status(package_id, session, package) + @staticmethod def _update_items_status(items, status, session): """Update status of all items in the package.""" @@ -103,7 +109,6 @@ def _update_package_submission_details(package, session): """Update package submission details.""" package.submitted_on = datetime.utcnow() package.submitted_by = TokenInfo.get_id() - package.status = PackageStatus.SUBMITTED session.add(package) @classmethod @@ -112,8 +117,9 @@ def submit_package(cls, package_id): package = cls._get_and_validate_complete_package(package_id) with session_scope() as session: + cls._update_items_status(package.items, ItemStatus.SUBMITTED.value, session) + cls._update_package_status(package_id, session, package) cls._update_package_submission_details(package, session) - cls._update_items_status(package.items, ItemStatus.SUBMITTED, session) session.flush() session.commit() return package diff --git a/submit-web/src/components/PackageStatusChip/index.tsx b/submit-web/src/components/PackageStatusChip/index.tsx index 8605ba0f..0b23c544 100644 --- a/submit-web/src/components/PackageStatusChip/index.tsx +++ b/submit-web/src/components/PackageStatusChip/index.tsx @@ -1,6 +1,6 @@ import { PackageStatus } from "@/models/Package"; import { Chip } from "@mui/material"; -import { BCDesignTokens } from "epic.theme"; +import { BCDesignTokens, EAOColors } from "epic.theme"; type StyleProps = { sx: Record; @@ -45,6 +45,24 @@ const statusStyles: Record = { }, label: "Completed", }, + PARTIALLY_COMPLETED: { + label: "Partially Completed", + sx: { + borderRadius: 1, + border: `1px solid ${BCDesignTokens.supportBorderColorWarning}`, + background: BCDesignTokens.supportSurfaceColorWarning, + height: "24px", + }, + }, + NEW_SUBMISSION: { + sx: { + borderRadius: 1, + border: `1px solid ${EAOColors.DecisionDark}`, + background: EAOColors.DecisionLight, + height: "24px", + }, + label: "New Submission", + }, }; export default function PackageStatusChip({ diff --git a/submit-web/src/models/Package.ts b/submit-web/src/models/Package.ts index f459aa3a..9ee04ec0 100644 --- a/submit-web/src/models/Package.ts +++ b/submit-web/src/models/Package.ts @@ -10,7 +10,10 @@ export type PackageStatus = | "APPROVED" | "REJECTED" | "COMPLETED" - | "SUBMITTED"; + | "SUBMITTED" + | "PARTIALLY_COMPLETED" + | "NEW_SUBMISSION"; + export const PACKAGE_STATUS: Record< PackageStatus, { value: PackageStatus; label: string } @@ -35,6 +38,14 @@ export const PACKAGE_STATUS: Record< value: "SUBMITTED", label: "Submitted", }, + PARTIALLY_COMPLETED: { + value: "PARTIALLY_COMPLETED", + label: "Partially Completed", + }, + NEW_SUBMISSION: { + value: "NEW_SUBMISSION", + label: "New Submission", + }, }; export type SubmissionPackage = { From d73dfa8088ab36d5d9a3886d00f23dd341ead054 Mon Sep 17 00:00:00 2001 From: Jad Date: Wed, 16 Oct 2024 18:14:18 -0700 Subject: [PATCH 4/4] Fix flake8 whitespace around , issue --- submit-api/src/submit_api/schemas/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submit-api/src/submit_api/schemas/package.py b/submit-api/src/submit_api/schemas/package.py index 17cff70b..0bb65900 100644 --- a/submit-api/src/submit_api/schemas/package.py +++ b/submit-api/src/submit_api/schemas/package.py @@ -61,7 +61,7 @@ class Meta: # pylint: disable=too-few-public-methods name = fields.Str(data_key="name") type = fields.Nested(PackageTypeSchema, data_key="type") type_id = fields.Int(data_key="type_id") - status = fields.List(fields.Enum(enum=PackageStatus), enum=PackageStatus ,data_key="status") + status = fields.List(fields.Enum(enum=PackageStatus), enum=PackageStatus, data_key="status") submitted_on = fields.DateTime(data_key="submitted_on") submitted_by_account_user = fields.Pluck(AccountUserSchema, "full_name", data_key="submitted_by") meta = fields.Nested(PackageMetadataSchema, data_key="meta", many=True)