From cb46e0f78f96d3bc0ca208ee11504ac002adeba6 Mon Sep 17 00:00:00 2001
From: Dave Pisek <dpisek@gitlab.com>
Date: Thu, 4 May 2023 15:18:58 +0200
Subject: [PATCH 1/8] Migrate GlDropdown to GlListbox in severity filter

Uses GlListbox instead of GlDropdown within the severity filter UI
component, which is used on security reports pages.

Changelog: changed
EE: true
---
 .../shared/filters/querystring_sync.vue       |   3 +-
 .../shared/filters/severity_filter.vue        | 105 ++++++++++--------
 .../components/pipeline/filters_spec.js       |   5 +-
 .../shared/filters/severity_filter_spec.js    | 100 ++++++-----------
 4 files changed, 100 insertions(+), 113 deletions(-)

diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/querystring_sync.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/querystring_sync.vue
index a423f6667a7a482c..a1419c159235d2ed 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/querystring_sync.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/querystring_sync.vue
@@ -9,7 +9,8 @@ export default {
     },
     value: {
       type: Array,
-      required: true,
+      required: false,
+      default: () => [],
     },
     validValues: {
       type: Array,
diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
index 2b00eae874d5bc91..12f604612d10c1c2 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
@@ -1,79 +1,92 @@
 <script>
-import { GlDropdown } from '@gitlab/ui';
-import { xor } from 'lodash';
+import { GlCollapsibleListbox } from '@gitlab/ui';
 import { s__ } from '~/locale';
 import { SEVERITY_LEVELS } from 'ee/security_dashboard/store/constants';
-import DropdownButtonText from './dropdown_button_text.vue';
+import { getSelectedOptionsText } from 'ee/security_dashboard/components/shared/filters/utils';
 import QuerystringSync from './querystring_sync.vue';
-import FilterItem from './filter_item.vue';
 import { ALL_ID } from './constants';
 
 // For backwards compatibility with existing bookmarks, the ID needs to be capitalized.
-export const DROPDOWN_OPTIONS = Object.entries(SEVERITY_LEVELS).map(([id, text]) => ({
+export const SEVERITY_LEVEL_ITEMS = Object.entries(SEVERITY_LEVELS).map(([id, text]) => ({
   id: id.toUpperCase(),
+  value: id.toUpperCase(),
   text,
 }));
-const VALID_IDS = DROPDOWN_OPTIONS.map(({ id }) => id);
+
+export const FILTER_ITEMS = [
+  {
+    id: ALL_ID,
+    value: ALL_ID,
+    text: s__('SecurityReports|All severities'),
+  },
+  ...SEVERITY_LEVEL_ITEMS,
+];
+
+const VALID_IDS = SEVERITY_LEVEL_ITEMS.map(({ id }) => id);
 
 export default {
-  components: { GlDropdown, DropdownButtonText, QuerystringSync, FilterItem },
+  components: { GlCollapsibleListbox, QuerystringSync },
   data: () => ({
-    selected: [],
+    selectedIds: [ALL_ID],
   }),
   computed: {
-    selectedItemTexts() {
-      const options = DROPDOWN_OPTIONS.filter(({ id }) => this.selected.includes(id));
-      // Return the text for selected items, or all items if nothing is selected.
-      return options.length ? options.map(({ text }) => text) : [this.$options.i18n.allItemsText];
+    toggleText() {
+      return getSelectedOptionsText(this.listboxItems[0].options, this.selectedIds);
     },
-  },
-  watch: {
-    selected() {
-      this.$emit('filter-changed', { severity: this.selected });
+    listboxItems() {
+      const optionsGroup = {
+        text: this.$options.i18n.label,
+        options: FILTER_ITEMS,
+      };
+      return [optionsGroup];
     },
   },
-  methods: {
-    deselectAll() {
-      this.selected = [];
-    },
-    toggleSelected(id) {
-      this.selected = xor(this.selected, [id]);
-    },
-    setSelected(ids) {
-      this.selected = ids.filter((id) => VALID_IDS.includes(id));
+  watch: {
+    selectedIds: {
+      handler(selection = [], prevSelection = []) {
+        const lastSelectedId = selection.at(-1);
+        const prevLastSelectedId = prevSelection.at(-1);
+
+        if (!prevSelection.length || lastSelectedId === prevLastSelectedId) {
+          return;
+        }
+
+        const shouldSelectAll = lastSelectedId === ALL_ID || selection.length === 0;
+        this.selectedIds = shouldSelectAll
+          ? [ALL_ID]
+          : selection.filter((id) => VALID_IDS.includes(id));
+
+        this.$emit('filter-changed', { severity: shouldSelectAll ? [] : this.selectedIds });
+      },
     },
   },
   i18n: {
     label: s__('SecurityReports|Severity'),
     allItemsText: s__('SecurityReports|All severities'),
   },
-  DROPDOWN_OPTIONS,
-  ALL_ID,
+  VALID_IDS,
 };
 </script>
 
 <template>
   <div>
-    <querystring-sync querystring-key="severity" :value="selected" @input="setSelected" />
+    <querystring-sync
+      v-model="selectedIds"
+      querystring-key="severity"
+      :valid-values="$options.VALID_IDS"
+    />
     <label class="gl-mb-2">{{ $options.i18n.label }}</label>
-    <gl-dropdown :header-text="$options.i18n.label" block toggle-class="gl-mb-0">
-      <template #button-text>
-        <dropdown-button-text :items="selectedItemTexts" :name="$options.i18n.label" />
+    <gl-collapsible-listbox
+      v-model="selectedIds"
+      :items="listboxItems"
+      :toggle-text="toggleText"
+      multiple
+      block
+      toggle-class="gl-mb-0"
+    >
+      <template #list-item="{ item }">
+        <span :data-testid="item.id">{{ item.text }}</span>
       </template>
-      <filter-item
-        :is-checked="!selected.length"
-        :text="$options.i18n.allItemsText"
-        :data-testid="$options.ALL_ID"
-        @click="deselectAll"
-      />
-      <filter-item
-        v-for="{ id, text } in $options.DROPDOWN_OPTIONS"
-        :key="id"
-        :data-testid="id"
-        :is-checked="selected.includes(id)"
-        :text="text"
-        @click="toggleSelected(id)"
-      />
-    </gl-dropdown>
+    </gl-collapsible-listbox>
   </div>
 </template>
diff --git a/ee/spec/frontend/security_dashboard/components/pipeline/filters_spec.js b/ee/spec/frontend/security_dashboard/components/pipeline/filters_spec.js
index 797ec56b94e91310..fd7f42f45b65f11f 100644
--- a/ee/spec/frontend/security_dashboard/components/pipeline/filters_spec.js
+++ b/ee/spec/frontend/security_dashboard/components/pipeline/filters_spec.js
@@ -69,6 +69,7 @@ describe('Filter component', () => {
 
       createWrapper({ mountFn: mount });
       await nextTick();
+
       // The other filters will trigger the mock as well, so we'll clear it before clicking on a
       // scanner filter item.
       mock.mockClear();
@@ -76,8 +77,8 @@ describe('Filter component', () => {
       const filterId = 'severity';
       const optionId = 'MEDIUM';
       const option = wrapper.findByTestId(optionId);
-      option.vm.$emit('click');
-      await nextTick();
+
+      await option.trigger('click');
 
       expect(mock).toHaveBeenCalledTimes(1);
       expect(mock).toHaveBeenCalledWith(expect.any(Object), { [filterId]: [optionId] });
diff --git a/ee/spec/frontend/security_dashboard/components/shared/filters/severity_filter_spec.js b/ee/spec/frontend/security_dashboard/components/shared/filters/severity_filter_spec.js
index 648ee7d310619372..7abaa6c8f8faf9d5 100644
--- a/ee/spec/frontend/security_dashboard/components/shared/filters/severity_filter_spec.js
+++ b/ee/spec/frontend/security_dashboard/components/shared/filters/severity_filter_spec.js
@@ -1,15 +1,13 @@
-import { GlDropdown } from '@gitlab/ui';
-import { nextTick } from 'vue';
+import { GlCollapsibleListbox } from '@gitlab/ui';
 import SeverityFilter, {
-  DROPDOWN_OPTIONS,
+  SEVERITY_LEVEL_ITEMS,
+  FILTER_ITEMS,
 } from 'ee/security_dashboard/components/shared/filters/severity_filter.vue';
 import { ALL_ID } from 'ee/security_dashboard/components/shared/filters/constants';
 import QuerystringSync from 'ee/security_dashboard/components/shared/filters/querystring_sync.vue';
-import DropdownButtonText from 'ee/security_dashboard/components/shared/filters/dropdown_button_text.vue';
-import FilterItem from 'ee/security_dashboard/components/shared/filters/filter_item.vue';
 import { mountExtended } from 'helpers/vue_test_utils_helper';
 
-const OPTION_IDS = DROPDOWN_OPTIONS.map(({ id }) => id);
+const OPTION_IDS = SEVERITY_LEVEL_ITEMS.map(({ id }) => id);
 
 describe('Severity Filter component', () => {
   let wrapper;
@@ -21,20 +19,13 @@ describe('Severity Filter component', () => {
   };
 
   const findQuerystringSync = () => wrapper.findComponent(QuerystringSync);
-  const findDropdownItems = () => wrapper.findAllComponents(FilterItem);
-  const findDropdownItem = (id) => wrapper.findByTestId(id);
+  const findListbox = () => wrapper.findComponent(GlCollapsibleListbox);
+  const findListboxItem = (id) => wrapper.findByTestId(`listbox-item-${id}`);
 
-  const clickDropdownItem = async (id) => {
-    findDropdownItem(id).vm.$emit('click');
-    await nextTick();
-  };
+  const clickListboxItem = (id) => findListboxItem(id).trigger('click');
 
   const expectSelectedItems = (ids) => {
-    const checkedItems = findDropdownItems()
-      .wrappers.filter((item) => item.props('isChecked'))
-      .map((item) => item.attributes('data-testid'));
-
-    expect(checkedItems).toEqual(ids);
+    expect(findListbox().props('selected')).toEqual(ids);
   };
 
   beforeEach(() => {
@@ -45,14 +36,15 @@ describe('Severity Filter component', () => {
     it('has expected props', () => {
       expect(findQuerystringSync().props()).toMatchObject({
         querystringKey: 'severity',
-        value: [],
+        value: [ALL_ID],
+        validValues: OPTION_IDS,
       });
     });
 
-    it('receives empty array when All Statuses option is clicked', async () => {
-      await clickDropdownItem(ALL_ID);
+    it('receives "ALL_ID" when All Statuses option is clicked', async () => {
+      await clickListboxItem(ALL_ID);
 
-      expect(findQuerystringSync().props('value')).toEqual([]);
+      expect(findQuerystringSync().props('value')).toEqual([ALL_ID]);
     });
 
     it.each`
@@ -62,8 +54,7 @@ describe('Severity Filter component', () => {
       ${['INVALID']}                   | ${[ALL_ID]}
       ${[]}                            | ${[ALL_ID]}
     `('restores selected items - $emitted', async ({ emitted, expected }) => {
-      findQuerystringSync().vm.$emit('input', emitted);
-      await nextTick();
+      await findQuerystringSync().vm.$emit('input', emitted);
 
       expectSelectedItems(expected);
     });
@@ -74,49 +65,30 @@ describe('Severity Filter component', () => {
       expect(wrapper.find('label').text()).toBe(SeverityFilter.i18n.label);
     });
 
-    it('shows the dropdown with correct header text', () => {
-      expect(wrapper.findComponent(GlDropdown).props('headerText')).toBe(SeverityFilter.i18n.label);
-    });
-
-    it('shows the DropdownButtonText component with the correct props', () => {
-      expect(wrapper.findComponent(DropdownButtonText).props()).toMatchObject({
-        items: [SeverityFilter.i18n.allItemsText],
-        name: SeverityFilter.i18n.label,
+    it('shows the ListBox component with the correct props', () => {
+      expect(findListbox().props()).toMatchObject({
+        items: [
+          {
+            text: 'Severity',
+            options: FILTER_ITEMS,
+          },
+        ],
+        toggleText: 'All severities',
+        multiple: true,
+        block: true,
       });
     });
   });
 
   describe('dropdown items', () => {
-    it('shows all dropdown items with correct text', () => {
-      expect(findDropdownItems()).toHaveLength(DROPDOWN_OPTIONS.length + 1);
-
-      expect(findDropdownItem(ALL_ID).text()).toBe(SeverityFilter.i18n.allItemsText);
-      DROPDOWN_OPTIONS.forEach(({ id, text }) => {
-        expect(findDropdownItem(id).text()).toBe(text);
-      });
-    });
+    it.each(OPTION_IDS)('toggles the item selection when clicked on %s', async (id) => {
+      await clickListboxItem(id);
 
-    it('allows multiple items to be selected', async () => {
-      const ids = [];
+      expectSelectedItems([id]);
 
-      for await (const id of OPTION_IDS) {
-        await clickDropdownItem(id);
-        ids.push(id);
+      await clickListboxItem(id);
 
-        expectSelectedItems(ids);
-      }
-    });
-
-    it('toggles the item selection when clicked on', async () => {
-      for await (const id of OPTION_IDS) {
-        await clickDropdownItem(id);
-
-        expectSelectedItems([id]);
-
-        await clickDropdownItem(id);
-
-        expectSelectedItems([ALL_ID]);
-      }
+      expectSelectedItems([ALL_ID]);
     });
 
     it('selects ALL item when created', () => {
@@ -124,15 +96,15 @@ describe('Severity Filter component', () => {
     });
 
     it('selects ALL item and deselects everything else when it is clicked', async () => {
-      await clickDropdownItem(OPTION_IDS[0]);
-      await clickDropdownItem(ALL_ID);
-      await clickDropdownItem(ALL_ID); // Click again to verify that it doesn't toggle.
+      await clickListboxItem(OPTION_IDS[0]);
+      await clickListboxItem(ALL_ID);
+      await clickListboxItem(ALL_ID); // Click again to verify that it doesn't toggle.
 
       expectSelectedItems([ALL_ID]);
     });
 
     it('deselects the ALL item when another item is clicked', async () => {
-      await clickDropdownItem(OPTION_IDS[0]);
+      await clickListboxItem(OPTION_IDS[0]);
 
       expectSelectedItems([OPTION_IDS[0]]);
     });
@@ -143,10 +115,10 @@ describe('Severity Filter component', () => {
       const ids = [];
 
       for await (const id of OPTION_IDS) {
-        await clickDropdownItem(id);
+        await clickListboxItem(id);
         ids.push(id);
 
-        expect(wrapper.emitted('filter-changed')[ids.length - 1][0].severity).toEqual(ids);
+        expect(wrapper.emitted('filter-changed').at(-1)[0].severity).toEqual(ids);
       }
     });
   });
-- 
GitLab


From c35890921fb44f2feab3a123fa04643c6699e0e5 Mon Sep 17 00:00:00 2001
From: Dave Pisek <dpisek@gitlab.com>
Date: Mon, 15 May 2023 12:54:23 +0200
Subject: [PATCH 2/8] Review feedback: remove slot content

---
 .../components/shared/filters/severity_filter.vue           | 6 +-----
 .../security_dashboard/components/pipeline/filters_spec.js  | 2 +-
 2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
index 12f604612d10c1c2..a691119dc021a8ae 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
@@ -83,10 +83,6 @@ export default {
       multiple
       block
       toggle-class="gl-mb-0"
-    >
-      <template #list-item="{ item }">
-        <span :data-testid="item.id">{{ item.text }}</span>
-      </template>
-    </gl-collapsible-listbox>
+    />
   </div>
 </template>
diff --git a/ee/spec/frontend/security_dashboard/components/pipeline/filters_spec.js b/ee/spec/frontend/security_dashboard/components/pipeline/filters_spec.js
index fd7f42f45b65f11f..ddb9af2d7ebe5b87 100644
--- a/ee/spec/frontend/security_dashboard/components/pipeline/filters_spec.js
+++ b/ee/spec/frontend/security_dashboard/components/pipeline/filters_spec.js
@@ -76,7 +76,7 @@ describe('Filter component', () => {
 
       const filterId = 'severity';
       const optionId = 'MEDIUM';
-      const option = wrapper.findByTestId(optionId);
+      const option = wrapper.findByTestId(`listbox-item-${optionId}`);
 
       await option.trigger('click');
 
-- 
GitLab


From bb8d2e65e67dd5279201bcfddfe41726cf9b1c74 Mon Sep 17 00:00:00 2001
From: Dave Pisek <dpisek@gitlab.com>
Date: Mon, 15 May 2023 13:08:20 +0200
Subject: [PATCH 3/8] Review feedback: simplify watchers

---
 .../shared/filters/severity_filter.vue        | 46 +++++++++----------
 1 file changed, 21 insertions(+), 25 deletions(-)

diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
index a691119dc021a8ae..ce7812430d545ba1 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
@@ -31,39 +31,32 @@ export default {
   }),
   computed: {
     toggleText() {
-      return getSelectedOptionsText(this.listboxItems[0].options, this.selectedIds);
-    },
-    listboxItems() {
-      const optionsGroup = {
-        text: this.$options.i18n.label,
-        options: FILTER_ITEMS,
-      };
-      return [optionsGroup];
+      return getSelectedOptionsText(FILTER_ITEMS, this.selectedIds);
     },
   },
   watch: {
     selectedIds: {
-      handler(selection = [], prevSelection = []) {
-        const lastSelectedId = selection.at(-1);
-        const prevLastSelectedId = prevSelection.at(-1);
-
-        if (!prevSelection.length || lastSelectedId === prevLastSelectedId) {
-          return;
-        }
-
-        const shouldSelectAll = lastSelectedId === ALL_ID || selection.length === 0;
-        this.selectedIds = shouldSelectAll
-          ? [ALL_ID]
-          : selection.filter((id) => VALID_IDS.includes(id));
-
-        this.$emit('filter-changed', { severity: shouldSelectAll ? [] : this.selectedIds });
+      handler() {
+        this.$emit('filter-changed', {
+          severity: this.selectedIds.filter((value) => value !== ALL_ID),
+        });
       },
     },
   },
+  methods: {
+    updateSelected(selected) {
+      if (!selected.length || selected.at(-1) === ALL_ID) {
+        this.selectedIds = [ALL_ID];
+      } else {
+        this.selectedIds = selected.filter((value) => value !== ALL_ID);
+      }
+    },
+  },
   i18n: {
     label: s__('SecurityReports|Severity'),
     allItemsText: s__('SecurityReports|All severities'),
   },
+  FILTER_ITEMS,
   VALID_IDS,
 };
 </script>
@@ -71,18 +64,21 @@ export default {
 <template>
   <div>
     <querystring-sync
-      v-model="selectedIds"
+      :value="selectedIds"
       querystring-key="severity"
       :valid-values="$options.VALID_IDS"
+      @input="updateSelected"
     />
     <label class="gl-mb-2">{{ $options.i18n.label }}</label>
     <gl-collapsible-listbox
-      v-model="selectedIds"
-      :items="listboxItems"
+      :header-text="$options.i18n.label"
+      :items="$options.FILTER_ITEMS"
+      :selected="selectedIds"
       :toggle-text="toggleText"
       multiple
       block
       toggle-class="gl-mb-0"
+      @select="updateSelected"
     />
   </div>
 </template>
-- 
GitLab


From cb3d4f90406b382004539fe747e928fb81d107d4 Mon Sep 17 00:00:00 2001
From: Dave Pisek <dpisek@gitlab.com>
Date: Mon, 15 May 2023 13:13:59 +0200
Subject: [PATCH 4/8] Review feedback: remove unnused i18n

---
 .../components/shared/filters/severity_filter.vue                | 1 -
 1 file changed, 1 deletion(-)

diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
index ce7812430d545ba1..c3cc0706d3fcf04e 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
@@ -54,7 +54,6 @@ export default {
   },
   i18n: {
     label: s__('SecurityReports|Severity'),
-    allItemsText: s__('SecurityReports|All severities'),
   },
   FILTER_ITEMS,
   VALID_IDS,
-- 
GitLab


From 2eea94051ffe78c9ac256b0c4474b1ac00c41395 Mon Sep 17 00:00:00 2001
From: Dave Pisek <dpisek@gitlab.com>
Date: Mon, 15 May 2023 14:24:57 +0200
Subject: [PATCH 5/8] Fix failing specs

---
 .../shared/filters/severity_filter_spec.js        | 15 ++++-----------
 1 file changed, 4 insertions(+), 11 deletions(-)

diff --git a/ee/spec/frontend/security_dashboard/components/shared/filters/severity_filter_spec.js b/ee/spec/frontend/security_dashboard/components/shared/filters/severity_filter_spec.js
index 7abaa6c8f8faf9d5..d2ebcb8bb5feeed5 100644
--- a/ee/spec/frontend/security_dashboard/components/shared/filters/severity_filter_spec.js
+++ b/ee/spec/frontend/security_dashboard/components/shared/filters/severity_filter_spec.js
@@ -48,11 +48,9 @@ describe('Severity Filter component', () => {
     });
 
     it.each`
-      emitted                          | expected
-      ${['HIGH', 'MEDIUM']}            | ${['HIGH', 'MEDIUM']}
-      ${['INVALID', 'LOW', 'UNKNOWN']} | ${['LOW', 'UNKNOWN']}
-      ${['INVALID']}                   | ${[ALL_ID]}
-      ${[]}                            | ${[ALL_ID]}
+      emitted               | expected
+      ${['HIGH', 'MEDIUM']} | ${['HIGH', 'MEDIUM']}
+      ${[]}                 | ${[ALL_ID]}
     `('restores selected items - $emitted', async ({ emitted, expected }) => {
       await findQuerystringSync().vm.$emit('input', emitted);
 
@@ -67,12 +65,7 @@ describe('Severity Filter component', () => {
 
     it('shows the ListBox component with the correct props', () => {
       expect(findListbox().props()).toMatchObject({
-        items: [
-          {
-            text: 'Severity',
-            options: FILTER_ITEMS,
-          },
-        ],
+        items: FILTER_ITEMS,
         toggleText: 'All severities',
         multiple: true,
         block: true,
-- 
GitLab


From a87e115f7eda90fdaebf3c3f6d0820fcff202533 Mon Sep 17 00:00:00 2001
From: Dave Pisek <dpisek@gitlab.com>
Date: Mon, 22 May 2023 13:40:44 +0200
Subject: [PATCH 6/8] Refactor: Leverage improved helper

---
 .../components/shared/filters/severity_filter.vue             | 4 +---
 .../components/shared/filters/severity_filter_spec.js         | 2 +-
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
index c3cc0706d3fcf04e..04428be9fe3a02f6 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
@@ -8,21 +8,19 @@ import { ALL_ID } from './constants';
 
 // For backwards compatibility with existing bookmarks, the ID needs to be capitalized.
 export const SEVERITY_LEVEL_ITEMS = Object.entries(SEVERITY_LEVELS).map(([id, text]) => ({
-  id: id.toUpperCase(),
   value: id.toUpperCase(),
   text,
 }));
 
 export const FILTER_ITEMS = [
   {
-    id: ALL_ID,
     value: ALL_ID,
     text: s__('SecurityReports|All severities'),
   },
   ...SEVERITY_LEVEL_ITEMS,
 ];
 
-const VALID_IDS = SEVERITY_LEVEL_ITEMS.map(({ id }) => id);
+const VALID_IDS = SEVERITY_LEVEL_ITEMS.map(({ value }) => value);
 
 export default {
   components: { GlCollapsibleListbox, QuerystringSync },
diff --git a/ee/spec/frontend/security_dashboard/components/shared/filters/severity_filter_spec.js b/ee/spec/frontend/security_dashboard/components/shared/filters/severity_filter_spec.js
index d2ebcb8bb5feeed5..a477e8dcee8b08ff 100644
--- a/ee/spec/frontend/security_dashboard/components/shared/filters/severity_filter_spec.js
+++ b/ee/spec/frontend/security_dashboard/components/shared/filters/severity_filter_spec.js
@@ -7,7 +7,7 @@ import { ALL_ID } from 'ee/security_dashboard/components/shared/filters/constant
 import QuerystringSync from 'ee/security_dashboard/components/shared/filters/querystring_sync.vue';
 import { mountExtended } from 'helpers/vue_test_utils_helper';
 
-const OPTION_IDS = SEVERITY_LEVEL_ITEMS.map(({ id }) => id);
+const OPTION_IDS = SEVERITY_LEVEL_ITEMS.map(({ value }) => value);
 
 describe('Severity Filter component', () => {
   let wrapper;
-- 
GitLab


From c15b7d7fae876759e03777e9bdd955a21c2aae7a Mon Sep 17 00:00:00 2001
From: Dave Pisek <dpisek@gitlab.com>
Date: Mon, 22 May 2023 13:47:24 +0200
Subject: [PATCH 7/8] Revert change to querystring-sync

---
 .../components/shared/filters/querystring_sync.vue             | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/querystring_sync.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/querystring_sync.vue
index a1419c159235d2ed..a423f6667a7a482c 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/querystring_sync.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/querystring_sync.vue
@@ -9,8 +9,7 @@ export default {
     },
     value: {
       type: Array,
-      required: false,
-      default: () => [],
+      required: true,
     },
     validValues: {
       type: Array,
-- 
GitLab


From eed0dd998f8f61ec6423e9b0289756b05277429d Mon Sep 17 00:00:00 2001
From: Dave Pisek <dpisek@gitlab.com>
Date: Mon, 22 May 2023 15:28:33 +0200
Subject: [PATCH 8/8] Review feedback: remove css class

---
 .../components/shared/filters/severity_filter.vue                | 1 -
 1 file changed, 1 deletion(-)

diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
index 04428be9fe3a02f6..f9a72e9923833a22 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/severity_filter.vue
@@ -74,7 +74,6 @@ export default {
       :toggle-text="toggleText"
       multiple
       block
-      toggle-class="gl-mb-0"
       @select="updateSelected"
     />
   </div>
-- 
GitLab