Commit 34426a7f authored by Nick Kipling's avatar Nick Kipling

Adds package type tabs to packages list

Updated app to include tabs
Moved sorting into dedicated component
Updated list and refactored table headings
Updated API requests to support package_type param
Updated tests
Updated pot file
parent 81c37f85
<script> <script>
import { mapState, mapActions, mapGetters } from 'vuex'; import { mapState, mapGetters } from 'vuex';
import { import {
GlTable, GlTable,
GlPagination, GlPagination,
GlButton, GlButton,
GlSorting,
GlSortingItem,
GlModal, GlModal,
GlLink, GlLink,
GlIcon, GlIcon,
...@@ -15,21 +13,10 @@ import Tracking from '~/tracking'; ...@@ -15,21 +13,10 @@ import Tracking from '~/tracking';
import { s__, sprintf } from '~/locale'; import { s__, sprintf } from '~/locale';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { import {
LIST_KEY_NAME,
LIST_KEY_PROJECT, LIST_KEY_PROJECT,
LIST_KEY_VERSION,
LIST_KEY_PACKAGE_TYPE,
LIST_KEY_CREATED_AT,
LIST_KEY_ACTIONS, LIST_KEY_ACTIONS,
LIST_LABEL_NAME,
LIST_LABEL_PROJECT,
LIST_LABEL_VERSION,
LIST_LABEL_PACKAGE_TYPE,
LIST_LABEL_CREATED_AT,
LIST_LABEL_ACTIONS, LIST_LABEL_ACTIONS,
LIST_ORDER_BY_PACKAGE_TYPE, TABLE_HEADER_FIELDS,
ASCENDING_ODER,
DESCENDING_ORDER,
} from '../constants'; } from '../constants';
import { TrackingActions } from '../../shared/constants'; import { TrackingActions } from '../../shared/constants';
import { packageTypeToTrackCategory } from '../../shared/utils'; import { packageTypeToTrackCategory } from '../../shared/utils';
...@@ -40,8 +27,6 @@ export default { ...@@ -40,8 +27,6 @@ export default {
components: { components: {
GlTable, GlTable,
GlPagination, GlPagination,
GlSorting,
GlSortingItem,
GlButton, GlButton,
GlLink, GlLink,
TimeAgoTooltip, TimeAgoTooltip,
...@@ -63,8 +48,6 @@ export default { ...@@ -63,8 +48,6 @@ export default {
totalItems: state => state.pagination.total, totalItems: state => state.pagination.total,
page: state => state.pagination.page, page: state => state.pagination.page,
isGroupPage: state => state.config.isGroupPage, isGroupPage: state => state.config.isGroupPage,
orderBy: state => state.sorting.orderBy,
sort: state => state.sorting.sort,
isLoading: 'isLoading', isLoading: 'isLoading',
}), }),
...mapGetters({ list: 'getList' }), ...mapGetters({ list: 'getList' }),
...@@ -76,61 +59,29 @@ export default { ...@@ -76,61 +59,29 @@ export default {
this.$emit('page:changed', value); this.$emit('page:changed', value);
}, },
}, },
sortText() {
const field = this.sortableFields.find(s => s.orderBy === this.orderBy);
return field ? field.label : '';
},
isSortAscending() {
return this.sort === ASCENDING_ODER;
},
isListEmpty() { isListEmpty() {
return !this.list || this.list.length === 0; return !this.list || this.list.length === 0;
}, },
showActions() { showActions() {
return !this.isGroupPage; return !this.isGroupPage;
}, },
sortableFields() {
// This list is filtered in the case of the project page, and the project column is removed
return [
{
key: LIST_KEY_NAME,
label: LIST_LABEL_NAME,
orderBy: LIST_KEY_NAME,
class: ['text-left'],
},
{
key: LIST_KEY_PROJECT,
label: LIST_LABEL_PROJECT,
orderBy: LIST_KEY_PROJECT,
class: ['text-left'],
},
{
key: LIST_KEY_VERSION,
label: LIST_LABEL_VERSION,
orderBy: LIST_KEY_VERSION,
class: ['text-center'],
},
{
key: LIST_KEY_PACKAGE_TYPE,
label: LIST_LABEL_PACKAGE_TYPE,
orderBy: LIST_ORDER_BY_PACKAGE_TYPE,
class: ['text-center'],
},
{
key: LIST_KEY_CREATED_AT,
label: LIST_LABEL_CREATED_AT,
orderBy: LIST_KEY_CREATED_AT,
class: this.showActions ? ['text-center'] : ['text-right'],
},
].filter(f => f.key !== LIST_KEY_PROJECT || this.isGroupPage);
},
headerFields() { headerFields() {
const actions = { const fields = TABLE_HEADER_FIELDS.filter(
key: LIST_KEY_ACTIONS, f => f.key !== LIST_KEY_PROJECT || this.isGroupPage,
label: LIST_LABEL_ACTIONS, );
tdClass: ['text-right'],
}; if (this.showActions) {
return this.showActions ? [...this.sortableFields, actions] : this.sortableFields; const actions = {
key: LIST_KEY_ACTIONS,
label: LIST_LABEL_ACTIONS,
tdClass: ['text-right'],
};
return [...fields, actions];
}
fields[fields.length - 1].class = ['text-right'];
return fields;
}, },
modalAction() { modalAction() {
return s__('PackageRegistry|Delete package'); return s__('PackageRegistry|Delete package');
...@@ -157,16 +108,6 @@ export default { ...@@ -157,16 +108,6 @@ export default {
}, },
}, },
methods: { methods: {
...mapActions(['setSorting']),
onDirectionChange() {
const sort = this.isSortAscending ? DESCENDING_ORDER : ASCENDING_ODER;
this.setSorting({ sort });
this.$emit('sort:changed');
},
onSortItemClick(item) {
this.setSorting({ orderBy: item });
this.$emit('sort:changed');
},
setItemToBeDeleted(item) { setItemToBeDeleted(item) {
this.itemToBeDeleted = { ...item }; this.itemToBeDeleted = { ...item };
this.track(TrackingActions.REQUEST_DELETE_PACKAGE); this.track(TrackingActions.REQUEST_DELETE_PACKAGE);
...@@ -190,22 +131,6 @@ export default { ...@@ -190,22 +131,6 @@ export default {
<slot v-if="isListEmpty && !isLoading" name="empty-state"></slot> <slot v-if="isListEmpty && !isLoading" name="empty-state"></slot>
<template v-else> <template v-else>
<gl-sorting
class="my-3 align-self-end"
:text="sortText"
:is-ascending="isSortAscending"
@sortDirectionChange="onDirectionChange"
>
<gl-sorting-item
v-for="item in sortableFields"
ref="packageListSortItem"
:key="item.key"
@click="onSortItemClick(item.orderBy)"
>
{{ item.label }}
</gl-sorting-item>
</gl-sorting>
<gl-table <gl-table
:items="list" :items="list"
:fields="headerFields" :fields="headerFields"
......
<script> <script>
import { mapActions, mapState } from 'vuex'; import { mapActions, mapState } from 'vuex';
import { GlEmptyState } from '@gitlab/ui'; import { GlEmptyState, GlTab, GlTabs } from '@gitlab/ui';
import { s__, sprintf } from '~/locale'; import { s__, sprintf } from '~/locale';
import PackageList from './packages_list.vue'; import PackageList from './packages_list.vue';
import PackageSort from './packages_sort.vue';
import { PACKAGE_REGISTRY_TABS } from '../constants';
export default { export default {
components: { components: {
GlEmptyState, GlEmptyState,
GlTab,
GlTabs,
PackageList, PackageList,
PackageSort,
}, },
computed: { computed: {
...mapState({ ...mapState({
...@@ -28,37 +33,52 @@ export default { ...@@ -28,37 +33,52 @@ export default {
false, false,
); );
}, },
tabsToRender() {
return PACKAGE_REGISTRY_TABS;
},
}, },
mounted() { mounted() {
this.requestPackagesList(); this.requestPackagesList();
}, },
methods: { methods: {
...mapActions(['requestPackagesList', 'requestDeletePackage']), ...mapActions(['requestPackagesList', 'requestDeletePackage', 'setSelectedType']),
onPageChanged(page) { onPageChanged(page) {
return this.requestPackagesList({ page }); return this.requestPackagesList({ page });
}, },
onPackageDeleteRequest(item) { onPackageDeleteRequest(item) {
return this.requestDeletePackage(item); return this.requestDeletePackage(item);
}, },
tabChanged(e) {
const selectedType = PACKAGE_REGISTRY_TABS[e];
this.setSelectedType(selectedType);
this.requestPackagesList();
},
}, },
}; };
</script> </script>
<template> <template>
<package-list <gl-tabs @input="tabChanged">
@page:changed="onPageChanged" <template #tabs-end>
@package:delete="onPackageDeleteRequest" <div class="align-self-center ml-auto">
@sort:changed="requestPackagesList" <package-sort @sort:changed="requestPackagesList" />
> </div>
<template #empty-state>
<gl-empty-state
:title="s__('PackageRegistry|There are no packages yet')"
:svg-path="emptyListIllustration"
>
<template #description>
<p v-html="emptyListText"></p>
</template>
</gl-empty-state>
</template> </template>
</package-list>
<gl-tab v-for="(tab, index) in tabsToRender" :key="index" :title="tab.title">
<package-list @page:changed="onPageChanged" @package:delete="onPackageDeleteRequest">
<template #empty-state>
<gl-empty-state
:title="s__('PackageRegistry|There are no packages yet')"
:svg-path="emptyListIllustration"
>
<template #description>
<p v-html="emptyListText"></p>
</template>
</gl-empty-state>
</template>
</package-list>
</gl-tab>
</gl-tabs>
</template> </template>
<script>
import { GlSorting, GlSortingItem } from '@gitlab/ui';
import {
LIST_KEY_PROJECT,
ASCENDING_ODER,
DESCENDING_ORDER,
TABLE_HEADER_FIELDS,
} from '../constants';
import { mapState, mapActions } from 'vuex';
export default {
name: 'PackageSort',
components: {
GlSorting,
GlSortingItem,
},
computed: {
...mapState({
isGroupPage: state => state.config.isGroupPage,
orderBy: state => state.sorting.orderBy,
sort: state => state.sorting.sort,
}),
sortText() {
const field = this.sortableFields.find(s => s.orderBy === this.orderBy);
return field ? field.label : '';
},
sortableFields() {
// This list is filtered in the case of the project page, and the project column is removed
return TABLE_HEADER_FIELDS.filter(f => f.key !== LIST_KEY_PROJECT || this.isGroupPage);
},
isSortAscending() {
return this.sort === ASCENDING_ODER;
},
},
methods: {
...mapActions(['setSorting']),
onDirectionChange() {
const sort = this.isSortAscending ? DESCENDING_ORDER : ASCENDING_ODER;
this.setSorting({ sort });
this.$emit('sort:changed');
},
onSortItemClick(item) {
this.setSorting({ orderBy: item });
this.$emit('sort:changed');
},
},
};
</script>
<template>
<gl-sorting
:text="sortText"
:is-ascending="isSortAscending"
@sortDirectionChange="onDirectionChange"
>
<gl-sorting-item
v-for="item in sortableFields"
ref="packageListSortItem"
:key="item.key"
@click="onSortItemClick(item.orderBy)"
>
{{ item.label }}
</gl-sorting-item>
</gl-sorting>
</template>
import { __ } from '~/locale'; import { __, s__ } from '~/locale';
export const FETCH_PACKAGES_LIST_ERROR_MESSAGE = __( export const FETCH_PACKAGES_LIST_ERROR_MESSAGE = __(
'Something went wrong while fetching the packages list.', 'Something went wrong while fetching the packages list.',
...@@ -33,3 +33,59 @@ export const DESCENDING_ORDER = 'desc'; ...@@ -33,3 +33,59 @@ export const DESCENDING_ORDER = 'desc';
// The following is not translated because it is used to build a JavaScript exception error message // The following is not translated because it is used to build a JavaScript exception error message
export const MISSING_DELETE_PATH_ERROR = 'Missing delete_api_path link'; export const MISSING_DELETE_PATH_ERROR = 'Missing delete_api_path link';
export const TABLE_HEADER_FIELDS = [
{
key: LIST_KEY_NAME,
label: LIST_LABEL_NAME,
orderBy: LIST_KEY_NAME,
class: ['text-left'],
},
{
key: LIST_KEY_PROJECT,
label: LIST_LABEL_PROJECT,
orderBy: LIST_KEY_PROJECT,
class: ['text-left'],
},
{
key: LIST_KEY_VERSION,
label: LIST_LABEL_VERSION,
orderBy: LIST_KEY_VERSION,
class: ['text-center'],
},
{
key: LIST_KEY_PACKAGE_TYPE,
label: LIST_LABEL_PACKAGE_TYPE,
orderBy: LIST_ORDER_BY_PACKAGE_TYPE,
class: ['text-center'],
},
{
key: LIST_KEY_CREATED_AT,
label: LIST_LABEL_CREATED_AT,
orderBy: LIST_KEY_CREATED_AT,
class: ['text-center'],
},
];
export const PACKAGE_REGISTRY_TABS = [
{
title: __('All'),
type: null,
},
{
title: s__('PackageRegistry|Conan'),
type: 'conan',
},
{
title: s__('PackageRegistry|Maven'),
type: 'maven',
},
{
title: s__('PackageRegistry|NPM'),
type: 'npm',
},
{
title: s__('PackageRegistry|NuGet'),
type: 'nuget',
},
];
...@@ -14,20 +14,24 @@ import { ...@@ -14,20 +14,24 @@ import {
export const setInitialState = ({ commit }, data) => commit(types.SET_INITIAL_STATE, data); export const setInitialState = ({ commit }, data) => commit(types.SET_INITIAL_STATE, data);
export const setLoading = ({ commit }, data) => commit(types.SET_MAIN_LOADING, data); export const setLoading = ({ commit }, data) => commit(types.SET_MAIN_LOADING, data);
export const setSorting = ({ commit }, data) => commit(types.SET_SORTING, data); export const setSorting = ({ commit }, data) => commit(types.SET_SORTING, data);
export const setSelectedType = ({ commit }, data) => commit(types.SET_SELECTED_TYPE, data);
export const receivePackagesListSuccess = ({ commit }, { data, headers }) => { export const receivePackagesListSuccess = ({ commit }, { data, headers }) => {
commit(types.SET_PACKAGE_LIST_SUCCESS, data); commit(types.SET_PACKAGE_LIST_SUCCESS, data);
commit(types.SET_PAGINATION, headers); commit(types.SET_PAGINATION, headers);
}; };
export const requestPackagesList = ({ dispatch, state }, pagination = {}) => { export const requestPackagesList = ({ dispatch, state }, params = {}) => {
dispatch('setLoading', true); dispatch('setLoading', true);
const { page = DEFAULT_PAGE, per_page = DEFAULT_PAGE_SIZE } = pagination; const { page = DEFAULT_PAGE, per_page = DEFAULT_PAGE_SIZE } = params;
const { sort, orderBy } = state.sorting; const { sort, orderBy } = state.sorting;
const type = state.selectedType?.type?.toLowerCase();
const packageType = { package_type: type };
const apiMethod = state.config.isGroupPage ? 'groupPackages' : 'projectPackages'; const apiMethod = state.config.isGroupPage ? 'groupPackages' : 'projectPackages';
return Api[apiMethod](state.config.resourceId, { return Api[apiMethod](state.config.resourceId, {
params: { page, per_page, sort, order_by: orderBy }, params: { page, per_page, sort, order_by: orderBy, ...packageType },
}) })
.then(({ data, headers }) => { .then(({ data, headers }) => {
dispatch('receivePackagesListSuccess', { data, headers }); dispatch('receivePackagesListSuccess', { data, headers });
......
...@@ -4,3 +4,4 @@ export const SET_PACKAGE_LIST_SUCCESS = 'SET_PACKAGE_LIST_SUCCESS'; ...@@ -4,3 +4,4 @@ export const SET_PACKAGE_LIST_SUCCESS = 'SET_PACKAGE_LIST_SUCCESS';
export const SET_PAGINATION = 'SET_PAGINATION'; export const SET_PAGINATION = 'SET_PAGINATION';
export const SET_MAIN_LOADING = 'SET_MAIN_LOADING'; export const SET_MAIN_LOADING = 'SET_MAIN_LOADING';
export const SET_SORTING = 'SET_SORTING'; export const SET_SORTING = 'SET_SORTING';
export const SET_SELECTED_TYPE = 'SET_SELECTED_TYPE';
...@@ -26,4 +26,8 @@ export default { ...@@ -26,4 +26,8 @@ export default {
[types.SET_SORTING](state, sorting) { [types.SET_SORTING](state, sorting) {
state.sorting = { ...state.sorting, ...sorting }; state.sorting = { ...state.sorting, ...sorting };
}, },
[types.SET_SELECTED_TYPE](state, type) {
state.selectedType = type;
},
}; };
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`packages_list_app renders 1`] = ` exports[`packages_list_app renders 1`] = `
<div> <b-tabs-stub
<div activenavitemclass="gl-tab-nav-item-active gl-tab-nav-item-active-indigo"
class="row empty-state" class="gl-tabs"
> contentclass=",gl-tab-content"
<div navclass="gl-tabs-nav"
class="col-12" nofade="true"
> nonavstyle="true"
<div tag="div"
class="svg-250 svg-content" >
> <template>
<img
alt="There are no packages yet"
class=""
src="helpSvg"
/>
</div>
</div>
<div <b-tab-stub
class="col-12" buttonid=""
tag="div"
title="All"
titlelinkclass="gl-tab-nav-item"
>
<template>
<div>
<div
class="row empty-state"
>
<div
class="col-12"
>
<div
class="svg-250 svg-content"
>
<img
alt="There are no packages yet"
class=""
src="helpSvg"
/>
</div>
</div>
<div
class="col-12"
>
<div
class="text-content"
>
<h4
class="center"
style=""
>
There are no packages yet
</h4>
<p
class="center"
style=""
>
<p>
Learn how to
<a
href="helpUrl"
target="_blank"
>
publish and share your packages
</a>
with GitLab.
</p>
</p>
<div
class="text-center"
>
<!---->
<!---->
</div>
</div>
</div>
</div>
</div>
</template>
</b-tab-stub>
<b-tab-stub
buttonid=""
tag="div"
title="Conan"
titlelinkclass="gl-tab-nav-item"
>
<template>
<div>
<div
class="row empty-state"
>
<div
class="col-12"
>
<div
class="svg-250 svg-content"
>
<img
alt="There are no packages yet"
class=""
src="helpSvg"
/>
</div>
</div>
<div
class="col-12"
>
<div
class="text-content"
>
<h4
class="center"
style=""
>
There are no packages yet
</h4>
<p
class="center"
style=""
>
<p>
Learn how to
<a
href="helpUrl"
target="_blank"
>
publish and share your packages
</a>
with GitLab.
</p>
</p>
<div
class="text-center"
>
<!---->
<!---->
</div>
</div>
</div>
</div>
</div>
</template>
</b-tab-stub>
<b-tab-stub
buttonid=""
tag="div"
title="Maven"
titlelinkclass="gl-tab-nav-item"
> >
<div <template>
class="text-content" <div>
> <div
<h4 class="row empty-state"
class="center" >
style="" <div
> class="col-12"
There are no packages yet >
</h4> <div
class="svg-250 svg-content"
<p >
class="center" <img
style="" alt="There are no packages yet"
> class=""
<p> src="helpSvg"
Learn how to />
<a </div>
href="helpUrl" </div>
target="_blank"
> <div
publish and share your packages class="col-12"
</a> >
with GitLab. <div
</p> class="text-content"
</p> >
<h4
<div class="center"
class="text-center" style=""
> >
<!----> There are no packages yet
</h4>
<!---->
<p
class="center"
style=""
>
<p>
Learn how to
<a
href="helpUrl"
target="_blank"
>
publish and share your packages
</a>
with GitLab.
</p>
</p>
<div
class="text-center"
>
<!---->
<!---->
</div>
</div>
</div>
</div>
</div>
</template>
</b-tab-stub>
<b-tab-stub
buttonid=""
tag="div"
title="NPM"
titlelinkclass="gl-tab-nav-item"
>
<template>
<div>
<div
class="row empty-state"
>
<div
class="col-12"
>
<div
class="svg-250 svg-content"
>
<img
alt="There are no packages yet"
class=""
src="helpSvg"
/>
</div>
</div>
<div
class="col-12"
>
<div
class="text-content"
>
<h4
class="center"
style=""
>
There are no packages yet
</h4>
<p
class="center"
style=""
>
<p>
Learn how to
<a
href="helpUrl"
target="_blank"
>
publish and share your packages
</a>
with GitLab.
</p>
</p>
<div
class="text-center"
>
<!---->
<!---->
</div>
</div>
</div>
</div>
</div> </div>
</div> </template>
</b-tab-stub>
<b-tab-stub
buttonid=""
tag="div"
title="NuGet"
titlelinkclass="gl-tab-nav-item"
>
<template>
<div>
<div
class="row empty-state"
>
<div
class="col-12"
>
<div
class="svg-250 svg-content"
>
<img
alt="There are no packages yet"
class=""
src="helpSvg"
/>
</div>
</div>
<div
class="col-12"
>
<div
class="text-content"
>
<h4
class="center"
style=""
>
There are no packages yet
</h4>
<p
class="center"
style=""
>
<p>
Learn how to
<a
href="helpUrl"
target="_blank"
>
publish and share your packages
</a>
with GitLab.
</p>
</p>
<div
class="text-center"
>
<!---->
<!---->
</div>
</div>
</div>
</div>
</div>
</template>
</b-tab-stub>
</template>
<template>
<div
class="align-self-center ml-auto"
>
<package-sort-stub />
</div> </div>
</div> </template>
</div> </b-tabs-stub>
`; `;
import Vuex from 'vuex'; import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import { GlEmptyState } from '@gitlab/ui'; import { GlEmptyState, GlTab, GlTabs } from '@gitlab/ui';
import PackageListApp from 'ee/packages/list/components/packages_list_app.vue'; import PackageListApp from 'ee/packages/list/components/packages_list_app.vue';
const localVue = createLocalVue(); const localVue = createLocalVue();
...@@ -18,6 +18,7 @@ describe('packages_list_app', () => { ...@@ -18,6 +18,7 @@ describe('packages_list_app', () => {
const emptyListHelpUrl = 'helpUrl'; const emptyListHelpUrl = 'helpUrl';
const findListComponent = () => wrapper.find(PackageList); const findListComponent = () => wrapper.find(PackageList);
const findTabComponent = (index = 0) => wrapper.findAll(GlTab).at(index);
const mountComponent = () => { const mountComponent = () => {
wrapper = shallowMount(PackageListApp, { wrapper = shallowMount(PackageListApp, {
...@@ -27,6 +28,8 @@ describe('packages_list_app', () => { ...@@ -27,6 +28,8 @@ describe('packages_list_app', () => {
GlEmptyState, GlEmptyState,
GlLoadingIcon, GlLoadingIcon,
PackageList, PackageList,
GlTab,
GlTabs,
}, },
}); });
}; };
...@@ -81,4 +84,18 @@ describe('packages_list_app', () => { ...@@ -81,4 +84,18 @@ describe('packages_list_app', () => {
list.vm.$emit('sort:changed'); list.vm.$emit('sort:changed');
expect(store.dispatch).toHaveBeenCalledWith('requestPackagesList'); expect(store.dispatch).toHaveBeenCalledWith('requestPackagesList');
}); });
describe('tab change', () => {
it('calls requestPackagesList when all tab is clicked', () => {
findTabComponent().trigger('click');
expect(store.dispatch).toHaveBeenCalledWith('requestPackagesList');
});
it('calls requestPackagesList when a package type tab is clicked', () => {
findTabComponent(1).trigger('click');
expect(store.dispatch).toHaveBeenCalledWith('requestPackagesList');
});
});
}); });
import Vuex from 'vuex'; import Vuex from 'vuex';
import { last } from 'lodash'; import { last } from 'lodash';
import { GlTable, GlSorting, GlPagination, GlModal } from '@gitlab/ui'; import { GlTable, GlPagination, GlModal } from '@gitlab/ui';
import Tracking from '~/tracking'; import Tracking from '~/tracking';
import { mount, createLocalVue } from '@vue/test-utils'; import { mount, createLocalVue } from '@vue/test-utils';
import PackagesList from 'ee/packages/list/components/packages_list.vue'; import PackagesList from 'ee/packages/list/components/packages_list.vue';
...@@ -24,10 +24,8 @@ describe('packages_list', () => { ...@@ -24,10 +24,8 @@ describe('packages_list', () => {
const findPackagesListLoader = () => wrapper.find(PackagesListLoader); const findPackagesListLoader = () => wrapper.find(PackagesListLoader);
const findFirstActionColumn = () => wrapper.find({ ref: 'action-delete' }); const findFirstActionColumn = () => wrapper.find({ ref: 'action-delete' });
const findPackageListTable = () => wrapper.find(GlTable); const findPackageListTable = () => wrapper.find(GlTable);
const findPackageListSorting = () => wrapper.find(GlSorting);
const findPackageListPagination = () => wrapper.find(GlPagination); const findPackageListPagination = () => wrapper.find(GlPagination);
const findPackageListDeleteModal = () => wrapper.find(GlModal); const findPackageListDeleteModal = () => wrapper.find(GlModal);
const findSortingItems = () => wrapper.findAll(GlSortingItem);
const findFirstProjectColumn = () => wrapper.find({ ref: 'col-project' }); const findFirstProjectColumn = () => wrapper.find({ ref: 'col-project' });
const findPackageTags = () => wrapper.findAll(PackageTags); const findPackageTags = () => wrapper.findAll(PackageTags);
const findEmptySlot = () => wrapper.find({ name: 'empty-slot-stub' }); const findEmptySlot = () => wrapper.find({ name: 'empty-slot-stub' });
...@@ -127,11 +125,6 @@ describe('packages_list', () => { ...@@ -127,11 +125,6 @@ describe('packages_list', () => {
mountComponent(); mountComponent();
}); });
it('contains a sorting component', () => {
const sorting = findPackageListSorting();
expect(sorting.exists()).toBe(true);
});
it('contains a table component', () => { it('contains a table component', () => {
const sorting = findPackageListTable(); const sorting = findPackageListTable();
expect(sorting.exists()).toBe(true); expect(sorting.exists()).toBe(true);
...@@ -222,35 +215,6 @@ describe('packages_list', () => { ...@@ -222,35 +215,6 @@ describe('packages_list', () => {
}); });
}); });
describe('sorting component', () => {
let sorting;
let sortingItems;
beforeEach(() => {
mountComponent();
sorting = findPackageListSorting();
sortingItems = findSortingItems();
});
it('has all the sortable items', () => {
expect(sortingItems.length).toEqual(wrapper.vm.sortableFields.length);
});
it('on sort change set sorting in vuex and emit event', () => {
sorting.vm.$emit('sortDirectionChange');
expect(store.dispatch).toHaveBeenCalledWith('setSorting', { sort: 'asc' });
expect(wrapper.emitted('sort:changed')).toBeTruthy();
});
it('on sort item click set sorting and emit event', () => {
const item = sortingItems.at(0);
const { orderBy } = wrapper.vm.sortableFields[0];
item.vm.$emit('click');
expect(store.dispatch).toHaveBeenCalledWith('setSorting', { orderBy });
expect(wrapper.emitted('sort:changed')).toBeTruthy();
});
});
describe('pagination component', () => { describe('pagination component', () => {
let pagination; let pagination;
let modelEvent; let modelEvent;
......
import Vuex from 'vuex';
import { GlSorting } from '@gitlab/ui';
import { mount, createLocalVue } from '@vue/test-utils';
import PackagesSort from 'ee/packages/list/components/packages_sort.vue';
import stubChildren from 'helpers/stub_children';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('packages_sort', () => {
let wrapper;
let store;
let sorting;
let sortingItems;
const GlSortingItem = { name: 'sorting-item-stub', template: '<div><slot></slot></div>' };
const findPackageListSorting = () => wrapper.find(GlSorting);
const findSortingItems = () => wrapper.findAll(GlSortingItem);
const createStore = isGroupPage => {
const state = {
config: {
isGroupPage,
},
sorting: {
orderBy: 'version',
sort: 'desc',
},
};
store = new Vuex.Store({
state,
});
store.dispatch = jest.fn();
};
const mountComponent = (isGroupPage = false) => {
createStore(isGroupPage);
wrapper = mount(PackagesSort, {
localVue,
store,
stubs: {
...stubChildren(PackagesSort),
GlSortingItem,
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('when is in projects', () => {
beforeEach(() => {
mountComponent();
sorting = findPackageListSorting();
sortingItems = findSortingItems();
});
it('has all the sortable items', () => {
expect(sortingItems.length).toEqual(wrapper.vm.sortableFields.length);
});
it('on sort change set sorting in vuex and emit event', () => {
sorting.vm.$emit('sortDirectionChange');
expect(store.dispatch).toHaveBeenCalledWith('setSorting', { sort: 'asc' });
expect(wrapper.emitted('sort:changed')).toBeTruthy();
});
it('on sort item click set sorting and emit event', () => {
const item = sortingItems.at(0);
const { orderBy } = wrapper.vm.sortableFields[0];
item.vm.$emit('click');
expect(store.dispatch).toHaveBeenCalledWith('setSorting', { orderBy });
expect(wrapper.emitted('sort:changed')).toBeTruthy();
});
});
describe('when is in group', () => {
beforeEach(() => {
mountComponent(true);
sorting = findPackageListSorting();
sortingItems = findSortingItems();
});
it('has all the sortable items', () => {
expect(sortingItems.length).toEqual(wrapper.vm.sortableFields.length);
});
});
});
...@@ -72,6 +72,38 @@ describe('Actions Package list store', () => { ...@@ -72,6 +72,38 @@ describe('Actions Package list store', () => {
); );
}); });
it('should fetch packages of a certain type when selectedType is present', done => {
const packageType = 'maven';
testAction(
actions.requestPackagesList,
undefined,
{
config: { isGroupPage: false, resourceId: 1 },
sorting,
selectedType: { type: packageType },
},
[],
[
{ type: 'setLoading', payload: true },
{ type: 'receivePackagesListSuccess', payload: { data: 'foo', headers } },
{ type: 'setLoading', payload: false },
],
() => {
expect(Api.projectPackages).toHaveBeenCalledWith(1, {
params: {
page: 1,
per_page: 20,
sort: sorting.sort,
order_by: sorting.orderBy,
package_type: packageType,
},
});
done();
},
);
});
it('should create flash on API error', done => { it('should create flash on API error', done => {
Api.projectPackages = jest.fn().mockRejectedValue(); Api.projectPackages = jest.fn().mockRejectedValue();
testAction( testAction(
......
...@@ -77,4 +77,11 @@ describe('Mutations Registry Store', () => { ...@@ -77,4 +77,11 @@ describe('Mutations Registry Store', () => {
expect(mockState.sorting).toEqual({ ...mockState.sorting, orderBy: 'foo' }); expect(mockState.sorting).toEqual({ ...mockState.sorting, orderBy: 'foo' });
}); });
}); });
describe('SET_SELECTED_TYPE', () => {
it('should set the selected type', () => {
mutations[types.SET_SELECTED_TYPE](mockState, { type: 'maven' });
expect(mockState.selectedType).toEqual({ type: 'maven' });
});
});
}); });
...@@ -13855,6 +13855,9 @@ msgstr "" ...@@ -13855,6 +13855,9 @@ msgstr ""
msgid "PackageRegistry|Add NuGet Source" msgid "PackageRegistry|Add NuGet Source"
msgstr "" msgstr ""
msgid "PackageRegistry|Conan"
msgstr ""
msgid "PackageRegistry|Conan Command" msgid "PackageRegistry|Conan Command"
msgstr "" msgstr ""
...@@ -13918,12 +13921,21 @@ msgstr "" ...@@ -13918,12 +13921,21 @@ msgstr ""
msgid "PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab." msgid "PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab."
msgstr "" msgstr ""
msgid "PackageRegistry|Maven"
msgstr ""
msgid "PackageRegistry|Maven Command" msgid "PackageRegistry|Maven Command"
msgstr "" msgstr ""
msgid "PackageRegistry|Maven XML" msgid "PackageRegistry|Maven XML"
msgstr "" msgstr ""
msgid "PackageRegistry|NPM"
msgstr ""
msgid "PackageRegistry|NuGet"
msgstr ""
msgid "PackageRegistry|NuGet Command" msgid "PackageRegistry|NuGet Command"
msgstr "" msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment