diff --git a/.changelog/17940.txt b/.changelog/17940.txt new file mode 100644 index 000000000000..a40be61310ae --- /dev/null +++ b/.changelog/17940.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: Fixed a bug that prevented nodes from being filtered by the "Ineligible" and "Draining" state filters +``` diff --git a/ui/app/controllers/topology.js b/ui/app/controllers/topology.js index 901dcaa398cb..021d5dbea98b 100644 --- a/ui/app/controllers/topology.js +++ b/ui/app/controllers/topology.js @@ -136,8 +136,13 @@ export default class TopologyControllers extends Controller.extend(Searchable) { selectionDatacenter, selectionClass, } = this; + const matchState = + selectionState.includes(node.status) || + (selectionState.includes('ineligible') && !node.isEligible) || + (selectionState.includes('draining') && node.isDraining); + return ( - (selectionState.length ? selectionState.includes(node.status) : true) && + (selectionState.length ? matchState : true) && (selectionVersion.length ? selectionVersion.includes(node.version) : true) && diff --git a/ui/tests/acceptance/topology-test.js b/ui/tests/acceptance/topology-test.js index 87fbca0100d3..422bc2c5eac7 100644 --- a/ui/tests/acceptance/topology-test.js +++ b/ui/tests/acceptance/topology-test.js @@ -317,22 +317,70 @@ module('Acceptance | topology', function (hooks) { server.createList('node', 2, { nodeClass: 'foo-bar-baz', }); + + // Make sure we have at least one node draining and one ineligible. + server.create('node', { + schedulingEligibility: 'ineligible', + }); + server.create('node', 'draining'); + server.createList('allocation', 5); + // Count draining and ineligible nodes. + const counts = { + ineligible: 0, + draining: 0, + }; + server.db.nodes.forEach((n) => { + if (n.schedulingEligibility === 'ineligible') { + counts['ineligible'] += 1; + } + if (n.drain) { + counts['draining'] += 1; + } + }); + await Topology.visit(); - assert.dom('[data-test-topo-viz-node]').exists({ count: 12 }); + assert.dom('[data-test-topo-viz-node]').exists({ count: 14 }); + // Test search. await typeIn('input.node-search', server.schema.nodes.first().name); assert.dom('[data-test-topo-viz-node]').exists({ count: 1 }); await typeIn('input.node-search', server.schema.nodes.first().name); assert.dom('[data-test-topo-viz-node]').doesNotExist(); await click('[title="Clear search"]'); - assert.dom('[data-test-topo-viz-node]').exists({ count: 12 }); + assert.dom('[data-test-topo-viz-node]').exists({ count: 14 }); + // Test node class filter. await Topology.facets.class.toggle(); await Topology.facets.class.options .findOneBy('label', 'foo-bar-baz') .toggle(); assert.dom('[data-test-topo-viz-node]').exists({ count: 2 }); + await Topology.facets.class.options + .findOneBy('label', 'foo-bar-baz') + .toggle(); + + // Test ineligible state filter. + await Topology.facets.state.toggle(); + await Topology.facets.state.options + .findOneBy('label', 'Ineligible') + .toggle(); + assert + .dom('[data-test-topo-viz-node]') + .exists({ count: counts['ineligible'] }); + await Topology.facets.state.options + .findOneBy('label', 'Ineligible') + .toggle(); + await Topology.facets.state.toggle(); + + // Test draining state filter. + await Topology.facets.state.toggle(); + await Topology.facets.state.options.findOneBy('label', 'Draining').toggle(); + assert + .dom('[data-test-topo-viz-node]') + .exists({ count: counts['draining'] }); + await Topology.facets.state.options.findOneBy('label', 'Draining').toggle(); + await Topology.facets.state.toggle(); }); });