mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
[ui] Color indicators for server/client status (#18318)
* Color the status cell for servers and nodes * Testfix and changelog * Leader indicator moved post-word * Icon and badge treatment * Capitalizing test checks * HDS badges dont expose statusClass like we used to, so stop checking for it
This commit is contained in:
3
.changelog/18318.txt
Normal file
3
.changelog/18318.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:improvement
|
||||
ui: color-code node and server status cells
|
||||
```
|
||||
4
.github/workflows/ember-test-audit.yml
vendored
4
.github/workflows/ember-test-audit.yml
vendored
@@ -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:
|
||||
|
||||
@@ -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 '';
|
||||
}
|
||||
|
||||
@@ -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 '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,12 @@
|
||||
<td data-test-client-name class="is-200px is-truncatable" title="{{this.node.name}}">{{this.node.name}}</td>
|
||||
<td data-test-client-composite-status>
|
||||
<span class="tooltip" aria-label="{{this.node.status}} / {{if this.node.isDraining "draining" "not draining"}} / {{if this.node.isEligible "eligible" "not eligible"}}">
|
||||
<span class="{{this.compositeStatusClass}}">{{this.node.compositeStatus}}</span>
|
||||
<Hds::Badge
|
||||
@text={{capitalize this.node.compositeStatus}}
|
||||
@icon={{this.nodeStatusIcon}}
|
||||
@color={{this.nodeStatusColor}}
|
||||
@size="large"
|
||||
/>
|
||||
</span>
|
||||
</td>
|
||||
<td data-test-client-address class="is-200px is-truncatable">{{this.node.httpAddr}}</td>
|
||||
|
||||
@@ -9,8 +9,22 @@
|
||||
action=(action this.goToAgent)
|
||||
}}
|
||||
><LinkTo @route="servers.server" @model={{this.agent.id}} class="is-primary">{{this.agent.name}}</LinkTo></td>
|
||||
<td data-test-server-status>{{this.agent.status}}</td>
|
||||
<td data-test-server-is-leader>{{if this.agent.isLeader "True" "False"}}</td>
|
||||
<td data-test-server-status><span>
|
||||
<Hds::Badge
|
||||
@text={{capitalize this.agent.status}}
|
||||
@color={{this.agentStatusColor}}
|
||||
@size="large"
|
||||
/>
|
||||
</span></td>
|
||||
<td data-test-server-is-leader>
|
||||
|
||||
<Hds::Badge
|
||||
@text={{if this.agent.isLeader "True" "False"}}
|
||||
@icon={{if this.agent.isLeader "check-circle" ""}}
|
||||
@color={{if this.agent.isLeader "success" "neutral"}}
|
||||
@size="large"
|
||||
/>
|
||||
</td>
|
||||
<td data-test-server-address class="is-200px is-truncatable">{{this.agent.address}}</td>
|
||||
<td data-test-server-port>{{this.agent.serfPort}}</td>
|
||||
<td data-test-server-datacenter>{{this.agent.datacenter}}</td>
|
||||
|
||||
@@ -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']
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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'),
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user