debian-mirror-gitlab/app/assets/javascripts/groups/components/overview_tabs.vue

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

219 lines
7.2 KiB
Vue
Raw Normal View History

2022-10-11 01:57:18 +05:30
<script>
2022-11-25 23:54:43 +05:30
import { GlTabs, GlTab, GlSearchBoxByType, GlSorting, GlSortingItem } from '@gitlab/ui';
import { isString, debounce } from 'lodash';
2022-10-11 01:57:18 +05:30
import { __ } from '~/locale';
2022-11-25 23:54:43 +05:30
import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants';
2022-10-11 01:57:18 +05:30
import GroupsStore from '../store/groups_store';
import GroupsService from '../service/groups_service';
import {
ACTIVE_TAB_SUBGROUPS_AND_PROJECTS,
ACTIVE_TAB_SHARED,
ACTIVE_TAB_ARCHIVED,
2022-11-25 23:54:43 +05:30
OVERVIEW_TABS_SORTING_ITEMS,
2022-10-11 01:57:18 +05:30
} from '../constants';
2022-11-25 23:54:43 +05:30
import eventHub from '../event_hub';
2022-10-11 01:57:18 +05:30
import GroupsApp from './app.vue';
2023-03-04 22:38:38 +05:30
import SubgroupsAndProjectsEmptyState from './empty_states/subgroups_and_projects_empty_state.vue';
import SharedProjectsEmptyState from './empty_states/shared_projects_empty_state.vue';
import ArchivedProjectsEmptyState from './empty_states/archived_projects_empty_state.vue';
2022-10-11 01:57:18 +05:30
2022-11-25 23:54:43 +05:30
const [SORTING_ITEM_NAME] = OVERVIEW_TABS_SORTING_ITEMS;
2023-01-13 00:05:48 +05:30
const MIN_SEARCH_LENGTH = 3;
2022-11-25 23:54:43 +05:30
2022-10-11 01:57:18 +05:30
export default {
2023-03-04 22:38:38 +05:30
components: {
GlTabs,
GlTab,
GroupsApp,
GlSearchBoxByType,
GlSorting,
GlSortingItem,
SubgroupsAndProjectsEmptyState,
SharedProjectsEmptyState,
ArchivedProjectsEmptyState,
},
2022-11-25 23:54:43 +05:30
inject: ['endpoints', 'initialSort'],
2022-10-11 01:57:18 +05:30
data() {
2022-11-25 23:54:43 +05:30
const tabs = [
{
title: this.$options.i18n[ACTIVE_TAB_SUBGROUPS_AND_PROJECTS],
key: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS,
2023-03-04 22:38:38 +05:30
emptyStateComponent: SubgroupsAndProjectsEmptyState,
2022-11-25 23:54:43 +05:30
lazy: this.$route.name !== ACTIVE_TAB_SUBGROUPS_AND_PROJECTS,
service: new GroupsService(this.endpoints[ACTIVE_TAB_SUBGROUPS_AND_PROJECTS]),
store: new GroupsStore({ showSchemaMarkup: true }),
},
{
title: this.$options.i18n[ACTIVE_TAB_SHARED],
key: ACTIVE_TAB_SHARED,
2023-03-04 22:38:38 +05:30
emptyStateComponent: SharedProjectsEmptyState,
2022-11-25 23:54:43 +05:30
lazy: this.$route.name !== ACTIVE_TAB_SHARED,
service: new GroupsService(this.endpoints[ACTIVE_TAB_SHARED]),
store: new GroupsStore(),
},
{
title: this.$options.i18n[ACTIVE_TAB_ARCHIVED],
key: ACTIVE_TAB_ARCHIVED,
2023-03-04 22:38:38 +05:30
emptyStateComponent: ArchivedProjectsEmptyState,
2022-11-25 23:54:43 +05:30
lazy: this.$route.name !== ACTIVE_TAB_ARCHIVED,
service: new GroupsService(this.endpoints[ACTIVE_TAB_ARCHIVED]),
store: new GroupsStore(),
},
];
2022-10-11 01:57:18 +05:30
return {
2022-11-25 23:54:43 +05:30
tabs,
activeTabIndex: tabs.findIndex((tab) => tab.key === this.$route.name),
sort: SORTING_ITEM_NAME,
isAscending: true,
search: '',
2022-10-11 01:57:18 +05:30
};
},
2022-11-25 23:54:43 +05:30
computed: {
activeTab() {
return this.tabs[this.activeTabIndex];
},
sortQueryStringValue() {
return this.isAscending ? this.sort.asc : this.sort.desc;
},
},
2022-10-11 01:57:18 +05:30
mounted() {
2022-11-25 23:54:43 +05:30
this.search = this.$route.query?.filter || '';
2022-10-11 01:57:18 +05:30
2022-11-25 23:54:43 +05:30
const sortQueryStringValue = this.$route.query?.sort || this.initialSort;
const sort =
OVERVIEW_TABS_SORTING_ITEMS.find((sortOption) =>
[sortOption.asc, sortOption.desc].includes(sortQueryStringValue),
) || SORTING_ITEM_NAME;
this.sort = sort;
this.isAscending = sort.asc === sortQueryStringValue;
2022-10-11 01:57:18 +05:30
},
methods: {
handleTabInput(tabIndex) {
if (tabIndex === this.activeTabIndex) {
return;
}
this.activeTabIndex = tabIndex;
const tab = this.tabs[tabIndex];
tab.lazy = false;
// Vue router will convert `/` to `%2F` if you pass a string as a param
// If you pass an array as a param it will concatenate them with a `/`
// This makes sure we are always passing an array for the group param
const groupParam = isString(this.$route.params.group)
? this.$route.params.group.split('/')
: this.$route.params.group;
2022-11-25 23:54:43 +05:30
this.$router.push({ name: tab.key, params: { group: groupParam }, query: this.$route.query });
},
handleSearchOrSortChange() {
// Update query string
const query = {};
if (this.sortQueryStringValue !== this.initialSort) {
query.sort = this.isAscending ? this.sort.asc : this.sort.desc;
}
if (this.search) {
query.filter = this.search;
}
this.$router.push({ query });
// Reset `lazy` prop so that groups/projects are fetched with updated `sort` and `filter` params when switching tabs
this.tabs.forEach((tab, index) => {
if (index === this.activeTabIndex) {
return;
}
// eslint-disable-next-line no-param-reassign
tab.lazy = true;
});
// Update data
eventHub.$emit(`${this.activeTab.key}fetchFilteredAndSortedGroups`, {
filterGroupsBy: this.search,
sortBy: this.sortQueryStringValue,
});
},
handleSortDirectionChange() {
this.isAscending = !this.isAscending;
this.handleSearchOrSortChange();
},
handleSortingItemClick(sortingItem) {
if (sortingItem === this.sort) {
return;
}
this.sort = sortingItem;
this.handleSearchOrSortChange();
},
handleSearchInput(value) {
this.search = value;
2023-01-13 00:05:48 +05:30
if (!this.search || this.search.length >= MIN_SEARCH_LENGTH) {
this.debouncedSearch();
}
2022-10-11 01:57:18 +05:30
},
2022-11-25 23:54:43 +05:30
debouncedSearch: debounce(async function debouncedSearch() {
this.handleSearchOrSortChange();
}, DEBOUNCE_DELAY),
2022-10-11 01:57:18 +05:30
},
i18n: {
[ACTIVE_TAB_SUBGROUPS_AND_PROJECTS]: __('Subgroups and projects'),
[ACTIVE_TAB_SHARED]: __('Shared projects'),
[ACTIVE_TAB_ARCHIVED]: __('Archived projects'),
2022-11-25 23:54:43 +05:30
searchPlaceholder: __('Search'),
2022-10-11 01:57:18 +05:30
},
2022-11-25 23:54:43 +05:30
OVERVIEW_TABS_SORTING_ITEMS,
2022-10-11 01:57:18 +05:30
};
</script>
<template>
<gl-tabs content-class="gl-pt-0" :value="activeTabIndex" @input="handleTabInput">
<gl-tab
2023-03-04 22:38:38 +05:30
v-for="{ key, title, emptyStateComponent, lazy, service, store } in tabs"
2022-10-11 01:57:18 +05:30
:key="key"
:title="title"
:lazy="lazy"
>
2023-03-04 22:38:38 +05:30
<groups-app :action="key" :service="service" :store="store" :hide-projects="false">
<template v-if="emptyStateComponent" #empty-state>
<component :is="emptyStateComponent" />
</template>
</groups-app>
2022-10-11 01:57:18 +05:30
</gl-tab>
2022-11-25 23:54:43 +05:30
<template #tabs-end>
<li class="gl-flex-grow-1 gl-align-self-center gl-w-full gl-lg-w-auto gl-py-2">
<div class="gl-lg-display-flex gl-justify-content-end gl-mx-n2 gl-my-n2">
<div class="gl-p-2 gl-lg-form-input-md gl-w-full">
<gl-search-box-by-type
:value="search"
:placeholder="$options.i18n.searchPlaceholder"
data-qa-selector="groups_filter_field"
@input="handleSearchInput"
/>
</div>
<div class="gl-p-2 gl-w-full gl-lg-w-auto">
<gl-sorting
class="gl-w-full"
dropdown-class="gl-w-full"
data-testid="group_sort_by_dropdown"
:text="sort.label"
:is-ascending="isAscending"
@sortDirectionChange="handleSortDirectionChange"
>
<gl-sorting-item
v-for="sortingItem in $options.OVERVIEW_TABS_SORTING_ITEMS"
:key="sortingItem.label"
:active="sortingItem === sort"
@click="handleSortingItemClick(sortingItem)"
>{{ sortingItem.label }}</gl-sorting-item
>
</gl-sorting>
</div>
</div>
</li>
</template>
2022-10-11 01:57:18 +05:30
</gl-tabs>
</template>