Commit d1d2eb67 authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Clean up components by using constants

This moves the board list type labels into the constants file
parent 95e6eead
......@@ -5,17 +5,13 @@ import { __ } from '~/locale';
import boardsStore from '~/boards/stores/boards_store';
import eventHub from '~/sidebar/event_hub';
import { isScopedLabel } from '~/lib/utils/common_utils';
import { LIST } from '~/boards/constants';
import { LIST, ListType, ListTypeTitles } from '~/boards/constants';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
// 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',
listSettingsText: __('List settings'),
assignee: 'assignee',
milestone: 'milestone',
label: 'label',
labelListText: __('Label'),
components: {
GlButton,
GlDrawer,
......@@ -33,6 +29,11 @@ export default {
default: false,
},
},
data() {
return {
ListType,
};
},
computed: {
...mapGetters(['isSidebarOpen', 'shouldUseGraphQL']),
...mapState(['activeId', 'sidebarType', 'boardLists']),
......@@ -56,7 +57,7 @@ export default {
return this.activeList.type || this.activeList.listType || null;
},
listTypeTitle() {
return this.$options.labelListText;
return ListTypeTitles[ListType.label];
},
showSidebar() {
return this.sidebarType === LIST;
......@@ -98,7 +99,7 @@ export default {
>
<template #header>{{ $options.listSettingsText }}</template>
<template v-if="isSidebarOpen">
<div v-if="boardListType === $options.label">
<div v-if="boardListType === ListType.label">
<label class="js-list-label gl-display-block">{{ listTypeTitle }}</label>
<gl-label
:title="activeListLabel.title"
......
import { __ } from '~/locale';
export const BoardType = {
project: 'project',
group: 'group',
......@@ -12,6 +14,13 @@ export const ListType = {
label: 'label',
};
export const ListTypeTitles = {
assignee: __('Assignee'),
milestone: __('Milestone'),
iteration: __('Iteration'),
label: __('Label'),
};
export const inactiveId = 0;
export const ISSUABLE = 'issuable';
......
......@@ -2,13 +2,8 @@ export default class ListIteration {
constructor(obj) {
this.id = obj.id;
this.title = obj.title;
if (IS_EE) {
this.state = obj.state;
this.webUrl = obj.web_url || obj.webUrl;
this.description = obj.description;
}
this.state = obj.state;
this.webUrl = obj.web_url || obj.webUrl;
this.description = obj.description;
}
}
window.ListIteration = ListIteration;
<script>
import { GlAvatarLink, GlAvatarLabeled, GlLink } from '@gitlab/ui';
import { __ } from '~/locale';
import { ListType, ListTypeTitles } from '~/boards/constants';
export default {
milestone: 'milestone',
iteration: 'iteration',
assignee: 'assignee',
labelMilestoneText: __('Milestone'),
labelIterationText: __('Iteration'),
labelAssigneeText: __('Assignee'),
components: {
GlLink,
GlAvatarLink,
......@@ -24,31 +18,17 @@ export default {
required: true,
},
},
data() {
return {
ListType,
};
},
computed: {
activeListAssignee() {
return this.activeList.assignee;
},
activeListMilestone() {
return this.activeList.milestone;
activeListObject() {
return this.activeList[this.boardListType];
},
activeListIteration() {
return this.activeList.iteration;
},
listTypeTitle() {
switch (this.boardListType) {
case this.$options.milestone: {
return this.$options.labelMilestoneText;
}
case this.$options.assignee: {
return this.$options.labelAssigneeText;
}
case this.$options.iteration: {
return this.$options.labelIterationText;
}
default: {
return '';
}
}
listTypeHeader() {
return ListTypeTitles[this.boardListType] || '';
},
},
};
......@@ -56,27 +36,21 @@ export default {
<template>
<div>
<label class="js-list-label gl-display-block">{{ listTypeTitle }}</label>
<gl-link
v-if="boardListType === $options.milestone"
class="js-milestone"
:href="activeListMilestone.webUrl"
>{{ activeListMilestone.title }}</gl-link
>
<gl-link v-else-if="boardListType === $options.iteration" :href="activeListIteration.webUrl">{{
activeListIteration.title
}}</gl-link>
<label class="js-list-label gl-display-block">{{ listTypeHeader }}</label>
<gl-avatar-link
v-else-if="boardListType === $options.assignee"
v-if="boardListType === ListType.assignee"
class="js-assignee"
:href="activeListAssignee.webUrl"
:href="activeListObject.webUrl"
>
<gl-avatar-labeled
:size="32"
:label="activeListAssignee.name"
:sub-label="`@${activeListAssignee.username}`"
:src="activeListAssignee.avatar"
:label="activeListObject.name"
:sub-label="`@${activeListObject.username}`"
:src="activeListObject.avatar"
/>
</gl-avatar-link>
<gl-link v-else class="js-list-title" :href="activeListObject.webUrl">
{{ activeListObject.title }}
</gl-link>
</div>
</template>
......@@ -9,6 +9,10 @@ describe('BoardSettingsListType', () => {
webUrl: 'https://gitlab.com/h5bp/html5-boilerplate/-/milestones/1',
title: 'Backlog',
},
iteration: {
webUrl: 'https://gitlab.com/h5bp/-/iterations/1',
title: 'Sprint 1',
},
assignee: { webUrl: 'https://gitlab.com/root', name: 'root', username: 'root' },
};
const createComponent = (props) => {
......@@ -25,7 +29,7 @@ describe('BoardSettingsListType', () => {
it('renders the correct milestone text', () => {
createComponent({ activeId: 1, boardListType: 'milestone' });
expect(wrapper.find('.js-milestone').text()).toBe('Backlog');
expect(wrapper.find('.js-list-title').text()).toBe('Backlog');
});
it('renders the correct list type text', () => {
......@@ -35,6 +39,20 @@ describe('BoardSettingsListType', () => {
});
});
describe('when list type is "iteration"', () => {
it('renders the correct milestone text', () => {
createComponent({ activeId: 1, boardListType: 'iteration' });
expect(wrapper.find('.js-list-title').text()).toBe('Sprint 1');
});
it('renders the correct list type text', () => {
createComponent({ activeId: 1, boardListType: 'iteration' });
expect(wrapper.find('.js-list-label').text()).toBe('Iteration');
});
});
describe('when list type is "assignee"', () => {
afterEach(() => {
wrapper.destroy();
......
......@@ -4,6 +4,7 @@ import Issue from 'ee/boards/models/issue';
import List from 'ee/boards/models/list';
import { listObj } from 'jest/boards/mock_data';
import CeList from '~/boards/models/list';
import { ListType } from '~/boards/constants';
describe('List model', () => {
let list;
......@@ -15,16 +16,6 @@ describe('List model', () => {
// We need to mock axios since `new List` below makes a network request
axiosMock.onGet().replyOnce(200);
list = new List(listObj);
issue = new Issue({
title: 'Testing',
id: 2,
iid: 2,
labels: [],
assignees: [],
weight: 5,
});
});
afterEach(() => {
......@@ -33,67 +24,98 @@ describe('List model', () => {
axiosMock.restore();
});
it('inits totalWeight', () => {
expect(list.totalWeight).toBe(0);
});
describe('label lists', () => {
beforeEach(() => {
list = new List(listObj);
issue = new Issue({
title: 'Testing',
id: 2,
iid: 2,
labels: [],
assignees: [],
weight: 5,
});
});
it('inits totalWeight', () => {
expect(list.totalWeight).toBe(0);
});
describe('getIssues', () => {
it('calls CE getIssues', () => {
const ceGetIssues = jest
.spyOn(CeList.prototype, 'getIssues')
.mockReturnValue(Promise.resolve({}));
describe('getIssues', () => {
it('calls CE getIssues', () => {
const ceGetIssues = jest
.spyOn(CeList.prototype, 'getIssues')
.mockReturnValue(Promise.resolve({}));
return list.getIssues().then(() => {
expect(ceGetIssues).toHaveBeenCalled();
return list.getIssues().then(() => {
expect(ceGetIssues).toHaveBeenCalled();
});
});
});
it('sets total weight', () => {
jest.spyOn(CeList.prototype, 'getIssues').mockReturnValue(
Promise.resolve({
total_weight: 11,
}),
);
it('sets total weight', () => {
jest.spyOn(CeList.prototype, 'getIssues').mockReturnValue(
Promise.resolve({
total_weight: 11,
}),
);
return list.getIssues().then(() => {
expect(list.totalWeight).toBe(11);
return list.getIssues().then(() => {
expect(list.totalWeight).toBe(11);
});
});
});
});
describe('addIssue', () => {
it('updates totalWeight', () => {
list.addIssue(issue);
describe('addIssue', () => {
it('updates totalWeight', () => {
list.addIssue(issue);
expect(list.totalWeight).toBe(5);
});
expect(list.totalWeight).toBe(5);
});
it('calls CE addIssue with all args', () => {
const ceAddIssue = jest.spyOn(CeList.prototype, 'addIssue');
it('calls CE addIssue with all args', () => {
const ceAddIssue = jest.spyOn(CeList.prototype, 'addIssue');
list.addIssue(issue, list, 2);
list.addIssue(issue, list, 2);
expect(ceAddIssue).toHaveBeenCalledWith(issue, list, 2);
expect(ceAddIssue).toHaveBeenCalledWith(issue, list, 2);
});
});
});
describe('removeIssue', () => {
beforeEach(() => {
list.addIssue(issue);
});
describe('removeIssue', () => {
beforeEach(() => {
list.addIssue(issue);
});
it('updates totalWeight', () => {
list.removeIssue(issue);
it('updates totalWeight', () => {
list.removeIssue(issue);
expect(list.totalWeight).toBe(0);
expect(list.totalWeight).toBe(0);
});
it('calls CE removeIssue', () => {
const ceRemoveIssue = jest.spyOn(CeList.prototype, 'removeIssue');
list.removeIssue(issue);
expect(ceRemoveIssue).toHaveBeenCalledWith(issue);
});
});
});
it('calls CE removeIssue', () => {
const ceRemoveIssue = jest.spyOn(CeList.prototype, 'removeIssue');
describe('iteration lists', () => {
const iteration = {
id: 1000,
title: 'Sprint 1',
webUrl: 'https://gitlab.com/h5bp/-/iterations/1',
};
list.removeIssue(issue);
beforeEach(() => {
list = new List({ list_type: ListType.iteration, iteration });
});
expect(ceRemoveIssue).toHaveBeenCalledWith(issue);
it('sets the iteration and title', () => {
expect(list.iteration.id).toBe(iteration.id);
expect(list.title).toBe(iteration.title);
});
});
});
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