Commit 0791f443 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Merge branch '235922-boards-use-provide-inject-for-static-props' into 'master'

Boards - Use provide/inject for static props

See merge request gitlab-org/gitlab!42186
parents 47c0f61b 228dceec
<script>
/* eslint-disable vue/require-default-prop */
import IssueCardInner from './issue_card_inner.vue';
import boardsStore from '../stores/boards_store';
......@@ -19,11 +18,6 @@ export default {
default: () => ({}),
required: false,
},
issueLinkBase: {
type: String,
default: '',
required: false,
},
disabled: {
type: Boolean,
default: false,
......@@ -34,15 +28,6 @@ export default {
default: 0,
required: false,
},
rootPath: {
type: String,
default: '',
required: false,
},
groupId: {
type: Number,
required: false,
},
isActive: {
type: Boolean,
required: false,
......@@ -103,13 +88,6 @@ export default {
@mousemove="mouseMove"
@mouseup="showIssue($event)"
>
<issue-card-inner
:list="list"
:issue="issue"
:issue-link-base="issueLinkBase"
:group-id="groupId"
:root-path="rootPath"
:update-filters="true"
/>
<issue-card-inner :list="list" :issue="issue" :update-filters="true" />
</li>
</template>
......@@ -34,27 +34,15 @@ export default {
type: Boolean,
required: true,
},
issueLinkBase: {
type: String,
required: true,
},
rootPath: {
type: String,
required: true,
},
boardId: {
type: String,
required: true,
},
canAdminList: {
type: Boolean,
required: false,
default: false,
},
groupId: {
type: Number,
required: false,
default: null,
},
inject: {
boardId: {
type: String,
},
},
data() {
......@@ -151,22 +139,14 @@ export default {
<div
class="board-inner gl-display-flex gl-flex-direction-column gl-relative gl-h-full gl-rounded-base"
>
<board-list-header
:can-admin-list="canAdminList"
:list="list"
:disabled="disabled"
:board-id="boardId"
/>
<board-list-header :can-admin-list="canAdminList" :list="list" :disabled="disabled" />
<board-list
v-if="showBoardListAndBoardInfo"
ref="board-list"
:disabled="disabled"
:group-id="groupId || null"
:issue-link-base="issueLinkBase"
:issues="listIssues"
:list="list"
:loading="list.loading"
:root-path="rootPath"
/>
<board-blank-state v-if="canAdminList && list.id === 'blank'" />
......
......@@ -21,27 +21,10 @@ export default {
type: Boolean,
required: true,
},
groupId: {
type: Number,
required: false,
default: null,
},
disabled: {
type: Boolean,
required: true,
},
issueLinkBase: {
type: String,
required: true,
},
rootPath: {
type: String,
required: true,
},
boardId: {
type: String,
required: true,
},
},
computed: {
...mapState(['boardLists', 'error']),
......@@ -77,12 +60,8 @@ export default {
:key="list.id"
ref="board"
:can-admin-list="canAdminList"
:group-id="groupId"
:list="list"
:disabled="disabled"
:issue-link-base="issueLinkBase"
:root-path="rootPath"
:board-id="boardId"
/>
</div>
......@@ -92,9 +71,6 @@ export default {
:lists="boardLists"
:can-admin-list="canAdminList"
:disabled="disabled"
:board-id="boardId"
:group-id="groupId"
:root-path="rootPath"
/>
<board-content-sidebar />
</template>
......
......@@ -27,11 +27,6 @@ export default {
},
mixins: [glFeatureFlagMixin()],
props: {
groupId: {
type: Number,
required: false,
default: 0,
},
disabled: {
type: Boolean,
required: true,
......@@ -48,14 +43,6 @@ export default {
type: Boolean,
required: true,
},
issueLinkBase: {
type: String,
required: true,
},
rootPath: {
type: String,
required: true,
},
},
data() {
return {
......@@ -435,11 +422,7 @@ export default {
<div v-if="loading" class="board-list-loading text-center" :aria-label="__('Loading issues')">
<gl-loading-icon />
</div>
<board-new-issue
v-if="list.type !== 'closed' && showIssueForm"
:group-id="groupId"
:list="list"
/>
<board-new-issue v-if="list.type !== 'closed' && showIssueForm" :list="list" />
<ul
v-show="!loading"
ref="list"
......@@ -455,9 +438,6 @@ export default {
:index="index"
:list="list"
:issue="issue"
:issue-link-base="issueLinkBase"
:group-id="groupId"
:root-path="rootPath"
:disabled="disabled"
/>
<li v-if="showCount" class="board-list-count text-center" data-issue-id="-1">
......
......@@ -45,10 +45,6 @@ export default {
type: Boolean,
required: true,
},
boardId: {
type: String,
required: true,
},
canAdminList: {
type: Boolean,
required: false,
......@@ -60,6 +56,11 @@ export default {
default: false,
},
},
inject: {
boardId: {
type: String,
},
},
data() {
return {
weightFeatureAvailable: false,
......
......@@ -17,16 +17,16 @@ export default {
},
mixins: [glFeatureFlagMixin()],
props: {
groupId: {
type: Number,
required: false,
default: 0,
},
list: {
type: Object,
required: true,
},
},
inject: {
groupId: {
type: Number,
},
},
data() {
return {
title: '',
......@@ -139,7 +139,7 @@ export default {
<project-select v-if="groupId" :group-id="groupId" :list="list" />
<div class="clearfix gl-mt-3">
<gl-button
ref="submit-button"
ref="submitButton"
:disabled="disabled"
class="float-left"
variant="success"
......@@ -147,9 +147,14 @@ export default {
type="submit"
>{{ __('Submit issue') }}</gl-button
>
<gl-button class="float-right" type="button" variant="default" @click="cancel">{{
__('Cancel')
}}</gl-button>
<gl-button
ref="cancelButton"
class="float-right"
type="button"
variant="default"
@click="cancel"
>{{ __('Cancel') }}</gl-button
>
</div>
</form>
</div>
......
......@@ -30,28 +30,23 @@ export default {
type: Object,
required: true,
},
issueLinkBase: {
type: String,
required: true,
},
list: {
type: Object,
required: false,
default: () => ({}),
},
rootPath: {
type: String,
required: true,
},
updateFilters: {
type: Boolean,
required: false,
default: false,
},
},
inject: {
groupId: {
type: Number,
required: false,
default: null,
},
rootPath: {
type: String,
},
},
data() {
......
......@@ -26,14 +26,6 @@ export default {
type: String,
required: true,
},
issueLinkBase: {
type: String,
required: true,
},
rootPath: {
type: String,
required: true,
},
projectId: {
type: Number,
required: true,
......@@ -146,12 +138,7 @@ export default {
>
<div class="add-issues-container d-flex flex-column m-auto rounded">
<modal-header :project-id="projectId" :label-path="labelPath" />
<modal-list
v-if="!loading && showList && !filterLoading"
:issue-link-base="issueLinkBase"
:root-path="rootPath"
:empty-state-svg="emptyStateSvg"
/>
<modal-list v-if="!loading && showList && !filterLoading" :empty-state-svg="emptyStateSvg" />
<empty-state
v-if="showEmptyState"
:new-issue-path="newIssuePath"
......
......@@ -10,14 +10,6 @@ export default {
GlIcon,
},
props: {
issueLinkBase: {
type: String,
required: true,
},
rootPath: {
type: String,
required: true,
},
emptyStateSvg: {
type: String,
required: true,
......@@ -134,7 +126,7 @@ export default {
class="board-card position-relative p-3 rounded"
@click="toggleIssue($event, issue)"
>
<issue-card-inner :issue="issue" :issue-link-base="issueLinkBase" :root-path="rootPath" />
<issue-card-inner :issue="issue" />
<gl-icon
v-if="issue.selected"
:aria-label="'Issue #' + issue.id + ' selected'"
......
......@@ -15,16 +15,16 @@ export default {
GlLoadingIcon,
},
props: {
groupId: {
type: Number,
required: true,
default: 0,
},
list: {
type: Object,
required: true,
},
},
inject: {
groupId: {
type: Number,
},
},
data() {
return {
loading: true,
......
......@@ -82,12 +82,13 @@ export default () => {
BoardAddIssuesModal,
BoardSettingsSidebar: () => import('~/boards/components/board_settings_sidebar.vue'),
},
store,
apolloProvider,
provide: {
// TODO: Mv all non-reactive props from data/props to here.
boardId: $boardApp.dataset.boardId,
groupId: Number($boardApp.dataset.groupId) || null,
rootPath: $boardApp.dataset.rootPath,
},
store,
apolloProvider,
data() {
return {
state: boardsStore.state,
......@@ -95,10 +96,7 @@ export default () => {
boardsEndpoint: $boardApp.dataset.boardsEndpoint,
recentBoardsEndpoint: $boardApp.dataset.recentBoardsEndpoint,
listsEndpoint: $boardApp.dataset.listsEndpoint,
boardId: $boardApp.dataset.boardId,
disabled: parseBoolean($boardApp.dataset.disabled),
issueLinkBase: $boardApp.dataset.issueLinkBase,
rootPath: $boardApp.dataset.rootPath,
bulkUpdatePath: $boardApp.dataset.bulkUpdatePath,
detailIssue: boardsStore.detail,
parent: $boardApp.dataset.parent,
......@@ -116,7 +114,7 @@ export default () => {
recentBoardsEndpoint: this.recentBoardsEndpoint,
listsEndpoint: this.listsEndpoint,
bulkUpdatePath: this.bulkUpdatePath,
boardId: this.boardId,
boardId: $boardApp.dataset.boardId,
fullPath: $boardApp.dataset.fullPath,
};
this.setInitialBoardData({
......
......@@ -11,13 +11,13 @@ module BoardsHelper
lists_endpoint: board_lists_path(board),
board_id: board.id,
disabled: (!can?(current_user, :create_non_backlog_issues, board)).to_s,
issue_link_base: build_issue_link_base,
root_path: root_path,
full_path: full_path,
bulk_update_path: @bulk_issues_path,
time_tracking_limit_to_hours: Gitlab::CurrentSettings.time_tracking_limit_to_hours.to_s,
recent_boards_endpoint: recent_boards_path,
parent: current_board_parent.model_name.param_key
parent: current_board_parent.model_name.param_key,
group_id: @group&.id
}
end
......
......@@ -2,7 +2,6 @@
- group = local_assigns.fetch(:group, false)
-# TODO: Move group_id and can_admin_list to the board store
See: https://gitlab.com/gitlab-org/gitlab/-/issues/213082
- group_id = @group&.id || "null"
- can_admin_list = can?(current_user, :admin_list, current_board_parent) == true
- @no_breadcrumb_container = true
- @no_container = true
......@@ -24,11 +23,7 @@
"ref" => "board_content",
":lists" => "state.lists",
":can-admin-list" => can_admin_list,
":group-id" => group_id,
":disabled" => "disabled",
":issue-link-base" => "issueLinkBase",
":root-path" => "rootPath",
":board-id" => "boardId" }
":disabled" => "disabled" }
- else
.boards-list.w-100.py-3.px-2.text-nowrap{ data: { qa_selector: "boards_list" } }
.boards-app-loading.w-100.text-center{ "v-if" => "loading" }
......@@ -37,12 +32,8 @@
"v-for" => "list in state.lists",
"ref" => "board",
":can-admin-list" => can_admin_list,
":group-id" => group_id,
":list" => "list",
":disabled" => "disabled",
":issue-link-base" => "issueLinkBase",
":root-path" => "rootPath",
":board-id" => "boardId",
":key" => "list.id" }
= render "shared/boards/components/sidebar", group: group
= render_if_exists 'shared/boards/components/board_settings_sidebar'
......@@ -51,6 +42,4 @@
"milestone-path" => milestones_filter_dropdown_path,
"label-path" => labels_filter_path_with_defaults,
"empty-state-svg" => image_path('illustrations/issues.svg'),
":issue-link-base" => "issueLinkBase",
":root-path" => "rootPath",
":project-id" => @project.id }
......@@ -37,10 +37,6 @@ export default {
type: Boolean,
required: true,
},
rootPath: {
type: String,
required: true,
},
canAdminList: {
type: Boolean,
required: false,
......@@ -157,7 +153,6 @@ export default {
:issues="getIssuesByEpic(list.id, epic.id)"
:is-loading="isLoadingIssues"
:disabled="disabled"
:root-path="rootPath"
:epic-id="epic.id"
:epic-is-confidential="epic.confidential"
:can-admin-list="canAdminList"
......
......@@ -28,24 +28,11 @@ export default {
type: Boolean,
required: true,
},
boardId: {
type: String,
required: true,
},
canAdminList: {
type: Boolean,
required: false,
default: false,
},
groupId: {
type: Number,
required: false,
default: 0,
},
rootPath: {
type: String,
required: true,
},
},
computed: {
...mapState(['epics', 'isLoadingIssues']),
......@@ -125,7 +112,6 @@ export default {
:can-admin-list="canAdminList"
:list="list"
:disabled="disabled"
:board-id="boardId"
:is-swimlanes-header="true"
/>
</div>
......@@ -138,7 +124,6 @@ export default {
:lists="lists"
:is-loading-issues="isLoadingIssues"
:disabled="disabled"
:root-path="rootPath"
:can-admin-list="canAdminList"
/>
<div class="board-lane-unassigned-issues-title gl-sticky gl-display-inline-block gl-left-0">
......@@ -167,11 +152,9 @@ export default {
:key="`${list.id}-issues`"
:list="list"
:issues="unassignedIssues(list.id)"
:group-id="groupId"
:is-unassigned-issues-lane="true"
:is-loading="isLoadingIssues"
:disabled="disabled"
:root-path="rootPath"
:can-admin-list="canAdminList"
/>
</div>
......
......@@ -28,11 +28,6 @@ export default {
required: true,
default: () => [],
},
groupId: {
type: Number,
required: false,
default: 0,
},
isUnassignedIssuesLane: {
type: Boolean,
required: false,
......@@ -43,10 +38,6 @@ export default {
required: false,
default: false,
},
rootPath: {
type: String,
required: true,
},
canAdminList: {
type: Boolean,
required: false,
......@@ -150,7 +141,6 @@ export default {
<gl-loading-icon v-if="isLoading" class="gl-p-2" />
<board-new-issue
v-if="list.type !== 'closed' && showIssueForm && isUnassignedIssuesLane"
:group-id="groupId"
:list="list"
/>
<component
......@@ -167,7 +157,6 @@ export default {
:index="index"
:list="list"
:issue="issue"
:root-path="rootPath"
:is-active="isActiveIssue(issue)"
@show="showIssue(issue)"
/>
......
......@@ -15,9 +15,6 @@ describe('ee/BoardContent', () => {
lists: [],
canAdminList: false,
disabled: false,
issueLinkBase: '',
rootPath: '',
boardId: '',
},
stubs: {
'board-content-sidebar': BoardContentSidebar,
......
......@@ -74,13 +74,13 @@ describe('Board List Header Component', () => {
store,
localVue,
propsData: {
boardId,
disabled: false,
issueLinkBase: '/',
rootPath: '/',
list,
isSwimlanesHeader,
},
provide: {
boardId,
},
});
};
......
......@@ -15,7 +15,6 @@ describe('BoardList Component', () => {
const componentProps = {
groupId: undefined,
issueLinkBase: '/test/:project_path/issues',
};
({ mock, component } = createComponent({
......
......@@ -29,7 +29,6 @@ describe('EpicLane', () => {
epic: mockEpic,
lists: mockListsWithModel,
disabled: false,
rootPath: '/',
};
wrapper = shallowMount(EpicLane, {
......
......@@ -34,9 +34,7 @@ describe('EpicsSwimlanes', () => {
const store = createStore();
const defaultProps = {
lists: mockListsWithModel,
boardId: '1',
disabled: false,
rootPath: '/',
};
wrapper = shallowMount(EpicsSwimlanes, {
......
......@@ -55,7 +55,6 @@ describe('IssuesLaneList', () => {
list,
issues: mockIssues,
disabled: false,
rootPath: '/',
},
});
};
......
......@@ -17,10 +17,11 @@ describe('Issue card component', () => {
propsData: {
list,
issue,
...props,
},
provide: {
groupId: null,
rootPath: '/',
issueLinkBase: '/test',
...props,
},
});
};
......
......@@ -52,10 +52,12 @@ export default function createComponent({
list,
issues: list.issues,
loading: false,
issueLinkBase: '/issues',
rootPath: '/',
...componentProps,
},
provide: {
groupId: null,
rootPath: '/',
},
}).$mount();
Vue.nextTick(() => {
......
......@@ -45,10 +45,12 @@ const createComponent = ({ done, listIssueProps = {}, componentProps = {}, listP
list,
issues: list.issues,
loading: false,
issueLinkBase: '/issues',
rootPath: '/',
...componentProps,
},
provide: {
groupId: null,
rootPath: '/',
},
}).$mount();
Vue.nextTick(() => {
......
/* global List */
import Vue from 'vue';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import boardNewIssue from '~/boards/components/board_new_issue.vue';
......@@ -10,6 +11,7 @@ import '~/boards/models/list';
import { listObj, boardsMockInterceptor } from './mock_data';
describe('Issue boards new issue form', () => {
let wrapper;
let vm;
let list;
let mock;
......@@ -24,13 +26,11 @@ describe('Issue boards new issue form', () => {
const dummySubmitEvent = {
preventDefault() {},
};
vm.$refs.submitButton = vm.$el.querySelector('.btn-success');
return vm.submit(dummySubmitEvent);
wrapper.vm.$refs.submitButton = wrapper.find({ ref: 'submitButton' });
return wrapper.vm.submit(dummySubmitEvent);
};
beforeEach(() => {
setFixtures('<div class="test-container"></div>');
const BoardNewIssueComp = Vue.extend(boardNewIssue);
mock = new MockAdapter(axios);
......@@ -43,46 +43,52 @@ describe('Issue boards new issue form', () => {
newIssueMock = Promise.resolve(promiseReturn);
jest.spyOn(list, 'newIssue').mockImplementation(() => newIssueMock);
vm = new BoardNewIssueComp({
wrapper = mount(BoardNewIssueComp, {
propsData: {
disabled: false,
list,
},
}).$mount(document.querySelector('.test-container'));
provide: {
groupId: null,
},
});
vm = wrapper.vm;
return Vue.nextTick();
});
afterEach(() => {
vm.$destroy();
wrapper.destroy();
mock.restore();
});
it('calls submit if submit button is clicked', () => {
jest.spyOn(vm, 'submit').mockImplementation(e => e.preventDefault());
jest.spyOn(wrapper.vm, 'submit').mockImplementation();
vm.title = 'Testing Title';
return Vue.nextTick().then(() => {
vm.$el.querySelector('.btn-success').click();
expect(vm.submit.mock.calls.length).toBe(1);
return Vue.nextTick()
.then(submitIssue)
.then(() => {
expect(wrapper.vm.submit).toHaveBeenCalled();
});
});
it('disables submit button if title is empty', () => {
expect(vm.$el.querySelector('.btn-success').disabled).toBe(true);
expect(wrapper.find({ ref: 'submitButton' }).props().disabled).toBe(true);
});
it('enables submit button if title is not empty', () => {
vm.title = 'Testing Title';
wrapper.setData({ title: 'Testing Title' });
return Vue.nextTick().then(() => {
expect(vm.$el.querySelector('.form-control').value).toBe('Testing Title');
expect(vm.$el.querySelector('.btn-success').disabled).not.toBe(true);
expect(wrapper.find({ ref: 'input' }).element.value).toBe('Testing Title');
expect(wrapper.find({ ref: 'submitButton' }).props().disabled).toBe(false);
});
});
it('clears title after clicking cancel', () => {
vm.$el.querySelector('.btn-default').click();
wrapper.find({ ref: 'cancelButton' }).trigger('click');
return Vue.nextTick().then(() => {
expect(vm.title).toBe('');
......@@ -97,7 +103,7 @@ describe('Issue boards new issue form', () => {
describe('submit success', () => {
it('creates new issue', () => {
vm.title = 'submit title';
wrapper.setData({ title: 'submit issue' });
return Vue.nextTick()
.then(submitIssue)
......@@ -107,17 +113,18 @@ describe('Issue boards new issue form', () => {
});
it('enables button after submit', () => {
vm.title = 'submit issue';
jest.spyOn(wrapper.vm, 'submit').mockImplementation();
wrapper.setData({ title: 'submit issue' });
return Vue.nextTick()
.then(submitIssue)
.then(() => {
expect(vm.$el.querySelector('.btn-success').disabled).toBe(false);
expect(wrapper.vm.$refs.submitButton.props().disabled).toBe(false);
});
});
it('clears title after submit', () => {
vm.title = 'submit issue';
wrapper.setData({ title: 'submit issue' });
return Vue.nextTick()
.then(submitIssue)
......@@ -128,7 +135,7 @@ describe('Issue boards new issue form', () => {
it('sets detail issue after submit', () => {
expect(boardsStore.detail.issue.title).toBe(undefined);
vm.title = 'submit issue';
wrapper.setData({ title: 'submit issue' });
return Vue.nextTick()
.then(submitIssue)
......@@ -138,7 +145,7 @@ describe('Issue boards new issue form', () => {
});
it('sets detail list after submit', () => {
vm.title = 'submit issue';
wrapper.setData({ title: 'submit issue' });
return Vue.nextTick()
.then(submitIssue)
......@@ -149,7 +156,7 @@ describe('Issue boards new issue form', () => {
it('sets detail weight after submit', () => {
boardsStore.weightFeatureAvailable = true;
vm.title = 'submit issue';
wrapper.setData({ title: 'submit issue' });
return Vue.nextTick()
.then(submitIssue)
......@@ -160,7 +167,7 @@ describe('Issue boards new issue form', () => {
it('does not set detail weight after submit', () => {
boardsStore.weightFeatureAvailable = false;
vm.title = 'submit issue';
wrapper.setData({ title: 'submit issue' });
return Vue.nextTick()
.then(submitIssue)
......
......@@ -31,12 +31,14 @@ describe('Board card layout', () => {
propsData: {
list,
issue: list.issues[0],
issueLinkBase: '/',
disabled: false,
index: 0,
rootPath: '/',
...propsData,
},
provide: {
groupId: null,
rootPath: '/',
},
});
};
......
......@@ -38,12 +38,14 @@ describe('BoardCard', () => {
propsData: {
list,
issue: list.issues[0],
issueLinkBase: '/',
disabled: false,
index: 0,
rootPath: '/',
...propsData,
},
provide: {
groupId: null,
rootPath: '/',
},
});
};
......
......@@ -59,10 +59,11 @@ describe('Board Column Component', () => {
propsData: {
boardId,
disabled: false,
issueLinkBase: '/',
rootPath: '/',
list,
},
provide: {
boardId,
},
});
};
......
......@@ -39,11 +39,7 @@ describe('BoardContent', () => {
propsData: {
lists: mockListsWithModel,
canAdminList: true,
groupId: 1,
disabled: false,
issueLinkBase: '/',
rootPath: '/',
boardId: '1',
},
store,
});
......
......@@ -57,12 +57,12 @@ describe('Board List Header Component', () => {
wrapper = shallowMount(BoardListHeader, {
propsData: {
boardId,
disabled: false,
issueLinkBase: '/',
rootPath: '/',
list,
},
provide: {
boardId,
},
});
};
......
......@@ -47,13 +47,15 @@ describe('Issue card component', () => {
propsData: {
list,
issue,
issueLinkBase: '/test',
rootPath: '/',
},
store,
stubs: {
GlLabel: true,
},
provide: {
groupId: null,
rootPath: '/',
},
});
});
......
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