mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: log alert rule creation and clicking state filters (#55698)
* Add messages for new trackings * Track clicking on alert state filters * Track creating alert rule from panel * Track creating alert rule from scratch * Track on success and when cancelling a rule creation
This commit is contained in:
parent
09f8e026a1
commit
0d348dc0b1
@ -2,4 +2,9 @@ export const LogMessages = {
|
||||
filterByLabel: 'filtering alert instances by label',
|
||||
loadedList: 'loaded Alert Rules list',
|
||||
leavingRuleGroupEdit: 'leaving rule group edit without saving',
|
||||
alertRuleFromPanel: 'creating alert rule from panel',
|
||||
alertRuleFromScratch: 'creating alert rule from scratch',
|
||||
clickingAlertStateFilters: 'clicking alert state filters',
|
||||
cancelSavingAlertRule: 'user canceled alert rule creation',
|
||||
successSavingAlertRule: 'alert rule saved successfully',
|
||||
};
|
||||
|
@ -1,17 +1,18 @@
|
||||
import { SerializedError } from '@reduxjs/toolkit';
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import { render, waitFor, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { Router } from 'react-router-dom';
|
||||
import { byLabelText, byRole, byTestId, byText } from 'testing-library-selector';
|
||||
|
||||
import { locationService, setDataSourceSrv } from '@grafana/runtime';
|
||||
import { locationService, setDataSourceSrv, logInfo } from '@grafana/runtime';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
import { AccessControlAction } from 'app/types';
|
||||
import { PromAlertingRuleState, PromApplication } from 'app/types/unified-alerting-dto';
|
||||
|
||||
import { LogMessages } from './Analytics';
|
||||
import RuleList from './RuleList';
|
||||
import { discoverFeatures } from './api/buildInfo';
|
||||
import { fetchRules } from './api/prometheus';
|
||||
@ -44,6 +45,13 @@ jest.mock('app/core/core', () => ({
|
||||
emit: () => {},
|
||||
},
|
||||
}));
|
||||
jest.mock('@grafana/runtime', () => {
|
||||
const original = jest.requireActual('@grafana/runtime');
|
||||
return {
|
||||
...original,
|
||||
logInfo: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
jest.spyOn(config, 'getAllDataSources');
|
||||
|
||||
@ -745,4 +753,35 @@ describe('RuleList', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Analytics', () => {
|
||||
it('Sends log info when creating an alert rule from a scratch', async () => {
|
||||
enableRBAC();
|
||||
|
||||
grantUserPermissions([
|
||||
AccessControlAction.FoldersRead,
|
||||
AccessControlAction.AlertingRuleCreate,
|
||||
AccessControlAction.AlertingRuleRead,
|
||||
]);
|
||||
|
||||
mocks.getAllDataSourcesMock.mockReturnValue([]);
|
||||
setDataSourceSrv(new MockDataSourceSrv({}));
|
||||
mocks.api.fetchRules.mockResolvedValue([]);
|
||||
mocks.api.fetchRulerRules.mockResolvedValue({});
|
||||
|
||||
renderRuleList();
|
||||
|
||||
await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalledTimes(1));
|
||||
|
||||
const button = screen.getByText('New alert rule');
|
||||
|
||||
button.addEventListener('click', (event) => event.preventDefault(), false);
|
||||
|
||||
expect(button).toBeEnabled();
|
||||
|
||||
await userEvent.click(button);
|
||||
|
||||
expect(logInfo).toHaveBeenCalledWith(LogMessages.alertRuleFromScratch);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -3,10 +3,12 @@ import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
import { GrafanaTheme2, urlUtil } from '@grafana/data';
|
||||
import { logInfo } from '@grafana/runtime';
|
||||
import { Button, LinkButton, useStyles2, withErrorBoundary } from '@grafana/ui';
|
||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||
import { useDispatch } from 'app/types';
|
||||
|
||||
import { LogMessages } from './Analytics';
|
||||
import { AlertingPageWrapper } from './components/AlertingPageWrapper';
|
||||
import { NoRulesSplash } from './components/rules/NoRulesCTA';
|
||||
import { RuleListErrors } from './components/rules/RuleListErrors';
|
||||
@ -101,6 +103,7 @@ const RuleList = withErrorBoundary(
|
||||
<LinkButton
|
||||
href={urlUtil.renderUrl('alerting/new', { returnTo: location.pathname + location.search })}
|
||||
icon="plus"
|
||||
onClick={() => logInfo(LogMessages.alertRuleFromScratch)}
|
||||
>
|
||||
New alert rule
|
||||
</LinkButton>
|
||||
|
@ -0,0 +1,56 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
|
||||
import { logInfo } from '@grafana/runtime';
|
||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||
|
||||
import { LogMessages } from '../../Analytics';
|
||||
|
||||
import { NewRuleFromPanelButton } from './NewRuleFromPanelButton';
|
||||
|
||||
jest.mock('app/types', () => {
|
||||
const original = jest.requireActual('app/types');
|
||||
return {
|
||||
...original,
|
||||
useSelector: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
useLocation: () => ({
|
||||
pathname: 'localhost:3000/example/path',
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('@grafana/runtime', () => {
|
||||
const original = jest.requireActual('@grafana/runtime');
|
||||
return {
|
||||
...original,
|
||||
logInfo: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('react-use', () => ({
|
||||
useAsync: () => ({ loading: false, value: {} }),
|
||||
}));
|
||||
|
||||
describe('Analytics', () => {
|
||||
it('Sends log info when creating an alert rule from a panel', async () => {
|
||||
const panel = new PanelModel({
|
||||
id: 123,
|
||||
});
|
||||
const dashboard = new DashboardModel({
|
||||
id: 1,
|
||||
});
|
||||
render(<NewRuleFromPanelButton panel={panel} dashboard={dashboard} />);
|
||||
|
||||
const button = screen.getByText('Create alert rule from this panel');
|
||||
|
||||
button.addEventListener('click', (event) => event.preventDefault(), false);
|
||||
|
||||
await userEvent.click(button);
|
||||
|
||||
expect(logInfo).toHaveBeenCalledWith(LogMessages.alertRuleFromPanel);
|
||||
});
|
||||
});
|
@ -3,10 +3,12 @@ import { useLocation } from 'react-router-dom';
|
||||
import { useAsync } from 'react-use';
|
||||
|
||||
import { urlUtil } from '@grafana/data';
|
||||
import { logInfo } from '@grafana/runtime';
|
||||
import { Alert, Button, LinkButton } from '@grafana/ui';
|
||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||
import { useSelector } from 'app/types';
|
||||
|
||||
import { LogMessages } from '../../Analytics';
|
||||
import { panelToRuleFormValues } from '../../utils/rule-form';
|
||||
|
||||
interface Props {
|
||||
@ -46,7 +48,13 @@ export const NewRuleFromPanelButton: FC<Props> = ({ dashboard, panel, className
|
||||
});
|
||||
|
||||
return (
|
||||
<LinkButton icon="bell" href={ruleFormUrl} className={className} data-testid="create-alert-rule-button">
|
||||
<LinkButton
|
||||
icon="bell"
|
||||
onClick={() => logInfo(LogMessages.alertRuleFromPanel)}
|
||||
href={ruleFormUrl}
|
||||
className={className}
|
||||
data-testid="create-alert-rule-button"
|
||||
>
|
||||
Create alert rule from this panel
|
||||
</LinkButton>
|
||||
);
|
||||
|
@ -4,6 +4,7 @@ import { FormProvider, useForm, UseFormWatch } from 'react-hook-form';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { logInfo } from '@grafana/runtime';
|
||||
import { Button, ConfirmModal, CustomScrollbar, PageToolbar, Spinner, useStyles2 } from '@grafana/ui';
|
||||
import { useAppNotification } from 'app/core/copy/appNotification';
|
||||
import { useCleanup } from 'app/core/hooks/useCleanup';
|
||||
@ -11,6 +12,7 @@ import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||
import { useDispatch } from 'app/types';
|
||||
import { RuleWithLocation } from 'app/types/unified-alerting';
|
||||
|
||||
import { LogMessages } from '../../Analytics';
|
||||
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';
|
||||
import { deleteRuleAction, saveRuleFormAction } from '../../state/actions';
|
||||
import { RuleFormType, RuleFormValues } from '../../types/rule-form';
|
||||
@ -110,7 +112,13 @@ export const AlertRuleForm: FC<Props> = ({ existing }) => {
|
||||
<form onSubmit={(e) => e.preventDefault()} className={styles.form}>
|
||||
<PageToolbar title={`${existing ? 'Edit' : 'Create'} alert rule`} pageIcon="bell">
|
||||
<Link to={returnTo}>
|
||||
<Button variant="secondary" disabled={submitState.loading} type="button" fill="outline">
|
||||
<Button
|
||||
variant="secondary"
|
||||
disabled={submitState.loading}
|
||||
type="button"
|
||||
fill="outline"
|
||||
onClick={() => logInfo(LogMessages.cancelSavingAlertRule)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</Link>
|
||||
|
@ -1,8 +1,10 @@
|
||||
import React, { FC } from 'react';
|
||||
|
||||
import { logInfo } from '@grafana/runtime';
|
||||
import { CallToActionCard } from '@grafana/ui';
|
||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||
|
||||
import { LogMessages } from '../../Analytics';
|
||||
import { useRulesAccess } from '../../utils/accessControlHooks';
|
||||
|
||||
export const NoRulesSplash: FC = () => {
|
||||
@ -19,6 +21,7 @@ export const NoRulesSplash: FC = () => {
|
||||
proTipLink="https://grafana.com/docs/"
|
||||
proTipLinkTitle="Learn more"
|
||||
proTipTarget="_blank"
|
||||
onClick={() => logInfo(LogMessages.alertRuleFromScratch)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
|
||||
import { logInfo } from '@grafana/runtime';
|
||||
|
||||
import { LogMessages } from '../../Analytics';
|
||||
|
||||
import RulesFilter from './RulesFilter';
|
||||
|
||||
jest.mock('@grafana/runtime', () => {
|
||||
const original = jest.requireActual('@grafana/runtime');
|
||||
return {
|
||||
...original,
|
||||
logInfo: jest.fn(),
|
||||
DataSourcePicker: () => <></>,
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
useLocation: () => ({
|
||||
pathname: 'localhost:3000/example/path',
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('../../utils/misc', () => ({
|
||||
getFiltersFromUrlParams: jest.fn(() => ({ dataSource: {}, alertState: {}, queryString: '', ruleType: '' })),
|
||||
}));
|
||||
|
||||
describe('Analytics', () => {
|
||||
it('Sends log info when clicking alert state filters', async () => {
|
||||
render(<RulesFilter />);
|
||||
|
||||
const button = screen.getByText('Pending');
|
||||
|
||||
await userEvent.click(button);
|
||||
|
||||
expect(logInfo).toHaveBeenCalledWith(LogMessages.clickingAlertStateFilters);
|
||||
});
|
||||
});
|
@ -3,11 +3,12 @@ import { debounce } from 'lodash';
|
||||
import React, { FormEvent, useState } from 'react';
|
||||
|
||||
import { DataSourceInstanceSettings, GrafanaTheme, SelectableValue } from '@grafana/data';
|
||||
import { DataSourcePicker } from '@grafana/runtime';
|
||||
import { DataSourcePicker, logInfo } from '@grafana/runtime';
|
||||
import { Button, Field, Icon, Input, Label, RadioButtonGroup, Stack, Tooltip, useStyles } from '@grafana/ui';
|
||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||
import { PromAlertingRuleState, PromRuleType } from 'app/types/unified-alerting-dto';
|
||||
|
||||
import { LogMessages } from '../../Analytics';
|
||||
import { getFiltersFromUrlParams } from '../../utils/misc';
|
||||
import { alertStateToReadable } from '../../utils/rules';
|
||||
|
||||
@ -69,6 +70,7 @@ const RulesFilter = () => {
|
||||
}, 600);
|
||||
|
||||
const handleAlertStateChange = (value: string) => {
|
||||
logInfo(LogMessages.clickingAlertStateFilters);
|
||||
setQueryParams({ alertState: value });
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { createAsyncThunk } from '@reduxjs/toolkit';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { locationService, logInfo } from '@grafana/runtime';
|
||||
import {
|
||||
AlertmanagerAlert,
|
||||
AlertManagerCortexConfig,
|
||||
@ -32,6 +32,7 @@ import {
|
||||
} from 'app/types/unified-alerting-dto';
|
||||
|
||||
import { backendSrv } from '../../../../core/services/backend_srv';
|
||||
import { LogMessages } from '../Analytics';
|
||||
import {
|
||||
addAlertManagers,
|
||||
createOrUpdateSilence,
|
||||
@ -422,6 +423,9 @@ export const saveRuleFormAction = createAsyncThunk(
|
||||
} else {
|
||||
throw new Error('Unexpected rule form type');
|
||||
}
|
||||
|
||||
logInfo(LogMessages.successSavingAlertRule);
|
||||
|
||||
if (redirectOnSave) {
|
||||
locationService.push(redirectOnSave);
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user