267 lines
9.4 KiB
TypeScript
267 lines
9.4 KiB
TypeScript
import { Action, NgxsAfterBootstrap, State, StateContext } from '@ngxs/store';
|
|
import { Observable, of } from 'rxjs';
|
|
import { mergeMap, take, tap } from 'rxjs/operators';
|
|
import { TaskanaDate } from 'app/shared/util/taskana.date';
|
|
import {
|
|
CategoriesResponse,
|
|
ClassificationCategoriesService
|
|
} from '../../services/classification-categories/classification-categories.service';
|
|
import {
|
|
CopyClassification,
|
|
CreateClassification,
|
|
DeselectClassification,
|
|
GetClassifications,
|
|
RemoveSelectedClassification,
|
|
RestoreSelectedClassification,
|
|
SaveCreatedClassification,
|
|
SaveModifiedClassification,
|
|
SelectClassification,
|
|
SetSelectedClassificationType,
|
|
UpdateClassification
|
|
} from './classification.actions';
|
|
import { ClassificationsService } from '../../services/classifications/classifications.service';
|
|
import { DomainService } from '../../services/domain/domain.service';
|
|
import { Classification } from '../../models/classification';
|
|
import { ClassificationSummary } from '../../models/classification-summary';
|
|
import { ClassificationQueryFilterParameter } from '../../models/classification-query-filter-parameter';
|
|
import { ClassificationQuerySortParameter, Direction, Sorting } from '../../models/sorting';
|
|
|
|
class InitializeStore {
|
|
static readonly type = '[ClassificationState] Initializing state';
|
|
}
|
|
|
|
@State<ClassificationStateModel>({ name: 'classification' })
|
|
export class ClassificationState implements NgxsAfterBootstrap {
|
|
constructor(
|
|
private categoryService: ClassificationCategoriesService,
|
|
private classificationsService: ClassificationsService,
|
|
private domainService: DomainService
|
|
) {}
|
|
|
|
@Action(InitializeStore)
|
|
initializeStore(ctx: StateContext<ClassificationStateModel>): Observable<any> {
|
|
return this.categoryService.getClassificationCategoriesByType().pipe(
|
|
take(1),
|
|
tap((classificationTypes) => {
|
|
ctx.patchState({
|
|
classificationTypes,
|
|
classifications: undefined,
|
|
selectedClassificationType: Object.keys(classificationTypes)[0]
|
|
});
|
|
})
|
|
);
|
|
}
|
|
|
|
@Action(SetSelectedClassificationType)
|
|
setSelectedClassificationType(
|
|
ctx: StateContext<ClassificationStateModel>,
|
|
action: SetSelectedClassificationType
|
|
): Observable<null> {
|
|
if (ctx.getState().classificationTypes[action.selectedType]) {
|
|
ctx.patchState({
|
|
selectedClassificationType: action.selectedType,
|
|
selectedClassification: undefined
|
|
});
|
|
}
|
|
return of(null);
|
|
}
|
|
|
|
@Action(SelectClassification)
|
|
selectClassification(
|
|
ctx: StateContext<ClassificationStateModel>,
|
|
action: SelectClassification
|
|
): Observable<Classification | null> {
|
|
if (typeof action.classificationId !== 'undefined') {
|
|
return this.classificationsService.getClassification(action.classificationId).pipe(
|
|
take(1),
|
|
tap((selectedClassification) =>
|
|
ctx.patchState({
|
|
selectedClassification,
|
|
selectedClassificationType: selectedClassification.type
|
|
})
|
|
)
|
|
);
|
|
}
|
|
return of(null);
|
|
}
|
|
|
|
@Action(DeselectClassification)
|
|
deselectClassification(ctx: StateContext<ClassificationStateModel>): Observable<null> {
|
|
ctx.patchState({
|
|
selectedClassification: undefined
|
|
});
|
|
return of(null);
|
|
}
|
|
|
|
@Action(GetClassifications)
|
|
getClassifications(ctx: StateContext<ClassificationStateModel>): Observable<any> {
|
|
const { selectedClassificationType } = ctx.getState();
|
|
return this.domainService.getSelectedDomain().pipe(
|
|
mergeMap((domain) => {
|
|
const filter: ClassificationQueryFilterParameter = {
|
|
domain: [domain],
|
|
type: [selectedClassificationType]
|
|
};
|
|
const sort: Sorting<ClassificationQuerySortParameter> = {
|
|
'sort-by': ClassificationQuerySortParameter.KEY,
|
|
order: Direction.ASC
|
|
};
|
|
return this.classificationsService.getClassifications(filter, sort).pipe(
|
|
take(1),
|
|
tap((list) => ctx.patchState({ classifications: list.classifications }))
|
|
);
|
|
}),
|
|
tap(() => this.domainService.domainChangedComplete())
|
|
);
|
|
}
|
|
|
|
@Action(SaveCreatedClassification)
|
|
// 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(
|
|
take(1),
|
|
tap((classification) =>
|
|
ctx.patchState({
|
|
classifications: [...ctx.getState().classifications, classification],
|
|
selectedClassification: classification
|
|
})
|
|
)
|
|
);
|
|
}
|
|
|
|
@Action(SaveModifiedClassification)
|
|
saveClassification(ctx: StateContext<ClassificationStateModel>, action: SaveModifiedClassification): Observable<any> {
|
|
return this.classificationsService.putClassification(action.classification).pipe(
|
|
take(1),
|
|
tap((savedClassification) =>
|
|
ctx.patchState({
|
|
classifications: updateClassificationList(ctx.getState().classifications, savedClassification),
|
|
selectedClassification: savedClassification
|
|
})
|
|
)
|
|
);
|
|
}
|
|
|
|
@Action(RestoreSelectedClassification)
|
|
restoreSelectedClassification(
|
|
ctx: StateContext<ClassificationStateModel>,
|
|
action: RestoreSelectedClassification
|
|
): Observable<any> {
|
|
const state = ctx.getState();
|
|
|
|
// 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(CreateClassification)
|
|
newCreateClassification(ctx: StateContext<ClassificationStateModel>): Observable<null> {
|
|
// Initialization of a new classification
|
|
const state: ClassificationStateModel = ctx.getState();
|
|
const date = TaskanaDate.getDate();
|
|
const initialClassification: Classification = {
|
|
type: state.selectedClassificationType,
|
|
category: state.classificationTypes[state.selectedClassificationType][0],
|
|
created: date,
|
|
modified: date,
|
|
domain: this.domainService.getSelectedDomainValue()
|
|
};
|
|
if (state.selectedClassification) {
|
|
initialClassification.parentId = state.selectedClassification.classificationId;
|
|
initialClassification.parentKey = state.selectedClassification.key;
|
|
}
|
|
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);
|
|
}
|
|
|
|
@Action(RemoveSelectedClassification)
|
|
removeSelectedClassification(ctx: StateContext<ClassificationStateModel>): Observable<any> {
|
|
const sel = ctx.getState().selectedClassification;
|
|
return this.classificationsService.deleteClassification(sel.classificationId).pipe(
|
|
take(1),
|
|
tap(() => {
|
|
const classifications = ctx
|
|
.getState()
|
|
.classifications.filter((el) => el.classificationId !== sel.classificationId);
|
|
ctx.patchState({ selectedClassification: undefined, classifications });
|
|
})
|
|
);
|
|
}
|
|
|
|
@Action(UpdateClassification)
|
|
updateClassification(
|
|
ctx: StateContext<ClassificationStateModel>,
|
|
action: SaveModifiedClassification
|
|
): Observable<any> {
|
|
return this.classificationsService.putClassification(action.classification).pipe(
|
|
take(1),
|
|
tap((classification) => {
|
|
const state = ctx.getState();
|
|
let { selectedClassification } = state;
|
|
if (selectedClassification && selectedClassification.classificationId === classification.classificationId) {
|
|
selectedClassification = classification;
|
|
}
|
|
ctx.patchState({
|
|
classifications: updateClassificationList(state.classifications, classification),
|
|
selectedClassification
|
|
});
|
|
})
|
|
);
|
|
}
|
|
|
|
// initialize after Startup service has configured the taskanaRestUrl properly.
|
|
ngxsAfterBootstrap(ctx: StateContext<ClassificationStateModel>): Observable<null> {
|
|
ctx.dispatch(new InitializeStore());
|
|
return of(null);
|
|
}
|
|
}
|
|
|
|
function updateClassificationList(classifications: ClassificationSummary[], classification: Classification) {
|
|
return classifications.map((c) => {
|
|
if (c.classificationId === classification.classificationId) {
|
|
return classification;
|
|
}
|
|
return c;
|
|
});
|
|
}
|
|
|
|
export interface ClassificationStateModel {
|
|
classifications: ClassificationSummary[];
|
|
selectedClassification: Classification;
|
|
selectedClassificationType: string;
|
|
classificationTypes: CategoriesResponse;
|
|
badgeMessage: string;
|
|
}
|