From 03c27b1cdbddbf27ff42e7ff1e9d3ce397b253f5 Mon Sep 17 00:00:00 2001 From: streamich Date: Wed, 23 Dec 2020 16:14:54 +0100 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20use=20EuiSwitch=20fo?= =?UTF-8?q?r=20"Open=20in=20new=20window"=20toggle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/url_drilldown_collect_config/i18n.ts | 2 +- .../url_drilldown_collect_config.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/i18n.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/i18n.ts index 500ef21b61dc..e4ad6d828f0e 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/i18n.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/i18n.ts @@ -76,6 +76,6 @@ export const txtUrlTemplatePreviewLinkText = i18n.translate( export const txtUrlTemplateOpenInNewTab = i18n.translate( 'xpack.uiActionsEnhanced.drilldowns.urlDrilldownCollectConfig.openInNewTabLabel', { - defaultMessage: 'Open in new tab', + defaultMessage: 'Open in new window', } ); diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/url_drilldown_collect_config.tsx b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/url_drilldown_collect_config.tsx index eb8d01afbf42..82e9ed2780e1 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/url_drilldown_collect_config.tsx +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/url_drilldown_collect_config.tsx @@ -6,7 +6,6 @@ import React, { useRef, useState } from 'react'; import { - EuiCheckbox, EuiFormRow, EuiIcon, EuiLink, @@ -17,6 +16,7 @@ import { EuiText, EuiTextArea, EuiSelectableOption, + EuiSwitch, } from '@elastic/eui'; import { UrlDrilldownConfig } from '../../types'; import './index.scss'; @@ -111,7 +111,7 @@ export const UrlDrilldownCollectConfig: React.FC = ({ /> - Date: Wed, 23 Dec 2020 16:49:50 +0100 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20"URL=20encodin?= =?UTF-8?q?g"=20option=20and=20"Additional=20options"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../public/lib/url_drilldown.tsx | 1 + .../url_drilldown_collect_config/i18n.ts | 23 ++++++++- .../url_drilldown_collect_config.tsx | 49 +++++++++++++++---- .../public/drilldowns/url_drilldown/types.ts | 1 + 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx b/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx index bfeab263d20e..9a9fdb17382c 100644 --- a/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx +++ b/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx @@ -105,6 +105,7 @@ export class UrlDrilldown implements Drilldown ({ url: { template: '' }, openInNewTab: false, + encodeUrl: true, }); public readonly isConfigValid = (config: Config): config is Config => { diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/i18n.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/i18n.ts index e4ad6d828f0e..001e16393b16 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/i18n.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/i18n.ts @@ -34,7 +34,7 @@ export const txtAddVariableButtonTitle = i18n.translate( export const txtUrlTemplateLabel = i18n.translate( 'xpack.uiActionsEnhanced.drilldowns.urlDrilldownCollectConfig.urlTemplateLabel', { - defaultMessage: 'Enter URL template:', + defaultMessage: 'Enter URL:', } ); @@ -79,3 +79,24 @@ export const txtUrlTemplateOpenInNewTab = i18n.translate( defaultMessage: 'Open in new window', } ); + +export const txtUrlTemplateAdditionalOptions = i18n.translate( + 'xpack.uiActionsEnhanced.drilldowns.urlDrilldownCollectConfig.additionalOptions', + { + defaultMessage: 'Additional options', + } +); + +export const txtUrlTemplateEncodeUrl = i18n.translate( + 'xpack.uiActionsEnhanced.drilldowns.urlDrilldownCollectConfig.encodeUrl', + { + defaultMessage: 'Encode URL', + } +); + +export const txtUrlTemplateEncodeDescription = i18n.translate( + 'xpack.uiActionsEnhanced.drilldowns.urlDrilldownCollectConfig.encodeDescription', + { + defaultMessage: 'If enabled, URL will be escaped using percent encoding', + } +); diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/url_drilldown_collect_config.tsx b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/url_drilldown_collect_config.tsx index 82e9ed2780e1..04ed73b2ce0b 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/url_drilldown_collect_config.tsx +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/url_drilldown_collect_config.tsx @@ -17,6 +17,10 @@ import { EuiTextArea, EuiSelectableOption, EuiSwitch, + EuiAccordion, + EuiSpacer, + EuiPanel, + EuiTextColor, } from '@elastic/eui'; import { UrlDrilldownConfig } from '../../types'; import './index.scss'; @@ -28,6 +32,9 @@ import { txtUrlTemplateLabel, txtUrlTemplateOpenInNewTab, txtUrlTemplatePlaceholder, + txtUrlTemplateAdditionalOptions, + txtUrlTemplateEncodeUrl, + txtUrlTemplateEncodeDescription, } from './i18n'; export interface UrlDrilldownCollectConfig { @@ -110,15 +117,39 @@ export const UrlDrilldownCollectConfig: React.FC = ({ inputRef={textAreaRef} /> - - onConfig({ ...config, openInNewTab: !config.openInNewTab })} - /> - + + + + + + onConfig({ ...config, openInNewTab: !config.openInNewTab })} + /> + + + + {txtUrlTemplateEncodeUrl} + + {txtUrlTemplateEncodeDescription} + + } + checked={config.encodeUrl ?? true} + onChange={() => onConfig({ ...config, encodeUrl: !(config.encodeUrl ?? true) })} + /> + + + ); }; diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/types.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/types.ts index fb7d96aaf832..59942ab6ff94 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/types.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/types.ts @@ -7,6 +7,7 @@ export type UrlDrilldownConfig = { url: { format?: 'handlebars_v1'; template: string }; openInNewTab: boolean; + encodeUrl?: boolean; }; /** From 4764eaf451e3eee142b427dc60fbd7f003f29e57 Mon Sep 17 00:00:00 2001 From: streamich Date: Wed, 23 Dec 2020 16:53:35 +0100 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20make=20"Open=20in=20?= =?UTF-8?q?new=20window"=20true=20by=20default?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../drilldowns/url_drilldown/public/lib/url_drilldown.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx b/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx index 9a9fdb17382c..360bf70f1503 100644 --- a/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx +++ b/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx @@ -104,7 +104,7 @@ export class UrlDrilldown implements Drilldown ({ url: { template: '' }, - openInNewTab: false, + openInNewTab: true, encodeUrl: true, }); From b36e0a5e28daa6b830f7bd8b44b98485281be829 Mon Sep 17 00:00:00 2001 From: streamich Date: Wed, 23 Dec 2020 17:08:23 +0100 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20respect=20encoding?= =?UTF-8?q?=20config=20setting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../url_drilldown/public/lib/url_drilldown.tsx | 7 ++++++- .../public/drilldowns/url_drilldown/url_template.ts | 12 +++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx b/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx index 360bf70f1503..ffb068730516 100644 --- a/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx +++ b/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx @@ -134,7 +134,12 @@ export class UrlDrilldown implements Drilldown { return String(str).split(searchString).join(valueString); }); -export function compile(url: string, context: object): string { - const template = handlebars.compile(url, { strict: true, noEscape: true }); - return encodeURI(template(context)); +export function compile(urlTemplate: string, context: object, doEncode: boolean = true): string { + const handlebarsTemplate = handlebars.compile(urlTemplate, { strict: true, noEscape: true }); + let url: string = handlebarsTemplate(context); + + if (doEncode) { + url = encodeURI(url); + } + + return url; } From ccdb9fb27e9022cb2450067437154437525c2009 Mon Sep 17 00:00:00 2001 From: streamich Date: Mon, 28 Dec 2020 11:26:59 +0100 Subject: [PATCH 5/7] =?UTF-8?q?test:=20=F0=9F=92=8D=20add=20encoding=20tes?= =?UTF-8?q?ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../public/lib/url_drilldown.test.ts | 45 +++++++++++++++++++ .../url_drilldown/url_template.test.ts | 12 +++++ 2 files changed, 57 insertions(+) diff --git a/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.test.ts b/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.test.ts index e3730084d702..fc6a760cb869 100644 --- a/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.test.ts +++ b/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.test.ts @@ -443,3 +443,48 @@ describe('UrlDrilldown', () => { }); }); }); + +describe('encoding', () => { + const urlDrilldown = createDrilldown(); + const context: ActionContext = { + data: { + data: mockDataPoints, + }, + embeddable: mockEmbeddable, + }; + + test('encodes URL by default', async () => { + const config: Config = { + url: { + template: 'https://elastic.co?foo=head%26shoulders', + }, + openInNewTab: false, + }; + const url = await urlDrilldown.getHref(config, context); + expect(url).toBe('https://elastic.co?foo=head%2526shoulders'); + }); + + test('encodes URL when encoding is enabled', async () => { + const config: Config = { + url: { + template: 'https://elastic.co?foo=head%26shoulders', + }, + openInNewTab: false, + encodeUrl: true, + }; + const url = await urlDrilldown.getHref(config, context); + expect(url).toBe('https://elastic.co?foo=head%2526shoulders'); + }); + + test('does not encode URL when encoding is not enabled', async () => { + const config: Config = { + url: { + template: 'https://elastic.co?foo=head%26shoulders', + }, + openInNewTab: false, + encodeUrl: false, + }; + const url = await urlDrilldown.getHref(config, context); + expect(url).toBe('https://elastic.co?foo=head%26shoulders'); + }); +}); diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.test.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.test.ts index 68a9654316d4..72c0a5ade792 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.test.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.test.ts @@ -12,6 +12,18 @@ test('should compile url without variables', () => { expect(compile(url, {})).toBe(url); }); +test('by default, encodes URI', () => { + const url = 'https://elastic.co?foo=head%26shoulders'; + expect(compile(url, {})).not.toBe(url); + expect(compile(url, {})).toBe('https://elastic.co?foo=head%2526shoulders'); +}); + +test('when URI encoding is disabled, should not encode URI', () => { + const url = + 'https://xxxxx.service-now.com/nav_to.do?uri=incident.do%3Fsys_id%3D-1%26sysparm_query%3Dshort_description%3DHello'; + expect(compile(url, {}, false)).toBe(url); +}); + test('should fail on unknown syntax', () => { const url = 'https://elastic.co/{{}'; expect(() => compile(url, {})).toThrowError(); From 4542e7af51a1e8df8010edb1fa1be87b36aa0b4b Mon Sep 17 00:00:00 2001 From: streamich Date: Mon, 28 Dec 2020 12:33:49 +0100 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20URI=20encoding?= =?UTF-8?q?=20Handlebars=20helpers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../public/lib/url_drilldown.test.ts | 29 +++++++++++++++++++ .../drilldowns/url_drilldown/url_template.ts | 16 ++++++++-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.test.ts b/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.test.ts index fc6a760cb869..1c6d7e406618 100644 --- a/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.test.ts +++ b/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.test.ts @@ -461,6 +461,7 @@ describe('encoding', () => { openInNewTab: false, }; const url = await urlDrilldown.getHref(config, context); + expect(url).toBe('https://elastic.co?foo=head%2526shoulders'); }); @@ -473,6 +474,7 @@ describe('encoding', () => { encodeUrl: true, }; const url = await urlDrilldown.getHref(config, context); + expect(url).toBe('https://elastic.co?foo=head%2526shoulders'); }); @@ -485,6 +487,33 @@ describe('encoding', () => { encodeUrl: false, }; const url = await urlDrilldown.getHref(config, context); + expect(url).toBe('https://elastic.co?foo=head%26shoulders'); }); + + test('can encode URI component using "encodeURIComponent" Handlebars helper', async () => { + const config: Config = { + url: { + template: 'https://elastic.co?foo={{encodeURIComponent "head%26shoulders@gmail.com"}}', + }, + openInNewTab: false, + encodeUrl: false, + }; + const url = await urlDrilldown.getHref(config, context); + + expect(url).toBe('https://elastic.co?foo=head%2526shoulders%40gmail.com'); + }); + + test('can encode URI component using "encodeURIQuery" Handlebars helper', async () => { + const config: Config = { + url: { + template: 'https://elastic.co?foo={{encodeURIQuery "head%26shoulders@gmail.com"}}', + }, + openInNewTab: false, + encodeUrl: false, + }; + const url = await urlDrilldown.getHref(config, context); + + expect(url).toBe('https://elastic.co?foo=head%2526shoulders@gmail.com'); + }); }); diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.ts index eb4247466409..7533920d07d5 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.ts @@ -9,6 +9,7 @@ import { encode, RisonValue } from 'rison-node'; import dateMath from '@elastic/datemath'; import moment, { Moment } from 'moment'; import numeral from '@elastic/numeral'; +import { url } from '../../../../../../src/plugins/kibana_utils/public'; const handlebars = createHandlebars(); @@ -116,13 +117,22 @@ handlebars.registerHelper('replace', (...args) => { return String(str).split(searchString).join(valueString); }); +handlebars.registerHelper('encodeURIComponent', (component: unknown) => { + const str = String(component); + return encodeURIComponent(str); +}); +handlebars.registerHelper('encodeURIQuery', (component: unknown) => { + const str = String(component); + return url.encodeUriQuery(str); +}); + export function compile(urlTemplate: string, context: object, doEncode: boolean = true): string { const handlebarsTemplate = handlebars.compile(urlTemplate, { strict: true, noEscape: true }); - let url: string = handlebarsTemplate(context); + let processedUrl: string = handlebarsTemplate(context); if (doEncode) { - url = encodeURI(url); + processedUrl = encodeURI(processedUrl); } - return url; + return processedUrl; } From 51e78d17138a50fd1d17576e7e3988545d82f516 Mon Sep 17 00:00:00 2001 From: streamich Date: Mon, 28 Dec 2020 12:48:46 +0100 Subject: [PATCH 7/7] =?UTF-8?q?docs:=20=E2=9C=8F=EF=B8=8F=20add=20URL=20en?= =?UTF-8?q?coding=20methods=20to=20URL=20Drilldown=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/user/dashboard/url-drilldown.asciidoc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/user/dashboard/url-drilldown.asciidoc b/docs/user/dashboard/url-drilldown.asciidoc index df9fa2dca81f..b292c1ae5e03 100644 --- a/docs/user/dashboard/url-drilldown.asciidoc +++ b/docs/user/dashboard/url-drilldown.asciidoc @@ -133,6 +133,12 @@ Example: `{{split event.value ","}}` +|encodeURIComponent +a|Escapes string using built in `encodeURIComponent` function. + +|encodeURIQuery +a|Escapes string using built in `encodeURIComponent` function, while keeping "@", ":", "$", ",", and ";" characters as is. + |===