TSK-621 - Make classification categories configurable by type

This commit is contained in:
Jose Ignacio Recuerda Cambil 2018-07-30 16:39:38 +02:00 committed by Holger Hagen
parent 106cc050ca
commit 2dbc0de402
22 changed files with 190 additions and 129 deletions

View File

@ -95,8 +95,7 @@ public class TaskanaEngineConfiguration {
// List of configured classification types
protected List<String> classificationTypes = new ArrayList<String>();
// List of configured classification categories
protected List<String> classificationCategories = new ArrayList<String>();
protected Map<String, List<String>> classificationCategoriesByTypeMap = new HashMap<String, List<String>>();
public TaskanaEngineConfiguration(DataSource dataSource, boolean useManagedTransactions, String schemaName)
throws SQLException {
@ -234,11 +233,20 @@ public class TaskanaEngineConfiguration {
}
private void initClassificationCategories(Properties props) {
String classificationCategoryNames = props.getProperty(TASKANA_CLASSIFICATION_CATEGORIES_PROPERTY);
if (classificationCategoryNames != null && !classificationCategoryNames.isEmpty()) {
StringTokenizer st = new StringTokenizer(classificationCategoryNames, ",");
while (st.hasMoreTokens()) {
classificationCategories.add(st.nextToken().trim().toUpperCase());
if (classificationTypes != null && !classificationTypes.isEmpty()) {
String classificationCategoryNames;
StringTokenizer st;
List<String> classificationCategoriesAux;
for (String type : classificationTypes) {
classificationCategoriesAux = new ArrayList<>();
classificationCategoryNames = props.getProperty(TASKANA_CLASSIFICATION_CATEGORIES_PROPERTY + "." + type.toLowerCase());
if (classificationCategoryNames != null && !classificationCategoryNames.isEmpty()) {
st = new StringTokenizer(classificationCategoryNames, ",");
while (st.hasMoreTokens()) {
classificationCategoriesAux.add(st.nextToken().trim().toUpperCase());
}
classificationCategoriesByTypeMap.put(type, classificationCategoriesAux);
}
}
}
LOGGER.debug("Configured classification categories : {}", domains);
@ -432,12 +440,19 @@ public class TaskanaEngineConfiguration {
this.classificationTypes = classificationTypes;
}
public List<String> getClassificationCategories() {
public List<String> getAllClassificationCategories() {
List<String> classificationCategories = new ArrayList<>();
for (Map.Entry<String, List<String>> type : this.classificationCategoriesByTypeMap.entrySet()) {
classificationCategories.addAll(type.getValue());
}
return classificationCategories;
}
public void setClassificationCategories(List<String> classificationCategories) {
this.classificationCategories = classificationCategories;
public List<String> getClassificationCategoriesByType(String type) {
return classificationCategoriesByTypeMap.get(type);
}
public void setClassificationCategoriesByType(Map<String, List<String>> classificationCategoriesByType) {
this.classificationCategoriesByTypeMap = classificationCategoriesByType;
}
public Instant getTaskCleanupJobFirstRun() {

View File

@ -290,8 +290,8 @@ public class ClassificationServiceImpl implements ClassificationService {
}
if (classification.getCategory() != null
&& !taskanaEngine.getConfiguration().getClassificationCategories().contains(classification.getCategory())) {
throw new InvalidArgumentException("Given classification category " + classification.getCategory()
&& !taskanaEngine.getConfiguration().getClassificationCategoriesByType(classification.getType()).contains(classification.getCategory())) {
throw new InvalidArgumentException("Given classification category " + classification.getCategory() + " with type " + classification.getType()
+ " is not valid according to the configuration.");
}

View File

@ -42,12 +42,12 @@ public class TaskanaConfigAccTest extends TaskanaEngineImpl {
@Test
public void testClassificationCategories() {
assertEquals(4, getConfiguration().getClassificationCategories().size());
assertTrue(getConfiguration().getClassificationCategories().contains("EXTERNAL"));
assertTrue(getConfiguration().getClassificationCategories().contains("MANUAL"));
assertTrue(getConfiguration().getClassificationCategories().contains("AUTOMATIC"));
assertTrue(getConfiguration().getClassificationCategories().contains("PROCESS"));
assertFalse(getConfiguration().getClassificationCategories().contains("manual"));
assertEquals(4, getConfiguration().getClassificationCategoriesByType("TASK").size());
assertTrue(getConfiguration().getClassificationCategoriesByType("TASK").contains("EXTERNAL"));
assertTrue(getConfiguration().getClassificationCategoriesByType("TASK").contains("MANUAL"));
assertTrue(getConfiguration().getClassificationCategoriesByType("TASK").contains("AUTOMATIC"));
assertTrue(getConfiguration().getClassificationCategoriesByType("TASK").contains("PROCESS"));
assertFalse(getConfiguration().getClassificationCategoriesByType("TASK").contains("manual"));
}
}

View File

@ -6,7 +6,8 @@ taskana.roles.monitor=john|teamlead_2 | monitor
taskana.domains= Domain_A , DOMAIN_B
taskana.classification.types= TASK , document
taskana.classification.categories= EXTERNAL , manual, autoMAtic ,Process
taskana.classification.categories.task= EXTERNAL, manual, autoMAtic, Process
taskana.classification.categories.document= EXTERNAL
taskana.jobs.maxRetries=3
taskana.jobs.batchSize=50

View File

@ -4,7 +4,8 @@ taskana.roles.businessadmin=max|Moritz|businessadmin
taskana.domains= Domain_A , DOMAIN_B
taskana.classification.types= TASK , document
taskana.classification.categories= EXTERNAL , manual, autoMAtic ,Process
taskana.classification.categories.task= EXTERNAL, manual, autoMAtic, Process
taskana.classification.categories.document= EXTERNAL
taskana.jobs.cleanup.schedule=0 0 3 * * *
taskana.jobs.cleanup.runEvery=P1D

View File

@ -4,7 +4,8 @@ taskana.roles.businessadmin=max|Moritz|businessadmin
taskana.roles.monitor=john|teamlead_2 | monitor
taskana.domains=DOMAIN_A,DOMAIN_B,DOMAIN_C
taskana.classification.types=TASK,DOCUMENT
taskana.classification.categories= EXTERNAL , manual, autoMAtic ,Process
taskana.classification.categories.task= EXTERNAL, manual, autoMAtic, Process
taskana.classification.categories.document= EXTERNAL
taskana.jobs.maxRetries=3
taskana.jobs.batchSize=50

View File

@ -73,7 +73,7 @@ public class TaskanaEngineControllerIntTest {
headers.add("Authorization", "Basic dGVhbWxlYWRfMTp0ZWFtbGVhZF8x");
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<List<String>> response = template.exchange(
"http://127.0.0.1:" + port + "/v1/classification-categories", HttpMethod.GET, request,
"http://127.0.0.1:" + port + "/v1/classification-categories/?type=TASK", HttpMethod.GET, request,
new ParameterizedTypeReference<List<String>>() {
});
assertTrue(response.getBody().contains("MANUAL"));

View File

@ -214,7 +214,7 @@
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
</dependency>
</dependencies>
<build>

View File

@ -34,8 +34,11 @@ public class TaskanaEngineController {
}
@GetMapping(path = "/v1/classification-categories", produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<List<String>> getClassificationCategories() {
return new ResponseEntity<>(taskanaEngineConfiguration.getClassificationCategories(), HttpStatus.OK);
public ResponseEntity<List<String>> getClassificationCategories(String type) {
if (type != null) {
return new ResponseEntity<>(taskanaEngineConfiguration.getClassificationCategoriesByType(type), HttpStatus.OK);
}
return new ResponseEntity<>(taskanaEngineConfiguration.getAllClassificationCategories(), HttpStatus.OK);
}
@GetMapping(path = "/v1/classification-types", produces = {MediaType.APPLICATION_JSON_VALUE})

View File

@ -30,7 +30,6 @@ import {SavingWorkbasketService} from './services/saving-workbaskets/saving-work
import {ClassificationDefinitionService} from './services/classification-definition/classification-definition.service';
import {WorkbasketDefinitionService} from './services/workbasket-definition/workbasket-definition.service';
import {ClassificationsService} from './services/classifications/classifications.service';
import {ClassificationTypesService} from './services/classification-types/classification-types.service';
import {ClassificationCategoriesService} from './services/classification-categories-service/classification-categories.service';
const MODULES = [
@ -68,7 +67,6 @@ const DECLARATIONS = [
WorkbasketDefinitionService,
SavingWorkbasketService,
ClassificationsService,
ClassificationTypesService,
ClassificationCategoriesService,
]
})

View File

@ -24,11 +24,9 @@ import { TreeNodeModel } from 'app/models/tree-node';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { AlertService } from 'app/services/alert/alert.service';
import { TreeService } from 'app/services/tree/tree.service';
import { ClassificationTypesService } from 'app/administration/services/classification-types/classification-types.service';
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
@Component({
selector: 'taskana-dummy-detail',
template: 'dummydetail'
@ -45,7 +43,7 @@ describe('ClassificationDetailsComponent', () => {
let fixture: ComponentFixture<ClassificationDetailsComponent>;
const treeNodes: Array<TreeNodeModel> = new Array(new TreeNodeModel());
let classificationsService, classificationTypesService, classificationCategoriesService,
let classificationsService, classificationCategoriesService,
treeService, removeConfirmationService;
beforeEach(done => {
@ -54,7 +52,7 @@ describe('ClassificationDetailsComponent', () => {
imports: [FormsModule, HttpClientModule, RouterTestingModule.withRoutes(routes), AngularSvgIconModule],
declarations: [ClassificationDetailsComponent, DummyDetailComponent],
providers: [MasterAndDetailService, RequestInProgressService, ClassificationsService, HttpClient, ErrorModalService, AlertService,
TreeService, ClassificationTypesService, ClassificationCategoriesService,
TreeService, ClassificationCategoriesService,
CustomFieldsService]
})
};
@ -62,12 +60,11 @@ describe('ClassificationDetailsComponent', () => {
fixture = TestBed.createComponent(ClassificationDetailsComponent);
component = fixture.componentInstance;
classificationsService = TestBed.get(ClassificationsService);
classificationTypesService = TestBed.get(ClassificationTypesService);
classificationCategoriesService = TestBed.get(ClassificationCategoriesService);
classificationsService = TestBed.get(ClassificationsService);
removeConfirmationService = TestBed.get(RemoveConfirmationService);
spyOn(classificationsService, 'getClassifications').and.returnValue(of(treeNodes));
spyOn(classificationTypesService, 'getClassificationTypes').and.returnValue(of([]));
spyOn(classificationCategoriesService, 'getClassificationTypes').and.returnValue(of([]));
spyOn(classificationCategoriesService, 'getCategories').and.returnValue(of(['firstCategory', 'secondCategory']));
spyOn(classificationsService, 'deleteClassification').and.returnValue(of(true));
spyOn(classificationCategoriesService, 'getCategoryIcon').and.returnValue(new Pair('assets/icons/categories/external.svg'));

View File

@ -16,7 +16,6 @@ import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { AlertService } from 'app/services/alert/alert.service';
import { TreeService } from 'app/services/tree/tree.service';
import { ClassificationTypesService } from 'app/administration/services/classification-types/classification-types.service';
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
// tslint:disable:max-line-length
@ -78,7 +77,6 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
private requestInProgressService: RequestInProgressService,
private alertService: AlertService,
private treeService: TreeService,
private classificationTypeService: ClassificationTypesService,
private categoryService: ClassificationCategoriesService,
private domainService: DomainService,
private customFieldsService: CustomFieldsService,
@ -87,7 +85,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.classificationTypeService.getClassificationTypes().subscribe((classificationTypes: Array<string>) => {
this.categoryService.getClassificationTypes().subscribe((classificationTypes: Array<string>) => {
this.classificationTypes = classificationTypes;
})
this.classificationSelectedSubscription = this.classificationsService.getSelectedClassification()
@ -112,7 +110,6 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
this.fillClassificationInformation(this.selectedClassification ? this.selectedClassification : new ClassificationDefinition())
}
if (!this.classification || this.classification.classificationId !== id && id && id !== '') {
this.selectClassification(id);
}
@ -122,7 +119,6 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
this.showDetail = showDetail;
});
this.categoriesSubscription = this.categoryService.getCategories().subscribe((categories: Array<string>) => {
this.categories = categories;
if (categories.length > 0 && this.classification) {
@ -250,7 +246,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
this.classification.parentKey = classificationSelected.key;
this.classification.category = classificationSelected.category;
this.classification.domain = this.domainService.getSelectedDomainValue();
this.selectedClassificationSubscription = this.classificationTypeService.getSelectedClassificationType().subscribe(type => {
this.selectedClassificationSubscription = this.categoryService.getSelectedClassificationType().subscribe(type => {
if (this.classification) { this.classification.type = type; }
});
this.addDateToClassification();

View File

@ -19,7 +19,6 @@ import { ClassificationsService } from 'app/administration/services/classificati
import { ClassificationDefinitionService } from 'app/administration/services/classification-definition/classification-definition.service';
import { DomainService } from 'app/services/domain/domain.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { ClassificationTypesService } from 'app/administration/services/classification-types/classification-types.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { configureTests } from 'app/app.test.configuration';
import {
@ -45,7 +44,7 @@ describe('ClassificationListComponent', () => {
let fixture: ComponentFixture<ClassificationListComponent>;
const treeNodes: Array<TreeNodeModel> = new Array(new TreeNodeModel());
const classificationTypes: Array<string> = new Array<string>('type1', 'type2');
let classificationsService, classificationTypesService, classificationCategoriesService;
let classificationsService, classificationCategoriesService;
beforeEach(done => {
const configure = (testBed: TestBed) => {
@ -55,7 +54,7 @@ describe('ClassificationListComponent', () => {
imports: [HttpClientModule, RouterTestingModule.withRoutes(routes), FormsModule, AngularSvgIconModule],
providers: [
HttpClient, WorkbasketDefinitionService, AlertService, ClassificationsService, DomainService, ClassificationDefinitionService,
ErrorModalService, ClassificationTypesService, RequestInProgressService, ClassificationCategoriesService, TreeService
ErrorModalService, RequestInProgressService, ClassificationCategoriesService, TreeService
]
})
};
@ -64,10 +63,9 @@ describe('ClassificationListComponent', () => {
component = fixture.componentInstance;
classificationsService = testBed.get(ClassificationsService);
classificationTypesService = testBed.get(ClassificationTypesService);
classificationCategoriesService = testBed.get(ClassificationCategoriesService);
spyOn(classificationsService, 'getClassifications').and.returnValue(of(treeNodes));
spyOn(classificationTypesService, 'getClassificationTypes')
spyOn(classificationCategoriesService, 'getClassificationTypes')
.and.returnValue(of(classificationTypes));
spyOn(classificationCategoriesService, 'getCategories').and.returnValue(of(new Array<string>('cat1', 'cat2')));
spyOn(classificationCategoriesService, 'getCategoryIcon').and.returnValue(new Pair('assets/icons/categories/external.svg'));

View File

@ -7,7 +7,6 @@ import { Classification } from 'app/models/classification';
import { TreeNodeModel } from 'app/models/tree-node';
import { ClassificationsService } from 'app/administration/services/classifications/classifications.service';
import { ClassificationTypesService } from 'app/administration/services/classification-types/classification-types.service';
import {
ClassificationCategoriesService
} from 'app/administration/services/classification-categories-service/classification-categories.service';
@ -43,7 +42,6 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
private classificationService: ClassificationsService,
private router: Router,
private route: ActivatedRoute,
private classificationTypeService: ClassificationTypesService,
private categoryService: ClassificationCategoriesService) {
}
@ -53,12 +51,13 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
.subscribe(value => {
this.performRequest(true);
})
this.selectedClassificationSubscription = this.classificationTypeService.getSelectedClassificationType().subscribe(value => {
this.classificationTypeSelected = value;
this.selectedClassificationSubscription = this.categoryService.getSelectedClassificationType().subscribe(value => {
this.classificationTypeSelected = value;
this.performRequest();
})
this.categoriesSubscription = this.categoryService.getCategories().subscribe((categories: Array<string>) => {
this.categoriesSubscription =
this.categoryService.getCategories(this.classificationTypeSelected).subscribe((categories: Array<string>) => {
this.categories = categories;
});
}
@ -66,12 +65,13 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
selectClassificationType(classificationTypeSelected: string) {
this.classifications = [];
this.requestInProgress = true;
this.classificationTypeService.selectClassificationType(classificationTypeSelected);
this.categoryService.selectClassificationType(classificationTypeSelected);
this.classificationService.getClassifications()
.subscribe((classifications: Array<TreeNodeModel>) => {
this.classifications = classifications;
this.requestInProgress = false;
});
});
this.selectClassification(undefined);
}
selectClassification(id: string) {
@ -110,7 +110,7 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
.subscribe((classifications: Array<TreeNodeModel>) => {
this.requestInProgress = false;
this.classifications = classifications;
this.classificationTypeServiceSubscription = this.classificationTypeService.getClassificationTypes()
this.classificationTypeServiceSubscription = this.categoryService.getClassificationTypes()
.subscribe((classificationsTypes: Array<string>) => {
this.classificationsTypes = classificationsTypes;
});

View File

@ -2,34 +2,41 @@ import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from 'environments/environment';
import { Observable , ReplaySubject } from 'rxjs';
import { Observable , ReplaySubject, BehaviorSubject } from 'rxjs';
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
import { Pair } from 'app/models/pair';
@Injectable()
export class ClassificationCategoriesService {
private url = environment.taskanaRestUrl + '/v1/classification-categories';
private dataObs$ = new ReplaySubject<Array<string>>(1);
private mainUrl = environment.taskanaRestUrl;
// categories
private urlCategories = this.mainUrl + '/v1/classification-categories';
private param = '/?type=';
private dataObsCategories$ = new ReplaySubject<Array<string>>(1);
private categoriesObject = new Object();
private missingIcon = 'assets/icons/categories/missing-icon.svg';
private type = 'UNKNOW';
// type
private classificationTypeSelectedValue = 'TASK';
private urlType = this.mainUrl + '/v1/classification-types';
private classificationTypeSelected = new BehaviorSubject<string>(this.classificationTypeSelectedValue);
private dataObsType$ = new ReplaySubject<Array<string>>(1);
constructor(
private httpClient: HttpClient,
private customFieldsService: CustomFieldsService) { }
getCategories(forceRefresh = false): Observable<Array<string>> {
if (!this.dataObs$.observers.length || forceRefresh) {
this.httpClient.get<Array<string>>(this.url).subscribe(
data => { this.dataObs$.next(data); this.categoriesObject = this.getCustomCategoriesObject(data) },
error => {
this.dataObs$.error(error);
this.dataObs$ = new ReplaySubject(1);
}
getCategories(type?: string): Observable<Array<string>> {
if (!this.dataObsCategories$.observers.length || type !== this.type) {
this.httpClient.get<Array<string>>(type ? this.urlCategories + this.param + type : this.urlCategories).subscribe(
data => { this.dataObsCategories$.next(data); this.categoriesObject = this.getCustomCategoriesObject(data); this.type = type; },
error => { this.dataObsCategories$.error(error); this.dataObsCategories$ = new ReplaySubject(1); }
);
}
return this.dataObs$;
return this.dataObsCategories$;
};
getCategoryIcon(category: string): Pair {
@ -47,7 +54,6 @@ export class ClassificationCategoriesService {
this.getDefaultCategoryMap(categories), 'classifications.categories');
}
private getDefaultCategoryMap(categoryList: Array<string>): Object {
const defaultCategoryMap = new Object();
categoryList.forEach(element => {
@ -55,4 +61,27 @@ export class ClassificationCategoriesService {
});
return defaultCategoryMap;
}
getClassificationTypes(forceRefresh = false): Observable<Array<string>> {
if (!this.dataObsType$.observers.length || forceRefresh) {
this.httpClient.get<Array<string>>(this.urlType).subscribe(
data => this.dataObsType$.next(data),
error => {
this.dataObsType$.error(error);
this.dataObsType$ = new ReplaySubject(1);
}
);
}
return this.dataObsType$;
};
selectClassificationType(id: string) {
this.getCategories(id);
this.classificationTypeSelectedValue = id;
this.classificationTypeSelected.next(id);
}
getSelectedClassificationType(): Observable<string> {
return this.classificationTypeSelected.asObservable();
}
}

View File

@ -1,17 +0,0 @@
import { TestBed, inject } from '@angular/core/testing';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { ClassificationTypesService } from './classification-types.service';
describe('ClassificationTypesService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
providers: [HttpClient, ClassificationTypesService]
});
});
it('should be created', inject([ClassificationTypesService], (service: ClassificationTypesService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -1,40 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, BehaviorSubject, ReplaySubject } from 'rxjs';
import { environment } from 'environments/environment';
@Injectable()
export class ClassificationTypesService {
private url = environment.taskanaRestUrl + '/v1/classification-types';
private classificationTypeSelectedValue = 'TASK';
private classificationTypeSelected = new BehaviorSubject<string>(this.classificationTypeSelectedValue);
private dataObs$ = new ReplaySubject<Array<string>>(1);
constructor(private httpClient: HttpClient
) { }
getClassificationTypes(forceRefresh = false): Observable<Array<string>> {
if (!this.dataObs$.observers.length || forceRefresh) {
this.httpClient.get<Array<string>>(this.url).subscribe(
data => this.dataObs$.next(data),
error => {
this.dataObs$.error(error);
this.dataObs$ = new ReplaySubject(1);
}
);
}
return this.dataObs$;
};
selectClassificationType(id: string) {
this.classificationTypeSelectedValue = id;
this.classificationTypeSelected.next(id);
}
getSelectedClassificationType(): Observable<string> {
return this.classificationTypeSelected.asObservable();
}
}

View File

@ -8,7 +8,7 @@ import { Classification } from 'app/models/classification';
import { ClassificationDefinition } from 'app/models/classification-definition';
import { ClassificationResource } from 'app/models/classification-resource';
import { ClassificationTypesService } from '../classification-types/classification-types.service';
import { ClassificationCategoriesService } from '../classification-categories-service/classification-categories.service';
import { DomainService } from 'app/services/domain/domain.service';
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { Direction } from 'app/models/sorting';
@ -22,7 +22,7 @@ export class ClassificationsService {
constructor(
private httpClient: HttpClient,
private classificationTypeService: ClassificationTypesService,
private classificationCategoriesService: ClassificationCategoriesService,
private domainService: DomainService) {
}
@ -58,7 +58,7 @@ export class ClassificationsService {
return this.httpClient.get<ClassificationDefinition>(`${environment.taskanaRestUrl}/v1/classifications/${id}`)
.pipe(tap((classification: ClassificationDefinition) => {
if (classification) {
this.classificationTypeService.selectClassificationType(classification.type);
this.classificationCategoriesService.selectClassificationType(classification.type);
}
}));
}
@ -100,7 +100,7 @@ export class ClassificationsService {
// #endregion
private getClassificationObservable(classificationRef: Observable<any>): Observable<any> {
const classificationTypes = this.classificationTypeService.getSelectedClassificationType();
const classificationTypes = this.classificationCategoriesService.getSelectedClassificationType();
return combineLatest(
classificationRef,
classificationTypes,
@ -132,7 +132,6 @@ export class ClassificationsService {
return roots;
}
private findChildren(parent: any, children: Array<any>) {
if (children[parent.classificationId]) {
parent.children = children[parent.classificationId];

View File

@ -12,4 +12,42 @@ describe('CustomFieldsService', () => {
it('should be created', inject([CustomFieldsService], (service: CustomFieldsService) => {
expect(service).toBeTruthy();
}));
it('should take default icon path', inject([CustomFieldsService], (service: CustomFieldsService) => {
const categoriesData = {'DEFAULT': 'assets/icons/categories/default.svg'}
const returnedValue = service.getCustomObject(categoriesData, undefined);
expect(returnedValue).toBe(categoriesData);
expect(service).toBeTruthy();
}));
it('should take default icon path in merge', inject([CustomFieldsService], (service: CustomFieldsService) => {
const json = require('./taskana-customization-test.json');
service.initCustomFields('EN', json);
const categoriesDefault = json.EN.classifications.categories;
const categoriesData = {
'EXTERNAL': 'assets/icons/categories/external.svg',
'MANUAL': 'assets/icons/categories/manual.svg',
'AUTOMATIC': 'assets/icons/categories/automatic.svg',
'PROCESS': 'assets/icons/categories/external.svg'
};
const returnedValue = service.getCustomObject(categoriesData, 'classifications.categories');
expect(returnedValue).toEqual(categoriesDefault);
expect(service).toBeTruthy();
}));
it('should take merge icon path', inject([CustomFieldsService], (service: CustomFieldsService) => {
const json = require('./taskana-customization-test.json');
service.initCustomFields('EN', json);
const categoriesData = {'DEFAULT': 'assets/icons/categories/default.svg'}
const result = {
'AUTOMATIC': 'assets/icons/categories/automatic.svg',
'DEFAULT': 'assets/icons/categories/default.svg',
'EXTERNAL': 'assets/icons/categories/external.svg',
'MANUAL': 'assets/icons/categories/manual.svg',
'PROCESS': 'assets/icons/categories/process.svg'
};
const returnedValue = service.getCustomObject(categoriesData, 'classifications.categories');
expect(returnedValue).toEqual(result);
expect(service).toBeTruthy();
}));
});

View File

@ -58,6 +58,26 @@ export class CustomFieldsService {
return true;
});
value = this.mergeKeys(value, fallbackObject);
return value;
}
private mergeKeys(defaultObject: Object, newObject: Object) {
const value = new Object();
for (const item of Object.keys(defaultObject)) {
if (!value[item]) {
value[item] = defaultObject[item];
}
}
for (const item of Object.keys(newObject)) {
if (!value[item]) {
value[item] = newObject[item];
}
}
return value;
}

View File

@ -0,0 +1,22 @@
{
"EN": {
"classifications": {
"information": {
"custom1": {
"field": "Classification custom 1",
"visible": true
},
"custom3": {
"field": "",
"visible": false
}
},
"categories": {
"EXTERNAL": "assets/icons/categories/external.svg",
"MANUAL": "assets/icons/categories/manual.svg",
"AUTOMATIC": "assets/icons/categories/automatic.svg",
"PROCESS": "assets/icons/categories/process.svg"
}
}
}
}

View File

@ -59,4 +59,4 @@
}
}
}
}
}