Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ui/summary dashboard #9079

Merged
merged 34 commits into from
May 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
befb629
move key value to lib/core/addon so I can use inside replication engine
Monkeychip May 26, 2020
05e52ca
setup summary dasbhoard on replication summary component
Monkeychip May 26, 2020
a912311
set title for summary dashboard
andaley May 26, 2020
01fd5b2
do not show replication table rows on summary dashboard
andaley May 26, 2020
c890cdc
show that last_wal updates every 10 seconds
andaley May 26, 2020
0121803
show replication table rows on individual dashboards, but not summary
andaley May 27, 2020
a1dd392
remove extra bottom border on replication-dashboard
andaley May 27, 2020
1cd1fc8
add replicationDetailsSummary object and replication-summary-card
Monkeychip May 27, 2020
e71f023
setup structure and data calcs of replication summary card
Monkeychip May 27, 2020
536a9a8
fix links and styling on summary card
Monkeychip May 27, 2020
ee43fcb
breadcrumbs
Monkeychip May 27, 2020
a0f4fca
match state title on summary dashboard to individual dashboards
andaley May 27, 2020
59e29e3
add margin below replication header
andaley May 27, 2020
68f34fb
update breadcrumbs to show replication mode
andaley May 27, 2020
59df88c
align details link right
andaley May 27, 2020
fe2ebc6
add margin below tabs in replication header
andaley May 27, 2020
e00460f
user helper-text to make card text styling consistent across dashboards
andaley May 27, 2020
ca03f9f
remove unneeded code
andaley May 27, 2020
716de2e
add bottom border to summary state
andaley May 27, 2020
38846bc
add bottom margin to summary dashboard
andaley May 27, 2020
fc17ec7
add negative margins to bring values closer to related cell
Monkeychip May 28, 2020
b81dce9
fix failing test due to data-test attribute change and make storybook…
Monkeychip May 28, 2020
eefc064
setup replication summary card test. I suspect we'll move the hasErr…
Monkeychip May 28, 2020
3dff903
add to replication acceptance test for new summary dashboard
Monkeychip May 28, 2020
1b42499
remove pauseTest
Monkeychip May 28, 2020
bb2b4c8
add is-active to li element
Monkeychip May 28, 2020
df1464e
clean up
Monkeychip May 28, 2020
d092a01
dashboard test and clean up
Monkeychip May 28, 2020
901ad25
addressing pr comments
Monkeychip May 29, 2020
2f58e27
fix replication/null/status error
Monkeychip May 29, 2020
54d578a
add JSDocs for rep page and rep dash
Monkeychip May 29, 2020
74ddb0e
more pr cleanup
Monkeychip May 29, 2020
38e67d4
remove conditional and fix styling blue link
Monkeychip May 29, 2020
e29493b
fix conditional on when loading summary dashboard to check for primar…
Monkeychip May 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ui/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ App = Application.extend({
'version',
'wizard',
],
externalRoutes: {
replication: 'vault.cluster.replication.index',
},
},
},
kmip: {
Expand Down
37 changes: 33 additions & 4 deletions ui/app/styles/components/replication-dashboard.scss
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
.replication-dashboard {
box-shadow: none;

.selectable-card {
line-height: normal;

&:hover {
box-shadow: 0 0 0 1px rgba($grey-dark, 0.3);
}

.toolbar-link {
color: $blue-500;
}
}

.helper-text {
Expand All @@ -24,7 +30,8 @@
margin-top: $spacing-xl;
display: grid;

&.primary {
&.primary,
.summary {
margin: 2rem 0 2rem 0;
grid-template-columns: 1fr 2fr;

Expand All @@ -35,7 +42,7 @@

&.secondary {
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
grid-gap: $spacing-xl; //ARG TODO double check ok
grid-gap: $spacing-xl;
}

.card-container {
Expand All @@ -46,6 +53,10 @@
padding: $spacing-l;
line-height: 1.5;

&.summary {
grid-template-rows: 0.2fr 1fr 0.2fr 1fr;
}

&.has-border-danger:hover {
box-shadow: none;
}
Expand All @@ -55,10 +66,14 @@
min-height: 250px;
}

.grid-item-title {
grid-column: 1 / span 2;
.grid-item-top-left {
grid-column: 1 / span 1;
display: flex;
}
.grid-item-top-right {
grid-column: 2 / span 1;
justify-self: right;
}
.grid-item-left {
grid-column: 1/1;
grid-row: 2/2;
Expand All @@ -70,15 +85,29 @@
.grid-item-left-bottom {
grid-column: 1/1;
grid-row: 3/3;
margin-top: -8px;

display: flex;
align-items: center;
}
.grid-item-right-bottom {
grid-column: 2/2;
grid-row: 3/3;
margin-top: -8px;
}
.grid-item-full-bottom {
grid-column: 1 / span 2;
grid-row: 4/4;
}
}

&.summary {
margin-bottom: $spacing-xl;
}
}
.summary-state {
padding-bottom: $spacing-xl;
border-bottom: 1px solid rgba($grey-dark, 0.3);
}

// prevent double lines at the bottom of the dashboard
Expand Down
5 changes: 5 additions & 0 deletions ui/app/styles/components/replication-header.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.replication-header {
.tabs-container {
margin-bottom: $spacing-l;
}
}
1 change: 1 addition & 0 deletions ui/app/styles/core.scss
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
@import './components/raft-join';
@import './components/replication-dashboard';
@import './components/replication-doc-link';
@import './components/replication-header';
@import './components/replication-page';
@import './components/replication-primary-card';
@import './components/replication-summary';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { computed } from '@ember/object';
import Component from '@ember/component';
import utils from 'vault/lib/key-utils';
import layout from '../templates/components/key-value-header';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default Component.extend({
layout,
tagName: 'nav',
classNames: 'key-value-header breadcrumb',
ariaLabel: 'breadcrumbs',
Expand Down
52 changes: 51 additions & 1 deletion ui/lib/core/addon/components/replication-dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,43 @@ import { clusterStates } from 'core/helpers/cluster-states';
import { capitalize } from '@ember/string';
import layout from '../templates/components/replication-dashboard';

/**
* @module ReplicationDashboard
* The `ReplicationDashboard` component is a contextual component of the replication-page component.
* It organizes cluster data specific to mode (dr or performance) and also the type (primary or secondary).
* It is the parent contextual component of the replication-<name>-card components.
*
* @example
* ```js
* <ReplicationDashboard
@data={{model}}
@componentToRender='replication-primary-card'
@isSecondary=false
@isSummaryDashboard=false
@replicationDetailsSummary={}
@replicationDetails={{replicationDetails}}
@clusterMode=primary
@reindexingDetails={{reindexingDetails}}
/>
* ```
* @param {Object} data=null - An Ember data object that is pulled from the Ember Cluster Model.
* @param {String} [componentToRender=''] - A string that determines which card component is displayed. There are three options, replication-primary-card, replication-secondary-card, replication-summary-card.
* @param {Boolean} [isSecondary=false] - Used to determine the title and display logic.
* @param {Boolean} [isSummaryDashboard=false] - Only true when the cluster is both a dr and performance primary. If true, replicationDetailsSummary is populated and used to pass through the cluster details.
* @param {Object} replicationDetailsSummary=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.
* @param {Object} replicationDetails=null - An Ember data object pulled from the Ember Model. It contains details specific to the whether the replication is dr or performance.
* @param {String} clusterMode=null - The cluster mode passed through to a table component.
* @param {Object} reindexingDetails=null - An Ember data object used to show a reindexing progress bar.
*/

export default Component.extend({
layout,
componentToRender: '',
data: null,
isSecondary: false,
isSummaryDashboard: false,
replicationDetails: null,
isSecondary: null,
replicationDetailsSummary: null,
isSyncing: computed('replicationDetails.{state}', 'isSecondary', function() {
const { state } = this.replicationDetails;
const isSecondary = this.isSecondary;
Expand Down Expand Up @@ -40,4 +72,22 @@ export default Component.extend({

return progressBar;
}),
summaryState: computed(
'replicationDetailsSummary.dr.{state}',
'replicationDetailsSummary.performance.{state}',
function() {
const { replicationDetailsSummary } = this;
const drState = replicationDetailsSummary.dr.state;
const performanceState = replicationDetailsSummary.performance.state;

if (drState !== performanceState) {
// when DR and Performance is enabled on the same cluster,
// the states should always be the same
// we are leaving this console log statement to be sure
console.log('DR State: ', drState, 'Performance State: ', performanceState);
}

return drState;
}
),
});
2 changes: 2 additions & 0 deletions ui/lib/core/addon/components/replication-header.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import layout from '../templates/components/replication-header';

export default Component.extend({
layout,
classNames: ['replication-header'],
isSecondary: null,
secondaryId: null,
isSummaryDashboard: false,
'data-test-replication-header': true,
});
71 changes: 67 additions & 4 deletions ui/lib/core/addon/components/replication-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ import layout from '../templates/components/replication-page';
import { inject as service } from '@ember/service';
import { task } from 'ember-concurrency';

/**
* @module ReplicationPage
* The `ReplicationPage` component is the parent contextual component that holds the replication-dashboard, and various replication-<name>-card components.
* It is the top level component on routes displaying replication dashboards.
*
* @example
* ```js
* <ReplicationPage
@model={{cluster}}
/>
* ```
* @param {Object} cluster=null - An Ember data object that is pulled from the Ember Cluster Model.
*/

const MODE = {
dr: 'Disaster Recovery',
performance: 'Performance',
Expand All @@ -12,6 +26,7 @@ const MODE = {
export default Component.extend({
Monkeychip marked this conversation as resolved.
Show resolved Hide resolved
layout,
store: service(),
router: service(),
reindexingDetails: null,
didReceiveAttrs() {
this._super(arguments);
Expand All @@ -20,6 +35,13 @@ export default Component.extend({
getReplicationModeStatus: task(function*() {
let resp;
const { replicationMode } = this.model;

if (this.isSummaryDashboard) {
// the summary dashboard is not mode specific and will error
// while running replication/null/status in the replication-mode adapter
return;
}

try {
resp = yield this.get('store')
.adapterFor('replication-mode')
Expand All @@ -29,22 +51,45 @@ export default Component.extend({
}
this.set('reindexingDetails', resp);
}),
formattedReplicationMode: computed('model.{replicationMode}', function() {
isSummaryDashboard: computed('model.dr.{mode}', 'model.performance.{mode}', function() {
const router = this.router;
const currentRoute = router.get('currentRouteName');

// we only show the summary dashboard in the replication index route
if (currentRoute === 'vault.cluster.replication.index') {
const drMode = this.model.dr.mode;
const performanceMode = this.model.performance.mode;
return drMode === 'primary' && performanceMode === 'primary';
}
}),
formattedReplicationMode: computed('model.{replicationMode}', 'isSummaryDashboard', function() {
// dr or performance 🤯
const { isSummaryDashboard } = this;
if (isSummaryDashboard) {
return 'Disaster Recovery & Performance';
}
const mode = this.model.replicationMode;
return MODE[mode];
}),
clusterMode: computed('model.{replicationAttrs}', function() {
clusterMode: computed('model.{replicationAttrs}', 'isSummaryDashboard', function() {
Monkeychip marked this conversation as resolved.
Show resolved Hide resolved
// primary or secondary
const { model } = this;
const { isSummaryDashboard } = this;
if (isSummaryDashboard) {
// replicationAttrs does not exist when summaryDashboard
return 'primary';
}
return model.replicationAttrs.mode;
}),
isLoadingData: computed('clusterMode', 'model.{replicationAttrs}', function() {
const { clusterMode } = this;
const { model } = this;
const { isSummaryDashboard } = this;
if (isSummaryDashboard) {
return false;
}
const clusterId = model.replicationAttrs.clusterId;
const replicationDisabled = model.replicationAttrs.replicationDisabled;

if (clusterMode === 'bootstrapping' || (!clusterId && !replicationDisabled)) {
// if clusterMode is bootstrapping
// if no clusterId, the data hasn't loaded yet, wait for another status endpoint to be called
Expand All @@ -56,8 +101,26 @@ export default Component.extend({
const { clusterMode } = this;
return clusterMode === 'secondary';
}),
replicationDetails: computed('model.{replicationMode}', function() {
replicationDetailsSummary: computed('isSummaryDashboard', function() {
const { model } = this;
const { isSummaryDashboard } = this;
if (!isSummaryDashboard) {
return;
}
if (isSummaryDashboard) {
let combinedObject = {};
combinedObject.dr = model['dr'];
combinedObject.performance = model['performance'];
return combinedObject;
}
}),
replicationDetails: computed('model.{replicationMode}', 'isSummaryDashboard', function() {
const { model } = this;
const { isSummaryDashboard } = this;
if (isSummaryDashboard) {
// Cannot return null
return {};
}
const replicationMode = model.replicationMode;
return model[replicationMode];
}),
Expand Down
8 changes: 4 additions & 4 deletions ui/lib/core/addon/components/replication-secondary-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import { clusterStates } from 'core/helpers/cluster-states';

/**
* @module ReplicationSecondaryCard
* ReplicationSecondaryCard components
* The `ReplicationSecondaryCard` component is a card-like component. It displays cluster mode details specific for DR and Performance Secondaries.
*
* @example
* ```js
* <ReplicationSecondaryCard
@title='States'
@replicationDetails=replicationDetails
@replicationDetails={{replicationDetails}}
/>
* ```
* @param {string} [title=null] - The title to be displayed on the top left corner of the card.
* @param replicationDetails=null{DS.Model.replicationDetails} - An Ember data object off the Ember data model. It is computed at the parent component and passed through to this component.
* @param {String} [title=null] - The title to be displayed on the top left corner of the card.
* @param {Object} replicationDetails=null - An Ember data object pulled from the Ember Model. It contains details specific to the mode's replication.
*/

export default Component.extend({
Expand Down
44 changes: 44 additions & 0 deletions ui/lib/core/addon/components/replication-summary-card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import layout from '../templates/components/replication-summary-card';

/**
* @module ReplicationSummaryCard
* The `ReplicationSummaryCard` is a card-like component. It displays cluster mode details for both DR and Performance
*
* @example
* ```js
* <ReplicationSummaryCard
@title='States'
@replicationDetails={DS.Model.replicationDetailsSummary}
/>
* ```
* @param {String} [title=null] - The title to be displayed on the top left corner of the 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() {
Monkeychip marked this conversation as resolved.
Show resolved Hide resolved
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;
}),
});
Loading