Commit f0585a23 authored by Scott Stern's avatar Scott Stern Committed by Natalia Tepluhina

Connect settings button to open board list settings sidebar

When a user clicks on the board list settings
we show them a drawer with the board list settings
info
parent 67270875
...@@ -68,6 +68,8 @@ export default () => { ...@@ -68,6 +68,8 @@ export default () => {
Board, Board,
BoardSidebar, BoardSidebar,
BoardAddIssuesModal, BoardAddIssuesModal,
BoardSettingsSidebar: () =>
import('ee_component/boards/components/board_settings_sidebar.vue'),
}, },
store, store,
data: { data: {
......
export default () => ({ export default () => ({
isShowingLabels: true, isShowingLabels: true,
activeListId: 0,
}); });
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
":board-id" => "boardId", ":board-id" => "boardId",
":key" => "list.id" } ":key" => "list.id" }
= render "shared/boards/components/sidebar", group: group = render "shared/boards/components/sidebar", group: group
= render_if_exists 'shared/boards/components/board_settings_sidebar'
- if @project - if @project
%board-add-issues-modal{ "new-issue-path" => new_project_issue_path(@project), %board-add-issues-modal{ "new-issue-path" => new_project_issue_path(@project),
"milestone-path" => milestones_filter_dropdown_path, "milestone-path" => milestones_filter_dropdown_path,
......
import { mapActions } from 'vuex';
import boardPromotionState from 'ee/boards/components/board_promotion_state'; import boardPromotionState from 'ee/boards/components/board_promotion_state';
import Board from '~/boards/components/board'; import Board from '~/boards/components/board';
import { __, n__, sprintf } from '~/locale'; import { __, n__, sprintf } from '~/locale';
...@@ -28,4 +29,10 @@ export default Board.extend({ ...@@ -28,4 +29,10 @@ export default Board.extend({
); );
}, },
}, },
methods: {
...mapActions(['setActiveListId']),
openSidebarSettings() {
this.setActiveListId(this.list.id);
},
},
}); });
<script>
import { GlDrawer, GlLabel } from '@gitlab/ui';
import { __ } from '~/locale';
import boardsStore from '~/boards/stores/boards_store';
import { mapActions, mapState } from 'vuex';
// NOTE: need to revisit how we handle headerHeight, because we have so many different header and footer options.
export default {
headerHeight: process.env.NODE_ENV === 'development' ? '75px' : '40px',
components: {
GlDrawer,
GlLabel,
},
computed: {
...mapState(['activeListId']),
isOpen() {
return this.activeListId > 0;
},
activeList() {
return boardsStore.state.lists.find(({ id }) => id === this.activeListId);
},
activeListLabel() {
if (this.activeList) {
return this.activeList.label;
}
return { color: '', title: '' };
},
listSettingsText() {
return __('List Settings');
},
labelListText() {
return __('Label List');
},
},
methods: {
...mapActions(['setActiveListId']),
closeSidebar() {
this.setActiveListId(0);
},
},
};
</script>
<template>
<gl-drawer :open="isOpen" :header-height="$options.headerHeight" @close="closeSidebar">
<template #header>{{ listSettingsText }}</template>
<template>
<div class="js-board-settings-sidebar d-flex flex-column align-items-start">
<label>{{ labelListText }}</label>
<gl-label
:title="activeListLabel.title"
:background-color="activeListLabel.color"
color="light"
/>
</div>
</template>
</gl-drawer>
</template>
...@@ -13,6 +13,10 @@ export default { ...@@ -13,6 +13,10 @@ export default {
commit(types.TOGGLE_LABELS); commit(types.TOGGLE_LABELS);
}, },
setActiveListId({ commit }, listId) {
commit(types.SET_ACTIVE_LIST_ID, listId);
},
fetchAllBoards: () => { fetchAllBoards: () => {
notImplemented(); notImplemented();
}, },
......
...@@ -12,3 +12,4 @@ export const RECEIVE_REMOVE_BOARD_SUCCESS = 'RECEIVE_REMOVE_BOARD_SUCCESS'; ...@@ -12,3 +12,4 @@ export const RECEIVE_REMOVE_BOARD_SUCCESS = 'RECEIVE_REMOVE_BOARD_SUCCESS';
export const RECEIVE_REMOVE_BOARD_ERROR = 'RECEIVE_REMOVE_BOARD_ERROR'; export const RECEIVE_REMOVE_BOARD_ERROR = 'RECEIVE_REMOVE_BOARD_ERROR';
export const TOGGLE_PROMOTION_STATE = 'TOGGLE_PROMOTION_STATE'; export const TOGGLE_PROMOTION_STATE = 'TOGGLE_PROMOTION_STATE';
export const TOGGLE_LABELS = 'TOGGLE_LABELS'; export const TOGGLE_LABELS = 'TOGGLE_LABELS';
export const SET_ACTIVE_LIST_ID = 'SET_ACTIVE_LIST_ID';
...@@ -9,6 +9,9 @@ export default { ...@@ -9,6 +9,9 @@ export default {
[mutationTypes.TOGGLE_LABELS]: state => { [mutationTypes.TOGGLE_LABELS]: state => {
state.isShowingLabels = !state.isShowingLabels; state.isShowingLabels = !state.isShowingLabels;
}, },
[mutationTypes.SET_ACTIVE_LIST_ID]: (state, id) => {
state.activeListId = id;
},
[mutationTypes.REQUEST_AVAILABLE_BOARDS]: () => { [mutationTypes.REQUEST_AVAILABLE_BOARDS]: () => {
notImplemented(); notImplemented();
......
- if current_board_parent.beta_feature_available?(:wip_limits)
%board-settings-sidebar
- if current_board_parent.beta_feature_available?(:wip_limits) - if current_board_parent.beta_feature_available?(:wip_limits)
%gl-button.no-drag.rounded-right{ type: "button", %gl-button.no-drag.rounded-right{ type: "button",
"@click" => "openSidebarSettings",
"v-if" => "isSettingsShown", "v-if" => "isSettingsShown",
"aria-label" => _("List Settings"), "aria-label" => _("List Settings"),
"ref" => "settingsBtn", "ref" => "settingsBtn",
......
...@@ -188,7 +188,7 @@ describe 'issue boards', :js do ...@@ -188,7 +188,7 @@ describe 'issue boards', :js do
end end
context 'list settings' do context 'list settings' do
let!(:label) { create(:label, project: project, name: 'Label') } let!(:label) { create(:label, project: project, name: 'Brount') }
let!(:list) { create(:list, board: board, label: label, position: 1) } let!(:list) { create(:list, board: board, label: label, position: 1) }
before do before do
...@@ -201,6 +201,20 @@ describe 'issue boards', :js do ...@@ -201,6 +201,20 @@ describe 'issue boards', :js do
it 'shows the list settings button' do it 'shows the list settings button' do
expect(page).to have_selector(:button, "List Settings") expect(page).to have_selector(:button, "List Settings")
end end
it 'does not show the board list settings sidebar as default state' do
expect(page).not_to have_selector(".js-board-settings-sidebar")
end
context 'when settings button is clicked' do
it 'shows the board list settings sidebar' do
page.within(find(".board:nth-child(2)")) do
click_button('List Settings')
end
expect(page.find('.js-board-settings-sidebar').find('.gl-label-text')).to have_text("Brount")
end
end
end end
context 'When FF is turned off' do context 'When FF is turned off' do
...@@ -208,6 +222,10 @@ describe 'issue boards', :js do ...@@ -208,6 +222,10 @@ describe 'issue boards', :js do
stub_licensed_features(wip_limits: false) stub_licensed_features(wip_limits: false)
expect(page).to have_no_selector(:button, "List Settings") expect(page).to have_no_selector(:button, "List Settings")
end end
it 'does not show the board list settings sidebar' do
expect(page).not_to have_selector(".js-board-settings-sidebar")
end
end end
end end
......
import MockAdapter from 'axios-mock-adapter';
import axios from 'axios';
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import { GlDrawer, GlLabel } from '@gitlab/ui';
import BoardSettingsSidebar from 'ee/boards/components/board_settings_sidebar.vue';
import boardsStore from '~/boards/stores/boards_store';
// NOTE: needed for calling boardsStore.addList
import '~/boards/models/list';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('BoardSettingsSideBar', () => {
let wrapper;
let mock;
let storeActions;
const labelTitle = 'test';
const labelColor = '#FFFF';
const listId = 1;
const createComponent = (state = {}, actions = {}) => {
storeActions = actions;
const store = new Vuex.Store({
state,
actions: storeActions,
});
wrapper = shallowMount(BoardSettingsSidebar, {
store,
localVue,
});
};
beforeEach(() => {
boardsStore.create();
});
afterEach(() => {
wrapper.destroy();
});
describe('GlDrawer', () => {
it('finds a GlDrawer component', () => {
createComponent();
expect(wrapper.find(GlDrawer).exists()).toBe(true);
});
describe('on close', () => {
it('calls closeSidebar', done => {
const spy = jest.fn();
createComponent({}, { setActiveListId: spy });
wrapper.find(GlDrawer).vm.$emit('close');
return wrapper.vm
.$nextTick()
.then(() => {
expect(storeActions.setActiveListId).toHaveBeenCalledWith(
expect.anything(),
0,
undefined,
);
})
.then(done)
.catch(done.fail);
});
});
describe('when activeListId is zero', () => {
it('renders GlDrawer with open false', () => {
createComponent();
expect(wrapper.find(GlDrawer).props('open')).toBe(false);
});
});
describe('when activeListId is greater than zero', () => {
it('renders GlDrawer with open false', () => {
createComponent({ activeListId: 1 });
expect(wrapper.find(GlDrawer).props('open')).toBe(true);
});
});
describe('when activeListId is in boardsStore', () => {
beforeEach(() => {
mock = new MockAdapter(axios);
boardsStore.addList({ id: listId, label: { title: labelTitle, color: labelColor } });
createComponent({ activeListId: listId });
});
afterEach(() => {
mock.restore();
});
it('renders label title', () => {
expect(wrapper.find(GlLabel).props('title')).toEqual(labelTitle);
});
it('renders label background color', () => {
expect(wrapper.find(GlLabel).props('backgroundColor')).toEqual(labelColor);
});
});
describe('when activeListId is not in boardsStore', () => {
beforeEach(() => {
mock = new MockAdapter(axios);
boardsStore.addList({ id: listId, label: { title: labelTitle, color: labelColor } });
createComponent({ activeListId: 0 });
});
afterEach(() => {
mock.restore();
});
it('renders label title', () => {
expect(wrapper.find(GlLabel).props('title')).toEqual('');
});
it('renders label background color', () => {
expect(wrapper.find(GlLabel).props('backgroundColor')).toEqual('');
});
});
});
});
...@@ -18,6 +18,23 @@ describe('toggleShowLabels', () => { ...@@ -18,6 +18,23 @@ describe('toggleShowLabels', () => {
}); });
}); });
describe('setActiveListId', () => {
it('should commit mutation SET_ACTIVE_LIST_ID', done => {
const state = {
activeListId: 0,
};
testAction(
actions.setActiveListId,
1,
state,
[{ type: types.SET_ACTIVE_LIST_ID, payload: 1 }],
[],
done,
);
});
});
describe('fetchAllBoards', () => { describe('fetchAllBoards', () => {
expectNotImplemented(actions.fetchAllBoards); expectNotImplemented(actions.fetchAllBoards);
}); });
......
...@@ -28,6 +28,19 @@ describe('TOGGLE_LABELS', () => { ...@@ -28,6 +28,19 @@ describe('TOGGLE_LABELS', () => {
}); });
}); });
describe('SET_ACTIVE_LIST_ID', () => {
it('updates aciveListId to be the value that is passed', () => {
const expectedId = 1;
const state = {
activeListId: 0,
};
mutations.SET_ACTIVE_LIST_ID(state, expectedId);
expect(state.activeListId).toBe(expectedId);
});
});
describe('REQUEST_AVAILABLE_BOARDS', () => { describe('REQUEST_AVAILABLE_BOARDS', () => {
expectNotImplemented(mutations.REQUEST_AVAILABLE_BOARDS); expectNotImplemented(mutations.REQUEST_AVAILABLE_BOARDS);
}); });
......
...@@ -10223,6 +10223,9 @@ msgstr "" ...@@ -10223,6 +10223,9 @@ msgstr ""
msgid "Label" msgid "Label"
msgstr "" msgstr ""
msgid "Label List"
msgstr ""
msgid "Label actions dropdown" msgid "Label actions dropdown"
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