diff --git a/.changelog/17940.txt b/.changelog/17940.txt new file mode 100644 index 000000000..a40be6131 --- /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 4612c4bf4..a28d6253b 100644 --- a/ui/app/controllers/topology.js +++ b/ui/app/controllers/topology.js @@ -170,8 +170,13 @@ export default class TopologyControllers extends Controller.extend(Searchable) { selectionClass, selectionNodePool, } = 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 d541e804c..84c614ac4 100644 --- a/ui/tests/acceptance/topology-test.js +++ b/ui/tests/acceptance/topology-test.js @@ -334,6 +334,12 @@ module('Acceptance | topology', function (hooks) { 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'); + // Create node pool exclusive for these nodes. server.create('node-pool', { name: 'test-node-pool' }); server.createList('node', 3, { @@ -342,16 +348,32 @@ module('Acceptance | topology', function (hooks) { server.createList('allocation', 5); - await Topology.visit(); - assert.dom('[data-test-topo-viz-node]').exists({ count: 15 }); + // 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: 17 }); + + // 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: 15 }); + assert.dom('[data-test-topo-viz-node]').exists({ count: 17 }); + // Test node class filter. await Topology.facets.class.toggle(); await Topology.facets.class.options .findOneBy('label', 'foo-bar-baz') @@ -361,6 +383,29 @@ module('Acceptance | topology', function (hooks) { .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(); + + // Test node pool filter. await Topology.facets.nodePool.toggle(); await Topology.facets.nodePool.options .findOneBy('label', 'test-node-pool')