Skip to content

Commit

Permalink
💜 Cc 7187/purple banner for linking existing clusters (#20275)
Browse files Browse the repository at this point in the history
* Adding banner on services page

* Simplified version of setting/unsetting banner

* Translating the text based off of enterprise or not

* Add an integration test

* Adding an acceptance test

* Enable config dismissal as well

* Adding changelog

* Adding some copyrights to the other files

* Revert "Enable config dismissal as well"

This reverts commit e6784c4.

We'll be doing this in CC-7347
  • Loading branch information
chris-hut authored Jan 23, 2024
1 parent e5d1875 commit 5119667
Show file tree
Hide file tree
Showing 11 changed files with 225 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .changelog/20275.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:feature
ui: Added a banner to let users link their clusters to HCP
```
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default class HashiCorpConsul extends Component {
@service('env') env;

get consulVersion() {
const suffix = !['', 'oss'].includes(this.env.var('CONSUL_BINARY_TYPE')) ? '+ent' : '';
const suffix = this.env.isEnterprise ? '+ent' : '';
return `${this.env.var('CONSUL_VERSION')}${suffix}`;
}
}
24 changes: 24 additions & 0 deletions ui/packages/consul-ui/app/components/link-to-hcp-banner/index.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
{{#if this.hcpLinkStatus.shouldDisplayBanner}}
<Hds::Alert @type="page" @color="highlight" @onDismiss={{this.onDismiss}} class="link-to-hcp-banner"
data-test-link-to-hcp-banner as |A|>
<A.Title data-test-link-to-hcp-banner-title>{{t "components.link-to-hcp-banner.title"}}</A.Title>
<A.Description data-test-link-to-hcp-banner-description>{{t "components.link-to-hcp-banner.description"
isEnterprise=this.env.isEnterprise}}
</A.Description>
<A.Button @text={{t "components.link-to-hcp-banner.clusterLinkButton"}} @color="secondary" {{on "click"
this.onClusterLink}}
data-test-link-to-hcp-banner-button/>
<A.Link::Standalone @color="secondary" @icon="docs-link" @iconPosition="trailing" @text={{t
"components.link-to-hcp-banner.viewDocumentation"}}
@href="https://developer.hashicorp.com/hcp/docs/consul/self-managed"
data-test-link-to-hcp-banner-view-documentation/>
<A.Link::Standalone @color="secondary" @icon="docs-link" @iconPosition="trailing"
@text={{t "components.link-to-hcp-banner.consulCentralDocumentation"}}
@href="https://developer.hashicorp.com/hcp/docs/consul/concepts/consul-central"
data-test-link-to-hcp-banner-consul-central-documentation/>
</Hds::Alert>
{{/if}}
22 changes: 22 additions & 0 deletions ui/packages/consul-ui/app/components/link-to-hcp-banner/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';

export default class LinkToHcpBannerComponent extends Component {
@service('hcp-link-status') hcpLinkStatus;
@service('env') env;

@action
onDismiss() {
this.hcpLinkStatus.dismissHcpLinkBanner();
}
@action
onClusterLink() {
// TODO: CC-7147: Open simplified modal
}
}
3 changes: 3 additions & 0 deletions ui/packages/consul-ui/app/services/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import Service from '@ember/service';
import { env } from 'consul-ui/env';

export default class EnvService extends Service {
get isEnterprise() {
return !['', 'oss'].includes(this.var('CONSUL_BINARY_TYPE'));
}
// deprecated
// TODO: Remove this elsewhere in the app and use var instead
env(key) {
Expand Down
34 changes: 34 additions & 0 deletions ui/packages/consul-ui/app/services/hcp-link-status.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import Service from '@ember/service';
import { tracked } from '@glimmer/tracking';

const LOCAL_STORAGE_KEY = 'consul:hideHcpLinkBanner';

export default class HcpLinkStatus extends Service {
@tracked
alreadyLinked = false;
@tracked
userDismissedBanner = false;

get shouldDisplayBanner() {
return !this.alreadyLinked && !this.userDismissedBanner;
}

constructor() {
super(...arguments);
this.userDismissedBanner = !!localStorage.getItem(LOCAL_STORAGE_KEY);
}

userHasLinked() {
// TODO: CC-7145 - once can fetch the link status from the backend, fetch it and set it here
}

dismissHcpLinkBanner() {
localStorage.setItem(LOCAL_STORAGE_KEY, true);
this.userDismissedBanner = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ html[data-route^='dc.services.instance'] .app-view > header dl {
margin-bottom: 23px;
margin-right: 50px;
}
html[data-route^='dc.services.index'] .link-to-hcp-banner {
margin: 0 -48px;
}
html[data-route^='dc.services.instance'] .app-view > header dt {
font-weight: var(--token-typography-font-weight-bold);
}
Expand Down
2 changes: 1 addition & 1 deletion ui/packages/consul-ui/app/templates/dc/services/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ as |route|>
(or route.params.nspace route.model.user.token.Namespace 'default')

as |sort filters items partition nspace|}}

<LinkToHcpBanner/>
<AppView>
<BlockSlot @name="header">
<h1>
Expand Down
35 changes: 35 additions & 0 deletions ui/packages/consul-ui/tests/acceptance/link-to-hcp-banner-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import { module, test } from 'qunit';
import { click, visit } from '@ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';

const bannerSelector = '[data-test-link-to-hcp-banner]';
module('Acceptance | link to hcp banner', function (hooks) {
setupApplicationTest(hooks);

hooks.beforeEach(function () {
// clear local storage so we don't have any settings
window.localStorage.clear();
// setupTestEnv(this.owner, {
// CONSUL_ACLS_ENABLED: true,
// });
});

test('the banner is initially displayed on services page', async function (assert) {
assert.expect(3);
// default route is services page so we're good here
await visit('/');
// Expect the banner to be visible by default
assert.dom(bannerSelector).exists({ count: 1 });
// Click on the dismiss button
await click(`${bannerSelector} button[aria-label="Dismiss"]`);
assert.dom(bannerSelector).doesNotExist('Banner is gone after dismissing');
// Refresh the page
await visit('/');
assert.dom(bannerSelector).doesNotExist('Banner is still gone after refresh');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { click, render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import Service from '@ember/service';
import sinon from 'sinon';

const userDismissedBannerStub = sinon.stub();
const userHasLinkedStub = sinon.stub();
const dismissHcpLinkBannerStub = sinon.stub();
const bannerSelector = '[data-test-link-to-hcp-banner]';
module('Integration | Component | link-to-hcp-banner', function (hooks) {
setupRenderingTest(hooks);

class HcpLinkStatusStub extends Service {
get shouldDisplayBanner() {
return true;
}
userDismissedBanner = userDismissedBannerStub;
userHasLinked = userHasLinkedStub;
dismissHcpLinkBanner = dismissHcpLinkBannerStub;
}

class EnvStub extends Service {
isEnterprise = false;
var(key) {
return key;
}
}

hooks.beforeEach(function () {
this.owner.register('service:hcp-link-status', HcpLinkStatusStub);
this.owner.register('service:env', EnvStub);
});

test('it renders banner when hcp-link-status says it should', async function (assert) {
await render(hbs`<LinkToHcpBanner />`);

assert.dom(bannerSelector).exists({ count: 1 });
await click(`${bannerSelector} button[aria-label="Dismiss"]`);
assert.ok(dismissHcpLinkBannerStub.calledOnce, 'userDismissedBanner was called');
// Can't test that banner is no longer visible since service isn't hooked up
assert
.dom('[data-test-link-to-hcp-banner-title]')
.hasText(
'Link this cluster to HCP Consul Central in a few steps to start managing your clusters in one place'
);
assert
.dom('[data-test-link-to-hcp-banner-description]')
.hasText(
'By linking your clusters to HCP Consul Central, you’ll get global, cross-cluster metrics, visual service maps, and a global API. Link to access a free 90 day trial for full feature access in your HCP organization.'
);
});

test('banner does not render when hcp-link-status says it should NOT', async function (assert) {
class HcpLinkStatusStub extends Service {
get shouldDisplayBanner() {
return false;
}
userDismissedBanner = sinon.stub();
userHasLinked = sinon.stub();
dismissHcpLinkBanner = sinon.stub();
}
this.owner.register('service:hcp-link-status', HcpLinkStatusStub);
await render(hbs`<LinkToHcpBanner />`);
assert.dom(bannerSelector).doesNotExist();
});

test('it displays different banner text when consul is enterprise', async function (assert) {
class EnvStub extends Service {
isEnterprise = true;
var(key) {
return key;
}
}
this.owner.register('service:env', EnvStub);
await render(hbs`<LinkToHcpBanner />`);
assert
.dom('[data-test-link-to-hcp-banner-description]')
.hasText(
'By linking your clusters to HCP Consul Central, you’ll get global, cross-cluster metrics, visual service maps, and a global API. HCP Consul Central’s full feature set is included with an Enterprise license.'
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1

title: Link this cluster to HCP Consul Central in a few steps to start managing your clusters in one place
description: By linking your clusters to HCP Consul Central, you’ll get global, cross-cluster metrics, visual service maps, and a global API. {isEnterprise, select,
true {HCP Consul Central’s full feature set is included with an Enterprise license.}
other {Link to access a free 90 day trial for full feature access in your HCP organization.}}
clusterLinkButton: Link this cluster
viewDocumentation: View documentation
consulCentralDocumentation: Consul Central documentation

0 comments on commit 5119667

Please sign in to comment.