diff --git a/config/alfresco/messages/webclient.properties b/config/alfresco/messages/webclient.properties index 96ad13489d..8a4818dddf 100644 --- a/config/alfresco/messages/webclient.properties +++ b/config/alfresco/messages/webclient.properties @@ -901,10 +901,23 @@ old_password=Old Password new_password=New Password # Workflow messages +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. +available_workflows=Available workflows +step_choose_workflow=Choose Workflow +start_workflow_choose_title=Choose Workflow +start_workflow_choose_desc=Choose the workflow you want to start +step_workflow_options=Workflow Options +start_workflow_options_title=Workflow Options +start_workflow_options_desc=Select options for the workflow +start_workflow_finish_instruction=To start the workflow press Finish. To review or change your selections click Back. +start_workflow_no_metadata=There is no metadata to collect for this particular workflow. +users_and_roles=Users and their Roles manage_workitem=Manage WorkItem manage_workitem_title=Manage WorkItem manage_workitem_desc=This dialog allows the workitem to be managed -reassign=Reassign Task +reassign=Reassign # Admin Console messages title_admin_console=Administration Console diff --git a/config/alfresco/web-client-application-context.xml b/config/alfresco/web-client-application-context.xml index 4a95f9cbea..38489a4837 100644 --- a/config/alfresco/web-client-application-context.xml +++ b/config/alfresco/web-client-application-context.xml @@ -12,6 +12,7 @@ classpath:alfresco/web-client-config-properties.xml classpath:alfresco/web-client-config-navigation.xml classpath:alfresco/web-client-config-actions.xml + classpath:alfresco/web-client-config-workflow.xml classpath:alfresco/web-client-config-forum-actions.xml classpath:alfresco/extension/web-client-config-custom.xml diff --git a/config/alfresco/web-client-config-wizards.xml b/config/alfresco/web-client-config-wizards.xml index a3aad002c2..1936302ae0 100644 --- a/config/alfresco/web-client-config-wizards.xml +++ b/config/alfresco/web-client-config-wizards.xml @@ -182,6 +182,31 @@ + + + + + + + + + + + + diff --git a/config/alfresco/web-client-config-workflow.xml b/config/alfresco/web-client-config-workflow.xml new file mode 100644 index 0000000000..1202b210a8 --- /dev/null +++ b/config/alfresco/web-client-config-workflow.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + start_workflow + /images/icons/create_forum.gif + wizard:startWorkflow + #{WizardManager.setupParameters} + + #{actionContext.id} + + + + + + + + diff --git a/source/java/org/alfresco/web/bean/repository/Node.java b/source/java/org/alfresco/web/bean/repository/Node.java index f0a6e49e12..cfab7794b1 100644 --- a/source/java/org/alfresco/web/bean/repository/Node.java +++ b/source/java/org/alfresco/web/bean/repository/Node.java @@ -36,8 +36,6 @@ import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.web.app.Application; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; /** * Lighweight client side representation of a node held in the repository. @@ -48,28 +46,25 @@ public class Node implements Serializable { private static final long serialVersionUID = 3544390322739034169L; - protected static final Log logger = LogFactory.getLog(Node.class); - protected NodeRef nodeRef; - private String name; - private QName type; - private String path; - private String id; - private Set aspects = null; - private Map permissions; - private Boolean locked = null; - private Boolean workingCopyOwner = null; + protected String name; + protected QName type; + protected String path; + protected String id; + protected Set aspects = null; + protected Map permissions; + protected Boolean locked = null; + protected Boolean workingCopyOwner = null; protected QNameNodeMap properties; protected boolean propsRetrieved = false; protected ServiceRegistry services = null; + protected boolean childAssocsRetrieved = false; + protected QNameNodeMap childAssociations; + protected boolean assocsRetrieved = false; + protected QNameNodeMap associations; - private boolean childAssocsRetrieved = false; - private QNameNodeMap childAssociations; private Map> childAssociationsAdded; private Map> childAssociationsRemoved; - - private boolean assocsRetrieved = false; - private QNameNodeMap associations; private Map> associationsAdded; private Map> associationsRemoved; @@ -94,7 +89,7 @@ public class Node implements Serializable /** * @return All the properties known about this node. */ - public Map getProperties() + public final Map getProperties() { if (this.propsRetrieved == false) { @@ -120,7 +115,7 @@ public class Node implements Serializable { if (this.assocsRetrieved == false) { - associations = new QNameNodeMap(getServiceRegistry().getNamespaceService(), this); + this.associations = new QNameNodeMap(getServiceRegistry().getNamespaceService(), this); List assocs = getServiceRegistry().getNodeService().getTargetAssocs(this.nodeRef, RegexQNamePattern.MATCH_ALL); @@ -341,7 +336,7 @@ public class Node implements Serializable * * @return true if the permission is applied to the node for this user, false otherwise */ - public final boolean hasPermission(String permission) + public boolean hasPermission(String permission) { Boolean valid = null; if (permissions != null) diff --git a/source/java/org/alfresco/web/bean/repository/QNameNodeMap.java b/source/java/org/alfresco/web/bean/repository/QNameNodeMap.java index 92c0ecdc18..d12f40f28f 100644 --- a/source/java/org/alfresco/web/bean/repository/QNameNodeMap.java +++ b/source/java/org/alfresco/web/bean/repository/QNameNodeMap.java @@ -16,15 +16,11 @@ */ package org.alfresco.web.bean.repository; -import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.Set; import org.alfresco.service.namespace.NamespacePrefixResolver; import org.alfresco.service.namespace.QNameMap; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; /** * A extension of the repo QNameMap to provide custom property resolving support for Node wrappers. @@ -86,6 +82,7 @@ public final class QNameNodeMap extends QNameMap implements Map, Cloneable /** * @see java.util.Map#get(java.lang.Object) */ + @SuppressWarnings("unchecked") public Object get(Object key) { String qnameKey = Repository.resolveToQNameString(key.toString()); @@ -120,6 +117,7 @@ public final class QNameNodeMap extends QNameMap implements Map, Cloneable /** * Shallow copy the map by copying keys and values into a new QNameNodeMap */ + @SuppressWarnings("unchecked") public Object clone() { QNameNodeMap map = new QNameNodeMap(this.resolver, this.parent); diff --git a/source/java/org/alfresco/web/bean/repository/TransientNode.java b/source/java/org/alfresco/web/bean/repository/TransientNode.java new file mode 100644 index 0000000000..8ef05da567 --- /dev/null +++ b/source/java/org/alfresco/web/bean/repository/TransientNode.java @@ -0,0 +1,141 @@ +package org.alfresco.web.bean.repository; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Map; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.service.cmr.dictionary.AspectDefinition; +import org.alfresco.service.cmr.dictionary.AssociationDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.dictionary.TypeDefinition; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.GUID; + +/** + * Represents a transient node i.e. it is not and will not be present in the repository. + *

+ * This type of node is typically used to drive the property sheet when data collection + * is required for a type but the node does not need to be stored in the repository. An + * example use is the workflow, transient nodes are used to collect workitem metadata. + * + * @author gavinc + */ +public class TransientNode extends Node +{ + private static final long serialVersionUID = 2140554155948154106L; + + /** + * Constructor. + *

+ * NOTE: The name is NOT automatically added to the map of properties, + * if you need the name of this node to be in the map then add it to + * the map passed in to this constructor. + * + * @param type The type this node will represent + * @param name The name of the node + * @param data The properties and associations this node will have + */ + public TransientNode(QName type, String name, Map data) + { + // create a dummy NodeRef to pass to the constructor + super(new NodeRef(Repository.getStoreRef(), GUID.generate())); + + this.type = type; + this.name = name; + + // initialise the node + initNode(data); + } + + /** + * Initialises the node. + * + * @param data The properties and associations to initialise the node with + */ + protected void initNode(Map data) + { + // setup the transient node so that the super class methods work + // and do not need to go back to the repository + + DictionaryService ddService = this.getServiceRegistry().getDictionaryService(); + + // marshall the given properties and associations into the internal maps + this.associations = new QNameNodeMap(getServiceRegistry().getNamespaceService(), this); + this.childAssociations = new QNameNodeMap(getServiceRegistry().getNamespaceService(), this); + + if (data != null) + { + // go through all data items and allocate to the correct internal list + for (QName item : data.keySet()) + { + PropertyDefinition propDef = ddService.getProperty(item); + if (propDef != null) + { + this.properties.put(item, data.get(item)); + } + else + { + // see if the item is either type of association + AssociationDefinition assocDef = ddService.getAssociation(item); + if (assocDef != null) + { + if (assocDef.isChild()) + { + this.childAssociations.put(item, data.get(item)); + } + else + { + this.associations.put(item, data.get(item)); + } + } + } + } + } + + // show that the maps have been initialised + this.propsRetrieved = true; + this.assocsRetrieved = true; + this.childAssocsRetrieved = true; + + // setup the list of aspects the node would have + TypeDefinition typeDef = ddService.getType(this.type); + if (typeDef == null) + { + throw new AlfrescoRuntimeException("Failed to find type definition for start task: " + this.type); + } + + this.aspects = new HashSet(); + for (AspectDefinition aspectDef : typeDef.getDefaultAspects()) + { + this.aspects.add(aspectDef.getName()); + } + + // setup remaining variables + this.path = ""; + this.locked = Boolean.FALSE; + this.workingCopyOwner = Boolean.FALSE; + } + + @Override + public boolean hasPermission(String permission) + { + return true; + } + + @Override + public void reset() + { + // don't reset anything otherwise we'll lose our data + // with no way of getting it back!! + } + + @Override + public String toString() + { + return "Transient node of type: " + getType() + + "\nProperties: " + this.getProperties().toString(); + } +} diff --git a/source/java/org/alfresco/web/bean/wizard/WizardManager.java b/source/java/org/alfresco/web/bean/wizard/WizardManager.java index f708413da4..a967648627 100644 --- a/source/java/org/alfresco/web/bean/wizard/WizardManager.java +++ b/source/java/org/alfresco/web/bean/wizard/WizardManager.java @@ -187,6 +187,18 @@ public class WizardManager { return Integer.toString(this.currentStep); } + + /** + * Returns the name of the current step, wizards should use + * the name of the step rather than the step number to discover + * the position as extra steps can be added via configuration. + * + * @return The name of the current step + */ + public String getCurrentStepName() + { + return ((StepConfig)this.steps.get(this.currentStep-1)).getName(); + } /** * Returns a list of UIListItems representing the steps of the wizard diff --git a/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java b/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java new file mode 100644 index 0000000000..6393ebd320 --- /dev/null +++ b/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java @@ -0,0 +1,286 @@ +package org.alfresco.web.bean.workflow; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; + +import javax.faces.context.FacesContext; +import javax.faces.model.SelectItem; + +import org.alfresco.service.cmr.repository.AssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.workflow.WorkflowDefinition; +import org.alfresco.service.cmr.workflow.WorkflowPath; +import org.alfresco.service.cmr.workflow.WorkflowService; +import org.alfresco.service.cmr.workflow.WorkflowTask; +import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition; +import org.alfresco.service.cmr.workflow.WorkflowTaskState; +import org.alfresco.service.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.bean.repository.TransientNode; +import org.alfresco.web.bean.wizard.BaseWizardBean; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Bean implementation for the Start Workflow Wizard. + * + * @author gavinc + */ +public class StartWorkflowWizard extends BaseWizardBean +{ + protected String selectedWorkflow; + protected List availableWorkflows; + protected Map workflows; + protected WorkflowService workflowService; + protected Node startTaskNode; + protected boolean nextButtonDisabled = false; + + private static final Log logger = LogFactory.getLog(StartWorkflowWizard.class); + + // ------------------------------------------------------------------------------ + // Wizard implementation + + @Override + public void init(Map parameters) + { + super.init(parameters); + + // reset the selected workflow + if (this.availableWorkflows != null && this.availableWorkflows.size() > 0) + { + this.selectedWorkflow = (String)this.availableWorkflows.get(0).getValue(); + } + else + { + this.selectedWorkflow = null; + } + + this.startTaskNode = null; + } + + @Override + protected String finishImpl(FacesContext context, String outcome) + throws Exception + { + // TODO: Deal with workflows that don't require any data + + if (logger.isDebugEnabled()) + logger.debug("Starting workflow with params: " + this.startTaskNode.getProperties()); + + // start the workflow to get access to the start task + WorkflowPath path = this.workflowService.startWorkflow(this.selectedWorkflow, prepareTaskParams()); + if (path != null) + { + // extract the start task + List tasks = this.workflowService.getTasksForWorkflowPath(path.id); + if (tasks.size() == 1) + { + WorkflowTask startTask = tasks.get(0); + + if (logger.isDebugEnabled()) + logger.debug("Found start task:" + startTask); + + if (startTask.state == WorkflowTaskState.IN_PROGRESS) + { + // end the start task to trigger the first 'proper' + // task in the workflow + this.workflowService.endTask(startTask.id, null); + } + } + + if (logger.isDebugEnabled()) + logger.debug("Started workflow: " + this.selectedWorkflow); + } + + return outcome; + } + + @Override + public String next() + { + String stepName = Application.getWizardManager().getCurrentStepName(); + + if ("options".equals(stepName) && this.startTaskNode == null) + { + // retrieve the start task for the selected workflow, get the task + // definition and create a transient node to allow the property + // sheet to collect the required data. + + WorkflowDefinition flowDef = this.workflows.get(this.selectedWorkflow); + + if (logger.isDebugEnabled()) + logger.debug("Starting workflow: "+ flowDef); + + WorkflowTaskDefinition taskDef = flowDef.startTaskDefinition; + if (taskDef != null) + { + if (logger.isDebugEnabled()) + logger.debug("Start task definition: " + taskDef); + + // create an instance of a task from the data dictionary + this.startTaskNode = new TransientNode(taskDef.metadata.getName(), + "task_" + System.currentTimeMillis(), null); + + if (logger.isDebugEnabled()) + logger.debug("Created node for task: " + this.startTaskNode); + } + } + + return null; + } + + @Override + public boolean getNextButtonDisabled() + { + return this.nextButtonDisabled; + } + + // ------------------------------------------------------------------------------ + // Bean Getters and Setters + + /** + * Returns the workflow selected by the user + * + * @return The selected workflow + */ + public String getSelectedWorkflow() + { + return selectedWorkflow; + } + + /** + * Sets the selected workflow + * + * @param selectedWorkflow The workflow selected + */ + public void setSelectedWorkflow(String selectedWorkflow) + { + this.selectedWorkflow = selectedWorkflow; + } + + /** + * Returns the Node representing the start task metadata required + * + * @return The Node for the start task + */ + public Node getTaskMetadataNode() + { + return this.startTaskNode; + } + + /** + * @return Returns the summary data for the wizard. + */ + public String getSummary() + { + ResourceBundle bundle = Application.getBundle(FacesContext.getCurrentInstance()); + + String workflowName = null; + for (SelectItem item : this.availableWorkflows) + { + if (item.getValue().equals(this.selectedWorkflow)) + { + workflowName = item.getLabel(); + break; + } + } + + return buildSummary( + new String[] {bundle.getString("start_workflow")}, + new String[] {workflowName}); + } + + /** + * Returns a list of workflows that can be started. + * + * @return List of SelectItem objects representing the workflows + */ + public List getStartableWorkflows() + { + if (this.availableWorkflows == null) + { + this.availableWorkflows = new ArrayList(4); + this.workflows = new HashMap(4); + + List workflowDefs = this.workflowService.getDefinitions(); + for (WorkflowDefinition workflowDef : workflowDefs) + { + this.availableWorkflows.add(new SelectItem(workflowDef.id, workflowDef.name)); + this.workflows.put(workflowDef.id, workflowDef); + } + + // set the initial selected workflow to the first in the list, unless there are no + // workflows, in which disable the next button + if (this.availableWorkflows.size() > 0) + { + this.selectedWorkflow = (String)this.availableWorkflows.get(0).getValue(); + } + else + { + this.nextButtonDisabled = true; + } + } + + return availableWorkflows; + } + + /** + * Sets the workflow service to use + * + * @param workflowService WorkflowService instance + */ + public void setWorkflowService(WorkflowService workflowService) + { + this.workflowService = workflowService; + } + + protected Map prepareTaskParams() + { + Map params = new HashMap(); + + // marshal the properties and associations captured by the property sheet + // back into a Map to pass to the workflow service + + // go through all the properties in the transient node and add them to + // params map + Map props = this.startTaskNode.getProperties(); + for (String propName : props.keySet()) + { + QName propQName = Repository.resolveToQName(propName); + params.put(propQName, (Serializable)props.get(propName)); + } + + // go through any associations that have been added to the start task + // and build a list of NodeRefs representing the targets + Map> assocs = this.startTaskNode.getAddedAssociations(); + for (String assocName : assocs.keySet()) + { + QName assocQName = Repository.resolveToQName(assocName); + + // get the associations added and create list of targets + Map addedAssocs = assocs.get(assocName); + List targets = new ArrayList(addedAssocs.size()); + for (AssociationRef assoc : addedAssocs.values()) + { + targets.add(assoc.getTargetRef()); + } + + // add the targets for this particular association + params.put(assocQName, (Serializable)targets); + } + + // String reviewer = (String)this.startTaskNode.getProperties().get( +// ContentModel.PROP_NAME); +// Map params = new HashMap(1); +// params.put(QName.createQName(NamespaceService.DEFAULT_URI, "reviewer"), reviewer); + + + return params; + } +} diff --git a/source/java/org/alfresco/web/ui/repo/component/property/UIPropertySheet.java b/source/java/org/alfresco/web/ui/repo/component/property/UIPropertySheet.java index ea3acc89a5..d60b492400 100644 --- a/source/java/org/alfresco/web/ui/repo/component/property/UIPropertySheet.java +++ b/source/java/org/alfresco/web/ui/repo/component/property/UIPropertySheet.java @@ -35,6 +35,7 @@ import org.alfresco.config.Config; import org.alfresco.config.ConfigLookupContext; import org.alfresco.config.ConfigService; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; import org.alfresco.web.app.Application; import org.alfresco.web.app.servlet.FacesHelper; import org.alfresco.web.bean.repository.Node; @@ -626,8 +627,13 @@ public class UIPropertySheet extends UIPanel implements NamingContainer // create the property component UIProperty propComp = (UIProperty)context.getApplication(). createComponent(RepoConstants.ALFRESCO_FACES_PROPERTY); - FacesHelper.setupComponentId(context, propComp, PROP_ID_PREFIX + propertyName); - propComp.setName(propertyName); + + // get the property name in it's prefix form + QName qname = QName.createQName(propertyName); + String prefixPropName = qname.toPrefixString(); + + FacesHelper.setupComponentId(context, propComp, PROP_ID_PREFIX + prefixPropName); + propComp.setName(prefixPropName); // if this property sheet is set as read only, set all properties to read only if (isReadOnly()) @@ -642,7 +648,7 @@ public class UIPropertySheet extends UIPanel implements NamingContainer if (logger.isDebugEnabled()) logger.debug("Created property component " + propComp + "(" + propComp.getClientId(context) + - ") for '" + propertyName + + ") for '" + prefixPropName + "' and added it to property sheet " + this); } @@ -654,8 +660,13 @@ public class UIPropertySheet extends UIPanel implements NamingContainer String assocName = (String)iter.next(); UIAssociation assocComp = (UIAssociation)context.getApplication(). createComponent(RepoConstants.ALFRESCO_FACES_ASSOCIATION); - FacesHelper.setupComponentId(context, assocComp, ASSOC_ID_PREFIX + assocName); - assocComp.setName(assocName); + + // get the association name in it's prefix form + QName qname = QName.createQName(assocName); + String prefixAssocName = qname.toPrefixString(); + + FacesHelper.setupComponentId(context, assocComp, ASSOC_ID_PREFIX + prefixAssocName); + assocComp.setName(prefixAssocName); // if this property sheet is set as read only, set all properties to read only if (isReadOnly()) @@ -670,7 +681,7 @@ public class UIPropertySheet extends UIPanel implements NamingContainer if (logger.isDebugEnabled()) logger.debug("Created association component " + assocComp + "(" + assocComp.getClientId(context) + - ") for '" + assocName + + ") for '" + prefixAssocName + "' and added it to property sheet " + this); } diff --git a/source/web/WEB-INF/faces-config-beans.xml b/source/web/WEB-INF/faces-config-beans.xml index 6cd0af3096..d79b3e25bc 100644 --- a/source/web/WEB-INF/faces-config-beans.xml +++ b/source/web/WEB-INF/faces-config-beans.xml @@ -1739,6 +1739,44 @@ + + StartWorkflowWizard + org.alfresco.web.bean.workflow.StartWorkflowWizard + session + + nodeService + #{NodeService} + + + fileFolderService + #{FileFolderService} + + + searchService + #{SearchService} + + + navigator + #{NavigationBean} + + + browseBean + #{BrowseBean} + + + dictionaryService + #{DictionaryService} + + + namespaceService + #{NamespaceService} + + + workflowService + #{WorkflowService} + + + diff --git a/source/web/jsp/workflow/start-workflow-wizard/choose-workflow.jsp b/source/web/jsp/workflow/start-workflow-wizard/choose-workflow.jsp new file mode 100644 index 0000000000..d57f91f593 --- /dev/null +++ b/source/web/jsp/workflow/start-workflow-wizard/choose-workflow.jsp @@ -0,0 +1,28 @@ +<%-- + 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="/WEB-INF/alfresco.tld" prefix="a" %> +<%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %> + + + + + + + \ No newline at end of file diff --git a/source/web/jsp/workflow/start-workflow-wizard/workflow-options.jsp b/source/web/jsp/workflow/start-workflow-wizard/workflow-options.jsp new file mode 100644 index 0000000000..ef6e0942ff --- /dev/null +++ b/source/web/jsp/workflow/start-workflow-wizard/workflow-options.jsp @@ -0,0 +1,44 @@ +<%-- + 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="/WEB-INF/alfresco.tld" prefix="a" %> +<%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %> + +<%@ page import="org.alfresco.web.ui.common.PanelGenerator" %> + + + + <%PanelGenerator.generatePanelStart(out, request.getContextPath(), "yellowInner", "#ffffcc");%> +
+ + + + + + + +
+ <%PanelGenerator.generatePanelEnd(out, request.getContextPath(), "yellowInner");%> +
+
+ + + + + \ No newline at end of file