diff --git a/config/alfresco/messages/webclient.properties b/config/alfresco/messages/webclient.properties index 5f40a41cd8..63b350237c 100644 --- a/config/alfresco/messages/webclient.properties +++ b/config/alfresco/messages/webclient.properties @@ -187,6 +187,7 @@ raise_issue=Raise an Issue click_to_set_date=Click to set a date today=Today reset=Reset +label=Label # Properties username=User Name @@ -813,6 +814,7 @@ create_website_step1_title=Step One - Web Project Details create_website_step1_desc=Enter the information about the web project. website_dnsname=DNS name validation_invalid_dns_name=Invalid website DNS name, a minimum of 2 alpha-numeric characters are accepted. +website_webapp=Default Webapp website_selected_forms=Selected Web Content Forms website_save_location=Save Location website_save_location_info=Use the following pattern when saving content @@ -895,6 +897,9 @@ folder_preview=Preview Folder file_preview=Preview File selected=Selected create_form_content=Create Content +recent_snapshots=Recent Snapshots +snapshot_revert=Revert +snapshot_preview=Preview # Website actions and dialog messages title_import_content=Import Content into Website @@ -920,6 +925,10 @@ edit_file_description=Edit the properties of the file then click OK. edit_folder_properties=Edit Folder Properties edit_folder_description=Edit the properties of the folder then click OK. folder_props=Folder Properties +snapshot_properties=Snapshot Properties +snapshot_label=Label +snapshot_success=Snapshot ''{0}'' created for sandbox: {1} +snapshot_failure=Snapshot not created - the sandbox has not been modified since the last snapshot. # New User Wizard messages new_user_title=New User Wizard diff --git a/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java b/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java index 1fb6fc3758..183348b466 100644 --- a/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java +++ b/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java @@ -33,6 +33,7 @@ import javax.transaction.UserTransaction; import org.alfresco.model.ContentModel; import org.alfresco.repo.avm.AVMNodeConverter; +import org.alfresco.repo.avm.actions.AVMRevertStoreAction; import org.alfresco.repo.avm.actions.AVMUndoSandboxListAction; import org.alfresco.repo.avm.actions.SimpleAVMSubmitAction; import org.alfresco.service.cmr.action.Action; @@ -67,8 +68,10 @@ import org.alfresco.web.ui.common.Utils; import org.alfresco.web.ui.common.component.IBreadcrumbHandler; import org.alfresco.web.ui.common.component.UIActionLink; import org.alfresco.web.ui.common.component.UIBreadcrumb; +import org.alfresco.web.ui.common.component.UIModeList; import org.alfresco.web.ui.common.component.data.UIRichList; import org.alfresco.web.ui.wcm.WebResources; +import org.alfresco.web.ui.wcm.component.UISandboxSnapshots; import org.alfresco.web.ui.wcm.component.UIUserSandboxes; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -97,9 +100,15 @@ public class AVMBrowseBean implements IContextListener /** Component id the status messages are tied too */ private static final String COMPONENT_SANDBOXESPANEL = "sandboxes-panel"; + /** Top-level JSF form ID */ + private static final String FORM_ID = "browse-website"; + /** Content Manager role name */ private static final String ROLE_CONTENT_MANAGER = "ContentManager"; + /** Snapshot date filter selection */ + private String snapshotDateFilter = UISandboxSnapshots.FILTER_DATE_TODAY; + private String sandbox; private String username; private String sandboxTitle = null; @@ -436,6 +445,22 @@ public class AVMBrowseBean implements IContextListener this.sandboxTitle = sandboxTitle; } + /** + * @return Returns the Snapshot Date Filter. + */ + public String getSnapshotDateFilter() + { + return this.snapshotDateFilter; + } + + /** + * @param snapshotDateFilter The Snapshot Date Filter to set. + */ + public void setSnapshotDateFilter(String snapshotDateFilter) + { + this.snapshotDateFilter = snapshotDateFilter; + } + /** * @return icon image for the appropriate sandbox type */ @@ -665,6 +690,15 @@ public class AVMBrowseBean implements IContextListener updateUILocation(path); } + /** + * Action handler called when the Snapshot Date filter is changed by the user + */ + public void snapshotDateFilterChanged(ActionEvent event) + { + UIModeList filterComponent = (UIModeList)event.getComponent(); + setSnapshotDateFilter(filterComponent.getValue().toString()); + } + /** * Setup the context for a sandbox browse action */ @@ -758,12 +792,9 @@ public class AVMBrowseBean implements IContextListener tx.commit(); // if we get here, all was well - output friendly status message to the user - String msg = MessageFormat.format(Application.getMessage( context, MSG_SUBMIT_SUCCESS), node.getName()); - FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg); - String formId = Utils.getParentForm(context, event.getComponent()).getClientId(context); - context.addMessage(formId + ':' + COMPONENT_SANDBOXESPANEL, facesMsg); + displayStatusMessage(context, msg); } catch (Throwable err) { @@ -803,9 +834,7 @@ public class AVMBrowseBean implements IContextListener // if we get here, all was well - output friendly status message to the user 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); + displayStatusMessage(context, msg); } catch (Throwable err) { @@ -848,9 +877,7 @@ public class AVMBrowseBean implements IContextListener // TODO: different message once the submit screen is available String msg = MessageFormat.format(Application.getMessage( context, MSG_SUBMITSELECTED_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); + displayStatusMessage(context, msg); } catch (Throwable err) { @@ -893,9 +920,7 @@ public class AVMBrowseBean implements IContextListener // if we get here, all was well - output friendly status message to the user String msg = MessageFormat.format(Application.getMessage( context, MSG_REVERT_SUCCESS), node.getName()); - FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg); - String formId = Utils.getParentForm(context, event.getComponent()).getClientId(context); - context.addMessage(formId + ':' + COMPONENT_SANDBOXESPANEL, facesMsg); + displayStatusMessage(context, msg); } catch (Throwable err) { @@ -941,9 +966,7 @@ public class AVMBrowseBean implements IContextListener // if we get here, all was well - output friendly status message to the user String msg = MessageFormat.format(Application.getMessage( context, MSG_REVERTALL_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); + displayStatusMessage(context, msg); } catch (Throwable err) { @@ -952,7 +975,7 @@ public class AVMBrowseBean implements IContextListener try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} } } - + /** * Undo changes to items selected using multi-select */ @@ -992,9 +1015,7 @@ public class AVMBrowseBean implements IContextListener // TODO: different message once the submit screen is available String msg = MessageFormat.format(Application.getMessage( context, MSG_REVERTSELECTED_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); + displayStatusMessage(context, msg); } catch (Throwable err) { @@ -1006,6 +1027,44 @@ public class AVMBrowseBean implements IContextListener } } + public void revertSnapshot(ActionEvent event) + { + UIActionLink link = (UIActionLink)event.getComponent(); + Map params = link.getParameterMap(); + String sandbox = params.get("sandbox"); + String strVersion = params.get("version"); + int version = Integer.valueOf(strVersion); + + UserTransaction tx = null; + try + { + FacesContext context = FacesContext.getCurrentInstance(); + tx = Repository.getUserTransaction(context, false); + tx.begin(); + + Map args = new HashMap(1, 1.0f); + args.put(AVMRevertStoreAction.PARAM_VERSION, version); + Action action = this.actionService.createAction(AVMRevertStoreAction.NAME, args); + this.actionService.executeAction(action, AVMNodeConverter.ToNodeRef(-1, sandbox + ":/")); + + // commit the transaction + tx.commit(); + + // if we get here, all was well - output friendly status message to the user + //String msg = MessageFormat.format(Application.getMessage( + // context, MSG_REVERT_SUCCESS), node.getName()); + //displayStatusMessage(context, msg); + displayStatusMessage(context, "Reverted to version: " + version); + } + 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) {} + } + } + /** * Create web content from a specific Form via the User Sandbox 'Available Forms' panel */ @@ -1026,6 +1085,18 @@ public class AVMBrowseBean implements IContextListener // ------------------------------------------------------------------------------ // Private helpers + /** + * Display a status message to the user + * + * @param context + * @param msg Text message to display + */ + /*package*/ void displayStatusMessage(FacesContext context, String msg) + { + FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg); + context.addMessage(FORM_ID + ':' + COMPONENT_SANDBOXESPANEL, facesMsg); + } + /*package*/ boolean isCurrentPathNull() { return (this.currentPath == null); diff --git a/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java b/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java index 746193ab54..2096912d26 100644 --- a/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java +++ b/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java @@ -190,7 +190,7 @@ public class CreateFormWizard props.put(ContentModel.PROP_TITLE, this.getFormTitle()); props.put(ContentModel.PROP_DESCRIPTION, this.getFormDescription()); this.nodeService.addAspect(folderInfo.getNodeRef(), ContentModel.ASPECT_TITLED, props); - + props = new HashMap(3, 1.0f); props.put(WCMModel.PROP_XML_SCHEMA, fileInfo.getNodeRef()); props.put(WCMModel.PROP_XML_SCHEMA_ROOT_ELEMENT_NAME, diff --git a/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java b/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java index 607ea57b65..532f36e067 100644 --- a/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java +++ b/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java @@ -293,7 +293,7 @@ public class CreateWebContentWizard extends BaseContentWizard Form form = FormsService.getInstance().getForm(formName); if (form != null) { - items.add(new SelectItem(formName, formName)); + items.add(new SelectItem(formName, form.getTitle())); } } diff --git a/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java b/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java index 7bc88fdd96..6f7055f831 100644 --- a/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java +++ b/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java @@ -81,6 +81,8 @@ public class CreateWebsiteWizard extends BaseWizardBean private static final String MSG_NONE = "value_not_set"; private static final String ROLE_CONTENT_MANAGER = "ContentManager"; + + private static final String WEBAPP_DEFAULT = "ROOT"; private static Log logger = LogFactory.getLog(CreateWebsiteWizard.class); @@ -88,6 +90,7 @@ public class CreateWebsiteWizard extends BaseWizardBean protected String title; protected String name; protected String description; + protected String webapp = WEBAPP_DEFAULT; private String websitesFolderId = null; @@ -170,6 +173,11 @@ public class CreateWebsiteWizard extends BaseWizardBean uiFacetsProps.put(ContentModel.PROP_DESCRIPTION, this.description); this.nodeService.addAspect(nodeRef, ContentModel.ASPECT_UIFACETS, uiFacetsProps); + // set the default webapp name for the project + String webapp = (this.webapp != null && this.webapp.length() != 0) ? this.webapp : WEBAPP_DEFAULT; + this.nodeService.setProperty(nodeRef, ContentModel.PROP_DEFAULTWEBAPP, webapp); + + // call the delegate wizard bean to provide invite user functionality InviteWebsiteUsersWizard wiz = getInviteUsersWizard(); wiz.setNode(new Node(nodeRef)); outcome = wiz.finish(); @@ -459,6 +467,22 @@ public class CreateWebsiteWizard extends BaseWizardBean this.description = description; } + /** + * @return the default webapp name for the project + */ + public String getWebapp() + { + return this.webapp; + } + + /** + * @param webapp The default webapp name for the project + */ + public void setWebapp(String webapp) + { + this.webapp = webapp; + } + /** * @return summary text for the wizard */ diff --git a/source/java/org/alfresco/web/bean/wcm/ImportWebsiteDialog.java b/source/java/org/alfresco/web/bean/wcm/ImportWebsiteDialog.java index 841523514b..cb1fc653c2 100644 --- a/source/java/org/alfresco/web/bean/wcm/ImportWebsiteDialog.java +++ b/source/java/org/alfresco/web/bean/wcm/ImportWebsiteDialog.java @@ -213,8 +213,7 @@ public class ImportWebsiteDialog processZipImport(this.file, importRef); // After an import it's a good idea to snapshot the staging store - // TODO: Maybe a nice auto generated comment. - this.avmService.createSnapshot(store, null, null); + this.avmService.createSnapshot(store, "Import of file: " + this.fileName, null); } } else diff --git a/source/java/org/alfresco/web/bean/wcm/SnapshotSandboxDialog.java b/source/java/org/alfresco/web/bean/wcm/SnapshotSandboxDialog.java index b2c2a02518..f3cbe1a0af 100644 --- a/source/java/org/alfresco/web/bean/wcm/SnapshotSandboxDialog.java +++ b/source/java/org/alfresco/web/bean/wcm/SnapshotSandboxDialog.java @@ -16,23 +16,35 @@ */ package org.alfresco.web.bean.wcm; +import java.text.MessageFormat; +import java.util.Map; + import javax.faces.context.FacesContext; import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.web.app.Application; import org.alfresco.web.bean.dialog.BaseDialogBean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** + * Backing bean for the Snaphost Sandbox dialog. + * * @author Kevin Roast */ public class SnapshotSandboxDialog extends BaseDialogBean { private static final Log logger = LogFactory.getLog(SnapshotSandboxDialog.class); + private static final String MSG_SNAPSHOT_FAILURE = "snapshot_failure"; + private static final String MSG_SNAPSHOT_SUCCESS = "snapshot_success"; + protected AVMService avmService; protected AVMBrowseBean avmBrowseBean; + private String label; + private String description; + /** * @param avmBrowseBean The avmBrowseBean to set. @@ -50,13 +62,74 @@ public class SnapshotSandboxDialog extends BaseDialogBean this.avmService = avmService; } + /** + * @return Returns the snapshot description. + */ + public String getDescription() + { + return this.description; + } + + /** + * @param description The snapshot description to set. + */ + public void setDescription(String description) + { + this.description = description; + } + + /** + * @return Returns the snaphost label. + */ + public String getLabel() + { + return this.label; + } + + /** + * @param label The snapshot label to set. + */ + public void setLabel(String label) + { + this.label = label; + } + + /** + * @see org.alfresco.web.bean.dialog.BaseDialogBean#init(java.util.Map) + */ + @Override + public void init(Map parameters) + { + super.init(parameters); + this.label = null; + this.description = null; + } + /** * @see org.alfresco.web.bean.dialog.BaseDialogBean#finishImpl(javax.faces.context.FacesContext, java.lang.String) */ @Override protected String finishImpl(FacesContext context, String outcome) throws Exception { - return null; + // find the previous version - to see if a snapshot was acutally performed + int oldVersion = this.avmService.getLatestSnapshotID(this.avmBrowseBean.getSandbox()); + int version = this.avmService.createSnapshot( + this.avmBrowseBean.getSandbox(), this.label, this.description); + if (version > oldVersion) + { + // a new snapshot was created + String msg = MessageFormat.format(Application.getMessage( + context, MSG_SNAPSHOT_SUCCESS), this.label, this.avmBrowseBean.getSandbox()); + this.avmBrowseBean.displayStatusMessage(context, msg); + } + else + { + // no changes had occured - no snapshot was required + String msg = Application.getMessage(context, MSG_SNAPSHOT_FAILURE); + this.avmBrowseBean.displayStatusMessage(context, msg); + } + + return outcome; } } diff --git a/source/java/org/alfresco/web/forms/FormsService.java b/source/java/org/alfresco/web/forms/FormsService.java index d2de70b22a..05704ab2b0 100644 --- a/source/java/org/alfresco/web/forms/FormsService.java +++ b/source/java/org/alfresco/web/forms/FormsService.java @@ -233,7 +233,7 @@ public final class FormsService sp.addStore(Repository.getStoreRef()); sp.setLanguage(SearchService.LANGUAGE_LUCENE); sp.setQuery("ASPECT:\"" + WCMModel.ASPECT_FORM + - "\" AND @" + Repository.escapeQName(ContentModel.PROP_TITLE) + + "\" AND @" + Repository.escapeQName(ContentModel.PROP_NAME) + ":\"" + name + "\""); if (LOGGER.isDebugEnabled()) LOGGER.debug("running query [" + sp.getQuery() + "]"); @@ -242,14 +242,14 @@ public final class FormsService for (ResultSetRow row : rs) { final NodeRef nr = row.getNodeRef(); - if (this.nodeService.getProperty(nr, ContentModel.PROP_TITLE).equals(name)) + if (this.nodeService.getProperty(nr, ContentModel.PROP_NAME).equals(name)) { result = nr; break; } } if (result == null && LOGGER.isDebugEnabled()) - LOGGER.debug("unable to find tempalte type " + name); + LOGGER.debug("unable to find template type " + name); return result != null ? this.getForm(result) : null; } diff --git a/source/java/org/alfresco/web/ui/wcm/component/UISandboxSnapshots.java b/source/java/org/alfresco/web/ui/wcm/component/UISandboxSnapshots.java new file mode 100644 index 0000000000..3bfc452ebd --- /dev/null +++ b/source/java/org/alfresco/web/ui/wcm/component/UISandboxSnapshots.java @@ -0,0 +1,447 @@ +/* + * 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.wcm.component; + +import java.io.IOException; +import java.text.DateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; + +import javax.faces.component.UIComponent; +import javax.faces.component.UIParameter; +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import javax.faces.el.ValueBinding; +import javax.transaction.UserTransaction; + +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.avm.VersionDescriptor; +import org.alfresco.web.app.Application; +import org.alfresco.web.bean.repository.Repository; +import org.alfresco.web.ui.common.ComponentConstants; +import org.alfresco.web.ui.common.ConstantMethodBinding; +import org.alfresco.web.ui.common.Utils; +import org.alfresco.web.ui.common.component.SelfRenderingComponent; +import org.alfresco.web.ui.common.component.UIActionLink; +import org.alfresco.web.ui.repo.component.UIActions; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.web.jsf.FacesContextUtils; + +/** + * @author Kevin Roast + */ +public class UISandboxSnapshots extends SelfRenderingComponent +{ + private static Log logger = LogFactory.getLog(UISandboxSnapshots.class); + + // snapshot date filters + public static final String FILTER_DATE_ALL = "all"; + public static final String FILTER_DATE_TODAY = "today"; + public static final String FILTER_DATE_WEEK = "week"; + public static final String FILTER_DATE_MONTH = "month"; + + private static final String COMPONENT_ACTIONS = "org.alfresco.faces.Actions"; + + private static final String MSG_LABEL = "label"; + private static final String MSG_DESCRIPTION = "description"; + private static final String MSG_DATE = "date"; + private static final String MSG_USERNAME = "username"; + private static final String MSG_VERSION = "version"; + private static final String MSG_ACTIONS = "actions"; + + /** sandbox to show snapshots for */ + private String value; + + /** date filter to use when listing snapshots */ + private String dateFilter; + + + // ------------------------------------------------------------------------------ + // Component implementation + + /** + * @see javax.faces.component.UIComponent#getFamily() + */ + public String getFamily() + { + return "org.alfresco.faces.SandboxSnapshots"; + } + + 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 = (String)values[1]; + } + + public Object saveState(FacesContext context) + { + Object values[] = new Object[2]; + // standard component attributes are saved by the super class + values[0] = super.saveState(context); + values[1] = this.value; + return values; + } + + /** + * @see javax.faces.component.UIComponentBase#getRendersChildren() + */ + public boolean getRendersChildren() + { + return true; + } + + /** + * @see javax.faces.component.UIComponentBase#encodeChildren(javax.faces.context.FacesContext) + */ + public void encodeChildren(FacesContext context) throws IOException + { + // the child components are rendered explicitly during the encodeBegin() + } + + /** + * @see javax.faces.component.UIComponentBase#encodeBegin(javax.faces.context.FacesContext) + */ + @SuppressWarnings("unchecked") + public void encodeBegin(FacesContext context) throws IOException + { + if (isRendered() == false) + { + return; + } + + ResponseWriter out = context.getResponseWriter(); + + ResourceBundle bundle = Application.getBundle(context); + DateFormat df = Utils.getDateTimeFormat(context); + AVMService avmService = getAVMService(context); + UserTransaction tx = null; + try + { + tx = Repository.getUserTransaction(FacesContext.getCurrentInstance(), true); + tx.begin(); + + String sandbox = getValue(); + if (sandbox == null) + { + throw new IllegalArgumentException("Sandbox must be specified."); + } + + // TODO: apply tag style - removed hardcoded + out.write(""); + // header row + out.write(""); + + // get the list of snapshots we can potentially display + List versions; + String dateFilter = getDateFilter(); + if (dateFilter == null || dateFilter.equals(FILTER_DATE_ALL)) + { + versions = avmService.getAVMStoreVersions(sandbox); + } + else + { + Date toDate = new Date(); + Date fromDate; + if (FILTER_DATE_TODAY.equals(dateFilter)) + { + fromDate = new Date(toDate.getYear(), toDate.getMonth(), toDate.getDate(), 0, 0, 0); + } + else if (FILTER_DATE_WEEK.equals(dateFilter)) + { + fromDate = new Date(toDate.getTime() - (1000L*60L*60L*24L*7L)); + } + else if (FILTER_DATE_MONTH.equals(dateFilter)) + { + fromDate = new Date(toDate.getTime() - (1000L*60L*60L*24L*30L)); + } + else + { + throw new IllegalArgumentException("Unknown date filter mode: " + dateFilter); + } + versions = avmService.getAVMStoreVersions(sandbox, fromDate, toDate); + } + for (VersionDescriptor item : versions) + { + // only display snapshots with a valid tag - others are system generated snapshots + if (item.getTag() != null) + { + out.write(""); + } + } + + // end table + out.write("
"); + out.write(bundle.getString(MSG_LABEL)); + out.write(""); + out.write(bundle.getString(MSG_DESCRIPTION)); + out.write(""); + out.write(bundle.getString(MSG_DATE)); + out.write(""); + out.write(bundle.getString(MSG_USERNAME)); + out.write(""); + out.write(bundle.getString(MSG_VERSION)); + out.write(""); + out.write(bundle.getString(MSG_ACTIONS)); + out.write("
"); + out.write(item.getTag()); + out.write(""); + out.write(item.getDescription() != null ? item.getDescription() : ""); + out.write(""); + out.write(df.format(new Date(item.getCreateDate()))); + out.write(""); + out.write(item.getCreator()); + out.write(""); + out.write(Integer.toString(item.getVersionID())); + out.write(""); + // actions for the item + Map params = new HashMap(2, 1.0f); + params.put("sandbox", sandbox); + params.put("version", Integer.toString(item.getVersionID())); + Utils.encodeRecursive(context, aquireAction( + context, sandbox, "snapshot_revert", null, + "#{AVMBrowseBean.revertSnapshot}", null, null, params)); + out.write(" "); + Utils.encodeRecursive(context, aquireAction( + context, sandbox, "snapshot_preview", null, + null, null)); + out.write(" "); + + out.write("
"); + + tx.commit(); + } + catch (Throwable err) + { + try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} + throw new RuntimeException(err); + } + } + + /** + * Aquire a UIActionLink component for the specified action + * + * @param fc FacesContext + * @param sandbox Root sandbox name + * @param name Action name - will be used for I18N message lookup + * @param icon Icon to display for the action + * @param actionListener Actionlistener for the action + * @param outcome Navigation outcome for the action + * + * @return UIActionLink component + */ + private UIActionLink aquireAction(FacesContext fc, String sandbox, String name, String icon, + String actionListener, String outcome) + { + return aquireAction(fc, sandbox, name, icon, actionListener, outcome, null, null); + } + + /** + * Aquire a UIActionLink component for the specified action + * + * @param fc FacesContext + * @param sandbox Root sandbox name + * @param name Action name - will be used for I18N message lookup + * @param icon Icon to display for the action + * @param actionListener Actionlistener for the action + * @param outcome Navigation outcome for the action + * @param url HREF URL for the action + * @param params Parameters name/values for the action listener args + * + * @return UIActionLink component + */ + private UIActionLink aquireAction(FacesContext fc, String sandbox, String name, String icon, + String actionListener, String outcome, String url, Map params) + { + UIActionLink action = findAction(name, sandbox); + if (action == null) + { + action = createAction(fc, sandbox, name, icon, actionListener, outcome, url, params); + } + return action; + } + + /** + * Locate a child UIActionLink component by name. + * + * @param name Of the action component to find + * @param sandbox Sandbox the action component is tied to + * + * @return UIActionLink component if found, else null if not created yet + */ + private UIActionLink findAction(String name, String sandbox) + { + UIActionLink action = null; + String actionId = name + '_' + sandbox; + if (logger.isDebugEnabled()) + logger.debug("Finding action Id: " + actionId); + for (UIComponent component : (List)getChildren()) + { + if (actionId.equals(component.getId())) + { + action = (UIActionLink)component; + if (logger.isDebugEnabled()) + logger.debug("...found action Id: " + actionId); + break; + } + } + return action; + } + + /** + * Create a UIActionLink child component. + * + * @param fc FacesContext + * @param sandbox Root sandbox name + * @param name Action name - will be used for I18N message lookup + * @param icon Icon to display for the actio n + * @param actionListener Actionlistener for the action + * @param outcome Navigation outcome for the action + * @param url HREF URL for the action + * @param params Parameters name/values for the action listener args + * + * @return UIActionLink child component + */ + private UIActionLink createAction(FacesContext fc, String sandbox, String name, String icon, + String actionListener, String outcome, String url, Map params) + { + javax.faces.application.Application facesApp = fc.getApplication(); + UIActionLink control = (UIActionLink)facesApp.createComponent(UIActions.COMPONENT_ACTIONLINK); + + String id = name + '_' + sandbox; + if (logger.isDebugEnabled()) + logger.debug("...creating action Id: " + id); + control.setRendererType(UIActions.RENDERER_ACTIONLINK); + control.setId(id); + control.setValue(Application.getMessage(fc, name)); + control.setShowLink(icon != null ? false : true); + control.setImage(icon); + + if (actionListener != null) + { + control.setActionListener(facesApp.createMethodBinding( + actionListener, UIActions.ACTION_CLASS_ARGS)); + + // add sandbox as the default action listener parameter + if (params == null) + { + UIParameter param = (UIParameter)facesApp.createComponent(ComponentConstants.JAVAX_FACES_PARAMETER); + param.setId(id + "_1"); + param.setName("sandbox"); + param.setValue(sandbox); + control.getChildren().add(param); + } + else + { + // if a specific set of parameters are supplied, then add them instead + int idIndex = 1; + for (String key : params.keySet()) + { + UIParameter param = (UIParameter)facesApp.createComponent(ComponentConstants.JAVAX_FACES_PARAMETER); + param.setId(id + '_' + Integer.toString(idIndex++)); + param.setName(key); + String value = params.get(key); + if (value.startsWith("#{") == true) + { + ValueBinding vb = facesApp.createValueBinding(value); + param.setValueBinding("value", vb); + } + else + { + param.setValue(params.get(key)); + } + control.getChildren().add(param); + } + } + } + if (outcome != null) + { + control.setAction(new ConstantMethodBinding(outcome)); + } + if (url != null) + { + control.setHref(url); + control.setTarget("new"); + } + + this.getChildren().add(control); + + return control; + } + + private AVMService getAVMService(FacesContext fc) + { + return (AVMService)FacesContextUtils.getRequiredWebApplicationContext(fc).getBean("AVMService"); + } + + + // ------------------------------------------------------------------------------ + // Strongly typed component property accessors + + /** + * Returns the Sandbox to show the snapshots for + * + * @return The Sandbox name + */ + public String getValue() + { + ValueBinding vb = getValueBinding("value"); + if (vb != null) + { + this.value = (String)vb.getValue(getFacesContext()); + } + + return this.value; + } + + /** + * Sets the Sandbox to show the snapshots for + * + * @param value The Sandbox name + */ + public void setValue(String value) + { + this.value = value; + } + + /** + * @return Returns the date filter. + */ + public String getDateFilter() + { + ValueBinding vb = getValueBinding("dateFilter"); + if (vb != null) + { + this.dateFilter = (String)vb.getValue(getFacesContext()); + } + + return this.dateFilter; + } + + /** + * @param dateFilter The date filter to set. + */ + public void setDateFilter(String dateFilter) + { + this.dateFilter = dateFilter; + } +} 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 68d3d50f21..87fc0d48c6 100644 --- a/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java +++ b/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java @@ -452,6 +452,7 @@ public class UIUserSandboxes extends SelfRenderingComponent this.userNodes.put(username, nodes); // output the table of modified items + // TODO: apply tag style - removed hardcoded out.write(""); // header row @@ -665,6 +666,7 @@ public class UIUserSandboxes extends SelfRenderingComponent ResourceBundle bundle = Application.getBundle(fc); // output the table of available forms + // TODO: apply tag style - removed hardcoded out.write("
"); // header row @@ -800,7 +802,7 @@ public class UIUserSandboxes extends SelfRenderingComponent UIActionLink action = findAction(name, store); if (action == null) { - action = createAction(fc, store, username, name, icon, actionListener, outcome, null, null); + action = createAction(fc, store, username, name, icon, actionListener, outcome, url, params); } return action; } @@ -860,7 +862,7 @@ public class UIUserSandboxes extends SelfRenderingComponent control.setRendererType(UIActions.RENDERER_ACTIONLINK); control.setId(id); control.setValue(Application.getMessage(fc, name)); - control.setShowLink(false); + control.setShowLink(icon != null ? false : true); control.setImage(icon); if (actionListener != null) diff --git a/source/java/org/alfresco/web/ui/wcm/tag/SandboxSnapshotsTag.java b/source/java/org/alfresco/web/ui/wcm/tag/SandboxSnapshotsTag.java new file mode 100644 index 0000000000..19028eeea9 --- /dev/null +++ b/source/java/org/alfresco/web/ui/wcm/tag/SandboxSnapshotsTag.java @@ -0,0 +1,91 @@ +/* + * 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.wcm.tag; + +import javax.faces.component.UIComponent; + +import org.alfresco.web.ui.common.tag.BaseComponentTag; + +/** + * @author Kevin Roast + */ +public class SandboxSnapshotsTag extends BaseComponentTag +{ + /** + * @see javax.faces.webapp.UIComponentTag#getComponentType() + */ + public String getComponentType() + { + return "org.alfresco.faces.SandboxSnapshots"; + } + + /** + * @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); + + setStringProperty(component, "value", this.value); + setStringProperty(component, "dateFilter", this.dateFilter); + } + + /** + * @see org.alfresco.web.ui.common.tag.HtmlComponentTag#release() + */ + public void release() + { + super.release(); + this.value = null; + this.dateFilter = null; + } + + /** + * Set the value (sandbox to display snapshots for) + * + * @param value the value + */ + public void setValue(String value) + { + this.value = value; + } + + /** + * Set the dateFilter + * + * @param dateFilter the dateFilter + */ + public void setDateFilter(String dateFilter) + { + this.dateFilter = dateFilter; + } + + + /** the dateFilter */ + private String dateFilter; + + /** the value (sandbox to display snapshots for) */ + private String value; +} diff --git a/source/web/WEB-INF/faces-config-wcm.xml b/source/web/WEB-INF/faces-config-wcm.xml index fae5a99c32..7d6e5b18f7 100644 --- a/source/web/WEB-INF/faces-config-wcm.xml +++ b/source/web/WEB-INF/faces-config-wcm.xml @@ -8,10 +8,15 @@ org.alfresco.faces.UserSandboxesorg.alfresco.web.ui.wcm.component.UIUserSandboxes + + + org.alfresco.faces.UserSandboxes + org.alfresco.web.ui.wcm.component.UIUserSandboxes + - org.alfresco.faces.FormProcessor - org.alfresco.web.ui.wcm.component.UIFormProcessor + org.alfresco.faces.SandboxSnapshots + org.alfresco.web.ui.wcm.component.UISandboxSnapshots diff --git a/source/web/WEB-INF/wcm.tld b/source/web/WEB-INF/wcm.tld index a68a22140e..90595f47ae 100644 --- a/source/web/WEB-INF/wcm.tld +++ b/source/web/WEB-INF/wcm.tld @@ -43,6 +43,47 @@ true + + + sandboxSnapshots + org.alfresco.web.ui.wcm.tag.SandboxSnapshotsTag + JSP + Sandbox Snapshots List + Displays the list of snapshots for a sandbox + + + id + false + true + The component identifier for this component + + + + value + true + true + The sandbox to show the list of snapshots for + + + + binding + false + true + The value binding expression linking this component to a property in a backing bean + + + + rendered + false + true + + + + dateFilter + false + true + + formProcessor diff --git a/source/web/css/main.css b/source/web/css/main.css index e7fca05ce7..f0e10fb33f 100644 --- a/source/web/css/main.css +++ b/source/web/css/main.css @@ -581,3 +581,11 @@ a.topToolbarLinkHighlight, a.topToolbarLinkHighlight:link, a.topToolbarLinkHighl border-style: solid; border-color: #DDDDDD; } + +.snapshotItemsList +{ + background-color: #c6d8eb; + border-width: 1px; + border-style: solid; + border-color: #999999; +} diff --git a/source/web/jsp/wcm/browse-website.jsp b/source/web/jsp/wcm/browse-website.jsp index 2234dd8d7b..f37b9cb9d4 100644 --- a/source/web/jsp/wcm/browse-website.jsp +++ b/source/web/jsp/wcm/browse-website.jsp @@ -112,8 +112,38 @@ - + + + +
- + +
+ +
+
+ +
+ <%-- Sandbox snapshots list --%> + + + + + + +
: + + + + + + +
+
+ +
+
diff --git a/source/web/jsp/wcm/create-website-wizard/details.jsp b/source/web/jsp/wcm/create-website-wizard/details.jsp index 2cedf84858..18d85e7629 100644 --- a/source/web/jsp/wcm/create-website-wizard/details.jsp +++ b/source/web/jsp/wcm/create-website-wizard/details.jsp @@ -120,6 +120,19 @@ + + + + + + + + + + + + + diff --git a/source/web/jsp/wcm/snapshot-sandbox.jsp b/source/web/jsp/wcm/snapshot-sandbox.jsp index 51e8a7d601..22b2183635 100644 --- a/source/web/jsp/wcm/snapshot-sandbox.jsp +++ b/source/web/jsp/wcm/snapshot-sandbox.jsp @@ -18,3 +18,47 @@ <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="/WEB-INF/alfresco.tld" prefix="a" %> <%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %> + + + + + + + + + + + + + + + + + + +