summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipa Lacerda <filipa@gitlab.com>2019-02-06 12:19:00 +0000
committerFilipa Lacerda <filipa@gitlab.com>2019-02-06 12:19:00 +0000
commit5bfa8e2f5e03849645570ba8c2dbfcc5c834f1b1 (patch)
treeb8a5f15796039af3f659f74cbc131c401818be9b
parent3b4c4095bbda55ae0b4d32f9b17c0e4f03c5ceed (diff)
parentd279cc94088fddd6f6bb2847e456bbf68ae616ea (diff)
downloadgitlab-ce-5bfa8e2f5e03849645570ba8c2dbfcc5c834f1b1.tar.gz
Merge branch '43681-display-last-activity-and-created-at-datetimes-for-users-in-admin-users' into 'master'
Resolve "Display last activity and created at datetimes for users" Closes #43681 See merge request gitlab-org/gitlab-ce!24181
-rw-r--r--app/helpers/sorting_helper.rb20
-rw-r--r--app/helpers/users_helper.rb9
-rw-r--r--app/models/user.rb4
-rw-r--r--app/views/admin/users/_user.html.haml55
-rw-r--r--app/views/admin/users/_user_detail.html.haml17
-rw-r--r--app/views/admin/users/index.html.haml96
-rw-r--r--changelogs/unreleased/43681-display-last-activity-and-created-at-datetimes-for-users-in-admin-users.yml5
-rw-r--r--config/locales/de.yml1
-rw-r--r--config/locales/en.yml1
-rw-r--r--config/locales/es.yml1
-rw-r--r--locale/gitlab.pot72
-rw-r--r--spec/features/admin/admin_users_spec.rb42
-rw-r--r--spec/helpers/users_helper_spec.rb68
-rw-r--r--spec/support/helpers/features/responsive_table_helpers.rb32
14 files changed, 346 insertions, 77 deletions
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
index 02762897c89..07ec129dea3 100644
--- a/app/helpers/sorting_helper.rb
+++ b/app/helpers/sorting_helper.rb
@@ -128,7 +128,9 @@ module SortingHelper
sort_value_recently_created => sort_title_recently_created,
sort_value_oldest_created => sort_title_oldest_created,
sort_value_recently_updated => sort_title_recently_updated,
- sort_value_oldest_updated => sort_title_oldest_updated
+ sort_value_oldest_updated => sort_title_oldest_updated,
+ sort_value_recently_last_activity => sort_title_recently_last_activity,
+ sort_value_oldest_last_activity => sort_title_oldest_last_activity
}
end
@@ -317,6 +319,14 @@ module SortingHelper
s_('SortOptions|Most stars')
end
+ def sort_title_oldest_last_activity
+ s_('SortOptions|Oldest last activity')
+ end
+
+ def sort_title_recently_last_activity
+ s_('SortOptions|Recent last activity')
+ end
+
# Values.
def sort_value_access_level_asc
'access_level_asc'
@@ -445,4 +455,12 @@ module SortingHelper
def sort_value_most_stars
'stars_desc'
end
+
+ def sort_value_oldest_last_activity
+ 'last_activity_on_asc'
+ end
+
+ def sort_value_recently_last_activity
+ 'last_activity_on_desc'
+ end
end
diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb
index 73c1402eae5..73ca17c6605 100644
--- a/app/helpers/users_helper.rb
+++ b/app/helpers/users_helper.rb
@@ -74,6 +74,15 @@ module UsersHelper
Gitlab.config.gitlab.impersonation_enabled
end
+ def user_badges_in_admin_section(user)
+ [].tap do |badges|
+ badges << { text: s_('AdminUsers|Blocked'), variant: 'danger' } if user.blocked?
+ badges << { text: s_('AdminUsers|Admin'), variant: 'success' } if user.admin?
+ badges << { text: s_('AdminUsers|External'), variant: 'secondary' } if user.external?
+ badges << { text: s_("AdminUsers|It's you!"), variant: nil } if current_user == user
+ end
+ end
+
private
def get_profile_tabs
diff --git a/app/models/user.rb b/app/models/user.rb
index 691abe3175f..9c091ac366c 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -267,6 +267,8 @@ class User < ApplicationRecord
scope :without_projects, -> { joins('LEFT JOIN project_authorizations ON users.id = project_authorizations.user_id').where(project_authorizations: { user_id: nil }) }
scope :order_recent_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('current_sign_in_at', 'DESC')) }
scope :order_oldest_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('current_sign_in_at', 'ASC')) }
+ scope :order_recent_last_activity, -> { reorder(Gitlab::Database.nulls_last_order('last_activity_on', 'DESC')) }
+ scope :order_oldest_last_activity, -> { reorder(Gitlab::Database.nulls_first_order('last_activity_on', 'ASC')) }
scope :confirmed, -> { where.not(confirmed_at: nil) }
scope :by_username, -> (usernames) { iwhere(username: Array(usernames).map(&:to_s)) }
scope :for_todos, -> (todos) { where(id: todos.select(:user_id)) }
@@ -337,6 +339,8 @@ class User < ApplicationRecord
case order_method.to_s
when 'recent_sign_in' then order_recent_sign_in
when 'oldest_sign_in' then order_oldest_sign_in
+ when 'last_activity_on_desc' then order_recent_last_activity
+ when 'last_activity_on_asc' then order_oldest_last_activity
else
order_by(order_method)
end
diff --git a/app/views/admin/users/_user.html.haml b/app/views/admin/users/_user.html.haml
index a4e2c3252af..be7bfa958b2 100644
--- a/app/views/admin/users/_user.html.haml
+++ b/app/views/admin/users/_user.html.haml
@@ -1,36 +1,37 @@
-%li.flex-row
- .user-avatar
- = image_tag avatar_icon_for_user(user), class: "avatar", alt: ''
- .row-main-content
- .user-name.row-title.str-truncated-100
- = link_to user.name, [:admin, user], class: "js-user-link", data: { user_id: user.id }
- - if user.blocked?
- %span.badge.badge-danger blocked
- - if user.admin?
- %span.badge.badge-success Admin
- - if user.external?
- %span.badge.badge-secondary External
- - if user == current_user
- %span It's you!
- .row-second-line.str-truncated-100
- = mail_to user.email, user.email
- .controls
- = link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: 'btn'
- - unless user == current_user
- .dropdown.inline
- %a.dropdown-new.btn.btn-default#project-settings-button{ href: '#', data: { toggle: 'dropdown' } }
+.gl-responsive-table-row{ role: 'row' }
+ .table-section.section-40
+ .table-mobile-header{ role: 'rowheader' }
+ = _('Name')
+ .table-mobile-content
+ = render 'user_detail', user: user
+ .table-section.section-25
+ .table-mobile-header{ role: 'rowheader' }
+ = _('Created on')
+ .table-mobile-content
+ = l(user.created_at.to_date, format: :admin)
+ .table-section.section-15
+ .table-mobile-header{ role: 'rowheader' }
+ = _('Last activity')
+ .table-mobile-content
+ = user.last_activity_on.nil? ? _('Never') : l(user.last_activity_on, format: :admin)
+ .table-section.section-20.table-button-footer
+ .table-action-buttons
+ = link_to _('Edit'), edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: 'btn btn-default'
+ - unless user == current_user
+ %button.dropdown-new.btn.btn-default{ type: 'button', data: { toggle: 'dropdown' } }
= icon('cog')
= icon('caret-down')
%ul.dropdown-menu.dropdown-menu-right
%li.dropdown-header
- Settings
+ = _('Settings')
%li
- if user.ldap_blocked?
- %span.small Cannot unblock LDAP blocked users
+ %span.small
+ = s_('AdminUsers|Cannot unblock LDAP blocked users')
- elsif user.blocked?
- = link_to 'Unblock', unblock_admin_user_path(user), method: :put
+ = link_to _('Unblock'), unblock_admin_user_path(user), method: :put
- else
- = link_to 'Block', block_admin_user_path(user), data: { confirm: 'USER WILL BE BLOCKED! Are you sure?' }, method: :put
+ = link_to _('Block'), block_admin_user_path(user), data: { confirm: "#{s_('AdminUsers|User will be blocked').upcase}! #{_('Are you sure')}?" }, method: :put
- if user.access_locked?
%li
= link_to _('Unlock'), unlock_admin_user_path(user), method: :put, data: { confirm: _('Are you sure?') }
@@ -42,7 +43,7 @@
target: '#delete-user-modal',
delete_user_url: admin_user_path(user),
block_user_url: block_admin_user_path(user),
- username: user.name,
+ username: sanitize_name(user.name),
delete_contributions: false }, type: 'button' }
= s_('AdminUsers|Delete user')
@@ -51,6 +52,6 @@
target: '#delete-user-modal',
delete_user_url: admin_user_path(user, hard_delete: true),
block_user_url: block_admin_user_path(user),
- username: user.name,
+ username: sanitize_name(user.name),
delete_contributions: true }, type: 'button' }
= s_('AdminUsers|Delete user and contributions')
diff --git a/app/views/admin/users/_user_detail.html.haml b/app/views/admin/users/_user_detail.html.haml
new file mode 100644
index 00000000000..3319b4bad3a
--- /dev/null
+++ b/app/views/admin/users/_user_detail.html.haml
@@ -0,0 +1,17 @@
+.flex-list
+ .flex-row
+ = image_tag avatar_icon_for_user(user), class: 'avatar s32 d-none d-md-flex', alt: _('Avatar for %{name}') % { name: sanitize_name(user.name) }
+ .row-main-content
+ .row-title.str-truncated-100
+ = image_tag avatar_icon_for_user(user), class: 'avatar s16 d-xs-flex d-md-none mr-1 prepend-top-2', alt: _('Avatar for %{name}') % { name: sanitize_name(user.name) }
+ = link_to user.name, admin_user_path(user), class: 'text-plain js-user-link', data: { user_id: user.id }
+
+ = render_if_exists 'admin/users/user_detail_note', user: user
+
+ - user_badges_in_admin_section(user).each do |badge|
+ - css_badge = "badge badge-#{badge[:variant]}" if badge[:variant].present?
+ %span{ class: css_badge }
+ = badge[:text]
+
+ .row-second-line.str-truncated-100
+ = mail_to user.email, user.email, class: 'text-secondary'
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 600120c4f05..c3d5ce0fe70 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -2,72 +2,78 @@
- page_title "Users"
%div{ class: container_class }
- .prepend-top-default
+ .top-area.scrolling-tabs-container.inner-page-scroll-tabs
+ .fade-left
+ = icon('angle-left')
+ .fade-right
+ = icon('angle-right')
+ %ul.nav-links.nav.nav-tabs.scrolling-tabs
+ = nav_link(html_options: { class: active_when(params[:filter].nil?) }) do
+ = link_to admin_users_path do
+ = s_('AdminUsers|Active')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.active)
+ = nav_link(html_options: { class: active_when(params[:filter] == 'admins') }) do
+ = link_to admin_users_path(filter: "admins") do
+ = s_('AdminUsers|Admins')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.admins)
+ = nav_link(html_options: { class: "#{active_when(params[:filter] == 'two_factor_enabled')} filter-two-factor-enabled" }) do
+ = link_to admin_users_path(filter: 'two_factor_enabled') do
+ = s_('AdminUsers|2FA Enabled')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.with_two_factor)
+ = nav_link(html_options: { class: "#{active_when(params[:filter] == 'two_factor_disabled')} filter-two-factor-disabled" }) do
+ = link_to admin_users_path(filter: 'two_factor_disabled') do
+ = s_('AdminUsers|2FA Disabled')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.without_two_factor)
+ = nav_link(html_options: { class: active_when(params[:filter] == 'external') }) do
+ = link_to admin_users_path(filter: 'external') do
+ = s_('AdminUsers|External')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.external)
+ = nav_link(html_options: { class: active_when(params[:filter] == 'blocked') }) do
+ = link_to admin_users_path(filter: "blocked") do
+ = s_('AdminUsers|Blocked')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.blocked)
+ = nav_link(html_options: { class: active_when(params[:filter] == 'wop') }) do
+ = link_to admin_users_path(filter: "wop") do
+ = s_('AdminUsers|Without projects')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.without_projects)
+ .nav-controls
+ = render_if_exists 'admin/users/admin_email_users'
+ = link_to s_('AdminUsers|New user'), new_admin_user_path, class: 'btn btn-success btn-search float-right'
+
+ .filtered-search-block.row-content-block.border-top-0
= form_tag admin_users_path, method: :get do
- if params[:filter].present?
= hidden_field_tag "filter", h(params[:filter])
.search-holder
.search-field-holder
- = search_field_tag :search_query, params[:search_query], placeholder: 'Search by name, email or username', class: 'form-control search-text-input js-search-input', spellcheck: false
+ = search_field_tag :search_query, params[:search_query], placeholder: s_('AdminUsers|Search by name, email or username'), class: 'form-control search-text-input js-search-input', spellcheck: false
- if @sort.present?
= hidden_field_tag :sort, @sort
= icon("search", class: "search-icon")
- = button_tag 'Search users' if Rails.env.test?
+ = button_tag s_('AdminUsers|Search users') if Rails.env.test?
.dropdown.user-sort-dropdown
- toggle_text = if @sort.present? then users_sort_options_hash[@sort] else sort_title_name end
= dropdown_toggle(toggle_text, { toggle: 'dropdown' })
%ul.dropdown-menu.dropdown-menu-right
%li.dropdown-header
- Sort by
+ = s_('AdminUsers|Sort by')
%li
- users_sort_options_hash.each do |value, title|
= link_to admin_users_path(sort: value, filter: params[:filter], search_query: params[:search_query]) do
= title
- = link_to 'New user', new_admin_user_path, class: 'btn btn-success btn-search'
- .top-area.scrolling-tabs-container.inner-page-scroll-tabs
- .fade-left
- = icon('angle-left')
- .fade-right
- = icon('angle-right')
- %ul.nav-links.nav.nav-tabs.scrolling-tabs
- = nav_link(html_options: { class: active_when(params[:filter].nil?) }) do
- = link_to admin_users_path do
- Active
- %small.badge.badge-pill= limited_counter_with_delimiter(User.active)
- = nav_link(html_options: { class: active_when(params[:filter] == 'admins') }) do
- = link_to admin_users_path(filter: "admins") do
- Admins
- %small.badge.badge-pill= limited_counter_with_delimiter(User.admins)
- = nav_link(html_options: { class: "#{active_when(params[:filter] == 'two_factor_enabled')} filter-two-factor-enabled" }) do
- = link_to admin_users_path(filter: 'two_factor_enabled') do
- 2FA Enabled
- %small.badge.badge-pill= limited_counter_with_delimiter(User.with_two_factor)
- = nav_link(html_options: { class: "#{active_when(params[:filter] == 'two_factor_disabled')} filter-two-factor-disabled" }) do
- = link_to admin_users_path(filter: 'two_factor_disabled') do
- 2FA Disabled
- %small.badge.badge-pill= limited_counter_with_delimiter(User.without_two_factor)
- = nav_link(html_options: { class: active_when(params[:filter] == 'external') }) do
- = link_to admin_users_path(filter: 'external') do
- External
- %small.badge.badge-pill= limited_counter_with_delimiter(User.external)
- = nav_link(html_options: { class: active_when(params[:filter] == 'blocked') }) do
- = link_to admin_users_path(filter: "blocked") do
- Blocked
- %small.badge.badge-pill= limited_counter_with_delimiter(User.blocked)
- = nav_link(html_options: { class: active_when(params[:filter] == 'wop') }) do
- = link_to admin_users_path(filter: "wop") do
- Without projects
- %small.badge.badge-pill= limited_counter_with_delimiter(User.without_projects)
+ - if @users.empty?
+ .nothing-here-block.border-top-0
+ = s_('AdminUsers|No users found')
+ - else
+ .table-holder
+ .thead-white.text-nowrap.gl-responsive-table-row.table-row-header{ role: 'row' }
+ .table-section.section-40{ role: 'rowheader' }= _('Name')
+ .table-section.section-25{ role: 'rowheader' }= _('Created on')
+ .table-section.section-15{ role: 'rowheader' }= _('Last activity')
- %ul.flex-list.content-list
- - if @users.empty?
- %li
- .nothing-here-block No users found.
- - else
= render partial: 'admin/users/user', collection: @users
= paginate @users, theme: "gitlab"
#delete-user-modal
-
diff --git a/changelogs/unreleased/43681-display-last-activity-and-created-at-datetimes-for-users-in-admin-users.yml b/changelogs/unreleased/43681-display-last-activity-and-created-at-datetimes-for-users-in-admin-users.yml
new file mode 100644
index 00000000000..0fbf6314a27
--- /dev/null
+++ b/changelogs/unreleased/43681-display-last-activity-and-created-at-datetimes-for-users-in-admin-users.yml
@@ -0,0 +1,5 @@
+---
+title: Display last activity and created at datetimes for users
+merge_request: 24181
+author:
+type: added
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 38c3711c6c7..554e9913faa 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -43,6 +43,7 @@ de:
default: "%d.%m.%Y"
long: "%e. %B %Y"
short: "%e. %b"
+ admin: "%e %b, %Y"
month_names:
-
- Januar
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 0a43a1d9a6b..e8dbc033a7c 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -55,6 +55,7 @@ en:
default: "%Y-%m-%d"
long: "%B %d, %Y"
short: "%b %d"
+ admin: "%e %b, %Y"
month_names:
-
- January
diff --git a/config/locales/es.yml b/config/locales/es.yml
index fdc52b4ae11..78c07583933 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -42,6 +42,7 @@ es:
default: "%d/%m/%Y"
long: "%d de %B de %Y"
short: "%d de %b"
+ admin: "%e %b, %Y"
month_names:
-
- enero
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 1caf263b9f3..9ec590f90d8 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -468,9 +468,30 @@ msgstr ""
msgid "AdminSettings|When creating a new environment variable it will be protected by default."
msgstr ""
+msgid "AdminUsers|2FA Disabled"
+msgstr ""
+
+msgid "AdminUsers|2FA Enabled"
+msgstr ""
+
+msgid "AdminUsers|Active"
+msgstr ""
+
+msgid "AdminUsers|Admin"
+msgstr ""
+
+msgid "AdminUsers|Admins"
+msgstr ""
+
msgid "AdminUsers|Block user"
msgstr ""
+msgid "AdminUsers|Blocked"
+msgstr ""
+
+msgid "AdminUsers|Cannot unblock LDAP blocked users"
+msgstr ""
+
msgid "AdminUsers|Delete User %{username} and contributions?"
msgstr ""
@@ -483,12 +504,39 @@ msgstr ""
msgid "AdminUsers|Delete user and contributions"
msgstr ""
+msgid "AdminUsers|External"
+msgstr ""
+
+msgid "AdminUsers|It's you!"
+msgstr ""
+
+msgid "AdminUsers|New user"
+msgstr ""
+
+msgid "AdminUsers|No users found"
+msgstr ""
+
+msgid "AdminUsers|Search by name, email or username"
+msgstr ""
+
+msgid "AdminUsers|Search users"
+msgstr ""
+
+msgid "AdminUsers|Sort by"
+msgstr ""
+
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
msgid "AdminUsers|To confirm, type %{username}"
msgstr ""
+msgid "AdminUsers|User will be blocked"
+msgstr ""
+
+msgid "AdminUsers|Without projects"
+msgstr ""
+
msgid "Advanced permissions, Large File Storage and Two-Factor authentication settings."
msgstr ""
@@ -711,6 +759,9 @@ msgstr ""
msgid "Archived projects"
msgstr ""
+msgid "Are you sure"
+msgstr ""
+
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr ""
@@ -909,6 +960,9 @@ msgstr ""
msgid "Avatar for %{assigneeName}"
msgstr ""
+msgid "Avatar for %{name}"
+msgstr ""
+
msgid "Avatar will be removed. Are you sure?"
msgstr ""
@@ -1014,6 +1068,9 @@ msgstr ""
msgid "Bitbucket import"
msgstr ""
+msgid "Block"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -2348,6 +2405,9 @@ msgstr ""
msgid "Created by me"
msgstr ""
+msgid "Created on"
+msgstr ""
+
msgid "Created on:"
msgstr ""
@@ -4124,6 +4184,9 @@ msgstr[1] ""
msgid "Last Pipeline"
msgstr ""
+msgid "Last activity"
+msgstr ""
+
msgid "Last commit"
msgstr ""
@@ -6668,6 +6731,9 @@ msgstr ""
msgid "SortOptions|Oldest joined"
msgstr ""
+msgid "SortOptions|Oldest last activity"
+msgstr ""
+
msgid "SortOptions|Oldest sign in"
msgstr ""
@@ -6680,6 +6746,9 @@ msgstr ""
msgid "SortOptions|Priority"
msgstr ""
+msgid "SortOptions|Recent last activity"
+msgstr ""
+
msgid "SortOptions|Recent sign in"
msgstr ""
@@ -7668,6 +7737,9 @@ msgstr ""
msgid "Unable to load the diff. %{button_try_again}"
msgstr ""
+msgid "Unblock"
+msgstr ""
+
msgid "Undo"
msgstr ""
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index 931095936a6..b1c6f308bc6 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
describe "Admin::Users" do
- include Spec::Support::Helpers::Features::ListRowsHelpers
+ include Spec::Support::Helpers::Features::ResponsiveTableHelpers
let!(:user) do
create(:omniauth_user, provider: 'twitter', extern_uid: '123456')
end
- let!(:current_user) { create(:admin) }
+ let!(:current_user) { create(:admin, last_activity_on: 5.days.ago) }
before do
sign_in(current_user)
@@ -25,6 +25,8 @@ describe "Admin::Users" do
it "has users list" do
expect(page).to have_content(current_user.email)
expect(page).to have_content(current_user.name)
+ expect(page).to have_content(current_user.created_at.strftime("%e %b, %Y"))
+ expect(page).to have_content(current_user.last_activity_on.strftime("%e %b, %Y"))
expect(page).to have_content(user.email)
expect(page).to have_content(user.name)
expect(page).to have_link('Block', href: block_admin_user_path(user))
@@ -32,10 +34,24 @@ describe "Admin::Users" do
expect(page).to have_button('Delete user and contributions')
end
+ describe "view extra user information", :js do
+ it 'does not have the user popover open' do
+ expect(page).not_to have_selector('#__BV_popover_1__')
+ end
+
+ it 'shows the user popover on hover' do
+ first_user_link = page.first('.js-user-link')
+
+ first_user_link.hover
+
+ expect(page).to have_selector('#__BV_popover_1__')
+ end
+ end
+
describe 'search and sort' do
before do
- create(:user, name: 'Foo Bar')
- create(:user, name: 'Foo Baz')
+ create(:user, name: 'Foo Bar', last_activity_on: 3.days.ago)
+ create(:user, name: 'Foo Baz', last_activity_on: 2.days.ago)
create(:user, name: 'Dmitriy')
end
@@ -75,6 +91,24 @@ describe "Admin::Users" do
expect(first_row.text).to include('Foo Bar')
expect(second_row.text).to include('Foo Baz')
end
+
+ it 'sorts users by recent last activity' do
+ visit admin_users_path(search_query: 'Foo')
+
+ sort_by('Recent last activity')
+
+ expect(first_row.text).to include('Foo Baz')
+ expect(second_row.text).to include('Foo Bar')
+ end
+
+ it 'sorts users by oldest last activity' do
+ visit admin_users_path(search_query: 'Foo')
+
+ sort_by('Oldest last activity')
+
+ expect(first_row.text).to include('Foo Bar')
+ expect(second_row.text).to include('Foo Baz')
+ end
end
describe 'Two-factor Authentication filters' do
diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb
index ab67a5ab847..f3649495493 100644
--- a/spec/helpers/users_helper_spec.rb
+++ b/spec/helpers/users_helper_spec.rb
@@ -100,4 +100,72 @@ describe UsersHelper do
end
end
end
+
+ describe '#user_badges_in_admin_section' do
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ end
+
+ context 'with a blocked user' do
+ it "returns the blocked badge" do
+ blocked_user = create(:user, state: 'blocked')
+
+ badges = helper.user_badges_in_admin_section(blocked_user)
+
+ expect(badges).to eq([text: "Blocked", variant: "danger"])
+ end
+ end
+
+ context 'with an admin user' do
+ it "returns the admin badge" do
+ admin_user = create(:admin)
+
+ badges = helper.user_badges_in_admin_section(admin_user)
+
+ expect(badges).to eq([text: "Admin", variant: "success"])
+ end
+ end
+
+ context 'with an external user' do
+ it 'returns the external badge' do
+ external_user = create(:user, external: true)
+
+ badges = helper.user_badges_in_admin_section(external_user)
+
+ expect(badges).to eq([text: "External", variant: "secondary"])
+ end
+ end
+
+ context 'with the current user' do
+ it 'returns the "It\'s You" badge' do
+ badges = helper.user_badges_in_admin_section(user)
+
+ expect(badges).to eq([text: "It's you!", variant: nil])
+ end
+ end
+
+ context 'with an external blocked admin' do
+ it 'returns the blocked, admin and external badges' do
+ user = create(:admin, state: 'blocked', external: true)
+
+ badges = helper.user_badges_in_admin_section(user)
+
+ expect(badges).to eq([
+ { text: "Blocked", variant: "danger" },
+ { text: "Admin", variant: "success" },
+ { text: "External", variant: "secondary" }
+ ])
+ end
+ end
+
+ context 'get badges for normal user' do
+ it 'returns no badges' do
+ user = create(:user)
+
+ badges = helper.user_badges_in_admin_section(user)
+
+ expect(badges).to be_empty
+ end
+ end
+ end
end
diff --git a/spec/support/helpers/features/responsive_table_helpers.rb b/spec/support/helpers/features/responsive_table_helpers.rb
new file mode 100644
index 00000000000..7a175219fe9
--- /dev/null
+++ b/spec/support/helpers/features/responsive_table_helpers.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+# These helpers allow you to access rows in a responsive table
+#
+# Usage:
+# describe "..." do
+# include Spec::Support::Helpers::Features::ResponsiveTableHelpers
+# ...
+#
+# expect(first_row.text).to include("John Doe")
+# expect(second_row.text).to include("John Smith")
+#
+# Note:
+# index starts at 1 as index 0 is expected to be the table header
+#
+#
+module Spec
+ module Support
+ module Helpers
+ module Features
+ module ResponsiveTableHelpers
+ def first_row
+ page.all('.gl-responsive-table-row')[1]
+ end
+
+ def second_row
+ page.all('.gl-responsive-table-row')[2]
+ end
+ end
+ end
+ end
+ end
+end