Skip to content

Commit

Permalink
Merge pull request #11328 from radiantly/ui/feature/allow-${}-style-i…
Browse files Browse the repository at this point in the history
…nterpolation

ui: Allow ${ } interpolation for UI Dashboard template URLs
  • Loading branch information
jkirschner-hashicorp authored and hc-github-team-consul-core committed Oct 20, 2021
1 parent e480876 commit 069526e
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 6 deletions.
3 changes: 3 additions & 0 deletions .changelog/11328.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
config: Allow ${} style interpolation for UI Dashboard template URLs
```
11 changes: 9 additions & 2 deletions ui/packages/consul-ui/app/helpers/render-template.js
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
7 changes: 4 additions & 3 deletions website/content/docs/agent/options.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2182,9 +2182,10 @@ 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.

- `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
Expand Down

0 comments on commit 069526e

Please sign in to comment.