From 6c543f3ccfc23bdf8f07ae7e2c229febdf4cb6ea Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Thu, 25 Apr 2024 18:01:34 +0200
Subject: [PATCH 01/22] Utiliser une liste pour choisir les indicateurs. fixes
 #55

---
 .../www/client/ui/DominoListBuilder.java      | 106 ++++++++++++++++++
 .../www/client/view/LayoutView.java           |  22 +++-
 .../agrometinfo/www/client/public/style.css   |  15 +++
 .../fr/agrometinfo/www/shared/dto/HasId.java  |  18 ---
 .../agrometinfo/www/shared/dto/HasName.java   |  18 ---
 5 files changed, 138 insertions(+), 41 deletions(-)
 create mode 100644 www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
 delete mode 100644 www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasId.java
 delete mode 100644 www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasName.java

diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java b/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
new file mode 100644
index 0000000..85bcc39
--- /dev/null
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
@@ -0,0 +1,106 @@
+package fr.agrometinfo.www.client.ui;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.function.Consumer;
+
+import org.dominokit.domino.ui.grid.flex.FlexItem;
+import org.dominokit.domino.ui.grid.flex.FlexLayout;
+import org.dominokit.domino.ui.lists.ListGroup;
+import org.dominokit.domino.ui.utils.TextNode;
+
+/**
+ * Builder for a Domino {@link ListGroup}, a component that allow selecting a
+ * single option from a panel.
+ *
+ * @author Olivier Maury
+ *
+ * @param <T> The type of a single option value
+ */
+public final class DominoListBuilder<T> extends SelectBuilder<T, ListGroup<T>> {
+    /**
+     * The component.
+     */
+    private ListGroup<T> select;
+
+    @Override
+    public DominoListBuilder<T> addOption(final T option) {
+        return addOptions(Arrays.asList(option));
+    }
+
+    @Override
+    public DominoListBuilder<T> addOptions(final Collection<T> list) {
+        getSelect().addItems(new ArrayList<>(list));
+        return this;
+    }
+
+    @Override
+    public DominoListBuilder<T> addValueChangeHandler(final Consumer<String> handler) {
+        getSelect().addSelectionListener(selectedItems -> {
+            if (selectedItems == null || selectedItems.isEmpty()) {
+                return;
+            }
+            final T item = selectedItems.get(0).getValue();
+            handler.accept(getValueFunction().apply(item));
+        });
+        return this;
+    }
+
+    @Override
+    public ListGroup<T> build() {
+        Objects.requireNonNull(getValueFunction(), "setValueFunction() must be called before!");
+        Objects.requireNonNull(getTextFunction(), "setTextFunction() must be called before!");
+        return getSelect().setItemRenderer(
+                (listGroup, item) ->
+                item.setSelectable(true)
+                .appendChild(
+                        FlexLayout.create() //
+                        .appendChild(//
+                                FlexItem.create() //
+                                .setFlexGrow(1) //
+                                .appendChild(TextNode
+                                        .of(getTextFunction().apply(item.getValue())))))
+                );
+    }
+
+    private ListGroup<T> getSelect() {
+        if (select == null) {
+            select = ListGroup.<T>create();
+        }
+        return select;
+    }
+
+    @Override
+    public DominoListBuilder<T> removeOptions() {
+        getSelect().clearElement();
+        return this;
+    }
+
+    @Override
+    public DominoListBuilder<T> select(final T value) {
+        getSelect().getItems().stream() //
+        .filter(i -> Objects.equals(getValueFunction().apply(i.getValue()), getValueFunction().apply(value))) //
+        .findFirst() //
+        .ifPresent(toSelect -> select.select(Arrays.asList(toSelect)));
+        return this;
+    }
+
+    @Override
+    public DominoListBuilder<T> setPrompt(final String text) {
+        // no prompt for this component
+        return this;
+    }
+
+    /**
+     * Use an existing element.
+     *
+     * @param value existing ListGroup element
+     * @return same builder instance
+     */
+    public DominoListBuilder<T> setSelect(final ListGroup<T> value) {
+        select = value;
+        return this;
+    }
+}
diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
index bc76609..3d56e08 100644
--- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
@@ -18,6 +18,7 @@ import org.dominokit.domino.ui.grid.flex.FlexItem;
 import org.dominokit.domino.ui.icons.Icons;
 import org.dominokit.domino.ui.icons.MdiIcon;
 import org.dominokit.domino.ui.layout.Layout;
+import org.dominokit.domino.ui.lists.ListGroup;
 import org.dominokit.domino.ui.loaders.Loader;
 import org.dominokit.domino.ui.loaders.LoaderEffect;
 import org.dominokit.domino.ui.menu.Menu;
@@ -50,6 +51,7 @@ import fr.agrometinfo.www.client.presenter.LayoutPresenter;
 import fr.agrometinfo.www.client.presenter.MapPresenter;
 import fr.agrometinfo.www.client.presenter.RightPanelPresenter;
 import fr.agrometinfo.www.client.ui.AgroclimAppsMenu;
+import fr.agrometinfo.www.client.ui.DominoListBuilder;
 import fr.agrometinfo.www.client.ui.DominoSelectBuilder;
 import fr.agrometinfo.www.client.util.ApplicationUtils;
 import fr.agrometinfo.www.shared.dto.ChoiceDTO;
@@ -150,7 +152,7 @@ implements LayoutPresenter.View, LoadingHandler {
     /**
      * Selector for indicators.
      */
-    private final Select<IndicatorDTO> indicatorSelect = Select.create(CSTS.chooseIndicator());
+    private final ListGroup<IndicatorDTO> indicatorSelect = ListGroup.create();
 
     /**
      * Application layout.
@@ -342,9 +344,19 @@ implements LayoutPresenter.View, LoadingHandler {
 
         //
         GWT.log("LayoutView.initLeftPanel() indicators");
-        panel.appendChild(indicatorSelect);
-        new DominoSelectBuilder<IndicatorDTO>() //
+        panel.appendChild(//
+                Elements.div() //
+                .css("field-group lined list-group") //
+                .add(//
+                        Elements.label() //
+                        .css("field-label") //
+                        .add(Elements.span().textContent(CSTS.chooseIndicator()))) //
+                .add(indicatorSelect) //
+                );
+        new DominoListBuilder<IndicatorDTO>() //
         .setSelect(indicatorSelect) //
+        .setTextFunction(IndicatorDTO::getDescription) //
+        .setValueFunction(IndicatorDTO::getCode) //
         .addValueChangeHandler(this::onIndicatorChange) //
         .build();
 
@@ -546,7 +558,7 @@ implements LayoutPresenter.View, LoadingHandler {
             }
         }
         if (list == null || list.isEmpty()) {
-            indicatorSelect.removeAllOptions();
+            indicatorSelect.clearElement();
             return;
         }
         GWT.log("LayoutView.onPeriodChange() Indicators : " + list);
@@ -554,7 +566,7 @@ implements LayoutPresenter.View, LoadingHandler {
         final IndicatorDTO defaultIndicator = list.stream() //
                 .filter(i -> DEFAULT_INDICATOR.equals(i.getCode())) //
                 .findFirst().orElse(firstIndicator);
-        new DominoSelectBuilder<IndicatorDTO>() //
+        new DominoListBuilder<IndicatorDTO>() //
         .setSelect(indicatorSelect) //
         .setTextFunction(IndicatorDTO::getDescription) //
         .setValueFunction(IndicatorDTO::getCode) //
diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
index 61bc308..048618c 100644
--- a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
+++ b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
@@ -180,6 +180,21 @@ details.card-details[open] > summary i {
     transform: rotate(180deg);
 }
 
+div.list-group > label.field-label {
+    position: relative;
+}
+div.list-group .flex-item {
+    line-height: 2em;
+    transition: all .5s;
+    user-select: none;
+}
+div.list-group .d-list-item.selected {
+    background-color: #ededed;
+    color: #414141;
+}
+div.list-group .d-list-item:hover {
+    background-color: #f5f5f5;
+}
 
 .float-right {
     float: right;
diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasId.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasId.java
deleted file mode 100644
index f889b40..0000000
--- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasId.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package fr.agrometinfo.www.shared.dto;
-
-/**
- * The object has an identifier.
- *
- * @author Olivier Maury
- */
-public interface HasId {
-    /**
-     * @return identifier
-     */
-    Integer getId();
-
-    /**
-     * @param id identifier
-     */
-    void setId(Integer id);
-}
diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasName.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasName.java
deleted file mode 100644
index 75c0d07..0000000
--- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasName.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package fr.agrometinfo.www.shared.dto;
-
-/**
- * The object as name.
- *
- * @author Olivier Maury
- */
-public interface HasName {
-    /**
-     * @return name
-     */
-    String getName();
-
-    /**
-     * @param name name
-     */
-    void setName(String name);
-}
-- 
GitLab


From 88822474ce8e4348f0c966a89b6916737b65c013 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Thu, 25 Apr 2024 18:02:54 +0200
Subject: [PATCH 02/22] PMD

---
 .../main/java/fr/agrometinfo/www/client/view/LayoutView.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
index 3d56e08..66a064c 100644
--- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
@@ -345,7 +345,7 @@ implements LayoutPresenter.View, LoadingHandler {
         //
         GWT.log("LayoutView.initLeftPanel() indicators");
         panel.appendChild(//
-                Elements.div() //
+                div() //
                 .css("field-group lined list-group") //
                 .add(//
                         Elements.label() //
-- 
GitLab


From ab3ae42f0029fbe44135977b6ae2f3adf11640bb Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Thu, 25 Apr 2024 18:46:19 +0200
Subject: [PATCH 03/22] Padding

---
 .../main/resources/fr/agrometinfo/www/client/public/style.css | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
index 048618c..5053a42 100644
--- a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
+++ b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
@@ -181,10 +181,14 @@ details.card-details[open] > summary i {
 }
 
 div.list-group > label.field-label {
+    padding-left: 6px;
+    padding-right: 6px;
     position: relative;
 }
 div.list-group .flex-item {
     line-height: 2em;
+    padding-left: 6px;
+    padding-right: 6px;
     transition: all .5s;
     user-select: none;
 }
-- 
GitLab


From 74030ae8197d4b7c4e4829527eabc0df7d0a7b32 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Fri, 26 Apr 2024 11:15:45 +0200
Subject: [PATCH 04/22] =?UTF-8?q?Homog=C3=A9n=C3=A9iser=20les=20noms=20des?=
 =?UTF-8?q?=20variables?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 sql/migration.sql     | 9 +++++++++
 sql/schema.tables.sql | 1 +
 sql/translations.csv  | 8 ++++----
 3 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/sql/migration.sql b/sql/migration.sql
index 42dc9de..f06cc7c 100644
--- a/sql/migration.sql
+++ b/sql/migration.sql
@@ -213,6 +213,15 @@ END
 $BODY$
 language plpgsql;
 
+CREATE OR REPLACE FUNCTION upgrade20240426() RETURNS boolean AS $BODY$
+BEGIN
+    CREATE INDEX IF NOT EXISTS "IX_cellpra" ON cellpra (cell,pra);
+    UPDATE i18n SET translation=REPLACE(translation, 'tmax', 'Tmax');
+    RETURN true;
+END
+$BODY$
+language plpgsql;
+
 ---
 --
 -- Keep this call at the end to apply migration functions.
diff --git a/sql/schema.tables.sql b/sql/schema.tables.sql
index 3df03ed..e731dca 100644
--- a/sql/schema.tables.sql
+++ b/sql/schema.tables.sql
@@ -122,6 +122,7 @@ CREATE TABLE IF NOT EXISTS cellpra (
     CONSTRAINT "FK_cellpra_cell" FOREIGN KEY (cell) REFERENCES cell (id),
     CONSTRAINT "FK_cellpra_pra" FOREIGN KEY (pra) REFERENCES pra (id)
 );
+CREATE INDEX IF NOT EXISTS "IX_cellpra" ON cellpra (cell,pra);
 COMMENT ON TABLE cellpra IS 'Proportion of one cell in a PRA.';
 COMMENT ON COLUMN cellpra.cell IS 'Cell in a PRA.';
 COMMENT ON COLUMN cellpra.pra IS 'PRA containing at least a part of the cell.';
diff --git a/sql/translations.csv b/sql/translations.csv
index df51c15..0181ecf 100644
--- a/sql/translations.csv
+++ b/sql/translations.csv
@@ -5,12 +5,12 @@ frostdaystmin-description,en,Number of frost days (Tmin < 0 °C)
 frostdaystmin-description,fr,Nombre de jours de gel (Tmin < 0 °C)
 hdaystmax1,en,Hot days
 hdaystmax1,fr,Jours chauds
-hdaystmax1-description,en,Number of hot days (tmax > 25 °C)
-hdaystmax1-description,fr,Nombre de jours chauds (tmax > 25 °C)
+hdaystmax1-description,en,Number of hot days (Tmax > 25 °C)
+hdaystmax1-description,fr,Nombre de jours chauds (Tmax > 25 °C)
 hdaystmax,en,Hot days
 hdaystmax,fr,Jours chauds
-hdaystmax-description,en,Number of hot days (tmax > 35 °C)
-hdaystmax-description,fr,Nombre de jours chauds (tmax > 35 °C)
+hdaystmax-description,en,Number of hot days (Tmax > 35 °C)
+hdaystmax-description,fr,Nombre de jours chauds (Tmax > 35 °C)
 maxt,en,Average of maximal temperatures
 maxt,fr,Moyenne des températures maximales
 maxt-description,en,Average of maximal temperatures
-- 
GitLab


From d50af8c4611516744f4266affe423bd659904d46 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Tue, 30 Apr 2024 13:06:25 +0200
Subject: [PATCH 05/22] =?UTF-8?q?z-index=20de=20la=20modale=20de=20chargem?=
 =?UTF-8?q?ent=20des=20donn=C3=A9es?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../main/resources/fr/agrometinfo/www/client/public/style.css   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
index 5053a42..eb97c2c 100644
--- a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
+++ b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
@@ -223,7 +223,7 @@ div.list-group .d-list-item:hover {
     height: var(--logo-height);
 }
 body > .modal-backdrop {
-    z-index: 5;
+    z-index: 10;
 }
 .navbar-brand > .version {
     font-size: 0.5em;
-- 
GitLab


From c8b9c0c52b412d9fe4928307715905198a3b2646 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Tue, 30 Apr 2024 13:44:04 +0200
Subject: [PATCH 06/22] =?UTF-8?q?Version=202.0.0=20=CE=B13?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml            | 2 +-
 www-client/pom.xml | 2 +-
 www-server/pom.xml | 2 +-
 www-shared/pom.xml | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 838689e..370fda9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>fr.agrometinfo</groupId>
   <artifactId>www</artifactId>
-  <version>2.0.0-SNAPSHOT</version>
+  <version>2.0.0-alpha-3</version>
   <packaging>pom</packaging>
   <name>AgroMetInfo web app</name>
   <description>Website for AgroMetInfo in Jakarta EE 10 and GWT.</description>
diff --git a/www-client/pom.xml b/www-client/pom.xml
index f937fee..443e85f 100644
--- a/www-client/pom.xml
+++ b/www-client/pom.xml
@@ -7,7 +7,7 @@
     <parent>
         <groupId>fr.agrometinfo</groupId>
         <artifactId>www</artifactId>
-        <version>2.0.0-SNAPSHOT</version>
+        <version>2.0.0-alpha-3</version>
     </parent>
 
     <artifactId>www-client</artifactId>
diff --git a/www-server/pom.xml b/www-server/pom.xml
index 37ecee7..ad59801 100644
--- a/www-server/pom.xml
+++ b/www-server/pom.xml
@@ -7,7 +7,7 @@
   <parent>
     <groupId>fr.agrometinfo</groupId>
     <artifactId>www</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.0-alpha-3</version>
   </parent>
 
   <artifactId>www-server</artifactId>
diff --git a/www-shared/pom.xml b/www-shared/pom.xml
index 205c0f1..02fcd59 100644
--- a/www-shared/pom.xml
+++ b/www-shared/pom.xml
@@ -7,7 +7,7 @@
   <parent>
     <groupId>fr.agrometinfo</groupId>
     <artifactId>www</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.0-alpha-3</version>
   </parent>
 
   <artifactId>www-shared</artifactId>
-- 
GitLab


From 6052b444fdbd707fd03fca5bd0608c8596bad958 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Thu, 25 Apr 2024 18:01:34 +0200
Subject: [PATCH 07/22] Utiliser une liste pour choisir les indicateurs. fixes
 #55

---
 .../www/client/ui/DominoListBuilder.java      | 106 ++++++++++++++++++
 .../www/client/view/LayoutView.java           |  22 +++-
 .../agrometinfo/www/client/public/style.css   |  15 +++
 .../fr/agrometinfo/www/shared/dto/HasId.java  |  18 ---
 .../agrometinfo/www/shared/dto/HasName.java   |  18 ---
 5 files changed, 138 insertions(+), 41 deletions(-)
 create mode 100644 www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
 delete mode 100644 www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasId.java
 delete mode 100644 www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasName.java

diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java b/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
new file mode 100644
index 0000000..85bcc39
--- /dev/null
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
@@ -0,0 +1,106 @@
+package fr.agrometinfo.www.client.ui;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.function.Consumer;
+
+import org.dominokit.domino.ui.grid.flex.FlexItem;
+import org.dominokit.domino.ui.grid.flex.FlexLayout;
+import org.dominokit.domino.ui.lists.ListGroup;
+import org.dominokit.domino.ui.utils.TextNode;
+
+/**
+ * Builder for a Domino {@link ListGroup}, a component that allow selecting a
+ * single option from a panel.
+ *
+ * @author Olivier Maury
+ *
+ * @param <T> The type of a single option value
+ */
+public final class DominoListBuilder<T> extends SelectBuilder<T, ListGroup<T>> {
+    /**
+     * The component.
+     */
+    private ListGroup<T> select;
+
+    @Override
+    public DominoListBuilder<T> addOption(final T option) {
+        return addOptions(Arrays.asList(option));
+    }
+
+    @Override
+    public DominoListBuilder<T> addOptions(final Collection<T> list) {
+        getSelect().addItems(new ArrayList<>(list));
+        return this;
+    }
+
+    @Override
+    public DominoListBuilder<T> addValueChangeHandler(final Consumer<String> handler) {
+        getSelect().addSelectionListener(selectedItems -> {
+            if (selectedItems == null || selectedItems.isEmpty()) {
+                return;
+            }
+            final T item = selectedItems.get(0).getValue();
+            handler.accept(getValueFunction().apply(item));
+        });
+        return this;
+    }
+
+    @Override
+    public ListGroup<T> build() {
+        Objects.requireNonNull(getValueFunction(), "setValueFunction() must be called before!");
+        Objects.requireNonNull(getTextFunction(), "setTextFunction() must be called before!");
+        return getSelect().setItemRenderer(
+                (listGroup, item) ->
+                item.setSelectable(true)
+                .appendChild(
+                        FlexLayout.create() //
+                        .appendChild(//
+                                FlexItem.create() //
+                                .setFlexGrow(1) //
+                                .appendChild(TextNode
+                                        .of(getTextFunction().apply(item.getValue())))))
+                );
+    }
+
+    private ListGroup<T> getSelect() {
+        if (select == null) {
+            select = ListGroup.<T>create();
+        }
+        return select;
+    }
+
+    @Override
+    public DominoListBuilder<T> removeOptions() {
+        getSelect().clearElement();
+        return this;
+    }
+
+    @Override
+    public DominoListBuilder<T> select(final T value) {
+        getSelect().getItems().stream() //
+        .filter(i -> Objects.equals(getValueFunction().apply(i.getValue()), getValueFunction().apply(value))) //
+        .findFirst() //
+        .ifPresent(toSelect -> select.select(Arrays.asList(toSelect)));
+        return this;
+    }
+
+    @Override
+    public DominoListBuilder<T> setPrompt(final String text) {
+        // no prompt for this component
+        return this;
+    }
+
+    /**
+     * Use an existing element.
+     *
+     * @param value existing ListGroup element
+     * @return same builder instance
+     */
+    public DominoListBuilder<T> setSelect(final ListGroup<T> value) {
+        select = value;
+        return this;
+    }
+}
diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
index bc76609..3d56e08 100644
--- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
@@ -18,6 +18,7 @@ import org.dominokit.domino.ui.grid.flex.FlexItem;
 import org.dominokit.domino.ui.icons.Icons;
 import org.dominokit.domino.ui.icons.MdiIcon;
 import org.dominokit.domino.ui.layout.Layout;
+import org.dominokit.domino.ui.lists.ListGroup;
 import org.dominokit.domino.ui.loaders.Loader;
 import org.dominokit.domino.ui.loaders.LoaderEffect;
 import org.dominokit.domino.ui.menu.Menu;
@@ -50,6 +51,7 @@ import fr.agrometinfo.www.client.presenter.LayoutPresenter;
 import fr.agrometinfo.www.client.presenter.MapPresenter;
 import fr.agrometinfo.www.client.presenter.RightPanelPresenter;
 import fr.agrometinfo.www.client.ui.AgroclimAppsMenu;
+import fr.agrometinfo.www.client.ui.DominoListBuilder;
 import fr.agrometinfo.www.client.ui.DominoSelectBuilder;
 import fr.agrometinfo.www.client.util.ApplicationUtils;
 import fr.agrometinfo.www.shared.dto.ChoiceDTO;
@@ -150,7 +152,7 @@ implements LayoutPresenter.View, LoadingHandler {
     /**
      * Selector for indicators.
      */
-    private final Select<IndicatorDTO> indicatorSelect = Select.create(CSTS.chooseIndicator());
+    private final ListGroup<IndicatorDTO> indicatorSelect = ListGroup.create();
 
     /**
      * Application layout.
@@ -342,9 +344,19 @@ implements LayoutPresenter.View, LoadingHandler {
 
         //
         GWT.log("LayoutView.initLeftPanel() indicators");
-        panel.appendChild(indicatorSelect);
-        new DominoSelectBuilder<IndicatorDTO>() //
+        panel.appendChild(//
+                Elements.div() //
+                .css("field-group lined list-group") //
+                .add(//
+                        Elements.label() //
+                        .css("field-label") //
+                        .add(Elements.span().textContent(CSTS.chooseIndicator()))) //
+                .add(indicatorSelect) //
+                );
+        new DominoListBuilder<IndicatorDTO>() //
         .setSelect(indicatorSelect) //
+        .setTextFunction(IndicatorDTO::getDescription) //
+        .setValueFunction(IndicatorDTO::getCode) //
         .addValueChangeHandler(this::onIndicatorChange) //
         .build();
 
@@ -546,7 +558,7 @@ implements LayoutPresenter.View, LoadingHandler {
             }
         }
         if (list == null || list.isEmpty()) {
-            indicatorSelect.removeAllOptions();
+            indicatorSelect.clearElement();
             return;
         }
         GWT.log("LayoutView.onPeriodChange() Indicators : " + list);
@@ -554,7 +566,7 @@ implements LayoutPresenter.View, LoadingHandler {
         final IndicatorDTO defaultIndicator = list.stream() //
                 .filter(i -> DEFAULT_INDICATOR.equals(i.getCode())) //
                 .findFirst().orElse(firstIndicator);
-        new DominoSelectBuilder<IndicatorDTO>() //
+        new DominoListBuilder<IndicatorDTO>() //
         .setSelect(indicatorSelect) //
         .setTextFunction(IndicatorDTO::getDescription) //
         .setValueFunction(IndicatorDTO::getCode) //
diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
index cada1db..628ac72 100644
--- a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
+++ b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
@@ -180,6 +180,21 @@ details.card-details[open] > summary i {
     transform: rotate(180deg);
 }
 
+div.list-group > label.field-label {
+    position: relative;
+}
+div.list-group .flex-item {
+    line-height: 2em;
+    transition: all .5s;
+    user-select: none;
+}
+div.list-group .d-list-item.selected {
+    background-color: #ededed;
+    color: #414141;
+}
+div.list-group .d-list-item:hover {
+    background-color: #f5f5f5;
+}
 
 .float-right {
     float: right;
diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasId.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasId.java
deleted file mode 100644
index f889b40..0000000
--- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasId.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package fr.agrometinfo.www.shared.dto;
-
-/**
- * The object has an identifier.
- *
- * @author Olivier Maury
- */
-public interface HasId {
-    /**
-     * @return identifier
-     */
-    Integer getId();
-
-    /**
-     * @param id identifier
-     */
-    void setId(Integer id);
-}
diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasName.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasName.java
deleted file mode 100644
index 75c0d07..0000000
--- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasName.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package fr.agrometinfo.www.shared.dto;
-
-/**
- * The object as name.
- *
- * @author Olivier Maury
- */
-public interface HasName {
-    /**
-     * @return name
-     */
-    String getName();
-
-    /**
-     * @param name name
-     */
-    void setName(String name);
-}
-- 
GitLab


From 8ff6a748dbbd62b7325fe72e0d31f524dcc772a6 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Thu, 25 Apr 2024 18:02:54 +0200
Subject: [PATCH 08/22] PMD

---
 .../main/java/fr/agrometinfo/www/client/view/LayoutView.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
index 3d56e08..66a064c 100644
--- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
@@ -345,7 +345,7 @@ implements LayoutPresenter.View, LoadingHandler {
         //
         GWT.log("LayoutView.initLeftPanel() indicators");
         panel.appendChild(//
-                Elements.div() //
+                div() //
                 .css("field-group lined list-group") //
                 .add(//
                         Elements.label() //
-- 
GitLab


From eeee89bbcc0af881a2a5c1098e04a22726c832e4 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Thu, 25 Apr 2024 18:46:19 +0200
Subject: [PATCH 09/22] Padding

---
 .../main/resources/fr/agrometinfo/www/client/public/style.css | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
index 628ac72..eb97c2c 100644
--- a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
+++ b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
@@ -181,10 +181,14 @@ details.card-details[open] > summary i {
 }
 
 div.list-group > label.field-label {
+    padding-left: 6px;
+    padding-right: 6px;
     position: relative;
 }
 div.list-group .flex-item {
     line-height: 2em;
+    padding-left: 6px;
+    padding-right: 6px;
     transition: all .5s;
     user-select: none;
 }
-- 
GitLab


From 6ac6e9f87b68c6e1579bd1082186dccb9bc0ab1d Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Fri, 26 Apr 2024 11:15:45 +0200
Subject: [PATCH 10/22] =?UTF-8?q?Homog=C3=A9n=C3=A9iser=20les=20noms=20des?=
 =?UTF-8?q?=20variables?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 sql/migration.sql     | 9 +++++++++
 sql/schema.tables.sql | 1 +
 sql/translations.csv  | 8 ++++----
 3 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/sql/migration.sql b/sql/migration.sql
index 42dc9de..f06cc7c 100644
--- a/sql/migration.sql
+++ b/sql/migration.sql
@@ -213,6 +213,15 @@ END
 $BODY$
 language plpgsql;
 
+CREATE OR REPLACE FUNCTION upgrade20240426() RETURNS boolean AS $BODY$
+BEGIN
+    CREATE INDEX IF NOT EXISTS "IX_cellpra" ON cellpra (cell,pra);
+    UPDATE i18n SET translation=REPLACE(translation, 'tmax', 'Tmax');
+    RETURN true;
+END
+$BODY$
+language plpgsql;
+
 ---
 --
 -- Keep this call at the end to apply migration functions.
diff --git a/sql/schema.tables.sql b/sql/schema.tables.sql
index 3df03ed..e731dca 100644
--- a/sql/schema.tables.sql
+++ b/sql/schema.tables.sql
@@ -122,6 +122,7 @@ CREATE TABLE IF NOT EXISTS cellpra (
     CONSTRAINT "FK_cellpra_cell" FOREIGN KEY (cell) REFERENCES cell (id),
     CONSTRAINT "FK_cellpra_pra" FOREIGN KEY (pra) REFERENCES pra (id)
 );
+CREATE INDEX IF NOT EXISTS "IX_cellpra" ON cellpra (cell,pra);
 COMMENT ON TABLE cellpra IS 'Proportion of one cell in a PRA.';
 COMMENT ON COLUMN cellpra.cell IS 'Cell in a PRA.';
 COMMENT ON COLUMN cellpra.pra IS 'PRA containing at least a part of the cell.';
diff --git a/sql/translations.csv b/sql/translations.csv
index df51c15..0181ecf 100644
--- a/sql/translations.csv
+++ b/sql/translations.csv
@@ -5,12 +5,12 @@ frostdaystmin-description,en,Number of frost days (Tmin < 0 °C)
 frostdaystmin-description,fr,Nombre de jours de gel (Tmin < 0 °C)
 hdaystmax1,en,Hot days
 hdaystmax1,fr,Jours chauds
-hdaystmax1-description,en,Number of hot days (tmax > 25 °C)
-hdaystmax1-description,fr,Nombre de jours chauds (tmax > 25 °C)
+hdaystmax1-description,en,Number of hot days (Tmax > 25 °C)
+hdaystmax1-description,fr,Nombre de jours chauds (Tmax > 25 °C)
 hdaystmax,en,Hot days
 hdaystmax,fr,Jours chauds
-hdaystmax-description,en,Number of hot days (tmax > 35 °C)
-hdaystmax-description,fr,Nombre de jours chauds (tmax > 35 °C)
+hdaystmax-description,en,Number of hot days (Tmax > 35 °C)
+hdaystmax-description,fr,Nombre de jours chauds (Tmax > 35 °C)
 maxt,en,Average of maximal temperatures
 maxt,fr,Moyenne des températures maximales
 maxt-description,en,Average of maximal temperatures
-- 
GitLab


From 28f0fcd01342f2f5b0c3fd5f5cbd5f4114e379b7 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Fri, 3 May 2024 07:58:21 +0200
Subject: [PATCH 11/22] Supprimer la zone de recherche de Select

---
 .../main/java/fr/agrometinfo/www/client/view/LayoutView.java   | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
index 66a064c..6c1c89c 100644
--- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
@@ -341,6 +341,7 @@ implements LayoutPresenter.View, LoadingHandler {
         .setSelect(periodSelect) //
         .addValueChangeHandler(this::onPeriodChange) //
         .build();
+        periodSelect.setSearchable(false);
 
         //
         GWT.log("LayoutView.initLeftPanel() indicators");
@@ -359,6 +360,7 @@ implements LayoutPresenter.View, LoadingHandler {
         .setValueFunction(IndicatorDTO::getCode) //
         .addValueChangeHandler(this::onIndicatorChange) //
         .build();
+        indicatorSelect.setSearchable(false);
 
         //
         GWT.log("LayoutView.initLeftPanel() regions");
@@ -367,6 +369,7 @@ implements LayoutPresenter.View, LoadingHandler {
         .setSelect(regionSelect) //
         .addValueChangeHandler(this::onRegionChange) //
         .build();
+        regionSelect.setSearchable(false);
 
         //
         GWT.log("LayoutView.initLeftPanel() year");
-- 
GitLab


From ae026344bd6f48313d1ce15d264330105e1b4c69 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Fri, 3 May 2024 07:59:10 +0200
Subject: [PATCH 12/22] =?UTF-8?q?Homog=C3=A9n=C3=A9iser=20les=20noms=20des?=
 =?UTF-8?q?=20variables?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 sql/migration.sql | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sql/migration.sql b/sql/migration.sql
index f06cc7c..6dc1f88 100644
--- a/sql/migration.sql
+++ b/sql/migration.sql
@@ -208,6 +208,7 @@ BEGIN
     ALTER TABLE indicator DROP CONSTRAINT "FK_indicator_i18n_description";
     ALTER TABLE indicator ADD CONSTRAINT "FK_indicator_i18n_description" FOREIGN KEY (description) REFERENCES i18nkey (id);
     CREATE INDEX "IX_dailyvalue_doy" ON dailyvalue (EXTRACT(DOY FROM date), indicator);
+    UPDATE i18n SET translation=REPLACE(translation, ' (tmax', ' (Tmax')
     RETURN true;
 END
 $BODY$
-- 
GitLab


From 1b11eafcbbfe4ead5f6145094305853cbb35b1ac Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Fri, 3 May 2024 13:39:59 +0200
Subject: [PATCH 13/22] =?UTF-8?q?R=C3=A9duire=20la=20liste=20des=20indicat?=
 =?UTF-8?q?eurs?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../www/client/ui/CollapsedSelect.java        | 100 ++++++++++++++++++
 .../www/client/ui/DominoListBuilder.java      |  41 +++++--
 .../www/client/view/LayoutView.java           |  33 ++++--
 .../agrometinfo/www/client/public/style.css   |  16 ++-
 4 files changed, 170 insertions(+), 20 deletions(-)
 create mode 100644 www-client/src/main/java/fr/agrometinfo/www/client/ui/CollapsedSelect.java

diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/ui/CollapsedSelect.java b/www-client/src/main/java/fr/agrometinfo/www/client/ui/CollapsedSelect.java
new file mode 100644
index 0000000..e0c1396
--- /dev/null
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/ui/CollapsedSelect.java
@@ -0,0 +1,100 @@
+package fr.agrometinfo.www.client.ui;
+
+import org.jboss.elemento.Elements;
+import org.jboss.elemento.EventCallbackFn;
+import org.jboss.elemento.EventType;
+import org.jboss.elemento.HtmlContentBuilder;
+
+import elemental2.dom.HTMLDivElement;
+import elemental2.dom.HTMLElement;
+import elemental2.dom.MouseEvent;
+
+/**
+ * A component which mimics the Select component when the drop down list is
+ * closed.
+ *
+ * @author Olivier Maury
+ */
+public final class CollapsedSelect {
+    /**
+     * The root element.
+     */
+    private final HtmlContentBuilder<HTMLDivElement> root;
+    /**
+     * Span displaying the prompt.
+     */
+    private final HtmlContentBuilder<HTMLElement> promptSpan = Elements.span();
+    /**
+     * Span displaying the displayed text of the selected item.
+     */
+    private final HtmlContentBuilder<HTMLElement> selectionSpan = Elements.span();
+
+    /**
+     * Constructor.
+     *
+     * @param promptText    prompt text in the field label
+     * @param selectionText displayed text of the selected item
+     */
+    public CollapsedSelect(final String promptText, final String selectionText) {
+        this.root = Elements.div().css("field-group lined d-select floating")//
+                .add(Elements.div().css("field-cntr") //
+                        .add(Elements.div().css("flex-layout") //
+                                .add(Elements.div().css("flex-item field-input-cntr") //
+                                        .add(Elements.label().css("field-label") //
+                                                .add(promptSpan))
+                                        .add(Elements.button().css("select-button")
+                                                .add(Elements.span().css("select-value ellipsis-text") //
+                                                        .add(selectionSpan)))) //
+                                .add(Elements.div().css("field-mandatory-addon") //
+                                        .add(Elements.i() //
+                                                .css("mdi mdi-menu-down mdi-24px clickable-icon waves-effect")))))
+                .hidden(false);
+        setPromptText(promptText);
+        setSelectionText(selectionText);
+    }
+
+    /**
+     * @return root element
+     */
+    public HtmlContentBuilder<HTMLDivElement> getRoot() {
+        return root;
+    }
+
+    /**
+     * Hide the widget.
+     */
+    public void hide() {
+        root.hidden(true);
+    }
+
+    /**
+     * Add the given callback to the root element.
+     *
+     * @param callback
+     */
+    public void onClick(final EventCallbackFn<MouseEvent> callback) {
+        root.on(EventType.click, callback);
+    }
+
+    /**
+     * @param promptText prompt text in the field label
+     */
+    public void setPromptText(final String promptText) {
+        promptSpan.textContent(promptText);
+    }
+
+    /**
+     * @param selectionText displayed text of the selected item
+     */
+    public void setSelectionText(final String selectionText) {
+        selectionSpan.textContent(selectionText);
+    }
+
+    /**
+     * Show the widget.
+     */
+    public void show() {
+        root.hidden(false);
+    }
+
+}
diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java b/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
index 85bcc39..93e6a90 100644
--- a/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
@@ -9,7 +9,9 @@ import java.util.function.Consumer;
 import org.dominokit.domino.ui.grid.flex.FlexItem;
 import org.dominokit.domino.ui.grid.flex.FlexLayout;
 import org.dominokit.domino.ui.lists.ListGroup;
-import org.dominokit.domino.ui.utils.TextNode;
+import org.jboss.elemento.Elements;
+
+import elemental2.dom.HTMLDivElement;
 
 /**
  * Builder for a Domino {@link ListGroup}, a component that allow selecting a
@@ -36,6 +38,23 @@ public final class DominoListBuilder<T> extends SelectBuilder<T, ListGroup<T>> {
         return this;
     }
 
+    /**
+     * Add handler on the displayed text when value change.
+     *
+     * @param handler the handler receives the displayed text of selected option
+     * @return same builder instance
+     */
+    public DominoListBuilder<T> addTextChangeHandler(final Consumer<String> handler) {
+        getSelect().addSelectionListener(selectedItems -> {
+            if (selectedItems == null || selectedItems.isEmpty()) {
+                return;
+            }
+            final T item = selectedItems.get(0).getValue();
+            handler.accept(getTextFunction().apply(item));
+        });
+        return this;
+    }
+
     @Override
     public DominoListBuilder<T> addValueChangeHandler(final Consumer<String> handler) {
         getSelect().addSelectionListener(selectedItems -> {
@@ -53,16 +72,16 @@ public final class DominoListBuilder<T> extends SelectBuilder<T, ListGroup<T>> {
         Objects.requireNonNull(getValueFunction(), "setValueFunction() must be called before!");
         Objects.requireNonNull(getTextFunction(), "setTextFunction() must be called before!");
         return getSelect().setItemRenderer(
-                (listGroup, item) ->
-                item.setSelectable(true)
-                .appendChild(
-                        FlexLayout.create() //
-                        .appendChild(//
-                                FlexItem.create() //
-                                .setFlexGrow(1) //
-                                .appendChild(TextNode
-                                        .of(getTextFunction().apply(item.getValue())))))
-                );
+                (listGroup, item) -> {
+                    final FlexItem<HTMLDivElement> flexItem = FlexItem.create() //
+                            .setFlexGrow(1) //
+                            .appendChild(//
+                                    Elements.span().textContent(getTextFunction().apply(item.getValue())));
+                    item.setSelectable(true)
+                    .appendChild(
+                            FlexLayout.create() //
+                            .appendChild(flexItem));
+                });
     }
 
     private ListGroup<T> getSelect() {
diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
index 6c1c89c..c733bdc 100644
--- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
@@ -41,6 +41,7 @@ import elemental2.dom.DomGlobal;
 import elemental2.dom.HTMLAnchorElement;
 import elemental2.dom.HTMLDivElement;
 import elemental2.dom.HTMLElement;
+import elemental2.dom.HTMLLabelElement;
 import elemental2.dom.MouseEvent;
 import fr.agrometinfo.www.client.App;
 import fr.agrometinfo.www.client.event.LoadingEvent;
@@ -51,6 +52,7 @@ import fr.agrometinfo.www.client.presenter.LayoutPresenter;
 import fr.agrometinfo.www.client.presenter.MapPresenter;
 import fr.agrometinfo.www.client.presenter.RightPanelPresenter;
 import fr.agrometinfo.www.client.ui.AgroclimAppsMenu;
+import fr.agrometinfo.www.client.ui.CollapsedSelect;
 import fr.agrometinfo.www.client.ui.DominoListBuilder;
 import fr.agrometinfo.www.client.ui.DominoSelectBuilder;
 import fr.agrometinfo.www.client.util.ApplicationUtils;
@@ -220,6 +222,11 @@ implements LayoutPresenter.View, LoadingHandler {
      */
     private final HtmlContentBuilder<HTMLDivElement> links = div().css("links");
 
+    /**
+     * The replacement of indicatorSelect when it is hidden.
+     */
+    private final CollapsedSelect collapsedIndicatorSelect = new CollapsedSelect(CSTS.chooseIndicator(), "");
+
     /**
      * @param text     link text
      * @param callback {@link EventCallbackFn<MouseEvent>} to be added to the click
@@ -345,22 +352,32 @@ implements LayoutPresenter.View, LoadingHandler {
 
         //
         GWT.log("LayoutView.initLeftPanel() indicators");
-        panel.appendChild(//
-                div() //
-                .css("field-group lined list-group") //
-                .add(//
-                        Elements.label() //
-                        .css("field-label") //
-                        .add(Elements.span().textContent(CSTS.chooseIndicator()))) //
+        collapsedIndicatorSelect.hide();
+        panel.appendChild(collapsedIndicatorSelect.getRoot());
+        final HtmlContentBuilder<HTMLDivElement> indicatorPanel = div().css("field-group lined list-group");
+        final HtmlContentBuilder<HTMLLabelElement> indicatorLabel = Elements.label() //
+                .css("field-label") //
+                .add(Elements.span().textContent(CSTS.chooseIndicator()));
+        panel.appendChild(indicatorPanel//
+                .add(indicatorLabel) //
                 .add(indicatorSelect) //
                 );
         new DominoListBuilder<IndicatorDTO>() //
         .setSelect(indicatorSelect) //
+        .addTextChangeHandler(collapsedIndicatorSelect::setSelectionText) //
         .setTextFunction(IndicatorDTO::getDescription) //
         .setValueFunction(IndicatorDTO::getCode) //
         .addValueChangeHandler(this::onIndicatorChange) //
         .build();
-        indicatorSelect.setSearchable(false);
+
+        indicatorLabel.on(EventType.click, e -> {
+            indicatorPanel.hidden(true);
+            collapsedIndicatorSelect.show();
+        });
+        collapsedIndicatorSelect.onClick(e -> {
+            indicatorPanel.hidden(false);
+            collapsedIndicatorSelect.hide();
+        });
 
         //
         GWT.log("LayoutView.initLeftPanel() regions");
diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
index eb97c2c..bdbff67 100644
--- a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
+++ b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
@@ -181,9 +181,18 @@ details.card-details[open] > summary i {
 }
 
 div.list-group > label.field-label {
+    margin-bottom: 0;
     padding-left: 6px;
     padding-right: 6px;
     position: relative;
+    top: 0px;
+    width: 100%;
+}
+div.list-group > label.field-label:after {
+    content: "\F360";
+    text-align: right;
+    float: right;
+    font: normal normal normal 24px/1 "Material Design Icons";
 }
 div.list-group .flex-item {
     line-height: 2em;
@@ -194,7 +203,12 @@ div.list-group .flex-item {
 }
 div.list-group .d-list-item.selected {
     background-color: #ededed;
-    color: #414141;
+    color: #2a2a2a;
+}
+div.list-group .d-list-item.selected span:after {
+    content: "✓";
+    text-align: right;
+    float:right;
 }
 div.list-group .d-list-item:hover {
     background-color: #f5f5f5;
-- 
GitLab


From 40b2dfa548d8313f10635290dded99183662bf33 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Thu, 25 Apr 2024 18:01:34 +0200
Subject: [PATCH 14/22] Utiliser une liste pour choisir les indicateurs. fixes
 #55

---
 .../www/client/ui/DominoListBuilder.java      | 106 ++++++++++++++++++
 .../www/client/view/LayoutView.java           |  22 +++-
 .../agrometinfo/www/client/public/style.css   |  15 +++
 .../fr/agrometinfo/www/shared/dto/HasId.java  |  18 ---
 .../agrometinfo/www/shared/dto/HasName.java   |  18 ---
 5 files changed, 138 insertions(+), 41 deletions(-)
 create mode 100644 www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
 delete mode 100644 www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasId.java
 delete mode 100644 www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasName.java

diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java b/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
new file mode 100644
index 0000000..85bcc39
--- /dev/null
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
@@ -0,0 +1,106 @@
+package fr.agrometinfo.www.client.ui;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.function.Consumer;
+
+import org.dominokit.domino.ui.grid.flex.FlexItem;
+import org.dominokit.domino.ui.grid.flex.FlexLayout;
+import org.dominokit.domino.ui.lists.ListGroup;
+import org.dominokit.domino.ui.utils.TextNode;
+
+/**
+ * Builder for a Domino {@link ListGroup}, a component that allow selecting a
+ * single option from a panel.
+ *
+ * @author Olivier Maury
+ *
+ * @param <T> The type of a single option value
+ */
+public final class DominoListBuilder<T> extends SelectBuilder<T, ListGroup<T>> {
+    /**
+     * The component.
+     */
+    private ListGroup<T> select;
+
+    @Override
+    public DominoListBuilder<T> addOption(final T option) {
+        return addOptions(Arrays.asList(option));
+    }
+
+    @Override
+    public DominoListBuilder<T> addOptions(final Collection<T> list) {
+        getSelect().addItems(new ArrayList<>(list));
+        return this;
+    }
+
+    @Override
+    public DominoListBuilder<T> addValueChangeHandler(final Consumer<String> handler) {
+        getSelect().addSelectionListener(selectedItems -> {
+            if (selectedItems == null || selectedItems.isEmpty()) {
+                return;
+            }
+            final T item = selectedItems.get(0).getValue();
+            handler.accept(getValueFunction().apply(item));
+        });
+        return this;
+    }
+
+    @Override
+    public ListGroup<T> build() {
+        Objects.requireNonNull(getValueFunction(), "setValueFunction() must be called before!");
+        Objects.requireNonNull(getTextFunction(), "setTextFunction() must be called before!");
+        return getSelect().setItemRenderer(
+                (listGroup, item) ->
+                item.setSelectable(true)
+                .appendChild(
+                        FlexLayout.create() //
+                        .appendChild(//
+                                FlexItem.create() //
+                                .setFlexGrow(1) //
+                                .appendChild(TextNode
+                                        .of(getTextFunction().apply(item.getValue())))))
+                );
+    }
+
+    private ListGroup<T> getSelect() {
+        if (select == null) {
+            select = ListGroup.<T>create();
+        }
+        return select;
+    }
+
+    @Override
+    public DominoListBuilder<T> removeOptions() {
+        getSelect().clearElement();
+        return this;
+    }
+
+    @Override
+    public DominoListBuilder<T> select(final T value) {
+        getSelect().getItems().stream() //
+        .filter(i -> Objects.equals(getValueFunction().apply(i.getValue()), getValueFunction().apply(value))) //
+        .findFirst() //
+        .ifPresent(toSelect -> select.select(Arrays.asList(toSelect)));
+        return this;
+    }
+
+    @Override
+    public DominoListBuilder<T> setPrompt(final String text) {
+        // no prompt for this component
+        return this;
+    }
+
+    /**
+     * Use an existing element.
+     *
+     * @param value existing ListGroup element
+     * @return same builder instance
+     */
+    public DominoListBuilder<T> setSelect(final ListGroup<T> value) {
+        select = value;
+        return this;
+    }
+}
diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
index bc76609..3d56e08 100644
--- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
@@ -18,6 +18,7 @@ import org.dominokit.domino.ui.grid.flex.FlexItem;
 import org.dominokit.domino.ui.icons.Icons;
 import org.dominokit.domino.ui.icons.MdiIcon;
 import org.dominokit.domino.ui.layout.Layout;
+import org.dominokit.domino.ui.lists.ListGroup;
 import org.dominokit.domino.ui.loaders.Loader;
 import org.dominokit.domino.ui.loaders.LoaderEffect;
 import org.dominokit.domino.ui.menu.Menu;
@@ -50,6 +51,7 @@ import fr.agrometinfo.www.client.presenter.LayoutPresenter;
 import fr.agrometinfo.www.client.presenter.MapPresenter;
 import fr.agrometinfo.www.client.presenter.RightPanelPresenter;
 import fr.agrometinfo.www.client.ui.AgroclimAppsMenu;
+import fr.agrometinfo.www.client.ui.DominoListBuilder;
 import fr.agrometinfo.www.client.ui.DominoSelectBuilder;
 import fr.agrometinfo.www.client.util.ApplicationUtils;
 import fr.agrometinfo.www.shared.dto.ChoiceDTO;
@@ -150,7 +152,7 @@ implements LayoutPresenter.View, LoadingHandler {
     /**
      * Selector for indicators.
      */
-    private final Select<IndicatorDTO> indicatorSelect = Select.create(CSTS.chooseIndicator());
+    private final ListGroup<IndicatorDTO> indicatorSelect = ListGroup.create();
 
     /**
      * Application layout.
@@ -342,9 +344,19 @@ implements LayoutPresenter.View, LoadingHandler {
 
         //
         GWT.log("LayoutView.initLeftPanel() indicators");
-        panel.appendChild(indicatorSelect);
-        new DominoSelectBuilder<IndicatorDTO>() //
+        panel.appendChild(//
+                Elements.div() //
+                .css("field-group lined list-group") //
+                .add(//
+                        Elements.label() //
+                        .css("field-label") //
+                        .add(Elements.span().textContent(CSTS.chooseIndicator()))) //
+                .add(indicatorSelect) //
+                );
+        new DominoListBuilder<IndicatorDTO>() //
         .setSelect(indicatorSelect) //
+        .setTextFunction(IndicatorDTO::getDescription) //
+        .setValueFunction(IndicatorDTO::getCode) //
         .addValueChangeHandler(this::onIndicatorChange) //
         .build();
 
@@ -546,7 +558,7 @@ implements LayoutPresenter.View, LoadingHandler {
             }
         }
         if (list == null || list.isEmpty()) {
-            indicatorSelect.removeAllOptions();
+            indicatorSelect.clearElement();
             return;
         }
         GWT.log("LayoutView.onPeriodChange() Indicators : " + list);
@@ -554,7 +566,7 @@ implements LayoutPresenter.View, LoadingHandler {
         final IndicatorDTO defaultIndicator = list.stream() //
                 .filter(i -> DEFAULT_INDICATOR.equals(i.getCode())) //
                 .findFirst().orElse(firstIndicator);
-        new DominoSelectBuilder<IndicatorDTO>() //
+        new DominoListBuilder<IndicatorDTO>() //
         .setSelect(indicatorSelect) //
         .setTextFunction(IndicatorDTO::getDescription) //
         .setValueFunction(IndicatorDTO::getCode) //
diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
index cada1db..628ac72 100644
--- a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
+++ b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
@@ -180,6 +180,21 @@ details.card-details[open] > summary i {
     transform: rotate(180deg);
 }
 
+div.list-group > label.field-label {
+    position: relative;
+}
+div.list-group .flex-item {
+    line-height: 2em;
+    transition: all .5s;
+    user-select: none;
+}
+div.list-group .d-list-item.selected {
+    background-color: #ededed;
+    color: #414141;
+}
+div.list-group .d-list-item:hover {
+    background-color: #f5f5f5;
+}
 
 .float-right {
     float: right;
diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasId.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasId.java
deleted file mode 100644
index f889b40..0000000
--- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasId.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package fr.agrometinfo.www.shared.dto;
-
-/**
- * The object has an identifier.
- *
- * @author Olivier Maury
- */
-public interface HasId {
-    /**
-     * @return identifier
-     */
-    Integer getId();
-
-    /**
-     * @param id identifier
-     */
-    void setId(Integer id);
-}
diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasName.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasName.java
deleted file mode 100644
index 75c0d07..0000000
--- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/HasName.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package fr.agrometinfo.www.shared.dto;
-
-/**
- * The object as name.
- *
- * @author Olivier Maury
- */
-public interface HasName {
-    /**
-     * @return name
-     */
-    String getName();
-
-    /**
-     * @param name name
-     */
-    void setName(String name);
-}
-- 
GitLab


From 807fec7a17978ebb662d27250337c482275b1276 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Thu, 25 Apr 2024 18:02:54 +0200
Subject: [PATCH 15/22] PMD

---
 .../main/java/fr/agrometinfo/www/client/view/LayoutView.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
index 3d56e08..66a064c 100644
--- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
@@ -345,7 +345,7 @@ implements LayoutPresenter.View, LoadingHandler {
         //
         GWT.log("LayoutView.initLeftPanel() indicators");
         panel.appendChild(//
-                Elements.div() //
+                div() //
                 .css("field-group lined list-group") //
                 .add(//
                         Elements.label() //
-- 
GitLab


From 73403ad17a55252425163fc35577c4cde7f225d1 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Thu, 25 Apr 2024 18:46:19 +0200
Subject: [PATCH 16/22] Padding

---
 .../main/resources/fr/agrometinfo/www/client/public/style.css | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
index 628ac72..eb97c2c 100644
--- a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
+++ b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
@@ -181,10 +181,14 @@ details.card-details[open] > summary i {
 }
 
 div.list-group > label.field-label {
+    padding-left: 6px;
+    padding-right: 6px;
     position: relative;
 }
 div.list-group .flex-item {
     line-height: 2em;
+    padding-left: 6px;
+    padding-right: 6px;
     transition: all .5s;
     user-select: none;
 }
-- 
GitLab


From 9b3c7d2cc4a1469da72fb0ae234da227de8097ba Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Fri, 26 Apr 2024 11:15:45 +0200
Subject: [PATCH 17/22] =?UTF-8?q?Homog=C3=A9n=C3=A9iser=20les=20noms=20des?=
 =?UTF-8?q?=20variables?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 sql/migration.sql     | 9 +++++++++
 sql/schema.tables.sql | 1 +
 sql/translations.csv  | 8 ++++----
 3 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/sql/migration.sql b/sql/migration.sql
index 42dc9de..f06cc7c 100644
--- a/sql/migration.sql
+++ b/sql/migration.sql
@@ -213,6 +213,15 @@ END
 $BODY$
 language plpgsql;
 
+CREATE OR REPLACE FUNCTION upgrade20240426() RETURNS boolean AS $BODY$
+BEGIN
+    CREATE INDEX IF NOT EXISTS "IX_cellpra" ON cellpra (cell,pra);
+    UPDATE i18n SET translation=REPLACE(translation, 'tmax', 'Tmax');
+    RETURN true;
+END
+$BODY$
+language plpgsql;
+
 ---
 --
 -- Keep this call at the end to apply migration functions.
diff --git a/sql/schema.tables.sql b/sql/schema.tables.sql
index 85a7f2d..03ddaca 100644
--- a/sql/schema.tables.sql
+++ b/sql/schema.tables.sql
@@ -122,6 +122,7 @@ CREATE TABLE IF NOT EXISTS cellpra (
     CONSTRAINT "FK_cellpra_cell" FOREIGN KEY (cell) REFERENCES cell (id),
     CONSTRAINT "FK_cellpra_pra" FOREIGN KEY (pra) REFERENCES pra (id)
 );
+CREATE INDEX IF NOT EXISTS "IX_cellpra" ON cellpra (cell,pra);
 COMMENT ON TABLE cellpra IS 'Proportion of one cell in a PRA.';
 COMMENT ON COLUMN cellpra.cell IS 'Cell in a PRA.';
 COMMENT ON COLUMN cellpra.pra IS 'PRA containing at least a part of the cell.';
diff --git a/sql/translations.csv b/sql/translations.csv
index df51c15..0181ecf 100644
--- a/sql/translations.csv
+++ b/sql/translations.csv
@@ -5,12 +5,12 @@ frostdaystmin-description,en,Number of frost days (Tmin < 0 °C)
 frostdaystmin-description,fr,Nombre de jours de gel (Tmin < 0 °C)
 hdaystmax1,en,Hot days
 hdaystmax1,fr,Jours chauds
-hdaystmax1-description,en,Number of hot days (tmax > 25 °C)
-hdaystmax1-description,fr,Nombre de jours chauds (tmax > 25 °C)
+hdaystmax1-description,en,Number of hot days (Tmax > 25 °C)
+hdaystmax1-description,fr,Nombre de jours chauds (Tmax > 25 °C)
 hdaystmax,en,Hot days
 hdaystmax,fr,Jours chauds
-hdaystmax-description,en,Number of hot days (tmax > 35 °C)
-hdaystmax-description,fr,Nombre de jours chauds (tmax > 35 °C)
+hdaystmax-description,en,Number of hot days (Tmax > 35 °C)
+hdaystmax-description,fr,Nombre de jours chauds (Tmax > 35 °C)
 maxt,en,Average of maximal temperatures
 maxt,fr,Moyenne des températures maximales
 maxt-description,en,Average of maximal temperatures
-- 
GitLab


From 6b90f8fd97a58b550f38586b1704c2e1fb139cb4 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Fri, 3 May 2024 07:58:21 +0200
Subject: [PATCH 18/22] Supprimer la zone de recherche de Select

---
 .../main/java/fr/agrometinfo/www/client/view/LayoutView.java   | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
index 66a064c..6c1c89c 100644
--- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
@@ -341,6 +341,7 @@ implements LayoutPresenter.View, LoadingHandler {
         .setSelect(periodSelect) //
         .addValueChangeHandler(this::onPeriodChange) //
         .build();
+        periodSelect.setSearchable(false);
 
         //
         GWT.log("LayoutView.initLeftPanel() indicators");
@@ -359,6 +360,7 @@ implements LayoutPresenter.View, LoadingHandler {
         .setValueFunction(IndicatorDTO::getCode) //
         .addValueChangeHandler(this::onIndicatorChange) //
         .build();
+        indicatorSelect.setSearchable(false);
 
         //
         GWT.log("LayoutView.initLeftPanel() regions");
@@ -367,6 +369,7 @@ implements LayoutPresenter.View, LoadingHandler {
         .setSelect(regionSelect) //
         .addValueChangeHandler(this::onRegionChange) //
         .build();
+        regionSelect.setSearchable(false);
 
         //
         GWT.log("LayoutView.initLeftPanel() year");
-- 
GitLab


From c798a1d588640a30e88539e9f674f38c48bea1e2 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Fri, 3 May 2024 07:59:10 +0200
Subject: [PATCH 19/22] =?UTF-8?q?Homog=C3=A9n=C3=A9iser=20les=20noms=20des?=
 =?UTF-8?q?=20variables?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 sql/migration.sql | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sql/migration.sql b/sql/migration.sql
index f06cc7c..6dc1f88 100644
--- a/sql/migration.sql
+++ b/sql/migration.sql
@@ -208,6 +208,7 @@ BEGIN
     ALTER TABLE indicator DROP CONSTRAINT "FK_indicator_i18n_description";
     ALTER TABLE indicator ADD CONSTRAINT "FK_indicator_i18n_description" FOREIGN KEY (description) REFERENCES i18nkey (id);
     CREATE INDEX "IX_dailyvalue_doy" ON dailyvalue (EXTRACT(DOY FROM date), indicator);
+    UPDATE i18n SET translation=REPLACE(translation, ' (tmax', ' (Tmax')
     RETURN true;
 END
 $BODY$
-- 
GitLab


From b39c8f4d62af70560b45d44ab5b76c3e56cfc4e3 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Fri, 3 May 2024 13:39:59 +0200
Subject: [PATCH 20/22] =?UTF-8?q?R=C3=A9duire=20la=20liste=20des=20indicat?=
 =?UTF-8?q?eurs?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../www/client/ui/CollapsedSelect.java        | 100 ++++++++++++++++++
 .../www/client/ui/DominoListBuilder.java      |  41 +++++--
 .../www/client/view/LayoutView.java           |  33 ++++--
 .../agrometinfo/www/client/public/style.css   |  16 ++-
 4 files changed, 170 insertions(+), 20 deletions(-)
 create mode 100644 www-client/src/main/java/fr/agrometinfo/www/client/ui/CollapsedSelect.java

diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/ui/CollapsedSelect.java b/www-client/src/main/java/fr/agrometinfo/www/client/ui/CollapsedSelect.java
new file mode 100644
index 0000000..e0c1396
--- /dev/null
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/ui/CollapsedSelect.java
@@ -0,0 +1,100 @@
+package fr.agrometinfo.www.client.ui;
+
+import org.jboss.elemento.Elements;
+import org.jboss.elemento.EventCallbackFn;
+import org.jboss.elemento.EventType;
+import org.jboss.elemento.HtmlContentBuilder;
+
+import elemental2.dom.HTMLDivElement;
+import elemental2.dom.HTMLElement;
+import elemental2.dom.MouseEvent;
+
+/**
+ * A component which mimics the Select component when the drop down list is
+ * closed.
+ *
+ * @author Olivier Maury
+ */
+public final class CollapsedSelect {
+    /**
+     * The root element.
+     */
+    private final HtmlContentBuilder<HTMLDivElement> root;
+    /**
+     * Span displaying the prompt.
+     */
+    private final HtmlContentBuilder<HTMLElement> promptSpan = Elements.span();
+    /**
+     * Span displaying the displayed text of the selected item.
+     */
+    private final HtmlContentBuilder<HTMLElement> selectionSpan = Elements.span();
+
+    /**
+     * Constructor.
+     *
+     * @param promptText    prompt text in the field label
+     * @param selectionText displayed text of the selected item
+     */
+    public CollapsedSelect(final String promptText, final String selectionText) {
+        this.root = Elements.div().css("field-group lined d-select floating")//
+                .add(Elements.div().css("field-cntr") //
+                        .add(Elements.div().css("flex-layout") //
+                                .add(Elements.div().css("flex-item field-input-cntr") //
+                                        .add(Elements.label().css("field-label") //
+                                                .add(promptSpan))
+                                        .add(Elements.button().css("select-button")
+                                                .add(Elements.span().css("select-value ellipsis-text") //
+                                                        .add(selectionSpan)))) //
+                                .add(Elements.div().css("field-mandatory-addon") //
+                                        .add(Elements.i() //
+                                                .css("mdi mdi-menu-down mdi-24px clickable-icon waves-effect")))))
+                .hidden(false);
+        setPromptText(promptText);
+        setSelectionText(selectionText);
+    }
+
+    /**
+     * @return root element
+     */
+    public HtmlContentBuilder<HTMLDivElement> getRoot() {
+        return root;
+    }
+
+    /**
+     * Hide the widget.
+     */
+    public void hide() {
+        root.hidden(true);
+    }
+
+    /**
+     * Add the given callback to the root element.
+     *
+     * @param callback
+     */
+    public void onClick(final EventCallbackFn<MouseEvent> callback) {
+        root.on(EventType.click, callback);
+    }
+
+    /**
+     * @param promptText prompt text in the field label
+     */
+    public void setPromptText(final String promptText) {
+        promptSpan.textContent(promptText);
+    }
+
+    /**
+     * @param selectionText displayed text of the selected item
+     */
+    public void setSelectionText(final String selectionText) {
+        selectionSpan.textContent(selectionText);
+    }
+
+    /**
+     * Show the widget.
+     */
+    public void show() {
+        root.hidden(false);
+    }
+
+}
diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java b/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
index 85bcc39..93e6a90 100644
--- a/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/ui/DominoListBuilder.java
@@ -9,7 +9,9 @@ import java.util.function.Consumer;
 import org.dominokit.domino.ui.grid.flex.FlexItem;
 import org.dominokit.domino.ui.grid.flex.FlexLayout;
 import org.dominokit.domino.ui.lists.ListGroup;
-import org.dominokit.domino.ui.utils.TextNode;
+import org.jboss.elemento.Elements;
+
+import elemental2.dom.HTMLDivElement;
 
 /**
  * Builder for a Domino {@link ListGroup}, a component that allow selecting a
@@ -36,6 +38,23 @@ public final class DominoListBuilder<T> extends SelectBuilder<T, ListGroup<T>> {
         return this;
     }
 
+    /**
+     * Add handler on the displayed text when value change.
+     *
+     * @param handler the handler receives the displayed text of selected option
+     * @return same builder instance
+     */
+    public DominoListBuilder<T> addTextChangeHandler(final Consumer<String> handler) {
+        getSelect().addSelectionListener(selectedItems -> {
+            if (selectedItems == null || selectedItems.isEmpty()) {
+                return;
+            }
+            final T item = selectedItems.get(0).getValue();
+            handler.accept(getTextFunction().apply(item));
+        });
+        return this;
+    }
+
     @Override
     public DominoListBuilder<T> addValueChangeHandler(final Consumer<String> handler) {
         getSelect().addSelectionListener(selectedItems -> {
@@ -53,16 +72,16 @@ public final class DominoListBuilder<T> extends SelectBuilder<T, ListGroup<T>> {
         Objects.requireNonNull(getValueFunction(), "setValueFunction() must be called before!");
         Objects.requireNonNull(getTextFunction(), "setTextFunction() must be called before!");
         return getSelect().setItemRenderer(
-                (listGroup, item) ->
-                item.setSelectable(true)
-                .appendChild(
-                        FlexLayout.create() //
-                        .appendChild(//
-                                FlexItem.create() //
-                                .setFlexGrow(1) //
-                                .appendChild(TextNode
-                                        .of(getTextFunction().apply(item.getValue())))))
-                );
+                (listGroup, item) -> {
+                    final FlexItem<HTMLDivElement> flexItem = FlexItem.create() //
+                            .setFlexGrow(1) //
+                            .appendChild(//
+                                    Elements.span().textContent(getTextFunction().apply(item.getValue())));
+                    item.setSelectable(true)
+                    .appendChild(
+                            FlexLayout.create() //
+                            .appendChild(flexItem));
+                });
     }
 
     private ListGroup<T> getSelect() {
diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
index 6c1c89c..c733bdc 100644
--- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
@@ -41,6 +41,7 @@ import elemental2.dom.DomGlobal;
 import elemental2.dom.HTMLAnchorElement;
 import elemental2.dom.HTMLDivElement;
 import elemental2.dom.HTMLElement;
+import elemental2.dom.HTMLLabelElement;
 import elemental2.dom.MouseEvent;
 import fr.agrometinfo.www.client.App;
 import fr.agrometinfo.www.client.event.LoadingEvent;
@@ -51,6 +52,7 @@ import fr.agrometinfo.www.client.presenter.LayoutPresenter;
 import fr.agrometinfo.www.client.presenter.MapPresenter;
 import fr.agrometinfo.www.client.presenter.RightPanelPresenter;
 import fr.agrometinfo.www.client.ui.AgroclimAppsMenu;
+import fr.agrometinfo.www.client.ui.CollapsedSelect;
 import fr.agrometinfo.www.client.ui.DominoListBuilder;
 import fr.agrometinfo.www.client.ui.DominoSelectBuilder;
 import fr.agrometinfo.www.client.util.ApplicationUtils;
@@ -220,6 +222,11 @@ implements LayoutPresenter.View, LoadingHandler {
      */
     private final HtmlContentBuilder<HTMLDivElement> links = div().css("links");
 
+    /**
+     * The replacement of indicatorSelect when it is hidden.
+     */
+    private final CollapsedSelect collapsedIndicatorSelect = new CollapsedSelect(CSTS.chooseIndicator(), "");
+
     /**
      * @param text     link text
      * @param callback {@link EventCallbackFn<MouseEvent>} to be added to the click
@@ -345,22 +352,32 @@ implements LayoutPresenter.View, LoadingHandler {
 
         //
         GWT.log("LayoutView.initLeftPanel() indicators");
-        panel.appendChild(//
-                div() //
-                .css("field-group lined list-group") //
-                .add(//
-                        Elements.label() //
-                        .css("field-label") //
-                        .add(Elements.span().textContent(CSTS.chooseIndicator()))) //
+        collapsedIndicatorSelect.hide();
+        panel.appendChild(collapsedIndicatorSelect.getRoot());
+        final HtmlContentBuilder<HTMLDivElement> indicatorPanel = div().css("field-group lined list-group");
+        final HtmlContentBuilder<HTMLLabelElement> indicatorLabel = Elements.label() //
+                .css("field-label") //
+                .add(Elements.span().textContent(CSTS.chooseIndicator()));
+        panel.appendChild(indicatorPanel//
+                .add(indicatorLabel) //
                 .add(indicatorSelect) //
                 );
         new DominoListBuilder<IndicatorDTO>() //
         .setSelect(indicatorSelect) //
+        .addTextChangeHandler(collapsedIndicatorSelect::setSelectionText) //
         .setTextFunction(IndicatorDTO::getDescription) //
         .setValueFunction(IndicatorDTO::getCode) //
         .addValueChangeHandler(this::onIndicatorChange) //
         .build();
-        indicatorSelect.setSearchable(false);
+
+        indicatorLabel.on(EventType.click, e -> {
+            indicatorPanel.hidden(true);
+            collapsedIndicatorSelect.show();
+        });
+        collapsedIndicatorSelect.onClick(e -> {
+            indicatorPanel.hidden(false);
+            collapsedIndicatorSelect.hide();
+        });
 
         //
         GWT.log("LayoutView.initLeftPanel() regions");
diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
index eb97c2c..bdbff67 100644
--- a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
+++ b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css
@@ -181,9 +181,18 @@ details.card-details[open] > summary i {
 }
 
 div.list-group > label.field-label {
+    margin-bottom: 0;
     padding-left: 6px;
     padding-right: 6px;
     position: relative;
+    top: 0px;
+    width: 100%;
+}
+div.list-group > label.field-label:after {
+    content: "\F360";
+    text-align: right;
+    float: right;
+    font: normal normal normal 24px/1 "Material Design Icons";
 }
 div.list-group .flex-item {
     line-height: 2em;
@@ -194,7 +203,12 @@ div.list-group .flex-item {
 }
 div.list-group .d-list-item.selected {
     background-color: #ededed;
-    color: #414141;
+    color: #2a2a2a;
+}
+div.list-group .d-list-item.selected span:after {
+    content: "✓";
+    text-align: right;
+    float:right;
 }
 div.list-group .d-list-item:hover {
     background-color: #f5f5f5;
-- 
GitLab


From 0f04f3219ebcebea0a6f0731caa203d5fd302b0b Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Fri, 26 Apr 2024 11:15:45 +0200
Subject: [PATCH 21/22] =?UTF-8?q?Homog=C3=A9n=C3=A9iser=20les=20noms=20des?=
 =?UTF-8?q?=20variables?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 sql/migration.sql | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/sql/migration.sql b/sql/migration.sql
index 6dc1f88..2852359 100644
--- a/sql/migration.sql
+++ b/sql/migration.sql
@@ -223,6 +223,15 @@ END
 $BODY$
 language plpgsql;
 
+CREATE OR REPLACE FUNCTION upgrade20240426() RETURNS boolean AS $BODY$
+BEGIN
+    CREATE INDEX IF NOT EXISTS "IX_cellpra" ON cellpra (cell,pra);
+    UPDATE i18n SET translation=REPLACE(translation, 'tmax', 'Tmax');
+    RETURN true;
+END
+$BODY$
+language plpgsql;
+
 ---
 --
 -- Keep this call at the end to apply migration functions.
-- 
GitLab


From 0d68caf8e068ad37a2e6e7fc21a97ce50d5c0c29 Mon Sep 17 00:00:00 2001
From: Olivier Maury <Olivier.Maury@inrae.fr>
Date: Mon, 6 May 2024 09:35:51 +0200
Subject: [PATCH 22/22] Supprimer la zone de recherche de Select

---
 .../src/main/java/fr/agrometinfo/www/client/view/LayoutView.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
index c733bdc..9708094 100644
--- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java
@@ -394,6 +394,7 @@ implements LayoutPresenter.View, LoadingHandler {
         new DominoSelectBuilder<Entry<String, String>>() //
         .setSelect(yearSelect) //
         .addValueChangeHandler(this::onYearChange);
+        yearSelect.setSearchable(false);
 
         //
         GWT.log("LayoutView.initLeftPanel() comparison");
-- 
GitLab