mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge pull request #13540 from grafana/davkal/explore-compact-url-state
Explore: compact state URLs
This commit is contained in:
commit
352961b3d7
@ -36,14 +36,40 @@ describe('state functions', () => {
|
|||||||
range: DEFAULT_RANGE,
|
range: DEFAULT_RANGE,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns a valid Explore state from URL parameter', () => {
|
||||||
|
const paramValue =
|
||||||
|
'%7B"datasource":"Local","queries":%5B%7B"query":"metric"%7D%5D,"range":%7B"from":"now-1h","to":"now"%7D%7D';
|
||||||
|
expect(parseUrlState(paramValue)).toMatchObject({
|
||||||
|
datasource: 'Local',
|
||||||
|
queries: [{ query: 'metric' }],
|
||||||
|
range: {
|
||||||
|
from: 'now-1h',
|
||||||
|
to: 'now',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns a valid Explore state from a compact URL parameter', () => {
|
||||||
|
const paramValue = '%5B"now-1h","now","Local","metric"%5D';
|
||||||
|
expect(parseUrlState(paramValue)).toMatchObject({
|
||||||
|
datasource: 'Local',
|
||||||
|
queries: [{ query: 'metric' }],
|
||||||
|
range: {
|
||||||
|
from: 'now-1h',
|
||||||
|
to: 'now',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('serializeStateToUrlParam', () => {
|
describe('serializeStateToUrlParam', () => {
|
||||||
it('returns url parameter value for a state object', () => {
|
it('returns url parameter value for a state object', () => {
|
||||||
const state = {
|
const state = {
|
||||||
...DEFAULT_EXPLORE_STATE,
|
...DEFAULT_EXPLORE_STATE,
|
||||||
datasourceName: 'foo',
|
datasourceName: 'foo',
|
||||||
range: {
|
range: {
|
||||||
from: 'now - 5h',
|
from: 'now-5h',
|
||||||
to: 'now',
|
to: 'now',
|
||||||
},
|
},
|
||||||
queries: [
|
queries: [
|
||||||
@ -57,10 +83,33 @@ describe('state functions', () => {
|
|||||||
};
|
};
|
||||||
expect(serializeStateToUrlParam(state)).toBe(
|
expect(serializeStateToUrlParam(state)).toBe(
|
||||||
'{"datasource":"foo","queries":[{"query":"metric{test=\\"a/b\\"}"},' +
|
'{"datasource":"foo","queries":[{"query":"metric{test=\\"a/b\\"}"},' +
|
||||||
'{"query":"super{foo=\\"x/z\\"}"}],"range":{"from":"now - 5h","to":"now"}}'
|
'{"query":"super{foo=\\"x/z\\"}"}],"range":{"from":"now-5h","to":"now"}}'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns url parameter value for a state object', () => {
|
||||||
|
const state = {
|
||||||
|
...DEFAULT_EXPLORE_STATE,
|
||||||
|
datasourceName: 'foo',
|
||||||
|
range: {
|
||||||
|
from: 'now-5h',
|
||||||
|
to: 'now',
|
||||||
|
},
|
||||||
|
queries: [
|
||||||
|
{
|
||||||
|
query: 'metric{test="a/b"}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: 'super{foo="x/z"}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
expect(serializeStateToUrlParam(state, true)).toBe(
|
||||||
|
'["now-5h","now","foo","metric{test=\\"a/b\\"}","super{foo=\\"x/z\\"}"]'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('interplay', () => {
|
describe('interplay', () => {
|
||||||
it('can parse the serialized state into the original state', () => {
|
it('can parse the serialized state into the original state', () => {
|
||||||
const state = {
|
const state = {
|
||||||
|
@ -60,7 +60,20 @@ export async function getExploreUrl(
|
|||||||
export function parseUrlState(initial: string | undefined): ExploreUrlState {
|
export function parseUrlState(initial: string | undefined): ExploreUrlState {
|
||||||
if (initial) {
|
if (initial) {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(decodeURI(initial));
|
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];
|
||||||
|
const queries = parsed.slice(3).map(query => ({ query }));
|
||||||
|
return { datasource, queries, range };
|
||||||
|
}
|
||||||
|
return parsed;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
@ -68,11 +81,19 @@ export function parseUrlState(initial: string | undefined): ExploreUrlState {
|
|||||||
return { datasource: null, queries: [], range: DEFAULT_RANGE };
|
return { datasource: null, queries: [], range: DEFAULT_RANGE };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function serializeStateToUrlParam(state: ExploreState): string {
|
export function serializeStateToUrlParam(state: ExploreState, compact?: boolean): string {
|
||||||
const urlState: ExploreUrlState = {
|
const urlState: ExploreUrlState = {
|
||||||
datasource: state.datasourceName,
|
datasource: state.datasourceName,
|
||||||
queries: state.queries.map(q => ({ query: q.query })),
|
queries: state.queries.map(q => ({ query: q.query })),
|
||||||
range: state.range,
|
range: state.range,
|
||||||
};
|
};
|
||||||
|
if (compact) {
|
||||||
|
return JSON.stringify([
|
||||||
|
urlState.range.from,
|
||||||
|
urlState.range.to,
|
||||||
|
urlState.datasource,
|
||||||
|
...urlState.queries.map(q => q.query),
|
||||||
|
]);
|
||||||
|
}
|
||||||
return JSON.stringify(urlState);
|
return JSON.stringify(urlState);
|
||||||
}
|
}
|
||||||
|
@ -275,7 +275,6 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
const { onChangeSplit } = this.props;
|
const { onChangeSplit } = this.props;
|
||||||
if (onChangeSplit) {
|
if (onChangeSplit) {
|
||||||
onChangeSplit(false);
|
onChangeSplit(false);
|
||||||
this.saveState();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -292,7 +291,6 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
if (onChangeSplit) {
|
if (onChangeSplit) {
|
||||||
const state = this.cloneState();
|
const state = this.cloneState();
|
||||||
onChangeSplit(true, state);
|
onChangeSplit(true, state);
|
||||||
this.saveState();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,10 +38,17 @@ export class Wrapper extends Component<WrapperProps, WrapperState> {
|
|||||||
|
|
||||||
onChangeSplit = (split: boolean, splitState: ExploreState) => {
|
onChangeSplit = (split: boolean, splitState: ExploreState) => {
|
||||||
this.setState({ split, splitState });
|
this.setState({ split, splitState });
|
||||||
|
// When closing split, remove URL state for split part
|
||||||
|
if (!split) {
|
||||||
|
delete this.urlStates[STATE_KEY_RIGHT];
|
||||||
|
this.props.updateLocation({
|
||||||
|
query: this.urlStates,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onSaveState = (key: string, state: ExploreState) => {
|
onSaveState = (key: string, state: ExploreState) => {
|
||||||
const urlState = serializeStateToUrlParam(state);
|
const urlState = serializeStateToUrlParam(state, true);
|
||||||
this.urlStates[key] = urlState;
|
this.urlStates[key] = urlState;
|
||||||
this.props.updateLocation({
|
this.props.updateLocation({
|
||||||
query: this.urlStates,
|
query: this.urlStates,
|
||||||
|
Loading…
Reference in New Issue
Block a user