From bfc47d664991f4ee8e71c2b668cfb11522f067ae Mon Sep 17 00:00:00 2001
From: Julien Touchais <5978-julien.touchais@users.noreply.forgemia.inra.fr>
Date: Thu, 6 Feb 2025 14:24:18 +0100
Subject: [PATCH 1/5] refactor: :art: Prettier formatting

---
 src/components/SequenceBoard.vue | 135 ++++++++++---------------------
 src/typings/typeUtils.ts         |   4 +-
 2 files changed, 45 insertions(+), 94 deletions(-)

diff --git a/src/components/SequenceBoard.vue b/src/components/SequenceBoard.vue
index df6849b..694b03a 100644
--- a/src/components/SequenceBoard.vue
+++ b/src/components/SequenceBoard.vue
@@ -172,10 +172,7 @@ const splitSequence = computed(() =>
  */
 const isInObject = (position: number, objectId: string): boolean => {
   const object = props.objects?.[objectId]
-  return (
-    !!object &&
-    _inRange(position, object.start, object.end + 1)
-  )
+  return !!object && _inRange(position, object.start, object.end + 1)
 }
 
 /**
@@ -196,9 +193,7 @@ const objectIdsContaining = (position: number): string[] =>
  * @returns A list of tuples, `[object ID, object]` for each of the objects
  * containing the nucleotide.
  */
-const objectsContaining = (
-  position: number
-): [string, objectModel][] =>
+const objectsContaining = (position: number): [string, objectModel][] =>
   props.objects
     ? Object.entries(props.objects).filter(([objectId]) =>
         isInObject(position, objectId)
@@ -222,9 +217,7 @@ const objectsBoundaryPositions = computed(
     props.objects &&
     Object.values(props.objects).reduce(
       (objectsBoundaryPositions, object) =>
-        objectsBoundaryPositions
-          .add(object.start)
-          .add(object.end),
+        objectsBoundaryPositions.add(object.start).add(object.end),
       new Set<number>()
     )
 )
@@ -350,38 +343,34 @@ const objectsLineCount = ref<{
  * dividing by the line height.
  */
 const updateObjectsLineCount = () =>
-  (objectsLineCount.value = _mapValues(
-    props.objects,
-    (object) => {
-      // Parent DOM elements of the first and last nucleotide of the object
-      const objectStartNucleotideElementParent = objectBoundaryElements.value.find(
-        (element) =>
-          element.dataset.position === object.start.toString()
-      )?.offsetParent
-      const objectEndNucleotideElementParent = objectBoundaryElements.value.find(
-        (element) =>
-          element.dataset.position === object.end.toString()
+  (objectsLineCount.value = _mapValues(props.objects, (object) => {
+    // Parent DOM elements of the first and last nucleotide of the object
+    const objectStartNucleotideElementParent =
+      objectBoundaryElements.value.find(
+        (element) => element.dataset.position === object.start.toString()
       )?.offsetParent
+    const objectEndNucleotideElementParent = objectBoundaryElements.value.find(
+      (element) => element.dataset.position === object.end.toString()
+    )?.offsetParent
 
-      if (
-        !(
-          objectStartNucleotideElementParent instanceof HTMLElement &&
-          objectEndNucleotideElementParent instanceof HTMLElement
-        )
-      ) {
-        return undefined
-      }
-
-      return (
-        lineHeight.value &&
-        Math.round(
-          (objectEndNucleotideElementParent.offsetTop -
-            objectStartNucleotideElementParent.offsetTop) /
-            lineHeight.value
-        ) + 1
+    if (
+      !(
+        objectStartNucleotideElementParent instanceof HTMLElement &&
+        objectEndNucleotideElementParent instanceof HTMLElement
       )
+    ) {
+      return undefined
     }
-  ))
+
+    return (
+      lineHeight.value &&
+      Math.round(
+        (objectEndNucleotideElementParent.offsetTop -
+          objectStartNucleotideElementParent.offsetTop) /
+          lineHeight.value
+      ) + 1
+    )
+  }))
 
 /**
  * Width of the sequence container.
@@ -525,8 +514,7 @@ const objectBoxStyles = computed(() =>
   _mapValues(props.objects, (object, objectId) => {
     // DOM element of the first and last nucleotides of the object
     const objectStartNucleotideElement = objectBoundaryElements.value.find(
-      (element) =>
-        element.dataset.position === object.start.toString()
+      (element) => element.dataset.position === object.start.toString()
     )
     const objectEndNucleotideElement = objectBoundaryElements.value.find(
       (element) => element.dataset.position === object.end.toString()
@@ -557,8 +545,7 @@ const objectBoxStyles = computed(() =>
       (objectEndNucleotideElement.offsetWidth || 0)
 
     // Number of fragment in which the current object box is divided
-    const objectBoxFragmentsCount =
-      objectsLineCount.value?.[objectId] || 0
+    const objectBoxFragmentsCount = objectsLineCount.value?.[objectId] || 0
 
     // Array of length equals # of fragments, containing style for each of them
     return Array.from(
@@ -739,19 +726,13 @@ const lockTooltip = () => {
               v-if="
                 objectsContaining(
                   nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
-                ).find(
-                  ([, object]) =>
-                    object.shouldTooltip
-                )
+                ).find(([, object]) => object.shouldTooltip)
               "
               :class="[
                 'absolute -bottom-0.5 -left-[0.1875rem] -right-[0.1875rem] -top-0.5',
                 objectsContaining(
                   nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
-                ).find(
-                  ([, object]) =>
-                    object.link
-                )
+                ).find(([, object]) => object.link)
                   ? 'cursor-pointer'
                   : 'cursor-help'
               ]"
@@ -761,10 +742,7 @@ const lockTooltip = () => {
                 ).forEach(
                   ([objectId, object]) =>
                     object.shouldTooltip &&
-                    hoveredObjects.add([
-                      objectId,
-                      object
-                    ])
+                    hoveredObjects.add([objectId, object])
                 )
               "
               @mouseleave="hoveredObjects.clear()"
@@ -789,19 +767,13 @@ const lockTooltip = () => {
               v-if="
                 objectsContaining(
                   nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
-                ).find(
-                  ([, object]) =>
-                    object.shouldTooltip
-                )
+                ).find(([, object]) => object.shouldTooltip)
               "
               :class="[
                 'absolute -bottom-0.5 -left-[0.1875rem] -right-[0.1875rem] -top-0.5',
                 objectsContaining(
                   nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
-                ).find(
-                  ([, object]) =>
-                    object.link
-                )
+                ).find(([, object]) => object.link)
                   ? 'cursor-pointer'
                   : 'cursor-help'
               ]"
@@ -811,10 +783,7 @@ const lockTooltip = () => {
                 ).forEach(
                   ([objectId, object]) =>
                     object.shouldTooltip &&
-                    hoveredObjects.add([
-                      objectId,
-                      object
-                    ])
+                    hoveredObjects.add([objectId, object])
                 )
               "
               @mouseleave="hoveredObjects.clear()"
@@ -834,30 +803,22 @@ const lockTooltip = () => {
       </span>
 
       <span
-        v-for="[objectId, object] in Object.entries(
-          objects || {}
-        )"
+        v-for="[objectId, object] in Object.entries(objects || {})"
         :key="objectId"
         class="object"
       >
         <span
-          v-for="fragmentIndex in range(
-            objectsLineCount?.[objectId] || 0
-          )"
+          v-for="fragmentIndex in range(objectsLineCount?.[objectId] || 0)"
           :key="fragmentIndex"
           :style="objectBoxStyles?.[objectId]?.[fragmentIndex]"
           :class="[
             'object-fragment absolute h-8 border-y-2 bg-opacity-50 px-0.5 text-2xl mix-blend-multiply',
-            [
-              `!border-${object.color}-600`,
-              `bg-${object.color}-100`
-            ],
+            [`!border-${object.color}-600`, `bg-${object.color}-100`],
             {
               'rounded-l-xl border-l-2': fragmentIndex === 0,
               'rounded-r-xl border-r-2':
                 objectsLineCount &&
-                fragmentIndex + 1 ===
-                  objectsLineCount[objectId]
+                fragmentIndex + 1 === objectsLineCount[objectId]
             },
             object.shouldTooltip &&
               (object.link ? 'cursor-pointer' : 'cursor-help')
@@ -872,17 +833,11 @@ const lockTooltip = () => {
         @unlock="lockedTooltipObjects = undefined"
       >
         <ul class="flex flex-col gap-1">
-          <li
-            v-for="(object, index) in tooltipObjects"
-            :key="index"
-          >
+          <li v-for="(object, index) in tooltipObjects" :key="index">
             <RouterLink
               v-if="object[1].link"
               :to="object[1].link"
-              :class="[
-                `text-${object[1].color}-600`,
-                'whitespace-nowrap'
-              ]"
+              :class="[`text-${object[1].color}-600`, 'whitespace-nowrap']"
             >
               <slot
                 name="tooltip-item"
@@ -890,9 +845,7 @@ const lockTooltip = () => {
                 :object-id="object[0]"
               >
                 {{ object[1].name || object[1].link }}
-                {{
-                  object[1].type && ` - ${object[1].type}`
-                }}
+                {{ object[1].type && ` - ${object[1].type}` }}
               </slot>
             </RouterLink>
             <span v-else>
@@ -902,9 +855,7 @@ const lockTooltip = () => {
                 :object-id="object[0]"
               >
                 {{ object[1].name || object[1].link }}
-                {{
-                  object[1].type && ` - ${object[1].type}`
-                }}
+                {{ object[1].type && ` - ${object[1].type}` }}
               </slot>
             </span>
           </li>
diff --git a/src/typings/typeUtils.ts b/src/typings/typeUtils.ts
index d23a9f3..96c259a 100644
--- a/src/typings/typeUtils.ts
+++ b/src/typings/typeUtils.ts
@@ -115,6 +115,6 @@ export type SubType<BaseType, ConditionType> = Pick<
  * Checks if an array contains at least one element, narrowing its type.
  * @param array The array for which to check the length.
  */
-export function isNotEmpty<T>(array: T[]): array is [T,...T[]] {
+export function isNotEmpty<T>(array: T[]): array is [T, ...T[]] {
   return array.length >= 1
-}
\ No newline at end of file
+}
-- 
GitLab


From b370db4b95f14a5e8cc45496ee99330bd8727bbf Mon Sep 17 00:00:00 2001
From: Julien Touchais <5978-julien.touchais@users.noreply.forgemia.inra.fr>
Date: Thu, 6 Feb 2025 14:27:41 +0100
Subject: [PATCH 2/5] fix(advanced-selection): :bug: wrong gql query variable
 name

---
 src/components/SelectionFormGuide.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/SelectionFormGuide.vue b/src/components/SelectionFormGuide.vue
index 91b30ae..e11414f 100644
--- a/src/components/SelectionFormGuide.vue
+++ b/src/components/SelectionFormGuide.vue
@@ -74,7 +74,7 @@ const selection = ref<GuideSelectionModel>({
 const gqlQuery = useQuery({
   query: guideSelectionQuery,
   variables: toRef(() => ({
-    guideSubclass: selection.value.guideSubclasses?.length
+    guideSubclasses: selection.value.guideSubclasses?.length
       ? selection.value.guideSubclasses
       : undefined,
     targetNames: selection.value.targetNames?.length
-- 
GitLab


From cbe656e03023d1e9bd8a79518bf3ccc2232c05c7 Mon Sep 17 00:00:00 2001
From: Julien Touchais <5978-julien.touchais@users.noreply.forgemia.inra.fr>
Date: Thu, 6 Feb 2025 14:29:47 +0100
Subject: [PATCH 3/5] feat(advanced-selection): :sparkles: add a text to
 describe advanced selection

---
 src/views/SelectionView.vue | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/views/SelectionView.vue b/src/views/SelectionView.vue
index cf4fd8e..9868e25 100644
--- a/src/views/SelectionView.vue
+++ b/src/views/SelectionView.vue
@@ -180,6 +180,11 @@ const onlyTargetIdActiveMode = computed(() =>
       Advanced selection
     </h1>
 
+    <h3 class="my-8 text-center italic text-slate-500">
+      Filter the {{ activeMode }}s of the snoBoard's database to list them in
+      the table.
+    </h3>
+
     <SelectionForm
       v-model:current-mode-model="activeMode"
       v-model:selection-model="selection"
-- 
GitLab


From fb241fd3c7f962f31fff7465fcbcb9b1879b235e Mon Sep 17 00:00:00 2001
From: Julien Touchais <5978-julien.touchais@users.noreply.forgemia.inra.fr>
Date: Thu, 6 Feb 2025 14:33:14 +0100
Subject: [PATCH 4/5] feat(linear-sequence): :fire: instruction text always
 visible (no tooltip)

---
 src/components/SequenceBoard.vue | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/src/components/SequenceBoard.vue b/src/components/SequenceBoard.vue
index 694b03a..eb31849 100644
--- a/src/components/SequenceBoard.vue
+++ b/src/components/SequenceBoard.vue
@@ -14,7 +14,6 @@ import Toolbar from 'primevue/toolbar'
 import IconFa6SolidDna from '~icons/fa6-solid/dna'
 import IconFa6SolidCircleCheck from '~icons/fa6-solid/circle-check'
 import IconFa6RegularCopy from '~icons/fa6-regular/copy'
-import IconFa6SolidCircleInfo from '~icons/fa6-solid/circle-info'
 /**
  * Composables imports
  */
@@ -634,18 +633,9 @@ const lockTooltip = () => {
             <slot name="legend-item-description" :item="item" />
           </template>
         </BaseLegendButtonOverlay>
-        <span class="text-sm italic text-slate-600 md:hidden">
+        <span class="text-sm italic text-slate-600">
           Click on an object to lock its tooltip in place.
         </span>
-        <span
-          v-tooltip.right="{
-            value: 'Click on an object to lock its tooltip in place.',
-            pt: { text: 'text-xs' }
-          }"
-          class="absolute -right-2 -top-2 hidden text-base text-slate-600 md:inline"
-        >
-          <icon-fa6-solid-circle-info />
-        </span>
       </div>
     </template>
 
-- 
GitLab


From 7b9c6cb4d0941f5d0414c01d8405ebf92d5d57cd Mon Sep 17 00:00:00 2001
From: Julien Touchais <5978-julien.touchais@users.noreply.forgemia.inra.fr>
Date: Thu, 6 Feb 2025 14:37:00 +0100
Subject: [PATCH 5/5] feat(advanced-selection): :sparkles: add information
 about the role of each field

---
 src/components/SelectionFormGuide.vue        | 64 ++++++++++++++++++--
 src/components/SelectionFormModification.vue | 49 +++++++++++++--
 src/components/SelectionFormTarget.vue       | 49 +++++++++++++--
 3 files changed, 149 insertions(+), 13 deletions(-)

diff --git a/src/components/SelectionFormGuide.vue b/src/components/SelectionFormGuide.vue
index e11414f..f6e2be2 100644
--- a/src/components/SelectionFormGuide.vue
+++ b/src/components/SelectionFormGuide.vue
@@ -10,7 +10,7 @@ import BaseRenderedMarkdown from './BaseRenderedMarkdown.vue'
 import Chip from 'primevue/chip'
 import SelectButton from 'primevue/selectbutton'
 import MultiSelect from 'primevue/multiselect'
-import { GuideClass, ModifType } from '@/gql/codegen/graphql'
+import IconFa6SolidCircleQuestion from '~icons/fa6-solid/circle-question'
 /**
  * Composables imports
  */
@@ -19,6 +19,10 @@ import { useQuery } from '@urql/vue'
  * Other 3rd-party imports
  */
 import { uniqWith as _uniqWith, isEqual as _isEqual } from 'lodash-es'
+/**
+ * Types imports
+ */
+import { GuideClass, ModifType } from '@/gql/codegen/graphql'
 /**
  * Utils imports
  */
@@ -293,7 +297,19 @@ const organismIdOptionsWithDisabling = computed(() =>
   <div
     class="grid max-w-max grid-cols-[max-content_1fr] grid-rows-4 items-center gap-x-16 gap-y-8"
   >
-    <h3 class="text-lg font-bold">Guide subclasses</h3>
+    <h3 class="text-lg font-bold">
+      Guide subclasses
+      <span
+        v-tooltip.right="{
+          value: 'Only guides of the selected subclasses will be retained.',
+          pt: { text: 'text-xs' }
+        }"
+        class="-mt-1 inline-block align-top text-sm text-slate-600"
+      >
+        <icon-fa6-solid-circle-question class="inline" />
+      </span>
+    </h3>
+
     <SelectButton
       v-model="selection.guideSubclasses"
       :options="guideSubclassOptionsWithDisabling"
@@ -325,7 +341,20 @@ const organismIdOptionsWithDisabling = computed(() =>
       </template>
     </SelectButton>
 
-    <h3 class="text-lg font-bold">Targets</h3>
+    <h3 class="text-lg font-bold">
+      Targets
+      <span
+        v-tooltip.right="{
+          value:
+            'Only guides which interact with the selected targets will be retained.',
+          pt: { text: 'text-xs' }
+        }"
+        class="-mt-1 inline-block align-top text-sm text-slate-600"
+      >
+        <icon-fa6-solid-circle-question class="inline" />
+      </span>
+    </h3>
+
     <MultiSelect
       v-model="selection.targetNames"
       :options="targetNameOptionsWithDisablingGroups"
@@ -370,7 +399,20 @@ const organismIdOptionsWithDisabling = computed(() =>
       </template>
     </MultiSelect>
 
-    <h3 class="text-lg font-bold">Guided modification types</h3>
+    <h3 class="text-lg font-bold">
+      Guided modification types
+      <span
+        v-tooltip.right="{
+          value:
+            'Only guides which guide at least a modification of the selected types will be retained.',
+          pt: { text: 'text-xs' }
+        }"
+        class="-mt-1 inline-block align-top text-sm text-slate-600"
+      >
+        <icon-fa6-solid-circle-question class="inline" />
+      </span>
+    </h3>
+
     <SelectButton
       v-model="selection.modificationTypes"
       :options="modificationTypeOptionsWithDisabling"
@@ -389,7 +431,19 @@ const organismIdOptionsWithDisabling = computed(() =>
       </template>
     </SelectButton>
 
-    <h3 class="text-lg font-bold">Organisms</h3>
+    <h3 class="text-lg font-bold">
+      Organisms
+      <span
+        v-tooltip.right="{
+          value: 'Only guides of the selected organisms will be retained.',
+          pt: { text: 'text-xs' }
+        }"
+        class="-mt-1 inline-block align-top text-sm text-slate-600"
+      >
+        <icon-fa6-solid-circle-question class="inline" />
+      </span>
+    </h3>
+
     <MultiSelect
       v-model="selection.organismIds"
       :options="organismIdOptionsWithDisabling"
diff --git a/src/components/SelectionFormModification.vue b/src/components/SelectionFormModification.vue
index c0a2344..6c102b9 100644
--- a/src/components/SelectionFormModification.vue
+++ b/src/components/SelectionFormModification.vue
@@ -10,7 +10,7 @@ import BaseRenderedMarkdown from './BaseRenderedMarkdown.vue'
 import Chip from 'primevue/chip'
 import SelectButton from 'primevue/selectbutton'
 import MultiSelect from 'primevue/multiselect'
-import { ModifType } from '@/gql/codegen/graphql'
+import IconFa6SolidCircleQuestion from '~icons/fa6-solid/circle-question'
 /**
  * Composables imports
  */
@@ -19,6 +19,10 @@ import { useQuery } from '@urql/vue'
  * Other 3rd-party imports
  */
 import { uniqWith as _uniqWith, isEqual as _isEqual } from 'lodash-es'
+/**
+ * Types imports
+ */
+import { ModifType } from '@/gql/codegen/graphql'
 /**
  * Utils imports
  */
@@ -258,7 +262,19 @@ watchEffect(() => {
   <div
     class="grid max-w-max grid-cols-[max-content_1fr] grid-rows-3 items-center gap-x-16 gap-y-8"
   >
-    <h3 class="text-lg font-bold">Modification types</h3>
+    <h3 class="text-lg font-bold">
+      Modification types
+      <span
+        v-tooltip.right="{
+          value: 'Only modifications of the selected types will be retained.',
+          pt: { text: 'text-xs' }
+        }"
+        class="-mt-1 inline-block align-top text-sm text-slate-600"
+      >
+        <icon-fa6-solid-circle-question class="inline" />
+      </span>
+    </h3>
+
     <SelectButton
       v-model="selection.modificationTypes"
       :options="modificationTypeOptionsWithDisabling"
@@ -277,7 +293,19 @@ watchEffect(() => {
       </template>
     </SelectButton>
 
-    <h3 class="text-lg font-bold">Targets</h3>
+    <h3 class="text-lg font-bold">
+      Targets
+      <span
+        v-tooltip.right="{
+          value: 'Only modifications of the selected targets will be retained.',
+          pt: { text: 'text-xs' }
+        }"
+        class="-mt-1 inline-block align-top text-sm text-slate-600"
+      >
+        <icon-fa6-solid-circle-question class="inline" />
+      </span>
+    </h3>
+
     <MultiSelect
       v-model="selection.targetNames"
       :options="targetNameOptionsWithDisablingGroups"
@@ -317,7 +345,20 @@ watchEffect(() => {
       </template>
     </MultiSelect>
 
-    <h3 class="text-lg font-bold">Organisms</h3>
+    <h3 class="text-lg font-bold">
+      Organisms
+      <span
+        v-tooltip.right="{
+          value:
+            'Only modifications of the targets of the selected organisms will be retained.',
+          pt: { text: 'text-xs' }
+        }"
+        class="-mt-1 inline-block align-top text-sm text-slate-600"
+      >
+        <icon-fa6-solid-circle-question class="inline" />
+      </span>
+    </h3>
+
     <MultiSelect
       v-model="selection.organismIds"
       :options="organismIdOptionsWithDisabling"
diff --git a/src/components/SelectionFormTarget.vue b/src/components/SelectionFormTarget.vue
index d22e087..044ee38 100644
--- a/src/components/SelectionFormTarget.vue
+++ b/src/components/SelectionFormTarget.vue
@@ -10,7 +10,7 @@ import BaseRenderedMarkdown from './BaseRenderedMarkdown.vue'
 import Chip from 'primevue/chip'
 import SelectButton from 'primevue/selectbutton'
 import MultiSelect from 'primevue/multiselect'
-import { ModifType } from '@/gql/codegen/graphql'
+import IconFa6SolidCircleQuestion from '~icons/fa6-solid/circle-question'
 /**
  * Composables imports
  */
@@ -23,6 +23,10 @@ import {
   isEqual as _isEqual,
   remove as _remove
 } from 'lodash-es'
+/**
+ * Types imports
+ */
+import { ModifType } from '@/gql/codegen/graphql'
 /**
  * Utils imports
  */
@@ -262,7 +266,19 @@ watchEffect(() => {
   <div
     class="grid max-w-max grid-cols-[max-content_1fr] grid-rows-3 items-center gap-x-16 gap-y-8"
   >
-    <h3 class="text-lg font-bold">Targets</h3>
+    <h3 class="text-lg font-bold">
+      Target families
+      <span
+        v-tooltip.right="{
+          value: 'Only targets of the selected units will be retained.',
+          pt: { text: 'text-xs' }
+        }"
+        class="-mt-1 inline-block align-top text-sm text-slate-600"
+      >
+        <icon-fa6-solid-circle-question class="inline" />
+      </span>
+    </h3>
+
     <MultiSelect
       v-model="selection.targetNames"
       :options="targetNameOptionsWithDisablingGroups"
@@ -302,7 +318,20 @@ watchEffect(() => {
       </template>
     </MultiSelect>
 
-    <h3 class="text-lg font-bold">Modification types</h3>
+    <h3 class="text-lg font-bold">
+      Modification types
+      <span
+        v-tooltip.right="{
+          value:
+            'Only targets on which exist modifications of the selected types will be retained.',
+          pt: { text: 'text-xs' }
+        }"
+        class="-mt-1 inline-block align-top text-sm text-slate-600"
+      >
+        <icon-fa6-solid-circle-question class="inline" />
+      </span>
+    </h3>
+
     <SelectButton
       v-model="selection.modificationTypes"
       :options="modificationTypeOptionsWithDisabling"
@@ -321,7 +350,19 @@ watchEffect(() => {
       </template>
     </SelectButton>
 
-    <h3 class="text-lg font-bold">Organisms</h3>
+    <h3 class="text-lg font-bold">
+      Organisms
+      <span
+        v-tooltip.right="{
+          value: 'Only targets of the selected organisms will be retained.',
+          pt: { text: 'text-xs' }
+        }"
+        class="-mt-1 inline-block align-top text-sm text-slate-600"
+      >
+        <icon-fa6-solid-circle-question class="inline" />
+      </span>
+    </h3>
+
     <MultiSelect
       v-model="selection.organismIds"
       :options="organismIdOptionsWithDisabling"
-- 
GitLab