Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/groups')
-rw-r--r--app/assets/javascripts/groups/components/app.vue13
-rw-r--r--app/assets/javascripts/groups/components/group_item.vue22
-rw-r--r--app/assets/javascripts/groups/components/item_stats.vue8
-rw-r--r--app/assets/javascripts/groups/components/overview_tabs.vue103
-rw-r--r--app/assets/javascripts/groups/components/visibility_level_dropdown.vue48
-rw-r--r--app/assets/javascripts/groups/constants.js26
-rw-r--r--app/assets/javascripts/groups/index.js17
-rw-r--r--app/assets/javascripts/groups/init_overview_tabs.js78
-rw-r--r--app/assets/javascripts/groups/visibility_level.js24
9 files changed, 227 insertions, 112 deletions
diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue
index cd5521c599e..0bd7371d39b 100644
--- a/app/assets/javascripts/groups/components/app.vue
+++ b/app/assets/javascripts/groups/components/app.vue
@@ -17,11 +17,6 @@ export default {
GlLoadingIcon,
EmptyState,
},
- inject: {
- renderEmptyState: {
- default: false,
- },
- },
props: {
action: {
type: String,
@@ -45,6 +40,11 @@ export default {
type: Boolean,
required: true,
},
+ renderEmptyState: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -224,6 +224,9 @@ export default {
},
showLegacyEmptyState() {
const { containerEl } = this;
+
+ if (!containerEl) return;
+
const contentListEl = containerEl.querySelector(CONTENT_LIST_CLASS);
const emptyStateEl = containerEl.querySelector('.empty-state');
diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue
index 2f182b86d2c..961af800971 100644
--- a/app/assets/javascripts/groups/components/group_item.vue
+++ b/app/assets/javascripts/groups/components/group_item.vue
@@ -16,15 +16,15 @@ import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.
import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants';
import { helpPagePath } from '~/helpers/help_page_helper';
import { __ } from '~/locale';
-import { VISIBILITY_LEVELS_ENUM } from '~/visibility_level/constants';
+import { VISIBILITY_LEVELS_STRING_TO_INTEGER } from '~/visibility_level/constants';
import { VISIBILITY_TYPE_ICON, GROUP_VISIBILITY_TYPE, ITEM_TYPE } from '../constants';
import eventHub from '../event_hub';
-import itemActions from './item_actions.vue';
-import itemCaret from './item_caret.vue';
-import itemStats from './item_stats.vue';
-import itemTypeIcon from './item_type_icon.vue';
+import ItemActions from './item_actions.vue';
+import ItemCaret from './item_caret.vue';
+import ItemStats from './item_stats.vue';
+import ItemTypeIcon from './item_type_icon.vue';
export default {
directives: {
@@ -41,10 +41,10 @@ export default {
GlPopover,
GlLink,
UserAccessRoleBadge,
- itemCaret,
- itemTypeIcon,
- itemActions,
- itemStats,
+ ItemCaret,
+ ItemTypeIcon,
+ ItemActions,
+ ItemStats,
},
inject: ['currentGroupVisibility'],
props: {
@@ -111,8 +111,8 @@ export default {
shouldShowVisibilityWarning() {
return (
this.action === 'shared' &&
- VISIBILITY_LEVELS_ENUM[this.group.visibility] >
- VISIBILITY_LEVELS_ENUM[this.currentGroupVisibility]
+ VISIBILITY_LEVELS_STRING_TO_INTEGER[this.group.visibility] >
+ VISIBILITY_LEVELS_STRING_TO_INTEGER[this.currentGroupVisibility]
);
},
},
diff --git a/app/assets/javascripts/groups/components/item_stats.vue b/app/assets/javascripts/groups/components/item_stats.vue
index 2aa812250a0..a4c163b0a81 100644
--- a/app/assets/javascripts/groups/components/item_stats.vue
+++ b/app/assets/javascripts/groups/components/item_stats.vue
@@ -1,19 +1,19 @@
<script>
import { GlBadge } from '@gitlab/ui';
import isProjectPendingRemoval from 'ee_else_ce/groups/mixins/is_project_pending_removal';
-import timeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import {
ITEM_TYPE,
VISIBILITY_TYPE_ICON,
GROUP_VISIBILITY_TYPE,
PROJECT_VISIBILITY_TYPE,
} from '../constants';
-import itemStatsValue from './item_stats_value.vue';
+import ItemStatsValue from './item_stats_value.vue';
export default {
components: {
- timeAgoTooltip,
- itemStatsValue,
+ TimeAgoTooltip,
+ ItemStatsValue,
GlBadge,
},
mixins: [isProjectPendingRemoval],
diff --git a/app/assets/javascripts/groups/components/overview_tabs.vue b/app/assets/javascripts/groups/components/overview_tabs.vue
new file mode 100644
index 00000000000..325e42af0f8
--- /dev/null
+++ b/app/assets/javascripts/groups/components/overview_tabs.vue
@@ -0,0 +1,103 @@
+<script>
+import { GlTabs, GlTab } from '@gitlab/ui';
+import { isString } from 'lodash';
+import { __ } from '~/locale';
+import GroupsStore from '../store/groups_store';
+import GroupsService from '../service/groups_service';
+import {
+ ACTIVE_TAB_SUBGROUPS_AND_PROJECTS,
+ ACTIVE_TAB_SHARED,
+ ACTIVE_TAB_ARCHIVED,
+} from '../constants';
+import GroupsApp from './app.vue';
+
+export default {
+ components: { GlTabs, GlTab, GroupsApp },
+ inject: ['endpoints'],
+ data() {
+ return {
+ tabs: [
+ {
+ title: this.$options.i18n[ACTIVE_TAB_SUBGROUPS_AND_PROJECTS],
+ key: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS,
+ renderEmptyState: true,
+ lazy: false,
+ 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,
+ renderEmptyState: false,
+ lazy: true,
+ service: new GroupsService(this.endpoints[ACTIVE_TAB_SHARED]),
+ store: new GroupsStore(),
+ },
+ {
+ title: this.$options.i18n[ACTIVE_TAB_ARCHIVED],
+ key: ACTIVE_TAB_ARCHIVED,
+ renderEmptyState: false,
+ lazy: true,
+ service: new GroupsService(this.endpoints[ACTIVE_TAB_ARCHIVED]),
+ store: new GroupsStore(),
+ },
+ ],
+ activeTabIndex: 0,
+ };
+ },
+ mounted() {
+ const activeTabIndex = this.tabs.findIndex((tab) => tab.key === this.$route.name);
+
+ if (activeTabIndex === -1) {
+ return;
+ }
+
+ this.activeTabIndex = activeTabIndex;
+ },
+ 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;
+
+ this.$router.push({ name: tab.key, params: { group: groupParam } });
+ },
+ },
+ i18n: {
+ [ACTIVE_TAB_SUBGROUPS_AND_PROJECTS]: __('Subgroups and projects'),
+ [ACTIVE_TAB_SHARED]: __('Shared projects'),
+ [ACTIVE_TAB_ARCHIVED]: __('Archived projects'),
+ },
+};
+</script>
+
+<template>
+ <gl-tabs content-class="gl-pt-0" :value="activeTabIndex" @input="handleTabInput">
+ <gl-tab
+ v-for="{ key, title, renderEmptyState, lazy, service, store } in tabs"
+ :key="key"
+ :title="title"
+ :lazy="lazy"
+ >
+ <groups-app
+ :action="key"
+ :service="service"
+ :store="store"
+ :hide-projects="false"
+ :render-empty-state="renderEmptyState"
+ />
+ </gl-tab>
+ </gl-tabs>
+</template>
diff --git a/app/assets/javascripts/groups/components/visibility_level_dropdown.vue b/app/assets/javascripts/groups/components/visibility_level_dropdown.vue
deleted file mode 100644
index 0933045fc38..00000000000
--- a/app/assets/javascripts/groups/components/visibility_level_dropdown.vue
+++ /dev/null
@@ -1,48 +0,0 @@
-<script>
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
-
-export default {
- components: {
- GlDropdown,
- GlDropdownItem,
- },
- props: {
- visibilityLevelOptions: {
- type: Array,
- required: true,
- },
- defaultLevel: {
- type: Number,
- required: true,
- },
- },
- data() {
- return {
- selectedOption: this.getDefaultOption(),
- };
- },
- methods: {
- getDefaultOption() {
- return this.visibilityLevelOptions.find((option) => option.level === this.defaultLevel);
- },
- onClick(option) {
- this.selectedOption = option;
- },
- },
-};
-</script>
-<template>
- <div>
- <input type="hidden" name="group[visibility_level]" :value="selectedOption.level" />
- <gl-dropdown :text="selectedOption.label" class="gl-w-full" menu-class="gl-w-full! gl-mb-0">
- <gl-dropdown-item
- v-for="option in visibilityLevelOptions"
- :key="option.level"
- :secondary-text="option.description"
- @click="onClick(option)"
- >
- <div class="gl-font-weight-bold gl-mb-1">{{ option.label }}</div>
- </gl-dropdown-item>
- </gl-dropdown>
- </div>
-</template>
diff --git a/app/assets/javascripts/groups/constants.js b/app/assets/javascripts/groups/constants.js
index 0d09ad9442b..223c2975c11 100644
--- a/app/assets/javascripts/groups/constants.js
+++ b/app/assets/javascripts/groups/constants.js
@@ -1,8 +1,8 @@
import { __, s__ } from '~/locale';
import {
- VISIBILITY_LEVEL_PRIVATE,
- VISIBILITY_LEVEL_INTERNAL,
- VISIBILITY_LEVEL_PUBLIC,
+ VISIBILITY_LEVEL_PRIVATE_STRING,
+ VISIBILITY_LEVEL_INTERNAL_STRING,
+ VISIBILITY_LEVEL_PUBLIC_STRING,
} from '~/visibility_level/constants';
export const MAX_CHILDREN_COUNT = 20;
@@ -34,29 +34,31 @@ export const ITEM_TYPE = {
};
export const GROUP_VISIBILITY_TYPE = {
- [VISIBILITY_LEVEL_PUBLIC]: __(
+ [VISIBILITY_LEVEL_PUBLIC_STRING]: __(
'Public - The group and any public projects can be viewed without any authentication.',
),
- [VISIBILITY_LEVEL_INTERNAL]: __(
+ [VISIBILITY_LEVEL_INTERNAL_STRING]: __(
'Internal - The group and any internal projects can be viewed by any logged in user except external users.',
),
- [VISIBILITY_LEVEL_PRIVATE]: __(
+ [VISIBILITY_LEVEL_PRIVATE_STRING]: __(
'Private - The group and its projects can only be viewed by members.',
),
};
export const PROJECT_VISIBILITY_TYPE = {
- [VISIBILITY_LEVEL_PUBLIC]: __('Public - The project can be accessed without any authentication.'),
- [VISIBILITY_LEVEL_INTERNAL]: __(
+ [VISIBILITY_LEVEL_PUBLIC_STRING]: __(
+ 'Public - The project can be accessed without any authentication.',
+ ),
+ [VISIBILITY_LEVEL_INTERNAL_STRING]: __(
'Internal - The project can be accessed by any logged in user except external users.',
),
- [VISIBILITY_LEVEL_PRIVATE]: __(
+ [VISIBILITY_LEVEL_PRIVATE_STRING]: __(
'Private - Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group.',
),
};
export const VISIBILITY_TYPE_ICON = {
- [VISIBILITY_LEVEL_PUBLIC]: 'earth',
- [VISIBILITY_LEVEL_INTERNAL]: 'shield',
- [VISIBILITY_LEVEL_PRIVATE]: 'lock',
+ [VISIBILITY_LEVEL_PUBLIC_STRING]: 'earth',
+ [VISIBILITY_LEVEL_INTERNAL_STRING]: 'shield',
+ [VISIBILITY_LEVEL_PRIVATE_STRING]: 'lock',
};
diff --git a/app/assets/javascripts/groups/index.js b/app/assets/javascripts/groups/index.js
index a502fcd31ad..c3bf3f28509 100644
--- a/app/assets/javascripts/groups/index.js
+++ b/app/assets/javascripts/groups/index.js
@@ -4,9 +4,9 @@ import { parseBoolean } from '~/lib/utils/common_utils';
import UserCallout from '~/user_callout';
import Translate from '../vue_shared/translate';
-import groupsApp from './components/app.vue';
-import groupFolderComponent from './components/group_folder.vue';
-import groupItemComponent from './components/group_item.vue';
+import GroupsApp from './components/app.vue';
+import GroupFolderComponent from './components/group_folder.vue';
+import GroupItemComponent from './components/group_item.vue';
import { GROUPS_LIST_HOLDER_CLASS, CONTENT_LIST_CLASS } from './constants';
import GroupFilterableList from './groups_filterable_list';
import GroupsService from './service/groups_service';
@@ -33,8 +33,8 @@ export default (containerId = 'js-groups-tree', endpoint, action = '') => {
dataEl = containerEl.querySelector(CONTENT_LIST_CLASS);
}
- Vue.component('GroupFolder', groupFolderComponent);
- Vue.component('GroupItem', groupItemComponent);
+ Vue.component('GroupFolder', GroupFolderComponent);
+ Vue.component('GroupItem', GroupItemComponent);
Vue.use(GlToast);
@@ -42,7 +42,7 @@ export default (containerId = 'js-groups-tree', endpoint, action = '') => {
new Vue({
el,
components: {
- groupsApp,
+ GroupsApp,
},
provide() {
const {
@@ -52,7 +52,6 @@ export default (containerId = 'js-groups-tree', endpoint, action = '') => {
newSubgroupIllustration,
newProjectIllustration,
emptySubgroupIllustration,
- renderEmptyState,
canCreateSubgroups,
canCreateProjects,
currentGroupVisibility,
@@ -65,7 +64,6 @@ export default (containerId = 'js-groups-tree', endpoint, action = '') => {
newSubgroupIllustration,
newProjectIllustration,
emptySubgroupIllustration,
- renderEmptyState: parseBoolean(renderEmptyState),
canCreateSubgroups: parseBoolean(canCreateSubgroups),
canCreateProjects: parseBoolean(canCreateProjects),
currentGroupVisibility,
@@ -75,6 +73,7 @@ export default (containerId = 'js-groups-tree', endpoint, action = '') => {
const { dataset } = dataEl || this.$options.el;
const hideProjects = parseBoolean(dataset.hideProjects);
const showSchemaMarkup = parseBoolean(dataset.showSchemaMarkup);
+ const renderEmptyState = parseBoolean(dataset.renderEmptyState);
const service = new GroupsService(endpoint || dataset.endpoint);
const store = new GroupsStore({ hideProjects, showSchemaMarkup });
@@ -83,6 +82,7 @@ export default (containerId = 'js-groups-tree', endpoint, action = '') => {
store,
service,
hideProjects,
+ renderEmptyState,
loading: true,
containerId,
};
@@ -119,6 +119,7 @@ export default (containerId = 'js-groups-tree', endpoint, action = '') => {
store: this.store,
service: this.service,
hideProjects: this.hideProjects,
+ renderEmptyState: this.renderEmptyState,
containerId: this.containerId,
},
});
diff --git a/app/assets/javascripts/groups/init_overview_tabs.js b/app/assets/javascripts/groups/init_overview_tabs.js
new file mode 100644
index 00000000000..4fa3682c729
--- /dev/null
+++ b/app/assets/javascripts/groups/init_overview_tabs.js
@@ -0,0 +1,78 @@
+import Vue from 'vue';
+import VueRouter from 'vue-router';
+import { GlToast } from '@gitlab/ui';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import GroupFolder from './components/group_folder.vue';
+import GroupItem from './components/group_item.vue';
+import {
+ ACTIVE_TAB_SUBGROUPS_AND_PROJECTS,
+ ACTIVE_TAB_SHARED,
+ ACTIVE_TAB_ARCHIVED,
+} from './constants';
+import OverviewTabs from './components/overview_tabs.vue';
+
+export const createRouter = () => {
+ const routes = [
+ { name: ACTIVE_TAB_SHARED, path: '/groups/:group*/-/shared' },
+ { name: ACTIVE_TAB_ARCHIVED, path: '/groups/:group*/-/archived' },
+ { name: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, path: '/:group*' },
+ ];
+
+ const router = new VueRouter({
+ routes,
+ mode: 'history',
+ base: '/',
+ });
+
+ return router;
+};
+
+export const initGroupOverviewTabs = () => {
+ const el = document.getElementById('js-group-overview-tabs');
+
+ if (!el) return false;
+
+ Vue.component('GroupFolder', GroupFolder);
+ Vue.component('GroupItem', GroupItem);
+ Vue.use(GlToast);
+ Vue.use(VueRouter);
+
+ const router = createRouter();
+
+ const {
+ newSubgroupPath,
+ newProjectPath,
+ newSubgroupIllustration,
+ newProjectIllustration,
+ emptySubgroupIllustration,
+ canCreateSubgroups,
+ canCreateProjects,
+ currentGroupVisibility,
+ subgroupsAndProjectsEndpoint,
+ sharedProjectsEndpoint,
+ archivedProjectsEndpoint,
+ } = el.dataset;
+
+ return new Vue({
+ el,
+ router,
+ provide: {
+ newSubgroupPath,
+ newProjectPath,
+ newSubgroupIllustration,
+ newProjectIllustration,
+ emptySubgroupIllustration,
+ canCreateSubgroups: parseBoolean(canCreateSubgroups),
+ canCreateProjects: parseBoolean(canCreateProjects),
+ currentGroupVisibility,
+ endpoints: {
+ [ACTIVE_TAB_SUBGROUPS_AND_PROJECTS]: subgroupsAndProjectsEndpoint,
+ [ACTIVE_TAB_SHARED]: sharedProjectsEndpoint,
+ [ACTIVE_TAB_ARCHIVED]: archivedProjectsEndpoint,
+ },
+ },
+ render(createElement) {
+ return createElement(OverviewTabs);
+ },
+ });
+};
diff --git a/app/assets/javascripts/groups/visibility_level.js b/app/assets/javascripts/groups/visibility_level.js
deleted file mode 100644
index d570b5e65ac..00000000000
--- a/app/assets/javascripts/groups/visibility_level.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import Vue from 'vue';
-import VisibilityLevelDropdown from './components/visibility_level_dropdown.vue';
-
-export default () => {
- const el = document.querySelector('.js-visibility-level-dropdown');
-
- if (!el) {
- return null;
- }
-
- const { visibilityLevelOptions, defaultLevel } = el.dataset;
-
- return new Vue({
- el,
- render(createElement) {
- return createElement(VisibilityLevelDropdown, {
- props: {
- visibilityLevelOptions: JSON.parse(visibilityLevelOptions),
- defaultLevel: Number(defaultLevel),
- },
- });
- },
- });
-};