From 3ba558ff23443debd2c6c9aa5dc0e563bd5c1bea Mon Sep 17 00:00:00 2001 From: Unknown Date: Mon, 28 May 2018 17:55:30 +0200 Subject: [PATCH] TSK-535 :bugfixes for workplace --- .../java/pro/taskana/rest/TaskController.java | 738 +++++++++--------- .../services/workbasket/workbasket.service.ts | 3 - .../master-and-detail.component.html | 2 +- .../app/workplace/services/task.service.ts | 27 +- .../app/workplace/task/task.component.html | 36 +- web/src/app/workplace/task/task.component.ts | 83 +- .../taskdetails/taskdetails.component.html | 19 +- .../taskdetails/taskdetails.component.scss | 6 +- .../taskdetails/taskdetails.component.ts | 30 +- .../tasklist/tasklist.component.html | 8 +- .../tasklist/tasklist.component.scss | 12 +- .../workplace/tasklist/tasklist.component.ts | 32 +- .../workbasket-selector.component.html | 8 +- .../workbasket-selector.component.ts | 37 +- web/src/app/workplace/workplace.module.ts | 17 +- 15 files changed, 574 insertions(+), 484 deletions(-) diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/TaskController.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/TaskController.java index a3e15566d..a43ee758d 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/TaskController.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/TaskController.java @@ -1,369 +1,369 @@ -package pro.taskana.rest; - -import java.util.ArrayList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.hateoas.PagedResources; -import org.springframework.hateoas.PagedResources.PageMetadata; -import org.springframework.hateoas.config.EnableHypermediaSupport; -import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.MultiValueMap; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import pro.taskana.BaseQuery.SortDirection; -import pro.taskana.KeyDomain; -import pro.taskana.Task; -import pro.taskana.TaskQuery; -import pro.taskana.TaskService; -import pro.taskana.TaskState; -import pro.taskana.TaskSummary; -import pro.taskana.exceptions.AttachmentPersistenceException; -import pro.taskana.exceptions.ClassificationNotFoundException; -import pro.taskana.exceptions.ConcurrencyException; -import pro.taskana.exceptions.InvalidArgumentException; -import pro.taskana.exceptions.InvalidOwnerException; -import pro.taskana.exceptions.InvalidStateException; -import pro.taskana.exceptions.InvalidWorkbasketException; -import pro.taskana.exceptions.NotAuthorizedException; -import pro.taskana.exceptions.TaskAlreadyExistException; -import pro.taskana.exceptions.TaskNotFoundException; -import pro.taskana.exceptions.WorkbasketNotFoundException; -import pro.taskana.rest.resource.TaskResource; -import pro.taskana.rest.resource.TaskSummaryResource; -import pro.taskana.rest.resource.assembler.TaskResourceAssembler; -import pro.taskana.rest.resource.assembler.TaskSummaryResourcesAssembler; - -/** - * Controller for all {@link Task} related endpoints. - */ -@RestController -@EnableHypermediaSupport(type = HypermediaType.HAL) -@RequestMapping(path = "/v1/tasks", produces = "application/hal+json") -public class TaskController extends AbstractPagingController { - - private static final Logger LOGGER = LoggerFactory.getLogger(TaskController.class); - - private static final String STATE = "state"; - private static final String STATE_VALUE_CLAIMED = "CLAIMED"; - private static final String STATE_VALUE_COMPLETED = "COMPLETED"; - private static final String STATE_VALUE_READY = "READY"; - private static final String PRIORITY = "priority"; - private static final String NAME = "name"; - private static final String OWNER = "owner"; - private static final String DOMAIN = "domain"; - private static final String WORKBASKET_ID = "workbasket-id"; - private static final String WORKBASKET_KEY = "workbasket-key"; - private static final String CLASSIFICATION_KEY = "classification.key"; - private static final String POR_VALUE = "por.value"; - private static final String POR_TYPE = "por.type"; - private static final String POR_SYSTEM_INSTANCE = "por.instance"; - private static final String POR_SYSTEM = "por.system"; - private static final String POR_COMPANY = "por.company"; - private static final String DUE = "due"; - private static final String PLANNED = "planned"; - - private static final String SORT_BY = "sortBy"; - private static final String SORT_DIRECTION = "order"; - - private static final String PAGING_PAGE = "page"; - private static final String PAGING_PAGE_SIZE = "page-size"; - - @Autowired - private TaskService taskService; - - @Autowired - private TaskResourceAssembler taskResourceAssembler; - - @GetMapping - @Transactional(readOnly = true, rollbackFor = Exception.class) - public ResponseEntity> getTasks( - @RequestParam MultiValueMap params) throws InvalidArgumentException, NotAuthorizedException { - - TaskQuery query = taskService.createTaskQuery(); - query = applyFilterParams(query, params); - query = applySortingParams(query, params); - - PageMetadata pageMetadata = null; - List taskSummaries = null; - String page = params.getFirst(PAGING_PAGE); - String pageSize = params.getFirst(PAGING_PAGE_SIZE); - params.remove(PAGING_PAGE); - params.remove(PAGING_PAGE_SIZE); - validateNoInvalidParameterIsLeft(params); - if (page != null && pageSize != null) { - // paging - long totalElements = query.count(); - pageMetadata = initPageMetadata(pageSize, page, - totalElements); - taskSummaries = query.listPage((int) pageMetadata.getNumber(), - (int) pageMetadata.getSize()); - } else if (page == null && pageSize == null) { - // not paging - taskSummaries = query.list(); - } else { - throw new InvalidArgumentException("Paging information is incomplete."); - } - - TaskSummaryResourcesAssembler taskSummaryResourcesAssembler = new TaskSummaryResourcesAssembler(); - PagedResources pagedResources = taskSummaryResourcesAssembler.toResources(taskSummaries, - pageMetadata); - - return new ResponseEntity<>(pagedResources, HttpStatus.OK); - } - - @GetMapping(path = "/{taskId}") - @Transactional(readOnly = true, rollbackFor = Exception.class) - public ResponseEntity getTask(@PathVariable String taskId) - throws TaskNotFoundException, NotAuthorizedException { - Task task = taskService.getTask(taskId); - ResponseEntity result = new ResponseEntity<>(taskResourceAssembler.toResource(task), - HttpStatus.OK); - return result; - } - - @PostMapping(path = "/{taskId}/claim") - @Transactional(rollbackFor = Exception.class) - public ResponseEntity claimTask(@PathVariable String taskId, @RequestBody String userName) - throws TaskNotFoundException, InvalidStateException, InvalidOwnerException, NotAuthorizedException { - // TODO verify user - taskService.claim(taskId); - Task updatedTask = taskService.getTask(taskId); - ResponseEntity result = new ResponseEntity<>(taskResourceAssembler.toResource(updatedTask), - HttpStatus.OK); - return result; - } - - @RequestMapping(method = RequestMethod.POST, value = "/{taskId}/complete") - @Transactional(rollbackFor = Exception.class) - public ResponseEntity completeTask(@PathVariable String taskId) - throws TaskNotFoundException, InvalidOwnerException, InvalidStateException, NotAuthorizedException { - taskService.forceCompleteTask(taskId); - Task updatedTask = taskService.getTask(taskId); - ResponseEntity result = new ResponseEntity<>(taskResourceAssembler.toResource(updatedTask), - HttpStatus.OK); - return result; - } - - @RequestMapping(method = RequestMethod.DELETE, value = "/{taskId}") - @Transactional(rollbackFor = Exception.class) - public ResponseEntity deleteTask(@PathVariable String taskId) - throws TaskNotFoundException, InvalidStateException, NotAuthorizedException { - taskService.forceDeleteTask(taskId); - ResponseEntity result = new ResponseEntity<>(HttpStatus.OK); - return result; - } - - @RequestMapping(method = RequestMethod.POST) - @Transactional(rollbackFor = Exception.class) - public ResponseEntity createTask(@RequestBody TaskResource taskResource) - throws WorkbasketNotFoundException, ClassificationNotFoundException, NotAuthorizedException, - TaskAlreadyExistException, InvalidWorkbasketException, InvalidArgumentException { - Task createdTask = taskService.createTask(taskResourceAssembler.toModel(taskResource)); - ResponseEntity result = new ResponseEntity<>(taskResourceAssembler.toResource(createdTask), - HttpStatus.CREATED); - return result; - } - - @RequestMapping(path = "/{taskId}/transfer/{workbasketKey}") - @Transactional(rollbackFor = Exception.class) - public ResponseEntity transferTask(@PathVariable String taskId, @PathVariable String workbasketKey) - throws TaskNotFoundException, WorkbasketNotFoundException, NotAuthorizedException, InvalidWorkbasketException, - InvalidStateException { - Task updatedTask = taskService.transfer(taskId, workbasketKey); - ResponseEntity result = new ResponseEntity<>(taskResourceAssembler.toResource(updatedTask), - HttpStatus.OK); - return result; - } - - @PutMapping(path = "/{taskId}") - @Transactional(rollbackFor = Exception.class) - public ResponseEntity updateTask( - @PathVariable(value = "taskId") String taskId, - @RequestBody TaskResource taskResource) throws TaskNotFoundException, WorkbasketNotFoundException, - ClassificationNotFoundException, InvalidArgumentException, ConcurrencyException, InvalidWorkbasketException, - NotAuthorizedException, AttachmentPersistenceException { - ResponseEntity result; - if (taskId.equals(taskResource.getTaskId())) { - Task task = taskResourceAssembler.toModel(taskResource); - task = taskService.updateTask(task); - result = ResponseEntity.ok(taskResourceAssembler.toResource(task)); - } else { - throw new InvalidArgumentException( - "TaskId ('" + taskId - + "') is not identical with the taskId of to object in the payload which should be updated. ID=('" - + taskResource.getTaskId() + "')"); - } - - return result; - } - - private TaskQuery applyFilterParams(TaskQuery taskQuery, MultiValueMap params) - throws NotAuthorizedException, InvalidArgumentException { - - // apply filters - if (params.containsKey(NAME)) { - String[] names = extractCommaSeparatedFields(params.get(NAME)); - taskQuery.nameIn(names); - params.remove(NAME); - } - if (params.containsKey(PRIORITY)) { - String[] prioritesInString = extractCommaSeparatedFields(params.get(PRIORITY)); - int[] priorites = extractPriorities(prioritesInString); - taskQuery.priorityIn(priorites); - params.remove(PRIORITY); - } - if (params.containsKey(STATE)) { - TaskState[] states = extractStates(params); - taskQuery.stateIn(states); - params.remove(STATE); - } - if (params.containsKey(CLASSIFICATION_KEY)) { - String[] classificationKeys = extractCommaSeparatedFields(params.get(CLASSIFICATION_KEY)); - taskQuery.classificationKeyIn(classificationKeys); - params.remove(CLASSIFICATION_KEY); - } - if (params.containsKey(WORKBASKET_ID)) { - String[] workbaskets = extractCommaSeparatedFields(params.get(WORKBASKET_ID)); - taskQuery.workbasketIdIn(workbaskets); - params.remove(WORKBASKET_ID); - } - if (params.containsKey(WORKBASKET_KEY)) { - String[] domains = null; - if (params.get(DOMAIN) != null) { - domains = extractCommaSeparatedFields(params.get(DOMAIN)); - } - if (domains == null || domains.length != 1) { - throw new InvalidArgumentException("workbasket-key requires excactly one domain as second parameter."); - } - String[] workbasketKeys = extractCommaSeparatedFields(params.get(WORKBASKET_KEY)); - KeyDomain[] keyDomains = new KeyDomain[workbasketKeys.length]; - for (int i = 0; i < workbasketKeys.length; i++) { - keyDomains[i] = new KeyDomain(workbasketKeys[i], domains[0]); - } - taskQuery.workbasketKeyDomainIn(keyDomains); - params.remove(WORKBASKET_KEY); - params.remove(DOMAIN); - } - if (params.containsKey(OWNER)) { - String[] owners = extractCommaSeparatedFields(params.get(OWNER)); - taskQuery.ownerIn(owners); - params.remove(OWNER); - } - if (params.containsKey(POR_COMPANY)) { - String[] companies = extractCommaSeparatedFields(params.get(POR_COMPANY)); - taskQuery.primaryObjectReferenceCompanyIn(companies); - params.remove(POR_COMPANY); - } - if (params.containsKey(POR_SYSTEM)) { - String[] systems = extractCommaSeparatedFields(params.get(POR_SYSTEM)); - taskQuery.primaryObjectReferenceSystemIn(systems); - params.remove(POR_SYSTEM); - } - if (params.containsKey(POR_SYSTEM_INSTANCE)) { - String[] systemInstances = extractCommaSeparatedFields(params.get(POR_SYSTEM_INSTANCE)); - taskQuery.primaryObjectReferenceSystemInstanceIn(systemInstances); - params.remove(POR_SYSTEM_INSTANCE); - } - if (params.containsKey(POR_TYPE)) { - String[] types = extractCommaSeparatedFields(params.get(POR_TYPE)); - taskQuery.primaryObjectReferenceTypeIn(types); - params.remove(POR_TYPE); - } - if (params.containsKey(POR_VALUE)) { - String[] values = extractCommaSeparatedFields(params.get(POR_VALUE)); - taskQuery.primaryObjectReferenceValueIn(values); - params.remove(POR_VALUE); - } - return taskQuery; - } - - private TaskQuery applySortingParams(TaskQuery taskQuery, MultiValueMap params) - throws NotAuthorizedException, InvalidArgumentException { - - // sorting - String sortBy = params.getFirst(SORT_BY); - if (sortBy != null) { - SortDirection sortDirection; - if (params.getFirst(SORT_DIRECTION) != null && "desc".equals(params.getFirst(SORT_DIRECTION))) { - sortDirection = SortDirection.DESCENDING; - } else { - sortDirection = SortDirection.ASCENDING; - } - switch (sortBy) { - case (CLASSIFICATION_KEY): - taskQuery = taskQuery.orderByClassificationKey(sortDirection); - break; - case (POR_TYPE): - taskQuery = taskQuery.orderByPrimaryObjectReferenceType(sortDirection); - break; - case (POR_VALUE): - taskQuery = taskQuery.orderByPrimaryObjectReferenceValue(sortDirection); - break; - case (STATE): - taskQuery = taskQuery.orderByState(sortDirection); - break; - case (NAME): - taskQuery = taskQuery.orderByName(sortDirection); - break; - case (DUE): - taskQuery = taskQuery.orderByDue(sortDirection); - break; - case (PLANNED): - taskQuery = taskQuery.orderByPlanned(sortDirection); - break; - case (PRIORITY): - taskQuery = taskQuery.orderByPriority(sortDirection); - break; - default: - throw new InvalidArgumentException("Unknown filter attribute: " + sortBy); - } - } - params.remove(SORT_BY); - params.remove(SORT_DIRECTION); - return taskQuery; - } - - private int[] extractPriorities(String[] prioritesInString) { - int[] priorites = new int[prioritesInString.length]; - for (int i = 0; i < prioritesInString.length; i++) { - priorites[i] = Integer.getInteger(prioritesInString[i]); - } - return priorites; - } - - private TaskState[] extractStates(MultiValueMap params) throws InvalidArgumentException { - List states = new ArrayList<>(); - for (String item : params.get(STATE)) { - for (String state : item.split(",")) { - switch (state) { - case STATE_VALUE_READY: - states.add(TaskState.READY); - break; - case STATE_VALUE_COMPLETED: - states.add(TaskState.COMPLETED); - break; - case STATE_VALUE_CLAIMED: - states.add(TaskState.CLAIMED); - break; - default: - throw new InvalidArgumentException("Unknown status '" + state + "'"); - } - } - } - return states.toArray(new TaskState[0]); - } -} +package pro.taskana.rest; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.hateoas.PagedResources; +import org.springframework.hateoas.PagedResources.PageMetadata; +import org.springframework.hateoas.config.EnableHypermediaSupport; +import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import pro.taskana.BaseQuery.SortDirection; +import pro.taskana.KeyDomain; +import pro.taskana.Task; +import pro.taskana.TaskQuery; +import pro.taskana.TaskService; +import pro.taskana.TaskState; +import pro.taskana.TaskSummary; +import pro.taskana.exceptions.AttachmentPersistenceException; +import pro.taskana.exceptions.ClassificationNotFoundException; +import pro.taskana.exceptions.ConcurrencyException; +import pro.taskana.exceptions.InvalidArgumentException; +import pro.taskana.exceptions.InvalidOwnerException; +import pro.taskana.exceptions.InvalidStateException; +import pro.taskana.exceptions.InvalidWorkbasketException; +import pro.taskana.exceptions.NotAuthorizedException; +import pro.taskana.exceptions.TaskAlreadyExistException; +import pro.taskana.exceptions.TaskNotFoundException; +import pro.taskana.exceptions.WorkbasketNotFoundException; +import pro.taskana.rest.resource.TaskResource; +import pro.taskana.rest.resource.TaskSummaryResource; +import pro.taskana.rest.resource.assembler.TaskResourceAssembler; +import pro.taskana.rest.resource.assembler.TaskSummaryResourcesAssembler; + +/** + * Controller for all {@link Task} related endpoints. + */ +@RestController +@EnableHypermediaSupport(type = HypermediaType.HAL) +@RequestMapping(path = "/v1/tasks", produces = "application/hal+json") +public class TaskController extends AbstractPagingController { + + private static final Logger LOGGER = LoggerFactory.getLogger(TaskController.class); + + private static final String STATE = "state"; + private static final String STATE_VALUE_CLAIMED = "CLAIMED"; + private static final String STATE_VALUE_COMPLETED = "COMPLETED"; + private static final String STATE_VALUE_READY = "READY"; + private static final String PRIORITY = "priority"; + private static final String NAME = "name"; + private static final String OWNER = "owner"; + private static final String DOMAIN = "domain"; + private static final String WORKBASKET_ID = "workbasket-id"; + private static final String WORKBASKET_KEY = "workbasket-key"; + private static final String CLASSIFICATION_KEY = "classification.key"; + private static final String POR_VALUE = "por.value"; + private static final String POR_TYPE = "por.type"; + private static final String POR_SYSTEM_INSTANCE = "por.instance"; + private static final String POR_SYSTEM = "por.system"; + private static final String POR_COMPANY = "por.company"; + private static final String DUE = "due"; + private static final String PLANNED = "planned"; + + private static final String SORT_BY = "sortBy"; + private static final String SORT_DIRECTION = "order"; + + private static final String PAGING_PAGE = "page"; + private static final String PAGING_PAGE_SIZE = "page-size"; + + @Autowired + private TaskService taskService; + + @Autowired + private TaskResourceAssembler taskResourceAssembler; + + @GetMapping + @Transactional(readOnly = true, rollbackFor = Exception.class) + public ResponseEntity> getTasks( + @RequestParam MultiValueMap params) throws InvalidArgumentException, NotAuthorizedException { + + TaskQuery query = taskService.createTaskQuery(); + query = applyFilterParams(query, params); + query = applySortingParams(query, params); + + PageMetadata pageMetadata = null; + List taskSummaries = null; + String page = params.getFirst(PAGING_PAGE); + String pageSize = params.getFirst(PAGING_PAGE_SIZE); + params.remove(PAGING_PAGE); + params.remove(PAGING_PAGE_SIZE); + validateNoInvalidParameterIsLeft(params); + if (page != null && pageSize != null) { + // paging + long totalElements = query.count(); + pageMetadata = initPageMetadata(pageSize, page, + totalElements); + taskSummaries = query.listPage((int) pageMetadata.getNumber(), + (int) pageMetadata.getSize()); + } else if (page == null && pageSize == null) { + // not paging + taskSummaries = query.list(); + } else { + throw new InvalidArgumentException("Paging information is incomplete."); + } + + TaskSummaryResourcesAssembler taskSummaryResourcesAssembler = new TaskSummaryResourcesAssembler(); + PagedResources pagedResources = taskSummaryResourcesAssembler.toResources(taskSummaries, + pageMetadata); + + return new ResponseEntity<>(pagedResources, HttpStatus.OK); + } + + @GetMapping(path = "/{taskId}") + @Transactional(readOnly = true, rollbackFor = Exception.class) + public ResponseEntity getTask(@PathVariable String taskId) + throws TaskNotFoundException, NotAuthorizedException { + Task task = taskService.getTask(taskId); + ResponseEntity result = new ResponseEntity<>(taskResourceAssembler.toResource(task), + HttpStatus.OK); + return result; + } + + @PostMapping(path = "/{taskId}/claim") + @Transactional(rollbackFor = Exception.class) + public ResponseEntity claimTask(@PathVariable String taskId, @RequestBody String userName) + throws TaskNotFoundException, InvalidStateException, InvalidOwnerException, NotAuthorizedException { + // TODO verify user + taskService.claim(taskId); + Task updatedTask = taskService.getTask(taskId); + ResponseEntity result = new ResponseEntity<>(taskResourceAssembler.toResource(updatedTask), + HttpStatus.OK); + return result; + } + + @RequestMapping(method = RequestMethod.POST, value = "/{taskId}/complete") + @Transactional(rollbackFor = Exception.class) + public ResponseEntity completeTask(@PathVariable String taskId) + throws TaskNotFoundException, InvalidOwnerException, InvalidStateException, NotAuthorizedException { + taskService.forceCompleteTask(taskId); + Task updatedTask = taskService.getTask(taskId); + ResponseEntity result = new ResponseEntity<>(taskResourceAssembler.toResource(updatedTask), + HttpStatus.OK); + return result; + } + + @RequestMapping(method = RequestMethod.DELETE, value = "/{taskId}") + @Transactional(rollbackFor = Exception.class) + public ResponseEntity deleteTask(@PathVariable String taskId) + throws TaskNotFoundException, InvalidStateException, NotAuthorizedException { + taskService.forceDeleteTask(taskId); + ResponseEntity result = new ResponseEntity<>(HttpStatus.OK); + return result; + } + + @RequestMapping(method = RequestMethod.POST) + @Transactional(rollbackFor = Exception.class) + public ResponseEntity createTask(@RequestBody TaskResource taskResource) + throws WorkbasketNotFoundException, ClassificationNotFoundException, NotAuthorizedException, + TaskAlreadyExistException, InvalidWorkbasketException, InvalidArgumentException { + Task createdTask = taskService.createTask(taskResourceAssembler.toModel(taskResource)); + ResponseEntity result = new ResponseEntity<>(taskResourceAssembler.toResource(createdTask), + HttpStatus.CREATED); + return result; + } + + @RequestMapping(path = "/{taskId}/transfer/{workbasketId}") + @Transactional(rollbackFor = Exception.class) + public ResponseEntity transferTask(@PathVariable String taskId, @PathVariable String workbasketId) + throws TaskNotFoundException, WorkbasketNotFoundException, NotAuthorizedException, InvalidWorkbasketException, + InvalidStateException { + Task updatedTask = taskService.transfer(taskId, workbasketId); + ResponseEntity result = new ResponseEntity<>(taskResourceAssembler.toResource(updatedTask), + HttpStatus.OK); + return result; + } + + @PutMapping(path = "/{taskId}") + @Transactional(rollbackFor = Exception.class) + public ResponseEntity updateTask( + @PathVariable(value = "taskId") String taskId, + @RequestBody TaskResource taskResource) throws TaskNotFoundException, WorkbasketNotFoundException, + ClassificationNotFoundException, InvalidArgumentException, ConcurrencyException, InvalidWorkbasketException, + NotAuthorizedException, AttachmentPersistenceException { + ResponseEntity result; + if (taskId.equals(taskResource.getTaskId())) { + Task task = taskResourceAssembler.toModel(taskResource); + task = taskService.updateTask(task); + result = ResponseEntity.ok(taskResourceAssembler.toResource(task)); + } else { + throw new InvalidArgumentException( + "TaskId ('" + taskId + + "') is not identical with the taskId of to object in the payload which should be updated. ID=('" + + taskResource.getTaskId() + "')"); + } + + return result; + } + + private TaskQuery applyFilterParams(TaskQuery taskQuery, MultiValueMap params) + throws NotAuthorizedException, InvalidArgumentException { + + // apply filters + if (params.containsKey(NAME)) { + String[] names = extractCommaSeparatedFields(params.get(NAME)); + taskQuery.nameIn(names); + params.remove(NAME); + } + if (params.containsKey(PRIORITY)) { + String[] prioritesInString = extractCommaSeparatedFields(params.get(PRIORITY)); + int[] priorites = extractPriorities(prioritesInString); + taskQuery.priorityIn(priorites); + params.remove(PRIORITY); + } + if (params.containsKey(STATE)) { + TaskState[] states = extractStates(params); + taskQuery.stateIn(states); + params.remove(STATE); + } + if (params.containsKey(CLASSIFICATION_KEY)) { + String[] classificationKeys = extractCommaSeparatedFields(params.get(CLASSIFICATION_KEY)); + taskQuery.classificationKeyIn(classificationKeys); + params.remove(CLASSIFICATION_KEY); + } + if (params.containsKey(WORKBASKET_ID)) { + String[] workbaskets = extractCommaSeparatedFields(params.get(WORKBASKET_ID)); + taskQuery.workbasketIdIn(workbaskets); + params.remove(WORKBASKET_ID); + } + if (params.containsKey(WORKBASKET_KEY)) { + String[] domains = null; + if (params.get(DOMAIN) != null) { + domains = extractCommaSeparatedFields(params.get(DOMAIN)); + } + if (domains == null || domains.length != 1) { + throw new InvalidArgumentException("workbasket-key requires excactly one domain as second parameter."); + } + String[] workbasketKeys = extractCommaSeparatedFields(params.get(WORKBASKET_KEY)); + KeyDomain[] keyDomains = new KeyDomain[workbasketKeys.length]; + for (int i = 0; i < workbasketKeys.length; i++) { + keyDomains[i] = new KeyDomain(workbasketKeys[i], domains[0]); + } + taskQuery.workbasketKeyDomainIn(keyDomains); + params.remove(WORKBASKET_KEY); + params.remove(DOMAIN); + } + if (params.containsKey(OWNER)) { + String[] owners = extractCommaSeparatedFields(params.get(OWNER)); + taskQuery.ownerIn(owners); + params.remove(OWNER); + } + if (params.containsKey(POR_COMPANY)) { + String[] companies = extractCommaSeparatedFields(params.get(POR_COMPANY)); + taskQuery.primaryObjectReferenceCompanyIn(companies); + params.remove(POR_COMPANY); + } + if (params.containsKey(POR_SYSTEM)) { + String[] systems = extractCommaSeparatedFields(params.get(POR_SYSTEM)); + taskQuery.primaryObjectReferenceSystemIn(systems); + params.remove(POR_SYSTEM); + } + if (params.containsKey(POR_SYSTEM_INSTANCE)) { + String[] systemInstances = extractCommaSeparatedFields(params.get(POR_SYSTEM_INSTANCE)); + taskQuery.primaryObjectReferenceSystemInstanceIn(systemInstances); + params.remove(POR_SYSTEM_INSTANCE); + } + if (params.containsKey(POR_TYPE)) { + String[] types = extractCommaSeparatedFields(params.get(POR_TYPE)); + taskQuery.primaryObjectReferenceTypeIn(types); + params.remove(POR_TYPE); + } + if (params.containsKey(POR_VALUE)) { + String[] values = extractCommaSeparatedFields(params.get(POR_VALUE)); + taskQuery.primaryObjectReferenceValueIn(values); + params.remove(POR_VALUE); + } + return taskQuery; + } + + private TaskQuery applySortingParams(TaskQuery taskQuery, MultiValueMap params) + throws NotAuthorizedException, InvalidArgumentException { + + // sorting + String sortBy = params.getFirst(SORT_BY); + if (sortBy != null) { + SortDirection sortDirection; + if (params.getFirst(SORT_DIRECTION) != null && "desc".equals(params.getFirst(SORT_DIRECTION))) { + sortDirection = SortDirection.DESCENDING; + } else { + sortDirection = SortDirection.ASCENDING; + } + switch (sortBy) { + case (CLASSIFICATION_KEY): + taskQuery = taskQuery.orderByClassificationKey(sortDirection); + break; + case (POR_TYPE): + taskQuery = taskQuery.orderByPrimaryObjectReferenceType(sortDirection); + break; + case (POR_VALUE): + taskQuery = taskQuery.orderByPrimaryObjectReferenceValue(sortDirection); + break; + case (STATE): + taskQuery = taskQuery.orderByState(sortDirection); + break; + case (NAME): + taskQuery = taskQuery.orderByName(sortDirection); + break; + case (DUE): + taskQuery = taskQuery.orderByDue(sortDirection); + break; + case (PLANNED): + taskQuery = taskQuery.orderByPlanned(sortDirection); + break; + case (PRIORITY): + taskQuery = taskQuery.orderByPriority(sortDirection); + break; + default: + throw new InvalidArgumentException("Unknown filter attribute: " + sortBy); + } + } + params.remove(SORT_BY); + params.remove(SORT_DIRECTION); + return taskQuery; + } + + private int[] extractPriorities(String[] prioritesInString) { + int[] priorites = new int[prioritesInString.length]; + for (int i = 0; i < prioritesInString.length; i++) { + priorites[i] = Integer.getInteger(prioritesInString[i]); + } + return priorites; + } + + private TaskState[] extractStates(MultiValueMap params) throws InvalidArgumentException { + List states = new ArrayList<>(); + for (String item : params.get(STATE)) { + for (String state : item.split(",")) { + switch (state) { + case STATE_VALUE_READY: + states.add(TaskState.READY); + break; + case STATE_VALUE_COMPLETED: + states.add(TaskState.COMPLETED); + break; + case STATE_VALUE_CLAIMED: + states.add(TaskState.CLAIMED); + break; + default: + throw new InvalidArgumentException("Unknown status '" + state + "'"); + } + } + } + return states.toArray(new TaskState[0]); + } +} diff --git a/web/src/app/services/workbasket/workbasket.service.ts b/web/src/app/services/workbasket/workbasket.service.ts index 367edd40c..9441d9329 100644 --- a/web/src/app/services/workbasket/workbasket.service.ts +++ b/web/src/app/services/workbasket/workbasket.service.ts @@ -17,9 +17,6 @@ import {WorkbasketResource} from '../../models/workbasket-resource'; @Injectable() export class WorkbasketService { - workbasketKey: string; - workbasketName: string; - public workBasketSelected = new Subject(); public workBasketSaved = new Subject(); diff --git a/web/src/app/shared/master-and-detail/master-and-detail.component.html b/web/src/app/shared/master-and-detail/master-and-detail.component.html index d0b8c2703..78ca87825 100644 --- a/web/src/app/shared/master-and-detail/master-and-detail.component.html +++ b/web/src/app/shared/master-and-detail/master-and-detail.component.html @@ -17,7 +17,7 @@

Select a Task

- +
diff --git a/web/src/app/workplace/services/task.service.ts b/web/src/app/workplace/services/task.service.ts index 0feb1f954..bbc42c40f 100644 --- a/web/src/app/workplace/services/task.service.ts +++ b/web/src/app/workplace/services/task.service.ts @@ -4,16 +4,31 @@ import {HttpClient} from '@angular/common/http'; import {Injectable} from '@angular/core'; import {environment} from 'app/../environments/environment'; import {TaskResource} from 'app/workplace/models/task-resource'; +import {Subject} from 'rxjs/Subject'; @Injectable() export class TaskService { url = `${environment.taskanaRestUrl}/v1/tasks`; + taskChangedSource = new Subject(); + taskChangedStream = this.taskChangedSource.asObservable(); + + taskDeletedSource = new Subject(); + taskDeletedStream = this.taskDeletedSource.asObservable(); + + publishUpdatedTask(task: Task) { + this.taskChangedSource.next(task); + } + + publishDeletedTask(task: Task) { + this.taskDeletedSource.next(task); + } + constructor(private httpClient: HttpClient) { } - findTasksWithWorkbasket(basketKey: string): Observable { - return this.httpClient.get(`${this.url}?workbasket-id=${basketKey}`); + findTasksWithWorkbasket(basketId: string): Observable { + return this.httpClient.get(`${this.url}?workbasket-id=${basketId}`); } getTask(id: string): Observable { @@ -28,11 +43,15 @@ export class TaskService { return this.httpClient.post(`${this.url}/${id}/claim`, 'test'); } - transferTask(taskId: string, workbasketKey: string): Observable { - return this.httpClient.post(`${this.url}/${taskId}/transfer/${workbasketKey}`, ''); + transferTask(taskId: string, workbasketId: string): Observable { + return this.httpClient.post(`${this.url}/${taskId}/transfer/${workbasketId}`, ''); } updateTask(task: Task): Observable { return this.httpClient.put(`${this.url}/${task.taskId}`, task); } + + deleteTask(task: Task): Observable { + return this.httpClient.delete(`${this.url}/${task.taskId}`); + } } diff --git a/web/src/app/workplace/task/task.component.html b/web/src/app/workplace/task/task.component.html index a2582cec5..89b501af3 100644 --- a/web/src/app/workplace/task/task.component.html +++ b/web/src/app/workplace/task/task.component.html @@ -1,22 +1,32 @@ - +
-
- + + + - - -
-

{{task?.name}}

+

{{task?.name}}

diff --git a/web/src/app/workplace/task/task.component.ts b/web/src/app/workplace/task/task.component.ts index 6ae2e3816..463b11fee 100644 --- a/web/src/app/workplace/task/task.component.ts +++ b/web/src/app/workplace/task/task.component.ts @@ -1,10 +1,11 @@ -import {Component, OnInit} from '@angular/core'; +import {Component, OnDestroy, OnInit} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {Task} from 'app/workplace/models/task'; import {Workbasket} from 'app/models/workbasket'; import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser'; import {TaskService} from 'app/workplace/services/task.service'; import {WorkbasketService} from 'app/services/workbasket/workbasket.service'; +import {Subscription} from 'rxjs/Subscription'; @Component({ @@ -12,15 +13,17 @@ import {WorkbasketService} from 'app/services/workbasket/workbasket.service'; templateUrl: './task.component.html', styleUrls: ['./task.component.scss'] }) -export class TaskComponent implements OnInit { - task: Task = null; +export class TaskComponent implements OnInit, OnDestroy { + + routeSubscription: Subscription; + requestInProgress = false; + address = 'https://bing.com'; link: SafeResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.address); - autoCompleteData: string[] = []; - workbasket: string = null; - workbasketKey: string; + + task: Task = null; workbaskets: Workbasket[]; - requestInProgress = false; + constructor(private taskService: TaskService, private workbasketService: WorkbasketService, @@ -30,8 +33,10 @@ export class TaskComponent implements OnInit { } ngOnInit() { - const id = this.route.snapshot.params['id']; - this.getTask(id); + this.routeSubscription = this.route.params.subscribe(params => { + const id = params['id']; + this.getTask(id); + }); } getTask(id: string) { @@ -41,36 +46,35 @@ export class TaskComponent implements OnInit { this.requestInProgress = false; this.task = task; this.link = this.sanitizer.bypassSecurityTrustResourceUrl(`${this.address}/?q=${this.task.name}`); - this.workbasketService.getAllWorkBaskets().subscribe(workbaskets => { - this.workbaskets = workbaskets._embedded ? workbaskets._embedded.workbaskets : []; - this.workbaskets.forEach(workbasket => { - if (workbasket.key !== this.task.workbasketSummaryResource.key) { - this.autoCompleteData.push(workbasket.name); - } - }); - }); + this.getWorkbaskets(); }); } - transferTask() { - if (this.workbasket) { - this.workbaskets.forEach(workbasket => { - if (workbasket.name === this.workbasket) { - this.workbasketKey = workbasket.key; + getWorkbaskets() { + this.requestInProgress = true; + this.workbasketService.getAllWorkBaskets().subscribe(workbaskets => { + this.requestInProgress = false; + this.workbaskets = workbaskets._embedded ? workbaskets._embedded.workbaskets : []; + + let index = -1; + for (let i = 0; i < this.workbaskets.length; i++) { + if (this.workbaskets[i].name === this.task.workbasketSummaryResource.name) { + index = i; } - }); - - this.requestInProgress = true; - this.taskService.transferTask(this.task.taskId, this.workbasketKey).subscribe( - task => { - this.requestInProgress = false; - this.task = task - }); - this.navigateBack(); - } + } + if (index !== -1) { + this.workbaskets.splice(index, 1); + } + }); } - cancelTask() { + transferTask(workbasket: Workbasket) { + this.requestInProgress = true; + this.taskService.transferTask(this.task.taskId, workbasket.workbasketId).subscribe( + task => { + this.requestInProgress = false; + this.task = task + }); this.navigateBack(); } @@ -79,12 +83,19 @@ export class TaskComponent implements OnInit { this.taskService.completeTask(this.task.taskId).subscribe( task => { this.requestInProgress = false; - this.task = task + this.task = task; + this.taskService.publishUpdatedTask(task); + this.navigateBack(); }); - this.navigateBack(); } - private navigateBack() { + navigateBack() { this.router.navigate([{outlets: {detail: `taskdetail/${this.task.taskId}`}}], {relativeTo: this.route.parent}); } + + ngOnDestroy(): void { + if (this.routeSubscription) { + this.routeSubscription.unsubscribe(); + } + } } diff --git a/web/src/app/workplace/taskdetails/taskdetails.component.html b/web/src/app/workplace/taskdetails/taskdetails.component.html index 103c1f624..71ebddf49 100644 --- a/web/src/app/workplace/taskdetails/taskdetails.component.html +++ b/web/src/app/workplace/taskdetails/taskdetails.component.html @@ -1,14 +1,17 @@ - -
+ +
- +

{{task?.name}}

@@ -18,9 +21,9 @@
- +
@@ -63,7 +66,7 @@ name="task.due">
- + diff --git a/web/src/app/workplace/taskdetails/taskdetails.component.scss b/web/src/app/workplace/taskdetails/taskdetails.component.scss index ac338f344..f702654d2 100644 --- a/web/src/app/workplace/taskdetails/taskdetails.component.scss +++ b/web/src/app/workplace/taskdetails/taskdetails.component.scss @@ -1,6 +1,6 @@ .list-group { - max-height: 84vh; + max-height: 85vh; margin-bottom: 10px; - overflow:scroll; - -webkit-overflow-scrolling: touch; + overflow: hidden; + overflow-y: scroll; } diff --git a/web/src/app/workplace/taskdetails/taskdetails.component.ts b/web/src/app/workplace/taskdetails/taskdetails.component.ts index c9890da08..36e3d86af 100644 --- a/web/src/app/workplace/taskdetails/taskdetails.component.ts +++ b/web/src/app/workplace/taskdetails/taskdetails.component.ts @@ -1,15 +1,16 @@ -import {Component, OnInit} from '@angular/core'; -import {Task} from '../models/task'; +import {Component, OnDestroy, OnInit} from '@angular/core'; +import {Task} from 'app/workplace/models/task'; import {ActivatedRoute, Router} from '@angular/router'; -import {TaskService} from '../services/task.service'; +import {TaskService} from 'app/workplace/services/task.service'; import {Subscription} from 'rxjs/Subscription'; +import {Location} from '@angular/common'; @Component({ selector: 'taskana-task-details', templateUrl: './taskdetails.component.html', styleUrls: ['./taskdetails.component.scss'] }) -export class TaskdetailsComponent implements OnInit { +export class TaskdetailsComponent implements OnInit, OnDestroy { task: Task = null; requestInProgress = false; @@ -17,7 +18,8 @@ export class TaskdetailsComponent implements OnInit { constructor(private route: ActivatedRoute, private taskService: TaskService, - private router: Router) { + private router: Router, + private location: Location) { } ngOnInit() { @@ -40,10 +42,28 @@ export class TaskdetailsComponent implements OnInit { this.taskService.updateTask(this.task).subscribe(task => { this.requestInProgress = false; this.task = task; + this.taskService.publishUpdatedTask(task); }); } openTask(taskId: string) { this.router.navigate([{outlets: {detail: `task/${taskId}`}}], {relativeTo: this.route.parent}); } + + workOnTaskDisabled(): boolean { + return this.task ? this.task.state === 'COMPLETED' : false; + } + + deleteTask(): void { + this.taskService.deleteTask(this.task).subscribe(); + this.taskService.publishDeletedTask(this.task); + this.task = null; + this.router.navigate([`/workplace/tasks`]); + } + + ngOnDestroy(): void { + if (this.routeSubscription) { + this.routeSubscription.unsubscribe(); + } + } } diff --git a/web/src/app/workplace/tasklist/tasklist.component.html b/web/src/app/workplace/tasklist/tasklist.component.html index 85f7a4f52..42e670d10 100644 --- a/web/src/app/workplace/tasklist/tasklist.component.html +++ b/web/src/app/workplace/tasklist/tasklist.component.html @@ -1,9 +1,11 @@
- - + +
    -
  • There are no Tasks for this workbasket
  • +
  • + This Workbasket has no Tasks +
  • diff --git a/web/src/app/workplace/tasklist/tasklist.component.scss b/web/src/app/workplace/tasklist/tasklist.component.scss index 3d83732f2..3608dc8fd 100644 --- a/web/src/app/workplace/tasklist/tasklist.component.scss +++ b/web/src/app/workplace/tasklist/tasklist.component.scss @@ -1,8 +1,8 @@ .clickable { - cursor: pointer; + cursor: pointer; } -.task-list-full-height{ +.task-list-full-height { height: calc(100vh - 55px); } @@ -18,14 +18,15 @@ ul { max-height: 90vh; margin-bottom: 10px; - overflow:scroll; - -webkit-overflow-scrolling: touch; + overflow: hidden; + overflow-y: scroll; } -a > label{ +a > label { height: 2em; width: 100%; } + dd, dt { text-overflow: ellipsis; white-space: nowrap; @@ -42,6 +43,7 @@ dt > i { li > div.row > dl { margin-bottom: 0px; } + li > div.row > dl:first-child { margin-left: 10px; } diff --git a/web/src/app/workplace/tasklist/tasklist.component.ts b/web/src/app/workplace/tasklist/tasklist.component.ts index 3cc17db44..9dd0d46cd 100644 --- a/web/src/app/workplace/tasklist/tasklist.component.ts +++ b/web/src/app/workplace/tasklist/tasklist.component.ts @@ -1,22 +1,41 @@ -import {Component, Input, OnInit} from '@angular/core'; -import {Task} from '../models/task'; +import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {Task} from 'app/workplace/models/task'; import {ActivatedRoute, Router} from '@angular/router'; +import {TaskService} from 'app/workplace/services/task.service'; +import {Subscription} from 'rxjs/Subscription'; @Component({ selector: 'taskana-task-list', templateUrl: './tasklist.component.html', styleUrls: ['./tasklist.component.scss'] }) -export class TasklistComponent implements OnInit { +export class TasklistComponent implements OnInit, OnDestroy { private columnForOrdering: string; + private taskChangeSubscription: Subscription; + private taskDeletedSubscription: Subscription; selectedId = ''; @Input() tasks: Task[]; constructor(private router: Router, - private route: ActivatedRoute) { + private route: ActivatedRoute, + private taskService: TaskService) { this.columnForOrdering = 'id'; // default: order tasks by id + this.taskChangeSubscription = this.taskService.taskChangedStream.subscribe(task => { + for (let i = 0; i < this.tasks.length; i++) { + if (this.tasks[i].taskId === task.taskId) { + this.tasks[i] = task; + } + } + }); + this.taskDeletedSubscription = this.taskService.taskDeletedStream.subscribe(task => { + for (let i = 0; i < this.tasks.length; i++) { + if (this.tasks[i].taskId === task.taskId) { + this.tasks.splice(i, 1); + } + } + }) } ngOnInit() { @@ -34,4 +53,9 @@ export class TasklistComponent implements OnInit { this.selectedId = taskId; this.router.navigate([{outlets: {detail: `taskdetail/${this.selectedId}`}}], {relativeTo: this.route}); } + + ngOnDestroy(): void { + this.taskChangeSubscription.unsubscribe(); + this.taskDeletedSubscription.unsubscribe(); + } } diff --git a/web/src/app/workplace/workbasket-selector/workbasket-selector.component.html b/web/src/app/workplace/workbasket-selector/workbasket-selector.component.html index 645488f0e..b632c5dad 100644 --- a/web/src/app/workplace/workbasket-selector/workbasket-selector.component.html +++ b/web/src/app/workplace/workbasket-selector/workbasket-selector.component.html @@ -1,16 +1,14 @@
    - + [disabled]="!workbasketSelected">Go!
    -
    -
    - diff --git a/web/src/app/workplace/workbasket-selector/workbasket-selector.component.ts b/web/src/app/workplace/workbasket-selector/workbasket-selector.component.ts index e25341509..28d7dfb84 100644 --- a/web/src/app/workplace/workbasket-selector/workbasket-selector.component.ts +++ b/web/src/app/workplace/workbasket-selector/workbasket-selector.component.ts @@ -14,11 +14,13 @@ export class SelectorComponent implements OnInit { tasksChanged = new EventEmitter(); tasks: Task[] = []; - - autoCompleteData: string[] = []; + workbasketNames: string[] = []; result = ''; - resultKey: string; + resultId = ''; workbaskets: Workbasket[]; + currentBasket: Workbasket; + + workbasketSelected = false; constructor(private taskService: TaskService, private workbasketService: WorkbasketService) { @@ -28,34 +30,37 @@ export class SelectorComponent implements OnInit { this.workbasketService.getAllWorkBaskets().subscribe(workbaskets => { this.workbaskets = workbaskets._embedded ? workbaskets._embedded.workbaskets : []; this.workbaskets.forEach(workbasket => { - this.autoCompleteData.push(workbasket.name); + this.workbasketNames.push(workbasket.name); }); }); - if (this.workbasketService.workbasketKey) { - this.getTasks(this.workbasketService.workbasketKey); - this.result = this.workbasketService.workbasketName; - } } searchBasket() { if (this.workbaskets) { this.workbaskets.forEach(workbasket => { if (workbasket.name === this.result) { - this.resultKey = workbasket.workbasketId; + this.resultId = workbasket.workbasketId; + this.currentBasket = workbasket; } }); - this.getTasks(this.resultKey); - this.workbasketService.workbasketKey = this.resultKey; - this.workbasketService.workbasketName = this.result; - this.tasksChanged.emit(this.tasks); + + if (this.resultId.length > 0) { + this.getTasks(this.resultId); + this.tasksChanged.emit(this.tasks); + } else { + this.tasks = []; + this.tasksChanged.emit(this.tasks); + } + } + this.resultId = ''; } - getTasks(workbasketKey: string) { - this.taskService.findTasksWithWorkbasket(workbasketKey).subscribe( + getTasks(workbasketId: string) { + this.taskService.findTasksWithWorkbasket(workbasketId).subscribe( tasks => { + this.tasks.length = 0; if (!tasks || tasks._embedded === undefined) { - this.tasks.length = 0; return; } tasks._embedded.tasks.forEach(e => this.tasks.push(e)); diff --git a/web/src/app/workplace/workplace.module.ts b/web/src/app/workplace/workplace.module.ts index 93dc4cf2a..879996199 100644 --- a/web/src/app/workplace/workplace.module.ts +++ b/web/src/app/workplace/workplace.module.ts @@ -1,20 +1,19 @@ import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; -import {Ng2AutoCompleteModule} from 'ng2-auto-complete'; import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http'; import {AngularSvgIconModule} from 'angular-svg-icon'; import {WorkplaceRoutingModule} from './workplace-routing.module'; -import {AlertModule} from 'ngx-bootstrap'; +import {AlertModule, TypeaheadModule} from 'ngx-bootstrap'; -import { SelectorComponent } from './workbasket-selector/workbasket-selector.component'; -import { TasklistComponent } from './tasklist/tasklist.component'; -import { TaskdetailsComponent } from './taskdetails/taskdetails.component'; -import { TaskComponent } from './task/task.component'; -import { CodeComponent } from './components/code/code.component'; +import {SelectorComponent} from './workbasket-selector/workbasket-selector.component'; +import {TasklistComponent} from './tasklist/tasklist.component'; +import {TaskdetailsComponent} from './taskdetails/taskdetails.component'; +import {TaskComponent} from './task/task.component'; +import {CodeComponent} from './components/code/code.component'; -import { OrderTasksByPipe } from './util/orderTasksBy.pipe'; +import {OrderTasksByPipe} from './util/orderTasksBy.pipe'; import {TaskService} from './services/task.service'; import {WorkbasketService} from 'app/services/workbasket/workbasket.service'; @@ -23,9 +22,9 @@ import {CustomHttpClientInterceptor} from './services/custom-http-interceptor/cu const MODULES = [ + TypeaheadModule.forRoot(), CommonModule, FormsModule, - Ng2AutoCompleteModule, HttpClientModule, AngularSvgIconModule, WorkplaceRoutingModule,