diff --git a/changelog/19799.txt b/changelog/19799.txt new file mode 100644 index 000000000000..aee76ca689aa --- /dev/null +++ b/changelog/19799.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: Fix bad link to namespace when namespace name includes `.` +``` \ No newline at end of file diff --git a/ui/app/adapters/namespace.js b/ui/app/adapters/namespace.js index ff8eff59bf26..36d023e22e55 100644 --- a/ui/app/adapters/namespace.js +++ b/ui/app/adapters/namespace.js @@ -1,27 +1,27 @@ import ApplicationAdapter from './application'; -export default ApplicationAdapter.extend({ +export default class NamespaceAdapter extends ApplicationAdapter { pathForType() { return 'namespaces'; - }, + } urlForFindAll(modelName, snapshot) { if (snapshot.adapterOptions && snapshot.adapterOptions.forUser) { return `/${this.urlPrefix()}/internal/ui/namespaces`; } return `/${this.urlPrefix()}/namespaces?list=true`; - }, + } urlForCreateRecord(modelName, snapshot) { const id = snapshot.attr('path'); return this.buildURL(modelName, id); - }, + } createRecord(store, type, snapshot) { const id = snapshot.attr('path'); - return this._super(...arguments).then(() => { + return super.createRecord(...arguments).then(() => { return { id }; }); - }, + } findAll(store, type, sinceToken, snapshot) { if (snapshot.adapterOptions && typeof snapshot.adapterOptions.namespace !== 'undefined') { @@ -29,9 +29,9 @@ export default ApplicationAdapter.extend({ namespace: snapshot.adapterOptions.namespace, }); } - return this._super(...arguments); - }, + return super.findAll(...arguments); + } query() { return this.ajax(`/${this.urlPrefix()}/namespaces?list=true`); - }, -}); + } +} diff --git a/ui/app/components/namespace-link.js b/ui/app/components/namespace-link.js index 2e8d65a01922..65a7390aef60 100644 --- a/ui/app/components/namespace-link.js +++ b/ui/app/components/namespace-link.js @@ -11,10 +11,13 @@ export default Component.extend({ //public api targetNamespace: null, showLastSegment: false, + // set to true if targetNamespace is passed in unmodified + // otherwise, this assumes it is parsed as in namespace-picker + unparsed: false, - normalizedNamespace: computed('targetNamespace', function () { - const ns = this.targetNamespace; - return (ns || '').replace(/\.+/g, '/').replace(/☃/g, '.'); + normalizedNamespace: computed('targetNamespace', 'unparsed', function () { + const ns = this.targetNamespace || ''; + return this.unparsed ? ns : ns.replace(/\.+/g, '/').replace(/☃/g, '.'); }), namespaceDisplay: computed('normalizedNamespace', 'showLastSegment', function () { diff --git a/ui/app/serializers/namespace.js b/ui/app/serializers/namespace.js index 9b8172fb4d20..22034e4148ad 100644 --- a/ui/app/serializers/namespace.js +++ b/ui/app/serializers/namespace.js @@ -1,6 +1,10 @@ import ApplicationSerializer from './application'; -export default ApplicationSerializer.extend({ +export default class NamespaceSerializer extends ApplicationSerializer { + attrs = { + path: { serialize: false }, + }; + normalizeList(payload) { const data = payload.data.keys ? payload.data.keys.map((key) => ({ @@ -11,7 +15,7 @@ export default ApplicationSerializer.extend({ : payload.data; return data; - }, + } normalizeResponse(store, primaryModelClass, payload, id, requestType) { const nullResponses = ['deleteRecord', 'createRecord']; @@ -19,6 +23,6 @@ export default ApplicationSerializer.extend({ const normalizedPayload = nullResponses.includes(requestType) ? { id: cid, path: cid } : this.normalizeList(payload); - return this._super(store, primaryModelClass, normalizedPayload, id, requestType); - }, -}); + return super.normalizeResponse(store, primaryModelClass, normalizedPayload, id, requestType); + } +} diff --git a/ui/app/templates/vault/cluster/access/namespaces/index.hbs b/ui/app/templates/vault/cluster/access/namespaces/index.hbs index 989078788ba3..c4e56997ca6d 100644 --- a/ui/app/templates/vault/cluster/access/namespaces/index.hbs +++ b/ui/app/templates/vault/cluster/access/namespaces/index.hbs @@ -35,7 +35,7 @@ {{#let (concat this.currentNamespace (if this.currentNamespace "/") list.item.id) as |targetNamespace|}} {{#if (includes targetNamespace this.accessibleNamespaces)}}