From c6ac80972fb74b24b122ef381c06fa0ba5ccbeab Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Mon, 17 Apr 2023 13:25:58 +0100 Subject: [PATCH 01/11] WIP --- .../fetch_analytics_collections_api_logic.ts | 5 +++-- .../analytics_collection_table.tsx | 22 ++++++++++++++----- .../analytics_collections_logic.ts | 6 +++-- .../analytics_overview/analytics_overview.tsx | 5 ++++- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.ts index 399038a776c100..3a3937d2b16c35 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.ts @@ -12,9 +12,10 @@ import { HttpLogic } from '../../../shared/http'; export type FetchAnalyticsCollectionsApiLogicResponse = AnalyticsCollection[]; -export const fetchAnalyticsCollections = async () => { +export const fetchAnalyticsCollections = async (query = '') => { const { http } = HttpLogic.values; - const route = '/internal/enterprise_search/analytics/collections'; + const route = + '/internal/enterprise_search/analytics/collections' + query ? `?query=${query}` : ''; const response = await http.get(route); return response; diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.tsx index 2d52cf22f6ca2b..84d2646f94ccf4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.tsx @@ -7,6 +7,8 @@ import React, { useMemo, useState } from 'react'; +import { useActions } from 'kea'; + import { EuiFlexGrid, EuiFlexItem, @@ -19,6 +21,7 @@ import { EuiButtonGroup, useEuiTheme, EuiButton, + EuiFieldSearch, } from '@elastic/eui'; import { OnTimeChangeProps } from '@elastic/eui/src/components/date_picker/super_date_picker/super_date_picker'; @@ -31,6 +34,8 @@ import { AddAnalyticsCollection } from '../add_analytics_collections/add_analyti import { AnalyticsCollectionCardWithLens } from './analytics_collection_card/analytics_collection_card'; import { AnalyticsCollectionTableStyles } from './analytics_collection_table.styles'; +import { AnalyticsCollectionsLogic } from './analytics_collections_logic'; +import { increment } from 'fp-ts/lib/function'; const defaultQuickRanges: EuiSuperDatePickerCommonRange[] = [ { @@ -72,10 +77,12 @@ const defaultQuickRanges: EuiSuperDatePickerCommonRange[] = [ interface AnalyticsCollectionTableProps { collections: AnalyticsCollection[]; + onSearch: (query: string) => void; } export const AnalyticsCollectionTable: React.FC = ({ collections, + onSearch }) => { const { euiTheme } = useEuiTheme(); const analyticsCollectionTableStyles = AnalyticsCollectionTableStyles(euiTheme); @@ -113,6 +120,7 @@ export const AnalyticsCollectionTable: React.FC = [analyticsCollectionTableStyles.button] ); const [filterId, setFilterId] = useState(filterOptions[0].id); + const [query, setQuery] = useState(''); const [timeRange, setTimeRange] = useState<{ from: string; to: string }>({ from: defaultQuickRanges[0].start, to: defaultQuickRanges[0].end, @@ -127,12 +135,16 @@ export const AnalyticsCollectionTable: React.FC = - { + setQuery(e.target.value); }} + onSearch={onSearch} + incremental /> diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts index aa12b92b0f1773..e9091af7591dcd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts @@ -16,7 +16,7 @@ import { } from '../../api/index/fetch_analytics_collections_api_logic'; export interface AnalyticsCollectionsActions { - fetchAnalyticsCollections(): void; + fetchAnalyticsCollections(query: string): void; makeRequest: Actions<{}, FetchAnalyticsCollectionsApiLogicResponse>['makeRequest']; } export interface AnalyticsCollectionsValues { @@ -38,7 +38,9 @@ export const AnalyticsCollectionsLogic = kea< values: [FetchAnalyticsCollectionsAPILogic, ['data', 'status']], }, listeners: ({ actions }) => ({ - fetchAnalyticsCollections: () => { + fetchAnalyticsCollections: async ({ query }, breakpoint) => { + if (query) { + await breakpoint(200) actions.makeRequest({}); }, }), diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx index 562f587023b27a..778de4c1fa81e5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx @@ -72,7 +72,10 @@ export const AnalyticsOverview: React.FC = () => { ) : ( - + console.log(query)} + /> )} ); From 2a6487493f5231e18cc3b7547ce109e0aac61073 Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Tue, 18 Apr 2023 09:28:01 +0100 Subject: [PATCH 02/11] WIP --- .../fetch_analytics_collections_api_logic.ts | 17 +++++++--- .../analytics_collection_table.tsx | 8 ++--- .../analytics_collections_logic.ts | 33 ++++++++++++++----- .../analytics_overview/analytics_overview.tsx | 10 +++--- .../routes/enterprise_search/analytics.ts | 19 +++++++++-- 5 files changed, 62 insertions(+), 25 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.ts index 3a3937d2b16c35..88bdf5fcccc537 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.ts @@ -12,11 +12,20 @@ import { HttpLogic } from '../../../shared/http'; export type FetchAnalyticsCollectionsApiLogicResponse = AnalyticsCollection[]; -export const fetchAnalyticsCollections = async (query = '') => { +interface FetchAnalyticsCollectionsApiLogicArgs { + query: string; +} + +export const fetchAnalyticsCollections = async ({ + query = '', +}: FetchAnalyticsCollectionsApiLogicArgs) => { const { http } = HttpLogic.values; - const route = - '/internal/enterprise_search/analytics/collections' + query ? `?query=${query}` : ''; - const response = await http.get(route); + const route = '/internal/enterprise_search/analytics/collections'; + const response = await http.get(route, { + query: { + query, + }, + }); return response; }; diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.tsx index 84d2646f94ccf4..8e2290d549f7d3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.tsx @@ -7,15 +7,13 @@ import React, { useMemo, useState } from 'react'; -import { useActions } from 'kea'; - import { EuiFlexGrid, EuiFlexItem, EuiPanel, EuiSuperDatePicker, EuiSuperDatePickerCommonRange, - EuiSearchBar, + EuiEmptyPrompt, EuiFlexGroup, EuiSpacer, EuiButtonGroup, @@ -34,8 +32,6 @@ import { AddAnalyticsCollection } from '../add_analytics_collections/add_analyti import { AnalyticsCollectionCardWithLens } from './analytics_collection_card/analytics_collection_card'; import { AnalyticsCollectionTableStyles } from './analytics_collection_table.styles'; -import { AnalyticsCollectionsLogic } from './analytics_collections_logic'; -import { increment } from 'fp-ts/lib/function'; const defaultQuickRanges: EuiSuperDatePickerCommonRange[] = [ { @@ -82,7 +78,7 @@ interface AnalyticsCollectionTableProps { export const AnalyticsCollectionTable: React.FC = ({ collections, - onSearch + onSearch, }) => { const { euiTheme } = useEuiTheme(); const analyticsCollectionTableStyles = AnalyticsCollectionTableStyles(euiTheme); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts index e9091af7591dcd..057a0e34e38103 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts @@ -16,13 +16,14 @@ import { } from '../../api/index/fetch_analytics_collections_api_logic'; export interface AnalyticsCollectionsActions { - fetchAnalyticsCollections(query: string): void; + fetchAnalyticsCollections({ query }: { query: string }): { query: string }; makeRequest: Actions<{}, FetchAnalyticsCollectionsApiLogicResponse>['makeRequest']; } export interface AnalyticsCollectionsValues { analyticsCollections: AnalyticsCollection[]; data: typeof FetchAnalyticsCollectionsAPILogic.values.data; hasNoAnalyticsCollections: boolean; + isFirstRequest: boolean; isLoading: boolean; status: Status; } @@ -31,26 +32,42 @@ export const AnalyticsCollectionsLogic = kea< MakeLogicType >({ actions: { - fetchAnalyticsCollections: () => {}, + fetchAnalyticsCollections: ({ query }) => ({ + query, + }), + setIsFirstRequest: true, }, connect: { - actions: [FetchAnalyticsCollectionsAPILogic, ['makeRequest']], + actions: [FetchAnalyticsCollectionsAPILogic, ['makeRequest', 'apiSuccess', 'apiError']], values: [FetchAnalyticsCollectionsAPILogic, ['data', 'status']], }, listeners: ({ actions }) => ({ fetchAnalyticsCollections: async ({ query }, breakpoint) => { if (query) { - await breakpoint(200) - actions.makeRequest({}); + await breakpoint(200); + } + actions.makeRequest({ query }); }, }), path: ['enterprise_search', 'analytics', 'collections'], + reducers: { + isFirstRequest: [ + true, + { + apiError: () => false, + apiSuccess: () => false, + }, + ], + }, selectors: ({ selectors }) => ({ analyticsCollections: [() => [selectors.data], (data) => data || []], - hasNoAnalyticsCollections: [() => [selectors.data], (data) => data?.length === 0], + hasNoAnalyticsCollections: [ + () => [selectors.data, selectors.isFirstRequest], + (data, isFirstRequest) => data?.length === 0 && isFirstRequest, + ], isLoading: [ - () => [selectors.status], - (status) => [Status.LOADING, Status.IDLE].includes(status), + () => [selectors.status, selectors.isFirstRequest], + (status, isFirstRequest) => [Status.LOADING, Status.IDLE].includes(status) && isFirstRequest, ], }), }); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx index 778de4c1fa81e5..92ef2a4ed4e8dd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx @@ -29,7 +29,7 @@ import { AnalyticsOverviewEmptyPage } from './analytics_overview_empty_page'; export const AnalyticsOverview: React.FC = () => { const { fetchAnalyticsCollections } = useActions(AnalyticsCollectionsLogic); - const { analyticsCollections, isLoading, hasNoAnalyticsCollections } = + const { analyticsCollections, isLoading, hasNoAnalyticsCollections, isFirstRequest } = useValues(AnalyticsCollectionsLogic); const { isCloud } = useValues(KibanaLogic); @@ -39,7 +39,7 @@ export const AnalyticsOverview: React.FC = () => { useEffect(() => { if (isGated) return; - fetchAnalyticsCollections(); + fetchAnalyticsCollections({ query: '' }); }, []); return ( @@ -66,7 +66,7 @@ export const AnalyticsOverview: React.FC = () => { - ) : hasNoAnalyticsCollections ? ( + ) : hasNoAnalyticsCollections && isFirstRequest ? ( <> @@ -74,7 +74,9 @@ export const AnalyticsOverview: React.FC = () => { ) : ( console.log(query)} + onSearch={(query) => { + fetchAnalyticsCollections({ query }); + }} /> )} diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.ts index 4bc99895a6d444..92b040d7020891 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.ts @@ -50,12 +50,25 @@ export function registerAnalyticsRoutes({ router.get( { path: '/internal/enterprise_search/analytics/collections', - validate: {}, + validate: { + query: schema.object({ + query: schema.maybe(schema.string()), + }), + }, }, elasticsearchErrorHandler(log, async (context, request, response) => { const { client } = (await context.core).elasticsearch; - const collections = await fetchAnalyticsCollections(client); - return response.ok({ body: collections }); + try { + const query = request.query.query && request.query.query + '*'; + const collections = await fetchAnalyticsCollections(client, query); + return response.ok({ body: collections }); + } catch (error) { + if ((error as Error).message === ErrorCode.ANALYTICS_COLLECTION_NOT_FOUND) { + return response.ok({ body: [] }); + } + + throw error; + } }) ); From ef89024f85f1cf408be309eaef85a4452ae2ff84 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Thu, 20 Apr 2023 14:58:24 +0200 Subject: [PATCH 03/11] [Behavioral Analytics] Update fetch analytics collection logic. Split requests for fetching and searching --- .../analytics_collections_logic.ts | 46 +++++++++++++------ .../analytics_overview/analytics_overview.tsx | 16 +++---- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts index 057a0e34e38103..8dcd12aaad5219 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts @@ -16,15 +16,18 @@ import { } from '../../api/index/fetch_analytics_collections_api_logic'; export interface AnalyticsCollectionsActions { - fetchAnalyticsCollections({ query }: { query: string }): { query: string }; + fetchAnalyticsCollections(): void; makeRequest: Actions<{}, FetchAnalyticsCollectionsApiLogicResponse>['makeRequest']; + searchAnalyticsCollections(query?: string): { query: string }; } export interface AnalyticsCollectionsValues { analyticsCollections: AnalyticsCollection[]; data: typeof FetchAnalyticsCollectionsAPILogic.values.data; hasNoAnalyticsCollections: boolean; - isFirstRequest: boolean; - isLoading: boolean; + isFetching: boolean; + isSearchRequest: boolean; + isSearching: boolean; + searchQuery: string; status: Status; } @@ -32,17 +35,20 @@ export const AnalyticsCollectionsLogic = kea< MakeLogicType >({ actions: { - fetchAnalyticsCollections: ({ query }) => ({ + fetchAnalyticsCollections: true, + searchAnalyticsCollections: (query) => ({ query, }), - setIsFirstRequest: true, }, connect: { actions: [FetchAnalyticsCollectionsAPILogic, ['makeRequest', 'apiSuccess', 'apiError']], values: [FetchAnalyticsCollectionsAPILogic, ['data', 'status']], }, listeners: ({ actions }) => ({ - fetchAnalyticsCollections: async ({ query }, breakpoint) => { + fetchAnalyticsCollections: () => { + actions.makeRequest({}); + }, + searchAnalyticsCollections: async ({ query }, breakpoint) => { if (query) { await breakpoint(200); } @@ -51,23 +57,33 @@ export const AnalyticsCollectionsLogic = kea< }), path: ['enterprise_search', 'analytics', 'collections'], reducers: { - isFirstRequest: [ - true, + isSearchRequest: [ + false, { - apiError: () => false, - apiSuccess: () => false, + searchAnalyticsCollections: () => true, + }, + ], + searchQuery: [ + '', + { + searchAnalyticsCollections: (_, { query }) => query, }, ], }, selectors: ({ selectors }) => ({ analyticsCollections: [() => [selectors.data], (data) => data || []], hasNoAnalyticsCollections: [ - () => [selectors.data, selectors.isFirstRequest], - (data, isFirstRequest) => data?.length === 0 && isFirstRequest, + () => [selectors.data, selectors.searchQuery], + (data, searchQuery) => data?.length === 0 && !searchQuery, + ], + isFetching: [ + () => [selectors.status, selectors.isSearchRequest], + (status, isSearchRequest) => + [Status.LOADING, Status.IDLE].includes(status) && !isSearchRequest, ], - isLoading: [ - () => [selectors.status, selectors.isFirstRequest], - (status, isFirstRequest) => [Status.LOADING, Status.IDLE].includes(status) && isFirstRequest, + isSearching: [ + () => [selectors.status, selectors.isSearchRequest], + (status, isSearchRequest) => Status.LOADING === status && isSearchRequest, ], }), }); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx index 92ef2a4ed4e8dd..33bfa6d504bace 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx @@ -28,8 +28,9 @@ import { AnalyticsCollectionsLogic } from './analytics_collections_logic'; import { AnalyticsOverviewEmptyPage } from './analytics_overview_empty_page'; export const AnalyticsOverview: React.FC = () => { - const { fetchAnalyticsCollections } = useActions(AnalyticsCollectionsLogic); - const { analyticsCollections, isLoading, hasNoAnalyticsCollections, isFirstRequest } = + const { fetchAnalyticsCollections, searchAnalyticsCollections } = + useActions(AnalyticsCollectionsLogic); + const { analyticsCollections, hasNoAnalyticsCollections, isFetching, isSearching } = useValues(AnalyticsCollectionsLogic); const { isCloud } = useValues(KibanaLogic); @@ -39,14 +40,14 @@ export const AnalyticsOverview: React.FC = () => { useEffect(() => { if (isGated) return; - fetchAnalyticsCollections({ query: '' }); + fetchAnalyticsCollections(); }, []); return ( { - ) : hasNoAnalyticsCollections && isFirstRequest ? ( + ) : hasNoAnalyticsCollections && !isSearching ? ( <> @@ -74,9 +75,8 @@ export const AnalyticsOverview: React.FC = () => { ) : ( { - fetchAnalyticsCollections({ query }); - }} + isSearching={isSearching} + onSearch={searchAnalyticsCollections} /> )} From 6d1d25a7c0acb1443710add31f9ff13c8c67338f Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Thu, 20 Apr 2023 14:59:16 +0200 Subject: [PATCH 04/11] [Behavioral Analytics] Add not found state for collection list page --- .../analytics_collection_not_found.tsx | 43 +++++++++++++++++++ .../analytics_collection_table.tsx | 35 +++++++++------ 2 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_not_found.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_not_found.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_not_found.tsx new file mode 100644 index 00000000000000..146bbb8b40482b --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_not_found.tsx @@ -0,0 +1,43 @@ +/* + * 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 React from 'react'; + +import { EuiEmptyPrompt, EuiImage } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import noMlModelsGraphicDark from '../../../../assets/images/no_ml_models_dark.svg'; + +const ICON_WIDTH = 294; + +interface AnalyticsCollectionNotFoundProps { + query: string; +} + +export const AnalyticsCollectionNotFound: React.FC = ({ + query, +}) => ( + } + title={ +

+ {i18n.translate('xpack.enterpriseSearch.analytics.collections.emptyState.headingTitle', { + defaultMessage: 'No results found for “{query}”', + values: { query }, + })} +

+ } + body={ +

+ {i18n.translate('xpack.enterpriseSearch.analytics.collections.emptyState.subHeading', { + defaultMessage: 'Try searching for another term.', + })} +

+ } + /> +); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.tsx index 8e2290d549f7d3..705ddf29145ad4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.tsx @@ -13,7 +13,6 @@ import { EuiPanel, EuiSuperDatePicker, EuiSuperDatePickerCommonRange, - EuiEmptyPrompt, EuiFlexGroup, EuiSpacer, EuiButtonGroup, @@ -23,6 +22,7 @@ import { } from '@elastic/eui'; import { OnTimeChangeProps } from '@elastic/eui/src/components/date_picker/super_date_picker/super_date_picker'; + import { i18n } from '@kbn/i18n'; import { AnalyticsCollection } from '../../../../../common/types/analytics'; @@ -31,6 +31,7 @@ import { AddAnalyticsCollection } from '../add_analytics_collections/add_analyti import { AnalyticsCollectionCardWithLens } from './analytics_collection_card/analytics_collection_card'; +import { AnalyticsCollectionNotFound } from './analytics_collection_not_found'; import { AnalyticsCollectionTableStyles } from './analytics_collection_table.styles'; const defaultQuickRanges: EuiSuperDatePickerCommonRange[] = [ @@ -73,11 +74,13 @@ const defaultQuickRanges: EuiSuperDatePickerCommonRange[] = [ interface AnalyticsCollectionTableProps { collections: AnalyticsCollection[]; + isSearching: boolean; onSearch: (query: string) => void; } export const AnalyticsCollectionTable: React.FC = ({ collections, + isSearching, onSearch, }) => { const { euiTheme } = useEuiTheme(); @@ -139,8 +142,10 @@ export const AnalyticsCollectionTable: React.FC = onChange={(e) => { setQuery(e.target.value); }} + isLoading={isSearching} onSearch={onSearch} incremental + fullWidth /> @@ -170,18 +175,22 @@ export const AnalyticsCollectionTable: React.FC =
- - {collections.map((collection) => ( - - ))} - + {collections.length ? ( + + {collections.map((collection) => ( + + ))} + + ) : ( + + )} ( Date: Thu, 20 Apr 2023 22:23:05 +0200 Subject: [PATCH 05/11] [Behavioral Analytics] Fix kea logic issue related with same subpath --- .../analytics_collection_data_view_logic.ts | 4 +- ...nalytics_collection_explore_table_logic.ts | 38 ++++++++++++++----- .../analytics_collection_toolbar_logic.ts | 2 +- .../delete_analytics_collection_logic.ts | 2 +- .../analytics_collections_logic.ts | 2 +- 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_data_view_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_data_view_logic.ts index 8d53757db78b6c..f00ef0fecc1edf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_data_view_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_data_view_logic.ts @@ -16,7 +16,7 @@ import { FetchAnalyticsCollectionLogic, } from './fetch_analytics_collection_logic'; -interface AnalyticsCollectionDataViewLogicValues { +export interface AnalyticsCollectionDataViewLogicValues { dataView: DataView | null; } @@ -39,7 +39,7 @@ export const AnalyticsCollectionDataViewLogic = kea< actions.setDataView(await findOrCreateDataView(collection)); }, }), - path: ['enterprise_search', 'analytics', 'collections', 'dataView'], + path: ['enterprise_search', 'analytics', 'collection', 'dataView'], reducers: () => ({ dataView: [null, { setDataView: (_, { dataView }) => dataView }], }), diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts index cce07541a9a2e8..86dfe3228c781b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts @@ -16,7 +16,10 @@ import { import { KibanaLogic } from '../../../shared/kibana/kibana_logic'; -import { AnalyticsCollectionDataViewLogic } from './analytics_collection_data_view_logic'; +import { + AnalyticsCollectionDataViewLogic, + AnalyticsCollectionDataViewLogicValues, +} from './analytics_collection_data_view_logic'; import { getBaseSearchTemplate, @@ -33,7 +36,10 @@ import { TopReferrersTable, WorsePerformersTable, } from './analytics_collection_explore_table_types'; -import { AnalyticsCollectionToolbarLogic } from './analytics_collection_toolbar/analytics_collection_toolbar_logic'; +import { + AnalyticsCollectionToolbarLogic, + AnalyticsCollectionToolbarLogicValues, +} from './analytics_collection_toolbar/analytics_collection_toolbar_logic'; const BASE_PAGE_SIZE = 10; @@ -243,13 +249,16 @@ const tablesParams: { }; export interface AnalyticsCollectionExploreTableLogicValues { + dataView: AnalyticsCollectionDataViewLogicValues['dataView']; isLoading: boolean; items: ExploreTableItem[]; pageIndex: number; pageSize: number; search: string; + searchSessionId: AnalyticsCollectionToolbarLogicValues['searchSessionId']; selectedTable: ExploreTables | null; sorting: Sorting | null; + timeRange: AnalyticsCollectionToolbarLogicValues['timeRange']; totalItemsCount: number; } @@ -282,6 +291,15 @@ export const AnalyticsCollectionExploreTableLogic = kea< setSelectedTable: (id, sorting) => ({ id, sorting }), setTotalItemsCount: (count) => ({ count }), }, + connect: { + actions: [AnalyticsCollectionToolbarLogic, ['setTimeRange', 'setSearchSessionId']], + values: [ + AnalyticsCollectionDataViewLogic, + ['dataView'], + AnalyticsCollectionToolbarLogic, + ['timeRange', 'searchSessionId'], + ], + }, listeners: ({ actions, values }) => { const fetchItems = () => { if (values.selectedTable === null || !(values.selectedTable in tablesParams)) { @@ -289,7 +307,7 @@ export const AnalyticsCollectionExploreTableLogic = kea< } const { requestParams, parseResponse } = tablesParams[values.selectedTable] as TableParams; - const timeRange = AnalyticsCollectionToolbarLogic.values.timeRange; + const timeRange = values.timeRange; const search$ = KibanaLogic.values.data.search .search( @@ -301,8 +319,8 @@ export const AnalyticsCollectionExploreTableLogic = kea< timeRange, }), { - indexPattern: AnalyticsCollectionDataViewLogic.values.dataView || undefined, - sessionId: AnalyticsCollectionToolbarLogic.values.searchSessionId, + indexPattern: values.dataView || undefined, + sessionId: values.searchSessionId, } ) .subscribe({ @@ -324,12 +342,12 @@ export const AnalyticsCollectionExploreTableLogic = kea< return { onTableChange: fetchItems, setSearch: fetchItems, + setSearchSessionId: fetchItems, setSelectedTable: fetchItems, - [AnalyticsCollectionToolbarLogic.actionTypes.setTimeRange]: fetchItems, - [AnalyticsCollectionToolbarLogic.actionTypes.setSearchSessionId]: fetchItems, + setTimeRange: fetchItems, }; }, - path: ['enterprise_search', 'analytics', 'collections', 'explore', 'table'], + path: ['enterprise_search', 'analytics', 'collection', 'explore', 'table'], reducers: () => ({ isLoading: [ false, @@ -337,10 +355,10 @@ export const AnalyticsCollectionExploreTableLogic = kea< onTableChange: () => true, setItems: () => false, setSearch: () => true, + setSearchSessionId: () => true, setSelectedTable: () => true, setTableState: () => true, - [AnalyticsCollectionToolbarLogic.actionTypes.setTimeRange]: () => true, - [AnalyticsCollectionToolbarLogic.actionTypes.setSearchSessionId]: () => true, + setTimeRange: () => true, }, ], items: [[], { setItems: (_, { items }) => items }], diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_toolbar/analytics_collection_toolbar_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_toolbar/analytics_collection_toolbar_logic.ts index 412e3c502ab441..cfbe44b64d82c4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_toolbar/analytics_collection_toolbar_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_toolbar/analytics_collection_toolbar_logic.ts @@ -55,7 +55,7 @@ export const AnalyticsCollectionToolbarLogic = kea< actions.setSearchSessionId(null); }, }), - path: ['enterprise_search', 'analytics', 'collections', 'toolbar'], + path: ['enterprise_search', 'analytics', 'collection', 'toolbar'], reducers: () => ({ _searchSessionId: [ null, diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/delete_analytics_collection_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/delete_analytics_collection_logic.ts index ea0cf4476ac545..6913739863efa8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/delete_analytics_collection_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/delete_analytics_collection_logic.ts @@ -48,7 +48,7 @@ export const DeleteAnalyticsCollectionLogic = kea< actions.makeRequest({ name }); }, }), - path: ['enterprise_search', 'analytics', 'collections', 'delete'], + path: ['enterprise_search', 'analytics', 'collection', 'delete'], selectors: ({ selectors }) => ({ isLoading: [ () => [selectors.status], diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts index 8dcd12aaad5219..c4b0f05e77523a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts @@ -41,7 +41,7 @@ export const AnalyticsCollectionsLogic = kea< }), }, connect: { - actions: [FetchAnalyticsCollectionsAPILogic, ['makeRequest', 'apiSuccess', 'apiError']], + actions: [FetchAnalyticsCollectionsAPILogic, ['makeRequest']], values: [FetchAnalyticsCollectionsAPILogic, ['data', 'status']], }, listeners: ({ actions }) => ({ From 8113fbcb55e59739df7c5cf8feff9ba932b28fd6 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Fri, 21 Apr 2023 11:25:08 +0200 Subject: [PATCH 06/11] [Behavioral Analytics] Add loading state for search on explorer page --- .../analytics_collection_explore_table_logic.ts | 5 ++++- .../analytics_collection_explorer_table.tsx | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts index 86dfe3228c781b..707f837d6f61de 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts @@ -341,7 +341,10 @@ export const AnalyticsCollectionExploreTableLogic = kea< return { onTableChange: fetchItems, - setSearch: fetchItems, + setSearch: async (_, breakpoint) => { + await breakpoint(200); + fetchItems(); + }, setSearchSessionId: fetchItems, setSelectedTable: fetchItems, setTimeRange: fetchItems, diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explorer/analytics_collection_explorer_table.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explorer/analytics_collection_explorer_table.tsx index fe55aae3d16923..cc104fe93b7ba4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explorer/analytics_collection_explorer_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explorer/analytics_collection_explorer_table.tsx @@ -277,6 +277,7 @@ export const AnalyticsCollectionExplorerTable = () => { value={search} onChange={(event) => setSearch(event.target.value)} isClearable + isLoading={isLoading} incremental fullWidth /> From bf982e1ac03c05f5f19c4ec0e174bede7435848f Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 24 Apr 2023 12:56:00 +0200 Subject: [PATCH 07/11] [Behavioral Analytics] Add constant with search cooldown --- .../analytics_collection_explore_table_logic.ts | 3 ++- .../analytics_overview/analytics_collections_logic.ts | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts index 707f837d6f61de..c5cca289028862 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts @@ -42,6 +42,7 @@ import { } from './analytics_collection_toolbar/analytics_collection_toolbar_logic'; const BASE_PAGE_SIZE = 10; +const SEARCH_COOLDOWN = 200; export interface Sorting { direction: 'asc' | 'desc'; @@ -342,7 +343,7 @@ export const AnalyticsCollectionExploreTableLogic = kea< return { onTableChange: fetchItems, setSearch: async (_, breakpoint) => { - await breakpoint(200); + await breakpoint(SEARCH_COOLDOWN); fetchItems(); }, setSearchSessionId: fetchItems, diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts index c4b0f05e77523a..9f82369d4974d3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts @@ -15,6 +15,8 @@ import { FetchAnalyticsCollectionsApiLogicResponse, } from '../../api/index/fetch_analytics_collections_api_logic'; +const SEARCH_COOLDOWN = 200; + export interface AnalyticsCollectionsActions { fetchAnalyticsCollections(): void; makeRequest: Actions<{}, FetchAnalyticsCollectionsApiLogicResponse>['makeRequest']; @@ -50,7 +52,7 @@ export const AnalyticsCollectionsLogic = kea< }, searchAnalyticsCollections: async ({ query }, breakpoint) => { if (query) { - await breakpoint(200); + await breakpoint(SEARCH_COOLDOWN); } actions.makeRequest({ query }); }, From 8fd7f9a1e08f9be92696ae48f1996c40c8676f7e Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 24 Apr 2023 15:52:57 +0200 Subject: [PATCH 08/11] [Behavioral Analytics] Add tests --- .../analytics_collections_logic.test.ts | 93 +++++++++++++++++-- .../analytics_collections_logic.ts | 4 +- .../enterprise_search/analytics.test.ts | 74 +++++++++++++++ 3 files changed, 162 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.test.ts index 176ba5aabefcee..2a5a7c21a05eba 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.test.ts @@ -7,6 +7,8 @@ import { LogicMounter, mockFlashMessageHelpers } from '../../../__mocks__/kea_logic'; +import { nextTick } from '@kbn/test-jest-helpers'; + import { AnalyticsCollection } from '../../../../../common/types/analytics'; import { HttpError, Status } from '../../../../../common/types/api'; @@ -28,8 +30,11 @@ describe('analyticsCollectionsLogic', () => { const DEFAULT_VALUES = { analyticsCollections: [], data: undefined, - hasNoAnalyticsCollections: false, - isLoading: true, + hasNoAnalyticsCollections: true, + isFetching: true, + isSearchRequest: false, + isSearching: false, + searchQuery: '', status: Status.IDLE, }; @@ -45,9 +50,9 @@ describe('analyticsCollectionsLogic', () => { expect(AnalyticsCollectionsLogic.values).toEqual({ ...DEFAULT_VALUES, analyticsCollections: [], - hasNoAnalyticsCollections: true, data: [], - isLoading: false, + hasNoAnalyticsCollections: true, + isFetching: false, status: Status.SUCCESS, }); }); @@ -64,12 +69,23 @@ describe('analyticsCollectionsLogic', () => { expect(AnalyticsCollectionsLogic.values).toEqual({ ...DEFAULT_VALUES, analyticsCollections: collections, + hasNoAnalyticsCollections: false, data: collections, - isLoading: false, + isFetching: false, status: Status.SUCCESS, }); }); }); + + it('updates searchQuery when searchAnalyticsCollections is called', () => { + AnalyticsCollectionsLogic.actions.searchAnalyticsCollections('test'); + expect(AnalyticsCollectionsLogic.values.searchQuery).toBe('test'); + }); + + it('updates isSearchRequest when searchAnalyticsCollections is called', () => { + AnalyticsCollectionsLogic.actions.searchAnalyticsCollections('test'); + expect(AnalyticsCollectionsLogic.values.isSearchRequest).toBe(true); + }); }); describe('listeners', () => { @@ -84,11 +100,20 @@ describe('analyticsCollectionsLogic', () => { expect(mockFlashMessageHelpers.flashAPIErrors).toHaveBeenCalledWith({}); }); - it('calls makeRequest on fetchAnalyticsCollections', async () => { + it('calls makeRequest on fetchAnalyticsCollections', () => { AnalyticsCollectionsLogic.actions.makeRequest = jest.fn(); AnalyticsCollectionsLogic.actions.fetchAnalyticsCollections(); expect(AnalyticsCollectionsLogic.actions.makeRequest).toHaveBeenCalledWith({}); }); + + it('calls makeRequest query on searchAnalyticsCollections', async () => { + jest.useFakeTimers({ legacyFakeTimers: true }); + AnalyticsCollectionsLogic.actions.makeRequest = jest.fn(); + AnalyticsCollectionsLogic.actions.searchAnalyticsCollections('test'); + jest.advanceTimersByTime(200); + await nextTick(); + expect(AnalyticsCollectionsLogic.actions.makeRequest).toHaveBeenCalledWith({ query: 'test' }); + }); }); describe('selectors', () => { @@ -101,10 +126,64 @@ describe('analyticsCollectionsLogic', () => { analyticsCollections: [], data: [], hasNoAnalyticsCollections: true, - isLoading: false, + isFetching: false, status: Status.SUCCESS, }); }); }); + + describe('isFetching', () => { + it('updates on initialState', () => { + expect(AnalyticsCollectionsLogic.values.isFetching).toBe(true); + }); + + it('updates when fetchAnalyticsCollections listener triggered', () => { + AnalyticsCollectionsLogic.actions.fetchAnalyticsCollections(); + expect(AnalyticsCollectionsLogic.values.isFetching).toBe(true); + }); + + it('updates when apiSuccess listener triggered', () => { + FetchAnalyticsCollectionsAPILogic.actions.apiSuccess([]); + expect(AnalyticsCollectionsLogic.values.isFetching).toBe(false); + }); + + it('updates when search request triggered', () => { + AnalyticsCollectionsLogic.actions.searchAnalyticsCollections('test'); + expect(AnalyticsCollectionsLogic.values.isFetching).toBe(false); + }); + }); + + describe('isSearching', () => { + it('updates on initialState', () => { + expect(AnalyticsCollectionsLogic.values.isSearching).toBe(false); + }); + + it('updates when fetchAnalyticsCollections listener triggered', () => { + AnalyticsCollectionsLogic.actions.fetchAnalyticsCollections(); + expect(AnalyticsCollectionsLogic.values.isSearching).toBe(false); + }); + + it('updates when apiSuccess listener triggered', () => { + FetchAnalyticsCollectionsAPILogic.actions.apiSuccess([]); + expect(AnalyticsCollectionsLogic.values.isSearching).toBe(false); + }); + }); + + describe('hasNoAnalyticsCollections', () => { + it('returns false when no items and search query is not empty', () => { + AnalyticsCollectionsLogic.actions.searchAnalyticsCollections('test'); + expect(AnalyticsCollectionsLogic.values.searchQuery).toBe('test'); + expect(AnalyticsCollectionsLogic.values.hasNoAnalyticsCollections).toBe(false); + }); + + it('returns true when no items and search query is empty', () => { + AnalyticsCollectionsLogic.actions.searchAnalyticsCollections(''); + expect(AnalyticsCollectionsLogic.values.hasNoAnalyticsCollections).toBeTruthy(); + }); + + it('returns true when no items and search query is undefined', () => { + expect(AnalyticsCollectionsLogic.values.hasNoAnalyticsCollections).toBeTruthy(); + }); + }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts index 9f82369d4974d3..bfe86f2874a605 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collections_logic.ts @@ -75,8 +75,8 @@ export const AnalyticsCollectionsLogic = kea< selectors: ({ selectors }) => ({ analyticsCollections: [() => [selectors.data], (data) => data || []], hasNoAnalyticsCollections: [ - () => [selectors.data, selectors.searchQuery], - (data, searchQuery) => data?.length === 0 && !searchQuery, + () => [selectors.analyticsCollections, selectors.searchQuery], + (analyticsCollections, searchQuery) => analyticsCollections.length === 0 && !searchQuery, ], isFetching: [ () => [selectors.status, selectors.isSearchRequest], diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.test.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.test.ts index 2f97e6362a9eee..690379fc0c4c35 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.test.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.test.ts @@ -25,6 +25,80 @@ describe('Enterprise Search Analytics API', () => { let mockRouter: MockRouter; const mockClient = {}; + describe('GET /internal/enterprise_search/analytics/collections', () => { + beforeEach(() => { + const context = { + core: Promise.resolve({ elasticsearch: { client: mockClient } }), + } as jest.Mocked; + + mockRouter = new MockRouter({ + context, + method: 'get', + path: '/internal/enterprise_search/analytics/collections', + }); + + const mockDataPlugin = { + indexPatterns: { + dataViewsServiceFactory: jest.fn(), + }, + }; + + const mockedSavedObjects = { + getScopedClient: jest.fn(), + }; + + registerAnalyticsRoutes({ + ...mockDependencies, + data: mockDataPlugin as unknown as DataPluginStart, + savedObjects: mockedSavedObjects as unknown as SavedObjectsServiceStart, + router: mockRouter.router, + }); + }); + + it('fetches a defined analytics collections', async () => { + const mockData: AnalyticsCollection[] = [ + { + events_datastream: 'logs-elastic_analytics.events-example', + name: 'my_collection', + }, + { + events_datastream: 'logs-elastic_analytics.events-example2', + name: 'my_collection2', + }, + { + events_datastream: 'logs-elastic_analytics.events-example2', + name: 'my_collection3', + }, + ]; + + (fetchAnalyticsCollections as jest.Mock).mockImplementationOnce(() => { + return Promise.resolve(mockData); + }); + await mockRouter.callRoute({}); + + expect(mockRouter.response.ok).toHaveBeenCalledWith({ + body: mockData, + }); + }); + + it('passes the query string to the fetch function', async () => { + await mockRouter.callRoute({ query: { query: 'my_collection2' } }); + + expect(fetchAnalyticsCollections).toHaveBeenCalledWith(mockClient, 'my_collection2*'); + }); + + it('returns an empty obj when fetchAnalyticsCollections returns not found error', async () => { + (fetchAnalyticsCollections as jest.Mock).mockImplementationOnce(() => { + throw new Error(ErrorCode.ANALYTICS_COLLECTION_NOT_FOUND); + }); + await mockRouter.callRoute({}); + + expect(mockRouter.response.ok).toHaveBeenCalledWith({ + body: [], + }); + }); + }); + describe('GET /internal/enterprise_search/analytics/collections/{id}', () => { beforeEach(() => { const context = { From 73e0b7ed96b06e76bff306c7d13f2abfcc1995ed Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 24 Apr 2023 15:59:26 +0200 Subject: [PATCH 09/11] [Behavioral Analytics] Fix CI errors --- ...ch_analytics_collections_api_logic.test.ts | 2 +- .../fetch_analytics_collections_api_logic.ts | 2 +- .../analytics_collection_table.test.tsx | 22 +++++++++++++------ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.test.ts index 08478bf32b3620..7815d2910a989f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.test.ts @@ -21,7 +21,7 @@ describe('FetchAnalyticsCollectionsApiLogic', () => { it('calls the analytics collections list api', async () => { const promise = Promise.resolve([{ name: 'result' }]); http.get.mockReturnValue(promise); - const result = fetchAnalyticsCollections(); + const result = fetchAnalyticsCollections({}); await nextTick(); expect(http.get).toHaveBeenCalledWith('/internal/enterprise_search/analytics/collections'); await expect(result).resolves.toEqual([{ name: 'result' }]); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.ts index 88bdf5fcccc537..45567d92026392 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.ts @@ -13,7 +13,7 @@ import { HttpLogic } from '../../../shared/http'; export type FetchAnalyticsCollectionsApiLogicResponse = AnalyticsCollection[]; interface FetchAnalyticsCollectionsApiLogicArgs { - query: string; + query?: string; } export const fetchAnalyticsCollections = async ({ diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.test.tsx index 461f24df6a1ca4..af6c9a4ebb73c3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_table.test.tsx @@ -16,6 +16,7 @@ import { EuiButtonGroup, EuiSuperDatePicker } from '@elastic/eui'; import { AnalyticsCollection } from '../../../../../common/types/analytics'; import { AnalyticsCollectionCardWithLens } from './analytics_collection_card/analytics_collection_card'; +import { AnalyticsCollectionNotFound } from './analytics_collection_not_found'; import { AnalyticsCollectionTable } from './analytics_collection_table'; @@ -30,13 +31,18 @@ describe('AnalyticsCollectionTable', () => { name: 'example2', }, ]; + const props = { + collections: analyticsCollections, + isSearching: false, + onSearch: jest.fn(), + }; beforeEach(() => { jest.clearAllMocks(); }); it('renders cards', () => { - const wrapper = shallow(); + const wrapper = shallow(); const collectionCards = wrapper.find(AnalyticsCollectionCardWithLens); expect(collectionCards).toHaveLength(analyticsCollections.length); @@ -44,9 +50,7 @@ describe('AnalyticsCollectionTable', () => { }); it('renders filters', () => { - const buttonGroup = shallow( - - ).find(EuiButtonGroup); + const buttonGroup = shallow().find(EuiButtonGroup); expect(buttonGroup).toHaveLength(1); expect(buttonGroup.prop('options')).toHaveLength(4); @@ -54,12 +58,16 @@ describe('AnalyticsCollectionTable', () => { }); it('renders datePick', () => { - const datePicker = shallow( - - ).find(EuiSuperDatePicker); + const datePicker = shallow().find(EuiSuperDatePicker); expect(datePicker).toHaveLength(1); expect(datePicker.prop('start')).toEqual('now-7d'); expect(datePicker.prop('end')).toEqual('now'); }); + + it('renders not found page', () => { + const wrapper = shallow(); + + expect(wrapper.find(AnalyticsCollectionNotFound)).toHaveLength(1); + }); }); From 5b808c54a61dd4f6ea52ff2fa3e98d78c53237f6 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 24 Apr 2023 17:13:47 +0200 Subject: [PATCH 10/11] [Behavioral Analytics] Fix translations --- .../analytics_overview/analytics_collection_not_found.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_not_found.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_not_found.tsx index 146bbb8b40482b..8f3359e764b5b0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_not_found.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_collection_not_found.tsx @@ -26,7 +26,7 @@ export const AnalyticsCollectionNotFound: React.FC} title={

- {i18n.translate('xpack.enterpriseSearch.analytics.collections.emptyState.headingTitle', { + {i18n.translate('xpack.enterpriseSearch.analytics.collections.notFound.headingTitle', { defaultMessage: 'No results found for “{query}”', values: { query }, })} @@ -34,7 +34,7 @@ export const AnalyticsCollectionNotFound: React.FC - {i18n.translate('xpack.enterpriseSearch.analytics.collections.emptyState.subHeading', { + {i18n.translate('xpack.enterpriseSearch.analytics.collections.notFound.subHeading', { defaultMessage: 'Try searching for another term.', })}

From f7f29ae74186b5c156bac7400c58609bbb1d5962 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 24 Apr 2023 22:50:04 +0200 Subject: [PATCH 11/11] [Behavioral Analytics] Update tests --- ...etch_analytics_collections_api_logic.test.ts | 4 +++- ...ytics_collection_explore_table_logic.test.ts | 17 ++++++++++++++++- .../analytics_collection_explore_table_logic.ts | 3 +++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.test.ts index 7815d2910a989f..15d73d21ff8908 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/api/index/fetch_analytics_collections_api_logic.test.ts @@ -23,7 +23,9 @@ describe('FetchAnalyticsCollectionsApiLogic', () => { http.get.mockReturnValue(promise); const result = fetchAnalyticsCollections({}); await nextTick(); - expect(http.get).toHaveBeenCalledWith('/internal/enterprise_search/analytics/collections'); + expect(http.get).toHaveBeenCalledWith('/internal/enterprise_search/analytics/collections', { + query: { query: '' }, + }); await expect(result).resolves.toEqual([{ name: 'result' }]); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.test.ts index 6f02ab06fedfb9..226c521c448947 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.test.ts @@ -7,6 +7,8 @@ import { LogicMounter } from '../../../__mocks__/kea_logic'; +import { nextTick } from '@kbn/test-jest-helpers'; + import { KibanaLogic } from '../../../shared/kibana/kibana_logic'; import { @@ -38,6 +40,7 @@ describe('AnalyticsCollectionExplorerTablesLogic', () => { }); const defaultProps = { + dataView: null, isLoading: false, items: [], pageIndex: 0, @@ -45,6 +48,10 @@ describe('AnalyticsCollectionExplorerTablesLogic', () => { search: '', selectedTable: null, sorting: null, + timeRange: { + from: 'now-7d', + to: 'now', + }, totalItemsCount: 0, }; @@ -79,6 +86,10 @@ describe('AnalyticsCollectionExplorerTablesLogic', () => { }); describe('isLoading', () => { + beforeEach(() => { + mount({ selectedTable: ExploreTables.TopReferrers }); + }); + it('should handle onTableChange', () => { AnalyticsCollectionExploreTableLogic.actions.onTableChange({ page: { index: 2, size: 10 }, @@ -241,11 +252,15 @@ describe('AnalyticsCollectionExplorerTablesLogic', () => { }); }); - it('should fetch items when search changes', () => { + it('should fetch items when search changes', async () => { + jest.useFakeTimers({ legacyFakeTimers: true }); AnalyticsCollectionExploreTableLogic.actions.setSelectedTable(ExploreTables.WorsePerformers); (KibanaLogic.values.data.search.search as jest.Mock).mockClear(); AnalyticsCollectionExploreTableLogic.actions.setSearch('test'); + jest.advanceTimersByTime(200); + await nextTick(); + expect(KibanaLogic.values.data.search.search).toHaveBeenCalledWith(expect.any(Object), { indexPattern: undefined, sessionId: undefined, diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts index c5cca289028862..1cb13bf9dc336a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_explore_table_logic.ts @@ -304,6 +304,9 @@ export const AnalyticsCollectionExploreTableLogic = kea< listeners: ({ actions, values }) => { const fetchItems = () => { if (values.selectedTable === null || !(values.selectedTable in tablesParams)) { + actions.setItems([]); + actions.setTotalItemsCount(0); + return; }