. Soft Delete UI checkpoint
- List of deleted items for the Admin user - Search for deleted items by Name and full-text - First pass at Recover single item - First pass at Delete single item - Icons for Soft Delete UI from Linton git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2801 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
@@ -778,6 +778,7 @@ 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
|
||||||
search_deleted_items=Search Deleted Items
|
search_deleted_items=Search Deleted Items
|
||||||
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
|
||||||
@@ -797,6 +798,12 @@ delete_listed_items_confirm=Are you sure you want to permanently delete the list
|
|||||||
recover_listed_items=Recover Listed Items
|
recover_listed_items=Recover Listed Items
|
||||||
recover_listed_items_info=Recover the listed files and spaces from the deleted file store
|
recover_listed_items_info=Recover the listed files and spaces from the deleted file store
|
||||||
recover_listed_items_confirm=Are you sure you want to recover the listed deleted files and spaces from the deleted file store?
|
recover_listed_items_confirm=Are you sure you want to recover the listed deleted files and spaces from the deleted file store?
|
||||||
|
recovered_item_success=The item \"{0}\" has been successfully recovered.
|
||||||
|
recovered_item_parent=Failed to recover the item \"{0}\" as the original parent folder is missing, please select a new folder destination.
|
||||||
|
recovered_item_permission=Failed to recover the item \"{0}\" as you do not have the appropriate permissions to restore the item to the original parent folder, 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}
|
||||||
|
delete_item_success=The item \"{0}\" has been permanently deleted.
|
||||||
|
|
||||||
# Admin Console messages
|
# Admin Console messages
|
||||||
title_admin_console=Administration Console
|
title_admin_console=Administration Console
|
||||||
|
@@ -378,6 +378,7 @@
|
|||||||
</permissions>
|
</permissions>
|
||||||
<label-id>manage_deleted_items</label-id>
|
<label-id>manage_deleted_items</label-id>
|
||||||
<image>/images/icons/trashcan.gif</image>
|
<image>/images/icons/trashcan.gif</image>
|
||||||
|
<action-listener>#{TrashcanBean.setupTrashcan}</action-listener>
|
||||||
<action>dialog:manageDeletedItems</action>
|
<action>dialog:manageDeletedItems</action>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
@@ -16,13 +16,41 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.web.bean;
|
package org.alfresco.web.bean;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.faces.application.FacesMessage;
|
||||||
|
import javax.faces.context.FacesContext;
|
||||||
|
import javax.faces.event.ActionEvent;
|
||||||
|
import javax.transaction.UserTransaction;
|
||||||
|
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.repo.node.archive.NodeArchiveService;
|
||||||
|
import org.alfresco.repo.node.archive.RestoreNodeReport;
|
||||||
|
import org.alfresco.repo.node.archive.RestoreNodeReport.RestoreStatus;
|
||||||
|
import org.alfresco.repo.search.impl.lucene.QueryParser;
|
||||||
|
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||||
|
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
|
import org.alfresco.service.cmr.repository.Path;
|
||||||
|
import org.alfresco.service.cmr.search.ResultSet;
|
||||||
|
import org.alfresco.service.cmr.search.ResultSetRow;
|
||||||
|
import org.alfresco.service.cmr.search.SearchParameters;
|
||||||
import org.alfresco.service.cmr.search.SearchService;
|
import org.alfresco.service.cmr.search.SearchService;
|
||||||
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.alfresco.web.app.Application;
|
||||||
import org.alfresco.web.app.context.IContextListener;
|
import org.alfresco.web.app.context.IContextListener;
|
||||||
|
import org.alfresco.web.bean.repository.MapNode;
|
||||||
import org.alfresco.web.bean.repository.Node;
|
import org.alfresco.web.bean.repository.Node;
|
||||||
|
import org.alfresco.web.bean.repository.NodePropertyResolver;
|
||||||
|
import org.alfresco.web.bean.repository.QNameNodeMap;
|
||||||
|
import org.alfresco.web.bean.repository.Repository;
|
||||||
|
import org.alfresco.web.ui.common.Utils;
|
||||||
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,17 +58,52 @@ import org.alfresco.web.ui.common.component.data.UIRichList;
|
|||||||
*/
|
*/
|
||||||
public class TrashcanBean implements IContextListener
|
public class TrashcanBean implements IContextListener
|
||||||
{
|
{
|
||||||
|
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_PARENT = "recovered_item_parent";
|
||||||
|
private static final String MSG_RECOVERED_ITEM_FAILURE = "recovered_item_failure";
|
||||||
|
private static final String MSG_RECOVERED_ITEM_SUCCESS = "recovered_item_success";
|
||||||
|
|
||||||
|
private static final String OUTCOME_DIALOGCLOSE = "dialog:close";
|
||||||
|
|
||||||
|
private static final String RICHLIST_ID = "trashcan-list";
|
||||||
|
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 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_QUOTED = "PARENT:\"%s\" AND ASPECT:\"%s\" AND (@" + NAME_ATTR + ":\"%s\" TEXT:\"%s\")";
|
||||||
|
|
||||||
/** NodeService bean reference */
|
/** NodeService bean reference */
|
||||||
protected NodeService nodeService;
|
protected NodeService nodeService;
|
||||||
|
|
||||||
|
/** NodeArchiveService bean reference */
|
||||||
|
protected NodeArchiveService nodeArchiveService;
|
||||||
|
|
||||||
/** SearchService bean reference */
|
/** SearchService bean reference */
|
||||||
protected SearchService searchService;
|
protected SearchService searchService;
|
||||||
|
|
||||||
|
/** The DictionaryService bean reference */
|
||||||
|
protected DictionaryService dictionaryService;
|
||||||
|
|
||||||
/** Component reference for Deleted Items RichList control */
|
/** Component reference for Deleted Items RichList control */
|
||||||
protected UIRichList itemsRichList;
|
protected UIRichList itemsRichList;
|
||||||
|
|
||||||
/** Search text */
|
/** Search text */
|
||||||
private String searchText;
|
private String searchText = null;
|
||||||
|
|
||||||
|
/** We show an empty list until a Search or Show All is executed */
|
||||||
|
private boolean showItems = false;
|
||||||
|
|
||||||
|
/** Currently listed items */
|
||||||
|
private List<Node> listedItems = Collections.<Node>emptyList();
|
||||||
|
|
||||||
|
/** Current action context Node */
|
||||||
|
private Node actionNode;
|
||||||
|
|
||||||
|
/** Root node to the spaces store archive store*/
|
||||||
|
private NodeRef archiveRootRef = null;
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------
|
||||||
@@ -55,13 +118,29 @@ public class TrashcanBean implements IContextListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param searchService the search service
|
* @param searchService The search service
|
||||||
*/
|
*/
|
||||||
public void setSearchService(SearchService searchService)
|
public void setSearchService(SearchService searchService)
|
||||||
{
|
{
|
||||||
this.searchService = searchService;
|
this.searchService = searchService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param nodeArchiveService The nodeArchiveService to set.
|
||||||
|
*/
|
||||||
|
public void setNodeArchiveService(NodeArchiveService nodeArchiveService)
|
||||||
|
{
|
||||||
|
this.nodeArchiveService = nodeArchiveService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param dictionaryService The DictionaryService to set.
|
||||||
|
*/
|
||||||
|
public void setDictionaryService(DictionaryService dictionaryService)
|
||||||
|
{
|
||||||
|
this.dictionaryService = dictionaryService;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns the itemsRichList.
|
* @return Returns the itemsRichList.
|
||||||
*/
|
*/
|
||||||
@@ -94,31 +173,382 @@ public class TrashcanBean implements IContextListener
|
|||||||
this.searchText = searchText;
|
this.searchText = searchText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the listed items.
|
||||||
|
*/
|
||||||
|
public List<Node> getListedItems()
|
||||||
|
{
|
||||||
|
return this.listedItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param listedItems The listed items to set.
|
||||||
|
*/
|
||||||
|
public void setListedItems(List<Node> listedItems)
|
||||||
|
{
|
||||||
|
this.listedItems = listedItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param node The item context for the current action
|
||||||
|
*/
|
||||||
|
public void setItem(Node node)
|
||||||
|
{
|
||||||
|
this.actionNode = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the item context for the current action
|
||||||
|
*/
|
||||||
|
public Node getItem()
|
||||||
|
{
|
||||||
|
return this.actionNode;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the list of deleted items to display
|
* @return the list of deleted items to display
|
||||||
*/
|
*/
|
||||||
public List<Node> getItems()
|
public List<Node> getItems()
|
||||||
{
|
{
|
||||||
// TODO: need the following MapNode properties:
|
// to get deleted items from deleted items store
|
||||||
// deletedDate, locationPath, displayPath, deletedUsername [only for admin user]
|
// use a search to find the items - also filters by name/username
|
||||||
// TODO: get deleted items from deleted items store
|
List<Node> itemNodes = null;
|
||||||
// use a search - also use filters by name/username
|
|
||||||
return Collections.<Node>emptyList();
|
UserTransaction tx = null;
|
||||||
|
ResultSet results = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance(), true);
|
||||||
|
tx.begin();
|
||||||
|
|
||||||
|
// get the root node to the deleted items store
|
||||||
|
if (getArchiveRootRef() != null && this.showItems == true)
|
||||||
|
{
|
||||||
|
String query = getSearchQuery();
|
||||||
|
SearchParameters sp = new SearchParameters();
|
||||||
|
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
|
||||||
|
sp.setQuery(query);
|
||||||
|
sp.addStore(getArchiveRootRef().getStoreRef()); // the Archived Node store
|
||||||
|
|
||||||
|
results = this.searchService.query(sp);
|
||||||
|
itemNodes = new ArrayList<Node>(results.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (results != null && results.length() != 0)
|
||||||
|
{
|
||||||
|
for (ResultSetRow row : results)
|
||||||
|
{
|
||||||
|
NodeRef nodeRef = row.getNodeRef();
|
||||||
|
|
||||||
|
if (this.nodeService.exists(nodeRef))
|
||||||
|
{
|
||||||
|
QName type = this.nodeService.getType(nodeRef);
|
||||||
|
|
||||||
|
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) == true &&
|
||||||
|
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);
|
||||||
|
itemNodes.add(node);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
itemNodes.add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.commit();
|
||||||
|
}
|
||||||
|
catch (Throwable err)
|
||||||
|
{
|
||||||
|
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
|
||||||
|
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), new Object[] {err.getMessage()}), err );
|
||||||
|
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (results != null)
|
||||||
|
{
|
||||||
|
results.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.listedItems = (itemNodes != null ? itemNodes : Collections.<Node>emptyList());
|
||||||
|
|
||||||
|
return this.listedItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private NodePropertyResolver resolverLocationPath = new NodePropertyResolver() {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private NodePropertyResolver resolverDisplayPath = new NodePropertyResolver() {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private NodePropertyResolver resolverFileType16 = new NodePropertyResolver() {
|
||||||
|
public Object get(Node node) {
|
||||||
|
return Utils.getFileTypeImage(node.getName(), true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private NodePropertyResolver resolverSmallIcon = 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 + "-16.gif" : BrowseBean.SPACE_SMALL_DEFAULT + ".gif");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private NodePropertyResolver resolverDeletedDate = new NodePropertyResolver() {
|
||||||
|
public Object get(Node node) {
|
||||||
|
return node.getProperties().get(ContentModel.PROP_ARCHIVED_DATE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private NodePropertyResolver resolverDeletedBy = new NodePropertyResolver() {
|
||||||
|
public Object get(Node node) {
|
||||||
|
return node.getProperties().get(ContentModel.PROP_ARCHIVED_BY);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------
|
||||||
// Action handlers
|
// Action handlers
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// need the following navigation outcomes
|
|
||||||
// DONE deleteItem, recoverItem, recoverAllItems, deleteAllItems, recoverListedItems, deleteListedItems
|
|
||||||
// need the following Action Handlers:
|
// need the following Action Handlers:
|
||||||
// deleteItemOK, recoverItemOK, deleteAllItemsOK, recoverAllItemsOK, recoverListedItemsOK, deleteListedItemsOK
|
// deleteItemOK, recoverItemOK, deleteAllItemsOK, recoverAllItemsOK, recoverListedItemsOK, deleteListedItemsOK
|
||||||
// and following Action Event Handlers:
|
|
||||||
// setupItemAction, search
|
/**
|
||||||
// and following getters:
|
* Search the deleted item store by name
|
||||||
// listedItems, item (setup by setupItemAction!)
|
*/
|
||||||
|
public void search(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action handler to clear the current search results and show all items
|
||||||
|
*/
|
||||||
|
public void clearSearch(ActionEvent event)
|
||||||
|
{
|
||||||
|
contextUpdated();
|
||||||
|
this.searchText = null;
|
||||||
|
this.showItems = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action handler called to prepare the selected item for an action
|
||||||
|
*/
|
||||||
|
public void setupItemAction(ActionEvent event)
|
||||||
|
{
|
||||||
|
UIActionLink link = (UIActionLink)event.getComponent();
|
||||||
|
Map<String, String> params = link.getParameterMap();
|
||||||
|
String id = params.get("id");
|
||||||
|
if (id != null && id.length() != 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// create the node ref, then our node representation
|
||||||
|
NodeRef ref = new NodeRef(getArchiveRootRef().getStoreRef(), id);
|
||||||
|
Node node = new Node(ref);
|
||||||
|
|
||||||
|
// resolve icon in-case one has not been set
|
||||||
|
//node.addPropertyResolver("icon", this.resolverSpaceIcon);
|
||||||
|
|
||||||
|
// prepare a node for the action context
|
||||||
|
setItem(node);
|
||||||
|
}
|
||||||
|
catch (InvalidNodeRefException refErr)
|
||||||
|
{
|
||||||
|
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
|
||||||
|
FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {id}) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setItem(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the UI state in preparation for finishing the next action
|
||||||
|
contextUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String deleteItemOK()
|
||||||
|
{
|
||||||
|
Node item = getItem();
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.nodeArchiveService.purgeArchivedNode(item.getNodeRef());
|
||||||
|
|
||||||
|
FacesContext fc = FacesContext.getCurrentInstance();
|
||||||
|
String msg = MessageFormat.format(
|
||||||
|
Application.getMessage(fc, "delete_item_success"), item.getName());
|
||||||
|
FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg);
|
||||||
|
fc.addMessage(RICHLIST_MSG_ID, facesMsg);
|
||||||
|
}
|
||||||
|
catch (Throwable err)
|
||||||
|
{
|
||||||
|
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
|
||||||
|
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OUTCOME_DIALOGCLOSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String recoverItemOK()
|
||||||
|
{
|
||||||
|
String outcome = null;
|
||||||
|
|
||||||
|
Node item = getItem();
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
FacesContext fc = FacesContext.getCurrentInstance();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String msg;
|
||||||
|
FacesMessage errorfacesMsg = null;
|
||||||
|
|
||||||
|
RestoreNodeReport report = this.nodeArchiveService.restoreArchivedNode(item.getNodeRef());
|
||||||
|
switch (report.getStatus())
|
||||||
|
{
|
||||||
|
case SUCCESS:
|
||||||
|
msg = MessageFormat.format(
|
||||||
|
Application.getMessage(fc, MSG_RECOVERED_ITEM_SUCCESS), item.getName());
|
||||||
|
FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg);
|
||||||
|
fc.addMessage(RICHLIST_MSG_ID, facesMsg);
|
||||||
|
outcome = OUTCOME_DIALOGCLOSE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FAILURE_INVALID_PARENT:
|
||||||
|
msg = MessageFormat.format(
|
||||||
|
Application.getMessage(fc, MSG_RECOVERED_ITEM_PARENT), item.getName());
|
||||||
|
errorfacesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FAILURE_PERMISSION:
|
||||||
|
msg = MessageFormat.format(
|
||||||
|
Application.getMessage(fc, MSG_RECOVERED_ITEM_PERMISSION), item.getName());
|
||||||
|
errorfacesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FAILURE_INTEGRITY:
|
||||||
|
msg = MessageFormat.format(
|
||||||
|
Application.getMessage(fc, MSG_RECOVERED_ITEM_INTEGRITY), item.getName());
|
||||||
|
errorfacesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
String reason = report.getCause().getMessage();
|
||||||
|
msg = MessageFormat.format(
|
||||||
|
Application.getMessage(fc, MSG_RECOVERED_ITEM_FAILURE), item.getName(), reason);
|
||||||
|
errorfacesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// report the failure if one occured we stay on the current screen
|
||||||
|
if (errorfacesMsg != null)
|
||||||
|
{
|
||||||
|
fc.addMessage(null, errorfacesMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Throwable err)
|
||||||
|
{
|
||||||
|
// most exceptions will be caught and returned as RestoreNodeReport objects by the service
|
||||||
|
String reason = err.getMessage();
|
||||||
|
String msg = MessageFormat.format(
|
||||||
|
Application.getMessage(fc, MSG_RECOVERED_ITEM_FAILURE), item.getName(), reason);
|
||||||
|
FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg);
|
||||||
|
fc.addMessage(null, facesMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outcome;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action handler to reset all filters and search
|
||||||
|
*/
|
||||||
|
public void resetAll(ActionEvent event)
|
||||||
|
{
|
||||||
|
// TODO: reset all filter and search
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action handler to initially setup the trashcan screen
|
||||||
|
*/
|
||||||
|
public void setupTrashcan(ActionEvent event)
|
||||||
|
{
|
||||||
|
contextUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------
|
||||||
|
// Private helpers
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the archive store root node ref
|
||||||
|
*/
|
||||||
|
private NodeRef getArchiveRootRef()
|
||||||
|
{
|
||||||
|
if (this.archiveRootRef == null)
|
||||||
|
{
|
||||||
|
this.archiveRootRef = this.nodeArchiveService.getStoreArchiveNode(Repository.getStoreRef());
|
||||||
|
}
|
||||||
|
return this.archiveRootRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the search query to use when displaying the list of deleted items
|
||||||
|
*/
|
||||||
|
private String getSearchQuery()
|
||||||
|
{
|
||||||
|
String query;
|
||||||
|
if (this.searchText == null || this.searchText.length() == 0)
|
||||||
|
{
|
||||||
|
// search for ALL items in the archive store
|
||||||
|
query = String.format(SEARCH_ALL, archiveRootRef, ContentModel.ASPECT_ARCHIVED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// search by name in the archive store
|
||||||
|
String safeText = QueryParser.escape(this.searchText);
|
||||||
|
if (safeText.indexOf(' ') == -1)
|
||||||
|
{
|
||||||
|
query = String.format(SEARCH_NAME, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText, safeText);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
query = String.format(SEARCH_NAME_QUOTED, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText, safeText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------
|
||||||
@@ -133,5 +563,6 @@ public class TrashcanBean implements IContextListener
|
|||||||
{
|
{
|
||||||
this.itemsRichList.setValue(null);
|
this.itemsRichList.setValue(null);
|
||||||
}
|
}
|
||||||
|
this.showItems = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -244,7 +244,7 @@ public class NodePathLinkRenderer extends BaseRenderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disabled == false)
|
if (disabled == false && lastElementRef != null)
|
||||||
{
|
{
|
||||||
return renderPathElement(context, component, lastElementRef, buf.toString());
|
return renderPathElement(context, component, lastElementRef, buf.toString());
|
||||||
}
|
}
|
||||||
|
@@ -1483,10 +1483,18 @@
|
|||||||
<property-name>nodeService</property-name>
|
<property-name>nodeService</property-name>
|
||||||
<value>#{NodeService}</value>
|
<value>#{NodeService}</value>
|
||||||
</managed-property>
|
</managed-property>
|
||||||
|
<managed-property>
|
||||||
|
<property-name>nodeArchiveService</property-name>
|
||||||
|
<value>#{nodeArchiveService}</value>
|
||||||
|
</managed-property>
|
||||||
<managed-property>
|
<managed-property>
|
||||||
<property-name>searchService</property-name>
|
<property-name>searchService</property-name>
|
||||||
<value>#{SearchService}</value>
|
<value>#{SearchService}</value>
|
||||||
</managed-property>
|
</managed-property>
|
||||||
|
<managed-property>
|
||||||
|
<property-name>dictionaryService</property-name>
|
||||||
|
<value>#{DictionaryService}</value>
|
||||||
|
</managed-property>
|
||||||
</managed-bean>
|
</managed-bean>
|
||||||
|
|
||||||
<managed-bean>
|
<managed-bean>
|
||||||
|
Before Width: | Height: | Size: 553 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 553 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 970 B After Width: | Height: | Size: 608 B |
Before Width: | Height: | Size: 778 B After Width: | Height: | Size: 916 B |
@@ -140,6 +140,7 @@
|
|||||||
<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();" />
|
<h:inputText id="search-text" value="#{TrashcanBean.searchText}" size="35" maxlength="1024" onkeyup="updateButtonState();" onchange="updateButtonState();" />
|
||||||
<h:commandButton id="search-btn" value="#{msg.search_deleted_items}" actionListener="#{TrashcanBean.search}" disabled="true" />
|
<h:commandButton id="search-btn" value="#{msg.search_deleted_items}" actionListener="#{TrashcanBean.search}" disabled="true" />
|
||||||
|
<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 --%>
|
||||||
@@ -172,7 +173,7 @@
|
|||||||
<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.fileType16}" showLink="false" styleClass="inlineAction" />
|
<a:actionLink value="#{r.name}" href="#{r.url}" target="new" image="#{r.typeIcon}" showLink="false" styleClass="inlineAction" />
|
||||||
</f:facet>
|
</f:facet>
|
||||||
<a:actionLink value="#{r.name}" href="#{r.url}" target="new" />
|
<a:actionLink value="#{r.name}" href="#{r.url}" target="new" />
|
||||||
</a:column>
|
</a:column>
|
||||||
@@ -195,12 +196,12 @@
|
|||||||
</h:outputText>
|
</h:outputText>
|
||||||
</a:column>
|
</a:column>
|
||||||
|
|
||||||
<%-- Username column --%>
|
<%-- Deleted by user column --%>
|
||||||
<a:column width="120" style="text-align:left" rendered="#{NavigationBean.currentUser.admin == true}">
|
<a:column width="120" style="text-align:left" rendered="#{NavigationBean.currentUser.admin == true}">
|
||||||
<f:facet name="header">
|
<f:facet name="header">
|
||||||
<a:sortLink label="#{msg.deleted_user}" value="deletedUsername" styleClass="header"/>
|
<a:sortLink label="#{msg.deleted_user}" value="deletedBy" styleClass="header"/>
|
||||||
</f:facet>
|
</f:facet>
|
||||||
<h:outputText value="#{r.deletedUsername}" />
|
<h:outputText value="#{r.deletedBy}" />
|
||||||
</a:column>
|
</a:column>
|
||||||
|
|
||||||
<%-- Actions column --%>
|
<%-- Actions column --%>
|
||||||
@@ -208,10 +209,10 @@
|
|||||||
<f:facet name="header">
|
<f:facet name="header">
|
||||||
<h:outputText value="#{msg.actions}"/>
|
<h:outputText value="#{msg.actions}"/>
|
||||||
</f:facet>
|
</f:facet>
|
||||||
<a:actionLink value="#{msg.recover}" image="/images/icons/recover.gif" showLink="false" action="recoverItem" actionListener="#{TrashcanBean.setupItemAction}">
|
<a:actionLink value="#{msg.recover}" image="/images/icons/recover.gif" showLink="false" action="dialog:recoverItem" actionListener="#{TrashcanBean.setupItemAction}">
|
||||||
<f:param name="id" value="#{r.id}" />
|
<f:param name="id" value="#{r.id}" />
|
||||||
</a:actionLink>
|
</a:actionLink>
|
||||||
<a:actionLink value="#{msg.delete}" image="/images/icons/delete.gif" showLink="false" action="deleteItem" actionListener="#{TrashcanBean.setupItemAction}">
|
<a:actionLink value="#{msg.delete}" image="/images/icons/delete.gif" showLink="false" action="dialog:deleteItem" actionListener="#{TrashcanBean.setupItemAction}">
|
||||||
<f:param name="id" value="#{r.id}" />
|
<f:param name="id" value="#{r.id}" />
|
||||||
</a:actionLink>
|
</a:actionLink>
|
||||||
</a:column>
|
</a:column>
|
||||||
@@ -219,6 +220,8 @@
|
|||||||
<a:dataPager styleClass="pager" />
|
<a:dataPager styleClass="pager" />
|
||||||
</a:richList>
|
</a:richList>
|
||||||
|
|
||||||
|
<h:message for="trashcan-list" styleClass="statusMessage" />
|
||||||
|
|
||||||
</a:panel>
|
</a:panel>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
|