mirror of
https://github.com/hashicorp/vault.git
synced 2026-02-03 20:40:45 -05:00
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:
parent
efdaab7279
commit
483da17588
9 changed files with 136 additions and 21 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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}}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@
|
|||
<Messages::Page::List
|
||||
@messages={{this.model.messages}}
|
||||
@authenticated={{this.authenticated}}
|
||||
@pageFilter={{this.model.pageFilter}}
|
||||
@params={{this.model.params}}
|
||||
/>
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
<PowerSelect
|
||||
@eventType="click"
|
||||
@placeholder={{@placeholder}}
|
||||
@searchEnabled={{true}}
|
||||
@searchEnabled={{this.searchEnabled}}
|
||||
@search={{this.searchAndSuggest}}
|
||||
@options={{this.dropdownOptions}}
|
||||
@onChange={{this.selectOrCreate}}
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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`);
|
||||
|
|
|
|||
Loading…
Reference in a new issue