From 94b64a37e34665c392042a138427c36034bd7998 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
Date: Wed, 10 Apr 2024 09:44:57 -0500
Subject: [PATCH] UI: Replication page navigation fix (#26325)
* Add replication mirage handler
* Add test with skipped failed assertion
* Use component-calculated attrsForCurrentMode instead of cluster.replicationAttrs which wasn't triggering component updates
* assert previously-skipped assertion
* Add changelog
---
changelog/26325.txt | 3 +
.../addon/components/replication-summary.js | 6 +-
.../components/replication-summary.hbs | 14 +--
ui/mirage/handlers/index.js | 2 +
ui/mirage/handlers/replication.js | 107 ++++++++++++++++++
ui/tests/acceptance/replication-nav-test.js | 49 ++++++++
6 files changed, 172 insertions(+), 9 deletions(-)
create mode 100644 changelog/26325.txt
create mode 100644 ui/mirage/handlers/replication.js
create mode 100644 ui/tests/acceptance/replication-nav-test.js
diff --git a/changelog/26325.txt b/changelog/26325.txt
new file mode 100644
index 0000000000..cbfc6c1f9c
--- /dev/null
+++ b/changelog/26325.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+ui: fixed a bug where the replication pages did not update display when navigating between DR and performance
+```
diff --git a/ui/lib/replication/addon/components/replication-summary.js b/ui/lib/replication/addon/components/replication-summary.js
index 046d9f0f93..5a0bb0b4b9 100644
--- a/ui/lib/replication/addon/components/replication-summary.js
+++ b/ui/lib/replication/addon/components/replication-summary.js
@@ -4,7 +4,6 @@
*/
import { service } from '@ember/service';
-import { alias } from '@ember/object/computed';
import { computed } from '@ember/object';
import Component from '@ember/component';
import decodeConfigFromJWT from 'replication/utils/decode-config-from-jwt';
@@ -27,6 +26,7 @@ export default Component.extend(ReplicationActions, DEFAULTS, {
replicationMode: 'dr',
mode: 'primary',
version: service(),
+ rm: service('replication-mode'),
didReceiveAttrs() {
this._super(...arguments);
const initialReplicationMode = this.initialReplicationMode;
@@ -38,7 +38,9 @@ export default Component.extend(ReplicationActions, DEFAULTS, {
initialReplicationMode: null,
cluster: null,
- replicationAttrs: alias('cluster.replicationAttrs'),
+ attrsForCurrentMode: computed('cluster', 'rm.mode', function () {
+ return this.cluster[this.rm.mode];
+ }),
tokenIncludesAPIAddr: computed('token', function () {
const config = decodeConfigFromJWT(this.token);
diff --git a/ui/lib/replication/addon/templates/components/replication-summary.hbs b/ui/lib/replication/addon/templates/components/replication-summary.hbs
index 7fa582ffcb..963cef0199 100644
--- a/ui/lib/replication/addon/templates/components/replication-summary.hbs
+++ b/ui/lib/replication/addon/templates/components/replication-summary.hbs
@@ -334,7 +334,7 @@
{{/if}}
{{/if}}
{{else}}
- {{#if (eq this.replicationAttrs.mode "initializing")}}
+ {{#if (eq this.attrsForCurrentMode.mode "initializing")}}
The cluster is initializing replication. This may take some time.
{{else}}
{{this.cluster.replicationModeStatus.cluster_id}}
@@ -343,28 +343,28 @@
- {{#if (eq this.replicationAttrs.mode "secondary")}}
+ {{#if (eq this.attrsForCurrentMode.mode "secondary")}}
{{else}}
-
+
{{/if}}
diff --git a/ui/mirage/handlers/index.js b/ui/mirage/handlers/index.js
index 1c1e0d3b06..f7c290efc1 100644
--- a/ui/mirage/handlers/index.js
+++ b/ui/mirage/handlers/index.js
@@ -19,6 +19,7 @@ import mfaLogin from './mfa-login';
import oidcConfig from './oidc-config';
import reducedDisclosure from './reduced-disclosure';
import sync from './sync';
+import replication from './replication';
export {
base,
@@ -35,4 +36,5 @@ export {
reducedDisclosure,
customMessages,
sync,
+ replication,
};
diff --git a/ui/mirage/handlers/replication.js b/ui/mirage/handlers/replication.js
new file mode 100644
index 0000000000..4a1d2ff6c5
--- /dev/null
+++ b/ui/mirage/handlers/replication.js
@@ -0,0 +1,107 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+export default function (server) {
+ server.get('sys/replication/status', function () {
+ return {
+ data: {
+ dr: {
+ cluster_id: 'dr-cluster-id',
+ corrupted_merkle_tree: false,
+ known_secondaries: ['foobar'],
+ last_corruption_check_epoch: '-62135596800',
+ last_dr_wal: 98,
+ last_reindex_epoch: '0',
+ last_wal: 98,
+ merkle_root: 'ad721f32ed6789a1e5824841f358a517340a4585',
+ mode: 'primary',
+ primary_cluster_addr: 'dr-foobar',
+ secondaries: [
+ {
+ api_address: 'http://127.0.0.1:8202',
+ cluster_address: 'https://127.0.0.1:8203',
+ connection_status: 'disconnected',
+ last_heartbeat: '2024-04-09T09:04:22-05:00',
+ node_id: 'foobar',
+ },
+ ],
+ ssct_generation_counter: 0,
+ state: 'running',
+ },
+ performance: {
+ cluster_id: 'perf-cluster-id',
+ corrupted_merkle_tree: false,
+ known_secondaries: [],
+ last_corruption_check_epoch: '-62135596800',
+ last_performance_wal: 98,
+ last_reindex_epoch: '0',
+ last_wal: 98,
+ merkle_root: '618c9136bb443aa584f5d6b90755d42888c9c54a',
+ mode: 'primary',
+ primary_cluster_addr: 'perf-foobar',
+ secondaries: [],
+ ssct_generation_counter: 0,
+ state: 'running',
+ },
+ },
+ };
+ });
+
+ server.get('sys/replication/performance/status', function () {
+ return {
+ data: {
+ cluster_id: 'perf-cluster-id',
+ corrupted_merkle_tree: false,
+ known_secondaries: ['foobar'],
+ last_corruption_check_epoch: '-62135596800',
+ last_dr_wal: 98,
+ last_reindex_epoch: '0',
+ last_wal: 98,
+ merkle_root: 'ad721f32ed6789a1e5824841f358a517340a4585',
+ mode: 'primary',
+ primary_cluster_addr: 'perf-foobar',
+ secondaries: [
+ {
+ api_address: 'http://127.0.0.1:8202',
+ cluster_address: 'https://127.0.0.1:8203',
+ connection_status: 'disconnected',
+ last_heartbeat: '2024-04-09T09:04:22-05:00',
+ node_id: 'foobar',
+ },
+ ],
+ ssct_generation_counter: 0,
+ state: 'running',
+ },
+ };
+ });
+
+ server.get('sys/replication/dr/status', function () {
+ return {
+ data: {
+ cluster_id: 'dr-cluster-id',
+ corrupted_merkle_tree: false,
+ known_secondaries: ['foobar'],
+ last_corruption_check_epoch: '-62135596800',
+ last_dr_wal: 98,
+ last_reindex_epoch: '0',
+ last_wal: 98,
+ merkle_root: 'ad721f32ed6789a1e5824841f358a517340a4585',
+ mode: 'primary',
+ primary_cluster_addr: 'dr-foobar',
+ secondaries: [
+ {
+ api_address: 'http://127.0.0.1:8202',
+ cluster_address: 'https://127.0.0.1:8203',
+ connection_status: 'disconnected',
+ last_heartbeat: '2024-04-09T09:04:22-05:00',
+ node_id: 'foobar',
+ },
+ ],
+ ssct_generation_counter: 0,
+ state: 'running',
+ },
+ };
+ });
+}
diff --git a/ui/tests/acceptance/replication-nav-test.js b/ui/tests/acceptance/replication-nav-test.js
new file mode 100644
index 0000000000..fc5bcfa3cd
--- /dev/null
+++ b/ui/tests/acceptance/replication-nav-test.js
@@ -0,0 +1,49 @@
+/**
+ * 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 replicationHandlers from 'vault/mirage/handlers/replication';
+import { click } from '@ember/test-helpers';
+
+const SELECTORS = {
+ navReplication: '[data-test-sidebar-nav-link="Replication"]',
+ navPerformance: '[data-test-sidebar-nav-link="Performance"]',
+ navDR: '[data-test-sidebar-nav-link="Disaster Recovery"]',
+ title: '[data-test-replication-title]',
+ primaryCluster: '[data-test-value-div="primary_cluster_addr"]',
+ replicationSet: '[data-test-row-value="Replication set"]',
+ knownSecondariesTitle: '.known-secondaries-card h3',
+};
+module('Acceptance | Enterprise | replication navigation', function (hooks) {
+ setupApplicationTest(hooks);
+ setupMirage(hooks);
+
+ hooks.beforeEach(function () {
+ replicationHandlers(this.server);
+ return authPage.login();
+ });
+
+ test('navigate between replication types updates page', async function (assert) {
+ await click(SELECTORS.navReplication);
+ assert.dom(SELECTORS.title).hasText('Disaster Recovery & Performance primary');
+ await click(SELECTORS.navPerformance);
+
+ // Ensure data is expected for performance
+ assert.dom(SELECTORS.title).hasText('Performance primary');
+ assert.dom(SELECTORS.primaryCluster).hasText('perf-foobar');
+ assert.dom(SELECTORS.replicationSet).hasText('perf-cluster-id');
+ assert.dom(SELECTORS.knownSecondariesTitle).hasText('0 Known secondaries');
+
+ // Nav to DR and see updated data
+ await click(SELECTORS.navDR);
+ assert.dom(SELECTORS.title).hasText('Disaster Recovery primary');
+ assert.dom(SELECTORS.primaryCluster).hasText('dr-foobar');
+ assert.dom(SELECTORS.replicationSet).hasText('dr-cluster-id');
+ assert.dom(SELECTORS.knownSecondariesTitle).hasText('1 Known secondaries');
+ });
+});