Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui: Allow ${ } interpolation for UI Dashboard template URLs #11328

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -2174,9 +2174,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