From b8156d75ab4848a73a36a1bacaeef4776a5b7284 Mon Sep 17 00:00:00 2001 From: Sofie Hofmann <29145005+sofie29@users.noreply.github.com> Date: Mon, 16 Nov 2020 12:59:58 +0100 Subject: [PATCH] TSK-1448: Expand workbasket path with selected tab (#1333) --- .../workbasket-access-items.component.ts | 11 ---- .../workbasket-details.component.html | 6 +-- .../workbasket-details.component.spec.ts | 21 ++++---- .../workbasket-details.component.ts | 25 +++------ ...rkbasket-distribution-targets.component.ts | 6 --- .../workbasket-information.component.ts | 1 - .../workbasket-list-toolbar.component.spec.ts | 2 + .../workbasket-list.component.spec.ts | 2 + .../workbasket-store/workbasket.state.ts | 54 ++++++++++++++++++- 9 files changed, 76 insertions(+), 52 deletions(-) diff --git a/web/src/app/administration/components/workbasket-access-items/workbasket-access-items.component.ts b/web/src/app/administration/components/workbasket-access-items/workbasket-access-items.component.ts index 73ae9ff18..fc76cc77e 100644 --- a/web/src/app/administration/components/workbasket-access-items/workbasket-access-items.component.ts +++ b/web/src/app/administration/components/workbasket-access-items/workbasket-access-items.component.ts @@ -51,9 +51,6 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest @Input() action: ACTION; - @Input() - active: string; - @ViewChildren('htmlInputElement') inputs: QueryList; @@ -142,14 +139,6 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest } ngOnChanges(changes?: SimpleChanges) { - if (!this.initialized && changes.active && changes.active.currentValue === 'accessItems') { - this.init(); - } - if (this.initialized && typeof changes.workbasket !== 'undefined') { - if (changes.workbasket.currentValue.workbasketId !== changes.workbasket.previousValue.workbasketId) { - this.init(); - } - } if (changes.action) { this.setBadge(); } diff --git a/web/src/app/administration/components/workbasket-details/workbasket-details.component.html b/web/src/app/administration/components/workbasket-details/workbasket-details.component.html index 9c333247a..4a83c2244 100644 --- a/web/src/app/administration/components/workbasket-details/workbasket-details.component.html +++ b/web/src/app/administration/components/workbasket-details/workbasket-details.component.html @@ -37,15 +37,15 @@ - + - + - + diff --git a/web/src/app/administration/components/workbasket-details/workbasket-details.component.spec.ts b/web/src/app/administration/components/workbasket-details/workbasket-details.component.spec.ts index 381c03496..351d2ebd8 100644 --- a/web/src/app/administration/components/workbasket-details/workbasket-details.component.spec.ts +++ b/web/src/app/administration/components/workbasket-details/workbasket-details.component.spec.ts @@ -15,11 +15,7 @@ import { RequestInProgressService } from '../../../shared/services/request-in-pr import { SelectedRouteService } from '../../../shared/services/selected-route/selected-route'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatDialogModule } from '@angular/material/dialog'; -import { - engineConfigurationMock, - selectedWorkbasketMock, - workbasketReadStateMock -} from '../../../shared/store/mock-data/mock-store'; +import { selectedWorkbasketMock, workbasketReadStateMock } from '../../../shared/store/mock-data/mock-store'; import { StartupService } from '../../../shared/services/startup/startup.service'; import { TaskanaEngineService } from '../../../shared/services/taskana-engine/taskana-engine.service'; import { WindowRefService } from '../../../shared/services/window/window.service'; @@ -29,6 +25,8 @@ import { MatTabsModule } from '@angular/material/tabs'; import { MatMenuModule } from '@angular/material/menu'; import { MatToolbarModule } from '@angular/material/toolbar'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { CreateWorkbasket } from '../../../shared/store/workbasket-store/workbasket.actions'; +import { take } from 'rxjs/operators'; @Component({ selector: 'taskana-shared-spinner', template: '' }) class SpinnerStub { @@ -140,7 +138,6 @@ describe('WorkbasketDetailsComponent', () => { workbasket: workbasketCreateState }); fixture.detectChanges(); - expect(component.tabSelected).toMatch('information'); expect(component.selectedId).toBeUndefined(); }); @@ -165,9 +162,13 @@ describe('WorkbasketDetailsComponent', () => { expect(component.workbasket).toEqual(selectedWorkbasketMock); }); - it('should select information tab when action is CREATE', () => { - component.action = ACTION.CREATE; - component.selectTab('workbasket'); - expect(component.tabSelected).toEqual('information'); + it('should select information tab when action is CREATE', (done) => { + component.selectComponent(1); + store.dispatch(new CreateWorkbasket()); + fixture.detectChanges(); + component.selectedTab$.pipe(take(1)).subscribe((tab) => { + expect(tab).toEqual(0); + done(); + }); }); }); diff --git a/web/src/app/administration/components/workbasket-details/workbasket-details.component.ts b/web/src/app/administration/components/workbasket-details/workbasket-details.component.ts index 2c4d2e688..7b3623f56 100644 --- a/web/src/app/administration/components/workbasket-details/workbasket-details.component.ts +++ b/web/src/app/administration/components/workbasket-details/workbasket-details.component.ts @@ -9,6 +9,7 @@ import { Select, Store } from '@ngxs/store'; import { takeUntil } from 'rxjs/operators'; import { WorkbasketAndAction, WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors'; import { TaskanaDate } from '../../../shared/util/taskana.date'; +import { Location } from '@angular/common'; import { ICONTYPES } from '../../../shared/models/icon-types'; import { DeselectWorkbasket, @@ -16,6 +17,7 @@ import { SelectComponent } from '../../../shared/store/workbasket-store/workbasket.actions'; import { ButtonAction } from '../../models/button-action'; +import { WorkbasketComponent } from '../../models/workbasket-component'; @Component({ selector: 'taskana-administration-workbasket-details', @@ -28,12 +30,14 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy, OnChanges selectedId: string; requestInProgress = false; action: ACTION; - tabSelected = 'information'; badgeMessage = ''; @Select(WorkbasketSelectors.selectedWorkbasket) selectedWorkbasket$: Observable; + @Select(WorkbasketSelectors.selectedComponent) + selectedTab$: Observable; + @Select(WorkbasketSelectors.workbasketActiveAction) activeAction$: Observable; @@ -43,6 +47,7 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy, OnChanges destroy$ = new Subject(); constructor( + private location: Location, private route: ActivatedRoute, private router: Router, private domainService: DomainService, @@ -54,7 +59,6 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy, OnChanges this.selectedWorkbasketAndAction$.pipe(takeUntil(this.destroy$)).subscribe((selectedWorkbasketAndAction) => { this.action = selectedWorkbasketAndAction.action; if (this.action === ACTION.CREATE) { - this.tabSelected = 'information'; this.selectedId = undefined; this.badgeMessage = 'Creating new workbasket'; this.initWorkbasket(); @@ -99,10 +103,6 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy, OnChanges this.router.navigate(['./'], { relativeTo: this.route.parent }); } - selectTab(tab) { - this.tabSelected = this.action === ACTION.CREATE ? 'information' : tab; - } - getWorkbasketInformation(selectedWorkbasket?: Workbasket) { let workbasketIdSelected: string; if (selectedWorkbasket) { @@ -145,19 +145,6 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy, OnChanges selectComponent(index) { this.store.dispatch(new SelectComponent(index)); - switch (index) { - case 0: - this.selectTab('information'); - break; - case 1: - this.selectTab('access-items'); - break; - case 2: - this.selectTab('distribution-targets'); - break; - default: - break; - } } onSubmit() { diff --git a/web/src/app/administration/components/workbasket-distribution-targets/workbasket-distribution-targets.component.ts b/web/src/app/administration/components/workbasket-distribution-targets/workbasket-distribution-targets.component.ts index 1a49b374a..aff496266 100644 --- a/web/src/app/administration/components/workbasket-distribution-targets/workbasket-distribution-targets.component.ts +++ b/web/src/app/administration/components/workbasket-distribution-targets/workbasket-distribution-targets.component.ts @@ -42,9 +42,6 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnChanges @Input() action: ACTION; - @Input() - active: string; - badgeMessage = ''; distributionTargetsSelectedResource: WorkbasketDistributionTargets; @@ -95,9 +92,6 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnChanges } ngOnChanges(changes: SimpleChanges) { - if (!this.initialized && changes.active && changes.active.currentValue === 'distributionTargets') { - this.init(); - } if (changes.action) { this.setBadge(); } diff --git a/web/src/app/administration/components/workbasket-information/workbasket-information.component.ts b/web/src/app/administration/components/workbasket-information/workbasket-information.component.ts index 40253a9d1..7541ba6f0 100644 --- a/web/src/app/administration/components/workbasket-information/workbasket-information.component.ts +++ b/web/src/app/administration/components/workbasket-information/workbasket-information.component.ts @@ -74,7 +74,6 @@ export class WorkbasketInformationComponent implements OnInit, OnChanges, OnDest ) {} ngOnInit() { - this.store.dispatch(new SelectComponent(WorkbasketComponent.INFORMATION)); this.allTypes = new Map([ ['PERSONAL', 'Personal'], ['GROUP', 'Group'], diff --git a/web/src/app/administration/components/workbasket-list-toolbar/workbasket-list-toolbar.component.spec.ts b/web/src/app/administration/components/workbasket-list-toolbar/workbasket-list-toolbar.component.spec.ts index 4e3d25b8b..264975b34 100644 --- a/web/src/app/administration/components/workbasket-list-toolbar/workbasket-list-toolbar.component.spec.ts +++ b/web/src/app/administration/components/workbasket-list-toolbar/workbasket-list-toolbar.component.spec.ts @@ -16,6 +16,7 @@ import { TaskanaType } from '../../../shared/models/taskana-type'; import { MatIconModule } from '@angular/material/icon'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatDialogModule } from '@angular/material/dialog'; +import { RouterTestingModule } from '@angular/router/testing'; const getDomainFn = jest.fn().mockReturnValue(true); const domainServiceMock = jest.fn().mockImplementation( @@ -53,6 +54,7 @@ describe('WorkbasketListToolbarComponent', () => { TestBed.configureTestingModule({ imports: [ HttpClientTestingModule, + RouterTestingModule, NgxsModule.forRoot([WorkbasketState]), BrowserAnimationsModule, MatIconModule, diff --git a/web/src/app/administration/components/workbasket-list/workbasket-list.component.spec.ts b/web/src/app/administration/components/workbasket-list/workbasket-list.component.spec.ts index 67313a79a..af37b4339 100644 --- a/web/src/app/administration/components/workbasket-list/workbasket-list.component.spec.ts +++ b/web/src/app/administration/components/workbasket-list/workbasket-list.component.spec.ts @@ -22,6 +22,7 @@ import { MatSelectModule } from '@angular/material/select'; import { FormsModule } from '@angular/forms'; import { MatListModule, MatSelectionList } from '@angular/material/list'; import { DomainService } from '../../../shared/services/domain/domain.service'; +import { RouterTestingModule } from '@angular/router/testing'; const workbasketSavedTriggeredFn = jest.fn().mockReturnValue(of(1)); const workbasketSummaryFn = jest.fn().mockReturnValue(of({})); @@ -99,6 +100,7 @@ describe('WorkbasketListComponent', () => { TestBed.configureTestingModule({ imports: [ NgxsModule.forRoot([WorkbasketState]), + RouterTestingModule, MatSnackBarModule, MatDialogModule, FormsModule, diff --git a/web/src/app/shared/store/workbasket-store/workbasket.state.ts b/web/src/app/shared/store/workbasket-store/workbasket.state.ts index 46a4dca24..dd5e54620 100644 --- a/web/src/app/shared/store/workbasket-store/workbasket.state.ts +++ b/web/src/app/shared/store/workbasket-store/workbasket.state.ts @@ -31,6 +31,7 @@ import { WorkbasketDistributionTargets } from '../../models/workbasket-distribut import { WorkbasketSummary } from '../../models/workbasket-summary'; import { WorkbasketComponent } from '../../../administration/models/workbasket-component'; import { ButtonAction } from '../../../administration/models/button-action'; +import { ActivatedRoute } from '@angular/router'; class InitializeStore { static readonly type = '[Workbasket] Initializing state'; @@ -41,9 +42,36 @@ export class WorkbasketState implements NgxsAfterBootstrap { constructor( private workbasketService: WorkbasketService, private location: Location, - private notificationService: NotificationService + private notificationService: NotificationService, + private route: ActivatedRoute ) {} + @Action(InitializeStore) + initializeStore(ctx: StateContext): Observable { + // read the selected tab from the route + this.route.queryParams.pipe(take(2)).subscribe((params) => { + let tabName: string = params.tab; + let tab: number; + + switch (tabName) { + case 'information': + tab = WorkbasketComponent.INFORMATION; + break; + case 'access-items': + tab = WorkbasketComponent.ACCESS_ITEMS; + break; + case 'distribution-targets': + tab = WorkbasketComponent.DISTRIBUTION_TARGETS; + break; + default: + tab = WorkbasketComponent.INFORMATION; + } + + ctx.dispatch(new SelectComponent(tab)); + }); + return of(); + } + @Action(GetWorkbasketsSummary) getWorkbasketsSummary(ctx: StateContext, action: GetWorkbasketsSummary): Observable { ctx.patchState({ @@ -75,7 +103,25 @@ export class WorkbasketState implements NgxsAfterBootstrap { @Action(SelectWorkbasket) selectWorkbasket(ctx: StateContext, action: SelectWorkbasket): Observable { - this.location.go(this.location.path().replace(/(workbaskets).*/g, `workbaskets/(detail:${action.workbasketId})`)); + let selectedComponent; + switch (ctx.getState().selectedComponent) { + case WorkbasketComponent.INFORMATION: + selectedComponent = 'information'; + break; + case WorkbasketComponent.ACCESS_ITEMS: + selectedComponent = 'access-items'; + break; + case WorkbasketComponent.DISTRIBUTION_TARGETS: + selectedComponent = 'distribution-targets'; + break; + } + + this.location.go( + this.location + .path() + .replace(/(workbaskets).*/g, `workbaskets/(detail:${action.workbasketId})?tab=${selectedComponent}`) + ); + const id = action.workbasketId; if (typeof id !== 'undefined') { return this.workbasketService.getWorkBasket(id).pipe( @@ -106,6 +152,7 @@ export class WorkbasketState implements NgxsAfterBootstrap { this.location.go(this.location.path().replace(/(workbaskets).*/g, 'workbaskets/(detail:new-workbasket)')); ctx.patchState({ selectedWorkbasket: undefined, + selectedComponent: WorkbasketComponent.INFORMATION, action: ACTION.CREATE }); return of(null); @@ -122,12 +169,15 @@ export class WorkbasketState implements NgxsAfterBootstrap { switch (action.component) { case WorkbasketComponent.INFORMATION: ctx.patchState({ selectedComponent: WorkbasketComponent.INFORMATION }); + this.location.go(this.location.path().replace(/(tab).*/g, 'tab=information')); break; case WorkbasketComponent.ACCESS_ITEMS: ctx.patchState({ selectedComponent: WorkbasketComponent.ACCESS_ITEMS }); + this.location.go(this.location.path().replace(/(tab).*/g, 'tab=access-items')); break; case WorkbasketComponent.DISTRIBUTION_TARGETS: ctx.patchState({ selectedComponent: WorkbasketComponent.DISTRIBUTION_TARGETS }); + this.location.go(this.location.path().replace(/(tab).*/g, 'tab=distribution-targets')); break; } return of(null);