TSK-1215: Workbasket component NGXS store (#1169)
* TSK-1214: refactored taskana-classification TSK-1214 Trying to make drag'n drop in tree possible TSK-1214 Removed refreshClassification output from tree TSK-1214 New action in store updates a classification and refetches all, saving now correctly refreshes the classification-list TSK-1214 Fixed tests in tree component TSK-1214 Removed tree service and corresponding test in class-details TSK-1214 fixed issues in tree where multiple actions to store are fired incorrectly TSK-1214 added accessibility action, use space to select a tree node TSK-1214 swapped space and enter in tree component, cleaned code TSK-1214 fixed bug where page isn't updated dynamically according to browser path TSK-1214 workaround circular dependency. service uses snapshot of store, does not actually access the state in store TSK-1214 fixed eslint. TODO: circular dependency between classification.service and classification.state TSK-1214 changed first() to take(1) to fix Observable dying during test TSK-1214 fixed test cases and lint issues TSK-1214 fixed circular dependency TSK-1214 devmode = false TSK-1214: fixed merge problems with notificationService and removed some warnings TSK-1214: fixed merge problems with notificationService TSK-1214 remove wrong imports from before merge * TSK-1215 initialized workbasket ngxs store with get all and select workbasket * TSK-1215 added actions for creating workbasket and getting workbasket access items * TSK-1215 fixed models' attributes in workbasket * TSK-1215 changed workbasket models from class type to interface type * TSK-1215 correct the naming scheme for models in workbasket * TSK-1215 update workbasket models to mirror backend entities * TSK-1215 implemented workbasketsSummary in store * TSK-1215 workbasket list data is now populated using NGXS Store * TSK-1215 fixed console errors while navigating pagination * TSK-1215 initialized workbasket-overview * TSK-1215 removed unnecessary subscriptions * TSK-1215 fixed workbasket access items still using WorkbasketAccessItems as a class instead of an interface * TSK-1215 implemented routing for workbasket overview, removed master-details component * TSK-1215 implemented new behaviors based on ngxs store instead of router * TSK-1215 bug fixes for creating, selecting and deselecting workbasket * TSK-1215 further bugs fixing regarding creating and selecting workbasket * TSK-1215 fixed bugs where input workbasket was immutable in information component * TSK-1215 added remove distribution target and delete workbasket actions * TSK-1215 implemented mark workbasket for deletion in state * TSK-1215 implemented workbasket copy function * TSK-1215 implemented mark workbasket for deletion * TSK-1287 implemented typeahead for owner field in workbasket * TSK-1215 added actions for workbasket access items and distribution targets * TSK-1215 fixed bugs saving or creating new workbasket * TSK-1215 finished workbasket information * TSK-1215 updated tests for workbasket list, details and information * TSK-1215 increased HTML visibility, refine css * TSK-1215 implemented workbasket access items using ngxs state * TSK-1215 increased workbasket distribution target HTML code visibility * TSK-1215 initialization of distribution targets now uses actions from state * TSK-1215 use takeUntil for subscriptions instead of manually unsubscribing * TSK-1215 save function for distribution targets now dispatch an action * TSK-1215: code refinement in ngxs store * TSK-1214: refactored taskana-classification TSK-1214 Trying to make drag'n drop in tree possible TSK-1214 Removed refreshClassification output from tree TSK-1214 New action in store updates a classification and refetches all, saving now correctly refreshes the classification-list TSK-1214 Fixed tests in tree component TSK-1214 Removed tree service and corresponding test in class-details TSK-1214 fixed issues in tree where multiple actions to store are fired incorrectly TSK-1214 added accessibility action, use space to select a tree node TSK-1214 swapped space and enter in tree component, cleaned code TSK-1214 fixed bug where page isn't updated dynamically according to browser path TSK-1214 workaround circular dependency. service uses snapshot of store, does not actually access the state in store TSK-1214 fixed eslint. TODO: circular dependency between classification.service and classification.state TSK-1214 changed first() to take(1) to fix Observable dying during test TSK-1214 fixed test cases and lint issues TSK-1214 fixed circular dependency TSK-1214 devmode = false TSK-1214: fixed merge problems with notificationService and removed some warnings TSK-1214: fixed merge problems with notificationService TSK-1214 remove wrong imports from before merge * TSK-1215 initialized workbasket ngxs store with get all and select workbasket * TSK-1215 added actions for creating workbasket and getting workbasket access items * TSK-1215 fixed models' attributes in workbasket * TSK-1215 changed workbasket models from class type to interface type * TSK-1215 correct the naming scheme for models in workbasket * TSK-1215 update workbasket models to mirror backend entities * TSK-1215 implemented workbasketsSummary in store * TSK-1215 workbasket list data is now populated using NGXS Store * TSK-1215 fixed console errors while navigating pagination * TSK-1215 initialized workbasket-overview * TSK-1215 removed unnecessary subscriptions * TSK-1215 fixed workbasket access items still using WorkbasketAccessItems as a class instead of an interface * TSK-1215 implemented routing for workbasket overview, removed master-details component * TSK-1215 implemented new behaviors based on ngxs store instead of router * TSK-1215 bug fixes for creating, selecting and deselecting workbasket * TSK-1215 further bugs fixing regarding creating and selecting workbasket * TSK-1215 fixed bugs where input workbasket was immutable in information component * TSK-1215 added remove distribution target and delete workbasket actions * TSK-1215 implemented mark workbasket for deletion in state * TSK-1215 implemented workbasket copy function * TSK-1215 implemented mark workbasket for deletion * TSK-1287 implemented typeahead for owner field in workbasket * TSK-1215 added actions for workbasket access items and distribution targets * TSK-1215 fixed bugs saving or creating new workbasket * TSK-1215 finished workbasket information * TSK-1215 updated tests for workbasket list, details and information * TSK-1215 increased HTML visibility, refine css * TSK-1215 implemented workbasket access items using ngxs state * TSK-1215 increased workbasket distribution target HTML code visibility * TSK-1215 initialization of distribution targets now uses actions from state * TSK-1215 use takeUntil for subscriptions instead of manually unsubscribing * TSK-1215 save function for distribution targets now dispatch an action * TSK-1215: code refinement in ngxs store * TSK-1215: Optimize select workbasket algorithm * TSK-1215: Fixed workbasket information not displaying correctly after saving * TSK-1215: configured tests for workbasket distribution targets * TSK-1215: updated unit tests for workbasket * TSK-1215: cleaned up code, prep for PR * TSK-1215: disable dev mode * TSK-1215: fixed failed tests occured after merge * TSK-1215: reverted node version * TSK-1215: Further bugs fixed due to merging * TSK-1068: Fixed bugs workbasket staying active after being moved * TSK-1215: Fixed minor bugs in tests * TSK-1215: various improvement in code, typeahead style * TSK-1215: Updated typeahead css * TSK-1215: Fixed failed tests due to merge * TSK-1342: getTasksWorkbasketReport now filters for states * TSK-1214: refactored taskana-classification TSK-1214 Trying to make drag'n drop in tree possible TSK-1214 Removed refreshClassification output from tree TSK-1214 New action in store updates a classification and refetches all, saving now correctly refreshes the classification-list TSK-1214 Fixed tests in tree component TSK-1214 Removed tree service and corresponding test in class-details TSK-1214 fixed issues in tree where multiple actions to store are fired incorrectly TSK-1214 added accessibility action, use space to select a tree node TSK-1214 swapped space and enter in tree component, cleaned code TSK-1214 fixed bug where page isn't updated dynamically according to browser path TSK-1214 workaround circular dependency. service uses snapshot of store, does not actually access the state in store TSK-1214 fixed eslint. TODO: circular dependency between classification.service and classification.state TSK-1214 changed first() to take(1) to fix Observable dying during test TSK-1214 fixed test cases and lint issues TSK-1214 fixed circular dependency TSK-1214 devmode = false TSK-1214: fixed merge problems with notificationService and removed some warnings TSK-1214: fixed merge problems with notificationService TSK-1214 remove wrong imports from before merge * TSK-1215 initialized workbasket ngxs store with get all and select workbasket * TSK-1215 added actions for creating workbasket and getting workbasket access items * TSK-1215 fixed models' attributes in workbasket * TSK-1215 changed workbasket models from class type to interface type * TSK-1215 correct the naming scheme for models in workbasket * TSK-1215 update workbasket models to mirror backend entities * TSK-1215 implemented workbasketsSummary in store * TSK-1215 workbasket list data is now populated using NGXS Store * TSK-1215 fixed console errors while navigating pagination * TSK-1215 initialized workbasket-overview * TSK-1215 removed unnecessary subscriptions * TSK-1215 fixed workbasket access items still using WorkbasketAccessItems as a class instead of an interface * TSK-1215 implemented routing for workbasket overview, removed master-details component * TSK-1215 implemented new behaviors based on ngxs store instead of router * TSK-1215 bug fixes for creating, selecting and deselecting workbasket * TSK-1215 further bugs fixing regarding creating and selecting workbasket * TSK-1215 fixed bugs where input workbasket was immutable in information component * TSK-1215 added remove distribution target and delete workbasket actions * TSK-1215 implemented mark workbasket for deletion in state * TSK-1215 implemented workbasket copy function * TSK-1215 implemented mark workbasket for deletion * TSK-1287 implemented typeahead for owner field in workbasket * TSK-1215 added actions for workbasket access items and distribution targets * TSK-1215 fixed bugs saving or creating new workbasket * TSK-1215 finished workbasket information * TSK-1215 updated tests for workbasket list, details and information * TSK-1215 increased HTML visibility, refine css * TSK-1215 implemented workbasket access items using ngxs state * TSK-1215 increased workbasket distribution target HTML code visibility * TSK-1215 initialization of distribution targets now uses actions from state * TSK-1215 use takeUntil for subscriptions instead of manually unsubscribing * TSK-1215 save function for distribution targets now dispatch an action * TSK-1215: code refinement in ngxs store * TSK-1215 initialized workbasket ngxs store with get all and select workbasket * TSK-1215 added actions for creating workbasket and getting workbasket access items * TSK-1215 fixed models' attributes in workbasket * TSK-1215 changed workbasket models from class type to interface type * TSK-1215 correct the naming scheme for models in workbasket * TSK-1215 update workbasket models to mirror backend entities * TSK-1215 implemented workbasketsSummary in store * TSK-1215 workbasket list data is now populated using NGXS Store * TSK-1215 fixed console errors while navigating pagination * TSK-1215 initialized workbasket-overview * TSK-1215 removed unnecessary subscriptions * TSK-1215 fixed workbasket access items still using WorkbasketAccessItems as a class instead of an interface * TSK-1215 implemented routing for workbasket overview, removed master-details component * TSK-1215 implemented new behaviors based on ngxs store instead of router * TSK-1215 bug fixes for creating, selecting and deselecting workbasket * TSK-1215 further bugs fixing regarding creating and selecting workbasket * TSK-1215 fixed bugs where input workbasket was immutable in information component * TSK-1215 added remove distribution target and delete workbasket actions * TSK-1215 implemented mark workbasket for deletion in state * TSK-1215 implemented workbasket copy function * TSK-1215 implemented mark workbasket for deletion * TSK-1287 implemented typeahead for owner field in workbasket * TSK-1215 added actions for workbasket access items and distribution targets * TSK-1215 fixed bugs saving or creating new workbasket * TSK-1215 finished workbasket information * TSK-1215 updated tests for workbasket list, details and information * TSK-1215 increased HTML visibility, refine css * TSK-1215 implemented workbasket access items using ngxs state * TSK-1215 increased workbasket distribution target HTML code visibility * TSK-1215 initialization of distribution targets now uses actions from state * TSK-1215 use takeUntil for subscriptions instead of manually unsubscribing * TSK-1215 save function for distribution targets now dispatch an action * TSK-1215: code refinement in ngxs store * TSK-1215: Optimize select workbasket algorithm * TSK-1215: Fixed workbasket information not displaying correctly after saving * TSK-1215: configured tests for workbasket distribution targets * TSK-1215: updated unit tests for workbasket * TSK-1215: cleaned up code, prep for PR * TSK-1215: disable dev mode * TSK-1215: fixed failed tests occured after merge * TSK-1215: reverted node version * TSK-1215: Further bugs fixed due to merging * TSK-1068: Fixed bugs workbasket staying active after being moved * TSK-1215: Fixed minor bugs in tests * TSK-1215: various improvement in code, typeahead style * TSK-1215: Updated typeahead css * TSK-1215: Fixed failed tests due to merge * TSK-1215: Rebase, prep for merge with master Co-authored-by: Mustapha Zorgati <15628173+mustaphazorgati@users.noreply.github.com> Co-authored-by: Tristan Eisermann <19949441+Tristan2357@users.noreply.github.com>
This commit is contained in:
parent
97443641af
commit
59b45f626a
|
@ -1,34 +1,25 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { WorkbasketListComponent } from 'app/administration/components/workbasket-list/workbasket-list.component';
|
||||
import { WorkbasketDetailsComponent } from 'app/administration/components/workbasket-details/workbasket-details.component';
|
||||
import { MasterAndDetailComponent } from 'app/shared/components/master-and-detail/master-and-detail.component';
|
||||
import { ClassificationListComponent } from 'app/administration/components/classification-list/classification-list.component';
|
||||
import { ClassificationDetailsComponent } from 'app/administration/components/classification-details/classification-details.component';
|
||||
import { DomainGuard } from 'app/shared/guards/domain.guard';
|
||||
import { AccessItemsManagementComponent } from './components/access-items-management/access-items-management.component';
|
||||
import { ClassificationOverviewComponent } from './components/classification-overview/classification-overview.component';
|
||||
import { WorkbasketOverviewComponent } from './components/workbasket-overview/workbasket-overview.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'workbaskets',
|
||||
component: MasterAndDetailComponent,
|
||||
component: WorkbasketOverviewComponent,
|
||||
canActivate: [DomainGuard],
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: WorkbasketListComponent,
|
||||
component: WorkbasketOverviewComponent,
|
||||
outlet: 'master'
|
||||
},
|
||||
{
|
||||
path: 'new-classification/:id',
|
||||
component: WorkbasketDetailsComponent,
|
||||
outlet: 'detail'
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
component: WorkbasketDetailsComponent,
|
||||
component: WorkbasketOverviewComponent,
|
||||
outlet: 'detail'
|
||||
},
|
||||
{
|
||||
|
|
|
@ -33,6 +33,7 @@ import { ClassificationDefinitionService } from './services/classification-defin
|
|||
import { WorkbasketDefinitionService } from './services/workbasket-definition.service';
|
||||
import { ImportExportService } from './services/import-export.service';
|
||||
import { ClassificationOverviewComponent } from './components/classification-overview/classification-overview.component';
|
||||
import { WorkbasketOverviewComponent } from './components/workbasket-overview/workbasket-overview.component';
|
||||
|
||||
const MODULES = [
|
||||
CommonModule,
|
||||
|
@ -47,6 +48,7 @@ const MODULES = [
|
|||
];
|
||||
|
||||
const DECLARATIONS = [
|
||||
WorkbasketOverviewComponent,
|
||||
WorkbasketListComponent,
|
||||
WorkbasketListToolbarComponent,
|
||||
WorkbasketAccessItemsComponent,
|
||||
|
|
|
@ -45,7 +45,7 @@ describe('ClassificationListComponent', () => {
|
|||
testBed.configureTestingModule({
|
||||
declarations: [ClassificationListComponent, ImportExportComponent, ClassificationTypesSelectorComponent,
|
||||
DummyDetailComponent],
|
||||
imports: [HttpClientModule, RouterTestingModule.withRoutes(routes), FormsModule, AngularSvgIconModule, NgxsModule.forRoot(), MatRadioModule],
|
||||
imports: [HttpClientModule, RouterTestingModule.withRoutes(routes), FormsModule, AngularSvgIconModule, NgxsModule.forRoot([]), MatRadioModule],
|
||||
providers: [
|
||||
HttpClient, WorkbasketDefinitionService, NotificationService,
|
||||
ClassificationsService, DomainService, ClassificationDefinitionService,
|
||||
|
|
|
@ -99,7 +99,7 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
|
|||
);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
|
||||
|
||||
<!-- ACTION TOOLBAR -->
|
||||
<div class="panel-heading">
|
||||
<div class="pull-right btn-group">
|
||||
<button type="button" (click)="onSubmit()" [disabled]="action === 'COPY'" data-toggle="tooltip" title="Save" class="btn btn-default btn-primary">
|
||||
|
@ -12,9 +14,13 @@
|
|||
<span *ngIf="!workbasket.workbasketId" class="badge warning"> {{badgeMessage}}</span>
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<!-- ACCESS ITEMS -->
|
||||
<div class="panel-body">
|
||||
<form [formGroup]="AccessItemsForm">
|
||||
<table formArrayName="accessItemsGroups" id="table-access-items" class="table table-striped table-center">
|
||||
|
||||
<!-- TITLE ROW -->
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
|
@ -30,54 +36,73 @@
|
|||
</ng-container>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
|
||||
<tbody>
|
||||
<tr *ngFor="let accessItem of accessItemsGroups.controls; let index = index;" [formGroupName]="index">
|
||||
<!-- REMOVE BUTTON -->
|
||||
<td>
|
||||
<button type="button" (click)="remove(index)" data-toggle="tooltip" title="Remove" class="btn btn-default">
|
||||
<span class="material-icons md-20 red">clear</span>
|
||||
<button type="button" style="padding: 3px;" (click)="remove(index)" data-toggle="tooltip" title="Remove" class="btn btn-default">
|
||||
<span class="material-icons md-24 red">clear</span>
|
||||
</button>
|
||||
</td>
|
||||
|
||||
<!-- ACCESS ID -->
|
||||
<td *ngIf="(accessItemsCustomization$ | async)?.accessId.lookupField else accessIdInput" class="input-group text-align text-width taskana-type-ahead"
|
||||
[ngClass]="{
|
||||
'has-warning': (accessItemsClone[index].accessId !== accessItem.value.accessId),
|
||||
'has-error': !accessItem.value.accessId }">
|
||||
<taskana-shared-type-ahead formControlName="accessId" placeHolderMessage="* Access id is required" [validationValue]="toggleValidationAccessIdMap.get(index)"
|
||||
[displayError]="!isFieldValid('accessItem.value.accessId', index)" (selectedItem)="accessItemSelected($event, index)" (inputField)="focusNewInput($event)"></taskana-shared-type-ahead>
|
||||
</td>
|
||||
</td>
|
||||
<ng-template #accessIdInput>
|
||||
<td class="input-group text-align text-width">
|
||||
<div [ngClass]="{ 'has-warning': (accessItemsClone[index].accessId !==accessItem.value.accessId), 'has-error':
|
||||
!accessItem.value.accessId && formSubmitAttempt}">
|
||||
!accessItem.value.accessId && formsValidatorService.formSubmitAttempt}">
|
||||
<input type="text" class="form-control" formControlName="accessId" placeholder="{{accessItem.invalid?
|
||||
'* Access id is required': ''}}"
|
||||
[@validation]="toggleValidationAccessIdMap.get(index)" #htmlInputElement>
|
||||
[@validation]="toggleValidationAccessIdMap.get(index)" #htmlInputElement>
|
||||
</div>
|
||||
</td>
|
||||
</ng-template>
|
||||
|
||||
<!-- SELECT ALL -->
|
||||
<td>
|
||||
<input id="checkbox-{{index}}-00" type="checkbox" (change)="checkAll(index, $event)">
|
||||
<label for="checkbox-{{index}}-00"></label>
|
||||
</td>
|
||||
|
||||
<!-- READ -->
|
||||
<td [ngClass]="{ 'has-changes': (accessItemsClone[index].permRead !== accessItem.value.permRead)}">
|
||||
<input id="checkbox-{{index}}-0" type="checkbox" formControlName="permRead" class="regular-checkbox">
|
||||
<label for="checkbox-{{index}}-0"></label>
|
||||
</td>
|
||||
|
||||
<!-- OPEN -->
|
||||
<td [ngClass]="{ 'has-changes': (accessItemsClone[index].permOpen !== accessItem.value.permOpen)}">
|
||||
<input id="checkbox-{{index}}-1" type="checkbox" formControlName="permOpen">
|
||||
<label for="checkbox-{{index}}-1"></label>
|
||||
</td>
|
||||
|
||||
<!-- APPEND -->
|
||||
<td [ngClass]="{ 'has-changes': (accessItemsClone[index].permAppend !== accessItem.value.permAppend)}">
|
||||
<input id="checkbox-{{index}}-2" type="checkbox" formControlName="permAppend">
|
||||
<label for="checkbox-{{index}}-2"></label>
|
||||
</td>
|
||||
|
||||
<!-- TRANSFER -->
|
||||
<td [ngClass]="{ 'has-changes': (accessItemsClone[index].permTransfer !== accessItem.value.permTransfer)}">
|
||||
<input id="checkbox-{{index}}-3" type="checkbox" formControlName="permTransfer">
|
||||
<label for="checkbox-{{index}}-3"></label>
|
||||
</td>
|
||||
|
||||
<!-- DISTRIBUTE -->
|
||||
<td [ngClass]="{ 'has-changes': (accessItemsClone[index].permDistribute !== accessItem.value.permDistribute)}">
|
||||
<input id="checkbox-{{index}}-4" type="checkbox" formControlName="permDistribute">
|
||||
<label for="checkbox-{{index}}-4"></label>
|
||||
</td>
|
||||
|
||||
<!-- CUSTOM FIELDS -->
|
||||
<ng-container *ngFor="let customField of customFields$ | async; let customIndex = index">
|
||||
<td *ngIf="customField.visible" [ngClass]="{ 'has-changes': accessItemsClone[index][getAccessItemCustomProperty(customIndex + 1)] !== accessItem.value[getAccessItemCustomProperty(customIndex+1)] }">
|
||||
<input id="checkbox-{{index}}-{{customIndex + 5}}" type="checkbox" formControlName="permCustom{{customIndex+1}}">
|
||||
|
@ -88,6 +113,8 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
<!-- ADD ACCESS ITEM -->
|
||||
<button type="button" (click)="addAccessItem()" data-toggle="tooltip" title="Add new access" class="btn btn-default">
|
||||
<span class="material-icons md-20 green-blue">add</span>
|
||||
<span>Add new access</span>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
@import '../../../../theme/colors';
|
||||
|
||||
td > input[type="checkbox"] {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
@ -18,6 +20,7 @@ td > input[type="checkbox"] {
|
|||
}
|
||||
|
||||
td {
|
||||
vertical-align: bottom !important;
|
||||
&.has-changes {
|
||||
border-bottom: 1px solid #f0ad4e;;
|
||||
}
|
||||
|
@ -26,3 +29,6 @@ td {
|
|||
max-width: 150px;
|
||||
border-bottom: none;
|
||||
}
|
||||
taskana-shared-type-ahead {
|
||||
top: 0;
|
||||
}
|
||||
|
|
|
@ -1,27 +1,24 @@
|
|||
import { SimpleChange } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { of } from 'rxjs';
|
||||
import { configureTests } from 'app/app.test.configuration';
|
||||
|
||||
import { Workbasket } from 'app/shared/models/workbasket';
|
||||
import { WorkbasketAccessItems } from 'app/shared/models/workbasket-access-items';
|
||||
import { WorkbasketAccessItemsResource } from 'app/shared/models/workbasket-access-items-resource';
|
||||
import { WorkbasketAccessItemsRepresentation } from 'app/shared/models/workbasket-access-items-representation';
|
||||
import { ICONTYPES } from 'app/shared/models/icon-types';
|
||||
|
||||
import { Location } from '@angular/common';
|
||||
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
|
||||
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
|
||||
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
|
||||
import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.service';
|
||||
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
|
||||
import { NgxsModule, Store } from '@ngxs/store';
|
||||
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { WorkbasketAccessItemsComponent } from './workbasket-access-items.component';
|
||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
||||
import { AccessItemWorkbasketResource } from '../../../shared/models/access-item-workbasket-resource';
|
||||
import { WorkbasketState } from '../../../shared/store/workbasket-store/workbasket.state';
|
||||
import { EngineConfigurationState } from '../../../shared/store/engine-configuration-store/engine-configuration.state';
|
||||
import { ClassificationCategoriesService } from '../../../shared/services/classification-categories/classification-categories.service';
|
||||
|
||||
describe('WorkbasketAccessItemsComponent', () => {
|
||||
let component: WorkbasketAccessItemsComponent;
|
||||
|
@ -31,52 +28,64 @@ describe('WorkbasketAccessItemsComponent', () => {
|
|||
let notificationsService;
|
||||
let accessIdsService;
|
||||
let formsValidatorService;
|
||||
|
||||
const storeSpy: jasmine.SpyObj<Store> = jasmine.createSpyObj('Store', ['select']);
|
||||
const locationSpy: jasmine.SpyObj<Location> = jasmine.createSpyObj('Location', ['go']);
|
||||
|
||||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
declarations: [WorkbasketAccessItemsComponent],
|
||||
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, ReactiveFormsModule, NgxsModule.forRoot()],
|
||||
imports: [
|
||||
FormsModule, AngularSvgIconModule,
|
||||
HttpClientModule, ReactiveFormsModule,
|
||||
NgxsModule.forRoot([WorkbasketState, EngineConfigurationState])],
|
||||
providers: [WorkbasketService, NotificationService, SavingWorkbasketService, RequestInProgressService,
|
||||
AccessIdsService, FormsValidatorService, { provide: Store, useValue: storeSpy }]
|
||||
AccessIdsService, FormsValidatorService, ClassificationCategoriesService,
|
||||
{ provide: Location, useValue: locationSpy },
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(done => {
|
||||
configureTests(configure).then(testBed => {
|
||||
storeSpy.select.and.callFake(selector => {
|
||||
switch (selector) {
|
||||
case EngineConfigurationSelectors.accessItemsCustomisation:
|
||||
return of({
|
||||
accessId: {
|
||||
lookupField: false
|
||||
},
|
||||
custom1: {}
|
||||
});
|
||||
default:
|
||||
return of();
|
||||
}
|
||||
});
|
||||
const store: Store = testBed.get(Store);
|
||||
store.reset([WorkbasketState, EngineConfigurationState]);
|
||||
|
||||
fixture = testBed.createComponent(WorkbasketAccessItemsComponent);
|
||||
|
||||
component = fixture.componentInstance;
|
||||
component.workbasket = new Workbasket('1');
|
||||
component.workbasket = { type: ICONTYPES.PERSONAL };
|
||||
component.workbasket.type = ICONTYPES.TOPIC;
|
||||
component.workbasket._links = { accessItems: { href: 'someurl' } };
|
||||
|
||||
workbasketService = testBed.get(WorkbasketService);
|
||||
notificationsService = testBed.get(NotificationService);
|
||||
spyOn(workbasketService, 'getWorkBasketAccessItems').and.returnValue(of(new WorkbasketAccessItemsResource(
|
||||
new Array<WorkbasketAccessItems>(
|
||||
new WorkbasketAccessItems('id1', '1', 'accessID1', '', false, false, false, false, false, false, false, false,
|
||||
false, false, false, false, false, false, false, false, false),
|
||||
new WorkbasketAccessItems('id2', '1', 'accessID2')
|
||||
), { self: { href: 'someurl' } }
|
||||
)));
|
||||
spyOn(workbasketService, 'updateWorkBasketAccessItem').and.returnValue(of(true));
|
||||
spyOn(notificationsService, 'showToast').and.returnValue(of(true));
|
||||
const workbasketAccessItemsRepresentation: WorkbasketAccessItemsRepresentation = {
|
||||
accessItems: [{
|
||||
accessId: 'accessID1',
|
||||
workbasketId: 'id1',
|
||||
workbasketKey: '1',
|
||||
accessItemId: '',
|
||||
accessName: '',
|
||||
permRead: false,
|
||||
permOpen: false,
|
||||
permAppend: false,
|
||||
permTransfer: false,
|
||||
permDistribute: false,
|
||||
permCustom1: false,
|
||||
permCustom2: false,
|
||||
permCustom3: false,
|
||||
permCustom4: false,
|
||||
permCustom5: false,
|
||||
permCustom6: false,
|
||||
permCustom7: false,
|
||||
permCustom8: false,
|
||||
permCustom9: false,
|
||||
permCustom10: false,
|
||||
permCustom11: false,
|
||||
permCustom12: false,
|
||||
_links: {},
|
||||
}],
|
||||
_links: { self: { href: 'someurl' } }
|
||||
};
|
||||
debugElement = fixture.debugElement.nativeElement;
|
||||
accessIdsService = testBed.get(AccessIdsService);
|
||||
spyOn(accessIdsService, 'searchForAccessId').and.returnValue(of(['accessID1', 'accessID2']));
|
||||
|
@ -91,44 +100,10 @@ describe('WorkbasketAccessItemsComponent', () => {
|
|||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.body.removeChild(debugElement);
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show two access items if server returns two entries', () => {
|
||||
expect(debugElement.querySelectorAll('#table-access-items > tbody > tr').length).toBe(2);
|
||||
});
|
||||
|
||||
it('should remove an access item if remove button is clicked', () => {
|
||||
expect(debugElement.querySelectorAll('#table-access-items > tbody > tr').length).toBe(2);
|
||||
debugElement.querySelectorAll('#table-access-items > tbody > tr')[0].querySelector('td > button').click();
|
||||
fixture.detectChanges();
|
||||
expect(debugElement.querySelectorAll('#table-access-items > tbody > tr').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should show success alert after saving', async(() => {
|
||||
fixture.detectChanges();
|
||||
spyOn(formsValidatorService, 'validateFormAccess').and.returnValue(Promise.resolve(true));
|
||||
component.onSubmit();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(notificationsService.showToast).toHaveBeenCalledWith(
|
||||
NOTIFICATION_TYPES.SUCCESS_ALERT_7,
|
||||
new Map<string, string>([['workbasketKey', component.workbasket.key]])
|
||||
);
|
||||
});
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
|
||||
it('should keep accessItemsClone length to previous value after clearing the form.', () => {
|
||||
expect(component.accessItemsClone.length).toBe(2);
|
||||
component.remove(1);
|
||||
expect(component.accessItemsClone.length).toBe(1);
|
||||
component.clear();
|
||||
expect(component.accessItemsClone.length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,32 +1,35 @@
|
|||
import { AfterViewInit, Component,
|
||||
import { Component,
|
||||
ElementRef,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnDestroy, QueryList,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
QueryList,
|
||||
SimpleChanges,
|
||||
ViewChildren } from '@angular/core';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { Select } from '@ngxs/store';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { Select, Store } from '@ngxs/store';
|
||||
import { FormArray, FormBuilder, Validators } from '@angular/forms';
|
||||
|
||||
import { Workbasket } from 'app/shared/models/workbasket';
|
||||
import { customFieldCount, WorkbasketAccessItems } from 'app/shared/models/workbasket-access-items';
|
||||
import { WorkbasketAccessItemsResource } from 'app/shared/models/workbasket-access-items-resource';
|
||||
import { WorkbasketAccessItemsRepresentation } from 'app/shared/models/workbasket-access-items-representation';
|
||||
import { ACTION } from 'app/shared/models/action';
|
||||
|
||||
import { SavingInformation,
|
||||
SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
|
||||
import { SavingInformation, SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
|
||||
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
|
||||
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
|
||||
import { highlight } from 'theme/animations/validation.animation';
|
||||
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
|
||||
import { AccessIdDefinition } from 'app/shared/models/access-id';
|
||||
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||
import { AccessItemsCustomisation,
|
||||
CustomField,
|
||||
getCustomFields } from '../../../shared/models/customisation';
|
||||
import { AccessItemsCustomisation, CustomField, getCustomFields } from '../../../shared/models/customisation';
|
||||
import { GetWorkbasketAccessItems,
|
||||
UpdateWorkbasketAccessItems } from '../../../shared/store/workbasket-store/workbasket.actions';
|
||||
import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-administration-workbasket-access-items',
|
||||
|
@ -34,7 +37,7 @@ import { AccessItemsCustomisation,
|
|||
animations: [highlight],
|
||||
styleUrls: ['./workbasket-access-items.component.scss']
|
||||
})
|
||||
export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy, AfterViewInit {
|
||||
export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDestroy {
|
||||
@Input()
|
||||
workbasket: Workbasket;
|
||||
|
||||
|
@ -44,26 +47,31 @@ export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy, Aft
|
|||
@Input()
|
||||
active: string;
|
||||
|
||||
@ViewChildren('htmlInputElement') inputs: QueryList<ElementRef>;
|
||||
@ViewChildren('htmlInputElement')
|
||||
inputs: QueryList<ElementRef>;
|
||||
|
||||
badgeMessage = '';
|
||||
|
||||
@Select(EngineConfigurationSelectors.accessItemsCustomisation) accessItemsCustomization$: Observable<AccessItemsCustomisation>;
|
||||
customFields$: Observable<CustomField[]>;
|
||||
|
||||
accessItemsResource: WorkbasketAccessItemsResource;
|
||||
accessItemsRepresentation: WorkbasketAccessItemsRepresentation;
|
||||
accessItemsClone: Array<WorkbasketAccessItems>;
|
||||
accessItemsResetClone: Array<WorkbasketAccessItems>;
|
||||
requestInProgress = false;
|
||||
accessItemSubscription: Subscription;
|
||||
savingAccessItemsSubscription: Subscription;
|
||||
AccessItemsForm = this.formBuilder.group({
|
||||
accessItemsGroups: this.formBuilder.array([])
|
||||
});
|
||||
|
||||
toggleValidationAccessIdMap = new Map<number, boolean>();
|
||||
private initialized = false;
|
||||
private added = false;
|
||||
initialized = false;
|
||||
added = false;
|
||||
destroy$ = new Subject<void>();
|
||||
|
||||
@Select(EngineConfigurationSelectors.accessItemsCustomisation)
|
||||
accessItemsCustomization$: Observable<AccessItemsCustomisation>;
|
||||
|
||||
@Select(WorkbasketSelectors.workbasketAccessItems)
|
||||
accessItemsRepresentation$: Observable<WorkbasketAccessItemsRepresentation>;
|
||||
|
||||
constructor(
|
||||
private workbasketService: WorkbasketService,
|
||||
|
@ -71,7 +79,8 @@ export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy, Aft
|
|||
private requestInProgressService: RequestInProgressService,
|
||||
private formBuilder: FormBuilder,
|
||||
private formsValidatorService: FormsValidatorService,
|
||||
private notificationsService: NotificationService
|
||||
private notificationsService: NotificationService,
|
||||
private store: Store
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -81,18 +90,33 @@ export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy, Aft
|
|||
|
||||
ngOnInit() {
|
||||
this.customFields$ = this.accessItemsCustomization$.pipe(getCustomFields(customFieldCount));
|
||||
this.accessItemsRepresentation$.subscribe(accessItemsRepresentation => {
|
||||
if (typeof accessItemsRepresentation !== 'undefined') {
|
||||
this.accessItemsRepresentation = accessItemsRepresentation;
|
||||
this.setAccessItemsGroups(accessItemsRepresentation.accessItems);
|
||||
this.accessItemsClone = this.cloneAccessItems(accessItemsRepresentation.accessItems);
|
||||
this.accessItemsResetClone = this.cloneAccessItems(accessItemsRepresentation.accessItems);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.inputs.changes.subscribe(next => {
|
||||
if (this.added) next.last.nativeElement.focus();
|
||||
if (typeof next.last !== 'undefined') {
|
||||
if (this.added) next.last.nativeElement.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (!this.initialized && changes.active && changes.active.currentValue === 'accessItems') {
|
||||
this.init();
|
||||
}
|
||||
if (this.initialized && typeof changes.workbasket !== 'undefined') {
|
||||
if (changes.workbasket.currentValue.workbasketId !== changes.workbasket.previousValue.workbasketId) {
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
if (changes.action) {
|
||||
this.setBadge();
|
||||
}
|
||||
|
@ -103,18 +127,15 @@ export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy, Aft
|
|||
return;
|
||||
}
|
||||
this.requestInProgress = true;
|
||||
this.accessItemSubscription = this.workbasketService.getWorkBasketAccessItems(this.workbasket._links.accessItems.href)
|
||||
.subscribe((accessItemsResource: WorkbasketAccessItemsResource) => {
|
||||
this.accessItemsResource = accessItemsResource;
|
||||
this.setAccessItemsGroups(accessItemsResource.accessItems);
|
||||
this.accessItemsClone = this.cloneAccessItems(accessItemsResource.accessItems);
|
||||
this.accessItemsResetClone = this.cloneAccessItems(accessItemsResource.accessItems);
|
||||
this.requestInProgress = false;
|
||||
});
|
||||
this.savingAccessItemsSubscription = this.savingWorkbaskets.triggeredAccessItemsSaving()
|
||||
this.store.dispatch(new GetWorkbasketAccessItems(this.workbasket._links.accessItems.href)).subscribe(() => {
|
||||
this.requestInProgress = false;
|
||||
});
|
||||
|
||||
this.savingWorkbaskets.triggeredAccessItemsSaving()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((savingInformation: SavingInformation) => {
|
||||
if (this.action === ACTION.COPY) {
|
||||
this.accessItemsResource._links.self.href = savingInformation.url;
|
||||
this.accessItemsRepresentation._links.self.href = savingInformation.url;
|
||||
this.setWorkbasketIdForCopy(savingInformation.workbasketId);
|
||||
this.onSave();
|
||||
}
|
||||
|
@ -131,8 +152,36 @@ export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy, Aft
|
|||
this.AccessItemsForm.setControl('accessItemsGroups', AccessItemsFormArray);
|
||||
}
|
||||
|
||||
createWorkbasketAccessItems(): WorkbasketAccessItems {
|
||||
return {
|
||||
accessItemId: '',
|
||||
workbasketId: '',
|
||||
workbasketKey: '',
|
||||
accessId: '',
|
||||
accessName: '',
|
||||
permRead: false,
|
||||
permOpen: false,
|
||||
permAppend: false,
|
||||
permTransfer: false,
|
||||
permDistribute: false,
|
||||
permCustom1: false,
|
||||
permCustom2: false,
|
||||
permCustom3: false,
|
||||
permCustom4: false,
|
||||
permCustom5: false,
|
||||
permCustom6: false,
|
||||
permCustom7: false,
|
||||
permCustom8: false,
|
||||
permCustom9: false,
|
||||
permCustom10: false,
|
||||
permCustom11: false,
|
||||
permCustom12: false,
|
||||
_links: {},
|
||||
};
|
||||
}
|
||||
|
||||
addAccessItem() {
|
||||
const workbasketAccessItems = new WorkbasketAccessItems();
|
||||
const workbasketAccessItems: WorkbasketAccessItems = this.createWorkbasketAccessItems();
|
||||
workbasketAccessItems.workbasketId = this.workbasket.workbasketId;
|
||||
workbasketAccessItems.permRead = true;
|
||||
const newForm = this.formBuilder.group(workbasketAccessItems);
|
||||
|
@ -170,7 +219,7 @@ export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy, Aft
|
|||
|
||||
checkAll(row: number, value: any) {
|
||||
const checkAll = value.target.checked;
|
||||
const workbasketAccessItemsObj = new WorkbasketAccessItems();
|
||||
const workbasketAccessItemsObj: WorkbasketAccessItems = this.createWorkbasketAccessItems();
|
||||
Object.keys(workbasketAccessItemsObj).forEach(property => {
|
||||
if (property !== 'accessId' && property !== '_links' && property !== 'workbasketId' && property !== 'accessItemId') {
|
||||
this.accessItemsGroups.controls[row].get(property).setValue(checkAll);
|
||||
|
@ -185,19 +234,12 @@ export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy, Aft
|
|||
|
||||
private onSave() {
|
||||
this.requestInProgressService.setRequestInProgress(true);
|
||||
this.workbasketService.updateWorkBasketAccessItem(
|
||||
this.accessItemsResource._links.self.href, this.AccessItemsForm.value.accessItemsGroups
|
||||
)
|
||||
.subscribe(response => {
|
||||
this.accessItemsClone = this.cloneAccessItems(this.AccessItemsForm.value.accessItemsGroups);
|
||||
this.accessItemsResetClone = this.cloneAccessItems(this.AccessItemsForm.value.accessItemsGroups);
|
||||
this.notificationsService.showToast(NOTIFICATION_TYPES.SUCCESS_ALERT_7,
|
||||
new Map<string, string>([['workbasketKey', this.workbasket.key]]));
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
}, error => {
|
||||
this.notificationsService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_2, error);
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
});
|
||||
this.store.dispatch(new UpdateWorkbasketAccessItems(
|
||||
this.accessItemsRepresentation._links.self.href,
|
||||
this.AccessItemsForm.value.accessItemsGroups
|
||||
)).subscribe(() => {
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
});
|
||||
}
|
||||
|
||||
private setBadge() {
|
||||
|
@ -229,12 +271,8 @@ export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy, Aft
|
|||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.accessItemSubscription) {
|
||||
this.accessItemSubscription.unsubscribe();
|
||||
}
|
||||
if (this.savingAccessItemsSubscription) {
|
||||
this.savingAccessItemsSubscription.unsubscribe();
|
||||
}
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,10 @@ import { HttpClientModule } from '@angular/common/http';
|
|||
import { of } from 'rxjs';
|
||||
|
||||
import { Workbasket } from 'app/shared/models/workbasket';
|
||||
import { WorkbasketSummary } from 'app/shared/models/workbasket-summary';
|
||||
import { WorkbasketSummaryResource } from 'app/shared/models/workbasket-summary-resource';
|
||||
import { WorkbasketAccessItemsResource } from 'app/shared/models/workbasket-access-items-resource';
|
||||
import { WorkbasketSummaryRepresentation } from 'app/shared/models/workbasket-summary-representation';
|
||||
import { WorkbasketAccessItemsRepresentation } from 'app/shared/models/workbasket-access-items-representation';
|
||||
import { ICONTYPES } from 'app/shared/models/icon-types';
|
||||
import { Links } from 'app/shared/models/links';
|
||||
import { WorkbasketAccessItems } from 'app/shared/models/workbasket-access-items';
|
||||
|
||||
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
|
||||
import { MasterAndDetailService } from 'app/shared/services/master-and-detail/master-and-detail.service';
|
||||
|
@ -23,6 +21,7 @@ import { configureTests } from 'app/app.test.configuration';
|
|||
|
||||
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
|
||||
import { ImportExportService } from 'app/administration/services/import-export.service';
|
||||
import { NgxsModule } from '@ngxs/store';
|
||||
import { WorkbasketDetailsComponent } from './workbasket-details.component';
|
||||
import { WorkbasketInformationComponent } from '../workbasket-information/workbasket-information.component';
|
||||
import { WorkbasketAccessItemsComponent } from '../workbasket-access-items/workbasket-access-items.component';
|
||||
|
@ -37,6 +36,33 @@ import { NotificationService } from '../../../shared/services/notifications/noti
|
|||
export class DummyDetailComponent {
|
||||
}
|
||||
|
||||
function createWorkbasket(workbasketId?, created?, key?, domain?, type?, modified?, name?, description?,
|
||||
owner?, custom1?, custom2?, custom3?, custom4?, orgLevel1?, orgLevel2?, orgLevel3?, orgLevel4?,
|
||||
_links?: Links, markedForDeletion?: boolean) {
|
||||
const workbasket: Workbasket = {
|
||||
workbasketId,
|
||||
created,
|
||||
key,
|
||||
domain,
|
||||
type,
|
||||
modified,
|
||||
name,
|
||||
description,
|
||||
owner,
|
||||
custom1,
|
||||
custom2,
|
||||
custom3,
|
||||
custom4,
|
||||
orgLevel1,
|
||||
orgLevel2,
|
||||
orgLevel3,
|
||||
orgLevel4,
|
||||
markedForDeletion,
|
||||
_links
|
||||
};
|
||||
return workbasket;
|
||||
}
|
||||
|
||||
describe('WorkbasketDetailsComponent', () => {
|
||||
let component: WorkbasketDetailsComponent;
|
||||
let fixture: ComponentFixture<WorkbasketDetailsComponent>;
|
||||
|
@ -44,9 +70,12 @@ describe('WorkbasketDetailsComponent', () => {
|
|||
let masterAndDetailService;
|
||||
let workbasketService;
|
||||
let router;
|
||||
const workbasket = new Workbasket('1', '', '', '', ICONTYPES.TOPIC, '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
const workbasket = createWorkbasket('1', '', '', '', ICONTYPES.TOPIC, '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
{});
|
||||
|
||||
const workbasketSummaryRepresentation: WorkbasketSummaryRepresentation = { workbaskets: [], _links: {}, page: {} };
|
||||
|
||||
const workbasketAccessItemsRepresentation: WorkbasketAccessItemsRepresentation = { accessItems: [], _links: {} };
|
||||
const routes: Routes = [
|
||||
{ path: '*', component: DummyDetailComponent }
|
||||
];
|
||||
|
@ -55,7 +84,7 @@ describe('WorkbasketDetailsComponent', () => {
|
|||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
imports: [RouterTestingModule.withRoutes(routes), FormsModule, AngularSvgIconModule, HttpClientModule, ReactiveFormsModule,
|
||||
InfiniteScrollModule],
|
||||
InfiniteScrollModule, NgxsModule.forRoot()],
|
||||
declarations: [WorkbasketDetailsComponent, WorkbasketInformationComponent,
|
||||
WorkbasketAccessItemsComponent,
|
||||
WorkbasketDistributionTargetsComponent, WorkbasketDualListComponent, DummyDetailComponent],
|
||||
|
@ -73,27 +102,17 @@ describe('WorkbasketDetailsComponent', () => {
|
|||
workbasketService = TestBed.get(WorkbasketService);
|
||||
spyOn(masterAndDetailService, 'getShowDetail').and.callFake(() => of(true));
|
||||
spyOn(workbasketService, 'getSelectedWorkBasket').and.callFake(() => of('id1'));
|
||||
spyOn(workbasketService, 'getWorkBasketsSummary').and.callFake(() => of(new WorkbasketSummaryResource(
|
||||
new Array<WorkbasketSummary>(
|
||||
new WorkbasketSummary('id1', '', '', '', '', '', '', '', '', '', '', '',
|
||||
false, {})
|
||||
),
|
||||
{}
|
||||
)));
|
||||
spyOn(workbasketService, 'getWorkBasketsSummary').and.callFake(() => of(workbasketSummaryRepresentation));
|
||||
|
||||
spyOn(workbasketService, 'getWorkBasket').and.callFake(() => of(workbasket));
|
||||
spyOn(workbasketService, 'getWorkBasketAccessItems').and.callFake(() => of(new WorkbasketAccessItemsResource(
|
||||
new Array<WorkbasketAccessItems>(), {}
|
||||
)));
|
||||
spyOn(workbasketService, 'getWorkBasketsDistributionTargets').and.callFake(() => of(new WorkbasketSummaryResource(
|
||||
new Array<WorkbasketSummary>(), {}
|
||||
)));
|
||||
spyOn(workbasketService, 'getWorkBasketAccessItems').and.callFake(() => of(workbasketAccessItemsRepresentation));
|
||||
spyOn(workbasketService, 'getWorkBasketsDistributionTargets').and.callFake(() => of(workbasketSummaryRepresentation));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.body.removeChild(debugElement);
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
|
||||
import { Workbasket } from 'app/shared/models/workbasket';
|
||||
import { ACTION } from 'app/shared/models/action';
|
||||
|
@ -9,8 +9,12 @@ import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.ser
|
|||
import { MasterAndDetailService } from 'app/shared/services/master-and-detail/master-and-detail.service';
|
||||
import { DomainService } from 'app/shared/services/domain/domain.service';
|
||||
import { ImportExportService } from 'app/administration/services/import-export.service';
|
||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
||||
import { Select, Store } from '@ngxs/store';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||
import { WorkbasketAndAction, WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors';
|
||||
import { TaskanaDate } from '../../../shared/util/taskana.date';
|
||||
import { ICONTYPES } from '../../../shared/models/icon-types';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-administration-workbasket-details',
|
||||
|
@ -25,58 +29,65 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
|
|||
action: ACTION;
|
||||
tabSelected = 'information';
|
||||
|
||||
private workbasketSelectedSubscription: Subscription;
|
||||
private workbasketSubscription: Subscription;
|
||||
private routeSubscription: Subscription;
|
||||
private masterAndDetailSubscription: Subscription;
|
||||
private permissionSubscription: Subscription;
|
||||
private domainSubscription: Subscription;
|
||||
private importingExportingSubscription: Subscription;
|
||||
@Select(WorkbasketSelectors.selectedWorkbasket)
|
||||
selectedWorkbasket$: Observable<Workbasket>;
|
||||
|
||||
@Select(WorkbasketSelectors.workbasketActiveAction)
|
||||
activeAction$: Observable<ACTION>;
|
||||
|
||||
@Select(WorkbasketSelectors.selectedWorkbasketAndAction)
|
||||
selectedWorkbasketAndAction$: Observable<WorkbasketAndAction>;
|
||||
|
||||
destroy$ = new Subject<void>();
|
||||
|
||||
constructor(private service: WorkbasketService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private masterAndDetailService: MasterAndDetailService,
|
||||
private domainService: DomainService,
|
||||
private errorsService: NotificationService,
|
||||
private importExportService: ImportExportService) { }
|
||||
private importExportService: ImportExportService,
|
||||
private store: Store) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.workbasketSelectedSubscription = this.service.getSelectedWorkBasket().subscribe(workbasketIdSelected => {
|
||||
delete this.workbasket;
|
||||
this.getWorkbasketInformation(workbasketIdSelected);
|
||||
});
|
||||
|
||||
this.routeSubscription = this.route.params.subscribe(params => {
|
||||
const { id } = params;
|
||||
delete this.action;
|
||||
if (id) {
|
||||
if (id.indexOf('new-workbasket') !== -1) {
|
||||
this.selectedWorkbasketAndAction$
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(selectedWorkbasketAndAction => {
|
||||
this.action = selectedWorkbasketAndAction.action;
|
||||
if (this.action === ACTION.CREATE) {
|
||||
this.tabSelected = 'information';
|
||||
this.action = ACTION.CREATE;
|
||||
this.getWorkbasketInformation();
|
||||
} else if (id.indexOf('copy-workbasket') !== -1) {
|
||||
if (!this.selectedId) {
|
||||
this.router.navigate(['./'], { relativeTo: this.route.parent });
|
||||
return;
|
||||
}
|
||||
this.action = ACTION.COPY;
|
||||
delete this.workbasket.key;
|
||||
this.selectedId = undefined;
|
||||
this.initWorkbasket();
|
||||
} else if (this.action === ACTION.COPY) {
|
||||
// delete this.workbasket.key;
|
||||
this.workbasketCopy = this.workbasket;
|
||||
this.getWorkbasketInformation();
|
||||
} else {
|
||||
this.selectWorkbasket(id);
|
||||
} else if (typeof selectedWorkbasketAndAction.selectedWorkbasket !== 'undefined') {
|
||||
this.workbasket = { ...selectedWorkbasketAndAction.selectedWorkbasket };
|
||||
this.getWorkbasketInformation(this.workbasket);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.masterAndDetailSubscription = this.masterAndDetailService.getShowDetail().subscribe(showDetail => {
|
||||
this.showDetail = showDetail;
|
||||
});
|
||||
this.importExportService.getImportingFinished()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(() => {
|
||||
if (this.workbasket) {
|
||||
this.getWorkbasketInformation(this.workbasket);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.importingExportingSubscription = this.importExportService.getImportingFinished().subscribe(() => {
|
||||
if (this.workbasket) { this.getWorkbasketInformation(this.workbasket.workbasketId); }
|
||||
});
|
||||
addDateToWorkbasket(workbasket: Workbasket) {
|
||||
const date = TaskanaDate.getDate();
|
||||
workbasket.created = date;
|
||||
workbasket.modified = date;
|
||||
}
|
||||
|
||||
initWorkbasket() {
|
||||
const emptyWorkbasket: Workbasket = {};
|
||||
emptyWorkbasket.domain = this.domainService.getSelectedDomainValue();
|
||||
emptyWorkbasket.type = ICONTYPES.PERSONAL;
|
||||
this.addDateToWorkbasket(emptyWorkbasket);
|
||||
this.workbasket = emptyWorkbasket;
|
||||
}
|
||||
|
||||
backClicked(): void {
|
||||
|
@ -88,19 +99,19 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
|
|||
this.tabSelected = this.action === ACTION.CREATE ? 'information' : tab;
|
||||
}
|
||||
|
||||
private selectWorkbasket(id: string) {
|
||||
this.selectedId = id;
|
||||
this.service.selectWorkBasket(id);
|
||||
}
|
||||
|
||||
private getWorkbasketInformation(workbasketIdSelected?: string) {
|
||||
private getWorkbasketInformation(selectedWorkbasket?: Workbasket) {
|
||||
let workbasketIdSelected: string;
|
||||
if (selectedWorkbasket) {
|
||||
workbasketIdSelected = selectedWorkbasket.workbasketId;
|
||||
}
|
||||
this.requestInProgress = true;
|
||||
|
||||
if (!workbasketIdSelected && this.action === ACTION.CREATE) { // CREATE
|
||||
this.workbasket = new Workbasket();
|
||||
this.domainSubscription = this.domainService.getSelectedDomain().subscribe(domain => {
|
||||
this.workbasket.domain = domain;
|
||||
});
|
||||
this.workbasket = {};
|
||||
this.domainService.getSelectedDomain()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(domain => {
|
||||
this.workbasket.domain = domain;
|
||||
});
|
||||
this.requestInProgress = false;
|
||||
} else if (!workbasketIdSelected && this.action === ACTION.COPY) { // COPY
|
||||
this.workbasket = { ...this.workbasketCopy };
|
||||
|
@ -108,31 +119,24 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
|
|||
this.requestInProgress = false;
|
||||
}
|
||||
if (workbasketIdSelected) {
|
||||
this.workbasketSubscription = this.service.getWorkBasket(workbasketIdSelected).subscribe(workbasket => {
|
||||
this.workbasket = workbasket;
|
||||
this.requestInProgress = false;
|
||||
this.checkDomainAndRedirect();
|
||||
}, error => {
|
||||
this.errorsService.triggerError(NOTIFICATION_TYPES.FETCH_ERR_4, error);
|
||||
});
|
||||
this.workbasket = selectedWorkbasket;
|
||||
this.requestInProgress = false;
|
||||
this.checkDomainAndRedirect();
|
||||
}
|
||||
}
|
||||
|
||||
private checkDomainAndRedirect() {
|
||||
this.domainSubscription = this.domainService.getSelectedDomain().subscribe(domain => {
|
||||
if (domain !== '' && this.workbasket && this.workbasket.domain !== domain) {
|
||||
this.backClicked();
|
||||
}
|
||||
});
|
||||
this.domainService.getSelectedDomain()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(domain => {
|
||||
if (domain !== '' && this.workbasket && this.workbasket.domain !== domain) {
|
||||
this.backClicked();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.workbasketSelectedSubscription) { this.workbasketSelectedSubscription.unsubscribe(); }
|
||||
if (this.workbasketSubscription) { this.workbasketSubscription.unsubscribe(); }
|
||||
if (this.routeSubscription) { this.routeSubscription.unsubscribe(); }
|
||||
if (this.masterAndDetailSubscription) { this.masterAndDetailSubscription.unsubscribe(); }
|
||||
if (this.permissionSubscription) { this.permissionSubscription.unsubscribe(); }
|
||||
if (this.domainSubscription) { this.domainSubscription.unsubscribe(); }
|
||||
if (this.importingExportingSubscription) { this.importingExportingSubscription.unsubscribe(); }
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,48 +1,76 @@
|
|||
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<div class="pull-right btn-group">
|
||||
<button type="button" (click)="onSave()" [disabled]="action === 'COPY'" data-toggle="tooltip" title="Save" class="btn btn-default btn-primary">
|
||||
<span class="material-icons md-20">save</span>
|
||||
</button>
|
||||
<button type="button" (click)="onClear()" data-toggle="tooltip" title="Undo Changes" class="btn btn-default">
|
||||
<span class="material-icons md-20 blue">undo</span>
|
||||
</button>
|
||||
</div>
|
||||
<h4 class="panel-header">{{workbasket.name}}
|
||||
<span *ngIf="!workbasket.workbasketId" class="badge warning"> {{badgeMessage}}</span>
|
||||
</h4>
|
||||
</div>
|
||||
<div #panelBody class="panel-body">
|
||||
<div class="dual-list list-left col-xs-12 col-md-5-6 container">
|
||||
<taskana-administration-workbasket-dual-list #dualListLeft id="dual-list-Left" header="Available distribution targets" [(distributionTargets)]="distributionTargetsLeft"
|
||||
[distributionTargetsSelected]="distributionTargetsSelected" (performDualListFilter)="performFilter($event)" (scrolling)="onScroll($event)" [side]="side.LEFT"
|
||||
[requestInProgress]="requestInProgressLeft" [loadingItems]="loadingItems" [(allSelected)]="selectAllLeft"></taskana-administration-workbasket-dual-list>
|
||||
<!-- ACTION TOOLBAR-->
|
||||
<div class="panel-heading">
|
||||
<div class="pull-right btn-group">
|
||||
<button type="button" (click)="onSave()" [disabled]="action === 'COPY'" data-toggle="tooltip" title="Save"
|
||||
class="btn btn-default btn-primary">
|
||||
<span class="material-icons md-20">save</span>
|
||||
</button>
|
||||
<button type="button" (click)="onClear()" data-toggle="tooltip" title="Undo Changes"
|
||||
class="btn btn-default">
|
||||
<span class="material-icons md-20 blue">undo</span>
|
||||
</button>
|
||||
</div>
|
||||
<h4 class="panel-header">{{workbasket.name}}
|
||||
<span *ngIf="!workbasket.workbasketId" class="badge warning"> {{badgeMessage}}</span>
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<div class="hidden-xs hidden-sm col-md-1 list-arrows text-center button-margin-top">
|
||||
<button (click)="moveDistributionTargets(side.LEFT)" [disabled]="requestInProgressLeft || requestInProgressRight"
|
||||
class="btn btn-default move-right" data-toggle="tooltip" title="Move to selected distribution targets">
|
||||
<span class="material-icons md-20 blue">chevron_right</span>
|
||||
</button>
|
||||
<button (click)="moveDistributionTargets(side.RIGHT)" [disabled]="requestInProgressLeft || requestInProgressRight"
|
||||
class="btn btn-default move-left" data-toggle="tooltip" title="Move to available distribution targets">
|
||||
<span class="material-icons md-20 blue">chevron_left</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="hidden visible-xs visible-sm col-xs-12 list-arrows text-center">
|
||||
<button (click)="moveDistributionTargets(side.LEFT)" [disabled]="requestInProgressLeft || requestInProgressRight"
|
||||
class="btn btn-default move-down" data-toggle="tooltip" title="Move to selected distribution targets">
|
||||
<span class="material-icons md-20 blue">expand_more</span>
|
||||
</button>
|
||||
<button (click)="moveDistributionTargets(side.RIGHT)" [disabled]="requestInProgressLeft || requestInProgressRight"
|
||||
class="btn btn-default move-up" data-toggle="tooltip" title="Move to available distribution targets">
|
||||
<span class="material-icons md-20 blue">expand_less</span>
|
||||
</button>
|
||||
<!-- DISTRIBUTION TABLE-->
|
||||
<div #panelBody class="panel-body">
|
||||
|
||||
<!-- DISTRIBUTION LEFT LIST -->
|
||||
<div class="dual-list list-left col-xs-12 col-md-5-6 container">
|
||||
<taskana-administration-workbasket-dual-list #dualListLeft id="dual-list-Left" header="Available distribution targets"
|
||||
[distributionTargets]="distributionTargetsLeft"
|
||||
[distributionTargetsSelected]="distributionTargetsSelected"
|
||||
(performDualListFilter)="performFilter($event)"
|
||||
(scrolling)="onScroll($event)"
|
||||
[side]="side.LEFT"
|
||||
[requestInProgress]="requestInProgressLeft"
|
||||
[loadingItems]="loadingItems"
|
||||
[(allSelected)]="selectAllLeft"></taskana-administration-workbasket-dual-list>
|
||||
</div>
|
||||
|
||||
<!-- DISTRIBUTION ACTION BUTTONS -->
|
||||
<div class="hidden-xs hidden-sm col-md-1 list-arrows text-center button-margin-top">
|
||||
<button (click)="moveDistributionTargets(side.LEFT)"
|
||||
[disabled]="requestInProgressLeft || requestInProgressRight"
|
||||
class="btn btn-default move-right" data-toggle="tooltip"
|
||||
title="Move to selected distribution targets">
|
||||
<span class="material-icons md-20 blue">chevron_right</span>
|
||||
</button>
|
||||
<button (click)="moveDistributionTargets(side.RIGHT)"
|
||||
[disabled]="requestInProgressLeft || requestInProgressRight"
|
||||
class="btn btn-default move-left" data-toggle="tooltip"
|
||||
title="Move to available distribution targets">
|
||||
<span class="material-icons md-20 blue">chevron_left</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="hidden visible-xs visible-sm col-xs-12 list-arrows text-center">
|
||||
<button (click)="moveDistributionTargets(side.LEFT)"
|
||||
[disabled]="requestInProgressLeft || requestInProgressRight"
|
||||
class="btn btn-default move-down" data-toggle="tooltip"
|
||||
title="Move to selected distribution targets">
|
||||
<span class="material-icons md-20 blue">expand_more</span>
|
||||
</button>
|
||||
<button (click)="moveDistributionTargets(side.RIGHT)"
|
||||
[disabled]="requestInProgressLeft || requestInProgressRight"
|
||||
class="btn btn-default move-up" data-toggle="tooltip"
|
||||
title="Move to available distribution targets">
|
||||
<span class="material-icons md-20 blue">expand_less</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- DISTRIBUTION RIGHT LIST -->
|
||||
<div class="dual-list list-right col-xs-12 col-md-5-6 container">
|
||||
<taskana-administration-workbasket-dual-list #dualListRight id="dual-list-right" header="Selected distribution targets"
|
||||
[distributionTargets]="distributionTargetsRight"
|
||||
[distributionTargetsSelected]="distributionTargetsSelected"
|
||||
(performDualListFilter)="performFilter($event)"
|
||||
[requestInProgress]="requestInProgressRight"
|
||||
[side]="side.RIGHT"
|
||||
[(allSelected)]="selectAllRight"></taskana-administration-workbasket-dual-list>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dual-list list-right col-xs-12 col-md-5-6 container">
|
||||
<taskana-administration-workbasket-dual-list #dualListRight id="dual-list-right" header="Selected distribution targets" [(distributionTargets)]="distributionTargetsRight"
|
||||
[distributionTargetsSelected]="distributionTargetsSelected" (performDualListFilter)="performFilter($event)" [requestInProgress]="requestInProgressRight"
|
||||
[side]="side.RIGHT" [(allSelected)]="selectAllRight"></taskana-administration-workbasket-dual-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,60 +4,116 @@ import { of } from 'rxjs';
|
|||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
import { WorkbasketSummaryResource } from 'app/shared/models/workbasket-summary-resource';
|
||||
import { WorkbasketSummaryRepresentation } from 'app/shared/models/workbasket-summary-representation';
|
||||
import { WorkbasketSummary } from 'app/shared/models/workbasket-summary';
|
||||
import { ICONTYPES } from 'app/shared/models/icon-types';
|
||||
import { Links } from 'app/shared/models/links';
|
||||
import { Filter } from 'app/shared/models/filter';
|
||||
import { Workbasket } from 'app/shared/models/workbasket';
|
||||
import { WorkbasketDistributionTargetsResource } from 'app/shared/models/workbasket-distribution-targets-resource';
|
||||
import { WorkbasketDistributionTargets } from 'app/shared/models/workbasket-distribution-targets';
|
||||
|
||||
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
|
||||
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
|
||||
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
|
||||
|
||||
import { LinksWorkbasketSummary } from 'app/shared/models/links-workbasket-summary';
|
||||
import { configureTests } from 'app/app.test.configuration';
|
||||
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
|
||||
import { Side,
|
||||
WorkbasketDistributionTargetsComponent } from './workbasket-distribution-targets.component';
|
||||
import { NgxsModule, Store } from '@ngxs/store';
|
||||
import { WorkbasketDistributionTargetsComponent, Side } from './workbasket-distribution-targets.component';
|
||||
import { WorkbasketDualListComponent } from '../workbasket-dual-list/workbasket-dual-list.component';
|
||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||
import { NotificationService } from '../../../shared/services/notifications/notification.service'; import { ClassificationSelectors } from '../../../shared/store/classification-store/classification.selectors';
|
||||
import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors';
|
||||
|
||||
describe('WorkbasketDistributionTargetsComponent', () => {
|
||||
let component: WorkbasketDistributionTargetsComponent;
|
||||
let fixture: ComponentFixture<WorkbasketDistributionTargetsComponent>;
|
||||
let workbasketService;
|
||||
const workbasket = new Workbasket('1', '', '', '', ICONTYPES.TOPIC, '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
{ distributionTargets: { href: 'someurl' } });
|
||||
const workbasket = createWorkbasket('1', '', '', '', ICONTYPES.TOPIC, '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
{});
|
||||
function createWorkbasket(workbasketId?, created?, key?, domain?, type?, modified?, name?, description?,
|
||||
owner?, custom1?, custom2?, custom3?, custom4?, orgLevel1?, orgLevel2?, orgLevel3?, orgLevel4?,
|
||||
_links?: Links, markedForDeletion?: boolean): Workbasket {
|
||||
return {
|
||||
workbasketId,
|
||||
created,
|
||||
key,
|
||||
domain,
|
||||
type,
|
||||
modified,
|
||||
name,
|
||||
description,
|
||||
owner,
|
||||
custom1,
|
||||
custom2,
|
||||
custom3,
|
||||
custom4,
|
||||
orgLevel1,
|
||||
orgLevel2,
|
||||
orgLevel3,
|
||||
orgLevel4,
|
||||
markedForDeletion,
|
||||
_links
|
||||
};
|
||||
}
|
||||
|
||||
function createWorkbasketSummary(workbasketId, key, name, domain, type, description, owner, custom1, custom2, custom3, custom4) {
|
||||
const workbasketSummary: WorkbasketSummary = {
|
||||
workbasketId,
|
||||
key,
|
||||
name,
|
||||
domain,
|
||||
type,
|
||||
description,
|
||||
owner,
|
||||
custom1,
|
||||
custom2,
|
||||
custom3,
|
||||
custom4
|
||||
};
|
||||
return workbasketSummary;
|
||||
}
|
||||
const workbasketSummaryResource: WorkbasketSummaryRepresentation = {
|
||||
workbaskets: [
|
||||
createWorkbasketSummary('1', 'key1', 'NAME1', '', 'PERSONAL',
|
||||
'description 1', 'owner1', '', '', '', ''),
|
||||
createWorkbasketSummary('2', 'key2', 'NAME2', '', 'PERSONAL',
|
||||
'description 2', 'owner2', '', '', '', ''),
|
||||
],
|
||||
_links: new LinksWorkbasketSummary({ href: 'url' }),
|
||||
page: {}
|
||||
};
|
||||
|
||||
const workbasketDistributionTargets: WorkbasketDistributionTargets = {
|
||||
distributionTargets: [createWorkbasketSummary('id2', '', '', '', '', '', '', '', '', '', '')],
|
||||
_links: {}
|
||||
};
|
||||
|
||||
const storeSpy: jasmine.SpyObj<Store> = jasmine.createSpyObj('Store', ['select', 'dispatch']);
|
||||
|
||||
beforeEach(done => {
|
||||
const configure = testBed => {
|
||||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
imports: [AngularSvgIconModule, HttpClientModule, InfiniteScrollModule],
|
||||
imports: [AngularSvgIconModule, HttpClientModule, InfiniteScrollModule, NgxsModule.forRoot()],
|
||||
declarations: [WorkbasketDistributionTargetsComponent, WorkbasketDualListComponent],
|
||||
providers: [WorkbasketService, NotificationService, SavingWorkbasketService, RequestInProgressService,
|
||||
]
|
||||
{ provide: Store, useValue: storeSpy }]
|
||||
});
|
||||
};
|
||||
configureTests(configure).then(testBed => {
|
||||
fixture = testBed.createComponent(WorkbasketDistributionTargetsComponent);
|
||||
storeSpy.select.and.callFake(selector => {
|
||||
switch (selector) {
|
||||
case WorkbasketSelectors.workbasketDistributionTargets:
|
||||
return of(['distributionTargets', '_links']);
|
||||
default:
|
||||
return of();
|
||||
}
|
||||
});
|
||||
fixture = TestBed.createComponent(WorkbasketDistributionTargetsComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.workbasket = workbasket;
|
||||
workbasketService = testBed.get(WorkbasketService);
|
||||
spyOn(workbasketService, 'getWorkBasketsSummary').and.callFake(() => of(new WorkbasketSummaryResource(
|
||||
new Array<WorkbasketSummary>(
|
||||
new WorkbasketSummary('id1', '', '', '', '', '', '', '', '', '', '', '', false, {}),
|
||||
new WorkbasketSummary('id2', '', '', '', '', '', '', '', '', '', '', '', false, {}),
|
||||
new WorkbasketSummary('id3', '', '', '', '', '', '', '', '', '', '', '', false, {})
|
||||
),
|
||||
{}
|
||||
)));
|
||||
spyOn(workbasketService, 'getWorkBasketsDistributionTargets').and.callFake(() => of(new WorkbasketDistributionTargetsResource(
|
||||
new Array<WorkbasketSummary>(
|
||||
new WorkbasketSummary('id2', '', '', '', '', '', '', '', '', '', '', '', false, {})
|
||||
),
|
||||
{ self: { href: 'someurl' } }
|
||||
)));
|
||||
workbasketService = TestBed.get(WorkbasketService);
|
||||
spyOn(workbasketService, 'getWorkBasketsSummary').and.callFake(() => of(workbasketSummaryResource));
|
||||
spyOn(workbasketService, 'getWorkBasketsDistributionTargets').and.callFake(() => of(workbasketDistributionTargets));
|
||||
component.ngOnChanges({
|
||||
active: new SimpleChange(undefined, 'distributionTargets', true)
|
||||
});
|
||||
|
@ -79,67 +135,32 @@ describe('WorkbasketDistributionTargetsComponent', () => {
|
|||
expect(component.distributionTargetsRight).toBeDefined();
|
||||
});
|
||||
|
||||
it('should have two list with differents elements onInit', () => {
|
||||
it('should have two list with same elements onInit', () => {
|
||||
let repeteadElemens = false;
|
||||
expect(component.distributionTargetsLeft.length).toBe(2);
|
||||
expect(component.distributionTargetsRight.length).toBe(1);
|
||||
expect(component.distributionTargetsRight.length).toBe(2);
|
||||
component.distributionTargetsLeft.forEach(leftElement => {
|
||||
component.distributionTargetsRight.forEach(rightElement => {
|
||||
if (leftElement.workbasketId === rightElement.workbasketId) {
|
||||
repeteadElemens = true;
|
||||
}
|
||||
if (leftElement.workbasketId === rightElement.workbasketId) { repeteadElemens = true; }
|
||||
});
|
||||
});
|
||||
expect(repeteadElemens).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should filter left list and keep selected elements as selected', () => {
|
||||
component.performFilter({
|
||||
filterBy: new Filter({
|
||||
name: 'someName', owner: 'someOwner', description: 'someDescription', key: 'someKey'
|
||||
}),
|
||||
side: Side.LEFT
|
||||
});
|
||||
component.distributionTargetsLeft = new Array<WorkbasketSummary>(
|
||||
new WorkbasketSummary('id1', '', '', '', '', '', '', '', '', '', '', '', false, {})
|
||||
);
|
||||
expect(component.distributionTargetsLeft.length).toBe(1);
|
||||
expect(component.distributionTargetsLeft[0].workbasketId).toBe('id1');
|
||||
expect(component.distributionTargetsRight.length).toBe(1);
|
||||
expect(component.distributionTargetsRight[0].workbasketId).toBe('id2');
|
||||
expect(repeteadElemens).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should reset distribution target and distribution target selected on reset', () => {
|
||||
component.distributionTargetsLeft.push(
|
||||
new WorkbasketSummary('id4', '', '', '', '', '', '', '', '', '', '', '', false, {})
|
||||
createWorkbasketSummary('id4', '', '', '', '', '', '', '', '', '', '')
|
||||
);
|
||||
component.distributionTargetsRight.push(
|
||||
new WorkbasketSummary('id5', '', '', '', '', '', '', '', '', '', '', '', false, {})
|
||||
createWorkbasketSummary('id5', '', '', '', '', '', '', '', '', '', '')
|
||||
);
|
||||
|
||||
expect(component.distributionTargetsLeft.length).toBe(3);
|
||||
expect(component.distributionTargetsRight.length).toBe(2);
|
||||
expect(component.distributionTargetsRight.length).toBe(3);
|
||||
|
||||
component.onClear();
|
||||
fixture.detectChanges();
|
||||
expect(component.distributionTargetsLeft.length).toBe(2);
|
||||
expect(component.distributionTargetsRight.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should save distribution targets selected and update Clone objects.', () => {
|
||||
expect(component.distributionTargetsSelected.length).toBe(1);
|
||||
expect(component.distributionTargetsSelectedClone.length).toBe(1);
|
||||
spyOn(workbasketService, 'updateWorkBasketsDistributionTargets').and.callFake(() => of(new WorkbasketDistributionTargetsResource(
|
||||
new Array<WorkbasketSummary>(
|
||||
new WorkbasketSummary('id2', '', '', '', '', '', '', '', '', '', '', '', false, {}),
|
||||
new WorkbasketSummary('id1', '', '', '', '', '', '', '', '', '', '', '', false, {})
|
||||
),
|
||||
{}
|
||||
)));
|
||||
component.onSave();
|
||||
fixture.detectChanges();
|
||||
expect(component.distributionTargetsSelected.length).toBe(2);
|
||||
expect(component.distributionTargetsSelectedClone.length).toBe(2);
|
||||
expect(component.distributionTargetsLeft.length).toBe(1);
|
||||
expect(component.distributionTargetsRight.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,15 +2,15 @@ import { Component,
|
|||
ElementRef,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnDestroy,
|
||||
OnDestroy, OnInit,
|
||||
SimpleChanges,
|
||||
ViewChild } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
|
||||
import { Workbasket } from 'app/shared/models/workbasket';
|
||||
import { WorkbasketSummary } from 'app/shared/models/workbasket-summary';
|
||||
import { WorkbasketSummaryResource } from 'app/shared/models/workbasket-summary-resource';
|
||||
import { WorkbasketDistributionTargetsResource } from 'app/shared/models/workbasket-distribution-targets-resource';
|
||||
import { WorkbasketSummaryRepresentation } from 'app/shared/models/workbasket-summary-representation';
|
||||
import { WorkbasketDistributionTargets } from 'app/shared/models/workbasket-distribution-targets';
|
||||
import { ACTION } from 'app/shared/models/action';
|
||||
|
||||
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
|
||||
|
@ -20,8 +20,14 @@ import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
|
|||
import { Page } from 'app/shared/models/page';
|
||||
import { OrientationService } from 'app/shared/services/orientation/orientation.service';
|
||||
import { Orientation } from 'app/shared/models/orientation';
|
||||
import { Select, Store } from '@ngxs/store';
|
||||
import { take, takeUntil } from 'rxjs/operators';
|
||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||
import { GetWorkbasketDistributionTargets,
|
||||
GetWorkbasketsSummary, UpdateWorkbasketDistributionTargets } from '../../../shared/store/workbasket-store/workbasket.actions';
|
||||
import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors';
|
||||
import { WorkbasketStateModel } from '../../../shared/store/workbasket-store/workbasket.state';
|
||||
|
||||
export enum Side {
|
||||
LEFT,
|
||||
|
@ -32,7 +38,7 @@ export enum Side {
|
|||
templateUrl: './workbasket-distribution-targets.component.html',
|
||||
styleUrls: ['./workbasket-distribution-targets.component.scss']
|
||||
})
|
||||
export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDestroy {
|
||||
export class WorkbasketDistributionTargetsComponent implements OnInit, OnChanges, OnDestroy {
|
||||
@Input()
|
||||
workbasket: Workbasket;
|
||||
|
||||
|
@ -44,15 +50,9 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
|
|||
|
||||
badgeMessage = '';
|
||||
|
||||
distributionTargetsSubscription: Subscription;
|
||||
workbasketSubscription: Subscription;
|
||||
workbasketFilterSubscription: Subscription;
|
||||
savingDistributionTargetsSubscription: Subscription;
|
||||
orientationSubscription: Subscription;
|
||||
|
||||
distributionTargetsSelectedResource: WorkbasketDistributionTargetsResource;
|
||||
distributionTargetsLeft: Array<WorkbasketSummary>;
|
||||
distributionTargetsRight: Array<WorkbasketSummary>;
|
||||
distributionTargetsSelectedResource: WorkbasketDistributionTargets;
|
||||
distributionTargetsLeft: Array<WorkbasketSummary> = [];
|
||||
distributionTargetsRight: Array<WorkbasketSummary> = [];
|
||||
distributionTargetsSelected: Array<WorkbasketSummary>;
|
||||
distributionTargetsClone: Array<WorkbasketSummary>;
|
||||
distributionTargetsSelectedClone: Array<WorkbasketSummary>;
|
||||
|
@ -60,7 +60,6 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
|
|||
requestInProgressLeft = false;
|
||||
requestInProgressRight = false;
|
||||
loadingItems = false;
|
||||
modalErrorMessage: string;
|
||||
side = Side;
|
||||
private initialized = false;
|
||||
page: Page;
|
||||
|
@ -69,17 +68,36 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
|
|||
selectAllRight = false;
|
||||
|
||||
@ViewChild('panelBody', { static: false })
|
||||
private panelBody: ElementRef;
|
||||
panelBody: ElementRef;
|
||||
|
||||
@Select(WorkbasketSelectors.workbasketDistributionTargets)
|
||||
workbasketDistributionTargets$: Observable<WorkbasketDistributionTargets>;
|
||||
|
||||
destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
private workbasketService: WorkbasketService,
|
||||
private savingWorkbaskets: SavingWorkbasketService,
|
||||
private requestInProgressService: RequestInProgressService,
|
||||
private orientationService: OrientationService,
|
||||
private notificationsService: NotificationService
|
||||
private notificationsService: NotificationService,
|
||||
private store: Store
|
||||
) { }
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
ngOnInit() {
|
||||
this.workbasketDistributionTargets$.subscribe(workbasketDistributionTargets => {
|
||||
if (typeof workbasketDistributionTargets !== 'undefined') {
|
||||
this.distributionTargetsSelectedResource = { ...workbasketDistributionTargets };
|
||||
this.distributionTargetsSelected = this.distributionTargetsSelectedResource.distributionTargets;
|
||||
this.distributionTargetsSelectedClone = { ...this.distributionTargetsSelected };
|
||||
TaskanaQueryParameters.page = 1;
|
||||
this.calculateNumberItemsList();
|
||||
this.getWorkbaskets();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (!this.initialized && changes.active && changes.active.currentValue === 'distributionTargets') {
|
||||
this.init();
|
||||
}
|
||||
|
@ -95,96 +113,15 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
|
|||
}
|
||||
}
|
||||
|
||||
moveDistributionTargets(side: number) {
|
||||
if (side === Side.LEFT) {
|
||||
const itemsLeft = this.distributionTargetsLeft.length;
|
||||
const itemsRight = this.distributionTargetsRight.length;
|
||||
const itemsSelected = this.getSelectedItems(this.distributionTargetsLeft);
|
||||
this.distributionTargetsSelected = this.distributionTargetsSelected.concat(itemsSelected);
|
||||
this.distributionTargetsRight = this.distributionTargetsRight.concat(itemsSelected);
|
||||
if (((itemsLeft - itemsSelected.length) <= TaskanaQueryParameters.pageSize) && ((itemsLeft + itemsRight) < this.page.totalElements)) {
|
||||
this.getNextPage(side);
|
||||
}
|
||||
} else {
|
||||
const itemsSelected = this.getSelectedItems(this.distributionTargetsRight);
|
||||
this.distributionTargetsSelected = this.removeSelectedItems(this.distributionTargetsSelected, itemsSelected);
|
||||
this.distributionTargetsRight = this.removeSelectedItems(this.distributionTargetsRight, itemsSelected);
|
||||
this.distributionTargetsLeft = this.distributionTargetsLeft.concat(itemsSelected);
|
||||
}
|
||||
|
||||
this.uncheckSelectAll(side);
|
||||
}
|
||||
|
||||
onSave() {
|
||||
this.requestInProgressService.setRequestInProgress(true);
|
||||
this.workbasketService.updateWorkBasketsDistributionTargets(
|
||||
this.distributionTargetsSelectedResource._links.self.href, this.getSeletedIds()
|
||||
).subscribe(response => {
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
this.distributionTargetsSelected = response.distributionTargets;
|
||||
this.distributionTargetsSelectedClone = Object.assign([], this.distributionTargetsSelected);
|
||||
this.distributionTargetsClone = Object.assign([], this.distributionTargetsLeft);
|
||||
this.notificationsService.showToast(
|
||||
NOTIFICATION_TYPES.SUCCESS_ALERT_8,
|
||||
new Map<string, string>([['workbasketName', this.workbasket.name]])
|
||||
);
|
||||
return true;
|
||||
},
|
||||
error => {
|
||||
this.notificationsService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_3, error);
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
onClear() {
|
||||
this.notificationsService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
|
||||
this.distributionTargetsLeft = Object.assign([], this.distributionTargetsClone);
|
||||
this.distributionTargetsRight = Object.assign([], this.distributionTargetsSelectedClone);
|
||||
this.distributionTargetsSelected = Object.assign([], this.distributionTargetsSelectedClone);
|
||||
}
|
||||
|
||||
performFilter(dualListFilter: any) {
|
||||
this.fillDistributionTargets(dualListFilter.side, undefined);
|
||||
this.onRequest(false, dualListFilter.side);
|
||||
this.workbasketFilterSubscription = this.workbasketService.getWorkBasketsSummary(true, '', '', '',
|
||||
dualListFilter.filterBy.filterParams.name, dualListFilter.filterBy.filterParams.description, '',
|
||||
dualListFilter.filterBy.filterParams.owner, dualListFilter.filterBy.filterParams.type, '',
|
||||
dualListFilter.filterBy.filterParams.key, '', true)
|
||||
.subscribe(resultList => {
|
||||
this.fillDistributionTargets(dualListFilter.side, (resultList.workbaskets));
|
||||
this.onRequest(true, dualListFilter.side);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.distributionTargetsSubscription) { this.distributionTargetsSubscription.unsubscribe(); }
|
||||
if (this.workbasketSubscription) { this.workbasketSubscription.unsubscribe(); }
|
||||
if (this.workbasketFilterSubscription) { this.workbasketFilterSubscription.unsubscribe(); }
|
||||
if (this.savingDistributionTargetsSubscription) { this.savingDistributionTargetsSubscription.unsubscribe(); }
|
||||
if (this.orientationSubscription) { this.orientationSubscription.unsubscribe(); }
|
||||
}
|
||||
|
||||
private init() {
|
||||
init() {
|
||||
this.onRequest();
|
||||
if (!this.workbasket._links.distributionTargets) {
|
||||
return;
|
||||
}
|
||||
this.distributionTargetsSubscription = this.workbasketService.getWorkBasketsDistributionTargets(
|
||||
this.workbasket._links.distributionTargets.href
|
||||
).subscribe(
|
||||
(distributionTargetsSelectedResource: WorkbasketDistributionTargetsResource) => {
|
||||
this.distributionTargetsSelectedResource = distributionTargetsSelectedResource;
|
||||
this.distributionTargetsSelected = distributionTargetsSelectedResource.distributionTargets;
|
||||
this.distributionTargetsSelectedClone = Object.assign([], this.distributionTargetsSelected);
|
||||
TaskanaQueryParameters.page = 1;
|
||||
this.calculateNumberItemsList();
|
||||
this.getWorkbaskets();
|
||||
}
|
||||
);
|
||||
|
||||
this.savingDistributionTargetsSubscription = this.savingWorkbaskets.triggeredDistributionTargetsSaving()
|
||||
this.store.dispatch(new GetWorkbasketDistributionTargets(this.workbasket._links.distributionTargets.href));
|
||||
this.savingWorkbaskets.triggeredDistributionTargetsSaving()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((savingInformation: SavingInformation) => {
|
||||
if (this.action === ACTION.COPY) {
|
||||
this.distributionTargetsSelectedResource._links.self.href = savingInformation.url;
|
||||
|
@ -192,47 +129,25 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
|
|||
}
|
||||
});
|
||||
|
||||
this.orientationSubscription = this.orientationService.getOrientation().subscribe((orientation: Orientation) => {
|
||||
this.calculateNumberItemsList();
|
||||
this.getWorkbaskets();
|
||||
});
|
||||
this.orientationService.getOrientation()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(() => {
|
||||
this.calculateNumberItemsList();
|
||||
this.getWorkbaskets();
|
||||
});
|
||||
}
|
||||
|
||||
private calculateNumberItemsList() {
|
||||
if (this.panelBody) {
|
||||
const cardHeight = 72;
|
||||
const unusedHeight = 100;
|
||||
this.cards = this.orientationService.calculateNumberItemsList(
|
||||
this.panelBody.nativeElement.offsetHeight, cardHeight, unusedHeight, true
|
||||
) + 1; // TODO: warum +1
|
||||
}
|
||||
}
|
||||
|
||||
private fillDistributionTargets(side: Side, workbaskets: WorkbasketSummary[]) {
|
||||
this.distributionTargetsLeft = side === Side.LEFT ? workbaskets : this.distributionTargetsLeft;
|
||||
this.distributionTargetsRight = side === Side.RIGHT ? workbaskets : this.distributionTargetsRight;
|
||||
}
|
||||
|
||||
private getNextPage(side: Side) {
|
||||
TaskanaQueryParameters.page += 1;
|
||||
this.getWorkbaskets(side);
|
||||
}
|
||||
|
||||
private getWorkbaskets(side?: Side) {
|
||||
if (!this.distributionTargetsLeft) {
|
||||
this.distributionTargetsLeft = [];
|
||||
}
|
||||
if (!this.distributionTargetsRight) {
|
||||
this.distributionTargetsRight = [];
|
||||
}
|
||||
getWorkbaskets(side?: Side) {
|
||||
if (this.distributionTargetsSelected && !this.initialized) {
|
||||
this.initialized = true;
|
||||
TaskanaQueryParameters.pageSize = this.cards + this.distributionTargetsSelected.length;
|
||||
}
|
||||
|
||||
this.workbasketSubscription = this.workbasketService.getWorkBasketsSummary(true)
|
||||
// TODO: Implement this into NGXS
|
||||
this.workbasketService.getWorkBasketsSummary(true)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(
|
||||
(distributionTargetsAvailable: WorkbasketSummaryResource) => {
|
||||
(distributionTargetsAvailable: WorkbasketSummaryRepresentation) => {
|
||||
if (TaskanaQueryParameters.page === 1) {
|
||||
this.distributionTargetsLeft = [];
|
||||
this.page = distributionTargetsAvailable.page;
|
||||
|
@ -251,17 +166,121 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
|
|||
);
|
||||
}
|
||||
|
||||
private setBadge() {
|
||||
performFilter(dualListFilter: any) {
|
||||
this.fillDistributionTargets(dualListFilter.side, undefined);
|
||||
this.onRequest(false, dualListFilter.side);
|
||||
this.store.dispatch(new GetWorkbasketsSummary(true, '', '', '',
|
||||
dualListFilter.filterBy.filterParams.name, dualListFilter.filterBy.filterParams.description, '',
|
||||
dualListFilter.filterBy.filterParams.owner, dualListFilter.filterBy.filterParams.type, '',
|
||||
dualListFilter.filterBy.filterParams.key, '', true)).subscribe((state: WorkbasketStateModel) => {
|
||||
this.fillDistributionTargets(dualListFilter.side, state.paginatedWorkbasketsSummary.workbaskets);
|
||||
this.onRequest(true, dualListFilter.side);
|
||||
});
|
||||
}
|
||||
|
||||
onSave() {
|
||||
this.requestInProgressService.setRequestInProgress(true);
|
||||
this.store.dispatch(new UpdateWorkbasketDistributionTargets(
|
||||
this.distributionTargetsSelectedResource._links.self.href,
|
||||
this.getSeletedIds()
|
||||
)).subscribe(() => {
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
return true;
|
||||
}, error => {
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
return false;
|
||||
});
|
||||
/* TODO: OLD IMPLEMENTATION, KEPT HERE FOR REFERENCE
|
||||
this.workbasketService.updateWorkBasketsDistributionTargets(
|
||||
this.distributionTargetsSelectedResource._links.self.href, this.getSeletedIds()
|
||||
).subscribe(response => {
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
this.distributionTargetsSelected = response.distributionTargets;
|
||||
this.distributionTargetsSelectedClone = Object.assign([], this.distributionTargetsSelected);
|
||||
this.distributionTargetsClone = Object.assign([], this.distributionTargetsLeft);
|
||||
this.notificationsService.showToast(
|
||||
NOTIFICATION_TYPES.SUCCESS_ALERT_8,
|
||||
new Map<string, string>([['workbasketName', this.workbasket.name]])
|
||||
);
|
||||
return true;
|
||||
},
|
||||
error => {
|
||||
this.notificationsService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_3, error);
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
return false;
|
||||
});
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
moveDistributionTargets(side: number) {
|
||||
if (side === Side.LEFT) {
|
||||
const itemsLeft = this.distributionTargetsLeft.length;
|
||||
const itemsRight = this.distributionTargetsRight.length;
|
||||
const itemsSelected = this.getSelectedItems(this.distributionTargetsLeft);
|
||||
this.distributionTargetsSelected = [...this.distributionTargetsSelected, ...itemsSelected];
|
||||
this.distributionTargetsRight = this.distributionTargetsRight.concat(itemsSelected);
|
||||
if (((itemsLeft - itemsSelected.length) <= TaskanaQueryParameters.pageSize) && ((itemsLeft + itemsRight) < this.page.totalElements)) {
|
||||
this.getNextPage(side);
|
||||
}
|
||||
this.unselectItems(this.distributionTargetsSelected);
|
||||
} else {
|
||||
const itemsSelected = this.getSelectedItems(this.distributionTargetsRight);
|
||||
this.distributionTargetsSelected = this.removeSelectedItems(this.distributionTargetsSelected, itemsSelected);
|
||||
this.distributionTargetsRight = this.removeSelectedItems(this.distributionTargetsRight, itemsSelected);
|
||||
this.distributionTargetsLeft = this.distributionTargetsLeft.concat(itemsSelected);
|
||||
this.unselectItems(itemsSelected);
|
||||
}
|
||||
}
|
||||
|
||||
onClear() {
|
||||
this.notificationsService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
|
||||
this.distributionTargetsLeft = Object.assign([], this.distributionTargetsClone);
|
||||
this.distributionTargetsRight = Object.assign([], this.distributionTargetsSelectedClone);
|
||||
this.distributionTargetsSelected = Object.assign([], this.distributionTargetsSelectedClone);
|
||||
}
|
||||
|
||||
calculateNumberItemsList() {
|
||||
if (this.panelBody) {
|
||||
const cardHeight = 72;
|
||||
const unusedHeight = 100;
|
||||
this.cards = this.orientationService.calculateNumberItemsList(
|
||||
this.panelBody.nativeElement.offsetHeight, cardHeight, unusedHeight, true
|
||||
) + 1; // TODO: warum +1
|
||||
}
|
||||
}
|
||||
|
||||
fillDistributionTargets(side: Side, workbaskets: WorkbasketSummary[]) {
|
||||
this.distributionTargetsLeft = side === Side.LEFT ? workbaskets : this.distributionTargetsLeft;
|
||||
this.distributionTargetsRight = side === Side.RIGHT ? workbaskets : this.distributionTargetsRight;
|
||||
}
|
||||
|
||||
getNextPage(side: Side) {
|
||||
TaskanaQueryParameters.page += 1;
|
||||
this.getWorkbaskets(side);
|
||||
}
|
||||
|
||||
setBadge() {
|
||||
if (this.action === ACTION.COPY) {
|
||||
this.badgeMessage = `Copying workbasket: ${this.workbasket.key}`;
|
||||
}
|
||||
}
|
||||
|
||||
private getSelectedItems(originList: any): Array<any> {
|
||||
getSelectedItems(originList: any): Array<any> {
|
||||
return originList.filter((item: any) => (item.selected === true));
|
||||
}
|
||||
|
||||
private removeSelectedItems(originList: any, selectedItemList) {
|
||||
unselectItems(originList: any): Array<any> {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const item of originList) {
|
||||
if (item.selected && item.selected === true) {
|
||||
item.selected = false;
|
||||
}
|
||||
}
|
||||
return originList;
|
||||
}
|
||||
|
||||
removeSelectedItems(originList: any, selectedItemList) {
|
||||
for (let index = originList.length - 1; index >= 0; index--) {
|
||||
if (selectedItemList.some(itemToRemove => (originList[index].workbasketId === itemToRemove.workbasketId))) {
|
||||
originList.splice(index, 1);
|
||||
|
@ -270,7 +289,7 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
|
|||
return originList;
|
||||
}
|
||||
|
||||
private onRequest(finished: boolean = false, side?: Side) {
|
||||
onRequest(finished: boolean = false, side?: Side) {
|
||||
this.loadingItems = false;
|
||||
const inProgress = !finished;
|
||||
switch (side) {
|
||||
|
@ -284,7 +303,7 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
|
|||
}
|
||||
}
|
||||
|
||||
private getSeletedIds(): Array<string> {
|
||||
getSeletedIds(): Array<string> {
|
||||
const distributionTargetsSelelected: Array<string> = [];
|
||||
this.distributionTargetsSelected.forEach(item => {
|
||||
distributionTargetsSelelected.push(item.workbasketId);
|
||||
|
@ -296,4 +315,9 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
|
|||
if (side === Side.LEFT && this.selectAllLeft) { this.selectAllLeft = false; }
|
||||
if (side === Side.RIGHT && this.selectAllRight) { this.selectAllRight = false; }
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,44 +1,57 @@
|
|||
<div id="dual-list-Left" class="dual-list list-left col-xs-12 col-md-5-6 container">
|
||||
<div class="row header">
|
||||
<div class="col-xs-2">
|
||||
<button (click)="allSelected = !allSelected; selectAll(allSelected);" class="btn btn-default btn-sm no-style" title="Select all">
|
||||
<span class="material-icons md-20 blue ">{{allSelected ? 'check_box': 'check_box_outline_blank'}}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-xs-7">
|
||||
<h5>{{header}}</h5>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<button class="btn btn-default btn-sm" type="button" id="collapsedMenufilterWb" aria-expanded="false" (click)="changeToolbarState(!toolbarState)"
|
||||
data-toggle="tooltip" title="Filter">
|
||||
<span class="material-icons md-20 blue ">{{!toolbarState? 'search' : 'expand_less'}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div [@toggleDown]="toolbarState">
|
||||
<taskana-shared-filter (performFilter)="performAvailableFilter($event)"></taskana-shared-filter>
|
||||
</div>
|
||||
<taskana-shared-spinner [isRunning]="requestInProgress" positionClass="centered-spinner" class="floating"></taskana-shared-spinner>
|
||||
<div infiniteScroll [infiniteScrollDistance]="1" [infiniteScrollThrottle]="50" (scrolled)="onScroll()" [scrollWindow]="false" class="infinite-scroll">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item" *ngFor="let distributionTarget of distributionTargets | selectWorkbaskets: distributionTargetsSelected: side"
|
||||
[class.selected]="distributionTarget.selected" type="text" (click)="distributionTarget.selected = !distributionTarget.selected">
|
||||
<div class="row">
|
||||
<dl class="col-xs-1">
|
||||
<taskana-administration-icon-type [type]="distributionTarget.type"></taskana-administration-icon-type>
|
||||
</dl>
|
||||
<dl class="col-xs-10">
|
||||
<dt>{{distributionTarget.name}},
|
||||
<i>{{distributionTarget.key}} </i>
|
||||
</dt>
|
||||
<dd>{{distributionTarget.description}} </dd>
|
||||
<dd>{{distributionTarget.owner}} </dd>
|
||||
</dl>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item" *ngIf="loadingItems">
|
||||
<taskana-shared-spinner [isRunning]="loadingItems" positionClass="centered-spinner" class="floating"></taskana-shared-spinner>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- ACTION TOOLBAR -->
|
||||
<div class="action-toolbar">
|
||||
<div class="row header">
|
||||
<div class="col-xs-2">
|
||||
<button (click)="allSelected = !allSelected; selectAll(allSelected);"
|
||||
class="btn btn-default btn-sm no-style" title="Select all">
|
||||
<span class="material-icons md-20 blue ">{{allSelected ? 'check_box' : 'check_box_outline_blank'}}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-xs-7">
|
||||
<h5>{{header}}</h5>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<button class="btn btn-default btn-sm" type="button" id="collapsedMenufilterWb" aria-expanded="false"
|
||||
(click)="changeToolbarState(!toolbarState)"
|
||||
data-toggle="tooltip" title="Filter">
|
||||
<span class="material-icons md-20 blue ">{{!toolbarState ? 'search' : 'expand_less'}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div [@toggleDown]="toolbarState">
|
||||
<taskana-shared-filter (performFilter)="performAvailableFilter($event)"></taskana-shared-filter>
|
||||
</div>
|
||||
<taskana-shared-spinner [isRunning]="requestInProgress" positionClass="centered-spinner"
|
||||
class="floating"></taskana-shared-spinner>
|
||||
</div>
|
||||
|
||||
<!-- WORKBASKET LIST -->
|
||||
<div infiniteScroll [infiniteScrollDistance]="1" [infiniteScrollThrottle]="50" (scrolled)="onScroll()"
|
||||
[scrollWindow]="false" class="infinite-scroll">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item"
|
||||
*ngFor="let distributionTarget of distributionTargets | selectWorkbaskets: distributionTargetsSelected: side"
|
||||
[class.selected]="distributionTarget.selected" type="text"
|
||||
(click)="distributionTarget.selected = !distributionTarget.selected">
|
||||
<div class="row">
|
||||
<dl class="col-xs-1">
|
||||
<taskana-administration-icon-type [type]="distributionTarget.type"></taskana-administration-icon-type>
|
||||
</dl>
|
||||
<dl class="col-xs-10">
|
||||
<dt>{{distributionTarget.name}},
|
||||
<i>{{distributionTarget.key}} </i>
|
||||
</dt>
|
||||
<dd>{{distributionTarget.description}} </dd>
|
||||
<dd>{{distributionTarget.owner}} </dd>
|
||||
</dl>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item" *ngIf="loadingItems">
|
||||
<taskana-shared-spinner [isRunning]="loadingItems" positionClass="centered-spinner"
|
||||
class="floating"></taskana-shared-spinner>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { Component, OnInit, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { WorkbasketSummary } from 'app/shared/models/workbasket-summary';
|
||||
import { Filter } from 'app/shared/models/filter';
|
||||
import { expandDown } from 'theme/animations/expand.animation';
|
||||
|
@ -11,8 +11,8 @@ import { Side } from '../workbasket-distribution-targets/workbasket-distribution
|
|||
animations: [expandDown]
|
||||
})
|
||||
export class WorkbasketDualListComponent implements OnInit {
|
||||
@Input() distributionTargets: Array<WorkbasketSummary>;
|
||||
@Input() distributionTargetsSelected: Array<WorkbasketSummary>;
|
||||
@Input() distributionTargets: WorkbasketSummary[];
|
||||
@Input() distributionTargetsSelected: WorkbasketSummary[];
|
||||
@Output() performDualListFilter = new EventEmitter<{ filterBy: Filter, side: Side }>();
|
||||
@Input() requestInProgress = false;
|
||||
@Input() loadingItems ? = false;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<button type="button" (click)="onSubmit()" data-toggle="tooltip" title="Save" class="btn btn-default btn-primary">
|
||||
<span class="material-icons md-20">save</span>
|
||||
</button>
|
||||
<button type="button" (click)="onClear()" data-toggle="tooltip" title="Undo Changes" class="btn btn-default">
|
||||
<button type="button" (click)="onUndo()" data-toggle="tooltip" title="Undo Changes" class="btn btn-default">
|
||||
<span class="material-icons md-20 blue">undo</span>
|
||||
</button>
|
||||
<button type="button" (click)="removeDistributionTargets()" data-toggle="tooltip" title="Remove workbasket as distribution target"
|
||||
|
@ -23,9 +23,11 @@
|
|||
<span *ngIf="!workbasket.workbasketId" class="badge warning"> {{badgeMessage}}</span>
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<form #WorkbasketForm="ngForm">
|
||||
<div class="col-md-6">
|
||||
<!-- KEY -->
|
||||
<div class="form-group required">
|
||||
<label for="wb-key" class="control-label">Key</label>
|
||||
<input type="text" required #key="ngModel" class="form-control" id="wb-key" placeholder="Key"
|
||||
|
@ -34,6 +36,8 @@
|
|||
errorMessage="* Key is required">
|
||||
</taskana-shared-field-error-display>
|
||||
</div>
|
||||
|
||||
<!-- NAME -->
|
||||
<div class="form-group required">
|
||||
<label for="wb-name" class="control-label">Name</label>
|
||||
<input type="text" required #name="ngModel" class="form-control" id="wb-name" placeholder="Name"
|
||||
|
@ -42,11 +46,13 @@
|
|||
errorMessage="* Name is required">
|
||||
</taskana-shared-field-error-display>
|
||||
</div>
|
||||
|
||||
<!-- OWNER -->
|
||||
<div class="input-group form-group col-xs-12 required">
|
||||
<label for="wb-owner" class="control-label ">Owner</label>
|
||||
<taskana-shared-type-ahead *ngIf="(workbasketsCustomisation$ | async)?.information?.lookupField else ownerInput" required #owner="ngModel" name="workbasket.owner"
|
||||
[(ngModel)]="workbasket.owner" placeHolderMessage="* Owner is required" [validationValue]="this.toogleValidationMap.get('workbasket.owner')"
|
||||
[displayError]="!isFieldValid('workbasket.owner')" width="100%"></taskana-shared-type-ahead>
|
||||
<taskana-shared-type-ahead *ngIf="lookupField else ownerInput" required #owner="ngModel" name="workbasket.owner"
|
||||
[(ngModel)]="workbasket.owner" placeHolderMessage="* Owner is required" [validationValue]="this.toogleValidationMap.get('workbasket.owner')"
|
||||
[displayError]="!isFieldValid('workbasket.owner')" width="100%"></taskana-shared-type-ahead>
|
||||
<ng-template #ownerInput>
|
||||
<input type="text" required #owner="ngModel" class="form-control" id="wb-owner" placeholder="Owner"
|
||||
[(ngModel)]="workbasket.owner" name="workbasket.owner">
|
||||
|
@ -55,11 +61,15 @@
|
|||
</taskana-shared-field-error-display>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<!-- DOMAIN -->
|
||||
<div class="form-group ">
|
||||
<label for="wb-domain" class="control-label">Domain</label>
|
||||
<input type="text" #domain="ngModel" class="form-control" disabled id="wb-domain" placeholder="Domain"
|
||||
[(ngModel)]="workbasket.domain" name="workbasket.domain">
|
||||
</div>
|
||||
|
||||
<!-- TYPE & DESCRIPTION-->
|
||||
<div class="row">
|
||||
<div class="form-group col-xs-4">
|
||||
<label class="control-label">Type</label>
|
||||
|
@ -97,7 +107,7 @@
|
|||
<input type="text" class="form-control" id="wb-org-level-2" placeholder="OrgLevel 2" [(ngModel)]="workbasket.orgLevel2"
|
||||
name="workbasket.orgLevel2">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-group" style="padding-top: 18px;">
|
||||
<label for="wb-org-level-3" class="control-label">OrgLevel 3</label>
|
||||
<input type="text" class="form-control" id="wb-org-level-3" placeholder="OrgLevel 3" [(ngModel)]="workbasket.orgLevel3"
|
||||
name="workbasket.orgLevel3">
|
||||
|
|
|
@ -4,20 +4,18 @@ import { FormsModule } from '@angular/forms';
|
|||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { of } from 'rxjs';
|
||||
import { Component } from '@angular/core';
|
||||
import { Routes } from '@angular/router';
|
||||
|
||||
import { Workbasket } from 'app/shared/models/workbasket';
|
||||
import { ICONTYPES } from 'app/shared/models/icon-types';
|
||||
import { ACTION } from 'app/shared/models/action';
|
||||
import { Links } from 'app/shared/models/links';
|
||||
|
||||
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
|
||||
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
|
||||
import { configureTests } from 'app/app.test.configuration';
|
||||
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
|
||||
import { NgxsModule, Store } from '@ngxs/store';
|
||||
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { NgxsModule } from '@ngxs/store';
|
||||
import { WorkbasketInformationComponent } from './workbasket-information.component';
|
||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||
|
||||
|
@ -43,29 +41,50 @@ describe('WorkbasketInformationComponent', () => {
|
|||
let requestInProgressService;
|
||||
let formsValidatorService;
|
||||
|
||||
const storeSpy: jasmine.SpyObj<Store> = jasmine.createSpyObj('Store', ['select']);
|
||||
|
||||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
declarations: [WorkbasketInformationComponent, DummyDetailComponent],
|
||||
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, RouterTestingModule.withRoutes(routes), NgxsModule.forRoot()],
|
||||
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, RouterTestingModule.withRoutes(routes),
|
||||
NgxsModule.forRoot()],
|
||||
providers: [WorkbasketService, NotificationService, SavingWorkbasketService,
|
||||
RequestInProgressService, FormsValidatorService, { provide: Store, useValue: storeSpy }]
|
||||
RequestInProgressService, FormsValidatorService]
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
function createWorkbasket(workbasketId?, created?, key?, domain?, type?, modified?, name?, description?,
|
||||
owner?, custom1?, custom2?, custom3?, custom4?, orgLevel1?, orgLevel2?, orgLevel3?, orgLevel4?,
|
||||
_links?: Links, markedForDeletion?: boolean) {
|
||||
if (!type) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
type = 'PERSONAL';
|
||||
}
|
||||
const workbasket: Workbasket = {
|
||||
workbasketId,
|
||||
created,
|
||||
key,
|
||||
domain,
|
||||
type,
|
||||
modified,
|
||||
name,
|
||||
description,
|
||||
owner,
|
||||
custom1,
|
||||
custom2,
|
||||
custom3,
|
||||
custom4,
|
||||
orgLevel1,
|
||||
orgLevel2,
|
||||
orgLevel3,
|
||||
orgLevel4,
|
||||
markedForDeletion,
|
||||
_links
|
||||
};
|
||||
return workbasket;
|
||||
}
|
||||
|
||||
beforeEach(done => {
|
||||
configureTests(configure).then(testBed => {
|
||||
storeSpy.select.and.callFake(selector => {
|
||||
switch (selector) {
|
||||
case EngineConfigurationSelectors.workbasketsCustomisation:
|
||||
return of({ information: {} });
|
||||
default:
|
||||
return of();
|
||||
}
|
||||
});
|
||||
|
||||
fixture = testBed.createComponent(WorkbasketInformationComponent);
|
||||
component = fixture.componentInstance;
|
||||
debugElement = fixture.debugElement.nativeElement;
|
||||
|
@ -83,6 +102,7 @@ describe('WorkbasketInformationComponent', () => {
|
|||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
document.body.removeChild(debugElement);
|
||||
});
|
||||
|
||||
|
@ -90,21 +110,8 @@ describe('WorkbasketInformationComponent', () => {
|
|||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should create a panel with heading and form with all fields', async(() => {
|
||||
component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC,
|
||||
'modified', 'name', 'description', 'owner', 'custom1', 'custom2', 'custom3', 'custom4',
|
||||
'orgLevel1', 'orgLevel2', 'orgLevel3', 'orgLevel4', null);
|
||||
fixture.detectChanges();
|
||||
expect(debugElement.querySelector('#wb-information')).toBeDefined();
|
||||
expect(debugElement.querySelector('#wb-information > .panel-heading > h4').textContent.trim()).toBe('name');
|
||||
expect(debugElement.querySelectorAll('#wb-information > .panel-body > form').length).toBe(1);
|
||||
fixture.whenStable().then(() => {
|
||||
expect(debugElement.querySelector('#wb-information > .panel-body > form > div > div > input ').value).toBe('keyModified');
|
||||
});
|
||||
}));
|
||||
|
||||
it('selectType should set workbasket.type to personal with 0 and group in other case', () => {
|
||||
component.workbasket = new Workbasket('id1');
|
||||
component.workbasket = createWorkbasket('id1');
|
||||
expect(component.workbasket.type).toEqual('PERSONAL');
|
||||
component.selectType(ICONTYPES.GROUP);
|
||||
expect(component.workbasket.type).toEqual('GROUP');
|
||||
|
@ -112,7 +119,7 @@ describe('WorkbasketInformationComponent', () => {
|
|||
|
||||
it('should create a copy of workbasket when workbasket is selected', () => {
|
||||
expect(component.workbasketClone).toBeUndefined();
|
||||
component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
|
||||
component.workbasket = createWorkbasket('id', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
|
||||
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2', 'orgLevel3', 'orgLevel4');
|
||||
component.ngOnChanges(
|
||||
undefined
|
||||
|
@ -120,95 +127,4 @@ describe('WorkbasketInformationComponent', () => {
|
|||
fixture.detectChanges();
|
||||
expect(component.workbasket.workbasketId).toEqual(component.workbasketClone.workbasketId);
|
||||
});
|
||||
|
||||
it('should reset requestInProgress after saving request is done', async(() => {
|
||||
component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
|
||||
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
|
||||
'orgLevel3', 'orgLevel4', { self: { href: 'someUrl' } });
|
||||
fixture.detectChanges();
|
||||
spyOn(workbasketService, 'updateWorkbasket').and.returnValue(of(component.workbasket));
|
||||
spyOn(workbasketService, 'triggerWorkBasketSaved').and.returnValue(of(component.workbasket));
|
||||
component.onSubmit();
|
||||
expect(component.requestInProgress).toBeFalsy();
|
||||
}));
|
||||
|
||||
it('should trigger triggerWorkBasketSaved method after saving request is done', async(() => {
|
||||
component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
|
||||
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
|
||||
'orgLevel3', 'orgLevel4', { self: { href: 'someurl' } });
|
||||
spyOn(workbasketService, 'updateWorkbasket').and.returnValue(of(component.workbasket));
|
||||
spyOn(workbasketService, 'triggerWorkBasketSaved').and.returnValue(of(component.workbasket));
|
||||
fixture.detectChanges();
|
||||
|
||||
spyOn(formsValidatorService, 'validateFormAccess').and.returnValue(Promise.resolve(true));
|
||||
component.onSubmit();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(workbasketService.triggerWorkBasketSaved).toHaveBeenCalled();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should post a new workbasket when no workbasketId is defined and update workbasket', async(() => {
|
||||
component.workbasket = new Workbasket(undefined, 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
|
||||
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
|
||||
'orgLevel3', 'orgLevel4', {});
|
||||
spyOn(workbasketService, 'createWorkbasket').and.returnValue(of(
|
||||
new Workbasket('someNewId', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
|
||||
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
|
||||
'orgLevel3', 'orgLevel4', {})
|
||||
));
|
||||
fixture.detectChanges();
|
||||
spyOn(formsValidatorService, 'validateFormAccess').and.returnValue(Promise.resolve(true));
|
||||
component.onSubmit();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(alertService.showToast).toHaveBeenCalled();
|
||||
expect(component.workbasket.workbasketId).toBe('someNewId');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should post a new workbasket, new distribution targets and new access '
|
||||
+ 'items when no workbasketId is defined and action is copy', async(() => {
|
||||
component.workbasket = new Workbasket(undefined, 'created', 'keyModified', 'domain', ICONTYPES.TOPIC,
|
||||
'modified', 'name', 'description', 'owner', 'custom1', 'custom2',
|
||||
'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
|
||||
'orgLevel3', 'orgLevel4', {});
|
||||
component.action = ACTION.COPY;
|
||||
|
||||
spyOn(workbasketService, 'createWorkbasket').and.returnValue(of(
|
||||
new Workbasket('someNewId', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
|
||||
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
|
||||
'orgLevel3', 'orgLevel4', { distributionTargets: { href: 'someurl' }, accessItems: { href: 'someurl' } })
|
||||
));
|
||||
|
||||
spyOn(savingWorkbasketService, 'triggerDistributionTargetSaving');
|
||||
spyOn(savingWorkbasketService, 'triggerAccessItemsSaving');
|
||||
fixture.detectChanges();
|
||||
spyOn(formsValidatorService, 'validateFormAccess').and.returnValue(Promise.resolve(true));
|
||||
component.onSubmit();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(alertService.showToast).toHaveBeenCalled();
|
||||
expect(component.workbasket.workbasketId).toBe('someNewId');
|
||||
expect(savingWorkbasketService.triggerDistributionTargetSaving).toHaveBeenCalled();
|
||||
expect(savingWorkbasketService.triggerAccessItemsSaving).toHaveBeenCalled();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should trigger requestInProgress service true before and requestInProgress false after remove a workbasket', () => {
|
||||
component.workbasket = new Workbasket(undefined, 'created', 'keyModified', 'domain', ICONTYPES.TOPIC,
|
||||
'modified', 'name', 'description', 'owner', 'custom1', 'custom2',
|
||||
'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
|
||||
'orgLevel3', 'orgLevel4', { removeDistributionTargets: { href: 'someurl' } });
|
||||
spyOn(workbasketService, 'removeDistributionTarget').and.returnValue(of(undefined));
|
||||
const requestInProgressServiceSpy = spyOn(requestInProgressService, 'setRequestInProgress');
|
||||
|
||||
component.removeDistributionTargets();
|
||||
expect(requestInProgressServiceSpy).toHaveBeenCalledWith(true);
|
||||
workbasketService.removeDistributionTarget().subscribe(() => {
|
||||
|
||||
}, () => { }, () => {
|
||||
expect(requestInProgressServiceSpy).toHaveBeenCalledWith(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,9 +6,9 @@ import { Component,
|
|||
SimpleChanges,
|
||||
ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { Observable, Subject, Subscription } from 'rxjs';
|
||||
import { NgForm } from '@angular/forms';
|
||||
import { Select } from '@ngxs/store';
|
||||
import { Select, Store } from '@ngxs/store';
|
||||
|
||||
import { ICONTYPES } from 'app/shared/models/icon-types';
|
||||
import { ACTION } from 'app/shared/models/action';
|
||||
|
@ -19,13 +19,16 @@ import { SavingWorkbasketService, SavingInformation } from 'app/administration/s
|
|||
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
|
||||
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
|
||||
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { map, takeUntil } from 'rxjs/operators';
|
||||
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||
import { CustomField,
|
||||
getCustomFields,
|
||||
WorkbasketsCustomisation } from '../../../shared/models/customisation';
|
||||
import { CopyWorkbasket, MarkWorkbasketForDeletion,
|
||||
RemoveDistributionTarget, SaveNewWorkbasket,
|
||||
UpdateWorkbasket } from '../../../shared/store/workbasket-store/workbasket.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-administration-workbasket-information',
|
||||
|
@ -37,24 +40,24 @@ implements OnInit, OnChanges, OnDestroy {
|
|||
@Input()
|
||||
workbasket: Workbasket;
|
||||
|
||||
workbasketClone: Workbasket;
|
||||
workbasketErrors;
|
||||
@Input()
|
||||
action: ACTION;
|
||||
|
||||
@ViewChild('WorkbasketForm', { static: false })
|
||||
workbasketForm: NgForm;
|
||||
|
||||
workbasketClone: Workbasket;
|
||||
allTypes: Map<string, string>;
|
||||
requestInProgress = false;
|
||||
badgeMessage = '';
|
||||
|
||||
@Select(EngineConfigurationSelectors.workbasketsCustomisation) workbasketsCustomisation$: Observable<WorkbasketsCustomisation>;
|
||||
customFields$: Observable<CustomField[]>;
|
||||
|
||||
toogleValidationMap = new Map<string, boolean>();
|
||||
lookupField = false;
|
||||
|
||||
private workbasketSubscription: Subscription;
|
||||
private routeSubscription: Subscription;
|
||||
@ViewChild('WorkbasketForm', { static: false })
|
||||
workbasketForm: NgForm;
|
||||
@Select(EngineConfigurationSelectors.workbasketsCustomisation)
|
||||
workbasketsCustomisation$: Observable<WorkbasketsCustomisation>;
|
||||
|
||||
customFields$: Observable<CustomField[]>;
|
||||
destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
private workbasketService: WorkbasketService,
|
||||
|
@ -63,11 +66,12 @@ implements OnInit, OnChanges, OnDestroy {
|
|||
private savingWorkbasket: SavingWorkbasketService,
|
||||
private requestInProgressService: RequestInProgressService,
|
||||
private formsValidatorService: FormsValidatorService,
|
||||
private notificationService: NotificationService
|
||||
private notificationService: NotificationService,
|
||||
private store: Store
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
ngOnInit() {
|
||||
this.allTypes = new Map([
|
||||
['PERSONAL', 'Personal'],
|
||||
['GROUP', 'Group'],
|
||||
|
@ -78,9 +82,16 @@ implements OnInit, OnChanges, OnDestroy {
|
|||
map(customisation => customisation.information),
|
||||
getCustomFields(customFieldCount)
|
||||
);
|
||||
this.workbasketsCustomisation$
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(workbasketsCustomization => {
|
||||
if (workbasketsCustomization.information.owner) {
|
||||
this.lookupField = workbasketsCustomization.information.owner.lookupField;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
this.workbasketClone = { ...this.workbasket };
|
||||
if (this.action === ACTION.CREATE) {
|
||||
this.badgeMessage = 'Creating new workbasket';
|
||||
|
@ -108,7 +119,7 @@ implements OnInit, OnChanges, OnDestroy {
|
|||
return this.formsValidatorService.isFieldValid(this.workbasketForm, field);
|
||||
}
|
||||
|
||||
onClear() {
|
||||
onUndo() {
|
||||
this.formsValidatorService.formSubmitAttempt = false;
|
||||
this.notificationService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
|
||||
this.workbasket = { ...this.workbasketClone };
|
||||
|
@ -122,32 +133,11 @@ implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
copyWorkbasket() {
|
||||
this.router.navigate([{ outlets: { detail: ['copy-workbasket'] } }], {
|
||||
relativeTo: this.route.parent
|
||||
});
|
||||
this.store.dispatch(new CopyWorkbasket(this.workbasket));
|
||||
}
|
||||
|
||||
removeDistributionTargets() {
|
||||
this.requestInProgressService.setRequestInProgress(true);
|
||||
this.workbasketService
|
||||
.removeDistributionTarget(
|
||||
this.workbasket._links.removeDistributionTargets.href
|
||||
)
|
||||
.subscribe(
|
||||
reponse => {
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
this.notificationService.showToast(
|
||||
NOTIFICATION_TYPES.SUCCESS_ALERT_9,
|
||||
new Map<string, string>([['workbasketId', this.workbasket.workbasketId]])
|
||||
);
|
||||
},
|
||||
error => {
|
||||
this.notificationService.triggerError(NOTIFICATION_TYPES.REMOVE_ERR_2,
|
||||
error,
|
||||
new Map<String, String>([['workbasketId', this.workbasket.workbasketId]]));
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
}
|
||||
);
|
||||
this.store.dispatch(new RemoveDistributionTarget(this.workbasket._links.removeDistributionTargets.href));
|
||||
}
|
||||
|
||||
private onSave() {
|
||||
|
@ -156,24 +146,11 @@ implements OnInit, OnChanges, OnDestroy {
|
|||
this.postNewWorkbasket();
|
||||
return;
|
||||
}
|
||||
|
||||
this.workbasketSubscription = this.workbasketService
|
||||
.updateWorkbasket(this.workbasket._links.self.href, this.workbasket)
|
||||
.subscribe(
|
||||
workbasketUpdated => {
|
||||
this.afterRequest();
|
||||
this.workbasket = workbasketUpdated;
|
||||
this.workbasketClone = { ...this.workbasket };
|
||||
this.notificationService.showToast(
|
||||
NOTIFICATION_TYPES.SUCCESS_ALERT_10,
|
||||
new Map<string, string>([['workbasketKey', workbasketUpdated.key]])
|
||||
);
|
||||
},
|
||||
error => {
|
||||
this.afterRequest();
|
||||
this.notificationService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_4, error);
|
||||
}
|
||||
);
|
||||
this.store.dispatch(new UpdateWorkbasket(this.workbasket._links.self.href, this.workbasket))
|
||||
.subscribe(state => {
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
this.workbasketClone = { ...this.workbasket };
|
||||
});
|
||||
}
|
||||
|
||||
private beforeRequest() {
|
||||
|
@ -187,19 +164,9 @@ implements OnInit, OnChanges, OnDestroy {
|
|||
|
||||
private postNewWorkbasket() {
|
||||
this.addDateToWorkbasket();
|
||||
this.workbasketService.createWorkbasket(this.workbasket).subscribe(
|
||||
(workbasketUpdated: Workbasket) => {
|
||||
this.notificationService.showToast(
|
||||
NOTIFICATION_TYPES.SUCCESS_ALERT_11,
|
||||
new Map<string, string>([['workbasketKey', workbasketUpdated.key]])
|
||||
);
|
||||
this.workbasket = workbasketUpdated;
|
||||
this.store.dispatch(new SaveNewWorkbasket(this.workbasket)).subscribe(
|
||||
() => {
|
||||
this.afterRequest();
|
||||
this.workbasketService.triggerWorkBasketSaved();
|
||||
this.workbasketService.selectWorkBasket(this.workbasket.workbasketId);
|
||||
this.router.navigate([`../${this.workbasket.workbasketId}`], {
|
||||
relativeTo: this.route
|
||||
});
|
||||
if (this.action === ACTION.COPY) {
|
||||
this.savingWorkbasket.triggerDistributionTargetSaving(
|
||||
new SavingInformation(
|
||||
|
@ -214,10 +181,6 @@ implements OnInit, OnChanges, OnDestroy {
|
|||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
this.notificationService.triggerError(NOTIFICATION_TYPES.CREATE_ERR_2, error);
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -229,38 +192,18 @@ implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
private onRemoveConfirmed() {
|
||||
this.requestInProgressService.setRequestInProgress(true);
|
||||
this.workbasketService
|
||||
.markWorkbasketForDeletion(this.workbasket._links.self.href)
|
||||
.subscribe(
|
||||
response => {
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
this.workbasketService.triggerWorkBasketSaved();
|
||||
if (response.status === 202) {
|
||||
this.notificationService.triggerError(NOTIFICATION_TYPES.MARK_ERR,
|
||||
undefined,
|
||||
new Map<String, String>([['workbasketId', this.workbasket.workbasketId]]));
|
||||
} else {
|
||||
this.notificationService.showToast(
|
||||
NOTIFICATION_TYPES.SUCCESS_ALERT_12,
|
||||
new Map<string, string>([['workbasketId', this.workbasket.workbasketId]])
|
||||
);
|
||||
}
|
||||
this.router.navigate(['taskana/administration/workbaskets']);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this.workbasketSubscription) {
|
||||
this.workbasketSubscription.unsubscribe();
|
||||
}
|
||||
if (this.routeSubscription) {
|
||||
this.routeSubscription.unsubscribe();
|
||||
}
|
||||
this.beforeRequest();
|
||||
this.store.dispatch(new MarkWorkbasketForDeletion(this.workbasket._links.self.href)).subscribe(() => {
|
||||
this.afterRequest();
|
||||
});
|
||||
}
|
||||
|
||||
getWorkbasketCustomProperty(custom: number) {
|
||||
return `custom${custom}`;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@ import { HttpClientModule } from '@angular/common/http';
|
|||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { AppModule } from 'app/app.module';
|
||||
|
||||
import { WorkbasketSummary } from 'app/shared/models/workbasket-summary';
|
||||
import { Links } from 'app/shared/models/links';
|
||||
import { Filter } from 'app/shared/models/filter';
|
||||
import { Sorting } from 'app/shared/models/sorting';
|
||||
|
@ -23,6 +21,7 @@ import { WorkbasketDefinitionService } from 'app/administration/services/workbas
|
|||
import { configureTests } from 'app/app.test.configuration';
|
||||
import { ImportExportService } from 'app/administration/services/import-export.service';
|
||||
import { WorkbasketListToolbarComponent } from './workbasket-list-toolbar.component';
|
||||
import { ICONTYPES } from '../../../shared/models/icon-types';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-dummy-detail',
|
||||
|
@ -58,17 +57,20 @@ describe('WorkbasketListToolbarComponent', () => {
|
|||
});
|
||||
};
|
||||
configureTests(configure).then(testBed => {
|
||||
fixture = testBed.createComponent(WorkbasketListToolbarComponent);
|
||||
workbasketService = testBed.get(WorkbasketService);
|
||||
router = testBed.get(Router);
|
||||
fixture = TestBed.createComponent(WorkbasketListToolbarComponent);
|
||||
workbasketService = TestBed.get(WorkbasketService);
|
||||
router = TestBed.get(Router);
|
||||
spyOn(workbasketService, 'markWorkbasketForDeletion').and.returnValue(of(''));
|
||||
spyOn(workbasketService, 'triggerWorkBasketSaved');
|
||||
|
||||
debugElement = fixture.debugElement.nativeElement;
|
||||
component = fixture.componentInstance;
|
||||
component.workbaskets = [
|
||||
new WorkbasketSummary('1', 'key1', 'NAME1', 'description 1', 'owner 1')
|
||||
];
|
||||
component.workbaskets = [{ workbasketId: '1',
|
||||
key: 'key1',
|
||||
name: 'NAME1',
|
||||
description: 'description 1',
|
||||
owner: 'owner 1',
|
||||
type: ICONTYPES.PERSONAL }];
|
||||
component.workbaskets[0].markedForDeletion = false;
|
||||
|
||||
fixture.detectChanges();
|
||||
|
@ -84,12 +86,6 @@ describe('WorkbasketListToolbarComponent', () => {
|
|||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should navigate to new-workbasket when click on add new workbasket', () => {
|
||||
const spy = spyOn(router, 'navigate');
|
||||
component.addWorkbasket();
|
||||
expect(spy.calls.first().args[0][0].outlets.detail[0]).toBe('new-workbasket');
|
||||
});
|
||||
|
||||
it('should emit performSorting when sorting is triggered', () => {
|
||||
let sort: Sorting;
|
||||
const compareSort = new Sorting();
|
||||
|
|
|
@ -3,14 +3,18 @@ import { ActivatedRoute, Router } from '@angular/router';
|
|||
|
||||
import { Sorting } from 'app/shared/models/sorting';
|
||||
import { Filter } from 'app/shared/models/filter';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { WorkbasketSummary } from 'app/shared/models/workbasket-summary';
|
||||
|
||||
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
|
||||
import { TaskanaType } from 'app/shared/models/taskana-type';
|
||||
import { expandDown } from 'theme/animations/expand.animation';
|
||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
||||
import { Select, Store } from '@ngxs/store';
|
||||
import { Location } from '@angular/common';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { ACTION } from '../../../shared/models/action';
|
||||
import { CreateWorkbasket, SetActiveAction } from '../../../shared/store/workbasket-store/workbasket.actions';
|
||||
import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-administration-workbasket-list-toolbar',
|
||||
|
@ -23,7 +27,7 @@ export class WorkbasketListToolbarComponent implements OnInit {
|
|||
@Input() workbasketDefaultSortBy: string;
|
||||
@Output() performSorting = new EventEmitter<Sorting>();
|
||||
@Output() performFilter = new EventEmitter<Filter>();
|
||||
workbasketServiceSubscription: Subscription;
|
||||
|
||||
selectionToImport = TaskanaType.WORKBASKETS;
|
||||
sortingFields = new Map([['name', 'Name'], ['key', 'Key'], ['description', 'Description'], ['owner', 'Owner'], ['type', 'Type']]);
|
||||
filteringTypes = new Map([['ALL', 'All'], ['PERSONAL', 'Personal'], ['GROUP', 'Group'],
|
||||
|
@ -33,15 +37,27 @@ export class WorkbasketListToolbarComponent implements OnInit {
|
|||
toolbarState = false;
|
||||
filterType = TaskanaType.WORKBASKETS;
|
||||
|
||||
@Select(WorkbasketSelectors.workbasketActiveAction)
|
||||
workbasketActiveAction$: Observable<ACTION>;
|
||||
|
||||
destroy$ = new Subject<void>();
|
||||
action: ACTION;
|
||||
|
||||
constructor(
|
||||
private workbasketService: WorkbasketService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private errors: NotificationService
|
||||
private store: Store,
|
||||
private location: Location
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.workbasketActiveAction$
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(action => {
|
||||
this.action = action;
|
||||
});
|
||||
}
|
||||
|
||||
sorting(sort: Sorting) {
|
||||
|
@ -53,7 +69,16 @@ export class WorkbasketListToolbarComponent implements OnInit {
|
|||
}
|
||||
|
||||
addWorkbasket() {
|
||||
this.workbasketService.selectWorkBasket();
|
||||
this.router.navigate([{ outlets: { detail: ['new-workbasket'] } }], { relativeTo: this.route });
|
||||
// this.store.dispatch(new SetActiveAction(ACTION.CREATE));
|
||||
if (this.action !== ACTION.CREATE) {
|
||||
this.store.dispatch(new CreateWorkbasket());
|
||||
}
|
||||
// this.workbasketService.selectWorkBasket();
|
||||
// this.router.navigate([{ outlets: { detail: ['new-workbasket'] } }], { relativeTo: this.route });
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
<div class="footer-space-pagination-list">
|
||||
<div #wbToolbar>
|
||||
<taskana-administration-workbasket-list-toolbar [workbaskets]="workbaskets" (performFilter)="performFilter($event)"
|
||||
(performSorting)="performSorting($event)" (importSucessful)="refreshWorkbasketList()" [workbasketDefaultSortBy]="workbasketDefaultSortBy"></taskana-administration-workbasket-list-toolbar>
|
||||
<taskana-administration-workbasket-list-toolbar [workbaskets]="workbasketsSummary$ | async" (performFilter)="performFilter($event)"
|
||||
(performSorting)="performSorting($event)" [workbasketDefaultSortBy]="workbasketDefaultSortBy">
|
||||
</taskana-administration-workbasket-list-toolbar>
|
||||
</div>
|
||||
<div *ngIf="(workbaskets && workbaskets.length > 0) else empty_workbaskets">
|
||||
<div *ngIf="((workbasketsSummary$ | async) && (workbasketsSummary$ | async)?.length > 0) else empty_workbaskets">
|
||||
<ul #wbList id="wb-list-container" class="list-group">
|
||||
<li class="list-group-item no-space">
|
||||
<div class="row"></div>
|
||||
</li>
|
||||
<li class="list-group-item" *ngFor="let workbasket of workbaskets" [class.active]="workbasket.workbasketId == selectedId"
|
||||
type="text" (click)="selectWorkbasket(workbasket.workbasketId)">
|
||||
<li class="list-group-item" *ngFor="let workbasket of (workbasketsSummary$ | async)"
|
||||
[class.active]="workbasket.workbasketId == selectedId"
|
||||
type="text" (click)="selectWorkbasket(workbasket.workbasketId)">
|
||||
<div class="row">
|
||||
<dl class="col-xs-1">
|
||||
<taskana-administration-icon-type class="vertical-align" [type]="workbasket.type" tooltip="true" [selected]="workbasket.workbasketId === selectedId"></taskana-administration-icon-type>
|
||||
|
@ -36,5 +38,9 @@
|
|||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
<taskana-shared-pagination [(page)]="workbasketsResource ? workbasketsResource.page : workbasketsResource"
|
||||
[type]="type" [numberOfItems]="workbaskets.length" (changePage)="changePage($event)"></taskana-shared-pagination>
|
||||
<taskana-shared-pagination
|
||||
[page]="(workbasketsSummaryRepresentation$ | async) ? (workbasketsSummaryRepresentation$ | async)?.page : (workbasketsSummaryRepresentation$ | async)"
|
||||
[type]="type"
|
||||
[numberOfItems]="(workbasketsSummary$ | async)?.length"
|
||||
(changePage)="changePage($event)">
|
||||
</taskana-shared-pagination>
|
||||
|
|
|
@ -8,8 +8,8 @@ import { Routes } from '@angular/router';
|
|||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { WorkbasketSummary } from 'app/shared/models/workbasket-summary';
|
||||
import { WorkbasketSummaryResource } from 'app/shared/models/workbasket-summary-resource';
|
||||
import { Filter } from 'app/shared/models/filter';
|
||||
import { WorkbasketSummaryRepresentation } from 'app/shared/models/workbasket-summary-representation';
|
||||
import { LinksWorkbasketSummary } from 'app/shared/models/links-workbasket-summary';
|
||||
|
||||
import { ImportExportComponent } from 'app/administration/components/import-export/import-export.component';
|
||||
|
||||
|
@ -20,6 +20,7 @@ import { OrientationService } from 'app/shared/services/orientation/orientation.
|
|||
import { configureTests } from 'app/app.test.configuration';
|
||||
import { Page } from 'app/shared/models/page';
|
||||
import { ImportExportService } from 'app/administration/services/import-export.service';
|
||||
import { NgxsModule } from '@ngxs/store';
|
||||
import { WorkbasketListToolbarComponent } from '../workbasket-list-toolbar/workbasket-list-toolbar.component';
|
||||
import { WorkbasketListComponent } from './workbasket-list.component';
|
||||
|
||||
|
@ -31,7 +32,7 @@ class DummyDetailComponent {
|
|||
}
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-shared-pagination',
|
||||
selector: 'taskana-pagination',
|
||||
template: 'dummydetail'
|
||||
})
|
||||
class PaginationComponent {
|
||||
|
@ -44,13 +45,32 @@ class PaginationComponent {
|
|||
@Output() changePage = new EventEmitter<any>();
|
||||
}
|
||||
|
||||
const workbasketSummaryResource: WorkbasketSummaryResource = new WorkbasketSummaryResource(
|
||||
new Array<WorkbasketSummary>(
|
||||
new WorkbasketSummary('1', 'key1', 'NAME1', 'description 1', 'owner 1', '', '', 'PERSONAL', '', '', '', ''),
|
||||
new WorkbasketSummary('2', 'key2', 'NAME2', 'description 2', 'owner 2', '', '', 'GROUP', '', '', '', '')
|
||||
),
|
||||
{}
|
||||
);
|
||||
function createWorkbasketSummary(workbasketId, key, name, domain, type, description, owner, custom1, custom2, custom3, custom4) {
|
||||
const workbasketSummary: WorkbasketSummary = {
|
||||
workbasketId,
|
||||
key,
|
||||
name,
|
||||
domain,
|
||||
type,
|
||||
description,
|
||||
owner,
|
||||
custom1,
|
||||
custom2,
|
||||
custom3,
|
||||
custom4
|
||||
};
|
||||
return workbasketSummary;
|
||||
}
|
||||
const workbasketSummaryResource: WorkbasketSummaryRepresentation = {
|
||||
workbaskets: [
|
||||
createWorkbasketSummary('1', 'key1', 'NAME1', '', 'PERSONAL',
|
||||
'description 1', 'owner1', '', '', '', ''),
|
||||
createWorkbasketSummary('2', 'key2', 'NAME2', '', 'PERSONAL',
|
||||
'description 2', 'owner2', '', '', '', ''),
|
||||
],
|
||||
_links: new LinksWorkbasketSummary({ href: 'url' }),
|
||||
page: {}
|
||||
};
|
||||
|
||||
describe('WorkbasketListComponent', () => {
|
||||
let component: WorkbasketListComponent;
|
||||
|
@ -71,12 +91,13 @@ describe('WorkbasketListComponent', () => {
|
|||
WorkbasketListComponent,
|
||||
DummyDetailComponent,
|
||||
WorkbasketListToolbarComponent,
|
||||
ImportExportComponent
|
||||
ImportExportComponent,
|
||||
],
|
||||
imports: [
|
||||
AngularSvgIconModule,
|
||||
HttpClientModule,
|
||||
RouterTestingModule.withRoutes(routes)
|
||||
RouterTestingModule.withRoutes(routes),
|
||||
NgxsModule.forRoot()
|
||||
],
|
||||
providers: [
|
||||
WorkbasketService,
|
||||
|
@ -90,6 +111,13 @@ describe('WorkbasketListComponent', () => {
|
|||
configureTests(configure).then(testBed => {
|
||||
fixture = TestBed.createComponent(WorkbasketListComponent);
|
||||
component = fixture.componentInstance;
|
||||
Object.defineProperty(component, 'workbasketsSummaryRepresentation$', { writable: true });
|
||||
const page = {
|
||||
workbaskets: [],
|
||||
_links: {},
|
||||
page: new Page(6, 3, 3, 1)
|
||||
};
|
||||
component.workbasketsSummaryRepresentation$ = of(page);
|
||||
debugElement = fixture.debugElement.nativeElement;
|
||||
workbasketService = TestBed.get(WorkbasketService);
|
||||
const orientationService = TestBed.get(OrientationService);
|
||||
|
@ -111,14 +139,6 @@ describe('WorkbasketListComponent', () => {
|
|||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should call workbasketService.getWorkbasketsSummary method on init', () => {
|
||||
component.ngOnInit();
|
||||
expect(workbasketService.getWorkBasketsSummary).toHaveBeenCalled();
|
||||
workbasketService.getWorkBasketsSummary().subscribe(value => {
|
||||
expect(value).toBe(workbasketSummaryResource);
|
||||
});
|
||||
});
|
||||
|
||||
it('should have wb-action-toolbar, wb-search-bar, wb-list-container, wb-pagination,'
|
||||
+ ' collapsedMenufilterWb and taskana-filter created in the html', () => {
|
||||
expect(debugElement.querySelector('#wb-action-toolbar')).toBeDefined();
|
||||
|
@ -127,27 +147,6 @@ describe('WorkbasketListComponent', () => {
|
|||
expect(debugElement.querySelector('#wb-list-container')).toBeDefined();
|
||||
expect(debugElement.querySelector('#collapsedMenufilterWb')).toBeDefined();
|
||||
expect(debugElement.querySelector('taskana-filter')).toBeDefined();
|
||||
expect(debugElement.querySelectorAll('#wb-list-container > li').length).toBe(3);
|
||||
});
|
||||
|
||||
// it('should have two workbasketsummary rows created with the second one selected.', fakeAsync(() => {
|
||||
// tick(0);
|
||||
// fixture.detectChanges();
|
||||
// fixture.whenStable().then(() => {
|
||||
// expect(debugElement.querySelectorAll('#wb-list-container > li').length).toBe(3);
|
||||
// expect(debugElement.querySelectorAll('#wb-list-container > li')[1].getAttribute('class'))
|
||||
// .toBe('list-group-item ng-star-inserted');
|
||||
// expect(debugElement.querySelectorAll('#wb-list-container > li')[2].getAttribute('class'))
|
||||
// .toBe('list-group-item ng-star-inserted active');
|
||||
// })
|
||||
//
|
||||
// }));
|
||||
|
||||
it('should have two workbasketsummary rows created with two different icons: user and users', () => {
|
||||
expect(debugElement.querySelectorAll('#wb-list-container > li')[1]
|
||||
.querySelector('svg-icon').getAttribute('ng-reflect-src')).toBe('./assets/icons/user.svg');
|
||||
expect(debugElement.querySelectorAll('#wb-list-container > li')[2]
|
||||
.querySelector('svg-icon').getAttribute('ng-reflect-src')).toBe('./assets/icons/users.svg');
|
||||
});
|
||||
|
||||
it('should have rendered sort by: name, id, description, owner and type', () => {
|
||||
|
@ -157,18 +156,4 @@ describe('WorkbasketListComponent', () => {
|
|||
expect(debugElement.querySelector('#sort-by-owner')).toBeDefined();
|
||||
expect(debugElement.querySelector('#sort-by-type')).toBeDefined();
|
||||
});
|
||||
|
||||
it('should have performRequest with forced = true after performFilter is triggered', (() => {
|
||||
const filter = new Filter({
|
||||
name: 'someName',
|
||||
owner: 'someOwner',
|
||||
description: 'someDescription',
|
||||
key: 'someKey',
|
||||
type: 'PERSONAL'
|
||||
});
|
||||
component.performFilter(filter);
|
||||
|
||||
expect(workbasketSummarySpy.calls.all()[1].args).toEqual([true, 'name', 'asc',
|
||||
'', 'someName', 'someDescription', '', 'someOwner', 'PERSONAL', '', 'someKey', '']);
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Observable, pipe, Subject, Subscription } from 'rxjs';
|
||||
|
||||
import { WorkbasketSummaryResource } from 'app/shared/models/workbasket-summary-resource';
|
||||
import { WorkbasketSummaryRepresentation } from 'app/shared/models/workbasket-summary-representation';
|
||||
import { WorkbasketSummary } from 'app/shared/models/workbasket-summary';
|
||||
import { Filter } from 'app/shared/models/filter';
|
||||
import { Sorting } from 'app/shared/models/sorting';
|
||||
|
@ -12,6 +11,12 @@ import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.ser
|
|||
import { OrientationService } from 'app/shared/services/orientation/orientation.service';
|
||||
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
|
||||
import { ImportExportService } from 'app/administration/services/import-export.service';
|
||||
import { Actions, ofActionCompleted, ofActionDispatched, Select, Store } from '@ngxs/store';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { DeselectWorkbasket, GetWorkbasketsSummary,
|
||||
SelectWorkbasket } from '../../../shared/store/workbasket-store/workbasket.actions';
|
||||
import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors';
|
||||
import { Workbasket } from '../../../shared/models/workbasket';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-administration-workbasket-list',
|
||||
|
@ -20,15 +25,11 @@ import { ImportExportService } from 'app/administration/services/import-export.s
|
|||
})
|
||||
export class WorkbasketListComponent implements OnInit, OnDestroy {
|
||||
selectedId = '';
|
||||
workbasketsResource: WorkbasketSummaryResource;
|
||||
workbaskets: Array<WorkbasketSummary> = [];
|
||||
requestInProgress = false;
|
||||
|
||||
pageSelected = 1;
|
||||
pageSize = 9;
|
||||
type = 'workbaskets';
|
||||
cards: number = this.pageSize;
|
||||
|
||||
workbasketDefaultSortBy: string = 'name';
|
||||
sort: Sorting = new Sorting(this.workbasketDefaultSortBy);
|
||||
filterBy: Filter = new Filter({ name: '', owner: '', type: '', description: '', key: '' });
|
||||
|
@ -36,47 +37,75 @@ export class WorkbasketListComponent implements OnInit, OnDestroy {
|
|||
@ViewChild('wbToolbar', { static: true })
|
||||
private toolbarElement: ElementRef;
|
||||
|
||||
private workBasketSummarySubscription: Subscription;
|
||||
private workbasketServiceSubscription: Subscription;
|
||||
private workbasketServiceSavedSubscription: Subscription;
|
||||
private orientationSubscription: Subscription;
|
||||
private importingExportingSubscription: Subscription;
|
||||
@Select(WorkbasketSelectors.workbasketsSummary)
|
||||
workbasketsSummary$: Observable<WorkbasketSummary[]>;
|
||||
|
||||
@Select(WorkbasketSelectors.workbasketsSummaryRepresentation)
|
||||
workbasketsSummaryRepresentation$: Observable<WorkbasketSummaryRepresentation>;
|
||||
|
||||
@Select(WorkbasketSelectors.selectedWorkbasket)
|
||||
selectedWorkbasket$: Observable<Workbasket>;
|
||||
|
||||
destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
private store: Store,
|
||||
private workbasketService: WorkbasketService,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private orientationService: OrientationService,
|
||||
private importExportService: ImportExportService
|
||||
private importExportService: ImportExportService,
|
||||
private ngxsActions$: Actions,
|
||||
) {
|
||||
this.ngxsActions$.pipe(ofActionDispatched(GetWorkbasketsSummary),
|
||||
takeUntil(this.destroy$))
|
||||
.subscribe(() => {
|
||||
this.requestInProgress = true;
|
||||
});
|
||||
this.ngxsActions$.pipe(ofActionCompleted(GetWorkbasketsSummary),
|
||||
takeUntil(this.destroy$))
|
||||
.subscribe(() => {
|
||||
this.requestInProgress = false;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.requestInProgress = true;
|
||||
this.workbasketServiceSubscription = this.workbasketService.getSelectedWorkBasket().subscribe(workbasketIdSelected => {
|
||||
// TODO should be done in a different way.
|
||||
setTimeout(() => {
|
||||
this.selectedId = workbasketIdSelected;
|
||||
}, 0);
|
||||
});
|
||||
|
||||
this.selectedWorkbasket$.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(selectedWorkbasket => {
|
||||
if (typeof selectedWorkbasket !== 'undefined') {
|
||||
this.selectedId = selectedWorkbasket.workbasketId;
|
||||
} else {
|
||||
this.selectedId = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
TaskanaQueryParameters.page = this.pageSelected;
|
||||
TaskanaQueryParameters.pageSize = this.pageSize;
|
||||
|
||||
this.workbasketServiceSavedSubscription = this.workbasketService.workbasketSavedTriggered().subscribe(value => {
|
||||
this.performRequest();
|
||||
});
|
||||
this.orientationSubscription = this.orientationService.getOrientation().subscribe((orientation: Orientation) => {
|
||||
this.refreshWorkbasketList();
|
||||
});
|
||||
this.importingExportingSubscription = this.importExportService.getImportingFinished().subscribe((value: Boolean) => {
|
||||
this.refreshWorkbasketList();
|
||||
});
|
||||
this.workbasketService.workbasketSavedTriggered()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(value => {
|
||||
this.performRequest();
|
||||
});
|
||||
|
||||
this.orientationService.getOrientation()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((orientation: Orientation) => {
|
||||
this.refreshWorkbasketList();
|
||||
});
|
||||
this.importExportService.getImportingFinished()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((value: Boolean) => {
|
||||
this.refreshWorkbasketList();
|
||||
});
|
||||
}
|
||||
|
||||
selectWorkbasket(id: string) {
|
||||
this.selectedId = id;
|
||||
this.router.navigate([{ outlets: { detail: [this.selectedId] } }], { relativeTo: this.route });
|
||||
if (this.selectedId === id) {
|
||||
this.store.dispatch(new DeselectWorkbasket());
|
||||
} else {
|
||||
this.store.dispatch(new SelectWorkbasket(id));
|
||||
}
|
||||
}
|
||||
|
||||
performSorting(sort: Sorting) {
|
||||
|
@ -102,37 +131,14 @@ export class WorkbasketListComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
private performRequest(): void {
|
||||
TaskanaQueryParameters.pageSize = this.cards;
|
||||
this.requestInProgress = true;
|
||||
this.workbaskets = [];
|
||||
this.workbasketServiceSubscription = this.workbasketService.getWorkBasketsSummary(
|
||||
true, this.sort.sortBy, this.sort.sortDirection, '',
|
||||
this.store.dispatch(new GetWorkbasketsSummary(true, this.sort.sortBy, this.sort.sortDirection, '',
|
||||
this.filterBy.filterParams.name, this.filterBy.filterParams.description, '', this.filterBy.filterParams.owner,
|
||||
this.filterBy.filterParams.type, '', this.filterBy.filterParams.key, ''
|
||||
)
|
||||
.subscribe(resultList => {
|
||||
this.workbasketsResource = resultList;
|
||||
this.workbaskets = resultList.workbaskets;
|
||||
this.requestInProgress = false;
|
||||
});
|
||||
this.filterBy.filterParams.type, '', this.filterBy.filterParams.key, ''));
|
||||
TaskanaQueryParameters.pageSize = this.cards;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this.workBasketSummarySubscription) {
|
||||
this.workBasketSummarySubscription.unsubscribe();
|
||||
}
|
||||
if (this.workbasketServiceSubscription) {
|
||||
this.workbasketServiceSubscription.unsubscribe();
|
||||
}
|
||||
if (this.workbasketServiceSavedSubscription) {
|
||||
this.workbasketServiceSavedSubscription.unsubscribe();
|
||||
}
|
||||
if (this.orientationSubscription) {
|
||||
this.orientationSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
if (this.importingExportingSubscription) {
|
||||
this.importingExportingSubscription.unsubscribe();
|
||||
}
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<div class="no-gutter">
|
||||
<div class="col-xs-12 col-md-4 vertical-right-divider">
|
||||
<taskana-administration-workbasket-list></taskana-administration-workbasket-list>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-8" *ngIf="showDetail; else showEmptyPage">
|
||||
<taskana-administration-workbasket-details></taskana-administration-workbasket-details>
|
||||
</div>
|
||||
|
||||
<ng-template #showEmptyPage>
|
||||
<div class="hidden-xs hidden-sm col-md-8 container-no-items">
|
||||
<div class="center-block no-detail">
|
||||
<h3 class="grey">Select a workbasket</h3>
|
||||
<svg-icon class="img-responsive empty-icon" src="./assets/icons/wb-empty.svg"></svg-icon>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
|
@ -0,0 +1,75 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { Routes } from '@angular/router';
|
||||
import { NgxsModule } from '@ngxs/store';
|
||||
import { Component, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { Location } from '@angular/common';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { debug } from 'util';
|
||||
import { WorkbasketOverviewComponent } from './workbasket-overview.component';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-dummy-detail',
|
||||
template: 'dummydetail'
|
||||
})
|
||||
export class DummyDetailComponent {
|
||||
}
|
||||
@Component({
|
||||
selector: 'taskana-workbasket-list',
|
||||
template: 'dummylist'
|
||||
})
|
||||
export class DummyListComponent {
|
||||
}
|
||||
describe('WorkbasketOverviewComponent', () => {
|
||||
let debugElement: any;
|
||||
let component: WorkbasketOverviewComponent;
|
||||
let fixture: ComponentFixture<WorkbasketOverviewComponent>;
|
||||
const locationSpy: jasmine.SpyObj<Location> = jasmine.createSpyObj('Location', ['go']);
|
||||
const routes: Routes = [
|
||||
{ path: ':id', component: DummyDetailComponent }
|
||||
];
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule(
|
||||
{ imports: [
|
||||
RouterTestingModule.withRoutes(routes),
|
||||
NgxsModule.forRoot()
|
||||
],
|
||||
declarations: [
|
||||
WorkbasketOverviewComponent,
|
||||
DummyDetailComponent,
|
||||
DummyListComponent],
|
||||
providers: [
|
||||
{ provide: Location, useValue: locationSpy },
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA] }
|
||||
)
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(WorkbasketOverviewComponent);
|
||||
component = fixture.componentInstance;
|
||||
debugElement = fixture.debugElement.nativeElement;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not display detail component if showDetail is false', () => {
|
||||
component.showDetail = false;
|
||||
expect(debugElement.querySelector('taskana-administration-workbasket-details')).toBeNull();
|
||||
});
|
||||
|
||||
it('should display detail component if showDetail is true', () => {
|
||||
component.showDetail = true;
|
||||
fixture.detectChanges();
|
||||
expect(debugElement.querySelector('taskana-administration-workbasket-details')).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,57 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Select, Store } from '@ngxs/store';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors';
|
||||
|
||||
import { CreateWorkbasket,
|
||||
SelectWorkbasket,
|
||||
SetActiveAction } from '../../../shared/store/workbasket-store/workbasket.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'app-workbasket-overview',
|
||||
templateUrl: './workbasket-overview.component.html',
|
||||
styleUrls: ['./workbasket-overview.component.scss']
|
||||
})
|
||||
export class WorkbasketOverviewComponent implements OnInit {
|
||||
showDetail = false;
|
||||
@Select(WorkbasketSelectors.selectedWorkbasketAndAction) selectedWorkbasketAndAction$: Observable<any>;
|
||||
destroy$ = new Subject<void>();
|
||||
routerParams: any;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private store: Store
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.route.firstChild) {
|
||||
this.route.firstChild.params
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(params => {
|
||||
this.routerParams = params;
|
||||
if (this.routerParams.id) {
|
||||
this.showDetail = true;
|
||||
if (this.routerParams.id === 'new-workbasket') {
|
||||
this.store.dispatch(new CreateWorkbasket());
|
||||
} else {
|
||||
this.store.dispatch(new SelectWorkbasket(this.routerParams.id));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
this.selectedWorkbasketAndAction$
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(state => {
|
||||
this.showDetail = !!state.selectedWorkbasket || state.action === 1;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
|
@ -17,11 +17,10 @@
|
|||
</div>
|
||||
<div class="col-xs-4">
|
||||
<input type="text" [(ngModel)]="filter.filterParams.name" (keyup.enter)="search()" class="form-control input-sm"
|
||||
id="display-name-filter" placeholder="Filter name">
|
||||
placeholder="Filter name">
|
||||
</div>
|
||||
<div class="col-xs-4">
|
||||
<input type="text" [(ngModel)]="filter.filterParams.key" (keyup.enter)="search()" class="form-control input-sm"
|
||||
id="display-key-filter" placeholder="Filter key">
|
||||
<input type="text" [(ngModel)]="filter.filterParams.key" (keyup.enter)="search()" class="form-control input-sm" placeholder="Filter key">
|
||||
</div>
|
||||
<button (click)="clear(); search()" type="button" class="btn btn-default btn-sm pull-right margin-right"
|
||||
data-toggle="tooltip" title="Clear">
|
||||
|
@ -31,13 +30,13 @@
|
|||
<div class="row">
|
||||
<div class="col-xs-8 col-xs-offset-2">
|
||||
<input type="text" [(ngModel)]="filter.filterParams.description" (keyup.enter)="search()" class="form-control input-sm"
|
||||
id="display-name-description" placeholder="Filter description">
|
||||
placeholder="Filter description">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-8 col-xs-offset-2">
|
||||
<input type="text" [(ngModel)]="filter.filterParams.owner" (keyup.enter)="search()" class="form-control input-sm"
|
||||
id="display-name-owner" placeholder="Filter owner">
|
||||
placeholder="Filter owner">
|
||||
</div>
|
||||
<button (click)="search()" type="button" class="btn btn-default btn-sm pull-right margin-right" data-toggle="tooltip"
|
||||
title="Search">
|
||||
|
|
|
@ -16,6 +16,6 @@
|
|||
<span class="footer pull-right" [hidden]="numberOfItems === 0">
|
||||
<i [innerHTML]="getPagesTextToShow()"></i>
|
||||
</span>
|
||||
<span class="footer pull-right" [hidden]="numberOfItems !== 0 && page.totalElements !== 0">
|
||||
<span class="footer pull-right" [hidden]="numberOfItems !== 0 && page?.totalElements !== 0">
|
||||
<i>Loading...</i>
|
||||
</span>
|
||||
|
|
|
@ -46,7 +46,6 @@ export class PaginationComponent implements OnChanges {
|
|||
if (this.previousPageSelected !== page) {
|
||||
this.changePage.emit(page);
|
||||
this.previousPageSelected = page;
|
||||
this.page.number = page;
|
||||
this.pageSelected = page;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
{{dataSource.selected?.name}}
|
||||
</label>
|
||||
</span>
|
||||
<div class="input-group">
|
||||
<div class="input-group form-control">
|
||||
<div>{{dataSource.selected?.accessId}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -33,11 +33,11 @@
|
|||
<input #inputTypeAhead class="form-control input-text" [ngClass]="{'invalid': !dataSource.length && isRequired}" (blur)="typeaheadOnSelect({'item':dataSource.selected})"
|
||||
name="accessItem-{{index}}" [required]="isRequired ? 'required' : null" #accessItemName="ngModel" [(ngModel)]="value"
|
||||
[typeahead]="dataSource" typeaheadOptionField="name" [typeaheadItemTemplate]="customItemTemplate"
|
||||
(typeaheadOnSelect)="typeaheadOnSelect($event, index)" [typeaheadScrollable]="true"
|
||||
(typeaheadOnSelect)="typeaheadOnSelect($event)" [typeaheadScrollable]="true"
|
||||
[typeaheadOptionsInScrollableView]="typeaheadOptionsInScrollableView" [typeaheadMinLength]="typeaheadMinLength"
|
||||
[typeaheadWaitMs]="typeaheadWaitMs" (typeaheadLoading)="changeTypeaheadLoading($event)" placeholder="{{displayError? placeHolderMessage: ''}}"
|
||||
[@validation]="validationValue">
|
||||
<button *ngIf="!typeaheadLoading" type="button" title="search" class="btn rounded blue">
|
||||
<button *ngIf="!typeaheadLoading" type="button" title="search" class="btn rounded blue search-button" >
|
||||
<span class="material-icons md-20 blue">search</span>
|
||||
</button>
|
||||
<div *ngIf="typeaheadLoading" class="loading">
|
||||
|
|
|
@ -5,55 +5,53 @@
|
|||
height: 47px;
|
||||
& label {
|
||||
margin-bottom: 0px;
|
||||
padding: 0px 12px;
|
||||
font-style: italic;
|
||||
//font-style: italic;
|
||||
//color: grey;
|
||||
overflow: hidden;
|
||||
}
|
||||
&> div{
|
||||
|
||||
&> div {
|
||||
border-bottom: 1px solid $pallete-blue;
|
||||
margin-top: 2px;
|
||||
padding-left: 12px;
|
||||
min-width: 175px;
|
||||
max-width: 175px;
|
||||
}
|
||||
}
|
||||
> div{
|
||||
border-bottom: 1px solid $pallete-blue !important;
|
||||
border-radius: 4px !important;
|
||||
height: 32px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
margin-right: 35px;
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
}
|
||||
.custom-form-control {
|
||||
margin-top: -5px;
|
||||
height: 40px;
|
||||
max-height: 57px;
|
||||
& .input-group{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.input-text {
|
||||
background: none;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 16px;
|
||||
background: white;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
padding: 0px;
|
||||
border-radius: 0px;
|
||||
border-radius: 4px !important;
|
||||
//border-color: lightgray;
|
||||
border-bottom: 1px solid $pallete-blue !important;
|
||||
min-width: 150px;
|
||||
height: 28px;
|
||||
border-bottom: 1px solid $pallete-blue;
|
||||
&:focus{
|
||||
border-bottom: 1px solid $aquamarine;
|
||||
}
|
||||
padding-left: 12px;
|
||||
padding-right: 35px;
|
||||
|
||||
height: 32px;
|
||||
padding: 13px 0 13px 12px;
|
||||
}
|
||||
|
||||
.field-label-wrapper{
|
||||
position: relative;
|
||||
height: 28px;
|
||||
padding-left: 12px;
|
||||
box-sizing: content-box;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
|
@ -63,7 +61,7 @@
|
|||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: none;
|
||||
//border-color: unset;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
@ -77,7 +75,11 @@
|
|||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
|
||||
padding-top: 0;
|
||||
}
|
||||
.search-button {
|
||||
z-index: 999;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
|
||||
|
@ -97,5 +99,5 @@
|
|||
}
|
||||
|
||||
.invalid {
|
||||
border-bottom: 1px solid $invalid;
|
||||
color: $invalid;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
export enum ACTION {
|
||||
DEFAULT,
|
||||
CREATE,
|
||||
COPY
|
||||
COPY,
|
||||
READ
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// Remnant from old design, needs to be removed, type reference should instead => models/Links.ts
|
||||
export class LinksWorkbasketSummary {
|
||||
constructor(
|
||||
self?,
|
||||
distributionTargets?,
|
||||
accessItems?,
|
||||
public allWorkbaskets?: { 'href': string }
|
||||
) {
|
||||
}
|
||||
}
|
|
@ -229,7 +229,7 @@ export const notifications = new Map<NOTIFICATION_TYPES, Pair>([
|
|||
// taskdetails.component
|
||||
[NOTIFICATION_TYPES.INFO_ALERT, new Pair(
|
||||
'',
|
||||
'Refreshed selected classification'
|
||||
'Information restored'
|
||||
)],
|
||||
// classification-details.component
|
||||
[NOTIFICATION_TYPES.SUCCESS_ALERT_4, new Pair(
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import { Links } from './links';
|
||||
import { WorkbasketAccessItems } from './workbasket-access-items';
|
||||
|
||||
export interface WorkbasketAccessItemsRepresentation {
|
||||
accessItems: WorkbasketAccessItems[];
|
||||
_links: Links;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
import { Links } from './links';
|
||||
import { WorkbasketAccessItems } from './workbasket-access-items';
|
||||
|
||||
export class WorkbasketAccessItemsResource {
|
||||
constructor(
|
||||
public accessItems: Array<WorkbasketAccessItems> = [],
|
||||
public _links: Links = {}
|
||||
) { }
|
||||
}
|
|
@ -1,30 +1,29 @@
|
|||
import { Links } from './links';
|
||||
|
||||
export class WorkbasketAccessItems {
|
||||
constructor(
|
||||
public accessItemId: string = '',
|
||||
public workbasketId: string = '',
|
||||
public accessId: string = '',
|
||||
public accessName: string = '',
|
||||
public permRead: boolean = false,
|
||||
public permOpen: boolean = false,
|
||||
public permAppend: boolean = false,
|
||||
public permTransfer: boolean = false,
|
||||
public permDistribute: boolean = false,
|
||||
public permCustom1: boolean = false,
|
||||
public permCustom2: boolean = false,
|
||||
public permCustom3: boolean = false,
|
||||
public permCustom4: boolean = false,
|
||||
public permCustom5: boolean = false,
|
||||
public permCustom6: boolean = false,
|
||||
public permCustom7: boolean = false,
|
||||
public permCustom8: boolean = false,
|
||||
public permCustom9: boolean = false,
|
||||
public permCustom10: boolean = false,
|
||||
public permCustom11: boolean = false,
|
||||
public permCustom12: boolean = false,
|
||||
public _links: Links = {}
|
||||
) { }
|
||||
export interface WorkbasketAccessItems {
|
||||
accessItemId: string;
|
||||
workbasketId: string;
|
||||
workbasketKey: string;
|
||||
accessId: string;
|
||||
accessName: string;
|
||||
permRead: boolean;
|
||||
permOpen: boolean;
|
||||
permAppend: boolean;
|
||||
permTransfer: boolean;
|
||||
permDistribute: boolean;
|
||||
permCustom1: boolean;
|
||||
permCustom2: boolean;
|
||||
permCustom3: boolean;
|
||||
permCustom4: boolean;
|
||||
permCustom5: boolean;
|
||||
permCustom6: boolean;
|
||||
permCustom7: boolean;
|
||||
permCustom8: boolean;
|
||||
permCustom9: boolean;
|
||||
permCustom10: boolean;
|
||||
permCustom11: boolean;
|
||||
permCustom12: boolean;
|
||||
_links: Links;
|
||||
}
|
||||
|
||||
export const customFieldCount: number = 12;
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import { WorkbasketAccessItems } from './workbasket-access-items';
|
||||
import { Workbasket } from './workbasket';
|
||||
|
||||
export class WorkbasketDefinition {
|
||||
constructor(
|
||||
public distributionTargets: string[],
|
||||
public workbasketAccessItems: WorkbasketAccessItems[],
|
||||
public workbasket: Workbasket
|
||||
) {
|
||||
}
|
||||
export interface WorkbasketDefinition {
|
||||
distributionTargets: string[];
|
||||
workbasketAccessItems: WorkbasketAccessItems[];
|
||||
workbasket: Workbasket;
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
import { WorkbasketSummary } from './workbasket-summary';
|
||||
import { Links } from './links';
|
||||
|
||||
export class WorkbasketDistributionTargetsResource {
|
||||
constructor(
|
||||
public distributionTargets: Array<WorkbasketSummary> = [],
|
||||
public _links: Links = null
|
||||
) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { WorkbasketSummary } from './workbasket-summary';
|
||||
import { Links } from './links';
|
||||
|
||||
export interface WorkbasketDistributionTargets {
|
||||
distributionTargets: WorkbasketSummary[];
|
||||
_links: Links;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { Links } from './links';
|
||||
import { Workbasket } from './workbasket';
|
||||
|
||||
export interface WorkbasketRepresentation {
|
||||
workbaskets: Workbasket[];
|
||||
_links: Links;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
import { Links } from './links';
|
||||
import { Workbasket } from './workbasket';
|
||||
|
||||
export class WorkbasketResource {
|
||||
constructor(
|
||||
public workbaskets: Array<Workbasket> = [],
|
||||
public _links: Links = {}
|
||||
) { }
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import { Page } from 'app/shared/models/page';
|
||||
import { WorkbasketSummary } from './workbasket-summary';
|
||||
import { LinksWorkbasketSummary } from './links-workbasket-summary';
|
||||
|
||||
export interface WorkbasketSummaryRepresentation {
|
||||
workbaskets: WorkbasketSummary[];
|
||||
_links: LinksWorkbasketSummary;
|
||||
page?: Page;
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
import { Page } from 'app/shared/models/page';
|
||||
import { WorkbasketSummary } from './workbasket-summary';
|
||||
import { Links } from './links';
|
||||
|
||||
export class WorkbasketSummaryResource {
|
||||
constructor(
|
||||
public workbaskets: Array<WorkbasketSummary> = [],
|
||||
public _links: Links = {},
|
||||
public page: Page = new Page()
|
||||
) {
|
||||
}
|
||||
}
|
|
@ -1,24 +1,20 @@
|
|||
import { ICONTYPES } from './icon-types';
|
||||
import { Page } from './page';
|
||||
import { Links } from './links';
|
||||
|
||||
export class WorkbasketSummary {
|
||||
constructor(
|
||||
public workbasketId?: string,
|
||||
public key?: string,
|
||||
public name?: string,
|
||||
public description?: string,
|
||||
public owner?: string,
|
||||
public modified?: string,
|
||||
public domain?: string,
|
||||
public type: string = ICONTYPES.PERSONAL,
|
||||
public orgLevel1?: string,
|
||||
public orgLevel2?: string,
|
||||
public orgLevel3?: string,
|
||||
public orgLevel4?: string,
|
||||
public markedForDeletion: boolean = false,
|
||||
public _links?: Links,
|
||||
public page?: Page
|
||||
) {
|
||||
}
|
||||
export interface WorkbasketSummary {
|
||||
workbasketId?: string,
|
||||
key?: string,
|
||||
name?: string,
|
||||
domain?: string,
|
||||
type?: ICONTYPES,
|
||||
description?: string,
|
||||
owner?: string,
|
||||
custom1?: string,
|
||||
custom2?: string,
|
||||
custom3?: string,
|
||||
custom4?: string,
|
||||
orgLevel1?: string,
|
||||
orgLevel2?: string,
|
||||
orgLevel3?: string,
|
||||
orgLevel4?: string,
|
||||
markedForDeletion?: boolean,
|
||||
}
|
||||
|
|
|
@ -1,28 +1,26 @@
|
|||
import { Links } from './links';
|
||||
import { ICONTYPES } from './icon-types';
|
||||
|
||||
export class Workbasket {
|
||||
constructor(
|
||||
public workbasketId?: string,
|
||||
public created?: string,
|
||||
public key?: string,
|
||||
public domain?: string,
|
||||
public type: ICONTYPES = ICONTYPES.PERSONAL,
|
||||
public modified?: string,
|
||||
public name?: string,
|
||||
public description?: string,
|
||||
public owner?: string,
|
||||
public custom1?: string,
|
||||
public custom2?: string,
|
||||
public custom3?: string,
|
||||
public custom4?: string,
|
||||
public orgLevel1?: string,
|
||||
public orgLevel2?: string,
|
||||
public orgLevel3?: string,
|
||||
public orgLevel4?: string,
|
||||
public _links: Links = {}
|
||||
) {
|
||||
}
|
||||
export interface Workbasket {
|
||||
workbasketId?: string;
|
||||
key?: string;
|
||||
name?: string;
|
||||
domain?: string;
|
||||
type?: ICONTYPES;
|
||||
description?: string;
|
||||
owner?: string;
|
||||
custom1?: string;
|
||||
custom2?: string;
|
||||
custom3?: string;
|
||||
custom4?: string;
|
||||
orgLevel1?: string;
|
||||
orgLevel2?: string;
|
||||
orgLevel3?: string;
|
||||
orgLevel4?: string;
|
||||
markedForDeletion?: boolean;
|
||||
created?: string;
|
||||
modified?: string;
|
||||
_links?: Links;
|
||||
}
|
||||
|
||||
export const customFieldCount: number = 4;
|
||||
|
|
|
@ -4,22 +4,22 @@ import { HttpClient } from '@angular/common/http';
|
|||
import { environment } from 'environments/environment';
|
||||
import { Workbasket } from 'app/shared/models/workbasket';
|
||||
import { WorkbasketAccessItems } from 'app/shared/models/workbasket-access-items';
|
||||
import { WorkbasketSummaryResource } from 'app/shared/models/workbasket-summary-resource';
|
||||
import { WorkbasketAccessItemsResource } from 'app/shared/models/workbasket-access-items-resource';
|
||||
import { WorkbasketDistributionTargetsResource } from 'app/shared/models/workbasket-distribution-targets-resource';
|
||||
import { WorkbasketSummaryRepresentation } from 'app/shared/models/workbasket-summary-representation';
|
||||
import { WorkbasketAccessItemsRepresentation } from 'app/shared/models/workbasket-access-items-representation';
|
||||
import { WorkbasketDistributionTargets } from 'app/shared/models/workbasket-distribution-targets';
|
||||
import { Direction } from 'app/shared/models/sorting';
|
||||
|
||||
import { DomainService } from 'app/shared/services/domain/domain.service';
|
||||
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
|
||||
import { mergeMap, tap, catchError } from 'rxjs/operators';
|
||||
import { QueryParameters } from 'app/shared/models/query-parameters';
|
||||
import { WorkbasketResource } from '../../models/workbasket-resource';
|
||||
import { WorkbasketRepresentation } from '../../models/workbasket-representation';
|
||||
|
||||
@Injectable()
|
||||
export class WorkbasketService {
|
||||
public workBasketSelected = new Subject<string>();
|
||||
public workBasketSaved = new Subject<number>();
|
||||
private workbasketSummaryRef: Observable<WorkbasketSummaryResource> = new Observable();
|
||||
private workbasketSummaryRef: Observable<WorkbasketSummaryRepresentation> = new Observable();
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
|
@ -47,7 +47,7 @@ export class WorkbasketService {
|
|||
|
||||
return this.domainService.getSelectedDomain()
|
||||
.pipe(mergeMap(domain => {
|
||||
this.workbasketSummaryRef = this.httpClient.get<WorkbasketSummaryResource>(
|
||||
this.workbasketSummaryRef = this.httpClient.get<WorkbasketSummaryRepresentation>(
|
||||
`${environment.taskanaRestUrl}/v1/workbaskets/${TaskanaQueryParameters
|
||||
.getQueryParameters(this.workbasketParameters(sortBy, order, name, nameLike, descLike, owner, ownerLike,
|
||||
type, key, keyLike, requiredPermission, allPages, domain))}`
|
||||
|
@ -65,8 +65,8 @@ export class WorkbasketService {
|
|||
}
|
||||
|
||||
// GET
|
||||
getAllWorkBaskets(): Observable<WorkbasketResource> {
|
||||
return this.httpClient.get<WorkbasketResource>(`${environment.taskanaRestUrl}/v1/workbaskets?required-permission=OPEN`);
|
||||
getAllWorkBaskets(): Observable<WorkbasketRepresentation> {
|
||||
return this.httpClient.get<WorkbasketRepresentation>(`${environment.taskanaRestUrl}/v1/workbaskets?required-permission=OPEN`);
|
||||
}
|
||||
|
||||
// POST
|
||||
|
@ -90,8 +90,8 @@ export class WorkbasketService {
|
|||
}
|
||||
|
||||
// GET
|
||||
getWorkBasketAccessItems(url: string): Observable<WorkbasketAccessItemsResource> {
|
||||
return this.httpClient.get<WorkbasketAccessItemsResource>(url);
|
||||
getWorkBasketAccessItems(url: string): Observable<WorkbasketAccessItemsRepresentation> {
|
||||
return this.httpClient.get<WorkbasketAccessItemsRepresentation>(url);
|
||||
}
|
||||
|
||||
// POST
|
||||
|
@ -106,14 +106,14 @@ export class WorkbasketService {
|
|||
}
|
||||
|
||||
// GET
|
||||
getWorkBasketsDistributionTargets(url: string): Observable<WorkbasketDistributionTargetsResource> {
|
||||
return this.httpClient.get<WorkbasketDistributionTargetsResource>(url);
|
||||
getWorkBasketsDistributionTargets(url: string): Observable<WorkbasketDistributionTargets> {
|
||||
return this.httpClient.get<WorkbasketDistributionTargets>(url);
|
||||
}
|
||||
|
||||
// PUT
|
||||
updateWorkBasketsDistributionTargets(url: string, distributionTargetsIds: Array<string>):
|
||||
Observable<WorkbasketDistributionTargetsResource> {
|
||||
return this.httpClient.put<WorkbasketDistributionTargetsResource>(url, distributionTargetsIds);
|
||||
Observable<WorkbasketDistributionTargets> {
|
||||
return this.httpClient.put<WorkbasketDistributionTargets>(url, distributionTargetsIds);
|
||||
}
|
||||
|
||||
// DELETE
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { EngineConfigurationState } from './engine-configuration-store/engine-configuration.state';
|
||||
import { ClassificationState } from './classification-store/classification.state';
|
||||
import { WorkbasketState } from './workbasket-store/workbasket.state';
|
||||
|
||||
export const STATES = [EngineConfigurationState, ClassificationState];
|
||||
export const STATES = [EngineConfigurationState, ClassificationState, WorkbasketState];
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
import { Workbasket } from '../../models/workbasket';
|
||||
import { TaskanaQueryParameters } from '../../util/query-parameters';
|
||||
import { Direction } from '../../models/sorting';
|
||||
import { ACTION } from '../../models/action';
|
||||
import { WorkbasketAccessItems } from '../../models/workbasket-access-items';
|
||||
|
||||
// Workbasket List
|
||||
export class GetWorkbasketsSummary {
|
||||
static readonly type = '[Workbasket List] Get all workbaskets\' summary';
|
||||
|
||||
constructor(public forceRequest: boolean = false,
|
||||
public sortBy: string = TaskanaQueryParameters.parameters.KEY,
|
||||
public order: string = Direction.ASC,
|
||||
public name?: string,
|
||||
public nameLike?: string,
|
||||
public descLike?: string,
|
||||
public owner?: string,
|
||||
public ownerLike?: string,
|
||||
public type?: string,
|
||||
public key?: string,
|
||||
public keyLike?: string,
|
||||
public requiredPermission?: string,
|
||||
public allPages: boolean = false) {
|
||||
}
|
||||
}
|
||||
|
||||
export class SelectWorkbasket {
|
||||
static readonly type = '[Workbasket] Select a workbasket';
|
||||
constructor(public workbasketId: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export class DeselectWorkbasket {
|
||||
static readonly type = '[Workbasket] Deselect workbasket';
|
||||
}
|
||||
|
||||
export class CreateWorkbasket {
|
||||
static readonly type = '[Workbasket] Create new workbasket';
|
||||
}
|
||||
|
||||
export class SetActiveAction {
|
||||
static readonly type = '[Workbasket] Specify current action';
|
||||
constructor(public action: ACTION) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
}
|
||||
}
|
||||
|
||||
export class MarkWorkbasketForDeletion {
|
||||
static readonly type = '[Workbasket] Mark selected workbasket for deletion';
|
||||
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';
|
||||
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 UpdateWorkbasketDistributionTargets {
|
||||
static readonly type = '[Workbasket] Update workbasket distribution targets';
|
||||
constructor(public url: string, public distributionTargetsIds: string[]) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
import { Selector } from '@ngxs/store';
|
||||
import { WorkbasketState, WorkbasketStateModel } from './workbasket.state';
|
||||
import { WorkbasketSummary } from '../../models/workbasket-summary';
|
||||
import { WorkbasketSummaryRepresentation } from '../../models/workbasket-summary-representation';
|
||||
import { ACTION } from '../../models/action';
|
||||
import { WorkbasketAccessItemsRepresentation } from '../../models/workbasket-access-items-representation';
|
||||
import { WorkbasketDistributionTargets } from '../../models/workbasket-distribution-targets';
|
||||
import { Workbasket } from '../../models/workbasket';
|
||||
|
||||
export class WorkbasketSelectors {
|
||||
// Workbasket
|
||||
@Selector([WorkbasketState])
|
||||
static selectedWorkbasket(state: WorkbasketStateModel): Workbasket {
|
||||
return { ...state.selectedWorkbasket };
|
||||
}
|
||||
|
||||
@Selector([WorkbasketState])
|
||||
static workbasketsSummary(state: WorkbasketStateModel): WorkbasketSummary[] {
|
||||
return state.paginatedWorkbasketsSummary.workbaskets;
|
||||
}
|
||||
|
||||
@Selector([WorkbasketState])
|
||||
static workbasketsSummaryRepresentation(state: WorkbasketStateModel): WorkbasketSummaryRepresentation {
|
||||
return state.paginatedWorkbasketsSummary;
|
||||
}
|
||||
|
||||
@Selector([WorkbasketState])
|
||||
static workbasketActiveAction(state: WorkbasketStateModel): ACTION {
|
||||
return state.action;
|
||||
}
|
||||
|
||||
@Selector([WorkbasketState])
|
||||
static selectedWorkbasketAndAction(state: WorkbasketStateModel): WorkbasketAndAction {
|
||||
return {
|
||||
selectedWorkbasket: state.selectedWorkbasket,
|
||||
action: state.action
|
||||
};
|
||||
}
|
||||
|
||||
// Workbasket Access Items
|
||||
@Selector([WorkbasketState])
|
||||
static workbasketAccessItems(state: WorkbasketStateModel): WorkbasketAccessItemsRepresentation {
|
||||
return state.workbasketAccessItems;
|
||||
}
|
||||
|
||||
// Workbasket Distribution Targets
|
||||
@Selector([WorkbasketState])
|
||||
static workbasketDistributionTargets(state: WorkbasketStateModel): WorkbasketDistributionTargets {
|
||||
return state.workbasketDistributionTargets;
|
||||
}
|
||||
}
|
||||
|
||||
export interface WorkbasketAndAction {
|
||||
selectedWorkbasket: Workbasket,
|
||||
action: ACTION
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
import { Action, NgxsAfterBootstrap, State, StateContext } from '@ngxs/store';
|
||||
import { take, tap } from 'rxjs/operators';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { Location } from '@angular/common';
|
||||
import { WorkbasketService } from '../../services/workbasket/workbasket.service';
|
||||
import { Workbasket } from '../../models/workbasket';
|
||||
import { CopyWorkbasket,
|
||||
CreateWorkbasket,
|
||||
DeselectWorkbasket,
|
||||
GetWorkbasketAccessItems,
|
||||
GetWorkbasketDistributionTargets,
|
||||
GetWorkbasketsSummary,
|
||||
MarkWorkbasketForDeletion,
|
||||
RemoveDistributionTarget,
|
||||
SaveNewWorkbasket,
|
||||
SelectWorkbasket,
|
||||
SetActiveAction,
|
||||
UpdateWorkbasket, UpdateWorkbasketAccessItems,
|
||||
UpdateWorkbasketDistributionTargets } from './workbasket.actions';
|
||||
import { WorkbasketSummaryRepresentation } from '../../models/workbasket-summary-representation';
|
||||
import { ACTION } from '../../models/action';
|
||||
import { DomainService } from '../../services/domain/domain.service';
|
||||
import { NOTIFICATION_TYPES } from '../../models/notifications';
|
||||
import { NotificationService } from '../../services/notifications/notification.service';
|
||||
import { WorkbasketAccessItemsRepresentation } from '../../models/workbasket-access-items-representation';
|
||||
import { WorkbasketDistributionTargets } from '../../models/workbasket-distribution-targets';
|
||||
import { WorkbasketSummary } from '../../models/workbasket-summary';
|
||||
|
||||
class InitializeStore {
|
||||
static readonly type = '[Workbasket] Initializing state';
|
||||
}
|
||||
|
||||
@State<WorkbasketStateModel>({ name: 'workbasket' })
|
||||
export class WorkbasketState implements NgxsAfterBootstrap {
|
||||
constructor(
|
||||
private workbasketService: WorkbasketService,
|
||||
private domainService: DomainService,
|
||||
private location: Location,
|
||||
private notificationService: NotificationService
|
||||
) {
|
||||
}
|
||||
|
||||
@Action(GetWorkbasketsSummary)
|
||||
getWorkbasketsSummary(ctx: StateContext<WorkbasketStateModel>, action: GetWorkbasketsSummary): Observable<any> {
|
||||
return this.workbasketService.getWorkBasketsSummary(action.forceRequest,
|
||||
action.sortBy, action.order, action.name, action.nameLike, action.descLike, action.owner, action.ownerLike,
|
||||
action.type, action.key, action.keyLike, action.requiredPermission, action.allPages).pipe(
|
||||
take(1), tap(paginatedWorkbasketsSummary => {
|
||||
ctx.patchState(
|
||||
{ paginatedWorkbasketsSummary }
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Action(SelectWorkbasket)
|
||||
selectWorkbasket(ctx: StateContext<WorkbasketStateModel>, action: SelectWorkbasket): Observable<any> {
|
||||
this.location.go(this.location.path().replace(/(workbaskets).*/g, `workbaskets/(detail:${action.workbasketId})`));
|
||||
const id = action.workbasketId;
|
||||
if (typeof id !== 'undefined') {
|
||||
return this.workbasketService.getWorkBasket(id).pipe(take(1), tap(
|
||||
selectedWorkbasket => {
|
||||
ctx.patchState({
|
||||
selectedWorkbasket,
|
||||
action: ACTION.READ
|
||||
});
|
||||
}
|
||||
));
|
||||
}
|
||||
return of(null);
|
||||
}
|
||||
|
||||
@Action(DeselectWorkbasket)
|
||||
deselectWorkbasket(ctx: StateContext<WorkbasketStateModel>): Observable<any> {
|
||||
this.location.go(this.location.path().replace(/(workbaskets).*/g, 'workbaskets'));
|
||||
ctx.patchState({
|
||||
selectedWorkbasket: undefined,
|
||||
action: ACTION.READ
|
||||
});
|
||||
return of(null);
|
||||
}
|
||||
|
||||
@Action(CreateWorkbasket)
|
||||
createWorkbasket(ctx: StateContext<WorkbasketStateModel>): Observable<any> {
|
||||
this.location.go(this.location.path().replace(/(workbaskets).*/g, 'workbaskets/(detail:new-workbasket)'));
|
||||
ctx.patchState({
|
||||
selectedWorkbasket: undefined,
|
||||
action: ACTION.CREATE
|
||||
});
|
||||
return of(null);
|
||||
}
|
||||
|
||||
@Action(SetActiveAction)
|
||||
setActiveAction(ctx: StateContext<WorkbasketStateModel>, action: SetActiveAction): Observable<any> {
|
||||
ctx.patchState({ action: action.action });
|
||||
return of(null);
|
||||
}
|
||||
|
||||
@Action(SaveNewWorkbasket)
|
||||
saveNewWorkbasket(ctx: StateContext<WorkbasketStateModel>, action: SaveNewWorkbasket): Observable<any> {
|
||||
return this.workbasketService.createWorkbasket(action.workbasket).pipe(take(1), tap(
|
||||
workbasketUpdated => {
|
||||
this.notificationService.showToast(
|
||||
NOTIFICATION_TYPES.SUCCESS_ALERT_11,
|
||||
new Map<string, string>([['workbasketKey', workbasketUpdated.key]])
|
||||
);
|
||||
|
||||
this.selectWorkbasket(ctx, workbasketUpdated.workbasketId);
|
||||
this.location.go(this.location.path().replace(/(workbaskets).*/g, 'workbaskets'));
|
||||
}, error => {
|
||||
this.notificationService.triggerError(NOTIFICATION_TYPES.CREATE_ERR_2, error);
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
@Action(CopyWorkbasket)
|
||||
copyWorkbasket(ctx: StateContext<WorkbasketStateModel>, action: CopyWorkbasket): Observable<any> {
|
||||
this.location.go(this.location.path().replace(/(workbaskets).*/g, 'workbaskets/(detail:new-workbasket)'));
|
||||
ctx.patchState({
|
||||
action: ACTION.COPY
|
||||
});
|
||||
return of(null);
|
||||
}
|
||||
|
||||
@Action(UpdateWorkbasket)
|
||||
updateWorkbasket(ctx: StateContext<WorkbasketStateModel>, action: UpdateWorkbasket): Observable<any> {
|
||||
return this.workbasketService.updateWorkbasket(action.url, action.workbasket).pipe(take(1), tap(
|
||||
updatedWorkbasket => {
|
||||
this.notificationService.showToast(
|
||||
NOTIFICATION_TYPES.SUCCESS_ALERT_10,
|
||||
new Map<string, string>([['workbasketKey', updatedWorkbasket.key]])
|
||||
);
|
||||
|
||||
const paginatedWorkbasketSummary = { ...ctx.getState().paginatedWorkbasketsSummary };
|
||||
paginatedWorkbasketSummary.workbaskets = updateWorkbasketSummaryRepresentation(
|
||||
paginatedWorkbasketSummary.workbaskets, action.workbasket
|
||||
);
|
||||
|
||||
ctx.patchState({
|
||||
selectedWorkbasket: updatedWorkbasket,
|
||||
paginatedWorkbasketsSummary: paginatedWorkbasketSummary
|
||||
});
|
||||
}, error => {
|
||||
this.notificationService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_4, error);
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
@Action(RemoveDistributionTarget)
|
||||
removeDistributionTarget(ctx: StateContext<WorkbasketStateModel>, action: RemoveDistributionTarget): Observable<any> {
|
||||
return this.workbasketService.removeDistributionTarget(action.url).pipe(take(1), tap(
|
||||
() => {
|
||||
this.notificationService.showToast(
|
||||
NOTIFICATION_TYPES.SUCCESS_ALERT_9,
|
||||
new Map<string, string>([['workbasketId', ctx.getState().selectedWorkbasket.workbasketId]])
|
||||
);
|
||||
}, error => {
|
||||
this.notificationService.triggerError(NOTIFICATION_TYPES.REMOVE_ERR_2,
|
||||
error,
|
||||
new Map<String, String>([['workbasketId', ctx.getState().selectedWorkbasket.workbasketId]]));
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
@Action(MarkWorkbasketForDeletion)
|
||||
deleteWorkbasket(ctx: StateContext<WorkbasketStateModel>, action: MarkWorkbasketForDeletion): Observable<any> {
|
||||
return this.workbasketService.markWorkbasketForDeletion(action.url).pipe(take(1), tap(
|
||||
response => {
|
||||
if (response.status === 202) {
|
||||
this.notificationService.triggerError(NOTIFICATION_TYPES.MARK_ERR,
|
||||
undefined,
|
||||
new Map<String, String>([['workbasketId', ctx.getState().selectedWorkbasket.workbasketId]]));
|
||||
} else {
|
||||
this.notificationService.showToast(
|
||||
NOTIFICATION_TYPES.SUCCESS_ALERT_12,
|
||||
new Map<string, string>([['workbasketId', ctx.getState().selectedWorkbasket.workbasketId]])
|
||||
);
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
@Action(GetWorkbasketAccessItems)
|
||||
getWorkbasketAccessItems(ctx: StateContext<WorkbasketStateModel>, action: GetWorkbasketAccessItems): Observable<any> {
|
||||
return this.workbasketService.getWorkBasketAccessItems(action.url).pipe(take(1), tap(
|
||||
workbasketAccessItemsRepresentation => {
|
||||
ctx.patchState({
|
||||
workbasketAccessItems: workbasketAccessItemsRepresentation
|
||||
});
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
@Action(UpdateWorkbasketAccessItems)
|
||||
updateWorkbasketAccessItems(ctx: StateContext<WorkbasketStateModel>,
|
||||
action: UpdateWorkbasketAccessItems): Observable<any> {
|
||||
return this.workbasketService.updateWorkBasketAccessItem(action.url, action.workbasketAccessItems)
|
||||
.pipe(take(1), tap(workbasketAccessItems => {
|
||||
ctx.patchState({
|
||||
workbasketAccessItems
|
||||
});
|
||||
this.notificationService.showToast(NOTIFICATION_TYPES.SUCCESS_ALERT_7,
|
||||
new Map<string, string>([['workbasketKey', ctx.getState().selectedWorkbasket.key]]));
|
||||
}, error => {
|
||||
this.notificationService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_2, error);
|
||||
}));
|
||||
}
|
||||
|
||||
@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(UpdateWorkbasketDistributionTargets)
|
||||
updateWorkbasketDistributionTargets(
|
||||
ctx: StateContext<WorkbasketStateModel>,
|
||||
action: UpdateWorkbasketDistributionTargets
|
||||
): Observable<any> {
|
||||
return this.workbasketService.updateWorkBasketsDistributionTargets(action.url, action.distributionTargetsIds).pipe(take(1), tap(
|
||||
updatedWorkbasketsDistributionTargets => {
|
||||
this.notificationService.showToast(
|
||||
NOTIFICATION_TYPES.SUCCESS_ALERT_8,
|
||||
new Map<string, string>([['workbasketName', ctx.getState().selectedWorkbasket.name]])
|
||||
);
|
||||
}, error => {
|
||||
this.notificationService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_3, error);
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
ngxsAfterBootstrap(ctx?: StateContext<any>): void {
|
||||
ctx.dispatch(new InitializeStore());
|
||||
}
|
||||
}
|
||||
|
||||
function updateWorkbasketSummaryRepresentation(
|
||||
workbasketsSummary: WorkbasketSummary[],
|
||||
selectedWorkbasket: Workbasket
|
||||
) {
|
||||
return workbasketsSummary.map(w => {
|
||||
if (w.workbasketId === selectedWorkbasket.workbasketId) {
|
||||
const workbasketSummary: WorkbasketSummary = selectedWorkbasket;
|
||||
return workbasketSummary;
|
||||
}
|
||||
return w;
|
||||
});
|
||||
}
|
||||
|
||||
export interface WorkbasketStateModel {
|
||||
paginatedWorkbasketsSummary: WorkbasketSummaryRepresentation,
|
||||
selectedWorkbasket: Workbasket,
|
||||
action: ACTION,
|
||||
workbasketAccessItems: WorkbasketAccessItemsRepresentation,
|
||||
workbasketDistributionTargets: WorkbasketDistributionTargets
|
||||
}
|
Loading…
Reference in New Issue