From 730063b656a4cdd2a85fcc19411310014caac796 Mon Sep 17 00:00:00 2001 From: Matthew Irish Date: Fri, 2 Nov 2018 12:03:46 -0500 Subject: [PATCH] ui kv routing fix (#5650) * fix passing initialKey to the top level secret create page * add service that uses the private routing service because of various bugs * make custom router service more like the bundled router service * clear the store cache when the model changes --- ui/app/components/navigate-input.js | 5 +- .../vault/cluster/secrets/backend/create.js | 5 +- .../vault/cluster/secrets/backend/list.js | 11 ++- ui/app/services/router.js | 80 +++++++++++++++++++ .../templates/components/navigate-input.hbs | 1 + .../components/secret-list-header.hbs | 2 +- .../vault/cluster/secrets/backend/list.hbs | 2 +- 7 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 ui/app/services/router.js diff --git a/ui/app/components/navigate-input.js b/ui/app/components/navigate-input.js index 300a9afebd..b32ad6b4c2 100644 --- a/ui/app/components/navigate-input.js +++ b/ui/app/components/navigate-input.js @@ -61,8 +61,7 @@ export default Component.extend(FocusOnInsertMixin, { return `cert/${key}`; }, onEnter: function(val) { - let baseKey = this.get('baseKey'); - let mode = this.get('mode'); + let { baseKey, mode } = this; let extraParams = this.get('extraNavParams'); if (mode.startsWith('secrets') && (!val || val === baseKey)) { return; @@ -78,7 +77,7 @@ export default Component.extend(FocusOnInsertMixin, { if (baseKey) { this.transitionToRoute(route, this.keyForNav(baseKey), { queryParams: { - initialKey: val.replace(this.keyForNav(baseKey), ''), + initialKey: val, }, }); } else { diff --git a/ui/app/routes/vault/cluster/secrets/backend/create.js b/ui/app/routes/vault/cluster/secrets/backend/create.js index e60011aea0..3b45ac002b 100644 --- a/ui/app/routes/vault/cluster/secrets/backend/create.js +++ b/ui/app/routes/vault/cluster/secrets/backend/create.js @@ -2,9 +2,10 @@ import Route from '@ember/routing/route'; export default Route.extend({ beforeModel() { - let { secret } = this.paramsFor(this.routeName); + let { secret, initialKey } = this.paramsFor(this.routeName); + let qp = initialKey || secret; return this.transitionTo('vault.cluster.secrets.backend.create-root', { - queryParams: { initialKey: secret }, + queryParams: { initialKey: qp }, }); }, }); diff --git a/ui/app/routes/vault/cluster/secrets/backend/list.js b/ui/app/routes/vault/cluster/secrets/backend/list.js index 18a927f8eb..3171d1249e 100644 --- a/ui/app/routes/vault/cluster/secrets/backend/list.js +++ b/ui/app/routes/vault/cluster/secrets/backend/list.js @@ -70,9 +70,11 @@ export default Route.extend({ return model; }) .catch(err => { + // if we're at the root we don't want to throw if (backendModel && err.httpStatus === 404 && secret === '') { return []; } else { + // else we're throwing and dealing with this in the error action throw err; } }), @@ -109,6 +111,11 @@ export default Route.extend({ let { backend } = this.paramsFor('vault.cluster.secrets.backend'); let backendModel = this.store.peekRecord('secret-engine', backend); let has404 = this.get('has404'); + // only clear store cache if this is a new model + if (secret !== controller.get('baseKey.id')) { + this.store.clearAllDatasets(); + } + controller.set('hasModel', true); controller.setProperties({ model, @@ -153,9 +160,9 @@ export default Route.extend({ if (hasModel && error.httpStatus === 404) { this.set('has404', true); transition.abort(); - } else { - return true; + return false; } + return true; }, willTransition(transition) { diff --git a/ui/app/services/router.js b/ui/app/services/router.js new file mode 100644 index 0000000000..745c2bfb87 --- /dev/null +++ b/ui/app/services/router.js @@ -0,0 +1,80 @@ +import Service from '@ember/service'; +import { inject as service } from '@ember/service'; +import { alias } from '@ember/object/computed'; +export function extractRouteArgs(args) { + args = args.slice(); + let possibleQueryParams = args[args.length - 1]; + + let queryParams; + if (possibleQueryParams && possibleQueryParams.hasOwnProperty('queryParams')) { + queryParams = args.pop().queryParams; + } else { + queryParams = {}; + } + + let routeName = args.shift(); + + return { routeName, models: args, queryParams }; +} +//https://github.com/emberjs/ember.js/blob/abf753a3d494830dc9e95b1337b3654b671b11be/packages/ember-routing/lib/utils.js#L210 +export function shallowEqual(a, b) { + let k; + let aCount = 0; + let bCount = 0; + for (k in a) { + if (a.hasOwnProperty(k)) { + if (a[k] !== b[k]) { + return false; + } + aCount++; + } + } + + for (k in b) { + if (b.hasOwnProperty(k)) { + bCount++; + } + } + + return aCount === bCount; +} + +export default Service.extend({ + routing: service('-routing'), + router: alias('routing.router'), + transitionTo() { + let r = this.router; + return r.transitionTo.call(r, ...arguments); + }, + replaceWith() { + let r = this.router; + return r.replaceWith.call(r, ...arguments); + }, + urlFor() { + let r = this.router; + return r.generate.call(r, ...arguments); + }, + currentURL: alias('router.currentURL'), + currentRouteName: alias('router.currentRouteName'), + rootURL: alias('router.rootURL'), + location: alias('router.location'), + + //adapted from: + // https://github.com/emberjs/ember.js/blob/abf753a3d494830dc9e95b1337b3654b671b11be/packages/ember-routing/lib/services/router.js#L220 + isActive(...args) { + let { routeName, models, queryParams } = extractRouteArgs(args); + let routerMicrolib = this.router._routerMicrolib; + + if (!routerMicrolib.isActiveIntent(routeName, models, null)) { + return false; + } + let hasQueryParams = Object.keys(queryParams).length > 0; + + if (hasQueryParams) { + this.router._prepareQueryParams(routeName, models, queryParams, true /* fromRouterService */); + return shallowEqual(queryParams, routerMicrolib.state.queryParams); + } + + return true; + }, +}); diff --git a/ui/app/templates/components/navigate-input.hbs b/ui/app/templates/components/navigate-input.hbs index 3b7adf392e..e1fa3ee086 100644 --- a/ui/app/templates/components/navigate-input.hbs +++ b/ui/app/templates/components/navigate-input.hbs @@ -5,6 +5,7 @@ disabled={{disabled}} value={{@filter}} placeholder={{ or @placeholder "Filter keys" }} + type="text" oninput={{action "handleInput" value="target.value"}} onkeyup={{action "handleKeyUp" }} diff --git a/ui/app/templates/components/secret-list-header.hbs b/ui/app/templates/components/secret-list-header.hbs index 2c0a443791..9f8db5a022 100644 --- a/ui/app/templates/components/secret-list-header.hbs +++ b/ui/app/templates/components/secret-list-header.hbs @@ -31,7 +31,7 @@ {{#secret-link mode="create" secret='' - queryParams=(query-params initialKey=baseKey.id) + queryParams=(query-params initialKey=(or filter baseKey.id)) class="button has-icon-right is-ghost is-compact" data-test-secret-create=true }} diff --git a/ui/app/templates/vault/cluster/secrets/backend/list.hbs b/ui/app/templates/vault/cluster/secrets/backend/list.hbs index ba9076f178..c6a132620a 100644 --- a/ui/app/templates/vault/cluster/secrets/backend/list.hbs +++ b/ui/app/templates/vault/cluster/secrets/backend/list.hbs @@ -1,4 +1,4 @@ -{{secret-list-header isCertTab=(eq tab "certs") model=backendModel baseKey=baseKey backendCrumb=backendCrumb}} +{{secret-list-header isCertTab=(eq tab "certs") model=backendModel baseKey=baseKey backendCrumb=backendCrumb filter=filter}} {{#with (options-for-backend backendType tab) as |options|}}