Tony CHEMIT pushed to branch feature/issue_2755 at ultreiaio / ird-observe

Commits:

7 changed files:

Changes:

  • client/datasource/actions/src/main/resources/report/html/default/report.htmlclient/datasource/actions/src/main/i18n/templates/reportHtmlExport_en_GB.ftl
    ... ... @@ -74,7 +74,7 @@
    74 74
                 }
    
    75 75
                 new gridjs.Grid(config).render(container);
    
    76 76
             }
    
    77
    -        var json = ${json};
    
    77
    +        var json = ${data};
    
    78 78
         </script>
    
    79 79
     </head>
    
    80 80
     <body>
    

  • client/datasource/actions/src/main/i18n/templates/reportHtmlExport_es_ES.ftl
    1
    +<#--
    
    2
    + #%L
    
    3
    + ObServe Client :: DataSource :: Actions
    
    4
    + %%
    
    5
    + Copyright (C) 2008 - 2023 IRD, Ultreia.io
    
    6
    + %%
    
    7
    + This program is free software: you can redistribute it and/or modify
    
    8
    + it under the terms of the GNU General Public License as
    
    9
    + published by the Free Software Foundation, either version 3 of the
    
    10
    + License, or (at your option) any later version.
    
    11
    +
    
    12
    + This program is distributed in the hope that it will be useful,
    
    13
    + but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    14
    + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    15
    + GNU General Public License for more details.
    
    16
    +
    
    17
    + You should have received a copy of the GNU General Public
    
    18
    + License along with this program.  If not, see
    
    19
    + <http://www.gnu.org/licenses/gpl-3.0.html>.
    
    20
    + #L%
    
    21
    +-->

  • client/datasource/actions/src/main/i18n/templates/reportHtmlExport_fr_FR.ftl
    1
    +<#-- @ftlvariable name=".data_model" type="fr.ird.observe.client.datasource.actions.report.HtmlExportModel" -->
    
    2
    +<!DOCTYPE html>
    
    3
    +<!--
    
    4
    +  #%L
    
    5
    +  ObServe Client :: DataSource :: Actions
    
    6
    +  %%
    
    7
    +  Copyright (C) 2008 - 2023 IRD, Ultreia.io
    
    8
    +  %%
    
    9
    +  This program is free software: you can redistribute it and/or modify
    
    10
    +  it under the terms of the GNU General Public License as
    
    11
    +  published by the Free Software Foundation, either version 3 of the
    
    12
    +  License, or (at your option) any later version.
    
    13
    +
    
    14
    +  This program is distributed in the hope that it will be useful,
    
    15
    +  but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    16
    +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    17
    +  GNU General Public License for more details.
    
    18
    +
    
    19
    +  You should have received a copy of the GNU General Public
    
    20
    +  License along with this program.  If not, see
    
    21
    +  <http://www.gnu.org/licenses/gpl-3.0.html>.
    
    22
    +  #L%
    
    23
    +  -->
    
    24
    +
    
    25
    +<html lang="en">
    
    26
    +<head>
    
    27
    +    <link href="https://unpkg.com/gridjs/dist/theme/mermaid.min.css" rel="stylesheet"/>
    
    28
    +    <title>Report...</title>
    
    29
    +    <script src="https://unpkg.com/gridjs/dist/gridjs.umd.js"></script>
    
    30
    +    <style>
    
    31
    +        .config-panel {
    
    32
    +            padding: 10px;
    
    33
    +            margin: 10px 0;
    
    34
    +            background: #fcfcfc;
    
    35
    +            border: 1px solid #e9e9e9;
    
    36
    +            display: inline-block;
    
    37
    +        }
    
    38
    +
    
    39
    +        .config-panel label {
    
    40
    +            margin-right: 10px;
    
    41
    +        }
    
    42
    +
    
    43
    +        td.gridjs-td {
    
    44
    +            background-color: transparent;
    
    45
    +        }
    
    46
    +
    
    47
    +        tr:nth-child(even) {
    
    48
    +            background-color: #dddddd;
    
    49
    +        }
    
    50
    +    </style>
    
    51
    +    <script type="application/javascript">
    
    52
    +        const config = {
    
    53
    +            language: {
    
    54
    +                'search': {
    
    55
    +                    'placeholder': '🔍 Recherche...'
    
    56
    +                }
    
    57
    +            }
    
    58
    +        };
    
    59
    +        const json = ${.data_model.json};
    
    60
    +    </script>
    
    61
    +</head>
    
    62
    +<body>
    
    63
    +<h1>Rapport ${.data_model.selectedReport.name}</h1>
    
    64
    +<h2>Configuration</h2>
    
    65
    +<h3>Données sélectionnées :</h3>
    
    66
    +<ul>
    
    67
    +    <li>
    
    68
    +        <#assign selectDataModel = .data_model.selectDataModel.selectionDataModel />
    
    69
    +        <#assign selectDataCount = selectDataModel.getSelectedCount() />
    
    70
    +
    
    71
    +        <#if selectDataCount == 1> 1 marée <#else> ${selectDataCount} marées</#if>.
    
    72
    +        <ul>
    
    73
    +            <#list selectDataModel.getSelectedLabels() as key, value>
    
    74
    +                <li>
    
    75
    +                    ${key}
    
    76
    +                    <ul>
    
    77
    +                        <#list value as trip>
    
    78
    +                            <li>${trip}</li>
    
    79
    +                        </#list>
    
    80
    +                    </ul>
    
    81
    +                </li>
    
    82
    +            </#list>
    
    83
    +        </ul>
    
    84
    +    </li>
    
    85
    +</ul>
    
    86
    +<h3>Rapport sélectionné :</h3>
    
    87
    +
    
    88
    +<#assign selectedReport = .data_model.selectedReport />
    
    89
    +<p><b>${selectedReport.name}</b></p>
    
    90
    +<#list selectedReport.getVariables() as variable>
    
    91
    +    <li>
    
    92
    +        Variable ${variable.name} : ${variable.selectedValue}.
    
    93
    +    </li>
    
    94
    +</#list>
    
    95
    +<h2>Résultat</h2>
    
    96
    +
    
    97
    +<div class="config-panel">
    
    98
    +    <label><input id="search" type="checkbox" class="action" checked/> Search</label>
    
    99
    +    <label><input id="resizable" type="checkbox" class="action" checked/> Colonnes redimensionnables</label>
    
    100
    +    <label><input id="sort" type="checkbox" class="action" checked/> Sorting</label>
    
    101
    +    <label><input id="pagination" type="checkbox" class="action"/> Pagination</label>
    
    102
    +    <label>Page size<input id="paginationSize" type="number" disabled value="20"/></label>
    
    103
    +</div>
    
    104
    +<div id="wrapperParent">
    
    105
    +    <div id="wrapper"></div>
    
    106
    +</div>
    
    107
    +<script type="application/javascript">
    
    108
    +    const gridContainerParent = document.getElementById("wrapperParent");
    
    109
    +    const searchOption = document.getElementById("search");
    
    110
    +    const resizableOption = document.getElementById("resizable");
    
    111
    +    const paginationOption = document.getElementById("pagination");
    
    112
    +    const paginationSizeOption = document.getElementById("paginationSize");
    
    113
    +    const sortOption = document.getElementById("sort");
    
    114
    +
    
    115
    +    // FIXME Use options value from the very beginning :)
    
    116
    +
    
    117
    +    let grid = new gridjs.Grid({
    
    118
    +        search: true, resizable: true, sort: true,
    
    119
    +        language: config.language, data: []
    
    120
    +    });
    
    121
    +
    
    122
    +    function initGrid(json, container) {
    
    123
    +        let config = {data: json.data.data};
    
    124
    +        if (!!json.columnNames) {
    
    125
    +            config.columns = json.columnNames;
    
    126
    +        } else {
    
    127
    +            config.columns = null;
    
    128
    +        }
    
    129
    +        grid.updateConfig(config).render(container);
    
    130
    +    }
    
    131
    +
    
    132
    +    initGrid(json, document.getElementById("wrapper"));
    
    133
    +
    
    134
    +    function toggle(source) {
    
    135
    +        let newValue = source.checked;
    
    136
    +        let option = source.id;
    
    137
    +        switch (option) {
    
    138
    +            case "search":
    
    139
    +                toggleSearch(newValue);
    
    140
    +                break;
    
    141
    +            case "resizable":
    
    142
    +                toggleResizable(newValue);
    
    143
    +                break;
    
    144
    +            case "pagination":
    
    145
    +                togglePagination(newValue);
    
    146
    +                break;
    
    147
    +            case "paginationSize":
    
    148
    +                changePaginationSize(newValue);
    
    149
    +                break;
    
    150
    +            case "sort":
    
    151
    +                toggleSort(newValue);
    
    152
    +                break;
    
    153
    +        }
    
    154
    +    }
    
    155
    +
    
    156
    +    function toggleSearch(newValue) {
    
    157
    +        console.info("Toggle search to: " + newValue);
    
    158
    +        let newConfig = {
    
    159
    +            language: config.language,
    
    160
    +            data: grid.config.data,
    
    161
    +            columns: grid.config.columns,
    
    162
    +            resizable: resizableOption.checked,
    
    163
    +            pagination: paginationOption.checked ? {limit: paginationSizeOption.value} : false,
    
    164
    +            sort: sortOption.checked
    
    165
    +        };
    
    166
    +        if (newValue) {
    
    167
    +            newConfig.search = true;
    
    168
    +        }
    
    169
    +        updateGrid(newConfig);
    
    170
    +    }
    
    171
    +
    
    172
    +    function toggleResizable(newValue) {
    
    173
    +        console.info("Toggle resizable to: " + newValue);
    
    174
    +        let newConfig = {
    
    175
    +            language: config.language,
    
    176
    +            data: grid.config.data,
    
    177
    +            columns: grid.config.columns,
    
    178
    +            search: searchOption.checked,
    
    179
    +            pagination: paginationOption.checked ? {limit: paginationSizeOption.value} : false,
    
    180
    +            sort: sortOption.checked
    
    181
    +        };
    
    182
    +        if (newValue) {
    
    183
    +            newConfig.resizable = true;
    
    184
    +        }
    
    185
    +        updateGrid(newConfig);
    
    186
    +    }
    
    187
    +
    
    188
    +    function toggleSort(newValue) {
    
    189
    +        console.info("Toggle sort to: " + newValue);
    
    190
    +        let newConfig = {
    
    191
    +            language: config.language,
    
    192
    +            data: grid.config.data,
    
    193
    +            columns: grid.config.columns,
    
    194
    +            search: searchOption.checked,
    
    195
    +            pagination: paginationOption.checked ? {limit: paginationSizeOption.value} : false,
    
    196
    +            resizable: resizableOption.checked
    
    197
    +        };
    
    198
    +        if (newValue) {
    
    199
    +            newConfig.sort = true;
    
    200
    +        }
    
    201
    +        updateGrid(newConfig);
    
    202
    +    }
    
    203
    +
    
    204
    +    function togglePagination(newValue) {
    
    205
    +        console.info("Toggle pagination to: " + newValue);
    
    206
    +        let newConfig = {
    
    207
    +            language: config.language,
    
    208
    +            data: grid.config.data,
    
    209
    +            columns: grid.config.columns,
    
    210
    +            search: searchOption.checked,
    
    211
    +            resizable: resizableOption.checked,
    
    212
    +            sort: sortOption.checked,
    
    213
    +        };
    
    214
    +        if (newValue) {
    
    215
    +            newConfig.pagination = {
    
    216
    +                limit: paginationSizeOption.value
    
    217
    +            };
    
    218
    +            paginationSizeOption["disabled"] = null;
    
    219
    +        } else {
    
    220
    +
    
    221
    +            paginationSizeOption.disabled = true;
    
    222
    +        }
    
    223
    +
    
    224
    +
    
    225
    +        updateGrid(newConfig);
    
    226
    +    }
    
    227
    +
    
    228
    +    function changePaginationSize(newValue) {
    
    229
    +        console.info("Change pagination size to: " + newValue);
    
    230
    +        let newConfig = {
    
    231
    +            language: config.language,
    
    232
    +            data: grid.config.data,
    
    233
    +            columns: grid.config.columns,
    
    234
    +            search: searchOption.checked,
    
    235
    +            resizable: resizableOption.checked,
    
    236
    +            sort: sortOption.checked,
    
    237
    +            pagination: {
    
    238
    +                limit: paginationSizeOption.value
    
    239
    +            }
    
    240
    +        };
    
    241
    +        updateGrid(newConfig);
    
    242
    +    }
    
    243
    +
    
    244
    +    function updateGrid(newConfig) {
    
    245
    +        gridContainerParent.innerHTML = "<div id=\"wrapper\"></div>";
    
    246
    +        console.info(newConfig);
    
    247
    +        setTimeout(() => {
    
    248
    +            grid = new gridjs.Grid(newConfig).render(document.getElementById("wrapper"));
    
    249
    +        }, 200);
    
    250
    +    }
    
    251
    +
    
    252
    +    let actions = document.getElementsByClassName("action");
    
    253
    +    for (const action of document.getElementsByClassName("action")) {
    
    254
    +        action.addEventListener("click", function (event) {
    
    255
    +            toggle(this);
    
    256
    +        });
    
    257
    +    }
    
    258
    +    paginationSizeOption.addEventListener("change", function (event) {
    
    259
    +        toggle(this);
    
    260
    +    });
    
    261
    +</script>
    
    262
    +</body>
    
    263
    +</html>

  • client/datasource/actions/src/main/java/fr/ird/observe/client/datasource/actions/report/ResultJsonModel.javaclient/datasource/actions/src/main/java/fr/ird/observe/client/datasource/actions/report/HtmlExportModel.java
    ... ... @@ -22,6 +22,10 @@ package fr.ird.observe.client.datasource.actions.report;
    22 22
      * #L%
    
    23 23
      */
    
    24 24
     
    
    25
    +import com.google.gson.Gson;
    
    26
    +import fr.ird.observe.client.datasource.actions.config.SelectDataModel;
    
    27
    +import fr.ird.observe.report.Report;
    
    28
    +import io.ultreia.java4all.application.template.spi.GenerateTemplate;
    
    25 29
     import io.ultreia.java4all.util.matrix.DataMatrix;
    
    26 30
     
    
    27 31
     import java.util.List;
    
    ... ... @@ -34,24 +38,52 @@ import java.util.List;
    34 38
      * @author Tony Chemit - dev@tchemit.fr
    
    35 39
      * @since 9.3.0
    
    36 40
      */
    
    37
    -public class ResultJsonModel {
    
    41
    +@GenerateTemplate(template = "reportHtmlExport.ftl")
    
    42
    +public class HtmlExportModel {
    
    43
    +    /**
    
    44
    +     * Selected report.
    
    45
    +     */
    
    46
    +    private final transient Report selectedReport;
    
    47
    +    /**
    
    48
    +     * Selected data model.
    
    49
    +     */
    
    50
    +    private final transient SelectDataModel selectDataModel;
    
    38 51
     
    
    39 52
         private final List<String> columnNames;
    
    40 53
         private final List<String> rowNames;
    
    41 54
         private final DataMatrix data;
    
    42 55
         private final boolean withColumnHeader;
    
    43 56
         private final boolean withRowHeader;
    
    57
    +    private final transient String json;
    
    44 58
     
    
    45
    -    public ResultJsonModel(List<String> columnNames,
    
    59
    +    public HtmlExportModel(Gson gson,
    
    60
    +                           Report selectedReport,
    
    61
    +                           SelectDataModel selectDataModel,
    
    62
    +                           List<String> columnNames,
    
    46 63
                                List<String> rowNames,
    
    47 64
                                DataMatrix data,
    
    48 65
                                boolean withColumnHeader,
    
    49 66
                                boolean withRowHeader) {
    
    67
    +        this.selectedReport = selectedReport;
    
    68
    +        this.selectDataModel = selectDataModel;
    
    50 69
             this.columnNames = columnNames;
    
    51 70
             this.rowNames = rowNames;
    
    52 71
             this.data = data;
    
    53 72
             this.withColumnHeader = withColumnHeader;
    
    54 73
             this.withRowHeader = withRowHeader;
    
    74
    +        this.json = gson.toJson(this);
    
    75
    +    }
    
    76
    +
    
    77
    +    public String getJson() {
    
    78
    +        return json;
    
    79
    +    }
    
    80
    +
    
    81
    +    public Report getSelectedReport() {
    
    82
    +        return selectedReport;
    
    83
    +    }
    
    84
    +
    
    85
    +    public SelectDataModel getSelectDataModel() {
    
    86
    +        return selectDataModel;
    
    55 87
         }
    
    56 88
     
    
    57 89
         public List<String> getColumnNames() {
    

  • client/datasource/actions/src/main/java/fr/ird/observe/client/datasource/actions/report/ReportModel.java
    ... ... @@ -601,6 +601,11 @@ public class ReportModel extends AdminActionModel {
    601 601
             }
    
    602 602
         }
    
    603 603
     
    
    604
    +    public HtmlExportModel toJsonModel() {
    
    605
    +
    
    606
    +        return new HtmlExportModel(getClientConfig().getGsonSupplier().get(), getSelectedReport(), selectDataModel, getResultModel().getColumnNames(), getResultModel().getRowNames(), getResultModel().getData(), getResultModel().isWithColumnHeader(), getResultModel().isWithRowHeader());
    
    607
    +    }
    
    608
    +
    
    604 609
         private Map<String, FilterableComboBox<?>> initVariableComponents(ReportUI ui, Report report) {
    
    605 610
             Map<String, FilterableComboBox<?>> result = new TreeMap<>();
    
    606 611
             JPanel variablesPanel = ui.getReportVariableSelectorPanel();
    

  • client/datasource/actions/src/main/java/fr/ird/observe/client/datasource/actions/report/ResultTableModel.java
    ... ... @@ -236,6 +236,26 @@ public class ResultTableModel extends AbstractTableModel {
    236 236
             return data == null ? null : data.getValue(columnIndex, rowIndex);
    
    237 237
         }
    
    238 238
     
    
    239
    +    public List<String> getColumnNames() {
    
    240
    +        return columnNames;
    
    241
    +    }
    
    242
    +
    
    243
    +    public List<String> getRowNames() {
    
    244
    +        return rowNames;
    
    245
    +    }
    
    246
    +
    
    247
    +    public DataMatrix getData() {
    
    248
    +        return data;
    
    249
    +    }
    
    250
    +
    
    251
    +    public boolean isWithColumnHeader() {
    
    252
    +        return withColumnHeader;
    
    253
    +    }
    
    254
    +
    
    255
    +    public boolean isWithRowHeader() {
    
    256
    +        return withRowHeader;
    
    257
    +    }
    
    258
    +
    
    239 259
         public String getClipboardContent(boolean copyRowHeaders, boolean copyColumnHeaders) {
    
    240 260
             return getDataContent(copyRowHeaders, copyColumnHeaders, true, '\t');
    
    241 261
         }
    
    ... ... @@ -264,8 +284,4 @@ public class ResultTableModel extends AbstractTableModel {
    264 284
             result += data.getClipboardContent(copyRowHeaders || !withRowHeader, true, escapeCell, separator);
    
    265 285
             return result;
    
    266 286
         }
    
    267
    -
    
    268
    -    public ResultJsonModel toJsonModel() {
    
    269
    -        return new ResultJsonModel(columnNames, rowNames, data, withColumnHeader, withRowHeader);
    
    270
    -    }
    
    271 287
     }

  • client/datasource/actions/src/main/java/fr/ird/observe/client/datasource/actions/report/actions/ExportToHtml.java
    ... ... @@ -22,13 +22,12 @@ package fr.ird.observe.client.datasource.actions.report.actions;
    22 22
      * #L%
    
    23 23
      */
    
    24 24
     
    
    25
    -import com.google.common.base.Charsets;
    
    26
    -import com.google.common.io.Resources;
    
    27 25
     import fr.ird.observe.client.datasource.actions.ObserveKeyStrokesActions;
    
    28 26
     import fr.ird.observe.client.datasource.actions.actions.AdminTabUIActionSupport;
    
    27
    +import fr.ird.observe.client.datasource.actions.report.HtmlExportModel;
    
    28
    +import fr.ird.observe.client.datasource.actions.report.HtmlExportModelTemplate;
    
    29 29
     import fr.ird.observe.client.datasource.actions.report.ReportModel;
    
    30 30
     import fr.ird.observe.client.datasource.actions.report.ReportUI;
    
    31
    -import fr.ird.observe.client.datasource.actions.report.ResultJsonModel;
    
    32 31
     import fr.ird.observe.client.util.UIHelper;
    
    33 32
     import org.apache.logging.log4j.LogManager;
    
    34 33
     import org.apache.logging.log4j.Logger;
    
    ... ... @@ -79,20 +78,14 @@ public class ExportToHtml extends AdminTabUIActionSupport<ReportUI> {
    79 78
             // generate data file
    
    80 79
             Path dataFile = exportDirectory.resolve("data.json");
    
    81 80
             log.info("Generate data file for report ({}) at {}", reportId, dataFile);
    
    82
    -        ResultJsonModel dataModel = stepModel.getResultModel().toJsonModel();
    
    83
    -        String dataContent = getClientConfig().getGsonSupplier().get().toJson(dataModel);
    
    81
    +        HtmlExportModel dataModel = stepModel.toJsonModel();
    
    82
    +        String dataContent = dataModel.getJson();
    
    84 83
             Files.writeString(dataFile, dataContent);
    
    85 84
     
    
    86
    -//        // generate javascript file
    
    87
    -//        Path jsFile = exportDirectory.resolve("report.js");
    
    88
    -//        log.info("Generate js file for report ({}) at {}", reportId, jsFile);
    
    89
    -//        String jsContent = Resources.asCharSource(Resources.getResource("report/html/default/report.js"), Charsets.UTF_8).read();
    
    90
    -//        Files.writeString(jsFile, jsContent);
    
    91
    -
    
    92 85
             // generate html file
    
    93 86
             Path htmlFile = exportDirectory.resolve("report.html");
    
    94 87
             log.info("Generate html file for report ({}) at {}", reportId, htmlFile);
    
    95
    -        String fileContent = Resources.asCharSource(Resources.getResource("report/html/default/report.html"), Charsets.UTF_8).read().replace("${json}", dataContent);
    
    88
    +        String fileContent = HtmlExportModelTemplate.generate(dataModel);
    
    96 89
             Files.writeString(htmlFile, fileContent);
    
    97 90
     
    
    98 91
             // open html file