From 6447d91b01b4b5eb2d32ea13edff6b7f1437ce31 Mon Sep 17 00:00:00 2001 From: lastminutediorama Date: Thu, 17 Oct 2024 13:17:50 -0500 Subject: [PATCH 1/3] update scenario archiving --- .../scenarios-card-list.component.html | 8 +++-- .../scenarios-card-list.component.scss | 2 +- .../scenarios-card-list.component.spec.ts | 2 ++ .../scenarios-card-list.component.ts | 33 +++++++++++++++++-- .../scenario-card.component.html | 23 +++++++++---- .../scenario-card.component.scss | 13 ++++++++ .../scenario-card/scenario-card.component.ts | 23 ++++++++----- .../scenario-card/scenario-card.stories.ts | 17 +++++----- 8 files changed, 90 insertions(+), 31 deletions(-) diff --git a/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.html b/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.html index 569992d4d..54d0a9071 100644 --- a/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.html +++ b/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.html @@ -2,15 +2,17 @@ *ngFor="let s of scenarios" [name]="s.name" [creator]="s.creator" - [areas]="getAreas(s)" + [areas]="numberOfAreas(s)" [created_at]="s.created_at" [budget]=" hasResults(s) ? calculateTotals(s.scenario_result!).estimatedCost : null " [treatmentPlansCount]="s.tx_plan_count" - [status]="s.scenario_result?.status || 'PENDING'" + [resultStatus]="s.scenario_result?.status || 'PENDING'" + [archiveStatus]="s.status" (click)="handleClickedScenario(s)" [selected]="isSelected(s)" [treatmentPlansEnabled]="treatmentPlansEnabled" - [userCanArchiveScenario]="userCanArchiveScenario(s)"> + [userCanArchiveScenario]="userCanArchiveScenario(s)" + (toggleArchiveStatus)="toggleScenarioStatus(s)"> diff --git a/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.scss b/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.scss index f9ab5cfc3..a85421bd5 100644 --- a/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.scss +++ b/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.scss @@ -4,7 +4,7 @@ :host { display: flex; flex-direction: column; - justify-content: start; + justify-content: flex-start; gap: 20px; padding-top: 20px; padding-bottom: 20px; diff --git a/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.spec.ts b/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.spec.ts index 533ce999a..5e334acb7 100644 --- a/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.spec.ts +++ b/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.spec.ts @@ -2,6 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ScenariosCardListComponent } from './scenarios-card-list.component'; import { FeaturesModule } from '../../../features/features.module'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; describe('ScenariosCardListComponent', () => { let component: ScenariosCardListComponent; @@ -12,6 +13,7 @@ describe('ScenariosCardListComponent', () => { imports: [ FeaturesModule, HttpClientTestingModule, + MatSnackBarModule, ScenariosCardListComponent, ], }).compileComponents(); diff --git a/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.ts b/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.ts index c47cd7a75..7281556ee 100644 --- a/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.ts +++ b/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.ts @@ -9,7 +9,9 @@ import { } from '../../plan-helpers'; import { FeatureService } from '../../../features/feature.service'; import { Plan, Scenario, ScenarioResult } from '@types'; -import { AuthService } from '@services'; +import { AuthService, ScenarioService } from '@services'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { SNACK_BOTTOM_NOTICE_CONFIG, SNACK_ERROR_CONFIG } from '@shared'; @Component({ selector: 'app-scenarios-card-list', @@ -27,12 +29,14 @@ export class ScenariosCardListComponent { constructor( private featureService: FeatureService, - private authService: AuthService + private authService: AuthService, + private snackbar: MatSnackBar, + private scenarioService: ScenarioService ) {} treatmentPlansEnabled = this.featureService.isFeatureEnabled('treatments'); - getAreas(scenario: Scenario) { + numberOfAreas(scenario: Scenario) { return scenario.scenario_result?.result?.features?.length; } @@ -69,4 +73,27 @@ export class ScenariosCardListComponent { const user = this.authService.currentUser(); return user?.id === this.plan?.user || user?.id == scenario.user; } + + toggleScenarioStatus(scenario: Scenario) { + if (scenario.id) { + const originalStatus = scenario.status; + this.scenarioService.toggleScenarioStatus(Number(scenario.id)).subscribe({ + next: () => { + this.snackbar.open( + `"${scenario.name}" has been ${originalStatus === 'ARCHIVED' ? 'restored' : 'archived'}`, + 'Dismiss', + SNACK_BOTTOM_NOTICE_CONFIG + ); + //TODO: refetch the list + }, + error: (err) => { + this.snackbar.open( + `Error: ${err.error.error}`, + 'Dismiss', + SNACK_ERROR_CONFIG + ); + }, + }); + } + } } diff --git a/src/interface/src/styleguide/scenario-card/scenario-card.component.html b/src/interface/src/styleguide/scenario-card/scenario-card.component.html index 0eb5e2eb3..2386916e3 100644 --- a/src/interface/src/styleguide/scenario-card/scenario-card.component.html +++ b/src/interface/src/styleguide/scenario-card/scenario-card.component.html @@ -2,7 +2,7 @@
{{ name }}
@@ -27,17 +27,26 @@ mat-icon-button> more_vert - -
diff --git a/src/interface/src/styleguide/scenario-card/scenario-card.component.scss b/src/interface/src/styleguide/scenario-card/scenario-card.component.scss index 7c9f20cdd..ba5f09f0e 100644 --- a/src/interface/src/styleguide/scenario-card/scenario-card.component.scss +++ b/src/interface/src/styleguide/scenario-card/scenario-card.component.scss @@ -87,6 +87,9 @@ border: none; background-color: white; } + .scenario-more-menu { + width: 140px; + } .detail-row { display: flex; @@ -118,3 +121,13 @@ background-color: inherit; } } + +::ng-deep .scenario-more-menu .mat-icon { + margin-right: 8px; + height: 20px; + width: 20px; + font-size: 20px; +} +::ng-deep .scenario-more-menu .mat-mdc-menu-panel { + width: 140px; +} diff --git a/src/interface/src/styleguide/scenario-card/scenario-card.component.ts b/src/interface/src/styleguide/scenario-card/scenario-card.component.ts index 753c32f73..64410026b 100644 --- a/src/interface/src/styleguide/scenario-card/scenario-card.component.ts +++ b/src/interface/src/styleguide/scenario-card/scenario-card.component.ts @@ -46,7 +46,8 @@ export type ScenarioResultLabel = 'Done' | 'Running' | 'Failed'; styleUrl: './scenario-card.component.scss', }) export class ScenarioCardComponent { - @Input() status: ScenarioResultStatus = 'SUCCESS'; + @Input() resultStatus: ScenarioResultStatus = 'SUCCESS'; + @Input() archiveStatus: 'ACTIVE' | 'ARCHIVED' = 'ACTIVE'; @Input() name = ''; @Input() areas? = 0; @Input() budget: number | null = null; @@ -60,7 +61,7 @@ export class ScenarioCardComponent { @Output() openScenario = new EventEmitter(); @Output() openPlanningProgress = new EventEmitter(); - @Output() archiveScenario = new EventEmitter(); + @Output() toggleArchiveStatus = new EventEmitter(); @Output() clicked = new EventEmitter(); readonly chipsStatus: Record< @@ -82,17 +83,21 @@ export class ScenarioCardComponent { hasFailed(): boolean { const failedValues = ['LOADING', 'NOT_STARTED', 'PENDING', 'RUNNING']; - return failedValues.includes(this.status); + return failedValues.includes(this.resultStatus); } isRunning(): boolean { const runningValues = ['LOADING', 'NOT_STARTED', 'PENDING', 'RUNNING']; - return runningValues.includes(this.status); + return runningValues.includes(this.resultStatus); } isDone(): boolean { const doneValues = ['SUCCESS']; - return doneValues.includes(this.status); + return doneValues.includes(this.resultStatus); + } + + isArchived(): boolean { + return this.archiveStatus === 'ARCHIVED'; } @HostBinding('class.disabled-content') @@ -106,15 +111,15 @@ export class ScenarioCardComponent { } getChipStatus(): StatusChipStatus { - if (this.status) { - return this.chipsStatus[this.status].status; + if (this.resultStatus) { + return this.chipsStatus[this.resultStatus].status; } return 'failed'; } getChipLabel(): ScenarioResultLabel { - if (this.status) { - return this.chipsStatus[this.status].label; + if (this.resultStatus) { + return this.chipsStatus[this.resultStatus].label; } return 'Failed'; } diff --git a/src/interface/src/styleguide/scenario-card/scenario-card.stories.ts b/src/interface/src/styleguide/scenario-card/scenario-card.stories.ts index a5ba9d93c..9ae0a641d 100644 --- a/src/interface/src/styleguide/scenario-card/scenario-card.stories.ts +++ b/src/interface/src/styleguide/scenario-card/scenario-card.stories.ts @@ -25,32 +25,33 @@ export const Default: Story = { args: { name: 'Test Scenario', areas: 5, - status: 'SUCCESS', + resultStatus: 'SUCCESS', creator: 'Larry Larrington', created_at: '2024-01-01 12:34:00', budget: 1234567, treatmentPlansCount: 5, + userCanArchiveScenario: true, }, }; export const Running: Story = { args: { ...Default.args, - status: 'RUNNING', + resultStatus: 'RUNNING', }, }; export const Done: Story = { args: { ...Default.args, - status: 'SUCCESS', + resultStatus: 'SUCCESS', }, }; export const Failed: Story = { args: { ...Default.args, - status: 'FAILURE', + resultStatus: 'FAILURE', }, }; @@ -58,7 +59,7 @@ export const TreatmentsPlansEnabled: Story = { args: { name: 'Test Scenario', areas: 5, - status: 'SUCCESS', + resultStatus: 'SUCCESS', creator: 'Larry Larrington', created_at: '2024-01-01 12:34:00', budget: 1234567, @@ -67,16 +68,16 @@ export const TreatmentsPlansEnabled: Story = { }, }; -export const UserCanArchiveScenario: Story = { +export const UserCannotArchiveScenario: Story = { args: { name: 'Test Scenario', areas: 5, - status: 'SUCCESS', + resultStatus: 'SUCCESS', creator: 'Larry Larrington', created_at: '2024-01-01 12:34:00', budget: 1234567, treatmentPlansCount: 5, treatmentPlansEnabled: true, - userCanArchiveScenario: true, + userCanArchiveScenario: false, }, }; From 1ba4230027c691be8143b4467446483d40c95ea7 Mon Sep 17 00:00:00 2001 From: lastminutediorama Date: Thu, 17 Oct 2024 13:30:37 -0500 Subject: [PATCH 2/3] add featureflag reminder --- .../plan-summary/saved-scenarios/saved-scenarios.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/interface/src/app/plan/plan-summary/saved-scenarios/saved-scenarios.component.ts b/src/interface/src/app/plan/plan-summary/saved-scenarios/saved-scenarios.component.ts index a4b40523e..61e7e4cf1 100644 --- a/src/interface/src/app/plan/plan-summary/saved-scenarios/saved-scenarios.component.ts +++ b/src/interface/src/app/plan/plan-summary/saved-scenarios/saved-scenarios.component.ts @@ -141,6 +141,7 @@ export class SavedScenariosComponent implements OnInit { this.highlightedScenarioRow = row; } + //TODO: Remove this from here we permanently switch to new_planning_area toggleScenarioStatus(archive: boolean) { const id = this.highlightedScenarioRow?.id; From 8a4a6f4dbf042ffe21ca9d7bec63dcdd8de83a3a Mon Sep 17 00:00:00 2001 From: lastminutediorama Date: Fri, 18 Oct 2024 10:50:58 -0500 Subject: [PATCH 3/3] add child event to refresh --- .../saved-scenarios/saved-scenarios.component.html | 5 ++--- .../scenarios-card-list/scenarios-card-list.component.ts | 3 ++- .../styleguide/scenario-card/scenario-card.component.html | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/interface/src/app/plan/plan-summary/saved-scenarios/saved-scenarios.component.html b/src/interface/src/app/plan/plan-summary/saved-scenarios/saved-scenarios.component.html index 2c9f63298..eafe1fccf 100644 --- a/src/interface/src/app/plan/plan-summary/saved-scenarios/saved-scenarios.component.html +++ b/src/interface/src/app/plan/plan-summary/saved-scenarios/saved-scenarios.component.html @@ -193,9 +193,8 @@

Scenarios

*ngIf="activeScenarios.length > 0" [scenarios]="activeScenarios" [plan]="plan" - (viewScenario)=" - navigateToScenario($event) - "> + (viewScenario)="navigateToScenario($event)" + (triggerRefresh)="fetchScenarios()">
No active scenarios diff --git a/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.ts b/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.ts index 7281556ee..a54193918 100644 --- a/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.ts +++ b/src/interface/src/app/plan/plan-summary/scenarios-card-list/scenarios-card-list.component.ts @@ -26,6 +26,7 @@ export class ScenariosCardListComponent { @Input() plan: Plan | null = null; @Output() selectScenario = new EventEmitter(); @Output() viewScenario = new EventEmitter(); + @Output() triggerRefresh = new EventEmitter(); constructor( private featureService: FeatureService, @@ -84,7 +85,7 @@ export class ScenariosCardListComponent { 'Dismiss', SNACK_BOTTOM_NOTICE_CONFIG ); - //TODO: refetch the list + this.triggerRefresh.emit(); }, error: (err) => { this.snackbar.open( diff --git a/src/interface/src/styleguide/scenario-card/scenario-card.component.html b/src/interface/src/styleguide/scenario-card/scenario-card.component.html index 2386916e3..b7f74a34c 100644 --- a/src/interface/src/styleguide/scenario-card/scenario-card.component.html +++ b/src/interface/src/styleguide/scenario-card/scenario-card.component.html @@ -19,7 +19,7 @@ New Treatment Plan