Merge branch '1801-allow-event_filter-to-be-set-in-the-url' into 'master'
Allow events filter to be set in the URL in addition to cookie Closes #1801 See merge request gitlab-org/gitlab-ce!21557
This commit is contained in:
commit
46da2c0b01
|
@ -273,9 +273,10 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def event_filter
|
def event_filter
|
||||||
# Split using comma to maintain backward compatibility Ex/ "filter1,filter2"
|
@event_filter ||=
|
||||||
filters = cookies['event_filter'].split(',')[0] if cookies['event_filter'].present?
|
EventFilter.new(params[:event_filter].presence || cookies[:event_filter]).tap do |new_event_filter|
|
||||||
@event_filter ||= EventFilter.new(filters)
|
cookies[:event_filter] = new_event_filter.filter
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# JSON for infinite scroll via Pager object
|
# JSON for infinite scroll via Pager object
|
||||||
|
|
|
@ -40,7 +40,7 @@ class DashboardController < Dashboard::ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
@events = EventCollection
|
@events = EventCollection
|
||||||
.new(projects, offset: params[:offset].to_i, filter: @event_filter)
|
.new(projects, offset: params[:offset].to_i, filter: event_filter)
|
||||||
.to_a
|
.to_a
|
||||||
|
|
||||||
Events::RenderService.new(current_user).execute(@events)
|
Events::RenderService.new(current_user).execute(@events)
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
.fade-left= icon('angle-left')
|
.fade-left= icon('angle-left')
|
||||||
.fade-right= icon('angle-right')
|
.fade-right= icon('angle-right')
|
||||||
%ul.nav-links.event-filter.scrolling-tabs.nav.nav-tabs
|
%ul.nav-links.event-filter.scrolling-tabs.nav.nav-tabs
|
||||||
= event_filter_link EventFilter.all, _('All'), s_('EventFilterBy|Filter by all')
|
= event_filter_link EventFilter::ALL, _('All'), s_('EventFilterBy|Filter by all')
|
||||||
- if event_filter_visible(:repository)
|
- if event_filter_visible(:repository)
|
||||||
= event_filter_link EventFilter.push, _('Push events'), s_('EventFilterBy|Filter by push events')
|
= event_filter_link EventFilter::PUSH, _('Push events'), s_('EventFilterBy|Filter by push events')
|
||||||
- if event_filter_visible(:merge_requests)
|
- if event_filter_visible(:merge_requests)
|
||||||
= event_filter_link EventFilter.merged, _('Merge events'), s_('EventFilterBy|Filter by merge events')
|
= event_filter_link EventFilter::MERGED, _('Merge events'), s_('EventFilterBy|Filter by merge events')
|
||||||
- if event_filter_visible(:issues)
|
- if event_filter_visible(:issues)
|
||||||
= event_filter_link EventFilter.issue, _('Issue events'), s_('EventFilterBy|Filter by issue events')
|
= event_filter_link EventFilter::ISSUE, _('Issue events'), s_('EventFilterBy|Filter by issue events')
|
||||||
- if comments_visible?
|
- if comments_visible?
|
||||||
= event_filter_link EventFilter.comments, _('Comments'), s_('EventFilterBy|Filter by comments')
|
= event_filter_link EventFilter::COMMENTS, _('Comments'), s_('EventFilterBy|Filter by comments')
|
||||||
= event_filter_link EventFilter.team, _('Team'), s_('EventFilterBy|Filter by team')
|
= event_filter_link EventFilter::TEAM, _('Team'), s_('EventFilterBy|Filter by team')
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: "Allow events filter to be set in the URL in addition to cookie"
|
||||||
|
merge_request: 21557
|
||||||
|
author: Igor @igas
|
||||||
|
type: added
|
|
@ -1,76 +1,42 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class EventFilter
|
class EventFilter
|
||||||
attr_accessor :params
|
attr_accessor :filter
|
||||||
|
|
||||||
class << self
|
ALL = 'all'
|
||||||
def all
|
PUSH = 'push'
|
||||||
'all'
|
MERGED = 'merged'
|
||||||
end
|
ISSUE = 'issue'
|
||||||
|
COMMENTS = 'comments'
|
||||||
|
TEAM = 'team'
|
||||||
|
FILTERS = [ALL, PUSH, MERGED, ISSUE, COMMENTS, TEAM].freeze
|
||||||
|
|
||||||
def push
|
def initialize(filter)
|
||||||
'push'
|
# Split using comma to maintain backward compatibility Ex/ "filter1,filter2"
|
||||||
end
|
filter = filter.to_s.split(',')[0].to_s
|
||||||
|
@filter = FILTERS.include?(filter) ? filter : ALL
|
||||||
def merged
|
|
||||||
'merged'
|
|
||||||
end
|
|
||||||
|
|
||||||
def issue
|
|
||||||
'issue'
|
|
||||||
end
|
|
||||||
|
|
||||||
def comments
|
|
||||||
'comments'
|
|
||||||
end
|
|
||||||
|
|
||||||
def team
|
|
||||||
'team'
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(params)
|
def active?(key)
|
||||||
@params = if params
|
filter == key.to_s
|
||||||
params.dup
|
|
||||||
else
|
|
||||||
[] # EventFilter.default_filter
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop: disable CodeReuse/ActiveRecord
|
# rubocop: disable CodeReuse/ActiveRecord
|
||||||
def apply_filter(events)
|
def apply_filter(events)
|
||||||
return events if params.blank? || params == EventFilter.all
|
case filter
|
||||||
|
when PUSH
|
||||||
case params
|
|
||||||
when EventFilter.push
|
|
||||||
events.where(action: Event::PUSHED)
|
events.where(action: Event::PUSHED)
|
||||||
when EventFilter.merged
|
when MERGED
|
||||||
events.where(action: Event::MERGED)
|
events.where(action: Event::MERGED)
|
||||||
when EventFilter.comments
|
when COMMENTS
|
||||||
events.where(action: Event::COMMENTED)
|
events.where(action: Event::COMMENTED)
|
||||||
when EventFilter.team
|
when TEAM
|
||||||
events.where(action: [Event::JOINED, Event::LEFT, Event::EXPIRED])
|
events.where(action: [Event::JOINED, Event::LEFT, Event::EXPIRED])
|
||||||
when EventFilter.issue
|
when ISSUE
|
||||||
events.where(action: [Event::CREATED, Event::UPDATED, Event::CLOSED, Event::REOPENED])
|
events.where(action: [Event::CREATED, Event::UPDATED, Event::CLOSED, Event::REOPENED])
|
||||||
|
else
|
||||||
|
events
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# rubocop: enable CodeReuse/ActiveRecord
|
# rubocop: enable CodeReuse/ActiveRecord
|
||||||
|
|
||||||
def options(key)
|
|
||||||
filter = params.dup
|
|
||||||
|
|
||||||
if filter.include? key
|
|
||||||
filter.delete key
|
|
||||||
else
|
|
||||||
filter << key
|
|
||||||
end
|
|
||||||
|
|
||||||
filter
|
|
||||||
end
|
|
||||||
|
|
||||||
def active?(key)
|
|
||||||
if params.present?
|
|
||||||
params.include? key
|
|
||||||
else
|
|
||||||
key == EventFilter.all
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ module QA
|
||||||
module Project
|
module Project
|
||||||
class Activity < Page::Base
|
class Activity < Page::Base
|
||||||
view 'app/views/shared/_event_filter.html.haml' do
|
view 'app/views/shared/_event_filter.html.haml' do
|
||||||
element :push_events, "event_filter_link EventFilter.push, _('Push events')"
|
element :push_events, "event_filter_link EventFilter::PUSH, _('Push events')"
|
||||||
end
|
end
|
||||||
|
|
||||||
def go_to_push_events
|
def go_to_push_events
|
||||||
|
|
|
@ -24,7 +24,7 @@ FactoryBot.define do
|
||||||
|
|
||||||
factory :push_event, class: PushEvent do
|
factory :push_event, class: PushEvent do
|
||||||
project factory: :project_empty_repo
|
project factory: :project_empty_repo
|
||||||
author factory: :user
|
author(factory: :user) { project.creator }
|
||||||
action Event::PUSHED
|
action Event::PUSHED
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,10 @@ require 'spec_helper'
|
||||||
describe 'Projects > Activity > User sees activity' do
|
describe 'Projects > Activity > User sees activity' do
|
||||||
let(:project) { create(:project, :repository, :public) }
|
let(:project) { create(:project, :repository, :public) }
|
||||||
let(:user) { project.creator }
|
let(:user) { project.creator }
|
||||||
|
let(:issue) { create(:issue, project: project) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
create(:event, :created, project: project, target: issue, author: user)
|
||||||
event = create(:push_event, project: project, author: user)
|
event = create(:push_event, project: project, author: user)
|
||||||
create(:push_event_payload,
|
create(:push_event_payload,
|
||||||
event: event,
|
event: event,
|
||||||
|
@ -12,10 +14,18 @@ describe 'Projects > Activity > User sees activity' do
|
||||||
commit_to: '6d394385cf567f80a8fd85055db1ab4c5295806f',
|
commit_to: '6d394385cf567f80a8fd85055db1ab4c5295806f',
|
||||||
ref: 'fix',
|
ref: 'fix',
|
||||||
commit_count: 1)
|
commit_count: 1)
|
||||||
visit activity_project_path(project)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows the last push in the activity page', :js do
|
it 'shows the last push in the activity page', :js do
|
||||||
|
visit activity_project_path(project)
|
||||||
|
|
||||||
expect(page).to have_content "#{user.name} pushed new branch fix"
|
expect(page).to have_content "#{user.name} pushed new branch fix"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'allows to filter event with the "event_filter=issue" URL param', :js do
|
||||||
|
visit activity_project_path(project, event_filter: 'issue')
|
||||||
|
|
||||||
|
expect(page).not_to have_content "#{user.name} pushed new branch fix"
|
||||||
|
expect(page).to have_content "#{user.name} opened issue #{issue.to_reference}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,58 +1,119 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe EventFilter do
|
describe EventFilter do
|
||||||
|
describe 'FILTERS' do
|
||||||
|
it 'returns a definite list of filters' do
|
||||||
|
expect(described_class::FILTERS).to eq(%w[all push merged issue comments team])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#filter' do
|
||||||
|
it 'returns "all" if given filter is nil' do
|
||||||
|
expect(described_class.new(nil).filter).to eq(described_class::ALL)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns "all" if given filter is ""' do
|
||||||
|
expect(described_class.new('').filter).to eq(described_class::ALL)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns "all" if given filter is "foo"' do
|
||||||
|
expect(described_class.new('foo').filter).to eq('all')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#apply_filter' do
|
describe '#apply_filter' do
|
||||||
let(:source_user) { create(:user) }
|
set(:public_project) { create(:project, :public) }
|
||||||
let!(:public_project) { create(:project, :public) }
|
|
||||||
|
|
||||||
let!(:push_event) { create(:push_event, project: public_project, author: source_user) }
|
set(:push_event) { create(:push_event, project: public_project) }
|
||||||
let!(:merged_event) { create(:event, :merged, project: public_project, target: public_project, author: source_user) }
|
set(:merged_event) { create(:event, :merged, project: public_project, target: public_project) }
|
||||||
let!(:created_event) { create(:event, :created, project: public_project, target: public_project, author: source_user) }
|
set(:created_event) { create(:event, :created, project: public_project, target: public_project) }
|
||||||
let!(:updated_event) { create(:event, :updated, project: public_project, target: public_project, author: source_user) }
|
set(:updated_event) { create(:event, :updated, project: public_project, target: public_project) }
|
||||||
let!(:closed_event) { create(:event, :closed, project: public_project, target: public_project, author: source_user) }
|
set(:closed_event) { create(:event, :closed, project: public_project, target: public_project) }
|
||||||
let!(:reopened_event) { create(:event, :reopened, project: public_project, target: public_project, author: source_user) }
|
set(:reopened_event) { create(:event, :reopened, project: public_project, target: public_project) }
|
||||||
let!(:comments_event) { create(:event, :commented, project: public_project, target: public_project, author: source_user) }
|
set(:comments_event) { create(:event, :commented, project: public_project, target: public_project) }
|
||||||
let!(:joined_event) { create(:event, :joined, project: public_project, target: public_project, author: source_user) }
|
set(:joined_event) { create(:event, :joined, project: public_project, target: public_project) }
|
||||||
let!(:left_event) { create(:event, :left, project: public_project, target: public_project, author: source_user) }
|
set(:left_event) { create(:event, :left, project: public_project, target: public_project) }
|
||||||
|
|
||||||
it 'applies push filter' do
|
let(:filtered_events) { described_class.new(filter).apply_filter(Event.all) }
|
||||||
events = described_class.new(described_class.push).apply_filter(Event.all)
|
|
||||||
expect(events).to contain_exactly(push_event)
|
context 'with the "push" filter' do
|
||||||
|
let(:filter) { described_class::PUSH }
|
||||||
|
|
||||||
|
it 'filters push events only' do
|
||||||
|
expect(filtered_events).to contain_exactly(push_event)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'applies merged filter' do
|
context 'with the "merged" filter' do
|
||||||
events = described_class.new(described_class.merged).apply_filter(Event.all)
|
let(:filter) { described_class::MERGED }
|
||||||
expect(events).to contain_exactly(merged_event)
|
|
||||||
|
it 'filters merged events only' do
|
||||||
|
expect(filtered_events).to contain_exactly(merged_event)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'applies issue filter' do
|
context 'with the "issue" filter' do
|
||||||
events = described_class.new(described_class.issue).apply_filter(Event.all)
|
let(:filter) { described_class::ISSUE }
|
||||||
expect(events).to contain_exactly(created_event, updated_event, closed_event, reopened_event)
|
|
||||||
|
it 'filters issue events only' do
|
||||||
|
expect(filtered_events).to contain_exactly(created_event, updated_event, closed_event, reopened_event)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'applies comments filter' do
|
context 'with the "comments" filter' do
|
||||||
events = described_class.new(described_class.comments).apply_filter(Event.all)
|
let(:filter) { described_class::COMMENTS }
|
||||||
expect(events).to contain_exactly(comments_event)
|
|
||||||
|
it 'filters comment events only' do
|
||||||
|
expect(filtered_events).to contain_exactly(comments_event)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'applies team filter' do
|
context 'with the "team" filter' do
|
||||||
events = described_class.new(described_class.team).apply_filter(Event.all)
|
let(:filter) { described_class::TEAM }
|
||||||
expect(events).to contain_exactly(joined_event, left_event)
|
|
||||||
|
it 'filters team events only' do
|
||||||
|
expect(filtered_events).to contain_exactly(joined_event, left_event)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'applies all filter' do
|
context 'with the "all" filter' do
|
||||||
events = described_class.new(described_class.all).apply_filter(Event.all)
|
let(:filter) { described_class::ALL }
|
||||||
expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event)
|
|
||||||
|
it 'returns all events' do
|
||||||
|
expect(filtered_events).to eq(Event.all)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'applies no filter' do
|
context 'with an unknown filter' do
|
||||||
events = described_class.new(nil).apply_filter(Event.all)
|
let(:filter) { 'foo' }
|
||||||
expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event)
|
|
||||||
|
it 'returns all events' do
|
||||||
|
expect(filtered_events).to eq(Event.all)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'applies unknown filter' do
|
context 'with a nil filter' do
|
||||||
events = described_class.new('').apply_filter(Event.all)
|
let(:filter) { nil }
|
||||||
expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event)
|
|
||||||
|
it 'returns all events' do
|
||||||
|
expect(filtered_events).to eq(Event.all)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#active?' do
|
||||||
|
let(:event_filter) { described_class.new(described_class::TEAM) }
|
||||||
|
|
||||||
|
it 'returns false if filter does not include the given key' do
|
||||||
|
expect(event_filter.active?('foo')).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns false if the given key is nil' do
|
||||||
|
expect(event_filter.active?(nil)).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns true if filter does not include the given key' do
|
||||||
|
expect(event_filter.active?(described_class::TEAM)).to eq(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,7 +41,7 @@ describe EventCollection do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'allows filtering of events using an EventFilter' do
|
it 'allows filtering of events using an EventFilter' do
|
||||||
filter = EventFilter.new(EventFilter.issue)
|
filter = EventFilter.new(EventFilter::ISSUE)
|
||||||
events = described_class.new(projects, filter: filter).to_a
|
events = described_class.new(projects, filter: filter).to_a
|
||||||
|
|
||||||
expect(events.length).to eq(1)
|
expect(events.length).to eq(1)
|
||||||
|
|
Loading…
Reference in New Issue