Skip to content
Snippets Groups Projects

Migrate GlDropdown to GlListbox in severity filter

Merged David Pisek requested to merge 409701-migrate-severity_filter-to-listbox into master
Compare and
3 files
+ 85
118
Compare changes
  • Side-by-side
  • Inline
Files
3
<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]) => ({
id: id.toUpperCase(),
export const SEVERITY_LEVEL_ITEMS = Object.entries(SEVERITY_LEVELS).map(([id, text]) => ({
value: id.toUpperCase(),
text,
}));
const VALID_IDS = DROPDOWN_OPTIONS.map(({ id }) => id);
export const FILTER_ITEMS = [
{
value: ALL_ID,
text: s__('SecurityReports|All severities'),
},
...SEVERITY_LEVEL_ITEMS,
];
const VALID_IDS = SEVERITY_LEVEL_ITEMS.map(({ value }) => value);
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(FILTER_ITEMS, this.selectedIds);
},
},
watch: {
selected() {
this.$emit('filter-changed', { severity: this.selected });
selectedIds: {
handler() {
this.$emit('filter-changed', {
severity: this.selectedIds.filter((value) => value !== ALL_ID),
});
},
},
},
methods: {
deselectAll() {
this.selected = [];
},
toggleSelected(id) {
this.selected = xor(this.selected, [id]);
},
setSelected(ids) {
this.selected = ids.filter((id) => VALID_IDS.includes(id));
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'),
},
DROPDOWN_OPTIONS,
ALL_ID,
FILTER_ITEMS,
VALID_IDS,
};
</script>
<template>
<div>
<querystring-sync querystring-key="severity" :value="selected" @input="setSelected" />
<querystring-sync
:value="selectedIds"
querystring-key="severity"
:valid-values="$options.VALID_IDS"
@input="updateSelected"
/>
<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" />
</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
:header-text="$options.i18n.label"
:items="$options.FILTER_ITEMS"
:selected="selectedIds"
:toggle-text="toggleText"
multiple
block
@select="updateSelected"
/>
</div>
</template>
Loading