TSK-652, TSK-1170, TSK-1023 Fixed various bugs by introducing ngxs state management
TSK-1170 Remove @inputs from classification-types-selector TSK-1170 Import Store in Classification-Detail-Component TSK-1170 Removed getSelectedClassificationType() from category service TSK-1170 Removed getSelectedClassificationType() from category service TSK-1170 Put icons in store TSK-1170 Removed selectCategoryType from service TSK-1170 Refactored classification-category service TSK-1170 Fixed multiple calls of actions TSK-1170 TSK-1170: build ngxs store in parallel to the ngrx store TSK-1170: replaced ngrx store with ngxs store tests are still failing. TSK-1170 Split store into two stores TSK-1170 Fixed tests TSK-1170 added categories service test TSK-1170 Fixed checkstyle and test TSK-1170: minimized diff for classification-details component TSK-1170: replaced state with store observable in classificaiton details TSK-1170 Incorporated requested changes in spec files TSK-1170 Removed @output from classification-types-selector Removed getClassifications() call when selecting a classification type because the code is duplicated in performRequest() TSK-1170 Extracted selectors and actions TSK-1170 Dispatch action in classification-service TSK-1170 Incorporated 'set-value' function dynamically rendering classification types TSK-1170: disabled parent reference while creating classification TSK-1170 fixed two ways binding for classification types TSK-1170 removed console log TSK-1170: Category dropdown shows correct values TSK-1170 Renamed selectors TSK-1170
This commit is contained in:
parent
69fac1bdf4
commit
673f1896da
|
@ -18,6 +18,7 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
@ -82,14 +83,13 @@ public class TaskanaEngineConfiguration {
|
|||
|
||||
// global switch to enable JAAS based authentication and Taskana
|
||||
// authorizations
|
||||
protected boolean securityEnabled = true;
|
||||
protected boolean securityEnabled;
|
||||
protected boolean useManagedTransactions;
|
||||
// List of configured domain names
|
||||
protected List<String> domains = new ArrayList<String>();
|
||||
protected List<String> domains = new ArrayList<>();
|
||||
// List of configured classification types
|
||||
protected List<String> classificationTypes = new ArrayList<String>();
|
||||
protected Map<String, List<String>> classificationCategoriesByTypeMap =
|
||||
new HashMap<String, List<String>>();
|
||||
protected List<String> classificationTypes = new ArrayList<>();
|
||||
protected Map<String, List<String>> classificationCategoriesByTypeMap = new HashMap<>();
|
||||
// Properties for the monitor
|
||||
private boolean germanPublicHolidaysEnabled;
|
||||
private List<LocalDate> customHolidays;
|
||||
|
@ -294,8 +294,13 @@ public class TaskanaEngineConfiguration {
|
|||
return classificationCategories;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getClassificationCategoriesByTypeMap() {
|
||||
return this.classificationCategoriesByTypeMap.entrySet().stream()
|
||||
.collect(Collectors.toMap(Entry::getKey, e -> new ArrayList<>(e.getValue())));
|
||||
}
|
||||
|
||||
public List<String> getClassificationCategoriesByType(String type) {
|
||||
return classificationCategoriesByTypeMap.get(type);
|
||||
return classificationCategoriesByTypeMap.getOrDefault(type, Collections.emptyList());
|
||||
}
|
||||
|
||||
public void setClassificationCategoriesByType(
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package acceptance.config;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -83,9 +83,10 @@ class TaskanaConfigAccTest extends TaskanaEngineImpl {
|
|||
} finally {
|
||||
deleteFile(propertiesFileName);
|
||||
}
|
||||
assertNull(
|
||||
taskanaEngineConfiguration.getClassificationCategoriesByType(
|
||||
taskanaEngineConfiguration.getClassificationTypes().get(0)));
|
||||
assertThat(
|
||||
taskanaEngineConfiguration.getClassificationCategoriesByType(
|
||||
taskanaEngineConfiguration.getClassificationTypes().get(0)))
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -18,10 +18,12 @@ public final class Mapping {
|
|||
URL_MONITOR + "/tasks-classification-report";
|
||||
public static final String URL_MONITOR_TIMESTAMP = URL_MONITOR + "/timestamp-report";
|
||||
public static final String URL_DOMAIN = PRE + "domains";
|
||||
public static final String URL_CLASSIFICATIONCATEGORIES = PRE + "classification-categories";
|
||||
public static final String URL_CLASSIFICATIONTYPES = PRE + "classification-types";
|
||||
public static final String URL_CURRENTUSER = PRE + "current-user-info";
|
||||
public static final String URL_HISTORYENABLED = PRE + "history-provider-enabled";
|
||||
public static final String URL_CLASSIFICATION_CATEGORIES = PRE + "classification-categories";
|
||||
public static final String URL_CLASSIFICATION_TYPES = PRE + "classification-types";
|
||||
public static final String URL_CLASSIFICATION_CATEGORIES_BY_TYPES =
|
||||
PRE + "classifications-by-type";
|
||||
public static final String URL_CURRENT_USER = PRE + "current-user-info";
|
||||
public static final String URL_HISTORY_ENABLED = PRE + "history-provider-enabled";
|
||||
public static final String URL_VERSION = PRE + "version";
|
||||
public static final String URL_TASKS = PRE + "tasks";
|
||||
public static final String URL_TASKS_ID = URL_TASKS + "/{taskId}";
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package pro.taskana.rest;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
@ -46,7 +47,7 @@ public class TaskanaEngineController {
|
|||
return response;
|
||||
}
|
||||
|
||||
@GetMapping(path = Mapping.URL_CLASSIFICATIONCATEGORIES)
|
||||
@GetMapping(path = Mapping.URL_CLASSIFICATION_CATEGORIES)
|
||||
public ResponseEntity<List<String>> getClassificationCategories(String type) {
|
||||
LOGGER.debug("Entry to getClassificationCategories(type = {})", type);
|
||||
ResponseEntity<List<String>> response;
|
||||
|
@ -65,7 +66,7 @@ public class TaskanaEngineController {
|
|||
return response;
|
||||
}
|
||||
|
||||
@GetMapping(path = Mapping.URL_CLASSIFICATIONTYPES)
|
||||
@GetMapping(path = Mapping.URL_CLASSIFICATION_TYPES)
|
||||
public ResponseEntity<List<String>> getClassificationTypes() {
|
||||
ResponseEntity<List<String>> response =
|
||||
ResponseEntity.ok(taskanaEngineConfiguration.getClassificationTypes());
|
||||
|
@ -75,7 +76,17 @@ public class TaskanaEngineController {
|
|||
return response;
|
||||
}
|
||||
|
||||
@GetMapping(path = Mapping.URL_CURRENTUSER)
|
||||
@GetMapping(path = Mapping.URL_CLASSIFICATION_CATEGORIES_BY_TYPES)
|
||||
public ResponseEntity<Map<String, List<String>>> getClassificationCategoriesByTypeMap() {
|
||||
ResponseEntity<Map<String, List<String>>> response =
|
||||
ResponseEntity.ok(taskanaEngineConfiguration.getClassificationCategoriesByTypeMap());
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Exit from getClassificationCategoriesByTypeMap(), returning {}", response);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
@GetMapping(path = Mapping.URL_CURRENT_USER)
|
||||
public ResponseEntity<TaskanaUserInfoResource> getCurrentUserInfo() {
|
||||
LOGGER.debug("Entry to getCurrentUserInfo()");
|
||||
TaskanaUserInfoResource resource = new TaskanaUserInfoResource();
|
||||
|
@ -94,7 +105,7 @@ public class TaskanaEngineController {
|
|||
return response;
|
||||
}
|
||||
|
||||
@GetMapping(path = Mapping.URL_HISTORYENABLED)
|
||||
@GetMapping(path = Mapping.URL_HISTORY_ENABLED)
|
||||
public ResponseEntity<Boolean> getIsHistoryProviderEnabled() {
|
||||
ResponseEntity<Boolean> response = ResponseEntity.ok(taskanaEngine.isHistoryEnabled());
|
||||
LOGGER.debug("Exit from getIsHistoryProviderEnabled(), returning {}", response);
|
||||
|
|
|
@ -65,7 +65,7 @@ class TaskanaEngineControllerRestDocumentation extends BaseRestDocumentation {
|
|||
this.mockMvc
|
||||
.perform(
|
||||
RestDocumentationRequestBuilders.get(
|
||||
restHelper.toUrl(Mapping.URL_CLASSIFICATIONCATEGORIES))
|
||||
restHelper.toUrl(Mapping.URL_CLASSIFICATION_CATEGORIES))
|
||||
.accept("application/json")
|
||||
.header("Authorization", "Basic dGVhbWxlYWRfMTp0ZWFtbGVhZF8x"))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
|
@ -79,7 +79,7 @@ class TaskanaEngineControllerRestDocumentation extends BaseRestDocumentation {
|
|||
void getAllClassificationTypesDocTest() throws Exception {
|
||||
this.mockMvc
|
||||
.perform(
|
||||
RestDocumentationRequestBuilders.get(restHelper.toUrl(Mapping.URL_CLASSIFICATIONTYPES))
|
||||
RestDocumentationRequestBuilders.get(restHelper.toUrl(Mapping.URL_CLASSIFICATION_TYPES))
|
||||
.accept("application/json")
|
||||
.header("Authorization", "Basic dGVhbWxlYWRfMTp0ZWFtbGVhZF8x"))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
|
@ -93,7 +93,7 @@ class TaskanaEngineControllerRestDocumentation extends BaseRestDocumentation {
|
|||
void getCurrentUserInfo() throws Exception {
|
||||
this.mockMvc
|
||||
.perform(
|
||||
RestDocumentationRequestBuilders.get(restHelper.toUrl(Mapping.URL_CURRENTUSER))
|
||||
RestDocumentationRequestBuilders.get(restHelper.toUrl(Mapping.URL_CURRENT_USER))
|
||||
.accept("application/json")
|
||||
.header("Authorization", "Basic dGVhbWxlYWRfMTp0ZWFtbGVhZF8x"))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
|
@ -106,7 +106,7 @@ class TaskanaEngineControllerRestDocumentation extends BaseRestDocumentation {
|
|||
void getHistoryProviderIsEnabled() throws Exception {
|
||||
this.mockMvc
|
||||
.perform(
|
||||
RestDocumentationRequestBuilders.get(restHelper.toUrl(Mapping.URL_HISTORYENABLED))
|
||||
RestDocumentationRequestBuilders.get(restHelper.toUrl(Mapping.URL_HISTORY_ENABLED))
|
||||
.accept("application/json")
|
||||
.header("Authorization", "Basic dGVhbWxlYWRfMTp0ZWFtbGVhZF8x"))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
|
|
|
@ -43,7 +43,7 @@ class TaskanaEngineControllerIntTest {
|
|||
void testClassificationTypes() {
|
||||
ResponseEntity<List<String>> response =
|
||||
template.exchange(
|
||||
restHelper.toUrl(Mapping.URL_CLASSIFICATIONTYPES),
|
||||
restHelper.toUrl(Mapping.URL_CLASSIFICATION_TYPES),
|
||||
HttpMethod.GET,
|
||||
restHelper.defaultRequest(),
|
||||
ParameterizedTypeReference.forType(List.class));
|
||||
|
@ -54,7 +54,7 @@ class TaskanaEngineControllerIntTest {
|
|||
void testClassificationCategories() {
|
||||
ResponseEntity<List<String>> response =
|
||||
template.exchange(
|
||||
restHelper.toUrl(Mapping.URL_CLASSIFICATIONCATEGORIES),
|
||||
restHelper.toUrl(Mapping.URL_CLASSIFICATION_CATEGORIES),
|
||||
HttpMethod.GET,
|
||||
restHelper.defaultRequest(),
|
||||
ParameterizedTypeReference.forType(List.class));
|
||||
|
@ -65,7 +65,7 @@ class TaskanaEngineControllerIntTest {
|
|||
void testGetCurrentUserInfo() {
|
||||
ResponseEntity<TaskanaUserInfoResource> response =
|
||||
template.exchange(
|
||||
restHelper.toUrl(Mapping.URL_CURRENTUSER),
|
||||
restHelper.toUrl(Mapping.URL_CURRENT_USER),
|
||||
HttpMethod.GET,
|
||||
restHelper.defaultRequest(),
|
||||
ParameterizedTypeReference.forType(TaskanaUserInfoResource.class));
|
||||
|
|
|
@ -2358,6 +2358,22 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@ngxs/devtools-plugin": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@ngxs/devtools-plugin/-/devtools-plugin-3.6.2.tgz",
|
||||
"integrity": "sha512-0UUZlpXgEtrHoWNeVQXEvUyC6pW8nTACpqJgecuBjYJMa5imCCUSXdrpear8ztJuWwpLqMUSGk5cICNhKqK59g==",
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"@ngxs/store": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@ngxs/store/-/store-3.6.2.tgz",
|
||||
"integrity": "sha512-al7GU618SAuz2Ul4rFYVDgS1DM0gHReGOGvbnE7LBt4Etz3gsJERNYXPp2bSA7lZGaRPRaFfIHJN+Lm/GikFJw==",
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"@schematics/angular": {
|
||||
"version": "8.3.22",
|
||||
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-8.3.22.tgz",
|
||||
|
@ -3876,6 +3892,29 @@
|
|||
"to-object-path": "^0.3.0",
|
||||
"union-value": "^1.0.0",
|
||||
"unset-value": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extendable": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"set-value": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
|
||||
"integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"extend-shallow": "^2.0.1",
|
||||
"is-extendable": "^0.1.1",
|
||||
"is-plain-object": "^2.0.3",
|
||||
"split-string": "^3.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"caller-callsite": {
|
||||
|
@ -5072,9 +5111,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.3.382",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.382.tgz",
|
||||
"integrity": "sha512-gJfxOcgnBlXhfnUUObsq3n3ReU8CT6S8je97HndYRkKsNZMJJ38zO/pI5aqO7L3Myfq+E3pqPyKK/ynyLEQfBA==",
|
||||
"version": "1.3.390",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.390.tgz",
|
||||
"integrity": "sha512-4RvbM5x+002gKI8sltkqWEk5pptn0UnzekUx8RTThAMPDSb8jjpm6SwGiSnEve7f85biyZl8DMXaipaCxDjXag==",
|
||||
"dev": true
|
||||
},
|
||||
"elliptic": {
|
||||
|
@ -5773,9 +5812,9 @@
|
|||
}
|
||||
},
|
||||
"eslint-module-utils": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz",
|
||||
"integrity": "sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz",
|
||||
"integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^2.6.9",
|
||||
|
@ -6416,9 +6455,9 @@
|
|||
}
|
||||
},
|
||||
"figgy-pudding": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz",
|
||||
"integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==",
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
|
||||
"integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==",
|
||||
"dev": true
|
||||
},
|
||||
"figures": {
|
||||
|
@ -6631,9 +6670,9 @@
|
|||
}
|
||||
},
|
||||
"flatted": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz",
|
||||
"integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
|
||||
"integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
|
||||
"dev": true
|
||||
},
|
||||
"flush-write-stream": {
|
||||
|
@ -6647,9 +6686,9 @@
|
|||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.10.0.tgz",
|
||||
"integrity": "sha512-4eyLK6s6lH32nOvLLwlIOnr9zrL8Sm+OvW4pVTJNoXeGzYIkHVf+pADQi+OJ0E67hiuSLezPVPyBcIZO50TmmQ==",
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz",
|
||||
"integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^3.0.0"
|
||||
|
@ -6954,9 +6993,9 @@
|
|||
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
|
||||
},
|
||||
"handle-thing": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz",
|
||||
"integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
|
||||
"integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==",
|
||||
"dev": true
|
||||
},
|
||||
"har-schema": {
|
||||
|
@ -7165,9 +7204,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"html-escaper": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.1.tgz",
|
||||
"integrity": "sha512-hNX23TjWwD3q56HpWjUHOKj1+4KKlnjv9PcmBUYKVpga+2cnb9nDx/B1o0yO4n+RZXZdiNxzx6B24C9aNMTkkQ==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
|
||||
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
|
||||
"dev": true
|
||||
},
|
||||
"http-cache-semantics": {
|
||||
|
@ -7684,7 +7723,6 @@
|
|||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
|
||||
"integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isobject": "^3.0.1"
|
||||
}
|
||||
|
@ -7767,8 +7805,7 @@
|
|||
"isobject": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
||||
},
|
||||
"isstream": {
|
||||
"version": "0.1.2",
|
||||
|
@ -9740,9 +9777,9 @@
|
|||
}
|
||||
},
|
||||
"node-fetch-npm": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.3.tgz",
|
||||
"integrity": "sha512-DgwoKEsqLnFZtk3ap7GWBHcHwnUhsNmQqEDcdjfQ8GofLEFJ081NAd4Uin3R7RFZBWVJCwHISw1oaEqPgSLloA==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.4.tgz",
|
||||
"integrity": "sha512-iOuIQDWDyjhv9qSDrj9aq/klt6F9z1p2otB3AV7v3zBDcL/x+OfGsvGQZZCcMZbUf4Ujw1xGNQkjvGnVT22cKg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"encoding": "^0.1.11",
|
||||
|
@ -9822,21 +9859,10 @@
|
|||
}
|
||||
},
|
||||
"node-releases": {
|
||||
"version": "1.1.52",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.52.tgz",
|
||||
"integrity": "sha512-snSiT1UypkgGt2wxPqS6ImEUICbNCMb31yaxWrOLXjhlt2z2/IBpaOxzONExqSm4y5oLnAqjjRWu+wsDzK5yNQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver": "^6.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
"version": "1.1.53",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.53.tgz",
|
||||
"integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node-sass": {
|
||||
"version": "4.13.1",
|
||||
|
@ -11018,9 +11044,9 @@
|
|||
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",
|
||||
"integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ=="
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
|
||||
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
|
||||
},
|
||||
"public-encrypt": {
|
||||
"version": "4.0.3",
|
||||
|
@ -11854,26 +11880,11 @@
|
|||
"dev": true
|
||||
},
|
||||
"set-value": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
|
||||
"integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
|
||||
"dev": true,
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/set-value/-/set-value-3.0.2.tgz",
|
||||
"integrity": "sha512-npjkVoz+ank0zjlV9F47Fdbjfj/PfXyVhZvGALWsyIYU/qrMzpi6avjKW3/7KeSU2Df3I46BrN1xOI1+6vW0hA==",
|
||||
"requires": {
|
||||
"extend-shallow": "^2.0.1",
|
||||
"is-extendable": "^0.1.1",
|
||||
"is-plain-object": "^2.0.3",
|
||||
"split-string": "^3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extendable": "^0.1.0"
|
||||
}
|
||||
}
|
||||
"is-plain-object": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"setimmediate": {
|
||||
|
@ -11923,9 +11934,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"signal-exit": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
|
||||
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
|
||||
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
|
||||
},
|
||||
"slash": {
|
||||
"version": "1.0.0",
|
||||
|
@ -12638,24 +12649,46 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"string.prototype.trimleft": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
|
||||
"integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==",
|
||||
"string.prototype.trimend": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.0.tgz",
|
||||
"integrity": "sha512-EEJnGqa/xNfIg05SxiPSqRS7S9qwDhYts1TSLR1BQfYUfPe1stofgGKvwERK9+9yf+PpfBMlpBaCHucXGPQfUA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"function-bind": "^1.1.1"
|
||||
"es-abstract": "^1.17.5"
|
||||
}
|
||||
},
|
||||
"string.prototype.trimleft": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz",
|
||||
"integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.5",
|
||||
"string.prototype.trimstart": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"string.prototype.trimright": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz",
|
||||
"integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==",
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz",
|
||||
"integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"function-bind": "^1.1.1"
|
||||
"es-abstract": "^1.17.5",
|
||||
"string.prototype.trimend": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"string.prototype.trimstart": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.0.tgz",
|
||||
"integrity": "sha512-iCP8g01NFYiiBOnwG1Xc3WZLyoo+RuBymwIlWncShXDDJYWN6DbnM3odslBJdgCdRlq94B5s63NWAZlcn2CS4w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.5"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
|
@ -13322,6 +13355,29 @@
|
|||
"get-value": "^2.0.6",
|
||||
"is-extendable": "^0.1.1",
|
||||
"set-value": "^2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extendable": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"set-value": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
|
||||
"integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"extend-shallow": "^2.0.1",
|
||||
"is-extendable": "^0.1.1",
|
||||
"is-plain-object": "^2.0.3",
|
||||
"split-string": "^3.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"unique-filename": {
|
||||
|
@ -13589,12 +13645,12 @@
|
|||
"dev": true
|
||||
},
|
||||
"watchpack": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz",
|
||||
"integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==",
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.1.tgz",
|
||||
"integrity": "sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chokidar": "^2.0.2",
|
||||
"chokidar": "^2.1.8",
|
||||
"graceful-fs": "^4.1.2",
|
||||
"neo-async": "^2.5.0"
|
||||
},
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
"@angular/platform-browser": "8.2.14",
|
||||
"@angular/platform-browser-dynamic": "8.2.14",
|
||||
"@angular/router": "8.2.14",
|
||||
"@ngxs/devtools-plugin": "3.6.2",
|
||||
"@ngxs/store": "3.6.2",
|
||||
"angular-svg-icon": "7.2.1",
|
||||
"angular-tree-component": "8.5.2",
|
||||
"bootstrap": "4.3.1",
|
||||
|
@ -37,6 +39,7 @@
|
|||
"node-sass": "4.13.1",
|
||||
"popper.js": "1.16.0",
|
||||
"rxjs": "6.5.3",
|
||||
"set-value": "3.0.2",
|
||||
"zone.js": "0.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -26,18 +26,11 @@
|
|||
<th>Append</th>
|
||||
<th>Transfer</th>
|
||||
<th>Distribute</th>
|
||||
<th *ngIf="custom1Field.visible">{{custom1Field.field}}</th>
|
||||
<th *ngIf="custom2Field.visible">{{custom2Field.field}}</th>
|
||||
<th *ngIf="custom3Field.visible">{{custom3Field.field}}</th>
|
||||
<th *ngIf="custom4Field.visible">{{custom4Field.field}}</th>
|
||||
<th *ngIf="custom5Field.visible">{{custom5Field.field}}</th>
|
||||
<th *ngIf="custom6Field.visible">{{custom6Field.field}}</th>
|
||||
<th *ngIf="custom7Field.visible">{{custom7Field.field}}</th>
|
||||
<th *ngIf="custom8Field.visible">{{custom8Field.field}}</th>
|
||||
<th *ngIf="custom9Field.visible">{{custom9Field.field}}</th>
|
||||
<th *ngIf="custom10Field.visible">{{custom10Field.field}}</th>
|
||||
<th *ngIf="custom11Field.visible">{{custom11Field.field}}</th>
|
||||
<th *ngIf="custom12Field.visible">{{custom12Field.field}}</th>
|
||||
<ng-container *ngFor="let customField of customFields$ | async">
|
||||
<th *ngIf="customField.visible">
|
||||
{{customField.field}}
|
||||
</th>
|
||||
</ng-container>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2" class="text-align"><input type="text" formControlName="workbasketKeyFilter" (keyup.enter)="searchForAccessItemsWorkbaskets()"
|
||||
|
@ -74,7 +67,7 @@
|
|||
<td colspan="2">
|
||||
<label class="wrap">{{accessItem.value.workbasketKey}}</label>
|
||||
</td>
|
||||
<td *ngIf="accessIdField.lookupField else accessIdInput" colspan="2" class="text-align text-width taskana-type-ahead">
|
||||
<td *ngIf="(accessItemsCustomization$ | async)?.accessId.lookupField else accessIdInput" colspan="2" class="text-align text-width taskana-type-ahead">
|
||||
<div>
|
||||
<taskana-type-ahead formControlName="accessId" placeHolderMessage="* Access id is required"
|
||||
[validationValue]="toogleValidationAccessIdMap.get(index)" [displayError]="!isFieldValid('accessItem.value.accessId', index)"
|
||||
|
@ -109,60 +102,19 @@
|
|||
<input id="checkbox-{{index}}-4" type="checkbox" formControlName="permDistribute">
|
||||
<label for="checkbox-{{index}}-4"></label>
|
||||
</td>
|
||||
<td *ngIf="custom1Field.visible">
|
||||
<input id="checkbox-{{index}}-5" type="checkbox" formControlName="permCustom1">
|
||||
<label for="checkbox-{{index}}-5"></label>
|
||||
</td>
|
||||
<td *ngIf="custom2Field.visible">
|
||||
<input id="checkbox-{{index}}-6" type="checkbox" formControlName="permCustom2">
|
||||
<label for="checkbox-{{index}}-6"></label>
|
||||
</td>
|
||||
<td *ngIf="custom3Field.visible">
|
||||
<input id="checkbox-{{index}}-7" type="checkbox" formControlName="permCustom3">
|
||||
<label for="checkbox-{{index}}-7"></label>
|
||||
</td>
|
||||
<td *ngIf="custom4Field.visible">
|
||||
<input id="checkbox-{{index}}-8" type="checkbox" formControlName="permCustom4">
|
||||
<label for="checkbox-{{index}}-8"></label>
|
||||
</td>
|
||||
<td *ngIf="custom5Field.visible">
|
||||
<input id="checkbox-{{index}}-9" type="checkbox" formControlName="permCustom5">
|
||||
<label for="checkbox-{{index}}-9"></label>
|
||||
</td>
|
||||
<td *ngIf="custom6Field.visible">
|
||||
<input id="checkbox-{{index}}-10" type="checkbox" formControlName="permCustom6">
|
||||
<label for="checkbox-{{index}}-10"></label>
|
||||
</td>
|
||||
<td *ngIf="custom7Field.visible">
|
||||
<input id="checkbox-{{index}}-11" type="checkbox" formControlName="permCustom7">
|
||||
<label for="checkbox-{{index}}-11"></label>
|
||||
</td>
|
||||
<td *ngIf="custom8Field.visible">
|
||||
<input id="checkbox-{{index}}-12" type="checkbox" formControlName="permCustom8">
|
||||
<label for="checkbox-{{index}}-12"></label>
|
||||
</td>
|
||||
<td *ngIf="custom9Field.visible">
|
||||
<input id="checkbox-{{index}}-13" type="checkbox" formControlName="permCustom9">
|
||||
<label for="checkbox-{{index}}-13"></label>
|
||||
</td>
|
||||
<td *ngIf="custom10Field.visible">
|
||||
<input id="checkbox-{{index}}-14" type="checkbox" formControlName="permCustom10">
|
||||
<label for="checkbox-{{index}}-14"></label>
|
||||
</td>
|
||||
<td *ngIf="custom11Field.visible">
|
||||
<input id="checkbox-{{index}}-15" type="checkbox" formControlName="permCustom11">
|
||||
<label for="checkbox-{{index}}-15"></label>
|
||||
</td>
|
||||
<td *ngIf="custom12Field.visible">
|
||||
<input id="checkbox-{{index}}-16" type="checkbox" formControlName="permCustom12">
|
||||
<label for="checkbox-{{index}}-16"></label>
|
||||
</td>
|
||||
<ng-container *ngFor="let customField of customFields$ | async; let customIndex = index">
|
||||
<td *ngIf="customField.visible">
|
||||
<input id="checkbox-{{index}}-{{customIndex + 5}}" type="checkbox" formControlName="permCustom{{customIndex + 1}}">
|
||||
<label for="checkbox-{{index}}-{{customIndex + 5}}"></label>
|
||||
</td>
|
||||
</ng-container>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<button *ngIf="!isGroup" class="pull-left btn-group" type="button" class="btn btn-primary" data-toggle="modal"
|
||||
data-target="#myModal">
|
||||
<button *ngIf="!isGroup" class="btn btn-primary pull-left btn-group" type="button"
|
||||
data-toggle="modal"
|
||||
data-target="#myModal">
|
||||
Belonging groups
|
||||
</button>
|
||||
<div class="modal" id="myModal">
|
||||
|
|
|
@ -6,6 +6,7 @@ import { FormsValidatorService } from 'app/shared/services/forms/forms-validator
|
|||
import { AccessIdDefinition } from 'app/models/access-id';
|
||||
import { AccessItemsWorkbasketResource } from 'app/models/access-item-workbasket-resource';
|
||||
import { of } from 'rxjs';
|
||||
import { NgxsModule } from '@ngxs/store';
|
||||
import { AccessItemsManagementComponent } from './access-items-management.component';
|
||||
|
||||
|
||||
|
@ -14,20 +15,20 @@ describe('AccessItemsManagementComponent', () => {
|
|||
let fixture: ComponentFixture<AccessItemsManagementComponent>;
|
||||
let accessIdsService;
|
||||
|
||||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
imports: [NgxsModule.forRoot()],
|
||||
declarations: [AccessItemsManagementComponent],
|
||||
providers: [AccessIdsService, FormsValidatorService]
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
beforeEach(done => {
|
||||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
imports: [],
|
||||
declarations: [AccessItemsManagementComponent],
|
||||
providers: [AccessIdsService, FormsValidatorService]
|
||||
});
|
||||
};
|
||||
|
||||
configureTests(configure).then(testBed => {
|
||||
fixture = TestBed.createComponent(AccessItemsManagementComponent);
|
||||
fixture = testBed.createComponent(AccessItemsManagementComponent);
|
||||
component = fixture.componentInstance;
|
||||
accessIdsService = TestBed.get(AccessIdsService);
|
||||
accessIdsService = testBed.get(AccessIdsService);
|
||||
spyOn(accessIdsService, 'getAccessItemsPermissions').and.returnValue(of(new Array<AccessIdDefinition>()));
|
||||
spyOn(accessIdsService, 'getAccessItemsInformation').and.returnValue(of(new AccessItemsWorkbasketResource()));
|
||||
fixture.detectChanges();
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Select } from '@ngxs/store';
|
||||
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
|
||||
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
|
||||
import { AccessItemsWorkbasketResource } from 'app/models/access-item-workbasket-resource';
|
||||
import { AccessItemWorkbasket } from 'app/models/access-item-workbasket';
|
||||
import { SortingModel } from 'app/models/sorting';
|
||||
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
|
||||
import { MessageModal } from 'app/models/message-modal';
|
||||
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
|
||||
import { AlertModel, AlertType } from 'app/models/alert';
|
||||
import { AlertService } from 'app/services/alert/alert.service';
|
||||
import { EngineConfigurationSelectors } from 'app/store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { RequestInProgressService } from '../../services/requestInProgress/request-in-progress.service';
|
||||
import { AccessIdsService } from '../../shared/services/access-ids/access-ids.service';
|
||||
import { AccessIdDefinition } from '../../models/access-id';
|
||||
import { ErrorsService } from '../../services/errors/errors.service';
|
||||
import { ERROR_TYPES } from '../../models/errors';
|
||||
import { AccessItemsCustomisation, CustomField, getCustomFields } from '../../models/customisation';
|
||||
import { customFieldCount } from '../../models/workbasket-access-items';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-access-items-management',
|
||||
|
@ -40,22 +42,10 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
|
|||
isGroup: boolean;
|
||||
groupsKey = 'ou=groups';
|
||||
|
||||
accessIdField = this.customFieldsService.getCustomField('Owner', 'workbaskets.access-items.accessId');
|
||||
custom1Field = this.customFieldsService.getCustomField('Custom 1', 'workbaskets.access-items.custom1');
|
||||
custom2Field = this.customFieldsService.getCustomField('Custom 2', 'workbaskets.access-items.custom2');
|
||||
custom3Field = this.customFieldsService.getCustomField('Custom 3', 'workbaskets.access-items.custom3');
|
||||
custom4Field = this.customFieldsService.getCustomField('Custom 4', 'workbaskets.access-items.custom4');
|
||||
custom5Field = this.customFieldsService.getCustomField('Custom 5', 'workbaskets.access-items.custom5');
|
||||
custom6Field = this.customFieldsService.getCustomField('Custom 6', 'workbaskets.access-items.custom6');
|
||||
custom7Field = this.customFieldsService.getCustomField('Custom 7', 'workbaskets.access-items.custom7');
|
||||
custom8Field = this.customFieldsService.getCustomField('Custom 8', 'workbaskets.access-items.custom8');
|
||||
custom9Field = this.customFieldsService.getCustomField('Custom 9', 'workbaskets.access-items.custom9');
|
||||
custom10Field = this.customFieldsService.getCustomField('Custom 10', 'workbaskets.access-items.custom10');
|
||||
custom11Field = this.customFieldsService.getCustomField('Custom 11', 'workbaskets.access-items.custom11');
|
||||
custom12Field = this.customFieldsService.getCustomField('Custom 12', 'workbaskets.access-items.custom12');
|
||||
@Select(EngineConfigurationSelectors.accessItemsCustomisation) accessItemsCustomization$: Observable<AccessItemsCustomisation>;
|
||||
customFields$: Observable<CustomField[]>;
|
||||
|
||||
constructor(private formBuilder: FormBuilder,
|
||||
private customFieldsService: CustomFieldsService,
|
||||
private accessIdsService: AccessIdsService,
|
||||
private formsValidatorService: FormsValidatorService,
|
||||
private requestInProgressService: RequestInProgressService,
|
||||
|
@ -75,6 +65,10 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.customFields$ = this.accessItemsCustomization$.pipe(getCustomFields(customFieldCount));
|
||||
}
|
||||
|
||||
setAccessItemsGroups(accessItems: Array<AccessItemWorkbasket>) {
|
||||
const AccessItemsFormGroups = accessItems.map(accessItem => this.formBuilder.group(accessItem));
|
||||
AccessItemsFormGroups.forEach(accessItemGroup => {
|
||||
|
@ -96,9 +90,6 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
onSelectAccessId(selected: AccessIdDefinition) {
|
||||
if (!selected) {
|
||||
this.AccessItemsForm = null;
|
||||
|
|
|
@ -39,7 +39,7 @@ const MODULES = [
|
|||
SharedModule,
|
||||
AdministrationRoutingModule,
|
||||
TypeaheadModule,
|
||||
InfiniteScrollModule
|
||||
InfiniteScrollModule,
|
||||
];
|
||||
|
||||
const DECLARATIONS = [
|
||||
|
|
|
@ -30,9 +30,9 @@
|
|||
<span *ngIf="action=== 'CREATE'" class="badge warning"> {{badgeMessage}}</span>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="panel-body" style="padding: 0">
|
||||
<form #ClassificationForm="ngForm">
|
||||
<div class="row">
|
||||
<div class="row" style="padding: 15px">
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="form-group required">
|
||||
|
@ -67,26 +67,26 @@
|
|||
<div class="row">
|
||||
<div class="form-group col-xs-6">
|
||||
<label for="classification-priority" class="control-label">Priority</label>
|
||||
<taskana-number-picker [(ngModel)]="classification.priority" name="classification.priority"></taskana-number-picker>
|
||||
<taskana-number-picker [(ngModel)]="classification.priority" name="classification.priority" id="classification-priority"></taskana-number-picker>
|
||||
</div>
|
||||
<div class="form-group required btn-group col-xs-6">
|
||||
<label for="classification-category" class="control-label">Category</label>
|
||||
<div class="dropdown clearfix ">
|
||||
<button class="btn btn-default" type="button" data-toggle="dropdown" aria-haspopup="true"
|
||||
aria-expanded="true">
|
||||
aria-expanded="true" id="classification-category">
|
||||
<span class="text-top">
|
||||
<svg-icon class="blue fa-fw" src="{{getCategoryIcon(classification.category).name}}"
|
||||
data-toggle="tooltip" [title]="getCategoryIcon(classification.category).text"></svg-icon>
|
||||
<svg-icon class="blue fa-fw" src="{{(getCategoryIcon(classification.category) | async)?.name}}"
|
||||
data-toggle="tooltip" [title]="(getCategoryIcon(classification.category) | async)?.text"></svg-icon>
|
||||
</span>
|
||||
{{classification.category}}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu" aria-labelledby="dropdownMenu">
|
||||
<li>
|
||||
<a *ngFor="let category of categories" (click)="selectCategory(category)">
|
||||
<a *ngFor="let category of getAvailableCategories(classification.type)" (click)="selectCategory(category)">
|
||||
<span class="text-top">
|
||||
<svg-icon class="blue fa-fw" src="{{getCategoryIcon(category).name}}" data-toggle="tooltip"
|
||||
[title]="getCategoryIcon(category).text"></svg-icon>
|
||||
<svg-icon class="blue fa-fw" src="{{(getCategoryIcon(category) | async)?.name}}" data-toggle="tooltip"
|
||||
[title]="(getCategoryIcon(category) | async)?.text"></svg-icon>
|
||||
{{category}}
|
||||
</span>
|
||||
</a>
|
||||
|
@ -114,50 +114,18 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div *ngIf="custom1Field.visible" class="form-group">
|
||||
<label for="classification-custom-1" class="control-label">{{custom1Field.field}}</label>
|
||||
<input type="text" class="form-control" id="classification-custom-1" placeholder="{{custom1Field.field}}"
|
||||
[(ngModel)]="classification.custom1" name="classification.custom1">
|
||||
</div>
|
||||
<div *ngIf="custom2Field.visible" class="form-group">
|
||||
<label for="classification-custom-2" class="control-label">{{custom2Field.field}}</label>
|
||||
<input type="text" class="form-control" id="classification-custom-2" placeholder="{{custom2Field.field}}"
|
||||
[(ngModel)]="classification.custom2" name="classification.custom2">
|
||||
</div>
|
||||
<div *ngIf="custom3Field.visible" class="form-group">
|
||||
<label for="classification-custom-3" class="control-label">{{custom3Field.field}}</label>
|
||||
<input type="text" class="form-control" id="classification-custom-3" placeholder="{{custom3Field.field}}"
|
||||
[(ngModel)]="classification.custom3" name="classification.custom3">
|
||||
</div>
|
||||
<div *ngIf="custom4Field.visible" class="form-group">
|
||||
<label for="classification-custom-4" class="control-label">{{custom4Field.field}}</label>
|
||||
<input type="text" class="form-control" id="classification-custom-4" placeholder="{{custom4Field.field}}"
|
||||
[(ngModel)]="classification.custom4" name="classification.custom4">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div *ngIf="custom5Field.visible" class="form-group">
|
||||
<label for="classification-custom-5" class="control-label">{{custom5Field.field}}</label>
|
||||
<input type="text" class="form-control" id="classification-custom-5" placeholder="{{custom5Field.field}}"
|
||||
[(ngModel)]="classification.custom5" name="classification.custom5">
|
||||
</div>
|
||||
<div *ngIf="custom6Field.visible" class="form-group">
|
||||
<label for="classification-custom-6" class="control-label">{{custom6Field.field}}</label>
|
||||
<input type="text" class="form-control" id="classification-custom-6" placeholder="{{custom6Field.field}}"
|
||||
[(ngModel)]="classification.custom6" name="classification.custom6">
|
||||
</div>
|
||||
<div *ngIf="custom7Field.visible" class="form-group">
|
||||
<label for="classification-custom-7" class="control-label">{{custom7Field.field}}</label>
|
||||
<input type="text" class="form-control" id="classification-custom-7" placeholder="{{custom7Field.field}}"
|
||||
[(ngModel)]="classification.custom7" name="classification.custom7">
|
||||
</div>
|
||||
<div *ngIf="custom8Field.visible" class="form-group">
|
||||
<label for="classification-custom-8" class="control-label">{{custom8Field.field}}</label>
|
||||
<input type="text" class="form-control" id="classification-custom-8" placeholder="{{custom8Field.field}}"
|
||||
[(ngModel)]="classification.custom8" name="classification.custom8">
|
||||
|
||||
<div class="row custom-field-row">
|
||||
|
||||
<div class="custom-classification-form" *ngFor="let customField of (customFields$ | async), let i = index"
|
||||
style="width: 50%;">
|
||||
|
||||
<div *ngIf="customField.visible" class="form-group custom-field-wrapper">
|
||||
<label for="classification-custom-{{i + 1}}" class="control-label">{{customField.field}}</label>
|
||||
<input type="text" class="form-control" id="classification-custom-{{i + 1}}" placeholder="{{customField.field}}"
|
||||
[(ngModel)]="classification[getClassificationCustom(i + 1)]" name="classification.custom{{i + 1}}">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
.custom-field-row {
|
||||
display:flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: column;
|
||||
height: 40vh;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.custom-field-wrapper {
|
||||
height: 70px;
|
||||
padding: 0 15px
|
||||
}
|
|
@ -7,13 +7,12 @@ import { Component } from '@angular/core';
|
|||
import { of } from 'rxjs';
|
||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { configureTests } from 'app/app.test.configuration';
|
||||
import { NgxsModule, Store } from '@ngxs/store';
|
||||
|
||||
|
||||
import { ClassificationDefinition } from 'app/models/classification-definition';
|
||||
import { LinksClassification } from 'app/models/links-classfication';
|
||||
import { Pair } from 'app/models/pair';
|
||||
|
||||
import { ClassificationCategoriesService } from 'app/shared/services/classifications/classification-categories.service';
|
||||
import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-detail.service';
|
||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||
import { ClassificationsService } from 'app/shared/services/classifications/classifications.service';
|
||||
|
@ -21,11 +20,13 @@ import { TreeNodeModel } from 'app/models/tree-node';
|
|||
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
|
||||
import { AlertService } from 'app/services/alert/alert.service';
|
||||
import { TreeService } from 'app/services/tree/tree.service';
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
|
||||
import { ImportExportService } from 'app/administration/services/import-export/import-export.service';
|
||||
import { EngineConfigurationSelectors } from 'app/store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { ClassificationSelectors } from 'app/store/classification-store/classification.selectors';
|
||||
import { ClassificationDetailsComponent } from './classification-details.component';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-dummy-detail',
|
||||
template: 'dummydetail'
|
||||
|
@ -43,33 +44,42 @@ describe('ClassificationDetailsComponent', () => {
|
|||
const treeNodes: Array<TreeNodeModel> = new Array(new TreeNodeModel());
|
||||
|
||||
let classificationsService;
|
||||
let classificationCategoriesService;
|
||||
let treeService;
|
||||
let removeConfirmationService;
|
||||
|
||||
const storeSpy: jasmine.SpyObj<Store> = jasmine.createSpyObj('Store', ['select']);
|
||||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
imports: [FormsModule, HttpClientModule, RouterTestingModule.withRoutes(routes), AngularSvgIconModule, NgxsModule.forRoot()],
|
||||
declarations: [ClassificationDetailsComponent, DummyDetailComponent],
|
||||
providers: [MasterAndDetailService, RequestInProgressService, ClassificationsService, HttpClient, GeneralModalService, AlertService,
|
||||
TreeService, ImportExportService, { provide: Store, useValue: storeSpy }]
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(done => {
|
||||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
imports: [FormsModule, HttpClientModule, RouterTestingModule.withRoutes(routes), AngularSvgIconModule],
|
||||
declarations: [ClassificationDetailsComponent, DummyDetailComponent],
|
||||
providers: [MasterAndDetailService, RequestInProgressService, ClassificationsService, HttpClient, GeneralModalService, AlertService,
|
||||
TreeService, ClassificationCategoriesService, CustomFieldsService, ImportExportService]
|
||||
});
|
||||
};
|
||||
configureTests(configure).then(testBed => {
|
||||
fixture = TestBed.createComponent(ClassificationDetailsComponent);
|
||||
storeSpy.select.and.callFake(selector => {
|
||||
switch (selector) {
|
||||
case EngineConfigurationSelectors.classificationsCustomisation:
|
||||
return of({ information: {} });
|
||||
case ClassificationSelectors.selectCategories:
|
||||
return of(['EXTERNAL', 'MANUAL']);
|
||||
default:
|
||||
return of();
|
||||
}
|
||||
});
|
||||
|
||||
fixture = testBed.createComponent(ClassificationDetailsComponent);
|
||||
|
||||
component = fixture.componentInstance;
|
||||
classificationsService = TestBed.get(ClassificationsService);
|
||||
classificationCategoriesService = TestBed.get(ClassificationCategoriesService);
|
||||
removeConfirmationService = TestBed.get(RemoveConfirmationService);
|
||||
classificationsService = testBed.get(ClassificationsService);
|
||||
removeConfirmationService = testBed.get(RemoveConfirmationService);
|
||||
spyOn(classificationsService, 'getClassifications').and.returnValue(of(treeNodes));
|
||||
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'));
|
||||
component.classification = new ClassificationDefinition('id1');
|
||||
component.classification._links = new LinksClassification({ self: '' });
|
||||
treeService = TestBed.get(TreeService);
|
||||
treeService = testBed.get(TreeService);
|
||||
fixture.detectChanges();
|
||||
done();
|
||||
});
|
||||
|
@ -86,8 +96,4 @@ describe('ClassificationDetailsComponent', () => {
|
|||
removeConfirmationService.runCallbackFunction();
|
||||
expect(treeServiceSpy).toHaveBeenCalledWith('id1');
|
||||
});
|
||||
|
||||
it('should selected first classificationCategory if is defined', () => {
|
||||
expect(component.classification.category).toBe('firstCategory');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Select, Store } from '@ngxs/store';
|
||||
import { Observable, Subscription, zip } from 'rxjs';
|
||||
|
||||
import { ClassificationDefinition } from 'app/models/classification-definition';
|
||||
import { ClassificationDefinition, customFieldCount } from 'app/models/classification-definition';
|
||||
import { ACTION } from 'app/models/action';
|
||||
import { MessageModal } from 'app/models/message-modal';
|
||||
import { AlertModel, AlertType } from 'app/models/alert';
|
||||
|
||||
import { highlight } from 'app/shared/animations/validation.animation';
|
||||
|
@ -18,15 +18,17 @@ import { AlertService } from 'app/services/alert/alert.service';
|
|||
import { TreeService } from 'app/services/tree/tree.service';
|
||||
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
|
||||
|
||||
import { ClassificationCategoriesService } from 'app/shared/services/classifications/classification-categories.service';
|
||||
import { DomainService } from 'app/services/domain/domain.service';
|
||||
import { Pair } from 'app/models/pair';
|
||||
import { NgForm } from '@angular/forms';
|
||||
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
|
||||
import { ImportExportService } from 'app/administration/services/import-export/import-export.service';
|
||||
import { CustomFieldsService } from '../../../services/custom-fields/custom-fields.service';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
import { EngineConfigurationSelectors } from 'app/store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { ClassificationSelectors } from 'app/store/classification-store/classification.selectors';
|
||||
import { ERROR_TYPES } from '../../../models/errors';
|
||||
import { ErrorsService } from '../../../services/errors/errors.service';
|
||||
import { ClassificationCategoryImages, CustomField, getCustomFields } from '../../../models/customisation';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-classification-details',
|
||||
|
@ -37,22 +39,20 @@ import { ErrorsService } from '../../../services/errors/errors.service';
|
|||
export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
||||
classification: ClassificationDefinition;
|
||||
classificationClone: ClassificationDefinition;
|
||||
classificationCategories: string[];
|
||||
showDetail = false;
|
||||
classificationTypes: Array<string> = [];
|
||||
badgeMessage = '';
|
||||
requestInProgress = false;
|
||||
categories: Array<string> = [];
|
||||
categorySelected: string;
|
||||
spinnerIsRunning = false;
|
||||
custom1Field = this.customFieldsService.getCustomField('Custom 1', 'classifications.information.custom1');
|
||||
custom2Field = this.customFieldsService.getCustomField('Custom 2', 'classifications.information.custom2');
|
||||
custom3Field = this.customFieldsService.getCustomField('Custom 3', 'classifications.information.custom3');
|
||||
custom4Field = this.customFieldsService.getCustomField('Custom 4', 'classifications.information.custom4');
|
||||
custom5Field = this.customFieldsService.getCustomField('Custom 5', 'classifications.information.custom5');
|
||||
custom6Field = this.customFieldsService.getCustomField('Custom 6', 'classifications.information.custom6');
|
||||
custom7Field = this.customFieldsService.getCustomField('Custom 7', 'classifications.information.custom7');
|
||||
custom8Field = this.customFieldsService.getCustomField('Custom 8', 'classifications.information.custom8');
|
||||
@Select(ClassificationSelectors.selectCategories) categories$: Observable<string[]>;
|
||||
@Select(EngineConfigurationSelectors.selectCategoryIcons) categoryIcons$: Observable<ClassificationCategoryImages>;
|
||||
@Select(ClassificationSelectors.selectedClassificationType) selectedClassificationType$: Observable<string>;
|
||||
@Select(ClassificationSelectors.selectClassificationTypesObject) classificationTypes$: Observable<Object>;
|
||||
|
||||
spinnerIsRunning = false;
|
||||
customFields$: Observable<CustomField[]>;
|
||||
|
||||
@ViewChild('ClassificationForm', { static: false }) classificationForm: NgForm;
|
||||
toogleValidationMap = new Map<string, boolean>();
|
||||
private action: any;
|
||||
private classificationServiceSubscription: Subscription;
|
||||
private classificationSelectedSubscription: Subscription;
|
||||
|
@ -60,15 +60,9 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
|||
private masterAndDetailSubscription: Subscription;
|
||||
private classificationSavingSubscription: Subscription;
|
||||
private classificationRemoveSubscription: Subscription;
|
||||
private selectedClassificationSubscription: Subscription;
|
||||
private selectedClassificationTypeSubscription: Subscription;
|
||||
private categoriesSubscription: Subscription;
|
||||
private domainSubscription: Subscription;
|
||||
private importingExportingSubscription: Subscription;
|
||||
|
||||
@ViewChild('ClassificationForm', { static: false }) classificationForm: NgForm;
|
||||
toogleValidationMap = new Map<string, boolean>();
|
||||
|
||||
constructor(private classificationsService: ClassificationsService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
|
@ -77,19 +71,19 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
|||
private requestInProgressService: RequestInProgressService,
|
||||
private alertService: AlertService,
|
||||
private treeService: TreeService,
|
||||
private categoryService: ClassificationCategoriesService,
|
||||
private domainService: DomainService,
|
||||
private customFieldsService: CustomFieldsService,
|
||||
private removeConfirmationService: RemoveConfirmationService,
|
||||
private formsValidatorService: FormsValidatorService,
|
||||
private errorsService: ErrorsService,
|
||||
private importExportService: ImportExportService) {
|
||||
private importExportService: ImportExportService,
|
||||
private store: Store) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.categoryService.getClassificationTypes().subscribe((classificationTypes: Array<string>) => {
|
||||
this.classificationTypes = classificationTypes;
|
||||
});
|
||||
this.customFields$ = this.store.select(EngineConfigurationSelectors.classificationsCustomisation).pipe(
|
||||
map(customisation => customisation.information),
|
||||
getCustomFields(customFieldCount)
|
||||
);
|
||||
this.classificationSelectedSubscription = this.classificationsService.getSelectedClassification()
|
||||
.subscribe(classificationSelected => {
|
||||
if (classificationSelected && this.classification
|
||||
|
@ -122,20 +116,10 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
|||
this.showDetail = showDetail;
|
||||
});
|
||||
|
||||
this.categoriesSubscription = this.categoryService.getCategories().subscribe((categories: Array<string>) => {
|
||||
this.categories = categories;
|
||||
// ToDo: Remove this line during refactoring. Atm checking why it was written takes too long
|
||||
if (categories.length > 0 && this.classification) {
|
||||
// TSK-891 fix: The property is already set and is crucial value
|
||||
// Wrapped with an if to set a default if not already set.
|
||||
if (!this.classification.category) {
|
||||
[this.classification.category] = categories;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.importingExportingSubscription = this.importExportService.getImportingFinished().subscribe((value: Boolean) => {
|
||||
if (this.classification.classificationId) { this.selectClassification(this.classification.classificationId); }
|
||||
if (this.classification.classificationId) {
|
||||
this.selectClassification(this.classification.classificationId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -144,10 +128,6 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
|||
this.router.navigate(['./'], { relativeTo: this.route.parent });
|
||||
}
|
||||
|
||||
selectType(type: string) {
|
||||
this.classification.type = type;
|
||||
}
|
||||
|
||||
removeClassification() {
|
||||
this.removeConfirmationService.setRemoveConfirmation(this.removeClassificationConfirmation.bind(this),
|
||||
`You are going to delete classification: ${this.classification.key}. Can you confirm this action?`);
|
||||
|
@ -166,6 +146,37 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
onClear() {
|
||||
this.formsValidatorService.formSubmitAttempt = false;
|
||||
// new Key: ALERT_TYPES.INFO_ALERT
|
||||
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'Reset edited fields'));
|
||||
this.classification = { ...this.classificationClone };
|
||||
}
|
||||
|
||||
selectCategory(category: string) {
|
||||
this.classification.category = category;
|
||||
}
|
||||
|
||||
getCategoryIcon(category: string): Observable<Pair> {
|
||||
return this.categoryIcons$.pipe(map(
|
||||
iconMap => (iconMap[category]
|
||||
? new Pair(iconMap[category], category)
|
||||
: new Pair(iconMap.missing, 'Category does not match with the configuration'))
|
||||
));
|
||||
}
|
||||
|
||||
spinnerRunning(value) {
|
||||
this.spinnerIsRunning = value;
|
||||
}
|
||||
|
||||
validChanged(): void {
|
||||
this.classification.isValidInDomain = !this.classification.isValidInDomain;
|
||||
}
|
||||
|
||||
masterDomainSelected(): boolean {
|
||||
return this.domainService.getSelectedDomainValue() === '';
|
||||
}
|
||||
|
||||
private initProperties() {
|
||||
delete this.classification;
|
||||
delete this.action;
|
||||
|
@ -204,24 +215,6 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
onClear() {
|
||||
this.formsValidatorService.formSubmitAttempt = false;
|
||||
// new Key: ALERT_TYPES.INFO_ALERT
|
||||
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'Reset edited fields'));
|
||||
this.classification = { ...this.classificationClone };
|
||||
}
|
||||
|
||||
|
||||
selectCategory(category: string) {
|
||||
this.classification.category = category;
|
||||
}
|
||||
|
||||
getCategoryIcon(category: string): Pair {
|
||||
return this.categoryService.getCategoryIcon(category);
|
||||
}
|
||||
|
||||
spinnerRunning(value) { this.spinnerIsRunning = value; }
|
||||
|
||||
private afterRequest() {
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
this.classificationsService.triggerClassificationSaved();
|
||||
|
@ -251,23 +244,24 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
private addDateToClassification() {
|
||||
private addDateToClassification(classification: ClassificationDefinition) {
|
||||
const date = TaskanaDate.getDate();
|
||||
this.classification.created = date;
|
||||
this.classification.modified = date;
|
||||
classification.created = date;
|
||||
classification.modified = date;
|
||||
}
|
||||
|
||||
private initClassificationOnCreation(classificationSelected: ClassificationDefinition) {
|
||||
this.classification = new ClassificationDefinition();
|
||||
this.classification.parentId = classificationSelected.classificationId;
|
||||
this.classification.parentKey = classificationSelected.key;
|
||||
this.classification.category = classificationSelected.category;
|
||||
this.classification.domain = this.domainService.getSelectedDomainValue();
|
||||
this.selectedClassificationSubscription = this.categoryService.getSelectedClassificationType().subscribe(type => {
|
||||
if (this.classification) { this.classification.type = type; }
|
||||
zip(this.categories$, this.selectedClassificationType$).pipe(take(1)).subscribe(([categories, selectedType]: [string[], string]) => {
|
||||
const tempClassification: ClassificationDefinition = new ClassificationDefinition();
|
||||
// tempClassification.parentId = classificationSelected.classificationId;
|
||||
// tempClassification.parentKey = classificationSelected.key;
|
||||
[tempClassification.category] = categories;
|
||||
tempClassification.domain = this.domainService.getSelectedDomainValue();
|
||||
tempClassification.type = selectedType;
|
||||
this.addDateToClassification(tempClassification);
|
||||
this.classification = tempClassification;
|
||||
this.cloneClassification(this.classification);
|
||||
});
|
||||
this.addDateToClassification();
|
||||
this.cloneClassification(this.classification);
|
||||
}
|
||||
|
||||
private checkDomainAndRedirect() {
|
||||
|
@ -306,25 +300,44 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
|||
this.classificationClone = { ...classification };
|
||||
}
|
||||
|
||||
validChanged(): void {
|
||||
this.classification.isValidInDomain = !this.classification.isValidInDomain;
|
||||
getClassificationCustom(customNumber: number): string {
|
||||
return `custom${customNumber}`;
|
||||
}
|
||||
|
||||
masterDomainSelected(): boolean {
|
||||
return this.domainService.getSelectedDomainValue() === '';
|
||||
// TODO: Remove when classification is in store
|
||||
getAvailableCategories(type: string) {
|
||||
let returnCategories: string[] = [];
|
||||
this.classificationTypes$.subscribe(classTypes => {
|
||||
returnCategories = classTypes[type];
|
||||
});
|
||||
|
||||
return returnCategories;
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.masterAndDetailSubscription) { this.masterAndDetailSubscription.unsubscribe(); }
|
||||
if (this.routeSubscription) { this.routeSubscription.unsubscribe(); }
|
||||
if (this.classificationSelectedSubscription) { this.classificationSelectedSubscription.unsubscribe(); }
|
||||
if (this.classificationServiceSubscription) { this.classificationServiceSubscription.unsubscribe(); }
|
||||
if (this.classificationSavingSubscription) { this.classificationSavingSubscription.unsubscribe(); }
|
||||
if (this.classificationRemoveSubscription) { this.classificationRemoveSubscription.unsubscribe(); }
|
||||
if (this.selectedClassificationSubscription) { this.selectedClassificationSubscription.unsubscribe(); }
|
||||
if (this.selectedClassificationTypeSubscription) { this.selectedClassificationTypeSubscription.unsubscribe(); }
|
||||
if (this.categoriesSubscription) { this.categoriesSubscription.unsubscribe(); }
|
||||
if (this.domainSubscription) { this.domainSubscription.unsubscribe(); }
|
||||
if (this.importingExportingSubscription) { this.importingExportingSubscription.unsubscribe(); }
|
||||
if (this.masterAndDetailSubscription) {
|
||||
this.masterAndDetailSubscription.unsubscribe();
|
||||
}
|
||||
if (this.routeSubscription) {
|
||||
this.routeSubscription.unsubscribe();
|
||||
}
|
||||
if (this.classificationSelectedSubscription) {
|
||||
this.classificationSelectedSubscription.unsubscribe();
|
||||
}
|
||||
if (this.classificationServiceSubscription) {
|
||||
this.classificationServiceSubscription.unsubscribe();
|
||||
}
|
||||
if (this.classificationSavingSubscription) {
|
||||
this.classificationSavingSubscription.unsubscribe();
|
||||
}
|
||||
if (this.classificationRemoveSubscription) {
|
||||
this.classificationRemoveSubscription.unsubscribe();
|
||||
}
|
||||
if (this.domainSubscription) {
|
||||
this.domainSubscription.unsubscribe();
|
||||
}
|
||||
if (this.importingExportingSubscription) {
|
||||
this.importingExportingSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,16 +9,15 @@
|
|||
</taskana-import-export-component>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<taskana-classification-types-selector class="pull-right" [classificationTypes]="classificationsTypes"
|
||||
[(classificationTypeSelected)]="classificationTypeSelected" (classificationTypeChanged)=selectClassificationType($event)></taskana-classification-types-selector>
|
||||
<taskana-classification-types-selector class="pull-right"></taskana-classification-types-selector>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<div class="col-xs-2 category-filter">
|
||||
<button class="btn btn-default" data-toggle="dropdown" type="button" id="dropdown-classification-filter" data-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="true">
|
||||
<svg-icon *ngIf="selectedCategory else category_unselected" class="blue" [src]="getCategoryIcon(selectedCategory).name"
|
||||
data-toggle="tooltip" [title]="getCategoryIcon(category).text"></svg-icon>
|
||||
<svg-icon *ngIf="selectedCategory else category_unselected" class="blue" [src]="(getCategoryIcon(selectedCategory) | async)?.name"
|
||||
data-toggle="tooltip" [title]="(getCategoryIcon(category) | async)?.text"></svg-icon>
|
||||
<ng-template #category_unselected>
|
||||
<svg-icon data-toggle="tooltip" title="All" class="blue " src="./assets/icons/asterisk.svg"></svg-icon>
|
||||
</ng-template>
|
||||
|
@ -29,9 +28,9 @@
|
|||
<svg-icon class="blue" src="./assets/icons/asterisk.svg"></svg-icon>
|
||||
All
|
||||
</a>
|
||||
<a *ngFor="let category of categories" type="button" (click)="selectCategory(category);" data-toggle="tooltip"
|
||||
<a *ngFor="let category of categories$ | async" type="button" (click)="selectCategory(category);" data-toggle="tooltip"
|
||||
[title]="category">
|
||||
<svg-icon class="blue" [src]="getCategoryIcon(category).name" data-toggle="tooltip" [title]="getCategoryIcon(category).text"></svg-icon>
|
||||
<svg-icon class="blue" [src]="(getCategoryIcon(category) | async)?.name" data-toggle="tooltip" [title]="(getCategoryIcon(category) | async)?.text"></svg-icon>
|
||||
{{category}}
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
||||
import { of } from 'rxjs';
|
||||
import { Routes } from '@angular/router';
|
||||
|
@ -20,12 +20,12 @@ import { DomainService } from 'app/services/domain/domain.service';
|
|||
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
|
||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||
import { configureTests } from 'app/app.test.configuration';
|
||||
import { ClassificationCategoriesService } from 'app/shared/services/classifications/classification-categories.service';
|
||||
import { Pair } from 'app/models/pair';
|
||||
import { TreeService } from 'app/services/tree/tree.service';
|
||||
import { ImportExportService } from 'app/administration/services/import-export/import-export.service';
|
||||
import { NgxsModule } from '@ngxs/store';
|
||||
import { ClassificationListComponent } from './classification-list.component';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-dummy-detail',
|
||||
template: 'dummydetail'
|
||||
|
@ -37,38 +37,32 @@ const routes: Routes = [
|
|||
{ path: ':id', component: DummyDetailComponent }
|
||||
];
|
||||
|
||||
|
||||
describe('ClassificationListComponent', () => {
|
||||
let component: ClassificationListComponent;
|
||||
let fixture: ComponentFixture<ClassificationListComponent>;
|
||||
const treeNodes: Array<TreeNodeModel> = new Array(new TreeNodeModel());
|
||||
const classificationTypes: Array<string> = new Array<string>('type1', 'type2');
|
||||
let classificationsService;
|
||||
let classificationCategoriesService;
|
||||
|
||||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
declarations: [ClassificationListComponent, ImportExportComponent, ClassificationTypesSelectorComponent,
|
||||
DummyDetailComponent],
|
||||
imports: [HttpClientModule, RouterTestingModule.withRoutes(routes), FormsModule, AngularSvgIconModule, NgxsModule.forRoot()],
|
||||
providers: [
|
||||
HttpClient, WorkbasketDefinitionService, AlertService, ClassificationsService, DomainService, ClassificationDefinitionService,
|
||||
GeneralModalService, RequestInProgressService, TreeService, ImportExportService
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(done => {
|
||||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
declarations: [ClassificationListComponent, ImportExportComponent, ClassificationTypesSelectorComponent,
|
||||
DummyDetailComponent],
|
||||
imports: [HttpClientModule, RouterTestingModule.withRoutes(routes), FormsModule, AngularSvgIconModule],
|
||||
providers: [
|
||||
HttpClient, WorkbasketDefinitionService, AlertService, ClassificationsService, DomainService, ClassificationDefinitionService,
|
||||
GeneralModalService, RequestInProgressService, ClassificationCategoriesService, TreeService, ImportExportService
|
||||
]
|
||||
});
|
||||
};
|
||||
configureTests(configure).then(testBed => {
|
||||
fixture = testBed.createComponent(ClassificationListComponent);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
classificationsService = testBed.get(ClassificationsService);
|
||||
classificationCategoriesService = testBed.get(ClassificationCategoriesService);
|
||||
spyOn(classificationsService, 'getClassifications').and.returnValue(of(treeNodes));
|
||||
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'));
|
||||
|
||||
fixture.detectChanges();
|
||||
done();
|
||||
});
|
||||
|
|
|
@ -1,20 +1,25 @@
|
|||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Subscription, Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { Select } from '@ngxs/store';
|
||||
|
||||
import { TaskanaType } from 'app/models/taskana-type';
|
||||
import { Classification } from 'app/models/classification';
|
||||
import { TreeNodeModel } from 'app/models/tree-node';
|
||||
|
||||
import { ClassificationsService } from 'app/shared/services/classifications/classifications.service';
|
||||
import { ClassificationCategoriesService } from 'app/shared/services/classifications/classification-categories.service';
|
||||
import { Pair } from 'app/models/pair';
|
||||
import { ImportExportService } from 'app/administration/services/import-export/import-export.service';
|
||||
import { EngineConfigurationSelectors } from 'app/store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { ClassificationSelectors } from 'app/store/classification-store/classification.selectors';
|
||||
import { ClassificationDefinition } from '../../../../models/classification-definition';
|
||||
import { AlertModel, AlertType } from '../../../../models/alert';
|
||||
import { AlertService } from '../../../../services/alert/alert.service';
|
||||
import { ERROR_TYPES } from '../../../../models/errors';
|
||||
|
||||
import { ClassificationCategoryImages } from '../../../../models/customisation';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-classification-list',
|
||||
templateUrl: './classification-list.component.html',
|
||||
|
@ -27,23 +32,21 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
|
|||
requestInProgress = false;
|
||||
initialized = false;
|
||||
inputValue: string;
|
||||
categories: Array<string> = [];
|
||||
classifications: Array<Classification> = [];
|
||||
classificationsTypes: Array<string> = [];
|
||||
classificationTypeSelected: string;
|
||||
classifications: Classification[] = [];
|
||||
@Select(ClassificationSelectors.classificationTypes) classificationTypes$: Observable<string[]>;
|
||||
@Select(ClassificationSelectors.selectedClassificationType) classificationTypeSelected$: Observable<string>;
|
||||
@Select(ClassificationSelectors.selectCategories) categories$: Observable<string[]>;
|
||||
@Select(EngineConfigurationSelectors.selectCategoryIcons) categoryIcons$: Observable<ClassificationCategoryImages>;
|
||||
classificationServiceSubscription: Subscription;
|
||||
classificationTypeServiceSubscription: Subscription;
|
||||
classificationTypeSubscription: Subscription;
|
||||
classificationSelectedSubscription: Subscription;
|
||||
classificationSavedSubscription: Subscription;
|
||||
selectedClassificationSubscription: Subscription;
|
||||
categoriesSubscription: Subscription;
|
||||
importingExportingSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private classificationService: ClassificationsService,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private categoryService: ClassificationCategoriesService,
|
||||
private importExportService: ImportExportService,
|
||||
private alertService: AlertService
|
||||
) {
|
||||
|
@ -52,35 +55,27 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
|
|||
ngOnInit() {
|
||||
this.classificationSavedSubscription = this.classificationService
|
||||
.classificationSavedTriggered()
|
||||
.subscribe(value => {
|
||||
.subscribe(() => {
|
||||
this.performRequest(true);
|
||||
});
|
||||
this.selectedClassificationSubscription = this.categoryService.getSelectedClassificationType().subscribe(value => {
|
||||
this.classificationTypeSelected = value;
|
||||
|
||||
this.classificationTypeSubscription = this.classificationTypeSelected$.subscribe(() => {
|
||||
this.performRequest();
|
||||
this.selectClassification();
|
||||
this.selectedCategory = '';
|
||||
});
|
||||
|
||||
this.categoriesSubscription = this.categoryService.getCategories(this.classificationTypeSelected)
|
||||
.subscribe((categories: Array<string>) => { this.categories = categories; });
|
||||
this.importingExportingSubscription = this.importExportService.getImportingFinished().subscribe((value: Boolean) => {
|
||||
this.importingExportingSubscription = this.importExportService.getImportingFinished().subscribe(() => {
|
||||
this.performRequest(true);
|
||||
});
|
||||
}
|
||||
|
||||
selectClassificationType(classificationTypeSelected: string) {
|
||||
this.classifications = [];
|
||||
this.categoryService.selectClassificationType(classificationTypeSelected);
|
||||
this.getClassifications();
|
||||
this.selectClassification();
|
||||
}
|
||||
|
||||
selectClassification(id?: string) {
|
||||
this.selectedId = id;
|
||||
if (!id) {
|
||||
this.router.navigate(['taskana/administration/classifications']);
|
||||
return;
|
||||
|
||||
if (id) {
|
||||
this.router.navigate([{ outlets: { detail: [this.selectedId] } }], { relativeTo: this.route });
|
||||
}
|
||||
this.router.navigate([{ outlets: { detail: [this.selectedId] } }], { relativeTo: this.route });
|
||||
}
|
||||
|
||||
addClassification() {
|
||||
|
@ -91,8 +86,14 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
|
|||
this.selectedCategory = category;
|
||||
}
|
||||
|
||||
getCategoryIcon(category: string): Pair {
|
||||
return this.categoryService.getCategoryIcon(category);
|
||||
getCategoryIcon(category: string): Observable<Pair> {
|
||||
return this.categoryIcons$.pipe(
|
||||
map(
|
||||
iconMap => (iconMap[category]
|
||||
? new Pair(iconMap[category], category)
|
||||
: new Pair(iconMap.missing, 'Category does not match with the configuration'))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private performRequest(forceRequest = false) {
|
||||
|
@ -107,13 +108,9 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
|
|||
if (this.classificationSelectedSubscription) { this.classificationSelectedSubscription.unsubscribe(); }
|
||||
|
||||
this.classificationServiceSubscription = this.classificationService.getClassifications()
|
||||
.subscribe((classifications: Array<TreeNodeModel>) => {
|
||||
.subscribe((classifications: TreeNodeModel[]) => {
|
||||
this.requestInProgress = false;
|
||||
this.classifications = classifications;
|
||||
this.classificationTypeServiceSubscription = this.categoryService.getClassificationTypes()
|
||||
.subscribe((classificationsTypes: Array<string>) => {
|
||||
this.classificationsTypes = classificationsTypes;
|
||||
});
|
||||
});
|
||||
this.classificationSelectedSubscription = this.classificationService.getSelectedClassification()
|
||||
.subscribe((classificationSelected: ClassificationDefinition) => {
|
||||
|
@ -126,7 +123,7 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
|
|||
private getClassifications(key?: string) {
|
||||
this.requestInProgress = true;
|
||||
this.classificationService.getClassifications()
|
||||
.subscribe((classifications: Array<TreeNodeModel>) => {
|
||||
.subscribe((classifications: TreeNodeModel[]) => {
|
||||
this.classifications = classifications;
|
||||
this.requestInProgress = false;
|
||||
});
|
||||
|
@ -143,9 +140,9 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
|
|||
|
||||
ngOnDestroy(): void {
|
||||
if (this.classificationServiceSubscription) { this.classificationServiceSubscription.unsubscribe(); }
|
||||
if (this.classificationTypeServiceSubscription) { this.classificationTypeServiceSubscription.unsubscribe(); }
|
||||
if (this.classificationSelectedSubscription) { this.classificationSelectedSubscription.unsubscribe(); }
|
||||
if (this.classificationSavedSubscription) { this.classificationSavedSubscription.unsubscribe(); }
|
||||
if (this.importingExportingSubscription) { this.importingExportingSubscription.unsubscribe(); }
|
||||
if (this.classificationTypeSubscription) { this.classificationTypeSubscription.unsubscribe(); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,18 +25,9 @@
|
|||
<th>Append</th>
|
||||
<th>Transfer</th>
|
||||
<th>Distribute</th>
|
||||
<th *ngIf="custom1Field.visible">{{custom1Field.field}}</th>
|
||||
<th *ngIf="custom2Field.visible">{{custom2Field.field}}</th>
|
||||
<th *ngIf="custom3Field.visible">{{custom3Field.field}}</th>
|
||||
<th *ngIf="custom4Field.visible">{{custom4Field.field}}</th>
|
||||
<th *ngIf="custom5Field.visible">{{custom5Field.field}}</th>
|
||||
<th *ngIf="custom6Field.visible">{{custom6Field.field}}</th>
|
||||
<th *ngIf="custom7Field.visible">{{custom7Field.field}}</th>
|
||||
<th *ngIf="custom8Field.visible">{{custom8Field.field}}</th>
|
||||
<th *ngIf="custom9Field.visible">{{custom9Field.field}}</th>
|
||||
<th *ngIf="custom10Field.visible">{{custom10Field.field}}</th>
|
||||
<th *ngIf="custom11Field.visible">{{custom11Field.field}}</th>
|
||||
<th *ngIf="custom12Field.visible">{{custom12Field.field}}</th>
|
||||
<ng-container *ngFor="let customField of customFields$ | async">
|
||||
<th *ngIf="customField.visible">{{customField.field}}</th>
|
||||
</ng-container>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -46,7 +37,7 @@
|
|||
<span class="material-icons md-20 red">clear</span>
|
||||
</button>
|
||||
</td>
|
||||
<td *ngIf="accessIdField.lookupField else accessIdInput" class="input-group text-align text-width taskana-type-ahead"
|
||||
<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 }">
|
||||
|
@ -87,54 +78,12 @@
|
|||
<input id="checkbox-{{index}}-4" type="checkbox" formControlName="permDistribute">
|
||||
<label for="checkbox-{{index}}-4"></label>
|
||||
</td>
|
||||
<td *ngIf="custom1Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom1 !== accessItem.value.permCustom1)}">
|
||||
<input id="checkbox-{{index}}-5" type="checkbox" formControlName="permCustom1">
|
||||
<label for="checkbox-{{index}}-5"></label>
|
||||
</td>
|
||||
<td *ngIf="custom2Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom2 !== accessItem.value.permCustom2)}">
|
||||
<input id="checkbox-{{index}}-6" type="checkbox" formControlName="permCustom2">
|
||||
<label for="checkbox-{{index}}-6"></label>
|
||||
</td>
|
||||
<td *ngIf="custom3Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom3 !== accessItem.value.permCustom3)}">
|
||||
<input id="checkbox-{{index}}-7" type="checkbox" formControlName="permCustom3">
|
||||
<label for="checkbox-{{index}}-7"></label>
|
||||
</td>
|
||||
<td *ngIf="custom4Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom4 !== accessItem.value.permCustom4)}">
|
||||
<input id="checkbox-{{index}}-8" type="checkbox" formControlName="permCustom4">
|
||||
<label for="checkbox-{{index}}-8"></label>
|
||||
</td>
|
||||
<td *ngIf="custom5Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom5 !== accessItem.value.permCustom5)}">
|
||||
<input id="checkbox-{{index}}-9" type="checkbox" formControlName="permCustom5">
|
||||
<label for="checkbox-{{index}}-9"></label>
|
||||
</td>
|
||||
<td *ngIf="custom6Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom6 !== accessItem.value.permCustom6)}">
|
||||
<input id="checkbox-{{index}}-10" type="checkbox" formControlName="permCustom6">
|
||||
<label for="checkbox-{{index}}-10"></label>
|
||||
</td>
|
||||
<td *ngIf="custom7Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom7 !== accessItem.value.permCustom7)}">
|
||||
<input id="checkbox-{{index}}-11" type="checkbox" formControlName="permCustom7">
|
||||
<label for="checkbox-{{index}}-11"></label>
|
||||
</td>
|
||||
<td *ngIf="custom8Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom8 !== accessItem.value.permCustom8)}">
|
||||
<input id="checkbox-{{index}}-12" type="checkbox" formControlName="permCustom8">
|
||||
<label for="checkbox-{{index}}-12"></label>
|
||||
</td>
|
||||
<td *ngIf="custom9Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom9 !== accessItem.value.permCustom9)}">
|
||||
<input id="checkbox-{{index}}-13" type="checkbox" formControlName="permCustom9">
|
||||
<label for="checkbox-{{index}}-13"></label>
|
||||
</td>
|
||||
<td *ngIf="custom10Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom10 !== accessItem.value.permCustom10)}">
|
||||
<input id="checkbox-{{index}}-14" type="checkbox" formControlName="permCustom10">
|
||||
<label for="checkbox-{{index}}-14"></label>
|
||||
</td>
|
||||
<td *ngIf="custom11Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom11 !== accessItem.value.permCustom11)}">
|
||||
<input id="checkbox-{{index}}-15" type="checkbox" formControlName="permCustom11">
|
||||
<label for="checkbox-{{index}}-15"></label>
|
||||
</td>
|
||||
<td *ngIf="custom12Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom12 !== accessItem.value.permCustom12)}">
|
||||
<input id="checkbox-{{index}}-16" type="checkbox" formControlName="permCustom12">
|
||||
<label for="checkbox-{{index}}-16"></label>
|
||||
</td>
|
||||
<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}}">
|
||||
<label for="checkbox-{{index}}-{{customIndex + 5}}"></label>
|
||||
</td>
|
||||
</ng-container>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -19,9 +19,10 @@ import { SavingWorkbasketService } from 'app/administration/services/saving-work
|
|||
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
|
||||
import { AlertService } from 'app/services/alert/alert.service';
|
||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.service';
|
||||
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
|
||||
import { NgxsModule, Store } from '@ngxs/store';
|
||||
import { EngineConfigurationSelectors } from 'app/store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { AccessItemsComponent } from './access-items.component';
|
||||
|
||||
describe('AccessItemsComponent', () => {
|
||||
|
@ -33,26 +34,43 @@ describe('AccessItemsComponent', () => {
|
|||
let accessIdsService;
|
||||
let formsValidatorService;
|
||||
|
||||
const storeSpy: jasmine.SpyObj<Store> = jasmine.createSpyObj('Store', ['select']);
|
||||
|
||||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
declarations: [AccessItemsComponent],
|
||||
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, ReactiveFormsModule, NgxsModule.forRoot()],
|
||||
providers: [WorkbasketService, AlertService, GeneralModalService, SavingWorkbasketService, RequestInProgressService,
|
||||
AccessIdsService, FormsValidatorService, { provide: Store, useValue: storeSpy }]
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(done => {
|
||||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
declarations: [AccessItemsComponent],
|
||||
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, ReactiveFormsModule],
|
||||
providers: [WorkbasketService, AlertService, GeneralModalService, SavingWorkbasketService, RequestInProgressService,
|
||||
CustomFieldsService, AccessIdsService, FormsValidatorService]
|
||||
});
|
||||
};
|
||||
configureTests(configure).then(testBed => {
|
||||
fixture = TestBed.createComponent(AccessItemsComponent);
|
||||
storeSpy.select.and.callFake(selector => {
|
||||
switch (selector) {
|
||||
case EngineConfigurationSelectors.accessItemsCustomisation:
|
||||
return of({
|
||||
accessId: {
|
||||
lookupField: false
|
||||
},
|
||||
custom1: {}
|
||||
});
|
||||
default:
|
||||
return of();
|
||||
}
|
||||
});
|
||||
|
||||
fixture = testBed.createComponent(AccessItemsComponent);
|
||||
|
||||
component = fixture.componentInstance;
|
||||
component.workbasket = new Workbasket('1');
|
||||
component.workbasket.type = ICONTYPES.TOPIC;
|
||||
component.workbasket._links = new Links();
|
||||
component.workbasket._links.accessItems = { href: 'someurl' };
|
||||
|
||||
workbasketService = TestBed.get(WorkbasketService);
|
||||
alertService = TestBed.get(AlertService);
|
||||
workbasketService = testBed.get(WorkbasketService);
|
||||
alertService = testBed.get(AlertService);
|
||||
spyOn(workbasketService, 'getWorkBasketAccessItems').and.returnValue(of(new WorkbasketAccessItemsResource(
|
||||
new Array<WorkbasketAccessItems>(
|
||||
new WorkbasketAccessItems('id1', '1', 'accessID1', '', false, false, false, false, false, false, false, false,
|
||||
|
@ -64,11 +82,11 @@ describe('AccessItemsComponent', () => {
|
|||
spyOn(workbasketService, 'updateWorkBasketAccessItem').and.returnValue(of(true));
|
||||
spyOn(alertService, 'triggerAlert').and.returnValue(of(true));
|
||||
debugElement = fixture.debugElement.nativeElement;
|
||||
accessIdsService = TestBed.get(AccessIdsService);
|
||||
accessIdsService = testBed.get(AccessIdsService);
|
||||
spyOn(accessIdsService, 'getAccessItemsInformation').and.returnValue(of(new Array<string>(
|
||||
'accessID1', 'accessID2'
|
||||
)));
|
||||
formsValidatorService = TestBed.get(FormsValidatorService);
|
||||
formsValidatorService = testBed.get(FormsValidatorService);
|
||||
component.ngOnChanges({
|
||||
active: new SimpleChange(undefined, 'accessItems', true)
|
||||
});
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
import { Component, Input, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { Select } from '@ngxs/store';
|
||||
import { FormArray, FormBuilder, Validators } from '@angular/forms';
|
||||
|
||||
import { Workbasket } from 'app/models/workbasket';
|
||||
import { WorkbasketAccessItems } from 'app/models/workbasket-access-items';
|
||||
import { WorkbasketAccessItems, customFieldCount } from 'app/models/workbasket-access-items';
|
||||
import { WorkbasketAccessItemsResource } from 'app/models/workbasket-access-items-resource';
|
||||
import { ACTION } from 'app/models/action';
|
||||
import { AlertModel, AlertType } from 'app/models/alert';
|
||||
|
||||
import { SavingInformation,
|
||||
SavingWorkbasketService } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
|
||||
import { AlertModel, AlertType } from 'app/models/alert';
|
||||
import { SavingInformation, SavingWorkbasketService } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
|
||||
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
|
||||
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
|
||||
import { AlertService } from 'app/services/alert/alert.service';
|
||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
import { highlight } from 'app/shared/animations/validation.animation';
|
||||
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
|
||||
import { AccessIdDefinition } from 'app/models/access-id';
|
||||
import { EngineConfigurationSelectors } from 'app/store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { ERROR_TYPES } from '../../../../models/errors';
|
||||
import { ErrorsService } from '../../../../services/errors/errors.service';
|
||||
import { AccessItemsCustomisation, CustomField, getCustomFields } from '../../../../models/customisation';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-workbasket-access-items',
|
||||
|
@ -39,26 +40,13 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
|
|||
|
||||
badgeMessage = '';
|
||||
|
||||
accessIdField = this.customFieldsService.getCustomField('Owner', 'workbaskets.access-items.accessId');
|
||||
custom1Field = this.customFieldsService.getCustomField('Custom 1', 'workbaskets.access-items.custom1');
|
||||
custom2Field = this.customFieldsService.getCustomField('Custom 2', 'workbaskets.access-items.custom2');
|
||||
custom3Field = this.customFieldsService.getCustomField('Custom 3', 'workbaskets.access-items.custom3');
|
||||
custom4Field = this.customFieldsService.getCustomField('Custom 4', 'workbaskets.access-items.custom4');
|
||||
custom5Field = this.customFieldsService.getCustomField('Custom 5', 'workbaskets.access-items.custom5');
|
||||
custom6Field = this.customFieldsService.getCustomField('Custom 6', 'workbaskets.access-items.custom6');
|
||||
custom7Field = this.customFieldsService.getCustomField('Custom 7', 'workbaskets.access-items.custom7');
|
||||
custom8Field = this.customFieldsService.getCustomField('Custom 8', 'workbaskets.access-items.custom8');
|
||||
custom9Field = this.customFieldsService.getCustomField('Custom 9', 'workbaskets.access-items.custom9');
|
||||
custom10Field = this.customFieldsService.getCustomField('Custom 10', 'workbaskets.access-items.custom10');
|
||||
custom11Field = this.customFieldsService.getCustomField('Custom 11', 'workbaskets.access-items.custom11');
|
||||
custom12Field = this.customFieldsService.getCustomField('Custom 12', 'workbaskets.access-items.custom12');
|
||||
@Select(EngineConfigurationSelectors.accessItemsCustomisation) accessItemsCustomization$: Observable<AccessItemsCustomisation>;
|
||||
customFields$: Observable<CustomField[]>;
|
||||
|
||||
accessItemsResource: WorkbasketAccessItemsResource;
|
||||
accessItemsClone: Array<WorkbasketAccessItems>;
|
||||
accessItemsResetClone: Array<WorkbasketAccessItems>;
|
||||
requestInProgress = false;
|
||||
modalTitle: string;
|
||||
modalErrorMessage: string;
|
||||
accessItemsubscription: Subscription;
|
||||
savingAccessItemsSubscription: Subscription;
|
||||
AccessItemsForm = this.formBuilder.group({
|
||||
|
@ -74,7 +62,6 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
|
|||
private generalModalService: GeneralModalService,
|
||||
private savingWorkbaskets: SavingWorkbasketService,
|
||||
private requestInProgressService: RequestInProgressService,
|
||||
private customFieldsService: CustomFieldsService,
|
||||
private formBuilder: FormBuilder,
|
||||
private formsValidatorService: FormsValidatorService,
|
||||
private errorsService: ErrorsService
|
||||
|
@ -85,6 +72,10 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
|
|||
return this.AccessItemsForm.get('accessItemsGroups') as FormArray;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.customFields$ = this.accessItemsCustomization$.pipe(getCustomFields(customFieldCount));
|
||||
}
|
||||
|
||||
setAccessItemsGroups(accessItems: Array<WorkbasketAccessItems>) {
|
||||
const AccessItemsFormGroups = accessItems.map(accessItem => this.formBuilder.group(accessItem));
|
||||
AccessItemsFormGroups.forEach(accessItemGroup => {
|
||||
|
@ -225,4 +216,8 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
|
|||
element.workbasketId = workbasketId;
|
||||
});
|
||||
}
|
||||
|
||||
getAccessItemCustomProperty(customNumber: number): string {
|
||||
return `permCustom${customNumber}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
</div>
|
||||
<div class="input-group form-group col-xs-12 required">
|
||||
<label for="wb-owner" class="control-label ">Owner</label>
|
||||
<taskana-type-ahead *ngIf="ownerField.lookupField else ownerInput" required #owner="ngModel" name="workbasket.owner"
|
||||
<taskana-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-type-ahead>
|
||||
<ng-template #ownerInput>
|
||||
|
@ -107,26 +107,13 @@
|
|||
<input type="text" class="form-control" id="wb-org-level-4" placeholder="OrgLevel 4" [(ngModel)]="workbasket.orgLevel4"
|
||||
name="workbasket.orgLevel4">
|
||||
</div>
|
||||
<div *ngIf="custom1Field.visible" class="form-group">
|
||||
<label for="wb-custom-1" class="control-label">{{custom1Field.field}}</label>
|
||||
<input type="text" class="form-control" id="wb-custom-1" [placeholder]="custom1Field.field"
|
||||
[(ngModel)]="workbasket.custom1" name="workbasket.custom1">
|
||||
</div>
|
||||
<div *ngIf="custom2Field.visible" class="form-group">
|
||||
<label for="wb-custom-2" class="control-label">{{custom2Field.field}}</label>
|
||||
<input type="text" class="form-control" id="wb-custom-2" [placeholder]="custom2Field.field"
|
||||
[(ngModel)]="workbasket.custom2" name="workbasket.custom2">
|
||||
</div>
|
||||
<div *ngIf="custom3Field.visible" class="form-group">
|
||||
<label for="wb-custom-3" class="control-label">{{custom3Field.field}}</label>
|
||||
<input type="text" class="form-control" id="wb-custom-3" [placeholder]="custom3Field.field"
|
||||
[(ngModel)]="workbasket.custom3" name="workbasket.custom3">
|
||||
</div>
|
||||
<div *ngIf="custom4Field.visible" class="form-group">
|
||||
<label for="wb-custom-4" class="control-label">{{custom4Field.field}}</label>
|
||||
<input type="text" class="form-control" id="wb-custom-4" [placeholder]="custom4Field.field"
|
||||
[(ngModel)]="workbasket.custom4" name="workbasket.custom4">
|
||||
</div>
|
||||
<ng-container *ngFor="let customField of customFields$ | async; let index = index">
|
||||
<div *ngIf="customField.visible" class="form-group">
|
||||
<label for='wb-custom-{{index+1}}' class="control-label">{{customField.field}}</label>
|
||||
<input type="text" class="form-control" id="wb-custom-{{index+1}}" [placeholder]="customField.field"
|
||||
[(ngModel)]="workbasket[getWorkbasketCustomProperty(index + 1)]" name="workbasket[getWorkbasketCustomValue(index + 1)]">
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -17,9 +17,10 @@ import { GeneralModalService } from 'app/services/general-modal/general-modal.se
|
|||
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
|
||||
import { AlertService } from 'app/services/alert/alert.service';
|
||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
import { configureTests } from 'app/app.test.configuration';
|
||||
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
|
||||
import { NgxsModule, Store } from '@ngxs/store';
|
||||
import { EngineConfigurationSelectors } from 'app/store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { WorkbasketInformationComponent } from './workbasket-information.component';
|
||||
|
||||
@Component({
|
||||
|
@ -44,29 +45,38 @@ describe('WorkbasketInformationComponent', () => {
|
|||
let requestInProgressService;
|
||||
let formsValidatorService;
|
||||
|
||||
beforeEach(done => {
|
||||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
declarations: [WorkbasketInformationComponent, DummyDetailComponent],
|
||||
imports: [FormsModule,
|
||||
AngularSvgIconModule,
|
||||
HttpClientModule,
|
||||
RouterTestingModule.withRoutes(routes)],
|
||||
providers: [WorkbasketService, AlertService, SavingWorkbasketService, GeneralModalService, RequestInProgressService,
|
||||
CustomFieldsService, 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()],
|
||||
providers: [WorkbasketService, AlertService, SavingWorkbasketService, GeneralModalService,
|
||||
RequestInProgressService, FormsValidatorService, { provide: Store, useValue: storeSpy }]
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(done => {
|
||||
configureTests(configure).then(testBed => {
|
||||
fixture = TestBed.createComponent(WorkbasketInformationComponent);
|
||||
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;
|
||||
workbasketService = TestBed.get(WorkbasketService);
|
||||
alertService = TestBed.get(AlertService);
|
||||
savingWorkbasketService = TestBed.get(SavingWorkbasketService);
|
||||
requestInProgressService = TestBed.get(RequestInProgressService);
|
||||
workbasketService = testBed.get(WorkbasketService);
|
||||
alertService = testBed.get(AlertService);
|
||||
savingWorkbasketService = testBed.get(SavingWorkbasketService);
|
||||
requestInProgressService = testBed.get(RequestInProgressService);
|
||||
|
||||
formsValidatorService = TestBed.get(FormsValidatorService);
|
||||
formsValidatorService = testBed.get(FormsValidatorService);
|
||||
|
||||
spyOn(alertService, 'triggerAlert');
|
||||
fixture.detectChanges();
|
||||
|
@ -113,7 +123,7 @@ describe('WorkbasketInformationComponent', () => {
|
|||
expect(component.workbasket.workbasketId).toEqual(component.workbasketClone.workbasketId);
|
||||
});
|
||||
|
||||
it('should reset requestInProgress after saving request is done', () => {
|
||||
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', new Links({ href: 'someUrl' }));
|
||||
|
@ -122,7 +132,7 @@ describe('WorkbasketInformationComponent', () => {
|
|||
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',
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { Component, OnInit, Input, OnDestroy, OnChanges, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { NgForm } from '@angular/forms';
|
||||
import { Select } from '@ngxs/store';
|
||||
|
||||
import { ICONTYPES } from 'app/models/type';
|
||||
import { MessageModal } from 'app/models/message-modal';
|
||||
import { ACTION } from 'app/models/action';
|
||||
import { Workbasket } from 'app/models/workbasket';
|
||||
import { customFieldCount, Workbasket } from 'app/models/workbasket';
|
||||
import { AlertModel, AlertType } from 'app/models/alert';
|
||||
import { TaskanaDate } from 'app/shared/util/taskana.date';
|
||||
|
||||
|
@ -15,11 +15,13 @@ import { GeneralModalService } from 'app/services/general-modal/general-modal.se
|
|||
import { SavingWorkbasketService, SavingInformation } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
|
||||
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
|
||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
|
||||
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { EngineConfigurationSelectors } from 'app/store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { ERROR_TYPES } from '../../../../models/errors';
|
||||
import { ErrorsService } from '../../../../services/errors/errors.service';
|
||||
import { CustomField, getCustomFields, WorkbasketsCustomisation } from '../../../../models/customisation';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-workbasket-information',
|
||||
|
@ -40,30 +42,8 @@ implements OnInit, OnChanges, OnDestroy {
|
|||
requestInProgress = false;
|
||||
badgeMessage = '';
|
||||
|
||||
ownerField = this.customFieldsService.getCustomField(
|
||||
'Owner',
|
||||
'workbaskets.information.owner'
|
||||
);
|
||||
|
||||
custom1Field = this.customFieldsService.getCustomField(
|
||||
'Custom 1',
|
||||
'workbaskets.information.custom1'
|
||||
);
|
||||
|
||||
custom2Field = this.customFieldsService.getCustomField(
|
||||
'Custom 2',
|
||||
'workbaskets.information.custom2'
|
||||
);
|
||||
|
||||
custom3Field = this.customFieldsService.getCustomField(
|
||||
'Custom 3',
|
||||
'workbaskets.information.custom3'
|
||||
);
|
||||
|
||||
custom4Field = this.customFieldsService.getCustomField(
|
||||
'Custom 4',
|
||||
'workbaskets.information.custom4'
|
||||
);
|
||||
@Select(EngineConfigurationSelectors.workbasketsCustomisation) workbasketsCustomisation$: Observable<WorkbasketsCustomisation>;
|
||||
customFields$: Observable<CustomField[]>;
|
||||
|
||||
toogleValidationMap = new Map<string, boolean>();
|
||||
|
||||
|
@ -80,21 +60,24 @@ implements OnInit, OnChanges, OnDestroy {
|
|||
private generalModalService: GeneralModalService,
|
||||
private savingWorkbasket: SavingWorkbasketService,
|
||||
private requestInProgressService: RequestInProgressService,
|
||||
private customFieldsService: CustomFieldsService,
|
||||
private removeConfirmationService: RemoveConfirmationService,
|
||||
private formsValidatorService: FormsValidatorService,
|
||||
private errorsService: ErrorsService
|
||||
) {
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.allTypes = new Map([
|
||||
['PERSONAL', 'Personal'],
|
||||
['GROUP', 'Group'],
|
||||
['CLEARANCE', 'Clearance'],
|
||||
['TOPIC', 'Topic']
|
||||
]);
|
||||
this.customFields$ = this.workbasketsCustomisation$.pipe(
|
||||
map(customisation => customisation.information),
|
||||
getCustomFields(customFieldCount)
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit(): void { }
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
this.workbasketClone = { ...this.workbasket };
|
||||
if (this.action === ACTION.CREATE) {
|
||||
|
@ -290,4 +273,8 @@ implements OnInit, OnChanges, OnDestroy {
|
|||
this.routeSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
getWorkbasketCustomProperty(custom: number) {
|
||||
return `custom${custom}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import { AlertService } from 'app/services/alert/alert.service';
|
|||
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
|
||||
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
|
||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
import { configureTests } from 'app/app.test.configuration';
|
||||
|
||||
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
|
||||
|
@ -63,7 +62,7 @@ describe('WorkbasketDetailsComponent', () => {
|
|||
AccessItemsComponent,
|
||||
DistributionTargetsComponent, DualListComponent, DummyDetailComponent],
|
||||
providers: [WorkbasketService, MasterAndDetailService, GeneralModalService, RequestInProgressService,
|
||||
AlertService, SavingWorkbasketService, CustomFieldsService, ImportExportService]
|
||||
AlertService, SavingWorkbasketService, ImportExportService]
|
||||
});
|
||||
};
|
||||
configureTests(configure).then(testBed => {
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
* Modules
|
||||
*/
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||
import { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { NgxsModule } from '@ngxs/store';
|
||||
import { NgxsReduxDevtoolsPluginModule } from '@ngxs/devtools-plugin';
|
||||
import { AlertModule } from 'ngx-bootstrap';
|
||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
|
@ -15,7 +17,6 @@ import { SharedModule } from 'app/shared/shared.module';
|
|||
/**
|
||||
* Services
|
||||
*/
|
||||
|
||||
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
|
||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||
import { OrientationService } from 'app/services/orientation/orientation.service';
|
||||
|
@ -26,7 +27,6 @@ import { AlertService } from 'app/services/alert/alert.service';
|
|||
import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-detail.service';
|
||||
import { TreeService } from 'app/services/tree/tree.service';
|
||||
import { TitlesService } from 'app/services/titles/titles.service';
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
import { WindowRefService } from 'app/services/window/window.service';
|
||||
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
|
||||
import { NavBarComponent } from 'app/components/nav-bar/nav-bar.component';
|
||||
|
@ -36,14 +36,11 @@ import { RemoveConfirmationService } from './services/remove-confirmation/remove
|
|||
import { FormsValidatorService } from './shared/services/forms/forms-validator.service';
|
||||
import { UploadService } from './shared/services/upload/upload.service';
|
||||
import { ErrorsService } from './services/errors/errors.service';
|
||||
|
||||
|
||||
/**
|
||||
* Components
|
||||
*/
|
||||
import { AppComponent } from './app.component';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
|
||||
/**
|
||||
* Guards
|
||||
*/
|
||||
|
@ -51,7 +48,12 @@ import { DomainGuard } from './guards/domain.guard';
|
|||
import { BusinessAdminGuard } from './guards/business-admin.guard';
|
||||
import { MonitorGuard } from './guards/monitor.guard';
|
||||
import { UserGuard } from './guards/user.guard';
|
||||
|
||||
/**
|
||||
* Store
|
||||
*/
|
||||
import { ClassificationCategoriesService } from './shared/services/classifications/classification-categories.service';
|
||||
import { environment } from '../environments/environment';
|
||||
import { STATES } from './store';
|
||||
|
||||
const MODULES = [
|
||||
TabsModule.forRoot(),
|
||||
|
@ -64,7 +66,9 @@ const MODULES = [
|
|||
BrowserAnimationsModule,
|
||||
ReactiveFormsModule,
|
||||
TreeModule,
|
||||
SharedModule
|
||||
SharedModule,
|
||||
NgxsModule.forRoot(STATES, { developmentMode: !environment.production }),
|
||||
NgxsReduxDevtoolsPluginModule.forRoot({ disabled: environment.production, maxAge: 25 })
|
||||
];
|
||||
|
||||
const DECLARATIONS = [
|
||||
|
@ -104,12 +108,12 @@ export function startupServiceFactory(startupService: StartupService): () => Pro
|
|||
MasterAndDetailService,
|
||||
TreeService,
|
||||
TitlesService,
|
||||
CustomFieldsService,
|
||||
TaskanaEngineService,
|
||||
RemoveConfirmationService,
|
||||
FormsValidatorService,
|
||||
UploadService,
|
||||
ErrorsService,
|
||||
ClassificationCategoriesService,
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
|
|
@ -3,7 +3,6 @@ import { getTestBed, TestBed } from '@angular/core/testing';
|
|||
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
@ -35,7 +34,7 @@ export const configureTests = (configure: (testBed: TestBed) => void) => {
|
|||
testBed.configureTestingModule({
|
||||
imports: [BrowserAnimationsModule, SharedModule, FormsModule, ReactiveFormsModule, HttpClientModule, AngularSvgIconModule],
|
||||
providers: [{ provide: TaskanaEngineService, useClass: TaskanaEngineServiceMock },
|
||||
{ provide: DomainService, useClass: DomainServiceMock }, CustomFieldsService, RemoveConfirmationService,
|
||||
{ provide: DomainService, useClass: DomainServiceMock }, RemoveConfirmationService,
|
||||
AlertService, GeneralModalService, RequestInProgressService, OrientationService, SelectedRouteService, FormsValidatorService]
|
||||
});
|
||||
|
||||
|
|
|
@ -27,3 +27,5 @@ export class ClassificationDefinition {
|
|||
public _links?: LinksClassification) {
|
||||
}
|
||||
}
|
||||
|
||||
export const customFieldCount: number = 8;
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
|
||||
export class CustomField {
|
||||
constructor(
|
||||
public visible: boolean,
|
||||
public field: string
|
||||
) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
import { map } from 'rxjs/operators';
|
||||
import { OperatorFunction } from 'rxjs';
|
||||
|
||||
export interface Customisation {
|
||||
[language: string]: CustomisationContent
|
||||
}
|
||||
|
||||
export interface CustomisationContent {
|
||||
workbaskets?: WorkbasketsCustomisation;
|
||||
classifications?: ClassificationsCustomisation;
|
||||
tasks?: TasksCustomisation;
|
||||
}
|
||||
|
||||
export interface TasksCustomisation {
|
||||
information?: {
|
||||
owner: LookupField
|
||||
};
|
||||
}
|
||||
|
||||
export interface ClassificationsCustomisation {
|
||||
information?: CustomFields;
|
||||
categories?: ClassificationCategoryImages
|
||||
}
|
||||
|
||||
export interface ClassificationCategoryImages {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
export interface WorkbasketsCustomisation {
|
||||
information?: { owner: LookupField } & CustomFields;
|
||||
'access-items'?: AccessItemsCustomisation;
|
||||
}
|
||||
|
||||
export type AccessItemsCustomisation = { accessId?: LookupField } & CustomFields;
|
||||
|
||||
export interface CustomFields {
|
||||
[key: string]: CustomField
|
||||
}
|
||||
|
||||
export interface CustomField {
|
||||
visible: boolean
|
||||
field: string
|
||||
}
|
||||
|
||||
export interface LookupField {
|
||||
lookupField: boolean
|
||||
}
|
||||
|
||||
export function getCustomFields(amount: number): OperatorFunction<CustomFields, CustomField[]> {
|
||||
return map<CustomFields, CustomField[]>(customisation => [...Array(amount).keys()]
|
||||
.map(x => x + 1)
|
||||
.map(x => customisation[`custom${x}`] || {
|
||||
field: `Custom ${x}`,
|
||||
visible: true
|
||||
}));
|
||||
}
|
|
@ -26,3 +26,5 @@ export class WorkbasketAccessItems {
|
|||
public _links: Links = new Links()
|
||||
) { }
|
||||
}
|
||||
|
||||
export const customFieldCount: number = 12;
|
||||
|
|
|
@ -46,3 +46,5 @@ export class Workbasket {
|
|||
) {
|
||||
}
|
||||
}
|
||||
|
||||
export const customFieldCount: number = 4;
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { CustomFieldsService } from './custom-fields.service';
|
||||
|
||||
const json = require('./taskana-customization-test.json');
|
||||
|
||||
describe('CustomFieldsService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [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);
|
||||
expect(returnedValue).toBe(categoriesData);
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
|
||||
it('should take default icon path in merge', inject([CustomFieldsService], (service: CustomFieldsService) => {
|
||||
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) => {
|
||||
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();
|
||||
}));
|
||||
});
|
|
@ -1,78 +0,0 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { CustomField } from '../../models/customField';
|
||||
|
||||
@Injectable()
|
||||
export class CustomFieldsService {
|
||||
private customizedFields: any = {};
|
||||
|
||||
initCustomFields(language: string = 'EN', jsonFile: any) {
|
||||
this.customizedFields = jsonFile[language];
|
||||
}
|
||||
|
||||
getCustomField(fallbacktext: string, customPath?: string): CustomField {
|
||||
if (!customPath) {
|
||||
return new CustomField(true, fallbacktext);
|
||||
}
|
||||
return this.jsonPath(customPath, fallbacktext);
|
||||
}
|
||||
|
||||
getCustomObject(fallbackObject: Object, customPath?: string): Object {
|
||||
if (!customPath) {
|
||||
return fallbackObject;
|
||||
}
|
||||
return this.jsonPathObject(customPath, fallbackObject);
|
||||
}
|
||||
|
||||
private jsonPath(path: string, fallbacktext: string): CustomField {
|
||||
if (!this.customizedFields) {
|
||||
return new CustomField(true, fallbacktext);
|
||||
}
|
||||
const paths = path.split('.');
|
||||
let value = this.customizedFields;
|
||||
paths.every(element => {
|
||||
value = value[element];
|
||||
if (!value) {
|
||||
value = new CustomField(true, fallbacktext);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
private jsonPathObject(path: string, fallbackObject: Object): Object {
|
||||
if (!this.customizedFields) {
|
||||
return fallbackObject;
|
||||
}
|
||||
const paths = path.split('.');
|
||||
let value = this.customizedFields;
|
||||
paths.every(element => {
|
||||
value = value[element];
|
||||
if (!value) {
|
||||
value = fallbackObject;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
value = this.mergeKeys(value, fallbackObject);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private mergeKeys(defaultObject: Object, newObject: Object) {
|
||||
const value = {};
|
||||
|
||||
Object.keys(defaultObject).forEach(item => {
|
||||
value[item] = value[item] ? value[item] : defaultObject[item];
|
||||
});
|
||||
|
||||
Object.keys(newObject).forEach(item => {
|
||||
value[item] = value[item] ? value[item] : newObject[item];
|
||||
});
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ import { TestBed, inject, getTestBed } from '@angular/core/testing';
|
|||
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
||||
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
|
||||
import { StartupService } from './startup.service';
|
||||
import { CustomFieldsService } from '../custom-fields/custom-fields.service';
|
||||
import { TaskanaEngineService } from '../taskana-engine/taskana-engine.service';
|
||||
import { WindowRefService } from '../window/window.service';
|
||||
import { environment } from '../../../environments/environment';
|
||||
|
@ -29,7 +28,6 @@ describe('StartupService', () => {
|
|||
providers: [
|
||||
StartupService,
|
||||
HttpClient,
|
||||
CustomFieldsService,
|
||||
TaskanaEngineService,
|
||||
WindowRefService
|
||||
]
|
||||
|
|
|
@ -3,7 +3,6 @@ import { HttpClient } from '@angular/common/http';
|
|||
import { Router } from '@angular/router';
|
||||
import { environment } from 'app/../environments/environment';
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { WindowRefService } from 'app/services/window/window.service';
|
||||
|
@ -12,7 +11,6 @@ import { WindowRefService } from 'app/services/window/window.service';
|
|||
export class StartupService {
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private customFieldsService: CustomFieldsService,
|
||||
private taskanaEngineService: TaskanaEngineService,
|
||||
private injector: Injector,
|
||||
private window: WindowRefService
|
||||
|
@ -27,6 +25,7 @@ export class StartupService {
|
|||
return this.loadEnvironment();
|
||||
}
|
||||
|
||||
// TODO: refactor this
|
||||
getEnvironmentFilePromise() {
|
||||
return this.httpClient.get<any>('environments/data-sources/environment-information.json').pipe(map(jsonFile => {
|
||||
if (jsonFile && jsonFile.taskanaRestUrl) {
|
||||
|
@ -36,24 +35,12 @@ export class StartupService {
|
|||
if (jsonFile && jsonFile.taskanaLogoutUrl) {
|
||||
environment.taskanaLogoutUrl = jsonFile.taskanaLogoutUrl;
|
||||
}
|
||||
this.customFieldsService.initCustomFields('EN', jsonFile);
|
||||
})).toPromise()
|
||||
.catch(() => of(true));
|
||||
}
|
||||
|
||||
geCustomizedFieldsFilePromise() {
|
||||
return this.httpClient.get<any>('environments/data-sources/taskana-customization.json').pipe(map(jsonFile => {
|
||||
if (jsonFile) {
|
||||
this.customFieldsService.initCustomFields('EN', jsonFile);
|
||||
}
|
||||
})).toPromise()
|
||||
.catch(() => of(true));
|
||||
}
|
||||
|
||||
private loadEnvironment() {
|
||||
return this.getEnvironmentFilePromise().then(
|
||||
() => this.geCustomizedFieldsFilePromise()
|
||||
).then(
|
||||
() => this.taskanaEngineService.getUserInformation()
|
||||
).catch(error => {
|
||||
// this.window.nativeWindow.location.href = environment.taskanaRestUrl + '/login';
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<div class="dropdown clearfix btn-group">
|
||||
<button type="button" class="btn btn-default"> {{classificationTypeSelected}}</button>
|
||||
<button type="button" class="btn btn-default"> {{classificationTypeSelected$ | async}}</button>
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
<span class="caret"></span>
|
||||
<span class="sr-only">Toggle Dropdown</span>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right sortby-dropdown popup" aria-labelledby="sortingDropdown">
|
||||
<li *ngFor="let classificationType of classificationTypes">
|
||||
<li *ngFor="let classificationType of classificationTypes$ | async">
|
||||
<a (click)="select(classificationType)">
|
||||
<label>
|
||||
<span data-toggle="tooltip" class="material-icons md-20 blue">{{classificationTypeSelected === classificationType?
|
||||
<span data-toggle="tooltip" class="material-icons md-20 blue">{{(classificationTypeSelected$ | async) === classificationType?
|
||||
'check_box': 'check_box_outline_blank'}}</span>
|
||||
<span>{{classificationType}}</span>
|
||||
</label>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { NgxsModule } from '@ngxs/store';
|
||||
import { ClassificationTypesSelectorComponent } from './classification-types-selector.component';
|
||||
|
||||
describe('ClassificationTypesSelectorComponent', () => {
|
||||
|
@ -8,9 +9,10 @@ describe('ClassificationTypesSelectorComponent', () => {
|
|||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ClassificationTypesSelectorComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
imports: [NgxsModule.forRoot()],
|
||||
declarations: [ClassificationTypesSelectorComponent],
|
||||
providers: []
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -1,28 +1,22 @@
|
|||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Store, Select } from '@ngxs/store';
|
||||
import { ClassificationSelectors } from 'app/store/classification-store/classification.selectors';
|
||||
import { SetSelectedClassificationType } from 'app/store/classification-store/classification.actions';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-classification-types-selector',
|
||||
templateUrl: './classification-types-selector.component.html',
|
||||
styleUrls: ['./classification-types-selector.component.scss']
|
||||
})
|
||||
export class ClassificationTypesSelectorComponent implements OnInit {
|
||||
@Input()
|
||||
classificationTypes: Array<string> = [];
|
||||
export class ClassificationTypesSelectorComponent {
|
||||
@Select(ClassificationSelectors.selectedClassificationType) classificationTypeSelected$: Observable<string>;
|
||||
@Select(ClassificationSelectors.classificationTypes) classificationTypes$: Observable<string[]>;
|
||||
|
||||
@Input()
|
||||
classificationTypeSelected: string;
|
||||
constructor(private store: Store) {}
|
||||
|
||||
@Output()
|
||||
classificationTypeSelectedChange = new EventEmitter<string>();
|
||||
|
||||
@Output()
|
||||
classificationTypeChanged = new EventEmitter<string>();
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
select(value: string) {
|
||||
this.classificationTypeSelected = value;
|
||||
this.classificationTypeChanged.emit(value);
|
||||
select(value: string): void {
|
||||
this.store.dispatch(new SetSelectedClassificationType(value));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
|
||||
import { Customisation, CustomisationContent } from 'app/models/customisation';
|
||||
import { ClassificationCategoriesService, missingIcon } from './classification-categories.service';
|
||||
|
||||
describe('ClassificationCategoriesService', () => {
|
||||
let categoryService: ClassificationCategoriesService;
|
||||
let httpMock: HttpTestingController;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [HttpClientTestingModule],
|
||||
providers: [ClassificationCategoriesService]
|
||||
});
|
||||
|
||||
categoryService = TestBed.get(ClassificationCategoriesService);
|
||||
httpMock = TestBed.get(HttpTestingController);
|
||||
});
|
||||
|
||||
it('should insert missing icon into customisation', async(() => {
|
||||
const expectedCustomisationContent: CustomisationContent = { classifications:
|
||||
{ categories:
|
||||
{ missing: missingIcon } } };
|
||||
|
||||
const expectedCustomisation: Customisation = { EN: expectedCustomisationContent, DE: expectedCustomisationContent };
|
||||
|
||||
const initialCustomisations: Customisation[] = [
|
||||
{ EN: { classifications: { categories: {} } }, DE: { classifications: { categories: {} } } },
|
||||
{ EN: { classifications: {} }, DE: { classifications: {} } },
|
||||
{ EN: {}, DE: {} }
|
||||
];
|
||||
|
||||
initialCustomisations.forEach(initialCustomisation => {
|
||||
categoryService.getCustomisation()
|
||||
.subscribe(customisation => { expect(customisation).toEqual(expectedCustomisation); });
|
||||
|
||||
httpMock.expectOne('environments/data-sources/taskana-customization.json').flush(initialCustomisation);
|
||||
|
||||
httpMock.verify();
|
||||
});
|
||||
}));
|
||||
});
|
|
@ -2,87 +2,37 @@ import { HttpClient } from '@angular/common/http';
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { environment } from 'environments/environment';
|
||||
import { Observable, ReplaySubject, BehaviorSubject } from 'rxjs';
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
import { Pair } from 'app/models/pair';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import set from 'set-value';
|
||||
import { Customisation } from '../../../models/customisation';
|
||||
|
||||
const customisationUrl = 'environments/data-sources/taskana-customization.json';
|
||||
|
||||
export const missingIcon = 'assets/icons/categories/missing-icon.svg';
|
||||
|
||||
export interface CategoriesResponse { [key: string]: string[] }
|
||||
|
||||
@Injectable()
|
||||
export class ClassificationCategoriesService {
|
||||
private mainUrl = environment.taskanaRestUrl;
|
||||
private urlCategoriesByType = `${this.mainUrl}/v1/classifications-by-type`;
|
||||
|
||||
// categories
|
||||
private urlCategories = `${this.mainUrl}/v1/classification-categories`;
|
||||
private param = '/?type=';
|
||||
private dataObsCategories$ = new ReplaySubject<Array<string>>(1);
|
||||
private categoriesObject = {};
|
||||
private missingIcon = 'assets/icons/categories/missing-icon.svg';
|
||||
private type = 'UNKNOW';
|
||||
constructor(private httpClient: HttpClient) {}
|
||||
|
||||
// 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(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.dataObsCategories$;
|
||||
// TODO: convert to Map (maybe via ES6)
|
||||
getClassificationCategoriesByType(): Observable<CategoriesResponse> {
|
||||
return this.httpClient.get<CategoriesResponse>(this.urlCategoriesByType);
|
||||
}
|
||||
|
||||
getCategoryIcon(category: string): Pair {
|
||||
let categoryIcon = this.categoriesObject[category];
|
||||
let text = category;
|
||||
if (!categoryIcon) {
|
||||
categoryIcon = this.missingIcon;
|
||||
text = 'Category does not match with the configuration';
|
||||
}
|
||||
return new Pair(categoryIcon, text);
|
||||
}
|
||||
|
||||
private getCustomCategoriesObject(categories: Array<string>): Object {
|
||||
return this.customFieldsService.getCustomObject(
|
||||
this.getDefaultCategoryMap(categories), 'classifications.categories'
|
||||
getCustomisation(): Observable<Customisation> {
|
||||
return this.httpClient.get<Customisation>(customisationUrl).pipe(
|
||||
map(customisation => {
|
||||
Object.keys(customisation).forEach(lang => {
|
||||
set(customisation[lang], 'classifications.categories.missing', missingIcon);
|
||||
});
|
||||
return customisation;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private getDefaultCategoryMap(categoryList: Array<string>): Object {
|
||||
const defaultCategoryMap = {};
|
||||
categoryList.forEach(element => {
|
||||
defaultCategoryMap[element] = `assets/icons/categories/${element.toLowerCase()}.svg`;
|
||||
});
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { HttpClient } from '@angular/common/http';
|
|||
import { environment } from 'environments/environment';
|
||||
import { combineLatest, Observable, Subject } from 'rxjs';
|
||||
import { map, mergeMap, tap } from 'rxjs/operators';
|
||||
import { Select, Store } from '@ngxs/store';
|
||||
|
||||
import { Classification } from 'app/models/classification';
|
||||
import { ClassificationDefinition } from 'app/models/classification-definition';
|
||||
|
@ -12,7 +13,8 @@ import { DomainService } from 'app/services/domain/domain.service';
|
|||
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
|
||||
import { Direction } from 'app/models/sorting';
|
||||
import { QueryParametersModel } from 'app/models/query-parameters';
|
||||
import { ClassificationCategoriesService } from './classification-categories.service';
|
||||
import { ClassificationSelectors } from 'app/store/classification-store/classification.selectors';
|
||||
import { SetSelectedClassificationType } from 'app/store/classification-store/classification.actions';
|
||||
|
||||
@Injectable()
|
||||
export class ClassificationsService {
|
||||
|
@ -21,13 +23,14 @@ export class ClassificationsService {
|
|||
private classificationSaved = new Subject<number>();
|
||||
private classificationResourcePromise: Promise<ClassificationResource>;
|
||||
private lastDomain: string;
|
||||
// TODO: this should not be here in the service
|
||||
@Select(ClassificationSelectors.selectedClassificationType) classificationTypeSelected$: Observable<string>;
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private classificationCategoriesService: ClassificationCategoriesService,
|
||||
private domainService: DomainService
|
||||
) {
|
||||
}
|
||||
private domainService: DomainService,
|
||||
private store: Store
|
||||
) {}
|
||||
|
||||
private static classificationParameters(domain: string): QueryParametersModel {
|
||||
const parameters = new QueryParametersModel();
|
||||
|
@ -68,7 +71,7 @@ export class ClassificationsService {
|
|||
return this.httpClient.get<ClassificationDefinition>(`${this.url}${id}`)
|
||||
.pipe(tap((classification: ClassificationDefinition) => {
|
||||
if (classification) {
|
||||
this.classificationCategoriesService.selectClassificationType(classification.type);
|
||||
this.store.dispatch(new SetSelectedClassificationType(classification.type));
|
||||
}
|
||||
})).toPromise();
|
||||
}
|
||||
|
@ -107,15 +110,14 @@ export class ClassificationsService {
|
|||
|
||||
// #endregion
|
||||
|
||||
private getClassificationObservable(classificationRef: Observable<any>): Observable<Array<Classification>> {
|
||||
const classificationTypes: Observable<string> = this.classificationCategoriesService.getSelectedClassificationType();
|
||||
private getClassificationObservable(classificationRef: Observable<ClassificationResource>): Observable<Array<Classification>> {
|
||||
return combineLatest(
|
||||
[classificationRef,
|
||||
classificationTypes]
|
||||
this.classificationTypeSelected$]
|
||||
).pipe(
|
||||
map(
|
||||
(classification: any[]) => (
|
||||
classification[0].classifications ? this.buildHierarchy(classification[0].classifications, classification[1]) : []
|
||||
([resource, type]: [ClassificationResource, string]) => (
|
||||
resource.classifications ? this.buildHierarchy(resource.classifications, type) : []
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
(moveNode)="onMoveNode($event)" (treeDrop)="onDrop($event)">
|
||||
<ng-template #treeNodeTemplate let-node let-index="index">
|
||||
<span class="text-top">
|
||||
<svg-icon *ngIf="node.data.category" class="blue fa-fw" [src]="getCategoryIcon(node.data.category).name" data-toggle="tooltip"
|
||||
[title]="getCategoryIcon(node.data.category).text"></svg-icon>
|
||||
<svg-icon *ngIf="node.data.category" class="blue fa-fw" [src]="(getCategoryIcon(node.data.category) | async)?.name" data-toggle="tooltip"
|
||||
[title]="(getCategoryIcon(node.data.category) | async)?.text"></svg-icon>
|
||||
</span>
|
||||
<span>
|
||||
<strong>{{ node.data.key }}</strong>
|
||||
|
|
|
@ -3,14 +3,12 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
|
||||
import { TreeService } from 'app/services/tree/tree.service';
|
||||
import { configureTests } from 'app/app.test.configuration';
|
||||
import { Pair } from 'app/models/pair';
|
||||
import { NgxsModule } from '@ngxs/store';
|
||||
import { TaskanaTreeComponent } from './tree.component';
|
||||
import { ClassificationDefinition } from '../../models/classification-definition';
|
||||
import { LinksClassification } from '../../models/links-classfication';
|
||||
import { ClassificationCategoriesService } from '../services/classifications/classification-categories.service';
|
||||
import { ClassificationsService } from '../services/classifications/classifications.service';
|
||||
|
||||
@Component({
|
||||
|
@ -21,34 +19,27 @@ class TreeVendorComponent {
|
|||
@Input() options;
|
||||
@Input() state;
|
||||
@Input() nodes;
|
||||
treeModel = {
|
||||
getActiveNode() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe('TaskanaTreeComponent', () => {
|
||||
let component: TaskanaTreeComponent;
|
||||
let fixture: ComponentFixture<TaskanaTreeComponent>;
|
||||
let classificationCategoriesService;
|
||||
let classificationsService;
|
||||
let moveNodeEvent;
|
||||
let dropEvent;
|
||||
|
||||
beforeEach(done => {
|
||||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
imports: [AngularSvgIconModule, HttpClientModule],
|
||||
declarations: [TreeVendorComponent],
|
||||
providers: [TreeService, ClassificationCategoriesService, ClassificationsService]
|
||||
const configure = (testBed: TestBed) => {
|
||||
testBed.configureTestingModule({
|
||||
imports: [AngularSvgIconModule, HttpClientModule, NgxsModule.forRoot()],
|
||||
declarations: [TreeVendorComponent],
|
||||
providers: [TreeService, ClassificationsService]
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
};
|
||||
beforeEach(done => {
|
||||
configureTests(configure).then(testBed => {
|
||||
fixture = testBed.createComponent(TaskanaTreeComponent);
|
||||
classificationCategoriesService = testBed.get(ClassificationCategoriesService);
|
||||
spyOn(classificationCategoriesService, 'getCategoryIcon').and.returnValue(new Pair('assets/icons/categories/external.svg'));
|
||||
classificationsService = TestBed.get(ClassificationsService);
|
||||
classificationsService = testBed.get(ClassificationsService);
|
||||
spyOn(classificationsService, 'putClassification').and.callFake((url, classification) => classification);
|
||||
moveNodeEvent = {
|
||||
eventName: 'moveNode',
|
||||
|
|
|
@ -11,13 +11,16 @@ import { AfterViewChecked,
|
|||
import { TreeNodeModel } from 'app/models/tree-node';
|
||||
|
||||
import { ITreeOptions, KEYS, TreeComponent, TreeNode } from 'angular-tree-component';
|
||||
import { ClassificationCategoriesService } from 'app/shared/services/classifications/classification-categories.service';
|
||||
import { Pair } from 'app/models/pair';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { Select } from '@ngxs/store';
|
||||
import { EngineConfigurationSelectors } from 'app/store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { TreeService } from '../../services/tree/tree.service';
|
||||
import { Classification } from '../../models/classification';
|
||||
import { ClassificationDefinition } from '../../models/classification-definition';
|
||||
import { ClassificationsService } from '../services/classifications/classifications.service';
|
||||
import { ClassificationCategoryImages } from '../../models/customisation';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-tree',
|
||||
|
@ -25,9 +28,6 @@ import { ClassificationsService } from '../services/classifications/classificati
|
|||
styleUrls: ['./tree.component.scss'],
|
||||
})
|
||||
export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy {
|
||||
@ViewChild('tree', { static: true })
|
||||
private tree: TreeComponent;
|
||||
|
||||
@Input() treeNodes: Array<TreeNodeModel>;
|
||||
@Output() treeNodesChange = new EventEmitter<Array<TreeNodeModel>>();
|
||||
@Input() selectNodeId: string;
|
||||
|
@ -36,11 +36,7 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
|
|||
@Input() filterIcon = '';
|
||||
@Output() refreshClassification = new EventEmitter<string>();
|
||||
@Output() switchTaskanaSpinnerEmit = new EventEmitter<boolean>();
|
||||
|
||||
private filterTextOld: string;
|
||||
private filterIconOld = '';
|
||||
private removedNodeIdSubscription: Subscription;
|
||||
|
||||
@Select(EngineConfigurationSelectors.selectCategoryIcons) categoryIcons$: Observable<ClassificationCategoryImages>;
|
||||
options: ITreeOptions = {
|
||||
displayField: 'name',
|
||||
idField: 'classificationId',
|
||||
|
@ -59,6 +55,20 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
|
|||
allowDrop: true
|
||||
};
|
||||
|
||||
@ViewChild('tree', { static: true })
|
||||
private tree: TreeComponent;
|
||||
|
||||
private filterTextOld: string;
|
||||
private filterIconOld = '';
|
||||
private removedNodeIdSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private treeService: TreeService,
|
||||
private elementRef: ElementRef,
|
||||
private classificationsService: ClassificationsService,
|
||||
) {
|
||||
}
|
||||
|
||||
@HostListener('document:click', ['$event'])
|
||||
onDocumentClick(event) {
|
||||
if (this.checkValidElements(event) && this.tree.treeModel.getActiveNode()) {
|
||||
|
@ -66,14 +76,6 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
|
|||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
private treeService: TreeService,
|
||||
private categoryService: ClassificationCategoriesService,
|
||||
private elementRef: ElementRef,
|
||||
private classificationsService: ClassificationsService
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.removedNodeIdSubscription = this.treeService.getRemovedNodeId().subscribe(value => {
|
||||
const removedNode = this.getNode(value);
|
||||
|
@ -91,7 +93,7 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
|
|||
}
|
||||
|
||||
if (this.filterTextOld !== this.filterText
|
||||
|| this.filterIconOld !== this.filterIcon) {
|
||||
|| this.filterIconOld !== this.filterIcon) {
|
||||
this.filterIconOld = this.filterIcon;
|
||||
this.filterTextOld = this.filterText;
|
||||
this.filterNodes(this.filterText ? this.filterText : '', this.filterIcon);
|
||||
|
@ -127,8 +129,22 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
|
|||
}
|
||||
}
|
||||
|
||||
getCategoryIcon(category: string): Pair {
|
||||
return this.categoryService.getCategoryIcon(category);
|
||||
getCategoryIcon(category: string): Observable<Pair> {
|
||||
return this.categoryIcons$.pipe(map(
|
||||
iconMap => (iconMap[category]
|
||||
? new Pair(iconMap[category], category)
|
||||
: new Pair(iconMap.missing, 'Category does not match with the configuration'))
|
||||
));
|
||||
}
|
||||
|
||||
switchTaskanaSpinner(active: boolean) {
|
||||
this.switchTaskanaSpinnerEmit.emit(active);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.removedNodeIdSubscription) {
|
||||
this.removedNodeIdSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
private selectNode(nodeId: string) {
|
||||
|
@ -167,12 +183,12 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
|
|||
|
||||
private checkNameAndKey(node: any, text: string): boolean {
|
||||
return (node.data.name.toUpperCase().includes(text.toUpperCase())
|
||||
|| node.data.key.toUpperCase().includes(text.toUpperCase()));
|
||||
|| node.data.key.toUpperCase().includes(text.toUpperCase()));
|
||||
}
|
||||
|
||||
private checkIcon(node: any, iconText: string): boolean {
|
||||
return (node.data.category.toUpperCase() === iconText.toUpperCase()
|
||||
|| iconText === '');
|
||||
|| iconText === '');
|
||||
}
|
||||
|
||||
private manageTreeState() {
|
||||
|
@ -183,9 +199,9 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
|
|||
|
||||
private checkValidElements(event): boolean {
|
||||
return (this.elementRef.nativeElement.contains(event.target)
|
||||
|| this.elementRef.nativeElement === event.target)
|
||||
&& (event.target.localName === 'tree-viewport'
|
||||
|| event.target.localName === 'taskana-tree');
|
||||
|| this.elementRef.nativeElement === event.target)
|
||||
&& (event.target.localName === 'tree-viewport'
|
||||
|| event.target.localName === 'taskana-tree');
|
||||
}
|
||||
|
||||
private getClassification(classificationId: string): Promise<ClassificationDefinition> {
|
||||
|
@ -204,14 +220,4 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
|
|||
this.getNode(node.parentId).collapse();
|
||||
}
|
||||
}
|
||||
|
||||
switchTaskanaSpinner(active: boolean) {
|
||||
this.switchTaskanaSpinnerEmit.emit(active);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.removedNodeIdSubscription) {
|
||||
this.removedNodeIdSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export class SetSelectedClassificationType {
|
||||
static readonly type = '[Classification-Types-Selector] Set selected classification type';
|
||||
constructor(public selectedType: string) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import { Selector } from '@ngxs/store';
|
||||
import { ClassificationStateModel, ClassificationState } from './classification.state';
|
||||
|
||||
export class ClassificationSelectors {
|
||||
@Selector([ClassificationState])
|
||||
static classificationTypes(state: ClassificationStateModel): string[] {
|
||||
return Object.keys(state.classificationTypes);
|
||||
}
|
||||
|
||||
@Selector([ClassificationState])
|
||||
static selectedClassificationType(state: ClassificationStateModel): string {
|
||||
return state.selectedClassificationType;
|
||||
}
|
||||
|
||||
@Selector([ClassificationState])
|
||||
static selectCategories(state: ClassificationStateModel): string[] {
|
||||
return state.classificationTypes[state.selectedClassificationType];
|
||||
}
|
||||
|
||||
@Selector([ClassificationState])
|
||||
static selectClassificationTypesObject(state: ClassificationStateModel): Object {
|
||||
return state.classificationTypes;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
import { Action, State, StateContext } from '@ngxs/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { CategoriesResponse, ClassificationCategoriesService } from '../../shared/services/classifications/classification-categories.service';
|
||||
import { SetSelectedClassificationType } from './classification.actions';
|
||||
|
||||
class InitializeStore {
|
||||
static readonly type = '[ClassificationState] Initializing state';
|
||||
}
|
||||
|
||||
@State<ClassificationStateModel>({ name: 'classification' })
|
||||
export class ClassificationState {
|
||||
constructor(private categoryService: ClassificationCategoriesService) {
|
||||
}
|
||||
|
||||
@Action(SetSelectedClassificationType)
|
||||
setSelectedClassificationType(ctx: StateContext<ClassificationStateModel>, action: SetSelectedClassificationType): void {
|
||||
const state: ClassificationStateModel = ctx.getState();
|
||||
if (state.classificationTypes[action.selectedType]) {
|
||||
ctx.patchState({ selectedClassificationType: action.selectedType });
|
||||
}
|
||||
}
|
||||
|
||||
@Action(InitializeStore)
|
||||
initializeStore(ctx: StateContext<ClassificationStateModel>): Observable<any> {
|
||||
return this.categoryService.getClassificationCategoriesByType().pipe(
|
||||
tap(classificationTypes => {
|
||||
ctx.setState({
|
||||
...ctx.getState(),
|
||||
classificationTypes,
|
||||
selectedClassificationType: Object.keys(classificationTypes)[0],
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
ngxsOnInit(ctx: StateContext<ClassificationStateModel>): void {
|
||||
ctx.dispatch(new InitializeStore());
|
||||
}
|
||||
}
|
||||
|
||||
export interface ClassificationStateModel {
|
||||
selectedClassificationType: string;
|
||||
classificationTypes: CategoriesResponse,
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { WorkbasketsCustomisation, ClassificationsCustomisation, AccessItemsCustomisation, TasksCustomisation, ClassificationCategoryImages } from 'app/models/customisation';
|
||||
import { Selector } from '@ngxs/store';
|
||||
import { EngineConfigurationStateModel, EngineConfigurationState } from './engine-configuration.state';
|
||||
|
||||
export class EngineConfigurationSelectors {
|
||||
@Selector([EngineConfigurationState])
|
||||
static workbasketsCustomisation(state: EngineConfigurationStateModel): WorkbasketsCustomisation {
|
||||
return state.customisation[state.language].workbaskets;
|
||||
}
|
||||
|
||||
@Selector([EngineConfigurationState])
|
||||
static classificationsCustomisation(state: EngineConfigurationStateModel): ClassificationsCustomisation {
|
||||
return state.customisation[state.language].classifications;
|
||||
}
|
||||
|
||||
@Selector([EngineConfigurationState])
|
||||
static accessItemsCustomisation(state: EngineConfigurationStateModel): AccessItemsCustomisation {
|
||||
return state.customisation[state.language].workbaskets['access-items'];
|
||||
}
|
||||
|
||||
@Selector([EngineConfigurationState])
|
||||
static tasksCustomisation(state: EngineConfigurationStateModel): TasksCustomisation {
|
||||
return state.customisation[state.language].tasks;
|
||||
}
|
||||
|
||||
@Selector([EngineConfigurationState])
|
||||
static selectCategoryIcons(state: EngineConfigurationStateModel): ClassificationCategoryImages {
|
||||
return {
|
||||
...state.customisation[state.language].classifications.categories,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
import { Customisation } from 'app/models/customisation';
|
||||
import { State, NgxsOnInit, StateContext, Action } from '@ngxs/store';
|
||||
import { ClassificationCategoriesService } from 'app/shared/services/classifications/classification-categories.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
|
||||
class InitializeStore {
|
||||
static readonly type = '[EngineConfigurationState] Initializing state';
|
||||
}
|
||||
|
||||
@State<EngineConfigurationStateModel>({ name: 'engineConfiguration' })
|
||||
export class EngineConfigurationState implements NgxsOnInit {
|
||||
constructor(private categoryService: ClassificationCategoriesService) {
|
||||
}
|
||||
|
||||
@Action(InitializeStore)
|
||||
initializeStore(ctx: StateContext<EngineConfigurationStateModel>): Observable<any> {
|
||||
return this.categoryService.getCustomisation().pipe(
|
||||
tap(customisation => ctx.setState({
|
||||
...ctx.getState(),
|
||||
customisation,
|
||||
language: 'EN'
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
ngxsOnInit(ctx: StateContext<EngineConfigurationStateModel>): void {
|
||||
ctx.dispatch(new InitializeStore());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export interface EngineConfigurationStateModel {
|
||||
customisation: Customisation,
|
||||
language: string
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
import { EngineConfigurationState } from './engine-configuration-store/engine-configuration.state';
|
||||
import { ClassificationState } from './classification-store/classification.state';
|
||||
|
||||
export const STATES = [EngineConfigurationState, ClassificationState];
|
|
@ -65,7 +65,7 @@
|
|||
<taskana-date-picker placeholder="Due date" [value]="task.due" [name]="'task.due'" [id]="'task-due'" (dateOutput)="updateDate($event)"></taskana-date-picker>
|
||||
</div>
|
||||
<div class="form-group col-xs-2">
|
||||
<label for="task-priority" disabled class="control-label">Priority</label>
|
||||
<label for="task-priority" class="control-label">Priority</label>
|
||||
<taskana-number-picker [(ngModel)]="task.priority" title="priority" id="task-priority" name="task.priority"></taskana-number-picker>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -83,7 +83,7 @@
|
|||
</div>
|
||||
<div class="input-group form-group col-xs-12">
|
||||
<label for="wb-owner" class="control-label ">Owner</label>
|
||||
<taskana-type-ahead *ngIf="ownerField?.lookupField else ownerInput" #owner="ngModel" name="task.owner"
|
||||
<taskana-type-ahead *ngIf="(tasksCustomisation$ |async)?.information.owner.lookupField else ownerInput" #owner="ngModel" name="task.owner"
|
||||
[(ngModel)]="task.owner" width="100%" [isRequired]="false"></taskana-type-ahead>
|
||||
<ng-template #ownerInput>
|
||||
<input type="text" #task.owner="ngModel" class="form-control" id="ts-owner" placeholder="Owner" [(ngModel)]="task.owner"
|
||||
|
|
|
@ -4,7 +4,6 @@ import { FormsModule } from '@angular/forms';
|
|||
import { ClassificationsService } from 'app/shared/services/classifications/classifications.service';
|
||||
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
||||
import { ClassificationCategoriesService } from 'app/shared/services/classifications/classification-categories.service';
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
import { DomainService } from 'app/services/domain/domain.service';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { Routes } from '@angular/router';
|
||||
|
@ -39,7 +38,7 @@ xdescribe('GeneralComponent', () => {
|
|||
TestBed.configureTestingModule({
|
||||
imports: [FormsModule, HttpClientModule, RouterTestingModule.withRoutes(routes)],
|
||||
declarations: [TaskdetailsGeneralFieldsComponent, DummyDetailComponent],
|
||||
providers: [HttpClient, ClassificationCategoriesService, CustomFieldsService,
|
||||
providers: [HttpClient, ClassificationCategoriesService,
|
||||
DomainService, RequestInProgressService, SelectedRouteService, ClassificationsService]
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
import { Component, EventEmitter, Input, OnInit, Output, ViewChild, SimpleChanges, OnChanges, HostListener } from '@angular/core';
|
||||
import { Task } from 'app/workplace/models/task';
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
|
||||
import { NgForm } from '@angular/forms';
|
||||
import { DomainService } from 'app/services/domain/domain.service';
|
||||
import { Select } from '@ngxs/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { EngineConfigurationSelectors } from 'app/store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { ClassificationsService } from '../../../shared/services/classifications/classifications.service';
|
||||
import { Classification } from '../../../models/classification';
|
||||
import { TasksCustomisation } from '../../../models/customisation';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-task-details-general-fields',
|
||||
|
@ -30,14 +33,10 @@ export class TaskdetailsGeneralFieldsComponent implements OnInit, OnChanges {
|
|||
requestInProgress = false;
|
||||
classifications: Classification[];
|
||||
|
||||
ownerField = this.customFieldsService.getCustomField(
|
||||
'Owner',
|
||||
'tasks.information.owner'
|
||||
);
|
||||
@Select(EngineConfigurationSelectors.tasksCustomisation) tasksCustomisation$: Observable<TasksCustomisation>;
|
||||
|
||||
constructor(
|
||||
private classificationService: ClassificationsService,
|
||||
private customFieldsService: CustomFieldsService,
|
||||
private formsValidatorService: FormsValidatorService,
|
||||
private domainService: DomainService
|
||||
) {
|
||||
|
|
|
@ -66,4 +66,4 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ declare let __karma__: any;
|
|||
declare let require: any;
|
||||
|
||||
// Prevent Karma from running prematurely.
|
||||
__karma__.loaded = function () {};
|
||||
__karma__.loaded = function noop() {};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
|
|
Loading…
Reference in New Issue