Commit 73ab35bf authored by Simon Knox's avatar Simon Knox

Merge branch...

Merge branch '270583-improve-efficiency-when-creating-additional-boards-within-a-group-or-project' into 'master'

Boards - Remove default labels lists generation [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!49071
parents 920f4430 d619e43c
......@@ -2,7 +2,6 @@
import { mapGetters, mapActions, mapState } from 'vuex';
import BoardListHeader from 'ee_else_ce/boards/components/board_list_header_new.vue';
import BoardList from './board_list_new.vue';
import { ListType } from '../constants';
export default {
components: {
......@@ -36,16 +35,11 @@ export default {
listIssues() {
return this.getIssuesByList(this.list.id);
},
shouldFetchIssues() {
return this.list.type !== ListType.blank;
},
},
watch: {
filterParams: {
handler() {
if (this.shouldFetchIssues) {
this.fetchIssuesForList({ listId: this.list.id });
}
this.fetchIssuesForList({ listId: this.list.id });
},
deep: true,
immediate: true,
......
......@@ -72,9 +72,7 @@ export default {
return this.list?.label?.description || this.list.title || '';
},
showListHeaderButton() {
return (
!this.disabled && this.listType !== ListType.closed && this.listType !== ListType.blank
);
return !this.disabled && this.listType !== ListType.closed;
},
showMilestoneListDetails() {
return (
......@@ -106,9 +104,6 @@ export default {
this.listType !== ListType.backlog && this.showListHeaderButton && this.list.isExpanded
);
},
showBoardListAndBoardInfo() {
return this.listType !== ListType.blank;
},
uniqueKey() {
// eslint-disable-next-line @gitlab/require-i18n-strings
return `boards.${this.boardId}.${this.listType}.${this.list.id}`;
......@@ -286,7 +281,6 @@ export default {
</gl-tooltip>
<div
v-if="showBoardListAndBoardInfo"
class="issue-count-badge gl-display-inline-flex gl-pr-0 no-drag text-secondary"
:class="{
'gl-display-none!': !list.isExpanded && isSwimlanesHeader,
......
......@@ -75,9 +75,7 @@ export default {
return this.list?.label?.description || this.list.title || '';
},
showListHeaderButton() {
return (
!this.disabled && this.listType !== ListType.closed && this.listType !== ListType.blank
);
return !this.disabled && this.listType !== ListType.closed;
},
showMilestoneListDetails() {
return (
......@@ -111,9 +109,6 @@ export default {
this.listType !== ListType.backlog && this.showListHeaderButton && this.list.isExpanded
);
},
showBoardListAndBoardInfo() {
return this.listType !== ListType.blank;
},
uniqueKey() {
// eslint-disable-next-line @gitlab/require-i18n-strings
return `boards.${this.boardId}.${this.listType}.${this.list.id}`;
......@@ -299,7 +294,6 @@ export default {
<!-- EE end -->
<div
v-if="showBoardListAndBoardInfo"
class="issue-count-badge gl-display-inline-flex gl-pr-0 no-drag gl-text-gray-500"
:class="{
'gl-display-none!': !list.isExpanded && isSwimlanesHeader,
......
......@@ -9,7 +9,6 @@ export const ListType = {
backlog: 'backlog',
closed: 'closed',
label: 'label',
blank: 'blank',
};
export const inactiveId = 0;
......@@ -17,11 +16,7 @@ export const inactiveId = 0;
export const ISSUABLE = 'issuable';
export const LIST = 'list';
/* eslint-disable-next-line @gitlab/require-i18n-strings */
export const DEFAULT_LABELS = ['to do', 'doing'];
export default {
BoardType,
ListType,
DEFAULT_LABELS,
};
......@@ -181,7 +181,6 @@ export default () => {
.then(res => res.data)
.then(lists => {
lists.forEach(list => boardsStore.addList(list));
boardsStore.addBlankState();
this.loading = false;
})
.catch(() => {
......
......@@ -3,7 +3,7 @@ import { pick } from 'lodash';
import boardListsQuery from 'ee_else_ce/boards/graphql/board_lists.query.graphql';
import createGqClient, { fetchPolicies } from '~/lib/graphql';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { BoardType, ListType, inactiveId, DEFAULT_LABELS } from '~/boards/constants';
import { BoardType, ListType, inactiveId } from '~/boards/constants';
import * as types from './mutation_types';
import {
formatBoardLists,
......@@ -89,7 +89,6 @@ export default {
if (!lists.nodes.find(l => l.listType === ListType.backlog) && !hideBacklogList) {
dispatch('createList', { backlog: true });
}
dispatch('generateDefaultLists');
})
.catch(() => commit(types.RECEIVE_BOARD_LISTS_FAILURE));
},
......@@ -150,31 +149,6 @@ export default {
.catch(() => commit(types.RECEIVE_LABELS_FAILURE));
},
generateDefaultLists: async ({ state, commit, dispatch }) => {
if (state.disabled) {
return;
}
if (
Object.entries(state.boardLists).find(
([, list]) => list.type !== ListType.backlog && list.type !== ListType.closed,
)
) {
return;
}
const fetchLabelsAndCreateList = label => {
return dispatch('fetchLabels', label)
.then(res => {
if (res.length > 0) {
dispatch('createList', { labelId: res[0].id });
}
})
.catch(() => commit(types.GENERATE_DEFAULT_LISTS_FAILURE));
};
await Promise.all(DEFAULT_LABELS.map(fetchLabelsAndCreateList));
},
moveList: (
{ state, commit, dispatch },
{ listId, replacedListId, newIndex, adjustmentValue },
......
......@@ -3,7 +3,6 @@
/* global ListIssue */
import { sortBy, pick } from 'lodash';
import Vue from 'vue';
import Cookies from 'js-cookie';
import BoardsStoreEE from 'ee_else_ce/boards/stores/boards_store_ee';
import {
urlParamsToObject,
......@@ -125,20 +124,6 @@ const boardsStore = {
.querySelector(`.js-board-list-${getIdFromGraphQLId(listId)}`)
?.classList.remove('is-active');
},
shouldAddBlankState() {
// Decide whether to add the blank state
return !this.state.lists.filter(list => list.type !== 'backlog' && list.type !== 'closed')[0];
},
addBlankState() {
if (!this.shouldAddBlankState() || this.welcomeIsHidden()) return;
this.generateDefaultLists()
.then(res => res.data)
.then(data => Promise.all(data.map(list => this.addList(list))))
.catch(() => {
this.removeList(undefined, 'label');
});
},
findIssueLabel(issue, findLabel) {
return issue.labels.find(label => label.id === findLabel.id);
......@@ -202,9 +187,6 @@ const boardsStore = {
return list.issues.find(issue => issue.id === id);
},
welcomeIsHidden() {
return parseBoolean(Cookies.get('issue_board_welcome_hidden'));
},
removeList(id, type = 'blank') {
const list = this.findList('id', id, type);
......@@ -562,10 +544,6 @@ const boardsStore = {
return axios.get(this.state.endpoints.listsEndpoint);
},
generateDefaultLists() {
return axios.post(this.state.endpoints.listsEndpointGenerate, {});
},
createList(entityId, entityType) {
const list = {
[entityType]: entityId,
......
......@@ -32,11 +32,10 @@ export const addIssueToList = ({ state, listId, issueId, moveBeforeId, moveAfter
export default {
[mutationTypes.SET_INITIAL_BOARD_DATA](state, data) {
const { boardType, disabled, showPromotion, ...endpoints } = data;
const { boardType, disabled, ...endpoints } = data;
state.endpoints = endpoints;
state.boardType = boardType;
state.disabled = disabled;
state.showPromotion = showPromotion;
},
[mutationTypes.RECEIVE_BOARD_LISTS_SUCCESS]: (state, lists) => {
......
......@@ -4,7 +4,6 @@ export default () => ({
endpoints: {},
boardType: null,
disabled: false,
showPromotion: false,
isShowingLabels: true,
activeId: inactiveId,
sidebarType: '',
......
......@@ -71,8 +71,6 @@ class ProjectsController < Projects::ApplicationController
@project = ::Projects::CreateService.new(current_user, project_params(attributes: project_params_create_attributes)).execute
if @project.saved?
cookies[:issue_board_welcome_hidden] = { path: project_path(@project), value: nil, expires: Time.zone.at(0) }
redirect_to(
project_path(@project, custom_import_params),
notice: _("Project '%{project_name}' was successfully created.") % { project_name: @project.name }
......
---
title: Boards - Remove default labels lists generation
merge_request: 49071
author:
type: changed
......@@ -394,19 +394,6 @@ status.
If you're not able to do some of the things above, make sure you have the right
[permissions](#permissions).
### First time using an issue board
> The automatic creation of the **To Do** and **Doing** lists was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/202144) in GitLab 13.5.
The first time you open an issue board, you are presented with the default lists
(**Open**, **To Do**, **Doing**, and **Closed**).
If the **To Do** and **Doing** labels don't exist in the project or group, they are created, and
their lists appear as empty. If any of them already exists, the list is filled with the issues that
have that label.
![issue board default lists](img/issue_board_default_lists_v13_4.png)
### Create a new list
Create a new list by clicking the **Add list** dropdown button in the upper right corner of the issue board.
......@@ -566,6 +553,22 @@ To select and move multiple cards:
![Multi-select Issue Cards](img/issue_boards_multi_select_v12_4.png)
### First time using an issue board
> - The automatic creation of the **To Do** and **Doing** lists [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/202144) in GitLab 13.5.
> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/270583) in GitLab 13.7. In GitLab 13.7 and later, the **To Do** and **Doing** columns are not automatically created.
WARNING:
This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/270583) in GitLab 13.7.
The **To Do** and **Doing** columns are no longer automatically created.
In GitLab 13.5 and 13.6, the first time you open an issue board, you are presented with the default lists
(**Open**, **To Do**, **Doing**, and **Closed**).
If the **To Do** and **Doing** labels don't exist in the project or group, they are created, and
their lists appear as empty. If any of them already exists, the list is filled with the issues that
have that label.
## Tips
A few things to remember:
......
......@@ -245,7 +245,7 @@ RSpec.describe 'Scoped issue boards', :js do
find('.board-card', match: :first)
expect(page).to have_selector('.board', count: 4)
expect(page).to have_selector('.board', count: 2)
expect(all('.board').first).to have_selector('.board-card', count: 2)
expect(all('.board').last).to have_selector('.board-card', count: 1)
end
......
......@@ -76,7 +76,7 @@ describe('Board List Header Component', () => {
describe('Settings Button', () => {
const hasSettings = [ListType.assignee, ListType.milestone, ListType.label];
const hasNoSettings = [ListType.backlog, ListType.blank, ListType.closed];
const hasNoSettings = [ListType.backlog, ListType.closed];
it.each(hasSettings)('does render for List Type `%s`', listType => {
createComponent({ listType });
......
......@@ -82,7 +82,7 @@ describe('Board List Header Component', () => {
describe('Settings Button', () => {
const hasSettings = [ListType.assignee, ListType.milestone, ListType.label];
const hasNoSettings = [ListType.backlog, ListType.blank, ListType.closed];
const hasNoSettings = [ListType.backlog, ListType.closed];
it.each(hasSettings)('does render for List Type `%s`', listType => {
createComponent({ listType });
......
......@@ -27,11 +27,11 @@ RSpec.describe 'Issue Boards', :js do
end
it 'creates default lists' do
lists = ['Open', 'To Do', 'Doing', 'Closed']
lists = %w[Open Closed]
wait_for_requests
expect(page).to have_selector('.board', count: 4)
expect(page).to have_selector('.board', count: 2)
page.all('.board').each_with_index do |list, i|
expect(list.find('.board-title')).to have_content(lists[i])
......
......@@ -66,23 +66,6 @@ describe('boardsStore', () => {
});
});
describe('generateDefaultLists', () => {
const listsEndpointGenerate = `${endpoints.listsEndpoint}/generate.json`;
it('makes a request to generate default lists', () => {
axiosMock.onPost(listsEndpointGenerate).replyOnce(200, dummyResponse);
const expectedResponse = expect.objectContaining({ data: dummyResponse });
return expect(boardsStore.generateDefaultLists()).resolves.toEqual(expectedResponse);
});
it('fails for error response', () => {
axiosMock.onPost(listsEndpointGenerate).replyOnce(500);
return expect(boardsStore.generateDefaultLists()).rejects.toThrow();
});
});
describe('createList', () => {
const entityType = 'moorhen';
const entityId = 'quack';
......@@ -727,24 +710,6 @@ describe('boardsStore', () => {
});
});
it('check for blank state adding', () => {
expect(boardsStore.shouldAddBlankState()).toBe(true);
});
it('check for blank state not adding', () => {
boardsStore.addList(listObj);
expect(boardsStore.shouldAddBlankState()).toBe(false);
});
it('check for blank state adding when closed list exist', () => {
boardsStore.addList({
list_type: 'closed',
});
expect(boardsStore.shouldAddBlankState()).toBe(true);
});
it('removes list from state', () => {
boardsStore.addList(listObj);
......
......@@ -79,7 +79,7 @@ describe('Board List Header Component', () => {
const findCaret = () => wrapper.find('.board-title-caret');
describe('Add issue button', () => {
const hasNoAddButton = [ListType.blank, ListType.closed];
const hasNoAddButton = [ListType.closed];
const hasAddButton = [ListType.backlog, ListType.label, ListType.milestone, ListType.assignee];
it.each(hasNoAddButton)('does not render when List Type is `%s`', listType => {
......
......@@ -73,7 +73,7 @@ describe('Board List Header Component', () => {
const findCaret = () => wrapper.find('.board-title-caret');
describe('Add issue button', () => {
const hasNoAddButton = [ListType.blank, ListType.closed];
const hasNoAddButton = [ListType.closed];
const hasAddButton = [ListType.backlog, ListType.label, ListType.milestone, ListType.assignee];
it.each(hasNoAddButton)('does not render when List Type is `%s`', listType => {
......
......@@ -123,7 +123,7 @@ describe('fetchLists', () => {
payload: formattedLists,
},
],
[{ type: 'generateDefaultLists' }],
[],
done,
);
});
......@@ -153,37 +153,12 @@ describe('fetchLists', () => {
payload: formattedLists,
},
],
[{ type: 'createList', payload: { backlog: true } }, { type: 'generateDefaultLists' }],
[{ type: 'createList', payload: { backlog: true } }],
done,
);
});
});
describe('generateDefaultLists', () => {
let store;
beforeEach(() => {
const state = {
endpoints: { fullPath: 'gitlab-org', boardId: '1' },
boardType: 'group',
disabled: false,
boardLists: [{ type: 'backlog' }, { type: 'closed' }],
};
store = {
commit: jest.fn(),
dispatch: jest.fn(() => Promise.resolve()),
state,
};
});
it('should dispatch fetchLabels', () => {
return actions.generateDefaultLists(store).then(() => {
expect(store.dispatch.mock.calls[0]).toEqual(['fetchLabels', 'to do']);
expect(store.dispatch.mock.calls[1]).toEqual(['fetchLabels', 'doing']);
});
});
});
describe('createList', () => {
it('should dispatch addList action when creating backlog list', done => {
const backlogList = {
......
......@@ -33,19 +33,16 @@ describe('Board Store Mutations', () => {
};
const boardType = 'group';
const disabled = false;
const showPromotion = false;
mutations[types.SET_INITIAL_BOARD_DATA](state, {
...endpoints,
boardType,
disabled,
showPromotion,
});
expect(state.endpoints).toEqual(endpoints);
expect(state.boardType).toEqual(boardType);
expect(state.disabled).toEqual(disabled);
expect(state.showPromotion).toEqual(showPromotion);
});
});
......
......@@ -85,7 +85,7 @@ RSpec.shared_examples 'multiple issue boards' do
wait_for_requests
expect(page).to have_selector('.board', count: 5)
expect(page).to have_selector('.board', count: 3)
in_boards_switcher_dropdown do
click_link board.name
......@@ -93,7 +93,7 @@ RSpec.shared_examples 'multiple issue boards' do
wait_for_requests
expect(page).to have_selector('.board', count: 4)
expect(page).to have_selector('.board', count: 2)
end
it 'maintains sidebar state over board switch' do
......
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