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

Allow to save metadata editor default column layout #6245

Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -22,8 +22,8 @@ public class DataEditorSetting extends BaseBean {
@Column(name = "user_id")
private int userId;

@Column(name = "task_id")
private int taskId;
@Column(name = "task_id", nullable = true)
private Integer taskId;

@Column(name = "structure_width")
private float structureWidth;
Expand Down Expand Up @@ -59,20 +59,20 @@ public void setUserId(int userId) {
}

/**
* Get taskId.
* Get taskId. Either the id of the task or null, for a task-independent default layout.
*
* @return value of taskId
*/
public int getTaskId() {
public Integer getTaskId() {
return taskId;
}

/**
* Set taskId.
* Set taskId. Either the id of the task or null, for a task-independent default layout.
*
* @param taskId as int
*/
public void setTaskId(int taskId) {
public void setTaskId(Integer taskId) {
this.taskId = taskId;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--
-- (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.
--

SET SQL_SAFE_UPDATES = 0;

-- allow null in column task_id of table dataeditorsetting to store task-independent layout
ALTER TABLE dataeditor_setting MODIFY COLUMN task_id INT(11) NULL;

SET SQL_SAFE_UPDATES = 1;
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,15 @@ public void open(String processID, String referringView, String taskId) {
}

private void showDataEditorSettingsLoadedMessage() throws DAOException {
String task = ServiceManager.getTaskService().getById(templateTaskId).getTitle();
Locale locale = LocaleHelper.getCurrentLocale();
String title = Helper.getString(locale, "dataEditor.layoutLoadedSuccessfullyTitle");
String text = MessageFormat.format(Helper.getString(locale, "dataEditor.layoutLoadedSuccessfullyText"), task);
String text = Helper.getString(locale, "dataEditor.layoutLoadedSuccessfullyDefaultText");
if (templateTaskId > 0) {
String task = ServiceManager.getTaskService().getById(templateTaskId).getTitle();
text = MessageFormat.format(
Helper.getString(locale, "dataEditor.layoutLoadedSuccessfullyForTaskText"), task
);
}
String script = GROWL_MESSAGE.replace("SUMMARY", title).replace("DETAIL", text)
.replace("SEVERITY", "info");
PrimeFaces.current().executeScript("PF('notifications').removeAll();");
Expand All @@ -338,16 +343,13 @@ private void checkProjectFolderConfiguration() {
}

private void loadDataEditorSettings() {
if (templateTaskId > 0) {
dataEditorSetting = ServiceManager.getDataEditorSettingService().loadDataEditorSetting(user.getId(),
templateTaskId);
if (Objects.isNull(dataEditorSetting)) {
dataEditorSetting = new DataEditorSetting();
dataEditorSetting.setUserId(user.getId());
dataEditorSetting.setTaskId(templateTaskId);
}
} else {
dataEditorSetting = null;
// use template task id if it exists, otherwise use null for task-independent layout
Integer taskId = templateTaskId > 0 ? templateTaskId : null;
dataEditorSetting = ServiceManager.getDataEditorSettingService().loadDataEditorSetting(user.getId(), taskId);
if (Objects.isNull(dataEditorSetting)) {
dataEditorSetting = new DataEditorSetting();
dataEditorSetting.setUserId(user.getId());
dataEditorSetting.setTaskId(taskId);
}
}

Expand Down Expand Up @@ -1068,14 +1070,15 @@ public void updateNumberOfScans() {
* Save current metadata editor layout.
*/
public void saveDataEditorSetting() {
if (Objects.nonNull(dataEditorSetting) && dataEditorSetting.getTaskId() > 0) {
if (Objects.nonNull(dataEditorSetting)) {
try {
ServiceManager.getDataEditorSettingService().saveToDatabase(dataEditorSetting);
PrimeFaces.current().executeScript("PF('dataEditorSavingResultDialog').show();");
} catch (DAOException e) {
Helper.setErrorMessage("errorSaving", new Object[] {ObjectType.USER.getTranslationSingular() }, logger, e);
}
} else {
// should never happen any more, since layout settings are always created (even outside of task context)
logger.error("Could not save DataEditorSettings with userId {} and templateTaskId {}", user.getId(),
templateTaskId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@ public boolean areDataEditorSettingsDefinedForWorkflow(Workflow workflow) {

/**
* Delete data editor settings identified by task id.
* @param taskId ID of the associated task
* @param taskId ID of the associated task (or null for task-independent default layout)
* @throws DAOException if data editor setting could not be deleted from database
*
*/
public void removeFromDatabaseByTaskId(int taskId) throws DAOException {
public void removeFromDatabaseByTaskId(Integer taskId) throws DAOException {
List<DataEditorSetting> dataEditorSettings = getByTaskId(taskId);
for (DataEditorSetting dataEditorSetting: dataEditorSettings) {
dao.remove(dataEditorSetting.getId());
Expand All @@ -102,30 +102,41 @@ public void removeFromDatabaseByTaskId(int taskId) throws DAOException {

/**
* Retrieve data editor settings by task id.
* @param taskId ID of the task
* @param taskId ID of the task (or null for task-independent default layout)
*
* @return List of DataEditorSetting objects
*/
public List<DataEditorSetting> getByTaskId(int taskId) {
public List<DataEditorSetting> getByTaskId(Integer taskId) {
Map<String, Object> parameterMap = new HashMap<>();
parameterMap.put("taskId", taskId);
return getByQuery("FROM DataEditorSetting WHERE task_id = :taskId ORDER BY id ASC", parameterMap);
if (Objects.nonNull(taskId)) {
parameterMap.put("taskId", taskId);
return getByQuery("FROM DataEditorSetting WHERE task_id = :taskId ORDER BY id ASC", parameterMap);
}
return getByQuery("FROM DataEditorSetting WHERE task_id is NULL ORDER BY id ASC", parameterMap);
}

private List<DataEditorSetting> getByUserAndTask(int userId, int taskId) {
private List<DataEditorSetting> getByUserAndTask(int userId, Integer taskId) {
Map<String, Object> parameterMap = new HashMap<>();
parameterMap.put("userId", userId);
parameterMap.put("taskId", taskId);
return getByQuery("FROM DataEditorSetting WHERE user_id = :userId AND task_id = :taskId ORDER BY id ASC", parameterMap);
if (Objects.nonNull(taskId)) {
parameterMap.put("taskId", taskId);
return getByQuery(
"FROM DataEditorSetting WHERE user_id = :userId AND task_id = :taskId ORDER BY id ASC", parameterMap
);
}
return getByQuery(
"FROM DataEditorSetting WHERE user_id = :userId AND task_id IS NULL ORDER BY id ASC", parameterMap
);
}

/**
* Load DataEditorSetting from database or return null if no entry matches the specified ids.
* @param userId id of the user
* @param taskId id of the corresponding template task for the task that is currently edited
* @param taskId id of the corresponding template task for the task that is currently edited
* (or null for task-independent default layout)
* @return settings for the data editor
*/
public DataEditorSetting loadDataEditorSetting(int userId, int taskId) {
public DataEditorSetting loadDataEditorSetting(int userId, Integer taskId) {
List<DataEditorSetting> results = getByUserAndTask(userId, taskId);
if (Objects.nonNull(results) && !results.isEmpty()) {
return results.get(0);
Expand Down
7 changes: 4 additions & 3 deletions Kitodo/src/main/resources/messages/messages_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,6 @@ dataEditor.addMetadata.newMetadata=Neue Metadaten hinzuf\u00FCgen
dataEditor.addMetadata.noMetadataAddable=Zu dem ausgew\u00E4hlten Strukturelement k\u00F6nnen keine weiteren Metadaten hinzugef\u00FCgt werden!
dataEditor.addMetadata.noMetadataAddableToGroup=Zu dieser Gruppe k\u00F6nnen keine weiteren Metadaten hinzugef\u00FCgt werden!
dataEditor.addMetadata.toGroup=Metadaten zu Gruppe hinzuf\u00FCgen
dataEditor.cannotSaveLayout=Layout kann nur gespeichert werden, wenn der Editor \u00FCber eine Aufgabe ge\u00F6ffnet wird.
dataEditor.childNotContainedError=Elternelement von Struktur {0} enth\u00E4lt die Struktur nicht!
dataEditor.comment.correctionWorkflowAlreadyActive=Dieser Vorgang befindet sich bereits in einem Korrektur-Workflow
dataEditor.comment.firstTaskInWorkflow=Sie k\u00F6nnen f\u00FCr diesen Vorgang derzeit keinen Korrekturkommentar verfassen, da noch keine seiner Aufgaben abgeschlossen sind.
Expand Down Expand Up @@ -309,7 +308,8 @@ dataEditor.galleryStructuredView=Strukturierte Ansicht
dataEditor.galleryDetailView=Detailansicht
dataEditor.invalidMetadataValue=\u201E{0}\u201C kann nicht gespeichert werden: Der Wert ist ung\u00FCltig. Wert: {1}
dataEditor.invalidStructureField=\u201E{0}\u201C kann nicht gespeichert werden: Es gibt kein solches Feld ({1}).
dataEditor.saveLayout=Aktuelle Spaltenaufteilung als Standard f\u00FCr diese Aufgabe speichern
dataEditor.saveLayoutDefault=Aktuelle Spaltenaufteilung als Standard speichern
dataEditor.saveLayoutForTask=Aktuelle Spaltenaufteilung als Standard f\u00FCr diese Aufgabe speichern
dataEditor.mediaNotFound=Es wurden keine Medien gefunden, aber mindestens eine Dateireferenz ist vorhanden. Die automatische Entfernung der fehlenden Medien aus dem Werkst\u00FCck wurde \u00FCbersprungen.
dataEditor.multipleMetadataTasksText=Sie haben mehrere Aufgaben zum Editieren von Metadaten in Bearbeitung. Bitte w\u00E4hlen Sie eine dieser Aufgaben aus!
dataEditor.noParentsError=Elternelement von {0} konnte nicht gefunden werden!
Expand All @@ -323,7 +323,8 @@ dataEditor.position.currentPosition=Aktuelle Position
dataEditor.removeElement.noConsecutivePagesSelected=Strukturelemente k\u00F6nnen nur aus fortlaufenden Medien erstellt werden!
dataEditor.selectMetadataTask=Aufgabe w\u00E4hlen
dataEditor.layoutLoadedSuccessfullyTitle=Metadaten-Editor-Layout geladen
dataEditor.layoutLoadedSuccessfullyText=Spalteneinstellungen f\u00FCr Aufgabe "{0}" erfolgreich geladen
dataEditor.layoutLoadedSuccessfullyDefaultText=Allgemeine Spalteneinstellungen erfolgreich geladen
dataEditor.layoutLoadedSuccessfullyForTaskText=Spalteneinstellungen f\u00FCr Aufgabe "{0}" erfolgreich geladen
dataEditor.layoutSavedSuccessfullyTitle=Aktuelle Spaltenaufteilung erfolgreich gespeichert
dataEditor.layoutSavedSuccessfullyText=Ihre aktuellen Metadaten-Editor-Einstellungen wurden erfolgreich gespeichert! Sie werden f\u00FCr alle zuk\u00FCnftigen Aufgaben dieses Typs wiederverwendet.
dataEditor.renamingMediaComplete=Das Umbenennen der Medien ist abgeschlossen
Expand Down
7 changes: 4 additions & 3 deletions Kitodo/src/main/resources/messages/messages_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,6 @@ dataEditor.addMetadata.newMetadata=Add new metadata
dataEditor.addMetadata.noMetadataAddable=No additional metadata can be added to this structure!
dataEditor.addMetadata.noMetadataAddableToGroup=No further metadata can be added to this group
dataEditor.addMetadata.toGroup=Add metadata to group
dataEditor.cannotSaveLayout=Layout can only be saved, when the editor is accessed from a task.
dataEditor.childNotContainedError=Parents of structure {0} do not contain structure!
dataEditor.comment.correctionWorkflowAlreadyActive=This process is already in a correction workflow state
dataEditor.comment.firstTaskInWorkflow=Correction comments cannot be created for the first task in a workflow.
Expand Down Expand Up @@ -309,7 +308,8 @@ dataEditor.galleryStructuredView=Structured view
dataEditor.galleryDetailView=Detail view
dataEditor.invalidMetadataValue=Cannot store "{0}": The value is invalid. Value: {1}
dataEditor.invalidStructureField=Cannot save "{0}": There is no such field ({1}).
dataEditor.saveLayout=Save current layout as preset for this task
dataEditor.saveLayoutDefault=Save current layout as general preset
dataEditor.saveLayoutForTask=Save current layout as preset for this task
dataEditor.mediaNotFound=No media found, but at least one file reference is present. The automatic removal of missing media from the workpiece was skipped.
dataEditor.multipleMetadataTasksText=There are multiple metadata editing tasks assigned to you for the current process. Please select the task you want to work on!
dataEditor.noParentsError=No parents of structure {0} found!
Expand All @@ -323,7 +323,8 @@ dataEditor.position.currentPosition=Current position
dataEditor.removeElement.noConsecutivePagesSelected=Select consecutive pages to create structure elements!
dataEditor.selectMetadataTask=Select task
dataEditor.layoutLoadedSuccessfullyTitle=Custom layout loaded
dataEditor.layoutLoadedSuccessfullyText=Custom column settings for task "{0}" loaded successfully
dataEditor.layoutLoadedSuccessfullyDefaultText=Custom column settings loaded successfully
dataEditor.layoutLoadedSuccessfullyForTaskText=Custom column settings for task "{0}" loaded successfully
dataEditor.layoutSavedSuccessfullyTitle=Current layout successfully saved
dataEditor.layoutSavedSuccessfullyText=Your current editor settings have been saved successfully and will be applied to all future tasks of the same type.
dataEditor.renamingMediaComplete=Finished renaming media
Expand Down
9 changes: 6 additions & 3 deletions Kitodo/src/main/resources/messages/messages_es.properties
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,6 @@ dataEditor.addMetadata.newMetadata=Añadir nuevos metadatos
dataEditor.addMetadata.noMetadataAddable=No se pueden añadir más metadatos al elemento de estructura seleccionado.
dataEditor.addMetadata.noMetadataAddableToGroup=No se pueden añadir más metadatos a este grupo.
dataEditor.addMetadata.toGroup=Añadir metadatos al grupo
dataEditor.cannotSaveLayout=El diseño sólo se puede guardar si el editor se abre a través de una tarea.
dataEditor.childNotContainedError=El elemento padre de la estructura {0} no contiene la estructura.
dataEditor.comment.correctionWorkflowAlreadyActive=Esta tarea ya se encuentra en un flujo de trabajo de corrección.
dataEditor.comment.firstTaskInWorkflow=No puede escribir un comentario de corrección para esta tarea en este momento porque ninguna de sus tareas se ha completado todavía.
Expand Down Expand Up @@ -309,7 +308,9 @@ dataEditor.galleryStructuredView=Vista estructurada
dataEditor.galleryDetailView=Vista detallada
dataEditor.invalidMetadataValue=„{0}“ no se puede guardar: El valor no es válido. Valor: {1}
dataEditor.invalidStructureField=„{0}“ no se puede guardar: No existe tal campo ({1}).
dataEditor.saveLayout=Guarda el diseño de columna actual como el predeterminado para esta tarea.
# please check google translation below and remove comment if translation is acceptable
dataEditor.saveLayoutDefault=Guardar el diseño actual como preestablecido general
dataEditor.saveLayoutForTask=Guarda el diseño de columna actual como el predeterminado para esta tarea.
dataEditor.mediaNotFound=No se encontraron los medios, pero al menos un archivo de referencia está presente. La eleminación de los medios faltantes de la pieza de trabajo fue omitida.
dataEditor.multipleMetadataTasksText=Tiene varias tareas de edición de metadatos en curso. Por favor, seleccione una de estas tareas.
dataEditor.noParentsError=No se ha encontrado el elemento padre de {0}.
Expand All @@ -323,7 +324,9 @@ dataEditor.position.currentPosition=Posición actual
dataEditor.removeElement.noConsecutivePagesSelected=Los elementos estructurales sólo pueden crearse a partir de medios continuos.
dataEditor.selectMetadataTask=Seleccionar la tarea
dataEditor.layoutLoadedSuccessfullyTitle=¡La plantilla personificada está cargada!
dataEditor.layoutLoadedSuccessfullyText=La configuración de la columna personalizada para la tarea "{0}" se ha cargado correctamente.
# please check google translation below and remove comment if translation is acceptable
dataEditor.layoutLoadedSuccessfullyDefaultText=La configuración de columna personalizada se cargó correctamente
dataEditor.layoutLoadedSuccessfullyForTaskText=La configuración de la columna personalizada para la tarea "{0}" se ha cargado correctamente.
dataEditor.layoutSavedSuccessfullyTitle=La plantilla actual se guardó correctamente
dataEditor.layoutSavedSuccessfullyText=Su configuración actual del editor ha sido guardada con éxito y será aplicadad a todas las tareas futuras del mismo tipo.
dataEditor.renamingMediaComplete=El cambio de nombre de los medios ha finalizado
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@
<h:form id="metadataEditorLayoutForm">
<p:commandButton onclick="saveLayout()"
action="#{DataEditorForm.saveDataEditorSetting()}"
title="#{DataEditorForm.dataEditorSetting ne null ? msgs['dataEditor.saveLayout'] : msgs['dataEditor.cannotSaveLayout']}"
disabled="#{DataEditorForm.dataEditorSetting eq null}"
title="#{DataEditorForm.dataEditorSetting.taskId ne null ? msgs['dataEditor.saveLayoutForTask'] : msgs['dataEditor.saveLayoutDefault']}"
icon="fa fa-wrench"
styleClass="secondary"/>
<h:inputHidden id="structureWidth"
Expand Down
43 changes: 43 additions & 0 deletions Kitodo/src/test/java/org/kitodo/selenium/MetadataST.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
Expand Down Expand Up @@ -330,6 +331,48 @@
assertEquals(structureType, firstChild.getText(), "Added structure element has wrong type!");
}

/**
* Tests that column layout can be saved to database as is loaded into hidden form inputs.
* Does not test whether column layout is actually applied via Javascript (see resize.js).
*/
@Test
public void saveLayoutTest() throws Exception {
login("kowal");

Pages.getProcessesPage().goTo().editMetadata(MockDatabase.MEDIA_RENAMING_TEST_PROCESS_TITLE);

String structureWithId = "metadataEditorLayoutForm:structureWidth";
String metadataWidthId = "metadataEditorLayoutForm:metadataWidth";
String galleryWithId = "metadataEditorLayoutForm:galleryWidth";

Function<String, Double> getValue =
(id) -> Double.parseDouble(Browser.getDriver().findElement(By.id(id)).getAttribute("value"));
thomaslow marked this conversation as resolved.
Fixed
Show resolved Hide resolved

// by default, layout settings are all 0
assertEquals(0.0, getValue.apply(structureWithId));
assertEquals(0.0, getValue.apply(metadataWidthId));
assertEquals(0.0, getValue.apply(galleryWithId));

// save layout settings
Browser.getDriver().findElement(By.cssSelector("#metadataEditorLayoutForm button")).click();

// wait until success message is shown
await().ignoreExceptions().pollDelay(100, TimeUnit.MILLISECONDS).atMost(3, TimeUnit.SECONDS)
.until(Browser.getDriver().findElement(By.id("dataEditorSavingResultDialog_content"))::isDisplayed);

// confirm success message
Browser.getDriver().findElement(By.id("dataEditorSavingResultForm:reload")).click();

// re-open metadata editor
Pages.getMetadataEditorPage().closeEditor();
Pages.getProcessesPage().goTo().editMetadata(MockDatabase.MEDIA_RENAMING_TEST_PROCESS_TITLE);

// verify that layout was saved
assertTrue(0.0 < getValue.apply(structureWithId));
assertTrue(0.0 < getValue.apply(metadataWidthId));
assertTrue(0.0 < getValue.apply(galleryWithId));
}

/**
* Close metadata editor and logout after every test.
* @throws Exception when page navigation fails
Expand Down
Loading