mirror of https://github.com/status-im/consul.git
ui: Create Linked Services Tab for Terminating Gateways (#7858)
* Fix to bottom border not applying to the correct <li> * Create Linked Services tab with styling and tests * Add internal endpoint gateway-services-nodes to the codebase with tests * Upgrade consul-api-double to version 2.15.0
This commit is contained in:
parent
acccdbe45c
commit
2adfb42bde
|
@ -0,0 +1,17 @@
|
||||||
|
import Adapter from './application';
|
||||||
|
|
||||||
|
export default Adapter.extend({
|
||||||
|
requestForQueryRecord: function(request, { dc, ns, index, id }) {
|
||||||
|
if (typeof id === 'undefined') {
|
||||||
|
throw new Error('You must specify an id');
|
||||||
|
}
|
||||||
|
return request`
|
||||||
|
GET /v1/internal/ui/gateway-services-nodes/${id}?${{ dc }}
|
||||||
|
|
||||||
|
${{
|
||||||
|
...this.formatNspace(ns),
|
||||||
|
index,
|
||||||
|
}}
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,12 @@
|
||||||
|
import Model from 'ember-data/model';
|
||||||
|
import attr from 'ember-data/attr';
|
||||||
|
|
||||||
|
export const PRIMARY_KEY = 'uid';
|
||||||
|
export const SLUG_KEY = 'Name';
|
||||||
|
export default Model.extend({
|
||||||
|
[PRIMARY_KEY]: attr('string'),
|
||||||
|
[SLUG_KEY]: attr('string'),
|
||||||
|
Datacenter: attr('string'),
|
||||||
|
Namespace: attr('string'),
|
||||||
|
Services: attr(),
|
||||||
|
});
|
|
@ -19,6 +19,9 @@ export const routes = {
|
||||||
intentions: {
|
intentions: {
|
||||||
_options: { path: '/intentions' },
|
_options: { path: '/intentions' },
|
||||||
},
|
},
|
||||||
|
services: {
|
||||||
|
_options: { path: '/services' },
|
||||||
|
},
|
||||||
routing: {
|
routing: {
|
||||||
_options: { path: '/routing' },
|
_options: { path: '/routing' },
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,6 +8,7 @@ export default Route.extend({
|
||||||
intentionRepo: service('repository/intention'),
|
intentionRepo: service('repository/intention'),
|
||||||
chainRepo: service('repository/discovery-chain'),
|
chainRepo: service('repository/discovery-chain'),
|
||||||
proxyRepo: service('repository/proxy'),
|
proxyRepo: service('repository/proxy'),
|
||||||
|
gatewayRepo: service('repository/gateway'),
|
||||||
settings: service('settings'),
|
settings: service('settings'),
|
||||||
model: function(params, transition = {}) {
|
model: function(params, transition = {}) {
|
||||||
const dc = this.modelFor('dc').dc.Name;
|
const dc = this.modelFor('dc').dc.Name;
|
||||||
|
@ -17,8 +18,11 @@ export default Route.extend({
|
||||||
urls: this.settings.findBySlug('urls'),
|
urls: this.settings.findBySlug('urls'),
|
||||||
dc: dc,
|
dc: dc,
|
||||||
proxies: [],
|
proxies: [],
|
||||||
}).then(model => {
|
})
|
||||||
return ['connect-proxy', 'mesh-gateway'].includes(get(model, 'item.Service.Kind'))
|
.then(model => {
|
||||||
|
return ['connect-proxy', 'mesh-gateway', 'ingress-gateway', 'terminating-gateway'].includes(
|
||||||
|
get(model, 'item.Service.Kind')
|
||||||
|
)
|
||||||
? model
|
? model
|
||||||
: hash({
|
: hash({
|
||||||
intentions: this.intentionRepo.findByService(params.name, dc, nspace),
|
intentions: this.intentionRepo.findByService(params.name, dc, nspace),
|
||||||
|
@ -42,6 +46,14 @@ export default Route.extend({
|
||||||
proxies: this.proxyRepo.findAllBySlug(params.name, dc, nspace),
|
proxies: this.proxyRepo.findAllBySlug(params.name, dc, nspace),
|
||||||
...model,
|
...model,
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
.then(model => {
|
||||||
|
return ['ingress-gateway', 'terminating-gateway'].includes(get(model, 'item.Service.Kind'))
|
||||||
|
? hash({
|
||||||
|
gateway: this.gatewayRepo.findBySlug(params.name, dc, nspace),
|
||||||
|
...model,
|
||||||
|
})
|
||||||
|
: model;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setupController: function(controller, model) {
|
setupController: function(controller, model) {
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import Route from '@ember/routing/route';
|
||||||
|
|
||||||
|
export default Route.extend({
|
||||||
|
model: function() {
|
||||||
|
const parent = this.routeName
|
||||||
|
.split('.')
|
||||||
|
.slice(0, -1)
|
||||||
|
.join('.');
|
||||||
|
return this.modelFor(parent);
|
||||||
|
},
|
||||||
|
setupController: function(controller, model) {
|
||||||
|
controller.setProperties(model);
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,17 @@
|
||||||
|
import Serializer from './application';
|
||||||
|
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/gateway';
|
||||||
|
|
||||||
|
export default Serializer.extend({
|
||||||
|
primaryKey: PRIMARY_KEY,
|
||||||
|
slugKey: SLUG_KEY,
|
||||||
|
respondForQueryRecord: function(respond, query) {
|
||||||
|
return this._super(function(cb) {
|
||||||
|
return respond(function(headers, body) {
|
||||||
|
return cb(headers, {
|
||||||
|
Name: query.id,
|
||||||
|
Services: body,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, query);
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,8 @@
|
||||||
|
import RepositoryService from 'consul-ui/services/repository';
|
||||||
|
|
||||||
|
const modelName = 'gateway';
|
||||||
|
export default RepositoryService.extend({
|
||||||
|
getModelName: function() {
|
||||||
|
return modelName;
|
||||||
|
},
|
||||||
|
});
|
|
@ -1,7 +1,7 @@
|
||||||
.consul-service-list > ul {
|
.consul-service-list > ul {
|
||||||
@extend %consul-service-list;
|
@extend %consul-service-list;
|
||||||
}
|
}
|
||||||
%consul-service-list > li {
|
%consul-service-list > li:not(:first-child) {
|
||||||
@extend %consul-service-row;
|
@extend %consul-service-row;
|
||||||
}
|
}
|
||||||
%consul-service-row {
|
%consul-service-row {
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
|
// Services - Linked Services tab
|
||||||
|
.gateway-services-list > ul {
|
||||||
|
@extend %gateway-services-list;
|
||||||
|
}
|
||||||
|
%gateway-services-list > li:not(:first-child) {
|
||||||
|
@extend %gateway-service-row;
|
||||||
|
}
|
||||||
|
%gateway-service-row {
|
||||||
|
@extend %composite-row, %with-composite-row-intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service Detail - Proxy Info tab
|
||||||
.proxy-upstreams > ul {
|
.proxy-upstreams > ul {
|
||||||
@extend %proxy-upstreams-list;
|
@extend %proxy-upstreams-list;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,14 +17,23 @@
|
||||||
<ConsulKind @item={{item.Service}} />
|
<ConsulKind @item={{item.Service}} />
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
<BlockSlot @name="nav">
|
<BlockSlot @name="nav">
|
||||||
{{#if (not item.Service.Kind)}}
|
{{#if (or (not item.Service.Kind) (eq item.Service.Kind 'terminating-gateway'))}}
|
||||||
<TabNav @items={{
|
<TabNav @items={{
|
||||||
compact
|
compact
|
||||||
(array
|
(array
|
||||||
(hash label="Instances" href=(href-to "dc.services.show.instances") selected=(is-href "dc.services.show.instances"))
|
(hash label="Instances" href=(href-to "dc.services.show.instances") selected=(is-href "dc.services.show.instances"))
|
||||||
|
(if (eq item.Service.Kind 'terminating-gateway')
|
||||||
|
(hash label="Linked Services" href=(href-to "dc.services.show.services") selected=(is-href "dc.services.show.services"))
|
||||||
|
'')
|
||||||
|
(if (not item.Service.Kind)
|
||||||
(hash label="Intentions" href=(href-to "dc.services.show.intentions") selected=(is-href "dc.services.show.intentions"))
|
(hash label="Intentions" href=(href-to "dc.services.show.intentions") selected=(is-href "dc.services.show.intentions"))
|
||||||
(if (not-eq chain null) (hash label="Routing" href=(href-to "dc.services.show.routing") selected=(is-href "dc.services.show.routing")) '')
|
'')
|
||||||
|
(if chain
|
||||||
|
(hash label="Routing" href=(href-to "dc.services.show.routing") selected=(is-href "dc.services.show.routing"))
|
||||||
|
'')
|
||||||
|
(if (not item.Service.Kind)
|
||||||
(hash label="Tags" href=(href-to "dc.services.show.tags") selected=(is-href "dc.services.show.tags"))
|
(hash label="Tags" href=(href-to "dc.services.show.tags") selected=(is-href "dc.services.show.tags"))
|
||||||
|
'')
|
||||||
)
|
)
|
||||||
}}/>
|
}}/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<div id="services" class="tab-section">
|
||||||
|
<div role="tabpanel">
|
||||||
|
{{#if (gt gateway.Services.length 0)}}
|
||||||
|
<section>
|
||||||
|
<p>
|
||||||
|
The following services may receive traffic from external services through this gateway. Learn more about configuring gateways in our
|
||||||
|
<a href={{env 'CONSUL_TERMINATING_GATEWAYS_URL'}} target="_blank">step-by-step guide.</a>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<ListCollection @cellHeight={{73}} @items={{gateway.Services}} class="gateway-services-list" as |item index|>
|
||||||
|
<a data-test-service-name href={{href-to 'dc.services.show' item.Name}} class={{service/health-checks item}}>
|
||||||
|
{{item.Name}}
|
||||||
|
</a>
|
||||||
|
<ul>
|
||||||
|
{{#if (not-eq item.InstanceCount 0)}}
|
||||||
|
<li>
|
||||||
|
{{format-number item.InstanceCount}} {{pluralize item.InstanceCount 'Instance' without-count=true}}
|
||||||
|
</li>
|
||||||
|
{{/if}}
|
||||||
|
<TagList @item={{item}} as |Tags|>
|
||||||
|
<li>
|
||||||
|
<Tags />
|
||||||
|
</li>
|
||||||
|
</TagList>
|
||||||
|
</ul>
|
||||||
|
</ListCollection>
|
||||||
|
</section>
|
||||||
|
{{else}}
|
||||||
|
<p>
|
||||||
|
There are no linked services.
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -81,6 +81,8 @@ module.exports = function(environment, $ = process.env) {
|
||||||
CONSUL_DOCS_LEARN_URL: 'https://learn.hashicorp.com',
|
CONSUL_DOCS_LEARN_URL: 'https://learn.hashicorp.com',
|
||||||
CONSUL_DOCS_API_URL: 'https://www.consul.io/api',
|
CONSUL_DOCS_API_URL: 'https://www.consul.io/api',
|
||||||
CONSUL_COPYRIGHT_URL: 'https://www.hashicorp.com',
|
CONSUL_COPYRIGHT_URL: 'https://www.hashicorp.com',
|
||||||
|
CONSUL_TERMINATING_GATEWAYS_URL: 'https://www.consul.io/docs/connect/terminating_gateway',
|
||||||
|
CONSUL_INGRESS_GATEWAYS_URL: 'https://www.consul.io/docs/connect/ingress_gateway',
|
||||||
});
|
});
|
||||||
const isTestLike = ['staging', 'test'].indexOf(environment) > -1;
|
const isTestLike = ['staging', 'test'].indexOf(environment) > -1;
|
||||||
const isDevLike = ['development', 'staging', 'test'].indexOf(environment) > -1;
|
const isDevLike = ['development', 'staging', 'test'].indexOf(environment) > -1;
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
@setupApplicationTest
|
||||||
|
Feature: dc / services / gateway
|
||||||
|
Background:
|
||||||
|
Given 1 datacenter model with the value "dc1"
|
||||||
|
And 1 node models
|
||||||
|
And 1 service model from yaml
|
||||||
|
---
|
||||||
|
- Service:
|
||||||
|
Name: terminating-gateway-1
|
||||||
|
Kind: terminating-gateway
|
||||||
|
---
|
||||||
|
Scenario: Seeing the Linked Services tab
|
||||||
|
When I visit the service page for yaml
|
||||||
|
---
|
||||||
|
dc: dc1
|
||||||
|
service: terminating-gateway-1
|
||||||
|
---
|
||||||
|
And the title should be "terminating-gateway-1 - Consul"
|
||||||
|
And I see linkedServices on the tabs
|
||||||
|
When I click linkedServices on the tabs
|
||||||
|
And I see linkedServicesIsSelected on the tabs
|
||||||
|
Scenario: Seeing the list of Linked Services
|
||||||
|
Given 3 service models from yaml
|
||||||
|
When I visit the service page for yaml
|
||||||
|
---
|
||||||
|
dc: dc1
|
||||||
|
service: terminating-gateway-1
|
||||||
|
---
|
||||||
|
And the title should be "terminating-gateway-1 - Consul"
|
||||||
|
When I click linkedServices on the tabs
|
||||||
|
Then I see 3 service models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import steps from '../../../steps';
|
||||||
|
|
||||||
|
// step definitions that are shared between features should be moved to the
|
||||||
|
// tests/acceptance/steps/steps.js file
|
||||||
|
|
||||||
|
export default function(assert) {
|
||||||
|
return steps(assert).then('I should find a file', function() {
|
||||||
|
assert.ok(true, this.step);
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
module('Integration | Adapter | gateway', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
const dc = 'dc-1';
|
||||||
|
const id = 'slug';
|
||||||
|
test('requestForQueryRecord returns the correct url/method', function(assert) {
|
||||||
|
const adapter = this.owner.lookup('adapter:gateway');
|
||||||
|
const client = this.owner.lookup('service:client/http');
|
||||||
|
const expected = `GET /v1/internal/ui/gateway-services-nodes/${id}?dc=${dc}`;
|
||||||
|
const actual = adapter.requestForQueryRecord(client.url, {
|
||||||
|
dc: dc,
|
||||||
|
id: id,
|
||||||
|
});
|
||||||
|
assert.equal(actual, expected);
|
||||||
|
});
|
||||||
|
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
|
||||||
|
const adapter = this.owner.lookup('adapter:gateway');
|
||||||
|
const client = this.owner.lookup('service:client/http');
|
||||||
|
assert.throws(function() {
|
||||||
|
adapter.requestForQueryRecord(client.url, {
|
||||||
|
dc: dc,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
import { get } from 'consul-ui/tests/helpers/api';
|
||||||
|
import {
|
||||||
|
HEADERS_SYMBOL as META,
|
||||||
|
HEADERS_DATACENTER as DC,
|
||||||
|
HEADERS_NAMESPACE as NSPACE,
|
||||||
|
} from 'consul-ui/utils/http/consul';
|
||||||
|
|
||||||
|
module('Integration | Serializer | gateway', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
test('respondForQueryRecord returns the correct data for item endpoint', function(assert) {
|
||||||
|
const serializer = this.owner.lookup('serializer:gateway');
|
||||||
|
const dc = 'dc-1';
|
||||||
|
const id = 'slug';
|
||||||
|
const nspace = 'default';
|
||||||
|
const request = {
|
||||||
|
url: `/v1/internal/ui/gateway-services-nodes/${id}?dc=${dc}`,
|
||||||
|
};
|
||||||
|
return get(request.url).then(function(payload) {
|
||||||
|
const expected = {
|
||||||
|
Datacenter: dc,
|
||||||
|
[META]: {
|
||||||
|
[DC.toLowerCase()]: dc,
|
||||||
|
[NSPACE.toLowerCase()]: nspace,
|
||||||
|
},
|
||||||
|
uid: `["${nspace}","${dc}","${id}"]`,
|
||||||
|
Name: id,
|
||||||
|
Namespace: nspace,
|
||||||
|
Services: payload,
|
||||||
|
};
|
||||||
|
const actual = serializer.respondForQueryRecord(
|
||||||
|
function(cb) {
|
||||||
|
const headers = {};
|
||||||
|
const body = payload;
|
||||||
|
return cb(headers, body);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dc: dc,
|
||||||
|
id: id,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert.deepEqual(actual, expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { moduleFor, test } from 'ember-qunit';
|
||||||
|
import repo from 'consul-ui/tests/helpers/repo';
|
||||||
|
|
||||||
|
moduleFor('service:repository/gateway', 'Integration | Repository | gateway', {
|
||||||
|
// Specify the other units that are required for this test.
|
||||||
|
integration: true,
|
||||||
|
});
|
||||||
|
const dc = 'dc-1';
|
||||||
|
const id = 'slug';
|
||||||
|
const nspace = 'default';
|
||||||
|
test('findBySlug returns the correct data for item endpoint', function(assert) {
|
||||||
|
return repo(
|
||||||
|
'Gateway',
|
||||||
|
'findBySlug',
|
||||||
|
this.subject(),
|
||||||
|
function retrieveStub(stub) {
|
||||||
|
return stub(`/v1/internal/ui/gateway-services-nodes/${id}`);
|
||||||
|
},
|
||||||
|
function performTest(service) {
|
||||||
|
return service.findBySlug(id, dc);
|
||||||
|
},
|
||||||
|
function performAssertion(actual, expected) {
|
||||||
|
assert.deepEqual(
|
||||||
|
actual,
|
||||||
|
expected(function(payload) {
|
||||||
|
return Object.assign(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
Datacenter: dc,
|
||||||
|
Name: id,
|
||||||
|
Namespace: nspace,
|
||||||
|
uid: `["${nspace}","${dc}","${id}"]`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Services: payload,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
|
@ -7,7 +7,7 @@ export default function(visitable, attribute, collection, text, intentions, filt
|
||||||
dashboardAnchor: {
|
dashboardAnchor: {
|
||||||
href: attribute('href', '[data-test-dashboard-anchor]'),
|
href: attribute('href', '[data-test-dashboard-anchor]'),
|
||||||
},
|
},
|
||||||
tabs: tabs('tab', ['instances', 'intentions', 'routing', 'tags']),
|
tabs: tabs('tab', ['instances', 'linked-services', 'intentions', 'routing', 'tags']),
|
||||||
filter: filter,
|
filter: filter,
|
||||||
|
|
||||||
// TODO: These need to somehow move to subpages
|
// TODO: These need to somehow move to subpages
|
||||||
|
@ -15,5 +15,8 @@ export default function(visitable, attribute, collection, text, intentions, filt
|
||||||
address: text('[data-test-address]'),
|
address: text('[data-test-address]'),
|
||||||
}),
|
}),
|
||||||
intentions: intentions(),
|
intentions: intentions(),
|
||||||
|
services: collection('.gateway-services-list> ul > li:not(:first-child)', {
|
||||||
|
name: text('[data-test-service-name]'),
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
module('Unit | Adapter | gateway', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it exists', function(assert) {
|
||||||
|
let adapter = this.owner.lookup('adapter:gateway');
|
||||||
|
assert.ok(adapter);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
module('Unit | Model | gateway', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it exists', function(assert) {
|
||||||
|
let store = this.owner.lookup('service:store');
|
||||||
|
let model = store.createRecord('gateway', {});
|
||||||
|
assert.ok(model);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
module('Unit | Serializer | gateway', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it exists', function(assert) {
|
||||||
|
let store = this.owner.lookup('service:store');
|
||||||
|
let serializer = store.serializerFor('gateway');
|
||||||
|
|
||||||
|
assert.ok(serializer);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it serializes records', function(assert) {
|
||||||
|
let store = this.owner.lookup('service:store');
|
||||||
|
let record = store.createRecord('gateway', {});
|
||||||
|
|
||||||
|
let serializedRecord = record.serialize();
|
||||||
|
|
||||||
|
assert.ok(serializedRecord);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
module('Unit | Repository | gateway', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it exists', function(assert) {
|
||||||
|
const repo = this.owner.lookup('service:repository/gateway');
|
||||||
|
assert.ok(repo);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1211,9 +1211,9 @@
|
||||||
js-yaml "^3.13.1"
|
js-yaml "^3.13.1"
|
||||||
|
|
||||||
"@hashicorp/consul-api-double@^2.6.2":
|
"@hashicorp/consul-api-double@^2.6.2":
|
||||||
version "2.14.7"
|
version "2.15.0"
|
||||||
resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-2.14.7.tgz#80cd19461a3f3716bf76ba28bcabff842bcd9aef"
|
resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-2.15.0.tgz#033b3887449f92f26156b123f251f9e6e1b42e52"
|
||||||
integrity sha512-QjpwvrraUswn/hFh+9lIKuA9keCGOkh1yr/cT3I6fDiw4JKLyDLaRN8bF/JNGtgoA/SsQh10L1YI3feZ7M3VKw==
|
integrity sha512-uPzwU/MPzPDhhsLjY3X1rKIjZDOSbqYHMGM0f6n15cDF2lEcbeBHwE0snuCvqTDn72qBVdYZvA13AQBm8XCy2A==
|
||||||
|
|
||||||
"@hashicorp/ember-cli-api-double@^3.0.2":
|
"@hashicorp/ember-cli-api-double@^3.0.2":
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
|
|
Loading…
Reference in New Issue