UI: Update replication nav (#24283)

* replication gets its own subnav

* glimmerize replication-summary-card

* Simplify replication-summary-card

* update replication subnav + tests

* replication action block uses HDS card

* add/update test selectors

* test coverage

* Add changelog

* Update defaults on replication-summary-card

* test that the view updates between replication types

* typo
This commit is contained in:
Chelsea Shaw
2023-12-04 10:40:34 -06:00
committed by GitHub
parent 9082ebc996
commit af3901e256
21 changed files with 378 additions and 187 deletions

3
changelog/24283.txt Normal file
View File

@@ -0,0 +1,3 @@
```release-note:change
ui: add subnav for replication items
```

View File

@@ -20,9 +20,19 @@ export default class App extends Application {
},
replication: {
dependencies: {
services: ['auth', 'flash-messages', 'namespace', 'replication-mode', 'router', 'store', 'version'],
services: [
'auth',
'flash-messages',
'namespace',
'replication-mode',
'router',
'store',
'version',
'-portal',
],
externalRoutes: {
replication: 'vault.cluster.replication.index',
vault: 'vault.cluster',
},
},
},

View File

@@ -42,32 +42,6 @@
/>
{{/if}}
{{#if
(and
this.version.isEnterprise
this.namespace.inRootNamespace
this.cluster.anyReplicationEnabled
(has-permission "status" routeParams="replication")
)
}}
<Nav.Title data-test-sidebar-nav-heading="Replication">Replication</Nav.Title>
<Nav.Link
@route="vault.cluster.replication.mode.index"
@model="dr"
@text="Disaster Recovery"
data-test-sidebar-nav-link="Disaster Recovery"
/>
{{#if (has-feature "Performance Replication")}}
<Nav.Link
@route="vault.cluster.replication.mode.index"
@model="performance"
@text="Performance"
data-test-sidebar-nav-link="Performance"
/>
{{/if}}
{{/if}}
{{#if
(or
(and
@@ -79,7 +53,12 @@
<Nav.Title data-test-sidebar-nav-heading="Monitoring">Monitoring</Nav.Title>
{{/if}}
{{#if (and this.version.isEnterprise this.namespace.inRootNamespace (has-permission "status" routeParams="replication"))}}
<Nav.Link @route="vault.cluster.replication.index" @text="Replication" data-test-sidebar-nav-link="Replication" />
<Nav.Link
@route="vault.cluster.replication.index"
@text="Replication"
data-test-sidebar-nav-link="Replication"
@hasSubItems={{true}}
/>
{{/if}}
{{#if (and this.cluster.usingRaft this.namespace.inRootNamespace (has-permission "status" routeParams="raft"))}}
<Nav.Link

View File

@@ -76,7 +76,9 @@ export default class ClusterModel extends Model {
//replication mode - will only ever be 'unsupported'
//otherwise the particular mode will have the relevant mode attr through replication-attributes
@attr('string') mode;
// eg dr.mode or performance.mode
@attr('string')
mode;
get allReplicationDisabled() {
return this.dr?.replicationDisabled && this.performance?.replicationDisabled;
}

View File

@@ -11,8 +11,11 @@
margin-bottom: $spacing-24;
}
.action-block-width {
width: 100%;
}
.action-block {
box-shadow: 0 0 0 1px rgba($grey-dark, 0.3);
grid-template-columns: 2fr 1fr;
display: grid;
padding: $spacing-16 $spacing-24;

View File

@@ -0,0 +1,40 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
~}}
<Hds::Card::Container
@hasBorder={{true}}
class="replication-summary-card card-container summary"
data-test-replication-summary-card
>
<h3 class="title is-5 grid-item-top-left card-title">{{@title}}</h3>
<div class="grid-item-top-right">
<Hds::Button
@route="mode.index"
@model={{this.key}}
@text="Details"
@color="tertiary"
@icon="chevron-right"
@iconPosition="trailing"
data-test-manage-link={{@title}}
/>
</div>
<div class="grid-item-left">
<p class="title is-6">last_dr_wal</p>
<p class="helper-text is-label has-text-grey">
Index of last WAL entry written on local storage. Updates every ten seconds.
</p>
</div>
<div class="grid-item-right">
<p class="title is-6">known_secondaries</p>
<p class="helper-text is-label has-text-grey">Number of secondaries connected to this primary.</p>
</div>
<p class="title is-3 grid-item-bottom-left" data-test-lastWAL>{{format-number this.lastWAL}}</p>
<p class="title is-3 grid-item-bottom-right" data-test-known-secondaries>{{format-number this.knownSecondariesCount}}</p>
<div class="grid-item-bottom-row">
<p class="title is-6">merkle_root</p>
<p class="helper-text is-label has-text-grey">A snapshot of the merkle tree's root hash.</p>
<div><code class="is-word-break has-text-black" data-test-merkle-root>{{this.merkleRoot}}</code></div>
</div>
</Hds::Card::Container>

View File

@@ -3,9 +3,8 @@
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@ember/component';
import { computed } from '@ember/object';
import layout from '../templates/components/replication-summary-card';
import { get } from '@ember/object';
import Component from '@glimmer/component';
/**
* @module ReplicationSummaryCard
@@ -22,28 +21,17 @@ import layout from '../templates/components/replication-summary-card';
* @param {Object} replicationDetails=null - An Ember data object computed off the Ember Model. It combines the Model.dr and Model.performance objects into one and contains details specific to the mode replication.
*/
export default Component.extend({
layout,
title: null,
replicationDetails: null,
lastDrWAL: computed('replicationDetails.dr.lastWAL', function () {
return this.replicationDetails.dr.lastWAL || 0;
}),
lastPerformanceWAL: computed('replicationDetails.performance.lastWAL', function () {
return this.replicationDetails.performance.lastWAL || 0;
}),
merkleRootDr: computed('replicationDetails.dr.merkleRoot', function () {
return this.replicationDetails.dr.merkleRoot || '';
}),
merkleRootPerformance: computed('replicationDetails.performance.merkleRoot', function () {
return this.replicationDetails.performance.merkleRoot || '';
}),
knownSecondariesDr: computed('replicationDetails.dr.knownSecondaries', function () {
const knownSecondaries = this.replicationDetails.dr.knownSecondaries;
return knownSecondaries.length;
}),
knownSecondariesPerformance: computed('replicationDetails.performance.knownSecondaries', function () {
const knownSecondaries = this.replicationDetails.performance.knownSecondaries;
return knownSecondaries.length;
}),
});
export default class ReplicationSummaryCard extends Component {
get key() {
return this.args.title === 'Performance' ? 'performance' : 'dr';
}
get lastWAL() {
return get(this.args.replicationDetails, `${this.key}.lastWAL`) || 0;
}
get merkleRoot() {
return get(this.args.replicationDetails, `${this.key}.merkleRoot`) || 'no hash found';
}
get knownSecondariesCount() {
return get(this.args.replicationDetails, `${this.key}.knownSecondaries.length`) || 0;
}
}

View File

@@ -13,12 +13,14 @@
as |replicationAction|
}}
<div class="replication-actions-grid-item">
{{component
(concat "replication-action-" replicationAction)
onSubmit=(action "onSubmit")
replicationMode=this.replicationMode
model=this.model
}}
<Hds::Card::Container class="action-block-width" @hasBorder={{true}}>
{{component
(concat "replication-action-" replicationAction)
onSubmit=(action "onSubmit")
replicationMode=this.replicationMode
model=this.model
}}
</Hds::Card::Container>
</div>
{{/each}}
</div>

View File

@@ -20,7 +20,7 @@
{{/unless}}
</p.top>
<p.levelLeft>
<h1 class="title is-3">
<h1 class="title is-3" data-test-replication-title>
{{this.title}}
{{#if this.data.anyReplicationEnabled}}
<span class="tag is-light has-text-grey-dark" data-test-mode>

View File

@@ -110,16 +110,13 @@
</div>
</div>
<div class="level-right">
{{#if this.replicationDisabled}}
<Hds::Button
@text="Enable"
@route="mode.index"
@models={{array this.cluster.name this.mode}}
data-test-replication-promote-secondary
/>
{{else}}
<Hds::Button @text="Details" @color="secondary" @route="mode.index" @models={{array this.cluster.name this.mode}} />
{{/if}}
<Hds::Button
@route="mode.index"
@models={{array this.cluster.name this.mode}}
@color={{if this.replicationDisabled "primary" "secondary"}}
@text={{if this.replicationDisabled "Enable" "Details"}}
data-test-replication-details-link={{this.mode}}
/>
</div>
</div>
{{/if}}

View File

@@ -1,63 +0,0 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
~}}
<Hds::Card::Container
@hasBorder={{true}}
class="replication-summary-card card-container summary {{if this.hasErrorClass 'has-error-border'}}"
data-test-replication-summary-card
>
{{! Check if DR or Performance Card }}
{{#if (eq this.title "Disaster Recovery")}}
<h3 class="title is-5 grid-item-top-left card-title">{{this.title}}</h3>
<div class="grid-item-top-right">
<ToolbarLink @route="mode.index" @model="dr" data-test-manage-link={{this.title}}>
Details
</ToolbarLink>
</div>
<div class="grid-item-left">
<h6 class="title is-6">last_dr_wal</h6>
<p class="helper-text is-label has-text-grey">
Index of last WAL entry written on local storage. Updates every ten seconds.
</p>
</div>
<div class="grid-item-right">
<h6 class="title is-6">known_secondaries</h6>
<p class="helper-text is-label has-text-grey">Number of secondaries connected to this primary.</p>
</div>
<h2 class="title is-3 grid-item-bottom-left" data-test-lastWAL>{{format-number this.lastDrWAL}}</h2>
<h2 class="title is-3 grid-item-bottom-right" data-test-known-secondaries>{{format-number this.knownSecondariesDr}}</h2>
<div class="grid-item-bottom-row">
<h6 class="title is-6">merkle_root</h6>
<p class="helper-text is-label has-text-grey">A snapshot of the merkle tree's root hash.</p>
<div><code class="is-word-break has-text-black">{{this.merkleRootDr}}</code></div>
</div>
{{else}}
<h3 class="title is-5 grid-item-top-left card-title">{{this.title}}</h3>
<div class="grid-item-top-right">
<ToolbarLink @route="mode.index" @model="performance" data-test-manage-link={{this.title}}>
Details
</ToolbarLink>
</div>
<div class="grid-item-left">
<h6 class="title is-6">last_performance_wal</h6>
<p class="helper-text is-label has-text-grey">
Index of last WAL entry written on local storage. Updates every ten seconds.
</p>
</div>
<div class="grid-item-right">
<h6 class="title is-6">known_secondaries</h6>
<p class="helper-text is-label has-text-grey">Number of secondaries connected to this primary.</p>
</div>
<h2 class="title is-3 grid-item-bottom-left" data-test-lastWAL>{{format-number this.lastPerformanceWAL}}</h2>
<h2 class="title is-3 grid-item-bottom-right" data-test-known-secondaries>
{{format-number this.knownSecondariesPerformance}}
</h2>
<div class="grid-item-bottom-row">
<h6 class="title is-6">merkle_root</h6>
<p class="helper-text is-label has-text-grey">A snapshot of the merkle tree's root hash.</p>
<div><code class="is-word-break has-text-black">{{this.merkleRootPerformance}}</code></div>
</div>
{{/if}}
</Hds::Card::Container>

View File

@@ -14,8 +14,17 @@ const Eng = Engine.extend({
modulePrefix,
Resolver,
dependencies: {
services: ['auth', 'flash-messages', 'namespace', 'replication-mode', 'router', 'store', 'version'],
externalRoutes: ['replication'],
services: [
'auth',
'flash-messages',
'namespace',
'replication-mode',
'router',
'store',
'version',
'-portal',
],
externalRoutes: ['replication', 'vault'],
},
});

View File

@@ -3,4 +3,32 @@
SPDX-License-Identifier: BUSL-1.1
~}}
<Hds::SideNav::Portal @ariaLabel="Replication Navigation Links" data-test-sidebar-nav-panel="Replication" as |Nav|>
<Nav.BackLink
@route="vault"
@current-when={{false}}
@isRouteExternal={{true}}
@icon="arrow-left"
@text="Back to main navigation"
data-test-sidebar-nav-link="Back to main navigation"
/>
<Nav.Title data-test-sidebar-nav-heading="Replication">Replication</Nav.Title>
<Nav.Link
@route="replication"
@current-when="replication"
@isRouteExternal={{true}}
@text="Overview"
data-test-sidebar-nav-link="Overview"
/>
{{#if (not-eq this.model.mode "unsupported")}}
{{#if (has-feature "DR Replication")}}
<Nav.Link @route="mode" @model="dr" @text="Disaster Recovery" data-test-sidebar-nav-link="Disaster Recovery" />
{{/if}}
{{#if (has-feature "Performance Replication")}}
<Nav.Link @route="mode" @model="performance" @text="Performance" data-test-sidebar-nav-link="Performance" />
{{/if}}
{{/if}}
</Hds::SideNav::Portal>
{{outlet}}

View File

@@ -8,7 +8,7 @@
{{else if (or this.cluster.allReplicationDisabled this.cluster.replicationAttrs.replicationDisabled)}}
<PageHeader as |p|>
<p.levelLeft>
<h1 class="title is-3">
<h1 class="title is-3" data-test-replication-title>
{{#if this.initialReplicationMode}}
{{#if (eq this.initialReplicationMode "dr")}}
Enable Disaster Recovery Replication
@@ -36,6 +36,7 @@
replicationMode=this.replicationMode
)
}}
data-test-replication-enable-form
>
<div class="box is-sideless is-fullwidth is-marginless">
<MessageError @errors={{this.errors}} />
@@ -291,7 +292,7 @@
{{#if (not (and this.cluster.dr.replicationEnabled this.cluster.performance.replicationEnabled))}}
<PageHeader as |p|>
<p.levelLeft>
<h1 class="title is-3">
<h1 class="title is-3" data-test-replication-title>
Replication
</h1>
</p.levelLeft>

View File

@@ -0,0 +1,130 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { click, visit } from '@ember/test-helpers';
import authPage from 'vault/tests/pages/auth';
import { STATUS_DISABLED_RESPONSE, mockReplicationBlock } from 'vault/tests/helpers/replication';
const s = {
navLink: (title) => `[data-test-sidebar-nav-link="${title}"]`,
title: '[data-test-replication-title]',
detailLink: (mode) => `[data-test-replication-details-link="${mode}"]`,
summaryCard: '[data-test-replication-summary-card]',
dashboard: '[data-test-replication-dashboard]',
enableForm: '[data-test-replication-enable-form]',
knownSecondary: (name) => `[data-test-secondaries-node="${name}"]`,
};
module('Acceptance | Enterprise | replication modes', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(async function () {
this.setupMocks = (payload) => {
this.server.get('sys/replication/status', () => ({
data: payload,
}));
return authPage.login();
};
});
test('replication page when unsupported', async function (assert) {
await this.setupMocks({
data: {
mode: 'unsupported',
},
});
await visit('/vault/replication');
assert.dom(s.title).hasText('Replication unsupported', 'it shows the unsupported view');
// Nav links
assert.dom(s.navLink('Performance')).doesNotExist('hides performance link');
assert.dom(s.navLink('Disaster Recovery')).doesNotExist('hides dr link');
});
test('replication page when disabled', async function (assert) {
await this.setupMocks(STATUS_DISABLED_RESPONSE);
await visit('/vault/replication');
assert.dom(s.title).hasText('Enable Replication', 'it shows the enable view');
// Nav links
assert.dom(s.navLink('Performance')).exists('shows performance link');
assert.dom(s.navLink('Disaster Recovery')).exists('shows dr link');
await click(s.navLink('Performance'));
assert.dom(s.title).hasText('Enable Performance Replication', 'it shows the enable view for performance');
await click(s.navLink('Disaster Recovery'));
assert.dom(s.title).hasText('Enable Disaster Recovery Replication', 'it shows the enable view for dr');
});
['primary', 'secondary'].forEach((mode) => {
test(`replication page when perf ${mode} only`, async function (assert) {
await this.setupMocks({
dr: mockReplicationBlock(),
performance: mockReplicationBlock(mode),
});
await visit('/vault/replication');
assert.dom(s.title).hasText('Replication', 'it shows default view');
assert.dom(s.detailLink('performance')).hasText('Details', 'CTA to see performance details');
assert.dom(s.detailLink('dr')).hasText('Enable', 'CTA to enable dr');
// Nav links
assert.dom(s.navLink('Performance')).exists('shows performance link');
assert.dom(s.navLink('Disaster Recovery')).exists('shows dr link');
await click(s.navLink('Performance'));
assert.dom(s.title).hasText(`Performance ${mode}`, `it shows the performance title`);
assert.dom(s.dashboard).exists(`it shows the replication dashboard`);
await click(s.navLink('Disaster Recovery'));
assert.dom(s.title).hasText('Enable Disaster Recovery Replication', 'it shows the dr title');
assert.dom(s.enableForm).exists('it shows the enable view for dr');
});
});
// DR secondary mode is a whole other thing, test primary only here
test(`replication page when dr primary only`, async function (assert) {
await this.setupMocks({
dr: mockReplicationBlock('primary'),
performance: mockReplicationBlock(),
});
await visit('/vault/replication');
assert.dom(s.title).hasText('Replication', 'it shows default view');
assert.dom(s.detailLink('performance')).hasText('Enable', 'CTA to enable performance');
assert.dom(s.detailLink('dr')).hasText('Details', 'CTA to see dr details');
// Nav links
assert.dom(s.navLink('Performance')).exists('shows performance link');
assert.dom(s.navLink('Disaster Recovery')).exists('shows dr link');
await click(s.navLink('Performance'));
assert.dom(s.title).hasText(`Enable Performance Replication`, `it shows the performance title`);
assert.dom(s.enableForm).exists('it shows the enable view for performance');
await click(s.navLink('Disaster Recovery'));
assert.dom(s.title).hasText(`Disaster Recovery primary`, 'it shows the dr title');
assert.dom(s.dashboard).exists(`it shows the replication dashboard`);
});
test(`replication page both primary`, async function (assert) {
await this.setupMocks({
dr: mockReplicationBlock('primary'),
performance: mockReplicationBlock('primary'),
});
await visit('/vault/replication');
assert.dom(s.title).hasText('Disaster Recovery & Performance primary', 'it shows primary view');
assert.dom(s.summaryCard).exists({ count: 2 }, 'shows 2 summary cards');
await click(s.navLink('Performance'));
assert.dom(s.title).hasText(`Performance primary`, `it shows the performance mode details`);
await click(s.navLink('Disaster Recovery'));
assert.dom(s.title).hasText(`Disaster Recovery primary`, 'it shows the dr mode details');
});
});

View File

@@ -306,7 +306,7 @@ module('Acceptance | Enterprise | replication', function (hooks) {
.doesNotExist(`does not render replication summary card when both modes are not enabled as primary`);
// enable DR primary replication
await click('[data-test-replication-promote-secondary]');
await click('[data-test-replication-details-link="dr"]');
await click('[data-test-replication-enable]');
await pollCluster(this.owner);

View File

@@ -1,33 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
import authPage from 'vault/tests/pages/auth';
import { visit } from '@ember/test-helpers';
module('Acceptance | Enterprise | replication unsupported', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(async function () {
this.server.get('/sys/replication/status', function () {
return {
data: {
mode: 'unsupported',
},
};
});
return authPage.login();
});
test('replication page when unsupported', async function (assert) {
await visit('/vault/replication');
assert
.dom('[data-test-replication-title]')
.hasText('Replication unsupported', 'it shows the unsupported view');
});
});

View File

@@ -5,7 +5,7 @@
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { click, currentURL, fillIn } from '@ember/test-helpers';
import { click, currentURL } from '@ember/test-helpers';
import { setupMirage } from 'ember-cli-mirage/test-support';
import authPage from 'vault/tests/pages/auth';
@@ -22,11 +22,15 @@ module('Acceptance | Enterprise | sidebar navigation', function (hooks) {
// common links are tested in the sidebar-nav test and will not be covered here
test('it should render enterprise only navigation links', async function (assert) {
assert.expect(12);
assert.dom(panel('Cluster')).exists('Cluster nav panel renders');
await click(link('Replication'));
assert.strictEqual(currentURL(), '/vault/replication', 'Replication route renders');
await click('[data-test-replication-enable]');
assert.dom(panel('Replication')).exists(`Replication nav panel renders`);
assert.dom(link('Overview')).hasClass('active', 'Overview link is active');
assert.dom(link('Performance')).exists('Performance link exists');
assert.dom(link('Disaster Recovery')).exists('DR link exists');
await click(link('Performance'));
assert.strictEqual(
@@ -37,11 +41,6 @@ module('Acceptance | Enterprise | sidebar navigation', function (hooks) {
await click(link('Disaster Recovery'));
assert.strictEqual(currentURL(), '/vault/replication/dr', 'Replication dr route renders');
// disable replication now that we have checked the links
await click('[data-test-replication-link="manage"]');
await click('[data-test-replication-action-trigger]');
await fillIn('[data-test-confirmation-modal-input="Disable Replication?"]', 'Disaster Recovery');
await click('[data-test-confirm-button="Disable Replication?"]');
await click(link('Client Count'));
assert.strictEqual(currentURL(), '/vault/clients/dashboard', 'Client counts route renders');

View File

@@ -34,3 +34,63 @@ export const disableReplication = async (type, assert) => {
await settled();
}
};
export const STATUS_DISABLED_RESPONSE = {
dr: mockReplicationBlock(),
performance: mockReplicationBlock(),
};
/**
* Mock replication block returns the expected payload for a given replication type
* @param {string} mode disabled | primary | secondary
* @param {string} status connected | disconnected
* @returns expected object for a single replication type, eg dr or performance values
*/
export function mockReplicationBlock(mode = 'disabled', status = 'connected') {
switch (mode) {
case 'primary':
return {
cluster_id: '5f20f5ab-acea-0481-787e-71ec2ff5a60b',
known_secondaries: ['4'],
last_wal: 455,
merkle_root: 'aaaaaabbbbbbbccccccccddddddd',
mode: 'primary',
primary_cluster_addr: '',
secondaries: [
{
api_address: 'https://127.0.0.1:49277',
cluster_address: 'https://127.0.0.1:49281',
connection_status: status,
last_heartbeat: '2020-06-10T15:40:46-07:00',
node_id: '4',
},
],
state: 'stream-wals',
};
case 'secondary':
return {
cluster_id: '5f20f5ab-acea-0481-787e-71ec2ff5a60b',
known_primary_cluster_addrs: ['https://127.0.0.1:8201'],
last_remote_wal: 291,
merkle_root: 'aaaaaabbbbbbbccccccccddddddd',
corrupted_merkle_tree: false,
last_corruption_check_epoch: '1694456090',
mode: 'secondary',
primaries: [
{
api_address: 'https://127.0.0.1:49244',
cluster_address: 'https://127.0.0.1:8201',
connection_status: status,
last_heartbeat: '2020-06-10T15:40:46-07:00',
},
],
primary_cluster_addr: 'https://127.0.0.1:8201',
secondary_id: '2',
state: 'stream-wals',
};
default:
return {
mode: 'disabled',
};
}
}

View File

@@ -5,7 +5,7 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { render, settled } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
const TITLE = 'Disaster Recovery';
@@ -15,11 +15,13 @@ const REPLICATION_DETAILS = {
state: 'running',
lastWAL: 10,
knownSecondaries: ['https://127.0.0.1:8201', 'https://127.0.0.1:8202'],
merkleRoot: 'zzzzzzzyyyyyyyxxxxxxxwwwwww',
},
performance: {
state: 'running',
lastWAL: 20,
knownSecondaries: ['https://127.0.0.1:8201'],
merkleRoot: 'aaaaaabbbbbbbbccccccccdddddd',
},
};
@@ -44,6 +46,9 @@ module('Integration | Component | replication-summary-card', function (hooks) {
assert
.dom('[data-test-known-secondaries]')
.includesText(knownSecondaries, `shows the correct computed value of the known secondaries count`);
assert
.dom('[data-test-merkle-root]')
.includesText(REPLICATION_DETAILS.dr.merkleRoot, `shows the correct merkle root value`);
});
test('it shows the correct lastWAL and knownSecondaries when title is Performance', async function (assert) {
@@ -58,5 +63,38 @@ module('Integration | Component | replication-summary-card', function (hooks) {
assert
.dom('[data-test-known-secondaries]')
.includesText(knownSecondaries, `shows the correct computed value of the known secondaries count`);
assert
.dom('[data-test-merkle-root]')
.includesText(REPLICATION_DETAILS.performance.merkleRoot, `shows the correct merkle root value`);
});
test('it shows reasonable defaults', async function (assert) {
const data = {
dr: {
mode: 'disabled',
},
performance: {
mode: 'disabled',
},
};
this.set('replicationDetails', data);
await render(
hbs`<ReplicationSummaryCard @replicationDetails={{this.replicationDetails}} @title={{this.title}} />`
);
assert.dom('[data-test-lastWAL]').includesText('0', `shows the correct lastWAL value`);
assert
.dom('[data-test-known-secondaries]')
.includesText('0', `shows the correct default value of the known secondaries count`);
assert.dom('[data-test-merkle-root]').includesText('', `shows the correct merkle root value`);
await this.set('title', 'Performance');
await settled();
assert.dom('[data-test-lastWAL]').includesText('0', `shows the correct lastWAL value`);
assert
.dom('[data-test-known-secondaries]')
.includesText('0', `shows the correct default value of the known secondaries count`);
assert
.dom('[data-test-merkle-root]')
.includesText('no hash found', `shows the correct merkle root value`);
});
});

View File

@@ -21,7 +21,7 @@ module('Integration | Component | sidebar-nav-cluster', function (hooks) {
setupRenderingTest(hooks);
test('it should render nav headings', async function (assert) {
const headings = ['Vault', 'Replication', 'Monitoring'];
const headings = ['Vault', 'Monitoring'];
stubFeaturesAndPermissions(this.owner, true, true);
await renderComponent();
@@ -52,8 +52,6 @@ module('Integration | Component | sidebar-nav-cluster', function (hooks) {
'Access',
'Policies',
'Tools',
'Disaster Recovery',
'Performance',
'Replication',
'Raft Storage',
'Client Count',