diff --git a/public/app/core/utils/explore.ts b/public/app/core/utils/explore.ts index fdc63b931f7..10bb7997664 100644 --- a/public/app/core/utils/explore.ts +++ b/public/app/core/utils/explore.ts @@ -157,49 +157,72 @@ export function buildQueryTransaction( export const clearQueryKeys: (query: DataQuery) => object = ({ key, refId, ...rest }) => rest; -const isMetricSegment = (segment: { [key: string]: string }) => segment.hasOwnProperty('expr'); +const metricProperties = ['expr', 'target', 'datasource']; +const isMetricSegment = (segment: { [key: string]: string }) => + metricProperties.some(prop => segment.hasOwnProperty(prop)); const isUISegment = (segment: { [key: string]: string }) => segment.hasOwnProperty('ui'); +enum ParseUrlStateIndex { + RangeFrom = 0, + RangeTo = 1, + Datasource = 2, + SegmentsStart = 3, +} + +enum ParseUiStateIndex { + Graph = 0, + Logs = 1, + Table = 2, + Strategy = 3, +} + +export const safeParseJson = (text: string) => { + if (!text) { + return; + } + + try { + return JSON.parse(decodeURI(text)); + } catch (error) { + console.error(error); + } +}; + export function parseUrlState(initial: string | undefined): ExploreUrlState { - let uiState = DEFAULT_UI_STATE; - - if (initial) { - try { - const parsed = JSON.parse(decodeURI(initial)); - if (Array.isArray(parsed)) { - if (parsed.length <= 3) { - throw new Error('Error parsing compact URL state for Explore.'); - } - const range = { - from: parsed[0], - to: parsed[1], - }; - const datasource = parsed[2]; - let queries = []; - - parsed.slice(3).forEach(segment => { - if (isMetricSegment(segment)) { - queries = [...queries, segment]; - } - - if (isUISegment(segment)) { - uiState = { - showingGraph: segment.ui[0], - showingLogs: segment.ui[1], - showingTable: segment.ui[2], - dedupStrategy: segment.ui[3], - }; - } - }); - - return { datasource, queries, range, ui: uiState }; - } - return parsed; - } catch (e) { - console.error(e); - } + const parsed = safeParseJson(initial); + const errorResult = { datasource: null, queries: [], range: DEFAULT_RANGE, ui: DEFAULT_UI_STATE }; + + if (!parsed) { + return errorResult; + } + + if (!Array.isArray(parsed)) { + return parsed; + } + + if (parsed.length <= ParseUrlStateIndex.SegmentsStart) { + console.error('Error parsing compact URL state for Explore.'); + return errorResult; } - return { datasource: null, queries: [], range: DEFAULT_RANGE, ui: uiState }; + + const range = { + from: parsed[ParseUrlStateIndex.RangeFrom], + to: parsed[ParseUrlStateIndex.RangeTo], + }; + const datasource = parsed[ParseUrlStateIndex.Datasource]; + const parsedSegments = parsed.slice(ParseUrlStateIndex.SegmentsStart); + const queries = parsedSegments.filter(segment => isMetricSegment(segment)); + const uiState = parsedSegments.filter(segment => isUISegment(segment))[0]; + const ui = uiState + ? { + showingGraph: uiState.ui[ParseUiStateIndex.Graph], + showingLogs: uiState.ui[ParseUiStateIndex.Logs], + showingTable: uiState.ui[ParseUiStateIndex.Table], + dedupStrategy: uiState.ui[ParseUiStateIndex.Strategy], + } + : DEFAULT_UI_STATE; + + return { datasource, queries, range, ui }; } export function serializeStateToUrlParam(urlState: ExploreUrlState, compact?: boolean): string {