Commit ec2ff7cb authored by Natalia Tepluhina's avatar Natalia Tepluhina Committed by Martin Wortschack

Refactor participants component

- added participants component to design index

- refactored participants component to have showParticipantLabel prop

- added test for showParticipantLabel prop

- updated failing snapshots
parent 2a58cfc3
......@@ -28,6 +28,11 @@ export default {
required: false,
default: 7,
},
showParticipantLabel: {
type: Boolean,
required: false,
default: true,
},
},
data() {
return {
......@@ -80,6 +85,7 @@ export default {
<template>
<div>
<div
v-if="showParticipantLabel"
v-tooltip
:title="participantLabel"
class="sidebar-collapsed-icon"
......@@ -92,7 +98,7 @@ export default {
<gl-loading-icon v-if="loading" class="js-participants-collapsed-loading-icon" />
<span v-else class="js-participants-collapsed-count"> {{ participantCount }} </span>
</div>
<div class="title hide-collapsed">
<div v-if="showParticipantLabel" class="title hide-collapsed">
<gl-loading-icon
v-if="loading"
:inline="true"
......
---
title: Extend Design view sidebar with issue link and a list of participants
merge_request: 22103
author:
type: added
......@@ -105,7 +105,7 @@ export default {
<icon :size="18" name="close" />
</router-link>
<div class="overflow-hidden d-flex align-items-center">
<h2 class="m-0 str-truncated-100">{{ filename }}</h2>
<h2 class="m-0 str-truncated-100 gl-font-size-14">{{ filename }}</h2>
<small v-if="updatedAt" class="text-secondary">{{ updatedText }}</small>
</div>
<pagination :id="id" class="ml-auto flex-shrink-0" />
......
fragment Author on User {
avatarUrl
name
username
webUrl
}
\ No newline at end of file
#import "./diffRefs.fragment.graphql"
#import "./author.fragment.graphql"
fragment DesignNote on Note {
id
author {
avatarUrl
name
username
webUrl
...Author
}
body
bodyHtml
......
#import "../fragments/design.fragment.graphql"
#import "../fragments/author.fragment.graphql"
query getDesign($fullPath: ID!, $iid: String!, $atVersion: ID, $filenames: [String!]) {
project(fullPath: $fullPath) {
......@@ -9,6 +10,18 @@ query getDesign($fullPath: ID!, $iid: String!, $atVersion: ID, $filenames: [Stri
edges {
node {
...DesignItem
issue {
title
webPath
webUrl
participants {
edges {
node {
...Author
}
}
}
}
}
}
}
......
......@@ -10,10 +10,15 @@ import DesignOverlay from '../../components/design_overlay.vue';
import DesignDiscussion from '../../components/design_notes/design_discussion.vue';
import DesignReplyForm from '../../components/design_notes/design_reply_form.vue';
import DesignDestroyer from '../../components/design_destroyer.vue';
import Participants from '~/sidebar/components/participants/participants.vue';
import getDesignQuery from '../../graphql/queries/getDesign.query.graphql';
import appDataQuery from '../../graphql/queries/appData.query.graphql';
import createImageDiffNoteMutation from '../../graphql/mutations/createImageDiffNote.mutation.graphql';
import { extractDiscussions, extractDesign } from '../../utils/design_management_utils';
import {
extractDiscussions,
extractDesign,
extractParticipants,
} from '../../utils/design_management_utils';
import { updateStoreAfterAddImageDiffNote } from '../../utils/cache_update';
import {
ADD_DISCUSSION_COMMENT_ERROR,
......@@ -33,6 +38,7 @@ export default {
DesignReplyForm,
GlLoadingIcon,
GlAlert,
Participants,
},
mixins: [allVersionsMixin],
props: {
......@@ -51,8 +57,8 @@ export default {
height: 0,
},
projectPath: '',
issueId: '',
errorMessage: '',
issueIid: '',
};
},
apollo: {
......@@ -94,6 +100,9 @@ export default {
discussionStartingNotes() {
return this.discussions.map(discussion => discussion.notes[0]);
},
discussionParticipants() {
return extractParticipants(this.design.issue.participants);
},
markdownPreviewPath() {
return `/${this.projectPath}/preview_markdown?target_type=Issue`;
},
......@@ -130,6 +139,12 @@ export default {
},
};
},
issue() {
return {
...this.design.issue,
webPath: this.design.issue.webPath.substr(1),
};
},
},
mounted() {
Mousetrap.bind('esc', this.closeDesign);
......@@ -243,6 +258,15 @@ export default {
</div>
</div>
<div class="image-notes">
<h2 class="gl-font-size-20 font-weight-bold mt-0">{{ issue.title }}</h2>
<a class="text-tertiary text-decoration-none mb-3 d-block" :href="issue.webUrl">{{
issue.webPath
}}</a>
<participants
:participants="discussionParticipants"
:show-participant-label="false"
class="mb-4"
/>
<template v-if="renderDiscussions">
<design-discussion
v-for="(discussion, index) in discussions"
......@@ -274,7 +298,7 @@ export default {
/>
</apollo-mutation>
</template>
<h2 v-else class="new-discussion-disclaimer m-0">
<h2 v-else class="new-discussion-disclaimer gl-font-size-14 m-0">
{{ __("Click the image where you'd like to start a new discussion") }}
</h2>
</div>
......
......@@ -62,6 +62,23 @@ const addDiscussionCommentToStore = (store, createNote, query, queryVariables, d
];
design.notesCount += 1;
if (
!design.issue.participants.edges.some(
participant => participant.node.username === createNote.note.author.username,
)
) {
design.issue.participants.edges = [
...design.issue.participants.edges,
{
__typename: 'UserEdge',
node: {
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
__typename: 'User',
...createNote.note.author,
},
},
];
}
store.writeQuery({
query,
variables: queryVariables,
......@@ -101,6 +118,23 @@ const addImageDiffNoteToStore = (store, createImageDiffNote, query, variables) =
const design = extractDesign(data);
const notesCount = design.notesCount + 1;
design.discussions.edges = [...design.discussions.edges, newDiscussion];
if (
!design.issue.participants.edges.some(
participant => participant.node.username === createImageDiffNote.note.author.username,
)
) {
design.issue.participants.edges = [
...design.issue.participants.edges,
{
__typename: 'UserEdge',
node: {
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
__typename: 'User',
...createImageDiffNote.note.author,
},
},
];
}
store.writeQuery({
query,
variables,
......
......@@ -86,3 +86,11 @@ export const designUploadOptimisticResponse = files => {
},
};
};
const normalizeAuthor = author => ({
...author,
web_url: author.webUrl,
avatar_url: author.avatarUrl,
});
export const extractParticipants = users => users.edges.map(({ node }) => normalizeAuthor(node));
......@@ -4,10 +4,6 @@
.with-performance-bar & {
top: 35px;
}
h2 {
font-size: 14px;
}
}
.design-list-item {
......
......@@ -18,7 +18,7 @@ exports[`Design management toolbar component renders design and updated data 1`]
class="overflow-hidden d-flex align-items-center"
>
<h2
class="m-0 str-truncated-100"
class="m-0 str-truncated-100 gl-font-size-14"
>
test.jpg
</h2>
......
......@@ -7,6 +7,23 @@ export default {
updatedBy: {
name: 'test',
},
issue: {
title: 'My precious issue',
webPath: 'full-issue-path',
webUrl: 'full-issue-url',
participants: {
edges: [
{
node: {
name: 'Administrator',
username: 'root',
webUrl: 'link-to-author',
avatarUrl: 'link-to-avatar',
},
},
],
},
},
discussions: {
edges: [
{
......@@ -19,6 +36,12 @@ export default {
node: {
id: 'note-id',
body: '123',
author: {
name: 'Administrator',
username: 'root',
webUrl: 'link-to-author',
avatarUrl: 'link-to-avatar',
},
},
},
],
......
......@@ -37,6 +37,25 @@ exports[`Design management design index page renders design index 1`] = `
<div
class="image-notes"
>
<h2
class="gl-font-size-20 font-weight-bold mt-0"
>
My precious issue
</h2>
<a
class="text-tertiary text-decoration-none mb-3 d-block"
href="full-issue-url"
>
ull-issue-path
</a>
<participants-stub
class="mb-4"
numberoflessparticipants="7"
participants="[object Object]"
/>
<design-discussion-stub
designid="1"
discussion="[object Object]"
......@@ -114,7 +133,26 @@ exports[`Design management design index page with error GlAlert is rendered in c
class="image-notes"
>
<h2
class="new-discussion-disclaimer m-0"
class="gl-font-size-20 font-weight-bold mt-0"
>
My precious issue
</h2>
<a
class="text-tertiary text-decoration-none mb-3 d-block"
href="full-issue-url"
>
ull-issue-path
</a>
<participants-stub
class="mb-4"
numberoflessparticipants="7"
participants="[object Object]"
/>
<h2
class="new-discussion-disclaimer gl-font-size-14 m-0"
>
Click the image where you'd like to start a new discussion
......
......@@ -4,6 +4,7 @@ import { ApolloMutation } from 'vue-apollo';
import DesignIndex from 'ee/design_management/pages/design/index.vue';
import DesignDiscussion from 'ee/design_management/components/design_notes/design_discussion.vue';
import DesignReplyForm from 'ee/design_management/components/design_notes/design_reply_form.vue';
import Participants from '~/sidebar/components/participants/participants.vue';
import createImageDiffNoteMutation from 'ee/design_management/graphql/mutations/createImageDiffNote.mutation.graphql';
import design from '../../mock_data/design';
......@@ -44,6 +45,7 @@ describe('Design management design index page', () => {
const findDiscussions = () => wrapper.findAll(DesignDiscussion);
const findDiscussionForm = () => wrapper.find(DesignReplyForm);
const findParticipants = () => wrapper.find(Participants);
function createComponent(loading = false) {
const $apollo = {
......@@ -99,6 +101,22 @@ describe('Design management design index page', () => {
});
});
it('renders participants', () => {
setDesign();
wrapper.setData({
design,
});
return wrapper.vm.$nextTick().then(() => {
expect(findParticipants().exists()).toBe(true);
});
});
it('passes the correct amount of participants to the Participants component', () => {
expect(findParticipants().props('participants').length).toBe(1);
});
describe('when has no discussions', () => {
beforeEach(() => {
setDesign();
......
......@@ -46,7 +46,7 @@ describe('extractDiscussions', () => {
};
});
it('discards the edges.node artefacts of GraphQL', () => {
it('discards the edges.node artifacts of GraphQL', () => {
expect(extractDiscussions(discussions)).toEqual([
{ id: 1, notes: ['a'] },
{ id: 2, notes: ['b'] },
......
......@@ -182,4 +182,21 @@ describe('Participants', function() {
expect(vm.$emit).toHaveBeenCalledWith('toggleSidebar');
});
});
describe('when not showing participants label', () => {
beforeEach(() => {
vm = mountComponent(Participants, {
participants: PARTICIPANT_LIST,
showParticipantLabel: false,
});
});
it('does not show sidebar collapsed icon', () => {
expect(vm.$el.querySelector('.sidebar-collapsed-icon')).not.toBeTruthy();
});
it('does not show participants label title', () => {
expect(vm.$el.querySelector('.title')).not.toBeTruthy();
});
});
});
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