summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/members/components/members_tabs.vue
blob: 37b9135126d184d72eb330b2a95f5057833321bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
<script>
import { GlTabs, GlTab, GlBadge } from '@gitlab/ui';
import { mapState } from 'vuex';
import { urlParamsToObject } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
import { MEMBER_TYPES } from '../constants';
import MembersApp from './app.vue';

const countComputed = (state, namespace) => state[namespace]?.pagination?.totalItems || 0;

export default {
  name: 'MembersTabs',
  tabs: [
    {
      namespace: MEMBER_TYPES.user,
      title: __('Members'),
    },
    {
      namespace: MEMBER_TYPES.group,
      title: __('Groups'),
      attrs: { 'data-qa-selector': 'groups_list_tab' },
    },
    {
      namespace: MEMBER_TYPES.invite,
      title: __('Invited'),
      canManageMembersPermissionsRequired: true,
    },
    {
      namespace: MEMBER_TYPES.accessRequest,
      title: __('Access requests'),
      canManageMembersPermissionsRequired: true,
    },
  ],
  urlParams: [],
  components: { MembersApp, GlTabs, GlTab, GlBadge },
  inject: ['canManageMembers'],
  data() {
    return {
      selectedTabIndex: 0,
    };
  },
  computed: {
    ...mapState({
      userCount(state) {
        return countComputed(state, MEMBER_TYPES.user);
      },
      groupCount(state) {
        return countComputed(state, MEMBER_TYPES.group);
      },
      inviteCount(state) {
        return countComputed(state, MEMBER_TYPES.invite);
      },
      accessRequestCount(state) {
        return countComputed(state, MEMBER_TYPES.accessRequest);
      },
    }),
    urlParams() {
      return Object.keys(urlParamsToObject(window.location.search));
    },
    activeTabIndexCalculatedFromUrlParams() {
      return this.$options.tabs.findIndex(({ namespace }) => {
        return this.getTabUrlParams(namespace).some((urlParam) =>
          this.urlParams.includes(urlParam),
        );
      });
    },
  },
  created() {
    if (this.activeTabIndexCalculatedFromUrlParams === -1) {
      return;
    }

    this.selectedTabIndex = this.activeTabIndexCalculatedFromUrlParams;
  },
  methods: {
    getTabUrlParams(namespace) {
      const state = this.$store.state[namespace];
      const urlParams = [];

      if (state?.pagination?.paramName) {
        urlParams.push(state.pagination.paramName);
      }

      if (state?.filteredSearchBar?.searchParam) {
        urlParams.push(state.filteredSearchBar.searchParam);
      }

      return urlParams;
    },
    getTabCount({ namespace }) {
      return this[`${namespace}Count`];
    },
    showTab(tab, index) {
      if (tab.namespace === MEMBER_TYPES.user) {
        return true;
      }

      const { canManageMembersPermissionsRequired = false } = tab;
      const tabCanBeShown =
        this.getTabCount(tab) > 0 || this.activeTabIndexCalculatedFromUrlParams === index;

      if (canManageMembersPermissionsRequired) {
        return this.canManageMembers && tabCanBeShown;
      }

      return tabCanBeShown;
    },
  },
};
</script>

<template>
  <gl-tabs v-model="selectedTabIndex">
    <template v-for="(tab, index) in $options.tabs">
      <gl-tab v-if="showTab(tab, index)" :key="tab.namespace" :title-link-attributes="tab.attrs">
        <template slot="title">
          <span>{{ tab.title }}</span>
          <gl-badge size="sm" class="gl-tab-counter-badge">{{ getTabCount(tab) }}</gl-badge>
        </template>
        <members-app :namespace="tab.namespace" />
      </gl-tab>
    </template>
  </gl-tabs>
</template>