Member index (phase 2) - Search invitations (#17210)
* add ability to search invitations * add an invited scope * add a cypress test
This commit is contained in:
parent
ac7086eff2
commit
b1e7d8a5ec
7 changed files with 73 additions and 10 deletions
|
|
@ -3,7 +3,10 @@ module Admin
|
|||
layout "admin"
|
||||
|
||||
def index
|
||||
@invitations = User.where(registered: false).page(params[:page]).per(50)
|
||||
@invitations = Admin::UsersQuery.call(relation: User.invited,
|
||||
options: params.permit(
|
||||
:search,
|
||||
)).page(params[:page]).per(50)
|
||||
end
|
||||
|
||||
def new; end
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ class User < ApplicationRecord
|
|||
|
||||
scope :eager_load_serialized_data, -> { includes(:roles) }
|
||||
scope :registered, -> { where(registered: true) }
|
||||
scope :invited, -> { where(registered: false) }
|
||||
# Unfortunately pg_search's default SQL query is not performant enough in this
|
||||
# particular case (~ 500ms). There are multiple reasons:
|
||||
# => creates a complex query like `SELECT FROM users INNER JOIN users` to compute ranking.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,16 @@
|
|||
<h1 class="crayons-title ml-3 l:ml-0">Members<span class="screen-reader-only"> (Invitations)</span></h1>
|
||||
<%= render "admin/users/index/tabs" %>
|
||||
</div>
|
||||
<%= render "admin/users/index/controls" %>
|
||||
<div class="flex justify-content-between py-3">
|
||||
<%= form_with url: admin_invitations_path, method: :get, local: true, class:"grow-1" do |f| %>
|
||||
<% render "admin/users/index/search_field", f: f, placeholder: "Search invited members...", aria_label: "Search invited members by name, username, or email" %>
|
||||
<% end %>
|
||||
<div class="flex grow-1 justify-content-end">
|
||||
<%= paginate @invitations, theme: "admin", scope: @invitations, label: "Paginate invitations" %>
|
||||
<%= link_to "Invite member", new_admin_invitation_path, class: "c-cta c-cta--branded self-end" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</header>
|
||||
<table class="crayons-table crayons-table__lowercase" width="100%">
|
||||
<thead>
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
<%= paginate @users, theme: "admin", scope: @users, label: "Paginate users" %>
|
||||
</div>
|
||||
<div>
|
||||
<div id="search-users" class="hidden relative">
|
||||
<%= render "admin/users/index/search_field", f: f %>
|
||||
<div id="search-users" class="hidden">
|
||||
<%= render "admin/users/index/search_field", f: f, placeholder: "Search member...", aria_label: "Search member by name, username, email, or Twitter/GitHub usernames" %>
|
||||
</div>
|
||||
<div id="filter-users" class="hidden crayons-field flex-row items-center gap-2">
|
||||
<%= render "admin/users/index/filter_role_field", f: f %>
|
||||
|
|
@ -30,8 +30,8 @@
|
|||
<!-- Larger screen layout -->
|
||||
<div class="hidden m:flex justify-between">
|
||||
<%= form_with url: admin_users_path, method: :get, local: true, class: "flex flex-col m:flex-row gap-3 m:items-center py-3" do |f| %>
|
||||
<div class="crayons-field flex-1 flex-row items-center gap-2 relative">
|
||||
<%= render "admin/users/index/search_field", f: f %>
|
||||
<div class="crayons-field flex-1 flex-row items-center gap-2">
|
||||
<%= render "admin/users/index/search_field", f: f, placeholder: "Search member...", aria_label: "Search member by name, username, email, or Twitter/GitHub usernames" %>
|
||||
</div>
|
||||
<div class="crayons-field flex-row items-center gap-2">
|
||||
<%= render "admin/users/index/filter_role_field", f: f %>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<%= f.text_field :search, value: params[:search], class: "crayons-textfield mt-0", placeholder: "Search member...", aria: { label: "Search member by name, username, email, or Twitter/GitHub usernames" } %>
|
||||
<button type="submit" aria-label="Search" class="crayons-btn crayons-btn--ghost crayons-btn--s crayons-btn--icon-rounded absolute right-2 bottom-0 top-0 m-1">
|
||||
<%= crayons_icon_tag(:search, aria_hidden: true) %>
|
||||
</button>
|
||||
<div class="relative">
|
||||
<%= f.text_field :search, value: params[:search], class: "crayons-textfield mt-0", placeholder: placeholder, aria: { label: aria_label } %>
|
||||
<button type="submit" aria-label="Search" class="crayons-btn crayons-btn--ghost crayons-btn--s crayons-btn--icon-rounded absolute right-2 bottom-0 top-0 m-1">
|
||||
<%= crayons_icon_tag(:search, aria_hidden: true) %>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
describe('Invited users', () => {
|
||||
beforeEach(() => {
|
||||
cy.testSetup();
|
||||
cy.fixture('users/adminUser.json').as('user');
|
||||
cy.get('@user').then((user) => {
|
||||
cy.loginUser(user)
|
||||
.then(() => cy.enableFeatureFlag('member_index_view'))
|
||||
.then(() =>
|
||||
cy.inviteUser({
|
||||
name: 'Test user',
|
||||
email: 'test@test.com',
|
||||
}),
|
||||
)
|
||||
.then(() => cy.visitAndWaitForUserSideEffects('/admin/invitations'));
|
||||
});
|
||||
});
|
||||
|
||||
it('searches for an invited user', () => {
|
||||
// The single invited user should be visible on the page
|
||||
cy.findByText('test@test.com').should('exist');
|
||||
|
||||
// Search for a term that should match the entry
|
||||
cy.findByRole('textbox', {
|
||||
name: 'Search invited members by name, username, or email',
|
||||
}).type('test');
|
||||
cy.findByRole('button', { name: 'Search' }).click();
|
||||
cy.url().should('contain', 'search=test');
|
||||
cy.findByText('test@test.com').should('exist');
|
||||
|
||||
// Search for a term that shouldn't match the entry
|
||||
cy.findByRole('textbox', {
|
||||
name: 'Search invited members by name, username, or email',
|
||||
})
|
||||
.clear()
|
||||
.type('something');
|
||||
cy.findByRole('button', { name: 'Search' }).click();
|
||||
cy.url().should('contain', 'search=something');
|
||||
cy.findByText('test@test.com').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
|
@ -391,3 +391,11 @@ Cypress.Commands.add(
|
|||
return cy.wrap(subject).invoke('val', color).trigger('input');
|
||||
},
|
||||
);
|
||||
|
||||
Cypress.Commands.add('inviteUser', ({ name, email }) => {
|
||||
return cy.request(
|
||||
'POST',
|
||||
'/admin/invitations',
|
||||
`utf8=%E2%9C%93&user%5Bemail%5D=${email}&user%5Bname%5D=${name}&commit=Invite+User`,
|
||||
);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue