Skip to content

Commit 25010ff

Browse files
author
Maja Grubic
committed
Replacing URL regex parsing with legacy URLs
1 parent fe9ab85 commit 25010ff

6 files changed

Lines changed: 238 additions & 232 deletions

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
jest.mock('../', () => ({
21+
DashboardConstants: {
22+
ADD_EMBEDDABLE_ID: 'addEmbeddableId',
23+
ADD_EMBEDDABLE_TYPE: 'addEmbeddableType',
24+
},
25+
}));
26+
27+
jest.mock('../legacy_imports', () => {
28+
return {
29+
absoluteToParsedUrl: jest.fn(() => {
30+
return {
31+
basePath: '/pep',
32+
appId: 'kibana',
33+
appPath: '/dashboard?addEmbeddableType=lens&addEmbeddableId=123eb456cd&x=1&y=2&z=3',
34+
hostname: 'localhost',
35+
port: 5601,
36+
protocol: 'http:',
37+
addQueryParameter: () => {},
38+
getAbsoluteUrl: () => {
39+
return 'http://localhost:5601/pep/app/kibana#/dashboard?addEmbeddableType=lens&addEmbeddableId=123eb456cd&x=1&y=2&z=3';
40+
},
41+
};
42+
}),
43+
};
44+
});
45+
46+
import {
47+
addEmbeddableToDashboardUrl,
48+
getLensUrlFromDashboardAbsoluteUrl,
49+
getUrlVars,
50+
} from '../np_ready/url_helper';
51+
52+
describe('Dashboard URL Helper', () => {
53+
beforeEach(() => {
54+
jest.resetModules();
55+
});
56+
57+
it('addEmbeddableToDashboardUrl', () => {
58+
const id = '123eb456cd';
59+
const type = 'lens';
60+
const urlVars = {
61+
x: '1',
62+
y: '2',
63+
z: '3',
64+
};
65+
const basePath = '/pep';
66+
const url =
67+
"http://localhost:5601/pep/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!()";
68+
expect(addEmbeddableToDashboardUrl(url, basePath, id, urlVars, type)).toEqual(
69+
`http://localhost:5601/pep/app/kibana#/dashboard?addEmbeddableType=${type}&addEmbeddableId=${id}&x=1&y=2&z=3`
70+
);
71+
});
72+
73+
it('getUrlVars', () => {
74+
let url =
75+
"http://localhost:5601/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!()";
76+
expect(getUrlVars(url)).toEqual({
77+
_g: '(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))',
78+
_a: "(description:'',filters:!()",
79+
});
80+
url = 'http://mybusiness.mydomain.com/app/kibana#/dashboard?x=y&y=z';
81+
expect(getUrlVars(url)).toEqual({
82+
x: 'y',
83+
y: 'z',
84+
});
85+
url = 'http://notDashboardUrl';
86+
expect(getUrlVars(url)).toEqual({});
87+
url = 'http://localhost:5601/app/kibana#/dashboard/777182';
88+
expect(getUrlVars(url)).toEqual({});
89+
});
90+
91+
it('getLensUrlFromDashboardAbsoluteUrl', () => {
92+
const id = '1244';
93+
const basePath = '/wev';
94+
let url =
95+
"http://localhost:5601/wev/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!()";
96+
expect(getLensUrlFromDashboardAbsoluteUrl(url, basePath, id)).toEqual(
97+
'http://localhost:5601/wev/app/kibana#/lens/edit/1244'
98+
);
99+
100+
url =
101+
"http://localhost:5601/wev/app/kibana#/dashboard/625357282?_a=(description:'',filters:!()&_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))";
102+
expect(getLensUrlFromDashboardAbsoluteUrl(url, basePath, id)).toEqual(
103+
'http://localhost:5601/wev/app/kibana#/lens/edit/1244'
104+
);
105+
106+
url = 'http://myserver.mydomain.com:5601/wev/app/kibana#/dashboard/777182';
107+
expect(getLensUrlFromDashboardAbsoluteUrl(url, basePath, id)).toEqual(
108+
'http://myserver.mydomain.com:5601/wev/app/kibana#/lens/edit/1244'
109+
);
110+
});
111+
});

src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,4 @@ export { IInjector } from 'ui/chrome';
6767
export { SavedObjectLoader } from 'ui/saved_objects';
6868
export { VISUALIZE_EMBEDDABLE_TYPE } from '../visualize_embeddable';
6969
export { registerTimefilterWithGlobalStateFactory } from 'ui/timefilter/setup_router';
70+
export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url';
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
import { parse } from 'url';
20+
import { absoluteToParsedUrl } from '../legacy_imports';
21+
import { DashboardConstants } from './dashboard_constants';
22+
/**
23+
* Return query params from URL
24+
* @param url given url
25+
*/
26+
export function getUrlVars(url: string): Record<string, string> {
27+
const vars: Record<string, string> = {};
28+
// @ts-ignore
29+
url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(_, key, value) {
30+
// @ts-ignore
31+
vars[key] = value;
32+
});
33+
return vars;
34+
}
35+
36+
/** *
37+
* Returns dashboard URL with added embeddableType and embeddableId query params
38+
* eg.
39+
* input: url: http://localhost:5601/lib/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now)), embeddableId: 12345, embeddableType: 'lens'
40+
* output: http://localhost:5601/lib/app/kibana#dashboard?addEmbeddableType=lens&addEmbeddableId=12345&_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))
41+
* @param url dasbhoard absolute url
42+
* @param embeddableId id of the saved visualization
43+
* @param basePath current base path
44+
* @param urlVars url query params (optional)
45+
* @param embeddableType 'lens' or 'visualization' (optional, default is 'lens')
46+
*/
47+
export function addEmbeddableToDashboardUrl(
48+
url: string | undefined,
49+
basePath: string,
50+
embeddableId: string,
51+
urlVars?: Record<string, string>,
52+
embeddableType?: string
53+
): string | null {
54+
if (!url) {
55+
return null;
56+
}
57+
const dashboardUrl = getUrlWithoutQueryParams(url);
58+
const dashboardParsedUrl = absoluteToParsedUrl(dashboardUrl, basePath);
59+
if (urlVars) {
60+
const keys = Object.keys(urlVars).sort();
61+
keys.forEach(key => {
62+
dashboardParsedUrl.addQueryParameter(key, urlVars[key]);
63+
});
64+
}
65+
dashboardParsedUrl.addQueryParameter(
66+
DashboardConstants.ADD_EMBEDDABLE_TYPE,
67+
embeddableType || 'lens'
68+
);
69+
dashboardParsedUrl.addQueryParameter(DashboardConstants.ADD_EMBEDDABLE_ID, embeddableId);
70+
return dashboardParsedUrl.getAbsoluteUrl();
71+
}
72+
73+
/**
74+
* Return Lens URL from dashboard absolute URL
75+
* @param dashboardAbsoluteUrl
76+
* @param basePath current base path
77+
* @param id Lens id
78+
*/
79+
export function getLensUrlFromDashboardAbsoluteUrl(
80+
dashboardAbsoluteUrl: string | undefined | null,
81+
basePath: string | null,
82+
id: string
83+
): string | null {
84+
if (!dashboardAbsoluteUrl || !basePath) {
85+
return null;
86+
}
87+
const { host, protocol } = parse(dashboardAbsoluteUrl);
88+
return `${protocol}//${host}${basePath}/app/kibana#/lens/edit/${id}`;
89+
}
90+
91+
/**
92+
* Returns the portion of the URL without query params
93+
* eg.
94+
* input: http://localhost:5601/lib/app/kibana#/dashboard?param1=x&param2=y&param3=z
95+
* output:http://localhost:5601/lib/app/kibana#/dashboard
96+
* input: http://localhost:5601/lib/app/kibana#/dashboard/39292992?param1=x&param2=y&param3=z
97+
* output: http://localhost:5601/lib/app/kibana#/dashboard/39292992
98+
* @param url url to parse
99+
*/
100+
function getUrlWithoutQueryParams(url: string): string {
101+
return url.split('?')[0];
102+
}

x-pack/legacy/plugins/lens/public/app_plugin/plugin.tsx

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,10 @@ import { NOT_INTERNATIONALIZED_PRODUCT_NAME } from '../../common';
4444
import { KibanaLegacySetup } from '../../../../../../src/plugins/kibana_legacy/public';
4545
import { EditorFrameStart } from '../types';
4646
import {
47-
getKibanaBasePathFromDashboardUrl,
4847
addEmbeddableToDashboardUrl,
49-
getDashboardUrlWithQueryParams,
5048
getUrlVars,
51-
} from './url_helper';
49+
getLensUrlFromDashboardAbsoluteUrl,
50+
} from '../../../../../../src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper';
5251

5352
export interface LensPluginSetupDependencies {
5453
kibana_legacy: KibanaLegacySetup;
@@ -95,7 +94,6 @@ export class AppPlugin {
9594
}
9695
const { data, savedObjectsClient, editorFrame } = this.startDependencies;
9796
addHelpMenuToAppChrome(context.core.chrome);
98-
9997
const instance = editorFrame.createInstance({});
10098

10199
setReportManager(
@@ -126,25 +124,31 @@ export class AppPlugin {
126124
routeProps.history.push(`/lens/edit/${id}`);
127125
const url = context.core.chrome.navLinks.get('kibana:dashboard');
128126
if (!url) {
129-
return;
127+
throw new Error('Cannot get last dashboard url');
130128
}
131129
const lastDashboardAbsoluteUrl = url.url;
132-
const lensUrl = `${getKibanaBasePathFromDashboardUrl(
133-
lastDashboardAbsoluteUrl
134-
)}/lens/edit/${id}`;
135-
if (lastDashboardAbsoluteUrl && lensUrl) {
136-
const urlVars = getUrlVars(lastDashboardAbsoluteUrl);
137-
updateUrlTime(urlVars);
138-
window.history.pushState({}, '', lensUrl);
139-
const dashboardUrl = getDashboardUrlWithQueryParams(
140-
lastDashboardAbsoluteUrl,
141-
urlVars
142-
);
143-
const dashboardParsedUrl = addEmbeddableToDashboardUrl(dashboardUrl, id, 'lens');
144-
if (dashboardParsedUrl) {
145-
window.history.pushState({}, '', dashboardParsedUrl);
146-
}
130+
const basePath = context.core.http.basePath.get();
131+
const lensUrl = getLensUrlFromDashboardAbsoluteUrl(
132+
lastDashboardAbsoluteUrl,
133+
basePath,
134+
id
135+
);
136+
if (!lastDashboardAbsoluteUrl || !lensUrl) {
137+
throw new Error('Cannot get last dashboard url');
138+
}
139+
window.history.pushState({}, '', lensUrl);
140+
const urlVars = getUrlVars(lastDashboardAbsoluteUrl);
141+
updateUrlTime(urlVars); // we need to pass in timerange in query params directly
142+
const dashboardParsedUrl = addEmbeddableToDashboardUrl(
143+
lastDashboardAbsoluteUrl,
144+
basePath,
145+
id,
146+
urlVars
147+
);
148+
if (!dashboardParsedUrl) {
149+
throw new Error('Problem parsing dashboard url');
147150
}
151+
window.history.pushState({}, '', dashboardParsedUrl);
148152
}
149153
};
150154

x-pack/legacy/plugins/lens/public/app_plugin/url_helper.test.ts

Lines changed: 0 additions & 102 deletions
This file was deleted.

0 commit comments

Comments
 (0)