Commit 54617af5 authored by Donald Cook's avatar Donald Cook Committed by Simon Knox

Automate todo and doing board columns

Accidentally committed site speed directory
Removed it in a future commit

Removed commented out code

Removed unneeded code and tests

Removed unused rspec tests

Did not mean to commit sitespeed-result

Removing it here

Removed unneeded lib

Moved default list creation to store

Also updated docs

Removed unneeded code

Added back accidentally deleted code

More unneeded code removal

Fixed a couple more specs
parent f4f9e919
<script>
import { GlButton } from '@gitlab/ui';
import Cookies from 'js-cookie';
import { __ } from '~/locale';
import ListLabel from '~/boards/models/label';
import boardsStore from '../stores/boards_store';
export default {
components: {
GlButton,
},
data() {
return {
predefinedLabels: [
new ListLabel({ title: __('To Do'), color: '#F0AD4E' }),
new ListLabel({ title: __('Doing'), color: '#5CB85C' }),
],
};
},
methods: {
addDefaultLists() {
this.clearBlankState();
this.predefinedLabels.forEach((label, i) => {
boardsStore.addList({
title: label.title,
position: i,
list_type: 'label',
label: {
title: label.title,
color: label.color,
},
});
});
const loadListIssues = listObj => {
const list = boardsStore.findList('title', listObj.title);
if (!list) {
return null;
}
list.id = listObj.id;
list.label.id = listObj.label.id;
return list.getIssues().catch(() => {
// TODO: handle request error
});
};
// Save the labels
boardsStore
.generateDefaultLists()
.then(res => res.data)
.then(data => Promise.all(data.map(loadListIssues)))
.catch(() => {
boardsStore.removeList(undefined, 'label');
Cookies.remove('issue_board_welcome_hidden', {
path: '',
});
boardsStore.addBlankState();
});
},
clearBlankState: boardsStore.removeBlankState.bind(boardsStore),
},
};
</script>
<template>
<div class="board-blank-state p-3">
<p>
{{
s__('BoardBlankState|Add the following default lists to your Issue Board with one click:')
}}
</p>
<ul class="list-unstyled board-blank-state-list">
<li v-for="(label, index) in predefinedLabels" :key="index">
<span
:style="{ backgroundColor: label.color }"
class="label-color position-relative d-inline-block rounded"
></span>
{{ label.title }}
</li>
</ul>
<p>
{{
s__(
'BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board.',
)
}}
</p>
<gl-button
category="secondary"
variant="success"
block="block"
class="gl-mb-0"
@click.stop="addDefaultLists"
>
{{ s__('BoardBlankState|Add default lists') }}
</gl-button>
<gl-button category="secondary" variant="default" block="block" @click.stop="clearBlankState">
{{ s__("BoardBlankState|Nevermind, I'll use my own") }}
</gl-button>
</div>
</template>
...@@ -6,7 +6,6 @@ import BoardListHeader from 'ee_else_ce/boards/components/board_list_header.vue' ...@@ -6,7 +6,6 @@ import BoardListHeader from 'ee_else_ce/boards/components/board_list_header.vue'
import Tooltip from '~/vue_shared/directives/tooltip'; import Tooltip from '~/vue_shared/directives/tooltip';
import EmptyComponent from '~/vue_shared/components/empty_component'; import EmptyComponent from '~/vue_shared/components/empty_component';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import BoardBlankState from './board_blank_state.vue';
import BoardList from './board_list.vue'; import BoardList from './board_list.vue';
import boardsStore from '../stores/boards_store'; import boardsStore from '../stores/boards_store';
import eventHub from '../eventhub'; import eventHub from '../eventhub';
...@@ -16,7 +15,6 @@ import { ListType } from '../constants'; ...@@ -16,7 +15,6 @@ import { ListType } from '../constants';
export default { export default {
components: { components: {
BoardPromotionState: EmptyComponent, BoardPromotionState: EmptyComponent,
BoardBlankState,
BoardListHeader, BoardListHeader,
BoardList, BoardList,
}, },
...@@ -54,7 +52,7 @@ export default { ...@@ -54,7 +52,7 @@ export default {
computed: { computed: {
...mapGetters(['getIssues']), ...mapGetters(['getIssues']),
showBoardListAndBoardInfo() { showBoardListAndBoardInfo() {
return this.list.type !== ListType.blank && this.list.type !== ListType.promotion; return this.list.type !== ListType.promotion;
}, },
uniqueKey() { uniqueKey() {
// eslint-disable-next-line @gitlab/require-i18n-strings // eslint-disable-next-line @gitlab/require-i18n-strings
...@@ -148,7 +146,6 @@ export default { ...@@ -148,7 +146,6 @@ export default {
:list="list" :list="list"
:loading="list.loading" :loading="list.loading"
/> />
<board-blank-state v-if="canAdminList && list.id === 'blank'" />
<!-- Will be only available in EE --> <!-- Will be only available in EE -->
<board-promotion-state v-if="list.id === 'promotion'" /> <board-promotion-state v-if="list.id === 'promotion'" />
......
...@@ -13,7 +13,6 @@ import { ...@@ -13,7 +13,6 @@ import {
convertObjectPropsToCamelCase, convertObjectPropsToCamelCase,
} from '~/lib/utils/common_utils'; } from '~/lib/utils/common_utils';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
import { __ } from '~/locale';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { mergeUrlParams } from '~/lib/utils/url_utility'; import { mergeUrlParams } from '~/lib/utils/url_utility';
import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { getIdFromGraphQLId } from '~/graphql_shared/utils';
...@@ -119,7 +118,6 @@ const boardsStore = { ...@@ -119,7 +118,6 @@ const boardsStore = {
.catch(() => { .catch(() => {
// https://gitlab.com/gitlab-org/gitlab-foss/issues/30821 // https://gitlab.com/gitlab-org/gitlab-foss/issues/30821
}); });
this.removeBlankState();
}, },
updateNewListDropdown(listId) { updateNewListDropdown(listId) {
$(`.js-board-list-${listId}`).removeClass('is-active'); $(`.js-board-list-${listId}`).removeClass('is-active');
...@@ -129,21 +127,13 @@ const boardsStore = { ...@@ -129,21 +127,13 @@ const boardsStore = {
return !this.state.lists.filter(list => list.type !== 'backlog' && list.type !== 'closed')[0]; return !this.state.lists.filter(list => list.type !== 'backlog' && list.type !== 'closed')[0];
}, },
addBlankState() { addBlankState() {
if (!this.shouldAddBlankState() || this.welcomeIsHidden() || this.disabled) return; if (!this.shouldAddBlankState() || this.welcomeIsHidden()) return;
this.addList({ this.generateDefaultLists()
id: 'blank', .then(res => res.data)
list_type: 'blank', .then(data => Promise.all(data.map(list => this.addList(list))))
title: __('Welcome to your Issue Board!'), .catch(() => {
position: 0, this.removeList(undefined, 'label');
});
},
removeBlankState() {
this.removeList('blank');
Cookies.set('issue_board_welcome_hidden', 'true', {
expires: 365 * 10,
path: '',
}); });
}, },
......
...@@ -374,27 +374,22 @@ If you're not able to do some of the things above, make sure you have the right ...@@ -374,27 +374,22 @@ If you're not able to do some of the things above, make sure you have the right
### First time using an issue board ### First time using an issue board
The first time you open an issue board, you are presented with > The automatic creation of the **To Do** and **Doing** lists was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/202144) in GitLab 13.4.
the default lists (**Open** and **Closed**) and a welcome message that gives
you two options. You can either:
- Create a predefined set of labels (by default: **To Do** and **Doing**) and create their The first time you open an issue board, you are presented with the default lists
corresponding lists to the issue board. (**Open**, **To Do**, **Doing**, and **Closed**).
- Opt-out and use your own lists.
![issue board welcome message](img/issue_board_welcome_message.png) 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.
If you choose to use and create the predefined lists, they will appear as empty ![issue board default lists](img/issue_board_default_lists_v13_4.png)
because the labels associated to them will not exist up until that moment,
which means the system has no way of populating them automatically. That's of
course if the predefined labels don't already exist. If any of them does exist,
the list will be created and filled with the issues that have that label.
### Create a new list ### Create a new list
Create a new list by clicking the **Add list** button in the upper right corner of the issue board. Create a new list by clicking the **Add list** button in the upper right corner of the issue board.
![issue board welcome message](img/issue_board_add_list.png) ![creating a new list in an issue board](img/issue_board_add_list.png)
Then, choose the label or user to create the list from. The new list will be inserted Then, choose the label or user to create the list from. The new list will be inserted
at the end of the lists, before **Done**. Moving and reordering lists is as at the end of the lists, before **Done**. Moving and reordering lists is as
......
...@@ -245,7 +245,7 @@ RSpec.describe 'Scoped issue boards', :js do ...@@ -245,7 +245,7 @@ RSpec.describe 'Scoped issue boards', :js do
find('.board-card', match: :first) find('.board-card', match: :first)
expect(page).to have_selector('.board', count: 3) expect(page).to have_selector('.board', count: 4)
expect(all('.board').first).to have_selector('.board-card', count: 2) expect(all('.board').first).to have_selector('.board-card', count: 2)
expect(all('.board').last).to have_selector('.board-card', count: 1) expect(all('.board').last).to have_selector('.board-card', count: 1)
end end
......
...@@ -4087,18 +4087,6 @@ msgstr "" ...@@ -4087,18 +4087,6 @@ msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board" msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr "" msgstr ""
msgid "BoardBlankState|Add default lists"
msgstr ""
msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
msgstr ""
msgid "BoardBlankState|Nevermind, I'll use my own"
msgstr ""
msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
msgstr ""
msgid "Boards" msgid "Boards"
msgstr "" msgstr ""
...@@ -9135,9 +9123,6 @@ msgstr "" ...@@ -9135,9 +9123,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)" msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr "" msgstr ""
msgid "Doing"
msgstr ""
msgid "Domain" msgid "Domain"
msgstr "" msgstr ""
...@@ -28782,9 +28767,6 @@ msgstr "" ...@@ -28782,9 +28767,6 @@ msgstr ""
msgid "Welcome to the guided GitLab tour" msgid "Welcome to the guided GitLab tour"
msgstr "" msgstr ""
msgid "Welcome to your Issue Board!"
msgstr ""
msgid "Welcome to your issue board!" msgid "Welcome to your issue board!"
msgstr "" msgstr ""
......
...@@ -24,33 +24,11 @@ RSpec.describe 'Issue Boards', :js do ...@@ -24,33 +24,11 @@ RSpec.describe 'Issue Boards', :js do
context 'no lists' do context 'no lists' do
before do before do
visit project_board_path(project, board) visit project_board_path(project, board)
wait_for_requests
expect(page).to have_selector('.board', count: 3)
end
it 'shows blank state' do
expect(page).to have_content('Welcome to your Issue Board!')
end
it 'shows tooltip on add issues button' do
button = page.find('.filter-dropdown-container button', text: 'Add issues')
expect(button[:"data-original-title"]).to eq("Please add a list to your board first")
end
it 'hides the blank state when clicking nevermind button' do
page.within(find('.board-blank-state')) do
click_button("Nevermind, I'll use my own")
end
expect(page).to have_selector('.board', count: 2)
end end
it 'creates default lists' do it 'creates default lists' do
lists = ['Open', 'To Do', 'Doing', 'Closed'] lists = ['Open', 'To Do', 'Doing', 'Closed']
page.within(find('.board-blank-state')) do
click_button('Add default lists')
end
wait_for_requests wait_for_requests
expect(page).to have_selector('.board', count: 4) expect(page).to have_selector('.board', count: 4)
......
import Vue from 'vue';
import boardsStore from '~/boards/stores/boards_store';
import BoardBlankState from '~/boards/components/board_blank_state.vue';
describe('Boards blank state', () => {
let vm;
let fail = false;
beforeEach(done => {
const Comp = Vue.extend(BoardBlankState);
boardsStore.create();
jest.spyOn(boardsStore, 'addList').mockImplementation();
jest.spyOn(boardsStore, 'removeList').mockImplementation();
jest.spyOn(boardsStore, 'generateDefaultLists').mockImplementation(
() =>
new Promise((resolve, reject) => {
if (fail) {
reject();
} else {
resolve({
data: [
{
id: 1,
title: 'To Do',
label: { id: 1 },
},
{
id: 2,
title: 'Doing',
label: { id: 2 },
},
],
});
}
}),
);
vm = new Comp();
setImmediate(() => {
vm.$mount();
done();
});
});
it('renders pre-defined labels', () => {
expect(vm.$el.querySelectorAll('.board-blank-state-list li').length).toBe(2);
expect(vm.$el.querySelectorAll('.board-blank-state-list li')[0].textContent.trim()).toEqual(
'To Do',
);
expect(vm.$el.querySelectorAll('.board-blank-state-list li')[1].textContent.trim()).toEqual(
'Doing',
);
});
it('clears blank state', done => {
vm.$el.querySelector('.btn-default').click();
setImmediate(() => {
expect(boardsStore.welcomeIsHidden()).toBeTruthy();
done();
});
});
it('creates pre-defined labels', done => {
vm.$el.querySelector('.btn-success').click();
setImmediate(() => {
expect(boardsStore.addList).toHaveBeenCalledTimes(2);
expect(boardsStore.addList).toHaveBeenCalledWith(expect.objectContaining({ title: 'To Do' }));
expect(boardsStore.addList).toHaveBeenCalledWith(expect.objectContaining({ title: 'Doing' }));
done();
});
});
it('resets the store if request fails', done => {
fail = true;
vm.$el.querySelector('.btn-success').click();
setImmediate(() => {
expect(boardsStore.welcomeIsHidden()).toBeFalsy();
expect(boardsStore.removeList).toHaveBeenCalledWith(undefined, 'label');
done();
});
});
});
...@@ -745,14 +745,6 @@ describe('boardsStore', () => { ...@@ -745,14 +745,6 @@ describe('boardsStore', () => {
expect(boardsStore.shouldAddBlankState()).toBe(true); expect(boardsStore.shouldAddBlankState()).toBe(true);
}); });
it('adds the blank state', () => {
boardsStore.addBlankState();
const list = boardsStore.findList('type', 'blank', 'blank');
expect(list).toBeDefined();
});
it('removes list from state', () => { it('removes list from state', () => {
boardsStore.addList(listObj); boardsStore.addList(listObj);
......
...@@ -85,7 +85,7 @@ RSpec.shared_examples 'multiple issue boards' do ...@@ -85,7 +85,7 @@ RSpec.shared_examples 'multiple issue boards' do
wait_for_requests wait_for_requests
expect(page).to have_selector('.board', count: 3) expect(page).to have_selector('.board', count: 5)
in_boards_switcher_dropdown do in_boards_switcher_dropdown do
click_link board.name click_link board.name
...@@ -93,7 +93,7 @@ RSpec.shared_examples 'multiple issue boards' do ...@@ -93,7 +93,7 @@ RSpec.shared_examples 'multiple issue boards' do
wait_for_requests wait_for_requests
expect(page).to have_selector('.board', count: 2) expect(page).to have_selector('.board', count: 4)
end end
it 'maintains sidebar state over board switch' do 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