diff --git a/config/alfresco/messages/webclient.properties b/config/alfresco/messages/webclient.properties index 30372cb8aa..f91123259c 100644 --- a/config/alfresco/messages/webclient.properties +++ b/config/alfresco/messages/webclient.properties @@ -93,7 +93,6 @@ no_categories_applied_space=This space does not yet have any categories applied. has_following_categories_space=This space has the following categories applied... moved=moved copied=copied -document_action=The document will be {0} to ''{1}'' if the ''{2}'' action is taken. clipboard=Clipboard recent_spaces=Recent Spaces shortcuts=Shortcuts @@ -155,6 +154,7 @@ move=Move type=Type aspect=Aspect workflow=Workflow +workflows=Workflows rules=Rules system_error=System Error login=Login @@ -521,7 +521,6 @@ custom_view=Custom View view_links=Links not_inline_editable=This document is not inline editable. allow_inline_editing=Allow Inline Editing -not_in_workflow=This document is not part of any workflow. not_in_category=This document is not categorized. not_in_category_space=This space is not categorized. not_versioned=This document has no version history. @@ -947,14 +946,24 @@ email_space_users=Email Space users email_space_users_desc=Send an email to the users and groups assigned to this space. # Workflow messages +doc_not_in_simple_workflow=This document is not part of a simple workflow. +space_not_in_simple_workflow=This space is not part of a simple workflow. +doc_not_in_advanced_workflow=This document is not part of any advanced workflows. +space_not_in_advanced_workflow=This space is not part of any advanced workflows. +simple_workflow=Simple Workflow +advanced_workflows=Advanced Workflows +document_action=The document will be {0} to ''{1}'' if the ''{2}'' action is taken. +space_action=The space will be {0} to ''{1}'' if the ''{2}'' action is taken. +doc_part_of_advanced_workflows=This document is part of the following advanced workflow(s) +space_part_of_advanced_workflows=This document is part of the following advanced workflow(s) modify_workflow_props=Modify Properties of Simple Workflow name_approve_step=Name for approve step name_reject_step=Name for reject step select_reject_step=Do you want to provide a reject step? choose_copy_move_location=Choose whether you want to move or copy the content and also the location. -start_workflow=Start Workflow -start_workflow_wizard=Start New Workflow Wizard -start_workflow_desc=This wizard helps you start a workflow for an item in the repository. +start_workflow=Start Advanced Workflow +start_workflow_wizard=Start Advanced Workflow Wizard +start_workflow_desc=This wizard helps you start an advanced workflow for an item in the repository. available_workflows=Available workflows step_choose_workflow=Choose Workflow start_workflow_choose_title=Choose Workflow @@ -1004,6 +1013,7 @@ save_changes=Save Changes no_tasks=No tasks found. no_resources=No resources found. in_progress=In Progress +by=by # Workflow Definitions wf_review_due_date=Review Due Date diff --git a/config/alfresco/web-client-config-actions.xml b/config/alfresco/web-client-config-actions.xml index 7249c970dd..48096f03a9 100644 --- a/config/alfresco/web-client-config-actions.xml +++ b/config/alfresco/web-client-config-actions.xml @@ -254,6 +254,54 @@ + + + org.alfresco.web.action.evaluator.ApproveDocEvaluator + + /images/icons/approve.gif + #{SpaceDetailsBean.approve} + browse + + #{actionContext.id} + + + + + + org.alfresco.web.action.evaluator.RejectDocEvaluator + + /images/icons/reject.gif + #{SpaceDetailsBean.reject} + browse + + #{actionContext.id} + + + + + + org.alfresco.web.action.evaluator.ApproveDocEvaluator + + /images/icons/approve.gif + #{SpaceDetailsBean.approve} + browse + + #{actionContext.id} + + + + + + org.alfresco.web.action.evaluator.RejectDocEvaluator + + /images/icons/reject.gif + #{SpaceDetailsBean.reject} + browse + + #{actionContext.id} + + + @@ -361,7 +409,7 @@ - Write + CreateChildren manage_rules /images/icons/rule.gif @@ -555,6 +603,8 @@ + + @@ -603,6 +653,8 @@ + + diff --git a/config/alfresco/web-client-config-dialogs.xml b/config/alfresco/web-client-config-dialogs.xml index b159613f6f..7066d147da 100644 --- a/config/alfresco/web-client-config-dialogs.xml +++ b/config/alfresco/web-client-config-dialogs.xml @@ -25,18 +25,18 @@ diff --git a/config/alfresco/web-client-config-properties.xml b/config/alfresco/web-client-config-properties.xml index 6df11f4d08..03729a181d 100644 --- a/config/alfresco/web-client-config-properties.xml +++ b/config/alfresco/web-client-config-properties.xml @@ -159,6 +159,12 @@ + + + + + + @@ -182,7 +188,7 @@ - + diff --git a/source/java/org/alfresco/web/action/evaluator/ApproveDocEvaluator.java b/source/java/org/alfresco/web/action/evaluator/ApproveDocEvaluator.java index caf3a15cd6..162653efc7 100644 --- a/source/java/org/alfresco/web/action/evaluator/ApproveDocEvaluator.java +++ b/source/java/org/alfresco/web/action/evaluator/ApproveDocEvaluator.java @@ -16,13 +16,11 @@ */ package org.alfresco.web.action.evaluator; -import org.alfresco.model.ContentModel; -import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.web.action.ActionEvaluator; import org.alfresco.web.bean.repository.Node; /** - * UI Action Evaluator - 'Approve' workflow step for document. + * UI Action Evaluator - 'Approve' workflow step for document or space. * * @author Kevin Roast */ diff --git a/source/java/org/alfresco/web/action/evaluator/RejectDocEvaluator.java b/source/java/org/alfresco/web/action/evaluator/RejectDocEvaluator.java index 17489475ff..687cb73df0 100644 --- a/source/java/org/alfresco/web/action/evaluator/RejectDocEvaluator.java +++ b/source/java/org/alfresco/web/action/evaluator/RejectDocEvaluator.java @@ -16,13 +16,11 @@ */ package org.alfresco.web.action.evaluator; -import org.alfresco.model.ContentModel; -import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.web.action.ActionEvaluator; import org.alfresco.web.bean.repository.Node; /** - * UI Action Evaluator - 'Reject' workflow step for document. + * UI Action Evaluator - 'Reject' workflow step for document or space. * * @author Kevin Roast */ diff --git a/source/java/org/alfresco/web/bean/BaseDetailsBean.java b/source/java/org/alfresco/web/bean/BaseDetailsBean.java index 763b1915a3..09d0b7b6bb 100644 --- a/source/java/org/alfresco/web/bean/BaseDetailsBean.java +++ b/source/java/org/alfresco/web/bean/BaseDetailsBean.java @@ -16,6 +16,7 @@ */ package org.alfresco.web.bean; +import java.io.Serializable; import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; @@ -25,16 +26,22 @@ import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; import javax.transaction.UserTransaction; +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.repository.CopyService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.TemplateImageResolver; import org.alfresco.service.cmr.security.OwnableService; +import org.alfresco.service.namespace.QName; import org.alfresco.web.app.Application; +import org.alfresco.web.app.context.UIContextService; +import org.alfresco.web.bean.actions.handlers.SimpleWorkflowHandler; import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.ui.common.Utils; import org.alfresco.web.ui.common.Utils.URLMode; +import org.alfresco.web.ui.common.component.UIActionLink; import org.alfresco.web.ui.common.component.UIPanel.ExpandedEvent; /** @@ -58,11 +65,27 @@ public abstract class BaseDetailsBean /** OwnableService bean reference */ protected OwnableService ownableService; + /** CopyService bean reference */ + protected CopyService copyService; + /** Selected template Id */ protected String template; + /** The map of workflow properties */ + protected Map workflowProperties; + protected Map panels = new HashMap(4, 1.0f); + private static final String MSG_ERROR_WORKFLOW_REJECT = "error_workflow_reject"; + private static final String MSG_ERROR_WORKFLOW_APPROVE = "error_workflow_approve"; + private static final String MSG_ERROR_UPDATE_SIMPLEWORKFLOW = "error_update_simpleworkflow"; + + public BaseDetailsBean() + { + // initial state of some panels that don't use the default + panels.put("workflow-panel", false); + panels.put("category-panel", false); + } // ------------------------------------------------------------------------------ // Bean property getters and setters @@ -103,6 +126,16 @@ public abstract class BaseDetailsBean this.ownableService = ownableService; } + /** + * Sets the copy service instance the bean should use + * + * @param copyService The CopyService + */ + public void setCopyService(CopyService copyService) + { + this.copyService = copyService; + } + /** * @return Returns the panels expanded state map. */ @@ -249,6 +282,302 @@ public abstract class BaseDetailsBean } }; + /** + * Returns the properties for the attached workflow as a map + * + * @return Properties of the attached workflow, null if there is no workflow + */ + public Map getWorkflowProperties() + { + if (this.workflowProperties == null && + getNode().hasAspect(ContentModel.ASPECT_SIMPLE_WORKFLOW)) + { + // get the exisiting properties for the document + Map props = getNode().getProperties(); + + String approveStepName = (String)props.get( + ContentModel.PROP_APPROVE_STEP.toString()); + String rejectStepName = (String)props.get( + ContentModel.PROP_REJECT_STEP.toString()); + + Boolean approveMove = (Boolean)props.get( + ContentModel.PROP_APPROVE_MOVE.toString()); + Boolean rejectMove = (Boolean)props.get( + ContentModel.PROP_REJECT_MOVE.toString()); + + NodeRef approveFolder = (NodeRef)props.get( + ContentModel.PROP_APPROVE_FOLDER.toString()); + NodeRef rejectFolder = (NodeRef)props.get( + ContentModel.PROP_REJECT_FOLDER.toString()); + + // put the workflow properties in a separate map for use by the JSP + this.workflowProperties = new HashMap(7); + this.workflowProperties.put(SimpleWorkflowHandler.PROP_APPROVE_STEP_NAME, + approveStepName); + this.workflowProperties.put(SimpleWorkflowHandler.PROP_APPROVE_ACTION, + approveMove ? "move" : "copy"); + this.workflowProperties.put(SimpleWorkflowHandler.PROP_APPROVE_FOLDER, approveFolder); + + if (rejectStepName == null || rejectMove == null || rejectFolder == null) + { + this.workflowProperties.put(SimpleWorkflowHandler.PROP_REJECT_STEP_PRESENT, "no"); + } + else + { + this.workflowProperties.put(SimpleWorkflowHandler.PROP_REJECT_STEP_PRESENT, + "yes"); + this.workflowProperties.put(SimpleWorkflowHandler.PROP_REJECT_STEP_NAME, + rejectStepName); + this.workflowProperties.put(SimpleWorkflowHandler.PROP_REJECT_ACTION, + rejectMove ? "move" : "copy"); + this.workflowProperties.put(SimpleWorkflowHandler.PROP_REJECT_FOLDER, + rejectFolder); + } + } + + return this.workflowProperties; + } + + /** + * Cancel Workflow Edit dialog + */ + public String cancelWorkflowEdit() + { + // resets the workflow properties map so any changes made + // don't appear to be persisted + this.workflowProperties.clear(); + this.workflowProperties = null; + return "cancel"; + } + + /** + * Saves the details of the workflow stored in workflowProperties + * to the current document + * + * @return The outcome string + */ + public String saveWorkflow() + { + String outcome = "cancel"; + + UserTransaction tx = null; + + try + { + tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); + tx.begin(); + + // firstly retrieve all the properties for the current node + Map updateProps = this.nodeService.getProperties( + getNode().getNodeRef()); + + // update the simple workflow properties + + // set the approve step name + updateProps.put(ContentModel.PROP_APPROVE_STEP, + this.workflowProperties.get(SimpleWorkflowHandler.PROP_APPROVE_STEP_NAME)); + + // specify whether the approve step will copy or move the content + boolean approveMove = true; + String approveAction = (String)this.workflowProperties.get(SimpleWorkflowHandler.PROP_APPROVE_ACTION); + if (approveAction != null && approveAction.equals("copy")) + { + approveMove = false; + } + updateProps.put(ContentModel.PROP_APPROVE_MOVE, Boolean.valueOf(approveMove)); + + // create node ref representation of the destination folder + updateProps.put(ContentModel.PROP_APPROVE_FOLDER, + this.workflowProperties.get(SimpleWorkflowHandler.PROP_APPROVE_FOLDER)); + + // determine whether there should be a reject step + boolean requireReject = true; + String rejectStepPresent = (String)this.workflowProperties.get( + SimpleWorkflowHandler.PROP_REJECT_STEP_PRESENT); + if (rejectStepPresent != null && rejectStepPresent.equals("no")) + { + requireReject = false; + } + + if (requireReject) + { + // set the reject step name + updateProps.put(ContentModel.PROP_REJECT_STEP, + this.workflowProperties.get(SimpleWorkflowHandler.PROP_REJECT_STEP_NAME)); + + // specify whether the reject step will copy or move the content + boolean rejectMove = true; + String rejectAction = (String)this.workflowProperties.get( + SimpleWorkflowHandler.PROP_REJECT_ACTION); + if (rejectAction != null && rejectAction.equals("copy")) + { + rejectMove = false; + } + updateProps.put(ContentModel.PROP_REJECT_MOVE, Boolean.valueOf(rejectMove)); + + // create node ref representation of the destination folder + updateProps.put(ContentModel.PROP_REJECT_FOLDER, + this.workflowProperties.get(SimpleWorkflowHandler.PROP_REJECT_FOLDER)); + } + else + { + // set all the reject properties to null to signify there should + // be no reject step + updateProps.put(ContentModel.PROP_REJECT_STEP, null); + updateProps.put(ContentModel.PROP_REJECT_MOVE, null); + updateProps.put(ContentModel.PROP_REJECT_FOLDER, null); + } + + // set the properties on the node + this.nodeService.setProperties(getNode().getNodeRef(), updateProps); + + // commit the transaction + tx.commit(); + + // reset the state of the current document so it reflects the changes just made + getNode().reset(); + + outcome = "finish"; + } + catch (Throwable e) + { + try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} + Utils.addErrorMessage(MessageFormat.format(Application.getMessage( + FacesContext.getCurrentInstance(), MSG_ERROR_UPDATE_SIMPLEWORKFLOW), e.getMessage()), e); + } + + return outcome; + } + + /** + * Returns the name of the approve step of the attached workflow + * + * @return The name of the approve step or null if there is no workflow + */ + public String getApproveStepName() + { + String approveStepName = null; + + if (getNode().hasAspect(ContentModel.ASPECT_SIMPLE_WORKFLOW)) + { + approveStepName = (String)getNode().getProperties().get( + ContentModel.PROP_APPROVE_STEP.toString()); + } + + return approveStepName; + } + + /** + * Event handler called to handle the approve step of the simple workflow + * + * @param event The event that was triggered + */ + public void approve(ActionEvent event) + { + UIActionLink link = (UIActionLink)event.getComponent(); + Map params = link.getParameterMap(); + String id = params.get("id"); + if (id == null || id.length() == 0) + { + throw new AlfrescoRuntimeException("approve called without an id"); + } + + NodeRef docNodeRef = new NodeRef(Repository.getStoreRef(), id); + + UserTransaction tx = null; + try + { + tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); + tx.begin(); + + // call the service to perform the approve + WorkflowUtil.approve(docNodeRef, this.nodeService, this.copyService); + + // commit the transaction + tx.commit(); + + // if this was called via the document details dialog we need to reset the document node + if (getNode() != null) + { + getNode().reset(); + } + + // also make sure the UI will get refreshed + UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans(); + } + catch (Throwable e) + { + // rollback the transaction + try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} + Utils.addErrorMessage(MessageFormat.format(Application.getMessage( + FacesContext.getCurrentInstance(), MSG_ERROR_WORKFLOW_APPROVE), e.getMessage()), e); + } + } + + /** + * Returns the name of the reject step of the attached workflow + * + * @return The name of the reject step or null if there is no workflow + */ + public String getRejectStepName() + { + String approveStepName = null; + + if (getNode().hasAspect(ContentModel.ASPECT_SIMPLE_WORKFLOW)) + { + approveStepName = (String)getNode().getProperties().get( + ContentModel.PROP_REJECT_STEP.toString()); + } + + return approveStepName; + } + + /** + * Event handler called to handle the approve step of the simple workflow + * + * @param event The event that was triggered + */ + public void reject(ActionEvent event) + { + UIActionLink link = (UIActionLink)event.getComponent(); + Map params = link.getParameterMap(); + String id = params.get("id"); + if (id == null || id.length() == 0) + { + throw new AlfrescoRuntimeException("reject called without an id"); + } + + NodeRef docNodeRef = new NodeRef(Repository.getStoreRef(), id); + + UserTransaction tx = null; + try + { + tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); + tx.begin(); + + // call the service to perform the reject + WorkflowUtil.reject(docNodeRef, this.nodeService, this.copyService); + + // commit the transaction + tx.commit(); + + // if this was called via the document details dialog we need to reset the document node + if (getNode() != null) + { + getNode().reset(); + } + + // also make sure the UI will get refreshed + UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans(); + } + catch (Throwable e) + { + // rollback the transaction + try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} + Utils.addErrorMessage(MessageFormat.format(Application.getMessage( + FacesContext.getCurrentInstance(), MSG_ERROR_WORKFLOW_REJECT), e.getMessage()), e); + } + } // ------------------------------------------------------------------------------ // Action event handlers diff --git a/source/java/org/alfresco/web/bean/DocumentDetailsBean.java b/source/java/org/alfresco/web/bean/DocumentDetailsBean.java index 6d8c5eba3a..2659a3009c 100644 --- a/source/java/org/alfresco/web/bean/DocumentDetailsBean.java +++ b/source/java/org/alfresco/web/bean/DocumentDetailsBean.java @@ -29,13 +29,11 @@ import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; import javax.transaction.UserTransaction; -import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.alfresco.service.cmr.lock.LockService; import org.alfresco.service.cmr.repository.ContentData; -import org.alfresco.service.cmr.repository.CopyService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.TemplateNode; import org.alfresco.service.cmr.version.Version; @@ -43,9 +41,7 @@ import org.alfresco.service.cmr.version.VersionHistory; import org.alfresco.service.cmr.version.VersionService; import org.alfresco.service.namespace.QName; import org.alfresco.web.app.Application; -import org.alfresco.web.app.context.UIContextService; import org.alfresco.web.app.servlet.DownloadContentServlet; -import org.alfresco.web.bean.actions.handlers.SimpleWorkflowHandler; import org.alfresco.web.bean.repository.MapNode; import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Repository; @@ -68,17 +64,12 @@ public class DocumentDetailsBean extends BaseDetailsBean private static final String MSG_ERROR_ASPECT_INLINEEDITABLE = "error_aspect_inlineeditable"; private static final String MSG_ERROR_ASPECT_VERSIONING = "error_aspect_versioning"; private static final String MSG_ERROR_ASPECT_CLASSIFY = "error_aspect_classify"; - private static final String MSG_ERROR_WORKFLOW_REJECT = "error_workflow_reject"; - private static final String MSG_ERROR_WORKFLOW_APPROVE = "error_workflow_approve"; - private static final String MSG_ERROR_UPDATE_SIMPLEWORKFLOW = "error_update_simpleworkflow"; private static final String MSG_ERROR_UPDATE_CATEGORY = "error_update_category"; protected LockService lockService; - protected CopyService copyService; protected VersionService versionService; protected CheckOutCheckInService cociService; - private Map workflowProperties; private NodeRef addedCategory; private List categories; @@ -91,9 +82,9 @@ public class DocumentDetailsBean extends BaseDetailsBean */ public DocumentDetailsBean() { + super(); + // initial state of some panels that don't use the default - panels.put("workflow-panel", false); - panels.put("category-panel", false); panels.put("version-history-panel", false); } @@ -369,391 +360,6 @@ public class DocumentDetailsBean extends BaseDetailsBean return outcome; } - /** - * Returns an overview summary of the current state of the attached - * workflow (if any) - * - * @return Summary HTML - */ - public String getWorkflowOverviewHTML() - { - String html = null; - - if (getDocument().hasAspect(ContentModel.ASPECT_SIMPLE_WORKFLOW)) - { - // get the simple workflow aspect properties - Map props = getDocument().getProperties(); - - String approveStepName = (String)props.get( - ContentModel.PROP_APPROVE_STEP.toString()); - String rejectStepName = (String)props.get( - ContentModel.PROP_REJECT_STEP.toString()); - - Boolean approveMove = (Boolean)props.get( - ContentModel.PROP_APPROVE_MOVE.toString()); - Boolean rejectMove = (Boolean)props.get( - ContentModel.PROP_REJECT_MOVE.toString()); - - NodeRef approveFolder = (NodeRef)props.get( - ContentModel.PROP_APPROVE_FOLDER.toString()); - NodeRef rejectFolder = (NodeRef)props.get( - ContentModel.PROP_REJECT_FOLDER.toString()); - - String approveFolderName = null; - String rejectFolderName = null; - - // get the approve folder name - if (approveFolder != null) - { - Node node = new Node(approveFolder); - approveFolderName = node.getName(); - } - - // get the reject folder name - if (rejectFolder != null) - { - Node node = new Node(rejectFolder); - rejectFolderName = node.getName(); - } - - StringBuilder builder = new StringBuilder(); - - // calculate the approve action string - String action = null; - if (approveMove.booleanValue()) - { - action = Application.getMessage(FacesContext.getCurrentInstance(), "moved"); - } - else - { - action = Application.getMessage(FacesContext.getCurrentInstance(), "copied"); - } - - String docActionPattern = Application.getMessage(FacesContext.getCurrentInstance(), "document_action"); - Object[] params = new Object[] {action, approveFolderName, approveStepName}; - builder.append(MessageFormat.format(docActionPattern, params)); - - // add details of the reject step if there is one - if (rejectStepName != null && rejectMove != null && rejectFolderName != null) - { - if (rejectMove.booleanValue()) - { - action = Application.getMessage(FacesContext.getCurrentInstance(), "moved"); - } - else - { - action = Application.getMessage(FacesContext.getCurrentInstance(), "copied"); - } - - builder.append("

"); - params = new Object[] {action, rejectFolderName, rejectStepName}; - builder.append(MessageFormat.format(docActionPattern, params)); - builder.append("

"); - } - - html = builder.toString(); - } - - return html; - } - - /** - * Returns the properties for the attached workflow as a map - * - * @return Properties of the attached workflow, null if there is no workflow - */ - public Map getWorkflowProperties() - { - if (this.workflowProperties == null && - getDocument().hasAspect(ContentModel.ASPECT_SIMPLE_WORKFLOW)) - { - // get the exisiting properties for the document - Map props = getDocument().getProperties(); - - String approveStepName = (String)props.get( - ContentModel.PROP_APPROVE_STEP.toString()); - String rejectStepName = (String)props.get( - ContentModel.PROP_REJECT_STEP.toString()); - - Boolean approveMove = (Boolean)props.get( - ContentModel.PROP_APPROVE_MOVE.toString()); - Boolean rejectMove = (Boolean)props.get( - ContentModel.PROP_REJECT_MOVE.toString()); - - NodeRef approveFolder = (NodeRef)props.get( - ContentModel.PROP_APPROVE_FOLDER.toString()); - NodeRef rejectFolder = (NodeRef)props.get( - ContentModel.PROP_REJECT_FOLDER.toString()); - - // put the workflow properties in a separate map for use by the JSP - this.workflowProperties = new HashMap(7); - this.workflowProperties.put(SimpleWorkflowHandler.PROP_APPROVE_STEP_NAME, - approveStepName); - this.workflowProperties.put(SimpleWorkflowHandler.PROP_APPROVE_ACTION, - approveMove ? "move" : "copy"); - this.workflowProperties.put(SimpleWorkflowHandler.PROP_APPROVE_FOLDER, approveFolder); - - if (rejectStepName == null || rejectMove == null || rejectFolder == null) - { - this.workflowProperties.put(SimpleWorkflowHandler.PROP_REJECT_STEP_PRESENT, "no"); - } - else - { - this.workflowProperties.put(SimpleWorkflowHandler.PROP_REJECT_STEP_PRESENT, - "yes"); - this.workflowProperties.put(SimpleWorkflowHandler.PROP_REJECT_STEP_NAME, - rejectStepName); - this.workflowProperties.put(SimpleWorkflowHandler.PROP_REJECT_ACTION, - rejectMove ? "move" : "copy"); - this.workflowProperties.put(SimpleWorkflowHandler.PROP_REJECT_FOLDER, - rejectFolder); - } - } - - return this.workflowProperties; - } - - /** - * Cancel Workflow Edit dialog - */ - public String cancelWorkflowEdit() - { - // resets the workflow properties map so any changes made - // don't appear to be persisted - this.workflowProperties.clear(); - this.workflowProperties = null; - return "cancel"; - } - - /** - * Saves the details of the workflow stored in workflowProperties - * to the current document - * - * @return The outcome string - */ - public String saveWorkflow() - { - String outcome = "cancel"; - - UserTransaction tx = null; - - try - { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - // firstly retrieve all the properties for the current node - Map updateProps = this.nodeService.getProperties( - getDocument().getNodeRef()); - - // update the simple workflow properties - - // set the approve step name - updateProps.put(ContentModel.PROP_APPROVE_STEP, - this.workflowProperties.get(SimpleWorkflowHandler.PROP_APPROVE_STEP_NAME)); - - // specify whether the approve step will copy or move the content - boolean approveMove = true; - String approveAction = (String)this.workflowProperties.get(SimpleWorkflowHandler.PROP_APPROVE_ACTION); - if (approveAction != null && approveAction.equals("copy")) - { - approveMove = false; - } - updateProps.put(ContentModel.PROP_APPROVE_MOVE, Boolean.valueOf(approveMove)); - - // create node ref representation of the destination folder - updateProps.put(ContentModel.PROP_APPROVE_FOLDER, - this.workflowProperties.get(SimpleWorkflowHandler.PROP_APPROVE_FOLDER)); - - // determine whether there should be a reject step - boolean requireReject = true; - String rejectStepPresent = (String)this.workflowProperties.get( - SimpleWorkflowHandler.PROP_REJECT_STEP_PRESENT); - if (rejectStepPresent != null && rejectStepPresent.equals("no")) - { - requireReject = false; - } - - if (requireReject) - { - // set the reject step name - updateProps.put(ContentModel.PROP_REJECT_STEP, - this.workflowProperties.get(SimpleWorkflowHandler.PROP_REJECT_STEP_NAME)); - - // specify whether the reject step will copy or move the content - boolean rejectMove = true; - String rejectAction = (String)this.workflowProperties.get( - SimpleWorkflowHandler.PROP_REJECT_ACTION); - if (rejectAction != null && rejectAction.equals("copy")) - { - rejectMove = false; - } - updateProps.put(ContentModel.PROP_REJECT_MOVE, Boolean.valueOf(rejectMove)); - - // create node ref representation of the destination folder - updateProps.put(ContentModel.PROP_REJECT_FOLDER, - this.workflowProperties.get(SimpleWorkflowHandler.PROP_REJECT_FOLDER)); - } - else - { - // set all the reject properties to null to signify there should - // be no reject step - updateProps.put(ContentModel.PROP_REJECT_STEP, null); - updateProps.put(ContentModel.PROP_REJECT_MOVE, null); - updateProps.put(ContentModel.PROP_REJECT_FOLDER, null); - } - - // set the properties on the node - this.nodeService.setProperties(getDocument().getNodeRef(), updateProps); - - // commit the transaction - tx.commit(); - - // reset the state of the current document so it reflects the changes just made - getDocument().reset(); - - outcome = "finish"; - } - catch (Throwable e) - { - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} - Utils.addErrorMessage(MessageFormat.format(Application.getMessage( - FacesContext.getCurrentInstance(), MSG_ERROR_UPDATE_SIMPLEWORKFLOW), e.getMessage()), e); - } - - return outcome; - } - - /** - * Returns the name of the approve step of the attached workflow - * - * @return The name of the approve step or null if there is no workflow - */ - public String getApproveStepName() - { - String approveStepName = null; - - if (getDocument().hasAspect(ContentModel.ASPECT_SIMPLE_WORKFLOW)) - { - approveStepName = (String)getDocument().getProperties().get( - ContentModel.PROP_APPROVE_STEP.toString()); - } - - return approveStepName; - } - - /** - * Event handler called to handle the approve step of the simple workflow - * - * @param event The event that was triggered - */ - public void approve(ActionEvent event) - { - UIActionLink link = (UIActionLink)event.getComponent(); - Map params = link.getParameterMap(); - String id = params.get("id"); - if (id == null || id.length() == 0) - { - throw new AlfrescoRuntimeException("approve called without an id"); - } - - NodeRef docNodeRef = new NodeRef(Repository.getStoreRef(), id); - - UserTransaction tx = null; - try - { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - // call the service to perform the approve - WorkflowUtil.approve(docNodeRef, this.nodeService, this.copyService); - - // commit the transaction - tx.commit(); - - // if this was called via the document details dialog we need to reset the document node - if (getDocument() != null) - { - getDocument().reset(); - } - - // also make sure the UI will get refreshed - UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans(); - } - catch (Throwable e) - { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} - Utils.addErrorMessage(MessageFormat.format(Application.getMessage( - FacesContext.getCurrentInstance(), MSG_ERROR_WORKFLOW_APPROVE), e.getMessage()), e); - } - } - - /** - * Returns the name of the reject step of the attached workflow - * - * @return The name of the reject step or null if there is no workflow - */ - public String getRejectStepName() - { - String approveStepName = null; - - if (getDocument().hasAspect(ContentModel.ASPECT_SIMPLE_WORKFLOW)) - { - approveStepName = (String)getDocument().getProperties().get( - ContentModel.PROP_REJECT_STEP.toString()); - } - - return approveStepName; - } - - /** - * Event handler called to handle the approve step of the simple workflow - * - * @param event The event that was triggered - */ - public void reject(ActionEvent event) - { - UIActionLink link = (UIActionLink)event.getComponent(); - Map params = link.getParameterMap(); - String id = params.get("id"); - if (id == null || id.length() == 0) - { - throw new AlfrescoRuntimeException("reject called without an id"); - } - - NodeRef docNodeRef = new NodeRef(Repository.getStoreRef(), id); - - UserTransaction tx = null; - try - { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - // call the service to perform the reject - WorkflowUtil.reject(docNodeRef, this.nodeService, this.copyService); - - // commit the transaction - tx.commit(); - - // if this was called via the document details dialog we need to reset the document node - if (getDocument() != null) - { - getDocument().reset(); - } - - // also make sure the UI will get refreshed - UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans(); - } - catch (Throwable e) - { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} - Utils.addErrorMessage(MessageFormat.format(Application.getMessage( - FacesContext.getCurrentInstance(), MSG_ERROR_WORKFLOW_REJECT), e.getMessage()), e); - } - } - /** * Applies the classifiable aspect to the current document */ @@ -1099,16 +705,6 @@ public class DocumentDetailsBean extends BaseDetailsBean this.versionService = versionService; } - /** - * Sets the copy service instance the bean should use - * - * @param copyService The CopyService - */ - public void setCopyService(CopyService copyService) - { - this.copyService = copyService; - } - /** * Sets the checkincheckout service instance the bean should use * diff --git a/source/java/org/alfresco/web/bean/SpaceDetailsBean.java b/source/java/org/alfresco/web/bean/SpaceDetailsBean.java index 2f5f053b00..39b0793ad3 100644 --- a/source/java/org/alfresco/web/bean/SpaceDetailsBean.java +++ b/source/java/org/alfresco/web/bean/SpaceDetailsBean.java @@ -71,6 +71,8 @@ public class SpaceDetailsBean extends BaseDetailsBean */ public SpaceDetailsBean() { + super(); + // initial state of some panels that don't use the default panels.put("rules-panel", false); panels.put("dashboard-panel", false); diff --git a/source/java/org/alfresco/web/bean/WorkflowUtil.java b/source/java/org/alfresco/web/bean/WorkflowUtil.java index 8f8ed9077d..fa57b332d7 100644 --- a/source/java/org/alfresco/web/bean/WorkflowUtil.java +++ b/source/java/org/alfresco/web/bean/WorkflowUtil.java @@ -55,7 +55,7 @@ public class WorkflowUtil if (docNode.hasAspect(ContentModel.ASPECT_SIMPLE_WORKFLOW) == false) { - throw new AlfrescoRuntimeException("Cannot approve a document that is not part of a workflow."); + throw new AlfrescoRuntimeException("Cannot approve a node that is not part of a workflow."); } // get the simple workflow aspect properties @@ -69,23 +69,28 @@ public class WorkflowUtil if (approveMove.booleanValue()) { - // move the document to the specified folder + // move the node to the specified folder String qname = QName.createValidLocalName(docNode.getName()); nodeService.moveNode(ref, approveFolder, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, qname)); } else { - // copy the document to the specified folder - String qname = QName.createValidLocalName(docNode.getName()); - copyService.copy(ref, approveFolder, ContentModel.ASSOC_CONTAINS, - QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, qname)); + // copy the node to the specified folder + String name = docNode.getName(); + String qname = QName.createValidLocalName(name); + NodeRef newNode = copyService.copy(ref, approveFolder, ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, qname), true); + + // the copy service does not copy the name of the node so we + // need to update the property on the copied item + nodeService.setProperty(newNode, ContentModel.PROP_NAME, name); } if (logger.isDebugEnabled()) { String movedCopied = approveMove ? "moved" : "copied"; - logger.debug("Document has been approved and " + movedCopied + " to folder with id of " + + logger.debug("Node has been approved and " + movedCopied + " to folder with id of " + approveFolder.getId()); } } @@ -106,7 +111,7 @@ public class WorkflowUtil if (docNode.hasAspect(ContentModel.ASPECT_SIMPLE_WORKFLOW) == false) { - throw new AlfrescoRuntimeException("Cannot reject a document that is not part of a workflow."); + throw new AlfrescoRuntimeException("Cannot reject a node that is not part of a workflow."); } // get the simple workflow aspect properties @@ -118,7 +123,7 @@ public class WorkflowUtil if (rejectStep == null && rejectMove == null && rejectFolder == null) { - throw new AlfrescoRuntimeException("The workflow does not have a reject step defined,"); + throw new AlfrescoRuntimeException("The workflow does not have a reject step defined."); } // first we need to take off the simpleworkflow aspect @@ -142,7 +147,7 @@ public class WorkflowUtil if (logger.isDebugEnabled()) { String movedCopied = rejectMove ? "moved" : "copied"; - logger.debug("Document has been rejected and " + movedCopied + " to folder with id of " + + logger.debug("Node has been rejected and " + movedCopied + " to folder with id of " + rejectFolder.getId()); } } diff --git a/source/java/org/alfresco/web/bean/workflow/ReassignTaskDialog.java b/source/java/org/alfresco/web/bean/workflow/ReassignTaskDialog.java index b3077cfd57..7f6a72ee46 100644 --- a/source/java/org/alfresco/web/bean/workflow/ReassignTaskDialog.java +++ b/source/java/org/alfresco/web/bean/workflow/ReassignTaskDialog.java @@ -15,6 +15,10 @@ import javax.transaction.UserTransaction; import org.alfresco.model.ContentModel; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.SearchParameters; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.namespace.NamespaceService; @@ -137,12 +141,13 @@ public class ReassignTaskDialog extends BaseDialogBean { tx = Repository.getUserTransaction(context, true); tx.begin(); - + // build xpath to match available User/Person objects NodeRef peopleRef = personService.getPeopleContainer(); // NOTE: see SearcherComponentTest - String xpath = "*[like(@" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + "firstName, '%" + contains + "%', false)" + - " or " + "like(@" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + "lastName, '%" + contains + "%', false)]"; + String xpath = "*[not(@" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + "userName='guest') and " + + "(like(@" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + "firstName, '%" + contains + "%', false)" + + " or " + "like(@" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + "lastName, '%" + contains + "%', false))]"; List nodes = searchService.selectNodes( peopleRef, diff --git a/source/java/org/alfresco/web/ui/repo/component/UINodeWorkflowInfo.java b/source/java/org/alfresco/web/ui/repo/component/UINodeWorkflowInfo.java new file mode 100644 index 0000000000..92f36fcdfb --- /dev/null +++ b/source/java/org/alfresco/web/ui/repo/component/UINodeWorkflowInfo.java @@ -0,0 +1,349 @@ +package org.alfresco.web.ui.repo.component; + +import java.io.IOException; +import java.text.MessageFormat; +import java.text.SimpleDateFormat; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; + +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import javax.faces.el.ValueBinding; + +import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.workflow.WorkflowInstance; +import org.alfresco.service.cmr.workflow.WorkflowService; +import org.alfresco.service.namespace.QName; +import org.alfresco.web.app.Application; +import org.alfresco.web.bean.repository.Node; +import org.alfresco.web.bean.repository.Repository; +import org.alfresco.web.ui.common.component.SelfRenderingComponent; + +/** + * JSF component that displays information about the workflows a node is involved in. + *

+ * The node to show workflow information on. + * + * @author gavinc + */ +public class UINodeWorkflowInfo extends SelfRenderingComponent +{ + protected Node value = null; + + // ------------------------------------------------------------------------------ + // Component Impl + + @Override + public String getFamily() + { + return "org.alfresco.faces.NodeWorkflowInfo"; + } + + @Override + public void restoreState(FacesContext context, Object state) + { + Object values[] = (Object[])state; + // standard component attributes are restored by the super class + super.restoreState(context, values[0]); + this.value = (Node)values[1]; + } + + @Override + public Object saveState(FacesContext context) + { + Object values[] = new Object[8]; + // standard component attributes are saved by the super class + values[0] = super.saveState(context); + values[1] = this.value; + return values; + } + + @Override + @SuppressWarnings("unchecked") + public void encodeBegin(FacesContext context) throws IOException + { + if (!isRendered()) return; + + // get the node to display the information for + Node node = getValue(); + + if (node != null) + { + // get the services we need + NodeService nodeService = Repository.getServiceRegistry(context).getNodeService(); + DictionaryService ddService = Repository.getServiceRegistry(context).getDictionaryService(); + WorkflowService workflowService = Repository.getServiceRegistry(context).getWorkflowService(); + ResponseWriter out = context.getResponseWriter(); + ResourceBundle bundle = Application.getBundle(context); + + // render simple workflow info + renderSimpleWorkflowInfo(context, node, nodeService, ddService, out, bundle); + + // render advanced workflow info + renderAdvancedWorkflowInfo(context, node, nodeService, ddService, workflowService, out, bundle); + } + } + + @Override + public void encodeEnd(FacesContext context) throws IOException + { + if (!isRendered()) return; + } + + // ------------------------------------------------------------------------------ + // Strongly typed component property accessors + + /** + * Get the value, this will be a node representing a piece of content or a space + * + * @return the value + */ + public Node getValue() + { + ValueBinding vb = getValueBinding("value"); + if (vb != null) + { + this.value = (Node)vb.getValue(getFacesContext()); + } + + return this.value; + } + + /** + * Set the value, either a space or content node. + * + * @param value the value + */ + public void setValue(Node value) + { + this.value = value; + } + + // ------------------------------------------------------------------------------ + // Helper methods + + /** + * Renders the simple workflow details for the given node. + * + * @param context Faces context + * @param node The node + * @param nodeService The NodeService instance + * @param ddService The Data Dictionary instance + * @param out The response writer + * @param bundle Message bundle to get strings from + */ + protected void renderSimpleWorkflowInfo(FacesContext context, Node node, + NodeService nodeService, DictionaryService ddService, + ResponseWriter out, ResourceBundle bundle) + throws IOException + { + boolean isContent = true; + + QName type = nodeService.getType(node.getNodeRef()); + if (ddService.isSubClass(type, ContentModel.TYPE_FOLDER)) + { + isContent = false; + } + + // Render HTML for simple workflow + if (isContent) + { + // TODO: for now we only support advanced workflow on content so only + // render the simple workflow title if the node is a content node + out.write("

"); + out.write(bundle.getString("simple_workflow")); + out.write("
"); + } + out.write("
"); + + if (node.hasAspect(ContentModel.ASPECT_SIMPLE_WORKFLOW)) + { + // get the simple workflow aspect properties + Map props = node.getProperties(); + + String approveStepName = (String)props.get( + ContentModel.PROP_APPROVE_STEP.toString()); + String rejectStepName = (String)props.get( + ContentModel.PROP_REJECT_STEP.toString()); + + Boolean approveMove = (Boolean)props.get( + ContentModel.PROP_APPROVE_MOVE.toString()); + Boolean rejectMove = (Boolean)props.get( + ContentModel.PROP_REJECT_MOVE.toString()); + + NodeRef approveFolder = (NodeRef)props.get( + ContentModel.PROP_APPROVE_FOLDER.toString()); + NodeRef rejectFolder = (NodeRef)props.get( + ContentModel.PROP_REJECT_FOLDER.toString()); + + String approveFolderName = null; + String rejectFolderName = null; + + // get the approve folder name + if (approveFolder != null) + { + Node approveNode = new Node(approveFolder); + approveFolderName = approveNode.getName(); + } + + // get the reject folder name + if (rejectFolder != null) + { + Node rejectNode = new Node(rejectFolder); + rejectFolderName = rejectNode.getName(); + } + + // calculate the approve action string + String action = null; + if (approveMove.booleanValue()) + { + action = Application.getMessage(FacesContext.getCurrentInstance(), "moved"); + } + else + { + action = Application.getMessage(FacesContext.getCurrentInstance(), "copied"); + } + + String actionPattern = null; + if (isContent) + { + actionPattern = Application.getMessage(FacesContext.getCurrentInstance(), "document_action"); + } + else + { + actionPattern = Application.getMessage(FacesContext.getCurrentInstance(), "space_action"); + } + Object[] params = new Object[] {action, approveFolderName, approveStepName}; + out.write(MessageFormat.format(actionPattern, params)); + + // add details of the reject step if there is one + if (rejectStepName != null && rejectMove != null && rejectFolderName != null) + { + if (rejectMove.booleanValue()) + { + action = Application.getMessage(FacesContext.getCurrentInstance(), "moved"); + } + else + { + action = Application.getMessage(FacesContext.getCurrentInstance(), "copied"); + } + + out.write(" "); + params = new Object[] {action, rejectFolderName, rejectStepName}; + out.write(MessageFormat.format(actionPattern, params)); + } + } + else + { + // work out which no workflow message to show depending on the node type + if (isContent) + { + out.write(bundle.getString("doc_not_in_simple_workflow")); + } + else + { + out.write(bundle.getString("space_not_in_simple_workflow")); + } + } + out.write("
"); + } + + /** + * Renders the advanced workflow details for the given node. + * + * @param context Faces context + * @param node The node + * @param nodeService The NodeService instance + * @param ddService The Data Dictionary instance + * @param workflowService The WorkflowService instance + * @param out The response writer + * @param bundle Message bundle to get strings from + */ + protected void renderAdvancedWorkflowInfo(FacesContext context, Node node, + NodeService nodeService, DictionaryService ddService, WorkflowService workflowService, + ResponseWriter out, ResourceBundle bundle) + throws IOException + { + boolean isContent = true; + + QName type = nodeService.getType(node.getNodeRef()); + if (ddService.isSubClass(type, ContentModel.TYPE_FOLDER)) + { + isContent = false; + } + + // TODO: for now we only support advanced workflow on content so don't render + // anything for other types + if (isContent) + { + // Render HTML for advanved workflow + out.write("
"); + out.write(bundle.getString("advanced_workflows")); + out.write("
"); + + List workflows = workflowService.getWorkflowsForContent( + node.getNodeRef(), true); + if (workflows != null && workflows.size() > 0) + { + SimpleDateFormat format = new SimpleDateFormat(bundle.getString("date_pattern")); + + // list out all the workflows the document is part of + if (isContent) + { + out.write(bundle.getString("doc_part_of_advanced_workflows")); + } + else + { + out.write(bundle.getString("space_part_of_advanced_workflows")); + } + out.write(":
    "); + for (WorkflowInstance wi : workflows) + { + out.write("
  • "); + out.write(wi.definition.title); + if (wi.definition.description != null && wi.definition.description.length() > 0) + { + out.write(" ("); + out.write(wi.definition.description); + out.write(")"); + } + out.write(" "); + if (wi.startDate != null) + { + out.write(bundle.getString("started_on").toLowerCase()); + out.write(" "); + out.write(format.format(wi.startDate)); + out.write(" "); + } + if (wi.initiator != null) + { + out.write(bundle.getString("by")); + out.write(" "); + String userName = (String)nodeService.getProperty(wi.initiator, + ContentModel.PROP_USERNAME); + out.write(userName); + out.write("."); + } + out.write("
  • "); + } + out.write("
"); + } + else + { + if (isContent) + { + out.write(bundle.getString("doc_not_in_advanced_workflow")); + } + else + { + out.write(bundle.getString("space_not_in_advanced_workflow")); + } + } + out.write("
"); + } + } +} diff --git a/source/java/org/alfresco/web/ui/repo/component/property/BaseAssociationEditor.java b/source/java/org/alfresco/web/ui/repo/component/property/BaseAssociationEditor.java index b79bceb239..026c8e88e0 100644 --- a/source/java/org/alfresco/web/ui/repo/component/property/BaseAssociationEditor.java +++ b/source/java/org/alfresco/web/ui/repo/component/property/BaseAssociationEditor.java @@ -18,6 +18,7 @@ package org.alfresco.web.ui.repo.component.property; import java.io.IOException; +import java.io.Serializable; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; @@ -37,7 +38,9 @@ import org.alfresco.service.cmr.dictionary.AssociationDefinition; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.web.app.Application; @@ -701,7 +704,12 @@ public abstract class BaseAssociationEditor extends UIInput if (ContentModel.TYPE_PERSON.equals(nodeService.getType(targetRef))) { - out.write((String)nodeService.getProperty(targetRef, ContentModel.PROP_USERNAME)); + //out.write((String)nodeService.getProperty(targetRef, ContentModel.PROP_USERNAME)); + Map props = nodeService.getProperties(targetRef); + String firstName = (String)props.get(ContentModel.PROP_FIRSTNAME); + String lastName = (String)props.get(ContentModel.PROP_LASTNAME); + String fullName = firstName + " " + (lastName != null ? lastName : ""); + out.write(fullName); } else { @@ -821,21 +829,33 @@ public abstract class BaseAssociationEditor extends UIInput item.getId().equals(currentNode.getId()) == false) || this.removed.containsKey(item.getId())) { - out.write(""); } } } @@ -877,34 +897,52 @@ public abstract class BaseAssociationEditor extends UIInput if (contains != null && contains.length() > 0) { String safeContains = Utils.remove(contains.trim(), "\""); - query.append(" AND +@"); // if the association's target is the person type search on the - // username instead of the name property + // firstName and lastName properties instead of the name property if (type.equals(ContentModel.TYPE_PERSON.toString())) { - String userName = Repository.escapeQName(QName.createQName( - NamespaceService.CONTENT_MODEL_1_0_URI, "userName")); - query.append(userName); + query.append(" AND (@"); + String firstName = Repository.escapeQName(QName.createQName( + NamespaceService.CONTENT_MODEL_1_0_URI, "firstName")); + query.append(firstName); + query.append(":*" + safeContains + "*"); + query.append(" OR @"); + String lastName = Repository.escapeQName(QName.createQName( + NamespaceService.CONTENT_MODEL_1_0_URI, "lastName")); + query.append(lastName); + query.append(":*" + safeContains + "*)"); } else { + query.append(" AND +@"); String nameAttr = Repository.escapeQName(QName.createQName( NamespaceService.CONTENT_MODEL_1_0_URI, "name")); query.append(nameAttr); + query.append(":*" + safeContains + "*"); } - - query.append(":*" + safeContains + "*"); } if (logger.isDebugEnabled()) logger.debug("Query: " + query.toString()); + SearchParameters searchParams = new SearchParameters(); + searchParams.addStore(Repository.getStoreRef()); + searchParams.setLanguage(SearchService.LANGUAGE_LUCENE); + searchParams.setQuery(query.toString()); + + if (type.equals(ContentModel.TYPE_PERSON.toString())) + { + searchParams.addSort("@" + ContentModel.PROP_LASTNAME, true); + + if (logger.isDebugEnabled()) + logger.debug("Added lastname as sort column to query for people"); + } + ResultSet results = null; try { - results = Repository.getServiceRegistry(context).getSearchService().query( - Repository.getStoreRef(), SearchService.LANGUAGE_LUCENE, query.toString()); + results = Repository.getServiceRegistry(context).getSearchService().query(searchParams); this.availableOptions = results.getNodeRefs(); } finally diff --git a/source/java/org/alfresco/web/ui/repo/tag/NodeWorkflowInfoTag.java b/source/java/org/alfresco/web/ui/repo/tag/NodeWorkflowInfoTag.java new file mode 100644 index 0000000000..1355d15860 --- /dev/null +++ b/source/java/org/alfresco/web/ui/repo/tag/NodeWorkflowInfoTag.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.web.ui.repo.tag; + +import javax.faces.component.UIComponent; + +import org.alfresco.web.ui.common.tag.HtmlComponentTag; + +/** + * Tag class for the UINodeWorkflowInfo component + * + * @author gavinc + */ +public class NodeWorkflowInfoTag extends HtmlComponentTag +{ + private String value; + + /** + * @see javax.faces.webapp.UIComponentTag#getComponentType() + */ + public String getComponentType() + { + return "org.alfresco.faces.NodeWorkflowInfo"; + } + + /** + * @see javax.faces.webapp.UIComponentTag#getRendererType() + */ + public String getRendererType() + { + return null; + } + + /** + * @see javax.faces.webapp.UIComponentTag#setProperties(javax.faces.component.UIComponent) + */ + protected void setProperties(UIComponent component) + { + super.setProperties(component); + + setStringBindingProperty(component, "value", this.value); + } + + /** + * @see org.alfresco.web.ui.common.tag.HtmlComponentTag#release() + */ + public void release() + { + super.release(); + + this.value = null; + } + + /** + * Set the value + * + * @param value the value + */ + public void setValue(String value) + { + this.value = value; + } +} diff --git a/source/web/WEB-INF/faces-config-beans.xml b/source/web/WEB-INF/faces-config-beans.xml index d379a4a4be..1ab3c2d50e 100644 --- a/source/web/WEB-INF/faces-config-beans.xml +++ b/source/web/WEB-INF/faces-config-beans.xml @@ -1120,6 +1120,10 @@ ownableService #{OwnableService} + + copyService + #{CopyService} + diff --git a/source/web/WEB-INF/faces-config-navigation.xml b/source/web/WEB-INF/faces-config-navigation.xml index cd25917e57..7ce5308028 100644 --- a/source/web/WEB-INF/faces-config-navigation.xml +++ b/source/web/WEB-INF/faces-config-navigation.xml @@ -293,6 +293,10 @@ editCategories /jsp/dialog/edit-space-category.jsp + + editSimpleWorkflow + /jsp/dialog/edit-space-simple-workflow.jsp + @@ -343,6 +347,18 @@ + + /jsp/dialog/edit-space-simple-workflow.jsp + + cancel + /jsp/dialog/space-details.jsp + + + finish + /jsp/dialog/space-details.jsp + + + /jsp/dialog/edit-category.jsp diff --git a/source/web/WEB-INF/faces-config-repo.xml b/source/web/WEB-INF/faces-config-repo.xml index 72eefca71b..125b247e6d 100644 --- a/source/web/WEB-INF/faces-config-repo.xml +++ b/source/web/WEB-INF/faces-config-repo.xml @@ -154,6 +154,11 @@ org.alfresco.web.ui.repo.component.UIWorkflowSummary + + org.alfresco.faces.NodeWorkflowInfo + org.alfresco.web.ui.repo.component.UINodeWorkflowInfo + + org.alfresco.faces.PermissionEvaluator diff --git a/source/web/WEB-INF/repo.tld b/source/web/WEB-INF/repo.tld index e5b12d2aa3..101e1f9a36 100644 --- a/source/web/WEB-INF/repo.tld +++ b/source/web/WEB-INF/repo.tld @@ -1610,6 +1610,29 @@ + + nodeWorkflowInfo + org.alfresco.web.ui.repo.tag.NodeWorkflowInfoTag + JSP + + + The nodeWorkflowInfo component displays information about the workflows + a node is currently involved in. + + + + id + false + true + + + + value + true + true + + + dialogButtons org.alfresco.web.ui.repo.tag.DialogButtonsTag diff --git a/source/web/css/main.css b/source/web/css/main.css index 2a6e4c1746..07afece7a9 100644 --- a/source/web/css/main.css +++ b/source/web/css/main.css @@ -546,3 +546,16 @@ a.topToolbarLinkHighlight, a.topToolbarLinkHighlight:link, a.topToolbarLinkHighl padding-right: 9px; padding-top: 4px; } + +.nodeWorkflowInfoTitle +{ + font-weight: bold; + color: #003366; + padding-top: 3px; + padding-bottom: 3px; +} + +.nodeWorkflowInfoText +{ + padding-bottom: 8px; +} diff --git a/source/web/images/icons/edit_properties_large.gif b/source/web/images/icons/edit_properties_large.gif new file mode 100644 index 0000000000..ee8cbcae6e Binary files /dev/null and b/source/web/images/icons/edit_properties_large.gif differ diff --git a/source/web/images/icons/view_properties_large.gif b/source/web/images/icons/view_properties_large.gif new file mode 100644 index 0000000000..e60d64a9eb Binary files /dev/null and b/source/web/images/icons/view_properties_large.gif differ diff --git a/source/web/images/logo/ardenringcroft_logo.png b/source/web/images/logo/ardenringcroft_logo.png new file mode 100644 index 0000000000..eb8c3f6cf2 Binary files /dev/null and b/source/web/images/logo/ardenringcroft_logo.png differ diff --git a/source/web/jsp/dialog/about.jsp b/source/web/jsp/dialog/about.jsp index 0fb6309acf..fd8a0ce967 100644 --- a/source/web/jsp/dialog/about.jsp +++ b/source/web/jsp/dialog/about.jsp @@ -190,6 +190,15 @@ + + + + +
+ Kofax Release Script: +  •  + Arden Ringcroft +
Meta Data Extraction Framework and PDF/Open Office Format meta data extraction: diff --git a/source/web/jsp/dialog/document-details.jsp b/source/web/jsp/dialog/document-details.jsp index 4e575061ac..bb7327b815 100644 --- a/source/web/jsp/dialog/document-details.jsp +++ b/source/web/jsp/dialog/document-details.jsp @@ -180,7 +180,7 @@ - @@ -263,19 +263,16 @@ - + - - - - - +
diff --git a/source/web/jsp/dialog/edit-space-simple-workflow.jsp b/source/web/jsp/dialog/edit-space-simple-workflow.jsp new file mode 100644 index 0000000000..4ce8d6db01 --- /dev/null +++ b/source/web/jsp/dialog/edit-space-simple-workflow.jsp @@ -0,0 +1,289 @@ +<%-- + Copyright (C) 2005 Alfresco, Inc. + + Licensed under the Mozilla Public License version 1.1 + with a permitted attribution clause. You may obtain a + copy of the License at + + http://www.alfresco.org/legal/license.txt + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + either express or implied. See the License for the specific + language governing permissions and limitations under the + License. +--%> +<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> +<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ taglib uri="/WEB-INF/alfresco.tld" prefix="a" %> +<%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %> + +<%@ page buffer="32kb" contentType="text/html;charset=UTF-8" %> +<%@ page isELIgnored="false" %> +<%@ page import="org.alfresco.web.ui.common.PanelGenerator" %> + + + + + + + + <%-- load a bundle of properties with I18N strings --%> + + + + + <%-- Main outer table --%> + + + <%-- Title bar --%> + + + + + <%-- Main area --%> + + <%-- Shelf --%> + + + <%-- Work Area --%> + + +
+ <%@ include file="../parts/titlebar.jsp" %> +
+ <%@ include file="../parts/shelf.jsp" %> + + + <%-- Breadcrumb --%> + <%@ include file="../parts/breadcrumb.jsp" %> + + <%-- Status and Actions --%> + + + + + + + <%-- separator row with gradient shadow --%> + + + + + + + <%-- Details --%> + + + + + + + <%-- Error Messages --%> + + + + + + + <%-- separator row with bottom panel graphics --%> + + + + + + +
+ + <%-- Status and Actions inner contents table --%> + <%-- Generally this consists of an icon, textual summary and actions for the current object --%> + + + + + +
+ +
+
+
+ +
+ + + + + + +
+ <% PanelGenerator.generatePanelStart(out, request.getContextPath(), "white", "white"); %> + + + + + + + + + + + + + + + + + + + + + + + + + + +
: + +
+ + + + + + + + +
+ + + + + : + +
+
+ + + + +
+ + + + + +
+ + + + + + + + + +
+ :  + +
+ + + + + + + + +
+ + + + + : + +
+
+
+
+ <% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "white"); %> +
+ <% PanelGenerator.generatePanelStart(out, request.getContextPath(), "blue", "#D3E6FE"); %> + + + + + + + + +
+ +
+ +
+ <% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "blue"); %> +
+
+ <%-- messages tag to show messages not handled by other specific message tags --%> + +
+
+ +
+ +
+ +
\ No newline at end of file diff --git a/source/web/jsp/dialog/space-details.jsp b/source/web/jsp/dialog/space-details.jsp index 32dc64a698..fe13782bab 100644 --- a/source/web/jsp/dialog/space-details.jsp +++ b/source/web/jsp/dialog/space-details.jsp @@ -161,7 +161,7 @@ - @@ -201,6 +201,23 @@
+ + + + + + + + + + + +
+