From 995e45d28f6970c7d84d3a340e311443bcd80fae Mon Sep 17 00:00:00 2001 From: Benjamin Gamard Date: Mon, 12 Mar 2018 22:55:04 +0100 Subject: [PATCH] #202 Actions on route transitions (#204) #202 Actions on route transition --- .../docs/core/constant/ActionType.java | 13 +++ .../docs/core/dao/jpa/RouteStepDao.java | 5 +- .../com/sismics/docs/core/dao/jpa/TagDao.java | 4 - .../core/dao/jpa/criteria/TagCriteria.java | 9 -- .../docs/core/dao/jpa/dto/RouteStepDto.java | 14 +++ .../docs/core/model/jpa/RouteStep.java | 15 +++ .../sismics/docs/core/util/ActionUtil.java | 42 ++++++++ .../sismics/docs/core/util/action/Action.java | 20 ++++ .../docs/core/util/action/AddTagAction.java | 40 +++++++ .../resources/db/update/dbupdate-018-0.sql | 1 + .../docs/rest/resource/AuditLogResource.java | 2 +- .../rest/resource/RouteModelResource.java | 87 ++++++++++++++- .../docs/rest/resource/RouteResource.java | 44 ++++++-- .../settings/SettingsWorkflowEdit.js | 43 +++++++- docs-web/src/main/webapp/src/locale/en.json | 7 +- .../partial/docs/settings.workflow.edit.html | 43 +++++++- docs-web/src/main/webapp/src/style/main.less | 5 + .../docs/rest/TestRouteModelResource.java | 26 +++-- .../sismics/docs/rest/TestRouteResource.java | 102 +++++++++++++++++- 19 files changed, 472 insertions(+), 50 deletions(-) create mode 100644 docs-core/src/main/java/com/sismics/docs/core/constant/ActionType.java create mode 100644 docs-core/src/main/java/com/sismics/docs/core/util/ActionUtil.java create mode 100644 docs-core/src/main/java/com/sismics/docs/core/util/action/Action.java create mode 100644 docs-core/src/main/java/com/sismics/docs/core/util/action/AddTagAction.java diff --git a/docs-core/src/main/java/com/sismics/docs/core/constant/ActionType.java b/docs-core/src/main/java/com/sismics/docs/core/constant/ActionType.java new file mode 100644 index 00000000..bb51e590 --- /dev/null +++ b/docs-core/src/main/java/com/sismics/docs/core/constant/ActionType.java @@ -0,0 +1,13 @@ +package com.sismics.docs.core.constant; + +/** + * Action types. + * + * @author bgamard + */ +public enum ActionType { + /** + * Add a tag. + */ + ADD_TAG +} diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RouteStepDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RouteStepDao.java index 502256d8..ebb01595 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RouteStepDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RouteStepDao.java @@ -68,7 +68,7 @@ public class RouteStepDao { Map parameterMap = new HashMap<>(); List criteriaList = new ArrayList<>(); - StringBuilder sb = new StringBuilder("select rs.RTP_ID_C, rs.RTP_NAME_C c0, rs.RTP_TYPE_C c1, rs.RTP_TRANSITION_C c2, rs.RTP_COMMENT_C c3, rs.RTP_IDTARGET_C c4, u.USE_USERNAME_C as targetUsername, g.GRP_NAME_C, rs.RTP_ENDDATE_D c5, uv.USE_USERNAME_C as validatorUsername, rs.RTP_IDROUTE_C, rs.RTP_ORDER_N c6") + StringBuilder sb = new StringBuilder("select rs.RTP_ID_C, rs.RTP_NAME_C c0, rs.RTP_TYPE_C c1, rs.RTP_TRANSITION_C c2, rs.RTP_COMMENT_C c3, rs.RTP_IDTARGET_C c4, u.USE_USERNAME_C as targetUsername, g.GRP_NAME_C, rs.RTP_ENDDATE_D c5, uv.USE_USERNAME_C as validatorUsername, rs.RTP_IDROUTE_C, rs.RTP_TRANSITIONS_C, rs.RTP_ORDER_N c6") .append(" from T_ROUTE_STEP rs ") .append(" join T_ROUTE r on r.RTE_ID_C = rs.RTP_IDROUTE_C ") .append(" left join T_USER uv on uv.USE_ID_C = rs.RTP_IDVALIDATORUSER_C ") @@ -124,7 +124,8 @@ public class RouteStepDao { Timestamp endDateTimestamp = (Timestamp) o[i++]; dto.setEndDateTimestamp(endDateTimestamp == null ? null : endDateTimestamp.getTime()); dto.setValidatorUserName((String) o[i++]); - dto.setRouteId((String) o[i]); + dto.setRouteId((String) o[i++]); + dto.setTransitions((String) o[i]); dtoList.add(dto); } return dtoList; diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/TagDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/TagDao.java index 77c08fd0..4da52054 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/TagDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/TagDao.java @@ -195,10 +195,6 @@ public class TagDao { criteriaList.add("dt.DOT_IDDOCUMENT_C = :documentId"); parameterMap.put("documentId", criteria.getDocumentId()); } - if (criteria.getName() != null) { - criteriaList.add("t.TAG_NAME_C = :name"); - parameterMap.put("name", criteria.getName()); - } criteriaList.add("t.TAG_DELETEDATE_D is null"); diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/TagCriteria.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/TagCriteria.java index 030cf6a6..bb613a1b 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/TagCriteria.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/TagCriteria.java @@ -54,13 +54,4 @@ public class TagCriteria { this.documentId = documentId; return this; } - - public String getName() { - return name; - } - - public TagCriteria setName(String name) { - this.name = name; - return this; - } } diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/RouteStepDto.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/RouteStepDto.java index 70553b2e..d2ff2d1f 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/RouteStepDto.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/RouteStepDto.java @@ -62,6 +62,11 @@ public class RouteStepDto { */ private String validatorUserName; + /** + * Transitions data. + */ + private String transitions; + /** * Route ID. */ @@ -166,6 +171,15 @@ public class RouteStepDto { return this; } + public String getTransitions() { + return transitions; + } + + public RouteStepDto setTransitions(String transitions) { + this.transitions = transitions; + return this; + } + /** * Transform in JSON. * diff --git a/docs-core/src/main/java/com/sismics/docs/core/model/jpa/RouteStep.java b/docs-core/src/main/java/com/sismics/docs/core/model/jpa/RouteStep.java index 2207597d..f591fe34 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/model/jpa/RouteStep.java +++ b/docs-core/src/main/java/com/sismics/docs/core/model/jpa/RouteStep.java @@ -54,6 +54,12 @@ public class RouteStep { @Column(name = "RTP_COMMENT_C", length = 500) private String comment; + /** + * Transitions JSON data. + */ + @Column(name = "RTP_TRANSITIONS_C", length = 2000) + private String transitions; + /** * Target ID (user or group). */ @@ -198,6 +204,15 @@ public class RouteStep { return this; } + public String getTransitions() { + return transitions; + } + + public RouteStep setTransitions(String transitions) { + this.transitions = transitions; + return this; + } + @Override public String toString() { return MoreObjects.toStringHelper(this) diff --git a/docs-core/src/main/java/com/sismics/docs/core/util/ActionUtil.java b/docs-core/src/main/java/com/sismics/docs/core/util/ActionUtil.java new file mode 100644 index 00000000..ca623bef --- /dev/null +++ b/docs-core/src/main/java/com/sismics/docs/core/util/ActionUtil.java @@ -0,0 +1,42 @@ +package com.sismics.docs.core.util; + +import com.sismics.docs.core.constant.ActionType; +import com.sismics.docs.core.dao.jpa.dto.DocumentDto; +import com.sismics.docs.core.util.action.Action; +import com.sismics.docs.core.util.action.AddTagAction; +import org.slf4j.LoggerFactory; + +import javax.json.JsonObject; + +/** + * Action utilities. + * + * @author bgamard + */ +public class ActionUtil { + /** + * Logger. + */ + private static final org.slf4j.Logger log = LoggerFactory.getLogger(LuceneUtil.class); + + /** + * Execute an action. + * + * @param actionType Action type + * @param actionData Action data + * @param documentDto Document DTO + */ + public static void executeAction(ActionType actionType, JsonObject actionData, DocumentDto documentDto) { + Action action; + switch (actionType) { + case ADD_TAG: + action = new AddTagAction(); + break; + default: + log.error("Action type not handled: " + actionType); + return; + } + + action.execute(documentDto, actionData); + } +} diff --git a/docs-core/src/main/java/com/sismics/docs/core/util/action/Action.java b/docs-core/src/main/java/com/sismics/docs/core/util/action/Action.java new file mode 100644 index 00000000..25d6e91d --- /dev/null +++ b/docs-core/src/main/java/com/sismics/docs/core/util/action/Action.java @@ -0,0 +1,20 @@ +package com.sismics.docs.core.util.action; + +import com.sismics.docs.core.dao.jpa.dto.DocumentDto; + +import javax.json.JsonObject; + +/** + * Base action interface. + * + * @author bgamard + */ +public interface Action { + /** + * Execute the action. + * + * @param documentDto Document DTO + * @param action Action data + */ + void execute(DocumentDto documentDto, JsonObject action); +} diff --git a/docs-core/src/main/java/com/sismics/docs/core/util/action/AddTagAction.java b/docs-core/src/main/java/com/sismics/docs/core/util/action/AddTagAction.java new file mode 100644 index 00000000..28c5051f --- /dev/null +++ b/docs-core/src/main/java/com/sismics/docs/core/util/action/AddTagAction.java @@ -0,0 +1,40 @@ +package com.sismics.docs.core.util.action; + +import com.google.common.collect.Sets; +import com.sismics.docs.core.dao.jpa.TagDao; +import com.sismics.docs.core.dao.jpa.criteria.TagCriteria; +import com.sismics.docs.core.dao.jpa.dto.DocumentDto; +import com.sismics.docs.core.dao.jpa.dto.TagDto; + +import javax.json.JsonObject; +import java.util.List; +import java.util.Set; + +/** + * Action to add a tag. + * + * @author bgamard + */ +public class AddTagAction implements Action { + @Override + public void execute(DocumentDto documentDto, JsonObject action) { + if (action.getString("tag") == null) { + return; + } + + TagDao tagDao = new TagDao(); + List tagAddDtoList = tagDao.findByCriteria(new TagCriteria().setId(action.getString("tag")), null); + if (tagAddDtoList.isEmpty()) { + // The tag has been deleted since the route model creation + return; + } + + List tagDtoList = tagDao.findByCriteria(new TagCriteria().setDocumentId(documentDto.getId()), null); + Set tagIdSet = Sets.newHashSet(tagAddDtoList.get(0).getId()); + for (TagDto tagDto : tagDtoList) { + tagIdSet.add(tagDto.getId()); + } + + tagDao.updateTagList(documentDto.getId(), tagIdSet); + } +} diff --git a/docs-core/src/main/resources/db/update/dbupdate-018-0.sql b/docs-core/src/main/resources/db/update/dbupdate-018-0.sql index 17b4dd7b..bb11c357 100644 --- a/docs-core/src/main/resources/db/update/dbupdate-018-0.sql +++ b/docs-core/src/main/resources/db/update/dbupdate-018-0.sql @@ -1,4 +1,5 @@ alter table T_DOCUMENT add column DOC_UPDATEDATE_D datetime; update T_DOCUMENT set DOC_UPDATEDATE_D = DOC_CREATEDATE_D; alter table T_DOCUMENT alter column DOC_UPDATEDATE_D datetime not null; +alter table T_ROUTE_STEP add column RTP_TRANSITIONS_C varchar(2000); update T_CONFIG set CFG_VALUE_C = '18' where CFG_ID_C = 'DB_VERSION'; diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/AuditLogResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/AuditLogResource.java index 4a08fe84..26a48afa 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/AuditLogResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/AuditLogResource.java @@ -41,7 +41,7 @@ public class AuditLogResource extends BaseResource { * @apiSuccess {String} logs.id ID * @apiSuccess {String} logs.username Username * @apiSuccess {String} logs.target Entity ID - * @apiSuccess {String="Acl","Comment","Document","File","Group","Tag","User","RouteModel"} logs.class Entity type + * @apiSuccess {String="Acl","Comment","Document","File","Group","Tag","User","RouteModel","Route"} logs.class Entity type * @apiSuccess {String="CREATE","UPDATE","DELETE"} logs.type Type * @apiSuccess {String} logs.message Message * @apiSuccess {Number} logs.create_date Create date (timestamp) diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteModelResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteModelResource.java index 4fea590b..51f69ee5 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteModelResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteModelResource.java @@ -1,12 +1,18 @@ package com.sismics.docs.rest.resource; +import com.google.common.collect.Lists; import com.sismics.docs.core.constant.AclTargetType; +import com.sismics.docs.core.constant.ActionType; +import com.sismics.docs.core.constant.RouteStepTransition; import com.sismics.docs.core.constant.RouteStepType; import com.sismics.docs.core.dao.jpa.GroupDao; import com.sismics.docs.core.dao.jpa.RouteModelDao; +import com.sismics.docs.core.dao.jpa.TagDao; import com.sismics.docs.core.dao.jpa.UserDao; import com.sismics.docs.core.dao.jpa.criteria.RouteModelCriteria; +import com.sismics.docs.core.dao.jpa.criteria.TagCriteria; import com.sismics.docs.core.dao.jpa.dto.RouteModelDto; +import com.sismics.docs.core.dao.jpa.dto.TagDto; import com.sismics.docs.core.model.jpa.Group; import com.sismics.docs.core.model.jpa.RouteModel; import com.sismics.docs.core.model.jpa.User; @@ -120,6 +126,7 @@ public class RouteModelResource extends BaseResource { private void validateRouteModelSteps(String steps) { UserDao userDao = new UserDao(); GroupDao groupDao = new GroupDao(); + TagDao tagDao = new TagDao(); try (JsonReader reader = Json.createReader(new StringReader(steps))) { JsonArray stepsJson = reader.readArray(); @@ -128,19 +135,26 @@ public class RouteModelResource extends BaseResource { } for (int i = 0; i < stepsJson.size(); i++) { JsonObject step = stepsJson.getJsonObject(i); - if (step.size() != 3) { + if (step.size() != 4) { throw new ClientException("ValidationError", "Steps data not valid"); } - String type = step.getString("type"); + + // Name ValidationUtil.validateLength(step.getString("name"), "step.name", 1, 200, false); + + // Type + String typeStr = step.getString("type"); + RouteStepType type; try { - RouteStepType.valueOf(type); + type = RouteStepType.valueOf(typeStr); } catch (IllegalArgumentException e) { - throw new ClientException("ValidationError", type + "is not a valid route step type"); + throw new ClientException("ValidationError", typeStr + "is not a valid route step type"); } + + // Target JsonObject target = step.getJsonObject("target"); if (target.size() != 2) { - throw new ClientException("ValidationError", "Steps data not valid"); + throw new ClientException("ValidationError", "Step target is not valid"); } AclTargetType targetType; String targetTypeStr = target.getString("type"); @@ -166,6 +180,69 @@ public class RouteModelResource extends BaseResource { } break; } + + // Transitions + List transitionsNames = Lists.newArrayList(); + JsonArray transitions = step.getJsonArray("transitions"); + if (type == RouteStepType.VALIDATE) { + if (transitions.size() != 1) { + throw new ClientException("ValidationError", "VALIDATE steps should have one transition"); + } + transitionsNames.add(RouteStepTransition.VALIDATED); + } else if (type == RouteStepType.APPROVE) { + if (transitions.size() != 2) { + throw new ClientException("ValidationError", "APPROVE steps should have two transition"); + } + transitionsNames.add(RouteStepTransition.APPROVED); + transitionsNames.add(RouteStepTransition.REJECTED); + } + + for (int j = 0; j < transitions.size(); j++) { + // Transition + JsonObject transition = transitions.getJsonObject(j); + if (transition.size() != 2) { + throw new ClientException("ValidationError", "Transition data is not valid"); + } + + // Transition name + String routeStepTransitionStr = transition.getString("name"); + ValidationUtil.validateRequired(routeStepTransitionStr, "step.transitions.name"); + RouteStepTransition routeStepTransition; + try { + routeStepTransition = RouteStepTransition.valueOf(routeStepTransitionStr); + } catch (IllegalArgumentException e) { + throw new ClientException("ValidationError", routeStepTransitionStr + " is not a valid route step transition type"); + } + if (!transitionsNames.contains(routeStepTransition)) { + throw new ClientException("ValidationError", routeStepTransitionStr + " is not allowed for this step type"); + } + + // Actions + JsonArray actions = transition.getJsonArray("actions"); + for (int k = 0; k < actions.size(); k++) { + JsonObject action = actions.getJsonObject(k); + + // Action type + String actionTypeStr = action.getString("type"); + ActionType actionType; + ValidationUtil.validateRequired(routeStepTransitionStr, "step.transitions.actions.type"); + try { + actionType = ActionType.valueOf(actionTypeStr); + } catch (IllegalArgumentException e) { + throw new ClientException("ValidationError", actionTypeStr + " is not a valid action type"); + } + + // Action custom fields + if (actionType == ActionType.ADD_TAG) { + String tagId = action.getString("tag"); + ValidationUtil.validateRequired(routeStepTransitionStr, "step.transitions.actions.tag"); + List tagDtoList = tagDao.findByCriteria(new TagCriteria().setId(tagId), null); + if (tagDtoList.size() != 1) { + throw new ClientException("ValidationError", tagId + " is not a valid tag"); + } + } + } + } } } catch (JsonException e) { throw new ClientException("ValidationError", "Steps data not valid"); diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteResource.java index cfc9f53c..0f55d646 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteResource.java @@ -1,9 +1,6 @@ package com.sismics.docs.rest.resource; -import com.sismics.docs.core.constant.AclTargetType; -import com.sismics.docs.core.constant.PermType; -import com.sismics.docs.core.constant.RouteStepTransition; -import com.sismics.docs.core.constant.RouteStepType; +import com.sismics.docs.core.constant.*; import com.sismics.docs.core.dao.jpa.*; import com.sismics.docs.core.dao.jpa.criteria.RouteCriteria; import com.sismics.docs.core.dao.jpa.criteria.RouteStepCriteria; @@ -13,6 +10,7 @@ import com.sismics.docs.core.dao.jpa.dto.RouteStepDto; import com.sismics.docs.core.model.jpa.Route; import com.sismics.docs.core.model.jpa.RouteModel; import com.sismics.docs.core.model.jpa.RouteStep; +import com.sismics.docs.core.util.ActionUtil; import com.sismics.docs.core.util.RoutingUtil; import com.sismics.docs.core.util.SecurityUtil; import com.sismics.docs.core.util.jpa.SortCriteria; @@ -93,12 +91,17 @@ public class RouteResource extends BaseResource { JsonObject target = step.getJsonObject("target"); AclTargetType targetType = AclTargetType.valueOf(target.getString("type")); String targetName = target.getString("name"); + String transitions = null; + if (step.containsKey("transitions")) { + transitions = step.getJsonArray("transitions").toString(); + } RouteStep routeStep = new RouteStep() .setRouteId(route.getId()) .setName(step.getString("name")) .setOrder(order) .setType(RouteStepType.valueOf(step.getString("type"))) + .setTransitions(transitions) .setTargetId(SecurityUtil.getTargetIdFromName(targetName, targetType)); if (routeStep.getTargetId() == null) { @@ -149,7 +152,9 @@ public class RouteResource extends BaseResource { // Get the document AclDao aclDao = new AclDao(); - if (!aclDao.checkPermission(documentId, PermType.READ, getTargetIdList(null))) { + DocumentDao documentDao = new DocumentDao(); + DocumentDto documentDto = documentDao.getDocument(documentId, PermType.READ, getTargetIdList(null)); + if (documentDto == null) { throw new NotFoundException(); } @@ -168,18 +173,39 @@ public class RouteResource extends BaseResource { // Validate data ValidationUtil.validateRequired(transitionStr, "transition"); comment = ValidationUtil.validateLength(comment, "comment", 1, 500, true); - RouteStepTransition transition = RouteStepTransition.valueOf(transitionStr); - if (routeStepDto.getType() == RouteStepType.VALIDATE && transition != RouteStepTransition.VALIDATED - || routeStepDto.getType() == RouteStepType.APPROVE && transition != RouteStepTransition.APPROVED && transition != RouteStepTransition.REJECTED) { + RouteStepTransition routeStepTransition = RouteStepTransition.valueOf(transitionStr); + if (routeStepDto.getType() == RouteStepType.VALIDATE && routeStepTransition != RouteStepTransition.VALIDATED + || routeStepDto.getType() == RouteStepType.APPROVE + && routeStepTransition != RouteStepTransition.APPROVED && routeStepTransition != RouteStepTransition.REJECTED) { throw new ClientException("ValidationError", "Invalid transition for this route step type"); } // Validate the step and update ACLs - routeStepDao.endRouteStep(routeStepDto.getId(), transition, comment, principal.getId()); + routeStepDao.endRouteStep(routeStepDto.getId(), routeStepTransition, comment, principal.getId()); RouteStepDto newRouteStep = routeStepDao.getCurrentStep(documentId); RoutingUtil.updateAcl(documentId, newRouteStep, routeStepDto, principal.getId()); RoutingUtil.sendRouteStepEmail(documentId, routeStepDto); + // Execute actions + if (routeStepDto.getTransitions() != null) { + try (JsonReader reader = Json.createReader(new StringReader(routeStepDto.getTransitions()))) { + JsonArray transitions = reader.readArray(); + // Filter out our transition + for (int i = 0; i < transitions.size(); i++) { + JsonObject transition = transitions.getJsonObject(i); + if (transition.getString("name").equals(routeStepTransition.name())) { + // Transition found, execute those actions + JsonArray actions = transition.getJsonArray("actions"); + for (int j = 0; j < actions.size(); j++) { + JsonObject action = actions.getJsonObject(j); + ActionType actionType = ActionType.valueOf(action.getString("type")); + ActionUtil.executeAction(actionType, action, documentDto); + } + } + } + } + } + JsonObjectBuilder response = Json.createObjectBuilder() .add("readable", aclDao.checkPermission(documentId, PermType.READ, getTargetIdList(null))); if (newRouteStep != null) { diff --git a/docs-web/src/main/webapp/src/app/docs/controller/settings/SettingsWorkflowEdit.js b/docs-web/src/main/webapp/src/app/docs/controller/settings/SettingsWorkflowEdit.js index fe65e37d..783a997f 100644 --- a/docs-web/src/main/webapp/src/app/docs/controller/settings/SettingsWorkflowEdit.js +++ b/docs-web/src/main/webapp/src/app/docs/controller/settings/SettingsWorkflowEdit.js @@ -45,9 +45,11 @@ angular.module('docs').controller('SettingsWorkflowEdit', function($scope, $dial * Add a workflow step. */ $scope.addStep = function () { - $scope.workflow.steps.push({ + var step = { type: 'VALIDATE' - }); + }; + $scope.updateTransitions(step); + $scope.workflow.steps.push(step); }; /** @@ -64,6 +66,12 @@ angular.module('docs').controller('SettingsWorkflowEdit', function($scope, $dial Restangular.one('routemodel', $stateParams.id).get().then(function (data) { $scope.workflow = data; $scope.workflow.steps = JSON.parse(data.steps); + _.each($scope.workflow.steps, function (step) { + if (!step.transitions) { + // Patch for old route models + $scope.updateTransitions(step); + } + }); }); } else { $scope.workflow = { @@ -124,4 +132,35 @@ angular.module('docs').controller('SettingsWorkflowEdit', function($scope, $dial $scope.removeStep = function (step) { $scope.workflow.steps.splice($scope.workflow.steps.indexOf(step), 1); }; + + $scope.updateTransitions = function (step) { + if (step.type === 'VALIDATE') { + step.transitions = [{ + name: 'VALIDATED', + actions: [] + }]; + } else if (step.type === 'APPROVE') { + step.transitions = [{ + name: 'APPROVED', + actions: [] + }, { + name: 'REJECTED', + actions: [] + }]; + } + }; + + $scope.addAction = function (transition) { + transition.actions.push({ + type: 'ADD_TAG' + }); + }; + + $scope.removeAction = function (actions, action) { + actions.splice(actions.indexOf(action), 1); + }; + + Restangular.one('tag/list').get().then(function(data) { + $scope.tags = data.tags; + }); }); \ No newline at end of file diff --git a/docs-web/src/main/webapp/src/locale/en.json b/docs-web/src/main/webapp/src/locale/en.json index 54e16e84..4cb52a2e 100644 --- a/docs-web/src/main/webapp/src/locale/en.json +++ b/docs-web/src/main/webapp/src/locale/en.json @@ -301,7 +301,9 @@ "type_validate": "Validate", "target": "Assigned to", "target_help": "Approve: Accept or reject the review
Validate: Review and continue the workflow", - "add_step": "Add a workflow step" + "add_step": "Add a workflow step", + "actions": "What happens after?", + "remove_action": "Remove action" } }, "security": { @@ -507,6 +509,9 @@ "number": "Number required", "no_space": "Spaces are not allowed" }, + "action_type": { + "ADD_TAG": "Add this tag" + }, "pagination": { "previous": "Previous", "next": "Next", diff --git a/docs-web/src/main/webapp/src/partial/docs/settings.workflow.edit.html b/docs-web/src/main/webapp/src/partial/docs/settings.workflow.edit.html index f4d598b5..b557aad9 100644 --- a/docs-web/src/main/webapp/src/partial/docs/settings.workflow.edit.html +++ b/docs-web/src/main/webapp/src/partial/docs/settings.workflow.edit.html @@ -49,7 +49,7 @@ - @@ -82,17 +82,54 @@ +
+
+ {{ 'settings.workflow.edit.actions' | translate }} +
+
+
+
+ {{ 'workflow_transition.' + transition.name | translate }} +
+
+
+

{{ 'action_type.' + action.type | translate }}

+
+
+ +
+
+

+ + {{ 'settings.workflow.edit.remove_action' | translate }} + +

+
+
+ + + + +
+
+
+
+
-
+
-
+