TSK-1291: Removing action property in store to make the code cleaner

This commit is contained in:
Sofie Hofmann 2020-07-17 13:06:29 +02:00
parent 6e3c9b4560
commit 83a79eab18
11 changed files with 112 additions and 158 deletions

View File

@ -20,7 +20,7 @@
</button> </button>
</div> </div>
<h4 class="panel-header">{{classification.name}}&nbsp; [{{classification.type}}] <h4 class="panel-header">{{classification.name}}&nbsp; [{{classification.type}}]
<span *ngIf="action" class="badge warning"> {{badgeMessage}}</span> <span *ngIf="isCreatingNewClassification" class="badge warning"> {{badgeMessage$ | async}}</span>
</h4> </h4>
</div> </div>
@ -33,9 +33,9 @@
<!-- KEY --> <!-- KEY -->
<div class="form-group required"> <div class="form-group required">
<label for="classification-key" class="control-label">Key</label> <label for="classification-key" class="control-label">Key</label>
<input type="text" required #key="ngModel" [disabled]="!action" class="form-control" <input type="text" required #key="ngModel" [disabled]="!isCreatingNewClassification" class="form-control"
id="classification-key" placeholder="Key" [(ngModel)]="classification.key" name="classification.key"> id="classification-key" placeholder="Key" [(ngModel)]="classification.key" name="classification.key">
<taskana-shared-field-error-display *ngIf="action" [displayError]="!isFieldValid('classification.key')" <taskana-shared-field-error-display *ngIf="isCreatingNewClassification" [displayError]="!isFieldValid('classification.key')"
[validationTrigger]="this.toogleValidationMap.get('classification.key')" errorMessage="* Key is required"> [validationTrigger]="this.toogleValidationMap.get('classification.key')" errorMessage="* Key is required">
</taskana-shared-field-error-display> </taskana-shared-field-error-display>
</div> </div>

View File

@ -17,7 +17,6 @@ import { EngineConfigurationSelectors } from 'app/shared/store/engine-configurat
import { ClassificationSelectors } from 'app/shared/store/classification-store/classification.selectors'; import { ClassificationSelectors } from 'app/shared/store/classification-store/classification.selectors';
import { ClassificationDetailsComponent } from './classification-details.component'; import { ClassificationDetailsComponent } from './classification-details.component';
import { NotificationService } from '../../../shared/services/notifications/notification.service'; import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { ACTION } from '../../../shared/models/action';
@Component({ @Component({
selector: 'taskana-dummy-detail', selector: 'taskana-dummy-detail',
@ -100,20 +99,8 @@ describe('ClassificationDetailsComponent', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should copy the classification without its key', async done => { it('should enable editing of key on create and on copy', async done => {
const startClassification = { ...component.classification }; component.isCreatingNewClassification = true;
const copyButton = fixture.debugElement.nativeElement.querySelector('#copyButton');
copyButton.click();
fixture.detectChanges();
expect(component.classification.name).toEqual(startClassification.name);
expect(component.classification.classificationId).toEqual(startClassification.classificationId);
expect(component.classification.key).toBeNull();
expect(fixture.debugElement.nativeElement.querySelector('#classification-key').disabled).toEqual(false);
done();
});
it('should enable editing of key on create', async done => {
component.action = ACTION.CREATE;
await fixture.detectChanges(); await fixture.detectChanges();
expect(fixture.debugElement.nativeElement.querySelector('#classification-key').disabled).toEqual(false); expect(fixture.debugElement.nativeElement.querySelector('#classification-key').disabled).toEqual(false);
done(); done();

View File

@ -1,12 +1,9 @@
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { Select, Store } from '@ngxs/store'; import { Select, Store } from '@ngxs/store';
import { combineLatest, Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { ACTION } from 'app/shared/models/action';
import { highlight } from 'theme/animations/validation.animation'; import { highlight } from 'theme/animations/validation.animation';
import { ClassificationsService } from 'app/shared/services/classifications/classifications.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service'; import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { DomainService } from 'app/shared/services/domain/domain.service'; import { DomainService } from 'app/shared/services/domain/domain.service';
@ -27,12 +24,12 @@ import { Classification } from '../../../shared/models/classification';
import { customFieldCount } from '../../../shared/models/classification-summary'; import { customFieldCount } from '../../../shared/models/classification-summary';
import { CategoriesResponse } from '../../../shared/services/classification-categories/classification-categories.service'; import { CategoriesResponse } from '../../../shared/services/classification-categories/classification-categories.service';
import { CreateClassification, import { SaveCreatedClassification,
RemoveSelectedClassification, RemoveSelectedClassification,
RestoreSelectedClassification, RestoreSelectedClassification,
SaveClassification, SaveModifiedClassification,
SelectClassification, SelectClassification,
SetActiveAction } from '../../../shared/store/classification-store/classification.actions'; CopyClassification } from '../../../shared/store/classification-store/classification.actions';
@Component({ @Component({
selector: 'taskana-administration-classification-details', selector: 'taskana-administration-classification-details',
@ -42,25 +39,23 @@ import { CreateClassification,
}) })
export class ClassificationDetailsComponent implements OnInit, OnDestroy { export class ClassificationDetailsComponent implements OnInit, OnDestroy {
classification: Classification; classification: Classification;
badgeMessage = '';
requestInProgress = false; requestInProgress = false;
@Select(ClassificationSelectors.selectCategories) categories$: Observable<string[]>; @Select(ClassificationSelectors.selectCategories) categories$: Observable<string[]>;
@Select(EngineConfigurationSelectors.selectCategoryIcons) categoryIcons$: Observable<ClassificationCategoryImages>; @Select(EngineConfigurationSelectors.selectCategoryIcons) categoryIcons$: Observable<ClassificationCategoryImages>;
@Select(ClassificationSelectors.selectedClassificationType) selectedClassificationType$: Observable<string>; @Select(ClassificationSelectors.selectedClassificationType) selectedClassificationType$: Observable<string>;
@Select(ClassificationSelectors.selectClassificationTypesObject) classificationTypes$: Observable<CategoriesResponse>; @Select(ClassificationSelectors.selectClassificationTypesObject) classificationTypes$: Observable<CategoriesResponse>;
@Select(ClassificationSelectors.selectedClassification) selectedClassification$: Observable<Classification>; @Select(ClassificationSelectors.selectedClassification) selectedClassification$: Observable<Classification>;
@Select(ClassificationSelectors.activeAction) action$: Observable<ACTION>; @Select(ClassificationSelectors.getBadgeMessage) badgeMessage$: Observable<string>;
spinnerIsRunning = false; spinnerIsRunning = false;
customFields$: Observable<CustomField[]>; customFields$: Observable<CustomField[]>;
isCreatingNewClassification: boolean = false;
@ViewChild('ClassificationForm', { static: false }) classificationForm: NgForm; @ViewChild('ClassificationForm', { static: false }) classificationForm: NgForm;
toogleValidationMap = new Map<string, boolean>(); toogleValidationMap = new Map<string, boolean>();
action: ACTION;
destroy$ = new Subject<void>(); destroy$ = new Subject<void>();
constructor( constructor(
private classificationsService: ClassificationsService,
private location: Location, private location: Location,
private requestInProgressService: RequestInProgressService, private requestInProgressService: RequestInProgressService,
private domainService: DomainService, private domainService: DomainService,
@ -77,22 +72,10 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
getCustomFields(customFieldCount) getCustomFields(customFieldCount)
); );
combineLatest([this.selectedClassification$, this.action$]).pipe(takeUntil(this.destroy$)) this.selectedClassification$.pipe(takeUntil(this.destroy$))
.subscribe(([classification, action]) => { .subscribe(classification => {
this.action = action; this.classification = { ...classification };
if (this.action === ACTION.CREATE) { this.isCreatingNewClassification = typeof this.classification.classificationId === 'undefined';
this.selectedClassification$.pipe(take(1)).subscribe(initialClassification => {
this.classification = { ...initialClassification };
});
this.badgeMessage = 'Creating new classification';
} else if (this.action === ACTION.COPY) {
this.badgeMessage = `Copying Classification: ${this.classification.name}`;
this.classification = { ...classification };
this.classification.key = null;
} else {
this.badgeMessage = '';
this.classification = { ...classification };
}
}); });
this.importExportService.getImportingFinished().pipe(takeUntil(this.destroy$)).subscribe(() => { this.importExportService.getImportingFinished().pipe(takeUntil(this.destroy$)).subscribe(() => {
@ -120,28 +103,18 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
onRestore() { onRestore() {
this.formsValidatorService.formSubmitAttempt = false; this.formsValidatorService.formSubmitAttempt = false;
if (this.action === ACTION.CREATE) { this.store.dispatch(
this.categories$.pipe(take(1)).subscribe(categories => { new RestoreSelectedClassification(this.classification.classificationId)
const category = categories[0]; ).pipe(take(1)).subscribe(() => {
const { type, created, modified, domain, parentId, parentKey } = this.classification; this.notificationsService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
this.classification = { type, created, category, modified, domain, parentId, parentKey }; });
this.notificationsService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
});
} else {
this.store.dispatch(
new RestoreSelectedClassification(this.classification.classificationId)
).pipe(take(1)).subscribe(() => {
this.notificationsService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
});
}
} }
onCopy() { onCopy() {
if (this.action !== ACTION.CREATE) { if (this.isCreatingNewClassification) {
this.store.dispatch(new SetActiveAction(ACTION.COPY));
this.classification.key = null;
} else {
this.notificationsService.showToast(NOTIFICATION_TYPES.WARNING_CANT_COPY); this.notificationsService.showToast(NOTIFICATION_TYPES.WARNING_CANT_COPY);
} else {
this.store.dispatch(new CopyClassification());
} }
} }
@ -184,10 +157,9 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
private async onSave() { private async onSave() {
this.requestInProgressService.setRequestInProgress(true); this.requestInProgressService.setRequestInProgress(true);
if (this.action) { if (typeof this.classification.classificationId === 'undefined') {
this.classification.classificationId = null; // in case the id has been set, but a new classification should be created
this.store.dispatch( this.store.dispatch(
new CreateClassification(this.classification) new SaveCreatedClassification(this.classification)
).pipe(take(1)).subscribe(store => { ).pipe(take(1)).subscribe(store => {
this.notificationsService.showToast( this.notificationsService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT_2, NOTIFICATION_TYPES.SUCCESS_ALERT_2,
@ -204,7 +176,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
}); });
} else { } else {
try { try {
this.store.dispatch(new SaveClassification(this.classification)) this.store.dispatch(new SaveModifiedClassification(this.classification))
.pipe(take(1)).subscribe(() => { .pipe(take(1)).subscribe(() => {
this.afterRequest(); this.afterRequest();
this.notificationsService.showToast( this.notificationsService.showToast(

View File

@ -1,21 +1,19 @@
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Component, OnDestroy, OnInit } from '@angular/core';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { map, take, takeUntil } from 'rxjs/operators'; import { map, takeUntil } from 'rxjs/operators';
import { Actions, ofActionCompleted, ofActionDispatched, Select, Store } from '@ngxs/store'; import { Actions, ofActionCompleted, ofActionDispatched, Select, Store } from '@ngxs/store';
import { ImportExportService } from 'app/administration/services/import-export.service'; import { ImportExportService } from 'app/administration/services/import-export.service';
import { TaskanaType } from 'app/shared/models/taskana-type'; import { TaskanaType } from 'app/shared/models/taskana-type';
import { Pair } from 'app/shared/models/pair'; import { Pair } from 'app/shared/models/pair';
import { ClassificationsService } from 'app/shared/services/classifications/classifications.service';
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors'; import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
import { ClassificationSelectors } from 'app/shared/store/classification-store/classification.selectors'; import { ClassificationSelectors } from 'app/shared/store/classification-store/classification.selectors';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { ClassificationCategoryImages } from '../../../shared/models/customisation'; import { ClassificationCategoryImages } from '../../../shared/models/customisation';
import { GetClassifications, import { GetClassifications,
SetActiveAction } from '../../../shared/store/classification-store/classification.actions'; CreateClassification } from '../../../shared/store/classification-store/classification.actions';
import { ACTION } from '../../../shared/models/action';
import { DomainService } from '../../../shared/services/domain/domain.service'; import { DomainService } from '../../../shared/services/domain/domain.service';
import { ClassificationSummary } from '../../../shared/models/classification-summary'; import { ClassificationSummary } from '../../../shared/models/classification-summary';
@ -34,15 +32,12 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
@Select(ClassificationSelectors.selectedClassificationType) classificationTypeSelected$: Observable<string>; @Select(ClassificationSelectors.selectedClassificationType) classificationTypeSelected$: Observable<string>;
@Select(ClassificationSelectors.selectCategories) categories$: Observable<string[]>; @Select(ClassificationSelectors.selectCategories) categories$: Observable<string[]>;
@Select(ClassificationSelectors.classifications) classifications$: Observable<ClassificationSummary[]>; @Select(ClassificationSelectors.classifications) classifications$: Observable<ClassificationSummary[]>;
@Select(ClassificationSelectors.activeAction) activeAction$: Observable<ACTION>;
@Select(EngineConfigurationSelectors.selectCategoryIcons) categoryIcons$: Observable<ClassificationCategoryImages>; @Select(EngineConfigurationSelectors.selectCategoryIcons) categoryIcons$: Observable<ClassificationCategoryImages>;
action: ACTION;
destroy$ = new Subject<void>(); destroy$ = new Subject<void>();
classifications: ClassificationSummary[]; classifications: ClassificationSummary[];
constructor( constructor(
private classificationService: ClassificationsService,
private location: Location, private location: Location,
private importExportService: ImportExportService, private importExportService: ImportExportService,
private store: Store, private store: Store,
@ -79,12 +74,6 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
this.store.dispatch(new GetClassifications()); this.store.dispatch(new GetClassifications());
}); });
this.activeAction$
.pipe(takeUntil(this.destroy$))
.subscribe(action => {
this.action = action;
});
// needed, so that the list updates, when domain gets changed (could be placed anywhere and should be removed, when domain is in store) // needed, so that the list updates, when domain gets changed (could be placed anywhere and should be removed, when domain is in store)
this.domainService.getSelectedDomain().pipe(takeUntil(this.destroy$)).subscribe(domain => { this.domainService.getSelectedDomain().pipe(takeUntil(this.destroy$)).subscribe(domain => {
this.store.dispatch(GetClassifications); this.store.dispatch(GetClassifications);
@ -92,9 +81,7 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
} }
addClassification() { addClassification() {
if (this.action !== ACTION.CREATE) { this.store.dispatch(new CreateClassification());
this.store.dispatch(new SetActiveAction(ACTION.CREATE));
}
this.location.go(this.location.path().replace(/(classifications).*/g, 'classifications/new-classification')); this.location.go(this.location.path().replace(/(classifications).*/g, 'classifications/new-classification'));
} }

View File

@ -4,10 +4,7 @@ import { Observable, Subject } from 'rxjs';
import { Select, Store } from '@ngxs/store'; import { Select, Store } from '@ngxs/store';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { ClassificationSelectors } from '../../../shared/store/classification-store/classification.selectors'; import { ClassificationSelectors } from '../../../shared/store/classification-store/classification.selectors';
import { ACTION } from '../../../shared/models/action'; import { GetClassifications, SelectClassification, CreateClassification } from '../../../shared/store/classification-store/classification.actions';
import { GetClassifications,
SelectClassification,
SetActiveAction } from '../../../shared/store/classification-store/classification.actions';
import { Classification } from '../../../shared/models/classification'; import { Classification } from '../../../shared/models/classification';
@Component({ @Component({
@ -40,7 +37,7 @@ export class ClassificationOverviewComponent implements OnInit, OnDestroy {
.subscribe(() => this.store.dispatch(new GetClassifications())); .subscribe(() => this.store.dispatch(new GetClassifications()));
} }
if (this.routerParams.id && this.routerParams.id.indexOf('new-classification') !== -1) { if (this.routerParams.id && this.routerParams.id.indexOf('new-classification') !== -1) {
this.store.dispatch(new SetActiveAction(ACTION.CREATE)); this.store.dispatch(new CreateClassification());
} }
}); });
} }

View File

@ -7,7 +7,6 @@ import { configureTests } from 'app/app.test.configuration';
import { NgxsModule, Store } from '@ngxs/store'; import { NgxsModule, Store } from '@ngxs/store';
import { ClassificationSelectors } from 'app/shared/store/classification-store/classification.selectors'; import { ClassificationSelectors } from 'app/shared/store/classification-store/classification.selectors';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { ACTION } from 'app/shared/models/action';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { UpdateClassification } from 'app/shared/store/classification-store/classification.actions'; import { UpdateClassification } from 'app/shared/store/classification-store/classification.actions';
import { TaskanaTreeComponent } from './tree.component'; import { TaskanaTreeComponent } from './tree.component';
@ -51,8 +50,6 @@ describe('TaskanaTreeComponent', () => {
switch (selector) { switch (selector) {
case ClassificationSelectors.selectedClassificationId: case ClassificationSelectors.selectedClassificationId:
return of('id4'); return of('id4');
case ClassificationSelectors.activeAction:
return of(ACTION.CREATE);
case ClassificationSelectors.classifications: case ClassificationSelectors.classifications:
return of([{ classificationId: 'id4' }]); return of([{ classificationId: 'id4' }]);
default: default:

View File

@ -27,7 +27,6 @@ import { ClassificationSelectors } from '../../../shared/store/classification-st
import { DeselectClassification, import { DeselectClassification,
SelectClassification, SelectClassification,
UpdateClassification } from '../../../shared/store/classification-store/classification.actions'; UpdateClassification } from '../../../shared/store/classification-store/classification.actions';
import { ACTION } from '../../../shared/models/action';
import { ClassificationTreeService } from '../../services/classification-tree.service'; import { ClassificationTreeService } from '../../services/classification-tree.service';
@Component({ @Component({
@ -44,7 +43,6 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
@Output() switchTaskanaSpinnerEmit = new EventEmitter<boolean>(); @Output() switchTaskanaSpinnerEmit = new EventEmitter<boolean>();
@Select(EngineConfigurationSelectors.selectCategoryIcons) categoryIcons$: Observable<ClassificationCategoryImages>; @Select(EngineConfigurationSelectors.selectCategoryIcons) categoryIcons$: Observable<ClassificationCategoryImages>;
@Select(ClassificationSelectors.selectedClassificationId) selectedClassificationId$: Observable<string>; @Select(ClassificationSelectors.selectedClassificationId) selectedClassificationId$: Observable<string>;
@Select(ClassificationSelectors.activeAction) activeAction$: Observable<ACTION>;
@Select(ClassificationSelectors.classifications) classifications$: Observable<Classification[]>; @Select(ClassificationSelectors.classifications) classifications$: Observable<Classification[]>;
@Select(ClassificationSelectors.selectedClassificationType) classificationTypeSelected$: Observable<string>; @Select(ClassificationSelectors.selectedClassificationType) classificationTypeSelected$: Observable<string>;
@ -68,7 +66,6 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
private filterTextOld: string; private filterTextOld: string;
private filterIconOld = ''; private filterIconOld = '';
private action: ACTION;
private destroy$ = new Subject<void>(); private destroy$ = new Subject<void>();
constructor( constructor(
@ -89,10 +86,6 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
} }
ngOnInit() { ngOnInit() {
this.activeAction$.pipe(takeUntil(this.destroy$)).subscribe(action => {
this.action = action;
});
const computedTreeNodes$: Observable<TreeNodeModel[]> = this.classifications$.pipe( const computedTreeNodes$: Observable<TreeNodeModel[]> = this.classifications$.pipe(
filter(classifications => typeof (classifications) !== 'undefined'), filter(classifications => typeof (classifications) !== 'undefined'),
map(classifications => this.classificationTreeService.transformToTreeNode(classifications)) map(classifications => this.classificationTreeService.transformToTreeNode(classifications))
@ -146,7 +139,7 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
} }
onDeactivate(event: any) { onDeactivate(event: any) {
if (!event.treeModel.activeNodes.length && this.action !== ACTION.CREATE) { if (!event.treeModel.activeNodes.length) {
this.store.dispatch(new DeselectClassification()); this.store.dispatch(new DeselectClassification());
this.location.go(this.location.path().replace(/(classifications).*/g, 'classifications')); this.location.go(this.location.path().replace(/(classifications).*/g, 'classifications'));
} }

View File

@ -3,7 +3,7 @@ import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service'; import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { environment } from 'environments/environment'; import { environment } from 'environments/environment';
import { map, tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { NotificationService } from '../notifications/notification.service'; import { NotificationService } from '../notifications/notification.service';
import { NOTIFICATION_TYPES } from '../../models/notifications'; import { NOTIFICATION_TYPES } from '../../models/notifications';

View File

@ -1,4 +1,3 @@
import { ACTION } from '../../models/action';
import { Classification } from '../../models/classification'; import { Classification } from '../../models/classification';
export class SetSelectedClassificationType { export class SetSelectedClassificationType {
@ -19,12 +18,20 @@ export class DeselectClassification {
export class CreateClassification { export class CreateClassification {
static readonly type = '[Classification] Create a new classification'; static readonly type = '[Classification] Create a new classification';
}
export class CopyClassification {
static readonly type = '[Classification] Copy a classification';
}
export class SaveCreatedClassification {
static readonly type = '[Classification] Save a classification that has been newly created or copied';
constructor(public classification: Classification) { constructor(public classification: Classification) {
} }
} }
export class SaveClassification { export class SaveModifiedClassification {
static readonly type = '[Classification] Save a classification and select it'; static readonly type = '[Classification] Save an existing classification that has been modified';
constructor(public classification: Classification) { constructor(public classification: Classification) {
} }
} }
@ -35,12 +42,6 @@ export class RestoreSelectedClassification {
} }
} }
export class SetActiveAction {
static readonly type = '[Classification] Set the currently active Action';
constructor(public action?: ACTION) {
}
}
export class RemoveSelectedClassification { export class RemoveSelectedClassification {
static readonly type = '[Classification] Remove the selected Classification'; static readonly type = '[Classification] Remove the selected Classification';
} }

View File

@ -1,6 +1,5 @@
import { Selector } from '@ngxs/store'; import { Selector } from '@ngxs/store';
import { ClassificationStateModel, ClassificationState } from './classification.state'; import { ClassificationStateModel, ClassificationState } from './classification.state';
import { ACTION } from '../../models/action';
import { Classification } from '../../models/classification'; import { Classification } from '../../models/classification';
import { CategoriesResponse } from '../../services/classification-categories/classification-categories.service'; import { CategoriesResponse } from '../../services/classification-categories/classification-categories.service';
@ -35,13 +34,13 @@ export class ClassificationSelectors {
return state.selectedClassification; return state.selectedClassification;
} }
@Selector([ClassificationState])
static activeAction(state: ClassificationStateModel): ACTION {
return state.action;
}
@Selector([ClassificationState]) @Selector([ClassificationState])
static selectedClassificationId(state: ClassificationStateModel): string { static selectedClassificationId(state: ClassificationStateModel): string {
return state.selectedClassification.classificationId; return state.selectedClassification.classificationId;
} }
@Selector([ClassificationState])
static getBadgeMessage(state: ClassificationStateModel): string {
return state.badgeMessage;
}
} }

View File

@ -4,18 +4,16 @@ import { take, tap } from 'rxjs/operators';
import { TaskanaDate } from 'app/shared/util/taskana.date'; import { TaskanaDate } from 'app/shared/util/taskana.date';
import { CategoriesResponse, import { CategoriesResponse,
ClassificationCategoriesService } from '../../services/classification-categories/classification-categories.service'; ClassificationCategoriesService } from '../../services/classification-categories/classification-categories.service';
import { CreateClassification, import { SaveCreatedClassification,
DeselectClassification, DeselectClassification,
GetClassifications, GetClassifications, CopyClassification, CreateClassification,
RemoveSelectedClassification, RemoveSelectedClassification,
RestoreSelectedClassification, RestoreSelectedClassification,
SaveClassification, SaveModifiedClassification,
SelectClassification, SelectClassification,
SetActiveAction,
SetSelectedClassificationType, SetSelectedClassificationType,
UpdateClassification } from './classification.actions'; UpdateClassification } from './classification.actions';
import { ClassificationsService } from '../../services/classifications/classifications.service'; import { ClassificationsService } from '../../services/classifications/classifications.service';
import { ACTION } from '../../models/action';
import { DomainService } from '../../services/domain/domain.service'; import { DomainService } from '../../services/domain/domain.service';
import { Classification } from '../../models/classification'; import { Classification } from '../../models/classification';
import { ClassificationSummary } from '../../models/classification-summary'; import { ClassificationSummary } from '../../models/classification-summary';
@ -52,8 +50,7 @@ export class ClassificationState implements NgxsAfterBootstrap {
if (ctx.getState().classificationTypes[action.selectedType]) { if (ctx.getState().classificationTypes[action.selectedType]) {
ctx.patchState({ ctx.patchState({
selectedClassificationType: action.selectedType, selectedClassificationType: action.selectedType,
selectedClassification: undefined, selectedClassification: undefined
action: ACTION.DEFAULT
}); });
} }
return of(null); return of(null);
@ -66,8 +63,7 @@ export class ClassificationState implements NgxsAfterBootstrap {
take(1), take(1),
tap(selectedClassification => ctx.patchState({ tap(selectedClassification => ctx.patchState({
selectedClassification, selectedClassification,
selectedClassificationType: selectedClassification.type, selectedClassificationType: selectedClassification.type
action: ACTION.DEFAULT
})) }))
); );
} }
@ -77,8 +73,7 @@ export class ClassificationState implements NgxsAfterBootstrap {
@Action(DeselectClassification) @Action(DeselectClassification)
deselectClassification(ctx: StateContext<ClassificationStateModel>): Observable<null> { deselectClassification(ctx: StateContext<ClassificationStateModel>): Observable<null> {
ctx.patchState({ ctx.patchState({
selectedClassification: undefined, selectedClassification: undefined
action: ACTION.DEFAULT
}); });
return of(null); return of(null);
} }
@ -94,19 +89,19 @@ export class ClassificationState implements NgxsAfterBootstrap {
); );
} }
@Action(CreateClassification) @Action(SaveCreatedClassification)
createClassification(ctx: StateContext<ClassificationStateModel>, action: CreateClassification): Observable<any> { // this action is called when a copied or a new classification is saved
createClassification(ctx: StateContext<ClassificationStateModel>, action: SaveCreatedClassification): Observable<any> {
return this.classificationsService.postClassification(action.classification).pipe( return this.classificationsService.postClassification(action.classification).pipe(
take(1), tap(classification => ctx.patchState({ take(1), tap(classification => ctx.patchState({
classifications: [...ctx.getState().classifications, classification], classifications: [...ctx.getState().classifications, classification],
selectedClassification: classification, selectedClassification: classification
action: ACTION.DEFAULT
})) }))
); );
} }
@Action(SaveClassification) @Action(SaveModifiedClassification)
saveClassification(ctx: StateContext<ClassificationStateModel>, action: SaveClassification): Observable<any> { saveClassification(ctx: StateContext<ClassificationStateModel>, action: SaveModifiedClassification): Observable<any> {
return this.classificationsService.putClassification(action.classification).pipe( return this.classificationsService.putClassification(action.classification).pipe(
take(1), take(1),
tap(savedClassification => ctx.patchState({ tap(savedClassification => ctx.patchState({
@ -118,33 +113,59 @@ export class ClassificationState implements NgxsAfterBootstrap {
@Action(RestoreSelectedClassification) @Action(RestoreSelectedClassification)
restoreSelectedClassification(ctx: StateContext<ClassificationStateModel>, action: RestoreSelectedClassification): Observable<any> { restoreSelectedClassification(ctx: StateContext<ClassificationStateModel>, action: RestoreSelectedClassification): Observable<any> {
return this.classificationsService.getClassification(action.classificationId).pipe( const state = ctx.getState();
take(1),
tap(selectedClassification => ctx.patchState({ selectedClassification })) // check whether the classification already exists
); // returns true in case the classification was edited or copied
if (state.classifications.some(classification => classification.classificationId === action.classificationId)) {
return this.classificationsService.getClassification(action.classificationId).pipe(
take(1),
tap(selectedClassification => {
ctx.patchState({ selectedClassification });
})
);
}
// the classification is restored to a new classification
const category = state.classificationTypes[state.selectedClassificationType][0];
const { type, created, modified, domain, parentId, parentKey } = state.selectedClassification;
ctx.patchState({ selectedClassification: { type, created, category, modified, domain, parentId, parentKey } });
return of(null);
} }
@Action(SetActiveAction) @Action(CreateClassification)
setActiveAction(ctx: StateContext<ClassificationStateModel>, action: SetActiveAction): Observable<null> { newCreateClassification(ctx: StateContext<ClassificationStateModel>): Observable<null> {
if (action.action === ACTION.CREATE) { // Initialization of a new classification
// Initialization of a new classification const state: ClassificationStateModel = ctx.getState();
const state: ClassificationStateModel = ctx.getState(); const date = TaskanaDate.getDate();
const date = TaskanaDate.getDate(); const initialClassification: Classification = {
const initialClassification: Classification = { type: state.selectedClassificationType,
type: state.selectedClassificationType, category: state.classificationTypes[state.selectedClassificationType][0],
category: state.classificationTypes[state.selectedClassificationType][0], created: date,
created: date, modified: date,
modified: date, domain: this.domainService.getSelectedDomainValue(),
domain: this.domainService.getSelectedDomainValue(), };
}; if (state.selectedClassification) {
if (state.selectedClassification) { initialClassification.parentId = state.selectedClassification.classificationId;
initialClassification.parentId = state.selectedClassification.classificationId; initialClassification.parentKey = state.selectedClassification.key;
initialClassification.parentKey = state.selectedClassification.key;
}
ctx.patchState({ selectedClassification: initialClassification, action: action.action });
} else {
ctx.patchState({ action: action.action });
} }
ctx.patchState({
selectedClassification: initialClassification,
badgeMessage: 'Creating new classification'
});
return of(null);
}
@Action(CopyClassification)
newCopyClassification(ctx: StateContext<ClassificationStateModel>): Observable<null> {
const copy = { ...ctx.getState().selectedClassification };
copy.key = null;
copy.classificationId = undefined;
ctx.patchState({
selectedClassification: copy,
badgeMessage: `Copying Classification: ${copy.name}`
});
return of(null); return of(null);
} }
@ -161,7 +182,7 @@ export class ClassificationState implements NgxsAfterBootstrap {
} }
@Action(UpdateClassification) @Action(UpdateClassification)
updateClassification(ctx: StateContext<ClassificationStateModel>, action: SaveClassification): Observable<any> { updateClassification(ctx: StateContext<ClassificationStateModel>, action: SaveModifiedClassification): Observable<any> {
return this.classificationsService.putClassification(action.classification).pipe( return this.classificationsService.putClassification(action.classification).pipe(
take(1), take(1),
tap( tap(
@ -201,5 +222,5 @@ export interface ClassificationStateModel {
selectedClassification: Classification, selectedClassification: Classification,
selectedClassificationType: string; selectedClassificationType: string;
classificationTypes: CategoriesResponse, classificationTypes: CategoriesResponse,
action: ACTION, badgeMessage: string
} }