diff --git a/web/cypress/integration/workbaskets/workbaskets.spec.js b/web/cypress/integration/workbaskets/workbaskets.spec.js index 0dbd33c92..efe52b8ac 100644 --- a/web/cypress/integration/workbaskets/workbaskets.spec.js +++ b/web/cypress/integration/workbaskets/workbaskets.spec.js @@ -197,11 +197,6 @@ context('TASKANA Workbaskets', () => { cy.get('#wb-custom-4').should('have.value', Cypress.env('testValueWorkbaskets')); }); - it('should be possible', () => { - cy.visitTestWorkbasket(); - cy.visitWorkbasketsDistributionTargetsPage(); - }); - it('should be possible to remove all distribution targets', () => { cy.visitTestWorkbasket(); cy.visitWorkbasketsDistributionTargetsPage(); @@ -217,4 +212,53 @@ context('TASKANA Workbaskets', () => { cy.undoWorkbaskets(); }); + + it('should filter selected distribution targets including newly transferred targets', () => { + cy.visitTestWorkbasket(); + cy.visitWorkbasketsDistributionTargetsPage(); + + cy.get('#dual-list-Right > .distribution-targets-list > .mat-toolbar > :nth-child(2)').click(); + cy.get( + '#dual-list-Right > .distribution-targets-list > taskana-shared-workbasket-filter > .filter > .filter__expanded-filter > .filter__text-input > :nth-child(1) > :nth-child(2) > .mat-form-field-wrapper > .mat-form-field-flex > .mat-form-field-infix > .mat-input-element' + ) + .clear() + .type('002'); + cy.get('.filter__action-buttons > .filter__search-button').click(); + + cy.get( + '#dual-list-Right > .distribution-targets-list > .mat-selection-list > .cdk-virtual-scroll-viewport > .cdk-virtual-scroll-content-wrapper > :nth-child(1)' + ).should('contain.text', 'Basxet1'); + + cy.get('.filter__action-buttons > [mattooltip="Clear Workbasket filter"]').click(); + + cy.get( + '#dual-list-Right > .distribution-targets-list > .mat-selection-list > .cdk-virtual-scroll-viewport > .cdk-virtual-scroll-content-wrapper' + ) + .children() + .should('have.length', 2); + }); + + it('should filter available distribution targets', () => { + cy.visitTestWorkbasket(); + cy.visitWorkbasketsDistributionTargetsPage(); + + cy.get('#dual-list-Left > .distribution-targets-list > .mat-toolbar > :nth-child(2)').click(); + cy.get( + '#dual-list-Left > .distribution-targets-list > taskana-shared-workbasket-filter > .filter > .filter__expanded-filter > .filter__text-input > :nth-child(1) > :nth-child(2) > .mat-form-field-wrapper > .mat-form-field-flex > .mat-form-field-infix > .mat-input-element' + ) + .clear() + .type('008'); + + cy.get('.filter__action-buttons > .filter__search-button').click(); + + cy.get( + '#dual-list-Left > .distribution-targets-list > .mat-selection-list > .cdk-virtual-scroll-viewport > .cdk-virtual-scroll-content-wrapper' + ) + .children() + .should('have.length', 1); + + cy.get( + '#dual-list-Left > .distribution-targets-list > .mat-selection-list > .cdk-virtual-scroll-viewport > .cdk-virtual-scroll-content-wrapper > :nth-child(1)' + ).should('contain.text', 'BAsxet7'); + }); }); 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 e71672abe..b151423fe 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 @@ -15,6 +15,7 @@ import { CopyWorkbasket, DeselectWorkbasket, OnButtonPressed, + SaveNewWorkbasket, SelectComponent, UpdateWorkbasket, UpdateWorkbasketDistributionTargets @@ -97,6 +98,22 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy { .subscribe((wb) => (this.workbasket = wb)); }); }); + + this.ngxsActions$.pipe(ofActionSuccessful(SaveNewWorkbasket), takeUntil(this.destroy$)).subscribe(() => { + this.store + .dispatch(new UpdateWorkbasketDistributionTargets()) + .pipe(takeUntil(this.destroy$)) + .subscribe(() => { + this.selectedWorkbasket$ + .pipe( + take(5), + timeout(250), + catchError(() => of(null)), + filter((val) => val !== null) + ) + .subscribe((wb) => (this.workbasket = wb)); + }); + }); } selectComponent(index) { diff --git a/web/src/app/administration/components/workbasket-distribution-targets-list/workbasket-distribution-targets-list.component.ts b/web/src/app/administration/components/workbasket-distribution-targets-list/workbasket-distribution-targets-list.component.ts index 05dea6002..1e8610a19 100644 --- a/web/src/app/administration/components/workbasket-distribution-targets-list/workbasket-distribution-targets-list.component.ts +++ b/web/src/app/administration/components/workbasket-distribution-targets-list/workbasket-distribution-targets-list.component.ts @@ -58,6 +58,7 @@ export class WorkbasketDistributionTargetsListComponent toolbarState = false; distributionTargets: WorkbasketDistributionTarget[]; + distributionTargetsClone: WorkbasketDistributionTarget[]; @ViewChild('workbasket') distributionTargetsList: MatSelectionList; @ViewChild('scroller') workbasketList: CdkVirtualScrollViewport; @@ -69,30 +70,25 @@ export class WorkbasketDistributionTargetsListComponent ngOnInit(): void { if (this.side === Side.AVAILABLE) { - this.availableDistributionTargets$.pipe(takeUntil(this.destroy$)).subscribe((wbs) => { - this.distributionTargets = wbs.map((wb) => { - return { ...wb, selected: this.allSelected }; - }); - }); + this.availableDistributionTargets$.pipe(takeUntil(this.destroy$)).subscribe((wbs) => this.assignWbs(wbs)); this.availableDistributionTargetsFilter$.pipe(takeUntil(this.destroy$)).subscribe((filter) => { - if (typeof this.filter === 'undefined' || isEqual(this.filter, filter)) return; + if (typeof this.filter === 'undefined' || isEqual(this.filter, filter)) { + this.filter = filter; + return; + } this.filter = filter; this.store.dispatch(new FetchAvailableDistributionTargets(true, this.filter)); this.selectAll(false); }); } else { - this.workbasketDistributionTargets$.pipe().subscribe((wbs) => { - this.distributionTargets = wbs.map((wb) => { - return { ...wb }; - }); - }); + this.workbasketDistributionTargets$.pipe().subscribe((wbs) => this.assignWbs(wbs)); this.selectedDistributionTargetsFilter$.pipe(takeUntil(this.destroy$)).subscribe((filter) => { - if (typeof this.filter === 'undefined' || isEqual(this.filter, filter)) return; + if (typeof this.filter === 'undefined' || isEqual(this.filter, filter)) { + this.filter = filter; + return; + } this.filter = filter; - this.store - .dispatch(new FetchWorkbasketDistributionTargets(true)) - .pipe(take(1)) - .subscribe(() => this.applyFilter()); + this.applyFilter(); this.selectAll(false); }); } @@ -167,6 +163,11 @@ export class WorkbasketDistributionTargetsListComponent this.destroy$.complete(); } + private assignWbs(wbs: WorkbasketSummary[]) { + this.distributionTargets = wbs.map((wb) => ({ ...wb, selected: this.allSelected })); + this.distributionTargetsClone = this.distributionTargets; + } + private applyFilter() { function filterExact(target: WorkbasketDistributionTarget, filterStrings: string[], attribute: string) { if (!!filterStrings && filterStrings?.length !== 0) { @@ -186,7 +187,7 @@ export class WorkbasketDistributionTargetsListComponent return true; } - this.distributionTargets = this.distributionTargets?.filter((target) => { + this.distributionTargets = this.distributionTargetsClone?.filter((target) => { let matches = true; matches = matches && filterExact(target, this.filter.name, 'name'); matches = matches && filterExact(target, this.filter.key, 'key'); 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 83247b360..a6ad06169 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 @@ -3,14 +3,12 @@ import { forkJoin, Observable, Subject } from 'rxjs'; import { Workbasket } from 'app/shared/models/workbasket'; import { WorkbasketSummary } from 'app/shared/models/workbasket-summary'; -import { Actions, ofActionCompleted, Select, Store } from '@ngxs/store'; +import { Actions, Select, Store } from '@ngxs/store'; import { filter, take, takeUntil } from 'rxjs/operators'; import { NotificationService } from '../../../shared/services/notifications/notification.service'; import { FetchAvailableDistributionTargets, FetchWorkbasketDistributionTargets, - SaveNewWorkbasket, - UpdateWorkbasket, UpdateWorkbasketDistributionTargets } from '../../../shared/store/workbasket-store/workbasket.actions'; import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors'; 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 6c5e51a8d..5d056aeb9 100644 --- a/web/src/app/shared/store/workbasket-store/workbasket.state.ts +++ b/web/src/app/shared/store/workbasket-store/workbasket.state.ts @@ -237,7 +237,7 @@ export class WorkbasketState implements NgxsAfterBootstrap { tap((domain) => { this.location.go(this.location.path().replace(/(workbaskets).*/g, 'workbaskets/(detail:new-workbasket)')); - if (!ctx.getState().availableDistributionTargets) { + if (ctx.getState().availableDistributionTargets.workbaskets.length === 0) { ctx.dispatch(new FetchAvailableDistributionTargets(true)); } @@ -389,7 +389,8 @@ export class WorkbasketState implements NgxsAfterBootstrap { this.notificationService.showSuccess('WORKBASKET_DISTRIBUTION_TARGET_SAVE', { workbasketName: ctx.getState().selectedWorkbasket.name }); - + ctx.dispatch(new FetchAvailableDistributionTargets(true)); + ctx.dispatch(new FetchWorkbasketDistributionTargets(true)); return of(null); }, error: () => { @@ -404,12 +405,13 @@ export class WorkbasketState implements NgxsAfterBootstrap { ctx: StateContext, action: FetchWorkbasketDistributionTargets ): Observable { - const { selectedWorkbasket, distributionTargetsPage, workbasketDistributionTargets } = ctx.getState(); + const { selectedWorkbasket, distributionTargetsPage, workbasketDistributionTargets, availableDistributionTargets } = + ctx.getState(); const { filterParameter, sortParameter, refetchAll } = action; const nextDistributionTargetsPage = refetchAll ? 1 : distributionTargetsPage + 1; return this.workbasketService .getWorkBasketsDistributionTargets( - selectedWorkbasket._links.distributionTargets.href, + selectedWorkbasket._links?.distributionTargets.href, filterParameter, sortParameter, new WorkbasketQueryPagingParameter(nextDistributionTargetsPage) @@ -422,8 +424,14 @@ export class WorkbasketState implements NgxsAfterBootstrap { const idArrayNoDupe = [...new Set(completeArray.map((wb) => wb.workbasketId))]; wbt.distributionTargets = idArrayNoDupe.map((id) => completeArray.find((wb) => wb.workbasketId === id)); } + const distributionTargetSet = new Set(wbt.distributionTargets.map((wb) => wb.workbasketId)); + let availableTargets = cloneDeep(availableDistributionTargets); + availableTargets.workbaskets = availableTargets.workbaskets.filter((wb) => { + return !distributionTargetSet.has(wb.workbasketId); + }); ctx.patchState({ workbasketDistributionTargets: wbt, + availableDistributionTargets: availableTargets, distributionTargetsPage: nextDistributionTargetsPage }); })