Variables: variables in Markdown links are not interpolated (#51392)

* on a text panel first interpolate, then markdown, then sanitize;

* update devenv dashboard + e2e tests

* fix typo and undo changes in grafana/data

* handling of config option disableSanitizeHtml more readable when preparing markdown in text panel

* betterer

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
This commit is contained in:
Polina Boneva 2022-06-29 15:26:31 +03:00 committed by GitHub
parent 688164bbd6
commit f83f05d6b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 15 deletions

View File

@ -137,7 +137,7 @@ exports[`better eslint`] = {
[12, 17, 10, "Do not use any type assertions.", "1579919174"],
[12, 24, 3, "Unexpected any. Specify a different type.", "193409811"]
],
"e2e/dashboards-suite/dashboard-templating.spec.ts:3846708644": [
"e2e/dashboards-suite/dashboard-templating.spec.ts:1854610528": [
[12, 17, 3, "Unexpected any. Specify a different type.", "193409811"]
],
"e2e/dashboards-suite/textbox-variables.spec.ts:2500589821": [

View File

@ -34,7 +34,7 @@
},
"id": 11,
"options": {
"content": "## Global variables\n\n* `__dashboard` = `${__dashboard}`\n* `__dashboard.name` = `${__dashboard.name}`\n* `__dashboard.uid` = `${__dashboard.uid}`\n* `__org.name` = `${__org.name}`\n* `__org.id` = `${__org.id}`\n* `__user.id` = `${__user.id}`\n* `__user.login` = `${__user.login}`\n* `__user.email` = `${__user.email}`\n \n## Formats\n\n* `Server:raw` = `${Server:raw}`\n* `Server:regex` = `${Server:regex}`\n* `Server:lucene` = `${Server:lucene}`\n* `Server:glob` = `${Server:glob}`\n* `Server:pipe` = `${Server:pipe}`\n* `Server:distributed` = `${Server:distributed}`\n* `Server:csv` = `${Server:csv}`\n* `Server:html` = `${Server:html}`\n* `Server:json` = `${Server:json}`\n* `Server:percentencode` = `${Server:percentencode}`\n* `Server:singlequote` = `${Server:singlequote}`\n* `Server:doublequote` = `${Server:doublequote}`\n* `Server:sqlstring` = `${Server:sqlstring}`\n* `Server:date` = `${Server:date}`\n* `Server:text` = `${Server:text}`\n* `Server:queryparam` = `${Server:queryparam}`\n\n",
"content": "## Global variables\n\n* `__dashboard` = `${__dashboard}`\n* `__dashboard.name` = `${__dashboard.name}`\n* `__dashboard.uid` = `${__dashboard.uid}`\n* `__org.name` = `${__org.name}`\n* `__org.id` = `${__org.id}`\n* `__user.id` = `${__user.id}`\n* `__user.login` = `${__user.login}`\n* `__user.email` = `${__user.email}`\n \n## Formats\n\n* `Server:raw` = `${Server:raw}`\n* `Server:regex` = `${Server:regex}`\n* `Server:lucene` = `${Server:lucene}`\n* `Server:glob` = `${Server:glob}`\n* `Server:pipe` = `${Server:pipe}`\n* `Server:distributed` = `${Server:distributed}`\n* `Server:csv` = `${Server:csv}`\n* `Server:html` = `${Server:html}`\n* `Server:json` = `${Server:json}`\n* `Server:percentencode` = `${Server:percentencode}`\n* `Server:singlequote` = `${Server:singlequote}`\n* `Server:doublequote` = `${Server:doublequote}`\n* `Server:sqlstring` = `${Server:sqlstring}`\n* `Server:date` = `${Server:date}`\n* `Server:text` = `${Server:text}`\n* `Server:queryparam` = `${Server:queryparam}`\n\n## Sanitization\n\n * `1 < 2`\n\n## Link interpolation\n\n* [Example: ${__url_time_range}](https://example.com/?${__url_time_range})",
"mode": "markdown"
},
"pluginVersion": "7.1.0",

View File

@ -27,7 +27,7 @@ e2e.scenario({
`Server:pipe = A'A"A|BB\\B|CCC`,
`Server:distributed = A'A"A,Server=BB\\B,Server=CCC`,
`Server:csv = A'A"A,BB\\B,CCC`,
`Server:html = A'A"A, BB\\B, CCC`,
`Server:html = A'A&quot;A, BB\\B, CCC`,
`Server:json = ["A'A\\"A","BB\\\\B","CCC"]`,
`Server:percentencode = %7BA%27A%22A%2CBB%5CB%2CCCC%7D`,
`Server:singlequote = 'A\\'A"A','BB\\B','CCC'`,
@ -36,11 +36,13 @@ e2e.scenario({
`Server:date = null`,
`Server:text = All`,
`Server:queryparam = var-Server=All`,
`1 < 2`,
`Example: from=now-6h&to=now`,
];
e2e()
.get('.markdown-html li')
.should('have.length', 24)
.should('have.length', 26)
.each((element) => {
items.push(element.text());
})
@ -49,5 +51,10 @@ e2e.scenario({
expect(items[index]).to.equal(expected);
});
});
// Check link interpolation is working correctly
e2e()
.contains('a', 'Example: from=now-6h&to=now')
.should('have.attr', 'href', 'https://example.com/?from=now-6h&to=now');
},
});

View File

@ -41,24 +41,34 @@ export class TextPanel extends PureComponent<Props, State> {
}
prepareHTML(html: string): string {
return this.interpolateAndSanitizeString(html);
const result = this.interpolateString(html);
return config.disableSanitizeHtml ? result : this.sanitizeString(result);
}
prepareMarkdown(content: string): string {
// Sanitize is disabled here as we handle that after variable interpolation
return this.interpolateAndSanitizeString(
renderTextPanelMarkdown(content, {
noSanitize: config.disableSanitizeHtml,
})
);
// Always interpolate variables before converting to markdown
// because `marked` replaces '{' and '}' in URLs with '%7B' and '%7D'
// See https://marked.js.org/demo
let result = this.interpolateString(content);
if (config.disableSanitizeHtml) {
result = renderTextPanelMarkdown(result, {
noSanitize: true,
});
return result;
}
result = renderTextPanelMarkdown(result);
return this.sanitizeString(result);
}
interpolateAndSanitizeString(content: string): string {
interpolateString(content: string): string {
const { replaceVariables } = this.props;
return replaceVariables(content, {}, 'html');
}
content = replaceVariables(content, {}, 'html');
return config.disableSanitizeHtml ? content : textUtil.sanitizeTextPanelContent(content);
sanitizeString(content: string): string {
return textUtil.sanitizeTextPanelContent(content);
}
processContent(options: PanelOptions): string {