diff --git a/WebApp/WebContent/data_file/upload.xhtml b/WebApp/WebContent/data_file/upload.xhtml index c51ecc28c..e5767dc60 100644 --- a/WebApp/WebContent/data_file/upload.xhtml +++ b/WebApp/WebContent/data_file/upload.xhtml @@ -13,21 +13,109 @@ #{fileUpload.currentInstrument.name} - Upload Data Files + + + +
- - - - + + + + + + + + + + +
+ +
+ Found unrecognised run types. + Please assign them using the menu options. +
+ + + + Run Type + #{runType.runType().runName} + + + Category + + + + + + + + + + + + + +
+ + + + + + + + +
+
+
+
+ + + + + + + @@ -42,107 +130,34 @@ - -
- - + - -
- - + - -
- - + - -
- - - - - -
This file contained - unrecognised Run Types. Please assign them using the - menu options.
- - - - - - - - -
- - - -
- -
- - - - - - - - -
-
-
-
@@ -151,6 +166,7 @@ '); - for (var i = 0; i < messages.length; i++) { - var row = $('
  • '); + let html = $('
      '); + for (let i = 0; i < messages.length; i++) { + let row = $('
    • '); row.addClass(messages[i].severity); - var summary = $(''); + let summary = $(''); if (messages[i].type == "file") { summary = $('

      '); } @@ -29,17 +18,36 @@ function renderMessages(messages) { $('.ui-scrollpanel')[0].scrollTop = 0; } -function reprocessUploadedFiles() { - $('#uploadForm\\:fileList_data>tr').each(function() { - extractNext(); - }); +function runTypeChanged(rowIndex) { + let runType = PF('runType_' + rowIndex).getSelectedValue(); + if (runType == ALIAS_RUN_TYPE) { + PF('alias_' + rowIndex).jq.show() + } else { + PF('alias_' + rowIndex).jq.hide() + } } -function runTypeChanged(rowIndex, runTypeIndex) { - var runType = PF('missingRunType_' + rowIndex + '_' + runTypeIndex).getSelectedValue(); - if (runType == ALIAS_RUN_TYPE) { - PF('alias_' + rowIndex + '_' + runTypeIndex).jq.show() +function fileUploaded() { + if (PF('fileUploadWidget').files.length == 0) { + extractFiles(); + } +} + +function extractFiles() { + $('#uploadForm\\:uploadFiles').hide(); + processAllFiles(); // PF RemoteCommand + PF('extractProgress').show(); + PF('processedProgress').start(); +} + +function allFilesProcessed() { + PF('processedProgress').cancel(); + PF('extractProgress').hide(); + if ($('#uploadForm\\:unrecognisedRunTypeCount').val() > 0) { + PF('runTypesDialog').show(); } else { - PF('alias_' + rowIndex + '_' + runTypeIndex).jq.hide() + $('#uploadForm\\:fileDetails').show(); + $('#uploadForm\\:storeFileButton').show(); + updateFileList(); // PF remoteCommand } } diff --git a/WebApp/WebContent/resources/style/dataFiles.css b/WebApp/WebContent/resources/style/dataFiles.css index ad1d3d3c3..b8180a933 100644 --- a/WebApp/WebContent/resources/style/dataFiles.css +++ b/WebApp/WebContent/resources/style/dataFiles.css @@ -53,3 +53,8 @@ .runTypeFile >.ui-fieldset { margin: 0 0 20px 0; } + +#runTypesDialogContent { + display: flex; + flex-wrap: nowrap; +} diff --git a/WebApp/src/uk/ac/exeter/QuinCe/data/Instrument/InstrumentDB.java b/WebApp/src/uk/ac/exeter/QuinCe/data/Instrument/InstrumentDB.java index a8f507109..7a18b36d7 100644 --- a/WebApp/src/uk/ac/exeter/QuinCe/data/Instrument/InstrumentDB.java +++ b/WebApp/src/uk/ac/exeter/QuinCe/data/Instrument/InstrumentDB.java @@ -8,6 +8,7 @@ import java.sql.Statement; import java.sql.Types; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -48,6 +49,7 @@ import uk.ac.exeter.QuinCe.utils.MissingParam; import uk.ac.exeter.QuinCe.utils.MissingParamException; import uk.ac.exeter.QuinCe.utils.RecordNotFoundException; +import uk.ac.exeter.QuinCe.web.files.MissingRunType; import uk.ac.exeter.QuinCe.web.system.ResourceManager; /** @@ -1330,24 +1332,24 @@ public static PreparedStatement storeFileRunType(Connection conn, long fileId, * @throws MissingParamException * If any required parameters are missing */ - public static void storeFileRunTypes(DataSource dataSource, long fileId, - List assignments) + public static void storeFileRunTypes(DataSource dataSource, + Collection runTypes) throws MissingParamException, DatabaseException { MissingParam.checkMissing(dataSource, "dataSource"); - MissingParam.checkPositive(fileId, "fileDefinitionId"); - MissingParam.checkMissing(assignments, "runTypes", true); + MissingParam.checkMissing(runTypes, "runTypes", true); List stmts = new ArrayList( - assignments.size()); + runTypes.size()); Connection conn = null; try { conn = dataSource.getConnection(); conn.setAutoCommit(false); - for (RunTypeAssignment assignment : assignments) { - stmts.add(storeFileRunType(conn, fileId, assignment)); + for (MissingRunType runType : runTypes) { + stmts.add(storeFileRunType(conn, + runType.fileDefinition().getDatabaseId(), runType.runType())); } conn.commit(); diff --git a/WebApp/src/uk/ac/exeter/QuinCe/web/BaseManagedBean.java b/WebApp/src/uk/ac/exeter/QuinCe/web/BaseManagedBean.java index c73ae018d..aab423e4e 100644 --- a/WebApp/src/uk/ac/exeter/QuinCe/web/BaseManagedBean.java +++ b/WebApp/src/uk/ac/exeter/QuinCe/web/BaseManagedBean.java @@ -86,6 +86,11 @@ public abstract class BaseManagedBean { */ private boolean forceInstrumentReload = false; + /** + * Information for a progress bar. + */ + protected Progress progress = new Progress(); + /** * Set a message that can be displayed to the user on a form * @@ -582,4 +587,13 @@ public LocalDateTime getLastDate() { } return result; } + + /** + * Get the progress bar information. + * + * @return The progress bar information. + */ + public Progress getProgress() { + return progress; + } } diff --git a/WebApp/src/uk/ac/exeter/QuinCe/web/Progress.java b/WebApp/src/uk/ac/exeter/QuinCe/web/Progress.java new file mode 100644 index 000000000..74c9ea707 --- /dev/null +++ b/WebApp/src/uk/ac/exeter/QuinCe/web/Progress.java @@ -0,0 +1,84 @@ +package uk.ac.exeter.QuinCe.web; + +/** + * Information holder for a progress bar. + * + *

      + * The maximum value defaults to 100, in which case the progress value is + * assumed to be a percentage. Otherwise the value will be calculated as a + * percentage of the maximum. + *

      + */ +public class Progress { + + /** + * The label for the progress bar. + */ + private String name = "Progress"; + + /** + * The maximum (target) value of the progress bar. + * + *

      + * Defaults to 100 so it acts as a percentage. + *

      + */ + private float max = 100F; + + /** + * The current value. Starts at zero. + */ + private float value = 0F; + + /** + * Set the name/label for the progress bar. + * + * @param name + * The name. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Set the maximum value for the progress bar. + * + * @param max + * The maximum value. + */ + public void setMax(float max) { + this.max = max; + } + + /** + * Set the value for the progress bar. + * + * @param value + * The value. + */ + public void setValue(float value) { + this.value = value; + } + + public void increment() { + this.value += 1; + } + + /** + * Get the name/label for the progress bar. + * + * @return The name. + */ + public String getName() { + return name; + } + + /** + * Get the current progress as a percentage. + * + * @return The progress percentage. + */ + public float getProgress() { + return max == 100F ? value : (value / max) * 100; + } +} diff --git a/WebApp/src/uk/ac/exeter/QuinCe/web/files/DataFilesBean.java b/WebApp/src/uk/ac/exeter/QuinCe/web/files/DataFilesBean.java index 37094e1cf..2dd5cec8e 100644 --- a/WebApp/src/uk/ac/exeter/QuinCe/web/files/DataFilesBean.java +++ b/WebApp/src/uk/ac/exeter/QuinCe/web/files/DataFilesBean.java @@ -23,7 +23,7 @@ public class DataFilesBean extends FileUploadBean { /** - * Navigation to the file upload page + * Navigation to the file list page */ public static final String NAV_FILE_LIST = "file_list"; diff --git a/WebApp/src/uk/ac/exeter/QuinCe/web/files/MissingRunType.java b/WebApp/src/uk/ac/exeter/QuinCe/web/files/MissingRunType.java new file mode 100644 index 000000000..5bb302a67 --- /dev/null +++ b/WebApp/src/uk/ac/exeter/QuinCe/web/files/MissingRunType.java @@ -0,0 +1,15 @@ +package uk.ac.exeter.QuinCe.web.files; + +import java.util.List; + +import uk.ac.exeter.QuinCe.data.Instrument.FileDefinition; +import uk.ac.exeter.QuinCe.data.Instrument.RunTypes.RunTypeAssignment; + +public record MissingRunType(FileDefinition fileDefinition, + RunTypeAssignment runType) { + protected static boolean contains(List list, + FileDefinition fileDefinition, String runName) { + return list.stream().anyMatch(r -> r.fileDefinition.equals(fileDefinition) + && r.runType.getRunName().equals(runName)); + } +} diff --git a/WebApp/src/uk/ac/exeter/QuinCe/web/files/MultipleFileUploadBean.java b/WebApp/src/uk/ac/exeter/QuinCe/web/files/MultipleFileUploadBean.java index f4981268f..fda669df2 100644 --- a/WebApp/src/uk/ac/exeter/QuinCe/web/files/MultipleFileUploadBean.java +++ b/WebApp/src/uk/ac/exeter/QuinCe/web/files/MultipleFileUploadBean.java @@ -1,16 +1,20 @@ package uk.ac.exeter.QuinCe.web.files; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.util.TreeSet; +import java.util.stream.Collectors; import javax.faces.bean.ManagedBean; import javax.faces.bean.ViewScoped; import org.primefaces.model.file.UploadedFile; -import uk.ac.exeter.QuinCe.data.Files.DataFile; import uk.ac.exeter.QuinCe.data.Files.DataFileDB; import uk.ac.exeter.QuinCe.data.Files.FileExistsException; import uk.ac.exeter.QuinCe.data.Instrument.InstrumentDB; +import uk.ac.exeter.QuinCe.data.Instrument.RunTypes.RunTypeAssignment; import uk.ac.exeter.QuinCe.utils.DatabaseException; import uk.ac.exeter.QuinCe.utils.ExceptionUtils; import uk.ac.exeter.QuinCe.utils.MissingParamException; @@ -24,34 +28,49 @@ public class MultipleFileUploadBean extends FileUploadBean { * The data file object */ private TreeSet dataFiles = new TreeSet(); - private String displayClass = "hidden"; + + private List unrecognisedRunTypes; @Override public void processUploadedFile() { processUploadedFile(getFile()); } - public void processUploadedFile(UploadedFile uploadedFile) { + public synchronized void processUploadedFile(UploadedFile uploadedFile) { UploadedDataFile uploadedDataFile = new PrimeFacesUploadedDataFile( uploadedFile); dataFiles.add(uploadedDataFile); - setDisplayClass(""); } public TreeSet getUploadedFiles() { return dataFiles; } + public List getAllRunTypes() { + return getCurrentInstrument().getFileDefinitions().stream() + .map(df -> df.getRunTypes().values()).flatMap(Collection::stream) + .distinct().collect(Collectors.toList()); + } + + public List getAllRunTypesWithExclusion(String exclusion) { + return getCurrentInstrument().getFileDefinitions().stream() + .map(df -> df.getRunTypes().values()).flatMap(Collection::stream) + .distinct().collect(Collectors.toList()); + } + /** - * Extract files in file list that are not yet extracted + * (Re-)extract all files in the file list. */ - public void extractNext() { + public void processAllFiles() { + progress.setMax(dataFiles.size()); + progress.setValue(0); + dataFiles.forEach(f -> f.setProcessed(false)); for (UploadedDataFile file : dataFiles) { - if (file.getDataFile() == null && file.isStore()) { - file.extractFile(getCurrentInstrument(), getAppConfig(), false, false); - break; - } + file.extractFile(getCurrentInstrument(), getAppConfig(), false, false); + progress.increment(); } + + buildUnrecognisedRunTypes(); } /** @@ -77,21 +96,6 @@ public void store() throws MissingParamException, FileExistsException, } } - /** - * @return the displayClass - */ - public String getDisplayClass() { - return displayClass; - } - - /** - * @param displayClass - * the displayClass to set - */ - public void setDisplayClass(String displayClass) { - this.displayClass = displayClass; - } - /** * @return the class "hidden" if there are no datafiles yet. Otherwise returns * an empty string. @@ -104,25 +108,12 @@ public String getStoreFileButtonClass() { * Called when run types have been updated. This will initiate re-processing * of the uploaded files. */ - public void updateRunTypes(String fileName) { - DataFile dataFile = null; - - for (UploadedDataFile file : dataFiles) { - if (file.getName().equals(fileName)) { - dataFile = file.getDataFile(); - } + public void updateRunTypes() { + try { + InstrumentDB.storeFileRunTypes(getDataSource(), unrecognisedRunTypes); + } catch (Exception e) { + ExceptionUtils.printStackTrace(e); } - - if (null != dataFile) { - try { - InstrumentDB.storeFileRunTypes(getDataSource(), - dataFile.getFileDefinition().getDatabaseId(), - dataFile.getMissingRunTypes()); - } catch (Exception e) { - ExceptionUtils.printStackTrace(e); - } - } - unsetDataFiles(); } @@ -137,4 +128,37 @@ private void unsetDataFiles() { ((PrimeFacesUploadedDataFile) file).getUploadedFile()); } } + + private void buildUnrecognisedRunTypes() { + unrecognisedRunTypes = new ArrayList(); + + for (UploadedDataFile file : dataFiles) { + for (RunTypeAssignment runType : file.getMissingRunTypes()) { + if (!MissingRunType.contains(unrecognisedRunTypes, + file.getDataFile().getFileDefinition(), runType.getRunName())) { + unrecognisedRunTypes.add(new MissingRunType( + file.getDataFile().getFileDefinition(), runType)); + } + } + } + } + + public List getUnrecognisedRunTypes() { + + if (null == unrecognisedRunTypes) { + buildUnrecognisedRunTypes(); + } + + return unrecognisedRunTypes; + } + + public int getUnrecognisedRunTypeCount() { + return null == unrecognisedRunTypes ? 0 : unrecognisedRunTypes.size(); + } + + public List getRunTypeValuesWithExclusion(String exclusion) { + return getCurrentInstrument().getFileDefinitions().stream() + .map(fd -> fd.getRunTypeValues()).flatMap(Collection::stream).distinct() + .filter(r -> !r.equals(exclusion)).toList(); + } } diff --git a/WebApp/src/uk/ac/exeter/QuinCe/web/files/UploadedDataFile.java b/WebApp/src/uk/ac/exeter/QuinCe/web/files/UploadedDataFile.java index 6e0ea1aee..869e7b644 100644 --- a/WebApp/src/uk/ac/exeter/QuinCe/web/files/UploadedDataFile.java +++ b/WebApp/src/uk/ac/exeter/QuinCe/web/files/UploadedDataFile.java @@ -24,6 +24,7 @@ import uk.ac.exeter.QuinCe.data.Instrument.FileDefinition; import uk.ac.exeter.QuinCe.data.Instrument.Instrument; import uk.ac.exeter.QuinCe.data.Instrument.InstrumentFileSet; +import uk.ac.exeter.QuinCe.data.Instrument.RunTypes.RunTypeAssignment; import uk.ac.exeter.QuinCe.utils.ExceptionUtils; import uk.ac.exeter.QuinCe.web.system.ResourceManager; @@ -263,6 +264,11 @@ public boolean getHasUnrecognisedRunTypes() { return null != dataFile && dataFile.getMissingRunTypes().size() > 0; } + public List getMissingRunTypes() { + return null == dataFile ? new ArrayList() + : dataFile.getMissingRunTypes(); + } + /** * Determine whether or not this file will replace an existing file *