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 () => {
Board,
BoardSidebar,
BoardAddIssuesModal,
BoardSettingsSidebar: () =>
import('ee_component/boards/components/board_settings_sidebar.vue'),
},
store,
data: {
......
export default () => ({
isShowingLabels: true,
activeListId: 0,
});
......@@ -29,6 +29,7 @@
":board-id" => "boardId",
":key" => "list.id" }
= render "shared/boards/components/sidebar", group: group
= render_if_exists 'shared/boards/components/board_settings_sidebar'
- if @project
%board-add-issues-modal{ "new-issue-path" => new_project_issue_path(@project),
"milestone-path" => milestones_filter_dropdown_path,
......
import { mapActions } from 'vuex';
import boardPromotionState from 'ee/boards/components/board_promotion_state';
import Board from '~/boards/components/board';
import { __, n__, sprintf } from '~/locale';
......@@ -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 {
commit(types.TOGGLE_LABELS);
},
setActiveListId({ commit }, listId) {
commit(types.SET_ACTIVE_LIST_ID, listId);
},
fetchAllBoards: () => {
notImplemented();
},
......
......@@ -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 TOGGLE_PROMOTION_STATE = 'TOGGLE_PROMOTION_STATE';
export const TOGGLE_LABELS = 'TOGGLE_LABELS';
export const SET_ACTIVE_LIST_ID = 'SET_ACTIVE_LIST_ID';
......@@ -9,6 +9,9 @@ export default {
[mutationTypes.TOGGLE_LABELS]: state => {
state.isShowingLabels = !state.isShowingLabels;
},
[mutationTypes.SET_ACTIVE_LIST_ID]: (state, id) => {
state.activeListId = id;
},
[mutationTypes.REQUEST_AVAILABLE_BOARDS]: () => {
notImplemented();
......
- if current_board_parent.beta_feature_available?(:wip_limits)
%board-settings-sidebar
- if current_board_parent.beta_feature_available?(:wip_limits)
%gl-button.no-drag.rounded-right{ type: "button",
"@click" => "openSidebarSettings",
"v-if" => "isSettingsShown",
"aria-label" => _("List Settings"),
"ref" => "settingsBtn",
......
......@@ -188,7 +188,7 @@ describe 'issue boards', :js do
end
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) }
before do
......@@ -201,6 +201,20 @@ describe 'issue boards', :js do
it 'shows the list settings button' do
expect(page).to have_selector(:button, "List Settings")
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
context 'When FF is turned off' do
......@@ -208,6 +222,10 @@ describe 'issue boards', :js do
stub_licensed_features(wip_limits: false)
expect(page).to have_no_selector(:button, "List Settings")
end
it 'does not show the board list settings sidebar' do
expect(page).not_to have_selector(".js-board-settings-sidebar")
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', () => {
});
});
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', () => {
expectNotImplemented(actions.fetchAllBoards);
});
......
......@@ -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', () => {
expectNotImplemented(mutations.REQUEST_AVAILABLE_BOARDS);
});
......
......@@ -10223,6 +10223,9 @@ msgstr ""
msgid "Label"
msgstr ""
msgid "Label List"
msgstr ""
msgid "Label actions dropdown"
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