Added member search/filter UI to the members-activity screen

refs https://github.com/TryGhost/Team/issues/1290

- renamed `@updateExcludedEvents` to `@onChange` and updated associated action name so we have consistent naming for our select-like components
- added `<MembersActivity::MemberFilter>` component
  - utilises `<PowerSelect>` with a custom trigger component and  and a debounced search via the member's API
  - does not use `<PowerSelect>`'s default "selected" behaviour in favor of replacing the select with a button to provide a clearer "reset filter" UX that's easier to build/style outside of the power-select components
  - added `.ember-power-select-trigger-reset` class to reset margins, paddings, borders, and heights so that it's easier for a custom trigger's contents to control the display
This commit is contained in:
Kevin Ansfield 2022-01-27 14:59:12 +00:00
parent 21b4b15a1c
commit 98eb75ef06
7 changed files with 74 additions and 4 deletions

View File

@ -44,6 +44,6 @@ export default class MembersActivityEventTypeFilter extends Component {
const excludeString = Array.from(excludedEvents).join(',');
this.args.updateExcludedEvents(excludeString || null);
this.args.onChange(excludeString || null);
}
}

View File

@ -0,0 +1 @@
<div class="gh-btn"><span>Filter member {{svg-jar "arrow-down-small"}}</span></div>

View File

@ -0,0 +1,26 @@
{{#if @selected}}
<div class="gh-btn" {{on "click" (fn @onChange null)}}>
<span class="gh-btn-label-green">
{{@selected.name}}
&times;
</span>
</div>
{{else}}
<div class="gh-contentfilter-menu {{if @selected "gh-contentfilter-selected"}}">
<PowerSelect
@searchEnabled={{true}}
@search={{perform this.searchMembersTask}}
@selected={{@selected}}
@onChange={{@onChange}}
@matchTriggerWidth={{false}}
@triggerComponent="members-activity/member-filter-trigger"
@triggerClass="ember-power-select-trigger-reset"
@dropdownClass="gh-contentfilter-menu-dropdown"
@horizontalPosition="right"
as |member|
>
<strong>{{member.name}}</strong><br>
{{member.email}}
</PowerSelect>
</div>
{{/if}}

View File

@ -0,0 +1,20 @@
import Component from '@glimmer/component';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';
import {task, timeout} from 'ember-concurrency';
export default class MembersActivityMemberFilter extends Component {
@service store;
@action
clear() {
this.args.onChange(null);
}
@task
*searchMembersTask(term) {
yield timeout(300); // debounce
return yield this.store.query('member', {search: term, limit: 20});
}
}

View File

@ -32,10 +32,15 @@ export default class MembersActivityController extends Controller {
}
@action
updateExcludedEvents(newList) {
changeExcludedEvents(newList) {
this.router.transitionTo({queryParams: {excludedEvents: newList}});
}
@action
changeMember(member) {
this.router.transitionTo({queryParams: {member: member?.id}});
}
_getTypeFilter() {
let excludedEvents = this.member ?
new Set() :

View File

@ -179,6 +179,20 @@
color: var(--darkgrey);
}
/* Reset - Useful for custom trigger components */
.ember-power-select-trigger-reset {
padding: 0;
border: none;
border-radius: unset;
line-height: 0;
min-height: fit-content;
}
.ember-power-select-trigger-reset:focus,
.ember-power-select-trigger-reset--active {
border: none;
}
/*
HACK: ember-power-select has no separate class for the loading message
Issue: https://github.com/cibernox/ember-power-select/issues/479
@ -376,4 +390,4 @@
width: 1.4rem;
height: 1.4rem;
fill: var(--green-d1)
}
}

View File

@ -13,7 +13,11 @@
<MembersActivity::EventTypeFilter
@excludedEvents={{this.excludedEvents}}
@hideMemberOnlyEvents={{not this.member}}
@updateExcludedEvents={{this.updateExcludedEvents}} />
@onChange={{this.changeExcludedEvents}} />
<MembersActivity::MemberFilter
@selected={{this.memberRecord}}
@onChange={{this.changeMember}} />
</div>
</div>
</GhCanvasHeader>