Commit 8a9609d4 authored by Eulyeon Ko's avatar Eulyeon Ko

Hide archived projects

In group boards,
when creating a new issue,
archived projects should not appear
in the dropdown list.
parent 1e7ea614
......@@ -7,7 +7,7 @@ import {
GlIntersectionObserver,
GlLoadingIcon,
} from '@gitlab/ui';
import { mapActions, mapState } from 'vuex';
import { mapActions, mapState, mapGetters } from 'vuex';
import { s__ } from '~/locale';
import { featureAccessLevel } from '~/pages/projects/shared/permissions/constants';
import { ListType } from '../constants';
......@@ -49,7 +49,8 @@ export default {
};
},
computed: {
...mapState(['groupProjects', 'groupProjectsFlags']),
...mapState(['groupProjectsFlags']),
...mapGetters(['activeGroupProjects']),
selectedProjectName() {
return this.selectedProject.name || this.$options.i18n.dropdownText;
},
......@@ -65,7 +66,7 @@ export default {
};
},
isFetchResultEmpty() {
return this.groupProjects.length === 0;
return this.activeGroupProjects.length === 0;
},
hasNextPage() {
return this.groupProjectsFlags.pageInfo?.hasNextPage;
......@@ -84,7 +85,7 @@ export default {
methods: {
...mapActions(['fetchGroupProjects', 'setSelectedProject']),
selectProject(projectId) {
this.selectedProject = this.groupProjects.find((project) => project.id === projectId);
this.selectedProject = this.activeGroupProjects.find((project) => project.id === projectId);
this.setSelectedProject(this.selectedProject);
},
loadMoreProjects() {
......@@ -113,7 +114,7 @@ export default {
:placeholder="$options.i18n.searchPlaceholder"
/>
<gl-dropdown-item
v-for="project in groupProjects"
v-for="project in activeGroupProjects"
v-show="!groupProjectsFlags.isLoading"
:key="project.id"
:name="project.name"
......
......@@ -25,6 +25,7 @@ export default {
with_shared: false,
include_subgroups: true,
order_by: 'similarity',
archived: false,
},
components: {
GlLoadingIcon,
......
......@@ -8,6 +8,7 @@ query getGroupProjects($fullPath: ID!, $search: String, $after: String) {
name
fullPath
nameWithNamespace
archived
}
pageInfo {
...PageInfo
......
......@@ -29,6 +29,10 @@ export default {
return referencePath.slice(0, referencePath.indexOf('#'));
},
activeGroupProjects: (state) => {
return state.groupProjects.filter((p) => !p.archived);
},
getListByLabelId: (state) => (labelId) => {
if (!labelId) {
return null;
......
---
title: Hide archived projects from group boards project select dropdown
merge_request: 56452
author:
type: changed
......@@ -351,6 +351,7 @@ export const issues = {
[mockIssue4.id]: mockIssue4,
};
// The response from group project REST API
export const mockRawGroupProjects = [
{
id: 0,
......@@ -366,17 +367,34 @@ export const mockRawGroupProjects = [
},
];
export const mockGroupProjects = [
{
id: 0,
name: 'Example Project',
nameWithNamespace: 'Awesome Group / Example Project',
fullPath: 'awesome-group/example-project',
},
{
id: 1,
name: 'Foobar Project',
nameWithNamespace: 'Awesome Group / Foobar Project',
fullPath: 'awesome-group/foobar-project',
},
// The response from GraphQL endpoint
export const mockGroupProject1 = {
id: 0,
name: 'Example Project',
nameWithNamespace: 'Awesome Group / Example Project',
fullPath: 'awesome-group/example-project',
archived: false,
};
export const mockGroupProject2 = {
id: 1,
name: 'Foobar Project',
nameWithNamespace: 'Awesome Group / Foobar Project',
fullPath: 'awesome-group/foobar-project',
archived: false,
};
export const mockArchivedGroupProject = {
id: 2,
name: 'Archived Project',
nameWithNamespace: 'Awesome Group / Archived Project',
fullPath: 'awesome-group/archived-project',
archived: true,
};
export const mockGroupProjects = [mockGroupProject1, mockGroupProject2];
export const mockActiveGroupProjects = [
{ ...mockGroupProject1, archived: false },
{ ...mockGroupProject2, archived: false },
];
......@@ -27,6 +27,7 @@ const mockDefaultFetchOptions = {
with_shared: false,
include_subgroups: true,
order_by: 'similarity',
archived: false,
};
const itemsPerPage = 20;
......
import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlLoadingIcon } from '@gitlab/ui';
import { createLocalVue, mount } from '@vue/test-utils';
import { mount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
import ProjectSelect from '~/boards/components/project_select.vue';
import defaultState from '~/boards/stores/state';
import { mockList, mockGroupProjects } from './mock_data';
import { mockList, mockActiveGroupProjects } from './mock_data';
const localVue = createLocalVue();
localVue.use(Vuex);
const actions = {
fetchGroupProjects: jest.fn(),
setSelectedProject: jest.fn(),
};
const createStore = (state = defaultState) => {
return new Vuex.Store({
state,
actions,
});
};
const mockProjectsList1 = mockGroupProjects.slice(0, 1);
const mockProjectsList1 = mockActiveGroupProjects.slice(0, 1);
describe('ProjectSelect component', () => {
let wrapper;
let store;
const findLabel = () => wrapper.find("[data-testid='header-label']");
const findGlDropdown = () => wrapper.find(GlDropdown);
......@@ -36,20 +23,37 @@ describe('ProjectSelect component', () => {
const findInMenuLoadingIcon = () => wrapper.find("[data-testid='dropdown-text-loading-icon']");
const findEmptySearchMessage = () => wrapper.find("[data-testid='empty-result-message']");
const createWrapper = (state = {}) => {
const store = createStore({
groupProjects: [],
groupProjectsFlags: {
isLoading: false,
pageInfo: {
hasNextPage: false,
const createStore = ({ state, activeGroupProjects }) => {
Vue.use(Vuex);
store = new Vuex.Store({
state: {
defaultState,
groupProjectsFlags: {
isLoading: false,
pageInfo: {
hasNextPage: false,
},
},
...state,
},
actions: {
fetchGroupProjects: jest.fn(),
setSelectedProject: jest.fn(),
},
...state,
getters: {
activeGroupProjects: () => activeGroupProjects,
},
});
};
const createWrapper = ({ state = {}, activeGroupProjects = [] } = {}) => {
createStore({
state,
activeGroupProjects,
});
wrapper = mount(ProjectSelect, {
localVue,
propsData: {
list: mockList,
},
......@@ -93,7 +97,7 @@ describe('ProjectSelect component', () => {
describe('when dropdown menu is open', () => {
describe('by default', () => {
beforeEach(() => {
createWrapper({ groupProjects: mockGroupProjects });
createWrapper({ activeGroupProjects: mockActiveGroupProjects });
});
it('shows GlSearchBoxByType with default attributes', () => {
......@@ -128,7 +132,7 @@ describe('ProjectSelect component', () => {
describe('when a project is selected', () => {
beforeEach(() => {
createWrapper({ groupProjects: mockProjectsList1 });
createWrapper({ activeGroupProjects: mockProjectsList1 });
findFirstGlDropdownItem().find('button').trigger('click');
});
......@@ -142,7 +146,7 @@ describe('ProjectSelect component', () => {
describe('when projects are loading', () => {
beforeEach(() => {
createWrapper({ groupProjectsFlags: { isLoading: true } });
createWrapper({ state: { groupProjectsFlags: { isLoading: true } } });
});
it('displays and hides gl-loading-icon while and after fetching data', () => {
......
......@@ -7,6 +7,8 @@ import {
mockIssuesByListId,
issues,
mockLists,
mockGroupProject1,
mockArchivedGroupProject,
} from '../mock_data';
describe('Boards - Getters', () => {
......@@ -165,4 +167,14 @@ describe('Boards - Getters', () => {
expect(getters.getListByTitle(boardsState)('To Do')).toEqual(mockLists[1]);
});
});
describe('activeGroupProjects', () => {
const state = {
groupProjects: [mockGroupProject1, mockArchivedGroupProject],
};
it('returns only returns non-archived group projects', () => {
expect(getters.activeGroupProjects(state)).toEqual([mockGroupProject1]);
});
});
});
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