mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Security Solution][Notes] - add telemetry (#187362)
This commit is contained in:
parent
f03fa06d5e
commit
e4a44fd23e
15 changed files with 186 additions and 28 deletions
|
@ -169,31 +169,36 @@ const RowActionComponent = ({
|
|||
tabType,
|
||||
]);
|
||||
|
||||
const toggleShowNotes = useCallback(
|
||||
() =>
|
||||
openFlyout({
|
||||
right: {
|
||||
id: DocumentDetailsRightPanelKey,
|
||||
params: {
|
||||
id: eventId,
|
||||
indexName,
|
||||
scopeId: tableId,
|
||||
},
|
||||
const toggleShowNotes = useCallback(() => {
|
||||
openFlyout({
|
||||
right: {
|
||||
id: DocumentDetailsRightPanelKey,
|
||||
params: {
|
||||
id: eventId,
|
||||
indexName,
|
||||
scopeId: tableId,
|
||||
},
|
||||
left: {
|
||||
id: DocumentDetailsLeftPanelKey,
|
||||
path: {
|
||||
tab: LeftPanelNotesTab,
|
||||
},
|
||||
params: {
|
||||
id: eventId,
|
||||
indexName,
|
||||
scopeId: tableId,
|
||||
},
|
||||
},
|
||||
left: {
|
||||
id: DocumentDetailsLeftPanelKey,
|
||||
path: {
|
||||
tab: LeftPanelNotesTab,
|
||||
},
|
||||
}),
|
||||
[eventId, indexName, openFlyout, tableId]
|
||||
);
|
||||
params: {
|
||||
id: eventId,
|
||||
indexName,
|
||||
scopeId: tableId,
|
||||
},
|
||||
},
|
||||
});
|
||||
telemetry.reportOpenNoteInExpandableFlyoutClicked({
|
||||
location: tableId,
|
||||
});
|
||||
telemetry.reportDetailsFlyoutOpened({
|
||||
location: tableId,
|
||||
panel: 'left',
|
||||
});
|
||||
}, [eventId, indexName, openFlyout, tableId, telemetry]);
|
||||
|
||||
const Action = controlColumn.rowCellRender;
|
||||
|
||||
|
|
|
@ -84,6 +84,8 @@ export enum TelemetryEventTypes {
|
|||
ManualRuleRunCancelJob = 'Manual Rule Run Cancel Job',
|
||||
EventLogFilterByRunType = 'Event Log Filter By Run Type',
|
||||
EventLogShowSourceEventDateRange = 'Event Log -> Show Source -> Event Date Range',
|
||||
OpenNoteInExpandableFlyoutClicked = 'Open Note In Expandable Flyout Clicked',
|
||||
AddNoteFromExpandableFlyoutClicked = 'Add Note From Expandable Flyout Clicked',
|
||||
}
|
||||
|
||||
export enum ML_JOB_TELEMETRY_STATUS {
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { TelemetryEvent } from '../../types';
|
||||
import { TelemetryEventTypes } from '../../constants';
|
||||
|
||||
export const openNoteInExpandableFlyoutClickedEvent: TelemetryEvent = {
|
||||
eventType: TelemetryEventTypes.OpenNoteInExpandableFlyoutClicked,
|
||||
schema: {
|
||||
location: {
|
||||
type: 'text',
|
||||
_meta: {
|
||||
description: 'Table ID or timeline ID',
|
||||
optional: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const addNoteFromExpandableFlyoutClickedEvent: TelemetryEvent = {
|
||||
eventType: TelemetryEventTypes.AddNoteFromExpandableFlyoutClicked,
|
||||
schema: {
|
||||
isRelatedToATimeline: {
|
||||
type: 'boolean',
|
||||
_meta: {
|
||||
description: 'If the note was added related to a saved timeline',
|
||||
optional: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { RootSchema } from '@kbn/core/public';
|
||||
import type { TelemetryEventTypes } from '../../constants';
|
||||
|
||||
export interface OpenNoteInExpandableFlyoutClickedParams {
|
||||
location: string;
|
||||
}
|
||||
|
||||
export interface AddNoteFromExpandableFlyoutClickedParams {
|
||||
isRelatedToATimeline: boolean;
|
||||
}
|
||||
|
||||
export type NotesTelemetryEventParams =
|
||||
| OpenNoteInExpandableFlyoutClickedParams
|
||||
| AddNoteFromExpandableFlyoutClickedParams;
|
||||
|
||||
export type NotesTelemetryEvents =
|
||||
| {
|
||||
eventType: TelemetryEventTypes.OpenNoteInExpandableFlyoutClicked;
|
||||
schema: RootSchema<OpenNoteInExpandableFlyoutClickedParams>;
|
||||
}
|
||||
| {
|
||||
eventType: TelemetryEventTypes.AddNoteFromExpandableFlyoutClicked;
|
||||
schema: RootSchema<AddNoteFromExpandableFlyoutClickedParams>;
|
||||
};
|
|
@ -44,6 +44,10 @@ import {
|
|||
manualRuleRunOpenModalEvent,
|
||||
} from './manual_rule_run';
|
||||
import { eventLogFilterByRunTypeEvent, eventLogShowSourceEventDateRangeEvent } from './event_log';
|
||||
import {
|
||||
addNoteFromExpandableFlyoutClickedEvent,
|
||||
openNoteInExpandableFlyoutClickedEvent,
|
||||
} from './notes';
|
||||
|
||||
const mlJobUpdateEvent: TelemetryEvent = {
|
||||
eventType: TelemetryEventTypes.MLJobUpdate,
|
||||
|
@ -186,4 +190,6 @@ export const telemetryEvents = [
|
|||
manualRuleRunOpenModalEvent,
|
||||
eventLogFilterByRunTypeEvent,
|
||||
eventLogShowSourceEventDateRangeEvent,
|
||||
openNoteInExpandableFlyoutClickedEvent,
|
||||
addNoteFromExpandableFlyoutClickedEvent,
|
||||
];
|
||||
|
|
|
@ -40,4 +40,6 @@ export const createTelemetryClientMock = (): jest.Mocked<TelemetryClientStart> =
|
|||
reportManualRuleRunCancelJob: jest.fn(),
|
||||
reportManualRuleRunExecute: jest.fn(),
|
||||
reportManualRuleRunOpenModal: jest.fn(),
|
||||
reportOpenNoteInExpandableFlyoutClicked: jest.fn(),
|
||||
reportAddNoteFromExpandableFlyoutClicked: jest.fn(),
|
||||
});
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
*/
|
||||
|
||||
import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server';
|
||||
import type {
|
||||
AddNoteFromExpandableFlyoutClickedParams,
|
||||
OpenNoteInExpandableFlyoutClickedParams,
|
||||
} from './events/notes/types';
|
||||
import type {
|
||||
TelemetryClientStart,
|
||||
ReportAlertsGroupingChangedParams,
|
||||
|
@ -195,4 +199,16 @@ export class TelemetryClient implements TelemetryClientStart {
|
|||
): void {
|
||||
this.analytics.reportEvent(TelemetryEventTypes.EventLogShowSourceEventDateRange, params);
|
||||
}
|
||||
|
||||
public reportOpenNoteInExpandableFlyoutClicked = (
|
||||
params: OpenNoteInExpandableFlyoutClickedParams
|
||||
) => {
|
||||
this.analytics.reportEvent(TelemetryEventTypes.OpenNoteInExpandableFlyoutClicked, params);
|
||||
};
|
||||
|
||||
public reportAddNoteFromExpandableFlyoutClicked = (
|
||||
params: AddNoteFromExpandableFlyoutClickedParams
|
||||
) => {
|
||||
this.analytics.reportEvent(TelemetryEventTypes.AddNoteFromExpandableFlyoutClicked, params);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -66,6 +66,12 @@ import type {
|
|||
ReportEventLogShowSourceEventDateRangeParams,
|
||||
ReportEventLogTelemetryEventParams,
|
||||
} from './events/event_log/types';
|
||||
import type {
|
||||
AddNoteFromExpandableFlyoutClickedParams,
|
||||
NotesTelemetryEventParams,
|
||||
NotesTelemetryEvents,
|
||||
OpenNoteInExpandableFlyoutClickedParams,
|
||||
} from './events/notes/types';
|
||||
|
||||
export * from './events/ai_assistant/types';
|
||||
export * from './events/alerts_grouping/types';
|
||||
|
@ -129,7 +135,8 @@ export type TelemetryEventParams =
|
|||
| OnboardingHubStepFinishedParams
|
||||
| OnboardingHubStepLinkClickedParams
|
||||
| ReportManualRuleRunTelemetryEventParams
|
||||
| ReportEventLogTelemetryEventParams;
|
||||
| ReportEventLogTelemetryEventParams
|
||||
| NotesTelemetryEventParams;
|
||||
|
||||
export interface TelemetryClientStart {
|
||||
reportAlertsGroupingChanged(params: ReportAlertsGroupingChangedParams): void;
|
||||
|
@ -183,6 +190,10 @@ export interface TelemetryClientStart {
|
|||
reportEventLogShowSourceEventDateRange(
|
||||
params: ReportEventLogShowSourceEventDateRangeParams
|
||||
): void;
|
||||
|
||||
// new notes
|
||||
reportOpenNoteInExpandableFlyoutClicked(params: OpenNoteInExpandableFlyoutClickedParams): void;
|
||||
reportAddNoteFromExpandableFlyoutClicked(params: AddNoteFromExpandableFlyoutClickedParams): void;
|
||||
}
|
||||
|
||||
export type TelemetryEvent =
|
||||
|
@ -209,4 +220,5 @@ export type TelemetryEvent =
|
|||
}
|
||||
| OnboardingHubTelemetryEvent
|
||||
| ManualRuleRunTelemetryEvent
|
||||
| EventLogTelemetryEvent;
|
||||
| EventLogTelemetryEvent
|
||||
| NotesTelemetryEvents;
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
import { css } from '@emotion/react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import { TimelineId } from '../../../../../common/types';
|
||||
import { timelineSelectors } from '../../../../timelines/store';
|
||||
import { useIsTimelineFlyoutOpen } from '../../shared/hooks/use_is_timeline_flyout_open';
|
||||
|
@ -80,6 +81,7 @@ export interface AddNewNoteProps {
|
|||
* The checkbox is automatically checked if the flyout is opened from a timeline and that timeline is saved. It is disabled if the flyout is NOT opened from a timeline.
|
||||
*/
|
||||
export const AddNote = memo(({ eventId }: AddNewNoteProps) => {
|
||||
const { telemetry } = useKibana().services;
|
||||
const dispatch = useDispatch();
|
||||
const { addError: addErrorToast } = useAppToasts();
|
||||
const [editorValue, setEditorValue] = useState('');
|
||||
|
@ -110,8 +112,11 @@ export const AddNote = memo(({ eventId }: AddNewNoteProps) => {
|
|||
},
|
||||
})
|
||||
);
|
||||
telemetry.reportAddNoteFromExpandableFlyoutClicked({
|
||||
isRelatedToATimeline: checked && activeTimeline?.savedObjectId !== null,
|
||||
});
|
||||
setEditorValue('');
|
||||
}, [activeTimeline?.savedObjectId, checked, dispatch, editorValue, eventId]);
|
||||
}, [activeTimeline?.savedObjectId, checked, dispatch, editorValue, eventId, telemetry]);
|
||||
|
||||
// show a toast if the create note call fails
|
||||
useEffect(() => {
|
||||
|
|
|
@ -14,6 +14,7 @@ import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
|
|||
import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features';
|
||||
import { DocumentDetailsRightPanelKey } from '../../../../../flyout/document_details/shared/constants/panel_keys';
|
||||
import { useDeepEqualSelector } from '../../../../../common/hooks/use_selector';
|
||||
import { useKibana } from '../../../../../common/lib/kibana';
|
||||
import type {
|
||||
ColumnHeaderOptions,
|
||||
CellValueElementProps,
|
||||
|
@ -107,6 +108,7 @@ const StatefulEventComponent: React.FC<Props> = ({
|
|||
trailingControlColumns,
|
||||
onToggleShowNotes,
|
||||
}) => {
|
||||
const { telemetry } = useKibana().services;
|
||||
const trGroupRef = useRef<HTMLDivElement | null>(null);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
|
@ -224,6 +226,10 @@ const StatefulEventComponent: React.FC<Props> = ({
|
|||
},
|
||||
},
|
||||
});
|
||||
telemetry.reportDetailsFlyoutOpened({
|
||||
location: timelineId,
|
||||
panel: 'right',
|
||||
});
|
||||
} else {
|
||||
// opens the panel when clicking on the table row action
|
||||
dispatch(
|
||||
|
@ -241,6 +247,7 @@ const StatefulEventComponent: React.FC<Props> = ({
|
|||
expandableFlyoutDisabled,
|
||||
openFlyout,
|
||||
timelineId,
|
||||
telemetry,
|
||||
dispatch,
|
||||
tabType,
|
||||
]);
|
||||
|
|
|
@ -38,6 +38,7 @@ import type {
|
|||
DroppableStateSnapshot,
|
||||
} from '@hello-pangea/dnd';
|
||||
import { DocumentDetailsRightPanelKey } from '../../../../flyout/document_details/shared/constants/panel_keys';
|
||||
import { createTelemetryServiceMock } from '../../../../common/lib/telemetry/telemetry_service.mock';
|
||||
|
||||
jest.mock('../../../../common/hooks/use_app_toasts');
|
||||
jest.mock('../../../../common/components/guided_onboarding_tour/tour_step');
|
||||
|
@ -104,6 +105,8 @@ jest.mock('@kbn/expandable-flyout', () => {
|
|||
};
|
||||
});
|
||||
|
||||
const mockedTelemetry = createTelemetryServiceMock();
|
||||
|
||||
jest.mock('../../../../common/components/link_to', () => {
|
||||
const originalModule = jest.requireActual('../../../../common/components/link_to');
|
||||
return {
|
||||
|
@ -255,6 +258,7 @@ describe('Body', () => {
|
|||
savedObjects: {
|
||||
client: {},
|
||||
},
|
||||
telemetry: mockedTelemetry,
|
||||
timelines: {
|
||||
getLastUpdated: jest.fn(),
|
||||
getLoadingPanel: jest.fn(),
|
||||
|
|
|
@ -17,6 +17,7 @@ import type { EuiDataGridControlColumn } from '@elastic/eui';
|
|||
|
||||
import { DataLoadingState } from '@kbn/unified-data-table';
|
||||
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
|
||||
import { useKibana } from '../../../../../common/lib/kibana';
|
||||
import {
|
||||
DocumentDetailsLeftPanelKey,
|
||||
DocumentDetailsRightPanelKey,
|
||||
|
@ -87,6 +88,7 @@ export const EqlTabContentComponent: React.FC<Props> = ({
|
|||
pinnedEventIds,
|
||||
eventIdToNoteIds,
|
||||
}) => {
|
||||
const { telemetry } = useKibana().services;
|
||||
const dispatch = useDispatch();
|
||||
const { query: eqlQuery = '', ...restEqlOption } = eqlOptions;
|
||||
const { portalNode: eqlEventsCountPortalNode } = useEqlEventsCountPortal();
|
||||
|
@ -188,6 +190,13 @@ export const EqlTabContentComponent: React.FC<Props> = ({
|
|||
},
|
||||
},
|
||||
});
|
||||
telemetry.reportOpenNoteInExpandableFlyoutClicked({
|
||||
location: timelineId,
|
||||
});
|
||||
telemetry.reportDetailsFlyoutOpened({
|
||||
location: timelineId,
|
||||
panel: 'left',
|
||||
});
|
||||
} else {
|
||||
if (eventId) {
|
||||
setNotesEventId(eventId);
|
||||
|
@ -200,6 +209,7 @@ export const EqlTabContentComponent: React.FC<Props> = ({
|
|||
openFlyout,
|
||||
securitySolutionNotesEnabled,
|
||||
selectedPatterns,
|
||||
telemetry,
|
||||
timelineId,
|
||||
setNotesEventId,
|
||||
showNotesFlyout,
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
DocumentDetailsRightPanelKey,
|
||||
} from '../../../../../flyout/document_details/shared/constants/panel_keys';
|
||||
import type { ControlColumnProps } from '../../../../../../common/types';
|
||||
import { useKibana } from '../../../../../common/lib/kibana';
|
||||
import { timelineActions, timelineSelectors } from '../../../../store';
|
||||
import type { Direction } from '../../../../../../common/search_strategy';
|
||||
import { useTimelineEvents } from '../../../../containers';
|
||||
|
@ -94,6 +95,7 @@ export const PinnedTabContentComponent: React.FC<Props> = ({
|
|||
expandedDetail,
|
||||
eventIdToNoteIds,
|
||||
}) => {
|
||||
const { telemetry } = useKibana().services;
|
||||
const {
|
||||
browserFields,
|
||||
dataViewId,
|
||||
|
@ -224,6 +226,13 @@ export const PinnedTabContentComponent: React.FC<Props> = ({
|
|||
},
|
||||
},
|
||||
});
|
||||
telemetry.reportOpenNoteInExpandableFlyoutClicked({
|
||||
location: timelineId,
|
||||
});
|
||||
telemetry.reportDetailsFlyoutOpened({
|
||||
location: timelineId,
|
||||
panel: 'left',
|
||||
});
|
||||
} else {
|
||||
if (eventId) {
|
||||
setNotesEventId(eventId);
|
||||
|
@ -236,6 +245,7 @@ export const PinnedTabContentComponent: React.FC<Props> = ({
|
|||
openFlyout,
|
||||
securitySolutionNotesEnabled,
|
||||
selectedPatterns,
|
||||
telemetry,
|
||||
timelineId,
|
||||
setNotesEventId,
|
||||
showNotesFlyout,
|
||||
|
|
|
@ -116,7 +116,7 @@ export const QueryTabContentComponent: React.FC<Props> = ({
|
|||
selectedPatterns,
|
||||
} = useSourcererDataView(SourcererScopeName.timeline);
|
||||
|
||||
const { uiSettings, timelineDataService } = useKibana().services;
|
||||
const { uiSettings, telemetry, timelineDataService } = useKibana().services;
|
||||
const {
|
||||
query: { filterManager: timelineFilterManager },
|
||||
} = timelineDataService;
|
||||
|
@ -256,6 +256,13 @@ export const QueryTabContentComponent: React.FC<Props> = ({
|
|||
},
|
||||
},
|
||||
});
|
||||
telemetry.reportOpenNoteInExpandableFlyoutClicked({
|
||||
location: timelineId,
|
||||
});
|
||||
telemetry.reportDetailsFlyoutOpened({
|
||||
location: timelineId,
|
||||
panel: 'left',
|
||||
});
|
||||
} else {
|
||||
if (eventId) {
|
||||
setNotesEventId(eventId);
|
||||
|
@ -268,6 +275,7 @@ export const QueryTabContentComponent: React.FC<Props> = ({
|
|||
openFlyout,
|
||||
securitySolutionNotesEnabled,
|
||||
selectedPatterns,
|
||||
telemetry,
|
||||
timelineId,
|
||||
showNotesFlyout,
|
||||
setNotesEventId,
|
||||
|
|
|
@ -134,6 +134,7 @@ export const TimelineDataTableComponent: React.FC<DataTableProps> = memo(
|
|||
storage,
|
||||
dataViewFieldEditor,
|
||||
notifications: { toasts: toastsService },
|
||||
telemetry,
|
||||
theme,
|
||||
data: dataPluginContract,
|
||||
},
|
||||
|
@ -187,6 +188,10 @@ export const TimelineDataTableComponent: React.FC<DataTableProps> = memo(
|
|||
},
|
||||
},
|
||||
});
|
||||
telemetry.reportDetailsFlyoutOpened({
|
||||
location: timelineId,
|
||||
panel: 'right',
|
||||
});
|
||||
} else {
|
||||
dispatch(
|
||||
timelineActions.toggleDetailPanel({
|
||||
|
@ -199,7 +204,7 @@ export const TimelineDataTableComponent: React.FC<DataTableProps> = memo(
|
|||
|
||||
activeTimeline.toggleExpandedDetail({ ...updatedExpandedDetail });
|
||||
},
|
||||
[activeTab, dispatch, refetch, timelineId, isExpandableFlyoutDisabled, openFlyout]
|
||||
[refetch, isExpandableFlyoutDisabled, openFlyout, timelineId, telemetry, dispatch, activeTab]
|
||||
);
|
||||
|
||||
const onTimelineLegacyFlyoutClose = useCallback(() => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue