From fd51b3e76eda90981c10aacbe70e9c13b722dee0 Mon Sep 17 00:00:00 2001 From: radiantly Date: Fri, 15 Oct 2021 15:37:51 +0530 Subject: [PATCH 1/3] ui: Allow ${} interpolation for template URLs --- .../consul-ui/app/helpers/render-template.js | 11 +- .../helpers/render-template-test.js | 128 +++++++++++++++++- website/content/docs/agent/options.mdx | 8 +- 3 files changed, 141 insertions(+), 6 deletions(-) diff --git a/ui/packages/consul-ui/app/helpers/render-template.js b/ui/packages/consul-ui/app/helpers/render-template.js index 57c006b84c..071f2d1df1 100644 --- a/ui/packages/consul-ui/app/helpers/render-template.js +++ b/ui/packages/consul-ui/app/helpers/render-template.js @@ -1,8 +1,15 @@ import Helper from '@ember/component/helper'; import { inject as service } from '@ember/service'; -// simple mustache regexp `/{{item.Name}}/` -const templateRe = /{{([A-Za-z.0-9_-]+)}}/g; +// regexp that matches {{item.Name}} or ${item.Name} +// what this regex does +// (?:\$|\{) - Match either $ or { +// \{ - Match { +// ([a-z.0-9_-]+) - Capturing group +// (?:(?<=\$\{[^{]+) - Use a positive lookbehind to assert that ${ was matched previously +// |\} ) - or match a } +// \} - Match } +const templateRe = /(?:\$|\{)\{([a-z.0-9_-]+)(?:(?<=\$\{[^{]+)|\})\}/gi; let render; export default class RenderTemplateHelper extends Helper { @service('encoder') encoder; diff --git a/ui/packages/consul-ui/tests/integration/helpers/render-template-test.js b/ui/packages/consul-ui/tests/integration/helpers/render-template-test.js index 6136ca7ac3..0eb7736300 100644 --- a/ui/packages/consul-ui/tests/integration/helpers/render-template-test.js +++ b/ui/packages/consul-ui/tests/integration/helpers/render-template-test.js @@ -94,7 +94,133 @@ module('Integration | Helper | render-template', function(hooks) { result: 'http://localhost/?=%23Na%2Fme', }, ].forEach(item => { - test('it renders', async function(assert) { + test('it renders {{}} style interpolation`', async function(assert) { + this.set('template', item.href); + this.set('vars', item.vars); + + await render(hbs`{{render-template template vars}}`); + + assert.equal(this.element.textContent.trim(), item.result); + }); + }); + + [ + { + href: 'http://localhost/?=${Name}/${ID}', + vars: { + Name: 'name', + ID: 'id', + }, + result: 'http://localhost/?=name/id', + }, + { + href: 'http://localhost/?=${Name}/${ID}', + vars: { + Name: '{{Name}}', + ID: '{{ID}}', + }, + result: 'http://localhost/?=%7B%7BName%7D%7D/%7B%7BID%7D%7D', + }, + { + href: 'http://localhost/?=${deep.Name}/${deep.ID}', + vars: { + deep: { + Name: '{{Name}}', + ID: '{{ID}}', + }, + }, + result: 'http://localhost/?=%7B%7BName%7D%7D/%7B%7BID%7D%7D', + }, + { + href: 'http://localhost/?=${}/${}', + vars: { + Name: 'name', + ID: 'id', + }, + // If you don't pass actual variables then nothing + // gets replaced and nothing is URL encoded + result: 'http://localhost/?=${}/${}', + }, + { + href: 'http://localhost/?=${Service_Name}/${Meta-Key}', + vars: { + Service_Name: 'name', + ['Meta-Key']: 'id', + }, + result: 'http://localhost/?=name/id', + }, + { + href: 'http://localhost/?=${Service_Name}/${Meta-Key}', + vars: { + WrongPropertyName: 'name', + ['Meta-Key']: 'id', + }, + result: 'http://localhost/?=/id', + }, + { + href: 'http://localhost/?=${.Name}', + vars: { + ['.Name']: 'name', + }, + result: 'http://localhost/?=', + }, + { + href: 'http://localhost/?=${.}', + vars: { + ['.']: 'name', + }, + result: 'http://localhost/?=', + }, + { + href: 'http://localhost/?=${deep..Name}', + vars: { + deep: { + Name: 'Name', + ID: 'ID', + }, + }, + result: 'http://localhost/?=', + }, + { + href: 'http://localhost/?=${deep.Name}', + vars: { + deep: { + Name: '#Na/me', + ID: 'ID', + }, + }, + result: 'http://localhost/?=%23Na%2Fme', + }, + ].forEach(item => { + test('it renders ${} style interpolation', async function(assert) { + this.set('template', item.href); + this.set('vars', item.vars); + + await render(hbs`{{render-template template vars}}`); + + assert.equal(this.element.textContent.trim(), item.result); + }); + }); + + [ + { + href: 'http://localhost/?=${Name}/{{ID}}', + vars: { + Name: 'name', + ID: 'id', + }, + result: 'http://localhost/?=name/id', + }, + { + href: 'http://localhost/?=${Name}}/{{ID}', + vars: { + Name: 'name', + ID: 'id', + }, + result: 'http://localhost/?=name}/{{ID}', + }, + ].forEach(item => { + test('it renders both styles of interpolation when used together', async function(assert) { this.set('template', item.href); this.set('vars', item.vars); diff --git a/website/content/docs/agent/options.mdx b/website/content/docs/agent/options.mdx index 2b2c276e84..93dea72b1c 100644 --- a/website/content/docs/agent/options.mdx +++ b/website/content/docs/agent/options.mdx @@ -2174,9 +2174,11 @@ bind_addr = "{{ GetPrivateInterfaces | include \"network\" \"10.0.0.0/8\" | attr The placeholders available are: - - `{{Service.Name}}` - Replaced with the current service's name. - - `{{Service.Namespace}}` - Replaced with the current service's namespace or empty if namespaces are not enabled. - - `{{Datacenter}}` - Replaced with the current service's datacenter. + - `{{Service.Name}}` or `${Service.Name}` - Replaced with the current service's name. + - `{{Service.Namespace}}` or `${Service.Namespace}` - Replaced with the current service's namespace or empty if namespaces are not enabled. + - `{{Datacenter}}` or `${Datacenter}` - Replaced with the current service's datacenter. + + ~> **Note:** The `${}` style interpolation is only available from Consul TBD. - `ui_dir` - **This field is deprecated in Consul 1.9.0. See the [`ui_config.dir`](#ui_config_dir) field instead.** Equivalent to the [`-ui-dir`](#_ui_dir) command-line From 0e9a7d0cad3f2716974ee02c60fac53830a43518 Mon Sep 17 00:00:00 2001 From: radiantly Date: Tue, 19 Oct 2021 01:08:44 +0530 Subject: [PATCH 2/3] Add changelog note and amend docs --- .changelog/11328.txt | 3 +++ website/content/docs/agent/options.mdx | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 .changelog/11328.txt diff --git a/.changelog/11328.txt b/.changelog/11328.txt new file mode 100644 index 0000000000..637a3876e2 --- /dev/null +++ b/.changelog/11328.txt @@ -0,0 +1,3 @@ +```release-note:improvement +config: Allow ${} style interpolation for UI Dashboard template URLs +``` diff --git a/website/content/docs/agent/options.mdx b/website/content/docs/agent/options.mdx index 93dea72b1c..dbc1050adc 100644 --- a/website/content/docs/agent/options.mdx +++ b/website/content/docs/agent/options.mdx @@ -2174,11 +2174,13 @@ bind_addr = "{{ GetPrivateInterfaces | include \"network\" \"10.0.0.0/8\" | attr The placeholders available are: - - `{{Service.Name}}` or `${Service.Name}` - Replaced with the current service's name. - - `{{Service.Namespace}}` or `${Service.Namespace}` - Replaced with the current service's namespace or empty if namespaces are not enabled. - - `{{Datacenter}}` or `${Datacenter}` - Replaced with the current service's datacenter. + - `${Service.Name}` or `{{Service.Name}}` - Replaced with the current service's name. + - `${Service.Namespace}` or `{{Service.Namespace}}` - Replaced with the current + service's namespace or empty if namespaces are not enabled. + - `${Datacenter}` or `{{Datacenter}}` - Replaced with the current service's datacenter. - ~> **Note:** The `${}` style interpolation is only available from Consul TBD. + ~> **Note:** The newer `${}` style interpolation is only available from Consul TBD, but is + preferred as it does not conflict with Helm's own template interpolation. - `ui_dir` - **This field is deprecated in Consul 1.9.0. See the [`ui_config.dir`](#ui_config_dir) field instead.** Equivalent to the [`-ui-dir`](#_ui_dir) command-line From 66c9ef1876978edef4ed9743c914b280896ebfe5 Mon Sep 17 00:00:00 2001 From: radiantly Date: Tue, 19 Oct 2021 23:22:12 +0530 Subject: [PATCH 3/3] Remove note --- website/content/docs/agent/options.mdx | 3 --- 1 file changed, 3 deletions(-) diff --git a/website/content/docs/agent/options.mdx b/website/content/docs/agent/options.mdx index dbc1050adc..1daf34c97e 100644 --- a/website/content/docs/agent/options.mdx +++ b/website/content/docs/agent/options.mdx @@ -2179,9 +2179,6 @@ bind_addr = "{{ GetPrivateInterfaces | include \"network\" \"10.0.0.0/8\" | attr service's namespace or empty if namespaces are not enabled. - `${Datacenter}` or `{{Datacenter}}` - Replaced with the current service's datacenter. - ~> **Note:** The newer `${}` style interpolation is only available from Consul TBD, but is - preferred as it does not conflict with Helm's own template interpolation. - - `ui_dir` - **This field is deprecated in Consul 1.9.0. See the [`ui_config.dir`](#ui_config_dir) field instead.** Equivalent to the [`-ui-dir`](#_ui_dir) command-line flag. This configuration key is not required as of Consul version 0.7.0 and later.