TSK-1760: Started Rework of store for workbasketAccessItems
Now uses a virtually scrolling list and pages DistributionTargets
This commit is contained in:
parent
490a76cf4b
commit
0eb85565bc
|
@ -39,6 +39,7 @@
|
|||
"chart.js": "2.9.4",
|
||||
"core-js": "3.18.3",
|
||||
"file-saver": "2.0.5",
|
||||
"lodash": "^4.5.0",
|
||||
"ng2-charts": "2.4.3",
|
||||
"ngx-bootstrap": "7.1.0",
|
||||
"ngx-infinite-scroll": "10.0.1",
|
||||
|
@ -60,6 +61,7 @@
|
|||
"@typescript-eslint/parser": "5.1.0",
|
||||
"compression-webpack-plugin": "9.0.0",
|
||||
"cypress": "7.7.0",
|
||||
"@types/lodash": "^4.14.178",
|
||||
"cypress-intellij-reporter": "0.0.6",
|
||||
"eslint": "8.0.1",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
|
|
|
@ -56,6 +56,7 @@ import { MatRippleModule } from '@angular/material/core';
|
|||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatExpansionModule } from '@angular/material/expansion';
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
|
||||
const MODULES = [
|
||||
CommonModule,
|
||||
|
@ -66,7 +67,8 @@ const MODULES = [
|
|||
SharedModule,
|
||||
AdministrationRoutingModule,
|
||||
TypeaheadModule,
|
||||
InfiniteScrollModule
|
||||
InfiniteScrollModule,
|
||||
ScrollingModule
|
||||
];
|
||||
|
||||
const DECLARATIONS = [
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { ImportExportComponent } from './import-export.component';
|
||||
import { StartupService } from '../../../shared/services/startup/startup.service';
|
||||
|
@ -11,9 +11,7 @@ import { ImportExportService } from '../../services/import-export.service';
|
|||
import { HttpClient } from '@angular/common/http';
|
||||
import { of } from 'rxjs';
|
||||
import { ClassificationDefinitionService } from '../../services/classification-definition.service';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { TaskanaType } from '../../../shared/models/taskana-type';
|
||||
import { BlobGenerator } from '../../../shared/util/blob-generator';
|
||||
|
||||
jest.mock('../../../shared/util/blob-generator');
|
||||
|
||||
|
@ -45,31 +43,33 @@ xdescribe('ImportExportComponent', () => {
|
|||
})
|
||||
);
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [],
|
||||
declarations: [ImportExportComponent],
|
||||
providers: [
|
||||
StartupService,
|
||||
TaskanaEngineService,
|
||||
WindowRefService,
|
||||
WorkbasketDefinitionService,
|
||||
ClassificationDefinitionService,
|
||||
ImportExportService,
|
||||
{ provide: DomainService, useClass: domainServiceSpy },
|
||||
{ provide: NotificationService, useClass: notificationServiceSpy },
|
||||
{ provide: HttpClient, useClass: httpSpy }
|
||||
]
|
||||
}).compileComponents();
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [],
|
||||
declarations: [ImportExportComponent],
|
||||
providers: [
|
||||
StartupService,
|
||||
TaskanaEngineService,
|
||||
WindowRefService,
|
||||
WorkbasketDefinitionService,
|
||||
ClassificationDefinitionService,
|
||||
ImportExportService,
|
||||
{ provide: DomainService, useClass: domainServiceSpy },
|
||||
{ provide: NotificationService, useClass: notificationServiceSpy },
|
||||
{ provide: HttpClient, useClass: httpSpy }
|
||||
]
|
||||
}).compileComponents();
|
||||
|
||||
jest.clearAllMocks();
|
||||
jest.clearAllMocks();
|
||||
|
||||
fixture = TestBed.createComponent(ImportExportComponent);
|
||||
debugElement = fixture.debugElement;
|
||||
app = fixture.debugElement.componentInstance;
|
||||
app.currentSelection = TaskanaType.WORKBASKETS;
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
fixture = TestBed.createComponent(ImportExportComponent);
|
||||
debugElement = fixture.debugElement;
|
||||
app = fixture.debugElement.componentInstance;
|
||||
app.currentSelection = TaskanaType.WORKBASKETS;
|
||||
fixture.detectChanges();
|
||||
})
|
||||
);
|
||||
|
||||
it('should create component', () => {
|
||||
expect(app).toBeTruthy();
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
</taskana-administration-workbasket-access-items>
|
||||
</mat-tab>
|
||||
<mat-tab label="Distribution Targets">
|
||||
<taskana-administration-workbasket-distribution-targets [workbasket]="workbasket">
|
||||
<taskana-administration-workbasket-distribution-targets >
|
||||
</taskana-administration-workbasket-distribution-targets>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
<div id="dual-list-Left" class="distribution-targets-list">
|
||||
<div class="distribution-targets-list" id="dual-list-Left">
|
||||
<mat-toolbar>
|
||||
<span class="distribution-targets-list__header" matTooltip="{{header}}">{{header}}</span>
|
||||
|
||||
<!-- FILTER BUTTON -->
|
||||
<button mat-flat-button class="distribution-targets-list__action-button" (click)="changeToolbarState(!toolbarState)"
|
||||
<button (click)="changeToolbarState(!toolbarState)"
|
||||
class="distribution-targets-list__action-button" mat-flat-button
|
||||
>
|
||||
<span *ngIf="!toolbarState">
|
||||
Display filter
|
||||
|
@ -18,30 +19,53 @@
|
|||
<span style="flex: 1 1 auto"> </span>
|
||||
|
||||
<!-- SELECT ALL BUTTON -->
|
||||
<button mat-flat-button class="distribution-targets-list__action-button" (click)="selectAll(!allSelected);">
|
||||
<mat-icon class="button-icon" *ngIf="allSelected" matTooltip="Deselect all items">check_box</mat-icon>
|
||||
<mat-icon class="button-icon" *ngIf="!allSelected" matTooltip="Select all items">check_box_outline_blank</mat-icon>
|
||||
<button (click)="selectAll(!allSelected);" class="distribution-targets-list__action-button"
|
||||
mat-flat-button>
|
||||
<mat-icon *ngIf="allSelected" class="button-icon" matTooltip="Deselect all items">check_box
|
||||
</mat-icon>
|
||||
<mat-icon *ngIf="!allSelected" class="button-icon" matTooltip="Select all items">
|
||||
check_box_outline_blank
|
||||
</mat-icon>
|
||||
</button>
|
||||
</mat-toolbar>
|
||||
|
||||
<!-- FILTER COMPONENT -->
|
||||
<taskana-shared-workbasket-filter *ngIf="toolbarState" isExpanded="true" [component]="component"></taskana-shared-workbasket-filter>
|
||||
<taskana-shared-workbasket-filter *ngIf="toolbarState" [component]="component"
|
||||
isExpanded="true"></taskana-shared-workbasket-filter>
|
||||
|
||||
<!-- EMPTY LIST -->
|
||||
<div *ngIf="distributionTargets?.length == 0" class="distribution-targets-list__empty-list">
|
||||
|
||||
<!-- AVAILABLE SIDE -->
|
||||
<div *ngIf="side === 0" style="padding: 0 16px;">
|
||||
There are currently no Workbaskets for distribution
|
||||
</div>
|
||||
|
||||
<!-- SELECTED SIDE -->
|
||||
<div *ngIf="side === 1" style="padding: 0 16px;">
|
||||
There is currently no distributed Workbasket
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- WORKBASKET LIST -->
|
||||
<div class="{{toolbarState? 'distribution-targets-list__list--with-filter' : 'distribution-targets-list__list--no-filter'}}"
|
||||
infiniteScroll [infiniteScrollDistance]="1" [infiniteScrollThrottle]="50"
|
||||
[scrollWindow]="false" *ngIf="distributionTargets?.length > 0">
|
||||
<mat-selection-list #workbasket [multiple]="true">
|
||||
<mat-list-option class="workbasket-distribution-targets__workbaskets-item"
|
||||
*ngFor="let workbasket of distributionTargets | orderBy: ['type', 'name']"
|
||||
[selected]="workbasket.selected"
|
||||
(click)="workbasket.selected = !workbasket.selected"
|
||||
[value]="workbasket.workbasketId">
|
||||
<mat-selection-list #workbasket [multiple]="true">
|
||||
<cdk-virtual-scroll-viewport #scroller
|
||||
class="{{toolbarState? 'distribution-targets-list__list--with-filter' : 'distribution-targets-list__list--no-filter'}}"
|
||||
itemSize="90">
|
||||
<mat-list-option
|
||||
*cdkVirtualFor="let workbasket of distributionTargets| orderBy: ['type', 'name']; templateCacheSize: 0"
|
||||
(click)="updateSelectAll(!workbasket.selected) && (workbasket.selected = !workbasket.selected)"
|
||||
[selected]="workbasket.selected"
|
||||
[value]="workbasket.workbasketId"
|
||||
class="workbasket-distribution-targets__workbaskets-item">
|
||||
|
||||
<div class="distribution-targets-list__item-wrapper">
|
||||
|
||||
<!-- ICON -->
|
||||
<div class="distribution-targets-list__item-icon">
|
||||
<taskana-administration-icon-type [type]="workbasket.type" size="large" tooltip="true"></taskana-administration-icon-type>
|
||||
<taskana-administration-icon-type [type]="workbasket.type" size="large"
|
||||
tooltip="true"></taskana-administration-icon-type>
|
||||
</div>
|
||||
|
||||
<!-- INFO -->
|
||||
|
@ -54,32 +78,19 @@
|
|||
</div>
|
||||
|
||||
<!-- MARKED FOR DELETION -->
|
||||
<div class="workbaskets-item__marked" *ngIf="workbasket.markedForDeletion">
|
||||
<span title="Marked for deletion" matTooltip="Marked for deletion"
|
||||
class="material-icons md-20 {{workbasket.workbasketId === selectedId ? 'white': 'red' }} ">error</span>
|
||||
<div *ngIf="workbasket.markedForDeletion" class="workbaskets-item__marked">
|
||||
<span
|
||||
class="material-icons md-20 red "
|
||||
matTooltip="Marked for deletion"
|
||||
title="Marked for deletion">error</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
</mat-list-option>
|
||||
</mat-selection-list>
|
||||
</div>
|
||||
|
||||
<!-- EMPTY LIST -->
|
||||
<div class="distribution-targets-list__empty-list" *ngIf="distributionTargets?.length == 0">
|
||||
|
||||
<!-- AVAILABLE SIDE -->
|
||||
<div *ngIf="side === 0" style="padding: 0 16px;">
|
||||
There are currently no Workbaskets for distribution
|
||||
</div>
|
||||
|
||||
<!-- SELECTED SIDE -->
|
||||
<div *ngIf="side === 1" style="padding: 0 16px;">
|
||||
There is currently no distributed Workbasket
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
</mat-selection-list>
|
||||
|
||||
|
||||
</div>
|
||||
|
|
|
@ -1,15 +1,24 @@
|
|||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { ComponentFixture, fakeAsync, flush, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { Component, DebugElement, Input, Pipe, PipeTransform } from '@angular/core';
|
||||
import { WorkbasketDistributionTargetsListComponent } from './workbasket-distribution-targets-list.component';
|
||||
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
|
||||
import { WorkbasketType } from '../../../shared/models/workbasket-type';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { workbasketReadStateMock } from '../../../shared/store/mock-data/mock-store';
|
||||
import { Side } from '../workbasket-distribution-targets/workbasket-distribution-targets.component';
|
||||
import { engineConfigurationMock, workbasketReadStateMock } from '../../../shared/store/mock-data/mock-store';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { Side } from '../../models/workbasket-distribution-enums';
|
||||
import { NgxsModule, Store } from '@ngxs/store';
|
||||
import { WorkbasketState } from '../../../shared/store/workbasket-store/workbasket.state';
|
||||
import { animationFrameScheduler, EMPTY, of } from 'rxjs';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { DomainService } from '../../../shared/services/domain/domain.service';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
|
||||
@Component({ selector: 'taskana-shared-workbasket-filter', template: '' })
|
||||
class FilterStub {
|
||||
|
@ -38,6 +47,31 @@ describe('WorkbasketDistributionTargetsListComponent', () => {
|
|||
let fixture: ComponentFixture<WorkbasketDistributionTargetsListComponent>;
|
||||
let debugElement: DebugElement;
|
||||
let component: WorkbasketDistributionTargetsListComponent;
|
||||
let store: Store;
|
||||
|
||||
const routeParamsMock = { id: 'workbasket' };
|
||||
const activatedRouteMock = {
|
||||
firstChild: {
|
||||
params: of(routeParamsMock)
|
||||
}
|
||||
};
|
||||
|
||||
const httpSpy = jest.fn().mockImplementation(
|
||||
(): Partial<HttpClient> => ({
|
||||
get: jest.fn().mockReturnValue(of([])),
|
||||
post: jest.fn().mockReturnValue(of([]))
|
||||
})
|
||||
);
|
||||
|
||||
const domainServiceSpy: Partial<DomainService> = {
|
||||
getSelectedDomainValue: jest.fn().mockReturnValue(of(null)),
|
||||
getSelectedDomain: jest.fn().mockReturnValue(of('A')),
|
||||
getDomains: jest.fn().mockReturnValue(of(null))
|
||||
};
|
||||
|
||||
const requestInProgressServiceSpy: Partial<RequestInProgressService> = {
|
||||
setRequestInProgress: jest.fn().mockReturnValue(of(null))
|
||||
};
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
|
@ -46,12 +80,23 @@ describe('WorkbasketDistributionTargetsListComponent', () => {
|
|||
MatIconModule,
|
||||
MatToolbarModule,
|
||||
MatListModule,
|
||||
MatDialogModule,
|
||||
MatTooltipModule,
|
||||
InfiniteScrollModule,
|
||||
BrowserAnimationsModule
|
||||
ScrollingModule,
|
||||
BrowserAnimationsModule,
|
||||
NgxsModule.forRoot([WorkbasketState])
|
||||
],
|
||||
declarations: [WorkbasketDistributionTargetsListComponent, FilterStub, SpinnerStub, IconTypeStub, OrderByMock],
|
||||
providers: []
|
||||
providers: [
|
||||
{ provide: HttpClient, useValue: httpSpy },
|
||||
{
|
||||
provide: DomainService,
|
||||
useValue: domainServiceSpy
|
||||
},
|
||||
{ provide: ActivatedRoute, useValue: activatedRouteMock },
|
||||
{ provide: RequestInProgressService, useValue: requestInProgressServiceSpy }
|
||||
]
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(WorkbasketDistributionTargetsListComponent);
|
||||
|
@ -59,6 +104,13 @@ describe('WorkbasketDistributionTargetsListComponent', () => {
|
|||
component = fixture.componentInstance;
|
||||
component.distributionTargets = workbasketReadStateMock.paginatedWorkbasketsSummary.workbaskets;
|
||||
component.side = Side.AVAILABLE;
|
||||
component.transferDistributionTargetObservable = EMPTY;
|
||||
store = TestBed.inject(Store);
|
||||
store.reset({
|
||||
...store.snapshot(),
|
||||
engineConfiguration: engineConfigurationMock,
|
||||
workbasket: workbasketReadStateMock
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -83,13 +135,20 @@ describe('WorkbasketDistributionTargetsListComponent', () => {
|
|||
expect(debugElement.nativeElement.querySelector('taskana-shared-workbasket-filter')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should display all available workbaskets', () => {
|
||||
it('should display all available workbaskets', fakeAsync(() => {
|
||||
// On the first cycle we render the items.
|
||||
fixture.detectChanges();
|
||||
flush();
|
||||
// Flush the initial fake scroll event.
|
||||
animationFrameScheduler.flush();
|
||||
flush();
|
||||
fixture.detectChanges();
|
||||
|
||||
const distributionTargetList = debugElement.nativeElement.getElementsByClassName(
|
||||
'workbasket-distribution-targets__workbaskets-item'
|
||||
);
|
||||
expect(distributionTargetList).toHaveLength(5);
|
||||
});
|
||||
expect(distributionTargetList).toHaveLength(3);
|
||||
}));
|
||||
|
||||
it('should call orderBy pipe', () => {
|
||||
const orderBySpy = jest.spyOn(OrderByMock.prototype, 'transform');
|
||||
|
|
|
@ -1,18 +1,32 @@
|
|||
import {
|
||||
AfterContentChecked,
|
||||
AfterViewInit,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
Input,
|
||||
AfterContentChecked,
|
||||
ChangeDetectorRef,
|
||||
ViewChild,
|
||||
Output,
|
||||
EventEmitter,
|
||||
OnChanges,
|
||||
SimpleChanges
|
||||
OnInit,
|
||||
SimpleChanges,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { isEqual } from 'lodash';
|
||||
import { WorkbasketSummary } from 'app/shared/models/workbasket-summary';
|
||||
import { expandDown } from 'app/shared/animations/expand.animation';
|
||||
import { AllSelected, Side } from '../workbasket-distribution-targets/workbasket-distribution-targets.component';
|
||||
import { MatSelectionList } from '@angular/material/list';
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { Side } from '../../models/workbasket-distribution-enums';
|
||||
import { Select, Store } from '@ngxs/store';
|
||||
import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors';
|
||||
import { filter, map, pairwise, take, takeUntil, throttleTime } from 'rxjs/operators';
|
||||
import {
|
||||
FetchAvailableDistributionTargets,
|
||||
FetchWorkbasketDistributionTargets,
|
||||
TransferDistributionTargets
|
||||
} from '../../../shared/store/workbasket-store/workbasket.actions';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { WorkbasketQueryFilterParameter } from '../../../shared/models/workbasket-query-filter-parameter';
|
||||
import { FilterSelectors } from '../../../shared/store/filter-store/filter.selectors';
|
||||
import { WorkbasketDistributionTarget } from '../../../shared/models/workbasket-distribution-target';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-administration-workbasket-distribution-targets-list',
|
||||
|
@ -20,19 +34,68 @@ import { MatSelectionList } from '@angular/material/list';
|
|||
styleUrls: ['./workbasket-distribution-targets-list.component.scss'],
|
||||
animations: [expandDown]
|
||||
})
|
||||
export class WorkbasketDistributionTargetsListComponent implements AfterContentChecked, OnChanges {
|
||||
@Input() distributionTargets: WorkbasketSummary[];
|
||||
export class WorkbasketDistributionTargetsListComponent
|
||||
implements AfterContentChecked, OnChanges, OnInit, AfterViewInit
|
||||
{
|
||||
@Input() side: Side;
|
||||
@Input() header: string;
|
||||
@Input() allSelected;
|
||||
allSelected;
|
||||
@Input() component;
|
||||
@Input() transferDistributionTargetObservable: Observable<Side>;
|
||||
|
||||
@Output() allSelectedEmitter = new EventEmitter<AllSelected>();
|
||||
@Select(WorkbasketSelectors.workbasketDistributionTargets)
|
||||
workbasketDistributionTargets$: Observable<WorkbasketSummary[]>;
|
||||
|
||||
@Select(WorkbasketSelectors.availableDistributionTargets)
|
||||
availableDistributionTargets$: Observable<WorkbasketSummary[]>;
|
||||
|
||||
@Select(FilterSelectors.getAvailableDistributionTargetsFilter)
|
||||
availableDistributionTargetsFilter$: Observable<WorkbasketQueryFilterParameter>;
|
||||
|
||||
@Select(FilterSelectors.getSelectedDistributionTargetsFilter)
|
||||
selectedDistributionTargetsFilter$: Observable<WorkbasketQueryFilterParameter>;
|
||||
|
||||
toolbarState = false;
|
||||
@ViewChild('workbasket') distributionTargetsList: MatSelectionList;
|
||||
|
||||
constructor(private changeDetector: ChangeDetectorRef) {}
|
||||
distributionTargets: WorkbasketDistributionTarget[];
|
||||
|
||||
@ViewChild('workbasket') distributionTargetsList: MatSelectionList;
|
||||
@ViewChild('scroller') workbasketList: CdkVirtualScrollViewport;
|
||||
private destroy$ = new Subject<void>();
|
||||
private filter: WorkbasketQueryFilterParameter;
|
||||
private allSelectedDiff = 0;
|
||||
|
||||
constructor(private changeDetector: ChangeDetectorRef, private store: Store) {}
|
||||
|
||||
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.availableDistributionTargetsFilter$.pipe(takeUntil(this.destroy$)).subscribe((filter) => {
|
||||
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.selectedDistributionTargetsFilter$.pipe(takeUntil(this.destroy$)).subscribe((filter) => {
|
||||
if (isEqual(this.filter, filter)) return;
|
||||
this.filter = filter;
|
||||
this.store.dispatch(new FetchWorkbasketDistributionTargets(true, this.filter));
|
||||
this.selectAll(false);
|
||||
});
|
||||
}
|
||||
this.transferDistributionTargetObservable.subscribe((targetSide) => {
|
||||
if (targetSide !== this.side) this.transferDistributionTargets(targetSide);
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterContentChecked(): void {
|
||||
this.changeDetector.detectChanges();
|
||||
|
@ -44,17 +107,63 @@ export class WorkbasketDistributionTargetsListComponent implements AfterContentC
|
|||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.workbasketList
|
||||
.elementScrolled()
|
||||
.pipe(
|
||||
map(() => this.workbasketList.measureScrollOffset('bottom')),
|
||||
pairwise(),
|
||||
filter(([y1, y2]) => y2 < y1 && y2 < 270),
|
||||
throttleTime(200)
|
||||
)
|
||||
.subscribe(() => {
|
||||
if (this.side === Side.AVAILABLE) {
|
||||
this.store.dispatch(new FetchAvailableDistributionTargets(false, this.filter));
|
||||
} else {
|
||||
this.store.dispatch(new FetchWorkbasketDistributionTargets(false, this.filter));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
selectAll(selected: boolean) {
|
||||
if (typeof this.distributionTargetsList !== 'undefined') {
|
||||
this.allSelected = selected;
|
||||
this.distributionTargetsList.options.map((item) => (item['selected'] = selected));
|
||||
this.distributionTargets.map((item) => (item['selected'] = selected));
|
||||
|
||||
this.allSelectedEmitter.emit({ value: this.allSelected, side: this.side });
|
||||
this.distributionTargets.map((wb) => (wb.selected = selected));
|
||||
if (selected) this.allSelectedDiff = this.distributionTargets.length;
|
||||
else this.allSelectedDiff = 0;
|
||||
}
|
||||
}
|
||||
|
||||
transferDistributionTargets(targetSide: Side) {
|
||||
let selectedWBs = this.distributionTargets.filter((item: any) => item.selected === true);
|
||||
this.distributionTargets.forEach((wb) => (wb.selected = false));
|
||||
this.store
|
||||
.dispatch(new TransferDistributionTargets(targetSide, selectedWBs))
|
||||
.pipe(take(1))
|
||||
.subscribe(() => {
|
||||
if (this.distributionTargets.length === 0) {
|
||||
const desiredAction =
|
||||
targetSide === Side.SELECTED
|
||||
? new FetchAvailableDistributionTargets(false, this.filter)
|
||||
: new FetchWorkbasketDistributionTargets(false, this.filter);
|
||||
this.store.dispatch(desiredAction);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
changeToolbarState(state: boolean) {
|
||||
this.toolbarState = state;
|
||||
}
|
||||
|
||||
updateSelectAll(selected: boolean) {
|
||||
if (selected) this.allSelectedDiff++;
|
||||
else this.allSelectedDiff--;
|
||||
this.allSelected = this.allSelectedDiff === this.distributionTargets.length;
|
||||
return true;
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div *ngIf="workbasket" id="wb-information" class="workbasket-distribution-targets">
|
||||
<div id="wb-information" class="workbasket-distribution-targets">
|
||||
<mat-toolbar class="distribution-targets-list__action-toolbar" >
|
||||
<button mat-flat-button class="distribution-targets-list__action-button distribution-targets-list__toggle-view-button"
|
||||
*ngIf="!sideBySide" (click)="toggleSideBySideView()">
|
||||
|
@ -18,7 +18,7 @@
|
|||
style="justify-content: flex-end; margin-right: 2%">
|
||||
<button mat-flat-button color="accent"
|
||||
class="distribution-targets-list__action-button distribution-targets-list-dialog__add-button"
|
||||
(click)="moveDistributionTargets(side.AVAILABLE)">
|
||||
(click)="moveDistributionTargets(sideEnum.SELECTED)">
|
||||
Add selected distribution targets
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
|
@ -30,7 +30,7 @@
|
|||
style="justify-content: flex-end;">
|
||||
<button mat-flat-button color="warn"
|
||||
class="distribution-targets-list__action-button distribution-targets-list-dialog__remove-button"
|
||||
(click)="moveDistributionTargets(side.SELECTED)">
|
||||
(click)="moveDistributionTargets(sideEnum.AVAILABLE)">
|
||||
Remove selected distribution target
|
||||
<mat-icon>remove</mat-icon>
|
||||
</button>
|
||||
|
@ -43,7 +43,7 @@
|
|||
*ngIf="!displayingDistributionTargetsPicker && !sideBySide">
|
||||
<button mat-flat-button color="warn"
|
||||
class="distribution-targets-list__action-button distribution-targets-list-dialog__remove-button"
|
||||
(click)="moveDistributionTargets(side.SELECTED)">
|
||||
(click)="moveDistributionTargets(sideEnum.AVAILABLE)">
|
||||
Remove selected distribution target
|
||||
<mat-icon>remove</mat-icon>
|
||||
</button>
|
||||
|
@ -63,7 +63,7 @@
|
|||
*ngIf="displayingDistributionTargetsPicker && !sideBySide">
|
||||
<button mat-flat-button color="accent"
|
||||
class="distribution-targets-list__action-button distribution-targets-list-dialog__add-button"
|
||||
(click)="moveDistributionTargets(side.AVAILABLE)">
|
||||
(click)="moveDistributionTargets(sideEnum.SELECTED)">
|
||||
Add selected distribution targets
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
|
@ -86,23 +86,19 @@
|
|||
<taskana-administration-workbasket-distribution-targets-list
|
||||
[ngClass]="sideBySide ? 'distribution-targets-list__lists--left-side' : ''"
|
||||
header="Available distribution targets"
|
||||
[distributionTargets]="availableDistributionTargets"
|
||||
[side]="side.AVAILABLE"
|
||||
[allSelected]="selectAllLeft"
|
||||
[side]="sideEnum.AVAILABLE"
|
||||
*ngIf="displayingDistributionTargetsPicker"
|
||||
[component]="'availableDistributionTargets'"
|
||||
(allSelectedEmitter)="setAllSelected($event)"
|
||||
[transferDistributionTargetObservable]="transferDistributionTargetObservable"
|
||||
>
|
||||
</taskana-administration-workbasket-distribution-targets-list>
|
||||
|
||||
<taskana-administration-workbasket-distribution-targets-list
|
||||
header="Selected distribution targets"
|
||||
[distributionTargets]="selectedDistributionTargets"
|
||||
[side]="side.SELECTED"
|
||||
[allSelected]="selectAllRight"
|
||||
[side]="sideEnum.SELECTED"
|
||||
[hidden]="displayingDistributionTargetsPicker && !sideBySide"
|
||||
[component]="'selectedDistributionTargets'"
|
||||
(allSelectedEmitter)="setAllSelected($event)"
|
||||
[transferDistributionTargetObservable]="transferDistributionTargetObservable"
|
||||
>
|
||||
</taskana-administration-workbasket-distribution-targets-list>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { Component, DebugElement, Input } from '@angular/core';
|
||||
import { Side, WorkbasketDistributionTargetsComponent } from './workbasket-distribution-targets.component';
|
||||
import { WorkbasketDistributionTargetsComponent } from './workbasket-distribution-targets.component';
|
||||
import { WorkbasketSummary } from '../../../shared/models/workbasket-summary';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
|
@ -13,12 +13,9 @@ import { WorkbasketState } from '../../../shared/store/workbasket-store/workbask
|
|||
import { ActivatedRoute } from '@angular/router';
|
||||
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import {
|
||||
engineConfigurationMock,
|
||||
selectedWorkbasketMock,
|
||||
workbasketReadStateMock
|
||||
} from '../../../shared/store/mock-data/mock-store';
|
||||
import { engineConfigurationMock, workbasketReadStateMock } from '../../../shared/store/mock-data/mock-store';
|
||||
import { DomainService } from '../../../shared/services/domain/domain.service';
|
||||
import { Side } from '../../models/workbasket-distribution-enums';
|
||||
|
||||
const routeParamsMock = { id: 'workbasket' };
|
||||
const activatedRouteMock = {
|
||||
|
@ -26,6 +23,7 @@ const activatedRouteMock = {
|
|||
params: of(routeParamsMock)
|
||||
}
|
||||
};
|
||||
|
||||
@Component({ selector: 'taskana-administration-workbasket-distribution-targets-list', template: '' })
|
||||
class WorkbasketDistributionTargetsListStub {
|
||||
@Input() distributionTargets: WorkbasketSummary[];
|
||||
|
@ -36,21 +34,21 @@ class WorkbasketDistributionTargetsListStub {
|
|||
}
|
||||
|
||||
const domainServiceSpy: Partial<DomainService> = {
|
||||
getSelectedDomainValue: jest.fn().mockReturnValue(of()),
|
||||
getSelectedDomainValue: jest.fn().mockReturnValue(of(null)),
|
||||
getSelectedDomain: jest.fn().mockReturnValue(of('A')),
|
||||
getDomains: jest.fn().mockReturnValue(of())
|
||||
getDomains: jest.fn().mockReturnValue(of(null))
|
||||
};
|
||||
|
||||
const workbasketServiceSpy: Partial<WorkbasketService> = {
|
||||
getWorkBasketsSummary: jest.fn().mockReturnValue(of()),
|
||||
getWorkBasketsDistributionTargets: jest.fn().mockReturnValue(of())
|
||||
getWorkBasketsSummary: jest.fn().mockReturnValue(of(null)),
|
||||
getWorkBasketsDistributionTargets: jest.fn().mockReturnValue(of(null))
|
||||
};
|
||||
|
||||
const notificationsServiceSpy: Partial<NotificationService> = {
|
||||
showSuccess: jest.fn().mockReturnValue(true)
|
||||
};
|
||||
const requestInProgressServiceSpy: Partial<RequestInProgressService> = {
|
||||
setRequestInProgress: jest.fn().mockReturnValue(of())
|
||||
setRequestInProgress: jest.fn().mockReturnValue(of(null))
|
||||
};
|
||||
|
||||
describe('WorkbasketDistributionTargetsComponent', () => {
|
||||
|
@ -60,38 +58,39 @@ describe('WorkbasketDistributionTargetsComponent', () => {
|
|||
let store: Store;
|
||||
let actions$: Observable<any>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
MatIconModule,
|
||||
MatDialogModule,
|
||||
MatToolbarModule,
|
||||
MatButtonModule,
|
||||
NgxsModule.forRoot([WorkbasketState])
|
||||
],
|
||||
declarations: [WorkbasketDistributionTargetsComponent, WorkbasketDistributionTargetsListStub],
|
||||
providers: [
|
||||
{ provide: WorkbasketService, useValue: workbasketServiceSpy },
|
||||
{ provide: NotificationService, useValue: notificationsServiceSpy },
|
||||
{ provide: ActivatedRoute, useValue: activatedRouteMock },
|
||||
{ provide: RequestInProgressService, useValue: requestInProgressServiceSpy },
|
||||
{ provide: DomainService, useValue: domainServiceSpy }
|
||||
]
|
||||
}).compileComponents();
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
MatIconModule,
|
||||
MatDialogModule,
|
||||
MatToolbarModule,
|
||||
MatButtonModule,
|
||||
NgxsModule.forRoot([WorkbasketState])
|
||||
],
|
||||
declarations: [WorkbasketDistributionTargetsComponent, WorkbasketDistributionTargetsListStub],
|
||||
providers: [
|
||||
{ provide: WorkbasketService, useValue: workbasketServiceSpy },
|
||||
{ provide: NotificationService, useValue: notificationsServiceSpy },
|
||||
{ provide: ActivatedRoute, useValue: activatedRouteMock },
|
||||
{ provide: RequestInProgressService, useValue: requestInProgressServiceSpy },
|
||||
{ provide: DomainService, useValue: domainServiceSpy }
|
||||
]
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(WorkbasketDistributionTargetsComponent);
|
||||
debugElement = fixture.debugElement;
|
||||
component = fixture.componentInstance;
|
||||
store = TestBed.inject(Store);
|
||||
actions$ = TestBed.inject(Actions);
|
||||
store.reset({
|
||||
...store.snapshot(),
|
||||
engineConfiguration: engineConfigurationMock,
|
||||
workbasket: workbasketReadStateMock
|
||||
});
|
||||
component.workbasket = selectedWorkbasketMock;
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
fixture = TestBed.createComponent(WorkbasketDistributionTargetsComponent);
|
||||
debugElement = fixture.debugElement;
|
||||
component = fixture.componentInstance;
|
||||
store = TestBed.inject(Store);
|
||||
actions$ = TestBed.inject(Actions);
|
||||
store.reset({
|
||||
...store.snapshot(),
|
||||
engineConfiguration: engineConfigurationMock,
|
||||
workbasket: workbasketReadStateMock
|
||||
});
|
||||
fixture.detectChanges();
|
||||
})
|
||||
);
|
||||
|
||||
it('should create component', () => {
|
||||
expect(component).toBeTruthy();
|
||||
|
@ -110,72 +109,4 @@ describe('WorkbasketDistributionTargetsComponent', () => {
|
|||
expect(component.sideBySide).toBe(false);
|
||||
expect(debugElement.nativeElement.querySelector('.distribution-targets-list__lists--side')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should get available and selected distribution targets', () => {
|
||||
// mock-data has 8 entries, array should be filtered by selected distribution targets
|
||||
expect(component.availableDistributionTargets).toHaveLength(5);
|
||||
expect(component.availableDistributionTargetsUndoClone).toHaveLength(5);
|
||||
expect(component.availableDistributionTargetsFilterClone).toHaveLength(5);
|
||||
|
||||
// mock-data has 3 entries
|
||||
expect(component.selectedDistributionTargets).toHaveLength(3);
|
||||
expect(component.selectedDistributionTargetsUndoClone).toHaveLength(3);
|
||||
expect(component.selectedDistributionTargetsFilterClone).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('should move distribution targets to selected list', () => {
|
||||
component.availableDistributionTargets[0]['selected'] = true; // select first item in available array
|
||||
const removeSelectedItems = jest.spyOn(component, 'removeSelectedItems');
|
||||
component.moveDistributionTargets(Side.AVAILABLE);
|
||||
|
||||
expect(component.selectedDistributionTargets).toHaveLength(4); // mock-data only has 3
|
||||
expect(component.selectedDistributionTargetsFilterClone).toHaveLength(4);
|
||||
expect(removeSelectedItems).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should move distribution targets to available list', () => {
|
||||
component.selectedDistributionTargets[0]['selected'] = true; // select first item in available array
|
||||
const removeSelectedItems = jest.spyOn(component, 'removeSelectedItems');
|
||||
component.moveDistributionTargets(Side.SELECTED);
|
||||
|
||||
expect(component.availableDistributionTargets).toHaveLength(6); // mock-data has 5
|
||||
expect(component.availableDistributionTargetsFilterClone).toHaveLength(6);
|
||||
expect(removeSelectedItems).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set selectAll checkboxes to false when moving a workbasket', () => {
|
||||
component.selectAllRight = true;
|
||||
component.moveDistributionTargets(Side.SELECTED);
|
||||
expect(component.selectAllRight).toBeFalsy();
|
||||
|
||||
component.selectAllLeft = true;
|
||||
component.moveDistributionTargets(Side.AVAILABLE);
|
||||
expect(component.selectAllLeft).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should call unselectItems() when moving a workbasket', () => {
|
||||
const unselectItems = jest.spyOn(component, 'unselectItems');
|
||||
|
||||
[Side.SELECTED, Side.AVAILABLE].forEach((side) => {
|
||||
component.moveDistributionTargets(side);
|
||||
expect(unselectItems).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should reset distribution targets to last state when undo is called', () => {
|
||||
component.availableDistributionTargets[0]['selected'] = true; // select first item in available array
|
||||
|
||||
component.moveDistributionTargets(Side.AVAILABLE);
|
||||
expect(component.selectedDistributionTargets).toHaveLength(4); // mock-data only has 3
|
||||
|
||||
component.onClear();
|
||||
expect(component.selectedDistributionTargets).toHaveLength(3);
|
||||
expect(component.selectedDistributionTargetsFilterClone).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('should call performFilter when filter value from store is obtained', () => {
|
||||
const performFilter = jest.spyOn(component, 'performFilter');
|
||||
component.ngOnInit();
|
||||
expect(performFilter).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,37 +1,22 @@
|
|||
import { Component, Input, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { forkJoin, Observable, Subject } from 'rxjs';
|
||||
|
||||
import { Workbasket } from 'app/shared/models/workbasket';
|
||||
import { WorkbasketSummary } from 'app/shared/models/workbasket-summary';
|
||||
import { WorkbasketSummaryRepresentation } from 'app/shared/models/workbasket-summary-representation';
|
||||
import { WorkbasketDistributionTargets } from 'app/shared/models/workbasket-distribution-targets';
|
||||
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
|
||||
import { Actions, ofActionCompleted, Select, Store } from '@ngxs/store';
|
||||
import { filter, take, takeUntil } from 'rxjs/operators';
|
||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||
import {
|
||||
GetAvailableDistributionTargets,
|
||||
GetWorkbasketDistributionTargets,
|
||||
FetchAvailableDistributionTargets,
|
||||
FetchWorkbasketDistributionTargets,
|
||||
SaveNewWorkbasket,
|
||||
UpdateWorkbasket,
|
||||
UpdateWorkbasketDistributionTargets
|
||||
} from '../../../shared/store/workbasket-store/workbasket.actions';
|
||||
import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors';
|
||||
import { ButtonAction } from '../../models/button-action';
|
||||
import { Pair } from '../../../shared/models/pair';
|
||||
import { WorkbasketQueryFilterParameter } from '../../../shared/models/workbasket-query-filter-parameter';
|
||||
import { FilterSelectors } from '../../../shared/store/filter-store/filter.selectors';
|
||||
import { SetWorkbasketFilter } from '../../../shared/store/filter-store/filter.actions';
|
||||
|
||||
export enum Side {
|
||||
AVAILABLE,
|
||||
SELECTED
|
||||
}
|
||||
|
||||
export interface AllSelected {
|
||||
value: boolean;
|
||||
side?: Side;
|
||||
}
|
||||
import { Side } from '../../models/workbasket-distribution-enums';
|
||||
import { ClearWorkbasketFilter } from '../../../shared/store/filter-store/filter.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-administration-workbasket-distribution-targets',
|
||||
|
@ -39,33 +24,11 @@ export interface AllSelected {
|
|||
styleUrls: ['./workbasket-distribution-targets.component.scss']
|
||||
})
|
||||
export class WorkbasketDistributionTargetsComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
workbasket: Workbasket;
|
||||
|
||||
toolbarState = false;
|
||||
sideEnum = Side;
|
||||
sideBySide = true;
|
||||
displayingDistributionTargetsPicker = true;
|
||||
|
||||
side = Side;
|
||||
selectAllRight = false;
|
||||
selectAllLeft = false;
|
||||
|
||||
availableDistributionTargets: WorkbasketSummary[] = [];
|
||||
availableDistributionTargetsUndoClone: WorkbasketSummary[];
|
||||
availableDistributionTargetsFilterClone: WorkbasketSummary[] = [];
|
||||
availableDistributionTargetsFilter: WorkbasketQueryFilterParameter;
|
||||
|
||||
selectedDistributionTargets: WorkbasketSummary[];
|
||||
selectedDistributionTargetsUndoClone: WorkbasketSummary[];
|
||||
selectedDistributionTargetsFilterClone: WorkbasketSummary[] = [];
|
||||
selectedDistributionTargetsResource: WorkbasketDistributionTargets;
|
||||
selectedDistributionTargetsFilter: WorkbasketQueryFilterParameter;
|
||||
|
||||
@Select(WorkbasketSelectors.workbasketDistributionTargets)
|
||||
workbasketDistributionTargets$: Observable<WorkbasketDistributionTargets>;
|
||||
|
||||
@Select(WorkbasketSelectors.availableDistributionTargets)
|
||||
availableDistributionTargets$: Observable<WorkbasketSummary[]>;
|
||||
transferDistributionTargetObservable = new Subject<Side>();
|
||||
|
||||
@Select(WorkbasketSelectors.buttonAction)
|
||||
buttonAction$: Observable<ButtonAction>;
|
||||
|
@ -73,61 +36,16 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnDestroy
|
|||
@Select(WorkbasketSelectors.selectedWorkbasket)
|
||||
selectedWorkbasket$: Observable<Workbasket>;
|
||||
|
||||
@Select(FilterSelectors.getAvailableDistributionTargetsFilter)
|
||||
availableDistributionTargetsFilter$: Observable<WorkbasketQueryFilterParameter>;
|
||||
|
||||
@Select(FilterSelectors.getSelectedDistributionTargetsFilter)
|
||||
selectedDistributionTargetsFilter$: Observable<WorkbasketQueryFilterParameter>;
|
||||
|
||||
destroy$ = new Subject<void>();
|
||||
private selectedWorkbasket: WorkbasketSummary;
|
||||
|
||||
constructor(
|
||||
private workbasketService: WorkbasketService,
|
||||
private notificationsService: NotificationService,
|
||||
private store: Store,
|
||||
private ngxsActions$: Actions
|
||||
) {}
|
||||
constructor(private notificationsService: NotificationService, private store: Store, private ngxsActions$: Actions) {}
|
||||
|
||||
/**
|
||||
* Rework with modification based on old components,
|
||||
* would be ideal to completely redo whole components using drag and drop angular components and clearer logics
|
||||
*/
|
||||
ngOnInit() {
|
||||
if (this.workbasket?.workbasketId) {
|
||||
this.store.dispatch(new GetWorkbasketDistributionTargets(this.workbasket._links.distributionTargets.href));
|
||||
this.store.dispatch(new GetAvailableDistributionTargets());
|
||||
}
|
||||
|
||||
this.workbasketDistributionTargets$.pipe(takeUntil(this.destroy$)).subscribe((workbasketDistributionTargets) => {
|
||||
if (typeof workbasketDistributionTargets !== 'undefined') {
|
||||
this.selectedDistributionTargetsResource = { ...workbasketDistributionTargets };
|
||||
|
||||
this.selectedDistributionTargets = [];
|
||||
workbasketDistributionTargets.distributionTargets.forEach((distributionTarget) => {
|
||||
const target = {};
|
||||
Object.keys(distributionTarget).forEach((key) => {
|
||||
target[key] = distributionTarget[key];
|
||||
});
|
||||
this.selectedDistributionTargets.push(target);
|
||||
});
|
||||
|
||||
this.selectedDistributionTargetsFilterClone = [...this.selectedDistributionTargets];
|
||||
this.selectedDistributionTargetsUndoClone = [...this.selectedDistributionTargets];
|
||||
|
||||
this.getAvailableDistributionTargets();
|
||||
}
|
||||
});
|
||||
|
||||
this.availableDistributionTargetsFilter$.pipe(takeUntil(this.destroy$)).subscribe((filter) => {
|
||||
this.availableDistributionTargetsFilter = filter;
|
||||
this.performFilter({ left: 0, right: filter });
|
||||
});
|
||||
|
||||
this.selectedDistributionTargetsFilter$.pipe(takeUntil(this.destroy$)).subscribe((filter) => {
|
||||
this.selectedDistributionTargetsFilter = filter;
|
||||
this.performFilter({ left: 1, right: filter });
|
||||
});
|
||||
|
||||
// saving workbasket distributions targets when existing workbasket was modified
|
||||
this.ngxsActions$.pipe(ofActionCompleted(UpdateWorkbasket), takeUntil(this.destroy$)).subscribe(() => {
|
||||
this.onSave();
|
||||
|
@ -135,14 +53,21 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnDestroy
|
|||
|
||||
// saving workbasket distributions targets when workbasket was copied or created
|
||||
this.ngxsActions$.pipe(ofActionCompleted(SaveNewWorkbasket), takeUntil(this.destroy$)).subscribe(() => {
|
||||
this.selectedWorkbasket$.pipe(take(1)).subscribe((workbasket) => {
|
||||
this.selectedDistributionTargetsResource._links = {
|
||||
self: { href: workbasket._links.distributionTargets.href }
|
||||
};
|
||||
this.selectedWorkbasket$.pipe(take(1)).subscribe(() => {
|
||||
this.onSave();
|
||||
});
|
||||
});
|
||||
|
||||
this.selectedWorkbasket$.pipe(takeUntil(this.destroy$)).subscribe((wb) => {
|
||||
if (wb !== undefined && wb.workbasketId !== this.selectedWorkbasket?.workbasketId) {
|
||||
if (this.selectedWorkbasket?.workbasketId) {
|
||||
this.store.dispatch(new FetchWorkbasketDistributionTargets(true));
|
||||
this.store.dispatch(new FetchAvailableDistributionTargets(true));
|
||||
}
|
||||
this.selectedWorkbasket = wb;
|
||||
}
|
||||
});
|
||||
|
||||
this.buttonAction$
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.pipe(filter((buttonAction) => typeof buttonAction !== 'undefined'))
|
||||
|
@ -157,173 +82,27 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnDestroy
|
|||
});
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes.workbasket.currentValue !== changes.workbasket.previousValue) {
|
||||
this.setAllSelected({ value: false });
|
||||
this.getAvailableDistributionTargets();
|
||||
}
|
||||
}
|
||||
|
||||
setAllSelected(allSelected: AllSelected) {
|
||||
const side = allSelected.side;
|
||||
const value = allSelected.value;
|
||||
this.selectAllLeft = side === Side.AVAILABLE || typeof side === 'undefined' ? value : this.selectAllLeft;
|
||||
this.selectAllRight = side === Side.SELECTED || typeof side === 'undefined' ? value : this.selectAllRight;
|
||||
}
|
||||
|
||||
filterWorkbasketsByWorkbasketIDs(workbaskets: WorkbasketSummary[], IDs: WorkbasketSummary[]): WorkbasketSummary[] {
|
||||
const workbasketIds: string[] = IDs.map((workbasket) => workbasket.workbasketId);
|
||||
return workbaskets.filter((workbasket) => !workbasketIds.includes(workbasket.workbasketId));
|
||||
}
|
||||
|
||||
getAvailableDistributionTargets() {
|
||||
this.availableDistributionTargets$
|
||||
.pipe(
|
||||
take(1),
|
||||
filter((availableDistributionTargets) => typeof availableDistributionTargets !== 'undefined')
|
||||
)
|
||||
.subscribe((availableDistributionTargets) => {
|
||||
this.availableDistributionTargets = availableDistributionTargets.map((wb) => ({ ...wb }));
|
||||
|
||||
if (this.selectedDistributionTargets && this.selectedDistributionTargets.length !== 0) {
|
||||
this.availableDistributionTargets = this.filterWorkbasketsByWorkbasketIDs(
|
||||
this.availableDistributionTargets,
|
||||
this.selectedDistributionTargets
|
||||
);
|
||||
}
|
||||
|
||||
this.availableDistributionTargetsUndoClone = [...this.availableDistributionTargets];
|
||||
this.availableDistributionTargetsFilterClone = [...this.availableDistributionTargets];
|
||||
});
|
||||
}
|
||||
|
||||
changeToolbarState(state: boolean) {
|
||||
this.toolbarState = state;
|
||||
}
|
||||
|
||||
toggleDistributionTargetsPicker() {
|
||||
this.displayingDistributionTargetsPicker = !this.displayingDistributionTargetsPicker;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// an own filter would save a lot of work here because the workbasketService filter
|
||||
// returns all available distribution targets and must be filtered again
|
||||
performFilter({ left: side, right: filter }: Pair<Side, WorkbasketQueryFilterParameter>) {
|
||||
this.workbasketService
|
||||
.getWorkBasketsSummary(true, filter)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((distributionTargetsAvailable: WorkbasketSummaryRepresentation) => {
|
||||
const isFilterEmpty =
|
||||
filter['name-like'].length === 0 &&
|
||||
filter['key-like'].length === 0 &&
|
||||
filter['description-like'].length === 0 &&
|
||||
filter['owner-like'].length === 0 &&
|
||||
filter['type'].length === 0;
|
||||
|
||||
// filter available side
|
||||
if (side === Side.AVAILABLE) {
|
||||
if (isFilterEmpty) {
|
||||
this.availableDistributionTargets = this.availableDistributionTargetsFilterClone;
|
||||
} else {
|
||||
this.availableDistributionTargets = this.filterWorkbasketsByWorkbasketIDs(
|
||||
distributionTargetsAvailable.workbaskets,
|
||||
this.selectedDistributionTargetsFilterClone
|
||||
);
|
||||
}
|
||||
}
|
||||
// filter selected side
|
||||
else if (side === Side.SELECTED) {
|
||||
if (isFilterEmpty) {
|
||||
this.selectedDistributionTargets = this.selectedDistributionTargetsFilterClone;
|
||||
} else {
|
||||
const ids = distributionTargetsAvailable.workbaskets.map((workbasket) => workbasket.workbasketId);
|
||||
this.selectedDistributionTargets = this.selectedDistributionTargetsFilterClone.filter((workbasket) =>
|
||||
ids.includes(workbasket.workbasketId)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
onSave(): void {
|
||||
this.store.dispatch(new UpdateWorkbasketDistributionTargets());
|
||||
}
|
||||
|
||||
onSave() {
|
||||
this.store.dispatch(
|
||||
new UpdateWorkbasketDistributionTargets(
|
||||
this.selectedDistributionTargetsResource._links.self.href,
|
||||
this.getSelectedIds()
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
moveDistributionTargets(side: number) {
|
||||
// get all workbaskets without applied filter and without overwriting the selected property
|
||||
this.selectedDistributionTargets = this.selectedDistributionTargets.concat(
|
||||
this.filterWorkbasketsByWorkbasketIDs(
|
||||
this.selectedDistributionTargetsFilterClone,
|
||||
this.selectedDistributionTargets
|
||||
)
|
||||
);
|
||||
this.availableDistributionTargets = this.availableDistributionTargets.concat(
|
||||
this.filterWorkbasketsByWorkbasketIDs(
|
||||
this.availableDistributionTargetsFilterClone,
|
||||
this.availableDistributionTargets
|
||||
)
|
||||
);
|
||||
|
||||
if (side === Side.AVAILABLE) {
|
||||
// moving available items to selected side
|
||||
const itemsSelected = this.getSelectedItems(this.availableDistributionTargets);
|
||||
this.selectedDistributionTargets = this.selectedDistributionTargets.concat(itemsSelected);
|
||||
this.availableDistributionTargets = this.removeSelectedItems(this.availableDistributionTargets, itemsSelected);
|
||||
this.unselectItems(itemsSelected);
|
||||
} else {
|
||||
// moving selected items to available side
|
||||
const itemsSelected = this.getSelectedItems(this.selectedDistributionTargets);
|
||||
this.selectedDistributionTargets = this.removeSelectedItems(this.selectedDistributionTargets, itemsSelected);
|
||||
this.availableDistributionTargets = this.availableDistributionTargets.concat(itemsSelected);
|
||||
this.unselectItems(itemsSelected);
|
||||
}
|
||||
this.setAllSelected({ value: false, side: side });
|
||||
this.selectedDistributionTargetsFilterClone = this.selectedDistributionTargets;
|
||||
this.availableDistributionTargetsFilterClone = this.availableDistributionTargets;
|
||||
this.store.dispatch(new SetWorkbasketFilter(this.selectedDistributionTargetsFilter, 'selectedDistributionTargets'));
|
||||
this.store.dispatch(
|
||||
new SetWorkbasketFilter(this.availableDistributionTargetsFilter, 'availableDistributionTargets')
|
||||
);
|
||||
moveDistributionTargets(targetSide: Side): void {
|
||||
this.transferDistributionTargetObservable.next(targetSide);
|
||||
}
|
||||
|
||||
onClear() {
|
||||
this.notificationsService.showSuccess('WORKBASKET_DISTRIBUTION_TARGET_RESTORE');
|
||||
this.availableDistributionTargets = Object.assign([], this.availableDistributionTargetsUndoClone);
|
||||
this.availableDistributionTargetsFilterClone = Object.assign([], this.availableDistributionTargetsUndoClone);
|
||||
this.selectedDistributionTargets = Object.assign([], this.selectedDistributionTargetsUndoClone);
|
||||
this.selectedDistributionTargetsFilterClone = Object.assign([], this.selectedDistributionTargetsUndoClone);
|
||||
}
|
||||
|
||||
getSelectedItems(originList: any): any[] {
|
||||
return originList.filter((item: any) => item.selected === true);
|
||||
}
|
||||
|
||||
getSelectedIds(): string[] {
|
||||
return this.selectedDistributionTargetsFilterClone.map((distributionTarget) => distributionTarget.workbasketId);
|
||||
}
|
||||
|
||||
unselectItems(originList: any[]): any[] {
|
||||
return originList
|
||||
.filter((item) => item.selected)
|
||||
.map((item) => {
|
||||
item.selected = false;
|
||||
});
|
||||
}
|
||||
|
||||
removeSelectedItems(originList, selectedItemList) {
|
||||
const copyList = [...originList];
|
||||
for (let index = originList.length - 1; index >= 0; index--) {
|
||||
if (selectedItemList.some((itemToRemove) => originList[index].workbasketId === itemToRemove.workbasketId)) {
|
||||
copyList.splice(index, 1);
|
||||
}
|
||||
}
|
||||
return copyList;
|
||||
forkJoin([
|
||||
this.store.dispatch(new FetchWorkbasketDistributionTargets(true)),
|
||||
this.store.dispatch(new FetchAvailableDistributionTargets(true)),
|
||||
this.store.dispatch(new ClearWorkbasketFilter('selectedDistributionTargets')),
|
||||
this.store.dispatch(new ClearWorkbasketFilter('availableDistributionTargets'))
|
||||
])
|
||||
.pipe(take(1))
|
||||
.subscribe(() => this.notificationsService.showSuccess('WORKBASKET_DISTRIBUTION_TARGET_RESTORE'));
|
||||
}
|
||||
|
||||
toggleSideBySideView() {
|
||||
|
@ -332,6 +111,7 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnDestroy
|
|||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.transferDistributionTargetObservable.complete();
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
export enum Side {
|
||||
AVAILABLE,
|
||||
SELECTED
|
||||
}
|
||||
|
||||
export interface AllSelected {
|
||||
value: boolean;
|
||||
side?: Side;
|
||||
}
|
|
@ -29,7 +29,6 @@ export class NavBarComponent implements OnInit {
|
|||
ngOnInit() {
|
||||
this.selectedRouteSubscription = this.selectedRouteService.getSelectedRoute().subscribe((value: string) => {
|
||||
// does not work
|
||||
// console.log('router', value);
|
||||
this.selectedRoute = value;
|
||||
this.setTitle(value);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import { WorkbasketType } from './workbasket-type';
|
||||
import { WorkbasketSummary } from './workbasket-summary';
|
||||
|
||||
export interface WorkbasketDistributionTarget extends WorkbasketSummary {
|
||||
selected?: boolean;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { QueryPagingParameter } from './query-paging-parameter';
|
||||
|
||||
export class WorkbasketQueryPagingParameter implements QueryPagingParameter {
|
||||
public 'page-size' = 40;
|
||||
|
||||
constructor(public page: number) {}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { throwError as observableThrowError, Observable, Subject } from 'rxjs';
|
||||
import { Observable, Subject, throwError as observableThrowError } from 'rxjs';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { environment } from 'environments/environment';
|
||||
|
@ -10,7 +10,7 @@ import { WorkbasketDistributionTargets } from 'app/shared/models/workbasket-dist
|
|||
import { Sorting, WorkbasketQuerySortParameter } from 'app/shared/models/sorting';
|
||||
|
||||
import { DomainService } from 'app/shared/services/domain/domain.service';
|
||||
import { mergeMap, tap, catchError } from 'rxjs/operators';
|
||||
import { catchError, mergeMap, tap } from 'rxjs/operators';
|
||||
import { WorkbasketRepresentation } from '../../models/workbasket-representation';
|
||||
import { WorkbasketQueryFilterParameter } from '../../models/workbasket-query-filter-parameter';
|
||||
import { QueryPagingParameter } from '../../models/query-paging-parameter';
|
||||
|
@ -34,7 +34,7 @@ export class WorkbasketService {
|
|||
filterParameter?: WorkbasketQueryFilterParameter,
|
||||
sortParameter?: Sorting<WorkbasketQuerySortParameter>,
|
||||
pagingParameter?: QueryPagingParameter
|
||||
) {
|
||||
): Observable<WorkbasketSummaryRepresentation> {
|
||||
if (this.workbasketSummaryRef && !forceRequest) {
|
||||
return this.workbasketSummaryRef;
|
||||
}
|
||||
|
@ -105,8 +105,19 @@ export class WorkbasketService {
|
|||
}
|
||||
|
||||
// GET
|
||||
getWorkBasketsDistributionTargets(url: string): Observable<WorkbasketDistributionTargets> {
|
||||
return this.httpClient.get<WorkbasketDistributionTargets>(url);
|
||||
getWorkBasketsDistributionTargets(
|
||||
url: string,
|
||||
filterParameter?: WorkbasketQueryFilterParameter,
|
||||
sortParameter?: Sorting<WorkbasketQuerySortParameter>,
|
||||
pagingParameter?: QueryPagingParameter
|
||||
): Observable<WorkbasketDistributionTargets> {
|
||||
return this.httpClient.get<WorkbasketDistributionTargets>(
|
||||
`${url}/${asUrlQueryString({
|
||||
...filterParameter,
|
||||
...sortParameter,
|
||||
...pagingParameter
|
||||
})}`
|
||||
);
|
||||
}
|
||||
|
||||
// PUT
|
||||
|
|
|
@ -187,6 +187,588 @@ export const workbasketAccessItemsMock: WorkbasketAccessItemsRepresentation = {
|
|||
}
|
||||
};
|
||||
|
||||
export const workbasketAvailableDistributionTargets = {
|
||||
workbaskets: [
|
||||
{
|
||||
workbasketId: 'WBI:000000000000000000000000000000000000',
|
||||
key: 'ADMIN',
|
||||
name: 'Postkorb Admin',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'PERSONAL',
|
||||
description: 'Postkorb Admin',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:000000000000000000000000000000000900',
|
||||
key: 'sort001',
|
||||
name: 'basxet0',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'TOPIC',
|
||||
description: 'Lorem ipsum dolor sit amet.',
|
||||
owner: 'user-1-3',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:000000000000000000000000000000000901',
|
||||
key: 'Sort002',
|
||||
name: 'Basxet1',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'TOPIC',
|
||||
description: 'Lorem ipsum dolor sit amet.',
|
||||
owner: 'user-1-3',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:000000000000000000000000000000000902',
|
||||
key: 'sOrt003',
|
||||
name: 'bAsxet2',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'TOPIC',
|
||||
description: 'Lorem ipsum dolor sit amet.',
|
||||
owner: 'user-1-3',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:000000000000000000000000000000000903',
|
||||
key: 'soRt004',
|
||||
name: 'baSxet3',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'TOPIC',
|
||||
description: 'Lorem ipsum dolor sit amet.',
|
||||
owner: 'user-1-3',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:000000000000000000000000000000000904',
|
||||
key: 'sorT005',
|
||||
name: 'basXet4',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'TOPIC',
|
||||
description: 'Lorem ipsum dolor sit amet.',
|
||||
owner: 'user-1-3',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:000000000000000000000000000000000905',
|
||||
key: 'Sort006',
|
||||
name: 'basxEt5',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'TOPIC',
|
||||
description: 'Lorem ipsum dolor sit amet.',
|
||||
owner: 'user-1-3',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:000000000000000000000000000000000906',
|
||||
key: 'SOrt007',
|
||||
name: 'basxeT6',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'TOPIC',
|
||||
description: 'Lorem ipsum dolor sit amet.',
|
||||
owner: 'user-1-3',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:000000000000000000000000000000000907',
|
||||
key: 'SoRt008',
|
||||
name: 'BAsxet7',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'TOPIC',
|
||||
description: 'Lorem ipsum dolor sit amet.',
|
||||
owner: 'user-1-3',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:000000000000000000000000000000000908',
|
||||
key: 'SorT009',
|
||||
name: 'BaSxet8',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'TOPIC',
|
||||
description: 'Lorem ipsum dolor sit amet.',
|
||||
owner: 'user-1-3',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:000000000000000000000000000000000909',
|
||||
key: 'Sort010',
|
||||
name: 'BasXet9',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'TOPIC',
|
||||
description: 'Lorem ipsum dolor sit amet.',
|
||||
owner: 'user-1-3',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000004',
|
||||
key: 'TEAMLEAD-1',
|
||||
name: 'PPK Teamlead KSC 1',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'PERSONAL',
|
||||
description: 'PPK Teamlead KSC 1',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000005',
|
||||
key: 'TEAMLEAD-2',
|
||||
name: 'PPK Teamlead KSC 2',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'PERSONAL',
|
||||
description: 'PPK Teamlead KSC 2',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000006',
|
||||
key: 'USER-1-1',
|
||||
name: 'PPK User 1 KSC 1',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'PERSONAL',
|
||||
description: 'PPK User 1 KSC 1',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: 'custom4z',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000007',
|
||||
key: 'USER-1-2',
|
||||
name: 'PPK User 2 KSC 1',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'PERSONAL',
|
||||
description: 'PPK User 2 KSC 1',
|
||||
owner: 'user-1-2',
|
||||
custom1: 'custom1',
|
||||
custom2: 'custom2',
|
||||
custom3: 'custom3',
|
||||
custom4: 'custom4',
|
||||
orgLevel1: 'versicherung',
|
||||
orgLevel2: 'abteilung',
|
||||
orgLevel3: 'projekt',
|
||||
orgLevel4: 'team',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000008',
|
||||
key: 'USER-2-1',
|
||||
name: 'PPK User 1 KSC 2',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'PERSONAL',
|
||||
description: 'PPK User 1 KSC 2',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000009',
|
||||
key: 'USER-2-2',
|
||||
name: 'PPK User 2 KSC 2',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'PERSONAL',
|
||||
description: 'PPK User 2 KSC 2',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000010',
|
||||
key: 'TPK_VIP',
|
||||
name: 'Themenpostkorb VIP',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'TOPIC',
|
||||
description: 'Themenpostkorb VIP',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000011',
|
||||
key: 'GPK_B_KSC',
|
||||
name: 'Gruppenpostkorb KSC B',
|
||||
domain: 'DOMAIN_B',
|
||||
type: 'GROUP',
|
||||
description: 'Gruppenpostkorb KSC',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000012',
|
||||
key: 'GPK_B_KSC_1',
|
||||
name: 'Gruppenpostkorb KSC B1',
|
||||
domain: 'DOMAIN_B',
|
||||
type: 'GROUP',
|
||||
description: 'Gruppenpostkorb KSC 1',
|
||||
owner: '',
|
||||
custom1: 'custom1',
|
||||
custom2: 'custom2',
|
||||
custom3: 'custom3',
|
||||
custom4: 'custom4',
|
||||
orgLevel1: 'orgl1',
|
||||
orgLevel2: 'orgl2',
|
||||
orgLevel3: 'orgl3',
|
||||
orgLevel4: 'aorgl4',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000013',
|
||||
key: 'GPK_B_KSC_2',
|
||||
name: 'Gruppenpostkorb KSC B2',
|
||||
domain: 'DOMAIN_B',
|
||||
type: 'GROUP',
|
||||
description: 'Gruppenpostkorb KSC 2',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000014',
|
||||
key: 'USER-B-1',
|
||||
name: 'PPK User 1 KSC 1 Domain B',
|
||||
domain: 'DOMAIN_B',
|
||||
type: 'PERSONAL',
|
||||
description: 'PPK User 1 KSC 1 Domain B',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: 'custom20',
|
||||
custom3: '',
|
||||
custom4: 'custom4',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000015',
|
||||
key: 'USER-B-2',
|
||||
name: 'PPK User 2 KSC 1 Domain B',
|
||||
domain: 'DOMAIN_B',
|
||||
type: 'PERSONAL',
|
||||
description: 'PPK User 1 KSC 1 Domain B',
|
||||
owner: 'user-1-2',
|
||||
custom1: 'ABCABC',
|
||||
custom2: 'cust2',
|
||||
custom3: 'cust3',
|
||||
custom4: 'cust4',
|
||||
orgLevel1: 'orgl1',
|
||||
orgLevel2: 'orgl2',
|
||||
orgLevel3: 'orgl3',
|
||||
orgLevel4: 'orgl4',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000016',
|
||||
key: 'TPK_VIP_2',
|
||||
name: 'Themenpostkorb VIP 2',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'TOPIC',
|
||||
description: 'Themenpostkorb VIP',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000017',
|
||||
key: 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_key_1',
|
||||
name: 'Testpostkorb',
|
||||
domain: 'DOMAIN_TEST',
|
||||
type: 'TOPIC',
|
||||
description: null,
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000018',
|
||||
key: 'das_ist_eine_lange_description_und_ein_langer_owner',
|
||||
name: 'Testpostkorb',
|
||||
domain: 'DOMAIN_TEST',
|
||||
type: 'TOPIC',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consetetur sadipscingsed diam nonumy eirmod tempor invidunt ut labore sed diam nonumy eirmod tempor invidunt ut labore ore magna aliquyam erat, sed diam voluptua. At ves et accusam et justo duo dolores abcdfiskdk ekeke',
|
||||
owner: 'das_ist_eine_sehr_sehr_sehr_sehr_sehr_lange_user_id',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000019',
|
||||
key: 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_key_2',
|
||||
name: 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_Testpostkorbname_ohne_Leerzeichen',
|
||||
domain: 'DOMAIN_TEST',
|
||||
type: 'TOPIC',
|
||||
description: 'langer Key und langer Name ohne Leerzeichen',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000020',
|
||||
key: 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_key_3',
|
||||
name: 'das ist ein sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr langer Testpostkorbname mit Leerzeichen 1',
|
||||
domain: 'DOMAIN_TEST',
|
||||
type: 'TOPIC',
|
||||
description: 'langer Key und langer Name mit Leerzeichen',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000021',
|
||||
key: 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_key_4',
|
||||
name: 'das ist ein sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr langer Testpostkorbname mit Leerzeichen 2',
|
||||
domain: 'DOMAIN_TEST',
|
||||
type: 'TOPIC',
|
||||
description: 'langer Key, langer Name mit Leerzeichen und lange UserId',
|
||||
owner: 'das_ist_eine_sehr_sehr_sehr_sehr_sehr_lange_user_id',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000022',
|
||||
key: 'kurzer_key',
|
||||
name: 'das ist ein sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr langer Testpostkorbname mit Leerzeichen 3',
|
||||
domain: 'DOMAIN_TEST',
|
||||
type: 'TOPIC',
|
||||
description: 'kurzer Key und langer Name mit Leerzeichen',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000023',
|
||||
key: 'langer key, langer name, eine lange description, langer owner',
|
||||
name: 'das ist ein sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr langer Testpostkorbname mit Leerzeichen 4',
|
||||
domain: 'DOMAIN_TEST',
|
||||
type: 'TOPIC',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consetetur sadipscingsed diam nonumy eirmod tempor invidunt ut labore sed diam nonumy eirmod tempor invidunt ut labore ore magna aliquyam erat, sed diam voluptua. At ves et accusam et justo duo dolores abcdfiskdk ekeke',
|
||||
owner: 'das_ist_eine_sehr_sehr_sehr_sehr_sehr_lange_user_id',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
}
|
||||
],
|
||||
page: {
|
||||
size: 40,
|
||||
totalElements: 34,
|
||||
totalPages: 1,
|
||||
number: 1
|
||||
},
|
||||
_links: {
|
||||
self: {
|
||||
href: 'http://localhost:8080/taskana/api/v1/workbaskets/?page=1&page-size=40'
|
||||
},
|
||||
first: {
|
||||
href: 'http://localhost:8080/taskana/api/v1/workbaskets/?page-size=40&page=1'
|
||||
},
|
||||
last: {
|
||||
href: 'http://localhost:8080/taskana/api/v1/workbaskets/?page-size=40&page=1'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const workbasketReadStateMock = {
|
||||
selectedWorkbasket: selectedWorkbasketMock,
|
||||
paginatedWorkbasketsSummary: {
|
||||
|
@ -304,69 +886,6 @@ export const workbasketReadStateMock = {
|
|||
}
|
||||
},
|
||||
action: ACTION.READ,
|
||||
workbasketDistributionTargets: {
|
||||
_links: {
|
||||
self: {
|
||||
href: 'http://localhost:8080/taskana/api/v1/workbaskets/WBI:000000000000000000000000000000000900/distribution-targets'
|
||||
}
|
||||
},
|
||||
distributionTargets: [
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000001',
|
||||
key: 'GPK_KSC',
|
||||
name: 'Gruppenpostkorb KSC',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'GROUP',
|
||||
description: 'Gruppenpostkorb KSC',
|
||||
owner: 'owner0815',
|
||||
custom1: 'ABCQVW',
|
||||
custom2: '',
|
||||
custom3: 'xyz4',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000002',
|
||||
key: 'GPK_KSC_1',
|
||||
name: 'Gruppenpostkorb KSC 1',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'GROUP',
|
||||
description: 'Gruppenpostkorb KSC 1',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000003',
|
||||
key: 'GPK_KSC_2',
|
||||
name: 'Gruppenpostkorb KSC 2',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'GROUP',
|
||||
description: 'Gruppenpostkorb KSC 2',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
}
|
||||
]
|
||||
},
|
||||
workbasketAvailableDistributionTargets: [
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000001',
|
||||
|
@ -513,7 +1032,73 @@ export const workbasketReadStateMock = {
|
|||
markedForDeletion: false
|
||||
}
|
||||
],
|
||||
workbasketAccessItems: workbasketAccessItemsMock
|
||||
workbasketAccessItems: workbasketAccessItemsMock,
|
||||
workbasketDistributionTargets: {
|
||||
_links: {
|
||||
self: {
|
||||
href: 'http://localhost:8080/taskana/api/v1/workbaskets/WBI:000000000000000000000000000000000900/distribution-targets'
|
||||
}
|
||||
},
|
||||
distributionTargets: [
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000001',
|
||||
key: 'GPK_KSC',
|
||||
name: 'Gruppenpostkorb KSC',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'GROUP',
|
||||
description: 'Gruppenpostkorb KSC',
|
||||
owner: 'owner0815',
|
||||
custom1: 'ABCQVW',
|
||||
custom2: '',
|
||||
custom3: 'xyz4',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000002',
|
||||
key: 'GPK_KSC_1',
|
||||
name: 'Gruppenpostkorb KSC 1',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'GROUP',
|
||||
description: 'Gruppenpostkorb KSC 1',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
},
|
||||
{
|
||||
workbasketId: 'WBI:100000000000000000000000000000000003',
|
||||
key: 'GPK_KSC_2',
|
||||
name: 'Gruppenpostkorb KSC 2',
|
||||
domain: 'DOMAIN_A',
|
||||
type: 'GROUP',
|
||||
description: 'Gruppenpostkorb KSC 2',
|
||||
owner: '',
|
||||
custom1: '',
|
||||
custom2: '',
|
||||
custom3: '',
|
||||
custom4: '',
|
||||
orgLevel1: '',
|
||||
orgLevel2: '',
|
||||
orgLevel3: '',
|
||||
orgLevel4: '',
|
||||
markedForDeletion: false
|
||||
}
|
||||
]
|
||||
},
|
||||
distributionTargetsPage: 0,
|
||||
availableDistributionTargets: workbasketAvailableDistributionTargets,
|
||||
availableDistributionTargetsPage: 0
|
||||
};
|
||||
|
||||
export const settingsStateMock = {
|
||||
|
|
|
@ -6,6 +6,8 @@ import { WorkbasketComponent } from '../../../administration/models/workbasket-c
|
|||
import { ButtonAction } from '../../../administration/models/button-action';
|
||||
import { QueryPagingParameter } from '../../models/query-paging-parameter';
|
||||
import { WorkbasketQueryFilterParameter } from '../../models/workbasket-query-filter-parameter';
|
||||
import { WorkbasketSummary } from '../../models/workbasket-summary';
|
||||
import { Side } from '../../../administration/models/workbasket-distribution-enums';
|
||||
|
||||
// Workbasket List
|
||||
export class GetWorkbasketsSummary {
|
||||
|
@ -21,6 +23,7 @@ export class GetWorkbasketsSummary {
|
|||
|
||||
export class SelectWorkbasket {
|
||||
static readonly type = '[Workbasket] Select a workbasket';
|
||||
|
||||
constructor(public workbasketId: string) {}
|
||||
}
|
||||
|
||||
|
@ -34,68 +37,93 @@ export class CreateWorkbasket {
|
|||
|
||||
export class SetActiveAction {
|
||||
static readonly type = '[Workbasket] Specify current action';
|
||||
|
||||
constructor(public action: ACTION) {}
|
||||
}
|
||||
|
||||
//Workbasket Details
|
||||
export class SelectComponent {
|
||||
static readonly type = '[Workbasket] Select component';
|
||||
|
||||
constructor(public component: WorkbasketComponent) {}
|
||||
}
|
||||
|
||||
export class OnButtonPressed {
|
||||
static readonly type = '[Workbasket] Button pressed';
|
||||
|
||||
constructor(public button: ButtonAction) {}
|
||||
}
|
||||
|
||||
// Workbasket Information
|
||||
export class SaveNewWorkbasket {
|
||||
static readonly type = '[Workbasket] Save new workbasket';
|
||||
|
||||
constructor(public workbasket: Workbasket) {}
|
||||
}
|
||||
|
||||
export class CopyWorkbasket {
|
||||
static readonly type = '[Workbasket] Copy selected workbasket';
|
||||
|
||||
constructor(public workbasket: Workbasket) {}
|
||||
}
|
||||
|
||||
export class UpdateWorkbasket {
|
||||
static readonly type = '[Workbasket] Update a workbasket';
|
||||
constructor(public url: string, public workbasket: Workbasket) {}
|
||||
}
|
||||
|
||||
export class RemoveDistributionTarget {
|
||||
static readonly type = '[Workbasket] Remove distribution targets of selected workbasket';
|
||||
constructor(public url: string) {}
|
||||
constructor(public url: string, public workbasket: Workbasket) {}
|
||||
}
|
||||
|
||||
export class MarkWorkbasketForDeletion {
|
||||
static readonly type = '[Workbasket] Mark selected workbasket for deletion';
|
||||
|
||||
constructor(public url: string) {}
|
||||
}
|
||||
|
||||
export class RemoveDistributionTarget {
|
||||
static readonly type = '[Workbasket] Remove selected workbasket as distribution target';
|
||||
|
||||
constructor(public url: string) {}
|
||||
}
|
||||
|
||||
// Workbasket Access Items
|
||||
export class GetWorkbasketAccessItems {
|
||||
static readonly type = '[Workbasket] Get all workbasket access items';
|
||||
|
||||
constructor(public url: string) {}
|
||||
}
|
||||
|
||||
export class UpdateWorkbasketAccessItems {
|
||||
static readonly type = "[Workbasket] Update selected workbasket's access items";
|
||||
static readonly type = '[Workbasket] Update selected workbaskets access items';
|
||||
|
||||
constructor(public url: string, public workbasketAccessItems: WorkbasketAccessItems[]) {}
|
||||
}
|
||||
|
||||
// Workbasket Distribution Targets
|
||||
export class GetWorkbasketDistributionTargets {
|
||||
static readonly type = '[Workbasket] Get all workbasket distribution targets';
|
||||
constructor(public url: string) {}
|
||||
}
|
||||
|
||||
export class GetAvailableDistributionTargets {
|
||||
static readonly type = '[Workbasket] Get available distribution targets';
|
||||
}
|
||||
|
||||
export class UpdateWorkbasketDistributionTargets {
|
||||
static readonly type = '[Workbasket] Update workbasket distribution targets';
|
||||
constructor(public url: string, public distributionTargetsIds: string[]) {}
|
||||
}
|
||||
|
||||
export class FetchWorkbasketDistributionTargets {
|
||||
static readonly type = '[Workbasket] Fetch a subset of selected workbasket distribution targets';
|
||||
|
||||
constructor(
|
||||
public refetchAll: boolean,
|
||||
public filterParameter?: WorkbasketQueryFilterParameter,
|
||||
public sortParameter?: Sorting<WorkbasketQuerySortParameter>
|
||||
) {}
|
||||
}
|
||||
|
||||
export class FetchAvailableDistributionTargets {
|
||||
static readonly type = '[Workbasket] Fetch a subset of available workbasket distribution targets';
|
||||
|
||||
constructor(
|
||||
public refetchAll: boolean,
|
||||
public filterParameter?: WorkbasketQueryFilterParameter,
|
||||
public sortParameter?: Sorting<WorkbasketQuerySortParameter>
|
||||
) {}
|
||||
}
|
||||
|
||||
export class TransferDistributionTargets {
|
||||
static readonly type = '[Workbasket] Transfer a set of workbasket distribution targets';
|
||||
|
||||
constructor(public targetSide: Side, public workbasketSummaries: WorkbasketSummary[]) {}
|
||||
}
|
||||
|
|
|
@ -66,13 +66,13 @@ export class WorkbasketSelectors {
|
|||
|
||||
// Workbasket Distribution Targets
|
||||
@Selector([WorkbasketState])
|
||||
static workbasketDistributionTargets(state: WorkbasketStateModel): WorkbasketDistributionTargets {
|
||||
return state.workbasketDistributionTargets;
|
||||
static workbasketDistributionTargets(state: WorkbasketStateModel): WorkbasketSummary[] {
|
||||
return state.workbasketDistributionTargets.distributionTargets;
|
||||
}
|
||||
|
||||
@Selector([WorkbasketState])
|
||||
static availableDistributionTargets(state: WorkbasketStateModel): WorkbasketSummary[] {
|
||||
return state.workbasketAvailableDistributionTargets;
|
||||
return state.availableDistributionTargets.workbaskets;
|
||||
}
|
||||
|
||||
@Selector([WorkbasketState])
|
||||
|
|
|
@ -8,9 +8,9 @@ import {
|
|||
CopyWorkbasket,
|
||||
CreateWorkbasket,
|
||||
DeselectWorkbasket,
|
||||
GetAvailableDistributionTargets,
|
||||
FetchAvailableDistributionTargets,
|
||||
FetchWorkbasketDistributionTargets,
|
||||
GetWorkbasketAccessItems,
|
||||
GetWorkbasketDistributionTargets,
|
||||
GetWorkbasketsSummary,
|
||||
MarkWorkbasketForDeletion,
|
||||
OnButtonPressed,
|
||||
|
@ -19,6 +19,7 @@ import {
|
|||
SelectComponent,
|
||||
SelectWorkbasket,
|
||||
SetActiveAction,
|
||||
TransferDistributionTargets,
|
||||
UpdateWorkbasket,
|
||||
UpdateWorkbasketAccessItems,
|
||||
UpdateWorkbasketDistributionTargets
|
||||
|
@ -38,6 +39,9 @@ import { TaskanaDate } from '../../util/taskana.date';
|
|||
import { DomainService } from '../../services/domain/domain.service';
|
||||
import { ClearWorkbasketFilter } from '../filter-store/filter.actions';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { WorkbasketQueryPagingParameter } from '../../models/workbasket-query-paging-parameter';
|
||||
import { Side } from '../../../administration/models/workbasket-distribution-enums';
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
class InitializeStore {
|
||||
static readonly type = '[Workbasket] Initializing state';
|
||||
|
@ -77,12 +81,16 @@ export class WorkbasketState implements NgxsAfterBootstrap {
|
|||
}
|
||||
|
||||
ctx.patchState({
|
||||
badgeMessage: ''
|
||||
badgeMessage: '',
|
||||
availableDistributionTargetsPage: 0,
|
||||
distributionTargetsPage: 0,
|
||||
workbasketDistributionTargets: { distributionTargets: [], _links: {} },
|
||||
availableDistributionTargets: { workbaskets: [], _links: {} }
|
||||
});
|
||||
|
||||
ctx.dispatch(new SelectComponent(tab));
|
||||
});
|
||||
return of();
|
||||
return of(null);
|
||||
}
|
||||
|
||||
@Action(GetWorkbasketsSummary)
|
||||
|
@ -127,9 +135,6 @@ export class WorkbasketState implements NgxsAfterBootstrap {
|
|||
});
|
||||
|
||||
ctx.dispatch(new GetWorkbasketAccessItems(ctx.getState().selectedWorkbasket._links.accessItems.href));
|
||||
ctx.dispatch(
|
||||
new GetWorkbasketDistributionTargets(ctx.getState().selectedWorkbasket._links.distributionTargets.href)
|
||||
);
|
||||
|
||||
this.location.go(
|
||||
this.location
|
||||
|
@ -204,7 +209,7 @@ export class WorkbasketState implements NgxsAfterBootstrap {
|
|||
}
|
||||
|
||||
@Action(CopyWorkbasket)
|
||||
copyWorkbasket(ctx: StateContext<WorkbasketStateModel>, action: CopyWorkbasket): Observable<any> {
|
||||
copyWorkbasket(ctx: StateContext<WorkbasketStateModel>): Observable<any> {
|
||||
this.location.go(this.location.path().replace(/(workbaskets).*/g, 'workbaskets/(detail:new-workbasket)'));
|
||||
ctx.dispatch(new OnButtonPressed(undefined));
|
||||
|
||||
|
@ -230,21 +235,24 @@ export class WorkbasketState implements NgxsAfterBootstrap {
|
|||
tap((domain) => {
|
||||
this.location.go(this.location.path().replace(/(workbaskets).*/g, 'workbaskets/(detail:new-workbasket)'));
|
||||
|
||||
if (!ctx.getState().workbasketAvailableDistributionTargets) {
|
||||
ctx.dispatch(new GetAvailableDistributionTargets());
|
||||
if (!ctx.getState().availableDistributionTargets) {
|
||||
ctx.dispatch(new FetchAvailableDistributionTargets(true));
|
||||
}
|
||||
|
||||
const emptyWorkbasket: Workbasket = {};
|
||||
emptyWorkbasket.domain = domain;
|
||||
emptyWorkbasket.type = WorkbasketType.PERSONAL;
|
||||
|
||||
const date = TaskanaDate.getDate();
|
||||
const date: string = TaskanaDate.getDate();
|
||||
emptyWorkbasket.created = date;
|
||||
emptyWorkbasket.modified = date;
|
||||
emptyWorkbasket.owner = '';
|
||||
|
||||
const accessItems = { accessItems: [], _links: {} };
|
||||
const distributionTargets = { distributionTargets: [], _links: {} };
|
||||
const accessItems: WorkbasketAccessItemsRepresentation = { accessItems: [], _links: {} };
|
||||
const distributionTargets: WorkbasketDistributionTargets = {
|
||||
_links: {},
|
||||
distributionTargets: []
|
||||
};
|
||||
|
||||
ctx.patchState({
|
||||
action: ACTION.CREATE,
|
||||
|
@ -348,73 +356,144 @@ export class WorkbasketState implements NgxsAfterBootstrap {
|
|||
);
|
||||
}
|
||||
|
||||
@Action(GetWorkbasketDistributionTargets)
|
||||
getWorkbasketDistributionTargets(
|
||||
ctx: StateContext<WorkbasketStateModel>,
|
||||
action: GetWorkbasketDistributionTargets
|
||||
): Observable<any> {
|
||||
return this.workbasketService.getWorkBasketsDistributionTargets(action.url).pipe(
|
||||
take(1),
|
||||
tap((workbasketDistributionTargets) => {
|
||||
ctx.patchState({
|
||||
workbasketDistributionTargets
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Action(GetAvailableDistributionTargets)
|
||||
getAvailableDistributionTargets(ctx: StateContext<WorkbasketStateModel>): Observable<any> {
|
||||
return this.workbasketService.getWorkBasketsSummary(true).pipe(
|
||||
take(1),
|
||||
tap((workbasketAvailableDistributionTargets: WorkbasketSummaryRepresentation) => {
|
||||
ctx.patchState({
|
||||
workbasketAvailableDistributionTargets: workbasketAvailableDistributionTargets.workbaskets
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Action(UpdateWorkbasketDistributionTargets)
|
||||
updateWorkbasketDistributionTargets(
|
||||
ctx: StateContext<WorkbasketStateModel>,
|
||||
action: UpdateWorkbasketDistributionTargets
|
||||
): Observable<any> {
|
||||
updateWorkbasketDistributionTargets(ctx: StateContext<WorkbasketStateModel>): Observable<any> {
|
||||
this.requestInProgressService.setRequestInProgress(true);
|
||||
return this.workbasketService.updateWorkBasketsDistributionTargets(action.url, action.distributionTargetsIds).pipe(
|
||||
take(1),
|
||||
tap(
|
||||
(updatedWorkbasketsDistributionTargets) => {
|
||||
ctx.patchState({
|
||||
workbasketDistributionTargets: updatedWorkbasketsDistributionTargets
|
||||
});
|
||||
const workbasketId = ctx.getState().selectedWorkbasket?.workbasketId;
|
||||
|
||||
if (typeof workbasketId !== 'undefined') {
|
||||
this.workbasketService.getWorkBasket(workbasketId).subscribe((selectedWorkbasket) => {
|
||||
ctx.patchState({
|
||||
selectedWorkbasket,
|
||||
action: ACTION.READ
|
||||
});
|
||||
ctx.dispatch(new ClearWorkbasketFilter('selectedDistributionTargets'));
|
||||
ctx.dispatch(new ClearWorkbasketFilter('availableDistributionTargets'));
|
||||
});
|
||||
}
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
this.notificationService.showSuccess('WORKBASKET_DISTRIBUTION_TARGET_SAVE', {
|
||||
workbasketName: ctx.getState().selectedWorkbasket.name
|
||||
});
|
||||
|
||||
return of(null);
|
||||
},
|
||||
() => {
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
}
|
||||
return this.workbasketService
|
||||
.updateWorkBasketsDistributionTargets(
|
||||
ctx.getState().selectedWorkbasket._links.distributionTargets.href,
|
||||
ctx.getState().workbasketDistributionTargets.distributionTargets.map((w) => w.workbasketId)
|
||||
)
|
||||
);
|
||||
.pipe(
|
||||
take(1),
|
||||
tap({
|
||||
next: (updatedWorkbasketsDistributionTargets) => {
|
||||
ctx.patchState({
|
||||
workbasketDistributionTargets: updatedWorkbasketsDistributionTargets
|
||||
});
|
||||
const workbasketId = ctx.getState().selectedWorkbasket?.workbasketId;
|
||||
|
||||
if (typeof workbasketId !== 'undefined') {
|
||||
this.workbasketService.getWorkBasket(workbasketId).subscribe((selectedWorkbasket) => {
|
||||
ctx.patchState({
|
||||
selectedWorkbasket,
|
||||
action: ACTION.READ
|
||||
});
|
||||
ctx.dispatch(new ClearWorkbasketFilter('selectedDistributionTargets'));
|
||||
ctx.dispatch(new ClearWorkbasketFilter('availableDistributionTargets'));
|
||||
});
|
||||
}
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
this.notificationService.showSuccess('WORKBASKET_DISTRIBUTION_TARGET_SAVE', {
|
||||
workbasketName: ctx.getState().selectedWorkbasket.name
|
||||
});
|
||||
|
||||
return of(null);
|
||||
},
|
||||
error: () => {
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
ngxsAfterBootstrap(ctx?: StateContext<any>): void {
|
||||
@Action(FetchWorkbasketDistributionTargets)
|
||||
fetchWorkbasketDistributionTargets(
|
||||
ctx: StateContext<WorkbasketStateModel>,
|
||||
action: FetchWorkbasketDistributionTargets
|
||||
): Observable<any> {
|
||||
const { selectedWorkbasket, distributionTargetsPage, workbasketDistributionTargets } = ctx.getState();
|
||||
const { filterParameter, sortParameter, refetchAll } = action;
|
||||
const nextDistributionTargetsPage = refetchAll ? 1 : distributionTargetsPage + 1;
|
||||
return this.workbasketService
|
||||
.getWorkBasketsDistributionTargets(
|
||||
selectedWorkbasket._links.distributionTargets.href,
|
||||
filterParameter,
|
||||
sortParameter,
|
||||
new WorkbasketQueryPagingParameter(nextDistributionTargetsPage)
|
||||
)
|
||||
.pipe(
|
||||
take(1),
|
||||
tap((wbt: WorkbasketDistributionTargets) => {
|
||||
if (!refetchAll && workbasketDistributionTargets) {
|
||||
wbt.distributionTargets = workbasketDistributionTargets.distributionTargets.concat(wbt.distributionTargets);
|
||||
}
|
||||
ctx.patchState({
|
||||
workbasketDistributionTargets: wbt,
|
||||
distributionTargetsPage: nextDistributionTargetsPage
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Action(FetchAvailableDistributionTargets)
|
||||
fetchAvailableDistributionTargets(
|
||||
ctx: StateContext<WorkbasketStateModel>,
|
||||
action: FetchAvailableDistributionTargets
|
||||
): Observable<any> {
|
||||
const { availableDistributionTargetsPage, availableDistributionTargets } = ctx.getState();
|
||||
const { filterParameter, sortParameter, refetchAll } = action;
|
||||
const nextAvailableDistributionTargetsPage = refetchAll ? 1 : availableDistributionTargetsPage + 1;
|
||||
if (!refetchAll && nextAvailableDistributionTargetsPage > availableDistributionTargets.page?.totalPages) {
|
||||
return of(null);
|
||||
}
|
||||
return this.workbasketService
|
||||
.getWorkBasketsSummary(
|
||||
true,
|
||||
filterParameter,
|
||||
sortParameter,
|
||||
new WorkbasketQueryPagingParameter(nextAvailableDistributionTargetsPage)
|
||||
)
|
||||
.pipe(
|
||||
take(1),
|
||||
tap((wbSummaryRepresentation: WorkbasketSummaryRepresentation) => {
|
||||
const distributionTargetSet = new Set(
|
||||
ctx.getState().workbasketDistributionTargets.distributionTargets.map((wb) => wb.workbasketId)
|
||||
);
|
||||
wbSummaryRepresentation.workbaskets = wbSummaryRepresentation.workbaskets.filter((wb) => {
|
||||
return !distributionTargetSet.has(wb.workbasketId);
|
||||
});
|
||||
if (!refetchAll && availableDistributionTargets) {
|
||||
wbSummaryRepresentation.workbaskets = availableDistributionTargets.workbaskets.concat(
|
||||
wbSummaryRepresentation.workbaskets
|
||||
);
|
||||
}
|
||||
ctx.patchState({
|
||||
availableDistributionTargets: wbSummaryRepresentation,
|
||||
availableDistributionTargetsPage: nextAvailableDistributionTargetsPage
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Action(TransferDistributionTargets)
|
||||
transferDistributionTargets(ctx: StateContext<WorkbasketStateModel>, action: TransferDistributionTargets): void {
|
||||
let { workbasketDistributionTargets, availableDistributionTargets } = ctx.getState();
|
||||
const workbasketSummarySet = new Set(action.workbasketSummaries.map((wb) => wb.workbasketId));
|
||||
availableDistributionTargets = cloneDeep(availableDistributionTargets);
|
||||
workbasketDistributionTargets = cloneDeep(workbasketDistributionTargets);
|
||||
if (action.targetSide === Side.AVAILABLE) {
|
||||
workbasketDistributionTargets.distributionTargets = workbasketDistributionTargets.distributionTargets.filter(
|
||||
(wb) => !workbasketSummarySet.has(wb.workbasketId)
|
||||
);
|
||||
availableDistributionTargets.workbaskets = availableDistributionTargets.workbaskets.concat(
|
||||
action.workbasketSummaries
|
||||
);
|
||||
} else {
|
||||
availableDistributionTargets.workbaskets = availableDistributionTargets.workbaskets.filter(
|
||||
(wb) => !workbasketSummarySet.has(wb.workbasketId)
|
||||
);
|
||||
workbasketDistributionTargets.distributionTargets = workbasketDistributionTargets.distributionTargets.concat(
|
||||
action.workbasketSummaries
|
||||
);
|
||||
}
|
||||
ctx.patchState({
|
||||
availableDistributionTargets,
|
||||
workbasketDistributionTargets
|
||||
});
|
||||
}
|
||||
|
||||
ngxsAfterBootstrap(ctx: StateContext<WorkbasketStateModel>): void {
|
||||
ctx.dispatch(new InitializeStore());
|
||||
}
|
||||
}
|
||||
|
@ -438,7 +517,9 @@ export interface WorkbasketStateModel {
|
|||
action: ACTION;
|
||||
workbasketAccessItems: WorkbasketAccessItemsRepresentation;
|
||||
workbasketDistributionTargets: WorkbasketDistributionTargets;
|
||||
workbasketAvailableDistributionTargets: WorkbasketSummary[];
|
||||
distributionTargetsPage: number;
|
||||
availableDistributionTargets: WorkbasketSummaryRepresentation;
|
||||
availableDistributionTargetsPage: number;
|
||||
selectedComponent: WorkbasketComponent;
|
||||
badgeMessage: string;
|
||||
button: ButtonAction | undefined;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@use "sass:math";
|
||||
@use 'sass:math';
|
||||
|
||||
@import 'colors';
|
||||
.item {
|
||||
|
|
|
@ -504,5 +504,5 @@ li.list-group-item:hover {
|
|||
}
|
||||
|
||||
.hot-toast-icon {
|
||||
align-self: center !important
|
||||
align-self: center !important;
|
||||
}
|
||||
|
|
|
@ -1828,6 +1828,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
|
||||
|
||||
"@types/lodash@^4.14.178":
|
||||
version "4.14.178"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.178.tgz#341f6d2247db528d4a13ddbb374bcdc80406f4f8"
|
||||
integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==
|
||||
|
||||
"@types/minimatch@*":
|
||||
version "3.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
|
||||
|
@ -6755,7 +6760,7 @@ lodash.uniq@^4.5.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
||||
|
||||
lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21, lodash@^4.7.0:
|
||||
lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21, lodash@^4.5.0, lodash@^4.7.0:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
|
Loading…
Reference in New Issue