ui: Move healthcheck ordering to use new comparators (#8096)

This commit is contained in:
John Cowen 2020-06-16 14:13:29 +01:00 committed by GitHub
parent 2162f8a4fa
commit d2515ed409
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 96 additions and 149 deletions

View file

@ -1,47 +1,48 @@
<ul> <div>
{{#each (sort-by (action 'sortChecksByImportance') items) as |item| }} <ul>
{{! TODO: this component and its child should be moved to a single component }} {{#each items as |item| }}
<HealthcheckOutput class={{item.Status}} @tagName="li"> <li class={{concat 'healthcheck-output ' item.Status}}>
<BlockSlot @name="header"> <div>
<h3>{{item.Name}}</h3> <header>
</BlockSlot> <h3>{{item.Name}}</h3>
<BlockSlot @name="content"> </header>
<dl> <dl>
{{#if (eq item.ServiceName "")}} {{#if (eq item.ServiceName "")}}
<dt>NodeName</dt> <dt>NodeName</dt>
<dd>{{item.Node}}</dd> <dd>{{item.Node}}</dd>
{{else}} {{else}}
<dt>ServiceName</dt> <dt>ServiceName</dt>
<dd>{{item.ServiceName}}</dd> <dd>{{item.ServiceName}}</dd>
{{/if}} {{/if}}
</dl> </dl>
<dl> <dl>
<dt>CheckID</dt> <dt>CheckID</dt>
<dd>{{or item.CheckID '-'}}</dd> <dd>{{or item.CheckID '-'}}</dd>
</dl> </dl>
<dl> <dl>
<dt>Type</dt> <dt>Type</dt>
<dd> <dd>
{{item.Type}} {{item.Type}}
{{#if (and exposed (contains item.Type (array 'http' 'grpc')))}} {{#if (and exposed (contains item.Type (array 'http' 'grpc')))}}
<em data-test-exposed="true" data-tooltip="Expose.checks is set to true, so all registered HTTP and gRPC check paths are exposed through Envoy for the Consul agent.">Exposed</em> <em data-test-exposed="true" data-tooltip="Expose.checks is set to true, so all registered HTTP and gRPC check paths are exposed through Envoy for the Consul agent.">Exposed</em>
{{/if}} {{/if}}
</dd> </dd>
</dl> </dl>
<dl> <dl>
<dt>Notes</dt> <dt>Notes</dt>
<dd>{{or item.Notes '-'}}</dd> <dd>{{or item.Notes '-'}}</dd>
</dl> </dl>
<dl> <dl>
{{#if (not-eq item.Type 'ttl')}} {{#if (not-eq item.Type 'ttl')}}
<dt>Output</dt> <dt>Output</dt>
<dd> <dd>
<pre><code>{{item.Output}}</code></pre> <pre><code>{{item.Output}}</code></pre>
<CopyButton @value={{item.Output}} @name="output" /> <CopyButton @value={{item.Output}} @name="output" />
</dd> </dd>
{{/if}} {{/if}}
</dl> </dl>
</BlockSlot> </div>
</HealthcheckOutput> </li>
{{/each}} {{/each}}
</ul> </ul>
</div>

View file

@ -1,36 +1,5 @@
import Component from '@ember/component'; import Component from '@ember/component';
import { get } from '@ember/object';
export default Component.extend({ export default Component.extend({
// TODO: Could potentially do this on attr change tagName: '',
actions: {
sortChecksByImportance: function(a, b) {
const statusA = get(a, 'Status');
const statusB = get(b, 'Status');
switch (statusA) {
case 'passing':
// a = passing
// unless b is also passing then a is less important
return statusB === 'passing' ? 0 : 1;
case 'critical':
// a = critical
// unless b is also critical then a is more important
return statusB === 'critical' ? 0 : -1;
case 'warning':
// a = warning
switch (statusB) {
// b is passing so a is more important
case 'passing':
return -1;
// b is critical so a is less important
case 'critical':
return 1;
// a and b are both warning, therefore equal
default:
return 0;
}
}
return 0;
},
},
}); });

View file

@ -1,8 +0,0 @@
{{! TODO: this component and its parent should be moved to a single component }}
{{yield}}
<div>
<header>
<YieldSlot @name="header">{{yield}}</YieldSlot>
</header>
<YieldSlot @name="content">{{yield}}</YieldSlot>
</div>

View file

@ -1,6 +0,0 @@
import Component from '@ember/component';
import Slotted from 'block-slots';
export default Component.extend(Slotted, {
classNames: ['healthcheck-output'],
});

View file

@ -23,34 +23,4 @@ export default Controller.extend(WithEventSource, {
} }
} }
}), }),
actions: {
sortChecksByImportance: function(a, b) {
const statusA = get(a, 'Status');
const statusB = get(b, 'Status');
switch (statusA) {
case 'passing':
// a = passing
// unless b is also passing then a is less important
return statusB === 'passing' ? 0 : 1;
case 'critical':
// a = critical
// unless b is also critical then a is more important
return statusB === 'critical' ? 0 : -1;
case 'warning':
// a = warning
switch (statusB) {
// b is passing so a is more important
case 'passing':
return -1;
// b is critical so a is less important
case 'critical':
return 1;
// a and b are both warning, therefore equal
default:
return 0;
}
}
return 0;
},
},
}); });

View file

@ -1,10 +1,12 @@
import service from 'consul-ui/sort/comparators/service'; import service from 'consul-ui/sort/comparators/service';
import check from 'consul-ui/sort/comparators/check';
export function initialize(container) { export function initialize(container) {
// Service-less injection using private properties at a per-project level // Service-less injection using private properties at a per-project level
const Sort = container.resolveRegistration('service:sort'); const Sort = container.resolveRegistration('service:sort');
const comparators = { const comparators = {
service: service(), service: service(),
check: check(),
}; };
Sort.reopen({ Sort.reopen({
comparator: function(type) { comparator: function(type) {

View file

@ -0,0 +1,42 @@
export default () => key => {
if (key.startsWith('Status:')) {
return function(itemA, itemB) {
const [, dir] = key.split(':');
let a, b;
if (dir === 'asc') {
a = itemA;
b = itemB;
} else {
b = itemA;
a = itemB;
}
const statusA = a.Status;
const statusB = b.Status;
switch (statusA) {
case 'passing':
// a = passing
// unless b is also passing then a is less important
return statusB === 'passing' ? 0 : 1;
case 'critical':
// a = critical
// unless b is also critical then a is more important
return statusB === 'critical' ? 0 : -1;
case 'warning':
// a = warning
switch (statusB) {
// b is passing so a is more important
case 'passing':
return -1;
// b is critical so a is less important
case 'critical':
return 1;
// a and b are both warning, therefore equal
default:
return 0;
}
}
return 0;
};
}
return key;
};

View file

@ -1,7 +1,7 @@
<div id="health-checks" class="tab-section"> <div id="health-checks" class="tab-section">
<div role="tabpanel"> <div role="tabpanel">
{{#if (gt item.Checks.length 0) }} {{#if (gt item.Checks.length 0) }}
<HealthcheckList @items={{item.Checks}} /> <HealthcheckList @items={{sort-by (comparator 'check' 'Status:asc') item.Checks}} />
{{else}} {{else}}
<p> <p>
This node has no health checks. This node has no health checks.

View file

@ -2,7 +2,7 @@
<div role="tabpanel"> <div role="tabpanel">
{{#if (gt item.ServiceChecks.length 0) }} {{#if (gt item.ServiceChecks.length 0) }}
<section data-test-service-checks> <section data-test-service-checks>
<HealthcheckList @items={{item.ServiceChecks}} @exposed={{proxy.ServiceProxy.Expose.Checks}} /> <HealthcheckList @items={{sort-by (comparator 'check' 'Status:asc') item.ServiceChecks}} @exposed={{proxy.ServiceProxy.Expose.Checks}} />
</section> </section>
{{else}} {{else}}
<p> <p>
@ -11,7 +11,7 @@
{{/if}} {{/if}}
{{#if (gt item.NodeChecks.length 0) }} {{#if (gt item.NodeChecks.length 0) }}
<section data-test-node-checks> <section data-test-node-checks>
<HealthcheckList @items={{item.NodeChecks}} /> <HealthcheckList @items={{sort-by (comparator 'check' 'Status:asc') item.NodeChecks}} />
</section> </section>
{{else}} {{else}}
<p> <p>

View file

@ -140,7 +140,7 @@
{{#if (or (gt proxy.ServiceChecks.length 0) (gt proxy.NodeChecks.length 0))}} {{#if (or (gt proxy.ServiceChecks.length 0) (gt proxy.NodeChecks.length 0))}}
<section> <section>
<h3>Proxy health</h3> <h3>Proxy health</h3>
<HealthcheckList data-test-proxy-checks @items={{append proxy.ServiceChecks proxy.NodeChecks}} /> <HealthcheckList data-test-proxy-checks @items={{sort-by (comparator 'check' 'Status:asc') (append proxy.ServiceChecks proxy.NodeChecks)}} />
</section> </section>
{{/if}} {{/if}}
</div> </div>

View file

@ -1,23 +0,0 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, find } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | healthcheck output', function(hooks) {
setupRenderingTest(hooks);
test('it renders', async function(assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.on('myAction', function(val) { ... });
await render(hbs`{{healthcheck-output}}`);
assert.equal(find('*').textContent.trim(), '');
// Template block usage:
await render(hbs`
{{#healthcheck-output}}{{/healthcheck-output}}
`);
assert.equal(find('*').textContent.trim(), '');
});
});