Skip to content

Commit

Permalink
UI: [VAULT-17044] Replication card (#22354)
Browse files Browse the repository at this point in the history
  • Loading branch information
kiannaquach authored Aug 17, 2023
1 parent f69153c commit 0c0e1aa
Show file tree
Hide file tree
Showing 8 changed files with 390 additions and 0 deletions.
19 changes: 19 additions & 0 deletions ui/app/controllers/vault/cluster/dashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import Controller from '@ember/controller';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import timestamp from 'core/utils/timestamp';

export default class DashboardController extends Controller {
@tracked replicationUpdatedAt = timestamp.now().toISOString();

@action
refreshModel() {
this.replicationUpdatedAt = timestamp.now().toISOString();
this.send('refreshRoute');
}
}
14 changes: 14 additions & 0 deletions ui/app/routes/vault/cluster/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import { inject as service } from '@ember/service';
import { hash } from 'rsvp';
// eslint-disable-next-line ember/no-mixins
import ClusterRoute from 'vault/mixins/cluster-route';
import { action } from '@ember/object';

export default class VaultClusterDashboardRoute extends Route.extend(ClusterRoute) {
@service store;
@service namespace;
@service version;

async getVaultConfiguration() {
Expand All @@ -33,12 +35,24 @@ export default class VaultClusterDashboardRoute extends Route.extend(ClusterRout

model() {
const vaultConfiguration = this.getVaultConfiguration();
const clusterModel = this.modelFor('vault.cluster');
const replication = {
dr: clusterModel.dr,
performance: clusterModel.performance,
};

return hash({
vaultConfiguration,
replication,
secretsEngines: this.store.query('secret-engine', {}),
isRootNamespace: this.namespace.inRootNamespace,
version: this.version,
license: this.getLicense(),
});
}

@action
refreshRoute() {
this.refresh();
}
}
4 changes: 4 additions & 0 deletions ui/app/styles/core/title.scss
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
&.is-7 {
font-size: $size-7;
}

&.is-8 {
font-size: $size-8;
}
}

.form-section .title {
Expand Down
92 changes: 92 additions & 0 deletions ui/app/templates/components/dashboard/replication-card.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
~}}

<div class="is-flex-between">
<h3 class="title is-4 has-bottom-margin-xxs" data-test-client-count-title>
Replication
</h3>

<LinkTo class="is-no-underline" @route="vault.cluster.replication.index">
Details
</LinkTo>
</div>

{{! check if dr replication and performance replication exists }}
{{#if (or @replication.dr.clusterId @replication.performance.clusterId)}}
<hr class="has-background-gray-100" />
{{! check if user has access to both perf replication and dr replication }}
{{#if (and @version.hasPerfReplication @version.hasDRReplication)}}
<div
class="is-grid grid-2-columns grid-gap-2 has-top-margin-m has-bottom-margin-xs grid-align-items-start"
data-test-dr-perf-replication
>
<Dashboard::ReplicationStateText
@title="DR primary"
@name="dr"
@state={{@replication.dr.state}}
@clusterStates={{cluster-states @replication.dr.state}}
/>
<Dashboard::ReplicationStateText
@title="Perf primary"
@name="performance"
@state={{if @replication.performance.clusterId @replication.performance.state "not set up"}}
@clusterStates={{if @replication.performance.clusterId (cluster-states @replication.performance.state)}}
/>
</div>
{{! if user only has access to dr replication }}
{{else if @version.hasDRReplication}}
<LinkTo
class="title is-5 has-text-weight-semibold is-marginless"
@route="vault.cluster.replication.mode.index"
@model="dr"
>
DR Primary
</LinkTo>

<div
class="is-grid grid-2-columns grid-gap-2 has-top-margin-m has-bottom-margin-m grid-align-items-start"
data-test-dr-replication
>
<Dashboard::ReplicationStateText
@title="state"
@state={{@replication.dr.state}}
@clusterStates={{cluster-states @replication.dr.state}}
@subText="The current operating state of the cluster."
/>
<StatText
@label="known secondaries"
@value={{@replication.dr.knownSecondaries.length}}
@size="l"
@subText="Number of secondaries connected to this primary."
data-test-stat-text="known secondaries"
/>
</div>
{{/if}}
<div class="has-top-margin-s is-flex-center">
<Hds::Button
@text="Refresh"
@isIconOnly={{true}}
@color="tertiary"
@icon="sync"
class="has-padding-xxs"
{{on "click" @refresh}}
data-test-refresh
/>
<small class="has-left-margin-xs has-text-grey">
Updated
{{date-format @updatedAt "MMM dd, yyyy HH:mm:SS"}}
</small>
</div>
{{else}}
<EmptyState
@title="Replication not set up"
@message="Data will be listed here. Enable a primary replication cluster to get started."
class="has-top-margin-m"
>
<div>
<LinkTo @route="vault.cluster.replication">Enable replication</LinkTo>
</div>
</EmptyState>
{{/if}}
48 changes: 48 additions & 0 deletions ui/app/templates/components/dashboard/replication-state-text.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
~}}

<div>
{{#if @name}}
<LinkTo
class="title is-5 has-text-weight-semibold has-bottom-margin-xs"
@route="vault.cluster.replication.mode.index"
@model={{@name}}
data-test-title={{@title}}
>
{{@title}}
</LinkTo>
{{else}}
<h2 class="title is-5 has-text-weight-semibold has-bottom-margin-xs" data-test-title={{@title}}>
{{@title}}
</h2>
{{/if}}

{{#if @subText}}
<div class="title is-8 has-font-weight-normal has-text-grey-dark" data-test-subtext={{@title}}>
{{@subText}}
</div>
{{/if}}

<ToolTip @verticalPosition="above" @horizontalPosition="center" as |T|>
<T.Trigger
data-test-tooltip-trigger
tabindex="-1"
class="title is-3 has-font-weight-normal has-top-margin-xxs has-bottom-margin-xxs"
data-test-tooltip-title={{@title}}
>
{{or @state "not set up"}}

<FlightIcon
@name={{or @clusterStates.glyph "x-circle"}}
class={{if @clusterStates.isOk "has-text-success" "has-text-danger"}}
/>
</T.Trigger>
<T.Content @defaultClass="tool-tip smaller-font">
<div class="box" data-test-hover-copy-tooltip-text>
The cluster's current operating state
</div>
</T.Content>
</ToolTip>
</div>
12 changes: 12 additions & 0 deletions ui/app/templates/vault/cluster/dashboard.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@
<Dashboard::ClientCountCard @license={{@model.license}} />
</Hds::Card::Container>
{{/if}}

{{#if (and @model.version.isEnterprise @model.isRootNamespace)}}
<Hds::Card::Container @hasBorder={{true}} class="has-padding-l has-bottom-padding-m is-flex-column is-flex-half">
<Dashboard::ReplicationCard
@replication={{@model.replication}}
@version={{@model.version}}
@refresh={{this.refreshModel}}
@updatedAt={{this.replicationUpdatedAt}}
/>
</Hds::Card::Container>
{{/if}}

<Hds::Card::Container @hasBorder={{true}} class="has-padding-l is-flex-column is-flex-half">
<Dashboard::SecretsEnginesCard @secretsEngines={{@model.secretsEngines}} />
</Hds::Card::Container>
Expand Down
21 changes: 21 additions & 0 deletions ui/tests/helpers/components/dashboard/replication-card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

const SELECTORS = {
getReplicationTitle: (type, name) => `[data-test-${type}-replication] [data-test-title="${name}"]`,
getStateTooltipTitle: (type, name) => `[data-test-${type}-replication] [data-test-tooltip-title="${name}"]`,
getStateTooltipIcon: (type, name, icon) =>
`[data-test-${type}-replication] [data-test-tooltip-title="${name}"] [data-test-icon="${icon}"]`,
drOnlyStateSubText: '[data-test-dr-replication] [data-test-subtext="state"]',
knownSecondariesLabel: '[data-test-stat-text="known secondaries"] .stat-label',
knownSecondariesSubtext: '[data-test-stat-text="known secondaries"] .stat-text',
knownSecondariesValue: '[data-test-stat-text="known secondaries"] .stat-value',
replicationEmptyState: '[data-test-component="empty-state"]',
replicationEmptyStateTitle: '[data-test-component="empty-state"] .empty-state-title',
replicationEmptyStateMessage: '[data-test-component="empty-state"] .empty-state-message',
replicationEmptyStateActions: '[data-test-component="empty-state"] .empty-state-actions',
};

export default SELECTORS;
Loading

0 comments on commit 0c0e1aa

Please sign in to comment.