diff --git a/config/alfresco/messages/webclient.properties b/config/alfresco/messages/webclient.properties
index dd2c2b6c5c..05c97b8142 100644
--- a/config/alfresco/messages/webclient.properties
+++ b/config/alfresco/messages/webclient.properties
@@ -868,6 +868,7 @@ title_my_alfresco=My Alfresco
dashboard_info=My Alfresco Dashboard
dashboard_description=Configure this view and build your personal Alfresco dashboard
configure=Configure
+error_dashboard=An error occurred in one of the dashlets.
# My Alfresco Layout Manager wizard messages
configure_dashboard_title=Configure Dashboard Wizard
@@ -945,6 +946,9 @@ manage_workitem_desc=This dialog allows the work item to be managed
workitem_properties=Work Item Properties
id=Id
status=Status
+completed=Completed
+source=Source
+priority=Priority
my_workitems_todo_title=My Work Items To Do
my_workitems_todo_desc=List of your workflow items still to complete
my_workitems_completed_title=My Completed Work Items
@@ -953,7 +957,7 @@ due_date=Due Date
completed_on=Completed on
outcome=Outcome
reassign=Reassign
-
+cancel_workflow=Cancel Workflow
# Admin Console messages
title_admin_console=Administration Console
diff --git a/config/alfresco/web-client-config-workflow.xml b/config/alfresco/web-client-config-workflow.xml
index 6234f356fa..f6e3d58e64 100644
--- a/config/alfresco/web-client-config-workflow.xml
+++ b/config/alfresco/web-client-config-workflow.xml
@@ -15,10 +15,21 @@
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -43,10 +54,25 @@
reassign
- /images/icons/create_forum.gif
+ /images/icons/recover.gif
null
+
+ cancel_workflow
+ /images/icons/reject.gif
+ null
+
+
+
+ remove
+ /images/icons/delete.gif
+ #{DialogManager.bean.removePackageItem}
+
+ #{actionContext.id}
+
+
+
@@ -55,9 +81,32 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -103,7 +152,7 @@
+ actions-config-id="manage_workitem_actions" />
diff --git a/source/java/org/alfresco/web/bean/dialog/BaseDialogBean.java b/source/java/org/alfresco/web/bean/dialog/BaseDialogBean.java
index 45c1c906a4..fa3b203b6f 100644
--- a/source/java/org/alfresco/web/bean/dialog/BaseDialogBean.java
+++ b/source/java/org/alfresco/web/bean/dialog/BaseDialogBean.java
@@ -97,7 +97,7 @@ public abstract class BaseDialogBean implements IDialogBean
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
- Utils.addErrorMessage(formatErrorMessage(e));
+ Utils.addErrorMessage(formatErrorMessage(e), e);
outcome = getErrorOutcome(e);
}
}
diff --git a/source/java/org/alfresco/web/bean/workflow/ManageWorkItemDialog.java b/source/java/org/alfresco/web/bean/workflow/ManageWorkItemDialog.java
index 33d26071b7..d9c88b7ee7 100644
--- a/source/java/org/alfresco/web/bean/workflow/ManageWorkItemDialog.java
+++ b/source/java/org/alfresco/web/bean/workflow/ManageWorkItemDialog.java
@@ -8,6 +8,7 @@ import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
+import javax.faces.event.ActionEvent;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
@@ -25,10 +26,13 @@ import org.alfresco.web.app.Application;
import org.alfresco.web.bean.dialog.BaseDialogBean;
import org.alfresco.web.bean.repository.MapNode;
import org.alfresco.web.bean.repository.Node;
+import org.alfresco.web.bean.repository.NodePropertyResolver;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.TransientNode;
import org.alfresco.web.config.DialogsConfigElement.DialogButtonConfig;
import org.alfresco.web.ui.common.Utils;
+import org.alfresco.web.ui.common.component.UIActionLink;
+import org.alfresco.web.ui.common.component.data.UIRichList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -44,6 +48,8 @@ public class ManageWorkItemDialog extends BaseDialogBean
protected WorkflowTask workItem;
protected WorkflowTransition[] transitions;
protected List resources;
+ protected WorkItemCompleteResolver completeResolver = new WorkItemCompleteResolver();
+ protected UIRichList packageItemsRichList;
protected static final String ID_PREFIX = "transition_";
protected static final String CLIENT_ID_PREFIX = "dialog:" + ID_PREFIX;
@@ -179,22 +185,124 @@ public class ManageWorkItemDialog extends BaseDialogBean
}
catch (Throwable e)
{
- // reset the flag so we can re-attempt the operation
- isFinished = false;
-
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
- Utils.addErrorMessage(formatErrorMessage(e));
+ Utils.addErrorMessage(formatErrorMessage(e), e);
outcome = this.getErrorOutcome(e);
}
}
return outcome;
}
+
+ /**
+ * Removes an item from the workflow package
+ *
+ * @param event The event containing a reference to the item to remove
+ */
+ public void removePackageItem(ActionEvent event)
+ {
+ logger.info("remove package item: " + event);
+ }
+
+ /**
+ * Toggles the complete flag for a workflow package item
+ *
+ * @param event The event containing a reference to the item to toggle the status for
+ */
+ public void togglePackageItemComplete(ActionEvent event)
+ {
+ UserTransaction tx = null;
+ try
+ {
+ FacesContext context = FacesContext.getCurrentInstance();
+ tx = Repository.getUserTransaction(context);
+ tx.begin();
+
+ UIActionLink link = (UIActionLink)event.getComponent();
+ Map params = link.getParameterMap();
+
+ // create the node ref for the item we are toggling
+ NodeRef nodeRef = new NodeRef(Repository.getStoreRef(),
+ (String)params.get("id"));
+
+ // get the existing list of completed items
+ List completedItems = (List)this.workItem.properties.get(
+ WorkflowModel.PROP_COMPLETED_ITEMS);
+
+ if (completedItems == null)
+ {
+ // if it doesn't exist yet create the list and add the noderef
+ completedItems = new ArrayList(1);
+ completedItems.add(nodeRef);
+ this.workItem.properties.put(WorkflowModel.PROP_COMPLETED_ITEMS,
+ (Serializable)completedItems);
+ }
+ else
+ {
+ if (completedItems.contains(nodeRef))
+ {
+ // the item is already in the list remove it
+ completedItems.remove(nodeRef);
+
+ // NOTE: There is a bug somwehere which causes the list to be
+ // returned as a byte array instead of a list if an empty
+ // list is persisted, therefore if the list is now empty
+ // set the completed items back to null
+ if (completedItems.size() == 0)
+ {
+ this.workItem.properties.put(WorkflowModel.PROP_COMPLETED_ITEMS, null);
+ }
+ }
+ else
+ {
+ // the noderef is not in the list yet so just add it
+ completedItems.add(nodeRef);
+ }
+ }
+
+ // update the task with the updated parameters
+ this.workflowService.updateTask(this.workItem.id, this.workItem.properties,
+ null, null);
+
+ // commit the transaction
+ tx.commit();
+
+ // reset the rich list if the change was successful
+ this.packageItemsRichList.setValue(null);
+ }
+ catch (Throwable err)
+ {
+ Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
+ FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
+ this.resources = Collections.emptyList();
+ try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
+ }
+ }
// ------------------------------------------------------------------------------
// Bean Getters and Setters
+ /**
+ * Sets the rich list being used for the workflow package items
+ *
+ * @param richList The rich list instance
+ */
+ public void setPackageItemsRichList(UIRichList richList)
+ {
+ this.packageItemsRichList = richList;
+ }
+
+ /**
+ * Returns the rich list being used for the workflow package items
+ *
+ * @return The rich list instance
+ */
+ public UIRichList getPackageItemsRichList()
+ {
+ return this.packageItemsRichList;
+ }
+
/**
* Returns the Node representing the work item
*
@@ -213,7 +321,17 @@ public class ManageWorkItemDialog extends BaseDialogBean
*/
public List getResources()
{
- NodeRef workflowPackage = (NodeRef)this.workItem.properties.get(WorkflowModel.ASSOC_PACKAGE);
+ NodeRef workflowPackage = null;
+ Serializable obj = this.workItem.properties.get(WorkflowModel.ASSOC_PACKAGE);
+ // TODO: remove this workaroud where JBPM may return a String and not the NodeRef
+ if (obj instanceof NodeRef)
+ {
+ workflowPackage = (NodeRef)obj;
+ }
+ else if (obj instanceof String)
+ {
+ workflowPackage = new NodeRef((String)obj);
+ }
this.resources = new ArrayList(4);
@@ -257,6 +375,13 @@ public class ManageWorkItemDialog extends BaseDialogBean
MapNode node = new MapNode(nodeRef, this.nodeService, true);
this.browseBean.setupCommonBindingProperties(node);
+ // add property resolvers to show path information
+ node.addPropertyResolver("path", this.browseBean.resolverPath);
+ node.addPropertyResolver("displayPath", this.browseBean.resolverDisplayPath);
+
+ // add a property resolver to indicate whether the item has been completed or not
+ node.addPropertyResolver("completed", this.completeResolver);
+
this.resources.add(node);
}
}
@@ -297,4 +422,33 @@ public class ManageWorkItemDialog extends BaseDialogBean
{
this.workflowService = workflowService;
}
+
+ // ------------------------------------------------------------------------------
+ // Helper methods
+
+
+ // ------------------------------------------------------------------------------
+ // Inner classes
+
+ /**
+ * Property resolver to determine if the given node has been flagged as complete
+ */
+ protected class WorkItemCompleteResolver implements NodePropertyResolver
+ {
+ public Object get(Node node)
+ {
+ String result = Application.getMessage(FacesContext.getCurrentInstance(), "no");
+
+ List completedItems = (List)workItem.properties.get(
+ WorkflowModel.PROP_COMPLETED_ITEMS);
+
+ if (completedItems != null && completedItems.size() > 0 &&
+ completedItems.contains(node.getNodeRef()))
+ {
+ result = Application.getMessage(FacesContext.getCurrentInstance(), "yes");
+ }
+
+ return result;
+ }
+ }
}
diff --git a/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java b/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java
index b0c3fc53c9..cfe803bdef 100644
--- a/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java
+++ b/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java
@@ -87,12 +87,8 @@ public class StartWorkflowWizard extends BaseWizardBean
QName type = this.nodeService.getType(itemToWorkflow);
NodeRef workflowPackage = null;
- if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) ||
- this.dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDERLINK))
- {
- throw new UnsupportedOperationException("Workflow on a folder is not supported yet!");
- }
- else
+ if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) ||
+ this.dictionaryService.isSubClass(type, ContentModel.TYPE_FILELINK))
{
// create a workflow package and add the given item to workflow as a child
workflowPackage = this.workflowService.createPackage(null);
@@ -106,6 +102,13 @@ public class StartWorkflowWizard extends BaseWizardBean
params.put(WorkflowModel.ASSOC_PACKAGE, workflowPackage);
}
+ // setup the context for the workflow (this is the space the workflow was launched from)
+ Node workflowContext = this.navigator.getCurrentNode();
+ if (workflowContext != null)
+ {
+ params.put(WorkflowModel.PROP_CONTEXT, (Serializable)workflowContext.getNodeRef());
+ }
+
// start the workflow to get access to the start task
WorkflowPath path = this.workflowService.startWorkflow(this.selectedWorkflow, params);
if (path != null)
diff --git a/source/java/org/alfresco/web/bean/workflow/WorkflowBean.java b/source/java/org/alfresco/web/bean/workflow/WorkflowBean.java
index f5f487e4b6..4fc878221b 100644
--- a/source/java/org/alfresco/web/bean/workflow/WorkflowBean.java
+++ b/source/java/org/alfresco/web/bean/workflow/WorkflowBean.java
@@ -7,14 +7,18 @@ import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
+import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
+import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition;
import org.alfresco.service.cmr.workflow.WorkflowTaskState;
+import org.alfresco.service.cmr.workflow.WorkflowTransition;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ISO9075;
import org.alfresco.web.app.Application;
@@ -22,6 +26,7 @@ import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.TransientMapNode;
import org.alfresco.web.bean.repository.User;
+import org.alfresco.web.ui.common.Utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -32,6 +37,7 @@ import org.apache.commons.logging.LogFactory;
*/
public class WorkflowBean
{
+ protected NodeService nodeService;
protected WorkflowService workflowService;
protected List workItems;
protected List completedWorkItems;
@@ -50,19 +56,35 @@ public class WorkflowBean
public List getWorkItemsToDo()
{
// get the current username
- FacesContext fc = FacesContext.getCurrentInstance();
- User user = Application.getCurrentUser(fc);
+ FacesContext context = FacesContext.getCurrentInstance();
+ User user = Application.getCurrentUser(context);
String userName = ISO9075.encode(user.getUserName());
- // get the current in progress tasks for the current user
- List tasks = this.workflowService.getAssignedTasks(
- userName, WorkflowTaskState.IN_PROGRESS);
-
- // create a list of transient nodes to represent
- this.workItems = new ArrayList(tasks.size());
- for (WorkflowTask task : tasks)
+ UserTransaction tx = null;
+ try
{
- this.workItems.add(createWorkItem(task));
+ tx = Repository.getUserTransaction(context, true);
+ tx.begin();
+
+ // get the current in progress tasks for the current user
+ List tasks = this.workflowService.getAssignedTasks(
+ userName, WorkflowTaskState.IN_PROGRESS);
+
+ // create a list of transient nodes to represent
+ this.workItems = new ArrayList(tasks.size());
+ for (WorkflowTask task : tasks)
+ {
+ this.workItems.add(createWorkItem(task));
+ }
+
+ // commit the changes
+ tx.commit();
+ }
+ catch (Throwable e)
+ {
+ // rollback the transaction
+ try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
+ Utils.addErrorMessage("Failed to get to do work items: " + e.toString(), e);
}
return this.workItems;
@@ -77,19 +99,35 @@ public class WorkflowBean
public List getWorkItemsCompleted()
{
// get the current username
- FacesContext fc = FacesContext.getCurrentInstance();
- User user = Application.getCurrentUser(fc);
+ FacesContext context = FacesContext.getCurrentInstance();
+ User user = Application.getCurrentUser(context);
String userName = ISO9075.encode(user.getUserName());
- // get the current in progress tasks for the current user
- List tasks = this.workflowService.getAssignedTasks(
- userName, WorkflowTaskState.COMPLETED);
-
- // create a list of transient nodes to represent
- this.completedWorkItems = new ArrayList(tasks.size());
- for (WorkflowTask task : tasks)
+ UserTransaction tx = null;
+ try
{
- this.completedWorkItems.add(createWorkItem(task));
+ tx = Repository.getUserTransaction(context, true);
+ tx.begin();
+
+ // get the current in progress tasks for the current user
+ List tasks = this.workflowService.getAssignedTasks(
+ userName, WorkflowTaskState.COMPLETED);
+
+ // create a list of transient nodes to represent
+ this.completedWorkItems = new ArrayList(tasks.size());
+ for (WorkflowTask task : tasks)
+ {
+ this.completedWorkItems.add(createWorkItem(task));
+ }
+
+ // commit the changes
+ tx.commit();
+ }
+ catch (Throwable e)
+ {
+ // rollback the transaction
+ try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
+ Utils.addErrorMessage("Failed to get completed work items: " + e.toString(), e);
}
return this.completedWorkItems;
@@ -105,6 +143,16 @@ public class WorkflowBean
this.workflowService = workflowService;
}
+ /**
+ * Sets the node service to use
+ *
+ * @param nodeService NodeService instance
+ */
+ public void setNodeService(NodeService nodeService)
+ {
+ this.nodeService = nodeService;
+ }
+
// ------------------------------------------------------------------------------
// Helper methods
@@ -169,6 +217,50 @@ public class WorkflowBean
node.getProperties().put("type", taskDef.metadata.getTitle());
node.getProperties().put("id", task.id);
+ // add the name of the source space (if there is one)
+ // TODO: remove this workaroud where JBPM may return a String and not the NodeRef
+ Serializable obj = task.properties.get(WorkflowModel.PROP_CONTEXT);
+ NodeRef context = null;
+ if (obj instanceof NodeRef)
+ {
+ context = (NodeRef)obj;
+ }
+ else if (obj instanceof String)
+ {
+ context = new NodeRef((String)obj);
+ }
+
+ if (context != null)
+ {
+ String name = Repository.getNameForNode(this.nodeService, context);
+ node.getProperties().put("sourceSpaceName", name);
+ node.getProperties().put("sourceSpaceId", context.getId());
+ }
+
+ // add the outcome label for any completed task
+ if (task.state.equals(WorkflowTaskState.COMPLETED))
+ {
+ String outcome = null;
+ String transition = (String)task.properties.get(WorkflowModel.PROP_OUTCOME);
+ if (transition != null)
+ {
+ WorkflowTransition[] transitions = task.path.node.transitions;
+ for (WorkflowTransition trans : transitions)
+ {
+ if (trans.id.equals(transition))
+ {
+ outcome = trans.title;
+ break;
+ }
+ }
+
+ if (outcome != null)
+ {
+ node.getProperties().put("outcome", outcome);
+ }
+ }
+ }
+
return node;
}
}
diff --git a/source/web/WEB-INF/faces-config-beans.xml b/source/web/WEB-INF/faces-config-beans.xml
index 4f0504bcb6..e961805352 100644
--- a/source/web/WEB-INF/faces-config-beans.xml
+++ b/source/web/WEB-INF/faces-config-beans.xml
@@ -1785,6 +1785,10 @@
WorkflowBean
org.alfresco.web.bean.workflow.WorkflowBean
session
+
+ nodeService
+ #{NodeService}
+
workflowService
#{WorkflowService}
diff --git a/source/web/jsp/dashboards/container.jsp b/source/web/jsp/dashboards/container.jsp
index f5b8745a55..adc53b82af 100644
--- a/source/web/jsp/dashboards/container.jsp
+++ b/source/web/jsp/dashboards/container.jsp
@@ -100,6 +100,7 @@
+
diff --git a/source/web/jsp/workflow/manage-workitem-dialog.jsp b/source/web/jsp/workflow/manage-workitem-dialog.jsp
index f23dc7bfb8..77aae378b8 100644
--- a/source/web/jsp/workflow/manage-workitem-dialog.jsp
+++ b/source/web/jsp/workflow/manage-workitem-dialog.jsp
@@ -32,19 +32,21 @@
border="white" bgcolor="white" titleBorder="blue" titleBgcolor="#D3E6FE" styleClass="mainSubTitle">
-
- <%-- Primary column for details view mode --%>
-
+
+ <%-- Name column --%>
+
-
+
-
+
<%-- Description column --%>
@@ -60,19 +62,51 @@
-
+
+ <%-- Created Date column --%>
+
+
+
+
+
+
+
+
+
+ <%-- Modified Date column --%>
+
+
+
+
+
+
+
+
+
<%-- Actions column --%>
-
- <%-- actions are configured in web-client-config-actions.xml --%>
-
+
-
+ <%-- Completed column --%>
+ <%--
+
+
+
+
+
+
+
+
+ --%>
-
\ No newline at end of file
+
+ <%-- Put the package actions here --%>
+
+
diff --git a/source/web/jsp/workflow/start-workflow-wizard/workflow-options.jsp b/source/web/jsp/workflow/start-workflow-wizard/workflow-options.jsp
index ef6e0942ff..145307dc11 100644
--- a/source/web/jsp/workflow/start-workflow-wizard/workflow-options.jsp
+++ b/source/web/jsp/workflow/start-workflow-wizard/workflow-options.jsp
@@ -37,8 +37,10 @@
-
+
+
-
+
\ No newline at end of file
diff --git a/source/web/jsp/workflow/workitems-completed-dashlet.jsp b/source/web/jsp/workflow/workitems-completed-dashlet.jsp
index a8603f4d6b..67f437b03e 100644
--- a/source/web/jsp/workflow/workitems-completed-dashlet.jsp
+++ b/source/web/jsp/workflow/workitems-completed-dashlet.jsp
@@ -35,6 +35,14 @@
+ <%-- Source column --%>
+
+
+
+
+
+
+
<%-- Completed date column --%>
@@ -48,31 +56,19 @@
<%-- Outcome column --%>
-
+
-
+
<%-- Actions column --%>
- <%--
-
-
-
-
-
-
-
-
+
- --%>
diff --git a/source/web/jsp/workflow/workitems-todo-dashlet.jsp b/source/web/jsp/workflow/workitems-todo-dashlet.jsp
index 20c6d87b07..d8b406c7df 100644
--- a/source/web/jsp/workflow/workitems-todo-dashlet.jsp
+++ b/source/web/jsp/workflow/workitems-todo-dashlet.jsp
@@ -43,6 +43,14 @@
+ <%-- Source column --%>
+
+
+
+
+
+
+
<%-- Due date column --%>
@@ -61,26 +69,22 @@
+ <%-- Priority column --%>
+
+
+
+
+
+
+
<%-- Actions column --%>
- <%--
-
-
-
-
-
-
-
-
+
- --%>