. Soft Delete UI checkpoint

- List of deleted items for an individual user
  - Object details page for a deleted item
  - Reworking of some of the Deleted Items UI
  - Filter by user/date HTML complete (no implementation yet)
  - Recover a single item to a specific location
  - I18N messages added for sys:archive aspect and properties

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2817 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2006-05-10 17:12:37 +00:00
parent b9da374553
commit 0b58f9ff7f
9 changed files with 533 additions and 97 deletions

View File

@@ -778,13 +778,15 @@ manage_deleted_items=Manage Deleted Items
manage_deleted_items_description=Remove or recover previously deleted items manage_deleted_items_description=Remove or recover previously deleted items
recover_all_items=Recover All Items recover_all_items=Recover All Items
delete_all_items=Delete All Items delete_all_items=Delete All Items
deleted_items_info=Use the Search to find specific named deleted items and use the Filters to reduce the list. deleted_items_info=Use the Search to find deleted items by name or content and use the filters to reduce the list.
original_location=Original Location original_location=Original Location
deleted_date=Date Deleted deleted_date=Date Deleted
deleted_user=Deleted by User deleted_user=Deleted by User
recover=Recover recover=Recover
clear_search_results=Clear Search Results clear_search_results=Clear Search Results
search_deleted_items=Search Deleted Items search_deleted_items_name=Search by Name
search_deleted_items_text=Search by Content
deleted_items_for=for ''{0}''
delete_item=Delete Item delete_item=Delete Item
delete_item_info=Permanently delete an item from the deleted file store delete_item_info=Permanently delete an item from the deleted file store
delete_item_confirm=Are you sure you want to permanently delete \"{0}\" from the deleted file store? The item cannot be recovered once this action has been performed. delete_item_confirm=Are you sure you want to permanently delete \"{0}\" from the deleted file store? The item cannot be recovered once this action has been performed.
@@ -809,6 +811,10 @@ recovered_item_permission=Failed to recover the item \"{0}\" as you do not have
recovered_item_integrity=Failed to recover the item \"{0}\" as there is now an item in the original parent folder with the same name, please select a new folder destination. recovered_item_integrity=Failed to recover the item \"{0}\" as there is now an item in the original parent folder with the same name, please select a new folder destination.
recovered_item_failure=Failed to recover the item \"{0}\" due to error: {1} recovered_item_failure=Failed to recover the item \"{0}\" due to error: {1}
delete_item_success=The item \"{0}\" has been permanently deleted. delete_item_success=The item \"{0}\" has been permanently deleted.
title_deleted_item_details=Deleted Item Details
deleteditem_details_description=Details of the deleted item
alternative_destination=You may select a destination where you wish the recovered items to be placed. If you do not select a destination, the original location of the item is used. Recovery of an item may fail if the destination does not exist or you do not have permission to add items there.
deleted_when=When
# Admin Console messages # Admin Console messages
title_admin_console=Administration Console title_admin_console=Administration Console

View File

@@ -132,5 +132,12 @@
<show-property name="app:editInline" converter="org.alfresco.faces.BooleanLabelConverter" /> <show-property name="app:editInline" converter="org.alfresco.faces.BooleanLabelConverter" />
</property-sheet> </property-sheet>
</config> </config>
<config evaluator="aspect-name" condition="sys:archived">
<property-sheet>
<show-property name="sys:archivedBy" />
<show-property name="sys:archivedDate" />
</property-sheet>
</config>
</alfresco-config> </alfresco-config>

View File

@@ -49,7 +49,9 @@ import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.NodePropertyResolver; import org.alfresco.web.bean.repository.NodePropertyResolver;
import org.alfresco.web.bean.repository.QNameNodeMap; import org.alfresco.web.bean.repository.QNameNodeMap;
import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.wizard.NewSpaceWizard;
import org.alfresco.web.ui.common.Utils; 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.UIActionLink;
import org.alfresco.web.ui.common.component.data.UIRichList; import org.alfresco.web.ui.common.component.data.UIRichList;
@@ -58,6 +60,8 @@ import org.alfresco.web.ui.common.component.data.UIRichList;
*/ */
public class TrashcanBean implements IContextListener public class TrashcanBean implements IContextListener
{ {
private static final String MSG_DELETED_ITEMS_FOR = "deleted_items_for";
private static final String MSG_DELETED_ITEMS = "deleted_items";
private static final String MSG_RECOVERED_ITEM_INTEGRITY = "recovered_item_integrity"; private static final String MSG_RECOVERED_ITEM_INTEGRITY = "recovered_item_integrity";
private static final String MSG_RECOVERED_ITEM_PERMISSION = "recovered_item_permission"; private static final String MSG_RECOVERED_ITEM_PERMISSION = "recovered_item_permission";
private static final String MSG_RECOVERED_ITEM_PARENT = "recovered_item_parent"; private static final String MSG_RECOVERED_ITEM_PARENT = "recovered_item_parent";
@@ -69,11 +73,15 @@ public class TrashcanBean implements IContextListener
private static final String RICHLIST_ID = "trashcan-list"; private static final String RICHLIST_ID = "trashcan-list";
private static final String RICHLIST_MSG_ID = "trashcan" + ':' + RICHLIST_ID; private static final String RICHLIST_MSG_ID = "trashcan" + ':' + RICHLIST_ID;
private final static String NAME_ATTR = Repository.escapeQName(ContentModel.PROP_NAME); private final static String NAME_ATTR = Repository.escapeQName(ContentModel.PROP_NAME);
private final static String USER_ATTR = Repository.escapeQName(ContentModel.PROP_ARCHIVED_BY);
private final static String SEARCH_ALL = "PARENT:\"%s\" AND ASPECT:\"%s\""; private final static String SEARCH_ALL = "PARENT:\"%s\" AND ASPECT:\"%s\"";
private final static String SEARCH_NAME = "PARENT:\"%s\" AND ASPECT:\"%s\" AND (@" + NAME_ATTR + ":*%s* TEXT:%s)"; private final static String SEARCH_NAME = "PARENT:\"%s\" AND ASPECT:\"%s\" AND @" + NAME_ATTR + ":*%s*";
private final static String SEARCH_NAME_QUOTED = "PARENT:\"%s\" AND ASPECT:\"%s\" AND (@" + NAME_ATTR + ":\"%s\" TEXT:\"%s\")"; private final static String SEARCH_TEXT = "PARENT:\"%s\" AND ASPECT:\"%s\" AND TEXT:%s";
private final static String SEARCH_NAME_QUOTED = "PARENT:\"%s\" AND ASPECT:\"%s\" AND @" + NAME_ATTR + ":\"%s\"";
private final static String SEARCH_TEXT_QUOTED = "PARENT:\"%s\" AND ASPECT:\"%s\" AND TEXT:\"%s\"";
private final static String SEARCH_USERPREFIX = "@" + USER_ATTR + ":%s AND ";
/** NodeService bean reference */ /** NodeService bean reference */
protected NodeService nodeService; protected NodeService nodeService;
@@ -96,6 +104,8 @@ public class TrashcanBean implements IContextListener
/** We show an empty list until a Search or Show All is executed */ /** We show an empty list until a Search or Show All is executed */
private boolean showItems = false; private boolean showItems = false;
private boolean fullTextSearch = false;
/** Currently listed items */ /** Currently listed items */
private List<Node> listedItems = Collections.<Node>emptyList(); private List<Node> listedItems = Collections.<Node>emptyList();
@@ -105,6 +115,9 @@ public class TrashcanBean implements IContextListener
/** Root node to the spaces store archive store*/ /** Root node to the spaces store archive store*/
private NodeRef archiveRootRef = null; private NodeRef archiveRootRef = null;
/** Alternative destination for recovered items */
private NodeRef destination = null;
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
// Bean property getters and setters // Bean property getters and setters
@@ -173,6 +186,67 @@ public class TrashcanBean implements IContextListener
this.searchText = searchText; this.searchText = searchText;
} }
/**
* @return Returns the alternative destination to use if recovery fails.
*/
public NodeRef getDestination()
{
return this.destination;
}
/**
* @param destination The alternative destination to use if recovery fails.
*/
public void setDestination(NodeRef destination)
{
this.destination = destination;
}
/**
* @return Message to display in the title of the panel area
*/
public String getPanelMessage()
{
FacesContext fc = FacesContext.getCurrentInstance();
String msg = Application.getMessage(fc, MSG_DELETED_ITEMS);
if (isAdminUser() == false)
{
msg = msg + ' ' + MessageFormat.format(
Application.getMessage(fc, MSG_DELETED_ITEMS_FOR), Application.getCurrentUser(fc).getUserName());
}
return msg;
}
/**
* Returns the URL to the content for the current document item
*
* @return Content url to the current document item
*/
public String getItemBrowserUrl()
{
return Utils.generateURL(FacesContext.getCurrentInstance(), getItem(), URLMode.HTTP_INLINE);
}
/**
* Returns the download URL to the content for the current document item
*
* @return Download url to the current document item
*/
public String getItemDownloadUrl()
{
return Utils.generateURL(FacesContext.getCurrentInstance(), getItem(), URLMode.HTTP_DOWNLOAD);
}
/**
* Return the Alfresco NodeRef URL for the current item node
*
* @return the Alfresco NodeRef URL
*/
public String getItemNodeRefUrl()
{
return getItem().getNodeRef().toString();
}
/** /**
* @return Returns the listed items. * @return Returns the listed items.
*/ */
@@ -244,27 +318,24 @@ public class TrashcanBean implements IContextListener
{ {
QName type = this.nodeService.getType(nodeRef); QName type = this.nodeService.getType(nodeRef);
MapNode node = new MapNode(nodeRef, this.nodeService, false);
node.addPropertyResolver("locationPath", resolverLocationPath);
node.addPropertyResolver("displayPath", resolverDisplayPath);
node.addPropertyResolver("deletedDate", resolverDeletedDate);
node.addPropertyResolver("deletedBy", resolverDeletedBy);
node.addPropertyResolver("isFolder", resolverIsFolder);
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) == true && if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) == true &&
this.dictionaryService.isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER) == false) this.dictionaryService.isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER) == false)
{ {
MapNode node = new MapNode(nodeRef, this.nodeService, false);
node.addPropertyResolver("locationPath", resolverLocationPath);
node.addPropertyResolver("displayPath", resolverDisplayPath);
node.addPropertyResolver("deletedDate", resolverDeletedDate);
node.addPropertyResolver("deletedBy", resolverDeletedBy);
node.addPropertyResolver("typeIcon", this.resolverSmallIcon); node.addPropertyResolver("typeIcon", this.resolverSmallIcon);
itemNodes.add(node);
} }
else else
{ {
MapNode node = new MapNode(nodeRef, this.nodeService, false);
node.addPropertyResolver("locationPath", resolverLocationPath);
node.addPropertyResolver("displayPath", resolverDisplayPath);
node.addPropertyResolver("deletedDate", resolverDeletedDate);
node.addPropertyResolver("deletedBy", resolverDeletedBy);
node.addPropertyResolver("typeIcon", this.resolverFileType16); node.addPropertyResolver("typeIcon", this.resolverFileType16);
itemNodes.add(node);
} }
itemNodes.add(node);
} }
} }
} }
@@ -292,15 +363,12 @@ public class TrashcanBean implements IContextListener
private NodePropertyResolver resolverLocationPath = new NodePropertyResolver() { private NodePropertyResolver resolverLocationPath = new NodePropertyResolver() {
public Object get(Node node) { public Object get(Node node) {
//ChildAssociationRef childRef = (ChildAssociationRef)node.getProperties().get(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC);
//return nodeService.getPath(childRef.getChildRef());
return (Path)node.getProperties().get(ContentModel.PROP_ARCHIVED_ORIGINAL_PATH); return (Path)node.getProperties().get(ContentModel.PROP_ARCHIVED_ORIGINAL_PATH);
} }
}; };
private NodePropertyResolver resolverDisplayPath = new NodePropertyResolver() { private NodePropertyResolver resolverDisplayPath = new NodePropertyResolver() {
public Object get(Node node) { public Object get(Node node) {
//ChildAssociationRef childRef = (ChildAssociationRef)node.getProperties().get(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC);
return Repository.getDisplayPath((Path)node.getProperties().get(ContentModel.PROP_ARCHIVED_ORIGINAL_PATH)); return Repository.getDisplayPath((Path)node.getProperties().get(ContentModel.PROP_ARCHIVED_ORIGINAL_PATH));
} }
}; };
@@ -319,6 +387,20 @@ public class TrashcanBean implements IContextListener
} }
}; };
private NodePropertyResolver resolverFileType32 = new NodePropertyResolver() {
public Object get(Node node) {
return Utils.getFileTypeImage(node.getName(), false);
}
};
private NodePropertyResolver resolverLargeIcon = new NodePropertyResolver() {
public Object get(Node node) {
QNameNodeMap props = (QNameNodeMap)node.getProperties();
String icon = (String)props.getRaw("app:icon");
return "/images/icons/" + (icon != null ? icon : NewSpaceWizard.SPACE_ICON_DEFAULT) + ".gif";
}
};
private NodePropertyResolver resolverDeletedDate = new NodePropertyResolver() { private NodePropertyResolver resolverDeletedDate = new NodePropertyResolver() {
public Object get(Node node) { public Object get(Node node) {
return node.getProperties().get(ContentModel.PROP_ARCHIVED_DATE); return node.getProperties().get(ContentModel.PROP_ARCHIVED_DATE);
@@ -331,23 +413,42 @@ public class TrashcanBean implements IContextListener
} }
}; };
private NodePropertyResolver resolverIsFolder = new NodePropertyResolver() {
public Object get(Node node) {
return dictionaryService.isSubClass(node.getType(), ContentModel.TYPE_FOLDER);
}
};
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
// Action handlers // Action handlers
// TODO: // TODO:
// need the following Action Handlers: // need the following Action Handlers:
// deleteItemOK, recoverItemOK, deleteAllItemsOK, recoverAllItemsOK, recoverListedItemsOK, deleteListedItemsOK // deleteAllItemsOK, recoverAllItemsOK, recoverListedItemsOK, deleteListedItemsOK
/** /**
* Search the deleted item store by name * Search the deleted item store by name
*/ */
public void search(ActionEvent event) public void searchName(ActionEvent event)
{ {
// simply clear the current list and refresh the screen // simply clear the current list and refresh the screen
// the search query text will be found and processed by the getItems() method // the search query text will be found and processed by the getItems() method
contextUpdated(); contextUpdated();
this.showItems = true; this.showItems = true;
this.fullTextSearch = false;
}
/**
* Search the deleted item store by text
*/
public void searchContent(ActionEvent event)
{
// simply clear the current list and refresh the screen
// the search query text will be found and processed by the getItems() method
contextUpdated();
this.showItems = true;
this.fullTextSearch = true;
} }
/** /**
@@ -376,11 +477,24 @@ public class TrashcanBean implements IContextListener
NodeRef ref = new NodeRef(getArchiveRootRef().getStoreRef(), id); NodeRef ref = new NodeRef(getArchiveRootRef().getStoreRef(), id);
Node node = new Node(ref); Node node = new Node(ref);
// resolve icon in-case one has not been set node.addPropertyResolver("locationPath", resolverLocationPath);
//node.addPropertyResolver("icon", this.resolverSpaceIcon); node.addPropertyResolver("deletedDate", resolverDeletedDate);
node.addPropertyResolver("deletedBy", resolverDeletedBy);
node.addPropertyResolver("isFolder", resolverIsFolder);
if (this.dictionaryService.isSubClass(node.getType(), ContentModel.TYPE_FOLDER) == true &&
this.dictionaryService.isSubClass(node.getType(), ContentModel.TYPE_SYSTEM_FOLDER) == false)
{
node.addPropertyResolver("icon", this.resolverLargeIcon);
}
else
{
node.addPropertyResolver("icon", this.resolverFileType32);
}
// prepare a node for the action context // prepare a node for the action context
setItem(node); setItem(node);
setDestination(null);
} }
catch (InvalidNodeRefException refErr) catch (InvalidNodeRefException refErr)
{ {
@@ -397,6 +511,9 @@ public class TrashcanBean implements IContextListener
contextUpdated(); contextUpdated();
} }
/**
* Delete single item OK button handler
*/
public String deleteItemOK() public String deleteItemOK()
{ {
Node item = getItem(); Node item = getItem();
@@ -421,6 +538,9 @@ public class TrashcanBean implements IContextListener
return OUTCOME_DIALOGCLOSE; return OUTCOME_DIALOGCLOSE;
} }
/**
* Recover single item OK button handler
*/
public String recoverItemOK() public String recoverItemOK()
{ {
String outcome = null; String outcome = null;
@@ -434,7 +554,16 @@ public class TrashcanBean implements IContextListener
String msg; String msg;
FacesMessage errorfacesMsg = null; FacesMessage errorfacesMsg = null;
RestoreNodeReport report = this.nodeArchiveService.restoreArchivedNode(item.getNodeRef()); // restore the node - the user may have requested a restore to a different parent
RestoreNodeReport report;
if (this.destination == null)
{
report = this.nodeArchiveService.restoreArchivedNode(item.getNodeRef());
}
else
{
report = this.nodeArchiveService.restoreArchivedNode(item.getNodeRef(), this.destination, null, null);
}
switch (report.getStatus()) switch (report.getStatus())
{ {
case SUCCESS: case SUCCESS:
@@ -496,7 +625,7 @@ public class TrashcanBean implements IContextListener
*/ */
public void resetAll(ActionEvent event) public void resetAll(ActionEvent event)
{ {
// TODO: reset all filter and search // TODO: reset all filters
} }
/** /**
@@ -540,16 +669,43 @@ public class TrashcanBean implements IContextListener
String safeText = QueryParser.escape(this.searchText); String safeText = QueryParser.escape(this.searchText);
if (safeText.indexOf(' ') == -1) if (safeText.indexOf(' ') == -1)
{ {
query = String.format(SEARCH_NAME, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText, safeText); if (this.fullTextSearch)
{
query = String.format(SEARCH_TEXT, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText);
}
else
{
query = String.format(SEARCH_NAME, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText);
}
} }
else else
{ {
query = String.format(SEARCH_NAME_QUOTED, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText, safeText); if (this.fullTextSearch)
{
query = String.format(SEARCH_TEXT_QUOTED, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText);
}
else
{
query = String.format(SEARCH_NAME_QUOTED, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText);
}
} }
} }
if (isAdminUser() == false)
{
// prefix username clause
String username = Application.getCurrentUser(FacesContext.getCurrentInstance()).getUserName();
query = String.format(SEARCH_USERPREFIX, username) + query;
}
return query; return query;
} }
private boolean isAdminUser()
{
return Application.getCurrentUser(FacesContext.getCurrentInstance()).isAdmin();
}
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
// IContextListener implementation // IContextListener implementation

View File

@@ -92,70 +92,73 @@ public class NodePathLinkRenderer extends BaseRenderer
{ {
path = (Path)val; path = (Path)val;
} }
else else if (val != null)
{ {
throw new IllegalArgumentException("UINodePath component 'value' property must resolve to a NodeRef or Path!"); throw new IllegalArgumentException("UINodePath component 'value' property must resolve to a NodeRef or Path!");
} }
boolean isBreadcrumb = false; if (val != null)
Boolean breadcrumb = (Boolean)component.getAttributes().get("breadcrumb");
if (breadcrumb != null)
{ {
isBreadcrumb = breadcrumb.booleanValue(); boolean isBreadcrumb = false;
} Boolean breadcrumb = (Boolean)component.getAttributes().get("breadcrumb");
if (breadcrumb != null)
boolean isDisabled = false;
Boolean disabled = (Boolean)component.getAttributes().get("disabled");
if (disabled != null)
{
isDisabled = disabled.booleanValue();
}
boolean showLeaf = false;
Boolean showLeafBool = (Boolean)component.getAttributes().get("showLeaf");
if (showLeafBool != null)
{
showLeaf = showLeafBool.booleanValue();
}
// use Spring JSF integration to get the node service bean
NodeService service = getNodeService(context);
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance(), true);
tx.begin();
if (path == null)
{ {
path = service.getPath(nodeRef); isBreadcrumb = breadcrumb.booleanValue();
} }
if (isBreadcrumb == false || isDisabled == true) boolean isDisabled = false;
Boolean disabled = (Boolean)component.getAttributes().get("disabled");
if (disabled != null)
{ {
out.write(buildPathAsSingular(context, component, path, showLeaf, isDisabled)); isDisabled = disabled.booleanValue();
}
else
{
out.write(buildPathAsBreadcrumb(context, component, path, showLeaf));
} }
tx.commit(); boolean showLeaf = false;
} Boolean showLeafBool = (Boolean)component.getAttributes().get("showLeaf");
catch (InvalidNodeRefException refErr) if (showLeafBool != null)
{ {
// this error simple means we cannot output the path showLeaf = showLeafBool.booleanValue();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} }
}
catch (AccessDeniedException accessErr) // use Spring JSF integration to get the node service bean
{ NodeService service = getNodeService(context);
// this error simple means we cannot output the path UserTransaction tx = null;
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} try
} {
catch (Throwable err) tx = Repository.getUserTransaction(FacesContext.getCurrentInstance(), true);
{ tx.begin();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
throw new RuntimeException(err); if (path == null)
{
path = service.getPath(nodeRef);
}
if (isBreadcrumb == false || isDisabled == true)
{
out.write(buildPathAsSingular(context, component, path, showLeaf, isDisabled));
}
else
{
out.write(buildPathAsBreadcrumb(context, component, path, showLeaf));
}
tx.commit();
}
catch (InvalidNodeRefException refErr)
{
// this error simple means we cannot output the path
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
catch (AccessDeniedException accessErr)
{
// this error simple means we cannot output the path
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
catch (Throwable err)
{
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
throw new RuntimeException(err);
}
} }
} }

View File

@@ -923,6 +923,10 @@
<from-outcome>deleteListedItems</from-outcome> <from-outcome>deleteListedItems</from-outcome>
<to-view-id>/jsp/trashcan/delete-listed.jsp</to-view-id> <to-view-id>/jsp/trashcan/delete-listed.jsp</to-view-id>
</navigation-case> </navigation-case>
<navigation-case>
<from-outcome>itemDetails</from-outcome>
<to-view-id>/jsp/trashcan/item-details.jsp</to-view-id>
</navigation-case>
</navigation-rule> </navigation-rule>
</faces-config> </faces-config>

View File

@@ -393,6 +393,15 @@ a.topToolbarLinkHighlight, a.topToolbarLinkHighlight:link, a.topToolbarLinkHighl
padding-top: 3px; padding-top: 3px;
} }
.filterBorders
{
padding: 2px;
background-color: #cddbe8;
border-width: 1px;
border-style: solid;
border-color: #003366;
}
.wizardSectionHeading .wizardSectionHeading
{ {
padding: 2px; padding: 2px;

View File

@@ -0,0 +1,201 @@
<%--
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="64kb" contentType="text/html;charset=UTF-8" %>
<%@ page isELIgnored="false" %>
<%@ page import="org.alfresco.web.ui.common.PanelGenerator" %>
<r:page titleId="title_deleted_item_details">
<f:view>
<%-- load a bundle of properties with I18N strings --%>
<f:loadBundle basename="alfresco.messages.webclient" var="msg"/>
<h:form acceptCharset="UTF-8" id="deleteditem-details">
<%-- Main outer table --%>
<table cellspacing="0" cellpadding="2">
<%-- Title bar --%>
<tr>
<td colspan="2">
<%@ include file="../parts/titlebar.jsp" %>
</td>
</tr>
<%-- Main area --%>
<tr valign="top">
<%-- Shelf --%>
<td>
<%@ include file="../parts/shelf.jsp" %>
</td>
<%-- Work Area --%>
<td width="100%">
<table cellspacing="0" cellpadding="0" width="100%">
<%-- Breadcrumb --%>
<%@ include file="../parts/breadcrumb.jsp" %>
<%-- Status and Actions --%>
<tr>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/statuspanel_4.gif)" width="4"></td>
<td bgcolor="#EEEEEE">
<%-- Status and Actions inner contents table --%>
<%-- Generally this consists of an icon, textual summary and actions for the current object --%>
<table cellspacing="4" cellpadding="0" width="100%">
<tr>
<td width="32">
<img src="<%=request.getContextPath()%>/images/icons/details_large.gif" width=32 height=32>
</td>
<td>
<div class="mainTitle">
<h:outputText value="#{msg.details_of}" /> '<h:outputText value="#{TrashcanBean.item.name}" />'
</div>
<div class="mainSubText">
<h:outputText value="#{msg.original_location}" />: <r:nodePath value="#{TrashcanBean.item.properties.locationPath}" breadcrumb="true" actionListener="#{BrowseBean.clickSpacePath}" />
</div>
<div class="mainSubText"><h:outputText value="#{msg.deleteditem_details_description}" /></div>
</td>
</tr>
</table>
</td>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/statuspanel_6.gif)" width="4"></td>
</tr>
<%-- separator row with gradient shadow --%>
<tr>
<td><img src="<%=request.getContextPath()%>/images/parts/statuspanel_7.gif" width="4" height="9"></td>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/statuspanel_8.gif)"></td>
<td><img src="<%=request.getContextPath()%>/images/parts/statuspanel_9.gif" width="4" height="9"></td>
</tr>
<%-- Details --%>
<tr valign=top>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/whitepanel_4.gif)" width="4"></td>
<td>
<table cellspacing="0" cellpadding="3" border="0" width="100%">
<tr>
<td width="100%" valign="top">
<a:panel label="#{msg.view_links}" id="link-panel" progressive="true"
border="white" bgcolor="white" titleBorder="blue" titleBgcolor="#D3E6FE">
<table width="100%" cellspacing="2" cellpadding="2" border="0" align="center">
<tr>
<td>
<a:actionLink value="#{msg.view_in_browser}" href="#{TrashcanBean.itemBrowserUrl}" target="new" id="link1" rendered="#{TrashcanBean.item.properties.isFolder == false}" />
</td>
<td>
<a:actionLink value="#{msg.download_content}" href="#{TrashcanBean.itemDownloadUrl}" target="new" id="link2" rendered="#{TrashcanBean.item.properties.isFolder == false}" />
</td>
<td>
<a href='<a:outputText value="#{TrashcanBean.itemNodeRefUrl}" id="out1" />' onclick="return false;"><a:outputText value="#{msg.noderef_link}" id="out4" /></a>
</td>
</tr>
</table>
</a:panel>
<div style="padding:4px"></div>
<a:panel label="#{msg.properties}" id="properties-panel" progressive="true"
border="white" bgcolor="white" titleBorder="blue" titleBgcolor="#D3E6FE">
<table cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td width=80 align=center>
<%-- icon image for the object --%>
<table cellspacing=0 cellpadding=0 border=0>
<tr>
<td>
<div style="border: thin solid #CCCCCC; padding:4px">
<a:actionLink id="logo-content" value="#{TrashcanBean.item.name}" href="#{TrashcanBean.itemDownloadUrl}" target="new" rendered="#{TrashcanBean.item.properties.isFolder == false}"
image="#{TrashcanBean.item.properties.icon}" showLink="false" />
<a:actionLink id="logo-folder" value="#{TrashcanBean.item.name}" rendered="#{TrashcanBean.item.properties.isFolder == true}"
image="#{TrashcanBean.item.properties.icon}" showLink="false" />
</div>
</td>
<td><img src="<%=request.getContextPath()%>/images/parts/rightSideShadow42.gif" width=6 height=42></td>
</tr>
<tr>
<td colspan=2><img src="<%=request.getContextPath()%>/images/parts/bottomShadow42.gif" width=48 height=5></td>
</tr>
</table>
</td>
<td>
<%-- properties for the item --%>
<r:propertySheetGrid id="item-props" value="#{TrashcanBean.item}" var="itemProps"
columns="1" mode="view" labelStyleClass="propertiesLabel" externalConfig="true" />
<h:messages globalOnly="true" id="props-msgs" styleClass="errorMessage" layout="table" />
<h:message for="item-props" styleClass="statusMessage" />
</td>
</tr>
</table>
</a:panel>
</td>
<td valign="top">
<% PanelGenerator.generatePanelStart(out, request.getContextPath(), "blue", "#D3E6FE"); %>
<table cellpadding="1" cellspacing="1" border="0" width="100%">
<tr>
<td align="center">
<h:commandButton value="#{msg.close}" action="dialog:close" styleClass="wizardButton" />
</td>
</tr>
</table>
<% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "blue"); %>
<div style="padding:4px"></div>
<%-- Item Actions --%>
<a:panel label="#{msg.actions}" id="actions-panel" border="white" bgcolor="white" titleBorder="blue" titleBgcolor="#D3E6FE" style="text-align:center;white-space:nowrap" progressive="true">
<a:actionLink value="#{msg.recover}" image="/images/icons/recover.gif" action="dialog:recoverItem" padding="3">
<f:param name="id" value="#{TrashcanBean.item.id}" />
</a:actionLink>
<a:actionLink value="#{msg.delete}" image="/images/icons/delete.gif" action="dialog:deleteItem" padding="3">
<f:param name="id" value="#{TrashcanBean.item.id}" />
</a:actionLink>
</a:panel>
</td>
</tr>
</table>
</td>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/whitepanel_6.gif)" width="4"></td>
</tr>
<%-- separator row with bottom panel graphics --%>
<tr>
<td><img src="<%=request.getContextPath()%>/images/parts/whitepanel_7.gif" width="4" height="4"></td>
<td width="100%" align="center" style="background-image: url(<%=request.getContextPath()%>/images/parts/whitepanel_8.gif)"></td>
<td><img src="<%=request.getContextPath()%>/images/parts/whitepanel_9.gif" width="4" height="4"></td>
</tr>
</table>
</td>
</tr>
</table>
</h:form>
</f:view>
</r:page>

View File

@@ -98,14 +98,41 @@
<% PanelGenerator.generatePanelStart(out, request.getContextPath(), "white", "white"); %> <% PanelGenerator.generatePanelStart(out, request.getContextPath(), "white", "white"); %>
<table cellpadding="2" cellspacing="2" border="0"> <table cellpadding="2" cellspacing="2" border="0">
<tr> <tr>
<td class="mainSubTitle"> <td colspan=2 class="mainSubTitle">
<h:outputFormat value="#{msg.recover_item_confirm}"> <h:outputFormat value="#{msg.recover_item_confirm}">
<f:param value="#{TrashcanBean.item.name}"/> <f:param value="#{TrashcanBean.item.name}"/>
</h:outputFormat> </h:outputFormat>
</td> </td>
</tr> </tr>
<tr><td colspan=2 class="paddingRow"></td></tr>
<tr> <tr>
<td colspan=2>
<% PanelGenerator.generatePanelStart(out, request.getContextPath(), "yellowInner", "#ffffcc"); %>
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tr>
<td valign=top style="padding-top:2px" width=20><h:graphicImage url="/images/icons/info_icon.gif" width="16" height="16"/></td>
<td class="mainSubText">
<h:outputText value="#{msg.alternative_destination}" />
</td>
</tr>
</table>
<% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "yellowInner"); %>
</td>
</tr>
<tr><td colspan=2 class="paddingRow"></td></tr>
<tr>
<td> <td>
<h:outputText value="#{msg.destination}" />:&nbsp;
</td>
<td width=100%>
<r:spaceSelector id="space-selector" label="#{msg.select_destination_prompt}"
value="#{TrashcanBean.destination}" styleClass="selector" />
</td>
</tr>
<tr><td colspan=2 class="paddingRow"></td></tr>
<tr>
<td colspan=2>
<%-- Error Messages --%> <%-- Error Messages --%>
<%-- messages tag to show messages not handled by other specific message tags --%> <%-- messages tag to show messages not handled by other specific message tags --%>
<h:messages globalOnly="true" styleClass="errorMessage" layout="table" /> <h:messages globalOnly="true" styleClass="errorMessage" layout="table" />

View File

@@ -40,11 +40,13 @@
{ {
if (document.getElementById("trashcan:search-text").value.length == 0) if (document.getElementById("trashcan:search-text").value.length == 0)
{ {
document.getElementById("trashcan:search-btn").disabled = true; document.getElementById("trashcan:search-btn1").disabled = true;
document.getElementById("trashcan:search-btn2").disabled = true;
} }
else else
{ {
document.getElementById("trashcan:search-btn").disabled = false; document.getElementById("trashcan:search-btn1").disabled = false;
document.getElementById("trashcan:search-btn2").disabled = false;
} }
} }
</script> </script>
@@ -123,7 +125,7 @@
<td width="100%" valign="top"> <td width="100%" valign="top">
<%-- Deleted Items List --%> <%-- Deleted Items List --%>
<a:panel id="trashcan-panel" border="white" bgcolor="white" titleBorder="blue" titleBgcolor="#D3E6FE" styleClass="mainSubTitle" label="#{msg.deleted_items}"> <a:panel id="trashcan-panel" border="white" bgcolor="white" titleBorder="blue" titleBgcolor="#D3E6FE" styleClass="mainSubTitle" label="#{TrashcanBean.panelMessage}">
<% PanelGenerator.generatePanelStart(out, request.getContextPath(), "yellowInner", "#ffffcc"); %> <% PanelGenerator.generatePanelStart(out, request.getContextPath(), "yellowInner", "#ffffcc"); %>
<table cellpadding="0" cellspacing="0" border="0" width="100%"> <table cellpadding="0" cellspacing="0" border="0" width="100%">
@@ -139,18 +141,35 @@
<%-- Search controls --%> <%-- Search controls --%>
<div style="padding: 4px;"></div> <div style="padding: 4px;"></div>
<h:inputText id="search-text" value="#{TrashcanBean.searchText}" size="35" maxlength="1024" onkeyup="updateButtonState();" onchange="updateButtonState();" />&nbsp; <h:inputText id="search-text" value="#{TrashcanBean.searchText}" size="35" maxlength="1024" onkeyup="updateButtonState();" onchange="updateButtonState();" />&nbsp;
<h:commandButton id="search-btn" value="#{msg.search_deleted_items}" actionListener="#{TrashcanBean.search}" disabled="true" />&nbsp; <h:commandButton id="search-btn1" value="#{msg.search_deleted_items_name}" actionListener="#{TrashcanBean.searchName}" disabled="true" />&nbsp;
<h:commandButton id="search-btn2" value="#{msg.search_deleted_items_text}" actionListener="#{TrashcanBean.searchContent}" disabled="true" />&nbsp;
<h:commandButton id="clear-btn" value="#{msg.show_all}" actionListener="#{TrashcanBean.clearSearch}" /> <h:commandButton id="clear-btn" value="#{msg.show_all}" actionListener="#{TrashcanBean.clearSearch}" />
<div style="padding: 4px;"></div> <div style="padding: 4px;"></div>
<%-- Filter controls --%> <%-- Filter controls --%>
<table cellspacing=2 cellpadding=0 width=100%> <table cellspacing=2 cellpadding=0 width=100%>
<tr> <tr>
<td>...TODO: Date filter here...</td> <td class="filterBorders" width=100%>
<table cellspacing=2 cellpadding=0 width=100%>
<tr>
<td><img src="<%=request.getContextPath()%>/images/icons/filter.gif" width=16 height=16></td>
<td style="padding-left:8px"><nobr><h:outputText value="#{msg.deleted_when}" />:</nobr></td>
<td style="padding-left:12px" width=100%><b>All</b>&nbsp;&nbsp;Today&nbsp;&nbsp;This&nbsp;&nbsp;Week&nbsp;&nbsp;This Month</td>
</tr>
</table>
</td>
<td align=right><h:commandButton id="reset-btn" value="#{msg.resetall}" actionListener="#{TrashcanBean.resetAll}" /></td> <td align=right><h:commandButton id="reset-btn" value="#{msg.resetall}" actionListener="#{TrashcanBean.resetAll}" /></td>
</tr> </tr>
<tr> <tr>
<td>...TODO: Username filter here - admin only...</td> <td class="filterBorders" width=100%>
<table cellspacing=2 cellpadding=0 width=100%>
<tr>
<td><img src="<%=request.getContextPath()%>/images/icons/filter.gif" width=16 height=16></td>
<td style="padding-left:8px"><nobr><h:outputText value="#{msg.deleted_user}" />:</nobr></td>
<td style="padding-left:12px" width=100%><b>All</b>&nbsp;&nbsp;User&nbsp;<h:inputText id="user-search" size="12" maxlength="100" style="font-size:10px" onkeyup="" /></td>
</tr>
</table>
</td>
<td></td> <td></td>
</tr> </tr>
</table> </table>
@@ -158,9 +177,9 @@
<%-- TODO: only show user filter for admin user --%> <%-- TODO: only show user filter for admin user --%>
<div style="padding: 4px;"></div> <div style="padding: 4px;"></div>
<%-- Recover Listed Items button --%> <%-- Recover Listed Items actions --%>
<h:commandButton value="#{msg.recover_listed_items}" action="dialog:recoverListedItems" />&nbsp; <a:actionLink value="#{msg.recover_listed_items}" image="/images/icons/recover_all.gif" action="dialog:recoverListedItems" />&nbsp;
<h:commandButton value="#{msg.delete_listed_items}" action="dialog:deleteListedItems" /> <a:actionLink value="#{msg.delete_listed_items}" image="/images/icons/delete_all.gif" action="dialog:deleteListedItems"/>
<div style="padding: 4px;"></div> <div style="padding: 4px;"></div>
<a:richList id="trashcan-list" binding="#{TrashcanBean.itemsRichList}" viewMode="details" pageSize="10" <a:richList id="trashcan-list" binding="#{TrashcanBean.itemsRichList}" viewMode="details" pageSize="10"
@@ -168,14 +187,18 @@
value="#{TrashcanBean.items}" var="r" initialSortColumn="deletedDate" initialSortDescending="true"> value="#{TrashcanBean.items}" var="r" initialSortColumn="deletedDate" initialSortDescending="true">
<%-- Primary column showing item name --%> <%-- Primary column showing item name --%>
<a:column primary="true" width="200" style="padding:2px;text-align:left"> <a:column primary="true" width="150" style="padding:2px;text-align:left">
<f:facet name="header"> <f:facet name="header">
<a:sortLink label="#{msg.name}" value="name" mode="case-insensitive" styleClass="header"/> <a:sortLink label="#{msg.name}" value="name" mode="case-insensitive" styleClass="header"/>
</f:facet> </f:facet>
<f:facet name="small-icon"> <f:facet name="small-icon">
<a:actionLink value="#{r.name}" href="#{r.url}" target="new" image="#{r.typeIcon}" showLink="false" styleClass="inlineAction" /> <a:actionLink value="#{r.name}" action="dialog:itemDetails" actionListener="#{TrashcanBean.setupItemAction}" image="#{r.typeIcon}" showLink="false" styleClass="inlineAction">
<f:param name="id" value="#{r.id}" />
</a:actionLink>
</f:facet> </f:facet>
<a:actionLink value="#{r.name}" href="#{r.url}" target="new" /> <a:actionLink value="#{r.name}" action="dialog:itemDetails" actionListener="#{TrashcanBean.setupItemAction}">
<f:param name="id" value="#{r.id}" />
</a:actionLink>
</a:column> </a:column>
<%-- Original Location Path column --%> <%-- Original Location Path column --%>
@@ -183,11 +206,11 @@
<f:facet name="header"> <f:facet name="header">
<a:sortLink label="#{msg.original_location}" value="displayPath" styleClass="header"/> <a:sortLink label="#{msg.original_location}" value="displayPath" styleClass="header"/>
</f:facet> </f:facet>
<r:nodePath value="#{r.locationPath}" actionListener="#{BrowseBean.clickSpacePath}" /> <r:nodePath value="#{r.locationPath}" actionListener="#{BrowseBean.clickSpacePath}" showLeaf="#{r.isFolder == false}" />
</a:column> </a:column>
<%-- Deleted Date column --%> <%-- Deleted Date column --%>
<a:column style="text-align:left"> <a:column style="text-align:left;white-space:nowrap">
<f:facet name="header"> <f:facet name="header">
<a:sortLink label="#{msg.deleted_date}" value="deletedDate" styleClass="header"/> <a:sortLink label="#{msg.deleted_date}" value="deletedDate" styleClass="header"/>
</f:facet> </f:facet>