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