Skip to content

Commit

Permalink
Preliminary version of custom forms in approvals
Browse files Browse the repository at this point in the history
  • Loading branch information
mederly committed Jan 28, 2017
1 parent eb32c45 commit e47ef8d
Show file tree
Hide file tree
Showing 27 changed files with 258 additions and 70 deletions.
Expand Up @@ -42,7 +42,6 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.FormDefinitionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FormFieldGroupType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FormItemDisplayType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FormItemsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.prism.xml.ns._public.types_3.ItemPathType;
import com.evolveum.midpoint.schema.util.FormTypeUtil;
Expand Down
Expand Up @@ -43,12 +43,9 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractFormItemType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FormDefinitionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FormFieldGroupType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FormFieldType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FormType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.VariableBindingDefinitionType;
import com.evolveum.prism.xml.ns._public.types_3.ItemPathType;
import com.evolveum.midpoint.schema.util.FocusTypeUtil;
import com.evolveum.midpoint.schema.util.FormTypeUtil;

public class DynamicFormPanel<O extends ObjectType> extends BasePanel<ObjectWrapper<O>> {
Expand Down
Expand Up @@ -18,6 +18,7 @@
import com.evolveum.midpoint.gui.api.model.LoadableModel;
import com.evolveum.midpoint.model.api.WorkflowService;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.prism.query.builder.QueryBuilder;
Expand Down Expand Up @@ -82,8 +83,9 @@ public class PageWorkItem extends PageAdminWorkItems {
private static final String ID_WORK_ITEM_PANEL = "workItemPanel";

private static final Trace LOGGER = TraceManager.getTrace(PageWorkItem.class);
private static final String ID_MAIN_FORM = "mainForm";

private LoadableModel<WorkItemDto> workItemDtoModel;
private LoadableModel<WorkItemDto> workItemDtoModel;
private String taskId;

public PageWorkItem(PageParameters parameters) {
Expand Down Expand Up @@ -171,7 +173,7 @@ private void initLayout() {
new PropertyModel<>(workItemDtoModel, WorkItemDto.F_WORK_ITEM), workItemDtoModel);
add(summaryPanel);

Form mainForm = new Form("mainForm");
Form mainForm = new Form(ID_MAIN_FORM);
mainForm.setMultiPart(true);
add(mainForm);

Expand All @@ -180,6 +182,10 @@ private void initLayout() {
initButtons(mainForm);
}

public WorkItemPanel getWorkItemPanel() {
return (WorkItemPanel) get(ID_MAIN_FORM).get(ID_WORK_ITEM_PANEL);
}

private void initButtons(Form mainForm) {

VisibleEnableBehaviour isAllowedToSubmit = new VisibleEnableBehaviour() {
Expand Down Expand Up @@ -298,7 +304,8 @@ private void savePerformed(AjaxRequestTarget target, boolean decision) {

try {
WorkItemDto dto = workItemDtoModel.getObject();
getWorkflowService().approveOrRejectWorkItem(dto.getWorkItemId(), decision, dto.getApproverComment(), result);
ObjectDelta delta = getWorkItemPanel().getDeltaFromForm();
getWorkflowService().approveOrRejectWorkItem(dto.getWorkItemId(), decision, dto.getApproverComment(), delta, result);
} catch (Exception ex) {
result.recordFatalError("Couldn't save work item.", ex);
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't save work item", ex);
Expand Down
Expand Up @@ -139,7 +139,7 @@ private void approveOrRejectWorkItemsPerformed(AjaxRequestTarget target, boolean
for (WorkItemDto workItemDto : workItemDtoList) {
OperationResult result = mainResult.createSubresult(OPERATION_APPROVE_OR_REJECT_ITEM);
try {
workflowService.approveOrRejectWorkItem(workItemDto.getWorkItemId(), approve, null, result);
workflowService.approveOrRejectWorkItem(workItemDto.getWorkItemId(), approve, null, null, result);
result.computeStatus();
} catch (Exception e) {
result.recordPartialError("Couldn't approve/reject work item due to an unexpected exception.", e);
Expand Down
Expand Up @@ -19,7 +19,9 @@
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.gui.api.util.WebComponentUtil;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.schema.util.WfContextUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.component.prism.DynamicFormPanel;
Expand All @@ -35,8 +37,10 @@
import com.evolveum.midpoint.web.session.UserProfileStorage;
import com.evolveum.midpoint.web.util.OnePageParameterEncoder;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ApprovalLevelType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;
import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
Expand Down Expand Up @@ -192,8 +196,12 @@ public void onClick(AjaxRequestTarget target) {
ApprovalLevelType level = WfContextUtil.getCurrentApprovalLevel(dto.getWorkflowContext());
if (level != null && level.getFormRef() != null && level.getFormRef().getOid() != null) {
String formOid = level.getFormRef().getOid();
ObjectType focus = dto.getFocus(pageBase);
if (focus == null) {
focus = new UserType(pageBase.getPrismContext()); // TODO FIXME
}
DynamicFormPanel<UserType> customForm = new DynamicFormPanel<>(ID_CUSTOM_FORM,
(PrismObject<UserType>) new UserType(pageBase.getPrismContext()).asPrismObject(),
(PrismObject<UserType>) focus.asPrismObject(),
formOid, mainForm, false, pageBase);
add(customForm);
} else {
Expand All @@ -203,4 +211,12 @@ public void onClick(AjaxRequestTarget target) {
add(new TextArea<>(ID_APPROVER_COMMENT, new PropertyModel<String>(getModel(), WorkItemDto.F_APPROVER_COMMENT)));
}

public ObjectDelta getDeltaFromForm() throws SchemaException {
Component formPanel = get(ID_CUSTOM_FORM);
if (formPanel instanceof DynamicFormPanel) {
return ((DynamicFormPanel) formPanel).getObjectDelta();
} else {
return null;
}
}
}
Expand Up @@ -16,24 +16,34 @@

package com.evolveum.midpoint.web.page.admin.workflow.dto;

import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.gui.api.util.WebComponentUtil;
import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils;
import com.evolveum.midpoint.model.api.ModelInteractionService;
import com.evolveum.midpoint.model.api.visualizer.Scene;
import com.evolveum.midpoint.prism.Objectable;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.prism.xml.XmlTypeConverter;
import com.evolveum.midpoint.schema.DeltaConvertor;
import com.evolveum.midpoint.schema.ObjectTreeDeltas;
import com.evolveum.midpoint.schema.constants.ObjectTypes;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.WfContextUtil;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SystemException;
import com.evolveum.midpoint.web.component.DateLabelComponent;
import com.evolveum.midpoint.web.component.prism.show.SceneDto;
import com.evolveum.midpoint.web.component.prism.show.SceneUtil;
import com.evolveum.midpoint.web.component.util.Selectable;
import com.evolveum.midpoint.web.page.admin.server.dto.TaskChangesDto;
import com.evolveum.midpoint.web.page.admin.server.dto.TaskDto;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import com.evolveum.prism.xml.ns._public.types_3.ChangeTypeType;
import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -80,12 +90,14 @@ public class WorkItemDto extends Selectable {
//
// Depending on expected use (work item list vs. work item details)

protected WorkItemType workItem;
protected TaskType taskType;
protected List<TaskType> relatedTasks;
@Deprecated protected SceneDto deltas;
protected TaskChangesDto changes;
protected String approverComment;
private WorkItemType workItem;
private TaskType taskType;
private List<TaskType> relatedTasks;
@Deprecated private SceneDto deltas;
private TaskChangesDto changes;
private String approverComment;

private ObjectType focus;

public WorkItemDto(WorkItemType workItem) {
this(workItem, null, null);
Expand Down Expand Up @@ -116,7 +128,7 @@ public void prepareDeltaVisualization(String sceneNameKey, PrismContext prismCon
}

@Nullable
protected TaskType getTaskType() {
private TaskType getTaskType() {
if (taskType == null) {
taskType = WebComponentUtil.getObjectFromReference(workItem.getTaskRef(), TaskType.class);
}
Expand Down Expand Up @@ -321,4 +333,44 @@ public String getStageInfo() {
public List<InformationType> getAdditionalInformation() {
return workItem.getAdditionalInformation();
}

// Expects that we deal with primary changes of the focus (i.e. not of projections)
public ObjectType getFocus(PageBase pageBase) {
if (focus != null) {
return focus;
}
WfContextType wfc = getWorkflowContext();
WfPrimaryChangeProcessorStateType state = WfContextUtil.getPrimaryChangeProcessorState(wfc);
if (state == null || state.getDeltasToProcess() == null || state.getDeltasToProcess().getFocusPrimaryDelta() == null) {
return null;
}
ObjectDeltaType delta = state.getDeltasToProcess().getFocusPrimaryDelta();
if (delta.getChangeType() == ChangeTypeType.ADD) {
focus = (ObjectType) delta.getObjectToAdd();
} else if (delta.getChangeType() != ChangeTypeType.MODIFY) {
} else {
String oid = delta.getOid();
if (oid == null) {
throw new IllegalStateException("No OID in object modify delta: " + delta);
}
if (delta.getObjectType() == null) {
throw new IllegalStateException("No object type in object modify delta: " + delta);
}
Class<? extends ObjectType> clazz = ObjectTypes.getObjectTypeFromTypeQName(delta.getObjectType())
.getClassDefinition();
Task task = pageBase.createSimpleTask("getObject");
PrismObject<?> object = WebModelServiceUtils.loadObject(clazz, oid, pageBase, task, task.getResult());
if (object != null) {
focus = (ObjectType) object.asObjectable();
try {
ObjectDelta<Objectable> objectDelta = DeltaConvertor.createObjectDelta(delta, pageBase.getPrismContext());
objectDelta.applyTo(focus.asPrismObject());
} catch (SchemaException e) {
throw new SystemException("Cannot apply delta to focus object: " + e.getMessage(), e);
}
focus = (ObjectType) object.asObjectable();
}
}
return focus;
}
}
Expand Up @@ -27,6 +27,7 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTreeDeltasType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ProjectionObjectDeltaType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType;
import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.NotNull;

Expand Down Expand Up @@ -242,4 +243,20 @@ public void merge(ObjectTreeDeltas<F> deltasToMerge) throws SchemaException {
}
}
}

public static ObjectTreeDeltasType mergeDeltas(ObjectTreeDeltasType deltaTree, ObjectDeltaType deltaToMerge,
PrismContext prismContext) throws SchemaException {
if (deltaToMerge == null) {
return deltaTree;
}
ObjectTreeDeltasType deltaTreeToMerge = new ObjectTreeDeltasType();
deltaTreeToMerge.setFocusPrimaryDelta(deltaToMerge);
if (deltaTree == null) {
return deltaTreeToMerge;
}
ObjectTreeDeltas tree = fromObjectTreeDeltasType(deltaTree, prismContext);
ObjectTreeDeltas treeToMerge = fromObjectTreeDeltasType(deltaTreeToMerge, prismContext);
tree.merge(treeToMerge);
return tree.toObjectTreeDeltasType();
}
}
Expand Up @@ -108,6 +108,15 @@ public static ItemApprovalProcessStateType getItemApprovalProcessInfo(WfContextT
(ItemApprovalProcessStateType) processSpecificState : null;
}

public static WfPrimaryChangeProcessorStateType getPrimaryChangeProcessorState(WfContextType wfc) {
if (wfc == null) {
return null;
}
WfProcessorSpecificStateType state = wfc.getProcessorSpecificState();
return state instanceof WfPrimaryChangeProcessorStateType ?
(WfPrimaryChangeProcessorStateType) state : null;
}

public static ItemApprovalWorkItemPartType getItemApprovalWorkItemInfo(WorkItemType workItem) {
return workItem.getProcessSpecificPart() instanceof ItemApprovalWorkItemPartType ?
(ItemApprovalWorkItemPartType) workItem.getProcessSpecificPart() : null;
Expand Down
Expand Up @@ -927,7 +927,13 @@
</xsd:documentation>
</xsd:annotation>
</xsd:element>

<xsd:element name="additionalDelta" type="t:ObjectDeltaType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
TODO
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="decisionType" type="tns:DecisionType" />
Expand Down
@@ -1,5 +1,6 @@
package com.evolveum.midpoint.model.api;

import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
Expand All @@ -12,12 +13,14 @@ public interface WorkflowService {

/**
* Approves or rejects a work item (without supplying any further information).
* @param taskId identifier of activiti task backing the work item
* @param decision true = approve, false = reject
* @param parentResult
* @param comment
*/
void approveOrRejectWorkItem(String workItemId, boolean decision, String comment, OperationResult parentResult) throws SecurityViolationException;
* @param taskId identifier of activiti task backing the work item
* @param decision true = approve, false = reject
* @param comment
* @param additionalDelta
* @param parentResult
*/
void approveOrRejectWorkItem(String workItemId, boolean decision, String comment, ObjectDelta additionalDelta,
OperationResult parentResult) throws SecurityViolationException, SchemaException;

void stopProcessInstance(String instanceId, String username, OperationResult parentResult)
throws SchemaException, ObjectNotFoundException, SecurityViolationException;
Expand Down
Expand Up @@ -1993,9 +1993,10 @@ private void authorizeNodeCollectionOperation(ModelAuthorizationAction action, C

//region Workflow-related operations
@Override
public void approveOrRejectWorkItem(String workItemId, boolean decision, String comment, OperationResult parentResult)
throws SecurityViolationException {
getWorkflowManagerChecked().approveOrRejectWorkItem(workItemId, decision, comment, parentResult);
public void approveOrRejectWorkItem(String workItemId, boolean decision, String comment, ObjectDelta additionalDelta,
OperationResult parentResult)
throws SecurityViolationException, SchemaException {
getWorkflowManagerChecked().approveOrRejectWorkItem(workItemId, decision, comment, additionalDelta, parentResult);
}

@Override
Expand Down
Expand Up @@ -20,6 +20,7 @@
import com.evolveum.midpoint.prism.Containerable;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.SearchResultList;
Expand Down Expand Up @@ -63,13 +64,14 @@ <T extends Containerable> SearchResultList<T> searchContainers(Class<T> type, Ob

/**
* Approves or rejects a work item (without supplying any further information).
*
* @param taskId identifier of activiti task backing the work item
* @param taskId identifier of activiti task backing the work item
* @param decision true = approve, false = reject
* @param comment
* @param additionalDelta
* @param parentResult
*/
void approveOrRejectWorkItem(String taskId, boolean decision, String comment, OperationResult parentResult) throws SecurityViolationException;
void approveOrRejectWorkItem(String taskId, boolean decision, String comment, ObjectDelta additionalDelta,
OperationResult parentResult) throws SecurityViolationException, SchemaException;

void claimWorkItem(String workItemId, OperationResult result) throws ObjectNotFoundException, SecurityViolationException;

Expand Down
Expand Up @@ -21,6 +21,7 @@
import com.evolveum.midpoint.prism.Containerable;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.SearchResultList;
Expand Down Expand Up @@ -150,9 +151,10 @@ public <T extends Containerable> SearchResultList<T> searchContainers(Class<T> t
}

@Override
public void approveOrRejectWorkItem(String taskId, boolean decision, String comment, OperationResult parentResult)
throws SecurityViolationException {
workItemManager.completeWorkItem(taskId, ApprovalUtils.approvalStringValue(decision), comment, parentResult);
public void approveOrRejectWorkItem(String taskId, boolean decision, String comment, ObjectDelta additionalDelta,
OperationResult parentResult)
throws SecurityViolationException, SchemaException {
workItemManager.completeWorkItem(taskId, ApprovalUtils.approvalStringValue(decision), comment, additionalDelta, parentResult);
}

@Override
Expand Down

0 comments on commit e47ef8d

Please sign in to comment.