diff --git a/.changelog/18318.txt b/.changelog/18318.txt
new file mode 100644
index 00000000000..073fd28cb52
--- /dev/null
+++ b/.changelog/18318.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+ui: color-code node and server status cells
+```
diff --git a/.github/workflows/ember-test-audit.yml b/.github/workflows/ember-test-audit.yml
index 67aa066a668..b71d5fcfc8c 100644
--- a/.github/workflows/ember-test-audit.yml
+++ b/.github/workflows/ember-test-audit.yml
@@ -18,7 +18,7 @@ jobs:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
with:
ref: ${{ github.event.pull_request.base.sha }}
- - uses: nanasess/setup-chromedriver@6fb8f5ffa6b7dc11e631ff695fbd2fec0b04bb52 # v2.1.1
+ - uses: nanasess/setup-chromedriver@69cc01d772a1595b8aee87d52f53e71b3904d9d0 # v2.1.2
- name: Use Node.js
uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with:
@@ -35,7 +35,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- - uses: nanasess/setup-chromedriver@6fb8f5ffa6b7dc11e631ff695fbd2fec0b04bb52 # v2.1.1
+ - uses: nanasess/setup-chromedriver@69cc01d772a1595b8aee87d52f53e71b3904d9d0 # v2.1.2
- name: Use Node.js
uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with:
diff --git a/ui/app/components/client-node-row.js b/ui/app/components/client-node-row.js
index 16d964b0022..1375136294f 100644
--- a/ui/app/components/client-node-row.js
+++ b/ui/app/components/client-node-row.js
@@ -58,15 +58,37 @@ export default class ClientNodeRow extends Component.extend(
@watchRelationship('allocations') watch;
@computed('node.compositeStatus')
- get compositeStatusClass() {
+ get nodeStatusColor() {
let compositeStatus = this.get('node.compositeStatus');
if (compositeStatus === 'draining') {
- return 'status-text is-info';
+ return 'neutral';
} else if (compositeStatus === 'ineligible') {
- return 'status-text is-warning';
+ return 'warning';
} else if (compositeStatus === 'down') {
- return 'status-text is-danger';
+ return 'critical';
+ } else if (compositeStatus === 'ready') {
+ return 'success';
+ } else if (compositeStatus === 'initializing') {
+ return 'neutral';
+ } else {
+ return 'neutral';
+ }
+ }
+ @computed('node.compositeStatus')
+ get nodeStatusIcon() {
+ let compositeStatus = this.get('node.compositeStatus');
+
+ if (compositeStatus === 'draining') {
+ return 'minus-circle';
+ } else if (compositeStatus === 'ineligible') {
+ return 'skip';
+ } else if (compositeStatus === 'down') {
+ return 'x-circle';
+ } else if (compositeStatus === 'ready') {
+ return 'check-circle';
+ } else if (compositeStatus === 'initializing') {
+ return 'entry-point';
} else {
return '';
}
diff --git a/ui/app/components/server-agent-row.js b/ui/app/components/server-agent-row.js
index ee1a757e94a..a711e7e0de4 100644
--- a/ui/app/components/server-agent-row.js
+++ b/ui/app/components/server-agent-row.js
@@ -55,4 +55,20 @@ export default class ServerAgentRow extends Component {
click() {
this.goToAgent();
}
+
+ @computed('agent.status')
+ get agentStatusColor() {
+ let agentStatus = this.get('agent.status');
+ if (agentStatus === 'alive') {
+ return 'success';
+ } else if (agentStatus === 'failed') {
+ return 'critical';
+ } else if (agentStatus === 'leaving') {
+ return 'neutral';
+ } else if (agentStatus === 'left') {
+ return 'neutral';
+ } else {
+ return '';
+ }
+ }
}
diff --git a/ui/app/templates/components/client-node-row.hbs b/ui/app/templates/components/client-node-row.hbs
index 4f0ee33c299..66780e7bc33 100644
--- a/ui/app/templates/components/client-node-row.hbs
+++ b/ui/app/templates/components/client-node-row.hbs
@@ -14,7 +14,12 @@
{{this.node.name}} |
- {{this.node.compositeStatus}}
+
|
{{this.node.httpAddr}} |
diff --git a/ui/app/templates/components/server-agent-row.hbs b/ui/app/templates/components/server-agent-row.hbs
index dde32fded6a..302ace102b2 100644
--- a/ui/app/templates/components/server-agent-row.hbs
+++ b/ui/app/templates/components/server-agent-row.hbs
@@ -9,8 +9,22 @@
action=(action this.goToAgent)
}}
>{{this.agent.name}}
-{{this.agent.status}} |
-{{if this.agent.isLeader "True" "False"}} |
+
+
+ |
+
+
+
+ |
{{this.agent.address}} |
{{this.agent.serfPort}} |
{{this.agent.datacenter}} |
diff --git a/ui/tests/acceptance/clients-list-test.js b/ui/tests/acceptance/clients-list-test.js
index 9bc8747d4ea..82fd597c740 100644
--- a/ui/tests/acceptance/clients-list-test.js
+++ b/ui/tests/acceptance/clients-list-test.js
@@ -77,7 +77,7 @@ module('Acceptance | clients list', function (hooks) {
assert.equal(nodeRow.nodePool, node.nodePool, 'Node Pool');
assert.equal(
nodeRow.compositeStatus.text,
- 'draining',
+ 'Draining',
'Combined status, draining, and eligbility'
);
assert.equal(nodeRow.address, node.httpAddr);
@@ -111,7 +111,7 @@ module('Acceptance | clients list', function (hooks) {
assert.equal(nodeRow.id, node.id.split('-')[0], 'ID');
assert.equal(
nodeRow.compositeStatus.text,
- 'ready',
+ 'Ready',
'Combined status, draining, and eligbility'
);
assert.equal(nodeRow.allocations, running.length, '# Allocations');
@@ -156,38 +156,28 @@ module('Acceptance | clients list', function (hooks) {
});
await ClientsList.visit();
-
ClientsList.nodes[0].compositeStatus.as((readyClient) => {
- assert.equal(readyClient.text, 'ready');
- assert.ok(readyClient.isUnformatted, 'expected no status class');
+ assert.equal(readyClient.text, 'Ready');
+ console.log('readyClient', readyClient.text);
assert.equal(readyClient.tooltip, 'ready / not draining / eligible');
});
- assert.equal(ClientsList.nodes[1].compositeStatus.text, 'initializing');
- assert.equal(ClientsList.nodes[2].compositeStatus.text, 'down');
+ assert.equal(ClientsList.nodes[1].compositeStatus.text, 'Initializing');
+ assert.equal(ClientsList.nodes[2].compositeStatus.text, 'Down');
assert.equal(
ClientsList.nodes[2].compositeStatus.text,
- 'down',
+ 'Down',
'down takes priority over ineligible'
);
+ assert.equal(ClientsList.nodes[4].compositeStatus.text, 'Ineligible');
- assert.equal(ClientsList.nodes[4].compositeStatus.text, 'ineligible');
- assert.ok(
- ClientsList.nodes[4].compositeStatus.isWarning,
- 'expected warning class'
- );
-
- assert.equal(ClientsList.nodes[5].compositeStatus.text, 'draining');
- assert.ok(
- ClientsList.nodes[5].compositeStatus.isInfo,
- 'expected info class'
- );
+ assert.equal(ClientsList.nodes[5].compositeStatus.text, 'Draining');
await ClientsList.sortBy('compositeStatus');
assert.deepEqual(
ClientsList.nodes.map((n) => n.compositeStatus.text),
- ['ready', 'initializing', 'ineligible', 'draining', 'down', 'down']
+ ['Ready', 'Initializing', 'Ineligible', 'Draining', 'Down', 'Down']
);
// Simulate a client state change arriving through polling
@@ -201,7 +191,7 @@ module('Acceptance | clients list', function (hooks) {
assert.deepEqual(
ClientsList.nodes.map((n) => n.compositeStatus.text),
- ['initializing', 'ineligible', 'ineligible', 'draining', 'down', 'down']
+ ['Initializing', 'Ineligible', 'Ineligible', 'Draining', 'Down', 'Down']
);
});
diff --git a/ui/tests/acceptance/servers-list-test.js b/ui/tests/acceptance/servers-list-test.js
index ef1ae3f27c1..defdcd033f7 100644
--- a/ui/tests/acceptance/servers-list-test.js
+++ b/ui/tests/acceptance/servers-list-test.js
@@ -80,7 +80,11 @@ module('Acceptance | servers list', function (hooks) {
const agentRow = ServersList.servers.objectAt(0);
assert.equal(agentRow.name, agent.name, 'Name');
- assert.equal(agentRow.status, agent.member.Status, 'Status');
+ assert.equal(
+ agentRow.status,
+ agent.member.Status[0].toUpperCase() + agent.member.Status.substring(1),
+ 'Status'
+ );
assert.equal(agentRow.leader, 'True', 'Leader?');
assert.equal(agentRow.address, agent.member.Address, 'Address');
assert.equal(agentRow.serfPort, agent.member.Port, 'Serf Port');
diff --git a/ui/tests/pages/clients/list.js b/ui/tests/pages/clients/list.js
index ce4964a42a6..c5249ee6b10 100644
--- a/ui/tests/pages/clients/list.js
+++ b/ui/tests/pages/clients/list.js
@@ -44,8 +44,9 @@ export default create({
tooltip: attribute('aria-label', '.tooltip'),
- isInfo: hasClass('is-info', '.status-text'),
- isWarning: hasClass('is-warning', '.status-text'),
+ isInfo: hasClass('is-info'),
+ isSuccess: hasClass('is-success'),
+ isWarning: hasClass('is-warning'),
isUnformatted: isHidden('.status-text'),
},