Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"console",
"searchNavigation",
"share",
"usageCollection",
],
"requiredBundles": [
"kibanaReact",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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.
*/

export enum AnalyticsEvents {
// Empty promp actions
gettingStartedButtonClicked = 'getting_started_button_clicked',
createInConsoleClicked = 'create_in_console_clicked',
emptyPromptLoaded = 'empty_prompt_loaded',

// Error prompt loaded
genericErrorPromptLoaded = 'generic_error_prompt_loaded',
notFoundErrorPromptLoaded = 'not_found_error_prompt_loaded',
missingPermissionsErrorPromptLoaded = 'missing_permissions_error_prompt_loaded',

rulesetCreateClicked = 'ruleset_create_clicked',
rulesetUpdateClicked = 'ruleset_update_clicked',

// ruleset detail page actions
rulesetDetailPageLoaded = 'ruleset_details_page_loaded',
addRuleClicked = 'add_rule_clicked',
editRuleClicked = 'edit_rule_clicked',
deleteRuleClicked = 'delete_rule_clicked',
testInConsoleClicked = 'test_in_console_clicked',
deleteRulesetFromHeaderClicked = 'delete_ruleset_from_header_clicked',
backToRulesetListClicked = 'back_to_ruleset_list_clicked',

rulesReordered = 'rules_reordered',
ruleFlyoutDocumentsReordered = 'rule_flyout_documents_reordered',

// ruleset list page actions
editRulesetInlineNameClicked = 'edit_ruleset_inline_name_clicked',
editRulesetInlineDropdownClicked = 'edit_ruleset_inline_dropdown_clicked',
rulesetListPageLoaded = 'ruleset_list_page_loaded',
deleteRulesetInlineDropdownClicked = 'delete_ruleset_inline_dropdown_clicked',
testRulesetInlineDropdownClicked = 'test_ruleset_inline_dropdown_clicked',
rulesetSearched = 'ruleset_searched',
addRulesetClicked = 'add_ruleset_clicked',
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import React from 'react';
import React, { useEffect } from 'react';

import {
EuiButton,
Expand Down Expand Up @@ -35,14 +35,22 @@ import { useKibana } from '../../hooks/use_kibana';
import queryRulesImg from '../../assets/query-rules-context-alt.svg';
import queryRulesDarkImg from '../../assets/query-rules-context-alt-dark.svg';
import backgroundPanelImg from '../../assets/query-rule-panel-background.svg';
import { AnalyticsEvents } from '../../analytics/constants';
import { useUsageTracker } from '../../hooks/use_usage_tracker';
import backgroundPaneDarklImg from '../../assets/query-rule-panel-background-dark.svg';

interface EmptyPromptProps {
getStartedAction: () => void;
}
export const EmptyPrompt: React.FC<EmptyPromptProps> = ({ getStartedAction }) => {
const usageTracker = useUsageTracker();
const { application, share, console: consolePlugin } = useKibana().services;
const { euiTheme, colorMode } = useEuiTheme();

useEffect(() => {
usageTracker?.load(AnalyticsEvents.emptyPromptLoaded);
}, [usageTracker]);

const gradientOverlay = css({
background: `linear-gradient(180deg, ${transparentize(
euiTheme.colors.backgroundBasePlain,
Expand Down Expand Up @@ -101,7 +109,10 @@ export const EmptyPrompt: React.FC<EmptyPromptProps> = ({ getStartedAction }) =>
data-test-subj="searchQueryRulesEmptyPromptGetStartedButton"
color="primary"
fill
onClick={getStartedAction}
onClick={() => {
usageTracker?.click(AnalyticsEvents.gettingStartedButtonClicked);
getStartedAction();
}}
>
<FormattedMessage
id="xpack.queryRules.emptyPrompt.getStartedButton"
Expand Down Expand Up @@ -240,6 +251,7 @@ export const EmptyPrompt: React.FC<EmptyPromptProps> = ({ getStartedAction }) =>
defaultMessage: 'Create in Console',
})}
showIcon
data-test-subj={AnalyticsEvents.createInConsoleClicked}
/>
</EuiFlexItem>
</EuiHideFor>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
* 2.0.
*/

import React from 'react';
import React, { useEffect } from 'react';

import { EuiEmptyPrompt } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { useUsageTracker } from '../../hooks/use_usage_tracker';
import { AnalyticsEvents } from '../../analytics/constants';

const ERROR_MESSAGES = {
notFound: {
Expand All @@ -19,6 +21,7 @@ const ERROR_MESSAGES = {
defaultMessage="Requested resource was not found. Check if the URL is correct."
/>
),
analyticsEvent: AnalyticsEvents.notFoundErrorPromptLoaded,
},
generic: {
title: <FormattedMessage id="xpack.queryRules.errorTitle" defaultMessage="An error occurred" />,
Expand All @@ -28,6 +31,7 @@ const ERROR_MESSAGES = {
defaultMessage="An error occurred while fetching query rules. Check Kibana logs for more information."
/>
),
analyticsEvent: AnalyticsEvents.genericErrorPromptLoaded,
},
missingPermissions: {
title: (
Expand All @@ -42,12 +46,17 @@ const ERROR_MESSAGES = {
defaultMessage="You do not have the necessary permissions to manage query rules. Contact your system administrator."
/>
),
analyticsEvent: AnalyticsEvents.missingPermissionsErrorPromptLoaded,
},
};

export const ErrorPrompt: React.FC<{
errorType: 'missingPermissions' | 'generic' | 'notFound';
}> = ({ errorType }) => {
const useTracker = useUsageTracker();
useEffect(() => {
useTracker?.load?.(ERROR_MESSAGES[errorType].analyticsEvent);
}, [errorType, useTracker]);
return (
<EuiEmptyPrompt
iconType="logoElasticsearch"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import React, { useState, useEffect } from 'react';
import React, { useState } from 'react';

import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
import {
Expand All @@ -31,24 +31,16 @@ import { QueryRulesSets } from '../query_rules_sets/query_rules_sets';
import { CreateRulesetModal } from './create_ruleset_modal';

import { QueryRulesPageTemplate } from '../../layout/query_rules_page_template';
import { useUsageTracker } from '../../hooks/use_usage_tracker';
import { AnalyticsEvents } from '../../analytics/constants';

export const QueryRulesOverview = () => {
const usageTracker = useUsageTracker();
const { colorMode } = useEuiTheme();
const {
data: queryRulesData,
isInitialLoading,
isError,
error,
refetch,
} = useFetchQueryRulesSets();

useEffect(() => {
const interval = setInterval(() => {
refetch();
}, 1000);
return () => clearInterval(interval);
}, [refetch]);
const { data: queryRulesData, isInitialLoading, isError, error } = useFetchQueryRulesSets();
const [isCreateModalVisible, setIsCreateModalVisible] = useState(false);

const backgroundProps = css({
backgroundImage: `url(${
colorMode === 'DARK' ? queryRulesBackgroundDark : queryRulesBackground
Expand All @@ -61,6 +53,7 @@ export const QueryRulesOverview = () => {
alignContent: 'center',
backgroundPosition: 'center center',
});

return (
<QueryRulesPageTemplate restrictWidth={false}>
{!isInitialLoading && !isError && queryRulesData?._meta.totalItemCount !== 0 && (
Expand Down Expand Up @@ -95,6 +88,7 @@ export const QueryRulesOverview = () => {
fill
iconType="plusInCircle"
onClick={() => {
usageTracker?.click(AnalyticsEvents.addRulesetClicked);
setIsCreateModalVisible(true);
}}
>
Expand Down Expand Up @@ -143,6 +137,7 @@ export const QueryRulesOverview = () => {
<EuiFlexItem>
<EmptyPrompt
getStartedAction={() => {
usageTracker?.click(AnalyticsEvents.gettingStartedButtonClicked);
setIsCreateModalVisible(true);
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';

import { QueryRulesListRulesetsQueryRulesetListItem } from '@elastic/elasticsearch/lib/api/types';
import {
Expand All @@ -24,8 +24,11 @@ import { useQueryRulesSetsTableData } from '../../hooks/use_query_rules_sets_tab
import { QueryRulesSetsSearch } from './query_rules_sets_search';
import { DeleteRulesetModal } from './delete_ruleset_modal';
import { UseRunQueryRuleset } from '../../hooks/use_run_query_ruleset';
import { useUsageTracker } from '../../hooks/use_usage_tracker';
import { AnalyticsEvents } from '../../analytics/constants';

export const QueryRulesSets = () => {
const useTracker = useUsageTracker();
const {
services: { application, http },
} = useKibana();
Expand All @@ -43,6 +46,10 @@ export const QueryRulesSets = () => {
pageSize
);

useEffect(() => {
useTracker?.load?.(AnalyticsEvents.rulesetListPageLoaded);
}, [useTracker]);

if (!queryRulesData) {
return null;
}
Expand All @@ -57,6 +64,7 @@ export const QueryRulesSets = () => {
<EuiLink
data-test-subj="queryRuleSetName"
onClick={() => {
useTracker?.click?.(AnalyticsEvents.editRulesetInlineNameClicked);
application.navigateToUrl(
http.basePath.prepend(`${PLUGIN_ROUTE_ROOT}/ruleset/${name}`)
);
Expand Down Expand Up @@ -86,6 +94,9 @@ export const QueryRulesSets = () => {
content={i18n.translate('xpack.queryRules.queryRulesSetTable.actions.run', {
defaultMessage: 'Test in Console',
})}
onClick={() => {
useTracker?.click?.(AnalyticsEvents.testRulesetInlineDropdownClicked);
}}
/>
);
},
Expand All @@ -102,10 +113,12 @@ export const QueryRulesSets = () => {
icon: 'pencil',
color: 'text',
type: 'icon',
onClick: (ruleset: QueryRulesListRulesetsQueryRulesetListItem) =>
onClick: (ruleset: QueryRulesListRulesetsQueryRulesetListItem) => {
useTracker?.click?.(AnalyticsEvents.editRulesetInlineDropdownClicked);
application.navigateToUrl(
http.basePath.prepend(`${PLUGIN_ROUTE_ROOT}/ruleset/${ruleset.ruleset_id}`)
),
);
},
},
{
name: i18n.translate('xpack.queryRules.queryRulesSetTable.actions.delete', {
Expand All @@ -121,6 +134,7 @@ export const QueryRulesSets = () => {
type: 'icon',
isPrimary: true,
onClick: (ruleset: QueryRulesListRulesetsQueryRulesetListItem) => {
useTracker?.click?.(AnalyticsEvents.deleteRulesetInlineDropdownClicked);
setRulesetToDelete(ruleset.ruleset_id);
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import { EuiFieldSearch } from '@elastic/eui';
import React, { useCallback } from 'react';
import { useUsageTracker } from '../../hooks/use_usage_tracker';
import { AnalyticsEvents } from '../../analytics/constants';

interface QueryRulesSetsSearchProps {
searchKey: string;
Expand All @@ -17,12 +19,15 @@ export const QueryRulesSetsSearch: React.FC<QueryRulesSetsSearchProps> = ({
searchKey,
setSearchKey,
}) => {
const useTracker = useUsageTracker();
const onSearch = useCallback(
(newSearch: string) => {
useTracker?.load?.(AnalyticsEvents.rulesetSearched);

const trimSearch = newSearch.trim();
setSearchKey(trimSearch);
},
[setSearchKey]
[setSearchKey, useTracker]
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { QueryRuleFlyout } from './query_rule_flyout/query_rule_flyout';
import { useGenerateRuleId } from '../../hooks/use_generate_rule_id';
import { SearchQueryRulesQueryRule } from '../../types';
import { RulesetDetailEmptyPrompt } from '../empty_prompt/ruleset_detail_empty_prompt';
import { useUsageTracker } from '../../hooks/use_usage_tracker';
import { AnalyticsEvents } from '../../analytics/constants';

interface QueryRuleDetailPanelProps {
rules: SearchQueryRulesQueryRule[];
Expand Down Expand Up @@ -46,6 +48,8 @@ export const QueryRuleDetailPanel: React.FC<QueryRuleDetailPanelProps> = ({
const [ruleIdToEdit, setRuleIdToEdit] = React.useState<string | null>(null);
const [flyoutMode, setFlyoutMode] = React.useState<'create' | 'edit'>('edit');

const useTracker = useUsageTracker();

const { mutate: generateRuleId } = useGenerateRuleId(rulesetId);
useEffect(() => {
if (createMode && rules.length === 0) {
Expand Down Expand Up @@ -94,6 +98,7 @@ export const QueryRuleDetailPanel: React.FC<QueryRuleDetailPanelProps> = ({
color="primary"
data-test-subj="queryRulesetDetailAddRuleButton"
onClick={() => {
useTracker?.click(AnalyticsEvents.addRuleClicked);
generateRuleId(undefined, {
onSuccess: (newRuleId) => {
setFlyoutMode('create');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ import { css } from '@emotion/react';
import { QueryRulesQueryRule } from '@elastic/elasticsearch/lib/api/types';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import { useUsageTracker } from '../../../hooks/use_usage_tracker';
import { SearchQueryRulesQueryRule } from '../../../../common/types';
import { DroppableContainer } from '../styles';
import { QueryRuleDraggableListHeader } from './query_rule_draggable_list_header';
import { QueryRuleDraggableListItemActionTypeBadge } from './query_rule_draggable_item_action_type_badge';
import { QueryRuleDraggableItemCriteriaDisplay } from './query_rule_draggable_item_criteria_display';
import { DeleteRulesetRuleModal } from './delete_ruleset_rule_modal';
import { AnalyticsEvents } from '../../../analytics/constants';

export interface QueryRuleDraggableListItemProps {
rules: SearchQueryRulesQueryRule[];
Expand Down Expand Up @@ -60,6 +62,7 @@ export const QueryRuleDraggableListItem: React.FC<QueryRuleDraggableListItemProp
isLastItem = false,
}) => {
const { euiTheme } = useEuiTheme();
const useTracker = useUsageTracker();
const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);
const localTourTargetRef = useRef<HTMLDivElement>(null);
const effectiveRef = tourInfo?.tourTargetRef || localTourTargetRef;
Expand Down Expand Up @@ -174,6 +177,7 @@ export const QueryRuleDraggableListItem: React.FC<QueryRuleDraggableListItemProp
icon="pencil"
data-test-subj="searchQueryRulesQueryRulesetDetailEditButton"
onClick={() => {
useTracker?.click(AnalyticsEvents.editRuleClicked);
onEditRuleFlyoutOpen(queryRule.rule_id);
closePopover();
}}
Expand Down Expand Up @@ -204,6 +208,7 @@ export const QueryRuleDraggableListItem: React.FC<QueryRuleDraggableListItemProp
`}
data-test-subj="searchQueryRulesQueryRulesetDetailDeleteButton"
onClick={() => {
useTracker?.click(AnalyticsEvents.deleteRuleClicked);
setRuleToDelete(queryRule.rule_id);
closePopover();
}}
Expand Down Expand Up @@ -263,11 +268,13 @@ export const QueryRuleDraggableList: React.FC<QueryRuleDraggableListProps> = ({
tourInfo,
}) => {
const { euiTheme } = useEuiTheme();
const useTracker = useUsageTracker();

return (
<EuiDragDropContext
onDragEnd={({ source, destination }) => {
if (source && destination) {
useTracker?.click(AnalyticsEvents.rulesReordered);
const items = euiDragDropReorder(rules, source.index, destination.index);
onReorder(items);
}
Expand Down
Loading