Skip to content
Snippets Groups Projects
Commit b4d005eb authored by Felipe Artur's avatar Felipe Artur Committed by Phil Hughes
Browse files

Add 'only history' option to notes filter

parent 90473e06
No related branches found
No related tags found
No related merge requests found
Showing
with 144 additions and 19 deletions
<script>
import $ from 'jquery';
import Icon from '~/vue_shared/components/icon.vue';
import { mapGetters, mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
import { DISCUSSION_FILTERS_DEFAULT_VALUE, HISTORY_ONLY_FILTER_VALUE } from '../constants';
 
export default {
components: {
Loading
Loading
@@ -12,14 +13,17 @@ export default {
type: Array,
required: true,
},
defaultValue: {
selectedValue: {
type: Number,
default: null,
required: false,
},
},
data() {
return { currentValue: this.defaultValue };
return {
currentValue: this.selectedValue,
defaultValue: DISCUSSION_FILTERS_DEFAULT_VALUE,
};
},
computed: {
...mapGetters(['getNotesDataByProp']),
Loading
Loading
@@ -28,8 +32,11 @@ export default {
return this.filters.find(filter => filter.value === this.currentValue);
},
},
mounted() {
this.toggleCommentsForm();
},
methods: {
...mapActions(['filterDiscussion']),
...mapActions(['filterDiscussion', 'setCommentsDisabled']),
selectFilter(value) {
const filter = parseInt(value, 10);
 
Loading
Loading
@@ -39,6 +46,10 @@ export default {
if (filter === this.currentValue) return;
this.currentValue = filter;
this.filterDiscussion({ path: this.getNotesDataByProp('discussionsPath'), filter });
this.toggleCommentsForm();
},
toggleCommentsForm() {
this.setCommentsDisabled(this.currentValue === HISTORY_ONLY_FILTER_VALUE);
},
},
};
Loading
Loading
@@ -73,6 +84,10 @@ export default {
>
{{ filter.title }}
</button>
<div
v-if="filter.value === defaultValue"
class="dropdown-divider"
></div>
</li>
</ul>
</div>
Loading
Loading
Loading
Loading
@@ -60,6 +60,7 @@ export default {
'getNotesDataByProp',
'discussionCount',
'isLoading',
'commentsDisabled',
]),
noteableType() {
return this.noteableData.noteableType;
Loading
Loading
@@ -206,6 +207,7 @@ export default {
</ul>
 
<comment-form
v-if="!commentsDisabled"
:noteable-type="noteableType"
:markdown-version="markdownVersion"
/>
Loading
Loading
Loading
Loading
@@ -15,6 +15,8 @@ export const MERGE_REQUEST_NOTEABLE_TYPE = 'MergeRequest';
export const UNRESOLVE_NOTE_METHOD_NAME = 'delete';
export const RESOLVE_NOTE_METHOD_NAME = 'post';
export const DESCRIPTION_TYPE = 'changed the description';
export const HISTORY_ONLY_FILTER_VALUE = 2;
export const DISCUSSION_FILTERS_DEFAULT_VALUE = 0;
 
export const NOTEABLE_TYPE_MAPPING = {
Issue: ISSUE_NOTEABLE_TYPE,
Loading
Loading
Loading
Loading
@@ -6,7 +6,7 @@ export default store => {
 
if (discussionFilterEl) {
const { defaultFilter, notesFilters } = discussionFilterEl.dataset;
const defaultValue = defaultFilter ? parseInt(defaultFilter, 10) : null;
const selectedValue = defaultFilter ? parseInt(defaultFilter, 10) : null;
const filterValues = notesFilters ? JSON.parse(notesFilters) : {};
const filters = Object.keys(filterValues).map(entry => ({
title: entry,
Loading
Loading
@@ -24,7 +24,7 @@ export default store => {
return createElement('discussion-filter', {
props: {
filters,
defaultValue,
selectedValue,
},
});
},
Loading
Loading
Loading
Loading
@@ -364,5 +364,9 @@ export const filterDiscussion = ({ dispatch }, { path, filter }) => {
});
};
 
export const setCommentsDisabled = ({ commit }, data) => {
commit(types.DISABLE_COMMENTS, data);
};
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
Loading
Loading
@@ -192,5 +192,7 @@ export const firstUnresolvedDiscussionId = (state, getters) => diffOrder => {
return getters.unresolvedDiscussionsIdsByDate[0];
};
 
export const commentsDisabled = state => state.commentsDisabled;
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
Loading
Loading
@@ -21,6 +21,7 @@ export default () => ({
noteableData: {
current_user: {},
},
commentsDisabled: false,
},
actions,
getters,
Loading
Loading
Loading
Loading
@@ -15,6 +15,7 @@ export const UPDATE_DISCUSSION = 'UPDATE_DISCUSSION';
export const SET_DISCUSSION_DIFF_LINES = 'SET_DISCUSSION_DIFF_LINES';
export const SET_NOTES_FETCHED_STATE = 'SET_NOTES_FETCHED_STATE';
export const SET_NOTES_LOADING_STATE = 'SET_NOTES_LOADING_STATE';
export const DISABLE_COMMENTS = 'DISABLE_COMMENTS';
 
// DISCUSSION
export const COLLAPSE_DISCUSSION = 'COLLAPSE_DISCUSSION';
Loading
Loading
Loading
Loading
@@ -225,4 +225,8 @@ export default {
 
discussion.truncated_diff_lines = diffLines;
},
[types.DISABLE_COMMENTS](state, value) {
state.commentsDisabled = value;
},
};
Loading
Loading
@@ -117,6 +117,8 @@ class Note < ActiveRecord::Base
case notes_filter
when UserPreference::NOTES_FILTERS[:only_comments]
user
when UserPreference::NOTES_FILTERS[:only_activity]
system
else
all
end
Loading
Loading
Loading
Loading
@@ -4,7 +4,7 @@ class UserPreference < ActiveRecord::Base
# We could use enums, but Rails 4 doesn't support multiple
# enum options with same name for multiple fields, also it creates
# extra methods that aren't really needed here.
NOTES_FILTERS = { all_notes: 0, only_comments: 1 }.freeze
NOTES_FILTERS = { all_notes: 0, only_comments: 1, only_activity: 2 }.freeze
 
belongs_to :user
 
Loading
Loading
@@ -14,7 +14,8 @@ class UserPreference < ActiveRecord::Base
def notes_filters
{
s_('Notes|Show all activity') => NOTES_FILTERS[:all_notes],
s_('Notes|Show comments only') => NOTES_FILTERS[:only_comments]
s_('Notes|Show comments only') => NOTES_FILTERS[:only_comments],
s_('Notes|Show history only') => NOTES_FILTERS[:only_activity]
}
end
end
Loading
Loading
Loading
Loading
@@ -7,4 +7,8 @@ class UserPreferenceEntity < Grape::Entity
expose :notes_filters do |user_preference|
UserPreference.notes_filters
end
expose :default_notes_filter do |user_preference|
UserPreference::NOTES_FILTERS[:all_notes]
end
end
---
title: Add 'only history' option to notes filter
merge_request:
author:
type: changed
Loading
Loading
@@ -4165,6 +4165,9 @@ msgstr ""
msgid "Notes|Show comments only"
msgstr ""
 
msgid "Notes|Show history only"
msgstr ""
msgid "Notification events"
msgstr ""
 
Loading
Loading
Loading
Loading
@@ -13,7 +13,7 @@ describe NotesFinder do
let!(:comment) { create(:note_on_issue, project: project) }
let!(:system_note) { create(:note_on_issue, project: project, system: true) }
 
it 'filters system notes' do
it 'returns only user notes when using only_comments filter' do
finder = described_class.new(project, user, notes_filter: UserPreference::NOTES_FILTERS[:only_comments])
 
notes = finder.execute
Loading
Loading
@@ -21,6 +21,14 @@ describe NotesFinder do
expect(notes).to match_array(comment)
end
 
it 'returns only system notes when using only_activity filters' do
finder = described_class.new(project, user, notes_filter: UserPreference::NOTES_FILTERS[:only_activity])
notes = finder.execute
expect(notes).to match_array(system_note)
end
it 'gets all notes' do
finder = described_class.new(project, user, notes_filter: UserPreference::NOTES_FILTERS[:all_activity])
 
Loading
Loading
Loading
Loading
@@ -19,7 +19,7 @@ describe('DiscussionFilter component', () => {
},
];
const Component = Vue.extend(DiscussionFilter);
const defaultValue = discussionFiltersMock[0].value;
const selectedValue = discussionFiltersMock[0].value;
 
store.state.discussions = discussions;
vm = mountComponentWithStore(Component, {
Loading
Loading
@@ -27,7 +27,7 @@ describe('DiscussionFilter component', () => {
store,
props: {
filters: discussionFiltersMock,
defaultValue,
selectedValue,
},
});
});
Loading
Loading
@@ -63,4 +63,24 @@ describe('DiscussionFilter component', () => {
 
expect(vm.filterDiscussion).not.toHaveBeenCalled();
});
it('disables commenting when "Show history only" filter is applied', () => {
const filterItem = vm.$el.querySelector('.dropdown-menu li:last-child 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');
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');
expect(defaultFilter.lastChild.classList).toContain('dropdown-divider');
});
});
Loading
Loading
@@ -121,6 +121,13 @@ describe('note_app', () => {
).toEqual('Write a comment or drag your files here…');
});
 
it('should not render form when commenting is disabled', () => {
store.state.commentsDisabled = true;
vm = mountComponent();
expect(vm.$el.querySelector('.js-main-target-form')).toEqual(null);
});
it('should render form comment button as disabled', () => {
expect(vm.$el.querySelector('.js-note-new-discussion').getAttribute('disabled')).toEqual(
'disabled',
Loading
Loading
Loading
Loading
@@ -509,4 +509,17 @@ describe('Actions Notes Store', () => {
expect(mrWidgetEventHub.$emit).toHaveBeenCalledWith('mr.discussion.updated');
});
});
describe('setCommentsDisabled', () => {
it('should set comments disabled state', done => {
testAction(
actions.setCommentsDisabled,
true,
null,
[{ type: 'DISABLE_COMMENTS', payload: true }],
[],
done,
);
});
});
});
Loading
Loading
@@ -427,4 +427,14 @@ describe('Notes Store mutations', () => {
expect(state.discussions[0].expanded).toBe(true);
});
});
describe('DISABLE_COMMENTS', () => {
it('should set comments disabled state', () => {
const state = {};
mutations.DISABLE_COMMENTS(state, true);
expect(state.commentsDisabled).toEqual(true);
});
});
});
Loading
Loading
@@ -6,22 +6,43 @@ describe UserPreference do
describe '#set_notes_filter' do
let(:issuable) { build_stubbed(:issue) }
let(:user_preference) { create(:user_preference) }
let(:only_comments) { described_class::NOTES_FILTERS[:only_comments] }
 
it 'returns updated discussion filter' do
filter_name =
user_preference.set_notes_filter(only_comments, issuable)
shared_examples 'setting system notes' do
it 'returns updated discussion filter' do
filter_name =
user_preference.set_notes_filter(filter, issuable)
expect(filter_name).to eq(filter)
end
it 'updates discussion filter for issuable class' do
user_preference.set_notes_filter(filter, issuable)
expect(user_preference.reload.issue_notes_filter).to eq(filter)
end
end
context 'when filter is set to all notes' do
let(:filter) { described_class::NOTES_FILTERS[:all_notes] }
it_behaves_like 'setting system notes'
end
context 'when filter is set to only comments' do
let(:filter) { described_class::NOTES_FILTERS[:only_comments] }
 
expect(filter_name).to eq(only_comments)
it_behaves_like 'setting system notes'
end
 
it 'updates discussion filter for issuable class' do
user_preference.set_notes_filter(only_comments, issuable)
context 'when filter is set to only activity' do
let(:filter) { described_class::NOTES_FILTERS[:only_activity] }
 
expect(user_preference.reload.issue_notes_filter).to eq(only_comments)
it_behaves_like 'setting system notes'
end
 
context 'when notes_filter parameter is invalid' do
let(:only_comments) { described_class::NOTES_FILTERS[:only_comments] }
it 'returns the current notes filter' do
user_preference.set_notes_filter(only_comments, issuable)
 
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