summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/search/dropdown_filter
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/search/dropdown_filter')
-rw-r--r--app/assets/javascripts/search/dropdown_filter/components/dropdown_filter.vue100
-rw-r--r--app/assets/javascripts/search/dropdown_filter/constants/confidential_filter_data.js36
-rw-r--r--app/assets/javascripts/search/dropdown_filter/constants/state_filter_data.js42
-rw-r--r--app/assets/javascripts/search/dropdown_filter/index.js38
4 files changed, 216 insertions, 0 deletions
diff --git a/app/assets/javascripts/search/dropdown_filter/components/dropdown_filter.vue b/app/assets/javascripts/search/dropdown_filter/components/dropdown_filter.vue
new file mode 100644
index 00000000000..b6e2dd46358
--- /dev/null
+++ b/app/assets/javascripts/search/dropdown_filter/components/dropdown_filter.vue
@@ -0,0 +1,100 @@
+<script>
+import { mapState } from 'vuex';
+import { GlDropdown, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui';
+import { setUrlParams, visitUrl } from '~/lib/utils/url_utility';
+import { sprintf, s__ } from '~/locale';
+
+export default {
+ name: 'DropdownFilter',
+ components: {
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownDivider,
+ },
+ props: {
+ filterData: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ ...mapState(['query']),
+ scope() {
+ return this.query.scope;
+ },
+ supportedScopes() {
+ return Object.values(this.filterData.scopes);
+ },
+ initialFilter() {
+ return this.query[this.filterData.filterParam];
+ },
+ filter() {
+ return this.initialFilter || this.filterData.filters.ANY.value;
+ },
+ filtersArray() {
+ return this.filterData.filterByScope[this.scope];
+ },
+ selectedFilter: {
+ get() {
+ if (this.filtersArray.some(({ value }) => value === this.filter)) {
+ return this.filter;
+ }
+
+ return this.filterData.filters.ANY.value;
+ },
+ set(filter) {
+ visitUrl(setUrlParams({ [this.filterData.filterParam]: filter }));
+ },
+ },
+ selectedFilterText() {
+ const f = this.filtersArray.find(({ value }) => value === this.selectedFilter);
+ if (!f || f === this.filterData.filters.ANY) {
+ return sprintf(s__('Any %{header}'), { header: this.filterData.header });
+ }
+
+ return f.label;
+ },
+ showDropdown() {
+ return this.supportedScopes.includes(this.scope);
+ },
+ },
+ methods: {
+ dropDownItemClass(filter) {
+ return {
+ 'gl-border-b-solid gl-border-b-gray-100 gl-border-b-1 gl-pb-2! gl-mb-2':
+ filter === this.filterData.filters.ANY,
+ };
+ },
+ isFilterSelected(filter) {
+ return filter === this.selectedFilter;
+ },
+ handleFilterChange(filter) {
+ this.selectedFilter = filter;
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown
+ v-if="showDropdown"
+ :text="selectedFilterText"
+ class="col-3 gl-pt-4 gl-pl-0 gl-pr-0 gl-mr-4"
+ menu-class="gl-w-full! gl-pl-0"
+ >
+ <header class="gl-text-center gl-font-weight-bold gl-font-lg">
+ {{ filterData.header }}
+ </header>
+ <gl-dropdown-divider />
+ <gl-dropdown-item
+ v-for="f in filtersArray"
+ :key="f.value"
+ :is-check-item="true"
+ :is-checked="isFilterSelected(f.value)"
+ :class="dropDownItemClass(f)"
+ @click="handleFilterChange(f.value)"
+ >
+ {{ f.label }}
+ </gl-dropdown-item>
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/search/dropdown_filter/constants/confidential_filter_data.js b/app/assets/javascripts/search/dropdown_filter/constants/confidential_filter_data.js
new file mode 100644
index 00000000000..b29daca89cb
--- /dev/null
+++ b/app/assets/javascripts/search/dropdown_filter/constants/confidential_filter_data.js
@@ -0,0 +1,36 @@
+import { __ } from '~/locale';
+
+const header = __('Confidentiality');
+
+const filters = {
+ ANY: {
+ label: __('Any'),
+ value: null,
+ },
+ CONFIDENTIAL: {
+ label: __('Confidential'),
+ value: 'yes',
+ },
+ NOT_CONFIDENTIAL: {
+ label: __('Not confidential'),
+ value: 'no',
+ },
+};
+
+const scopes = {
+ ISSUES: 'issues',
+};
+
+const filterByScope = {
+ [scopes.ISSUES]: [filters.ANY, filters.CONFIDENTIAL, filters.NOT_CONFIDENTIAL],
+};
+
+const filterParam = 'confidential';
+
+export default {
+ header,
+ filters,
+ scopes,
+ filterByScope,
+ filterParam,
+};
diff --git a/app/assets/javascripts/search/dropdown_filter/constants/state_filter_data.js b/app/assets/javascripts/search/dropdown_filter/constants/state_filter_data.js
new file mode 100644
index 00000000000..0b93aa0be29
--- /dev/null
+++ b/app/assets/javascripts/search/dropdown_filter/constants/state_filter_data.js
@@ -0,0 +1,42 @@
+import { __ } from '~/locale';
+
+const header = __('Status');
+
+const filters = {
+ ANY: {
+ label: __('Any'),
+ value: 'all',
+ },
+ OPEN: {
+ label: __('Open'),
+ value: 'opened',
+ },
+ CLOSED: {
+ label: __('Closed'),
+ value: 'closed',
+ },
+ MERGED: {
+ label: __('Merged'),
+ value: 'merged',
+ },
+};
+
+const scopes = {
+ ISSUES: 'issues',
+ MERGE_REQUESTS: 'merge_requests',
+};
+
+const filterByScope = {
+ [scopes.ISSUES]: [filters.ANY, filters.OPEN, filters.CLOSED],
+ [scopes.MERGE_REQUESTS]: [filters.ANY, filters.OPEN, filters.MERGED, filters.CLOSED],
+};
+
+const filterParam = 'state';
+
+export default {
+ header,
+ filters,
+ scopes,
+ filterByScope,
+ filterParam,
+};
diff --git a/app/assets/javascripts/search/dropdown_filter/index.js b/app/assets/javascripts/search/dropdown_filter/index.js
new file mode 100644
index 00000000000..e5e0745d990
--- /dev/null
+++ b/app/assets/javascripts/search/dropdown_filter/index.js
@@ -0,0 +1,38 @@
+import Vue from 'vue';
+import Translate from '~/vue_shared/translate';
+import DropdownFilter from './components/dropdown_filter.vue';
+import stateFilterData from './constants/state_filter_data';
+import confidentialFilterData from './constants/confidential_filter_data';
+
+Vue.use(Translate);
+
+const mountDropdownFilter = (store, { id, filterData }) => {
+ const el = document.getElementById(id);
+
+ if (!el) return false;
+
+ return new Vue({
+ el,
+ store,
+ render(createElement) {
+ return createElement(DropdownFilter, {
+ props: {
+ filterData,
+ },
+ });
+ },
+ });
+};
+
+const dropdownFilters = [
+ {
+ id: 'js-search-filter-by-state',
+ filterData: stateFilterData,
+ },
+ {
+ id: 'js-search-filter-by-confidential',
+ filterData: confidentialFilterData,
+ },
+];
+
+export default store => [...dropdownFilters].map(filter => mountDropdownFilter(store, filter));