mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
This reverts commit a9cc3225ba
.
Co-authored-by: Elfo404 <me@giordanoricci.com>
This commit is contained in:
parent
f1834163ec
commit
dfa538ff92
@ -196,11 +196,15 @@ export const urlUtil = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an string that is used in URL to represent the Explore state. This is stringified json
|
* Create an string that is used in URL to represent the Explore state. This is basically just a stringified json
|
||||||
* that is used as a state of a single Explore pane - it does not represent full Explore URL.
|
* that is that used as a state of a single Explore pane so it does not represent full Explore URL.
|
||||||
*
|
*
|
||||||
* @param urlState
|
* @param urlState
|
||||||
|
* @param compact this parameter is deprecated and will be removed in a future release.
|
||||||
*/
|
*/
|
||||||
export function serializeStateToUrlParam(urlState: ExploreUrlState): string {
|
export function serializeStateToUrlParam(urlState: ExploreUrlState, compact?: boolean): string {
|
||||||
|
if (compact !== undefined) {
|
||||||
|
console.warn('`compact` parameter is deprecated and will be removed in a future release');
|
||||||
|
}
|
||||||
return JSON.stringify(urlState);
|
return JSON.stringify(urlState);
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,45 @@ describe('state functions', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns a valid Explore state from a compact URL parameter', () => {
|
||||||
|
const paramValue = '["now-1h","now","Local",{"expr":"metric"},{"ui":[true,true,true,"none"]}]';
|
||||||
|
expect(parseUrlState(paramValue)).toMatchObject({
|
||||||
|
datasource: 'Local',
|
||||||
|
queries: [{ expr: 'metric' }],
|
||||||
|
range: {
|
||||||
|
from: 'now-1h',
|
||||||
|
to: 'now',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not return a query for mode in the url', () => {
|
||||||
|
// Previous versions of Grafana included "Explore mode" in the URL; this should not be treated as a query.
|
||||||
|
const paramValue =
|
||||||
|
'["now-1h","now","x-ray-datasource",{"queryType":"getTraceSummaries"},{"mode":"Metrics"},{"ui":[true,true,true,"none"]}]';
|
||||||
|
expect(parseUrlState(paramValue)).toMatchObject({
|
||||||
|
datasource: 'x-ray-datasource',
|
||||||
|
queries: [{ queryType: 'getTraceSummaries' }],
|
||||||
|
range: {
|
||||||
|
from: 'now-1h',
|
||||||
|
to: 'now',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return queries if queryType is present in the url', () => {
|
||||||
|
const paramValue =
|
||||||
|
'["now-1h","now","x-ray-datasource",{"queryType":"getTraceSummaries"},{"ui":[true,true,true,"none"]}]';
|
||||||
|
expect(parseUrlState(paramValue)).toMatchObject({
|
||||||
|
datasource: 'x-ray-datasource',
|
||||||
|
queries: [{ queryType: 'getTraceSummaries' }],
|
||||||
|
range: {
|
||||||
|
from: 'now-1h',
|
||||||
|
to: 'now',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('serializeStateToUrlParam', () => {
|
describe('serializeStateToUrlParam', () => {
|
||||||
|
@ -165,6 +165,16 @@ export function buildQueryTransaction(
|
|||||||
|
|
||||||
export const clearQueryKeys: (query: DataQuery) => DataQuery = ({ key, ...rest }) => rest;
|
export const clearQueryKeys: (query: DataQuery) => DataQuery = ({ key, ...rest }) => rest;
|
||||||
|
|
||||||
|
const isSegment = (segment: { [key: string]: string }, ...props: string[]) =>
|
||||||
|
props.some((prop) => segment.hasOwnProperty(prop));
|
||||||
|
|
||||||
|
enum ParseUrlStateIndex {
|
||||||
|
RangeFrom = 0,
|
||||||
|
RangeTo = 1,
|
||||||
|
Datasource = 2,
|
||||||
|
SegmentsStart = 3,
|
||||||
|
}
|
||||||
|
|
||||||
export const safeParseJson = (text?: string): any | undefined => {
|
export const safeParseJson = (text?: string): any | undefined => {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return;
|
return;
|
||||||
@ -219,7 +229,25 @@ export function parseUrlState(initial: string | undefined): ExploreUrlState {
|
|||||||
return errorResult;
|
return errorResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(parsed)) {
|
||||||
return parsed;
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsed.length <= ParseUrlStateIndex.SegmentsStart) {
|
||||||
|
console.error('Error parsing compact URL state for Explore.');
|
||||||
|
return errorResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) => !isSegment(segment, 'ui', 'mode', '__panelsState'));
|
||||||
|
|
||||||
|
const panelsState = parsedSegments.find((segment) => isSegment(segment, '__panelsState'))?.__panelsState;
|
||||||
|
return { datasource, queries, range, panelsState };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateKey(index = 0): string {
|
export function generateKey(index = 0): string {
|
||||||
|
@ -12,40 +12,6 @@ import { splitOpen } from './state/main';
|
|||||||
|
|
||||||
type Mock = jest.Mock;
|
type Mock = jest.Mock;
|
||||||
|
|
||||||
type overrideParamsType = {
|
|
||||||
datasource?: string;
|
|
||||||
exprValue?: string;
|
|
||||||
rightDatasource?: string;
|
|
||||||
rightExprValue?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const defaultUrlParams = ({
|
|
||||||
datasource = 'loki',
|
|
||||||
exprValue = '{label="value"}',
|
|
||||||
rightDatasource,
|
|
||||||
rightExprValue,
|
|
||||||
}: overrideParamsType) => {
|
|
||||||
type urlParamsType = { left: string; right?: string };
|
|
||||||
|
|
||||||
const urlParams: urlParamsType = {
|
|
||||||
left: serializeStateToUrlParam({
|
|
||||||
datasource: datasource,
|
|
||||||
queries: [{ refId: 'A', expr: exprValue }],
|
|
||||||
range: { from: 'now-1h', to: 'now' },
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (rightDatasource) {
|
|
||||||
urlParams.right = serializeStateToUrlParam({
|
|
||||||
datasource: rightDatasource,
|
|
||||||
queries: [{ refId: 'A', expr: rightExprValue ? rightExprValue : exprValue }],
|
|
||||||
range: { from: 'now-1h', to: 'now' },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return urlParams;
|
|
||||||
};
|
|
||||||
|
|
||||||
jest.mock('app/core/core', () => {
|
jest.mock('app/core/core', () => {
|
||||||
return {
|
return {
|
||||||
contextSrv: {
|
contextSrv: {
|
||||||
@ -96,7 +62,13 @@ describe('Wrapper', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('runs query when url contains query and renders results', async () => {
|
it('runs query when url contains query and renders results', async () => {
|
||||||
const urlParams = defaultUrlParams({});
|
const urlParams = {
|
||||||
|
left: serializeStateToUrlParam({
|
||||||
|
datasource: 'loki',
|
||||||
|
queries: [{ refId: 'A', expr: '{ label="value"}' }],
|
||||||
|
range: { from: 'now-1h', to: 'now' },
|
||||||
|
}),
|
||||||
|
};
|
||||||
const { datasources } = setupExplore({ urlParams });
|
const { datasources } = setupExplore({ urlParams });
|
||||||
(datasources.loki.query as Mock).mockReturnValueOnce(makeLogsQueryResponse());
|
(datasources.loki.query as Mock).mockReturnValueOnce(makeLogsQueryResponse());
|
||||||
|
|
||||||
@ -107,7 +79,7 @@ describe('Wrapper', () => {
|
|||||||
await screen.findByText(/custom log line/i);
|
await screen.findByText(/custom log line/i);
|
||||||
|
|
||||||
// And that the editor gets the expr from the url
|
// And that the editor gets the expr from the url
|
||||||
await screen.findByText(`loki Editor input: {label="value"}`);
|
await screen.findByText(`loki Editor input: { label="value"}`);
|
||||||
|
|
||||||
// We did not change the url
|
// We did not change the url
|
||||||
expect(locationService.getSearchObject()).toEqual({
|
expect(locationService.getSearchObject()).toEqual({
|
||||||
@ -118,12 +90,12 @@ describe('Wrapper', () => {
|
|||||||
// We called the data source query method once
|
// We called the data source query method once
|
||||||
expect(datasources.loki.query).toBeCalledTimes(1);
|
expect(datasources.loki.query).toBeCalledTimes(1);
|
||||||
expect((datasources.loki.query as Mock).mock.calls[0][0]).toMatchObject({
|
expect((datasources.loki.query as Mock).mock.calls[0][0]).toMatchObject({
|
||||||
targets: [{ expr: '{label="value"}' }],
|
targets: [{ expr: '{ label="value"}' }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles url change and runs the new query', async () => {
|
it('handles url change and runs the new query', async () => {
|
||||||
const urlParams = defaultUrlParams({});
|
const urlParams = { left: JSON.stringify(['now-1h', 'now', 'loki', { expr: '{ label="value"}' }]) };
|
||||||
const { datasources } = setupExplore({ urlParams });
|
const { datasources } = setupExplore({ urlParams });
|
||||||
(datasources.loki.query as Mock).mockReturnValueOnce(makeLogsQueryResponse());
|
(datasources.loki.query as Mock).mockReturnValueOnce(makeLogsQueryResponse());
|
||||||
// Wait for rendering the logs
|
// Wait for rendering the logs
|
||||||
@ -131,25 +103,29 @@ describe('Wrapper', () => {
|
|||||||
|
|
||||||
(datasources.loki.query as Mock).mockReturnValueOnce(makeLogsQueryResponse('different log'));
|
(datasources.loki.query as Mock).mockReturnValueOnce(makeLogsQueryResponse('different log'));
|
||||||
|
|
||||||
locationService.partial(defaultUrlParams({ exprValue: '{label="different"}' }));
|
locationService.partial({
|
||||||
|
left: JSON.stringify(['now-1h', 'now', 'loki', { expr: '{ label="different"}' }]),
|
||||||
|
});
|
||||||
|
|
||||||
// Editor renders the new query
|
// Editor renders the new query
|
||||||
await screen.findByText(`loki Editor input: {label="different"}`);
|
await screen.findByText(`loki Editor input: { label="different"}`);
|
||||||
// Renders new response
|
// Renders new response
|
||||||
await screen.findByText(/different log/i);
|
await screen.findByText(/different log/i);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles url change and runs the new query with different datasource', async () => {
|
it('handles url change and runs the new query with different datasource', async () => {
|
||||||
const urlParams = defaultUrlParams({});
|
const urlParams = { left: JSON.stringify(['now-1h', 'now', 'loki', { expr: '{ label="value"}' }]) };
|
||||||
const { datasources } = setupExplore({ urlParams });
|
const { datasources } = setupExplore({ urlParams });
|
||||||
(datasources.loki.query as Mock).mockReturnValueOnce(makeLogsQueryResponse());
|
(datasources.loki.query as Mock).mockReturnValueOnce(makeLogsQueryResponse());
|
||||||
// Wait for rendering the logs
|
// Wait for rendering the logs
|
||||||
await screen.findByText(/custom log line/i);
|
await screen.findByText(/custom log line/i);
|
||||||
await screen.findByText(`loki Editor input: {label="value"}`);
|
await screen.findByText(`loki Editor input: { label="value"}`);
|
||||||
|
|
||||||
(datasources.elastic.query as Mock).mockReturnValueOnce(makeMetricsQueryResponse());
|
(datasources.elastic.query as Mock).mockReturnValueOnce(makeMetricsQueryResponse());
|
||||||
|
|
||||||
locationService.partial(defaultUrlParams({ datasource: 'elastic', exprValue: 'other query' }));
|
locationService.partial({
|
||||||
|
left: JSON.stringify(['now-1h', 'now', 'elastic', { expr: 'other query' }]),
|
||||||
|
});
|
||||||
|
|
||||||
// Editor renders the new query
|
// Editor renders the new query
|
||||||
await screen.findByText(`elastic Editor input: other query`);
|
await screen.findByText(`elastic Editor input: other query`);
|
||||||
@ -158,7 +134,7 @@ describe('Wrapper', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('handles changing the datasource manually', async () => {
|
it('handles changing the datasource manually', async () => {
|
||||||
const urlParams = defaultUrlParams({});
|
const urlParams = { left: JSON.stringify(['now-1h', 'now', 'loki', { expr: '{ label="value"}', refId: 'A' }]) };
|
||||||
const { datasources } = setupExplore({ urlParams });
|
const { datasources } = setupExplore({ urlParams });
|
||||||
(datasources.loki.query as Mock).mockReturnValueOnce(makeLogsQueryResponse());
|
(datasources.loki.query as Mock).mockReturnValueOnce(makeLogsQueryResponse());
|
||||||
await waitForExplore();
|
await waitForExplore();
|
||||||
@ -188,7 +164,18 @@ describe('Wrapper', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('inits with two panes if specified in url', async () => {
|
it('inits with two panes if specified in url', async () => {
|
||||||
const urlParams = defaultUrlParams({ rightDatasource: 'elastic', rightExprValue: 'error' });
|
const urlParams = {
|
||||||
|
left: serializeStateToUrlParam({
|
||||||
|
datasource: 'loki',
|
||||||
|
queries: [{ refId: 'A', expr: '{ label="value"}' }],
|
||||||
|
range: { from: 'now-1h', to: 'now' },
|
||||||
|
}),
|
||||||
|
right: serializeStateToUrlParam({
|
||||||
|
datasource: 'elastic',
|
||||||
|
queries: [{ refId: 'A', expr: 'error' }],
|
||||||
|
range: { from: 'now-1h', to: 'now' },
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
const { datasources } = setupExplore({ urlParams });
|
const { datasources } = setupExplore({ urlParams });
|
||||||
(datasources.loki.query as Mock).mockReturnValueOnce(makeLogsQueryResponse());
|
(datasources.loki.query as Mock).mockReturnValueOnce(makeLogsQueryResponse());
|
||||||
@ -205,7 +192,7 @@ describe('Wrapper', () => {
|
|||||||
expect(logsLines.length).toBe(2);
|
expect(logsLines.length).toBe(2);
|
||||||
|
|
||||||
// And that the editor gets the expr from the url
|
// And that the editor gets the expr from the url
|
||||||
await screen.findByText(`loki Editor input: {label="value"}`);
|
await screen.findByText(`loki Editor input: { label="value"}`);
|
||||||
await screen.findByText(`elastic Editor input: error`);
|
await screen.findByText(`elastic Editor input: error`);
|
||||||
|
|
||||||
// We did not change the url
|
// We did not change the url
|
||||||
@ -217,7 +204,7 @@ describe('Wrapper', () => {
|
|||||||
// We called the data source query method once
|
// We called the data source query method once
|
||||||
expect(datasources.loki.query).toBeCalledTimes(1);
|
expect(datasources.loki.query).toBeCalledTimes(1);
|
||||||
expect((datasources.loki.query as Mock).mock.calls[0][0]).toMatchObject({
|
expect((datasources.loki.query as Mock).mock.calls[0][0]).toMatchObject({
|
||||||
targets: [{ expr: '{label="value"}' }],
|
targets: [{ expr: '{ label="value"}' }],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(datasources.elastic.query).toBeCalledTimes(1);
|
expect(datasources.elastic.query).toBeCalledTimes(1);
|
||||||
@ -227,11 +214,11 @@ describe('Wrapper', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('can close a pane from a split', async () => {
|
it('can close a pane from a split', async () => {
|
||||||
const urlParams = defaultUrlParams({ rightDatasource: 'elastic' });
|
const urlParams = {
|
||||||
const { datasources } = setupExplore({ urlParams });
|
left: JSON.stringify(['now-1h', 'now', 'loki', { refId: 'A' }]),
|
||||||
(datasources.loki.query as Mock).mockReturnValueOnce(makeLogsQueryResponse());
|
right: JSON.stringify(['now-1h', 'now', 'elastic', { refId: 'A' }]),
|
||||||
(datasources.elastic.query as Mock).mockReturnValueOnce(makeLogsQueryResponse());
|
};
|
||||||
|
setupExplore({ urlParams });
|
||||||
const closeButtons = await screen.findAllByTitle(/Close split pane/i);
|
const closeButtons = await screen.findAllByTitle(/Close split pane/i);
|
||||||
await userEvent.click(closeButtons[1]);
|
await userEvent.click(closeButtons[1]);
|
||||||
|
|
||||||
@ -242,55 +229,65 @@ describe('Wrapper', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('handles url change to split view', async () => {
|
it('handles url change to split view', async () => {
|
||||||
const urlParams = defaultUrlParams({});
|
const urlParams = {
|
||||||
|
left: JSON.stringify(['now-1h', 'now', 'loki', { expr: '{ label="value"}' }]),
|
||||||
|
};
|
||||||
const { datasources } = setupExplore({ urlParams });
|
const { datasources } = setupExplore({ urlParams });
|
||||||
(datasources.loki.query as Mock).mockReturnValue(makeLogsQueryResponse());
|
(datasources.loki.query as Mock).mockReturnValue(makeLogsQueryResponse());
|
||||||
(datasources.elastic.query as Mock).mockReturnValue(makeLogsQueryResponse());
|
(datasources.elastic.query as Mock).mockReturnValue(makeLogsQueryResponse());
|
||||||
|
|
||||||
locationService.partial(defaultUrlParams({ rightDatasource: 'elastic', rightExprValue: 'error' }));
|
locationService.partial({
|
||||||
|
left: JSON.stringify(['now-1h', 'now', 'loki', { expr: '{ label="value"}' }]),
|
||||||
|
right: JSON.stringify(['now-1h', 'now', 'elastic', { expr: 'error' }]),
|
||||||
|
});
|
||||||
|
|
||||||
// Editor renders the new query
|
// Editor renders the new query
|
||||||
await screen.findByText(`loki Editor input: {label="value"}`);
|
await screen.findByText(`loki Editor input: { label="value"}`);
|
||||||
await screen.findByText(`elastic Editor input: error`);
|
await screen.findByText(`elastic Editor input: error`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles opening split with split open func', async () => {
|
it('handles opening split with split open func', async () => {
|
||||||
const urlParams = defaultUrlParams({});
|
const urlParams = {
|
||||||
|
left: JSON.stringify(['now-1h', 'now', 'loki', { expr: '{ label="value"}' }]),
|
||||||
|
};
|
||||||
const { datasources, store } = setupExplore({ urlParams });
|
const { datasources, store } = setupExplore({ urlParams });
|
||||||
(datasources.loki.query as Mock).mockReturnValue(makeLogsQueryResponse());
|
(datasources.loki.query as Mock).mockReturnValue(makeLogsQueryResponse());
|
||||||
(datasources.elastic.query as Mock).mockReturnValue(makeLogsQueryResponse());
|
(datasources.elastic.query as Mock).mockReturnValue(makeLogsQueryResponse());
|
||||||
|
|
||||||
// This is mainly to wait for render so that the left pane state is initialized as that is needed for splitOpen
|
// This is mainly to wait for render so that the left pane state is initialized as that is needed for splitOpen
|
||||||
// to work
|
// to work
|
||||||
await screen.findByText(`loki Editor input: {label="value"}`);
|
await screen.findByText(`loki Editor input: { label="value"}`);
|
||||||
|
|
||||||
store.dispatch(splitOpen<any>({ datasourceUid: 'elastic', query: { expr: 'error' } }) as any);
|
store.dispatch(splitOpen<any>({ datasourceUid: 'elastic', query: { expr: 'error' } }) as any);
|
||||||
|
|
||||||
// Editor renders the new query
|
// Editor renders the new query
|
||||||
await screen.findByText(`elastic Editor input: error`);
|
await screen.findByText(`elastic Editor input: error`);
|
||||||
await screen.findByText(`loki Editor input: {label="value"}`);
|
await screen.findByText(`loki Editor input: { label="value"}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('changes the document title of the explore page to include the datasource in use', async () => {
|
it('changes the document title of the explore page to include the datasource in use', async () => {
|
||||||
const urlParams = defaultUrlParams({});
|
const urlParams = {
|
||||||
|
left: JSON.stringify(['now-1h', 'now', 'loki', { expr: '{ label="value"}' }]),
|
||||||
|
};
|
||||||
const { datasources } = setupExplore({ urlParams });
|
const { datasources } = setupExplore({ urlParams });
|
||||||
(datasources.loki.query as Mock).mockReturnValue(makeLogsQueryResponse());
|
(datasources.loki.query as Mock).mockReturnValue(makeLogsQueryResponse());
|
||||||
// This is mainly to wait for render so that the left pane state is initialized as that is needed for the title
|
// This is mainly to wait for render so that the left pane state is initialized as that is needed for the title
|
||||||
// to include the datasource
|
// to include the datasource
|
||||||
await screen.findByText(`loki Editor input: {label="value"}`);
|
await screen.findByText(`loki Editor input: { label="value"}`);
|
||||||
|
|
||||||
await waitFor(() => expect(document.title).toEqual('Explore - loki - Grafana'));
|
await waitFor(() => expect(document.title).toEqual('Explore - loki - Grafana'));
|
||||||
});
|
});
|
||||||
it('changes the document title to include the two datasources in use in split view mode', async () => {
|
it('changes the document title to include the two datasources in use in split view mode', async () => {
|
||||||
const urlParams = defaultUrlParams({});
|
const urlParams = {
|
||||||
|
left: JSON.stringify(['now-1h', 'now', 'loki', { expr: '{ label="value"}' }]),
|
||||||
|
};
|
||||||
const { datasources, store } = setupExplore({ urlParams });
|
const { datasources, store } = setupExplore({ urlParams });
|
||||||
(datasources.loki.query as Mock).mockReturnValue(makeLogsQueryResponse());
|
(datasources.loki.query as Mock).mockReturnValue(makeLogsQueryResponse());
|
||||||
(datasources.elastic.query as Mock).mockReturnValue(makeLogsQueryResponse());
|
(datasources.elastic.query as Mock).mockReturnValue(makeLogsQueryResponse());
|
||||||
|
|
||||||
// This is mainly to wait for render so that the left pane state is initialized as that is needed for splitOpen
|
// This is mainly to wait for render so that the left pane state is initialized as that is needed for splitOpen
|
||||||
// to work
|
// to work
|
||||||
await screen.findByText(`loki Editor input: {label="value"}`);
|
await screen.findByText(`loki Editor input: { label="value"}`);
|
||||||
|
|
||||||
store.dispatch(splitOpen<any>({ datasourceUid: 'elastic', query: { expr: 'error' } }) as any);
|
store.dispatch(splitOpen<any>({ datasourceUid: 'elastic', query: { expr: 'error' } }) as any);
|
||||||
await waitFor(() => expect(document.title).toEqual('Explore - loki | elastic - Grafana'));
|
await waitFor(() => expect(document.title).toEqual('Explore - loki | elastic - Grafana'));
|
||||||
|
Loading…
Reference in New Issue
Block a user