Cc 7145 hcp link status api (#20330)

* feat: add api call to hcp/link endpoint

* updated

* updated

* update approach to get the linking status

* updated application template

* feat: add api call to hcp/link endpoint

* updated

* updated

* update approach to get the linking status

* updated application template

* update purple banner links

* Hook up the linked check to the purple banner

* fixed lint issue

* Updated tests for new link status API calls as args instead of from service

---------

Co-authored-by: Chris Hut <tophernuts@gmail.com>
This commit is contained in:
Valeriia Ruban 2024-01-26 09:57:18 -08:00 committed by GitHub
parent 37ebaa6920
commit 049ca102c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 119 additions and 30 deletions

View File

@ -2,7 +2,7 @@
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
{{#if this.hcpLinkStatus.shouldDisplayBanner}}
{{#if (and this.hcpLinkStatus.shouldDisplayBanner this.notLinked)}}
<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>

View File

@ -11,6 +11,10 @@ export default class LinkToHcpBannerComponent extends Component {
@service('hcp-link-status') hcpLinkStatus;
@service('env') env;
get notLinked() {
return this.args.linkData?.isLinked === false;
}
@action
onDismiss() {
this.hcpLinkStatus.dismissHcpLinkBanner();

View File

@ -9,13 +9,11 @@ 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;
return !this.userDismissedBanner;
}
constructor() {

View File

@ -0,0 +1,42 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import RepositoryService from 'consul-ui/services/repository';
import dataSource from 'consul-ui/decorators/data-source';
export default class HcpLinkService extends RepositoryService {
@dataSource('/:partition/:ns/:dc/hcp-link')
async fetch({ partition, ns, dc }, { uri }, request) {
let result;
try {
result = (
await request`
GET /api/hcp/v2/link/global
`
)((headers, body) => {
return {
meta: {
version: 2,
uri: uri,
},
body: {
isLinked: (body.status['consul.io/hcp/link']['conditions'] || []).some(
(condition) => condition.type === 'linked' && condition.state === 'STATE_TRUE'
),
},
headers,
};
});
} catch (e) {
// set linked to false if the global link is not found
if (e.statusCode === 404) {
result = Promise.resolve({ isLinked: false });
} else {
result = Promise.resolve(null);
}
}
return result;
}
}

View File

@ -43,18 +43,18 @@
{{#if (not-eq route.currentName 'oauth-provider-debug')}}
{{! redirect if we aren't on a URL with dc information }}
{{! redirect if we aren't on a URL with dc information }}
{{#if (eq route.currentName 'index')}}
{{! until we get to the dc route we don't know any permissions }}
{{! as we don't know the dc, any inital permission based }}
{{! redirects are in the dc.show route}}
{{! until we get to the dc route we don't know any permissions }}
{{! as we don't know the dc, any inital permission based }}
{{! redirects are in the dc.show route}}
{{! 2022-04-15: Temporarily reverting the services page to the default }}
{{! 2022-04-15: Temporarily reverting the services page to the default }}
{{did-insert
(route-action 'replaceWith' 'dc.services.index' (hash dc=(env 'CONSUL_DATACENTER_LOCAL')))
}}
{{else}}
{{! If we are notfound, guess the params we need }}
{{! If we are notfound, guess the params we need }}
{{#if (eq route.currentName 'notfound')}}
<DataSource
@src={{uri '/*/*/*/notfound/${path}' (hash path=route.params.notfound)}}
@ -70,11 +70,11 @@
''
)
(if (can 'use nspaces') (or route.params.nspace notfound.nspace token.Namespace '') '')
as |partition nspace|
as |partition nspace|
}}
{{! Make sure we have enough to show the app chrome}}
{{! Don't show anything until we have a list of DCs }}
{{! Make sure we have enough to show the app chrome}}
{{! Don't show anything until we have a list of DCs }}
<DataSource @src={{uri '/*/*/*/datacenters'}} as |dcs|>
{{! Once we have a list of DCs make sure the DC we are asking for exists }}
{{! If not use the DC that the UI is running in }}
@ -85,20 +85,20 @@
(hash Name=(env 'CONSUL_DATACENTER_LOCAL'))
)
dcs.data
as |dc dcs|
as |dc dcs|
}}
{{#if (and (gt dc.Name.length 0) dcs)}}
{{! figure out our current DC and convert it to a model }}
{{! figure out our current DC and convert it to a model }}
<DataSource
@src={{uri
'/${partition}/*/${dc}/datacenter-cache/${name}'
(hash dc=dc.Name partition=partition name=dc.Name)
}}
'/${partition}/*/${dc}/datacenter-cache/${name}'
(hash dc=dc.Name partition=partition name=dc.Name)
}}
as |dc|
>
{{#if dc.data}}
<HashicorpConsul
<HashicorpConsul
id='wrapper'
@dcs={{dcs}}
@dc={{dc.data}}
@ -110,10 +110,10 @@
>
{{#if error}}
{{! If we got an error from anything, show an error page }}
{{! If we got an error from anything, show an error page }}
<AppError @error={{error}} @login={{consul.login.open}} />
{{else}}
{{! Otherwise show the rest of the app}}
{{! Otherwise show the rest of the app}}
<Outlet
@name='application'
@model={{hash app=consul user=(hash token=token) dc=dc.data dcs=dcs}}
@ -135,7 +135,7 @@
{{/let}}
{{/if}}
{{else}}
{{! Routes with no main navigation }}
{{! Routes with no main navigation }}
<Outlet @name='application' @model={{hash user=(hash token=token)}} as |o|>
{{outlet}}
</Outlet>

View File

@ -62,7 +62,11 @@ as |route|>
(or route.params.nspace route.model.user.token.Namespace 'default')
as |sort filters items partition nspace|}}
<LinkToHcpBanner/>
{{#let route.params.dc as |dc|}}
<DataSource @src={{uri '/${partition}/*/${dc}/hcp-link' (hash dc=dc partition=partition name=dc) }} as |hcpLink|>
<LinkToHcpBanner @linkData={{hcpLink.data}}/>
</DataSource>
{{/let}}
<AppView>
<BlockSlot @name="header">
<h1>

View File

@ -0,0 +1,16 @@
{
"status": {
"consul.io/hcp/link": {
"conditions": [
{
"message": "Successfully linked to cluster 'organization/f53e5646-6529-4698-ae29-d74f8bd22a01/project/6994bb7a-5561-4d5c-8bb0-cf40177e5b77/hashicorp.consul.global-network-manager.cluster/mkam-vm'",
"reason": "SUCCESS",
"state": "STATE_FALSE",
"type": "linked"
}
],
"observedGeneration":"01HMA2VPHVKNF6QR8TD07KDN5K",
"updatedAt":"2024-01-16T21:29:25.923140Z"
}
}
}

View File

@ -11,7 +11,6 @@ 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) {
@ -22,7 +21,6 @@ module('Integration | Component | link-to-hcp-banner', function (hooks) {
return true;
}
userDismissedBanner = userDismissedBannerStub;
userHasLinked = userHasLinkedStub;
dismissHcpLinkBanner = dismissHcpLinkBannerStub;
}
@ -39,7 +37,8 @@ module('Integration | Component | link-to-hcp-banner', function (hooks) {
});
test('it renders banner when hcp-link-status says it should', async function (assert) {
await render(hbs`<LinkToHcpBanner />`);
this.linkData = { isLinked: false };
await render(hbs`<LinkToHcpBanner @linkData={{this.linkData}} />`);
assert.dom(bannerSelector).exists({ count: 1 });
await click(`${bannerSelector} button[aria-label="Dismiss"]`);
@ -62,12 +61,37 @@ module('Integration | Component | link-to-hcp-banner', function (hooks) {
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 />`);
this.linkData = { isLinked: false };
await render(hbs`<LinkToHcpBanner @linkData={{this.linkData}} />`);
assert.dom(bannerSelector).doesNotExist();
});
test('banner does not render when cluster is already linked', async function (assert) {
class HcpLinkStatusStub extends Service {
get shouldDisplayBanner() {
return true;
}
dismissHcpLinkBanner = sinon.stub();
}
this.owner.register('service:hcp-link-status', HcpLinkStatusStub);
this.linkData = { isLinked: true };
await render(hbs`<LinkToHcpBanner @linkData={{this.linkData}} />`);
assert.dom(bannerSelector).doesNotExist();
});
test('banner does not render when we have no cluster link status info', async function (assert) {
class HcpLinkStatusStub extends Service {
get shouldDisplayBanner() {
return true;
}
dismissHcpLinkBanner = sinon.stub();
}
this.owner.register('service:hcp-link-status', HcpLinkStatusStub);
this.linkData = undefined;
await render(hbs`<LinkToHcpBanner @linkData={{this.linkData}} />`);
assert.dom(bannerSelector).doesNotExist();
});
@ -79,7 +103,8 @@ module('Integration | Component | link-to-hcp-banner', function (hooks) {
}
}
this.owner.register('service:env', EnvStub);
await render(hbs`<LinkToHcpBanner />`);
this.linkData = { isLinked: false };
await render(hbs`<LinkToHcpBanner @linkData={{this.linkData}} />`);
assert
.dom('[data-test-link-to-hcp-banner-description]')
.hasText(