Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remember sort order and pagination of the process and search result list #5358

Merged
merged 12 commits into from
Oct 13, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public class BaseForm implements Serializable {
protected static final String DEFAULT_LINK = "desktop.jsf";
private static final String LIST_PAGE = TEMPLATE_ROOT + "{0}?keepPagination=true&" + REDIRECT_PARAMETER;
protected final String usersPage = MessageFormat.format(LIST_PAGE, "users");
protected final String processesPage = MessageFormat.format(LIST_PAGE, "processes");
protected final String processesPage = "processes?" + REDIRECT_PARAMETER;
protected final String projectsPage = MessageFormat.format(LIST_PAGE, "projects");
protected final String tasksPage = MessageFormat.format(LIST_PAGE, "tasks");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import org.kitodo.production.services.data.ProcessService;
import org.kitodo.production.services.file.FileService;
import org.kitodo.production.services.workflow.WorkflowControllerService;
import org.primefaces.PrimeFaces;
import org.primefaces.model.SortOrder;

@Named("ProcessForm")
Expand Down Expand Up @@ -85,6 +86,8 @@ public class ProcessForm extends TemplateBaseForm {
private List<SelectItem> customColumns;

private static final String CREATE_PROCESS_PATH = "/pages/processFromTemplate.jsf?faces-redirect=true";
private static final String PROCESS_TABLE_VIEW_ID = "/pages/processes.xhtml";
private static final String PROCESS_TABLE_ID = "processesTabView:processesForm:processesTable";

@Inject
private CustomListColumnInitializer initializer;
Expand Down Expand Up @@ -971,7 +974,7 @@ public String getTaskEditReferer() {
public void setProcessEditReferer(String referer) {
if (!referer.isEmpty()) {
if ("processes".equals(referer)) {
this.processEditReferer = referer + "?keepPagination=true";
this.processEditReferer = referer;
} else if ("searchResult".equals(referer)) {
this.processEditReferer = "searchResult.jsf";
} else if (!referer.contains("taskEdit") || this.processEditReferer.isEmpty()) {
Expand Down Expand Up @@ -1151,4 +1154,31 @@ public String getAmount() {
}
}

/**
* Resets the process list multi view state such that the sort order and pagination is reset to their defaults.
*/
public void resetProcessListMultiViewState() {
if (!Objects.isNull(FacesContext.getCurrentInstance())) {
thomaslow marked this conversation as resolved.
Show resolved Hide resolved
// check whether there is a mulit view state registered (to avoid warning log message in case there is not)
Object mvs = PrimeFaces.current().multiViewState().get(PROCESS_TABLE_VIEW_ID, PROCESS_TABLE_ID, false, null);
if (Objects.nonNull(mvs)) {
// clear multi view state only if there is a state available
PrimeFaces.current().multiViewState().clear(PROCESS_TABLE_VIEW_ID, PROCESS_TABLE_ID);
}
}
}

/**
* Navigates to processes list and optionally resets table view state.
*
* @param resetTableViewState whether to reset table view state
*/
public String navigateToProcessesList(boolean resetTableViewState) {
if (resetTableViewState) {
setFirstRow(0);
resetProcessListMultiViewState();
}
return "/pages/processes?tabIndex=0&faces-redirect=true";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.Objects;

import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Named;

import org.apache.logging.log4j.LogManager;
Expand All @@ -44,6 +45,9 @@
public class SearchResultForm extends ProcessListBaseView {
private static final Logger logger = LogManager.getLogger(SearchResultForm.class);

private static final String SEARCH_RESULT_VIEW_ID = "/pages/searchResult.xhtml";
private static final String SEARCH_RESULT_TABLE_ID = "searchResultTabView:searchResultForm:searchResultTable";

private List<ProcessDTO> filteredList = new ArrayList<>();
private List<ProcessDTO> resultList = new ArrayList<>();
private String searchQuery;
Expand Down Expand Up @@ -76,6 +80,7 @@ public String searchForProcessesBySearchQuery() {
setCurrentTaskStatusFilter(null);
setCurrentProjectFilter(null);
setCurrentTaskFilter(null);
resetSearchResultTableViewState();
return searchResultListPath;
}

Expand Down Expand Up @@ -299,4 +304,19 @@ public void setCurrentProjectFilter(Integer currentProjectFilter) {
this.currentProjectFilter = currentProjectFilter;
}

/**
* This method resets the view state of the search result table, which was
* enabled by adding "multiViewState=true" to the DataTable component.
*
* <p>This affects both the pagination state and the sort order of
* the table. It should be called whenever a new search is triggered such
* that the user is presented with the most relevant results (page 1)
* in the default order.</p>
*/
public void resetSearchResultTableViewState() {
if (!Objects.isNull(FacesContext.getCurrentInstance())) {
PrimeFaces.current().multiViewState().clear(SEARCH_RESULT_VIEW_ID, SEARCH_RESULT_TABLE_ID);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ public void initMetadataEditor() {
*/
public String open(String processID, String referringView) {
try {
this.referringView = referringView + ("processes".equals(referringView) ? "?keepPagination=true" : "");
this.referringView = referringView;
this.process = ServiceManager.getProcessService().getById(Integer.parseInt(processID));
this.currentChildren.addAll(process.getChildren());
this.user = ServiceManager.getUserService().getCurrentUser();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,12 @@

<h:panelGroup rendered="#{SecurityAccessController.hasAuthorityToViewProcessPage()}">
<li class="nav-pic-text">
<h:link value="#{msgs.processes}" id="linkProcesses" outcome="processes?tabIndex=0">
<i class="fa fa-clipboard fa-lg"/>
</h:link>
<h:form id="linkProcessesNavigationForm">
<h:commandLink id="linkProcesses" action="#{ProcessForm.navigateToProcessesList(true)}">
<i class="fa fa-clipboard fa-lg"/>
<h:outputText value="#{msgs.processes}" />
</h:commandLink>
</h:form>
</li>
</h:panelGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
rows="#{LoginForm.loggedUser.tableSize}"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {JumpToPageInput} {NextPageLink} {LastPageLink}"
currentPageReportTemplate="#{msgs.currentPageReportTemplate}"
paginatorPosition="bottom">
paginatorPosition="bottom"
multiViewState="true">


<p:ajax event="page"
Expand Down Expand Up @@ -159,7 +160,7 @@
<f:param name="referer" value="processes"/>
<f:param name="id" value="#{parent.id}"/>
</h:link>
<h:commandLink action="#{DataEditorForm.open(parent.id, 'processes?keepPagination=true')}"
<h:commandLink action="#{DataEditorForm.open(parent.id, 'processes')}"
styleClass="action"
title="#{msgs.metadataEdit}"
rendered="#{SecurityAccessController.hasAuthorityToOpenMetadataEditor()}">
Expand Down
8 changes: 5 additions & 3 deletions Kitodo/src/main/webapp/pages/desktop.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@
<p:ajax update="processTable" oncomplete="setScrollbarLayout()"/>
</p:commandButton>
</h:form>
<p:button id="allProcesses" value="#{msgs.allProcesses}"
outcome="processes?tabIndex=0"
icon="fa fa-search fa-lg" iconPos="right" styleClass="secondary"/>
<h:form id="allProcessesDesktopForm">
<p:commandButton id="allProcesses" value="#{msgs.allProcesses}"
action="#{ProcessForm.navigateToProcessesList(true)}"
icon="fa fa-search fa-lg" iconPos="right" styleClass="secondary"/>
</h:form>
</div>
</div>
<div class="content-body">
Expand Down
5 changes: 1 addition & 4 deletions Kitodo/src/main/webapp/pages/processes.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@
<f:viewParam name="tabIndex"/>
<!--@elvariable id="tabIndex" type="java.lang.Integer"-->
<f:viewAction action="#{ProcessForm.setActiveTabIndexFromTemplate(tabIndex)}" />
<!--@elvariable id="keepPagination" type="java.lang.String"-->
<f:viewParam name="keepPagination"/>
<f:viewAction action="#{ProcessForm.resetPaginator(keepPagination)}"/>
<!--@elvariable id="projecttitle" type="java.lang.String"-->
<f:viewParam name="projecttitle"/>
<o:viewAction action="#{ProcessForm.setFilter('project:' += projecttitle)}" if="#{not empty projecttitle}"/>
Expand Down Expand Up @@ -120,7 +117,7 @@

<ui:define name="breadcrumbs">
<p:menuitem value="#{msgs.desktop}" url="desktop.jsf" icon="fa fa-home"/>
<p:menuitem value="#{msgs.processes}" icon="fa fa-clipboard"/>
<p:menuitem value="#{msgs.processes}" icon="fa fa-clipboard" />
</ui:define>

<ui:define name="dialog">
Expand Down
3 changes: 2 additions & 1 deletion Kitodo/src/main/webapp/pages/searchResult.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
rows="#{LoginForm.loggedUser.tableSize}"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {NextPageLink} {LastPageLink}"
currentPageReportTemplate="#{msgs.currentPageReportTemplate}"
paginatorPosition="bottom">
paginatorPosition="bottom"
multiViewState="true">
<p:ajax event="rowToggle"
oncomplete="registerRowToggleEvents();" />

Expand Down
106 changes: 106 additions & 0 deletions Kitodo/src/test/java/org/kitodo/selenium/ProcessesSortingST.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* (c) Kitodo. Key to digital objects e. V. <[email protected]>
*
* This file is part of the Kitodo project.
*
* It is licensed under GNU General Public License version 3 or later.
*
* For the full copyright and license information, please read the
* GPL3-License.txt file that was distributed with this source code.
*/

package org.kitodo.selenium;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.kitodo.selenium.testframework.BaseTestSelenium;
import org.kitodo.selenium.testframework.Browser;
import org.kitodo.selenium.testframework.Pages;
import org.kitodo.selenium.testframework.pages.ProcessesPage;


/**
* Tests the processes list for various requirements related to sorting it.
*/
public class ProcessesSortingST extends BaseTestSelenium {

@SuppressWarnings("unused")
private static final Logger logger = LogManager.getLogger(ProcessesSortingST.class);

private static ProcessesPage processesPage;

@BeforeClass
public static void setup() throws Exception {
processesPage = Pages.getProcessesPage();
}

@Before
public void login() throws Exception {
Pages.getLoginPage().goTo().performLoginAsAdmin();
}

@After
public void logout() throws Exception {
Pages.getTopNavigation().logout();
}

/**
* Verifies that clicking the header of the title column of the processes list
* will indeed trigger that processes are sorted by title.
*/
@Test
public void sortByProcessTitle() throws Exception {
processesPage.goTo();

// check that default sort order (descending by id) has second process as first element in the process list
assertEquals("Second process", processesPage.getProcessTitles().get(0));

// click on column header to trigger ascending order by process title
processesPage.clickProcessesTitleColumnForSorting();

// check that first process is now first element in list of processes
assertEquals("First process", processesPage.getProcessTitles().get(0));

// click again to trigger descending order for process title
processesPage.clickProcessesTitleColumnForSorting();

// check that second process is again first element in list of processes
assertEquals("Second process", processesPage.getProcessTitles().get(0));
}

/**
* Verifies that the current sorting of the processes list is remembered
* even when reloading the processes page.
*/
@Test
public void sortOrderIsRememberedAfterReload() throws Exception {
processesPage.goTo();

// check that default sort order (descending by id) has second process as first element in the process list
assertEquals("Second process", processesPage.getProcessTitles().get(0));

// click on column header to trigger ascending order by process title
processesPage.clickProcessesTitleColumnForSorting();

// check that first process is now first element in list of processes
assertEquals("First process", processesPage.getProcessTitles().get(0));

// reload page
Browser.getDriver().navigate().refresh();

// check that first process is still first element in list of processes
assertEquals("First process", processesPage.getProcessTitles().get(0));

// navigate to process list via main menu, which resets sort order
processesPage.goTo();

// check that default sort order is restored
assertEquals("Second process", processesPage.getProcessTitles().get(0));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ public class ProcessesPage extends Page<ProcessesPage> {
private static final String PROCESSES_FORM = PROCESSES_TAB_VIEW + ":processesForm";
private static final String BATCH_FORM = PROCESSES_TAB_VIEW + ":batchForm";
private static final String PROCESSES_TABLE = PROCESSES_FORM + ":processesTable";
private static final String PROCESSES_TABLE_TITLE_COLUMN = PROCESSES_TABLE + ":titleColumn";
private static final String PROCESS_TITLE = "Second process";
private static final String WAIT_FOR_ACTIONS_BUTTON = "Wait for actions menu button";
private static final String WAIT_FOR_ACTIONS_MENU = "Wait for actions menu to open";
private static final String WAIT_FOR_TITLE_COLUMN_SORT = "Wait for title column sorting";

@SuppressWarnings("unused")
@FindBy(id = PROCESSES_TAB_VIEW)
Expand All @@ -47,6 +49,10 @@ public class ProcessesPage extends Page<ProcessesPage> {
@FindBy(id = PROCESSES_TABLE + DATA)
private WebElement processesTable;

@SuppressWarnings("unused")
@FindBy(id = PROCESSES_TABLE_TITLE_COLUMN)
private WebElement processesTableTitleColumn;

@SuppressWarnings("unused")
@FindBy(id = BATCH_FORM + ":selectBatches")
private WebElement batchesSelect;
Expand Down Expand Up @@ -335,4 +341,23 @@ private void switchToTabByIndex(int index) throws Exception {
public void navigateToExtendedSearch() throws IllegalAccessException, InstantiationException {
clickButtonAndWaitForRedirect(searchForProcessesButton, Pages.getExtendedSearchPage().getUrl());
}

/**
* Clicks the header of the title column of the processes table in order to
* trigger sorting the processes list by title.
*/
public void clickProcessesTitleColumnForSorting() {
// remember aria-sort attribute of th-tag of title column
String previousAriaSort = processesTableTitleColumn.getAttribute("aria-sort");

// click title th-tag to trigger sorting
processesTableTitleColumn.click();

// wait for the sorting to be applied (which requires ajax request to backend)
await(WAIT_FOR_TITLE_COLUMN_SORT)
.pollDelay(200, TimeUnit.MILLISECONDS)
.atMost(10, TimeUnit.SECONDS)
.ignoreExceptions()
.until(() -> !processesTableTitleColumn.getAttribute("aria-sort").equals(previousAriaSort));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
public class TopNavigationPage extends Page<TopNavigationPage> {

private static final String ARGUMENTS_CLICK = "arguments[0].click()";
private static final String LINK_PROCESSES_ID = "linkProcessesNavigationForm:linkProcesses";

@SuppressWarnings("unused")
@FindBy(id = "user-menu")
Expand All @@ -51,7 +52,7 @@ public class TopNavigationPage extends Page<TopNavigationPage> {
private WebElement linkTasks;

@SuppressWarnings("unused")
@FindBy(id = "linkProcesses")
@FindBy(id = LINK_PROCESSES_ID)
private WebElement linkProcesses;

@SuppressWarnings("unused")
Expand Down Expand Up @@ -162,7 +163,7 @@ void gotoTasks() throws InterruptedException {
*/
void gotoProcesses() {
RemoteWebDriver driver = Browser.getDriver();
((JavascriptExecutor) driver).executeScript(ARGUMENTS_CLICK, driver.findElement(By.id("linkProcesses")));
((JavascriptExecutor) driver).executeScript(ARGUMENTS_CLICK, driver.findElement(By.id(LINK_PROCESSES_ID)));
}

/**
Expand Down