diff --git a/owlcms/src/main/java/app/owlcms/apputils/queryparameters/ContextFreeDisplayParameters.java b/owlcms/src/main/java/app/owlcms/apputils/queryparameters/ContextFreeDisplayParameters.java index 7a6649e41..f51bdbc35 100644 --- a/owlcms/src/main/java/app/owlcms/apputils/queryparameters/ContextFreeDisplayParameters.java +++ b/owlcms/src/main/java/app/owlcms/apputils/queryparameters/ContextFreeDisplayParameters.java @@ -107,7 +107,7 @@ public default HashMap> readParams(Location location, if (!r.isIgnoreGroupFromURL()) { List ageGroupNames = parametersMap.get(AGEGROUP); if (ageGroupNames != null && ageGroupNames.get(0) != null) { - //TODO urldecode the agegroup ? + //CHECK urldecode the agegroup ? ageGroup = AgeGroupRepository.findByName(ageGroupNames.get(0)); } else if (fop != null && isVideo(location) && fop.getVideoAgeGroup() != null) { ageGroup = fop.getVideoAgeGroup(); diff --git a/owlcms/src/main/java/app/owlcms/data/records/RecordDefinitionReader.java b/owlcms/src/main/java/app/owlcms/data/records/RecordDefinitionReader.java index 6e286a231..d7088f9f1 100644 --- a/owlcms/src/main/java/app/owlcms/data/records/RecordDefinitionReader.java +++ b/owlcms/src/main/java/app/owlcms/data/records/RecordDefinitionReader.java @@ -37,6 +37,7 @@ import app.owlcms.data.records.RecordEvent.MissingAgeGroup; import app.owlcms.data.records.RecordEvent.MissingGender; import app.owlcms.data.records.RecordEvent.UnknownIWFBodyWeightCategory; +import app.owlcms.i18n.Translator; import app.owlcms.utils.LoggerUtils; import app.owlcms.utils.ResourceWalker; import app.owlcms.utils.ZipUtils; @@ -159,7 +160,7 @@ public static List createRecords(Workbook workbook, String name, String logger.error("[" + sheet.getSheetName() + "," + cell.getAddress() + "]"); } } - logger.warn("normal {} {} {}", iRecord, rec.getBwCatUpper(), rec.getBwCatLower()); + logger.debug("normal {} {} {}", iRecord, rec.getBwCatUpper(), rec.getBwCatLower()); if (rec.getBwCatUpper() < rec.getBwCatLower()) { throw new Exception(cellValue + " upper limit on bodyweight category should be >= to "+rec.getAgeGrpLower()); @@ -169,7 +170,7 @@ public static List createRecords(Workbook workbook, String name, String long cellValue = Math.round(cell.getNumericCellValue()); rec.setBwCatString(Long.toString(cellValue)); rec.setBwCatUpper(Math.toIntExact(cellValue)); - logger.warn("illegalstate {} {} {}", iRecord, rec.getBwCatUpper(), rec.getBwCatLower()); + logger.debug("illegalstate {} {} {}", iRecord, rec.getBwCatUpper(), rec.getBwCatLower()); if (rec.getBwCatUpper() <= rec.getBwCatLower()) { throw new Exception(cellValue + " upper limit on bodyweight category should be > to "+rec.getBwCatLower()); @@ -203,34 +204,32 @@ public static List createRecords(Workbook workbook, String name, String int intExact = Math.toIntExact(cellValue); if (cellValue < 3000) { rec.setBirthYear(intExact); - logger.warn("number {}", intExact); + logger.debug("number {}", intExact); } else { LocalDate epoch = LocalDate.of(1900, 1, 1); LocalDate plusDays = epoch.plusDays(intExact - 2); // Excel quirks: 1 is 1900-01-01 and mistakenly assumes 1900-02-29 existed rec.setBirthDate(plusDays); - logger.warn("plusDays {}", rec.getRecordDateAsString()); + logger.debug("plusDays {}", rec.getRecordDateAsString()); } } else if (cell.getCellType() == CellType.STRING) { String cellValue = cell.getStringCellValue(); - logger.warn("string value = '{}'", cellValue); + logger.debug("string value = '{}'", cellValue); try { LocalDate date = LocalDate.parse(cellValue, ymdFormatter); rec.setBirthDate(date); - logger.warn("date {}", date); + logger.debug("date {}", date); } catch (DateTimeParseException e) { try { YearMonth date = YearMonth.parse(cellValue, ymFormatter); rec.setBirthYear(date.getYear()); - logger.warn("datemonth {}", date.getYear()); + logger.debug("datemonth {}", date.getYear()); } catch (DateTimeParseException e2) { try { Year date = Year.parse(cellValue, yFormatter); rec.setBirthYear(date.getValue()); - logger.warn("year {}", date.getValue()); + logger.debug("year {}", date.getValue()); } catch (DateTimeParseException e3) { - logger.error(cellValue - + " not in yyyy-MM-dd or yyyy-MM or yyyy date format"); throw new Exception(cellValue + " not in yyyy-MM-dd or yyyy-MM or yyyy date format"); } @@ -253,34 +252,32 @@ public static List createRecords(Workbook workbook, String name, String int intExact = Math.toIntExact(cellValue); if (cellValue < 3000) { rec.setRecordYear(intExact); - logger.warn("number {}", intExact); + logger.debug("number {}", intExact); } else { LocalDate epoch = LocalDate.of(1900, 1, 1); LocalDate plusDays = epoch.plusDays(intExact - 2); // Excel quirks: 1 is 1900-01-01 and mistakenly assumes 1900-02-29 existed rec.setRecordDate(plusDays); - logger.warn("plusDays {}", rec.getRecordDateAsString()); + logger.debug("plusDays {}", rec.getRecordDateAsString()); } } else if (cell.getCellType() == CellType.STRING) { String cellValue = cell.getStringCellValue(); - logger.warn("string value = '{}'", cellValue); + logger.debug("string value = '{}'", cellValue); try { LocalDate date = LocalDate.parse(cellValue, ymdFormatter); rec.setRecordDate(date); - logger.warn("date {}", date); + logger.debug("date {}", date); } catch (DateTimeParseException e) { try { YearMonth date = YearMonth.parse(cellValue, ymFormatter); rec.setRecordYear(date.getYear()); - logger.warn("datemonth {}", date.getYear()); + logger.debug("datemonth {}", date.getYear()); } catch (DateTimeParseException e2) { try { Year date = Year.parse(cellValue, yFormatter); rec.setRecordYear(date.getValue()); - logger.warn("year {}", date.getValue()); + logger.debug("year {}", date.getValue()); } catch (DateTimeParseException e3) { - logger.error(cellValue - + " not in yyyy-MM-dd or yyyy-MM or yyyy date format"); throw new Exception(cellValue + " not in yyyy-MM-dd or yyyy-MM or yyyy date format"); } @@ -329,7 +326,7 @@ public static List createRecords(Workbook workbook, String name, String comp2.setAgeGroupsFileName(name); startupLogger.info("inserted {} record entries.", iRecord); logger.info("inserted {} record entries.", iRecord); - errors.add(Integer.toString(iRecord)); + errors.add(Translator.translate("Records.Inserted",iRecord)); return errors; }); } @@ -356,20 +353,24 @@ public static void readFolder(Path recordsPath) throws IOException { } - public static void readInputStream(InputStream is, String fileName) { + public static List readInputStream(InputStream is, String fileName) { + List errors = new ArrayList<>(); try (Workbook workbook = WorkbookFactory.create(is)) { logger.info("loading record definition file {} {}", fileName, FilenameUtils.removeExtension(fileName)); startupLogger.info("loading record definition file {}", fileName); - createRecords(workbook, fileName, + errors = createRecords(workbook, fileName, FilenameUtils.removeExtension(fileName.toString())); + return errors; } catch (Exception e) { logger.error("could not process record definition file {}\n{}", fileName, LoggerUtils./**/stackTrace(e)); startupLogger.error( "could not process record definition file {}. See log files for details.", fileName); + errors.add(Translator.translate("Records.couldNotProcess",fileName)); + return errors; } } diff --git a/owlcms/src/main/java/app/owlcms/data/records/RecordRepository.java b/owlcms/src/main/java/app/owlcms/data/records/RecordRepository.java index faddd1068..58736d2f0 100644 --- a/owlcms/src/main/java/app/owlcms/data/records/RecordRepository.java +++ b/owlcms/src/main/java/app/owlcms/data/records/RecordRepository.java @@ -226,7 +226,7 @@ private static String filteringWhere(Gender gender, Integer age, Double bw, Stri if (groupName != null) { whereList.add("(groupNameString = :groupName)"); } - if (newRecords != null) { + if (newRecords != null && newRecords) { whereList.add("(groupNameString is not null)"); } if (whereList.size() == 0) { diff --git a/owlcms/src/main/java/app/owlcms/nui/preparation/RecordConfigEditingFormFactory.java b/owlcms/src/main/java/app/owlcms/nui/preparation/RecordConfigEditingFormFactory.java index af8dc938a..5a956208b 100644 --- a/owlcms/src/main/java/app/owlcms/nui/preparation/RecordConfigEditingFormFactory.java +++ b/owlcms/src/main/java/app/owlcms/nui/preparation/RecordConfigEditingFormFactory.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; import org.vaadin.crudui.crud.CrudOperation; @@ -14,6 +15,7 @@ import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.checkbox.Checkbox; +import com.vaadin.flow.component.dialog.Dialog; import com.vaadin.flow.component.formlayout.FormLayout; import com.vaadin.flow.component.formlayout.FormLayout.FormItem; import com.vaadin.flow.component.formlayout.FormLayout.ResponsiveStep; @@ -24,6 +26,7 @@ import com.vaadin.flow.component.html.Hr; import com.vaadin.flow.component.html.Label; import com.vaadin.flow.component.html.Paragraph; +import com.vaadin.flow.component.html.Pre; import com.vaadin.flow.component.orderedlayout.FlexComponent.Alignment; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout; @@ -123,6 +126,7 @@ public Component buildNewForm(CrudOperation operation, RecordConfig comp, boolea FormLayout recordsOrderLayout = recordOrderForm(); FormLayout provisionalLayout = provisionalForm(); FormLayout officialLayout = officialForm(); + FormLayout exportLayout = exportAllForm(); TabSheet ts = new TabSheet(); @@ -132,9 +136,9 @@ public Component buildNewForm(CrudOperation operation, RecordConfig comp, boolea recordsOrderLayout, separator(), officialLayout)); - ts.add(Translator.translate("Records.ProvisionalSection"), + ts.add(Translator.translate("Records.manageNewRecords"), new VerticalLayout( - provisionalLayout)); + provisionalLayout, separator(), exportLayout)); VerticalLayout mainLayout = new VerticalLayout( @@ -162,7 +166,7 @@ private FormLayout provisionalForm() { recordsAvailableLayout.add(title); recordsAvailableLayout.setColspan(title, 2); Div newRecords = DownloadButtonFactory.createDynamicXLSDownloadButton("records", - Translator.translate("Results.NewRecords"), new JXLSExportRecords(UI.getCurrent())); + Translator.translate("Results.NewRecords"), new JXLSExportRecords(UI.getCurrent(),false)); recordsAvailableLayout.addFormItem(newRecords, Translator.translate("Results.NewRecords")); recordsAvailableLayout.addFormItem(clearNewRecords, Translator.translate("Preparation.ClearNewRecordsExplanation")); @@ -170,6 +174,19 @@ private FormLayout provisionalForm() { return recordsAvailableLayout; } + private FormLayout exportAllForm() { + FormLayout recordsAvailableLayout = createLayout(); + Component title = createTitle("Records.exportAllRecordsTitle"); + + recordsAvailableLayout.add(title); + recordsAvailableLayout.setColspan(title, 2); + Div newRecords = DownloadButtonFactory.createDynamicXLSDownloadButton("records", + Translator.translate("Records.exportAllRecordsTitle"), new JXLSExportRecords(UI.getCurrent(),true)); + recordsAvailableLayout.addFormItem(newRecords, Translator.translate("Records.exportAllRecordsLabel")); + + return recordsAvailableLayout; + } + private FormLayout officialForm() { Button clearNewRecords = new Button(Translator.translate("Records.ClearOfficialRecords"), buttonClickEvent -> { @@ -188,8 +205,22 @@ private FormLayout officialForm() { uploadRecords.setUploadButton(uploadButton); uploadRecords.setDropLabel(new Label(Translator.translate("Records.UploadDropZone"))); uploadRecords.addSucceededListener(e -> { - RecordDefinitionReader.readInputStream(receiver.getInputStream(), receiver.getFileName()); - UI.getCurrent().getPage().reload(); + List errors = RecordDefinitionReader.readInputStream(receiver.getInputStream(), receiver.getFileName()); + if (errors.isEmpty()) { + UI.getCurrent().getPage().reload(); + } else { + Pre errorsComponent = new Pre(); + errorsComponent.add(errors.stream().collect(Collectors.joining(System.lineSeparator()))); + Dialog d = new Dialog(); + Button okButton = new Button(Translator.translate("OK"), + x -> { + d.close(); + UI.getCurrent().getPage().reload(); + }); + d.add(errorsComponent); + d.getFooter().add(okButton); + d.open(); + } }); FormLayout recordsAvailableLayout = createLayout(); diff --git a/owlcms/src/main/java/app/owlcms/nui/results/ResultsNavigationContent.java b/owlcms/src/main/java/app/owlcms/nui/results/ResultsNavigationContent.java index 3f594abac..92b46761a 100644 --- a/owlcms/src/main/java/app/owlcms/nui/results/ResultsNavigationContent.java +++ b/owlcms/src/main/java/app/owlcms/nui/results/ResultsNavigationContent.java @@ -64,7 +64,7 @@ public ResultsNavigationContent() { getTranslation("TimingStatistics"), new JXLSTimingStats(UI.getCurrent())); ((Button) timingStats.getComponentAt(0)).setWidth("100%"); Div newRecords = DownloadButtonFactory.createDynamicXLSDownloadButton("records", - getTranslation("Results.NewRecords"), new JXLSExportRecords(UI.getCurrent())); + getTranslation("Results.NewRecords"), new JXLSExportRecords(UI.getCurrent(),false)); ((Button) newRecords.getComponentAt(0)).setWidth("100%"); FlexibleGridLayout grid1 = HomeNavigationContent.navigationGrid(groupResults); diff --git a/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSExportRecords.java b/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSExportRecords.java index 1e826b78a..d15abc8fa 100644 --- a/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSExportRecords.java +++ b/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSExportRecords.java @@ -38,13 +38,15 @@ public class JXLSExportRecords extends JXLSWorkbookStreamSource { Group group; private List records; //private List bestRecords; + private boolean allRecords; public JXLSExportRecords(Group group, boolean excludeNotWeighed, UI ui) { super(); } - public JXLSExportRecords(UI ui) { + public JXLSExportRecords(UI ui, boolean allRecords) { super(); + this.allRecords = allRecords; } @Override @@ -91,7 +93,7 @@ public List getSortedAthletes() { } String groupName = group != null ? group.getName() : null; - records = RecordRepository.findFiltered(null, null, null, groupName, true); + records = RecordRepository.findFiltered(null, null, null, groupName, !allRecords); records.sort(sortRecords()); // // keep best record if beaten several times diff --git a/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSWorkbookStreamSource.java b/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSWorkbookStreamSource.java index 19c1d73e6..6aa549352 100644 --- a/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSWorkbookStreamSource.java +++ b/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSWorkbookStreamSource.java @@ -344,7 +344,7 @@ protected void setReportingInfo() { getReportingBeans().put("group", getGroup()); // reuse existing logic for processing records - JXLSExportRecords jxlsExportRecords = new JXLSExportRecords(null); + JXLSExportRecords jxlsExportRecords = new JXLSExportRecords(null,false); jxlsExportRecords.setGroup(getGroup()); logger.debug("fetching records for session {} category {}", getGroup(), getCategory()); try { diff --git a/owlcms/src/test/java/app/owlcms/tests/RecordDefinitionReaderTest.java b/owlcms/src/test/java/app/owlcms/tests/RecordDefinitionReaderTest.java index ed74df292..6e9406dd6 100644 --- a/owlcms/src/test/java/app/owlcms/tests/RecordDefinitionReaderTest.java +++ b/owlcms/src/test/java/app/owlcms/tests/RecordDefinitionReaderTest.java @@ -171,7 +171,7 @@ public void _09_testOrder() throws IOException { RecordDefinitionReader.createRecords(wb, streamURI, null); List records = RecordRepository.findFiltered(null, null, null, null, null); - records.sort(new JXLSExportRecords(null).sortRecords()); + records.sort(new JXLSExportRecords(null,false).sortRecords()); String results = records.stream().map(RecordEvent::toString).collect( Collectors.joining(System.lineSeparator(),"",System.lineSeparator())); @@ -197,7 +197,7 @@ public void _10_testMessages() throws IOException { List errors = RecordDefinitionReader.createRecords(wb, streamURI, null); List records = RecordRepository.findFiltered(null, null, null, null, null); - records.sort(new JXLSExportRecords(null).sortRecords()); + records.sort(new JXLSExportRecords(null,true).sortRecords()); String results = records.stream().map(RecordEvent::toString).collect( Collectors.joining(System.lineSeparator(),"",System.lineSeparator())); diff --git a/shared/src/main/resources/i18n/translation4.csv b/shared/src/main/resources/i18n/translation4.csv index 3adc94429..031521da5 100644 --- a/shared/src/main/resources/i18n/translation4.csv +++ b/shared/src/main/resources/i18n/translation4.csv @@ -954,4 +954,9 @@ Pause,Pause,,Pausa,,Pausa,Pausa,Pausa,Pause,,,Pausa,Пауза,Pause,Paus,Pause, Jury.NoInterruption,No interruption during a countdown,,Sin interrupción durante una cuenta regresiva,,Sin interrupción durante una cuenta regresiva,Sin interrupción durante una cuenta regresiva,Sin interrupción durante una cuenta regresiva,Pas de d'interruption durant un compte à rebours,,,No interruption during a countdown,No interruption during a countdown,No interruption during a countdown,No interruption during a countdown,No interruption during a countdown,No interruption during a countdown,No interruption during a countdown,No interruption during a countdown,No interruption during a countdown,945,,Jury dialog Jury.NoInterruptionDuringCountdown,The announcer or timekeeper must stop the countdown explicitly.,,El locutor o cronometrador debe detener la cuenta regresiva explícitamente.,,El locutor o cronometrador debe detener la cuenta regresiva explícitamente.,El locutor o cronometrador debe detener la cuenta regresiva explícitamente.,El locutor o cronometrador debe detener la cuenta regresiva explícitamente.,L'annonceur ou le chronométreur doit interrompre explicitement le compte à rebours.,,,The announcer or timekeeper must stop the countdown explicitly.,The announcer or timekeeper must stop the countdown explicitly.,The announcer or timekeeper must stop the countdown explicitly.,The announcer or timekeeper must stop the countdown explicitly.,The announcer or timekeeper must stop the countdown explicitly.,The announcer or timekeeper must stop the countdown explicitly.,The announcer or timekeeper must stop the countdown explicitly.,The announcer or timekeeper must stop the countdown explicitly.,The announcer or timekeeper must stop the countdown explicitly.,946,,Jury dialog OK,OK,,OK,OK,OK,OK,OK,OK,,,OK,OK,OK,OK,OK,OK,OK,OK,OK,947,,Generic Button Label -DisplayParameters.LiftingOrder,Lifting Order,,Lifting Order,Lifting Order,Lifting Order,Lifting Order,Lifting Order,Ordre de passage,,,Lifting Order,Lifting Order,Lifting Order,Lifting Order,Lifting Order,Lifting Order,Lifting Order,Lifting Order,Lifting Order,948,,Display options for PublicResults \ No newline at end of file +DisplayParameters.LiftingOrder,Lifting Order,,Lifting Order,Lifting Order,Lifting Order,Lifting Order,Lifting Order,Ordre de passage,,,Lifting Order,Lifting Order,Lifting Order,Lifting Order,Lifting Order,Lifting Order,Lifting Order,Lifting Order,Lifting Order,948,,Display options for PublicResults +Records.Inserted,{0} records inserted.,,{0} récords insertados.,,{0} récords insertados.,{0} récords insertados.,{0} récords insertados.,{0} records insérés.,,,{0} records inserted.,{0} records inserted.,{0} records inserted.,{0} records inserted.,{0} records inserted.,{0} records inserted.,{0} records inserted.,{0} records inserted.,{0} records inserted.,949,,Records processing confirmation message +Records.couldNotProcess,Error opening file {0},,Error al procesar el archivo {0},,Error al procesar el archivo {0},Error al procesar el archivo {0},Error al procesar el archivo {0},Erreur à l'ouverture du fichier {0},,,Error opening file {0},Error opening file {0},Error opening file {0},Error opening file {0},Error opening file {0},Error opening file {0},Error opening file {0},Error opening file {0},Error opening file {0},950,,Records processing error message +Records.exportAllRecordsTitle,Export all records,,Exportar todos los récords,Exportar todos los récords,Exportar todos los récords,Exportar todos los récords,Exportar todos los récords,Exporter tous les records,,,Export all records,Export all records,Export all records,Export all records,Export all records,Export all records,Export all records,Export all records,Export all records,951,,Records processing option +Records.exportAllRecordsLabel,Export all records as single file,,Exportar todos los récords en un solo archivo,,Exportar todos los récords en un solo archivo,Exportar todos los récords en un solo archivo,Exportar todos los récords en un solo archivo,Exporter tous les records en un seul fichier,,,Export all records as single file,Export all records as single file,Export all records as single file,Export all records as single file,Export all records as single file,Export all records as single file,Export all records as single file,Export all records as single file,Export all records as single file,952,, +Records.manageNewRecords,Manage New Records,Manage New Records,Manage New Records,Manage New Records,Manage New Records,Manage New Records,Manage New Records,Gérer les nouveaux records,,,Manage New Records,Manage New Records,Manage New Records,Manage New Records,Manage New Records,Manage New Records,Manage New Records,Manage New Records,Manage New Records,953,,Tab on Records Management Page \ No newline at end of file diff --git a/src/main/markdown/ReleaseNotes.md b/src/main/markdown/ReleaseNotes.md index f1b1bb16f..b2b26b779 100644 --- a/src/main/markdown/ReleaseNotes.md +++ b/src/main/markdown/ReleaseNotes.md @@ -2,6 +2,11 @@ > *Alpha releases are for initial feedback. Features can be incomplete, subject to change, or broken.* +- alpha03: Records + - Improved error messages when reading the records file are now visible in the user interface + + - Now possible to export all records. The output is in a single Excel however. + - alpha02: Public Results - It is now possible to choose the lifting order instead of the start number order on the remote scoreboard (click on the scoreboard to see the options) - Flags are shown on the remote scoreboard if present in the main owlcms `local/flags`