UI: VAULT-21514 filter by message type and status (#25384)

* Working filter

* Refactor action

* Reset query params

* Add filter tests

* Clean up tests

* Add changelog

* Remove extra space

* Address feedback

* Dont reset query params

* Remove changelog
This commit is contained in:
Kianna 2024-02-14 10:28:08 -08:00 committed by GitHub
parent efdaab7279
commit 483da17588
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 136 additions and 21 deletions

View file

@ -11,8 +11,11 @@ export default class MessageAdapter extends ApplicationAdapter {
}
query(store, type, query) {
const { authenticated } = query;
return super.query(store, type, { authenticated, list: true });
const { authenticated, type: messageType, active } = query;
const params = { authenticated, list: true };
if (messageType) params.type = messageType;
if (typeof active === 'boolean') params.active = active;
return super.query(store, type, params);
}
queryRecord(store, type, id) {

View file

@ -9,16 +9,40 @@
@breadcrumbs={{this.breadcrumbs}}
>
<:toolbarFilters>
{{#if @messages.meta.total}}
<FilterInput
aria-label="Search by message title"
placeholder="Search by message title"
id="message-filter"
value={{@pageFilter}}
@autofocus={{true}}
@onInput={{this.onFilterChange}}
<FilterInput
aria-label="Search by message title"
placeholder="Search by message title"
id="message-filter"
value={{@params.pageFilter}}
@autofocus={{true}}
@onInput={{this.onFilterInputChange}}
/>
<div>
<SearchSelect
@id="filter-by-message-status"
class="has-left-margin-s"
@options={{this.statusFilterOptions}}
@selectLimit="1"
@searchEnabled={{false}}
@fallbackComponent="select"
@onChange={{fn this.onFilterChange "status"}}
@placeholder="Filter by message status"
@inputValue={{if @params.status (array @params.status)}}
data-test-filter-by-message-status
/>
{{/if}}
</div>
<SearchSelect
@id="filter-by-message-type"
class="has-left-margin-s"
@options={{this.typeFilterOptions}}
@selectLimit="1"
@searchEnabled={{false}}
@fallbackComponent="select"
@onChange={{fn this.onFilterChange "type"}}
@placeholder="Filter by message type"
@inputValue={{if @params.type (array @params.type)}}
data-test-filter-by-message-type
/>
</:toolbarFilters>
<:toolbarActions>
<Hds::Button
@ -68,7 +92,7 @@
<dd.Interactive @text="Edit" @route="messages.message.edit" @model={{message.id}} />
{{/if}}
{{#if message.canDeleteCustomMessages}}
<dd.Interactive @text="Disable" @color="critical" {{on "click" (fn (mut this.messageToDelete) message)}} />
<dd.Interactive @text="Delete" @color="critical" {{on "click" (fn (mut this.messageToDelete) message)}} />
{{/if}}
</Hds::Dropdown>
{{/if}}

View file

@ -91,6 +91,20 @@ export default class MessagesList extends Component {
return [{ label: 'Messages' }, { label }];
}
get statusFilterOptions() {
return [
{ id: 'active', name: 'active' },
{ id: 'inactive', name: 'inactive' },
];
}
get typeFilterOptions() {
return [
{ id: 'modal', name: 'modal' },
{ id: 'banner', name: 'banner' },
];
}
// callback from HDS pagination to set the queryParams page
get paginationQueryParams() {
return (page) => {
@ -100,6 +114,12 @@ export default class MessagesList extends Component {
};
}
transitionToMessagesWithParams(queryParams) {
this.router.transitionTo('vault.cluster.config-ui.messages', {
queryParams,
});
}
@task
*deleteMessage(message) {
try {
@ -117,10 +137,16 @@ export default class MessagesList extends Component {
}
@action
onFilterChange(pageFilter) {
this.router.transitionTo('vault.cluster.config-ui.messages', {
queryParams: { pageFilter },
});
onFilterInputChange(pageFilter) {
this.transitionToMessagesWithParams({ pageFilter });
}
@action
onFilterChange(filterType, [filterOption]) {
const param = {};
param[filterType] = filterOption;
param.page = 1;
this.transitionToMessagesWithParams(param);
}
@action

View file

@ -5,9 +5,11 @@
import Controller from '@ember/controller';
export default class MessagesController extends Controller {
queryParams = ['authenticated', 'page', 'pageFilter'];
queryParams = ['authenticated', 'page', 'pageFilter', 'status', 'type'];
authenticated = true;
page = 1;
pageFilter = '';
type = null;
status = null;
}

View file

@ -20,17 +20,30 @@ export default class MessagesRoute extends Route {
pageFilter: {
refreshModel: true,
},
status: {
refreshModel: true,
},
type: {
refreshModel: true,
},
};
model(params) {
const { authenticated, page, pageFilter } = params;
const { authenticated, page, pageFilter, status, type } = params;
const filter = pageFilter
? (dataset) => dataset.filter((item) => item?.title.toLowerCase().includes(pageFilter.toLowerCase()))
: null;
let active;
if (status === 'active') active = true;
if (status === 'inactive') active = false;
const messages = this.store
.lazyPaginatedQuery('config-ui/message', {
authenticated,
pageFilter: filter,
active,
type,
responsePath: 'data.keys',
page: page || 1,
size: 10,
@ -42,7 +55,7 @@ export default class MessagesRoute extends Route {
throw e;
});
return hash({
pageFilter,
params,
messages,
});
}
@ -56,6 +69,9 @@ export default class MessagesRoute extends Route {
resetController(controller, isExiting) {
if (isExiting) {
controller.set('pageFilter', null);
controller.set('page', 1);
controller.set('status', null);
controller.set('type', null);
}
}
}

View file

@ -6,5 +6,5 @@
<Messages::Page::List
@messages={{this.model.messages}}
@authenticated={{this.authenticated}}
@pageFilter={{this.model.pageFilter}}
@params={{this.model.params}}
/>

View file

@ -38,7 +38,7 @@
<PowerSelect
@eventType="click"
@placeholder={{@placeholder}}
@searchEnabled={{true}}
@searchEnabled={{this.searchEnabled}}
@search={{this.searchAndSuggest}}
@options={{this.dropdownOptions}}
@onChange={{this.selectOrCreate}}

View file

@ -93,6 +93,11 @@ export default class SearchSelect extends Component {
return this.args.nameKey || 'name';
}
get searchEnabled() {
if (typeof this.args.searchEnabled === 'boolean') return this.args.searchEnabled;
return true;
}
addSearchText(optionsToFormat) {
// maps over array of objects or response from query
return optionsToFormat.toArray().map((option) => {

View file

@ -12,6 +12,7 @@ import logout from 'vault/tests/pages/logout';
import { format, addDays, startOfDay } from 'date-fns';
import { datetimeLocalStringFormat } from 'core/utils/date-formatters';
import { PAGE } from 'vault/tests/helpers/config-ui/message-selectors';
import { clickTrigger } from 'ember-power-select/test-support/helpers';
module('Acceptance | config-ui', function (hooks) {
setupApplicationTest(hooks);
@ -93,6 +94,44 @@ module('Acceptance | config-ui', function (hooks) {
await click(PAGE.confirmButton);
assert.dom('[data-test-component="empty-state"]').exists('Message was deleted');
});
test('it should filter by type and status', async function (assert) {
assert.expect(6);
await this.createMessage('banner', null);
await this.createMessage('banner');
await visit('vault/config-ui/messages');
// check number of messages with status filters
await clickTrigger('#filter-by-message-status');
await click('.ember-power-select-options [data-option-index="0"]');
assert.dom('.linked-block').exists({ count: 1 }, 'filtered by active');
await click('[data-test-selected-list-button="delete"]');
await clickTrigger('#filter-by-message-status');
await click('.ember-power-select-options [data-option-index="1"]');
assert.dom('.linked-block').exists({ count: 1 }, 'filtered by inactive');
await click('[data-test-selected-list-button="delete"]');
// check number of messages with type filters
await clickTrigger('#filter-by-message-type');
await click('.ember-power-select-options [data-option-index="0"]');
assert.dom('.linked-block').exists({ count: 0 }, 'filtered by modal');
await click('[data-test-selected-list-button="delete"]');
await clickTrigger('#filter-by-message-type');
await click('.ember-power-select-options [data-option-index="1"]');
assert.dom('.linked-block').exists({ count: 2 }, 'filtered by banner');
await click('[data-test-selected-list-button="delete"]');
// check number of messages with no filters
assert.dom('.linked-block').exists({ count: 2 }, 'no filters selected');
// clean up custom messages
await click(PAGE.listItem('Awesome custom message title'));
await click(PAGE.confirmActionButton('Delete message'));
await click(PAGE.confirmButton);
await click(PAGE.listItem('Awesome custom message title'));
await click(PAGE.confirmActionButton('Delete message'));
await click(PAGE.confirmButton);
assert.dom('[data-test-component="empty-state"]').exists('Message was deleted');
});
test('it should display preview a message when all required fields are filled out', async function (assert) {
assert.expect(2);
await visit(`vault/config-ui/messages`);