From 7194a3c93744080e47e197d450cbcddfe82ed51e Mon Sep 17 00:00:00 2001
From: Brendan Le Ny <bleny@codelutin.com>
Date: Tue, 1 Jun 2021 11:54:07 +0200
Subject: [PATCH 01/27] =?UTF-8?q?Change=20l'information=20retourn=C3=A9e?=
 =?UTF-8?q?=20au=20frontend=20pour=20d=C3=A9crire=20une=20application=20po?=
 =?UTF-8?q?ur=20quelque-chose=20de=20plus=20adapt=C3=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../inra/oresing/rest/ApplicationResult.java  | 23 +++++++++++++++++++
 .../fr/inra/oresing/rest/OreSiResources.java  | 10 ++++++--
 .../inra/oresing/rest/OreSiResourcesTest.java | 12 ++++------
 3 files changed, 36 insertions(+), 9 deletions(-)
 create mode 100644 src/main/java/fr/inra/oresing/rest/ApplicationResult.java

diff --git a/src/main/java/fr/inra/oresing/rest/ApplicationResult.java b/src/main/java/fr/inra/oresing/rest/ApplicationResult.java
new file mode 100644
index 000000000..3f3af5e07
--- /dev/null
+++ b/src/main/java/fr/inra/oresing/rest/ApplicationResult.java
@@ -0,0 +1,23 @@
+package fr.inra.oresing.rest;
+
+import lombok.Value;
+
+import java.util.Map;
+
+@Value
+public class ApplicationResult {
+    String id;
+    String name;
+    String title;
+    Map<String, Reference> references;
+
+    @Value
+    public static class Reference {
+        Map<String, Column> columns;
+
+        @Value
+        public static class Column {
+            String title;
+        }
+    }
+}
diff --git a/src/main/java/fr/inra/oresing/rest/OreSiResources.java b/src/main/java/fr/inra/oresing/rest/OreSiResources.java
index 6be34e4b2..82d5412be 100644
--- a/src/main/java/fr/inra/oresing/rest/OreSiResources.java
+++ b/src/main/java/fr/inra/oresing/rest/OreSiResources.java
@@ -1,6 +1,7 @@
 package fr.inra.oresing.rest;
 
 import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
 import fr.inra.oresing.checker.CheckerException;
 import fr.inra.oresing.model.Application;
 import fr.inra.oresing.model.BinaryFile;
@@ -81,9 +82,14 @@ public class OreSiResources {
     }
 
     @GetMapping(value = "/applications/{nameOrId}", produces = MediaType.APPLICATION_JSON_VALUE)
-    public ResponseEntity<Application> getApplication(@PathVariable("nameOrId") String nameOrId) {
+    public ResponseEntity<ApplicationResult> getApplication(@PathVariable("nameOrId") String nameOrId) {
         Application application = service.getApplication(nameOrId);
-        return ResponseEntity.ok(application);
+        Map<String, ApplicationResult.Reference> references = Maps.transformValues(application.getConfiguration().getReferences(), referenceDescription -> {
+            Map<String, ApplicationResult.Reference.Column> columns = Maps.transformEntries(referenceDescription.getColumns(), (column, columnDescription) -> new ApplicationResult.Reference.Column(column));
+            return new ApplicationResult.Reference(columns);
+        });
+        ApplicationResult applicationResult = new ApplicationResult(application.getId().toString(), application.getName(), application.getConfiguration().getApplication().getName(), references);
+        return ResponseEntity.ok(applicationResult);
     }
 
     @GetMapping(value = "/applications/{nameOrId}/configuration", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
diff --git a/src/test/java/fr/inra/oresing/rest/OreSiResourcesTest.java b/src/test/java/fr/inra/oresing/rest/OreSiResourcesTest.java
index dbc430eda..a72b8524a 100644
--- a/src/test/java/fr/inra/oresing/rest/OreSiResourcesTest.java
+++ b/src/test/java/fr/inra/oresing/rest/OreSiResourcesTest.java
@@ -5,7 +5,6 @@ import com.google.common.base.Charsets;
 import com.google.common.io.Resources;
 import com.jayway.jsonpath.JsonPath;
 import fr.inra.oresing.OreSiNg;
-import fr.inra.oresing.model.Application;
 import fr.inra.oresing.model.OreSiUser;
 import fr.inra.oresing.persistence.AuthenticationService;
 import lombok.extern.slf4j.Slf4j;
@@ -37,9 +36,9 @@ import javax.servlet.http.Cookie;
 import java.io.InputStream;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
-import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
 
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -118,12 +117,11 @@ public class OreSiResourcesTest {
                 .andExpect(jsonPath("$.id", Is.is(appId)))
                 .andReturn().getResponse().getContentAsString();
 
-        Application app2 = objectMapper.readValue(response, Application.class);
+        ApplicationResult applicationResult = objectMapper.readValue(response, ApplicationResult.class);
 
-        Date now = new Date();
-        Assert.assertEquals("monsore", app2.getName());
-        Assert.assertEquals(List.of("especes", "projet", "sites", "themes", "type de fichiers", "type_de_sites", "types_de_donnees_par_themes_de_sites_et_projet", "unites", "valeurs_qualitatives", "variables", "variables_et_unites_par_types_de_donnees"), app2.getReferenceType());
-        Assert.assertEquals(List.of("pem"), app2.getDataType());
+        Assert.assertEquals("monsore", applicationResult.getName());
+        Assert.assertEquals(Set.of("especes", "projet", "sites", "themes", "type de fichiers", "type_de_sites", "types_de_donnees_par_themes_de_sites_et_projet", "unites", "valeurs_qualitatives", "variables", "variables_et_unites_par_types_de_donnees"), applicationResult.getReferences().keySet());
+//        Assert.assertEquals(List.of("pem"), applicationResult.getDataType());
 
         // Ajout de referentiel
         for (Map.Entry<String, String> e : fixtures.getMonsoreReferentielFiles().entrySet()) {
-- 
GitLab


From ec58e452fa808f002c35a36173b5345f76881851 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Tue, 1 Jun 2021 12:05:27 +0200
Subject: [PATCH 02/27] =?UTF-8?q?Cr=C3=A9e=20une=20ApplicationDetailsPage?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ui2/src/router/index.js                         | 11 +++++++++--
 ui2/src/services/rest/ApplicationService.js     |  4 ++++
 ui2/src/style/_common.scss                      |  4 ++++
 .../ApplicationCreationView.vue                 |  0
 .../application/ApplicationDetailsView.vue      | 13 +++++++++++++
 .../{ => application}/ApplicationsView.vue      | 17 ++++++++++++++---
 6 files changed, 44 insertions(+), 5 deletions(-)
 rename ui2/src/views/{ => application}/ApplicationCreationView.vue (100%)
 create mode 100644 ui2/src/views/application/ApplicationDetailsView.vue
 rename ui2/src/views/{ => application}/ApplicationsView.vue (74%)

diff --git a/ui2/src/router/index.js b/ui2/src/router/index.js
index e72efccf6..357e31fd9 100644
--- a/ui2/src/router/index.js
+++ b/ui2/src/router/index.js
@@ -1,8 +1,9 @@
 import Vue from "vue";
 import VueRouter from "vue-router";
 import LoginView from "@/views/LoginView.vue";
-import ApplicationsView from "@/views/ApplicationsView.vue";
-import ApplicationCreationView from "@/views/ApplicationCreationView.vue";
+import ApplicationsView from "@/views/application/ApplicationsView.vue";
+import ApplicationCreationView from "@/views/application/ApplicationCreationView.vue";
+import ApplicationDetailsView from "@/views/application/ApplicationDetailsView.vue";
 
 Vue.use(VueRouter);
 
@@ -26,6 +27,12 @@ const routes = [
     name: "Application creation",
     component: ApplicationCreationView,
   },
+  {
+    path: "/application/:name",
+    name: "Application view",
+    component: ApplicationDetailsView,
+    props: true,
+  },
 ];
 
 const router = new VueRouter({
diff --git a/ui2/src/services/rest/ApplicationService.js b/ui2/src/services/rest/ApplicationService.js
index 2a6737154..30b8561f7 100644
--- a/ui2/src/services/rest/ApplicationService.js
+++ b/ui2/src/services/rest/ApplicationService.js
@@ -16,4 +16,8 @@ export class ApplicationService extends Fetcher {
   async getApplications() {
     return this.get("applications/");
   }
+
+  async getApplication(id) {
+    return this.get("applications/" + id);
+  }
 }
diff --git a/ui2/src/style/_common.scss b/ui2/src/style/_common.scss
index 0237eb0c7..e9eaf9c75 100644
--- a/ui2/src/style/_common.scss
+++ b/ui2/src/style/_common.scss
@@ -19,6 +19,10 @@ a {
   color: $info;
 }
 
+.clickable {
+  cursor: pointer;
+}
+
 // Input style
 
 .input-field {
diff --git a/ui2/src/views/ApplicationCreationView.vue b/ui2/src/views/application/ApplicationCreationView.vue
similarity index 100%
rename from ui2/src/views/ApplicationCreationView.vue
rename to ui2/src/views/application/ApplicationCreationView.vue
diff --git a/ui2/src/views/application/ApplicationDetailsView.vue b/ui2/src/views/application/ApplicationDetailsView.vue
new file mode 100644
index 000000000..39c79b372
--- /dev/null
+++ b/ui2/src/views/application/ApplicationDetailsView.vue
@@ -0,0 +1,13 @@
+<template>
+  <PageView> </PageView>
+</template>
+
+<script>
+import { Component, Vue } from "vue-property-decorator";
+import PageView from "@/views/common/PageView.vue";
+
+@Component({
+  components: { PageView },
+})
+export default class ApplicationDetailsView extends Vue {}
+</script>
diff --git a/ui2/src/views/ApplicationsView.vue b/ui2/src/views/application/ApplicationsView.vue
similarity index 74%
rename from ui2/src/views/ApplicationsView.vue
rename to ui2/src/views/application/ApplicationsView.vue
index e6845c3e6..ec72b6dce 100644
--- a/ui2/src/views/ApplicationsView.vue
+++ b/ui2/src/views/application/ApplicationsView.vue
@@ -18,10 +18,14 @@
         height="100%"
       >
         <b-table-column field="name" label="Name" sortable width="50%" v-slot="props">
-          {{ props.row.name }}
+          <div @click="displayApplication(props.row)" class="clickable">
+            {{ props.row.name }}
+          </div>
         </b-table-column>
         <b-table-column field="creationDate" label="Creation Date" sortable v-slot="props">
-          {{ new Date(props.row.creationDate) }}
+          <div @click="displayApplication(props.row)" class="clickable">
+            {{ new Date(props.row.creationDate) }}
+          </div>
         </b-table-column>
       </b-table>
     </PageView>
@@ -31,7 +35,7 @@
 <script>
 import { ApplicationService } from "@/services/rest/ApplicationService";
 import { Component, Vue } from "vue-property-decorator";
-import PageView from "./common/PageView.vue";
+import PageView from "@/views/common/PageView.vue";
 
 @Component({
   components: { PageView },
@@ -52,5 +56,12 @@ export default class ApplicationsView extends Vue {
   createApplication() {
     this.$router.push("/applicationCreation");
   }
+
+  displayApplication(application) {
+    if (!application) {
+      return;
+    }
+    this.$router.push("/application/" + application.name);
+  }
 }
 </script>
-- 
GitLab


From 6103ab7c1345f71bd65b63eb4f809cd45014d6d0 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Tue, 1 Jun 2021 18:00:46 +0200
Subject: [PATCH 03/27] =?UTF-8?q?Ajoute=20la=20s=C3=A9lection=20de=20r?=
 =?UTF-8?q?=C3=A9f=C3=A9rentiels=20et=20dataset?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../application/DatasetSelection.vue          | 43 +++++++++++++
 .../application/ReferenceSelection.vue        | 42 +++++++++++++
 ui2/src/locales/en.json                       | 12 +++-
 ui2/src/locales/fr.json                       | 12 +++-
 ui2/src/main.js                               |  8 ++-
 ui2/src/router/index.js                       |  2 +-
 ui2/src/services/rest/ApplicationService.js   | 12 +++-
 .../application/ApplicationDetailsView.vue    | 42 +++++++++++--
 .../views/application/ApplicationsView.vue    | 60 +++++++++----------
 ui2/src/views/common/PageView.vue             |  8 ++-
 10 files changed, 199 insertions(+), 42 deletions(-)
 create mode 100644 ui2/src/components/application/DatasetSelection.vue
 create mode 100644 ui2/src/components/application/ReferenceSelection.vue

diff --git a/ui2/src/components/application/DatasetSelection.vue b/ui2/src/components/application/DatasetSelection.vue
new file mode 100644
index 000000000..0e2bae73f
--- /dev/null
+++ b/ui2/src/components/application/DatasetSelection.vue
@@ -0,0 +1,43 @@
+<template>
+  <div>
+    <b-select
+      v-model="chosenDataType"
+      :placeholder="$t('datasetSelection.placeholder')"
+      @input="loadDataset"
+      expanded
+      v-if="application"
+    >
+      <option v-for="type in application.dataType" :key="type" :value="type">
+        {{ type }}
+      </option>
+    </b-select>
+  </div>
+</template>
+
+<script>
+import { ApplicationService } from "@/services/rest/ApplicationService";
+import { Component, Prop, Vue } from "vue-property-decorator";
+
+@Component({
+  components: {},
+})
+export default class DatasetSelection extends Vue {
+  @Prop() application;
+
+  applicationService = ApplicationService.INSTANCE;
+
+  chosenDataType = null;
+  dataset = null;
+
+  async loadDataset() {
+    try {
+      this.dataset = await this.applicationService.getDataset(
+        this.chosenDataType,
+        this.application.name
+      );
+    } catch (error) {
+      this.alertService.toastServerError();
+    }
+  }
+}
+</script>
diff --git a/ui2/src/components/application/ReferenceSelection.vue b/ui2/src/components/application/ReferenceSelection.vue
new file mode 100644
index 000000000..cd54b192e
--- /dev/null
+++ b/ui2/src/components/application/ReferenceSelection.vue
@@ -0,0 +1,42 @@
+<template>
+  <div>
+    <b-select
+      v-model="chosenReferenceType"
+      :placeholder="$t('referenceSelection.placeholder')"
+      @input="getReference"
+      expanded
+      v-if="application"
+    >
+      <option v-for="type in application.referenceType" :key="type" :value="type">
+        {{ type }}
+      </option>
+    </b-select>
+  </div>
+</template>
+
+<script>
+import { ApplicationService } from "@/services/rest/ApplicationService";
+import { Component, Prop, Vue } from "vue-property-decorator";
+
+@Component({
+  components: {},
+})
+export default class ReferenceSelection extends Vue {
+  @Prop() application;
+  applicationService = ApplicationService.INSTANCE;
+
+  chosenReferenceType = null;
+  reference = null;
+
+  async getReference() {
+    try {
+      this.reference = await this.applicationService.getReference(
+        this.chosenReferenceType,
+        this.application.name
+      );
+    } catch (error) {
+      this.alertService.toastServerError();
+    }
+  }
+}
+</script>
diff --git a/ui2/src/locales/en.json b/ui2/src/locales/en.json
index 7be687b97..b84ae454d 100644
--- a/ui2/src/locales/en.json
+++ b/ui2/src/locales/en.json
@@ -34,7 +34,6 @@
   "menu": {
     "logout": "Log out",
     "applications": "Applications",
-    "references": "References",
     "french": "Français",
     "english": "English",
     "language": "Language"
@@ -66,5 +65,16 @@
     "unknownCheckerName": "For the validation rule : <code>{lineValidationRuleKey}</code>, '<code>{checkerName}</code>' is declared but is not a known checker",
     "csvBoundToUnknownVariable": "In the CSV format, header <code>{header}</code> is bound to unknown variable <code>{variable}</code>. Known variables: <code>{variables}</code>",
     "csvBoundToUnknownVariableComponent": "In the CSV format, header <code>{header}</code> is bound to <code>{variable}</code> but it has no <code>{component}</code> component. Known components: <code>{components}</code>"
+  },
+  "applicationDetailsView": {
+    "application": "Application details",
+    "references": "References",
+    "dataset": "Datasets"
+  },
+  "referenceSelection": {
+    "placeholder": "Chose the reference"
+  },
+  "datasetSelection": {
+    "placeholder": "Chose the dataset"
   }
 }
diff --git a/ui2/src/locales/fr.json b/ui2/src/locales/fr.json
index 1cc85cb59..dfabff25b 100644
--- a/ui2/src/locales/fr.json
+++ b/ui2/src/locales/fr.json
@@ -34,7 +34,6 @@
   "menu": {
     "logout": "Se déconnecter",
     "applications": "Applications",
-    "references": "Référentiels",
     "french": "Français",
     "english": "English",
     "language": "Langue"
@@ -66,5 +65,16 @@
     "unknownCheckerName": "Pour la règle de validation <code>{lineValidationRuleKey}</code>, '<code>{checkerName}</code>' est déclaré mais ce n’est pas un contrôle connu",
     "csvBoundToUnknownVariable": "Dans le format CSV, l’entête <code>{header}</code> est lié à la variable <code>{variable}</code> qui n'est pas connue. Variables connues <code>{variables}</code>",
     "csvBoundToUnknownVariableComponent": "Dans le format CSV, l’entête <code>{header}</code> est lié à la variable <code>{variable}</code> mais elle n'a pas de composant <code>{component}</code>. <br>Composants connus <code>{components}</code>"
+  },
+  "applicationDetailsView": {
+    "application": "Détail de l'application",
+    "references": "Référentiels",
+    "dataset": "Données"
+  },
+  "referenceSelection": {
+    "placeholder": "Choisir le référentiel"
+  },
+  "datasetSelection": {
+    "placeholder": "Choisir les données"
   }
 }
diff --git a/ui2/src/main.js b/ui2/src/main.js
index 6ac7201b9..b04fe18ba 100644
--- a/ui2/src/main.js
+++ b/ui2/src/main.js
@@ -10,13 +10,16 @@ import {
   faArrowDown,
   faArrowUp,
   faCheck,
+  faDraftingCompass,
   faExclamationCircle,
   faEye,
   faEyeSlash,
   faGlobe,
   faPlus,
+  faPoll,
   faSignOutAlt,
   faUpload,
+  faWrench,
 } from "@fortawesome/free-solid-svg-icons";
 import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
 library.add(
@@ -31,7 +34,10 @@ library.add(
   faArrowUp,
   faArrowDown,
   faAngleLeft,
-  faAngleRight
+  faAngleRight,
+  faWrench,
+  faPoll,
+  faDraftingCompass
 );
 Vue.component("vue-fontawesome", FontAwesomeIcon);
 
diff --git a/ui2/src/router/index.js b/ui2/src/router/index.js
index 357e31fd9..41b14e4e9 100644
--- a/ui2/src/router/index.js
+++ b/ui2/src/router/index.js
@@ -28,7 +28,7 @@ const routes = [
     component: ApplicationCreationView,
   },
   {
-    path: "/application/:name",
+    path: "/application/:applicationName",
     name: "Application view",
     component: ApplicationDetailsView,
     props: true,
diff --git a/ui2/src/services/rest/ApplicationService.js b/ui2/src/services/rest/ApplicationService.js
index 30b8561f7..15b15358f 100644
--- a/ui2/src/services/rest/ApplicationService.js
+++ b/ui2/src/services/rest/ApplicationService.js
@@ -17,7 +17,15 @@ export class ApplicationService extends Fetcher {
     return this.get("applications/");
   }
 
-  async getApplication(id) {
-    return this.get("applications/" + id);
+  async getApplication(name) {
+    return this.get("applications/" + name);
+  }
+
+  async getDataset(dataset, applicationName) {
+    return this.get(`applications/${applicationName}/data/${dataset}`);
+  }
+
+  async getReference(reference, applicationName) {
+    return this.get(`applications/${applicationName}/references/${reference}`);
   }
 }
diff --git a/ui2/src/views/application/ApplicationDetailsView.vue b/ui2/src/views/application/ApplicationDetailsView.vue
index 39c79b372..9cb155a83 100644
--- a/ui2/src/views/application/ApplicationDetailsView.vue
+++ b/ui2/src/views/application/ApplicationDetailsView.vue
@@ -1,13 +1,47 @@
 <template>
-  <PageView> </PageView>
+  <PageView>
+    <h1 class="title main-title">{{ applicationName }}</h1>
+    <b-tabs type="is-boxed" expanded class="mt-4">
+      <b-tab-item :label="$t('applicationDetailsView.application')" icon="wrench"> </b-tab-item>
+      <b-tab-item :label="$t('applicationDetailsView.references')" icon="drafting-compass">
+        <ReferenceSelection :key="application.id" :application="application" />
+      </b-tab-item>
+      <b-tab-item :label="$t('applicationDetailsView.dataset')" icon="poll">
+        <DatasetSelection :key="application.id" :application="application" />
+      </b-tab-item>
+    </b-tabs>
+  </PageView>
 </template>
 
 <script>
-import { Component, Vue } from "vue-property-decorator";
+import { Component, Prop, Vue } from "vue-property-decorator";
 import PageView from "@/views/common/PageView.vue";
+import ReferenceSelection from "@/components/application/ReferenceSelection.vue";
+import { Application } from "@/model/Application";
+import { ApplicationService } from "@/services/rest/ApplicationService";
+import { AlertService } from "@/services/AlertService";
+import DatasetSelection from "@/components/application/DatasetSelection.vue";
 
 @Component({
-  components: { PageView },
+  components: { PageView, ReferenceSelection, DatasetSelection },
 })
-export default class ApplicationDetailsView extends Vue {}
+export default class ApplicationDetailsView extends Vue {
+  @Prop() applicationName;
+
+  applicationService = ApplicationService.INSTANCE;
+  alertService = AlertService.INSTANCE;
+  application = new Application();
+
+  created() {
+    this.init();
+  }
+
+  async init() {
+    try {
+      this.application = await this.applicationService.getApplication(this.applicationName);
+    } catch (error) {
+      this.alertService.toastServerError();
+    }
+  }
+}
 </script>
diff --git a/ui2/src/views/application/ApplicationsView.vue b/ui2/src/views/application/ApplicationsView.vue
index ec72b6dce..1f3358273 100644
--- a/ui2/src/views/application/ApplicationsView.vue
+++ b/ui2/src/views/application/ApplicationsView.vue
@@ -1,35 +1,33 @@
 <template>
-  <div>
-    <PageView>
-      <h1 class="title main-title">{{ $t("titles.applications-page") }}</h1>
-      <div class="buttons">
-        <b-button type="is-primary" @click="createApplication" icon-right="plus">
-          {{ $t("applications.create") }}
-        </b-button>
-      </div>
-      <b-table
-        :data="applications"
-        :striped="true"
-        :isFocusable="true"
-        :isHoverable="true"
-        :sticky-header="true"
-        :paginated="true"
-        :per-page="15"
-        height="100%"
-      >
-        <b-table-column field="name" label="Name" sortable width="50%" v-slot="props">
-          <div @click="displayApplication(props.row)" class="clickable">
-            {{ props.row.name }}
-          </div>
-        </b-table-column>
-        <b-table-column field="creationDate" label="Creation Date" sortable v-slot="props">
-          <div @click="displayApplication(props.row)" class="clickable">
-            {{ new Date(props.row.creationDate) }}
-          </div>
-        </b-table-column>
-      </b-table>
-    </PageView>
-  </div>
+  <PageView>
+    <h1 class="title main-title">{{ $t("titles.applications-page") }}</h1>
+    <div class="buttons">
+      <b-button type="is-primary" @click="createApplication" icon-right="plus">
+        {{ $t("applications.create") }}
+      </b-button>
+    </div>
+    <b-table
+      :data="applications"
+      :striped="true"
+      :isFocusable="true"
+      :isHoverable="true"
+      :sticky-header="true"
+      :paginated="true"
+      :per-page="15"
+      height="100%"
+    >
+      <b-table-column field="name" label="Name" sortable width="50%" v-slot="props">
+        <div @click="displayApplication(props.row)" class="clickable">
+          {{ props.row.name }}
+        </div>
+      </b-table-column>
+      <b-table-column field="creationDate" label="Creation Date" sortable v-slot="props">
+        <div @click="displayApplication(props.row)" class="clickable">
+          {{ new Date(props.row.creationDate) }}
+        </div>
+      </b-table-column>
+    </b-table>
+  </PageView>
 </template>
 
 <script>
diff --git a/ui2/src/views/common/PageView.vue b/ui2/src/views/common/PageView.vue
index d2d33980d..9c0f0edfc 100644
--- a/ui2/src/views/common/PageView.vue
+++ b/ui2/src/views/common/PageView.vue
@@ -1,7 +1,7 @@
 <template>
   <div class="PageView">
     <MenuView v-if="hasMenu" />
-    <div class="container PageView-container">
+    <div :class="`container PageView-container ${hasMenu ? '' : 'noMenu'}`">
       <slot></slot>
     </div>
   </div>
@@ -36,5 +36,11 @@ export default class PageView extends Vue {
 
 .PageView-container {
   width: 100%;
+  height: calc(100% - #{$menu-height});
+  padding-top: 1.5rem;
+
+  &.noMenu {
+    height: 100%;
+  }
 }
 </style>
-- 
GitLab


From f23b70e1e98ea274e078d21df0bf7fecdb35134b Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Tue, 1 Jun 2021 18:04:22 +0200
Subject: [PATCH 04/27] Ajoute traduction des noms de colonnes

---
 ui2/src/locales/en.json                        |  3 ++-
 ui2/src/locales/fr.json                        |  3 ++-
 ui2/src/views/application/ApplicationsView.vue | 15 +++++++++++++--
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/ui2/src/locales/en.json b/ui2/src/locales/en.json
index b84ae454d..9b6ecceec 100644
--- a/ui2/src/locales/en.json
+++ b/ui2/src/locales/en.json
@@ -42,7 +42,8 @@
     "chose-config": "Chose a configuration",
     "create": "Create application",
     "name": "Application name",
-    "name-placeholder": "Write down the application name"
+    "name-placeholder": "Write down the application name",
+    "creation-date": "Creation date"
   },
   "errors": {
     "emptyFile": "File is empty",
diff --git a/ui2/src/locales/fr.json b/ui2/src/locales/fr.json
index dfabff25b..1b07d95b6 100644
--- a/ui2/src/locales/fr.json
+++ b/ui2/src/locales/fr.json
@@ -42,7 +42,8 @@
     "chose-config": "Choisir une configuration",
     "create": "Créer l'application",
     "name": "Nom de l'application",
-    "name-placeholder": "Entrer le nom de l'application"
+    "name-placeholder": "Entrer le nom de l'application",
+    "creation-date": "Date de création"
   },
   "errors": {
     "emptyFile": "Le fichier est vide",
diff --git a/ui2/src/views/application/ApplicationsView.vue b/ui2/src/views/application/ApplicationsView.vue
index 1f3358273..cd7be17c3 100644
--- a/ui2/src/views/application/ApplicationsView.vue
+++ b/ui2/src/views/application/ApplicationsView.vue
@@ -16,12 +16,23 @@
       :per-page="15"
       height="100%"
     >
-      <b-table-column field="name" label="Name" sortable width="50%" v-slot="props">
+      <b-table-column
+        field="name"
+        :label="$t('applications.name')"
+        sortable
+        width="50%"
+        v-slot="props"
+      >
         <div @click="displayApplication(props.row)" class="clickable">
           {{ props.row.name }}
         </div>
       </b-table-column>
-      <b-table-column field="creationDate" label="Creation Date" sortable v-slot="props">
+      <b-table-column
+        field="creationDate"
+        :label="$t('applications.creation-date')"
+        sortable
+        v-slot="props"
+      >
         <div @click="displayApplication(props.row)" class="clickable">
           {{ new Date(props.row.creationDate) }}
         </div>
-- 
GitLab


From c09474dbf61906387766f9d90b100d1db878ee40 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Tue, 8 Jun 2021 18:00:17 +0200
Subject: [PATCH 05/27] =?UTF-8?q?Supprime=20des=20composants=20obsol=C3=A8?=
 =?UTF-8?q?tes?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../application/DatasetSelection.vue          | 43 -------------------
 .../application/ReferenceSelection.vue        | 42 ------------------
 ui2/src/locales/en.json                       |  6 ---
 ui2/src/locales/fr.json                       |  6 ---
 .../application/ApplicationDetailsView.vue    |  9 +---
 5 files changed, 2 insertions(+), 104 deletions(-)
 delete mode 100644 ui2/src/components/application/DatasetSelection.vue
 delete mode 100644 ui2/src/components/application/ReferenceSelection.vue

diff --git a/ui2/src/components/application/DatasetSelection.vue b/ui2/src/components/application/DatasetSelection.vue
deleted file mode 100644
index 0e2bae73f..000000000
--- a/ui2/src/components/application/DatasetSelection.vue
+++ /dev/null
@@ -1,43 +0,0 @@
-<template>
-  <div>
-    <b-select
-      v-model="chosenDataType"
-      :placeholder="$t('datasetSelection.placeholder')"
-      @input="loadDataset"
-      expanded
-      v-if="application"
-    >
-      <option v-for="type in application.dataType" :key="type" :value="type">
-        {{ type }}
-      </option>
-    </b-select>
-  </div>
-</template>
-
-<script>
-import { ApplicationService } from "@/services/rest/ApplicationService";
-import { Component, Prop, Vue } from "vue-property-decorator";
-
-@Component({
-  components: {},
-})
-export default class DatasetSelection extends Vue {
-  @Prop() application;
-
-  applicationService = ApplicationService.INSTANCE;
-
-  chosenDataType = null;
-  dataset = null;
-
-  async loadDataset() {
-    try {
-      this.dataset = await this.applicationService.getDataset(
-        this.chosenDataType,
-        this.application.name
-      );
-    } catch (error) {
-      this.alertService.toastServerError();
-    }
-  }
-}
-</script>
diff --git a/ui2/src/components/application/ReferenceSelection.vue b/ui2/src/components/application/ReferenceSelection.vue
deleted file mode 100644
index cd54b192e..000000000
--- a/ui2/src/components/application/ReferenceSelection.vue
+++ /dev/null
@@ -1,42 +0,0 @@
-<template>
-  <div>
-    <b-select
-      v-model="chosenReferenceType"
-      :placeholder="$t('referenceSelection.placeholder')"
-      @input="getReference"
-      expanded
-      v-if="application"
-    >
-      <option v-for="type in application.referenceType" :key="type" :value="type">
-        {{ type }}
-      </option>
-    </b-select>
-  </div>
-</template>
-
-<script>
-import { ApplicationService } from "@/services/rest/ApplicationService";
-import { Component, Prop, Vue } from "vue-property-decorator";
-
-@Component({
-  components: {},
-})
-export default class ReferenceSelection extends Vue {
-  @Prop() application;
-  applicationService = ApplicationService.INSTANCE;
-
-  chosenReferenceType = null;
-  reference = null;
-
-  async getReference() {
-    try {
-      this.reference = await this.applicationService.getReference(
-        this.chosenReferenceType,
-        this.application.name
-      );
-    } catch (error) {
-      this.alertService.toastServerError();
-    }
-  }
-}
-</script>
diff --git a/ui2/src/locales/en.json b/ui2/src/locales/en.json
index 9b6ecceec..a0571752e 100644
--- a/ui2/src/locales/en.json
+++ b/ui2/src/locales/en.json
@@ -71,11 +71,5 @@
     "application": "Application details",
     "references": "References",
     "dataset": "Datasets"
-  },
-  "referenceSelection": {
-    "placeholder": "Chose the reference"
-  },
-  "datasetSelection": {
-    "placeholder": "Chose the dataset"
   }
 }
diff --git a/ui2/src/locales/fr.json b/ui2/src/locales/fr.json
index 1b07d95b6..627ba74bc 100644
--- a/ui2/src/locales/fr.json
+++ b/ui2/src/locales/fr.json
@@ -71,11 +71,5 @@
     "application": "Détail de l'application",
     "references": "Référentiels",
     "dataset": "Données"
-  },
-  "referenceSelection": {
-    "placeholder": "Choisir le référentiel"
-  },
-  "datasetSelection": {
-    "placeholder": "Choisir les données"
   }
 }
diff --git a/ui2/src/views/application/ApplicationDetailsView.vue b/ui2/src/views/application/ApplicationDetailsView.vue
index 9cb155a83..fe2d0f43a 100644
--- a/ui2/src/views/application/ApplicationDetailsView.vue
+++ b/ui2/src/views/application/ApplicationDetailsView.vue
@@ -4,11 +4,8 @@
     <b-tabs type="is-boxed" expanded class="mt-4">
       <b-tab-item :label="$t('applicationDetailsView.application')" icon="wrench"> </b-tab-item>
       <b-tab-item :label="$t('applicationDetailsView.references')" icon="drafting-compass">
-        <ReferenceSelection :key="application.id" :application="application" />
-      </b-tab-item>
-      <b-tab-item :label="$t('applicationDetailsView.dataset')" icon="poll">
-        <DatasetSelection :key="application.id" :application="application" />
       </b-tab-item>
+      <b-tab-item :label="$t('applicationDetailsView.dataset')" icon="poll"> </b-tab-item>
     </b-tabs>
   </PageView>
 </template>
@@ -16,14 +13,12 @@
 <script>
 import { Component, Prop, Vue } from "vue-property-decorator";
 import PageView from "@/views/common/PageView.vue";
-import ReferenceSelection from "@/components/application/ReferenceSelection.vue";
 import { Application } from "@/model/Application";
 import { ApplicationService } from "@/services/rest/ApplicationService";
 import { AlertService } from "@/services/AlertService";
-import DatasetSelection from "@/components/application/DatasetSelection.vue";
 
 @Component({
-  components: { PageView, ReferenceSelection, DatasetSelection },
+  components: { PageView },
 })
 export default class ApplicationDetailsView extends Vue {
   @Prop() applicationName;
-- 
GitLab


From 13b97170a26559b07b90be51f9ab2dbd6ead49c7 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Tue, 8 Jun 2021 18:37:31 +0200
Subject: [PATCH 06/27] Premier brouillon d'un ReferencesManagement

---
 .../application/ReferencesManagement.vue      | 25 +++++++++++++++++++
 ui2/src/main.js                               |  6 ++++-
 ui2/src/model/ApplicationResult.js            | 18 +++++++++++++
 .../application/ApplicationDetailsView.vue    | 10 +++++---
 4 files changed, 54 insertions(+), 5 deletions(-)
 create mode 100644 ui2/src/components/application/ReferencesManagement.vue
 create mode 100644 ui2/src/model/ApplicationResult.js

diff --git a/ui2/src/components/application/ReferencesManagement.vue b/ui2/src/components/application/ReferencesManagement.vue
new file mode 100644
index 000000000..8aca89c14
--- /dev/null
+++ b/ui2/src/components/application/ReferencesManagement.vue
@@ -0,0 +1,25 @@
+<template>
+  <div>
+    <div>
+      <b-button @click="setOpenSite" :icon-left="openSite ? 'caret-up' : 'caret-down'" /> Site
+      <div v-if="openSite">Parcelle</div>
+    </div>
+    <div>Unités</div>
+  </div>
+</template>
+
+<script>
+import { Component, Prop, Vue } from "vue-property-decorator";
+@Component({
+  components: {},
+})
+export default class ReferencesManagement extends Vue {
+  @Prop() application;
+
+  openSite = false;
+
+  setOpenSite() {
+    this.openSite = !this.openSite;
+  }
+}
+</script>
diff --git a/ui2/src/main.js b/ui2/src/main.js
index b04fe18ba..185e8ed69 100644
--- a/ui2/src/main.js
+++ b/ui2/src/main.js
@@ -9,6 +9,8 @@ import {
   faAngleRight,
   faArrowDown,
   faArrowUp,
+  faCaretDown,
+  faCaretUp,
   faCheck,
   faDraftingCompass,
   faExclamationCircle,
@@ -37,7 +39,9 @@ library.add(
   faAngleRight,
   faWrench,
   faPoll,
-  faDraftingCompass
+  faDraftingCompass,
+  faCaretUp,
+  faCaretDown
 );
 Vue.component("vue-fontawesome", FontAwesomeIcon);
 
diff --git a/ui2/src/model/ApplicationResult.js b/ui2/src/model/ApplicationResult.js
new file mode 100644
index 000000000..c6631f3e8
--- /dev/null
+++ b/ui2/src/model/ApplicationResult.js
@@ -0,0 +1,18 @@
+export class ApplicationResult {
+  id;
+  name;
+  title;
+  references = {
+    idRef: {
+      id: "",
+      label: "",
+      children: [],
+      columns: {
+        id: "",
+        label: "",
+        key: false,
+        linkedTo: "",
+      },
+    },
+  };
+}
diff --git a/ui2/src/views/application/ApplicationDetailsView.vue b/ui2/src/views/application/ApplicationDetailsView.vue
index fe2d0f43a..ecad562f5 100644
--- a/ui2/src/views/application/ApplicationDetailsView.vue
+++ b/ui2/src/views/application/ApplicationDetailsView.vue
@@ -1,9 +1,10 @@
 <template>
   <PageView>
-    <h1 class="title main-title">{{ applicationName }}</h1>
+    <h1 class="title main-title">{{ application.title }}</h1>
     <b-tabs type="is-boxed" expanded class="mt-4">
       <b-tab-item :label="$t('applicationDetailsView.application')" icon="wrench"> </b-tab-item>
       <b-tab-item :label="$t('applicationDetailsView.references')" icon="drafting-compass">
+        <ReferencesManagement :application="application" />
       </b-tab-item>
       <b-tab-item :label="$t('applicationDetailsView.dataset')" icon="poll"> </b-tab-item>
     </b-tabs>
@@ -13,19 +14,20 @@
 <script>
 import { Component, Prop, Vue } from "vue-property-decorator";
 import PageView from "@/views/common/PageView.vue";
-import { Application } from "@/model/Application";
+import { ApplicationResult } from "@/model/ApplicationResult";
 import { ApplicationService } from "@/services/rest/ApplicationService";
 import { AlertService } from "@/services/AlertService";
+import ReferencesManagement from "@/components/application/ReferencesManagement.vue";
 
 @Component({
-  components: { PageView },
+  components: { PageView, ReferencesManagement },
 })
 export default class ApplicationDetailsView extends Vue {
   @Prop() applicationName;
 
   applicationService = ApplicationService.INSTANCE;
   alertService = AlertService.INSTANCE;
-  application = new Application();
+  application = new ApplicationResult();
 
   created() {
     this.init();
-- 
GitLab


From 9e8f114112f93984d93cd1cc69d7633d4c333823 Mon Sep 17 00:00:00 2001
From: Brendan Le Ny <bleny@codelutin.com>
Date: Tue, 8 Jun 2021 18:47:32 +0200
Subject: [PATCH 07/27] =?UTF-8?q?Compl=C3=A8te=20les=20informations=20reto?=
 =?UTF-8?q?urn=C3=A9es=20au=20front=20pour=20la=20description=20des=20r?=
 =?UTF-8?q?=C3=A9f=C3=A9rentiels=20d'une=20application?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../inra/oresing/rest/ApplicationResult.java  |  7 +++++
 .../fr/inra/oresing/rest/OreSiResources.java  | 27 ++++++++++++++++---
 2 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/src/main/java/fr/inra/oresing/rest/ApplicationResult.java b/src/main/java/fr/inra/oresing/rest/ApplicationResult.java
index 3f3af5e07..f3ee50860 100644
--- a/src/main/java/fr/inra/oresing/rest/ApplicationResult.java
+++ b/src/main/java/fr/inra/oresing/rest/ApplicationResult.java
@@ -3,6 +3,7 @@ package fr.inra.oresing.rest;
 import lombok.Value;
 
 import java.util.Map;
+import java.util.Set;
 
 @Value
 public class ApplicationResult {
@@ -13,11 +14,17 @@ public class ApplicationResult {
 
     @Value
     public static class Reference {
+        String id;
+        String label;
+        Set<String> children;
         Map<String, Column> columns;
 
         @Value
         public static class Column {
+            String id;
             String title;
+            boolean key;
+            String linkedTo;
         }
     }
 }
diff --git a/src/main/java/fr/inra/oresing/rest/OreSiResources.java b/src/main/java/fr/inra/oresing/rest/OreSiResources.java
index 82d5412be..34f625553 100644
--- a/src/main/java/fr/inra/oresing/rest/OreSiResources.java
+++ b/src/main/java/fr/inra/oresing/rest/OreSiResources.java
@@ -1,10 +1,15 @@
 package fr.inra.oresing.rest;
 
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Ordering;
+import com.google.common.collect.TreeMultimap;
 import fr.inra.oresing.checker.CheckerException;
 import fr.inra.oresing.model.Application;
 import fr.inra.oresing.model.BinaryFile;
+import fr.inra.oresing.model.Configuration;
 import fr.inra.oresing.model.ReferenceValue;
 import fr.inra.oresing.persistence.OreSiRepository;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -84,9 +89,25 @@ public class OreSiResources {
     @GetMapping(value = "/applications/{nameOrId}", produces = MediaType.APPLICATION_JSON_VALUE)
     public ResponseEntity<ApplicationResult> getApplication(@PathVariable("nameOrId") String nameOrId) {
         Application application = service.getApplication(nameOrId);
-        Map<String, ApplicationResult.Reference> references = Maps.transformValues(application.getConfiguration().getReferences(), referenceDescription -> {
-            Map<String, ApplicationResult.Reference.Column> columns = Maps.transformEntries(referenceDescription.getColumns(), (column, columnDescription) -> new ApplicationResult.Reference.Column(column));
-            return new ApplicationResult.Reference(columns);
+        TreeMultimap<String, String> childrenPerReferences = TreeMultimap.create();
+        application.getConfiguration().getCompositeReferences().values().forEach(compositeReferenceDescription -> {
+            ImmutableList<String> referenceTypes = compositeReferenceDescription.getComponents().stream()
+                    .map(Configuration.CompositeReferenceComponentDescription::getReference)
+                    .collect(ImmutableList.toImmutableList());
+            ImmutableSortedSet<String> sortedReferenceTypes = ImmutableSortedSet.copyOf(Ordering.explicit(referenceTypes), referenceTypes);
+            sortedReferenceTypes.forEach(reference -> {
+                String child = sortedReferenceTypes.higher(reference);
+                if (child == null) {
+                    // on est sur le dernier élément de la hiérarchie, pas de descendant
+                } else {
+                    childrenPerReferences.put(reference, child);
+                }
+            });
+        });
+        Map<String, ApplicationResult.Reference> references = Maps.transformEntries(application.getConfiguration().getReferences(), (reference, referenceDescription) -> {
+            Map<String, ApplicationResult.Reference.Column> columns = Maps.transformEntries(referenceDescription.getColumns(), (column, columnDescription) -> new ApplicationResult.Reference.Column(column, column, referenceDescription.getKeyColumns().contains(column), null));
+            Set<String> children = childrenPerReferences.get(reference);
+            return new ApplicationResult.Reference(reference, reference, children, columns);
         });
         ApplicationResult applicationResult = new ApplicationResult(application.getId().toString(), application.getName(), application.getConfiguration().getApplication().getName(), references);
         return ResponseEntity.ok(applicationResult);
-- 
GitLab


From 95e7bae48921c3957750d41daa9581cfae8b5d74 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Thu, 10 Jun 2021 18:14:49 +0200
Subject: [PATCH 08/27] =?UTF-8?q?Premier=20jet=20de=20reconstitution=20de?=
 =?UTF-8?q?=20hi=C3=A9rarchie?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../application/ReferencesManagement.vue      | 20 ++++++++---
 ui2/src/components/common/CollapsibleTree.vue | 15 +++++++++
 ui2/src/model/ApplicationResult.js            |  2 +-
 ui2/src/utils/ConversionUtils.js              | 33 +++++++++++++++++++
 .../application/ApplicationDetailsView.vue    |  5 ++-
 5 files changed, 67 insertions(+), 8 deletions(-)
 create mode 100644 ui2/src/components/common/CollapsibleTree.vue
 create mode 100644 ui2/src/utils/ConversionUtils.js

diff --git a/ui2/src/components/application/ReferencesManagement.vue b/ui2/src/components/application/ReferencesManagement.vue
index 8aca89c14..350a7252a 100644
--- a/ui2/src/components/application/ReferencesManagement.vue
+++ b/ui2/src/components/application/ReferencesManagement.vue
@@ -1,7 +1,12 @@
 <template>
   <div>
     <div>
-      <b-button @click="setOpenSite" :icon-left="openSite ? 'caret-up' : 'caret-down'" /> Site
+      <FontAwesomeIcon
+        @click="openSite = !openSite"
+        :icon="openSite ? 'caret-up' : 'caret-down'"
+        class="clickable"
+      />
+      Site
       <div v-if="openSite">Parcelle</div>
     </div>
     <div>Unités</div>
@@ -10,16 +15,23 @@
 
 <script>
 import { Component, Prop, Vue } from "vue-property-decorator";
+import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
+import { convertReferencesToTrees } from "@/utils/ConversionUtils";
+
 @Component({
-  components: {},
+  components: { FontAwesomeIcon },
 })
 export default class ReferencesManagement extends Vue {
   @Prop() application;
 
   openSite = false;
+  references = [];
 
-  setOpenSite() {
-    this.openSite = !this.openSite;
+  created() {
+    if (!this.application || !this.application.id) {
+      return;
+    }
+    this.references = convertReferencesToTrees(Object.values(this.application.references));
   }
 }
 </script>
diff --git a/ui2/src/components/common/CollapsibleTree.vue b/ui2/src/components/common/CollapsibleTree.vue
new file mode 100644
index 000000000..21d82ecde
--- /dev/null
+++ b/ui2/src/components/common/CollapsibleTree.vue
@@ -0,0 +1,15 @@
+<template>
+  <div></div>
+</template>
+
+<script>
+import { Component, Prop, Vue } from "vue-property-decorator";
+import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
+
+@Component({
+  components: { FontAwesomeIcon },
+})
+export default class CollapsibleTree extends Vue {
+  @Prop() application;
+}
+</script>
diff --git a/ui2/src/model/ApplicationResult.js b/ui2/src/model/ApplicationResult.js
index c6631f3e8..835c10792 100644
--- a/ui2/src/model/ApplicationResult.js
+++ b/ui2/src/model/ApplicationResult.js
@@ -9,7 +9,7 @@ export class ApplicationResult {
       children: [],
       columns: {
         id: "",
-        label: "",
+        title: "",
         key: false,
         linkedTo: "",
       },
diff --git a/ui2/src/utils/ConversionUtils.js b/ui2/src/utils/ConversionUtils.js
new file mode 100644
index 000000000..b0ec6a540
--- /dev/null
+++ b/ui2/src/utils/ConversionUtils.js
@@ -0,0 +1,33 @@
+export function convertReferencesToTrees(references) {
+  const array = references.filter((ref) => {
+    return !references.some(
+      (r) => r.children && r.children.length !== 0 && r.children.some((c) => c === ref.id)
+    );
+  });
+  return convert(array, references);
+}
+
+function convert(references, initialRef) {
+  references.forEach((ref) => {
+    if (ref.children && ref.children.length !== 0) {
+      const children = ref.children.map((c) => initialRef.find((r) => r.id === c));
+      ref.children = convert(children, initialRef);
+    } else {
+      return ref;
+      //   const parentIndex = initialRef.findIndex(
+      //     (r) => r.children && r.children.length !== 0 && r.children.some((c) => c === ref.id)
+      //   );
+      //   if (!parentIndex) {
+      //     return ref;
+      //   } else {
+      //     return (initialRef[parentIndex].children = initialRef[parentIndex].children.map((c) => {
+      //       if (c === ref.id) {
+      //         return ref;
+      //       }
+      //       return c;
+      //     }));
+      //   }
+    }
+  });
+  return references;
+}
diff --git a/ui2/src/views/application/ApplicationDetailsView.vue b/ui2/src/views/application/ApplicationDetailsView.vue
index ecad562f5..f72a35ac6 100644
--- a/ui2/src/views/application/ApplicationDetailsView.vue
+++ b/ui2/src/views/application/ApplicationDetailsView.vue
@@ -2,11 +2,10 @@
   <PageView>
     <h1 class="title main-title">{{ application.title }}</h1>
     <b-tabs type="is-boxed" expanded class="mt-4">
-      <b-tab-item :label="$t('applicationDetailsView.application')" icon="wrench"> </b-tab-item>
       <b-tab-item :label="$t('applicationDetailsView.references')" icon="drafting-compass">
-        <ReferencesManagement :application="application" />
+        <ReferencesManagement :application="application" :key="application.id" />
       </b-tab-item>
-      <b-tab-item :label="$t('applicationDetailsView.dataset')" icon="poll"> </b-tab-item>
+      <b-tab-item :label="$t('applicationDetailsView.dataset')" icon="poll">À venir</b-tab-item>
     </b-tabs>
   </PageView>
 </template>
-- 
GitLab


From 552603c4d8d894dcaa6c5ee1f81803e58b4d16fe Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Fri, 11 Jun 2021 10:23:42 +0200
Subject: [PATCH 09/27] =?UTF-8?q?Enl=C3=A8ve=20l'effet=20de=20bord=20modif?=
 =?UTF-8?q?iant=20les=20ref=20initiales?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ui2/src/utils/ConversionUtils.js | 30 +++++++++++-------------------
 1 file changed, 11 insertions(+), 19 deletions(-)

diff --git a/ui2/src/utils/ConversionUtils.js b/ui2/src/utils/ConversionUtils.js
index b0ec6a540..3e35a15cb 100644
--- a/ui2/src/utils/ConversionUtils.js
+++ b/ui2/src/utils/ConversionUtils.js
@@ -1,32 +1,24 @@
-export function convertReferencesToTrees(references) {
-  const array = references.filter((ref) => {
+export function convertReferencesToTrees(initialReference) {
+  const references = JSON.parse(JSON.stringify(initialReference));
+  const parents = references.filter((ref) => {
     return !references.some(
       (r) => r.children && r.children.length !== 0 && r.children.some((c) => c === ref.id)
     );
   });
-  return convert(array, references);
+  return replaceChildrenIdByObject(parents, references);
 }
 
-function convert(references, initialRef) {
+function replaceChildrenIdByObject(references, initialRef) {
   references.forEach((ref) => {
     if (ref.children && ref.children.length !== 0) {
-      const children = ref.children.map((c) => initialRef.find((r) => r.id === c));
-      ref.children = convert(children, initialRef);
+      const children = ref.children.map((c) => {
+        const index = initialRef.findIndex((r) => r.id === c);
+        const [child] = initialRef.splice(index, 1);
+        return child;
+      });
+      ref.children = replaceChildrenIdByObject(children, initialRef);
     } else {
       return ref;
-      //   const parentIndex = initialRef.findIndex(
-      //     (r) => r.children && r.children.length !== 0 && r.children.some((c) => c === ref.id)
-      //   );
-      //   if (!parentIndex) {
-      //     return ref;
-      //   } else {
-      //     return (initialRef[parentIndex].children = initialRef[parentIndex].children.map((c) => {
-      //       if (c === ref.id) {
-      //         return ref;
-      //       }
-      //       return c;
-      //     }));
-      //   }
     }
   });
   return references;
-- 
GitLab


From 6214a857fa50d7df67e4d5adbcc59966de8f0ba2 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Fri, 11 Jun 2021 11:16:52 +0200
Subject: [PATCH 10/27] =?UTF-8?q?Ajoute=20un=20arbre=20pour=20afficher=20l?=
 =?UTF-8?q?es=20r=C3=A9f=C3=A9rentiels?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../application/ReferencesManagement.vue      | 22 +++++++--------
 ui2/src/components/common/CollapsibleTree.vue | 27 +++++++++++++++++--
 2 files changed, 34 insertions(+), 15 deletions(-)

diff --git a/ui2/src/components/application/ReferencesManagement.vue b/ui2/src/components/application/ReferencesManagement.vue
index 350a7252a..d7b8a0fe8 100644
--- a/ui2/src/components/application/ReferencesManagement.vue
+++ b/ui2/src/components/application/ReferencesManagement.vue
@@ -1,30 +1,26 @@
 <template>
   <div>
-    <div>
-      <FontAwesomeIcon
-        @click="openSite = !openSite"
-        :icon="openSite ? 'caret-up' : 'caret-down'"
-        class="clickable"
-      />
-      Site
-      <div v-if="openSite">Parcelle</div>
-    </div>
-    <div>Unités</div>
+    <CollapsibleTree
+      v-for="ref in references"
+      :key="ref.id"
+      :label="ref.label"
+      :children="ref.children"
+      :level="0"
+    />
   </div>
 </template>
 
 <script>
 import { Component, Prop, Vue } from "vue-property-decorator";
-import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
 import { convertReferencesToTrees } from "@/utils/ConversionUtils";
+import CollapsibleTree from "@/components/common/CollapsibleTree.vue";
 
 @Component({
-  components: { FontAwesomeIcon },
+  components: { CollapsibleTree },
 })
 export default class ReferencesManagement extends Vue {
   @Prop() application;
 
-  openSite = false;
   references = [];
 
   created() {
diff --git a/ui2/src/components/common/CollapsibleTree.vue b/ui2/src/components/common/CollapsibleTree.vue
index 21d82ecde..1eee21da1 100644
--- a/ui2/src/components/common/CollapsibleTree.vue
+++ b/ui2/src/components/common/CollapsibleTree.vue
@@ -1,5 +1,24 @@
 <template>
-  <div></div>
+  <div>
+    <div>
+      <FontAwesomeIcon
+        v-if="children && children.length !== 0"
+        @click="displayChildren = !displayChildren"
+        :icon="displayChildren ? 'caret-up' : 'caret-down'"
+        class="clickable"
+      />
+      <div :style="`transform:translate(${level * 50}px);`">{{ label }}</div>
+    </div>
+    <div v-if="displayChildren">
+      <CollapsibleTree
+        v-for="child in children"
+        :key="child.id"
+        :label="child.label"
+        :children="child.children"
+        :level="level + 1"
+      />
+    </div>
+  </div>
 </template>
 
 <script>
@@ -10,6 +29,10 @@ import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
   components: { FontAwesomeIcon },
 })
 export default class CollapsibleTree extends Vue {
-  @Prop() application;
+  @Prop() label;
+  @Prop() children;
+  @Prop() level;
+
+  displayChildren = false;
 }
 </script>
-- 
GitLab


From c02ae5c01bcbeac2c252b62ace2d1e198492db94 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Fri, 11 Jun 2021 11:54:14 +0200
Subject: [PATCH 11/27] =?UTF-8?q?Ajoute=20du=20style=20=C3=A0=20l'arbre?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ui2/src/components/common/CollapsibleTree.vue | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/ui2/src/components/common/CollapsibleTree.vue b/ui2/src/components/common/CollapsibleTree.vue
index 1eee21da1..daba82da4 100644
--- a/ui2/src/components/common/CollapsibleTree.vue
+++ b/ui2/src/components/common/CollapsibleTree.vue
@@ -1,11 +1,16 @@
 <template>
   <div>
-    <div>
+    <div
+      :class="`CollapsibleTree-header ${
+        children && children.length !== 0 && displayChildren ? '' : 'mb-1'
+      }`"
+      :style="`background-color:rgba(240, 245, 245, ${1 - level / 2})`"
+    >
       <FontAwesomeIcon
         v-if="children && children.length !== 0"
         @click="displayChildren = !displayChildren"
         :icon="displayChildren ? 'caret-up' : 'caret-down'"
-        class="clickable"
+        class="clickable mr-3"
       />
       <div :style="`transform:translate(${level * 50}px);`">{{ label }}</div>
     </div>
@@ -36,3 +41,12 @@ export default class CollapsibleTree extends Vue {
   displayChildren = false;
 }
 </script>
+
+<style lang="scss" scoped>
+.CollapsibleTree-header {
+  display: flex;
+  align-items: center;
+  height: 40px;
+  padding: 0.75rem;
+}
+</style>
-- 
GitLab


From 723554f791e490482935ec0664654f97473a59d9 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Fri, 11 Jun 2021 12:25:27 +0200
Subject: [PATCH 12/27] =?UTF-8?q?Ajoute=20l'icone=20de=20t=C3=A9l=C3=A9cha?=
 =?UTF-8?q?rgement/?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../application/ReferencesManagement.vue      |  8 +++
 ui2/src/components/common/CollapsibleTree.vue | 70 ++++++++++++++++---
 2 files changed, 70 insertions(+), 8 deletions(-)

diff --git a/ui2/src/components/application/ReferencesManagement.vue b/ui2/src/components/application/ReferencesManagement.vue
index d7b8a0fe8..adc38810b 100644
--- a/ui2/src/components/application/ReferencesManagement.vue
+++ b/ui2/src/components/application/ReferencesManagement.vue
@@ -6,6 +6,8 @@
       :label="ref.label"
       :children="ref.children"
       :level="0"
+      :withDownload="true"
+      :onClickLabelCb="(event, label) => openRefDetails(event, label)"
     />
   </div>
 </template>
@@ -29,5 +31,11 @@ export default class ReferencesManagement extends Vue {
     }
     this.references = convertReferencesToTrees(Object.values(this.application.references));
   }
+
+  openRefDetails(event, label) {
+    event.stopPropagation();
+
+    console.log("OUVRIR DETAILS DE LA REF:", label);
+  }
 }
 </script>
diff --git a/ui2/src/components/common/CollapsibleTree.vue b/ui2/src/components/common/CollapsibleTree.vue
index daba82da4..a970dd44f 100644
--- a/ui2/src/components/common/CollapsibleTree.vue
+++ b/ui2/src/components/common/CollapsibleTree.vue
@@ -1,18 +1,36 @@
 <template>
   <div>
     <div
-      :class="`CollapsibleTree-header ${
+      :class="`CollapsibleTree-header ${children && children.length !== 0 ? 'clickable' : ''} ${
         children && children.length !== 0 && displayChildren ? '' : 'mb-1'
       }`"
       :style="`background-color:rgba(240, 245, 245, ${1 - level / 2})`"
+      @click="displayChildren = !displayChildren"
     >
-      <FontAwesomeIcon
-        v-if="children && children.length !== 0"
-        @click="displayChildren = !displayChildren"
-        :icon="displayChildren ? 'caret-up' : 'caret-down'"
-        class="clickable mr-3"
-      />
-      <div :style="`transform:translate(${level * 50}px);`">{{ label }}</div>
+      <div class="CollapsibleTree-header-infos">
+        <FontAwesomeIcon
+          v-if="children && children.length !== 0"
+          :icon="displayChildren ? 'caret-up' : 'caret-down'"
+          class="clickable mr-3"
+        />
+        <div
+          class="clickable CollapsibleTree-header-label"
+          :style="`transform:translate(${level * 50}px);`"
+          @click="(event) => onClickLabelCb(event, label)"
+        >
+          {{ label }}
+        </div>
+      </div>
+      <b-field class="file is-primary" v-if="withDownload">
+        <b-upload v-model="refFile" class="file-label" accept=".csv">
+          <span class="file-name" v-if="refFile">
+            {{ refFile.name }}
+          </span>
+          <span class="file-cta">
+            <b-icon class="file-icon" icon="upload"></b-icon>
+          </span>
+        </b-upload>
+      </b-field>
     </div>
     <div v-if="displayChildren">
       <CollapsibleTree
@@ -21,6 +39,8 @@
         :label="child.label"
         :children="child.children"
         :level="level + 1"
+        :withDownload="withDownload"
+        :onClickLabelCb="onClickLabelCb"
       />
     </div>
   </div>
@@ -37,8 +57,11 @@ export default class CollapsibleTree extends Vue {
   @Prop() label;
   @Prop() children;
   @Prop() level;
+  @Prop() withDownload;
+  @Prop() onClickLabelCb;
 
   displayChildren = false;
+  refFile = null;
 }
 </script>
 
@@ -48,5 +71,36 @@ export default class CollapsibleTree extends Vue {
   align-items: center;
   height: 40px;
   padding: 0.75rem;
+  justify-content: space-between;
+
+  .file-icon {
+    margin-right: 0;
+  }
+
+  .file-name {
+    border-top-style: none;
+    border-right-style: none;
+    border-bottom-style: none;
+    border-left-width: 2px;
+    border-radius: 0px;
+    opacity: 0.8;
+    background-color: rgba(250, 250, 250, 1);
+
+    &:hover {
+      opacity: 1;
+    }
+  }
+}
+
+.CollapsibleTree-header-infos {
+  display: flex;
+  align-items: center;
+}
+
+.CollapsibleTree-header-label {
+  &:hover {
+    color: $primary;
+    text-decoration: underline;
+  }
 }
 </style>
-- 
GitLab


From 454d75f82066cda99f4b4f862943ed65f71e25c5 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Mon, 14 Jun 2021 17:41:24 +0200
Subject: [PATCH 13/27] =?UTF-8?q?Cr=C3=A9e=20un=20panneau=20lat=C3=A9ral?=
 =?UTF-8?q?=20g=C3=A9n=C3=A9rique.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../application/ReferencesManagement.vue      | 15 +++-
 ui2/src/components/common/SidePanel.vue       | 72 +++++++++++++++++++
 ui2/src/main.js                               |  4 +-
 ui2/src/style/_common.scss                    |  2 +-
 ui2/src/style/_variables.scss                 | 12 ++--
 .../application/ApplicationDetailsView.vue    | 10 ++-
 ui2/src/views/common/PageView.vue             |  5 +-
 7 files changed, 107 insertions(+), 13 deletions(-)
 create mode 100644 ui2/src/components/common/SidePanel.vue

diff --git a/ui2/src/components/application/ReferencesManagement.vue b/ui2/src/components/application/ReferencesManagement.vue
index adc38810b..d566eb6b2 100644
--- a/ui2/src/components/application/ReferencesManagement.vue
+++ b/ui2/src/components/application/ReferencesManagement.vue
@@ -9,6 +9,12 @@
       :withDownload="true"
       :onClickLabelCb="(event, label) => openRefDetails(event, label)"
     />
+    <SidePanel
+      :leftAlign="true"
+      :open="openPanel"
+      :title="chosenRef && chosenRef.label"
+      @openStateChanged="(newVal) => (openPanel = newVal)"
+    />
   </div>
 </template>
 
@@ -16,14 +22,17 @@
 import { Component, Prop, Vue } from "vue-property-decorator";
 import { convertReferencesToTrees } from "@/utils/ConversionUtils";
 import CollapsibleTree from "@/components/common/CollapsibleTree.vue";
+import SidePanel from "../common/SidePanel.vue";
 
 @Component({
-  components: { CollapsibleTree },
+  components: { CollapsibleTree, SidePanel },
 })
 export default class ReferencesManagement extends Vue {
   @Prop() application;
 
   references = [];
+  openPanel = false;
+  chosenRef = null;
 
   created() {
     if (!this.application || !this.application.id) {
@@ -34,8 +43,8 @@ export default class ReferencesManagement extends Vue {
 
   openRefDetails(event, label) {
     event.stopPropagation();
-
-    console.log("OUVRIR DETAILS DE LA REF:", label);
+    this.openPanel = this.chosenRef && this.chosenRef.label === label ? !this.openPanel : true;
+    this.chosenRef = Object.values(this.application.references).find((ref) => ref.label === label);
   }
 }
 </script>
diff --git a/ui2/src/components/common/SidePanel.vue b/ui2/src/components/common/SidePanel.vue
new file mode 100644
index 000000000..af99ccbb7
--- /dev/null
+++ b/ui2/src/components/common/SidePanel.vue
@@ -0,0 +1,72 @@
+<template>
+  <div :class="`SidePanel ${leftAlign ? 'left-align' : 'right-align'} ${innerOpen ? 'open' : ''}`">
+    <h1 class="title main-title">{{ title }}</h1>
+    <b-button class="SidePanel-close-button" icon-left="times" @click="innerOpen = false" />
+    <slot></slot>
+  </div>
+</template>
+
+<script>
+import { Component, Prop, Vue, Watch } from "vue-property-decorator";
+import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
+
+@Component({
+  components: { FontAwesomeIcon },
+})
+export default class SidePanel extends Vue {
+  @Prop({ default: false }) leftAlign;
+  @Prop({ default: false }) open;
+  @Prop({ default: "" }) title;
+
+  innerOpen = false;
+
+  created() {
+    this.innerOpen = this.open;
+  }
+
+  @Watch("open")
+  onExternalOpenStateChanged(newVal) {
+    this.innerOpen = newVal;
+  }
+
+  @Watch("innerOpen")
+  onInnerOpenStateChanged(newVal) {
+    this.$emit("openStateChanged", newVal);
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.SidePanel {
+  background-color: $light;
+  z-index: 1;
+  position: absolute;
+  height: 100%;
+  top: 0;
+  width: 33%;
+  padding: $container-padding-vert 2.5rem;
+  transition: transform 250ms;
+
+  &.right-align {
+    right: 0;
+    transform: translateX(100%);
+    &.open {
+      transform: translateX(0);
+    }
+  }
+
+  &.left-align {
+    left: 0;
+    transform: translateX(-100%);
+    &.open {
+      transform: translateX(0);
+    }
+  }
+}
+
+.SidePanel-close-button {
+  position: absolute;
+  top: 0;
+  right: 0;
+}
+</style>
diff --git a/ui2/src/main.js b/ui2/src/main.js
index 185e8ed69..0e0737266 100644
--- a/ui2/src/main.js
+++ b/ui2/src/main.js
@@ -20,6 +20,7 @@ import {
   faPlus,
   faPoll,
   faSignOutAlt,
+  faTimes,
   faUpload,
   faWrench,
 } from "@fortawesome/free-solid-svg-icons";
@@ -41,7 +42,8 @@ library.add(
   faPoll,
   faDraftingCompass,
   faCaretUp,
-  faCaretDown
+  faCaretDown,
+  faTimes
 );
 Vue.component("vue-fontawesome", FontAwesomeIcon);
 
diff --git a/ui2/src/style/_common.scss b/ui2/src/style/_common.scss
index e9eaf9c75..883a76358 100644
--- a/ui2/src/style/_common.scss
+++ b/ui2/src/style/_common.scss
@@ -6,7 +6,7 @@ body {
 
 .title {
   color: $primary;
-  margin-top: 1.5rem;
+  margin-top: $title-margin-top;
 
   &.main-title {
     display: flex;
diff --git a/ui2/src/style/_variables.scss b/ui2/src/style/_variables.scss
index 4b6281368..9004cb4bd 100644
--- a/ui2/src/style/_variables.scss
+++ b/ui2/src/style/_variables.scss
@@ -6,9 +6,11 @@ $font-family: "LiberationSans", Helvetica, Arial, sans-serif;
 
 $text-default-color: #2c3e50;
 $light-text: rgb(230, 230, 230);
-// InputWithValidation
-$input-field-margin-bot: 1rem;
-$input-help-margin-top: 0.25rem;
+
+// PageView
+$container-padding-hor: 3rem;
+$container-padding-vert: $container-padding-hor / 2;
+$title-margin-top: 1.5rem;
 
 // MenuView
 $menu-height: 80px;
@@ -19,11 +21,11 @@ $menu-height: 80px;
 ***************************************************************************************************/
 
 // General variables
-$primary: rgb(0,163,166);
+$primary: rgb(0, 163, 166);
 $info: #4ec6c2;
 $success: #bade81;
 $warning: #ffec60;
 $danger: #d13a18;
 $dark: #4b6464;
-$light: #aab7b7;
+$light: rgb(202, 216, 216);
 $family-primary: $font-family;
diff --git a/ui2/src/views/application/ApplicationDetailsView.vue b/ui2/src/views/application/ApplicationDetailsView.vue
index f72a35ac6..ecd584089 100644
--- a/ui2/src/views/application/ApplicationDetailsView.vue
+++ b/ui2/src/views/application/ApplicationDetailsView.vue
@@ -1,7 +1,7 @@
 <template>
   <PageView>
     <h1 class="title main-title">{{ application.title }}</h1>
-    <b-tabs type="is-boxed" expanded class="mt-4">
+    <b-tabs type="is-boxed" expanded class="mt-4 ApplicationDetailsView-tabs">
       <b-tab-item :label="$t('applicationDetailsView.references')" icon="drafting-compass">
         <ReferencesManagement :application="application" :key="application.id" />
       </b-tab-item>
@@ -41,3 +41,11 @@ export default class ApplicationDetailsView extends Vue {
   }
 }
 </script>
+
+<style lang="scss">
+.ApplicationDetailsView-tabs.b-tabs {
+  .tab-content {
+    position: initial;
+  }
+}
+</style>
diff --git a/ui2/src/views/common/PageView.vue b/ui2/src/views/common/PageView.vue
index 9c0f0edfc..57154602c 100644
--- a/ui2/src/views/common/PageView.vue
+++ b/ui2/src/views/common/PageView.vue
@@ -1,7 +1,7 @@
 <template>
   <div class="PageView">
     <MenuView v-if="hasMenu" />
-    <div :class="`container PageView-container ${hasMenu ? '' : 'noMenu'}`">
+    <div :class="`PageView-container ${hasMenu ? '' : 'noMenu'}`">
       <slot></slot>
     </div>
   </div>
@@ -37,7 +37,8 @@ export default class PageView extends Vue {
 .PageView-container {
   width: 100%;
   height: calc(100% - #{$menu-height});
-  padding-top: 1.5rem;
+  padding: $container-padding-vert $container-padding-hor;
+  position: relative;
 
   &.noMenu {
     height: 100%;
-- 
GitLab


From 3c36b50c45bb567f8e4a4a6f489ede4a657d66bd Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Mon, 14 Jun 2021 18:49:50 +0200
Subject: [PATCH 14/27] =?UTF-8?q?Cr=C3=A9e=20un=20panneau=20sp=C3=A9cifiqu?=
 =?UTF-8?q?e=20pour=20les=20r=C3=A9f=C3=A9rentiels.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../application/ReferencesDetailsPanel.vue    | 55 +++++++++++++++++++
 .../application/ReferencesManagement.vue      | 10 ++--
 ui2/src/components/common/SidePanel.vue       |  3 +-
 ui2/src/locales/en.json                       | 11 +++-
 ui2/src/locales/fr.json                       | 11 +++-
 ui2/src/main.js                               |  6 +-
 ui2/src/services/AlertService.js              | 16 +++++-
 .../application/ApplicationDetailsView.vue    |  2 +-
 8 files changed, 102 insertions(+), 12 deletions(-)
 create mode 100644 ui2/src/components/application/ReferencesDetailsPanel.vue

diff --git a/ui2/src/components/application/ReferencesDetailsPanel.vue b/ui2/src/components/application/ReferencesDetailsPanel.vue
new file mode 100644
index 000000000..c9ac774d1
--- /dev/null
+++ b/ui2/src/components/application/ReferencesDetailsPanel.vue
@@ -0,0 +1,55 @@
+<template>
+  <SidePanel :open="open" :leftAlign="leftAlign" :title="reference && reference.label">
+    <div class="Panel-buttons">
+      <b-button type="is-primary" icon-left="eye">{{
+        $t("referencesManagement.consult")
+      }}</b-button>
+      <b-button icon-left="download">{{ $t("referencesManagement.download") }}</b-button>
+      <b-button type="is-danger" icon-left="trash-alt" @click="askDeletionConfirmation">{{
+        $t("referencesManagement.delete")
+      }}</b-button>
+    </div>
+  </SidePanel>
+</template>
+
+<script>
+import { AlertService } from "@/services/AlertService";
+import { Component, Prop, Vue } from "vue-property-decorator";
+import SidePanel from "../common/SidePanel.vue";
+
+@Component({
+  components: { SidePanel },
+})
+export default class ReferencesDetailsPanel extends Vue {
+  @Prop({ default: false }) leftAlign;
+  @Prop({ default: false }) open;
+  @Prop() reference;
+
+  alertService = AlertService.INSTANCE;
+
+  askDeletionConfirmation() {
+    this.alertService.dialog(
+      this.$t("alert.warning"),
+      this.$t("alert.reference-deletion-msg", { label: this.reference.label }),
+      this.$t("alert.delete"),
+      "is-danger",
+      () => this.deleteReference()
+    );
+  }
+
+  deleteReference() {
+    console.log("DELETE", this.reference);
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.Panel-buttons {
+  display: flex;
+  flex-direction: column;
+
+  .button {
+    margin-bottom: 0.5rem;
+  }
+}
+</style>
diff --git a/ui2/src/components/application/ReferencesManagement.vue b/ui2/src/components/application/ReferencesManagement.vue
index d566eb6b2..55408d6ea 100644
--- a/ui2/src/components/application/ReferencesManagement.vue
+++ b/ui2/src/components/application/ReferencesManagement.vue
@@ -9,10 +9,10 @@
       :withDownload="true"
       :onClickLabelCb="(event, label) => openRefDetails(event, label)"
     />
-    <SidePanel
-      :leftAlign="true"
+    <ReferencesDetailsPanel
+      :leftAlign="false"
       :open="openPanel"
-      :title="chosenRef && chosenRef.label"
+      :reference="chosenRef"
       @openStateChanged="(newVal) => (openPanel = newVal)"
     />
   </div>
@@ -22,10 +22,10 @@
 import { Component, Prop, Vue } from "vue-property-decorator";
 import { convertReferencesToTrees } from "@/utils/ConversionUtils";
 import CollapsibleTree from "@/components/common/CollapsibleTree.vue";
-import SidePanel from "../common/SidePanel.vue";
+import ReferencesDetailsPanel from "./ReferencesDetailsPanel.vue";
 
 @Component({
-  components: { CollapsibleTree, SidePanel },
+  components: { CollapsibleTree, ReferencesDetailsPanel },
 })
 export default class ReferencesManagement extends Vue {
   @Prop() application;
diff --git a/ui2/src/components/common/SidePanel.vue b/ui2/src/components/common/SidePanel.vue
index af99ccbb7..3acb689dd 100644
--- a/ui2/src/components/common/SidePanel.vue
+++ b/ui2/src/components/common/SidePanel.vue
@@ -8,10 +8,9 @@
 
 <script>
 import { Component, Prop, Vue, Watch } from "vue-property-decorator";
-import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
 
 @Component({
-  components: { FontAwesomeIcon },
+  components: {},
 })
 export default class SidePanel extends Vue {
   @Prop({ default: false }) leftAlign;
diff --git a/ui2/src/locales/en.json b/ui2/src/locales/en.json
index a0571752e..a479236f0 100644
--- a/ui2/src/locales/en.json
+++ b/ui2/src/locales/en.json
@@ -25,7 +25,10 @@
     "cancel": "Cancel",
     "server-error": "A server error occured",
     "user-unknown": "Unknown user",
-    "application-creation-success": "L'application a été créée !"
+    "application-creation-success": "L'application a été créée !",
+    "warning": "Warning !",
+    "reference-deletion-msg": "You're about to delete the reference : {label}. Are you sure ?",
+    "delete": "Delete"
   },
   "message": {
     "app-config-error": "Error in yaml file",
@@ -71,5 +74,11 @@
     "application": "Application details",
     "references": "References",
     "dataset": "Datasets"
+  },
+  "referencesManagement": {
+    "actions": "Actions",
+    "consult": "Consult",
+    "download": "Download",
+    "delete": "Delete"
   }
 }
diff --git a/ui2/src/locales/fr.json b/ui2/src/locales/fr.json
index 627ba74bc..576fa9809 100644
--- a/ui2/src/locales/fr.json
+++ b/ui2/src/locales/fr.json
@@ -25,7 +25,10 @@
     "cancel": "Annuler",
     "server-error": "Une erreur serveur est survenue",
     "user-unknown": "Identifiants inconnus",
-    "application-creation-success": "L'application a été créée !"
+    "application-creation-success": "L'application a été créée !",
+    "warning": "Attention !",
+    "reference-deletion-msg": "Vous allez supprimer le référentiel : {label}. Êtes-vous sûr ?",
+    "delete": "Supprimer"
   },
   "message": {
     "app-config-error": "Erreur dans le fichier yaml",
@@ -71,5 +74,11 @@
     "application": "Détail de l'application",
     "references": "Référentiels",
     "dataset": "Données"
+  },
+  "referencesManagement": {
+    "actions": "Actions",
+    "consult": "Consulter",
+    "download": "Télécharger",
+    "delete": "Supprimer"
   }
 }
diff --git a/ui2/src/main.js b/ui2/src/main.js
index 0e0737266..d96d4e015 100644
--- a/ui2/src/main.js
+++ b/ui2/src/main.js
@@ -12,6 +12,7 @@ import {
   faCaretDown,
   faCaretUp,
   faCheck,
+  faDownload,
   faDraftingCompass,
   faExclamationCircle,
   faEye,
@@ -21,6 +22,7 @@ import {
   faPoll,
   faSignOutAlt,
   faTimes,
+  faTrashAlt,
   faUpload,
   faWrench,
 } from "@fortawesome/free-solid-svg-icons";
@@ -43,7 +45,9 @@ library.add(
   faDraftingCompass,
   faCaretUp,
   faCaretDown,
-  faTimes
+  faTimes,
+  faTrashAlt,
+  faDownload
 );
 Vue.component("vue-fontawesome", FontAwesomeIcon);
 
diff --git a/ui2/src/services/AlertService.js b/ui2/src/services/AlertService.js
index be93def85..9064f6b9e 100644
--- a/ui2/src/services/AlertService.js
+++ b/ui2/src/services/AlertService.js
@@ -1,6 +1,6 @@
 import { i18n } from "@/main";
 import { BuefyTypes } from "@/utils/BuefyUtils";
-import { ToastProgrammatic } from "buefy";
+import { ToastProgrammatic, DialogProgrammatic } from "buefy";
 
 const TOAST_INFO_DURATION = 3000;
 const TOAST_ERROR_DURATION = 8000;
@@ -44,4 +44,18 @@ export class AlertService {
   toastServerError(error) {
     this.toastError(i18n.t("alert.server-error"), error);
   }
+
+  dialog(title, message, confirmText, type, onConfirmCb) {
+    DialogProgrammatic.confirm({
+      title: title,
+      message: message,
+      confirmText: confirmText,
+      type: type,
+      hasIcon: true,
+      cancelText: this.cancelMsg,
+      onConfirm: () => {
+        onConfirmCb();
+      },
+    });
+  }
 }
diff --git a/ui2/src/views/application/ApplicationDetailsView.vue b/ui2/src/views/application/ApplicationDetailsView.vue
index ecd584089..1e94385cd 100644
--- a/ui2/src/views/application/ApplicationDetailsView.vue
+++ b/ui2/src/views/application/ApplicationDetailsView.vue
@@ -1,7 +1,7 @@
 <template>
   <PageView>
     <h1 class="title main-title">{{ application.title }}</h1>
-    <b-tabs type="is-boxed" expanded class="mt-4 ApplicationDetailsView-tabs">
+    <b-tabs type="is-boxed" expanded class="mt-4 ApplicationDetailsView-tabs" :animated="false">
       <b-tab-item :label="$t('applicationDetailsView.references')" icon="drafting-compass">
         <ReferencesManagement :application="application" :key="application.id" />
       </b-tab-item>
-- 
GitLab


From e68cd601d5fb349425245a4c0fcb7508f151e6bd Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Tue, 15 Jun 2021 11:49:48 +0200
Subject: [PATCH 15/27] Donne un cb de fermeture au SidePanel

---
 ui2/src/components/application/ReferencesDetailsPanel.vue | 8 +++++++-
 ui2/src/components/application/ReferencesManagement.vue   | 2 +-
 ui2/src/components/common/SidePanel.vue                   | 3 ++-
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/ui2/src/components/application/ReferencesDetailsPanel.vue b/ui2/src/components/application/ReferencesDetailsPanel.vue
index c9ac774d1..7b017a863 100644
--- a/ui2/src/components/application/ReferencesDetailsPanel.vue
+++ b/ui2/src/components/application/ReferencesDetailsPanel.vue
@@ -1,5 +1,10 @@
 <template>
-  <SidePanel :open="open" :leftAlign="leftAlign" :title="reference && reference.label">
+  <SidePanel
+    :open="open"
+    :leftAlign="leftAlign"
+    :title="reference && reference.label"
+    :closeCb="closeCb"
+  >
     <div class="Panel-buttons">
       <b-button type="is-primary" icon-left="eye">{{
         $t("referencesManagement.consult")
@@ -24,6 +29,7 @@ export default class ReferencesDetailsPanel extends Vue {
   @Prop({ default: false }) leftAlign;
   @Prop({ default: false }) open;
   @Prop() reference;
+  @Prop() closeCb;
 
   alertService = AlertService.INSTANCE;
 
diff --git a/ui2/src/components/application/ReferencesManagement.vue b/ui2/src/components/application/ReferencesManagement.vue
index 55408d6ea..9dd3cfe16 100644
--- a/ui2/src/components/application/ReferencesManagement.vue
+++ b/ui2/src/components/application/ReferencesManagement.vue
@@ -13,7 +13,7 @@
       :leftAlign="false"
       :open="openPanel"
       :reference="chosenRef"
-      @openStateChanged="(newVal) => (openPanel = newVal)"
+      :closeCb="(newVal) => (openPanel = newVal)"
     />
   </div>
 </template>
diff --git a/ui2/src/components/common/SidePanel.vue b/ui2/src/components/common/SidePanel.vue
index 3acb689dd..ff6565ff9 100644
--- a/ui2/src/components/common/SidePanel.vue
+++ b/ui2/src/components/common/SidePanel.vue
@@ -16,6 +16,7 @@ export default class SidePanel extends Vue {
   @Prop({ default: false }) leftAlign;
   @Prop({ default: false }) open;
   @Prop({ default: "" }) title;
+  @Prop() closeCb;
 
   innerOpen = false;
 
@@ -30,7 +31,7 @@ export default class SidePanel extends Vue {
 
   @Watch("innerOpen")
   onInnerOpenStateChanged(newVal) {
-    this.$emit("openStateChanged", newVal);
+    this.closeCb(newVal);
   }
 }
 </script>
-- 
GitLab


From de5b83754be107bcf83a63f2f7aa4fe429d1fec3 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Tue, 15 Jun 2021 15:00:40 +0200
Subject: [PATCH 16/27] =?UTF-8?q?Met=20=C3=A0=20jour=20la=20route=20en=20f?=
 =?UTF-8?q?onction=20de=20l'index=20de=20tab?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ui2/src/router/index.js                       |  2 +-
 .../application/ApplicationDetailsView.vue    | 27 +++++++++++++++++--
 .../views/application/ApplicationsView.vue    |  2 +-
 3 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/ui2/src/router/index.js b/ui2/src/router/index.js
index 41b14e4e9..d2e25baf8 100644
--- a/ui2/src/router/index.js
+++ b/ui2/src/router/index.js
@@ -28,7 +28,7 @@ const routes = [
     component: ApplicationCreationView,
   },
   {
-    path: "/application/:applicationName",
+    path: "/application/:applicationName/:tabIndex",
     name: "Application view",
     component: ApplicationDetailsView,
     props: true,
diff --git a/ui2/src/views/application/ApplicationDetailsView.vue b/ui2/src/views/application/ApplicationDetailsView.vue
index 1e94385cd..1783e4e29 100644
--- a/ui2/src/views/application/ApplicationDetailsView.vue
+++ b/ui2/src/views/application/ApplicationDetailsView.vue
@@ -1,7 +1,14 @@
 <template>
   <PageView>
     <h1 class="title main-title">{{ application.title }}</h1>
-    <b-tabs type="is-boxed" expanded class="mt-4 ApplicationDetailsView-tabs" :animated="false">
+    <b-tabs
+      v-model="currentTabIndex"
+      type="is-boxed"
+      expanded
+      class="mt-4 ApplicationDetailsView-tabs"
+      :animated="false"
+      @input="onTabSelection"
+    >
       <b-tab-item :label="$t('applicationDetailsView.references')" icon="drafting-compass">
         <ReferencesManagement :application="application" :key="application.id" />
       </b-tab-item>
@@ -11,7 +18,7 @@
 </template>
 
 <script>
-import { Component, Prop, Vue } from "vue-property-decorator";
+import { Component, Prop, Vue, Watch } from "vue-property-decorator";
 import PageView from "@/views/common/PageView.vue";
 import { ApplicationResult } from "@/model/ApplicationResult";
 import { ApplicationService } from "@/services/rest/ApplicationService";
@@ -23,12 +30,16 @@ import ReferencesManagement from "@/components/application/ReferencesManagement.
 })
 export default class ApplicationDetailsView extends Vue {
   @Prop() applicationName;
+  @Prop() tabIndex;
 
   applicationService = ApplicationService.INSTANCE;
   alertService = AlertService.INSTANCE;
   application = new ApplicationResult();
 
+  currentTabIndex = 0;
+
   created() {
+    this.currentTabIndex = parseInt(this.tabIndex);
     this.init();
   }
 
@@ -39,6 +50,18 @@ export default class ApplicationDetailsView extends Vue {
       this.alertService.toastServerError();
     }
   }
+
+  @Watch("tabIndex")
+  onExternalTabIndexChanged(newVal) {
+    this.currentTabIndex = parseInt(newVal);
+  }
+
+  onTabSelection() {
+    const params = this.$router.currentRoute.params;
+    if (this.currentTabIndex.toString() !== params["tabIndex"]) {
+      this.$router.push({ params: { tabIndex: this.currentTabIndex } });
+    }
+  }
 }
 </script>
 
diff --git a/ui2/src/views/application/ApplicationsView.vue b/ui2/src/views/application/ApplicationsView.vue
index cd7be17c3..d0c318fda 100644
--- a/ui2/src/views/application/ApplicationsView.vue
+++ b/ui2/src/views/application/ApplicationsView.vue
@@ -70,7 +70,7 @@ export default class ApplicationsView extends Vue {
     if (!application) {
       return;
     }
-    this.$router.push("/application/" + application.name);
+    this.$router.push("/application/" + application.name + "/0");
   }
 }
 </script>
-- 
GitLab


From f5866d61d040c337e0d6c00f2131dab44ec923ba Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Tue, 15 Jun 2021 16:11:52 +0200
Subject: [PATCH 17/27] Supprime les onglets pr affichage des applications

---
 .../application/ReferencesManagement.vue      | 50 -------------
 .../ReferencesDetailsPanel.vue                |  0
 ui2/src/locales/en.json                       |  9 +--
 ui2/src/locales/fr.json                       |  9 +--
 ui2/src/router/index.js                       |  8 +-
 .../application/ApplicationDetailsView.vue    | 74 -------------------
 .../views/application/ApplicationsView.vue    | 25 +++----
 .../references/ReferencesManagementView.vue   | 69 +++++++++++++++++
 8 files changed, 89 insertions(+), 155 deletions(-)
 delete mode 100644 ui2/src/components/application/ReferencesManagement.vue
 rename ui2/src/components/{application => references}/ReferencesDetailsPanel.vue (100%)
 delete mode 100644 ui2/src/views/application/ApplicationDetailsView.vue
 create mode 100644 ui2/src/views/references/ReferencesManagementView.vue

diff --git a/ui2/src/components/application/ReferencesManagement.vue b/ui2/src/components/application/ReferencesManagement.vue
deleted file mode 100644
index 9dd3cfe16..000000000
--- a/ui2/src/components/application/ReferencesManagement.vue
+++ /dev/null
@@ -1,50 +0,0 @@
-<template>
-  <div>
-    <CollapsibleTree
-      v-for="ref in references"
-      :key="ref.id"
-      :label="ref.label"
-      :children="ref.children"
-      :level="0"
-      :withDownload="true"
-      :onClickLabelCb="(event, label) => openRefDetails(event, label)"
-    />
-    <ReferencesDetailsPanel
-      :leftAlign="false"
-      :open="openPanel"
-      :reference="chosenRef"
-      :closeCb="(newVal) => (openPanel = newVal)"
-    />
-  </div>
-</template>
-
-<script>
-import { Component, Prop, Vue } from "vue-property-decorator";
-import { convertReferencesToTrees } from "@/utils/ConversionUtils";
-import CollapsibleTree from "@/components/common/CollapsibleTree.vue";
-import ReferencesDetailsPanel from "./ReferencesDetailsPanel.vue";
-
-@Component({
-  components: { CollapsibleTree, ReferencesDetailsPanel },
-})
-export default class ReferencesManagement extends Vue {
-  @Prop() application;
-
-  references = [];
-  openPanel = false;
-  chosenRef = null;
-
-  created() {
-    if (!this.application || !this.application.id) {
-      return;
-    }
-    this.references = convertReferencesToTrees(Object.values(this.application.references));
-  }
-
-  openRefDetails(event, label) {
-    event.stopPropagation();
-    this.openPanel = this.chosenRef && this.chosenRef.label === label ? !this.openPanel : true;
-    this.chosenRef = Object.values(this.application.references).find((ref) => ref.label === label);
-  }
-}
-</script>
diff --git a/ui2/src/components/application/ReferencesDetailsPanel.vue b/ui2/src/components/references/ReferencesDetailsPanel.vue
similarity index 100%
rename from ui2/src/components/application/ReferencesDetailsPanel.vue
rename to ui2/src/components/references/ReferencesDetailsPanel.vue
diff --git a/ui2/src/locales/en.json b/ui2/src/locales/en.json
index a479236f0..694ec9da0 100644
--- a/ui2/src/locales/en.json
+++ b/ui2/src/locales/en.json
@@ -46,7 +46,9 @@
     "create": "Create application",
     "name": "Application name",
     "name-placeholder": "Write down the application name",
-    "creation-date": "Creation date"
+    "creation-date": "Creation date",
+    "actions": "Actions",
+    "references": "References"
   },
   "errors": {
     "emptyFile": "File is empty",
@@ -70,11 +72,6 @@
     "csvBoundToUnknownVariable": "In the CSV format, header <code>{header}</code> is bound to unknown variable <code>{variable}</code>. Known variables: <code>{variables}</code>",
     "csvBoundToUnknownVariableComponent": "In the CSV format, header <code>{header}</code> is bound to <code>{variable}</code> but it has no <code>{component}</code> component. Known components: <code>{components}</code>"
   },
-  "applicationDetailsView": {
-    "application": "Application details",
-    "references": "References",
-    "dataset": "Datasets"
-  },
   "referencesManagement": {
     "actions": "Actions",
     "consult": "Consult",
diff --git a/ui2/src/locales/fr.json b/ui2/src/locales/fr.json
index 576fa9809..524122a40 100644
--- a/ui2/src/locales/fr.json
+++ b/ui2/src/locales/fr.json
@@ -46,7 +46,9 @@
     "create": "Créer l'application",
     "name": "Nom de l'application",
     "name-placeholder": "Entrer le nom de l'application",
-    "creation-date": "Date de création"
+    "creation-date": "Date de création",
+    "actions": "Actions",
+    "references": "Référentiels"
   },
   "errors": {
     "emptyFile": "Le fichier est vide",
@@ -70,11 +72,6 @@
     "csvBoundToUnknownVariable": "Dans le format CSV, l’entête <code>{header}</code> est lié à la variable <code>{variable}</code> qui n'est pas connue. Variables connues <code>{variables}</code>",
     "csvBoundToUnknownVariableComponent": "Dans le format CSV, l’entête <code>{header}</code> est lié à la variable <code>{variable}</code> mais elle n'a pas de composant <code>{component}</code>. <br>Composants connus <code>{components}</code>"
   },
-  "applicationDetailsView": {
-    "application": "Détail de l'application",
-    "references": "Référentiels",
-    "dataset": "Données"
-  },
   "referencesManagement": {
     "actions": "Actions",
     "consult": "Consulter",
diff --git a/ui2/src/router/index.js b/ui2/src/router/index.js
index d2e25baf8..e143fae3e 100644
--- a/ui2/src/router/index.js
+++ b/ui2/src/router/index.js
@@ -3,7 +3,7 @@ import VueRouter from "vue-router";
 import LoginView from "@/views/LoginView.vue";
 import ApplicationsView from "@/views/application/ApplicationsView.vue";
 import ApplicationCreationView from "@/views/application/ApplicationCreationView.vue";
-import ApplicationDetailsView from "@/views/application/ApplicationDetailsView.vue";
+import ReferencesManagementView from "@/views/references/ReferencesManagementView.vue";
 
 Vue.use(VueRouter);
 
@@ -28,9 +28,9 @@ const routes = [
     component: ApplicationCreationView,
   },
   {
-    path: "/application/:applicationName/:tabIndex",
-    name: "Application view",
-    component: ApplicationDetailsView,
+    path: "/applications/:applicationName/references",
+    name: "References management view",
+    component: ReferencesManagementView,
     props: true,
   },
 ];
diff --git a/ui2/src/views/application/ApplicationDetailsView.vue b/ui2/src/views/application/ApplicationDetailsView.vue
deleted file mode 100644
index 1783e4e29..000000000
--- a/ui2/src/views/application/ApplicationDetailsView.vue
+++ /dev/null
@@ -1,74 +0,0 @@
-<template>
-  <PageView>
-    <h1 class="title main-title">{{ application.title }}</h1>
-    <b-tabs
-      v-model="currentTabIndex"
-      type="is-boxed"
-      expanded
-      class="mt-4 ApplicationDetailsView-tabs"
-      :animated="false"
-      @input="onTabSelection"
-    >
-      <b-tab-item :label="$t('applicationDetailsView.references')" icon="drafting-compass">
-        <ReferencesManagement :application="application" :key="application.id" />
-      </b-tab-item>
-      <b-tab-item :label="$t('applicationDetailsView.dataset')" icon="poll">À venir</b-tab-item>
-    </b-tabs>
-  </PageView>
-</template>
-
-<script>
-import { Component, Prop, Vue, Watch } from "vue-property-decorator";
-import PageView from "@/views/common/PageView.vue";
-import { ApplicationResult } from "@/model/ApplicationResult";
-import { ApplicationService } from "@/services/rest/ApplicationService";
-import { AlertService } from "@/services/AlertService";
-import ReferencesManagement from "@/components/application/ReferencesManagement.vue";
-
-@Component({
-  components: { PageView, ReferencesManagement },
-})
-export default class ApplicationDetailsView extends Vue {
-  @Prop() applicationName;
-  @Prop() tabIndex;
-
-  applicationService = ApplicationService.INSTANCE;
-  alertService = AlertService.INSTANCE;
-  application = new ApplicationResult();
-
-  currentTabIndex = 0;
-
-  created() {
-    this.currentTabIndex = parseInt(this.tabIndex);
-    this.init();
-  }
-
-  async init() {
-    try {
-      this.application = await this.applicationService.getApplication(this.applicationName);
-    } catch (error) {
-      this.alertService.toastServerError();
-    }
-  }
-
-  @Watch("tabIndex")
-  onExternalTabIndexChanged(newVal) {
-    this.currentTabIndex = parseInt(newVal);
-  }
-
-  onTabSelection() {
-    const params = this.$router.currentRoute.params;
-    if (this.currentTabIndex.toString() !== params["tabIndex"]) {
-      this.$router.push({ params: { tabIndex: this.currentTabIndex } });
-    }
-  }
-}
-</script>
-
-<style lang="scss">
-.ApplicationDetailsView-tabs.b-tabs {
-  .tab-content {
-    position: initial;
-  }
-}
-</style>
diff --git a/ui2/src/views/application/ApplicationsView.vue b/ui2/src/views/application/ApplicationsView.vue
index d0c318fda..bfc21d229 100644
--- a/ui2/src/views/application/ApplicationsView.vue
+++ b/ui2/src/views/application/ApplicationsView.vue
@@ -16,16 +16,8 @@
       :per-page="15"
       height="100%"
     >
-      <b-table-column
-        field="name"
-        :label="$t('applications.name')"
-        sortable
-        width="50%"
-        v-slot="props"
-      >
-        <div @click="displayApplication(props.row)" class="clickable">
-          {{ props.row.name }}
-        </div>
+      <b-table-column field="name" :label="$t('applications.name')" sortable v-slot="props">
+        {{ props.row.name }}
       </b-table-column>
       <b-table-column
         field="creationDate"
@@ -33,9 +25,12 @@
         sortable
         v-slot="props"
       >
-        <div @click="displayApplication(props.row)" class="clickable">
-          {{ new Date(props.row.creationDate) }}
-        </div>
+        {{ new Date(props.row.creationDate) }}
+      </b-table-column>
+      <b-table-column field="actions" :label="$t('applications.actions')" v-slot="props">
+        <b-button icon-left="drafting-compass" @click="displayReferencesManagement(props.row)">{{
+          $t("applications.references")
+        }}</b-button>
       </b-table-column>
     </b-table>
   </PageView>
@@ -66,11 +61,11 @@ export default class ApplicationsView extends Vue {
     this.$router.push("/applicationCreation");
   }
 
-  displayApplication(application) {
+  displayReferencesManagement(application) {
     if (!application) {
       return;
     }
-    this.$router.push("/application/" + application.name + "/0");
+    this.$router.push("/applications/" + application.name + "/references");
   }
 }
 </script>
diff --git a/ui2/src/views/references/ReferencesManagementView.vue b/ui2/src/views/references/ReferencesManagementView.vue
new file mode 100644
index 000000000..2c32ec239
--- /dev/null
+++ b/ui2/src/views/references/ReferencesManagementView.vue
@@ -0,0 +1,69 @@
+<template>
+  <PageView>
+    <h1 class="title main-title">{{ application.title }}</h1>
+    <div>
+      <CollapsibleTree
+        v-for="ref in references"
+        :key="ref.id"
+        :label="ref.label"
+        :children="ref.children"
+        :level="0"
+        :withDownload="true"
+        :onClickLabelCb="(event, label) => openRefDetails(event, label)"
+      />
+      <ReferencesDetailsPanel
+        :leftAlign="false"
+        :open="openPanel"
+        :reference="chosenRef"
+        :closeCb="(newVal) => (openPanel = newVal)"
+      />
+    </div>
+  </PageView>
+</template>
+
+<script>
+import { Component, Prop, Vue } from "vue-property-decorator";
+import { convertReferencesToTrees } from "@/utils/ConversionUtils";
+import CollapsibleTree from "@/components/common/CollapsibleTree.vue";
+import ReferencesDetailsPanel from "@/components/references/ReferencesDetailsPanel.vue";
+import { ApplicationService } from "@/services/rest/ApplicationService";
+import PageView from "../common/PageView.vue";
+import { ApplicationResult } from "@/model/ApplicationResult";
+
+@Component({
+  components: { CollapsibleTree, ReferencesDetailsPanel, PageView },
+})
+export default class ReferencesManagementView extends Vue {
+  @Prop() applicationName;
+
+  applicationService = ApplicationService.INSTANCE;
+
+  references = [];
+  openPanel = false;
+  chosenRef = null;
+  application = new ApplicationResult();
+
+  created() {
+    console.log(this.applicationName);
+    this.init();
+  }
+
+  async init() {
+    try {
+      this.application = await this.applicationService.getApplication(this.applicationName);
+      if (!this.application || !this.application.id) {
+        return;
+      }
+      this.references = convertReferencesToTrees(Object.values(this.application.references));
+    } catch (error) {
+      this.alertService.toastServerError();
+    }
+  }
+
+  openRefDetails(event, label) {
+    event.stopPropagation();
+    this.openPanel = this.chosenRef && this.chosenRef.label === label ? !this.openPanel : true;
+    this.chosenRef = Object.values(this.application.references).find((ref) => ref.label === label);
+  }
+}
+</script>
-- 
GitLab


From 2b61c39fe669780d887cdae3e9982ed37c2592e2 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Tue, 15 Jun 2021 16:31:12 +0200
Subject: [PATCH 18/27] Rend le menu collapsible.

---
 ui2/src/style/_variables.scss     |   1 +
 ui2/src/views/common/MenuView.vue | 100 +++++++++++++++++++-----------
 2 files changed, 65 insertions(+), 36 deletions(-)

diff --git a/ui2/src/style/_variables.scss b/ui2/src/style/_variables.scss
index 9004cb4bd..c276b43bd 100644
--- a/ui2/src/style/_variables.scss
+++ b/ui2/src/style/_variables.scss
@@ -6,6 +6,7 @@ $font-family: "LiberationSans", Helvetica, Arial, sans-serif;
 
 $text-default-color: #2c3e50;
 $light-text: rgb(230, 230, 230);
+$primary-slightly-transparent: rgba(0, 163, 166, 0.8);
 
 // PageView
 $container-padding-hor: 3rem;
diff --git a/ui2/src/views/common/MenuView.vue b/ui2/src/views/common/MenuView.vue
index 5880b3ddd..7fe563a62 100644
--- a/ui2/src/views/common/MenuView.vue
+++ b/ui2/src/views/common/MenuView.vue
@@ -1,39 +1,46 @@
 <template>
-  <b-navbar class="menu-view">
-    <template #start>
-      <b-navbar-item tag="router-link" :to="{ path: '/applications' }">
-        {{ $t("menu.applications") }}
-      </b-navbar-item>
-    </template>
-
-    <template #end>
-      <b-navbar-item tag="div">
-        <div class="buttons">
-          <b-button type="is-info" @click="logout" icon-right="sign-out-alt">{{
-            $t("menu.logout")
-          }}</b-button>
-        </div>
-      </b-navbar-item>
-      <b-navbar-item tag="div">
-        <b-field>
-          <b-select
-            v-model="chosenLocale"
-            :placeholder="$t('menu.language')"
-            icon="globe"
-            @input="setUserPrefLocale"
-          >
-            <option :value="locales.FRENCH">{{ $t("menu.french") }}</option>
-            <option :value="locales.ENGLISH">{{ $t("menu.english") }}</option>
-          </b-select>
-        </b-field>
-      </b-navbar-item>
-      <b-navbar-item href="https://www.inrae.fr/">
-        <img class="logo_blanc" src="@/assets/logo-inrae_blanc.svg" />
-        <img class="logo_vert" src="@/assets/Logo-INRAE.svg" />
-      </b-navbar-item>
-      <img class="logo_rep" src="@/assets/Rep-FR-logo.svg" />
-    </template>
-  </b-navbar>
+  <div class="menu-view-container">
+    <b-navbar class="menu-view" v-if="open">
+      <template #start>
+        <b-navbar-item tag="router-link" :to="{ path: '/applications' }">
+          {{ $t("menu.applications") }}
+        </b-navbar-item>
+      </template>
+
+      <template #end>
+        <b-navbar-item tag="div">
+          <div class="buttons">
+            <b-button type="is-info" @click="logout" icon-right="sign-out-alt">{{
+              $t("menu.logout")
+            }}</b-button>
+          </div>
+        </b-navbar-item>
+        <b-navbar-item tag="div">
+          <b-field>
+            <b-select
+              v-model="chosenLocale"
+              :placeholder="$t('menu.language')"
+              icon="globe"
+              @input="setUserPrefLocale"
+            >
+              <option :value="locales.FRENCH">{{ $t("menu.french") }}</option>
+              <option :value="locales.ENGLISH">{{ $t("menu.english") }}</option>
+            </b-select>
+          </b-field>
+        </b-navbar-item>
+        <b-navbar-item href="https://www.inrae.fr/">
+          <img class="logo_blanc" src="@/assets/logo-inrae_blanc.svg" />
+          <img class="logo_vert" src="@/assets/Logo-INRAE.svg" />
+        </b-navbar-item>
+        <img class="logo_rep" src="@/assets/Rep-FR-logo.svg" />
+      </template>
+    </b-navbar>
+    <FontAwesomeIcon
+      @click="open = !open"
+      :icon="open ? 'caret-up' : 'caret-down'"
+      class="clickable mr-3 menu-view-collapsible-icon"
+    />
+  </div>
 </template>
 
 <script>
@@ -43,9 +50,10 @@ import { LoginService } from "@/services/rest/LoginService";
 import { UserPreferencesService } from "@/services/UserPreferencesService";
 
 import { Locales } from "@/utils/LocaleUtils.js";
+import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
 
 @Component({
-  components: {},
+  components: { FontAwesomeIcon },
 })
 export default class MenuView extends Vue {
   loginService = LoginService.INSTANCE;
@@ -53,6 +61,7 @@ export default class MenuView extends Vue {
 
   locales = Locales;
   chosenLocale = "";
+  open = true;
 
   created() {
     this.chosenLocale = this.userPreferencesService.getUserPrefLocale();
@@ -119,4 +128,23 @@ export default class MenuView extends Vue {
     }
   }
 }
+
+.menu-view-container {
+  line-height: 0;
+}
+
+.menu-view-collapsible-icon {
+  width: 100%;
+  background-color: $primary-slightly-transparent;
+  height: 30px;
+  opacity: 0.8;
+
+  &:hover {
+    opacity: 1;
+  }
+
+  path {
+    fill: white;
+  }
+}
 </style>
-- 
GitLab


From f98c527ce7d308d2b5b4f55cc169cba8593086e4 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Tue, 15 Jun 2021 16:35:23 +0200
Subject: [PATCH 19/27] Ajoute des exemples dans les placeholders

---
 ui2/src/locales/en.json | 6 +++---
 ui2/src/locales/fr.json | 6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/ui2/src/locales/en.json b/ui2/src/locales/en.json
index 694ec9da0..da3c20d9a 100644
--- a/ui2/src/locales/en.json
+++ b/ui2/src/locales/en.json
@@ -9,9 +9,9 @@
     "signin": "Sign in",
     "signup": "Sign up",
     "login": "Login",
-    "login-placeholder": "Write down the login",
+    "login-placeholder": "Ex: michel",
     "pwd": "Password",
-    "pwd-placeholder": "Write down the password",
+    "pwd-placeholder": "Ex: xxxx",
     "pwd-forgotten": "Forgotten password ? "
   },
   "validation": {
@@ -45,7 +45,7 @@
     "chose-config": "Chose a configuration",
     "create": "Create application",
     "name": "Application name",
-    "name-placeholder": "Write down the application name",
+    "name-placeholder": "Ex : olac",
     "creation-date": "Creation date",
     "actions": "Actions",
     "references": "References"
diff --git a/ui2/src/locales/fr.json b/ui2/src/locales/fr.json
index 524122a40..10d16fce8 100644
--- a/ui2/src/locales/fr.json
+++ b/ui2/src/locales/fr.json
@@ -9,9 +9,9 @@
     "signin": "Se connecter",
     "signup": "Créer un compte",
     "login": "Identifiant",
-    "login-placeholder": "Entrer l'identifiant",
+    "login-placeholder": "Ex: michel",
     "pwd": "Mot de passe",
-    "pwd-placeholder": "Entrer le mot de passe",
+    "pwd-placeholder": "Ex: xxxx",
     "pwd-forgotten": "Mot de passe oublié ?"
   },
   "validation": {
@@ -45,7 +45,7 @@
     "chose-config": "Choisir une configuration",
     "create": "Créer l'application",
     "name": "Nom de l'application",
-    "name-placeholder": "Entrer le nom de l'application",
+    "name-placeholder": "Ex : olac",
     "creation-date": "Date de création",
     "actions": "Actions",
     "references": "Référentiels"
-- 
GitLab


From 77ff988854b1ff9706d4dd7eabdb992374e61840 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Tue, 15 Jun 2021 17:06:34 +0200
Subject: [PATCH 20/27] :construction: Ajoute un sous menu

---
 ui2/src/components/common/CollapsibleTree.vue |  9 +--
 ui2/src/components/common/SubMenu.vue         | 49 ++++++++++++++
 ui2/src/style/_common.scss                    |  8 +++
 ui2/src/style/_variables.scss                 | 65 ++++++++++---------
 .../references/ReferencesManagementView.vue   | 10 ++-
 5 files changed, 99 insertions(+), 42 deletions(-)
 create mode 100644 ui2/src/components/common/SubMenu.vue

diff --git a/ui2/src/components/common/CollapsibleTree.vue b/ui2/src/components/common/CollapsibleTree.vue
index a970dd44f..488ecd4c0 100644
--- a/ui2/src/components/common/CollapsibleTree.vue
+++ b/ui2/src/components/common/CollapsibleTree.vue
@@ -14,7 +14,7 @@
           class="clickable mr-3"
         />
         <div
-          class="clickable CollapsibleTree-header-label"
+          class="link"
           :style="`transform:translate(${level * 50}px);`"
           @click="(event) => onClickLabelCb(event, label)"
         >
@@ -96,11 +96,4 @@ export default class CollapsibleTree extends Vue {
   display: flex;
   align-items: center;
 }
-
-.CollapsibleTree-header-label {
-  &:hover {
-    color: $primary;
-    text-decoration: underline;
-  }
-}
 </style>
diff --git a/ui2/src/components/common/SubMenu.vue b/ui2/src/components/common/SubMenu.vue
new file mode 100644
index 000000000..4643085fe
--- /dev/null
+++ b/ui2/src/components/common/SubMenu.vue
@@ -0,0 +1,49 @@
+<template>
+  <div class="SubMenu">
+    <span class="SubMenu-root">{{ root }}</span>
+    <div v-for="path in paths" :key="path.label">
+      <span class="SubMenu-path-separator mr-1 ml-1">/</span>
+      <span @click="path.clickCb" class="link"> {{ path.label }}</span>
+    </div>
+  </div>
+</template>
+
+<script>
+import { Component, Prop, Vue } from "vue-property-decorator";
+
+export class SubMenuPath {
+  label;
+  clickCb;
+
+  constructor(label, clickCb) {
+    this.label = label;
+    this.clickCb = clickCb;
+  }
+}
+
+@Component({
+  components: {},
+})
+export default class SubMenu extends Vue {
+  @Prop() root;
+  @Prop() paths;
+
+  created() {
+    console.log(this.paths);
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.SubMenu {
+  display: flex;
+  height: 40px;
+  background-color: $info-transparent;
+}
+
+.SubMenu-root {
+  color: $dark;
+  font-weight: 600;
+  font-size: 1.2em;
+}
+</style>
diff --git a/ui2/src/style/_common.scss b/ui2/src/style/_common.scss
index 883a76358..04baf8edb 100644
--- a/ui2/src/style/_common.scss
+++ b/ui2/src/style/_common.scss
@@ -23,6 +23,14 @@ a {
   cursor: pointer;
 }
 
+.link {
+  cursor: pointer;
+  &:hover {
+    color: $primary;
+    text-decoration: underline;
+  }
+}
+
 // Input style
 
 .input-field {
diff --git a/ui2/src/style/_variables.scss b/ui2/src/style/_variables.scss
index c276b43bd..4abde752e 100644
--- a/ui2/src/style/_variables.scss
+++ b/ui2/src/style/_variables.scss
@@ -1,32 +1,33 @@
-/**************************************************************************************************
-*                       Global app variables (defined in the app)                                 *
-***************************************************************************************************/
-
-$font-family: "LiberationSans", Helvetica, Arial, sans-serif;
-
-$text-default-color: #2c3e50;
-$light-text: rgb(230, 230, 230);
-$primary-slightly-transparent: rgba(0, 163, 166, 0.8);
-
-// PageView
-$container-padding-hor: 3rem;
-$container-padding-vert: $container-padding-hor / 2;
-$title-margin-top: 1.5rem;
-
-// MenuView
-$menu-height: 80px;
-
-/**************************************************************************************************
-*                                   Buefy/Bulma customizations                                   *
-*        see all customizable variables here https://buefy.org/documentation/customization/       *
-***************************************************************************************************/
-
-// General variables
-$primary: rgb(0, 163, 166);
-$info: #4ec6c2;
-$success: #bade81;
-$warning: #ffec60;
-$danger: #d13a18;
-$dark: #4b6464;
-$light: rgb(202, 216, 216);
-$family-primary: $font-family;
+/**************************************************************************************************
+*                       Global app variables (defined in the app)                                 *
+***************************************************************************************************/
+
+$font-family: "LiberationSans", Helvetica, Arial, sans-serif;
+
+$text-default-color: #2c3e50;
+$light-text: rgb(230, 230, 230);
+$primary-slightly-transparent: rgba(0, 163, 166, 0.8);
+$info-transparent: rgba(78, 198, 194, 0.3);
+
+// PageView
+$container-padding-hor: 3rem;
+$container-padding-vert: $container-padding-hor / 2;
+$title-margin-top: 1.5rem;
+
+// MenuView
+$menu-height: 80px;
+
+/**************************************************************************************************
+*                                   Buefy/Bulma customizations                                   *
+*        see all customizable variables here https://buefy.org/documentation/customization/       *
+***************************************************************************************************/
+
+// General variables
+$primary: rgb(0, 163, 166);
+$info: rgb(78, 198, 194);
+$success: #bade81;
+$warning: #ffec60;
+$danger: #d13a18;
+$dark: #4b6464;
+$light: rgb(202, 216, 216);
+$family-primary: $font-family;
diff --git a/ui2/src/views/references/ReferencesManagementView.vue b/ui2/src/views/references/ReferencesManagementView.vue
index 2c32ec239..95c8bf8be 100644
--- a/ui2/src/views/references/ReferencesManagementView.vue
+++ b/ui2/src/views/references/ReferencesManagementView.vue
@@ -1,5 +1,6 @@
 <template>
   <PageView>
+    <SubMenu :root="application.title" :paths="subMenuPaths" />
     <h1 class="title main-title">{{ application.title }}</h1>
     <div>
       <CollapsibleTree
@@ -29,9 +30,10 @@ import ReferencesDetailsPanel from "@/components/references/ReferencesDetailsPan
 import { ApplicationService } from "@/services/rest/ApplicationService";
 import PageView from "../common/PageView.vue";
 import { ApplicationResult } from "@/model/ApplicationResult";
+import SubMenu, { SubMenuPath } from "@/components/common/SubMenu.vue";
 
 @Component({
-  components: { CollapsibleTree, ReferencesDetailsPanel, PageView },
+  components: { CollapsibleTree, ReferencesDetailsPanel, PageView, SubMenu },
 })
 export default class ReferencesManagementView extends Vue {
   @Prop() applicationName;
@@ -42,9 +44,13 @@ export default class ReferencesManagementView extends Vue {
   openPanel = false;
   chosenRef = null;
   application = new ApplicationResult();
+  subMenuPaths = [
+    new SubMenuPath("references", () =>
+      this.$router.push(`/applications/${this.applicationName}/references`)
+    ),
+  ];
 
   created() {
-    console.log(this.applicationName);
     this.init();
   }
 
-- 
GitLab


From 5983d30c1ebacfe7c87a6117fcd00ade1767e55a Mon Sep 17 00:00:00 2001
From: Brendan Le Ny <bleny@codelutin.com>
Date: Tue, 15 Jun 2021 17:42:53 +0200
Subject: [PATCH 21/27] =?UTF-8?q?Corrige=20les=20donn=C3=A9es=20renvoy?=
 =?UTF-8?q?=C3=A9es=20au=20front=20au=20chargement=20du=20contenu=20d'un?=
 =?UTF-8?q?=20r=C3=A9f=C3=A9rentiel?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../inra/oresing/rest/GetReferenceResult.java  | 18 ++++++++++++++++++
 .../fr/inra/oresing/rest/OreSiResources.java   | 15 +++++++++++++--
 .../inra/oresing/rest/OreSiResourcesTest.java  | 13 ++++++-------
 3 files changed, 37 insertions(+), 9 deletions(-)
 create mode 100644 src/main/java/fr/inra/oresing/rest/GetReferenceResult.java

diff --git a/src/main/java/fr/inra/oresing/rest/GetReferenceResult.java b/src/main/java/fr/inra/oresing/rest/GetReferenceResult.java
new file mode 100644
index 000000000..d1488cc30
--- /dev/null
+++ b/src/main/java/fr/inra/oresing/rest/GetReferenceResult.java
@@ -0,0 +1,18 @@
+package fr.inra.oresing.rest;
+
+import lombok.Value;
+
+import java.util.Map;
+import java.util.Set;
+
+@Value
+public class GetReferenceResult {
+    Set<ReferenceValue> referenceValues;
+
+    @Value
+    public static class ReferenceValue {
+        String hierarchicalKey;
+        String naturalKey;
+        Map<String, String> values;
+    }
+}
diff --git a/src/main/java/fr/inra/oresing/rest/OreSiResources.java b/src/main/java/fr/inra/oresing/rest/OreSiResources.java
index 34f625553..c21f7d125 100644
--- a/src/main/java/fr/inra/oresing/rest/OreSiResources.java
+++ b/src/main/java/fr/inra/oresing/rest/OreSiResources.java
@@ -2,6 +2,7 @@ package fr.inra.oresing.rest;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Ordering;
@@ -30,6 +31,7 @@ import org.springframework.web.util.UriUtils;
 import java.io.IOException;
 import java.net.URI;
 import java.nio.charset.Charset;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -164,12 +166,21 @@ public class OreSiResources {
      * @return un tableau de chaine
      */
     @GetMapping(value = "/applications/{nameOrId}/references/{refType}", produces = MediaType.APPLICATION_JSON_VALUE)
-    public ResponseEntity<List<ReferenceValue>> listReferences(
+    public ResponseEntity<GetReferenceResult> listReferences(
             @PathVariable("nameOrId") String nameOrId,
             @PathVariable("refType") String refType,
             @RequestParam MultiValueMap<String, String> params) {
         List<ReferenceValue> list = service.findReference(nameOrId, refType, params);
-        return ResponseEntity.ok(list);
+        ImmutableSet<GetReferenceResult.ReferenceValue> referenceValues = list.stream()
+                .map(referenceValue ->
+                        new GetReferenceResult.ReferenceValue(
+                            referenceValue.getHierarchicalKey(),
+                            referenceValue.getNaturalKey(),
+                            referenceValue.getRefValues()
+                        )
+                )
+                .collect(ImmutableSortedSet.toImmutableSortedSet(Comparator.comparing(GetReferenceResult.ReferenceValue::getHierarchicalKey)));
+        return ResponseEntity.ok(new GetReferenceResult(referenceValues));
     }
 
     @GetMapping(value = "/applications/{nameOrId}/references/{refType}/{column}", produces = MediaType.APPLICATION_JSON_VALUE)
diff --git a/src/test/java/fr/inra/oresing/rest/OreSiResourcesTest.java b/src/test/java/fr/inra/oresing/rest/OreSiResourcesTest.java
index 06c356d0e..ed6123d07 100644
--- a/src/test/java/fr/inra/oresing/rest/OreSiResourcesTest.java
+++ b/src/test/java/fr/inra/oresing/rest/OreSiResourcesTest.java
@@ -36,7 +36,6 @@ import javax.servlet.http.Cookie;
 import java.io.InputStream;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
@@ -146,8 +145,8 @@ public class OreSiResourcesTest {
                 .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
                 .andReturn().getResponse().getContentAsString();
 
-        List refs = objectMapper.readValue(getReferencesResponse, List.class);
-        Assert.assertEquals(9, refs.size());
+        GetReferenceResult GetReferenceResult = objectMapper.readValue(getReferencesResponse, GetReferenceResult.class);
+        Assert.assertEquals(9, GetReferenceResult.getReferenceValues().size());
 
         // ajout de data
         resource = getClass().getResource(fixtures.getPemDataResourceName());
@@ -371,8 +370,8 @@ public class OreSiResourcesTest {
                 .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
                 .andReturn().getResponse().getContentAsString();
 
-        List refs = objectMapper.readValue(getReferenceResponse, List.class);
-        Assert.assertEquals(103, refs.size());
+        GetReferenceResult refs = objectMapper.readValue(getReferenceResponse, GetReferenceResult.class);
+        Assert.assertEquals(103, refs.getReferenceValues().size());
 
         // Ajout de referentiel
         for (Map.Entry<String, String> e : fixtures.getAcbbReferentielFiles().entrySet()) {
@@ -397,8 +396,8 @@ public class OreSiResourcesTest {
                 .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
                 .andReturn().getResponse().getContentAsString();
 
-        refs = objectMapper.readValue(getReferenceResponse, List.class);
-        Assert.assertEquals(103, refs.size());
+        refs = objectMapper.readValue(getReferenceResponse, GetReferenceResult.class);
+        Assert.assertEquals(103, refs.getReferenceValues().size());
 
         // ajout de data
         try (InputStream in = getClass().getResourceAsStream(fixtures.getFluxToursDataResourceName())) {
-- 
GitLab


From efbd6812b6179f56b507b989d0c366d0f9f7a965 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Wed, 16 Jun 2021 17:59:31 +0200
Subject: [PATCH 22/27] =?UTF-8?q?Am=C3=A9liore=20le=20style=20du=20sous-me?=
 =?UTF-8?q?nu?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ui2/src/components/common/CollapsibleTree.vue |  2 +-
 ui2/src/components/common/SubMenu.vue         | 14 ++++++-----
 ui2/src/locales/en.json                       |  6 +++--
 ui2/src/locales/fr.json                       |  6 +++--
 ui2/src/main.js                               |  4 ++-
 .../references/ReferencesManagementView.vue   | 25 +++++++++++++------
 6 files changed, 38 insertions(+), 19 deletions(-)

diff --git a/ui2/src/components/common/CollapsibleTree.vue b/ui2/src/components/common/CollapsibleTree.vue
index 488ecd4c0..e08213784 100644
--- a/ui2/src/components/common/CollapsibleTree.vue
+++ b/ui2/src/components/common/CollapsibleTree.vue
@@ -10,7 +10,7 @@
       <div class="CollapsibleTree-header-infos">
         <FontAwesomeIcon
           v-if="children && children.length !== 0"
-          :icon="displayChildren ? 'caret-up' : 'caret-down'"
+          :icon="displayChildren ? 'caret-down' : 'caret-right'"
           class="clickable mr-3"
         />
         <div
diff --git a/ui2/src/components/common/SubMenu.vue b/ui2/src/components/common/SubMenu.vue
index 4643085fe..1c796bd60 100644
--- a/ui2/src/components/common/SubMenu.vue
+++ b/ui2/src/components/common/SubMenu.vue
@@ -1,9 +1,13 @@
 <template>
   <div class="SubMenu">
     <span class="SubMenu-root">{{ root }}</span>
-    <div v-for="path in paths" :key="path.label">
+    <div v-for="(path, index) in paths" :key="path.label">
       <span class="SubMenu-path-separator mr-1 ml-1">/</span>
-      <span @click="path.clickCb" class="link"> {{ path.label }}</span>
+      <span
+        @click="index !== paths.length - 1 ? path.clickCb : ''"
+        :class="index !== paths.length - 1 ? 'link' : ''"
+        >{{ path.label }}</span
+      >
     </div>
   </div>
 </template>
@@ -27,10 +31,6 @@ export class SubMenuPath {
 export default class SubMenu extends Vue {
   @Prop() root;
   @Prop() paths;
-
-  created() {
-    console.log(this.paths);
-  }
 }
 </script>
 
@@ -39,6 +39,8 @@ export default class SubMenu extends Vue {
   display: flex;
   height: 40px;
   background-color: $info-transparent;
+  align-items: center;
+  padding: 0.5rem;
 }
 
 .SubMenu-root {
diff --git a/ui2/src/locales/en.json b/ui2/src/locales/en.json
index 17c1f7053..62facb478 100644
--- a/ui2/src/locales/en.json
+++ b/ui2/src/locales/en.json
@@ -2,7 +2,7 @@
   "titles": {
     "login-page": "Welcome to SI-ORE",
     "applications-page": "My applications",
-    "references-page": "My references",
+    "references-page": "{applicationName} references",
     "application-creation": "Application creation"
   },
   "login": {
@@ -80,6 +80,8 @@
     "actions": "Actions",
     "consult": "Consult",
     "download": "Download",
-    "delete": "Delete"
+    "delete": "Delete",
+    "references": "References",
+    "data": "Data"
   }
 }
diff --git a/ui2/src/locales/fr.json b/ui2/src/locales/fr.json
index 8cda2930c..ef3c339d6 100644
--- a/ui2/src/locales/fr.json
+++ b/ui2/src/locales/fr.json
@@ -2,7 +2,7 @@
   "titles": {
     "login-page": "Bienvenue sur SI-ORE",
     "applications-page": "Mes applications",
-    "references-page": "Mes référentiels",
+    "references-page": "Référentiels de {applicationName}",
     "application-creation": "Créer une application"
   },
   "login": {
@@ -80,6 +80,8 @@
     "actions": "Actions",
     "consult": "Consulter",
     "download": "Télécharger",
-    "delete": "Supprimer"
+    "delete": "Supprimer",
+    "references": "Référentiels",
+    "data": "Données"
   }
 }
diff --git a/ui2/src/main.js b/ui2/src/main.js
index 7665747a1..4b248832a 100644
--- a/ui2/src/main.js
+++ b/ui2/src/main.js
@@ -26,6 +26,7 @@ import {
   faUpload,
   faWrench,
   faVial,
+  faCaretRight,
 } from "@fortawesome/free-solid-svg-icons";
 import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
 library.add(
@@ -49,7 +50,8 @@ library.add(
   faTimes,
   faTrashAlt,
   faDownload,
-  faVial
+  faVial,
+  faCaretRight
 );
 Vue.component("vue-fontawesome", FontAwesomeIcon);
 
diff --git a/ui2/src/views/references/ReferencesManagementView.vue b/ui2/src/views/references/ReferencesManagementView.vue
index 95c8bf8be..c71dba800 100644
--- a/ui2/src/views/references/ReferencesManagementView.vue
+++ b/ui2/src/views/references/ReferencesManagementView.vue
@@ -1,7 +1,9 @@
 <template>
-  <PageView>
+  <PageView class="ReferencesManagementView">
     <SubMenu :root="application.title" :paths="subMenuPaths" />
-    <h1 class="title main-title">{{ application.title }}</h1>
+    <h1 class="title main-title">
+      {{ $t("titles.references-page", { applicationName: application.title }) }}
+    </h1>
     <div>
       <CollapsibleTree
         v-for="ref in references"
@@ -44,13 +46,14 @@ export default class ReferencesManagementView extends Vue {
   openPanel = false;
   chosenRef = null;
   application = new ApplicationResult();
-  subMenuPaths = [
-    new SubMenuPath("references", () =>
-      this.$router.push(`/applications/${this.applicationName}/references`)
-    ),
-  ];
+  subMenuPaths = [];
 
   created() {
+    this.subMenuPaths = [
+      new SubMenuPath(this.$t("referencesManagement.references").toLowerCase(), () =>
+        this.$router.push(`/applications/${this.applicationName}/references`)
+      ),
+    ];
     this.init();
   }
 
@@ -73,3 +76,11 @@ export default class ReferencesManagementView extends Vue {
   }
 }
 </script>
+
+<style lang="scss">
+.ReferencesManagementView {
+  .PageView-container {
+    padding-top: 0.5rem;
+  }
+}
+</style>
-- 
GitLab


From 8d25b9fc47d07b3c324a02b8e11e108f22197fb1 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Wed, 16 Jun 2021 19:31:05 +0200
Subject: [PATCH 23/27] =?UTF-8?q?Ajoute=20la=20page=20affichant=20les=20do?=
 =?UTF-8?q?nn=C3=A9es=20de=20r=C3=A9f=C3=A9rences?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ui2/src/components/common/SubMenu.vue         |   6 +-
 .../references/ReferencesDetailsPanel.vue     |   6 +-
 ui2/src/locales/en.json                       |   1 +
 ui2/src/locales/fr.json                       |   1 +
 ui2/src/router/index.js                       |   6 ++
 ui2/src/views/common/MenuView.vue             |   2 +-
 ui2/src/views/common/PageView.vue             |   5 +
 .../views/references/ReferenceTableView.vue   | 101 ++++++++++++++++++
 .../references/ReferencesManagementView.vue   |  13 +--
 9 files changed, 129 insertions(+), 12 deletions(-)
 create mode 100644 ui2/src/views/references/ReferenceTableView.vue

diff --git a/ui2/src/components/common/SubMenu.vue b/ui2/src/components/common/SubMenu.vue
index 1c796bd60..2b5d444c6 100644
--- a/ui2/src/components/common/SubMenu.vue
+++ b/ui2/src/components/common/SubMenu.vue
@@ -4,7 +4,7 @@
     <div v-for="(path, index) in paths" :key="path.label">
       <span class="SubMenu-path-separator mr-1 ml-1">/</span>
       <span
-        @click="index !== paths.length - 1 ? path.clickCb : ''"
+        @click="index !== paths.length - 1 ? path.clickCb() : ''"
         :class="index !== paths.length - 1 ? 'link' : ''"
         >{{ path.label }}</span
       >
@@ -40,7 +40,9 @@ export default class SubMenu extends Vue {
   height: 40px;
   background-color: $info-transparent;
   align-items: center;
-  padding: 0.5rem;
+  padding: 0.5rem $container-padding-hor;
+  width: calc(100% + 2 * #{$container-padding-hor});
+  transform: translateX(-$container-padding-hor);
 }
 
 .SubMenu-root {
diff --git a/ui2/src/components/references/ReferencesDetailsPanel.vue b/ui2/src/components/references/ReferencesDetailsPanel.vue
index 7b017a863..10c56d924 100644
--- a/ui2/src/components/references/ReferencesDetailsPanel.vue
+++ b/ui2/src/components/references/ReferencesDetailsPanel.vue
@@ -6,7 +6,7 @@
     :closeCb="closeCb"
   >
     <div class="Panel-buttons">
-      <b-button type="is-primary" icon-left="eye">{{
+      <b-button type="is-primary" icon-left="eye" @click="emitConsult">{{
         $t("referencesManagement.consult")
       }}</b-button>
       <b-button icon-left="download">{{ $t("referencesManagement.download") }}</b-button>
@@ -46,6 +46,10 @@ export default class ReferencesDetailsPanel extends Vue {
   deleteReference() {
     console.log("DELETE", this.reference);
   }
+
+  emitConsult() {
+    this.$emit("consultReference", this.reference.id);
+  }
 }
 </script>
 
diff --git a/ui2/src/locales/en.json b/ui2/src/locales/en.json
index 62facb478..847b772b6 100644
--- a/ui2/src/locales/en.json
+++ b/ui2/src/locales/en.json
@@ -3,6 +3,7 @@
     "login-page": "Welcome to SI-ORE",
     "applications-page": "My applications",
     "references-page": "{applicationName} references",
+    "references-data": "{refName} data",
     "application-creation": "Application creation"
   },
   "login": {
diff --git a/ui2/src/locales/fr.json b/ui2/src/locales/fr.json
index ef3c339d6..8d5802fc0 100644
--- a/ui2/src/locales/fr.json
+++ b/ui2/src/locales/fr.json
@@ -3,6 +3,7 @@
     "login-page": "Bienvenue sur SI-ORE",
     "applications-page": "Mes applications",
     "references-page": "Référentiels de {applicationName}",
+    "references-data": "Données de {refName}",
     "application-creation": "Créer une application"
   },
   "login": {
diff --git a/ui2/src/router/index.js b/ui2/src/router/index.js
index e143fae3e..0001e72b4 100644
--- a/ui2/src/router/index.js
+++ b/ui2/src/router/index.js
@@ -4,6 +4,7 @@ import LoginView from "@/views/LoginView.vue";
 import ApplicationsView from "@/views/application/ApplicationsView.vue";
 import ApplicationCreationView from "@/views/application/ApplicationCreationView.vue";
 import ReferencesManagementView from "@/views/references/ReferencesManagementView.vue";
+import ReferenceTable from "@/views/references/ReferenceTableView.vue";
 
 Vue.use(VueRouter);
 
@@ -33,6 +34,11 @@ const routes = [
     component: ReferencesManagementView,
     props: true,
   },
+  {
+    path: "/applications/:applicationName/references/:refId",
+    component: ReferenceTable,
+    props: true,
+  },
 ];
 
 const router = new VueRouter({
diff --git a/ui2/src/views/common/MenuView.vue b/ui2/src/views/common/MenuView.vue
index 7fe563a62..b98c505e9 100644
--- a/ui2/src/views/common/MenuView.vue
+++ b/ui2/src/views/common/MenuView.vue
@@ -61,7 +61,7 @@ export default class MenuView extends Vue {
 
   locales = Locales;
   chosenLocale = "";
-  open = true;
+  open = false;
 
   created() {
     this.chosenLocale = this.userPreferencesService.getUserPrefLocale();
diff --git a/ui2/src/views/common/PageView.vue b/ui2/src/views/common/PageView.vue
index 57154602c..0da059501 100644
--- a/ui2/src/views/common/PageView.vue
+++ b/ui2/src/views/common/PageView.vue
@@ -32,6 +32,11 @@ export default class PageView extends Vue {
 <style lang="scss" scoped>
 .PageView {
   height: 100%;
+  &.with-submenu {
+    .PageView-container {
+      padding-top: 0rem;
+    }
+  }
 }
 
 .PageView-container {
diff --git a/ui2/src/views/references/ReferenceTableView.vue b/ui2/src/views/references/ReferenceTableView.vue
new file mode 100644
index 000000000..4fc66f428
--- /dev/null
+++ b/ui2/src/views/references/ReferenceTableView.vue
@@ -0,0 +1,101 @@
+<template>
+  <PageView class="with-submenu">
+    <SubMenu :root="application.title" :paths="subMenuPaths" />
+    <h1 class="title main-title">
+      {{ $t("titles.references-data", { refName: reference.label }) }}
+    </h1>
+
+    <div v-if="reference && columns">
+      <b-table
+        :data="[]"
+        :striped="true"
+        :isFocusable="true"
+        :isHoverable="true"
+        :sticky-header="true"
+        :paginated="true"
+        :per-page="15"
+        height="100%"
+      >
+        <b-table-column
+          v-for="column in columns"
+          :key="column.id"
+          :field="column.title"
+          :label="column.title"
+          sortable
+          :sticky="column.key"
+        >
+        </b-table-column>
+      </b-table>
+    </div>
+  </PageView>
+</template>
+
+<script>
+import SubMenu, { SubMenuPath } from "@/components/common/SubMenu.vue";
+import { ApplicationResult } from "@/model/ApplicationResult";
+import { AlertService } from "@/services/AlertService";
+import { ApplicationService } from "@/services/rest/ApplicationService";
+import { Prop, Vue, Component } from "vue-property-decorator";
+import PageView from "../common/PageView.vue";
+
+@Component({
+  components: { PageView, SubMenu },
+})
+export default class ReferenceTableView extends Vue {
+  @Prop() applicationName;
+  @Prop() refId;
+
+  alertService = AlertService.INSTANCE;
+  applicationService = ApplicationService.INSTANCE;
+
+  application = new ApplicationResult();
+  subMenuPaths = [];
+  reference = {};
+  columns = [];
+
+  created() {
+    this.init();
+  }
+
+  async init() {
+    try {
+      this.application = await this.applicationService.getApplication(this.applicationName);
+      this.setInitialVariables();
+    } catch (error) {
+      this.alertService.toastServerError();
+    }
+  }
+
+  setInitialVariables() {
+    if (!this.application || !this.application.references) {
+      return;
+    }
+
+    this.reference = Object.values(this.application.references).find(
+      (ref) => ref.id === this.refId
+    );
+
+    this.subMenuPaths = [
+      new SubMenuPath(this.$t("referencesManagement.references").toLowerCase(), () =>
+        this.$router.push(`/applications/${this.applicationName}/references`)
+      ),
+      new SubMenuPath(this.reference.label, () =>
+        this.$router.push(`/applications/${this.applicationName}/references/${this.refId}`)
+      ),
+    ];
+
+    if (this.reference && this.reference.columns) {
+      this.columns = Object.values(this.reference.columns).sort((c1, c2) => {
+        if (c1.title < c2.title) {
+          return -1;
+        }
+
+        if (c1.title > c2.title) {
+          return 1;
+        }
+        return 0;
+      });
+    }
+  }
+}
+</script>
diff --git a/ui2/src/views/references/ReferencesManagementView.vue b/ui2/src/views/references/ReferencesManagementView.vue
index c71dba800..0ad0d53aa 100644
--- a/ui2/src/views/references/ReferencesManagementView.vue
+++ b/ui2/src/views/references/ReferencesManagementView.vue
@@ -1,5 +1,5 @@
 <template>
-  <PageView class="ReferencesManagementView">
+  <PageView class="with-submenu">
     <SubMenu :root="application.title" :paths="subMenuPaths" />
     <h1 class="title main-title">
       {{ $t("titles.references-page", { applicationName: application.title }) }}
@@ -19,6 +19,7 @@
         :open="openPanel"
         :reference="chosenRef"
         :closeCb="(newVal) => (openPanel = newVal)"
+        @consultReference="consultReference"
       />
     </div>
   </PageView>
@@ -74,13 +75,9 @@ export default class ReferencesManagementView extends Vue {
     this.openPanel = this.chosenRef && this.chosenRef.label === label ? !this.openPanel : true;
     this.chosenRef = Object.values(this.application.references).find((ref) => ref.label === label);
   }
-}
-</script>
 
-<style lang="scss">
-.ReferencesManagementView {
-  .PageView-container {
-    padding-top: 0.5rem;
+  consultReference(id) {
+    this.$router.push(`/applications/${this.applicationName}/references/${id}`);
   }
 }
-</style>
+</script>
-- 
GitLab


From 312cb017fb55a05c6a3fe60b5d03e79ffe13d093 Mon Sep 17 00:00:00 2001
From: Brendan Le Ny <bleny@codelutin.com>
Date: Thu, 17 Jun 2021 14:57:14 +0200
Subject: [PATCH 24/27] =?UTF-8?q?Exposer=20au=20front=20les=20types=20de?=
 =?UTF-8?q?=20donn=C3=A9es,=20les=20variables=20et=20les=20composants?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../inra/oresing/rest/ApplicationResult.java  | 21 +++++++++++++++++++
 .../fr/inra/oresing/rest/OreSiResources.java  | 11 +++++++++-
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/src/main/java/fr/inra/oresing/rest/ApplicationResult.java b/src/main/java/fr/inra/oresing/rest/ApplicationResult.java
index f3ee50860..70da2822b 100644
--- a/src/main/java/fr/inra/oresing/rest/ApplicationResult.java
+++ b/src/main/java/fr/inra/oresing/rest/ApplicationResult.java
@@ -11,6 +11,7 @@ public class ApplicationResult {
     String name;
     String title;
     Map<String, Reference> references;
+    Map<String, DataType> dataTypes;
 
     @Value
     public static class Reference {
@@ -27,4 +28,24 @@ public class ApplicationResult {
             String linkedTo;
         }
     }
+
+    @Value
+    public static class DataType {
+        String id;
+        String label;
+        Map<String, Variable> variables;
+
+        @Value
+        public static class Variable {
+            String id;
+            String label;
+            Map<String, Component> components;
+
+            @Value
+            public static class Component {
+                String id;
+                String label;
+            }
+        }
+    }
 }
diff --git a/src/main/java/fr/inra/oresing/rest/OreSiResources.java b/src/main/java/fr/inra/oresing/rest/OreSiResources.java
index c21f7d125..b94fbf109 100644
--- a/src/main/java/fr/inra/oresing/rest/OreSiResources.java
+++ b/src/main/java/fr/inra/oresing/rest/OreSiResources.java
@@ -111,7 +111,16 @@ public class OreSiResources {
             Set<String> children = childrenPerReferences.get(reference);
             return new ApplicationResult.Reference(reference, reference, children, columns);
         });
-        ApplicationResult applicationResult = new ApplicationResult(application.getId().toString(), application.getName(), application.getConfiguration().getApplication().getName(), references);
+        Map<String, ApplicationResult.DataType> dataTypes = Maps.transformEntries(application.getConfiguration().getDataTypes(), (dataType, dataTypeDescription) -> {
+            Map<String, ApplicationResult.DataType.Variable> variables = Maps.transformEntries(dataTypeDescription.getData(), (variable, variableDescription) -> {
+                Map<String, ApplicationResult.DataType.Variable.Component> components = Maps.transformEntries(variableDescription.getComponents(), (component, componentDescription) -> {
+                    return new ApplicationResult.DataType.Variable.Component(component, component);
+                });
+                return new ApplicationResult.DataType.Variable(variable, variable, components);
+            });
+            return new ApplicationResult.DataType(dataType, dataType, variables);
+        });
+        ApplicationResult applicationResult = new ApplicationResult(application.getId().toString(), application.getName(), application.getConfiguration().getApplication().getName(), references, dataTypes);
         return ResponseEntity.ok(applicationResult);
     }
 
-- 
GitLab


From f7e07847c476a5a95845af6d4b4bdb69ba87d7ec Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Thu, 17 Jun 2021 16:59:53 +0200
Subject: [PATCH 25/27] =?UTF-8?q?Branche=20le=20t=C3=A9l=C3=A9versement=20?=
 =?UTF-8?q?au=20backend?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ui2/src/components/common/CollapsibleTree.vue | 13 +++++++++----
 ui2/src/locales/en.json                       |  4 +++-
 ui2/src/locales/fr.json                       |  4 +++-
 ui2/src/services/rest/ApplicationService.js   |  4 ----
 ui2/src/services/rest/ReferenceService.js     | 19 +++++++++++++++++++
 .../references/ReferencesManagementView.vue   | 17 ++++++++++++++++-
 6 files changed, 50 insertions(+), 11 deletions(-)
 create mode 100644 ui2/src/services/rest/ReferenceService.js

diff --git a/ui2/src/components/common/CollapsibleTree.vue b/ui2/src/components/common/CollapsibleTree.vue
index e08213784..652fb7790 100644
--- a/ui2/src/components/common/CollapsibleTree.vue
+++ b/ui2/src/components/common/CollapsibleTree.vue
@@ -21,8 +21,13 @@
           {{ label }}
         </div>
       </div>
-      <b-field class="file is-primary" v-if="withDownload">
-        <b-upload v-model="refFile" class="file-label" accept=".csv">
+      <b-field class="file is-primary" v-if="onUploadCb">
+        <b-upload
+          v-model="refFile"
+          class="file-label"
+          accept=".csv"
+          @input="() => onUploadCb(label, refFile)"
+        >
           <span class="file-name" v-if="refFile">
             {{ refFile.name }}
           </span>
@@ -39,8 +44,8 @@
         :label="child.label"
         :children="child.children"
         :level="level + 1"
-        :withDownload="withDownload"
         :onClickLabelCb="onClickLabelCb"
+        :onUploadCb="onUploadCb"
       />
     </div>
   </div>
@@ -57,8 +62,8 @@ export default class CollapsibleTree extends Vue {
   @Prop() label;
   @Prop() children;
   @Prop() level;
-  @Prop() withDownload;
   @Prop() onClickLabelCb;
+  @Prop() onUploadCb;
 
   displayChildren = false;
   refFile = null;
diff --git a/ui2/src/locales/en.json b/ui2/src/locales/en.json
index 847b772b6..7a13a47c2 100644
--- a/ui2/src/locales/en.json
+++ b/ui2/src/locales/en.json
@@ -30,7 +30,9 @@
     "application-validate-success": "The YAML file is valid!",
     "warning": "Warning !",
     "reference-deletion-msg": "You're about to delete the reference : {label}. Are you sure ?",
-    "delete": "Delete"
+    "delete": "Delete",
+    "reference-csv-upload-error": "An error occured while uploading the csv file",
+    "reference-updated": "Reference updated"
   },
   "message": {
     "app-config-error": "Error in yaml file",
diff --git a/ui2/src/locales/fr.json b/ui2/src/locales/fr.json
index 8d5802fc0..2a24d21b6 100644
--- a/ui2/src/locales/fr.json
+++ b/ui2/src/locales/fr.json
@@ -30,7 +30,9 @@
     "application-validate-success": "Le fichier YAML est valide !",
     "warning": "Attention !",
     "reference-deletion-msg": "Vous allez supprimer le référentiel : {label}. Êtes-vous sûr ?",
-    "delete": "Supprimer"
+    "delete": "Supprimer",
+    "reference-csv-upload-error": "Une erreur s'est produite au téléversement du fichier csv",
+    "reference-updated": "Référentiel mis à jour"
   },
   "message": {
     "app-config-error": "Erreur dans le fichier yaml",
diff --git a/ui2/src/services/rest/ApplicationService.js b/ui2/src/services/rest/ApplicationService.js
index 914600308..54869e111 100644
--- a/ui2/src/services/rest/ApplicationService.js
+++ b/ui2/src/services/rest/ApplicationService.js
@@ -25,10 +25,6 @@ export class ApplicationService extends Fetcher {
     return this.get(`applications/${applicationName}/data/${dataset}`);
   }
 
-  async getReference(reference, applicationName) {
-    return this.get(`applications/${applicationName}/references/${reference}`);
-  }
-
   async validateConfiguration(applicationConfig) {
     return this.post("validate-configuration", {
       file: applicationConfig.file,
diff --git a/ui2/src/services/rest/ReferenceService.js b/ui2/src/services/rest/ReferenceService.js
new file mode 100644
index 000000000..49c4d596b
--- /dev/null
+++ b/ui2/src/services/rest/ReferenceService.js
@@ -0,0 +1,19 @@
+import { Fetcher } from "../Fetcher";
+
+export class ReferenceService extends Fetcher {
+  static INSTANCE = new ReferenceService();
+
+  constructor() {
+    super();
+  }
+
+  async getReference(applicationName, referenceId) {
+    return this.get(`applications/${applicationName}/references/${referenceId}`);
+  }
+
+  async createReference(applicationName, referenceId, refFile) {
+    return this.post(`applications/${applicationName}/references/${referenceId}`, {
+      file: refFile,
+    });
+  }
+}
diff --git a/ui2/src/views/references/ReferencesManagementView.vue b/ui2/src/views/references/ReferencesManagementView.vue
index 0ad0d53aa..f5151530f 100644
--- a/ui2/src/views/references/ReferencesManagementView.vue
+++ b/ui2/src/views/references/ReferencesManagementView.vue
@@ -11,8 +11,8 @@
         :label="ref.label"
         :children="ref.children"
         :level="0"
-        :withDownload="true"
         :onClickLabelCb="(event, label) => openRefDetails(event, label)"
+        :onUploadCb="(label, refFile) => uploadReferenceCsv(label, refFile)"
       />
       <ReferencesDetailsPanel
         :leftAlign="false"
@@ -31,9 +31,12 @@ import { convertReferencesToTrees } from "@/utils/ConversionUtils";
 import CollapsibleTree from "@/components/common/CollapsibleTree.vue";
 import ReferencesDetailsPanel from "@/components/references/ReferencesDetailsPanel.vue";
 import { ApplicationService } from "@/services/rest/ApplicationService";
+import { ReferenceService } from "@/services/rest/ReferenceService";
+
 import PageView from "../common/PageView.vue";
 import { ApplicationResult } from "@/model/ApplicationResult";
 import SubMenu, { SubMenuPath } from "@/components/common/SubMenu.vue";
+import { AlertService } from "@/services/AlertService";
 
 @Component({
   components: { CollapsibleTree, ReferencesDetailsPanel, PageView, SubMenu },
@@ -42,6 +45,8 @@ export default class ReferencesManagementView extends Vue {
   @Prop() applicationName;
 
   applicationService = ApplicationService.INSTANCE;
+  referenceService = ReferenceService.INSTANCE;
+  alertService = AlertService.INSTANCE;
 
   references = [];
   openPanel = false;
@@ -79,5 +84,15 @@ export default class ReferencesManagementView extends Vue {
   consultReference(id) {
     this.$router.push(`/applications/${this.applicationName}/references/${id}`);
   }
+
+  async uploadReferenceCsv(label, refFile) {
+    const reference = Object.values(this.application.references).find((ref) => ref.label === label);
+    try {
+      await this.referenceService.createReference(this.applicationName, reference.id, refFile);
+      this.alertService.toastSuccess(this.$t("alert.reference-updated"));
+    } catch (error) {
+      this.alertService.toastError(this.$t("alert.reference-csv-upload-error"), error);
+    }
+  }
 }
 </script>
-- 
GitLab


From 6cbdcae934a856c37307b5ea3071548b1c434e82 Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Thu, 17 Jun 2021 17:23:32 +0200
Subject: [PATCH 26/27] =?UTF-8?q?Branche=20les=20donn=C3=A9es=20de=20r?=
 =?UTF-8?q?=C3=A9f=C3=A9rentiels=20au=20back?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ui2/src/services/rest/ReferenceService.js     |  2 +-
 .../views/references/ReferenceTableView.vue   | 30 +++++++++++++++----
 2 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/ui2/src/services/rest/ReferenceService.js b/ui2/src/services/rest/ReferenceService.js
index 49c4d596b..36c03c446 100644
--- a/ui2/src/services/rest/ReferenceService.js
+++ b/ui2/src/services/rest/ReferenceService.js
@@ -7,7 +7,7 @@ export class ReferenceService extends Fetcher {
     super();
   }
 
-  async getReference(applicationName, referenceId) {
+  async getReferenceValues(applicationName, referenceId) {
     return this.get(`applications/${applicationName}/references/${referenceId}`);
   }
 
diff --git a/ui2/src/views/references/ReferenceTableView.vue b/ui2/src/views/references/ReferenceTableView.vue
index 4fc66f428..ac4054039 100644
--- a/ui2/src/views/references/ReferenceTableView.vue
+++ b/ui2/src/views/references/ReferenceTableView.vue
@@ -7,7 +7,7 @@
 
     <div v-if="reference && columns">
       <b-table
-        :data="[]"
+        :data="tableValues"
         :striped="true"
         :isFocusable="true"
         :isHoverable="true"
@@ -19,11 +19,13 @@
         <b-table-column
           v-for="column in columns"
           :key="column.id"
-          :field="column.title"
+          :field="column.id"
           :label="column.title"
           sortable
           :sticky="column.key"
+          v-slot="props"
         >
+          {{ props.row[column.id] }}
         </b-table-column>
       </b-table>
     </div>
@@ -35,6 +37,7 @@ import SubMenu, { SubMenuPath } from "@/components/common/SubMenu.vue";
 import { ApplicationResult } from "@/model/ApplicationResult";
 import { AlertService } from "@/services/AlertService";
 import { ApplicationService } from "@/services/rest/ApplicationService";
+import { ReferenceService } from "@/services/rest/ReferenceService";
 import { Prop, Vue, Component } from "vue-property-decorator";
 import PageView from "../common/PageView.vue";
 
@@ -47,20 +50,30 @@ export default class ReferenceTableView extends Vue {
 
   alertService = AlertService.INSTANCE;
   applicationService = ApplicationService.INSTANCE;
+  referenceService = ReferenceService.INSTANCE;
 
   application = new ApplicationResult();
   subMenuPaths = [];
   reference = {};
   columns = [];
+  referenceValues = [];
+  tableValues = [];
 
-  created() {
-    this.init();
+  async created() {
+    await this.init();
+    this.setInitialVariables();
   }
 
   async init() {
     try {
       this.application = await this.applicationService.getApplication(this.applicationName);
-      this.setInitialVariables();
+      const references = await this.referenceService.getReferenceValues(
+        this.applicationName,
+        this.refId
+      );
+      if (references) {
+        this.referenceValues = references.referenceValues;
+      }
     } catch (error) {
       this.alertService.toastServerError();
     }
@@ -96,6 +109,13 @@ export default class ReferenceTableView extends Vue {
         return 0;
       });
     }
+
+    console.log(this.columns);
+
+    if (this.referenceValues) {
+      this.tableValues = Object.values(this.referenceValues).map((refValue) => refValue.values);
+      console.log(this.tableValues);
+    }
   }
 }
 </script>
-- 
GitLab


From c6a7493e3571a87d00c63add053619b9d8a0d1eb Mon Sep 17 00:00:00 2001
From: Aurore Lecointe <lecointe@codelutin.com>
Date: Thu, 17 Jun 2021 17:55:29 +0200
Subject: [PATCH 27/27] =?UTF-8?q?Met=20les=20actions=20sur=20les=20r=C3=A9?=
 =?UTF-8?q?f=C3=A9rentiels=20sur=20la=20ligne?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ui2/src/components/common/CollapsibleTree.vue | 65 ++++++++++++++-----
 .../references/ReferencesDetailsPanel.vue     |  8 ---
 ui2/src/model/Button.js                       | 15 +++++
 .../references/ReferencesManagementView.vue   | 19 +++++-
 4 files changed, 80 insertions(+), 27 deletions(-)
 create mode 100644 ui2/src/model/Button.js

diff --git a/ui2/src/components/common/CollapsibleTree.vue b/ui2/src/components/common/CollapsibleTree.vue
index 652fb7790..d12ccdda5 100644
--- a/ui2/src/components/common/CollapsibleTree.vue
+++ b/ui2/src/components/common/CollapsibleTree.vue
@@ -21,21 +21,34 @@
           {{ label }}
         </div>
       </div>
-      <b-field class="file is-primary" v-if="onUploadCb">
-        <b-upload
-          v-model="refFile"
-          class="file-label"
-          accept=".csv"
-          @input="() => onUploadCb(label, refFile)"
-        >
-          <span class="file-name" v-if="refFile">
-            {{ refFile.name }}
-          </span>
-          <span class="file-cta">
-            <b-icon class="file-icon" icon="upload"></b-icon>
-          </span>
-        </b-upload>
-      </b-field>
+      <div class="CollapsibleTree-buttons">
+        <b-field class="file button is-small is-info" v-if="onUploadCb">
+          <b-upload
+            v-model="refFile"
+            class="file-label"
+            accept=".csv"
+            @input="() => onUploadCb(label, refFile)"
+          >
+            <span class="file-name" v-if="refFile">
+              {{ refFile.name }}
+            </span>
+            <span class="file-cta">
+              <b-icon class="file-icon" icon="upload"></b-icon>
+            </span>
+          </b-upload>
+        </b-field>
+        <div v-for="button in buttons" :key="button.id">
+          <b-button
+            :icon-left="button.iconName"
+            size="is-small"
+            @click="button.clickCb(label)"
+            class="ml-1"
+            :type="button.type"
+          >
+            {{ button.label }}</b-button
+          >
+        </div>
+      </div>
     </div>
     <div v-if="displayChildren">
       <CollapsibleTree
@@ -46,6 +59,7 @@
         :level="level + 1"
         :onClickLabelCb="onClickLabelCb"
         :onUploadCb="onUploadCb"
+        :buttons="buttons"
       />
     </div>
   </div>
@@ -64,6 +78,7 @@ export default class CollapsibleTree extends Vue {
   @Prop() level;
   @Prop() onClickLabelCb;
   @Prop() onUploadCb;
+  @Prop() buttons;
 
   displayChildren = false;
   refFile = null;
@@ -71,10 +86,12 @@ export default class CollapsibleTree extends Vue {
 </script>
 
 <style lang="scss" scoped>
+$row-height: 40px;
+
 .CollapsibleTree-header {
   display: flex;
   align-items: center;
-  height: 40px;
+  height: $row-height;
   padding: 0.75rem;
   justify-content: space-between;
 
@@ -101,4 +118,20 @@ export default class CollapsibleTree extends Vue {
   display: flex;
   align-items: center;
 }
+
+.CollapsibleTree-buttons {
+  display: flex;
+  height: $row-height;
+  align-items: center;
+
+  .file {
+    margin-bottom: 0;
+
+    .file-cta {
+      height: 100%;
+      background-color: transparent;
+      border-color: transparent;
+    }
+  }
+}
 </style>
diff --git a/ui2/src/components/references/ReferencesDetailsPanel.vue b/ui2/src/components/references/ReferencesDetailsPanel.vue
index 10c56d924..1fdae4b09 100644
--- a/ui2/src/components/references/ReferencesDetailsPanel.vue
+++ b/ui2/src/components/references/ReferencesDetailsPanel.vue
@@ -6,10 +6,6 @@
     :closeCb="closeCb"
   >
     <div class="Panel-buttons">
-      <b-button type="is-primary" icon-left="eye" @click="emitConsult">{{
-        $t("referencesManagement.consult")
-      }}</b-button>
-      <b-button icon-left="download">{{ $t("referencesManagement.download") }}</b-button>
       <b-button type="is-danger" icon-left="trash-alt" @click="askDeletionConfirmation">{{
         $t("referencesManagement.delete")
       }}</b-button>
@@ -46,10 +42,6 @@ export default class ReferencesDetailsPanel extends Vue {
   deleteReference() {
     console.log("DELETE", this.reference);
   }
-
-  emitConsult() {
-    this.$emit("consultReference", this.reference.id);
-  }
 }
 </script>
 
diff --git a/ui2/src/model/Button.js b/ui2/src/model/Button.js
new file mode 100644
index 000000000..5d3d08c39
--- /dev/null
+++ b/ui2/src/model/Button.js
@@ -0,0 +1,15 @@
+export class Button {
+  id;
+  label;
+  iconName;
+  clickCb;
+  type;
+
+  constructor(label, iconName, clickCb, type, id) {
+    this.label = label;
+    this.iconName = iconName;
+    this.clickCb = clickCb;
+    this.id = id ? id : label ? label : iconName;
+    this.type = type;
+  }
+}
diff --git a/ui2/src/views/references/ReferencesManagementView.vue b/ui2/src/views/references/ReferencesManagementView.vue
index f5151530f..370caf82f 100644
--- a/ui2/src/views/references/ReferencesManagementView.vue
+++ b/ui2/src/views/references/ReferencesManagementView.vue
@@ -13,13 +13,13 @@
         :level="0"
         :onClickLabelCb="(event, label) => openRefDetails(event, label)"
         :onUploadCb="(label, refFile) => uploadReferenceCsv(label, refFile)"
+        :buttons="buttons"
       />
       <ReferencesDetailsPanel
         :leftAlign="false"
         :open="openPanel"
         :reference="chosenRef"
         :closeCb="(newVal) => (openPanel = newVal)"
-        @consultReference="consultReference"
       />
     </div>
   </PageView>
@@ -37,6 +37,7 @@ import PageView from "../common/PageView.vue";
 import { ApplicationResult } from "@/model/ApplicationResult";
 import SubMenu, { SubMenuPath } from "@/components/common/SubMenu.vue";
 import { AlertService } from "@/services/AlertService";
+import { Button } from "@/model/Button";
 
 @Component({
   components: { CollapsibleTree, ReferencesDetailsPanel, PageView, SubMenu },
@@ -53,6 +54,15 @@ export default class ReferencesManagementView extends Vue {
   chosenRef = null;
   application = new ApplicationResult();
   subMenuPaths = [];
+  buttons = [
+    new Button(
+      this.$t("referencesManagement.consult"),
+      "eye",
+      (label) => this.consultReference(label),
+      "is-primary"
+    ),
+    new Button(this.$t("referencesManagement.download"), "download"),
+  ];
 
   created() {
     this.subMenuPaths = [
@@ -81,8 +91,11 @@ export default class ReferencesManagementView extends Vue {
     this.chosenRef = Object.values(this.application.references).find((ref) => ref.label === label);
   }
 
-  consultReference(id) {
-    this.$router.push(`/applications/${this.applicationName}/references/${id}`);
+  consultReference(label) {
+    const ref = Object.values(this.application.references).find((ref) => ref.label === label);
+    if (ref) {
+      this.$router.push(`/applications/${this.applicationName}/references/${ref.id}`);
+    }
   }
 
   async uploadReferenceCsv(label, refFile) {
-- 
GitLab