mirror of
https://github.com/kemko/nomad.git
synced 2026-01-08 03:15:42 +03:00
Implement faceted search on the clients page
This commit is contained in:
committed by
Preetha Appan
parent
498f513dc0
commit
21f8351929
@@ -1,8 +1,11 @@
|
||||
import { alias } from '@ember/object/computed';
|
||||
import Controller, { inject as controller } from '@ember/controller';
|
||||
import { computed } from '@ember/object';
|
||||
import { scheduleOnce } from '@ember/runloop';
|
||||
import intersection from 'lodash.intersection';
|
||||
import Sortable from 'nomad-ui/mixins/sortable';
|
||||
import Searchable from 'nomad-ui/mixins/searchable';
|
||||
import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize';
|
||||
|
||||
export default Controller.extend(Sortable, Searchable, {
|
||||
clientsController: controller('clients'),
|
||||
@@ -15,6 +18,10 @@ export default Controller.extend(Sortable, Searchable, {
|
||||
searchTerm: 'search',
|
||||
sortProperty: 'sort',
|
||||
sortDescending: 'desc',
|
||||
qpClass: 'class',
|
||||
qpStatus: 'status',
|
||||
qpDatacenter: 'dc',
|
||||
qpFlags: 'flags',
|
||||
},
|
||||
|
||||
currentPage: 1,
|
||||
@@ -25,12 +32,97 @@ export default Controller.extend(Sortable, Searchable, {
|
||||
|
||||
searchProps: computed(() => ['id', 'name', 'datacenter']),
|
||||
|
||||
listToSort: alias('nodes'),
|
||||
qpClass: '',
|
||||
qpStatus: '',
|
||||
qpDatacenter: '',
|
||||
qpFlags: '',
|
||||
|
||||
selectionClass: selection('qpClass'),
|
||||
selectionStatus: selection('qpStatus'),
|
||||
selectionDatacenter: selection('qpDatacenter'),
|
||||
selectionFlags: selection('qpFlags'),
|
||||
|
||||
optionsClass: computed('nodes.[]', function() {
|
||||
const classes = Array.from(new Set(this.get('nodes').mapBy('nodeClass'))).compact();
|
||||
|
||||
// Remove any invalid node classes from the query param/selection
|
||||
scheduleOnce('actions', () => {
|
||||
this.set('qpClass', serialize(intersection(classes, this.get('selectionClass'))));
|
||||
});
|
||||
|
||||
return classes.sort().map(dc => ({ key: dc, label: dc }));
|
||||
}),
|
||||
|
||||
optionsStatus: computed(() => [
|
||||
{ key: 'initializing', label: 'Initializing' },
|
||||
{ key: 'ready', label: 'Ready' },
|
||||
{ key: 'down', label: 'Down' },
|
||||
]),
|
||||
|
||||
optionsDatacenter: computed('nodes.[]', function() {
|
||||
const datacenters = Array.from(new Set(this.get('nodes').mapBy('datacenter'))).compact();
|
||||
|
||||
// Remove any invalid datacenters from the query param/selection
|
||||
scheduleOnce('actions', () => {
|
||||
this.set(
|
||||
'qpDatacenter',
|
||||
serialize(intersection(datacenters, this.get('selectionDatacenter')))
|
||||
);
|
||||
});
|
||||
|
||||
return datacenters.sort().map(dc => ({ key: dc, label: dc }));
|
||||
}),
|
||||
|
||||
optionsFlags: computed(() => [
|
||||
{ key: 'ineligible', label: 'Ineligible' },
|
||||
{ key: 'draining', label: 'Draining' },
|
||||
]),
|
||||
|
||||
filteredNodes: computed(
|
||||
'nodes.[]',
|
||||
'selectionClass',
|
||||
'selectionStatus',
|
||||
'selectionDatacenter',
|
||||
'selectionFlags',
|
||||
function() {
|
||||
const {
|
||||
selectionClass: classes,
|
||||
selectionStatus: statuses,
|
||||
selectionDatacenter: datacenters,
|
||||
selectionFlags: flags,
|
||||
} = this.getProperties(
|
||||
'selectionClass',
|
||||
'selectionStatus',
|
||||
'selectionDatacenter',
|
||||
'selectionFlags'
|
||||
);
|
||||
|
||||
const onlyIneligible = flags.includes('ineligible');
|
||||
const onlyDraining = flags.includes('draining');
|
||||
|
||||
return this.get('nodes').filter(node => {
|
||||
if (classes.length && !classes.includes(node.get('nodeClass'))) return false;
|
||||
if (statuses.length && !statuses.includes(node.get('status'))) return false;
|
||||
if (datacenters.length && !datacenters.includes(node.get('datacenter'))) return false;
|
||||
|
||||
if (onlyIneligible && node.get('isEligible')) return false;
|
||||
if (onlyDraining && !node.get('isDraining')) return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
),
|
||||
|
||||
listToSort: alias('filteredNodes'),
|
||||
listToSearch: alias('listSorted'),
|
||||
sortedNodes: alias('listSearched'),
|
||||
|
||||
isForbidden: alias('clientsController.isForbidden'),
|
||||
|
||||
setFacetQueryParam(queryParam, selection) {
|
||||
this.set(queryParam, serialize(selection));
|
||||
},
|
||||
|
||||
actions: {
|
||||
gotoNode(node) {
|
||||
this.transitionToRoute('clients.client', node);
|
||||
|
||||
@@ -2,16 +2,44 @@
|
||||
{{#if isForbidden}}
|
||||
{{partial "partials/forbidden-message"}}
|
||||
{{else}}
|
||||
{{#if nodes.length}}
|
||||
<div class="content">
|
||||
<div>
|
||||
<div class="columns">
|
||||
{{#if nodes.length}}
|
||||
<div class="column is-one-third">
|
||||
{{search-box
|
||||
searchTerm=(mut searchTerm)
|
||||
onChange=(action resetPagination)
|
||||
placeholder="Search clients..."}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="column is-centered">
|
||||
<div class="button-bar is-pulled-right">
|
||||
{{multi-select-dropdown
|
||||
data-test-facet-class
|
||||
label="Class"
|
||||
options=optionsClass
|
||||
selection=selectionClass
|
||||
onSelect=(action setFacetQueryParam "qpClass")}}
|
||||
{{multi-select-dropdown
|
||||
data-test-facet-status
|
||||
label="Status"
|
||||
options=optionsStatus
|
||||
selection=selectionStatus
|
||||
onSelect=(action setFacetQueryParam "qpStatus")}}
|
||||
{{multi-select-dropdown
|
||||
data-test-facet-datacenter
|
||||
label="Datacenter"
|
||||
options=optionsDatacenter
|
||||
selection=selectionDatacenter
|
||||
onSelect=(action setFacetQueryParam "qpDatacenter")}}
|
||||
{{multi-select-dropdown
|
||||
data-test-facet-flags
|
||||
label="Flags"
|
||||
options=optionsFlags
|
||||
selection=selectionFlags
|
||||
onSelect=(action setFacetQueryParam "qpFlags")}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#list-pagination
|
||||
source=sortedNodes
|
||||
size=pageSize
|
||||
|
||||
Reference in New Issue
Block a user