diff --git a/ui/packages/consul-ui/app/adapters/permission.js b/ui/packages/consul-ui/app/adapters/permission.js index cdcee918d..dcd357ae2 100644 --- a/ui/packages/consul-ui/app/adapters/permission.js +++ b/ui/packages/consul-ui/app/adapters/permission.js @@ -4,20 +4,20 @@ import { inject as service } from '@ember/service'; export default class PermissionAdapter extends Adapter { @service('env') env; - requestForAuthorize(request, { dc, ns, permissions = [], index }) { + requestForAuthorize(request, { dc, ns, resources = [], index }) { // the authorize endpoint is slightly different to all others in that it // ignores an ns parameter, but accepts a Namespace property on each // resource. Here we hide this different from the rest of the app as - // currently we never need to ask for permissions/resources for mutiple + // currently we never need to ask for permissions/resources for multiple // different namespaces in one call so here we use the ns param and add // this to the resources instead of passing through on the queryParameter if (this.env.var('CONSUL_NSPACES_ENABLED')) { - permissions = permissions.map(item => ({ ...item, Namespace: ns })); + resources = resources.map(item => ({ ...item, Namespace: ns })); } return request` POST /v1/internal/acl/authorize?${{ dc, index }} - ${permissions} + ${resources} `; } diff --git a/ui/packages/consul-ui/app/decorators/data-source.js b/ui/packages/consul-ui/app/decorators/data-source.js new file mode 100644 index 000000000..39626f86d --- /dev/null +++ b/ui/packages/consul-ui/app/decorators/data-source.js @@ -0,0 +1,52 @@ +import { runInDebug } from '@ember/debug'; +import wayfarer from 'wayfarer'; + +const router = wayfarer(); +const routes = {}; +export default path => (target, propertyKey, desc) => { + runInDebug(() => { + routes[path] = { cls: target, method: propertyKey }; + }); + router.on(path, function(params, owner) { + const container = owner.lookup('service:container'); + const instance = container.get(target); + return configuration => desc.value.apply(instance, [params, configuration]); + }); + return desc; +}; +export const match = path => { + return router.match(path); +}; + +runInDebug(() => { + window.DataSourceRoutes = () => { + // debug time only way to access the application and be able to lookup + // services, don't use ConsulUi global elsewhere! + const container = window.ConsulUi.__container__.lookup('service:container'); + const win = window.open('', '_blank'); + win.document.write(` +
++${Object.entries(routes) + .map(([key, value]) => { + let cls = container + .keyForClass(value.cls) + .split('/') + .pop(); + cls = cls + .split('-') + .map(item => `${item[0].toUpperCase()}${item.substr(1)}`) + .join(''); + return `${key} + ${cls}Repository.${value.method}(params) + +`; + }) + .join('')} ++ + `); + win.focus(); + return; + }; +}); diff --git a/ui/packages/consul-ui/app/instance-initializers/container.js b/ui/packages/consul-ui/app/instance-initializers/container.js new file mode 100644 index 000000000..ee19684ca --- /dev/null +++ b/ui/packages/consul-ui/app/instance-initializers/container.js @@ -0,0 +1,32 @@ +import { runInDebug } from '@ember/debug'; + +export default { + name: 'container', + initialize(application) { + const container = application.lookup('service:container'); + // find all the services and add their classes to the container so we can + // look instances up by class afterwards as we then resolve the + // registration for each of these further down this means that any top + // level code for these services is executed, this is most useful for + // making sure any annotation type decorators are executed. + // For now we only want repositories, so only look for those for the moment + let repositories = container + .get('container-debug-adapter:main') + .catalogEntriesByType('service') + .filter(item => item.startsWith('repository/')); + + // during testing we get -test files in here, filter those out but only in debug envs + runInDebug(() => (repositories = repositories.filter(item => !item.endsWith('-test')))); + + // 'service' service is not returned by catalogEntriesByType, possibly + // related to pods and the service being called 'service': + // https://github.com/ember-cli/ember-resolver/blob/c07287af17766bfd3acf390f867fea17686f77d2/addon/resolvers/classic/container-debug-adapter.js#L80 + // so push it on the end + repositories.push('repository/service'); + // + repositories.forEach(item => { + const key = `service:${item}`; + container.set(key, container.resolveRegistration(key)); + }); + }, +}; diff --git a/ui/packages/consul-ui/app/mixins/token/with-actions.js b/ui/packages/consul-ui/app/mixins/token/with-actions.js index 6c9509e42..f3d1ad2a3 100644 --- a/ui/packages/consul-ui/app/mixins/token/with-actions.js +++ b/ui/packages/consul-ui/app/mixins/token/with-actions.js @@ -8,11 +8,11 @@ export default Mixin.create(WithBlockingActions, { actions: { use: function(item) { return this.repo - .findBySlug( - get(item, 'AccessorID'), - this.modelFor('dc').dc.Name, - this.modelFor('nspace').nspace.substr(1) - ) + .findBySlug({ + ns: this.modelFor('nspace').nspace.substr(1), + dc: this.modelFor('dc').dc.Name, + id: get(item, 'AccessorID'), + }) .then(item => { return this.settings.persist({ token: { diff --git a/ui/packages/consul-ui/app/routes/dc.js b/ui/packages/consul-ui/app/routes/dc.js index 19404acff..5fafb2926 100644 --- a/ui/packages/consul-ui/app/routes/dc.js +++ b/ui/packages/consul-ui/app/routes/dc.js @@ -43,7 +43,10 @@ export default class DcRoute extends Route { app.nspaces.length > 1 ? findActiveNspace(app.nspaces, nspace) : app.nspaces.firstObject; // When disabled nspaces is [], so nspace is undefined - const permissions = await this.permissionsRepo.findAll(params.dc, get(nspace || {}, 'Name')); + const permissions = await this.permissionsRepo.findAll({ + dc: params.dc, + nspace: get(nspace || {}, 'Name'), + }); return { dc, nspace, @@ -79,7 +82,10 @@ export default class DcRoute extends Route { const controller = this.controllerFor('application'); Promise.all([ this.nspacesRepo.findAll(), - this.permissionsRepo.findAll(get(controller, 'dc.Name'), get(controller, 'nspace.Name')), + this.permissionsRepo.findAll({ + dc: get(controller, 'dc.Name'), + nspace: get(controller, 'nspace.Name'), + }), ]).then(([nspaces, permissions]) => { if (typeof controller !== 'undefined') { controller.setProperties({ diff --git a/ui/packages/consul-ui/app/routes/dc/acls/auth-methods/index.js b/ui/packages/consul-ui/app/routes/dc/acls/auth-methods/index.js index f45d92397..4702ec091 100644 --- a/ui/packages/consul-ui/app/routes/dc/acls/auth-methods/index.js +++ b/ui/packages/consul-ui/app/routes/dc/acls/auth-methods/index.js @@ -22,10 +22,10 @@ export default class IndexRoute extends Route { model(params) { return hash({ ...this.repo.status({ - items: this.repo.findAllByDatacenter( - this.modelFor('dc').dc.Name, - this.modelFor('nspace').nspace.substr(1) - ), + items: this.repo.findAllByDatacenter({ + dc: this.modelFor('dc').dc.Name, + ns: this.modelFor('nspace').nspace.substr(1), + }), }), searchProperties: this.queryParams.searchproperty.empty[0], }); diff --git a/ui/packages/consul-ui/app/routes/dc/acls/edit.js b/ui/packages/consul-ui/app/routes/dc/acls/edit.js index 60ed4371e..0835c4e9e 100644 --- a/ui/packages/consul-ui/app/routes/dc/acls/edit.js +++ b/ui/packages/consul-ui/app/routes/dc/acls/edit.js @@ -13,7 +13,10 @@ export default class EditRoute extends Route.extend(WithAclActions) { model(params) { return hash({ - item: this.repo.findBySlug(params.id, this.modelFor('dc').dc.Name), + item: this.repo.findBySlug({ + dc: this.modelFor('dc').dc.Name, + id: params.id, + }), types: ['management', 'client'], }); } diff --git a/ui/packages/consul-ui/app/routes/dc/acls/index.js b/ui/packages/consul-ui/app/routes/dc/acls/index.js index c5761cc43..2e896fc29 100644 --- a/ui/packages/consul-ui/app/routes/dc/acls/index.js +++ b/ui/packages/consul-ui/app/routes/dc/acls/index.js @@ -30,7 +30,7 @@ export default class IndexRoute extends Route.extend(WithAclActions) { } async model(params) { - const _items = this.repo.findAllByDatacenter(this.modelFor('dc').dc.Name); + const _items = this.repo.findAllByDatacenter({ dc: this.modelFor('dc').dc.Name }); const _token = this.settings.findBySlug('token'); return { items: await _items, diff --git a/ui/packages/consul-ui/app/routes/dc/acls/policies/edit.js b/ui/packages/consul-ui/app/routes/dc/acls/policies/edit.js index 5705a180a..145952393 100644 --- a/ui/packages/consul-ui/app/routes/dc/acls/policies/edit.js +++ b/ui/packages/consul-ui/app/routes/dc/acls/policies/edit.js @@ -21,15 +21,21 @@ export default class EditRoute extends SingleRoute.extend(WithPolicyActions) { ...model, ...{ routeName: this.routeName, - items: tokenRepo.findByPolicy(get(model.item, 'ID'), dc, nspace).catch(function(e) { - switch (get(e, 'errors.firstObject.status')) { - case '403': - case '401': - // do nothing the SingleRoute will have caught it already - return; - } - throw e; - }), + items: tokenRepo + .findByPolicy({ + ns: nspace, + dc: dc, + id: get(model.item, 'ID'), + }) + .catch(function(e) { + switch (get(e, 'errors.firstObject.status')) { + case '403': + case '401': + // do nothing the SingleRoute will have caught it already + return; + } + throw e; + }), }, }); }); diff --git a/ui/packages/consul-ui/app/routes/dc/acls/policies/index.js b/ui/packages/consul-ui/app/routes/dc/acls/policies/index.js index 394f4c6f2..68a3fba07 100644 --- a/ui/packages/consul-ui/app/routes/dc/acls/policies/index.js +++ b/ui/packages/consul-ui/app/routes/dc/acls/policies/index.js @@ -26,10 +26,10 @@ export default class IndexRoute extends Route.extend(WithPolicyActions) { model(params) { return hash({ ...this.repo.status({ - items: this.repo.findAllByDatacenter( - this.modelFor('dc').dc.Name, - this.modelFor('nspace').nspace.substr(1) - ), + items: this.repo.findAllByDatacenter({ + ns: this.modelFor('nspace').nspace.substr(1), + dc: this.modelFor('dc').dc.Name, + }), }), searchProperties: this.queryParams.searchproperty.empty[0], }); diff --git a/ui/packages/consul-ui/app/routes/dc/acls/roles/edit.js b/ui/packages/consul-ui/app/routes/dc/acls/roles/edit.js index e45862e96..524d5ce80 100644 --- a/ui/packages/consul-ui/app/routes/dc/acls/roles/edit.js +++ b/ui/packages/consul-ui/app/routes/dc/acls/roles/edit.js @@ -20,15 +20,21 @@ export default class EditRoute extends SingleRoute.extend(WithRoleActions) { return hash({ ...model, ...{ - items: tokenRepo.findByRole(get(model.item, 'ID'), dc, nspace).catch(function(e) { - switch (get(e, 'errors.firstObject.status')) { - case '403': - case '401': - // do nothing the SingleRoute will have caught it already - return; - } - throw e; - }), + items: tokenRepo + .findByRole({ + ns: nspace, + dc: dc, + id: get(model.item, 'ID'), + }) + .catch(function(e) { + switch (get(e, 'errors.firstObject.status')) { + case '403': + case '401': + // do nothing the SingleRoute will have caught it already + return; + } + throw e; + }), }, }); }); diff --git a/ui/packages/consul-ui/app/routes/dc/acls/roles/index.js b/ui/packages/consul-ui/app/routes/dc/acls/roles/index.js index 46c14f493..ab06f02d1 100644 --- a/ui/packages/consul-ui/app/routes/dc/acls/roles/index.js +++ b/ui/packages/consul-ui/app/routes/dc/acls/roles/index.js @@ -22,10 +22,10 @@ export default class IndexRoute extends Route.extend(WithRoleActions) { model(params) { return hash({ ...this.repo.status({ - items: this.repo.findAllByDatacenter( - this.modelFor('dc').dc.Name, - this.modelFor('nspace').nspace.substr(1) - ), + items: this.repo.findAllByDatacenter({ + ns: this.modelFor('nspace').nspace.substr(1), + dc: this.modelFor('dc').dc.Name, + }), }), searchProperties: this.queryParams.searchproperty.empty[0], }); diff --git a/ui/packages/consul-ui/app/routes/dc/acls/tokens/index.js b/ui/packages/consul-ui/app/routes/dc/acls/tokens/index.js index bfc26b5f9..1441e1ea1 100644 --- a/ui/packages/consul-ui/app/routes/dc/acls/tokens/index.js +++ b/ui/packages/consul-ui/app/routes/dc/acls/tokens/index.js @@ -35,10 +35,10 @@ export default class IndexRoute extends Route.extend(WithTokenActions) { model(params) { return hash({ ...this.repo.status({ - items: this.repo.findAllByDatacenter( - this.modelFor('dc').dc.Name, - this.modelFor('nspace').nspace.substr(1) - ), + items: this.repo.findAllByDatacenter({ + ns: this.modelFor('nspace').nspace.substr(1), + dc: this.modelFor('dc').dc.Name, + }), }), nspace: this.modelFor('nspace').nspace.substr(1), token: this.settings.findBySlug('token'), diff --git a/ui/packages/consul-ui/app/routes/dc/intentions/edit.js b/ui/packages/consul-ui/app/routes/dc/intentions/edit.js index 36aa0fd6e..52d150235 100644 --- a/ui/packages/consul-ui/app/routes/dc/intentions/edit.js +++ b/ui/packages/consul-ui/app/routes/dc/intentions/edit.js @@ -11,7 +11,11 @@ export default class EditRoute extends Route { let item; if (typeof intention_id !== 'undefined') { - item = await this.repo.findBySlug(intention_id, dc, nspace); + item = await this.repo.findBySlug({ + ns: nspace, + dc: dc, + id: intention_id, + }); } else { const defaultNspace = this.env.var('CONSUL_NSPACES_ENABLED') ? '*' : 'default'; item = await this.repo.create({ diff --git a/ui/packages/consul-ui/app/routes/dc/kv/edit.js b/ui/packages/consul-ui/app/routes/dc/kv/edit.js index 127332cf9..f18fca372 100644 --- a/ui/packages/consul-ui/app/routes/dc/kv/edit.js +++ b/ui/packages/consul-ui/app/routes/dc/kv/edit.js @@ -24,14 +24,26 @@ export default class EditRoute extends Route { nspace: nspace || 'default', parent: typeof key !== 'undefined' - ? this.repo.findBySlug(ascend(key, 1) || '/', dc, nspace) - : this.repo.findBySlug('/', dc, nspace), + ? this.repo.findBySlug({ + ns: nspace, + dc: dc, + id: ascend(key, 1) || '/', + }) + : this.repo.findBySlug({ + ns: nspace, + dc: dc, + id: '/', + }), item: create ? this.repo.create({ Datacenter: dc, Namespace: nspace, }) - : this.repo.findBySlug(key, dc, nspace), + : this.repo.findBySlug({ + ns: nspace, + dc: dc, + id: key, + }), session: null, }).then(model => { // TODO: Consider loading this after initial page load @@ -41,7 +53,11 @@ export default class EditRoute extends Route { return hash({ ...model, ...{ - session: this.sessionRepo.findByKey(session, dc, nspace), + session: this.sessionRepo.findByKey({ + ns: nspace, + dc: dc, + id: session, + }), }, }); } diff --git a/ui/packages/consul-ui/app/routes/dc/kv/index.js b/ui/packages/consul-ui/app/routes/dc/kv/index.js index bbbccde3d..5b043c6a3 100644 --- a/ui/packages/consul-ui/app/routes/dc/kv/index.js +++ b/ui/packages/consul-ui/app/routes/dc/kv/index.js @@ -31,12 +31,30 @@ export default class IndexRoute extends Route { const dc = this.modelFor('dc').dc.Name; const nspace = this.modelFor('nspace').nspace.substr(1); return hash({ - parent: this.repo.findBySlug(key, dc, nspace), + parent: this.repo.findBySlug({ + ns: nspace, + dc: dc, + id: key, + }), }).then(model => { return hash({ ...model, ...{ - items: this.repo.findAllBySlug(get(model.parent, 'Key'), dc, nspace), + items: this.repo + .findAllBySlug({ + ns: nspace, + dc: dc, + id: get(model.parent, 'Key'), + }) + .catch(e => { + const status = get(e, 'errors.firstObject.status'); + switch (status) { + case '403': + return this.transitionTo('dc.acls.tokens'); + default: + return this.transitionTo('dc.kv.index'); + } + }), }, }); }); diff --git a/ui/packages/consul-ui/app/routes/dc/nspaces/edit.js b/ui/packages/consul-ui/app/routes/dc/nspaces/edit.js index 28dc3408b..8d619c7eb 100644 --- a/ui/packages/consul-ui/app/routes/dc/nspaces/edit.js +++ b/ui/packages/consul-ui/app/routes/dc/nspaces/edit.js @@ -28,7 +28,7 @@ export default class EditRoute extends Route.extend(WithNspaceActions) { }, }) ) - : repo.findBySlug(params.name), + : repo.findBySlug({ id: params.name }), }); } diff --git a/ui/packages/consul-ui/app/routing/single.js b/ui/packages/consul-ui/app/routing/single.js index d221aa8ab..4ee0ea35f 100644 --- a/ui/packages/consul-ui/app/routing/single.js +++ b/ui/packages/consul-ui/app/routing/single.js @@ -27,7 +27,11 @@ export default Route.extend({ Namespace: nspace, }) ) - : repo.findBySlug(params.id, dc, nspace), + : repo.findBySlug({ + ns: nspace, + dc: dc, + id: params.id, + }), }), }); }, diff --git a/ui/packages/consul-ui/app/services/container.js b/ui/packages/consul-ui/app/services/container.js new file mode 100644 index 000000000..bdd4d6fd2 --- /dev/null +++ b/ui/packages/consul-ui/app/services/container.js @@ -0,0 +1,36 @@ +import Service from '@ember/service'; + +export default class ContainerService extends Service { + constructor(owner) { + super(...arguments); + this._owner = owner; + this._wm = new WeakMap(); + } + + set(key, value) { + this._wm.set(value, key); + } + + // vaguely private, used publicly for debugging purposes + keyForClass(cls) { + return this._wm.get(cls); + } + + get(key) { + if (typeof key !== 'string') { + key = this.keyForClass(key); + } + return this.lookup(key); + } + + lookup(key) { + return this._owner.lookup(key); + } + + resolveRegistration(key) { + // ember resolveRegistration returns an ember flavoured class extending + // from the actual class, access the actual class from the + // prototype/parent which is what decorators pass through as target + return this._owner.resolveRegistration(key).prototype; + } +} diff --git a/ui/packages/consul-ui/app/services/data-source/protocols/http.js b/ui/packages/consul-ui/app/services/data-source/protocols/http.js index 97493b7b3..a771ad221 100644 --- a/ui/packages/consul-ui/app/services/data-source/protocols/http.js +++ b/ui/packages/consul-ui/app/services/data-source/protocols/http.js @@ -1,95 +1,28 @@ import Service, { inject as service } from '@ember/service'; import { get } from '@ember/object'; +import { getOwner } from '@ember/application'; +import { match } from 'consul-ui/decorators/data-source'; +import { singularize } from 'ember-inflector'; export default class HttpService extends Service { - @service('repository/dc') - datacenters; + @service('repository/dc') datacenters; + @service('repository/node') leader; + @service('repository/service') gateways; + @service('repository/service-instance') 'proxy-service-instance'; + @service('repository/proxy') 'proxy-instance'; + @service('repository/nspace') namespaces; + @service('repository/metrics') metrics; + @service('repository/oidc-provider') oidc; - @service('repository/node') - nodes; - - @service('repository/node') - node; - - @service('repository/node') - leader; - - @service('repository/service') - gateways; - - @service('repository/service') - services; - - @service('repository/service') - service; - - @service('repository/service-instance') - 'service-instance'; - - @service('repository/service-instance') - 'proxy-service-instance'; - - @service('repository/service-instance') - 'service-instances'; - - @service('repository/proxy') - proxies; - - @service('repository/proxy') - 'proxy-instance'; - - @service('repository/discovery-chain') - 'discovery-chain'; - - @service('repository/topology') - topology; - - @service('repository/coordinate') - coordinates; - - @service('repository/session') - sessions; - - @service('repository/nspace') - namespaces; - - @service('repository/intention') - intentions; - - @service('repository/intention') - intention; - - @service('repository/kv') - kv; - - @service('repository/token') - token; - - @service('repository/policy') - policies; - - @service('repository/policy') - policy; - - @service('repository/role') - roles; - - @service('repository/oidc-provider') - oidc; - - @service('repository/metrics') - metrics; - - @service('data-source/protocols/http/blocking') - type; + @service('data-source/protocols/http/blocking') type; source(src, configuration) { - // TODO: Consider adding/requiring 'action': nspace, dc, model, action, ...rest - const [, nspace, dc, model, ...rest] = src.split('/').map(decodeURIComponent); - // nspaces can be filled, blank or * - // so we might get urls like //dc/services - let find; - const repo = this[model]; + const [, , , model] = src.split('/'); + const owner = getOwner(this); + const route = match(src); + const find = route.cb(route.params, owner); + + const repo = this[model] || owner.lookup(`service:repository/${singularize(model)}`); configuration.createEvent = function(result = {}, configuration) { const event = { type: 'message', @@ -101,141 +34,6 @@ export default class HttpService extends Service { } return event; }; - let method, slug, more, protocol; - switch (model) { - case 'metrics': - [method, slug, ...more] = rest; - switch (method) { - case 'summary-for-service': - [protocol, ...more] = more; - find = configuration => - repo.findServiceSummary(protocol, slug, dc, nspace, configuration); - break; - case 'upstream-summary-for-service': - find = configuration => repo.findUpstreamSummary(slug, dc, nspace, configuration); - break; - case 'downstream-summary-for-service': - find = configuration => repo.findDownstreamSummary(slug, dc, nspace, configuration); - break; - } - break; - case 'datacenters': - case 'namespaces': - find = configuration => repo.findAll(configuration); - break; - case 'services': - case 'nodes': - case 'roles': - case 'policies': - find = configuration => repo.findAllByDatacenter(dc, nspace, configuration); - break; - case 'leader': - find = configuration => repo.findLeader(dc, configuration); - break; - case 'intentions': - [method, ...slug] = rest; - switch (method) { - case 'for-service': - find = configuration => repo.findByService(slug, dc, nspace, configuration); - break; - default: - find = configuration => repo.findAllByDatacenter(dc, nspace, configuration); - break; - } - break; - case 'service-instances': - [method, ...slug] = rest; - switch (method) { - case 'for-service': - find = configuration => repo.findByService(slug, dc, nspace, configuration); - break; - } - break; - case 'coordinates': - [method, ...slug] = rest; - switch (method) { - case 'for-node': - find = configuration => repo.findAllByNode(slug, dc, configuration); - break; - } - break; - case 'proxies': - [method, ...slug] = rest; - switch (method) { - case 'for-service': - find = configuration => repo.findAllBySlug(slug, dc, nspace, configuration); - break; - } - break; - case 'gateways': - [method, ...slug] = rest; - switch (method) { - case 'for-service': - find = configuration => repo.findGatewayBySlug(slug, dc, nspace, configuration); - break; - } - break; - case 'sessions': - [method, ...slug] = rest; - switch (method) { - case 'for-node': - find = configuration => repo.findByNode(slug, dc, nspace, configuration); - break; - } - break; - case 'token': - find = configuration => repo.self(rest[1], dc); - break; - case 'discovery-chain': - case 'node': - find = configuration => repo.findBySlug(rest[0], dc, nspace, configuration); - break; - case 'service-instance': - // id, node, service - find = configuration => - repo.findBySlug(rest[0], rest[1], rest[2], dc, nspace, configuration); - break; - case 'proxy-service-instance': - // id, node, service - find = configuration => - repo.findProxyBySlug(rest[0], rest[1], rest[2], dc, nspace, configuration); - break; - case 'proxy-instance': - // id, node, service - find = configuration => - repo.findInstanceBySlug(rest[0], rest[1], rest[2], dc, nspace, configuration); - break; - case 'topology': - // id, service kind - find = configuration => repo.findBySlug(rest[0], rest[1], dc, nspace, configuration); - break; - case 'policy': - case 'kv': - case 'intention': - slug = rest[0]; - if (slug) { - find = configuration => repo.findBySlug(slug, dc, nspace, configuration); - } else { - find = configuration => - Promise.resolve(repo.create({ Datacenter: dc, Namespace: nspace })); - } - break; - case 'oidc': - [method, ...slug] = rest; - switch (method) { - case 'providers': - find = configuration => repo.findAllByDatacenter(dc, nspace, configuration); - break; - case 'provider': - find = configuration => repo.findBySlug(slug[0], dc, nspace); - break; - case 'authorize': - find = configuration => - repo.authorize(slug[0], slug[1], slug[2], dc, nspace, configuration); - break; - } - break; - } return this.type.source(find, configuration); } } diff --git a/ui/packages/consul-ui/app/services/repository.js b/ui/packages/consul-ui/app/services/repository.js index 4d7f2181c..cdfb20eea 100644 --- a/ui/packages/consul-ui/app/services/repository.js +++ b/ui/packages/consul-ui/app/services/repository.js @@ -23,43 +23,33 @@ export default class RepositoryService extends Service { } /** - * Creates a set of permissions base don a slug, loads in the access - * permissions for themand checks/validates + * Creates a set of permissions based on an id/slug, loads in the access + * permissions for them and checks/validates */ - async authorizeBySlug(cb, access, slug, dc, nspace) { - return this.validatePermissions( - cb, - await this.permissions.findBySlug(slug, this.getModelName(), dc, nspace), - access, - dc, - nspace - ); + async authorizeBySlug(cb, access, params) { + params.resources = await this.permissions.findBySlug(params, this.getModelName()); + return this.validatePermissions(cb, access, params); } /** * Loads in the access permissions and checks/validates them for a set of * permissions */ - async authorizeByPermissions(cb, permissions, access, dc, nspace) { - return this.validatePermissions( - cb, - await this.permissions.authorize(permissions, dc, nspace), - access, - dc, - nspace - ); + async authorizeByPermissions(cb, access, params) { + params.resources = await this.permissions.authorize(params); + return this.validatePermissions(cb, access, params); } /** * Checks already loaded permissions for certain access before calling cb to * return the thing you wanted to check the permissions on */ - async validatePermissions(cb, permissions, access, dc, nspace) { + async validatePermissions(cb, access, params) { // inspect the permissions for this segment/slug remotely, if we have zero // permissions fire a fake 403 so we don't even request the model/resource - if (permissions.length > 0) { - const permission = permissions.find(item => item.Access === access); - if (permission && permission.Allow === false) { + if (params.resources.length > 0) { + const resource = params.resources.find(item => item.Access === access); + if (resource && resource.Allow === false) { // TODO: Here we temporarily make a hybrid HTTPError/ember-data HTTP error // we should eventually use HTTPError's everywhere const e = new HTTPError(403); @@ -71,7 +61,7 @@ export default class RepositoryService extends Service { // add the `Resource` information to the record/model so we can inspect // them in other places like templates etc if (get(item, 'Resources')) { - set(item, 'Resources', permissions); + set(item, 'Resources', params.resources); } return item; } @@ -102,34 +92,29 @@ export default class RepositoryService extends Service { return this.store.peekRecord(this.getModelName(), id); } - findAllByDatacenter(dc, nspace, configuration = {}) { - const query = { - dc: dc, - ns: nspace, - }; + findAllByDatacenter(params, configuration = {}) { if (typeof configuration.cursor !== 'undefined') { - query.index = configuration.cursor; - query.uri = configuration.uri; + params.index = configuration.cursor; + params.uri = configuration.uri; } - return this.store.query(this.getModelName(), query); + return this.store.query(this.getModelName(), params); } - async findBySlug(slug, dc, nspace, configuration = {}) { - const query = { - dc: dc, - ns: nspace, - id: slug, - }; + async findBySlug(params, configuration = {}) { + if (params.id === '') { + return this.create({ + Datacenter: params.dc, + Namespace: params.ns, + }); + } if (typeof configuration.cursor !== 'undefined') { - query.index = configuration.cursor; - query.uri = configuration.uri; + params.index = configuration.cursor; + params.uri = configuration.uri; } return this.authorizeBySlug( - () => this.store.queryRecord(this.getModelName(), query), + () => this.store.queryRecord(this.getModelName(), params), ACCESS_READ, - slug, - dc, - nspace + params ); } diff --git a/ui/packages/consul-ui/app/services/repository/auth-method.js b/ui/packages/consul-ui/app/services/repository/auth-method.js index 818b3ecac..392db0b2d 100644 --- a/ui/packages/consul-ui/app/services/repository/auth-method.js +++ b/ui/packages/consul-ui/app/services/repository/auth-method.js @@ -2,6 +2,7 @@ import RepositoryService from 'consul-ui/services/repository'; import statusFactory from 'consul-ui/utils/acls-status'; import isValidServerErrorFactory from 'consul-ui/utils/http/acl/is-valid-server-error'; import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/auth-method'; +import dataSource from 'consul-ui/decorators/data-source'; const isValidServerError = isValidServerErrorFactory(); const status = statusFactory(isValidServerError, Promise); @@ -20,6 +21,16 @@ export default class AuthMethodService extends RepositoryService { return SLUG_KEY; } + @dataSource('/:ns/:dc/auth-methods') + async findAllByDatacenter() { + return super.findAllByDatacenter(...arguments); + } + + @dataSource('/:ns/:dc/auth-method/:id') + async findBySlug() { + return super.findBySlug(...arguments); + } + status(obj) { return status(obj); } diff --git a/ui/packages/consul-ui/app/services/repository/coordinate.js b/ui/packages/consul-ui/app/services/repository/coordinate.js index 5978893f0..af0e6f3bf 100644 --- a/ui/packages/consul-ui/app/services/repository/coordinate.js +++ b/ui/packages/consul-ui/app/services/repository/coordinate.js @@ -4,6 +4,7 @@ import RepositoryService from 'consul-ui/services/repository'; import tomographyFactory from 'consul-ui/utils/tomography'; import distance from 'consul-ui/utils/distance'; const tomography = tomographyFactory(distance); +import dataSource from 'consul-ui/decorators/data-source'; const modelName = 'coordinate'; export default class CoordinateService extends RepositoryService { @@ -13,25 +14,21 @@ export default class CoordinateService extends RepositoryService { // Coordinates don't need nspaces so we have a custom method here // that doesn't accept nspaces - findAllByDatacenter(dc, configuration = {}) { - const query = { - dc: dc, - }; + @dataSource('/:ns/:dc/coordinates') + findAllByDatacenter(params, configuration = {}) { if (typeof configuration.cursor !== 'undefined') { - query.index = configuration.cursor; - query.uri = configuration.uri; + params.index = configuration.cursor; + params.uri = configuration.uri; } - return this.store.query(this.getModelName(), query); + return this.store.query(this.getModelName(), params); } - findAllByNode(node, dc, configuration) { - return this.findAllByDatacenter(dc, configuration).then(function(coordinates) { + @dataSource('/:ns/:dc/coordinates/for-node/:id') + findAllByNode(params, configuration) { + return this.findAllByDatacenter(params, configuration).then(function(coordinates) { let results = {}; if (get(coordinates, 'length') > 1) { - results = tomography( - node, - coordinates - ); + results = tomography(params.id, coordinates); } results.meta = get(coordinates, 'meta'); return results; diff --git a/ui/packages/consul-ui/app/services/repository/dc.js b/ui/packages/consul-ui/app/services/repository/dc.js index cb0a3cd61..6eec243ef 100644 --- a/ui/packages/consul-ui/app/services/repository/dc.js +++ b/ui/packages/consul-ui/app/services/repository/dc.js @@ -2,6 +2,7 @@ import { inject as service } from '@ember/service'; import RepositoryService from 'consul-ui/services/repository'; import { get } from '@ember/object'; import Error from '@ember/error'; +import dataSource from 'consul-ui/decorators/data-source'; const modelName = 'dc'; export default class DcService extends RepositoryService { @@ -12,7 +13,8 @@ export default class DcService extends RepositoryService { return modelName; } - async findAll() { + @dataSource('/:ns/:dc/datacenters') + async findAll(params, configuration = {}) { return this.store.query(this.getModelName(), {}); } diff --git a/ui/packages/consul-ui/app/services/repository/discovery-chain.js b/ui/packages/consul-ui/app/services/repository/discovery-chain.js index cb7fd8894..2b1947674 100644 --- a/ui/packages/consul-ui/app/services/repository/discovery-chain.js +++ b/ui/packages/consul-ui/app/services/repository/discovery-chain.js @@ -1,6 +1,7 @@ import { inject as service } from '@ember/service'; import { get, set } from '@ember/object'; import RepositoryService from 'consul-ui/services/repository'; +import dataSource from 'consul-ui/decorators/data-source'; const modelName = 'discovery-chain'; const ERROR_MESH_DISABLED = 'Connect must be enabled in order to use this endpoint'; @@ -12,8 +13,9 @@ export default class DiscoveryChainService extends RepositoryService { return modelName; } - findBySlug(slug, dc, nspace, configuration = {}) { - const datacenter = this.dcs.peekOne(dc); + @dataSource('/:ns/:dc/discovery-chain/:id') + findBySlug(params, configuration = {}) { + const datacenter = this.dcs.peekOne(params.dc); if (datacenter !== null && !get(datacenter, 'MeshEnabled')) { return Promise.resolve(); } diff --git a/ui/packages/consul-ui/app/services/repository/intention.js b/ui/packages/consul-ui/app/services/repository/intention.js index d215797e1..e959e9aed 100644 --- a/ui/packages/consul-ui/app/services/repository/intention.js +++ b/ui/packages/consul-ui/app/services/repository/intention.js @@ -1,6 +1,7 @@ import { set, get } from '@ember/object'; import RepositoryService from 'consul-ui/services/repository'; import { PRIMARY_KEY } from 'consul-ui/models/intention'; +import dataSource from 'consul-ui/decorators/data-source'; const modelName = 'intention'; export default class IntentionRepository extends RepositoryService { @@ -34,13 +35,13 @@ export default class IntentionRepository extends RepositoryService { // legacy intentions are strange that in order to read/write you need access // to either/or the destination or source - async authorizeBySlug(cb, access, slug, dc, nspace) { - const [, source, , destination] = slug.split(':'); + async authorizeBySlug(cb, access, params) { + const [, source, , destination] = params.id.split(':'); const ability = this.permissions.abilityFor(this.getModelName()); - const permissions = ability + params.resources = ability .generateForSegment(source) .concat(ability.generateForSegment(destination)); - return this.authorizeByPermissions(cb, permissions, access, dc, nspace); + return this.authorizeByPermissions(cb, access, params); } async persist(obj) { @@ -56,11 +57,22 @@ export default class IntentionRepository extends RepositoryService { return res; } - async findByService(slug, dc, nspace, configuration = {}) { + @dataSource('/:ns/:dc/intentions') + async findAllByDatacenter() { + return super.findAllByDatacenter(...arguments); + } + + @dataSource('/:ns/:dc/intention/:id') + async findBySlug() { + return super.findBySlug(...arguments); + } + + @dataSource('/:ns/:dc/intentions/for-service/:id') + async findByService(params, configuration = {}) { const query = { - dc, - nspace, - filter: `SourceName == "${slug}" or DestinationName == "${slug}" or SourceName == "*" or DestinationName == "*"`, + dc: params.dc, + nspace: params.nspace, + filter: `SourceName == "${params.id}" or DestinationName == "${params.id}" or SourceName == "*" or DestinationName == "*"`, }; if (typeof configuration.cursor !== 'undefined') { query.index = configuration.cursor; diff --git a/ui/packages/consul-ui/app/services/repository/kv.js b/ui/packages/consul-ui/app/services/repository/kv.js index fadc4feed..145cb5e25 100644 --- a/ui/packages/consul-ui/app/services/repository/kv.js +++ b/ui/packages/consul-ui/app/services/repository/kv.js @@ -3,6 +3,7 @@ import isFolder from 'consul-ui/utils/isFolder'; import { get } from '@ember/object'; import { PRIMARY_KEY } from 'consul-ui/models/kv'; import { ACCESS_LIST } from 'consul-ui/abilities/base'; +import dataSource from 'consul-ui/decorators/data-source'; const modelName = 'kv'; export default class KvService extends RepositoryService { @@ -15,71 +16,65 @@ export default class KvService extends RepositoryService { } // this one gives you the full object so key,values and meta - async findBySlug(slug, dc, nspace, configuration = {}) { - if (isFolder(slug)) { + @dataSource('/:ns/:dc/kv/*id') + async findBySlug(params, configuration = {}) { + if (isFolder(params.id)) { // we only use findBySlug for a folder when we are looking to create a // parent for a key for retriveing something Model shaped. Therefore we // only use existing records or a fake record with the correct Key, - // which means we don't need to inpsect permissions as its an already + // which means we don't need to inspect permissions as its an already // existing KV or a fake one // TODO: This very much shouldn't be here, // needs to eventually use ember-datas generateId thing // in the meantime at least our fingerprinter - const id = JSON.stringify([nspace, dc, slug]); - let item = this.store.peekRecord(this.getModelName(), id); + const uid = JSON.stringify([params.ns, params.dc, params.id]); + let item = this.store.peekRecord(this.getModelName(), uid); if (!item) { item = this.create({ - Key: slug, - Datacenter: dc, - Namespace: nspace, + Key: params.id, + Datacenter: params.dc, + Namespace: params.ns, }); } return item; } else { - return super.findBySlug(slug, dc, nspace, configuration); + return super.findBySlug(...arguments); } } // this one only gives you keys // https://www.consul.io/api/kv.html - findAllBySlug(key, dc, nspace, configuration = {}) { - if (key === '/') { - key = ''; + findAllBySlug(params, configuration = {}) { + if (params.id === '/') { + params.id = ''; } return this.authorizeBySlug( async () => { - const query = { - id: key, - dc: dc, - ns: nspace, - separator: '/', - }; + params.separator = '/'; if (typeof configuration.cursor !== 'undefined') { - query.index = configuration.cursor; + params.index = configuration.cursor; } let items; try { - items = await this.store.query(this.getModelName(), query); + items = await this.store.query(this.getModelName(), params); } catch (e) { if (get(e, 'errors.firstObject.status') === '404') { // TODO: This very much shouldn't be here, // needs to eventually use ember-datas generateId thing // in the meantime at least our fingerprinter - const id = JSON.stringify([dc, key]); - const record = this.store.peekRecord(this.getModelName(), id); + const uid = JSON.stringify([params.ns, params.dc, params.id]); + const record = this.store.peekRecord(this.getModelName(), uid); if (record) { record.unloadRecord(); } } throw e; } - return items.filter(item => key !== get(item, 'Key')); + return items.filter(item => params.id !== get(item, 'Key')); }, ACCESS_LIST, - key, - dc, - nspace + params ); } } diff --git a/ui/packages/consul-ui/app/services/repository/metrics.js b/ui/packages/consul-ui/app/services/repository/metrics.js index ab97ec488..f9079f6e5 100644 --- a/ui/packages/consul-ui/app/services/repository/metrics.js +++ b/ui/packages/consul-ui/app/services/repository/metrics.js @@ -1,9 +1,9 @@ import { inject as service } from '@ember/service'; import RepositoryService from 'consul-ui/services/repository'; +import dataSource from 'consul-ui/decorators/data-source'; // CONSUL_METRICS_POLL_INTERVAL controls how long between each poll to the // metrics provider - export default class MetricsService extends RepositoryService { @service('ui-config') config; @service('env') env; @@ -11,6 +11,10 @@ export default class MetricsService extends RepositoryService { error = null; + getModelName() { + return 'metrics'; + } + init() { super.init(...arguments); const config = this.config.get(); @@ -34,13 +38,26 @@ export default class MetricsService extends RepositoryService { } } - findServiceSummary(protocol, slug, dc, nspace, configuration = {}) { + @dataSource('/:ns/:dc/metrics/summary-for-service/:slug/:protocol') + findServiceSummary(params, configuration = {}) { if (this.error) { return Promise.reject(this.error); } const promises = [ - this.provider.serviceRecentSummarySeries(slug, dc, nspace, protocol, {}), - this.provider.serviceRecentSummaryStats(slug, dc, nspace, protocol, {}), + this.provider.serviceRecentSummarySeries( + params.slug, + params.dc, + params.ns, + params.protocol, + {} + ), + this.provider.serviceRecentSummaryStats( + params.slug, + params.dc, + params.ns, + params.protocol, + {} + ), ]; return Promise.all(promises).then(results => { return { @@ -53,27 +70,33 @@ export default class MetricsService extends RepositoryService { }); } - findUpstreamSummary(slug, dc, nspace, configuration = {}) { + @dataSource('/:ns/:dc/metrics/upstream-summary-for-service/:slug/:protocol') + findUpstreamSummary(params, configuration = {}) { if (this.error) { return Promise.reject(this.error); } - return this.provider.upstreamRecentSummaryStats(slug, dc, nspace, {}).then(result => { - result.meta = { - interval: this.env.var('CONSUL_METRICS_POLL_INTERVAL') || 10000, - }; - return result; - }); + return this.provider + .upstreamRecentSummaryStats(params.slug, params.dc, params.ns, {}) + .then(result => { + result.meta = { + interval: this.env.var('CONSUL_METRICS_POLL_INTERVAL') || 10000, + }; + return result; + }); } - findDownstreamSummary(slug, dc, nspace, configuration = {}) { + @dataSource('/:ns/:dc/metrics/downstream-summary-for-service/:slug/:protocol') + findDownstreamSummary(params, configuration = {}) { if (this.error) { return Promise.reject(this.error); } - return this.provider.downstreamRecentSummaryStats(slug, dc, nspace, {}).then(result => { - result.meta = { - interval: this.env.var('CONSUL_METRICS_POLL_INTERVAL') || 10000, - }; - return result; - }); + return this.provider + .downstreamRecentSummaryStats(params.slug, params.dc, params.ns, {}) + .then(result => { + result.meta = { + interval: this.env.var('CONSUL_METRICS_POLL_INTERVAL') || 10000, + }; + return result; + }); } } diff --git a/ui/packages/consul-ui/app/services/repository/node.js b/ui/packages/consul-ui/app/services/repository/node.js index 7b557f4ea..9c5e7cff8 100644 --- a/ui/packages/consul-ui/app/services/repository/node.js +++ b/ui/packages/consul-ui/app/services/repository/node.js @@ -1,4 +1,5 @@ import RepositoryService from 'consul-ui/services/repository'; +import dataSource from 'consul-ui/decorators/data-source'; const modelName = 'node'; export default class NodeService extends RepositoryService { @@ -6,13 +7,21 @@ export default class NodeService extends RepositoryService { return modelName; } - findLeader(dc, configuration = {}) { - const query = { - dc: dc, - }; + @dataSource('/:ns/:dc/nodes') + async findAllByDatacenter() { + return super.findAllByDatacenter(...arguments); + } + + @dataSource('/:ns/:dc/node/:id') + async findBySlug() { + return super.findBySlug(...arguments); + } + + @dataSource('/:ns/:dc/leader') + findLeader(params, configuration = {}) { if (typeof configuration.refresh !== 'undefined') { - query.uri = configuration.uri; + params.uri = configuration.uri; } - return this.store.queryLeader(this.getModelName(), query); + return this.store.queryLeader(this.getModelName(), params); } } diff --git a/ui/packages/consul-ui/app/services/repository/nspace.js b/ui/packages/consul-ui/app/services/repository/nspace.js index da962e2f9..b448288dd 100644 --- a/ui/packages/consul-ui/app/services/repository/nspace.js +++ b/ui/packages/consul-ui/app/services/repository/nspace.js @@ -1,5 +1,6 @@ import RepositoryService from 'consul-ui/services/repository'; import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/nspace'; +import dataSource from 'consul-ui/decorators/data-source'; const modelName = 'nspace'; export default class NspaceService extends RepositoryService { @@ -37,7 +38,13 @@ export default class NspaceService extends RepositoryService { return res; } - findAll(configuration = {}) { + @dataSource('/:ns/:dc/namespace/:id') + async findBySlug() { + return super.findBySlug(...arguments); + } + + @dataSource('/:ns/:dc/namespaces') + findAll(params, configuration = {}) { const query = {}; if (typeof configuration.cursor !== 'undefined') { query.index = configuration.cursor; diff --git a/ui/packages/consul-ui/app/services/repository/nspace/enabled.js b/ui/packages/consul-ui/app/services/repository/nspace/enabled.js index 8239c6346..2e385fd85 100644 --- a/ui/packages/consul-ui/app/services/repository/nspace/enabled.js +++ b/ui/packages/consul-ui/app/services/repository/nspace/enabled.js @@ -24,7 +24,7 @@ export default class EnabledService extends RepositoryService { return modelName; } - findAll(configuration = {}) { + findAll(params, configuration = {}) { const query = {}; if (typeof configuration.cursor !== 'undefined') { query.index = configuration.cursor; diff --git a/ui/packages/consul-ui/app/services/repository/oidc-provider.js b/ui/packages/consul-ui/app/services/repository/oidc-provider.js index 77907013c..6c5286924 100644 --- a/ui/packages/consul-ui/app/services/repository/oidc-provider.js +++ b/ui/packages/consul-ui/app/services/repository/oidc-provider.js @@ -2,6 +2,7 @@ import { inject as service } from '@ember/service'; import RepositoryService from 'consul-ui/services/repository'; import { getOwner } from '@ember/application'; import { set } from '@ember/object'; +import dataSource from 'consul-ui/decorators/data-source'; const modelName = 'oidc-provider'; const OAUTH_PROVIDER_NAME = 'oidc-with-url'; @@ -18,15 +19,19 @@ export default class OidcProviderService extends RepositoryService { return modelName; } - authorize(id, code, state, dc, nspace, configuration = {}) { - const query = { - id: id, - code: code, - state: state, - dc: dc, - ns: nspace, - }; - return this.store.authorize(this.getModelName(), query); + @dataSource('/:ns/:dc/oidc/providers') + async findAllByDatacenter() { + return super.findAllByDatacenter(...arguments); + } + + @dataSource('/:ns/:dc/oidc/provider/:id') + async findBySlug() { + return super.findBySlug(...arguments); + } + + @dataSource('/:ns/:dc/oidc/authorize/:id/:code/:state') + authorize(params, configuration = {}) { + return this.store.authorize(this.getModelName(), params); } logout(id, code, state, dc, nspace, configuration = {}) { diff --git a/ui/packages/consul-ui/app/services/repository/permission.js b/ui/packages/consul-ui/app/services/repository/permission.js index ff8a18ee5..b78b56ba5 100644 --- a/ui/packages/consul-ui/app/services/repository/permission.js +++ b/ui/packages/consul-ui/app/services/repository/permission.js @@ -97,31 +97,27 @@ export default class PermissionService extends RepositoryService { * If ACLs are disabled, then you have access to everything, hence we check * that here and only make the request if ACLs are enabled */ - async authorize(resources, dc, nspace) { + async authorize(params) { if (!this.env.var('CONSUL_ACLS_ENABLED')) { - return resources.map(item => { + return params.resources.map(item => { return { ...item, Allow: true, }; }); } else { - let permissions = []; + let resources = []; try { - permissions = await this.store.authorize('permission', { - dc: dc, - ns: nspace, - permissions: resources, - }); + resources = await this.store.authorize('permission', params); } catch (e) { runInDebug(() => console.error(e)); // passthrough } - return permissions; + return resources; } } - async findBySlug(segment, model, dc, nspace) { + async findBySlug(params, model) { let ability; try { ability = this._can.abilityFor(model); @@ -129,21 +125,23 @@ export default class PermissionService extends RepositoryService { return []; } - const resources = ability.generateForSegment(segment.toString()); + const resources = ability.generateForSegment(params.id.toString()); // if we get no resources for a segment it means that this // ability/permission isn't segmentable if (resources.length === 0) { return []; } - return this.authorize(resources, dc, nspace); + params.resources = resources; + return this.authorize(params); } - async findByPermissions(resources, dc, nspace) { - return this.authorize(resources, dc, nspace); + async findByPermissions(params) { + return this.authorize(params); } - async findAll(dc, nspace) { - this.permissions = await this.findByPermissions(REQUIRED_PERMISSIONS, dc, nspace); + async findAll(params) { + params.resources = REQUIRED_PERMISSIONS; + this.permissions = await this.findByPermissions(params); return this.permissions; } } diff --git a/ui/packages/consul-ui/app/services/repository/policy.js b/ui/packages/consul-ui/app/services/repository/policy.js index 57c4dedbe..694e9ceb9 100644 --- a/ui/packages/consul-ui/app/services/repository/policy.js +++ b/ui/packages/consul-ui/app/services/repository/policy.js @@ -3,6 +3,7 @@ import { get } from '@ember/object'; import statusFactory from 'consul-ui/utils/acls-status'; import isValidServerErrorFactory from 'consul-ui/utils/http/acl/is-valid-server-error'; import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/policy'; +import dataSource from 'consul-ui/decorators/data-source'; const isValidServerError = isValidServerErrorFactory(); const status = statusFactory(isValidServerError, Promise); @@ -21,6 +22,16 @@ export default class PolicyService extends RepositoryService { return SLUG_KEY; } + @dataSource('/:ns/:dc/policies') + async findAllByDatacenter() { + return super.findAllByDatacenter(...arguments); + } + + @dataSource('/:ns/:dc/policy/:id') + async findBySlug() { + return super.findBySlug(...arguments); + } + status(obj) { return status(obj); } diff --git a/ui/packages/consul-ui/app/services/repository/proxy.js b/ui/packages/consul-ui/app/services/repository/proxy.js index df0563afb..ea76d7e70 100644 --- a/ui/packages/consul-ui/app/services/repository/proxy.js +++ b/ui/packages/consul-ui/app/services/repository/proxy.js @@ -1,6 +1,8 @@ import RepositoryService from 'consul-ui/services/repository'; import { PRIMARY_KEY } from 'consul-ui/models/proxy'; import { get, set } from '@ember/object'; +import dataSource from 'consul-ui/decorators/data-source'; + const modelName = 'proxy'; export default class ProxyService extends RepositoryService { getModelName() { @@ -11,17 +13,13 @@ export default class ProxyService extends RepositoryService { return PRIMARY_KEY; } - findAllBySlug(slug, dc, nspace, configuration = {}) { - const query = { - id: slug, - ns: nspace, - dc: dc, - }; + @dataSource('/:ns/:dc/proxies/for-service/:id') + findAllBySlug(params, configuration = {}) { if (typeof configuration.cursor !== 'undefined') { - query.index = configuration.cursor; - query.uri = configuration.uri; + params.index = configuration.cursor; + params.uri = configuration.uri; } - return this.store.query(this.getModelName(), query).then(items => { + return this.store.query(this.getModelName(), params).then(items => { items.forEach(item => { // swap out the id for the services id // so we can then assign the proxy to it if it exists @@ -37,17 +35,18 @@ export default class ProxyService extends RepositoryService { }); } - findInstanceBySlug(id, node, slug, dc, nspace, configuration) { - return this.findAllBySlug(slug, dc, nspace, configuration).then(function(items) { + @dataSource('/:ns/:dc/proxy-instance/:serviceId/:node/:id') + findInstanceBySlug(params, nspace, configuration) { + return this.findAllBySlug(params, configuration).then(function(items) { let res = {}; if (get(items, 'length') > 0) { let instance = items - .filterBy('ServiceProxy.DestinationServiceID', id) - .findBy('NodeName', node); + .filterBy('ServiceProxy.DestinationServiceID', params.serviceId) + .findBy('NodeName', params.node); if (instance) { res = instance; } else { - instance = items.findBy('ServiceProxy.DestinationServiceName', slug); + instance = items.findBy('ServiceProxy.DestinationServiceName', params.id); if (instance) { res = instance; } diff --git a/ui/packages/consul-ui/app/services/repository/role.js b/ui/packages/consul-ui/app/services/repository/role.js index 6c40c3929..32b17aac4 100644 --- a/ui/packages/consul-ui/app/services/repository/role.js +++ b/ui/packages/consul-ui/app/services/repository/role.js @@ -2,6 +2,7 @@ import RepositoryService from 'consul-ui/services/repository'; import statusFactory from 'consul-ui/utils/acls-status'; import isValidServerErrorFactory from 'consul-ui/utils/http/acl/is-valid-server-error'; import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/role'; +import dataSource from 'consul-ui/decorators/data-source'; const isValidServerError = isValidServerErrorFactory(); const status = statusFactory(isValidServerError, Promise); @@ -20,6 +21,16 @@ export default class RoleService extends RepositoryService { return SLUG_KEY; } + @dataSource('/:ns/:dc/roles') + async findAllByDatacenter() { + return super.findAllByDatacenter(...arguments); + } + + @dataSource('/:ns/:dc/role/:id') + async findBySlug() { + return super.findBySlug(...arguments); + } + status(obj) { return status(obj); } diff --git a/ui/packages/consul-ui/app/services/repository/service-instance.js b/ui/packages/consul-ui/app/services/repository/service-instance.js index ec604d38e..5d4ede9c7 100644 --- a/ui/packages/consul-ui/app/services/repository/service-instance.js +++ b/ui/packages/consul-ui/app/services/repository/service-instance.js @@ -2,6 +2,7 @@ import RepositoryService from 'consul-ui/services/repository'; import { inject as service } from '@ember/service'; import { set } from '@ember/object'; import { ACCESS_READ } from 'consul-ui/abilities/base'; +import dataSource from 'consul-ui/decorators/data-source'; const modelName = 'service-instance'; export default class ServiceInstanceService extends RepositoryService { @@ -10,47 +11,34 @@ export default class ServiceInstanceService extends RepositoryService { return modelName; } - async findByService(slug, dc, nspace, configuration = {}) { - const query = { - dc: dc, - ns: nspace, - id: slug, - }; + @dataSource('/:ns/:dc/service-instances/for-service/:id') + async findByService(params, configuration = {}) { if (typeof configuration.cursor !== 'undefined') { - query.index = configuration.cursor; - query.uri = configuration.uri; + params.index = configuration.cursor; + params.uri = configuration.uri; } return this.authorizeBySlug( - async () => this.store.query(this.getModelName(), query), + async () => this.store.query(this.getModelName(), params), ACCESS_READ, - slug, - dc, - nspace + params ); } - async findBySlug(serviceId, node, service, dc, nspace, configuration = {}) { - const query = { - dc: dc, - ns: nspace, - serviceId: serviceId, - node: node, - id: service, - }; + @dataSource('/:ns/:dc/service-instance/:serviceId/:node/:id') + async findBySlug(params, configuration = {}) { if (typeof configuration.cursor !== 'undefined') { - query.index = configuration.cursor; - query.uri = configuration.uri; + params.index = configuration.cursor; + params.uri = configuration.uri; } return this.authorizeBySlug( - async () => this.store.queryRecord(this.getModelName(), query), + async () => this.store.queryRecord(this.getModelName(), params), ACCESS_READ, - service, - dc, - nspace + params ); } - async findProxyBySlug(serviceId, node, service, dc, nspace, configuration = {}) { + @dataSource('/:ns/:dc/proxy-service-instance/:serviceId/:node/:id') + async findProxyBySlug(params, configuration = {}) { const instance = await this.findBySlug(...arguments); let proxy = this.store.peekRecord('proxy', instance.uid); // Currently, we call the proxy endpoint before this endpoint diff --git a/ui/packages/consul-ui/app/services/repository/service.js b/ui/packages/consul-ui/app/services/repository/service.js index b804b486b..4ada89702 100644 --- a/ui/packages/consul-ui/app/services/repository/service.js +++ b/ui/packages/consul-ui/app/services/repository/service.js @@ -1,20 +1,23 @@ import RepositoryService from 'consul-ui/services/repository'; +import dataSource from 'consul-ui/decorators/data-source'; + const modelName = 'service'; -export default class _RepositoryService extends RepositoryService { +export default class ServiceService extends RepositoryService { getModelName() { return modelName; } - findGatewayBySlug(slug, dc, nspace, configuration = {}) { - const query = { - dc: dc, - ns: nspace, - gateway: slug, - }; + @dataSource('/:ns/:dc/services') + async findAllByDatacenter() { + return super.findAllByDatacenter(...arguments); + } + + @dataSource('/:ns/:dc/gateways/for-service/:gateway') + findGatewayBySlug(params, configuration = {}) { if (typeof configuration.cursor !== 'undefined') { - query.index = configuration.cursor; - query.uri = configuration.uri; + params.index = configuration.cursor; + params.uri = configuration.uri; } - return this.store.query(this.getModelName(), query); + return this.store.query(this.getModelName(), params); } } diff --git a/ui/packages/consul-ui/app/services/repository/session.js b/ui/packages/consul-ui/app/services/repository/session.js index bc98df92d..8534232cd 100644 --- a/ui/packages/consul-ui/app/services/repository/session.js +++ b/ui/packages/consul-ui/app/services/repository/session.js @@ -1,5 +1,6 @@ import { inject as service } from '@ember/service'; import RepositoryService from 'consul-ui/services/repository'; +import dataSource from 'consul-ui/decorators/data-source'; const modelName = 'session'; export default class SessionService extends RepositoryService { @@ -10,21 +11,18 @@ export default class SessionService extends RepositoryService { return modelName; } - findByNode(node, dc, nspace, configuration = {}) { - const query = { - id: node, - dc: dc, - ns: nspace, - }; + @dataSource('/:ns/:dc/sessions/for-node/:id') + findByNode(params, configuration = {}) { if (typeof configuration.cursor !== 'undefined') { - query.index = configuration.cursor; - query.uri = configuration.uri; + params.index = configuration.cursor; + params.uri = configuration.uri; } - return this.store.query(this.getModelName(), query); + return this.store.query(this.getModelName(), params); } // TODO: Why Key? Probably should be findBySlug like the others - findByKey(slug, dc, nspace) { + @dataSource('/:ns/:dc/sessions/for-key/:id') + findByKey(params, configuration = {}) { return this.findBySlug(...arguments); } } diff --git a/ui/packages/consul-ui/app/services/repository/token.js b/ui/packages/consul-ui/app/services/repository/token.js index 75f4017d6..08987e2bd 100644 --- a/ui/packages/consul-ui/app/services/repository/token.js +++ b/ui/packages/consul-ui/app/services/repository/token.js @@ -3,6 +3,7 @@ import { get } from '@ember/object'; import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/token'; import statusFactory from 'consul-ui/utils/acls-status'; import isValidServerErrorFactory from 'consul-ui/utils/http/acl/is-valid-server-error'; +import dataSource from 'consul-ui/decorators/data-source'; const isValidServerError = isValidServerErrorFactory(); const status = statusFactory(isValidServerError, Promise); @@ -25,11 +26,13 @@ export default class TokenService extends RepositoryService { return status(obj); } - self(secret, dc) { + @dataSource('/:ns/:dc/token/self/:secret') + self(params) { + // TODO: Does this need ns passing through? return this.store .self(this.getModelName(), { - secret: secret, - dc: dc, + secret: params.secret, + dc: params.dc, }) .catch(e => { // If we get this 500 RPC error, it means we are a legacy ACL cluster @@ -37,7 +40,7 @@ export default class TokenService extends RepositoryService { if (isValidServerError(e)) { return { AccessorID: null, - SecretID: secret, + SecretID: params.secret, }; } return Promise.reject(e); @@ -48,19 +51,19 @@ export default class TokenService extends RepositoryService { return this.store.clone(this.getModelName(), get(item, PRIMARY_KEY)); } - findByPolicy(id, dc, nspace) { + findByPolicy(params) { return this.store.query(this.getModelName(), { - policy: id, - dc: dc, - ns: nspace, + policy: params.id, + dc: params.dc, + ns: params.ns, }); } - findByRole(id, dc, nspace) { + findByRole(params) { return this.store.query(this.getModelName(), { - role: id, - dc: dc, - ns: nspace, + role: params.id, + dc: params.dc, + ns: params.ns, }); } } diff --git a/ui/packages/consul-ui/app/services/repository/topology.js b/ui/packages/consul-ui/app/services/repository/topology.js index bd9fb0309..74b6df5e8 100644 --- a/ui/packages/consul-ui/app/services/repository/topology.js +++ b/ui/packages/consul-ui/app/services/repository/topology.js @@ -1,6 +1,7 @@ import { inject as service } from '@ember/service'; import RepositoryService from 'consul-ui/services/repository'; import { get, set } from '@ember/object'; +import dataSource from 'consul-ui/decorators/data-source'; const modelName = 'topology'; const ERROR_MESH_DISABLED = 'Connect must be enabled in order to use this endpoint'; @@ -13,24 +14,19 @@ export default class TopologyService extends RepositoryService { return modelName; } - findBySlug(slug, kind, dc, nspace, configuration = {}) { - const datacenter = this.dcs.peekOne(dc); + @dataSource('/:ns/:dc/topology/:id/:kind') + findBySlug(params, configuration = {}) { + const datacenter = this.dcs.peekOne(params.dc); if (datacenter !== null && !get(datacenter, 'MeshEnabled')) { return Promise.resolve(); } - const query = { - dc: dc, - ns: nspace, - id: slug, - kind: kind, - }; if (typeof configuration.cursor !== 'undefined') { - query.index = configuration.cursor; - query.uri = configuration.uri; + params.index = configuration.cursor; + params.uri = configuration.uri; } - return this.store.queryRecord(this.getModelName(), query).catch(e => { + return this.store.queryRecord(this.getModelName(), params).catch(e => { const code = get(e, 'errors.firstObject.status'); - const body = get(e, 'errors.firstObject.detail').trim(); + const body = (get(e, 'errors.firstObject.detail') || '').trim(); switch (code) { case '500': if (datacenter !== null && body.endsWith(ERROR_MESH_DISABLED)) { diff --git a/ui/packages/consul-ui/package.json b/ui/packages/consul-ui/package.json index f29d858e7..957f1164c 100644 --- a/ui/packages/consul-ui/package.json +++ b/ui/packages/consul-ui/package.json @@ -160,7 +160,8 @@ "tape": "^5.0.1", "text-encoding": "^0.7.0", "tippy.js": "^6.2.7", - "torii": "^0.10.1" + "torii": "^0.10.1", + "wayfarer": "^7.0.1" }, "resolutions": { "ember-basic-dropdown": "^3.0.10" diff --git a/ui/packages/consul-ui/tests/integration/services/repository/acl-test.js b/ui/packages/consul-ui/tests/integration/services/repository/acl-test.js index 5883ab4f1..bf91f9168 100644 --- a/ui/packages/consul-ui/tests/integration/services/repository/acl-test.js +++ b/ui/packages/consul-ui/tests/integration/services/repository/acl-test.js @@ -19,7 +19,7 @@ test('findByDatacenter returns the correct data for list endpoint', function(ass }); }, function performTest(service) { - return service.findAllByDatacenter(dc); + return service.findAllByDatacenter({ dc }); }, function performAssertion(actual, expected) { assert.deepEqual( @@ -47,7 +47,7 @@ test('findBySlug returns the correct data for item endpoint', function(assert) { return stub(`/v1/acl/info/${id}?dc=${dc}`); }, function performTest(service) { - return service.findBySlug(id, dc); + return service.findBySlug({ id, dc }); }, function performAssertion(actual, expected) { assert.deepEqual( diff --git a/ui/packages/consul-ui/tests/integration/services/repository/auth-method-test.js b/ui/packages/consul-ui/tests/integration/services/repository/auth-method-test.js index 2d489be3a..966128d0b 100644 --- a/ui/packages/consul-ui/tests/integration/services/repository/auth-method-test.js +++ b/ui/packages/consul-ui/tests/integration/services/repository/auth-method-test.js @@ -25,7 +25,10 @@ const undefinedNspace = 'default'; ); }, function performTest(service) { - return service.findAllByDatacenter(dc, nspace || undefinedNspace); + return service.findAllByDatacenter({ + dc: dc, + nspace: nspace || undefinedNspace, + }); }, function performAssertion(actual, expected) { assert.deepEqual( diff --git a/ui/packages/consul-ui/tests/integration/services/repository/coordinate-test.js b/ui/packages/consul-ui/tests/integration/services/repository/coordinate-test.js index cdb390b67..f46db8168 100644 --- a/ui/packages/consul-ui/tests/integration/services/repository/coordinate-test.js +++ b/ui/packages/consul-ui/tests/integration/services/repository/coordinate-test.js @@ -24,7 +24,7 @@ test('findAllByDatacenter returns the correct data for list endpoint', function( }); }, function performTest(service) { - return service.findAllByDatacenter(dc); + return service.findAllByDatacenter({ dc }); }, function performAssertion(actual, expected) { assert.deepEqual( @@ -51,11 +51,11 @@ test('findAllByNode calls findAllByDatacenter with the correct arguments', funct cursor: 1, }; const service = this.subject(); - service.findAllByDatacenter = function(dc, configuration) { + service.findAllByDatacenter = function(params, configuration) { assert.equal(arguments.length, 2, 'Expected to be called with the correct number of arguments'); - assert.equal(dc, datacenter); + assert.equal(params.dc, datacenter); assert.deepEqual(configuration, conf); return Promise.resolve([]); }; - return service.findAllByNode('node-name', datacenter, conf); + return service.findAllByNode({ node: 'node-name', dc: datacenter }, conf); }); diff --git a/ui/packages/consul-ui/tests/integration/services/repository/discovery-chain-test.js b/ui/packages/consul-ui/tests/integration/services/repository/discovery-chain-test.js index 9b5ea1e89..6333c06d9 100644 --- a/ui/packages/consul-ui/tests/integration/services/repository/discovery-chain-test.js +++ b/ui/packages/consul-ui/tests/integration/services/repository/discovery-chain-test.js @@ -18,7 +18,7 @@ test('findBySlug returns the correct data for item endpoint', function(assert) { }); }, function performTest(service) { - return service.findBySlug(id, dc); + return service.findBySlug({ id, dc }); }, function performAssertion(actual, expected) { const result = expected(function(payload) { diff --git a/ui/packages/consul-ui/tests/integration/services/repository/kv-test.js b/ui/packages/consul-ui/tests/integration/services/repository/kv-test.js index 98bd9b55a..d7810aeac 100644 --- a/ui/packages/consul-ui/tests/integration/services/repository/kv-test.js +++ b/ui/packages/consul-ui/tests/integration/services/repository/kv-test.js @@ -23,7 +23,7 @@ const undefinedNspace = 'default'; ); }, function performTest(service) { - return service.findAllBySlug(id, dc, nspace || undefinedNspace); + return service.findAllBySlug({ id, dc, ns: nspace || undefinedNspace }); }, function performAssertion(actual, expected) { assert.deepEqual( @@ -51,7 +51,7 @@ const undefinedNspace = 'default'; return stub(`/v1/kv/${id}?dc=${dc}${typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``}`); }, function(service) { - return service.findBySlug(id, dc, nspace || undefinedNspace); + return service.findBySlug({ id, dc, ns: nspace || undefinedNspace }); }, function(actual, expected) { assert.deepEqual( diff --git a/ui/packages/consul-ui/tests/integration/services/repository/node-test.js b/ui/packages/consul-ui/tests/integration/services/repository/node-test.js index a7a1f5d67..edd5899f9 100644 --- a/ui/packages/consul-ui/tests/integration/services/repository/node-test.js +++ b/ui/packages/consul-ui/tests/integration/services/repository/node-test.js @@ -25,7 +25,7 @@ test('findByDatacenter returns the correct data for list endpoint', function(ass }); }, function performTest(service) { - return service.findAllByDatacenter(dc); + return service.findAllByDatacenter({ dc }); }, function performAssertion(actual, expected) { actual.forEach(item => { @@ -44,7 +44,7 @@ test('findBySlug returns the correct data for item endpoint', function(assert) { return stub(`/v1/internal/ui/node/${id}?dc=${dc}`); }, function(service) { - return service.findBySlug(id, dc); + return service.findBySlug({ id, dc }); }, function(actual, expected) { assert.equal(actual.uid, `["${nspace}","${dc}","${actual.ID}"]`); diff --git a/ui/packages/consul-ui/tests/integration/services/repository/policy-test.js b/ui/packages/consul-ui/tests/integration/services/repository/policy-test.js index 287db1739..3b25fd954 100644 --- a/ui/packages/consul-ui/tests/integration/services/repository/policy-test.js +++ b/ui/packages/consul-ui/tests/integration/services/repository/policy-test.js @@ -29,7 +29,7 @@ const undefinedNspace = 'default'; ); }, function performTest(service) { - return service.findAllByDatacenter(dc, nspace || undefinedNspace); + return service.findAllByDatacenter({ dc, ns: nspace || undefinedNspace }); }, function performAssertion(actual, expected) { assert.deepEqual( @@ -59,7 +59,7 @@ const undefinedNspace = 'default'; ); }, function performTest(service) { - return service.findBySlug(id, dc, nspace || undefinedNspace); + return service.findBySlug({ id, dc, ns: nspace || undefinedNspace }); }, function performAssertion(actual, expected) { assert.deepEqual( diff --git a/ui/packages/consul-ui/tests/integration/services/repository/role-test.js b/ui/packages/consul-ui/tests/integration/services/repository/role-test.js index d3dc26084..197b30a23 100644 --- a/ui/packages/consul-ui/tests/integration/services/repository/role-test.js +++ b/ui/packages/consul-ui/tests/integration/services/repository/role-test.js @@ -30,7 +30,7 @@ const undefinedNspace = 'default'; ); }, function performTest(service) { - return service.findAllByDatacenter(dc, nspace || undefinedNspace); + return service.findAllByDatacenter({ dc, ns: nspace || undefinedNspace }); }, function performAssertion(actual, expected) { assert.deepEqual( @@ -61,7 +61,7 @@ const undefinedNspace = 'default'; ); }, function performTest(service) { - return service.findBySlug(id, dc, nspace || undefinedNspace); + return service.findBySlug({ id, dc, ns: nspace || undefinedNspace }); }, function performAssertion(actual, expected) { assert.deepEqual( diff --git a/ui/packages/consul-ui/tests/integration/services/repository/service-test.js b/ui/packages/consul-ui/tests/integration/services/repository/service-test.js index 39eea2a7e..586c9d8dd 100644 --- a/ui/packages/consul-ui/tests/integration/services/repository/service-test.js +++ b/ui/packages/consul-ui/tests/integration/services/repository/service-test.js @@ -33,7 +33,7 @@ const undefinedNspace = 'default'; ); }, function performTest(service) { - return service.findGatewayBySlug(gateway, dc, nspace || undefinedNspace, conf); + return service.findGatewayBySlug({ gateway, dc, ns: nspace || undefinedNspace }, conf); }, function performAssertion(actual, expected) { const result = expected(function(payload) { diff --git a/ui/packages/consul-ui/tests/integration/services/repository/session-test.js b/ui/packages/consul-ui/tests/integration/services/repository/session-test.js index 300252a31..d5f199d1f 100644 --- a/ui/packages/consul-ui/tests/integration/services/repository/session-test.js +++ b/ui/packages/consul-ui/tests/integration/services/repository/session-test.js @@ -29,7 +29,7 @@ const undefinedNspace = 'default'; ); }, function performTest(service) { - return service.findByNode(id, dc, nspace || undefinedNspace); + return service.findByNode({ id, dc, ns: nspace || undefinedNspace }); }, function performAssertion(actual, expected) { assert.deepEqual( @@ -59,7 +59,7 @@ const undefinedNspace = 'default'; ); }, function(service) { - return service.findByKey(id, dc, nspace || undefinedNspace); + return service.findByKey({ id, dc, ns: nspace || undefinedNspace }); }, function(actual, expected) { assert.deepEqual( diff --git a/ui/packages/consul-ui/tests/integration/services/repository/token-test.js b/ui/packages/consul-ui/tests/integration/services/repository/token-test.js index 8d26cc39c..864adf6fa 100644 --- a/ui/packages/consul-ui/tests/integration/services/repository/token-test.js +++ b/ui/packages/consul-ui/tests/integration/services/repository/token-test.js @@ -26,7 +26,7 @@ const undefinedNspace = 'default'; ); }, function performTest(service) { - return service.findAllByDatacenter(dc, nspace || undefinedNspace); + return service.findAllByDatacenter({ dc, ns: nspace || undefinedNspace }); }, function performAssertion(actual, expected) { assert.deepEqual( @@ -57,7 +57,7 @@ const undefinedNspace = 'default'; ); }, function performTest(service) { - return service.findBySlug(id, dc, nspace || undefinedNspace); + return service.findBySlug({ id, dc, ns: nspace || undefinedNspace }); }, function performAssertion(actual, expected) { assert.deepEqual( @@ -99,7 +99,7 @@ const undefinedNspace = 'default'; ); }, function performTest(service) { - return service.findByPolicy(policy, dc, nspace || undefinedNspace); + return service.findByPolicy({ id: policy, dc, ns: nspace || undefinedNspace }); }, function performAssertion(actual, expected) { assert.deepEqual( @@ -136,7 +136,7 @@ const undefinedNspace = 'default'; ); }, function performTest(service) { - return service.findByRole(role, dc, nspace || undefinedNspace); + return service.findByRole({ id: role, dc, ns: nspace || undefinedNspace }); }, function performAssertion(actual, expected) { assert.deepEqual( diff --git a/ui/packages/consul-ui/tests/integration/services/repository/topology-test.js b/ui/packages/consul-ui/tests/integration/services/repository/topology-test.js index 45098469e..7ab7af665 100644 --- a/ui/packages/consul-ui/tests/integration/services/repository/topology-test.js +++ b/ui/packages/consul-ui/tests/integration/services/repository/topology-test.js @@ -19,7 +19,7 @@ test('findBySlug returns the correct data for item endpoint', function(assert) { }); }, function performTest(service) { - return service.findBySlug(id, kind, dc); + return service.findBySlug({ id, kind, dc }); }, function performAssertion(actual, expected) { const result = expected(function(payload) { diff --git a/ui/yarn.lock b/ui/yarn.lock index e102d55ac..411468edb 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -13365,6 +13365,11 @@ nan@^2.12.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== +nanoassert@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-1.1.0.tgz#4f3152e09540fde28c76f44b19bbcd1d5a42478d" + integrity sha1-TzFS4JVA/eKMdvRLGbvNHVpCR40= + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -17877,6 +17882,13 @@ watchpack@^1.5.0, watchpack@^1.7.4: chokidar "^3.4.1" watchpack-chokidar2 "^2.0.0" +wayfarer@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/wayfarer/-/wayfarer-7.0.1.tgz#17a64d351d49f9d3d6c508155867df7658184ce3" + integrity sha512-yf+kAlOYnJRjLxflLy+1+xEclb6222EAVvAjSY+Yz2qAIDrXeN5wLl/G302Mwv3E0KMg1HT/WDGsvSymX0U7Rw== + dependencies: + nanoassert "^1.1.0" + wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"