diff --git a/config/alfresco/messages/webclient.properties b/config/alfresco/messages/webclient.properties index b26747cc90..8cc82d755b 100644 --- a/config/alfresco/messages/webclient.properties +++ b/config/alfresco/messages/webclient.properties @@ -852,8 +852,11 @@ user_sandboxes=User Sandboxes sandbox_preview=Preview Website sandbox_create=Create New Content sandbox_browse=Browse Website +sandbox_revert=Undo +sandbox_revertall=Undo All sandbox_submitall=Submit All sandbox_submitselected=Submit Selected +sandbox_revertselected=Undo Selected sandbox_icon=Browse Website import_website_content=Import Website Content title_browse_sandbox=Browse Sandbox @@ -864,15 +867,19 @@ website_browse_folders=Browse Folders website_browse_files=Browse Files creator=Creator modified_items=Modified Items +content_forms=Available Content Forms store_created_on=Created On store_created_by=Created By store_working_users=There are {0} user(s) working on this web project. avm_node_deleted=Deleted +revert=Revert submit=Submit submit_success=Successfully submitted item: {0} submitall_success=Successfully submitted sandbox for user: {0} folder_preview=Preview Folder file_preview=Preview File +selected=Selected +create_form_content=Create Content # Website actions and dialog messages title_import_content=Import Content into Website diff --git a/config/alfresco/web-client-config-wcm-actions.xml b/config/alfresco/web-client-config-wcm-actions.xml index 6bfe4e53a4..8e3df83ab6 100644 --- a/config/alfresco/web-client-config-wcm-actions.xml +++ b/config/alfresco/web-client-config-wcm-actions.xml @@ -85,6 +85,19 @@ + + + + Read + + revert + /images/icons/revert.gif + #{AVMBrowseBean.revertNode} + + #{actionContext.path} + + + folder_preview @@ -199,6 +212,7 @@ + @@ -208,6 +222,7 @@ false + @@ -217,6 +232,7 @@ false + diff --git a/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java b/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java index 4833391ba5..48089388f6 100644 --- a/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java +++ b/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java @@ -727,23 +727,6 @@ public class AVMBrowseBean implements IContextListener tx = Repository.getUserTransaction(context, false); tx.begin(); -// NodeRef nodeRef = getAvmActionNode().getNodeRef(); -// String name = (String)this.nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); -// NodeRef workflowPackage = this.workflowService.createPackage(null); -// ChildAssociationRef childRef = -// this.nodeService.createNode(workflowPackage, ContentModel.ASSOC_CONTAINS, -// QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, -// name), ContentModel.TYPE_CMOBJECT); -// Map aspectProperties = new HashMap(1); -// aspectProperties.put(ContentModel.PROP_NODE_REF, nodeRef); -// NodeRef childNodeRef = childRef.getChildRef(); -// this.nodeService.addAspect(childNodeRef, ContentModel.ASPECT_REFERENCES_NODE, aspectProperties); -// -// Map actionParams = new HashMap(); -// actionParams.put(StartAVMWorkflowAction.PARAM_WORKFLOW_NAME, "jbpm$wcmwf:submit"); -// Action action = this.actionService.createAction(ACTION_AVM_WORKFLOW, actionParams); -// this.actionService.executeAction(action, workflowPackage); - Action action = this.actionService.createAction(ACTION_AVM_SUBMIT); this.actionService.executeAction(action, getAvmActionNode().getNodeRef()); @@ -807,6 +790,9 @@ public class AVMBrowseBean implements IContextListener } } + /** + * Submit items selected using multi-select + */ public void submitSelected(ActionEvent event) { UIActionLink link = (UIActionLink)event.getComponent(); @@ -815,6 +801,61 @@ public class AVMBrowseBean implements IContextListener String username = params.get("username"); List selected = this.userSandboxes.getSelectedNodes(username); + if (selected != null) + { + UserTransaction tx = null; + try + { + FacesContext context = FacesContext.getCurrentInstance(); + tx = Repository.getUserTransaction(context, false); + tx.begin(); + + for (AVMNodeDescriptor node : selected) + { + Action action = this.actionService.createAction(ACTION_AVM_SUBMIT); + this.actionService.executeAction(action, AVMNodeConverter.ToNodeRef(-1, node.getPath())); + } + + // commit the transaction + tx.commit(); + + // if we get here, all was well - output friendly status message to the user + // TODO: different message once the submit screen is available + String msg = MessageFormat.format(Application.getMessage( + context, MSG_SUBMITALL_SUCCESS), username); + FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg); + String formId = Utils.getParentForm(context, event.getComponent()).getClientId(context); + context.addMessage(formId + ':' + COMPONENT_SANDBOXESPANEL, facesMsg); + } + catch (Throwable err) + { + err.printStackTrace(System.err); + Utils.addErrorMessage(MessageFormat.format(Application.getMessage( + FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err); + try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} + } + } + } + + /** + * Undo changes to a single node + */ + public void revertNode(ActionEvent event) + { + } + + /** + * Undo changes to the entire sandbox + */ + public void revertAll(ActionEvent event) + { + } + + /** + * Undo changes to items selected using multi-select + */ + public void revertSelected(ActionEvent event) + { } diff --git a/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java b/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java index a0ce41414c..da337a3549 100644 --- a/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java +++ b/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java @@ -75,7 +75,7 @@ public class RenderingEngineTemplateImpl { return (String) this.nodeService.getProperty(this.nodeRef, - ContentModel.PROP_TITLE); + ContentModel.PROP_NAME); } public String getDescription() diff --git a/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java b/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java index 3be876c2e3..1a563dfde4 100644 --- a/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java +++ b/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java @@ -79,9 +79,11 @@ public class UIUserSandboxes extends SelfRenderingComponent private static final String COMPONENT_ACTIONS = "org.alfresco.faces.Actions"; - private static final String ACT_PANEL = "_panel"; + private static final String ACT_MODIFIED_PANEL = "_items"; + private static final String ACT_FORMS_PANEL = "_forms"; private static final String MSG_MODIFIED_ITEMS = "modified_items"; + private static final String MSG_CONTENT_FORMS = "content_forms"; private static final String MSG_SIZE = "size"; private static final String MSG_CREATED = "created_date"; private static final String MSG_USERNAME = "username"; @@ -90,6 +92,7 @@ public class UIUserSandboxes extends SelfRenderingComponent private static final String MSG_MODIFIED = "modified_date"; private static final String MSG_ACTIONS = "actions"; private static final String MSG_DELETED_ITEM = "avm_node_deleted"; + private static final String MSG_SELECTED = "selected"; private static final String SPACE_ICON = "/images/icons/" + BrowseBean.SPACE_SMALL_DEFAULT + ".gif"; @@ -109,6 +112,9 @@ public class UIUserSandboxes extends SelfRenderingComponent private String[] checkedItems = null; + /** transient list of available web forms */ + private List forms = null; + // ------------------------------------------------------------------------------ // Component implementation @@ -172,9 +178,14 @@ public class UIUserSandboxes extends SelfRenderingComponent Map requestMap = context.getExternalContext().getRequestParameterMap(); Map valuesMap = context.getExternalContext().getRequestParameterValuesMap(); - // detect if a panel has been expanded/collapsed - String fieldId = getClientId(context) + ACT_PANEL; + // detect if Modified Items or Available Content Forms panel has been expanded/collapsed + String fieldId = getClientId(context) + ACT_FORMS_PANEL; String value = (String)requestMap.get(fieldId); + if (value == null || value.length() == 0) + { + fieldId = getClientId(context) + ACT_MODIFIED_PANEL; + value = (String)requestMap.get(fieldId); + } if (value != null && value.length() != 0) { // expand/collapse the specified users panel @@ -210,6 +221,7 @@ public class UIUserSandboxes extends SelfRenderingComponent this.rowToUserLookup.clear(); this.userToRowLookup.clear(); this.userNodes.clear(); + this.forms = null; ResourceBundle bundle = Application.getBundle(context); AVMService avmService = getAVMService(context); @@ -310,6 +322,11 @@ public class UIUserSandboxes extends SelfRenderingComponent "#{AVMBrowseBean.submitAll}", null, null)); out.write(" "); + Utils.encodeRecursive(context, aquireAction( + context, mainStore, username, "sandbox_revertall", "/images/icons/revert.gif", + "#{AVMBrowseBean.revertAll}", null, null)); + out.write(" "); + Utils.encodeRecursive(context, aquireAction( context, mainStore, username, "sandbox_browse", "/images/icons/space_small.gif", "#{AVMBrowseBean.setupSandboxAction}", "browseSandbox", null)); @@ -318,21 +335,42 @@ public class UIUserSandboxes extends SelfRenderingComponent // modified items panel out.write(""); String panelImage = WebResources.IMAGE_COLLAPSED; - if (this.expandedPanels.contains(username)) + if (this.expandedPanels.contains(username + ACT_MODIFIED_PANEL)) { panelImage = WebResources.IMAGE_EXPANDED; } out.write(Utils.buildImageTag(context, panelImage, 11, 11, "", - Utils.generateFormSubmit(context, this, getClientId(context) + ACT_PANEL, username))); + Utils.generateFormSubmit(context, this, getClientId(context) + ACT_MODIFIED_PANEL, username + ACT_MODIFIED_PANEL))); out.write(" "); out.write(bundle.getString(MSG_MODIFIED_ITEMS)); out.write(""); - if (this.expandedPanels.contains(username)) + if (this.expandedPanels.contains(username + ACT_MODIFIED_PANEL)) { out.write("
"); // list the modified docs for this sandbox user - renderUserFiles(context, out, username, index, storeRoot); + renderUserFiles(context, out, username, storeRoot, index); + } + out.write(""); + + // content forms panel + out.write(""); + panelImage = WebResources.IMAGE_COLLAPSED; + if (this.expandedPanels.contains(username + ACT_FORMS_PANEL)) + { + panelImage = WebResources.IMAGE_EXPANDED; + } + out.write(Utils.buildImageTag(context, panelImage, 11, 11, "", + Utils.generateFormSubmit(context, this, getClientId(context) + ACT_FORMS_PANEL, username + ACT_FORMS_PANEL))); + out.write(" "); + out.write(bundle.getString(MSG_CONTENT_FORMS)); + out.write(""); + if (this.expandedPanels.contains(username + ACT_FORMS_PANEL)) + { + out.write("
"); + + // list the content forms for this sandbox user + renderContentForms(context, out, websiteRef, username, storeRoot); } out.write(""); @@ -370,8 +408,9 @@ public class UIUserSandboxes extends SelfRenderingComponent * * @throws IOException */ - private void renderUserFiles(FacesContext fc, ResponseWriter out, String username, int index, String storeRoot) - throws IOException + private void renderUserFiles( + FacesContext fc, ResponseWriter out, String username, String storeRoot, int index) + throws IOException { AVMSyncService avmSyncService = getAVMSyncService(fc); AVMService avmService = getAVMService(fc); @@ -406,7 +445,7 @@ public class UIUserSandboxes extends SelfRenderingComponent this.userNodes.put(username, nodes); // output the table of modified items - out.write(""); + out.write("
"); // header row out.write(""); - out.write(""); } + // output multi-select actions for this user out.write(""); // end table @@ -580,6 +625,69 @@ public class UIUserSandboxes extends SelfRenderingComponent } } + /** + * Render the list of content forms available for this sandbox. + * + * @param fc FacesContext + * @param out ResponseWriter + * + * @throws IOException + */ + private void renderContentForms( + FacesContext fc, ResponseWriter out, NodeRef websiteRef, String username, String storeRoot) + throws IOException + { + NodeService nodeService = getNodeService(fc); + String userStorePrefix = AVMConstants.buildAVMUserMainStoreName(storeRoot, username); + + // only need to collect the list of forms once per render + // TODO: execute permission evaluations on a per user basis against each form? + if (this.forms == null) + { + List webFormRefs = nodeService.getChildAssocs( + websiteRef, ContentModel.ASSOC_WEBFORM, RegexQNamePattern.MATCH_ALL); + this.forms = new ArrayList(webFormRefs.size()); + for (ChildAssociationRef ref : webFormRefs) + { + this.forms.add(ref.getChildRef()); + } + } + if (this.forms.size() != 0) + { + ResourceBundle bundle = Application.getBundle(fc); + + // output the table of available forms + out.write("
"); @@ -415,8 +454,7 @@ public class UIUserSandboxes extends SelfRenderingComponent out.write(Integer.toString(index)); out.write("' onclick='"); out.write("javascript:_sb_select(this);"); - out.write("'>"); + out.write("'>"); out.write(bundle.getString(MSG_NAME)); out.write(""); out.write(bundle.getString(MSG_CREATED)); @@ -565,10 +603,17 @@ public class UIUserSandboxes extends SelfRenderingComponent out.write("
"); + out.write(bundle.getString(MSG_SELECTED)); + out.write(": "); Utils.encodeRecursive(fc, aquireAction( fc, userStorePrefix, username, "sandbox_submitselected", "/images/icons/submit.gif", "#{AVMBrowseBean.submitSelected}", null, null)); + out.write(" "); + Utils.encodeRecursive(fc, aquireAction( + fc, userStorePrefix, username, "sandbox_revertselected", "/images/icons/revert.gif", + "#{AVMBrowseBean.revertSelected}", null, null)); out.write("
"); + + // header row + out.write(""); + + for (NodeRef formRef : this.forms) + { + out.write(""); + } + + out.write("
"); + out.write(bundle.getString(MSG_NAME)); + out.write(""); + out.write(bundle.getString(MSG_DESCRIPTION)); + out.write(""); + out.write(bundle.getString(MSG_ACTIONS)); + out.write("
"); + String title = (String)nodeService.getProperty(formRef, ContentModel.PROP_TITLE); + out.write(title != null ? title : ""); + out.write(""); + String desc = (String)nodeService.getProperty(formRef, ContentModel.PROP_DESCRIPTION); + out.write(desc != null ? desc : ""); + out.write(""); + // actions + Utils.encodeRecursive(fc, aquireAction( + fc, userStorePrefix, username, "create_form_content", "/images/icons/new_content.gif", + null, "wizard:createWebContent", null)); + out.write("
"); + } + } + /** * @return Byte size converter */ diff --git a/source/web/css/main.css b/source/web/css/main.css index ca47a41ab1..e7fca05ce7 100644 --- a/source/web/css/main.css +++ b/source/web/css/main.css @@ -576,8 +576,8 @@ a.topToolbarLinkHighlight, a.topToolbarLinkHighlight:link, a.topToolbarLinkHighl .modifiedItemsList { - background-color: #EEEEEE; + background-color: #f8f8f8; border-width: 1px; - border-style: dashed; - border-color: #AAAAAA; + border-style: solid; + border-color: #DDDDDD; } diff --git a/source/web/images/icons/revert.gif b/source/web/images/icons/revert.gif new file mode 100644 index 0000000000..aa523b84e4 Binary files /dev/null and b/source/web/images/icons/revert.gif differ diff --git a/source/web/images/icons/revert_large.gif b/source/web/images/icons/revert_large.gif new file mode 100644 index 0000000000..bec0134e1b Binary files /dev/null and b/source/web/images/icons/revert_large.gif differ