Commit 4f251ab3 authored by Miguel Rincon's avatar Miguel Rincon

Update the url when a panel is expanded

Respond to a change in the current view of dashboard by updating the
browser URL effectively syncronnizing with the panel specific URL.
parent 34dcf767
......@@ -259,8 +259,17 @@ export default {
);
}
},
expandedPanel: {
handler({ group, panel }) {
const dashboardPath = this.currentDashboard || this.firstDashboard.path;
updateHistory({
url: panelToUrl(dashboardPath, group, panel),
title: document.title,
});
},
deep: true,
},
},
created() {
this.setInitialState({
metricsEndpoint: this.metricsEndpoint,
......
import { pickBy } from 'lodash';
import { queryToObject, mergeUrlParams, removeParams } from '~/lib/utils/url_utility';
import {
timeRangeParamNames,
......@@ -174,25 +173,30 @@ export const expandedPanelPayloadFromUrl = (dashboard, search = window.location.
* Convert panel information to a URL for the user to
* bookmark or share highlighting a specific panel.
*
* @param {String} dashboardPath - Dashboard path used as identifier
* @param {String} group - Group Identifier
* If no group/panel is set, the dashboard URL is returned.
*
* @param {?String} dashboard - Dashboard path, used as identifier for a dashboard
* @param {?String} group - Group Identifier
* @param {?Object} panel - Panel object from the dashboard
* @param {?String} url - Base URL including current search params
* @returns Dashboard URL which expands a panel (chart)
*/
export const panelToUrl = (dashboardPath, group, panel, url = window.location.href) => {
if (!group || !panel) {
return null;
export const panelToUrl = (dashboard = null, group, panel, url = window.location.href) => {
const params = {
dashboard,
};
if (group && panel) {
params.group = group;
params.title = panel.title;
params.y_label = panel.y_label;
} else {
// Remove existing parameters if any
params.group = null;
params.title = null;
params.y_label = null;
}
const params = pickBy(
{
dashboard: dashboardPath,
group,
title: panel.title,
y_label: panel.y_label,
},
value => value != null,
);
return mergeUrlParams(params, url);
};
......
---
title: Update metrics dashboard url when a panel is expanded or contracted
merge_request: 30704
author:
type: added
......@@ -234,6 +234,90 @@ describe('Dashboard', () => {
});
});
describe('when the panel is expanded', () => {
let group;
let panel;
const expandPanel = (mockGroup, mockPanel) => {
store.commit(`monitoringDashboard/${types.SET_EXPANDED_PANEL}`, {
group: mockGroup,
panel: mockPanel,
});
};
beforeEach(() => {
setupStoreWithData(store);
const { panelGroups } = store.state.monitoringDashboard.dashboard;
group = panelGroups[0].group;
[panel] = panelGroups[0].panels;
jest.spyOn(window.history, 'pushState').mockImplementation();
});
afterEach(() => {
window.history.pushState.mockRestore();
});
it('URL is updated with panel parameters', () => {
createMountedWrapper({ hasMetrics: true });
expandPanel(group, panel);
const expectedSearch = objectToQuery({
group,
title: panel.title,
y_label: panel.y_label,
});
return wrapper.vm.$nextTick(() => {
expect(window.history.pushState).toHaveBeenCalledTimes(1);
expect(window.history.pushState).toHaveBeenCalledWith(
expect.anything(), // state
expect.any(String), // document title
expect.stringContaining(`?${expectedSearch}`),
);
});
});
it('URL is updated with panel parameters and custom dashboard', () => {
const dashboard = 'dashboard.yml';
createMountedWrapper({ hasMetrics: true, currentDashboard: dashboard });
expandPanel(group, panel);
const expectedSearch = objectToQuery({
dashboard,
group,
title: panel.title,
y_label: panel.y_label,
});
return wrapper.vm.$nextTick(() => {
expect(window.history.pushState).toHaveBeenCalledTimes(1);
expect(window.history.pushState).toHaveBeenCalledWith(
expect.anything(), // state
expect.any(String), // document title
expect.stringContaining(`?${expectedSearch}`),
);
});
});
it('URL is updated with no parameters', () => {
expandPanel(group, panel);
createMountedWrapper({ hasMetrics: true });
expandPanel(null, null);
return wrapper.vm.$nextTick(() => {
expect(window.history.pushState).toHaveBeenCalledTimes(1);
expect(window.history.pushState).toHaveBeenCalledWith(
expect.anything(), // state
expect.any(String), // document title
expect.not.stringContaining('?'), // no params
);
});
});
});
describe('when all requests have been commited by the store', () => {
beforeEach(() => {
createMountedWrapper({ hasMetrics: true });
......
......@@ -274,9 +274,10 @@ describe('monitoring/utils', () => {
const [panelGroup] = metricsDashboardViewModel.panelGroups;
const [panel] = panelGroup.panels;
const getUrlParams = url => urlUtils.queryToObject(url.split('?')[1]);
it('returns URL for a panel when query parameters are given', () => {
const [, query] = panelToUrl(dashboard, panelGroup.group, panel).split('?');
const params = urlUtils.queryToObject(query);
const params = getUrlParams(panelToUrl(dashboard, panelGroup.group, panel));
expect(params).toEqual({
dashboard,
......@@ -286,12 +287,14 @@ describe('monitoring/utils', () => {
});
});
it('returns `null` if group is missing', () => {
expect(panelToUrl(dashboard, null, panel)).toBe(null);
it('returns a dashboard only URL if group is missing', () => {
const params = getUrlParams(panelToUrl(dashboard, null, panel));
expect(params).toEqual({ dashboard: 'metrics.yml' });
});
it('returns `null` if panel is missing', () => {
expect(panelToUrl(dashboard, panelGroup.group, null)).toBe(null);
it('returns a dashboard only URL if panel is missing', () => {
const params = getUrlParams(panelToUrl(dashboard, panelGroup.group, null));
expect(params).toEqual({ dashboard: 'metrics.yml' });
});
});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment