Commit c8b9a0d2 authored by Illya Klymov's avatar Illya Klymov

Merge branch 'ss/add-assignees-to-sidebar' into 'master'

Add assignees to boards sidebar

See merge request gitlab-org/gitlab!41913
parents 33dc1a9c 41276da1
......@@ -84,6 +84,10 @@ export default () => {
},
store,
apolloProvider,
provide: {
// TODO: Mv all non-reactive props from data/props to here.
rootPath: $boardApp.dataset.rootPath,
},
data() {
return {
state: boardsStore.state,
......
......@@ -59,7 +59,7 @@ export default {
};
},
assigneeUrl() {
return this.user.web_url;
return this.user.web_url || this.user.webUrl;
},
},
};
......
<script>
import { n__ } from '~/locale';
import UncollapsedAssigneeList from '~/sidebar/components/assignees/uncollapsed_assignee_list.vue';
export default {
components: {
UncollapsedAssigneeList,
},
inject: ['rootPath'],
props: {
users: {
type: Array,
required: true,
},
},
computed: {
assigneesText() {
return n__('Assignee', '%d Assignees', this.users.length);
},
emptyUsers() {
return this.users.length === 0;
},
},
};
</script>
<template>
<div class="gl-display-flex gl-flex-direction-column">
<label data-testid="assigneeLabel">{{ assigneesText }}</label>
<div v-if="emptyUsers" data-testid="none">
<span>
{{ __('None') }}
</span>
</div>
<uncollapsed-assignee-list v-else :users="users" :root-path="rootPath" />
</div>
</template>
......@@ -73,9 +73,9 @@ export default {
:root-path="rootPath"
:issuable-type="issuableType"
>
<div class="ml-2">
<span class="author"> {{ user.name }} </span>
<span class="username"> {{ username }} </span>
<div class="ml-2 gl-line-height-normal">
<div>{{ user.name }}</div>
<div>{{ username }}</div>
</div>
</assignee-avatar-link>
<div v-else>
......
......@@ -361,13 +361,6 @@
margin: 0;
}
.username {
display: block;
margin-top: 4px;
font-size: 13px;
font-weight: $gl-font-weight-normal;
}
.hide-expanded {
display: none;
}
......
......@@ -3,10 +3,12 @@ import { mapState, mapActions, mapGetters } from 'vuex';
import { GlDrawer } from '@gitlab/ui';
import { ISSUABLE } from '~/boards/constants';
import { contentTop } from '~/lib/utils/common_utils';
import IssuableAssignees from '~/sidebar/components/assignees/issuable_assignees.vue';
export default {
headerHeight: `${contentTop()}px`,
components: {
IssuableAssignees,
GlDrawer,
},
computed: {
......@@ -38,5 +40,9 @@ export default {
<p class="gl-mb-0">{{ getActiveIssue.referencePath }}</p>
</div>
</template>
<template>
<issuable-assignees :users="getActiveIssue.assignees" />
</template>
</gl-drawer>
</template>
......@@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils';
import { GlDrawer } from '@gitlab/ui';
import waitForPromises from 'helpers/wait_for_promises';
import BoardContentSidebar from 'ee_component/boards/components/board_content_sidebar.vue';
import IssuableAssignees from '~/sidebar/components/assignees/issuable_assignees.vue';
import { createStore } from '~/boards/stores';
import { ISSUABLE } from '~/boards/constants';
......@@ -11,6 +12,9 @@ describe('ee/BoardContentSidebar', () => {
const createComponent = () => {
wrapper = mount(BoardContentSidebar, {
provide: {
rootPath: '',
},
store,
});
};
......@@ -19,7 +23,7 @@ describe('ee/BoardContentSidebar', () => {
store = createStore();
store.state.sidebarType = ISSUABLE;
store.state.activeId = 1;
store.state.issues = { '1': { title: 'One', referencePath: 'path' } };
store.state.issues = { '1': { title: 'One', referencePath: 'path', assignees: [] } };
store.state.activeId = '1';
createComponent();
......@@ -45,6 +49,10 @@ describe('ee/BoardContentSidebar', () => {
expect(wrapper.find('[data-testid="issue-title"]').text()).toContain('path');
});
it('renders IssuableAssignees', () => {
expect(wrapper.find(IssuableAssignees).exists()).toBe(true);
});
describe('when we emit close', () => {
it('hides GlDrawer', async () => {
expect(wrapper.find(GlDrawer).props('open')).toBe(true);
......
......@@ -152,9 +152,7 @@ RSpec.describe "Issues > User edits issue", :js do
visit project_issue_path(project, issue2)
page.within '.assignee' do
page.within '.value .author' do
expect(page).to have_content user.name
end
expect(page).to have_content user.name
click_link 'Edit'
click_link user.name
......
import { shallowMount } from '@vue/test-utils';
import IssuableAssignees from '~/sidebar/components/assignees/issuable_assignees.vue';
import UncollapsedAssigneeList from '~/sidebar/components/assignees/uncollapsed_assignee_list.vue';
describe('IssuableAssignees', () => {
let wrapper;
const createComponent = (props = { users: [] }) => {
wrapper = shallowMount(IssuableAssignees, {
provide: {
rootPath: '',
},
propsData: { ...props },
});
};
const findLabel = () => wrapper.find('[data-testid="assigneeLabel"');
const findUncollapsedAssigneeList = () => wrapper.find(UncollapsedAssigneeList);
const findEmptyAssignee = () => wrapper.find('[data-testid="none"]');
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('when no assignees are present', () => {
beforeEach(() => {
createComponent();
});
it('renders "None"', () => {
expect(findEmptyAssignee().text()).toBe('None');
});
it('renders "0 assignees"', () => {
expect(findLabel().text()).toBe('0 Assignees');
});
});
describe('when assignees are present', () => {
it('renders UncollapsedAssigneesList', () => {
createComponent({ users: [{ id: 1 }] });
expect(findUncollapsedAssigneeList().exists()).toBe(true);
});
it.each`
assignees | expected
${[{ id: 1 }]} | ${'Assignee'}
${[{ id: 1 }, { id: 2 }]} | ${'2 Assignees'}
`(
'when assignees have a length of $assignees.length, it renders $expected',
({ assignees, expected }) => {
createComponent({ users: assignees });
expect(findLabel().text()).toBe(expected);
},
);
});
});
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