From 9ec446edee43ac4841b5d42d52550302e74a6ae0 Mon Sep 17 00:00:00 2001 From: VineetBala-AOT Date: Wed, 4 Dec 2024 19:13:17 -0800 Subject: [PATCH] Adding a new document --- .../704b7a6d5500_create_initial_tables.py | 3 +- .../ac00a91a43c4_add_document_type_tables.py | 39 +++-- .../src/condition_api/models/amendment.py | 2 +- .../src/condition_api/models/document.py | 3 +- .../resources/condition_attribute.py | 2 +- .../src/condition_api/resources/document.py | 3 +- .../condition_api/resources/subcondition.py | 8 +- .../src/condition_api/schemas/condition.py | 26 +-- .../schemas/condition_attribute.py | 24 +++ .../src/condition_api/schemas/document.py | 18 +- .../src/condition_api/schemas/project.py | 57 +------ .../src/condition_api/schemas/subcondition.py | 22 +++ .../services/condition_service.py | 28 +-- .../services/document_service.py | 13 +- condition-lib/loadConditions.py | 14 +- .../ConditionDetails/ConditionHeader.tsx | 6 +- .../src/components/ConditionDetails/index.tsx | 2 +- .../components/Conditions/ConditionsTable.tsx | 4 +- .../src/components/Conditions/index.tsx | 160 ++++++------------ .../components/Documents/DocumentTableRow.tsx | 2 +- .../src/components/Documents/index.tsx | 6 +- .../Projects/DocumentStatusChip.tsx | 4 +- .../src/components/Projects/index.tsx | 74 +++++--- .../Shared/layout/SideNav/BreadcrumbNav.tsx | 32 ++-- .../Shared/layout/SideNav/breadCrumbStore.ts | 6 +- condition-web/src/models/Condition.ts | 8 +- condition-web/src/models/Document.ts | 12 +- .../condition/$conditionNumber/index.tsx | 2 +- .../$projectId/document/$documentId/index.tsx | 28 ++- .../document-category/$categoryId/index.tsx | 16 +- .../_dashboard/projects/index.tsx | 2 +- 31 files changed, 326 insertions(+), 300 deletions(-) create mode 100644 condition-api/src/condition_api/schemas/condition_attribute.py create mode 100644 condition-api/src/condition_api/schemas/subcondition.py diff --git a/condition-api/migrations/versions/704b7a6d5500_create_initial_tables.py b/condition-api/migrations/versions/704b7a6d5500_create_initial_tables.py index bf28b7f..d4588c4 100644 --- a/condition-api/migrations/versions/704b7a6d5500_create_initial_tables.py +++ b/condition-api/migrations/versions/704b7a6d5500_create_initial_tables.py @@ -72,7 +72,8 @@ def upgrade(): sa.Column('document_id', sa.String(length=255), nullable=False), sa.Column('amended_id', sa.Integer(), nullable=True), sa.Column('document_type', sa.String(length=100), nullable=False), - sa.Column('display_name', sa.Text(), nullable=True), + sa.Column('document_label', sa.Text(), nullable=True), + sa.Column('document_link', sa.Text(), nullable=True), sa.Column('document_file_name', sa.Text(), nullable=True), sa.Column('date_issued', sa.Date(), nullable=True), sa.Column('act', sa.Integer(), nullable=True), diff --git a/condition-api/migrations/versions/ac00a91a43c4_add_document_type_tables.py b/condition-api/migrations/versions/ac00a91a43c4_add_document_type_tables.py index 750a947..72df2af 100644 --- a/condition-api/migrations/versions/ac00a91a43c4_add_document_type_tables.py +++ b/condition-api/migrations/versions/ac00a91a43c4_add_document_type_tables.py @@ -51,9 +51,9 @@ def upgrade(): # Use op.bulk_insert with the table object op.bulk_insert(document_categories, [ - {'id': 1, 'category_name': 'Exemption Order and Amendments', + {'id': 1, 'category_name': 'Certificate and Amendments', 'created_date': datetime.utcnow(), 'updated_date': datetime.utcnow()}, - {'id': 2, 'category_name': 'Certificate and Amendments', + {'id': 2, 'category_name': 'Exemption Order and Amendments', 'created_date': datetime.utcnow(), 'updated_date': datetime.utcnow()}, {'id': 3, 'category_name': 'Other', 'created_date': datetime.utcnow(), 'updated_date': datetime.utcnow()}, @@ -69,20 +69,14 @@ def upgrade(): # Use op.bulk_insert with the table object op.bulk_insert(document_types, [ - {'id': 1, 'document_category_id': 2, 'document_type': 'Application Materials', + {'id': 1, 'document_category_id': 1, 'document_type': 'Certificate', 'created_date': datetime.utcnow(), 'updated_date': datetime.utcnow()}, - {'id': 2, 'document_category_id': 1, 'document_type': 'Order', + {'id': 2, 'document_category_id': 2, 'document_type': 'Exemption Order', 'created_date': datetime.utcnow(), 'updated_date': datetime.utcnow()}, - {'id': 3, 'document_category_id': 2, 'document_type': 'Comment/Submission', - 'created_date': datetime.utcnow(), 'updated_date': datetime.utcnow()}, - {'id': 4, 'document_category_id': 3, 'document_type': 'Other', - 'created_date': datetime.utcnow(), 'updated_date': datetime.utcnow()}, - {'id': 5, 'document_category_id': 2, 'document_type': 'Decision Materials', - 'created_date': datetime.utcnow(), 'updated_date': datetime.utcnow()}, - {'id': 6, 'document_category_id': 2, 'document_type': 'Schedule B/Certificate', - 'created_date': datetime.utcnow(), 'updated_date': datetime.utcnow()}, - {'id': 7, 'document_category_id': 2, 'document_type': 'Amendment', + {'id': 3, 'document_category_id': 1, 'document_type': 'Amendment', 'created_date': datetime.utcnow(), 'updated_date': datetime.utcnow()}, + {'id': 4, 'document_category_id': 3, 'document_type': 'Other Order', + 'created_date': datetime.utcnow(), 'updated_date': datetime.utcnow()} ]) with op.batch_alter_table("documents", schema='condition') as batch_op: @@ -99,11 +93,30 @@ def upgrade(): referent_schema='condition', ondelete='CASCADE' ) + + with op.batch_alter_table("amendments", schema='condition') as batch_op: + batch_op.drop_column("document_type") + batch_op.add_column(sa.Column('document_type_id', sa.Integer(), nullable=True)) + + op.create_foreign_key( + 'fk_document_type_id', + 'amendments', + 'document_types', + ['document_type_id'], + ['id'], + source_schema='condition', + referent_schema='condition', + ondelete='CASCADE' + ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint('fk_document_type_id', 'amendments', type_='foreignkey', schema='condition') + with op.batch_alter_table("amendments", schema='condition') as batch_op: + batch_op.drop_column("document_type_id") + batch_op.add_column(sa.Column('document_type', sa.String(length=100), nullable=True)) op.drop_constraint('fk_document_type_id', 'documents', type_='foreignkey', schema='condition') with op.batch_alter_table("documents", schema='condition') as batch_op: batch_op.drop_column("document_type_id") diff --git a/condition-api/src/condition_api/models/amendment.py b/condition-api/src/condition_api/models/amendment.py index 7e48289..f5a6eb6 100644 --- a/condition-api/src/condition_api/models/amendment.py +++ b/condition-api/src/condition_api/models/amendment.py @@ -17,7 +17,7 @@ class Amendment(BaseModel): id = Column(Integer, primary_key=True, autoincrement=True) document_id = Column(Integer, ForeignKey('condition.documents.id', ondelete='CASCADE'), nullable=False) amended_document_id = Column(String(255), nullable=False) - document_type = Column(String(100), nullable=False) + document_type_id = Column(Integer, ForeignKey('condition.document_types.id', ondelete='CASCADE'), nullable=True) amendment_name = Column(Text) date_issued = Column(Date) act = Column(Integer) diff --git a/condition-api/src/condition_api/models/document.py b/condition-api/src/condition_api/models/document.py index 15a6066..4674fae 100644 --- a/condition-api/src/condition_api/models/document.py +++ b/condition-api/src/condition_api/models/document.py @@ -18,7 +18,8 @@ class Document(BaseModel): document_id = Column(String(255), nullable=False) amended_id = Column(Integer, ForeignKey('condition.documents.id', ondelete='CASCADE'), nullable=True) document_type_id = Column(Integer, ForeignKey('condition.document_types.id', ondelete='CASCADE'), nullable=True) - display_name = Column(Text) + document_label = Column(Text) + document_link = Column(Text) document_file_name = Column(Text) date_issued = Column(Date) act = Column(Integer) diff --git a/condition-api/src/condition_api/resources/condition_attribute.py b/condition-api/src/condition_api/resources/condition_attribute.py index 0eb4bc4..b20eaa2 100644 --- a/condition-api/src/condition_api/resources/condition_attribute.py +++ b/condition-api/src/condition_api/resources/condition_attribute.py @@ -17,7 +17,7 @@ from flask_restx import Namespace, Resource, cors from marshmallow import ValidationError -from condition_api.schemas.condition import ConditionAttributeSchema +from condition_api.schemas.condition_attribute import ConditionAttributeSchema from condition_api.services.condition_attribute_service import ConditionAttributeService from condition_api.utils.util import cors_preflight diff --git a/condition-api/src/condition_api/resources/document.py b/condition-api/src/condition_api/resources/document.py index b76ddf3..dd248dc 100644 --- a/condition-api/src/condition_api/resources/document.py +++ b/condition-api/src/condition_api/resources/document.py @@ -19,8 +19,7 @@ from condition_api.models.document_type import DocumentType from condition_api.models.project import Project -from condition_api.schemas.document import DocumentTypeSchema -from condition_api.schemas.project import DocumentSchema +from condition_api.schemas.document import DocumentSchema, DocumentTypeSchema from condition_api.services.document_service import DocumentService from condition_api.utils.util import cors_preflight diff --git a/condition-api/src/condition_api/resources/subcondition.py b/condition-api/src/condition_api/resources/subcondition.py index 304428a..ba07aba 100644 --- a/condition-api/src/condition_api/resources/subcondition.py +++ b/condition-api/src/condition_api/resources/subcondition.py @@ -18,7 +18,7 @@ from flask_restx import Namespace, Resource, cors from marshmallow import ValidationError -from condition_api.schemas.condition import SubConditionSchema +from condition_api.schemas.subcondition import SubconditionSchema from condition_api.services.subcondition_service import SubConditionService from condition_api.utils.util import cors_preflight @@ -30,7 +30,7 @@ """ subcondition_model = ApiHelper.convert_ma_schema_to_restx_model( - API, SubConditionSchema(), "SubCondition" + API, SubconditionSchema(), "SubCondition" ) @cors_preflight("PATCH, OPTIONS") @@ -49,8 +49,8 @@ class Subconditions(Resource): def patch(): """Edit multiple subconditions.""" try: - subconditions_data = SubConditionSchema(many=True).load(API.payload) + subconditions_data = SubconditionSchema(many=True).load(API.payload) updated_subconditions = SubConditionService.update_subconditions(subconditions_data) - return SubConditionSchema(many=True).dump(updated_subconditions), HTTPStatus.OK + return SubconditionSchema(many=True).dump(updated_subconditions), HTTPStatus.OK except ValidationError as err: return {"message": str(err)}, HTTPStatus.BAD_REQUEST diff --git a/condition-api/src/condition_api/schemas/condition.py b/condition-api/src/condition_api/schemas/condition.py index a6be0a0..96b1a4a 100644 --- a/condition-api/src/condition_api/schemas/condition.py +++ b/condition-api/src/condition_api/schemas/condition.py @@ -4,20 +4,8 @@ """ from marshmallow import Schema, fields - -class ConditionAttributeSchema(Schema): - id = fields.Str(required=True, data_key="id") - key = fields.Str(required=True, data_key="key") - value = fields.Raw(allow_none=True, data_key="value") - -class SubConditionSchema(Schema): - """Recursive schema for subconditions.""" - subcondition_id = fields.Str(data_key="subcondition_id") - subcondition_identifier = fields.Str(data_key="subcondition_identifier") - subcondition_text = fields.Str(data_key="subcondition_text") - - # Recursively define subconditions (i.e., subconditions can have child subconditions) - subconditions = fields.List(fields.Nested(lambda: SubConditionSchema()), data_key="subconditions") +from condition_api.schemas.condition_attribute import ConditionAttributeSchema +from condition_api.schemas.subcondition import SubconditionSchema class ConditionSchema(Schema): """Condition schema.""" @@ -37,17 +25,19 @@ class ConditionSchema(Schema): condition_attributes = fields.List(fields.Nested(ConditionAttributeSchema), data_key="condition_attributes") # Condition can also have its own subconditions (recursive nesting) - subconditions = fields.List(fields.Nested(SubConditionSchema), data_key="subconditions") + subconditions = fields.List(fields.Nested(SubconditionSchema), data_key="subconditions") class ProjectDocumentConditionSchema(Schema): """Top-level schema to include project and document names.""" project_name = fields.Str(data_key="project_name") - document_type = fields.Str(data_key="document_type") + document_category = fields.Str(data_key="document_category") + document_category_id = fields.Str(data_key="document_category_id") + document_label = fields.Str(data_key="document_label") conditions = fields.List(fields.Nested(ConditionSchema), data_key="conditions") class ProjectDocumentConditionDetailSchema(Schema): """Top-level schema to include project and document names.""" project_name = fields.Str(data_key="project_name") - document_type = fields.Str(data_key="document_type") - display_name = fields.Str(data_key="display_name") + document_category = fields.Str(data_key="document_category") + document_label = fields.Str(data_key="document_label") condition = fields.Nested(ConditionSchema, data_key="condition") diff --git a/condition-api/src/condition_api/schemas/condition_attribute.py b/condition-api/src/condition_api/schemas/condition_attribute.py new file mode 100644 index 0000000..4c71eed --- /dev/null +++ b/condition-api/src/condition_api/schemas/condition_attribute.py @@ -0,0 +1,24 @@ +"""Condition Attribute model class. + +Manages the Condition Attribute +""" + +from marshmallow import EXCLUDE, Schema, fields + +class BaseSchema(Schema): + """Base schema to exclude unknown fields in the deserialized output.""" + + class Meta: + unknown = EXCLUDE + + +class ConditionAttributeSchema(BaseSchema): + """Condition Attribute schema.""" + deliverable_name = fields.Str(data_key="deliverable_name") + is_plan = fields.Bool(data_key="is_plan") + approval_type = fields.Str(data_key="approval_type") + stakeholders_to_consult = fields.List(fields.Str(), data_key="stakeholders_to_consult") + stakeholders_to_submit_to = fields.List(fields.Str(), data_key="stakeholders_to_submit_to") + consultation_required = fields.Bool(data_key="consultation_required") + related_phase = fields.Str(data_key="related_phase") + days_prior_to_commencement = fields.Int(data_key="days_prior_to_commencement") diff --git a/condition-api/src/condition_api/schemas/document.py b/condition-api/src/condition_api/schemas/document.py index a29ca10..4e45aee 100644 --- a/condition-api/src/condition_api/schemas/document.py +++ b/condition-api/src/condition_api/schemas/document.py @@ -4,6 +4,7 @@ """ from marshmallow import Schema, fields +from condition_api.schemas.condition import ConditionSchema class DocumentTypeSchema(Schema): """Documents type schema.""" @@ -16,9 +17,24 @@ class DocumentSchema(Schema): """Documents schema.""" document_id = fields.Str(data_key="document_id") - document_name = fields.Str(data_key="document_name") + document_label = fields.Str(data_key="document_label") + document_link = fields.Str(data_key="document_link") + document_file_name = fields.Str(data_key="document_file_name") + document_category_id = fields.Str(data_key="document_category_id") + document_category = fields.Str(data_key="document_category") + document_types = fields.List(fields.Str(), data_key="document_types") + document_type_id = fields.Int(data_key="document_type_id") + date_issued = fields.Str(data_key="date_issued") year_issued = fields.Int(data_key="year_issued") + act = fields.Int(data_key="act") + project_id = fields.Str(data_key="project_id") + first_nations = fields.List(fields.Str(), data_key="first_nations") + consultation_records_required = fields.Bool(data_key="consultation_records_required") status = fields.Bool(data_key="status") + amendment_count = fields.Int(data_key="amendment_count") + + # Each document can have multiple conditions + conditions = fields.List(fields.Nested(ConditionSchema), data_key="conditions") class ProjectDocumentAllAmendmentsSchema(Schema): """Top-level schema to include all amendments related to a document.""" diff --git a/condition-api/src/condition_api/schemas/project.py b/condition-api/src/condition_api/schemas/project.py index a5cb6b2..6d8f72a 100644 --- a/condition-api/src/condition_api/schemas/project.py +++ b/condition-api/src/condition_api/schemas/project.py @@ -4,6 +4,7 @@ """ from marshmallow import EXCLUDE, Schema, fields +from condition_api.schemas.document import DocumentSchema class BaseSchema(Schema): """Base schema to exclude unknown fields in the deserialized output.""" @@ -11,62 +12,6 @@ class BaseSchema(Schema): class Meta: unknown = EXCLUDE - -class SubconditionSchema(BaseSchema): - """Subcondition schema.""" - subcondition_id = fields.Str(data_key="subcondition_id") - subcondition_identifier = fields.Str(data_key="subcondition_identifier") - subcondition_text = fields.Str(data_key="subcondition_text") - - # Recursively define subconditions (i.e., subconditions can have child subconditions) - subconditions = fields.List(fields.Nested(lambda: SubconditionSchema()), data_key="subconditions") - -class ConditionAttributeSchema(BaseSchema): - """Condition Attribute schema.""" - deliverable_name = fields.Str(data_key="deliverable_name") - is_plan = fields.Bool(data_key="is_plan") - approval_type = fields.Str(data_key="approval_type") - stakeholders_to_consult = fields.List(fields.Str(), data_key="stakeholders_to_consult") - stakeholders_to_submit_to = fields.List(fields.Str(), data_key="stakeholders_to_submit_to") - consultation_required = fields.Bool(data_key="consultation_required") - related_phase = fields.Str(data_key="related_phase") - days_prior_to_commencement = fields.Int(data_key="days_prior_to_commencement") - - -class ConditionSchema(BaseSchema): - """Condition schema.""" - condition_name = fields.Str(data_key="condition_name") - condition_number = fields.Int(data_key="condition_number") - condition_text = fields.Str(data_key="condition_text") - topic_tags = fields.List(fields.Str(), data_key="topic_tags") - subtopic_tags = fields.List(fields.Str(), data_key="subtopic_tags") - - # Add subconditions and condition attributes to the condition - subconditions = fields.List(fields.Nested(SubconditionSchema), data_key="subconditions") - condition_attributes = fields.List(fields.Nested(ConditionAttributeSchema), data_key="condition_attributes") - - -class DocumentSchema(BaseSchema): - """Document schema.""" - document_id = fields.Str(data_key="document_id") - display_name = fields.Str(data_key="display_name") - document_file_name = fields.Str(data_key="document_file_name") - document_category_id = fields.Str(data_key="document_category_id") - document_category = fields.Str(data_key="document_category") - document_types = fields.List(fields.Str(), data_key="document_types") - document_type_id = fields.Int(data_key="document_type_id") - date_issued = fields.Str(data_key="date_issued") - act = fields.Int(data_key="act") - project_id = fields.Str(data_key="project_id") - first_nations = fields.List(fields.Str(), data_key="first_nations") - consultation_records_required = fields.Bool(data_key="consultation_records_required") - status = fields.Bool(data_key="status") - amendment_count = fields.Int(data_key="amendment_count") - - # Each document can have multiple conditions - conditions = fields.List(fields.Nested(ConditionSchema), data_key="conditions") - - class ProjectSchema(BaseSchema): """Project schema, including documents, conditions, subconditions, and deliverables.""" diff --git a/condition-api/src/condition_api/schemas/subcondition.py b/condition-api/src/condition_api/schemas/subcondition.py new file mode 100644 index 0000000..8679c01 --- /dev/null +++ b/condition-api/src/condition_api/schemas/subcondition.py @@ -0,0 +1,22 @@ +"""Subconditio model class. + +Manages the Subconditio +""" + +from marshmallow import EXCLUDE, Schema, fields + +class BaseSchema(Schema): + """Base schema to exclude unknown fields in the deserialized output.""" + + class Meta: + unknown = EXCLUDE + + +class SubconditionSchema(BaseSchema): + """Subcondition schema.""" + subcondition_id = fields.Str(data_key="subcondition_id") + subcondition_identifier = fields.Str(data_key="subcondition_identifier") + subcondition_text = fields.Str(data_key="subcondition_text") + + # Recursively define subconditions (i.e., subconditions can have child subconditions) + subconditions = fields.List(fields.Nested(lambda: SubconditionSchema()), data_key="subconditions") diff --git a/condition-api/src/condition_api/services/condition_service.py b/condition-api/src/condition_api/services/condition_service.py index 8095bda..d1ffcdd 100644 --- a/condition-api/src/condition_api/services/condition_service.py +++ b/condition-api/src/condition_api/services/condition_service.py @@ -32,9 +32,9 @@ def get_condition_details(project_id, document_id, condition_number): condition_data = ( db.session.query( projects.project_name, - document_categories.category_name.label('document_type'), + document_categories.category_name.label('document_category'), extract('year', documents.date_issued).label('year_issued'), - documents.display_name, + documents.document_label, conditions.id, conditions.condition_name, conditions.condition_number, @@ -83,8 +83,8 @@ def get_condition_details(project_id, document_id, condition_number): return None project_name = condition_data[0].project_name if condition_data else None - document_type = condition_data[0].document_type if condition_data else None - display_name = condition_data[0].display_name if condition_data else None + document_category = condition_data[0].document_category if condition_data else None + document_label = condition_data[0].document_label if condition_data else None # Extract condition details condition = { @@ -153,8 +153,8 @@ def get_condition_details(project_id, document_id, condition_number): return { "project_name": project_name, - "document_type": document_type, - "display_name": display_name, + "document_category": document_category, + "document_label": document_label, "condition": condition } @@ -191,7 +191,9 @@ def get_all_conditions(project_id, document_id): condition_data = ( db.session.query( projects.project_name, - document_categories.category_name.label('document_type'), + document_categories.category_name.label('document_category'), + document_categories.id.label('document_category_id'), + documents.document_label, conditions.condition_name, conditions.condition_number, conditions.condition_text, @@ -236,6 +238,7 @@ def get_all_conditions(project_id, document_id): .group_by( projects.project_name, document_categories.category_name, + document_categories.id, conditions.condition_name, conditions.condition_number, conditions.condition_text, @@ -247,7 +250,8 @@ def get_all_conditions(project_id, document_id): subconditions.subcondition_text, subconditions.parent_subcondition_id, amendment_subquery.c.amendment_names, - documents.date_issued + documents.date_issued, + documents.document_label ) .all() ) @@ -256,7 +260,9 @@ def get_all_conditions(project_id, document_id): subcondition_map = {} project_name = condition_data[0].project_name if condition_data else None - document_type = condition_data[0].document_type if condition_data else None + document_category = condition_data[0].document_category if condition_data else None + document_category_id = condition_data[0].document_category_id if condition_data else None + document_label = condition_data[0].document_label if condition_data else None # Process the query result for row in condition_data: @@ -299,7 +305,9 @@ def get_all_conditions(project_id, document_id): # Return all conditions return { "project_name": project_name, - "document_type": document_type, + "document_category": document_category, + "document_category_id": document_category_id, + "document_label": document_label, "conditions": list(conditions_map.values()) } diff --git a/condition-api/src/condition_api/services/document_service.py b/condition-api/src/condition_api/services/document_service.py index 41ae09b..4ebcda8 100644 --- a/condition-api/src/condition_api/services/document_service.py +++ b/condition-api/src/condition_api/services/document_service.py @@ -23,7 +23,7 @@ def get_all_documents_by_category(project_id, category_id): DocumentCategory.category_name.label('document_category'), Document.id.label('id'), Document.document_id.label('document_id'), - Document.display_name.label('document_name'), + Document.document_label.label('document_label'), extract('year', Document.date_issued).label('year_issued'), case( (func.count(Condition.id) == 0, None), @@ -49,7 +49,7 @@ def get_all_documents_by_category(project_id, category_id): DocumentCategory.category_name, Document.id, Document.document_id, - Document.display_name, + Document.document_label, Document.date_issued ).all() @@ -65,7 +65,7 @@ def get_all_documents_by_category(project_id, category_id): # Fetch all amendments associated with the original document amendments_query = db.session.query( Amendment.amended_document_id.label('document_id'), - Amendment.amendment_name.label('document_name'), + Amendment.amendment_name.label('document_label'), extract('year', Amendment.date_issued).label('year_issued'), func.min(case((Condition.is_approved == False, 0), else_=1)).label('status') ).outerjoin( @@ -80,7 +80,7 @@ def get_all_documents_by_category(project_id, category_id): # Append the main document to the result list result.append({ 'document_id': document.document_id, - 'document_name': document.document_name, + 'document_label': document.document_label, 'year_issued': document.year_issued, 'status': document.status }) @@ -89,7 +89,7 @@ def get_all_documents_by_category(project_id, category_id): for amendment in amendments_query: result.append({ 'document_id': amendment.document_id, - 'document_name': amendment.document_name, + 'document_label': amendment.document_label, 'year_issued': amendment.year_issued, 'status': amendment.status }) @@ -120,7 +120,8 @@ def create_document(project_id, document): document_id=document_id, date_issued=date_issued, project_id=project_id, - display_name=document.get("display_name"), + document_label=document.get("document_label"), + document_link=document.get("document_link"), document_type_id=document.get("document_type_id") ) db.session.add(new_document) diff --git a/condition-lib/loadConditions.py b/condition-lib/loadConditions.py index 6f89a7f..2060f11 100644 --- a/condition-lib/loadConditions.py +++ b/condition-lib/loadConditions.py @@ -60,20 +60,14 @@ def reset_tables(): def get_document_category_id(document_type): """Determine the document_category_id based on document_type.""" - if document_type == "Application Materials": - return 1 - elif document_type == "Order": + if document_type == "Order": return 2 - elif document_type == "Comment/Submission": - return 3 elif document_type == "Other": return 4 elif document_type == "Amendment": - return 7 + return 3 elif document_type == "Schedule B/Certificate": - return 6 - elif document_type == "Decision Materials": - return 5 + return 1 def load_data(folder_path): for filename in os.listdir(folder_path): @@ -109,7 +103,7 @@ def load_data(folder_path): # Insert into the 'documents' table cur.execute(""" INSERT INTO condition.documents ( - document_id, document_type_id, display_name, document_file_name, + document_id, document_type_id, document_label, document_file_name, date_issued, act, first_nations, consultation_records_required, project_id, created_date ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, NOW()) """, ( diff --git a/condition-web/src/components/ConditionDetails/ConditionHeader.tsx b/condition-web/src/components/ConditionDetails/ConditionHeader.tsx index 006434f..3d9957b 100644 --- a/condition-web/src/components/ConditionDetails/ConditionHeader.tsx +++ b/condition-web/src/components/ConditionDetails/ConditionHeader.tsx @@ -18,7 +18,7 @@ type ConditionHeaderProps = { documentId: string; conditionNumber: number; projectName: string; - documentName: string; + documentLabel: string; condition: ConditionModel; setCondition: React.Dispatch>; }; @@ -28,7 +28,7 @@ const ConditionHeader = ({ documentId, conditionNumber, projectName, - documentName, + documentLabel, condition, setCondition }: ConditionHeaderProps) => { @@ -182,7 +182,7 @@ const ConditionHeader = ({ - {documentName} + {documentLabel} diff --git a/condition-web/src/components/ConditionDetails/index.tsx b/condition-web/src/components/ConditionDetails/index.tsx index 25a275a..261e242 100644 --- a/condition-web/src/components/ConditionDetails/index.tsx +++ b/condition-web/src/components/ConditionDetails/index.tsx @@ -46,7 +46,7 @@ export const ConditionDetails = ({ documentId={documentId} conditionNumber={conditionNumber} projectName={initialCondition?.project_name || ""} - documentName={initialCondition?.display_name || ""} + documentLabel={initialCondition?.document_label || ""} condition={condition} setCondition={setCondition} /> diff --git a/condition-web/src/components/Conditions/ConditionsTable.tsx b/condition-web/src/components/Conditions/ConditionsTable.tsx index 889370e..2daf32e 100644 --- a/condition-web/src/components/Conditions/ConditionsTable.tsx +++ b/condition-web/src/components/Conditions/ConditionsTable.tsx @@ -16,11 +16,13 @@ import { projectId, documentId, headless, + noConditions, }: { conditions: Array; projectId: string; documentId: string; headless?: boolean; + noConditions: boolean; }) { return ( @@ -54,7 +56,7 @@ import { )} - {conditions?.map((condition) => ( + {!noConditions && conditions?.map((condition) => ( { +export const Conditions = ({ + projectName, + projectId, + documentCategory, + documentLabel, + documentId, + conditions +}: ConditionsParam) => { - const navigate = useNavigate(); - const [isToggled, setIsToggled] = useState(true); const [hasAmendments, setHasAmendments] = useState(false); const [isToggleEnabled, setIsToggleEnabled] = useState(false); - const [showAddConditionPage, setShowAddConditionPage] = useState(false); const [isLoading, setIsLoading] = useState(true); + const [noConditions, setNoConditions] = useState(false); useEffect(() => { // Check if all conditions have status as true @@ -52,91 +57,15 @@ export const Conditions = ({ projectName, projectId, documentName, documentId, c !condition.condition_text || condition.is_approved === null ); - setShowAddConditionPage(invalidConditions); + setNoConditions(invalidConditions); } setIsLoading(false); }, [conditions]); - const handleToggle = (event: React.ChangeEvent) => { - const checked = event.target.checked; - setIsToggled(checked); - if (!checked) { - navigate({ - to: `/amendments/project/${projectId}/document/${documentId}`, - }); - } - }; - if (isLoading) { return
Loading...
; } - if (showAddConditionPage) { - return ( - - - - {projectName} - - - } - label={""} - > - - - - - - - {documentName} - - - - - - - - - - - - - - - ); - } - return ( {/* Showing results message */} @@ -167,37 +96,53 @@ export const Conditions = ({ projectName, projectId, documentName, documentId, c > - - {/* Add horizontal padding to the document name */} - {documentName} - {hasAmendments && ( - - )} + + + {documentCategory} + - - - - + + + {documentLabel} + {hasAmendments && ( + + )} + + + + + + - - } - label="View Consolidated Certificate" - labelPlacement="end" - /> - + + diff --git a/condition-web/src/components/Documents/DocumentTableRow.tsx b/condition-web/src/components/Documents/DocumentTableRow.tsx index d9380b4..1015b66 100644 --- a/condition-web/src/components/Documents/DocumentTableRow.tsx +++ b/condition-web/src/components/Documents/DocumentTableRow.tsx @@ -58,7 +58,7 @@ export default function DocumentTableRow({ projectId, document }: DocumentRowPro fontSize={18} align="left" > - {document.document_name ?? "--"} + {document.document_label ?? "--"} diff --git a/condition-web/src/components/Documents/index.tsx b/condition-web/src/components/Documents/index.tsx index b0e8e43..af8b408 100644 --- a/condition-web/src/components/Documents/index.tsx +++ b/condition-web/src/components/Documents/index.tsx @@ -22,10 +22,10 @@ type DocumentsParam = { documents?: AllDocumentModel[]; projectName: string; projectId: string; - documentName: string; + documentLabel: string; }; -export const Documents = ({ projectName, projectId, documentName, documents }: DocumentsParam) => { +export const Documents = ({ projectName, projectId, documentLabel, documents }: DocumentsParam) => { const navigate = useNavigate(); const [isToggled, setIsToggled] = useState(false); const [isToggleEnabled, setIsToggleEnabled] = useState(false); @@ -92,7 +92,7 @@ export const Documents = ({ projectName, projectId, documentName, documents }: D > {/* Document Name and Icon */} - {documentName} + {documentLabel} diff --git a/condition-web/src/components/Projects/DocumentStatusChip.tsx b/condition-web/src/components/Projects/DocumentStatusChip.tsx index cca9ad9..86837dd 100644 --- a/condition-web/src/components/Projects/DocumentStatusChip.tsx +++ b/condition-web/src/components/Projects/DocumentStatusChip.tsx @@ -26,8 +26,8 @@ const statusStyles: Record = { nodata: { sx: { borderRadius: 1, - border: `2px solid ${BCDesignTokens.themeGold100}`, - background: "#FFDEB8", + border: `2px solid #CE3E39`, + background: "#F4E1E2", }, label: "Data Entry Required", }, diff --git a/condition-web/src/components/Projects/index.tsx b/condition-web/src/components/Projects/index.tsx index 1a5eb61..821a7a9 100644 --- a/condition-web/src/components/Projects/index.tsx +++ b/condition-web/src/components/Projects/index.tsx @@ -1,6 +1,6 @@ import { useState } from "react"; import { useNavigate } from "@tanstack/react-router"; -import { DocumentTypeModel } from "@/models/Document"; +import { DocumentType, DocumentTypeModel } from "@/models/Document"; import { ProjectModel } from "@/models/Project"; import { Autocomplete, @@ -47,10 +47,11 @@ export const Projects = ({ projects, documentType }: ProjectsParams) => { const [openModal, setOpenModal] = useState(false); const [selectedProject, setSelectedProject] = useState(null); const [selectedDocumentType, setSelectedDocumentType] = useState(null); - const [documentName, setDocumentName] = useState(""); + const [documentLabel, setDocumentLabel] = useState(""); + const [documentLink, setDocumentLink] = useState(""); const [dateIssued, setDateIssued] = useState(null); const [errors, setErrors] = useState({ - documentName: false, + documentLabel: false, dateIssued: false, }); @@ -82,24 +83,38 @@ export const Projects = ({ projects, documentType }: ProjectsParams) => { setOpenModal(false); setSelectedProject(null); setSelectedDocumentType(null); - setDocumentName(""); + setDocumentLabel(""); + setDocumentLink(""); setDateIssued(null); } const handleCancelCreateNewDocument = () => { setSelectedProject(null); setSelectedDocumentType(null); - setDocumentName(""); + setDocumentLabel(""); + setDocumentLink(""); setDateIssued(null); } const filteredDocumentTypes = documentType.filter((type) => { if (!selectedProject || !selectedProject.documents) return true; - const isExcluded = selectedProject.documents.some((document) => - document.document_types.includes("Schedule B/Certificate") + const hasCertificate = selectedProject.documents.some((document) => + document.document_types.includes(DocumentType.Certificate) ); - return type.document_type !== "Schedule B/Certificate" || !isExcluded; + const hasExemptionOrder = selectedProject.documents.some((document) => + document.document_types.includes(DocumentType.ExemptionOrder) + ); + + if (type.document_type === DocumentType.Certificate) { + return !hasExemptionOrder; // Exclude Certificate if ExemptionOrder is present + } + + if (type.document_type === DocumentType.ExemptionOrder) { + return !hasCertificate; // Exclude ExemptionOrder if Certificate is present + } + + return true; }); const onCreateFailure = () => { @@ -124,7 +139,8 @@ export const Projects = ({ projects, documentType }: ProjectsParams) => { : undefined; const data: CreateDocumentModel = { - display_name: documentName, + document_label: documentLabel, + document_link: documentLink, document_type_id: selectedDocumentType, date_issued: formattedDateIssued, }; @@ -183,14 +199,14 @@ export const Projects = ({ projects, documentType }: ProjectsParams) => { color="primary" size="small" sx={{ - width: "50%", + width: "30%", height: "70%", borderRadius: "4px", paddingLeft: "2px" }} onClick={handleOpenCreateNewDocument} > - Create New Document + Add Document @@ -232,7 +248,7 @@ export const Projects = ({ projects, documentType }: ProjectsParams) => { alignItems="center" padding={"14px 5px 14px 14px"} > - Create New Document + Add Document @@ -271,7 +287,7 @@ export const Projects = ({ projects, documentType }: ProjectsParams) => { /> {/* Document Type Selector */} - Which Document are you creating? + What is the source Document? { disabled={!selectedProject} /> {/* Document Name Field */} - Document Name + Document Label setDocumentName(e.target.value)} - error={errors.documentName} - helperText={errors.documentName && "Document name is required"} + value={documentLabel} + onChange={(e) => setDocumentLabel(e.target.value)} + error={errors.documentLabel} + helperText={errors.documentLabel && "Document label is required"} fullWidth - placeholder="Enter document name" + placeholder="Document Label" + size="small" + disabled={!selectedProject} + /> + {/* Document Link Field */} + Link to Document + setDocumentLink(e.target.value)} + fullWidth + placeholder="Link to Document" size="small" disabled={!selectedProject} /> @@ -327,15 +353,19 @@ export const Projects = ({ projects, documentType }: ProjectsParams) => { - diff --git a/condition-web/src/components/Shared/layout/SideNav/BreadcrumbNav.tsx b/condition-web/src/components/Shared/layout/SideNav/BreadcrumbNav.tsx index 2f86343..7e3244e 100644 --- a/condition-web/src/components/Shared/layout/SideNav/BreadcrumbNav.tsx +++ b/condition-web/src/components/Shared/layout/SideNav/BreadcrumbNav.tsx @@ -39,16 +39,28 @@ const BreadcrumbNav: React.FC = () => { > {breadcrumbs.map(({ title, path }) => ( - - {title} - + path ? ( + + {title} + + ) : ( + + {title} + + ) ))} diff --git a/condition-web/src/components/Shared/layout/SideNav/breadCrumbStore.ts b/condition-web/src/components/Shared/layout/SideNav/breadCrumbStore.ts index fc9087d..15897a7 100644 --- a/condition-web/src/components/Shared/layout/SideNav/breadCrumbStore.ts +++ b/condition-web/src/components/Shared/layout/SideNav/breadCrumbStore.ts @@ -8,7 +8,7 @@ interface BreadCrumb { interface BreadCrumbStore { breadcrumbs: BreadCrumb[]; setBreadcrumbs: (breadcrumbs: BreadCrumb[]) => void; - replaceBreadcrumb: (oldTitle: string, newTitle: string) => void; + replaceBreadcrumb: (oldTitle: string, newTitle: string, newPath?: string) => void; } // Create the Zustand store @@ -19,11 +19,11 @@ export const useBreadCrumb = create((set) => ({ breadcrumbs, })); }, - replaceBreadcrumb: (oldTitle, newTitle) => { + replaceBreadcrumb: (oldTitle, newTitle, newPath) => { set((state) => ({ breadcrumbs: state.breadcrumbs.map((breadcrumb) => breadcrumb.title === oldTitle - ? { ...breadcrumb, title: newTitle } + ? { ...breadcrumb, title: newTitle, path: newPath ?? breadcrumb.path } : breadcrumb, ), })); diff --git a/condition-web/src/models/Condition.ts b/condition-web/src/models/Condition.ts index 7c5d9e3..8df337f 100644 --- a/condition-web/src/models/Condition.ts +++ b/condition-web/src/models/Condition.ts @@ -49,13 +49,15 @@ export type PartialUpdateTopicTagsModel = Partial; export interface ProjectDocumentConditionModel { project_name: string; - document_type: string; + document_category: string; + document_category_id: number; + document_label: string; conditions?: ConditionModel[]; } export interface ProjectDocumentConditionDetailModel { project_name: string; - document_type: string; - display_name: string; + document_category: string; + document_label: string; condition: ConditionModel; } diff --git a/condition-web/src/models/Document.ts b/condition-web/src/models/Document.ts index 688a95c..a4d0e79 100644 --- a/condition-web/src/models/Document.ts +++ b/condition-web/src/models/Document.ts @@ -2,7 +2,7 @@ import { ConditionModel } from "./Condition"; export interface DocumentModel { document_id: string; - display_name: string; + document_label: string; document_category_id: number; document_category: string; document_file_name: string; @@ -36,7 +36,7 @@ export const DOCUMENT_STATUS: Record< export interface AllDocumentModel { document_id: string; - document_name: string; + document_label: string; year_issued: number; status: boolean; } @@ -55,7 +55,13 @@ export interface DocumentTypeModel { } export interface CreateDocumentModel { - display_name: string | null; + document_label: string | null; + document_link: string | null; document_type_id?: number | null; date_issued?: string | null; } + +export enum DocumentType { + 'ExemptionOrder' = 'Exemption Order', + 'Certificate' = 'Certificate', +} diff --git a/condition-web/src/routes/_authenticated/_dashboard/conditions/project/$projectId/document/$documentId/condition/$conditionNumber/index.tsx b/condition-web/src/routes/_authenticated/_dashboard/conditions/project/$projectId/document/$documentId/condition/$conditionNumber/index.tsx index 2276222..4fcafe2 100644 --- a/condition-web/src/routes/_authenticated/_dashboard/conditions/project/$projectId/document/$documentId/condition/$conditionNumber/index.tsx +++ b/condition-web/src/routes/_authenticated/_dashboard/conditions/project/$projectId/document/$documentId/condition/$conditionNumber/index.tsx @@ -50,7 +50,7 @@ function ConditionPage() { useEffect(() => { if (conditionDetails) { replaceBreadcrumb(META_PROJECT_TITLE, conditionDetails?.project_name || ""); - replaceBreadcrumb(META_DOCUMENT_TITLE, conditionDetails?.document_type || ""); + replaceBreadcrumb(META_DOCUMENT_TITLE, conditionDetails?.document_category || ""); replaceBreadcrumb(META_CONDITION_TITLE, conditionDetails?.condition.condition_name || ""); } }, [conditionDetails, replaceBreadcrumb, META_PROJECT_TITLE, META_DOCUMENT_TITLE, META_CONDITION_TITLE]); diff --git a/condition-web/src/routes/_authenticated/_dashboard/conditions/project/$projectId/document/$documentId/index.tsx b/condition-web/src/routes/_authenticated/_dashboard/conditions/project/$projectId/document/$documentId/index.tsx index 06be0b2..22fcc49 100644 --- a/condition-web/src/routes/_authenticated/_dashboard/conditions/project/$projectId/document/$documentId/index.tsx +++ b/condition-web/src/routes/_authenticated/_dashboard/conditions/project/$projectId/document/$documentId/index.tsx @@ -17,8 +17,9 @@ export const Route = createFileRoute( }, meta: ({ params }) => [ { title: "Home", path: "/projects/" }, - { title: `${params.projectId}`, path: `/projects/` }, // Fixed Projects path - { title: `${params.documentId}`, path: `/_authenticated/_dashboard/conditions/project/${params.projectId}/document/${params.documentId}/` } // Path to the specific document + { title: `${params.projectId}`, path: `/projects/` }, + { title: `Document Category`, path: `/documents/projects/${params.projectId}/document-category/` }, + { title: `Document Label`, path: undefined } ], }); @@ -42,14 +43,26 @@ function ConditionPage() { if (isConditionsError) return ; const META_PROJECT_TITLE = `${projectId}`; - const META_DOCUMENT_TITLE = `${documentId}`; + const META_DOCUMENT_CATEGORY = `Document Category`; + const META_DOCUMENT_LABEL = `Document Label`; const { replaceBreadcrumb } = useBreadCrumb(); useEffect(() => { if (documentConditions) { - replaceBreadcrumb(META_PROJECT_TITLE, documentConditions?.project_name || ""); - replaceBreadcrumb(META_DOCUMENT_TITLE, documentConditions?.document_type || ""); + replaceBreadcrumb(META_PROJECT_TITLE, documentConditions?.project_name || META_PROJECT_TITLE); + + replaceBreadcrumb( + META_DOCUMENT_CATEGORY, + documentConditions?.document_category || META_DOCUMENT_CATEGORY, + `/documents/project/${projectId}/document-category/${documentConditions.document_category_id}/` + ); + + replaceBreadcrumb( + META_DOCUMENT_LABEL, + documentConditions?.document_label || META_DOCUMENT_LABEL, + undefined + ); } - }, [documentConditions, replaceBreadcrumb, META_PROJECT_TITLE, META_DOCUMENT_TITLE]); + }, [documentConditions, replaceBreadcrumb, META_PROJECT_TITLE, META_DOCUMENT_CATEGORY, META_DOCUMENT_LABEL]); return ( @@ -62,7 +75,8 @@ function ConditionPage() { diff --git a/condition-web/src/routes/_authenticated/_dashboard/documents/project/$projectId/document-category/$categoryId/index.tsx b/condition-web/src/routes/_authenticated/_dashboard/documents/project/$projectId/document-category/$categoryId/index.tsx index 70eb7b9..49795c7 100644 --- a/condition-web/src/routes/_authenticated/_dashboard/documents/project/$projectId/document-category/$categoryId/index.tsx +++ b/condition-web/src/routes/_authenticated/_dashboard/documents/project/$projectId/document-category/$categoryId/index.tsx @@ -13,12 +13,12 @@ export const Route = createFileRoute( )({ component: DocumentPage, notFoundComponent: () => { - return

Document not found!

; + return

Document Category not found!

; }, meta: ({ params }) => [ { title: "Home", path: "/projects/" }, - { title: `${params.projectId}`, path: `/projects/` }, // Fixed Projects path - { title: `${params.categoryId}`, path: `/_authenticated/_dashboard/documents/projects/${params.projectId}/document-category/${params.categoryId}/` } // Path to the specific document + { title: `${params.projectId}`, path: `/projects/` }, + { title: `${params.categoryId}`, path: `/projects/` } ], }); @@ -41,14 +41,14 @@ function DocumentPage() { if (isAmendmentsError) return ; const META_PROJECT_TITLE = `${projectId}`; - const META_DOCUMENT_TITLE = `${categoryId}`; + const META_DOCUMENT_CATEGORY = `${categoryId}`; const { replaceBreadcrumb } = useBreadCrumb(); useEffect(() => { if (allDocuments) { - replaceBreadcrumb(META_PROJECT_TITLE, allDocuments?.project_name || ""); - replaceBreadcrumb(META_DOCUMENT_TITLE, allDocuments?.document_type || ""); + replaceBreadcrumb(META_PROJECT_TITLE, allDocuments?.project_name || META_PROJECT_TITLE); + replaceBreadcrumb(META_DOCUMENT_CATEGORY, allDocuments?.document_category || META_DOCUMENT_CATEGORY); } - }, [allDocuments, replaceBreadcrumb, META_PROJECT_TITLE, META_DOCUMENT_TITLE]); + }, [allDocuments, replaceBreadcrumb, META_PROJECT_TITLE, META_DOCUMENT_CATEGORY]); return ( @@ -61,7 +61,7 @@ function DocumentPage() { diff --git a/condition-web/src/routes/_authenticated/_dashboard/projects/index.tsx b/condition-web/src/routes/_authenticated/_dashboard/projects/index.tsx index 4b9e20d..28923b6 100644 --- a/condition-web/src/routes/_authenticated/_dashboard/projects/index.tsx +++ b/condition-web/src/routes/_authenticated/_dashboard/projects/index.tsx @@ -11,7 +11,7 @@ import { PageGrid } from "@/components/Shared/PageGrid"; export const Route = createFileRoute("/_authenticated/_dashboard/projects/")({ component: ProjectsPage, meta: () => [ - { title: "Home", path: "/_authenticated/_dashboard/projects/" }, + { title: "Home", path: "/projects/" }, ], });