Skip to content
Snippets Groups Projects
Commit 2dd22ecb authored by Kushal Pandya's avatar Kushal Pandya Committed by Phil Hughes
Browse files

Add support for toggling discussion filter from notes section

Adds discussion note style section under notes app from where
user can toggle discussion when they have selected a filter to show
only system notes.
parent 8baf9e5f
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -7,7 +7,9 @@ import {
DISCUSSION_FILTERS_DEFAULT_VALUE,
HISTORY_ONLY_FILTER_VALUE,
DISCUSSION_TAB_LABEL,
DISCUSSION_FILTER_TYPES,
} from '../constants';
import notesEventHub from '../event_hub';
 
export default {
components: {
Loading
Loading
@@ -46,6 +48,7 @@ export default {
this.toggleFilters(currentTab);
}
 
notesEventHub.$on('dropdownSelect', this.selectFilter);
window.addEventListener('hashchange', this.handleLocationHash);
this.handleLocationHash();
},
Loading
Loading
@@ -53,6 +56,7 @@ export default {
this.toggleCommentsForm();
},
destroyed() {
notesEventHub.$off('dropdownSelect', this.selectFilter);
window.removeEventListener('hashchange', this.handleLocationHash);
},
methods: {
Loading
Loading
@@ -86,12 +90,23 @@ export default {
this.setTargetNoteHash(hash);
}
},
filterType(value) {
if (value === 0) {
return DISCUSSION_FILTER_TYPES.ALL;
} else if (value === 1) {
return DISCUSSION_FILTER_TYPES.COMMENTS;
}
return DISCUSSION_FILTER_TYPES.HISTORY;
},
},
};
</script>
 
<template>
<div v-if="displayFilters" class="discussion-filter-container d-inline-block align-bottom">
<div
v-if="displayFilters"
class="discussion-filter-container js-discussion-filter-container d-inline-block align-bottom"
>
<button
id="discussion-filter-dropdown"
ref="dropdownToggle"
Loading
Loading
@@ -102,12 +117,17 @@ export default {
{{ currentFilter.title }} <icon name="chevron-down" />
</button>
<div
ref="dropdownMenu"
class="dropdown-menu dropdown-menu-selectable dropdown-menu-right"
aria-labelledby="discussion-filter-dropdown"
>
<div class="dropdown-content">
<ul>
<li v-for="filter in filters" :key="filter.value">
<li
v-for="filter in filters"
:key="filter.value"
:data-filter-type="filterType(filter.value)"
>
<button
:class="{ 'is-active': filter.value === currentValue }"
class="qa-filter-options"
Loading
Loading
<script>
import { GlButton } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import { __, sprintf } from '~/locale';
import notesEventHub from '../event_hub';
export default {
components: {
GlButton,
Icon,
},
computed: {
timelineContent() {
return sprintf(
__(
"You're only seeing %{startTag}other activity%{endTag} in the feed. To add a comment, switch to one of the following options.",
),
{
startTag: `<b>`,
endTag: `</b>`,
},
false,
);
},
},
methods: {
selectFilter(value) {
notesEventHub.$emit('dropdownSelect', value);
},
},
};
</script>
<template>
<li class="timeline-entry note note-wrapper discussion-filter-note js-discussion-filter-note">
<div class="timeline-icon">
<icon name="comment" />
</div>
<div class="timeline-content">
<div v-html="timelineContent"></div>
<div class="discussion-filter-actions mt-2">
<gl-button variant="default" @click="selectFilter(0)">
{{ __('Show all activity') }}
</gl-button>
<gl-button variant="default" @click="selectFilter(1)">
{{ __('Show comments only') }}
</gl-button>
</div>
</div>
</li>
</template>
Loading
Loading
@@ -6,6 +6,7 @@ import * as constants from '../constants';
import eventHub from '../event_hub';
import noteableNote from './noteable_note.vue';
import noteableDiscussion from './noteable_discussion.vue';
import discussionFilterNote from './discussion_filter_note.vue';
import systemNote from '../../vue_shared/components/notes/system_note.vue';
import commentForm from './comment_form.vue';
import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue';
Loading
Loading
@@ -24,6 +25,7 @@ export default {
placeholderNote,
placeholderSystemNote,
skeletonLoadingContainer,
discussionFilterNote,
},
props: {
noteableData: {
Loading
Loading
@@ -235,6 +237,7 @@ export default {
:help-page-path="helpPagePath"
/>
</template>
<discussion-filter-note v-show="commentsDisabled" />
</ul>
 
<comment-form v-if="!commentsDisabled" :noteable-type="noteableType" />
Loading
Loading
Loading
Loading
@@ -24,3 +24,9 @@ export const NOTEABLE_TYPE_MAPPING = {
MergeRequest: MERGE_REQUEST_NOTEABLE_TYPE,
Epic: EPIC_NOTEABLE_TYPE,
};
export const DISCUSSION_FILTER_TYPES = {
ALL: 'all',
COMMENTS: 'comments',
HISTORY: 'history',
};
Loading
Loading
@@ -4,7 +4,7 @@ $note-form-margin-left: 72px;
 
@mixin vertical-line($left) {
&::before {
content: '';
content: "";
border-left: 2px solid $gray-100;
position: absolute;
top: 0;
Loading
Loading
@@ -53,12 +53,12 @@ $note-form-margin-left: 72px;
&.note-form {
margin-left: 0;
 
@include notes-media('min', map-get($grid-breakpoints, md)) {
@include notes-media("min", map-get($grid-breakpoints, md)) {
margin-left: $note-form-margin-left;
}
 
.timeline-icon {
@include notes-media('min', map-get($grid-breakpoints, sm)) {
@include notes-media("min", map-get($grid-breakpoints, sm)) {
margin-left: -$note-icon-gutter-width;
}
}
Loading
Loading
@@ -242,7 +242,7 @@ $note-form-margin-left: 72px;
}
 
.note-header {
@include notes-media('max', map-get($grid-breakpoints, xs)) {
@include notes-media("max", map-get($grid-breakpoints, xs)) {
.inline {
display: block;
}
Loading
Loading
@@ -303,28 +303,8 @@ $note-form-margin-left: 72px;
}
}
 
.timeline-icon {
float: left;
display: flex;
align-items: center;
background-color: $white-light;
width: $system-note-icon-size;
height: $system-note-icon-size;
border: 1px solid $border-color;
border-radius: $system-note-icon-size;
margin: -6px $gl-padding 0 0;
svg {
width: $system-note-svg-size;
height: $system-note-svg-size;
fill: $gray-darkest;
display: block;
margin: 0 auto;
}
}
.timeline-content {
@include notes-media('min', map-get($grid-breakpoints, sm)) {
@include notes-media("min", map-get($grid-breakpoints, sm)) {
margin-left: 30px;
}
}
Loading
Loading
@@ -368,7 +348,7 @@ $note-form-margin-left: 72px;
}
 
&::after {
content: '';
content: "";
height: 70px;
position: absolute;
left: $gl-padding-24;
Loading
Loading
@@ -380,6 +360,37 @@ $note-form-margin-left: 72px;
}
}
}
.system-note,
.discussion-filter-note {
.timeline-icon {
float: left;
display: flex;
align-items: center;
background-color: $white-light;
width: $system-note-icon-size;
height: $system-note-icon-size;
border: 1px solid $border-color;
border-radius: $system-note-icon-size;
margin: -6px $gl-padding 0 0;
svg {
width: $system-note-svg-size;
height: $system-note-svg-size;
fill: $gray-darkest;
display: block;
margin: 0 auto;
}
}
}
.discussion-filter-note {
.timeline-icon {
width: $system-note-icon-size + 6;
height: $system-note-icon-size + 6;
margin-top: -8px;
}
}
}
 
// Diff code in discussion view
Loading
Loading
@@ -579,7 +590,7 @@ $note-form-margin-left: 72px;
.note-headline-light {
display: inline;
 
@include notes-media('max', map-get($grid-breakpoints, xs)) {
@include notes-media("max", map-get($grid-breakpoints, xs)) {
display: block;
}
}
Loading
Loading
@@ -645,7 +656,7 @@ $note-form-margin-left: 72px;
margin-left: 10px;
color: $gray-darkest;
 
@include notes-media('max', map-get($grid-breakpoints, sm) - 1) {
@include notes-media("max", map-get($grid-breakpoints, sm) - 1) {
float: none;
margin-left: 0;
}
Loading
Loading
@@ -764,7 +775,7 @@ $note-form-margin-left: 72px;
}
 
.line-resolve-all-container {
@include notes-media('min', map-get($grid-breakpoints, sm)) {
@include notes-media("min", map-get($grid-breakpoints, sm)) {
margin-right: 0;
}
 
Loading
Loading
@@ -905,7 +916,6 @@ $note-form-margin-left: 72px;
}
 
.discussion-filter-container {
.btn > svg {
width: $gl-col-padding;
height: $gl-col-padding;
Loading
Loading
@@ -927,7 +937,6 @@ $note-form-margin-left: 72px;
//This needs to be deleted when Snippet/Commit comments are convered to Vue
// See https://gitlab.com/gitlab-org/gitlab-ce/issues/53918#note_117038785
.unstyled-comments {
.discussion-header {
padding: $gl-padding;
border-bottom: 1px solid $border-color;
Loading
Loading
---
title: Add support for toggling discussion filter from notes section
merge_request: 25426
author:
type: added
Loading
Loading
@@ -6743,9 +6743,15 @@ msgstr ""
msgid "Sherlock Transactions"
msgstr ""
 
msgid "Show all activity"
msgstr ""
msgid "Show command"
msgstr ""
 
msgid "Show comments only"
msgstr ""
msgid "Show complete raw log"
msgstr ""
 
Loading
Loading
@@ -8654,6 +8660,9 @@ msgstr ""
msgid "You'll need to use different branch names to get a valid comparison."
msgstr ""
 
msgid "You're only seeing %{startTag}other activity%{endTag} in the feed. To add a comment, switch to one of the following options."
msgstr ""
msgid "You're receiving this email because %{reason}."
msgstr ""
 
Loading
Loading
import Vue from 'vue';
import DiscussionFilterNote from '~/notes/components/discussion_filter_note.vue';
import eventHub from '~/notes/event_hub';
import mountComponent from '../../helpers/vue_mount_component_helper';
describe('DiscussionFilterNote component', () => {
let vm;
const createComponent = () => {
const Component = Vue.extend(DiscussionFilterNote);
return mountComponent(Component);
};
beforeEach(() => {
vm = createComponent();
});
afterEach(() => {
vm.$destroy();
});
describe('computed', () => {
describe('timelineContent', () => {
it('returns string containing instruction for switching feed type', () => {
expect(vm.timelineContent).toBe(
"You're only seeing <b>other activity</b> in the feed. To add a comment, switch to one of the following options.",
);
});
});
});
describe('methods', () => {
describe('selectFilter', () => {
it('emits `dropdownSelect` event on `eventHub` with provided param', () => {
spyOn(eventHub, '$emit');
vm.selectFilter(1);
expect(eventHub.$emit).toHaveBeenCalledWith('dropdownSelect', 1);
});
});
});
describe('template', () => {
it('renders component container element', () => {
expect(vm.$el.classList.contains('discussion-filter-note')).toBe(true);
});
it('renders comment icon element', () => {
expect(vm.$el.querySelector('.timeline-icon svg use').getAttribute('xlink:href')).toContain(
'comment',
);
});
it('renders filter information note', () => {
expect(vm.$el.querySelector('.timeline-content').innerText.trim()).toContain(
"You're only seeing other activity in the feed. To add a comment, switch to one of the following options.",
);
});
it('renders filter buttons', () => {
const buttonsContainerEl = vm.$el.querySelector('.discussion-filter-actions');
expect(buttonsContainerEl.querySelector('button:first-child').innerText.trim()).toContain(
'Show all activity',
);
expect(buttonsContainerEl.querySelector('button:last-child').innerText.trim()).toContain(
'Show comments only',
);
});
it('clicking `Show all activity` button calls `selectFilter("all")` method', () => {
const showAllBtn = vm.$el.querySelector('.discussion-filter-actions button:first-child');
spyOn(vm, 'selectFilter');
showAllBtn.dispatchEvent(new Event('click'));
expect(vm.selectFilter).toHaveBeenCalledWith(0);
});
it('clicking `Show comments only` button calls `selectFilter("comments")` method', () => {
const showAllBtn = vm.$el.querySelector('.discussion-filter-actions button:last-child');
spyOn(vm, 'selectFilter');
showAllBtn.dispatchEvent(new Event('click'));
expect(vm.selectFilter).toHaveBeenCalledWith(1);
});
});
});
import Vue from 'vue';
import createStore from '~/notes/stores';
import DiscussionFilter from '~/notes/components/discussion_filter.vue';
import { DISCUSSION_FILTERS_DEFAULT_VALUE } from '~/notes/constants';
import { DISCUSSION_FILTERS_DEFAULT_VALUE, DISCUSSION_FILTER_TYPES } from '~/notes/constants';
import { mountComponentWithStore } from '../../helpers/vue_mount_component_helper';
import { discussionFiltersMock, discussionMock } from '../mock_data';
 
Loading
Loading
@@ -54,14 +54,18 @@ describe('DiscussionFilter component', () => {
});
 
it('updates to the selected item', () => {
const filterItem = vm.$el.querySelector('.dropdown-menu li:last-child button');
const filterItem = vm.$el.querySelector(
`.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.HISTORY}"] button`,
);
filterItem.click();
 
expect(vm.currentFilter.title).toEqual(filterItem.textContent.trim());
});
 
it('only updates when selected filter changes', () => {
const filterItem = vm.$el.querySelector('.dropdown-menu li:first-child button');
const filterItem = vm.$el.querySelector(
`.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.ALL}"] button`,
);
 
spyOn(vm, 'filterDiscussion');
filterItem.click();
Loading
Loading
@@ -70,21 +74,27 @@ describe('DiscussionFilter component', () => {
});
 
it('disables commenting when "Show history only" filter is applied', () => {
const filterItem = vm.$el.querySelector('.dropdown-menu li:last-child button');
const filterItem = vm.$el.querySelector(
`.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.HISTORY}"] button`,
);
filterItem.click();
 
expect(vm.$store.state.commentsDisabled).toBe(true);
});
 
it('enables commenting when "Show history only" filter is not applied', () => {
const filterItem = vm.$el.querySelector('.dropdown-menu li:first-child button');
const filterItem = vm.$el.querySelector(
`.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.ALL}"] button`,
);
filterItem.click();
 
expect(vm.$store.state.commentsDisabled).toBe(false);
});
 
it('renders a dropdown divider for the default filter', () => {
const defaultFilter = vm.$el.querySelector('.dropdown-menu li:first-child');
const defaultFilter = vm.$el.querySelector(
`.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.ALL}"]`,
);
 
expect(defaultFilter.lastChild.classList).toContain('dropdown-divider');
});
Loading
Loading
Loading
Loading
@@ -126,6 +126,13 @@ describe('note_app', () => {
expect(wrapper.find('.js-main-target-form').exists()).toBe(false);
});
 
it('should render discussion filter note `commentsDisabled` is true', () => {
store.state.commentsDisabled = true;
wrapper = mountComponent();
expect(wrapper.find('.js-discussion-filter-note').exists()).toBe(true);
});
it('should render form comment button as disabled', () => {
expect(wrapper.find('.js-note-new-discussion').attributes('disabled')).toEqual('disabled');
});
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment