Query History: Add feature tracking for query history (#49685)

* Add feature tracking for query history

* Fix unit tests

* Update event names
This commit is contained in:
Piotr Jamróz 2022-05-26 16:04:10 +02:00 committed by GitHub
parent c6ac9410b2
commit e0adb41e80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 8 deletions

View File

@ -18,6 +18,11 @@ const mockDS = mockDataSource({
type: DataSourceType.Alertmanager, type: DataSourceType.Alertmanager,
}); });
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
reportInteraction: jest.fn(),
}));
jest.mock('@grafana/runtime/src/services/dataSourceSrv', () => { jest.mock('@grafana/runtime/src/services/dataSourceSrv', () => {
return { return {
getDataSourceSrv: () => ({ getDataSourceSrv: () => ({

View File

@ -3,7 +3,7 @@ import React, { useState, useEffect } from 'react';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { GrafanaTheme, DataSourceApi, DataQuery } from '@grafana/data'; import { GrafanaTheme, DataSourceApi, DataQuery } from '@grafana/data';
import { getDataSourceSrv } from '@grafana/runtime'; import { config, getDataSourceSrv, reportInteraction } from '@grafana/runtime';
import { stylesFactory, useTheme, TextArea, Button, IconButton } from '@grafana/ui'; import { stylesFactory, useTheme, TextArea, Button, IconButton } from '@grafana/ui';
import { notifyApp } from 'app/core/actions'; import { notifyApp } from 'app/core/actions';
import appEvents from 'app/core/app_events'; import appEvents from 'app/core/app_events';
@ -176,12 +176,17 @@ export function RichHistoryCard(props: Props) {
const onRunQuery = async () => { const onRunQuery = async () => {
const queriesToRun = query.queries; const queriesToRun = query.queries;
if (query.datasourceName !== datasourceInstance?.name) { const differentDataSource = query.datasourceName !== datasourceInstance?.name;
if (differentDataSource) {
await changeDatasource(exploreId, query.datasourceName, { importQueries: true }); await changeDatasource(exploreId, query.datasourceName, { importQueries: true });
setQueries(exploreId, queriesToRun); setQueries(exploreId, queriesToRun);
} else { } else {
setQueries(exploreId, queriesToRun); setQueries(exploreId, queriesToRun);
} }
reportInteraction('grafana_explore_query_history_run', {
queryHistoryEnabled: config.queryHistoryEnabled,
differentDataSource,
});
}; };
const onCopyQuery = () => { const onCopyQuery = () => {
@ -196,6 +201,14 @@ export function RichHistoryCard(props: Props) {
}; };
const onDeleteQuery = () => { const onDeleteQuery = () => {
const performDelete = (queryId: string) => {
deleteHistoryItem(queryId);
dispatch(notifyApp(createSuccessNotification('Query deleted')));
reportInteraction('grafana_explore_query_history_deleted', {
queryHistoryEnabled: config.queryHistoryEnabled,
});
};
// For starred queries, we want confirmation. For non-starred, we don't. // For starred queries, we want confirmation. For non-starred, we don't.
if (query.starred) { if (query.starred) {
appEvents.publish( appEvents.publish(
@ -204,20 +217,20 @@ export function RichHistoryCard(props: Props) {
text: 'Are you sure you want to permanently delete your starred query?', text: 'Are you sure you want to permanently delete your starred query?',
yesText: 'Delete', yesText: 'Delete',
icon: 'trash-alt', icon: 'trash-alt',
onConfirm: () => { onConfirm: () => performDelete(query.id),
deleteHistoryItem(query.id);
dispatch(notifyApp(createSuccessNotification('Query deleted')));
},
}) })
); );
} else { } else {
deleteHistoryItem(query.id); performDelete(query.id);
dispatch(notifyApp(createSuccessNotification('Query deleted')));
} }
}; };
const onStarrQuery = () => { const onStarrQuery = () => {
starHistoryItem(query.id, !query.starred); starHistoryItem(query.id, !query.starred);
reportInteraction('grafana_explore_query_history_starred', {
queryHistoryEnabled: config.queryHistoryEnabled,
newValue: !query.starred,
});
}; };
const toggleActiveUpdateComment = () => setActiveUpdateComment(!activeUpdateComment); const toggleActiveUpdateComment = () => setActiveUpdateComment(!activeUpdateComment);
@ -225,6 +238,9 @@ export function RichHistoryCard(props: Props) {
const onUpdateComment = () => { const onUpdateComment = () => {
commentHistoryItem(query.id, comment); commentHistoryItem(query.id, comment);
setActiveUpdateComment(false); setActiveUpdateComment(false);
reportInteraction('grafana_explore_query_history_commented', {
queryHistoryEnabled: config.queryHistoryEnabled,
});
}; };
const onCancelUpdateComment = () => { const onCancelUpdateComment = () => {

View File

@ -17,6 +17,7 @@ jest.mock('@grafana/runtime', () => ({
getList: () => [], getList: () => [],
}; };
}, },
reportInteraction: jest.fn(),
})); }));
const setup = (propOverrides?: Partial<Props>) => { const setup = (propOverrides?: Partial<Props>) => {

View File

@ -2,6 +2,7 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { config, reportInteraction } from '@grafana/runtime';
import { useTheme2 } from '@grafana/ui'; import { useTheme2 } from '@grafana/ui';
// Types // Types
import { ExploreItemState, StoreState } from 'app/types'; import { ExploreItemState, StoreState } from 'app/types';
@ -86,6 +87,9 @@ export function RichHistoryContainer(props: Props) {
useEffect(() => { useEffect(() => {
initRichHistory(); initRichHistory();
reportInteraction('grafana_explore_query_history_opened', {
queryHistoryEnabled: config.queryHistoryEnabled,
});
}, [initRichHistory]); }, [initRichHistory]);
if (!richHistorySettings) { if (!richHistorySettings) {

View File

@ -40,9 +40,13 @@ import {
const fetchMock = jest.fn(); const fetchMock = jest.fn();
const postMock = jest.fn(); const postMock = jest.fn();
const getMock = jest.fn(); const getMock = jest.fn();
const reportInteractionMock = jest.fn();
jest.mock('@grafana/runtime', () => ({ jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'), ...jest.requireActual('@grafana/runtime'),
getBackendSrv: () => ({ fetch: fetchMock, post: postMock, get: getMock }), getBackendSrv: () => ({ fetch: fetchMock, post: postMock, get: getMock }),
reportInteraction: (...args: object[]) => {
reportInteractionMock(...args);
},
})); }));
jest.mock('app/core/core', () => ({ jest.mock('app/core/core', () => ({
@ -84,6 +88,7 @@ describe('Explore: Query History', () => {
fetchMock.mockClear(); fetchMock.mockClear();
postMock.mockClear(); postMock.mockClear();
getMock.mockClear(); getMock.mockClear();
reportInteractionMock.mockClear();
tearDown(); tearDown();
}); });
@ -109,6 +114,11 @@ describe('Explore: Query History', () => {
// previously added query is in query history // previously added query is in query history
await openQueryHistory(); await openQueryHistory();
await assertQueryHistoryExists(RAW_QUERY); await assertQueryHistoryExists(RAW_QUERY);
expect(reportInteractionMock).toBeCalledTimes(2);
expect(reportInteractionMock).toBeCalledWith('grafana_explore_query_history_opened', {
queryHistoryEnabled: false,
});
}); });
it('adds recently added query if the query history panel is already open', async () => { it('adds recently added query if the query history panel is already open', async () => {
@ -159,10 +169,17 @@ describe('Explore: Query History', () => {
starQueryHistory(1, ExploreId.left); starQueryHistory(1, ExploreId.left);
await assertQueryHistoryIsStarred([false, true], ExploreId.left); await assertQueryHistoryIsStarred([false, true], ExploreId.left);
await assertQueryHistoryIsStarred([false, true], ExploreId.right); await assertQueryHistoryIsStarred([false, true], ExploreId.right);
expect(reportInteractionMock).toBeCalledWith('grafana_explore_query_history_starred', {
queryHistoryEnabled: false,
newValue: true,
});
deleteQueryHistory(0, ExploreId.left); deleteQueryHistory(0, ExploreId.left);
await assertQueryHistory(['{"expr":"query #1"}'], ExploreId.left); await assertQueryHistory(['{"expr":"query #1"}'], ExploreId.left);
await assertQueryHistory(['{"expr":"query #1"}'], ExploreId.right); await assertQueryHistory(['{"expr":"query #1"}'], ExploreId.right);
expect(reportInteractionMock).toBeCalledWith('grafana_explore_query_history_deleted', {
queryHistoryEnabled: false,
});
}); });
it('updates query history settings', async () => { it('updates query history settings', async () => {
@ -198,6 +215,9 @@ describe('Explore: Query History', () => {
await openQueryHistory(); await openQueryHistory();
expect(postMock).not.toBeCalledWith('/api/query-history/migrate', { queries: [] }); expect(postMock).not.toBeCalledWith('/api/query-history/migrate', { queries: [] });
expect(reportInteractionMock).toBeCalledWith('grafana_explore_query_history_opened', {
queryHistoryEnabled: false,
});
}); });
it('migrates query history from local storage', async () => { it('migrates query history from local storage', async () => {
@ -225,6 +245,9 @@ describe('Explore: Query History', () => {
url: expect.stringMatching('/api/query-history/migrate'), url: expect.stringMatching('/api/query-history/migrate'),
}) })
); );
expect(reportInteractionMock).toBeCalledWith('grafana_explore_query_history_opened', {
queryHistoryEnabled: true,
});
}); });
}); });