From f984712afae7c00c92a7a4a52c9ca33807fe24b1 Mon Sep 17 00:00:00 2001
From: Valentin Rigal <rigal@teklia.com>
Date: Thu, 11 Apr 2024 10:15:50 +0000
Subject: [PATCH] Support toggling dataset element uniqueness

---
 src/api/dataset.ts                            |  4 +--
 src/components/Corpus/Datasets/EditModal.vue  | 29 +++++++++++++++----
 src/components/Corpus/Datasets/List.vue       |  3 +-
 src/components/Corpus/Datasets/Row.vue        |  4 +++
 .../Navigation/DatasetFromSelectionModal.vue  | 12 +++++++-
 src/types/dataset.ts                          |  1 +
 src/views/Dataset/Details.vue                 |  5 ++++
 7 files changed, 49 insertions(+), 9 deletions(-)

diff --git a/src/api/dataset.ts b/src/api/dataset.ts
index 9db7186d4..a31e43ade 100644
--- a/src/api/dataset.ts
+++ b/src/api/dataset.ts
@@ -5,9 +5,9 @@ import { Dataset, DatasetElementList, ElementDatasetSet } from '@/types/dataset'
 
 export interface DatasetListParameters extends CursorPaginationParameters { set?: string | null }
 
-export type DatasetEdit = Pick<Dataset, 'id' | 'name' | 'description'>
+export type DatasetEdit = Pick<Dataset, 'id' | 'name' | 'description' | 'unique_elements'>
 
-export interface DatasetCreate extends Pick<Dataset, 'name' | 'description'> {
+export interface DatasetCreate extends Pick<Dataset, 'name' | 'description' | 'unique_elements'> {
   set_names: string[]
 }
 
diff --git a/src/components/Corpus/Datasets/EditModal.vue b/src/components/Corpus/Datasets/EditModal.vue
index 4a2decb68..047d75234 100644
--- a/src/components/Corpus/Datasets/EditModal.vue
+++ b/src/components/Corpus/Datasets/EditModal.vue
@@ -80,6 +80,20 @@
           </div>
         </div>
       </div>
+      <div class="field">
+        <div class="control">
+          <label class="checkbox">
+            <input
+              type="checkbox"
+              v-model="newDataset.unique_elements"
+            />
+            Require unique elements among sets
+          </label>
+        </div>
+        <template v-if="fieldErrors.unique_elements">
+          <p class="help is-danger">{{ fieldErrors.unique_elements }}</p>
+        </template>
+      </div>
     </form>
     <template v-slot:footer="{ close }">
       <button class="button" v-on:click="close">Cancel</button>
@@ -135,7 +149,8 @@ export default {
     newDataset: {
       name: '',
       description: '',
-      sets: []
+      sets: [],
+      unique_elements: true
     },
     loading: false,
     fieldErrors: {}
@@ -145,7 +160,8 @@ export default {
       this.newDataset = {
         name: this.datasetInstance.name,
         description: this.datasetInstance.description,
-        sets: this.datasetInstance.sets
+        sets: this.datasetInstance.sets,
+        unique_elements: this.datasetInstance.unique_elements
       }
     }
   },
@@ -175,7 +191,8 @@ export default {
       this.loading = true
       const data = {
         name: this.newDataset.name.trim(),
-        description: this.newDataset.description.trim()
+        description: this.newDataset.description.trim(),
+        unique_elements: this.newDataset.unique_elements
       }
       // Add list of set names to the payload when creating a new dataset
       if (!this.datasetInstance) {
@@ -234,13 +251,15 @@ export default {
           this.newDataset = {
             name: this.datasetInstance.name,
             description: this.datasetInstance.description,
-            sets: this.datasetInstance.sets
+            sets: this.datasetInstance.sets,
+            unique_elements: this.datasetInstance.unique_elements
           }
         } else {
           this.newDataset = {
             name: '',
             description: '',
-            sets: ['train', 'validation', 'test']
+            sets: ['train', 'validation', 'test'],
+            unique_elements: true
           }
         }
         this.fieldErrors = {}
diff --git a/src/components/Corpus/Datasets/List.vue b/src/components/Corpus/Datasets/List.vue
index 332543aec..c434c4c95 100644
--- a/src/components/Corpus/Datasets/List.vue
+++ b/src/components/Corpus/Datasets/List.vue
@@ -5,6 +5,7 @@
         <th>Name</th>
         <th>Description</th>
         <th>State</th>
+        <th>Unique elements</th>
         <th class="is-narrow">Actions</th>
       </tr>
     </thead>
@@ -16,7 +17,7 @@
         :corpus-id="corpusId"
       />
       <tr>
-        <td colspan="3"></td>
+        <td colspan="4"></td>
         <td class="is-narrow has-text-right">
           <button
             class="button is-primary"
diff --git a/src/components/Corpus/Datasets/Row.vue b/src/components/Corpus/Datasets/Row.vue
index 5410f19e3..a964783e6 100644
--- a/src/components/Corpus/Datasets/Row.vue
+++ b/src/components/Corpus/Datasets/Row.vue
@@ -12,6 +12,10 @@
     <td>
       <StateTag :state="dataset.state" />
     </td>
+    <td>
+      <span v-if="dataset.unique_elements">✅</span>
+      <span v-else>❌</span>
+    </td>
     <td>
       <span class="is-inline-flex">
         <button
diff --git a/src/components/Navigation/DatasetFromSelectionModal.vue b/src/components/Navigation/DatasetFromSelectionModal.vue
index f009355fb..1cf7b7299 100644
--- a/src/components/Navigation/DatasetFromSelectionModal.vue
+++ b/src/components/Navigation/DatasetFromSelectionModal.vue
@@ -72,6 +72,9 @@
                 </select>
               </span>
             </div>
+            <template v-if="fieldErrors.set_id">
+              <p v-for="err in fieldErrors.set_id" :key="err" class="help is-danger">{{ err }}</p>
+            </template>
           </div>
         </div>
       </div>
@@ -94,6 +97,7 @@
 </template>
 
 <script lang="ts">
+import { isAxiosError } from 'axios'
 import { mapState, mapActions } from 'pinia'
 import { corporaMixin, truncateMixin } from '@/mixins'
 import { UUID_REGEX } from '@/config'
@@ -137,7 +141,8 @@ export default defineComponent({
     /**
      * Name of the set elements will be added to
      */
-    selectedSet: null as DatasetSet | null
+    selectedSet: null as DatasetSet | null,
+    fieldErrors: {} as { [key: string]: string[] | undefined }
   }),
   computed: {
     ...mapState(useDatasetStore, ['corpusDatasets', 'singleCorpusDatasets']),
@@ -160,6 +165,7 @@ export default defineComponent({
       if (!this.selectedDataset || !this.selectedSet) return
 
       this.loading = true
+      this.fieldErrors = {}
       try {
         await this.addDatasetElementsSelection(
           this.corpusId,
@@ -169,6 +175,10 @@ export default defineComponent({
         this.selectedDataset = null
         this.selectedSet = null
         this.$emit('update:modelValue', false)
+      } catch (err) {
+        if (isAxiosError(err) && err.response?.status === 400 && err.response.data) {
+          this.fieldErrors = err.response.data
+        }
       } finally {
         this.loading = false
       }
diff --git a/src/types/dataset.ts b/src/types/dataset.ts
index 166b51abe..82c19149d 100644
--- a/src/types/dataset.ts
+++ b/src/types/dataset.ts
@@ -18,6 +18,7 @@ export interface Dataset {
   corpus_id: UUID
   creator: string
   task_id: UUID | null
+  unique_elements: boolean
   created: string
   updated: string
 }
diff --git a/src/views/Dataset/Details.vue b/src/views/Dataset/Details.vue
index 88f9b13b9..33b3e79a2 100644
--- a/src/views/Dataset/Details.vue
+++ b/src/views/Dataset/Details.vue
@@ -24,6 +24,11 @@
         <label class="label mr-2">State</label>
         <StateTag :state="dataset.state" />
       </div>
+      <div class="field is-horizontal">
+        <label class="label mr-2">Unique elements</label>
+        <span v-if="dataset.unique_elements">✅</span>
+        <span v-else>❌</span>
+      </div>
       <div class="field">
         <label class="label">Description</label>
         <div class="control">
-- 
GitLab