Skip to content

Commit

Permalink
Merge pull request #5511 from effective-webwork/Processes-selection
Browse files Browse the repository at this point in the history
Processes selection
  • Loading branch information
solth authored Feb 20, 2023
2 parents 61affed + 01f059d commit 3d57aa9
Show file tree
Hide file tree
Showing 10 changed files with 455 additions and 20 deletions.
43 changes: 43 additions & 0 deletions Kitodo/src/main/java/org/kitodo/production/forms/ProcessForm.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@
import org.kitodo.production.services.file.FileService;
import org.kitodo.production.services.workflow.WorkflowControllerService;
import org.primefaces.PrimeFaces;
import org.primefaces.event.SelectEvent;
import org.primefaces.event.ToggleSelectEvent;
import org.primefaces.event.UnselectEvent;
import org.primefaces.model.SortOrder;

@Named("ProcessForm")
Expand Down Expand Up @@ -1125,4 +1128,44 @@ public String navigateToProcessesList(boolean resetTableViewState) {
return "/pages/processes?tabIndex=0&faces-redirect=true";
}

/**
* Callback function triggered when a process is unselected in the data table.
*
* @param unselectEvent as UnUnselectEvent
*/
public void onRowUnselect(UnselectEvent unselectEvent) {
if (allSelected) {
excludedProcessIds.add(getProcessId(unselectEvent.getObject()));
}
}

/**
* Callback function triggered when a process is selected in the data table.
*
* @param selectEvent as SelectEvent
*/
public void onRowSelect(SelectEvent selectEvent) {
if (allSelected) {
excludedProcessIds.remove(getProcessId(selectEvent.getObject()));
PrimeFaces.current().executeScript("PF('processesTable').selection=new Array('@all')");
PrimeFaces.current().executeScript("$(PF('processesTable').selectionHolder).val('@all')");
}
}

/**
* Callback function triggered when all processes are selected or unselected in the data table.
*
* @param toggleSelectEvent as ToggleSelectEvent
*/
public void selectAll(ToggleSelectEvent toggleSelectEvent) {
setAllSelected(false);
}

private int getProcessId(Object process) {
if (process instanceof Process) {
return ((Process) process).getId();
} else {
return ((ProcessDTO) process).getId();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand All @@ -42,6 +43,8 @@
import org.kitodo.production.services.data.ProcessService;
import org.kitodo.production.services.dataformat.MetsService;
import org.primefaces.PrimeFaces;
import org.primefaces.component.datatable.DataTable;
import org.primefaces.event.data.PageEvent;
import org.primefaces.model.charts.hbar.HorizontalBarChartModel;
import org.primefaces.model.charts.pie.PieChartModel;

Expand All @@ -62,6 +65,9 @@ public class ProcessListBaseView extends BaseForm {

private final HashMap<Integer, Boolean> exportable = new HashMap<>();

boolean allSelected = false;
HashSet<Integer> excludedProcessIds = new HashSet<>();

/**
* Constructor.
*/
Expand All @@ -70,6 +76,43 @@ public ProcessListBaseView() {
super.setLazyDTOModel(new LazyProcessDTOModel(ServiceManager.getProcessService()));
}

/**
* Gets excludedProcessIds.
*
* @return value of excludedProcessIds
*/
public HashSet<Integer> getExcludedProcessIds() {
return excludedProcessIds;
}

/**
* Sets excludedProcessIds.
*
* @param excludedProcessIds value of excludedProcessIds
*/
public void setExcludedProcessIds(HashSet<Integer> excludedProcessIds) {
this.excludedProcessIds = excludedProcessIds;
}

/**
* Gets allSelected.
*
* @return value of allSelected
*/
public boolean isAllSelected() {
return allSelected;
}

/**
* Sets allSelected.
*
* @param allSelected value of allSelected
*/
public void setAllSelected(boolean allSelected) {
this.allSelected = allSelected;
excludedProcessIds.clear();
}

/**
* Returns the list of the processes currently selected in the user interface.
* Converts ProcessDTO instances to Process instances in case of displaying search results.
Expand All @@ -79,6 +122,16 @@ public ProcessListBaseView() {
@SuppressWarnings("unchecked")
public List<Process> getSelectedProcesses() {
List<Process> selectedProcesses = new ArrayList<>();
ProcessService processService = ServiceManager.getProcessService();
if (allSelected) {
try {
this.selectedProcessesOrProcessDTOs = processService.findByQuery(processService.getQueryForFilter(
this.isShowClosedProcesses(), isShowInactiveProjects(), getFilter())
.mustNot(processService.createSetQueryForIds(new ArrayList<>(excludedProcessIds))), false);
} catch (DataException e) {
logger.error(e.getMessage());
}
}
if (selectedProcessesOrProcessDTOs.size() > 0) {
if (selectedProcessesOrProcessDTOs.get(0) instanceof ProcessDTO) {
// list contains ProcessDTO instances
Expand All @@ -87,11 +140,11 @@ public List<Process> getSelectedProcesses() {
.convertDtosToBeans((List<ProcessDTO>) selectedProcessesOrProcessDTOs);
} catch (DAOException e) {
Helper.setErrorMessage(ERROR_LOADING_MANY,
new Object[] {ObjectType.PROCESS.getTranslationPlural() }, logger, e);
new Object[]{ObjectType.PROCESS.getTranslationPlural()}, logger, e);
}
} else if (selectedProcessesOrProcessDTOs.get(0) instanceof Process) {
// list contains Process instances
selectedProcesses = (List<Process>) selectedProcessesOrProcessDTOs;
selectedProcesses = (List<Process>) selectedProcessesOrProcessDTOs;
}
}
return selectedProcesses;
Expand Down Expand Up @@ -556,4 +609,17 @@ public void setSelectedProcessesOrProcessDTOs(List<? extends Object> selectedPro
this.selectedProcessesOrProcessDTOs = selectedProcessesOrProcessDTOs;
}

/**
* Update selection and first row to show in datatable on PageEvent.
* @param pageEvent PageEvent triggered by data tables paginator
*/
public void onPageChange(PageEvent pageEvent) {
this.setFirstRow(((DataTable) pageEvent.getSource()).getFirst());
if (allSelected) {
PrimeFaces.current()
.executeScript("PF('processesTable').selectAllRows();");
excludedProcessIds.forEach(processId -> PrimeFaces.current()
.executeScript("PF('processesTable').unselectRow($('tr[data-rk=\"" + processId + "\"]'), true);"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public LazyDTOModel(SearchDatabaseService searchService) {
public Object getRowData(String rowKey) {
try {
return searchService.getById(Integer.parseInt(rowKey));
} catch (DAOException e) {
} catch (DAOException | NumberFormatException e) {
logger.error(e.getMessage());
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,13 @@ protected <O extends BaseDTO> List<O> convertRelatedJSONObjectToDTO(Map<String,
return service.findByQuery(createSetQueryForIds(ids), true);
}

private QueryBuilder createSetQueryForIds(List<Integer> ids) {
/**
* Builds a ElasticSearch query for list of Ids.
*
* @param ids as a List of Integer
* @return query as QueryBuilder
*/
public QueryBuilder createSetQueryForIds(List<Integer> ids) {
return termsQuery("_id", ids);
}

Expand Down
24 changes: 14 additions & 10 deletions Kitodo/src/main/webapp/WEB-INF/resources/js/lists.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,7 @@ function registerRowToggleEvents(event) {
PrimeFaces.widget.DataTable.prototype.updateData = (function () {
let cachedFunction = PrimeFaces.widget.DataTable.prototype.updateData;
return function () {
let reselectAll = (typeof this.selection !== "undefined" && this.selection[0] === '@all');
let result = cachedFunction.apply(this, arguments);
if (reselectAll) {
this.selectAllRows();
}
return result;
};
})();
Expand All @@ -53,10 +49,18 @@ $(document).on("click", ".allSelectable .ui-chkbox-all .ui-chkbox-box", function
table.unselectAllRows();
});

$(document).on("click", ".allSelectable .ui-chkbox .ui-chkbox-box", function () {
let tableId = $(this).closest(".allSelectable").attr('id').split(":").at(-1);
let table = new PF(tableId);
if (typeof table.selection !== "undefined" && table.selection[0] === '@all') {
table.unselectAllRows();
}
$(window).on("load", function () {
$.ready.then(function () {
if (typeof PF('processesTable').selection !== "undefined" && (PF('processesTable').selection[0] === '@all' || PF('processesTable').selection.length === PF('processesTable').cfg.paginator.rowCount )) {
PF('processesTable').selectAllRows();
PF('processesTable').selection=new Array("@all");
$(PF('processesTable').selectionHolder).val('@all');
let excludedIds = $('#excludedProcessIds').children();
for(let i = 0; i < excludedIds.length; i++) {
let processId = excludedIds.get(i).textContent;
PF('processesTable').unselectRow($('tr[data-rk="' + processId + '"]'), true);
}

}
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
lazy="true"
paginator="true"
resizableColumns="true"
rowSelectMode="checkbox"
liveResize="true"
sortBy="#{process.id}"
sortOrder="descending"
Expand All @@ -42,9 +43,15 @@
<p:ajax event="page"
listener="#{ProcessForm.onPageChange}"/>
<p:ajax event="rowToggle"
oncomplete="registerRowToggleEvents();" />
oncomplete="registerRowToggleEvents();"/>
<p:ajax event="rowSelectCheckbox"
listener="#{ProcessForm.onRowSelect}"/>
<p:ajax event="rowUnselectCheckbox"
listener="#{ProcessForm.onRowUnselect}"/>
<p:ajax event="toggleSelect"
listener="#{ProcessForm.selectAll}"/>

<p:column styleClass="checkboxListColumn" selectionMode="multiple" resizable="false"/>
<p:column id="selectionColumn" styleClass="checkboxListColumn" selectionMode="multiple" resizable="false"/>

<p:column styleClass="hierarchy-info">
<p:rowToggler rendered="#{process.getParentID() ne 0 or process.hasChildren() or ProcessForm.getCurrentTasksForUser(process).size() gt 0}"/>
Expand Down Expand Up @@ -246,12 +253,18 @@

</p:dataTable>

<p:overlayPanel widgetVar="allSelectableOverlayPanel" dismissable="true" styleClass="allSelectableOverlayPanel" >
<p:overlayPanel id="allSelectableOverlayPanel" widgetVar="allSelectableOverlayPanel" dismissable="true" styleClass="allSelectableOverlayPanel" >
<ul>
<li><p:commandLink value="#{msgs.selectAllRowsOnPage}" onclick="PF('processesTable').unselectAllRows();PF('processesTable').selectAllRowsOnPage();PF('allSelectableOverlayPanel').hide();"/></li>
<li><p:commandLink value="#{msgs.selectAllRows}" onclick="PF('processesTable').selectAllRows();PF('allSelectableOverlayPanel').hide();"/></li>
<li><p:commandLink id="selectAllRowsOnPage" value="#{msgs.selectAllRowsOnPage}" onclick="PF('processesTable').unselectAllRows();PF('processesTable').selectAllRowsOnPage();PF('allSelectableOverlayPanel').hide();"/></li>
<li><p:commandLink id="selectAllRows" value="#{msgs.selectAllRows}" actionListener="#{ProcessForm.setAllSelected(true)}" onclick="PF('processesTable').selectAllRows();PF('allSelectableOverlayPanel').hide();"/></li>
</ul>
</p:overlayPanel>

<ul style="display: none" id="excludedProcessIds">
<p:repeat value="#{ProcessForm.excludedProcessIds}" var="processId">
<li>#{processId}</li>
</p:repeat>
</ul>

<div id="dropDownMenus">
<p:commandButton id="actionsButton" value="#{msgs.actions}" styleClass="secondary"
Expand Down
112 changes: 112 additions & 0 deletions Kitodo/src/test/java/org/kitodo/production/forms/ProcessFormIT.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* (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.production.forms;

import java.sql.Date;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.kitodo.MockDatabase;
import org.kitodo.SecurityTestUtils;
import org.kitodo.data.database.beans.Process;
import org.kitodo.data.database.beans.Project;
import org.kitodo.data.database.beans.Template;
import org.kitodo.production.services.ServiceManager;

public class ProcessFormIT {

private ProcessForm processForm = new ProcessForm();

/**
* Setup Database and start elasticsearch.
*
* @throws Exception If databaseConnection failed.
*/
@BeforeClass
public static void prepareDatabase() throws Exception {
MockDatabase.startNode();
MockDatabase.insertProcessesFull();
addProcesses();
SecurityTestUtils.addUserDataToSecurityContext(ServiceManager.getUserService().getById(1), 1);
}

private static void addProcesses() throws Exception {
Project projectOne = ServiceManager.getProjectService().getById(1);
Template template = ServiceManager.getTemplateService().getById(1);

Process forthProcess = new Process();
forthProcess.setTitle("Forth process");
LocalDate localDate = LocalDate.of(2020, 3, 20);
forthProcess.setCreationDate(Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
forthProcess.setWikiField("SelectionTest");
forthProcess.setDocket(ServiceManager.getDocketService().getById(1));
forthProcess.setProject(projectOne);
forthProcess.setRuleset(ServiceManager.getRulesetService().getById(1));
forthProcess.setTemplate(template);
ServiceManager.getProcessService().save(forthProcess);

Process fifthProcess = new Process();
fifthProcess.setTitle("Fifth process");
localDate = LocalDate.of(2020, 4, 20);
fifthProcess.setCreationDate(Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
fifthProcess.setWikiField("SelectionTest");
fifthProcess.setDocket(ServiceManager.getDocketService().getById(1));
fifthProcess.setProject(projectOne);
fifthProcess.setRuleset(ServiceManager.getRulesetService().getById(1));
fifthProcess.setTemplate(template);
ServiceManager.getProcessService().save(fifthProcess);
}

/**
* Cleanup the database and stop elasticsearch.
*
* @throws Exception if elasticsearch could not been stopped.
*/
@AfterClass
public static void cleanDatabase() throws Exception {
MockDatabase.stopNode();
MockDatabase.cleanDatabase();
}

/**
* Tests the selection in the process data table.
*/
@Test
public void testProcessesSelection() throws Exception {
List<Integer> selectedIds;
processForm.setAllSelected(true);

selectedIds = processForm.getSelectedProcesses()
.stream().map(Process::getId).sorted().collect(Collectors.toList());
Assert.assertEquals(new ArrayList<>(Arrays.asList(1, 2, 4, 5)), selectedIds);

processForm.getExcludedProcessIds().add(4);
selectedIds = processForm.getSelectedProcesses()
.stream().map(Process::getId).sorted().collect(Collectors.toList());

Assert.assertEquals(new ArrayList<>(Arrays.asList(1, 2, 5)), selectedIds);

processForm.setAllSelected(false);
processForm.selectedProcessesOrProcessDTOs = ServiceManager.getProcessService().findByAnything("SelectionTest");
selectedIds = processForm.getSelectedProcesses()
.stream().map(Process::getId).sorted().collect(Collectors.toList());
Assert.assertEquals(new ArrayList<>(Arrays.asList(4, 5)), selectedIds);
}
}
Loading

0 comments on commit 3d57aa9

Please sign in to comment.