Skip to content

Commit ecda7c0

Browse files
Merge branch 'master' into func-tests/refactor-dashboard-page
2 parents b0a4400 + f7ba362 commit ecda7c0

File tree

130 files changed

+4202
-3885
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+4202
-3885
lines changed

docs/management/advanced-options.asciidoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ Refresh the page to apply the changes.
187187
=== Search settings
188188

189189
[horizontal]
190-
`courier:batchSearches`:: When disabled, dashboard panels will load individually, and search requests will terminate when
190+
`courier:batchSearches`:: **Deprecated in 7.6. Starting in 8.0, this setting will be optimized internally.**
191+
When disabled, dashboard panels will load individually, and search requests will terminate when
191192
users navigate away or update the query. When enabled, dashboard panels will load together when all of the data is loaded,
192193
and searches will not terminate.
193194
`courier:customRequestPreference`:: {ref}/search-request-body.html#request-body-search-preference[Request preference]

src/core/utils/merge.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,15 @@ describe('merge', () => {
6161
expect(merge({ a: 0 }, {}, {})).toEqual({ a: 0 });
6262
expect(merge({ a: 0 }, { a: 1 }, {})).toEqual({ a: 1 });
6363
});
64+
65+
test(`doesn't pollute prototypes`, () => {
66+
merge({}, JSON.parse('{ "__proto__": { "foo": "bar" } }'));
67+
merge({}, JSON.parse('{ "constructor": { "prototype": { "foo": "bar" } } }'));
68+
merge(
69+
{},
70+
JSON.parse('{ "__proto__": { "foo": "bar" } }'),
71+
JSON.parse('{ "constructor": { "prototype": { "foo": "bar" } } }')
72+
);
73+
expect(({} as any).foo).toBe(undefined);
74+
});
6475
});
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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+
url =
112+
"http://localhost:5601/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!()";
113+
expect(getLensUrlFromDashboardAbsoluteUrl(url, '', id)).toEqual(
114+
'http://localhost:5601/app/kibana#/lens/edit/1244'
115+
);
116+
});
117+
});

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';

src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import {
3737
KbnUrl,
3838
SavedObjectSaveOpts,
3939
unhashUrl,
40-
VISUALIZE_EMBEDDABLE_TYPE,
4140
} from '../legacy_imports';
4241
import { FilterStateManager } from '../../../../data/public';
4342
import {
@@ -334,13 +333,12 @@ export class DashboardAppController {
334333
// This code needs to be replaced with a better mechanism for adding new embeddables of
335334
// any type from the add panel. Likely this will happen via creating a visualization "inline",
336335
// without navigating away from the UX.
337-
if ($routeParams[DashboardConstants.NEW_VISUALIZATION_ID_PARAM]) {
338-
container.addSavedObjectEmbeddable(
339-
VISUALIZE_EMBEDDABLE_TYPE,
340-
$routeParams[DashboardConstants.NEW_VISUALIZATION_ID_PARAM]
341-
);
342-
kbnUrl.removeParam(DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM);
343-
kbnUrl.removeParam(DashboardConstants.NEW_VISUALIZATION_ID_PARAM);
336+
if ($routeParams[DashboardConstants.ADD_EMBEDDABLE_TYPE]) {
337+
const type = $routeParams[DashboardConstants.ADD_EMBEDDABLE_TYPE];
338+
const id = $routeParams[DashboardConstants.ADD_EMBEDDABLE_ID];
339+
container.addSavedObjectEmbeddable(type, id);
340+
kbnUrl.removeParam(DashboardConstants.ADD_EMBEDDABLE_TYPE);
341+
kbnUrl.removeParam(DashboardConstants.ADD_EMBEDDABLE_ID);
344342
}
345343
}
346344

src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@
1919

2020
export const DashboardConstants = {
2121
ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM: 'addToDashboard',
22-
NEW_VISUALIZATION_ID_PARAM: 'addVisualization',
2322
LANDING_PAGE_PATH: '/dashboards',
2423
CREATE_NEW_DASHBOARD_URL: '/dashboard',
24+
ADD_EMBEDDABLE_ID: 'addEmbeddableId',
25+
ADD_EMBEDDABLE_TYPE: 'addEmbeddableType',
2526
};
2627

2728
export function createDashboardEditUrl(id: string) {
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 | undefined,
82+
id: string
83+
): string | null {
84+
if (!dashboardAbsoluteUrl || basePath === null || basePath === undefined) {
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+
}

src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ import { unhashUrl } from '../../../../../../../plugins/kibana_utils/public';
3535

3636
import { initVisEditorDirective } from './visualization_editor';
3737
import { initVisualizationDirective } from './visualization';
38-
3938
import {
39+
VISUALIZE_EMBEDDABLE_TYPE,
4040
subscribeWithScope,
4141
absoluteToParsedUrl,
4242
KibanaParsedUrl,
@@ -588,7 +588,11 @@ function VisualizeAppController(
588588
getBasePath()
589589
);
590590
dashboardParsedUrl.addQueryParameter(
591-
DashboardConstants.NEW_VISUALIZATION_ID_PARAM,
591+
DashboardConstants.ADD_EMBEDDABLE_TYPE,
592+
VISUALIZE_EMBEDDABLE_TYPE
593+
);
594+
dashboardParsedUrl.addQueryParameter(
595+
DashboardConstants.ADD_EMBEDDABLE_ID,
592596
savedVis.id
593597
);
594598
kbnUrl.change(dashboardParsedUrl.appPath);

src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/new_vis_modal.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ describe('NewVisModal', () => {
144144
expect(window.location.assign).toBeCalledWith('#/visualize/create?type=vis&foo=true&bar=42');
145145
});
146146

147-
it('closes if visualization with aliasUrl and addToDashboard in editorParams', () => {
147+
it('closes and redirects properly if visualization with aliasUrl and addToDashboard in editorParams', () => {
148148
const onClose = jest.fn();
149149
window.location.assign = jest.fn();
150150
const wrapper = mountWithIntl(
@@ -160,7 +160,7 @@ describe('NewVisModal', () => {
160160
);
161161
const visButton = wrapper.find('button[data-test-subj="visType-visWithAliasUrl"]');
162162
visButton.simulate('click');
163-
expect(window.location.assign).toBeCalledWith('testbasepath/aliasUrl');
163+
expect(window.location.assign).toBeCalledWith('testbasepath/aliasUrl?addToDashboard');
164164
expect(onClose).toHaveBeenCalled();
165165
});
166166
});

src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/new_vis_modal.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,15 +143,18 @@ class NewVisModal extends React.Component<TypeSelectionProps, TypeSelectionState
143143
this.trackUiMetric(METRIC_TYPE.CLICK, visType.name);
144144
}
145145

146+
let params;
146147
if ('aliasUrl' in visType) {
147-
window.location.assign(this.props.addBasePath(visType.aliasUrl));
148+
params = this.props.addBasePath(visType.aliasUrl);
148149
if (this.props.editorParams && this.props.editorParams.includes('addToDashboard')) {
150+
params = `${params}?addToDashboard`;
149151
this.props.onClose();
150152
}
153+
window.location.assign(params);
151154
return;
152155
}
153156

154-
let params = [`type=${encodeURIComponent(visType.name)}`];
157+
params = [`type=${encodeURIComponent(visType.name)}`];
155158

156159
if (searchType) {
157160
params.push(`${searchType === 'search' ? 'savedSearchId' : 'indexPattern'}=${searchId}`);

0 commit comments

Comments
 (0)