diff --git a/ui/app/components/allocation-service-sidebar.hbs b/ui/app/components/allocation-service-sidebar.hbs index b4af0fd2f..c77b089b0 100644 --- a/ui/app/components/allocation-service-sidebar.hbs +++ b/ui/app/components/allocation-service-sidebar.hbs @@ -91,13 +91,13 @@ {{#if this.checks.length}} - + Name - + Status - + Output @@ -125,6 +125,15 @@ + + +
+ {{#each (dedupe-by-property (filter-by "Check" row.model.Check @service.healthChecks) prop="Timestamp") as |check|}} + + {{/each}} +
+ +
{{/if}} diff --git a/ui/app/components/service-status-indicator.hbs b/ui/app/components/service-status-indicator.hbs new file mode 100644 index 000000000..766c55481 --- /dev/null +++ b/ui/app/components/service-status-indicator.hbs @@ -0,0 +1 @@ + diff --git a/ui/app/helpers/dedupe-by-property.js b/ui/app/helpers/dedupe-by-property.js new file mode 100644 index 000000000..f771e4f2c --- /dev/null +++ b/ui/app/helpers/dedupe-by-property.js @@ -0,0 +1,15 @@ +// Takes an array and a property name and returns a new array with all the duplicates removed. +import { helper } from '@ember/component/helper'; + +export default helper(function dedupeByProperty([arr], { prop }) { + const seen = new Set(); + return arr.filter((item) => { + const val = item[prop]; + if (seen.has(val)) { + return false; + } else { + seen.add(val); + return true; + } + }); +}); diff --git a/ui/app/routes/allocations/allocation.js b/ui/app/routes/allocations/allocation.js index 7656c3770..26788bbd4 100644 --- a/ui/app/routes/allocations/allocation.js +++ b/ui/app/routes/allocations/allocation.js @@ -25,7 +25,7 @@ export default class AllocationRoute extends Route.extend(WithWatchers) { if (doesAllocHaveServices) { controller.set( 'watchHealthChecks', - this.watchHealthChecks.perform(model, 'getServiceHealth') + this.watchHealthChecks.perform(model, 'getServiceHealth', 2000) ); } } diff --git a/ui/app/styles/components/services.scss b/ui/app/styles/components/services.scss index 7a3c7ab3a..a2adc66e7 100644 --- a/ui/app/styles/components/services.scss +++ b/ui/app/styles/components/services.scss @@ -67,3 +67,54 @@ margin-right: 5px; } } + +table.health-checks { + table-layout: fixed; + th.name { + width: 20%; + } + th.status { + width: 15%; + } + th.output { + width: 65%; + } + tbody tr td { + border-bottom-width: 0; + } + + .service-status-indicators { + td { + border-bottom-width: 1px; + text-align: right; + & > div { + display: grid; + grid-auto-flow: column; + justify-content: end; + gap: 2px; + width: calc( + 750px - 3rem - 50px + ); //Sidebar width - padding - table padding + height: 20px; + padding-top: 30px; + margin-top: -20px; + overflow: hidden; + box-sizing: content-box; + .service-status-indicator { + width: 8px; + height: 8px; + display: block; + position: relative; + &.status-success { + background-color: $nomad-green; + top: 0px; + } + &.status-failure { + background-color: $red; + top: 12px; + } + } + } + } + } +} diff --git a/ui/tests/integration/components/allocation-service-sidebar-test.js b/ui/tests/integration/components/allocation-service-sidebar-test.js index c970bde2d..1cb6c6278 100644 --- a/ui/tests/integration/components/allocation-service-sidebar-test.js +++ b/ui/tests/integration/components/allocation-service-sidebar-test.js @@ -78,7 +78,7 @@ module( ); assert.dom('h1 .aggregate-status').includesText('Healthy'); assert - .dom('table.health-checks tbody tr') + .dom('table.health-checks tbody tr:not(.service-status-indicators)') .exists({ count: 2 }, 'has two rows'); this.set('service', unhealthyService);