diff --git a/ui/app/components/clients/counts-card.hbs b/ui/app/components/clients/counts-card.hbs
index df3d7a7a46..776340bdc0 100644
--- a/ui/app/components/clients/counts-card.hbs
+++ b/ui/app/components/clients/counts-card.hbs
@@ -35,10 +35,10 @@ Data visualizations render in in a flex row with a 1/3-width left element and a
{{#if @legend}}
- {{#each @legend as |l|}}
+ {{#each @legend as |l idx|}}
-
- {{capitalize l.label}}
+
+ {{l.label}}
{{/each}}
diff --git a/ui/app/components/clients/running-total.ts b/ui/app/components/clients/running-total.ts
index c930b1d9bc..8a9b9f4c0d 100644
--- a/ui/app/components/clients/running-total.ts
+++ b/ui/app/components/clients/running-total.ts
@@ -36,12 +36,13 @@ export default class RunningTotal extends Component {
get chartLegend() {
if (this.showStacked) {
return [
- { key: 'entity_clients', label: 'entity clients' },
- { key: 'non_entity_clients', label: 'non-entity clients' },
- ...(this.flags.secretsSyncIsActivated ? [{ key: 'secret_syncs', label: 'secret sync clients' }] : []),
- { key: 'acme_clients', label: 'acme clients' },
+ { key: 'entity_clients', label: 'Entity clients' },
+ { key: 'non_entity_clients', label: 'Non-entity clients' },
+ { key: 'acme_clients', label: 'ACME clients' },
+ // MUST BE LAST because conditionally renders and legend color mapping for stacked bars will be off otherwise
+ ...(this.flags.secretsSyncIsActivated ? [{ key: 'secret_syncs', label: 'Secret sync clients' }] : []),
];
}
- return [{ key: 'new_clients', label: 'new clients' }];
+ return [{ key: 'new_clients', label: 'New clients' }];
}
}
diff --git a/ui/app/styles/core/charts.scss b/ui/app/styles/core/charts.scss
index 88db198796..55f616fa64 100644
--- a/ui/app/styles/core/charts.scss
+++ b/ui/app/styles/core/charts.scss
@@ -7,11 +7,12 @@
*/
// LEGEND STYLING (positioning is in chart-container.scss)
-$blue-500: #1c345f;
-$secret_syncs: #6cc5b0;
-$acme_clients: #ff725c;
-$entity_clients: #4269d0;
-$non_entity_clients: #efb117;
+$single: #1c345f;
+// stacked bar chart color scheme
+$first: #4269d0;
+$second: #efb117;
+$third: #ff725c;
+$fourth: #6cc5b0;
.legend-container {
.dots {
@@ -20,20 +21,22 @@ $non_entity_clients: #efb117;
border-radius: 50%;
display: inline-block;
}
- .legend-new_clients {
- background-color: $blue-500;
+ .legend-dot-new_clients {
+ background-color: $single;
}
- .legend-entity_clients {
- background-color: $entity_clients;
+ // numbers are indices because chart legend is iterated over to ensure
+ // legend colors match the correct stacked-bar-# class below
+ .legend-dot-0 {
+ background-color: $first;
}
- .legend-non_entity_clients {
- background-color: $non_entity_clients;
+ .legend-dot-1 {
+ background-color: $second;
}
- .legend-secret_syncs {
- background-color: $secret_syncs;
+ .legend-dot-2 {
+ background-color: $third;
}
- .legend-acme_clients {
- background-color: $acme_clients;
+ .legend-dot-3 {
+ background-color: $fourth;
}
}
@@ -85,7 +88,7 @@ $non_entity_clients: #efb117;
}
.lineal-chart-bar {
- fill: var(--token-color-palette-blue-500);
+ fill: var(--token-color-palette-single);
}
.lineal-axis {
@@ -98,20 +101,21 @@ $non_entity_clients: #efb117;
}
}
-// @colorScale arg for Lineal::VBars is "stacked-bar", indices are added by lineal
+// @colorScale arg for Lineal::VBars is "stacked-bar", numbers are added by lineal (not 0-indexed)
.stacked-bar-1 {
- color: $entity_clients;
- fill: $entity_clients;
+ color: $first;
+ fill: $first;
}
.stacked-bar-2 {
- color: $non_entity_clients;
- fill: $non_entity_clients;
+ color: $second;
+ fill: $second;
}
.stacked-bar-3 {
- color: $secret_syncs;
- fill: $secret_syncs;
+ color: $third;
+ fill: $third;
}
+// MUST BE LAST because conditionally renders and legend color mapping for stacked bars will be off otherwise
.stacked-bar-4 {
- color: $acme_clients;
- fill: $acme_clients;
+ color: $fourth;
+ fill: $fourth;
}
diff --git a/ui/tests/acceptance/clients/counts/overview-test.js b/ui/tests/acceptance/clients/counts/overview-test.js
index f0485c1335..4b5c8e82c8 100644
--- a/ui/tests/acceptance/clients/counts/overview-test.js
+++ b/ui/tests/acceptance/clients/counts/overview-test.js
@@ -42,7 +42,7 @@ module('Acceptance | clients | overview', function (hooks) {
assert.dom(CLIENT_COUNT.statTextValue('Secret sync')).doesNotExist();
assert.dom(CLIENT_COUNT.statTextValue('Entity')).exists('other stats are still visible');
await click(GENERAL.inputByAttr('toggle view'));
- assert.dom(CHARTS.legend).hasText('Entity clients Non-entity clients Acme clients');
+ assert.dom(CHARTS.legend).hasText('Entity clients Non-entity clients ACME clients');
});
// These tests use the clientsHandler which dynamically generates activity data, used for asserting date querying, etc
@@ -277,7 +277,12 @@ module('Acceptance | clients | overview', function (hooks) {
await visit('/vault/clients/counts/overview');
assert.dom(CLIENT_COUNT.statTextValue('Secret sync')).exists('shows secret sync data on overview');
await click(GENERAL.inputByAttr('toggle view'));
- assert.dom(CHARTS.legend).hasText('Entity clients Non-entity clients Secret sync clients Acme clients');
+ assert
+ .dom(CHARTS.legend)
+ .hasText(
+ 'Entity clients Non-entity clients ACME clients Secret sync clients',
+ 'it renders legend in order that matches the stacked bar data'
+ );
});
test('it should hide secrets sync stats when feature is NOT activated', async function (assert) {
@@ -295,7 +300,12 @@ module('Acceptance | clients | overview', function (hooks) {
.doesNotExist('stat is hidden because feature is not activated');
assert.dom(CLIENT_COUNT.statTextValue('Entity')).exists('other stats are still visible');
await click(GENERAL.inputByAttr('toggle view'));
- assert.dom(CHARTS.legend).hasText('Entity clients Non-entity clients Acme clients');
+ assert
+ .dom(CHARTS.legend)
+ .hasText(
+ 'Entity clients Non-entity clients ACME clients',
+ 'it renders legend in order that matches the stacked bar data and does not include secret sync'
+ );
});
test('it should show secrets sync stats for HVD managed clusters', async function (assert) {
@@ -306,7 +316,12 @@ module('Acceptance | clients | overview', function (hooks) {
await visit('/vault/clients/counts/overview');
assert.dom(CLIENT_COUNT.statTextValue('Secret sync')).exists();
await click(GENERAL.inputByAttr('toggle view'));
- assert.dom(CHARTS.legend).hasText('Entity clients Non-entity clients Secret sync clients Acme clients');
+ assert
+ .dom(CHARTS.legend)
+ .hasText(
+ 'Entity clients Non-entity clients ACME clients Secret sync clients',
+ 'it renders legend in order that matches the stacked bar data'
+ );
});
});
});
diff --git a/ui/tests/integration/components/clients/running-total-test.js b/ui/tests/integration/components/clients/running-total-test.js
index 6bf423b647..4fbdacf6d8 100644
--- a/ui/tests/integration/components/clients/running-total-test.js
+++ b/ui/tests/integration/components/clients/running-total-test.js
@@ -101,14 +101,19 @@ module('Integration | Component | clients/running-total', function (hooks) {
.dom(CLIENT_COUNT.card('Client usage trends for selected billing period'))
.exists('running total component renders');
assert.dom(CHARTS.chart('Client usage by month')).exists('bar chart renders');
- assert.dom(CHARTS.legend).hasText('Entity clients Non-entity clients Secret sync clients Acme clients');
+ assert
+ .dom(CHARTS.legend)
+ .hasText(
+ 'Entity clients Non-entity clients ACME clients Secret sync clients',
+ 'it renders legend in order that matches the stacked bar data and secret sync clients is last'
+ );
// assert each legend item is correct
const expectedLegend = [
{ label: 'Entity clients', color: 'rgb(66, 105, 208)' },
{ label: 'Non-entity clients', color: 'rgb(239, 177, 23)' },
+ { label: 'ACME clients', color: 'rgb(255, 114, 92)' },
{ label: 'Secret sync clients', color: 'rgb(108, 197, 176)' },
- { label: 'Acme clients', color: 'rgb(255, 114, 92)' },
];
findAll('.legend-item').forEach((e, i) => {
@@ -172,13 +177,13 @@ module('Integration | Component | clients/running-total', function (hooks) {
await click(GENERAL.inputByAttr('toggle view'));
assert
.dom(CHARTS.legend)
- .hasText('Entity clients Non-entity clients Acme clients', 'legend does not include sync clients');
+ .hasText('Entity clients Non-entity clients ACME clients', 'legend does not include sync clients');
// assert each legend item is correct
const expectedLegend = [
{ label: 'Entity clients', color: 'rgb(66, 105, 208)' },
{ label: 'Non-entity clients', color: 'rgb(239, 177, 23)' },
- { label: 'Acme clients', color: 'rgb(255, 114, 92)' },
+ { label: 'ACME clients', color: 'rgb(255, 114, 92)' },
];
findAll('.legend-item').forEach((e, i) => {