From b6946522d52ef993482793e13103dbd7fbc1bc00 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Thu, 22 Aug 2024 09:12:03 -0400 Subject: [PATCH 01/21] Rename component --- .../details/components/investigation_details/index.stories.tsx | 2 +- .../{index.tsx => investigation_details.tsx} | 0 .../public/pages/details/investigation_details_page.tsx | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/{index.tsx => investigation_details.tsx} (100%) diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/index.stories.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/index.stories.tsx index 8dfb18a753ac2..0db6f0fc5b71c 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/index.stories.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/index.stories.tsx @@ -7,7 +7,7 @@ import { ComponentMeta, ComponentStoryObj } from '@storybook/react'; import React from 'react'; -import { InvestigationDetails as Component } from '.'; +import { InvestigationDetails as Component } from './investigation_details'; import { KibanaReactStorybookDecorator } from '../../../../../.storybook/storybook_decorator'; const meta: ComponentMeta = { diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx similarity index 100% rename from x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/index.tsx rename to x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx index 90af6b4591c69..8145523398b00 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx @@ -15,7 +15,7 @@ import { paths } from '../../../common/paths'; import { useFetchAlert } from '../../hooks/use_get_alert_details'; import { useFetchInvestigation } from '../../hooks/use_get_investigation_details'; import { useKibana } from '../../hooks/use_kibana'; -import { InvestigationDetails } from './components/investigation_details'; +import { InvestigationDetails } from './components/investigation_details/investigation_details'; import { InvestigationDetailsPathParams } from './types'; export function InvestigationDetailsPage() { From 68c145c2b7bf0d182b8bf8378f73bc6ef35b87b5 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Thu, 22 Aug 2024 09:14:33 -0400 Subject: [PATCH 02/21] Remove extra component --- .../investigation_details.tsx | 17 +---------------- .../details/investigation_details_page.tsx | 12 +++++++++++- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx index c1c77ef564545..92cc324ee625e 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx @@ -8,7 +8,6 @@ import datemath from '@elastic/datemath'; import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; import { AuthenticatedUser } from '@kbn/security-plugin/common'; import React from 'react'; -import useAsync from 'react-use/lib/useAsync'; import { AddObservationUI } from '../../../../components/add_observation_ui'; import { InvestigateSearchBar } from '../../../../components/investigate_search_bar'; import { InvestigateWidgetGrid } from '../../../../components/investigate_widget_grid'; @@ -16,7 +15,7 @@ import { useFetchInvestigation } from '../../../../hooks/use_fetch_investigation import { useKibana } from '../../../../hooks/use_kibana'; import { InvestigationNotes } from '../investigation_notes/investigation_notes'; -function InvestigationDetailsWithUser({ +export function InvestigationDetails({ user, investigationId, }: { @@ -105,17 +104,3 @@ function InvestigationDetailsWithUser({ ); } - -export function InvestigationDetails({ investigationId }: { investigationId: string }) { - const { - core: { security }, - } = useKibana(); - - const user = useAsync(() => { - return security.authc.getCurrentUser(); - }, [security]); - - return user.value ? ( - - ) : null; -} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx index 8145523398b00..9c5653bebb123 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx @@ -11,6 +11,7 @@ import { alertOriginSchema } from '@kbn/investigation-shared'; import { ALERT_RULE_CATEGORY } from '@kbn/rule-data-utils/src/default_alerts_as_data'; import React from 'react'; import { useParams } from 'react-router-dom'; +import { useAsync } from 'react-use'; import { paths } from '../../../common/paths'; import { useFetchAlert } from '../../hooks/use_get_alert_details'; import { useFetchInvestigation } from '../../hooks/use_get_investigation_details'; @@ -22,12 +23,17 @@ export function InvestigationDetailsPage() { const { core: { http: { basePath }, + security, }, dependencies: { start: { observabilityShared }, }, } = useKibana(); + const user = useAsync(() => { + return security.authc.getCurrentUser(); + }, [security]); + const { investigationId } = useParams(); const ObservabilityPageTemplate = observabilityShared.navigation.PageTemplate; @@ -44,6 +50,10 @@ export function InvestigationDetailsPage() { const { data: alertDetails } = useFetchAlert({ id: alertId }); + if (!user.value) { + return null; + } + if (isFetchInvestigationLoading) { return (

@@ -106,7 +116,7 @@ export function InvestigationDetailsPage() { ], }} > - + ); } From 39f5cd47ea7c7052792aa740c30c0dfada62b7b3 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Thu, 22 Aug 2024 09:28:26 -0400 Subject: [PATCH 03/21] fix eslint --- packages/kbn-eslint-config/.eslintrc.js | 1 - .../public/pages/details/investigation_details_page.tsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/kbn-eslint-config/.eslintrc.js b/packages/kbn-eslint-config/.eslintrc.js index de3bb8e313ccc..a68dc6ecd949e 100644 --- a/packages/kbn-eslint-config/.eslintrc.js +++ b/packages/kbn-eslint-config/.eslintrc.js @@ -314,7 +314,6 @@ module.exports = { '@kbn/eslint/no_constructor_args_in_property_initializers': 'error', '@kbn/eslint/no_this_in_property_initializers': 'error', '@kbn/eslint/no_unsafe_console': 'error', - '@kbn/eslint/no_unsafe_js_yaml': 'error', '@kbn/imports/no_unresolvable_imports': 'error', '@kbn/imports/uniform_imports': 'error', '@kbn/imports/no_unused_imports': 'error', diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx index 9c5653bebb123..8bce69ea125af 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx @@ -11,7 +11,7 @@ import { alertOriginSchema } from '@kbn/investigation-shared'; import { ALERT_RULE_CATEGORY } from '@kbn/rule-data-utils/src/default_alerts_as_data'; import React from 'react'; import { useParams } from 'react-router-dom'; -import { useAsync } from 'react-use'; +import useAsync from 'react-use/lib/useAsync'; import { paths } from '../../../common/paths'; import { useFetchAlert } from '../../hooks/use_get_alert_details'; import { useFetchInvestigation } from '../../hooks/use_get_investigation_details'; From 70efe09f52476cc6b6a6e27dcedab5438c636375 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Thu, 22 Aug 2024 13:44:22 -0400 Subject: [PATCH 04/21] wip: attempt at registration of esql item --- .../src/schema/investigation_item.ts | 13 +- .../investigation/item_definition_registry.ts | 35 +++ .../investigate/public/plugin.tsx | 26 +- .../investigate/public/types.ts | 10 +- .../investigate_app/public/items/README.md | 1 + .../esql_item/get_date_histogram_results.ts | 54 ++++ .../items/esql_item/register_esql_item.tsx | 265 ++++++++++++++++++ .../public/items/register_items.ts | 22 ++ .../investigation_details.tsx | 4 +- .../investigate_app/public/plugin.tsx | 22 ++ 10 files changed, 435 insertions(+), 17 deletions(-) create mode 100644 x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts create mode 100644 x-pack/plugins/observability_solution/investigate_app/public/items/README.md create mode 100644 x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/get_date_histogram_results.ts create mode 100644 x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx create mode 100644 x-pack/plugins/observability_solution/investigate_app/public/items/register_items.ts diff --git a/packages/kbn-investigation-shared/src/schema/investigation_item.ts b/packages/kbn-investigation-shared/src/schema/investigation_item.ts index 8689224960c52..8efc8c04187a2 100644 --- a/packages/kbn-investigation-shared/src/schema/investigation_item.ts +++ b/packages/kbn-investigation-shared/src/schema/investigation_item.ts @@ -8,20 +8,23 @@ import * as t from 'io-ts'; -const esqlItemSchema = t.type({ - title: t.string, +const investigationEsqlItemSchema = t.type({ type: t.literal('esql'), params: t.type({ esql: t.string, suggestion: t.any, }), }); +type InvestigationEsqlItem = t.TypeOf; -const investigationItemsSchema = esqlItemSchema; // replace with union with various item types +const investigationItemsSchema = investigationEsqlItemSchema; // replace with union with various item types +type InvestigationItems = t.TypeOf; +type InvestigationItemTypes = t.TypeOf; const investigationItemSchema = t.intersection([ - t.type({ id: t.string, createdAt: t.number, createdBy: t.string }), + t.type({ id: t.string, createdAt: t.number, createdBy: t.string, title: t.string }), investigationItemsSchema, ]); -export { investigationItemSchema, investigationItemsSchema, esqlItemSchema }; +export type { InvestigationItems, InvestigationItemTypes, InvestigationEsqlItem }; +export { investigationItemSchema, investigationItemsSchema, investigationEsqlItemSchema }; diff --git a/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts b/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts new file mode 100644 index 0000000000000..0120ad3d4a550 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts @@ -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 { InvestigationItemTypes, InvestigationItems } from '@kbn/investigation-shared'; +import { GlobalWidgetParameters } from '../../common/types'; + +export interface ItemDefinition { + type: InvestigationItemTypes; + render: (option: { + item: InvestigationItems; + params: GlobalWidgetParameters; + }) => Promise; +} + +export class ItemDefinitionRegistry { + private readonly definitions: ItemDefinition[] = []; + + constructor() {} + + public registerItem(definition: ItemDefinition) { + this.definitions.push(definition); + } + + public getItemDefinitions(): ItemDefinition[] { + return this.definitions; + } + + public getItemDefinitionByType(type: InvestigationItemTypes): ItemDefinition | undefined { + return this.definitions.find((definition) => definition.type === type); + } +} diff --git a/x-pack/plugins/observability_solution/investigate/public/plugin.tsx b/x-pack/plugins/observability_solution/investigate/public/plugin.tsx index 887753446c4a9..62d003a462726 100644 --- a/x-pack/plugins/observability_solution/investigate/public/plugin.tsx +++ b/x-pack/plugins/observability_solution/investigate/public/plugin.tsx @@ -11,10 +11,11 @@ import type { Plugin, PluginInitializerContext, } from '@kbn/core/public'; -import { GetInvestigationResponse } from '@kbn/investigation-shared'; +import { GetInvestigationResponse, InvestigationItemTypes } from '@kbn/investigation-shared'; import type { Logger } from '@kbn/logging'; import { useMemo } from 'react'; import { createUseInvestigation } from './hooks/use_investigation'; +import { ItemDefinition, ItemDefinitionRegistry } from './investigation/item_definition_registry'; import type { ConfigSchema, InvestigatePublicSetup, @@ -33,19 +34,23 @@ export class InvestigatePlugin InvestigateStartDependencies > { - logger: Logger; - - widgetRegistry: WidgetRegistry = new WidgetRegistry(); - - registrationPromises: Array> = []; + private logger: Logger; + private widgetRegistry: WidgetRegistry = new WidgetRegistry(); + private itemDefinitionRegistry: ItemDefinitionRegistry = new ItemDefinitionRegistry(); constructor(context: PluginInitializerContext) { this.logger = context.logger.get(); } + setup(coreSetup: CoreSetup, pluginsSetup: InvestigateSetupDependencies): InvestigatePublicSetup { return { + // new + registerItemDefinition: (definition: ItemDefinition) => { + this.itemDefinitionRegistry.registerItem(definition); + }, + // old register: (callback) => { - const registrationPromise = Promise.race([ + Promise.race([ callback(this.widgetRegistry.registerWidget), new Promise((resolve, reject) => { setTimeout(() => { @@ -58,14 +63,17 @@ export class InvestigatePlugin ); return Promise.resolve(); }); - - this.registrationPromises.push(registrationPromise); }, }; } start(coreStart: CoreStart, pluginsStart: InvestigateStartDependencies): InvestigatePublicStart { return { + // new + getItemDefinitions: () => this.itemDefinitionRegistry.getItemDefinitions(), + getItemDefinitionByType: (type: InvestigationItemTypes) => + this.itemDefinitionRegistry.getItemDefinitionByType(type), + // old getWidgetDefinitions: this.widgetRegistry.getWidgetDefinitions, useInvestigation: ({ user, diff --git a/x-pack/plugins/observability_solution/investigate/public/types.ts b/x-pack/plugins/observability_solution/investigate/public/types.ts index dc6eb8b62021d..47d4afb4fb861 100644 --- a/x-pack/plugins/observability_solution/investigate/public/types.ts +++ b/x-pack/plugins/observability_solution/investigate/public/types.ts @@ -7,12 +7,13 @@ /* eslint-disable @typescript-eslint/no-empty-interface*/ import type { AuthenticatedUser } from '@kbn/core/public'; +import type { GetInvestigationResponse, InvestigationItemTypes } from '@kbn/investigation-shared'; import type { CompatibleJSONSchema } from '@kbn/observability-ai-assistant-plugin/public'; -import type { GetInvestigationResponse } from '@kbn/investigation-shared'; import type { FromSchema } from 'json-schema-to-ts'; import type { InvestigateWidget } from '../common'; import type { GlobalWidgetParameters, InvestigateWidgetCreate } from '../common/types'; import type { UseInvestigationApi } from './hooks/use_investigation'; +import { ItemDefinition } from './investigation/item_definition_registry'; export type OnWidgetAdd = (create: InvestigateWidgetCreate) => Promise; @@ -62,10 +63,17 @@ export interface InvestigateSetupDependencies {} export interface InvestigateStartDependencies {} export interface InvestigatePublicSetup { + // new + registerItemDefinition: (itemDefinition: ItemDefinition) => void; + // old register: (callback: (registerWidget: RegisterWidget) => Promise) => void; } export interface InvestigatePublicStart { + // new: + getItemDefinitions: () => ItemDefinition[]; + getItemDefinitionByType: (type: InvestigationItemTypes) => ItemDefinition | undefined; + // old: getWidgetDefinitions: () => WidgetDefinition[]; useInvestigation: ({}: { user: AuthenticatedUser; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/README.md b/x-pack/plugins/observability_solution/investigate_app/public/items/README.md new file mode 100644 index 0000000000000..710c9fd3624ec --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/README.md @@ -0,0 +1 @@ +This folder replaces widgets/ diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/get_date_histogram_results.ts b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/get_date_histogram_results.ts new file mode 100644 index 0000000000000..0ddfe6e38b887 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/get_date_histogram_results.ts @@ -0,0 +1,54 @@ +/* + * 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 { Suggestion } from '@kbn/lens-plugin/public'; +import type { ESQLColumn } from '@kbn/es-types'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import type { EsqlService } from '../../services/esql'; + +export async function getDateHistogramResults({ + query, + esql, + timeRange, + filter, + suggestion, + signal, + columns, +}: { + query: string; + esql: EsqlService; + timeRange: { + from: string; + to: string; + }; + filter: QueryDslQueryContainer; + suggestion: Suggestion; + signal: AbortSignal; + columns: ESQLColumn[]; +}) { + const groupingExpression = `BUCKET(@timestamp, 50, "${timeRange.from}", "${timeRange.to}")`; + const dateHistoQuery = `${query} | STATS count = COUNT(*) BY ${groupingExpression}`; + + const dateHistoResponse = + suggestion.visualizationId === 'lnsDatatable' && + columns.find((column) => column.name === '@timestamp') + ? await esql.queryWithMeta({ + query: dateHistoQuery, + signal, + filter, + }) + : undefined; + + return dateHistoResponse + ? { + columns: dateHistoResponse.query.columns, + values: dateHistoResponse.query.values, + query: dateHistoQuery, + groupingExpression, + } + : undefined; +} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx new file mode 100644 index 0000000000000..31d68de6ba534 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx @@ -0,0 +1,265 @@ +/* + * 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 { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; +import { css } from '@emotion/css'; +import type { DataView } from '@kbn/data-views-plugin/common'; +import type { ESQLSearchResponse } from '@kbn/es-types'; +import { ESQLDataGrid } from '@kbn/esql-datagrid/public'; +import { i18n } from '@kbn/i18n'; +import { type GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; +import { InvestigationEsqlItem } from '@kbn/investigation-shared'; +import type { Suggestion } from '@kbn/lens-plugin/public'; +import { useAbortableAsync } from '@kbn/observability-ai-assistant-plugin/public'; +import React, { useMemo } from 'react'; +import { ErrorMessage } from '../../components/error_message'; +import { useKibana } from '../../hooks/use_kibana'; +import { getDatatableFromEsqlResponse } from '../../utils/get_data_table_from_esql_response'; +import { getEsFilterFromOverrides } from '../../utils/get_es_filter_from_overrides'; +import { getLensAttrsForSuggestion } from '../../utils/get_lens_attrs_for_suggestion'; +import type { Options } from '../register_items'; +import { getDateHistogramResults } from './get_date_histogram_results'; + +const lensClassName = css` + height: 100%; +`; + +interface Props { + suggestion: Suggestion; + dataView: DataView; + esqlQuery: string; + columns: ESQLSearchResponse['columns']; + allColumns: ESQLSearchResponse['all_columns']; + values: ESQLSearchResponse['values']; + dateHistogramResults?: { + query: string; + columns: ESQLSearchResponse['columns']; + values: ESQLSearchResponse['values']; + groupingExpression: string; + }; +} + +export function EsqlWidget({ + suggestion, + dataView, + esqlQuery, + columns, + allColumns, + values, + dateHistogramResults, +}: Props) { + const { + dependencies: { + start: { lens }, + }, + } = useKibana(); + + const datatable = useMemo(() => { + return getDatatableFromEsqlResponse({ + columns, + values, + all_columns: allColumns, + }); + }, [columns, values, allColumns]); + + const input = useMemo(() => { + return getLensAttrsForSuggestion({ + suggestion, + dataView, + query: esqlQuery, + table: datatable, + }); + }, [suggestion, dataView, esqlQuery, datatable]); + + const memoizedQueryObject = useMemo(() => { + return { esql: esqlQuery }; + }, [esqlQuery]); + + const initialColumns = useMemo(() => { + const timestampColumn = datatable.columns.find((column) => column.name === '@timestamp'); + const messageColumn = datatable.columns.find((column) => column.name === 'message'); + + if (datatable.columns.length > 20 && timestampColumn && messageColumn) { + const hasDataForBothColumns = datatable.rows.every((row) => { + const timestampValue = row['@timestamp']; + const messageValue = row.message; + + return timestampValue !== null && timestampValue !== undefined && !!messageValue; + }); + + if (hasDataForBothColumns) { + return [timestampColumn, messageColumn]; + } + } + return datatable.columns; + }, [datatable.columns, datatable.rows]); + + const previewInput = useAbortableAsync( + async ({ signal }) => { + if (!dateHistogramResults) { + return undefined; + } + + const lensHelper = await lens.stateHelperApi(); + + const suggestionsFromLensHelper = await lensHelper.suggestions( + { + dataViewSpec: dataView.toSpec(), + fieldName: '', + textBasedColumns: [ + { + id: dateHistogramResults.groupingExpression, + name: i18n.translate('xpack.investigateApp.esqlWidget.groupedByDateLabel', { + defaultMessage: '@timestamp', + }), + meta: { + type: 'date', + }, + }, + { + id: 'count', + name: 'count', + meta: { + type: 'number', + }, + }, + ], + query: { + esql: dateHistogramResults.query, + }, + }, + dataView, + ['lnsDatatable'] + ); + + const suggestionForHistogram = suggestionsFromLensHelper?.[0]; + + if (!suggestionForHistogram) { + return undefined; + } + + return getLensAttrsForSuggestion({ + suggestion: suggestionForHistogram, + dataView, + query: dateHistogramResults.query, + table: getDatatableFromEsqlResponse({ + columns: dateHistogramResults.columns, + values: dateHistogramResults.values, + }), + }); + }, + [dataView, lens, dateHistogramResults] + ); + + if (input.attributes.visualizationType === 'lnsDatatable') { + let innerElement: React.ReactElement; + if (previewInput.error) { + innerElement = ; + } else if (previewInput.value) { + innerElement = ; + } else { + innerElement = ; + } + return ( + + div { + height: 128px; + } + `} + > + {innerElement} + + + + + + ); + } + + return ( + div { + height: 128px; + } + `} + > + + + ); +} + +export function registerEsqlItem({ + dependencies: { + setup: { investigate }, + }, + services, +}: Options) { + investigate.registerItemDefinition({ + type: 'esql', + render: async (option: { item: InvestigationEsqlItem; params: GlobalWidgetParameters }) => { + const controller = new AbortController(); + const { esql: esqlQuery, suggestion: suggestionFromParameters } = option.item.params; + const { timeRange } = option.params; + + const esql = await services.esql; + + const esFilters = [ + getEsFilterFromOverrides({ + timeRange, + }), + ]; + + const getFilter = () => ({ + bool: { + filter: [...esFilters], + }, + }); + + const mainResponse = await esql.queryWithMeta({ + query: esqlQuery, + signal: controller.signal, + filter: getFilter(), + }); + + const suggestion = suggestionFromParameters || mainResponse.meta.suggestions[0]; + + const dateHistoResponse = await getDateHistogramResults({ + query: esqlQuery, + columns: mainResponse.query.columns, + esql, + filter: getFilter(), + signal: controller.signal, + suggestion, + timeRange, + }); + + return ( + + ); + }, + }); +} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/register_items.ts b/x-pack/plugins/observability_solution/investigate_app/public/items/register_items.ts new file mode 100644 index 0000000000000..440e7755a50ba --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/register_items.ts @@ -0,0 +1,22 @@ +/* + * 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 { InvestigateAppServices } from '../services/types'; +import type { InvestigateAppSetupDependencies, InvestigateAppStartDependencies } from '../types'; +import { registerEsqlItem } from './esql_item/register_esql_item'; + +export interface Options { + dependencies: { + setup: InvestigateAppSetupDependencies; + start: InvestigateAppStartDependencies; + }; + services: InvestigateAppServices; +} + +export function registerItems(options: Options) { + registerEsqlItem(options); +} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx index 92cc324ee625e..d2cb74735059a 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx @@ -7,7 +7,7 @@ import datemath from '@elastic/datemath'; import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; import { AuthenticatedUser } from '@kbn/security-plugin/common'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { AddObservationUI } from '../../../../components/add_observation_ui'; import { InvestigateSearchBar } from '../../../../components/investigate_search_bar'; import { InvestigateWidgetGrid } from '../../../../components/investigate_widget_grid'; @@ -27,7 +27,7 @@ export function InvestigationDetails({ start: { investigate }, }, } = useKibana(); - // const widgetDefinitions = investigate.getWidgetDefinitions(); + const itemDefinitions = investigate.getItemDefinitions(); const { data: investigationData } = useFetchInvestigation({ id: investigationId }); const { diff --git a/x-pack/plugins/observability_solution/investigate_app/public/plugin.tsx b/x-pack/plugins/observability_solution/investigate_app/public/plugin.tsx index 75b07099cbb62..6309f41b26229 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/plugin.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/plugin.tsx @@ -125,6 +125,28 @@ export class InvestigateAppPlugin .getStartServices() .then(([, pluginsStart]) => pluginsStart); + // new + Promise.all([ + pluginsStartPromise, + import('./items/register_items').then((m) => m.registerItems), + getCreateEsqlService(), + ]).then(([pluginsStart, registerItems, createEsqlService]) => { + registerItems({ + dependencies: { + setup: pluginsSetup, + start: pluginsStart, + }, + services: { + esql: createEsqlService({ + data: pluginsStart.data, + dataViews: pluginsStart.dataViews, + lens: pluginsStart.lens, + }), + }, + }); + }); + + // old pluginsSetup.investigate.register((registerWidget) => Promise.all([ pluginsStartPromise, From 83f5505e3c29696b103517d91c7236cbda0c947f Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Thu, 22 Aug 2024 14:52:56 -0400 Subject: [PATCH 05/21] wip: generate items --- .../src/schema/investigation_item.ts | 11 +- .../investigation/item_definition_registry.ts | 11 +- .../investigate_app/kibana.jsonc | 1 - .../investigate_widget_grid/index.tsx | 9 +- .../items/esql_item/register_esql_item.tsx | 22 ++-- .../investigation_details.tsx | 116 ++++++++++++------ 6 files changed, 118 insertions(+), 52 deletions(-) diff --git a/packages/kbn-investigation-shared/src/schema/investigation_item.ts b/packages/kbn-investigation-shared/src/schema/investigation_item.ts index 8efc8c04187a2..0e8cc707c5bc2 100644 --- a/packages/kbn-investigation-shared/src/schema/investigation_item.ts +++ b/packages/kbn-investigation-shared/src/schema/investigation_item.ts @@ -9,6 +9,7 @@ import * as t from 'io-ts'; const investigationEsqlItemSchema = t.type({ + title: t.string, type: t.literal('esql'), params: t.type({ esql: t.string, @@ -22,9 +23,15 @@ type InvestigationItems = t.TypeOf; type InvestigationItemTypes = t.TypeOf; const investigationItemSchema = t.intersection([ - t.type({ id: t.string, createdAt: t.number, createdBy: t.string, title: t.string }), + t.type({ id: t.string, createdAt: t.number, createdBy: t.string }), investigationItemsSchema, ]); +type InvestigationItem = t.TypeOf; -export type { InvestigationItems, InvestigationItemTypes, InvestigationEsqlItem }; +export type { + InvestigationItem, + InvestigationItems, + InvestigationItemTypes, + InvestigationEsqlItem, +}; export { investigationItemSchema, investigationItemsSchema, investigationEsqlItemSchema }; diff --git a/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts b/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts index 0120ad3d4a550..04d9b87d3ccee 100644 --- a/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts +++ b/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts @@ -8,12 +8,19 @@ import { InvestigationItemTypes, InvestigationItems } from '@kbn/investigation-shared'; import { GlobalWidgetParameters } from '../../common/types'; +type ItemDefinitionGenerateData = Record; + +// type `data` somehow export interface ItemDefinition { type: InvestigationItemTypes; - render: (option: { + generate: (option: { item: InvestigationItems; params: GlobalWidgetParameters; - }) => Promise; + }) => Promise; + render: (option: { + data: ItemDefinitionGenerateData; + item: InvestigationItems; + }) => React.ReactNode; } export class ItemDefinitionRegistry { diff --git a/x-pack/plugins/observability_solution/investigate_app/kibana.jsonc b/x-pack/plugins/observability_solution/investigate_app/kibana.jsonc index 5b31cbc3973a2..19861110a579e 100644 --- a/x-pack/plugins/observability_solution/investigate_app/kibana.jsonc +++ b/x-pack/plugins/observability_solution/investigate_app/kibana.jsonc @@ -23,7 +23,6 @@ "requiredBundles": [ "kibanaReact", "kibanaUtils", - "esql", "esqlDataGrid", ], "optionalPlugins": [], diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.tsx index 41c3b3a3e8b66..9b6198d01c13a 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.tsx @@ -5,18 +5,17 @@ * 2.0. */ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { InvestigationItem } from '@kbn/investigation-shared'; import React from 'react'; import 'react-grid-layout/css/styles.css'; import 'react-resizable/css/styles.css'; import { GridItem } from '../grid_item'; import './styles.scss'; -export interface InvestigateWidgetGridItem { - id: string; - title: string; - element: React.ReactNode; +export type InvestigateWidgetGridItem = InvestigationItem & { loading: boolean; -} + element: React.ReactNode; +}; interface InvestigateWidgetGridProps { items: InvestigateWidgetGridItem[]; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx index 31d68de6ba534..17e59faa4da9b 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx @@ -212,7 +212,7 @@ export function registerEsqlItem({ }: Options) { investigate.registerItemDefinition({ type: 'esql', - render: async (option: { item: InvestigationEsqlItem; params: GlobalWidgetParameters }) => { + generate: async (option: { item: InvestigationEsqlItem; params: GlobalWidgetParameters }) => { const controller = new AbortController(); const { esql: esqlQuery, suggestion: suggestionFromParameters } = option.item.params; const { timeRange } = option.params; @@ -249,15 +249,23 @@ export function registerEsqlItem({ timeRange, }); + return { + mainResponse, + suggestion, + dateHistoResponse, + }; + }, + render: (option: { item: InvestigationEsqlItem; data: Record }) => { + const { item, data = {} } = option; return ( ); }, diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx index d2cb74735059a..370d9b572a648 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx @@ -4,11 +4,13 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import datemath from '@elastic/datemath'; + import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { InvestigationItem } from '@kbn/investigation-shared'; import { AuthenticatedUser } from '@kbn/security-plugin/common'; -import React, { useEffect, useState } from 'react'; -import { AddObservationUI } from '../../../../components/add_observation_ui'; +import { noop } from 'lodash'; +import React, { useEffect } from 'react'; import { InvestigateSearchBar } from '../../../../components/investigate_search_bar'; import { InvestigateWidgetGrid } from '../../../../components/investigate_widget_grid'; import { useFetchInvestigation } from '../../../../hooks/use_fetch_investigation'; @@ -27,22 +29,66 @@ export function InvestigationDetails({ start: { investigate }, }, } = useKibana(); - const itemDefinitions = investigate.getItemDefinitions(); - const { data: investigationData } = useFetchInvestigation({ id: investigationId }); + const { data: investigation } = useFetchInvestigation({ id: investigationId }); - const { - addItem, - copyItem, - deleteItem, - investigation, - setGlobalParameters, - renderableInvestigation, - } = investigate.useInvestigation({ - user, - investigationData, - }); + const [renderableItems, setRenderableItems] = React.useState< + Array + >([]); + + useEffect(() => { + async function renderItems(items: InvestigationItem[]) { + return await Promise.all( + items.map(async (item) => { + const itemDefinition = investigate.getItemDefinitionByType(item.type); + if (!itemDefinition) { + return Promise.resolve({ + ...item, + loading: false, + element: ( +
+ {i18n.translate('xpack.investigateApp.renderableItems.div.notFoundLabel', { + defaultMessage: 'Not found for type {type}', + values: { type: item.type }, + })} +
+ ), + }); + } + + const data = await itemDefinition.generate({ + item, + params: { + timeRange: { + from: investigation + ? new Date(investigation.params.timeRange.from).toISOString() + : new Date().toISOString(), + to: investigation + ? new Date(investigation.params.timeRange.to).toISOString() + : new Date().toISOString(), + }, + }, + }); + + return Promise.resolve({ + ...item, + loading: false, + element: itemDefinition.render({ + data, + item, + }), + }); + }) + ); + } + + if (investigation) { + renderItems(investigation.items).then((nextRenderableItems) => + setRenderableItems(nextRenderableItems) + ); + } + }, [investigation]); - if (!investigation || !renderableInvestigation || !investigationData) { + if (!investigation || !renderableItems) { return ; } @@ -54,47 +100,47 @@ export function InvestigationDetails({ { - const nextDateRange = { - from: datemath.parse(dateRange.from)!.toISOString(), - to: datemath.parse(dateRange.to)!.toISOString(), - }; - await setGlobalParameters({ - ...renderableInvestigation.parameters, - timeRange: nextDateRange, - }); + // const nextDateRange = { + // from: datemath.parse(dateRange.from)!.toISOString(), + // to: datemath.parse(dateRange.to)!.toISOString(), + // }; + // await setGlobalParameters({ + // ...renderableInvestigation.parameters, + // timeRange: nextDateRange, + // }); }} /> { - return copyItem(copiedItem.id); + return noop(); // copyItem(copiedItem.id); }} onItemDelete={async (deletedItem) => { - return deleteItem(deletedItem.id); + return noop(); // deleteItem(deletedItem.id); }} /> - { return addItem(widget); }} - /> + /> */} From 6420de029b134edb1872565c0a184cd98b567f79 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Thu, 22 Aug 2024 15:55:30 -0400 Subject: [PATCH 06/21] rename types --- .../src/schema/investigation_item.ts | 20 ++++++++----------- .../investigation/item_definition_registry.ts | 6 +++--- .../investigate/public/plugin.tsx | 4 ++-- .../investigate/public/types.ts | 4 ++-- .../items/esql_item/register_esql_item.tsx | 6 +++--- .../investigation_details.tsx | 9 ++++----- 6 files changed, 22 insertions(+), 27 deletions(-) diff --git a/packages/kbn-investigation-shared/src/schema/investigation_item.ts b/packages/kbn-investigation-shared/src/schema/investigation_item.ts index 0e8cc707c5bc2..d55038c46d0f4 100644 --- a/packages/kbn-investigation-shared/src/schema/investigation_item.ts +++ b/packages/kbn-investigation-shared/src/schema/investigation_item.ts @@ -8,7 +8,7 @@ import * as t from 'io-ts'; -const investigationEsqlItemSchema = t.type({ +const esqlItemSchema = t.type({ title: t.string, type: t.literal('esql'), params: t.type({ @@ -16,22 +16,18 @@ const investigationEsqlItemSchema = t.type({ suggestion: t.any, }), }); -type InvestigationEsqlItem = t.TypeOf; -const investigationItemsSchema = investigationEsqlItemSchema; // replace with union with various item types -type InvestigationItems = t.TypeOf; -type InvestigationItemTypes = t.TypeOf; +const investigationItemsSchema = esqlItemSchema; // replace with union with various item types const investigationItemSchema = t.intersection([ t.type({ id: t.string, createdAt: t.number, createdBy: t.string }), investigationItemsSchema, ]); + +type EsqlItem = t.TypeOf; +type InvestigationItems = t.TypeOf; +type InvestigationItemType = t.TypeOf; type InvestigationItem = t.TypeOf; -export type { - InvestigationItem, - InvestigationItems, - InvestigationItemTypes, - InvestigationEsqlItem, -}; -export { investigationItemSchema, investigationItemsSchema, investigationEsqlItemSchema }; +export type { InvestigationItem, InvestigationItems, InvestigationItemType, EsqlItem }; +export { investigationItemSchema, investigationItemsSchema, esqlItemSchema }; diff --git a/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts b/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts index 04d9b87d3ccee..ffcfac098e972 100644 --- a/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts +++ b/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { InvestigationItemTypes, InvestigationItems } from '@kbn/investigation-shared'; +import { InvestigationItemType, InvestigationItems } from '@kbn/investigation-shared'; import { GlobalWidgetParameters } from '../../common/types'; type ItemDefinitionGenerateData = Record; // type `data` somehow export interface ItemDefinition { - type: InvestigationItemTypes; + type: InvestigationItemType; generate: (option: { item: InvestigationItems; params: GlobalWidgetParameters; @@ -36,7 +36,7 @@ export class ItemDefinitionRegistry { return this.definitions; } - public getItemDefinitionByType(type: InvestigationItemTypes): ItemDefinition | undefined { + public getItemDefinitionByType(type: InvestigationItemType): ItemDefinition | undefined { return this.definitions.find((definition) => definition.type === type); } } diff --git a/x-pack/plugins/observability_solution/investigate/public/plugin.tsx b/x-pack/plugins/observability_solution/investigate/public/plugin.tsx index 62d003a462726..19457946d0ef0 100644 --- a/x-pack/plugins/observability_solution/investigate/public/plugin.tsx +++ b/x-pack/plugins/observability_solution/investigate/public/plugin.tsx @@ -11,7 +11,7 @@ import type { Plugin, PluginInitializerContext, } from '@kbn/core/public'; -import { GetInvestigationResponse, InvestigationItemTypes } from '@kbn/investigation-shared'; +import { GetInvestigationResponse, InvestigationItemType } from '@kbn/investigation-shared'; import type { Logger } from '@kbn/logging'; import { useMemo } from 'react'; import { createUseInvestigation } from './hooks/use_investigation'; @@ -71,7 +71,7 @@ export class InvestigatePlugin return { // new getItemDefinitions: () => this.itemDefinitionRegistry.getItemDefinitions(), - getItemDefinitionByType: (type: InvestigationItemTypes) => + getItemDefinitionByType: (type: InvestigationItemType) => this.itemDefinitionRegistry.getItemDefinitionByType(type), // old getWidgetDefinitions: this.widgetRegistry.getWidgetDefinitions, diff --git a/x-pack/plugins/observability_solution/investigate/public/types.ts b/x-pack/plugins/observability_solution/investigate/public/types.ts index 47d4afb4fb861..89895910f42e7 100644 --- a/x-pack/plugins/observability_solution/investigate/public/types.ts +++ b/x-pack/plugins/observability_solution/investigate/public/types.ts @@ -7,7 +7,7 @@ /* eslint-disable @typescript-eslint/no-empty-interface*/ import type { AuthenticatedUser } from '@kbn/core/public'; -import type { GetInvestigationResponse, InvestigationItemTypes } from '@kbn/investigation-shared'; +import type { GetInvestigationResponse, InvestigationItemType } from '@kbn/investigation-shared'; import type { CompatibleJSONSchema } from '@kbn/observability-ai-assistant-plugin/public'; import type { FromSchema } from 'json-schema-to-ts'; import type { InvestigateWidget } from '../common'; @@ -72,7 +72,7 @@ export interface InvestigatePublicSetup { export interface InvestigatePublicStart { // new: getItemDefinitions: () => ItemDefinition[]; - getItemDefinitionByType: (type: InvestigationItemTypes) => ItemDefinition | undefined; + getItemDefinitionByType: (type: InvestigationItemType) => ItemDefinition | undefined; // old: getWidgetDefinitions: () => WidgetDefinition[]; useInvestigation: ({}: { diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx index 17e59faa4da9b..fe6f15454b952 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx @@ -11,7 +11,7 @@ import type { ESQLSearchResponse } from '@kbn/es-types'; import { ESQLDataGrid } from '@kbn/esql-datagrid/public'; import { i18n } from '@kbn/i18n'; import { type GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; -import { InvestigationEsqlItem } from '@kbn/investigation-shared'; +import { EsqlItem } from '@kbn/investigation-shared'; import type { Suggestion } from '@kbn/lens-plugin/public'; import { useAbortableAsync } from '@kbn/observability-ai-assistant-plugin/public'; import React, { useMemo } from 'react'; @@ -212,7 +212,7 @@ export function registerEsqlItem({ }: Options) { investigate.registerItemDefinition({ type: 'esql', - generate: async (option: { item: InvestigationEsqlItem; params: GlobalWidgetParameters }) => { + generate: async (option: { item: EsqlItem; params: GlobalWidgetParameters }) => { const controller = new AbortController(); const { esql: esqlQuery, suggestion: suggestionFromParameters } = option.item.params; const { timeRange } = option.params; @@ -255,7 +255,7 @@ export function registerEsqlItem({ dateHistoResponse, }; }, - render: (option: { item: InvestigationEsqlItem; data: Record }) => { + render: (option: { item: EsqlItem; data: Record }) => { const { item, data = {} } = option; return ( Date: Fri, 23 Aug 2024 10:38:58 -0400 Subject: [PATCH 07/21] Add embeddable item type --- .../src/schema/investigation_item.ts | 27 ++- .../investigation/item_definition_registry.ts | 3 +- .../investigate/public/types.ts | 4 +- .../register_embeddable_item.tsx | 189 ++++++++++++++++++ .../items/esql_item/register_esql_item.tsx | 13 +- .../public/items/register_items.ts | 2 + 6 files changed, 227 insertions(+), 11 deletions(-) create mode 100644 x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx diff --git a/packages/kbn-investigation-shared/src/schema/investigation_item.ts b/packages/kbn-investigation-shared/src/schema/investigation_item.ts index d55038c46d0f4..60cc380d5e389 100644 --- a/packages/kbn-investigation-shared/src/schema/investigation_item.ts +++ b/packages/kbn-investigation-shared/src/schema/investigation_item.ts @@ -17,7 +17,18 @@ const esqlItemSchema = t.type({ }), }); -const investigationItemsSchema = esqlItemSchema; // replace with union with various item types +const embeddableItemSchema = t.type({ + title: t.string, + type: t.literal('embeddable'), + params: t.type({ + type: t.string, + savedObjectId: t.union([t.string, t.undefined]), + config: t.record(t.string, t.any), + }), +}); + +const investigationItemsSchema = t.union([esqlItemSchema, embeddableItemSchema]); // replace with union with various item types +const investigationItemTypeSchema = t.union([t.literal('esql'), t.literal('embeddable')]); const investigationItemSchema = t.intersection([ t.type({ id: t.string, createdAt: t.number, createdBy: t.string }), @@ -25,9 +36,17 @@ const investigationItemSchema = t.intersection([ ]); type EsqlItem = t.TypeOf; +type EmbeddableItem = t.TypeOf; type InvestigationItems = t.TypeOf; -type InvestigationItemType = t.TypeOf; +type InvestigationItemType = t.TypeOf; + type InvestigationItem = t.TypeOf; -export type { InvestigationItem, InvestigationItems, InvestigationItemType, EsqlItem }; -export { investigationItemSchema, investigationItemsSchema, esqlItemSchema }; +export type { + InvestigationItem, + InvestigationItems, + InvestigationItemType, + EsqlItem, + EmbeddableItem, +}; +export { investigationItemSchema, investigationItemsSchema, esqlItemSchema, embeddableItemSchema }; diff --git a/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts b/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts index ffcfac098e972..05d227616639c 100644 --- a/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts +++ b/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts @@ -10,9 +10,8 @@ import { GlobalWidgetParameters } from '../../common/types'; type ItemDefinitionGenerateData = Record; -// type `data` somehow export interface ItemDefinition { - type: InvestigationItemType; + type: string; generate: (option: { item: InvestigationItems; params: GlobalWidgetParameters; diff --git a/x-pack/plugins/observability_solution/investigate/public/types.ts b/x-pack/plugins/observability_solution/investigate/public/types.ts index 89895910f42e7..b2bf3a3384f15 100644 --- a/x-pack/plugins/observability_solution/investigate/public/types.ts +++ b/x-pack/plugins/observability_solution/investigate/public/types.ts @@ -7,7 +7,7 @@ /* eslint-disable @typescript-eslint/no-empty-interface*/ import type { AuthenticatedUser } from '@kbn/core/public'; -import type { GetInvestigationResponse, InvestigationItemType } from '@kbn/investigation-shared'; +import type { GetInvestigationResponse } from '@kbn/investigation-shared'; import type { CompatibleJSONSchema } from '@kbn/observability-ai-assistant-plugin/public'; import type { FromSchema } from 'json-schema-to-ts'; import type { InvestigateWidget } from '../common'; @@ -72,7 +72,7 @@ export interface InvestigatePublicSetup { export interface InvestigatePublicStart { // new: getItemDefinitions: () => ItemDefinition[]; - getItemDefinitionByType: (type: InvestigationItemType) => ItemDefinition | undefined; + getItemDefinitionByType: (type: string) => ItemDefinition | undefined; // old: getWidgetDefinitions: () => WidgetDefinition[]; useInvestigation: ({}: { diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx b/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx new file mode 100644 index 0000000000000..301e4328b3a82 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx @@ -0,0 +1,189 @@ +/* + * 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 { EuiLoadingSpinner } from '@elastic/eui'; +import { css } from '@emotion/css'; +import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public'; +import type { GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; +import { + EmbeddableItem, + InvestigationItems, + embeddableItemSchema, +} from '@kbn/investigation-shared'; +import { useAbortableAsync } from '@kbn/observability-ai-assistant-plugin/public'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { v4 } from 'uuid'; +import { ErrorMessage } from '../../components/error_message'; +import { useKibana } from '../../hooks/use_kibana'; +import { Options } from '../register_items'; + +const embeddableClassName = css` + height: 100%; + > [data-shared-item] { + height: 100%; + } +`; + +type Props = EmbeddableItem['params'] & GlobalWidgetParameters; + +type ParentApi = ReturnType['getParentApi']>; + +function ReactEmbeddable({ type, config, timeRange: { from, to }, savedObjectId }: Props) { + const configWithOverrides = useMemo(() => { + return { + ...config, + timeRange: { + from, + to, + }, + }; + }, [config, from, to]); + + const configWithOverridesRef = useRef(configWithOverrides); + + configWithOverridesRef.current = configWithOverrides; + + const api = useMemo(() => { + return { + getSerializedStateForChild: () => ({ rawState: configWithOverridesRef.current }), + }; + }, []); + + return ( + api} + maybeId={savedObjectId} + onAnyStateChange={(state) => { + // console.log('onAnyStateChange', state); + }} + onApiAvailable={(childApi) => { + // console.log('onApiAvailable', childApi); + }} + hidePanelChrome + /> + ); +} + +function LegacyEmbeddable({ type, config, timeRange: { from, to }, savedObjectId }: Props) { + const { + dependencies: { + start: { embeddable }, + }, + } = useKibana(); + + const [targetElement, setTargetElement] = useState(null); + + const embeddableInstanceAsync = useAbortableAsync(async () => { + const factory = embeddable.getEmbeddableFactory(type); + + if (!factory) { + throw new Error(`Cannot find embeddable factory for ${type}`); + } + + const configWithId = { + id: savedObjectId ?? v4(), + ...config, + }; + + const configWithOverrides = { + ...configWithId, + timeRange: { + from, + to, + }, + }; + + if (savedObjectId) { + return factory.createFromSavedObject(configWithOverrides.id, configWithOverrides); + } + + const instance = await factory.create(configWithOverrides); + + return instance; + }, [type, savedObjectId, config, from, to, embeddable]); + + const embeddableInstance = embeddableInstanceAsync.value; + + useEffect(() => { + if (!targetElement || !embeddableInstance) { + return; + } + + embeddableInstance.render(targetElement); + + return () => {}; + }, [embeddableInstance, targetElement]); + + useEffect(() => { + return () => { + if (embeddableInstance) { + embeddableInstance.destroy(); + } + }; + }, [embeddableInstance]); + + if (embeddableInstanceAsync.error) { + return ; + } + + if (!embeddableInstance) { + return ; + } + + return ( +
{ + setTargetElement(element); + }} + /> + ); +} + +function EmbeddableWidget(props: Props) { + const { + dependencies: { + start: { embeddable }, + }, + } = useKibana(); + + if (embeddable.reactEmbeddableRegistryHasKey(props.type)) { + return ; + } + + return ; +} + +export function registerEmbeddableItem({ + dependencies: { + setup: { investigate }, + }, + services, +}: Options) { + investigate.registerItemDefinition({ + type: 'esql', + generate: async (option: { item: InvestigationItems; params: GlobalWidgetParameters }) => { + return { + timeRange: option.params.timeRange, + }; + }, + render: (option: { item: InvestigationItems; data: Record }) => { + if (!embeddableItemSchema.is(option.item)) { + return null; + } + + const parameters = { + type: option.item.params.type, + config: option.item.params.config, + savedObjectId: option.item.params.savedObjectId, + timeRange: option.data.timeRange, + }; + + return ; + }, + }); +} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx index fe6f15454b952..f7f4aa51977e1 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx @@ -11,7 +11,7 @@ import type { ESQLSearchResponse } from '@kbn/es-types'; import { ESQLDataGrid } from '@kbn/esql-datagrid/public'; import { i18n } from '@kbn/i18n'; import { type GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; -import { EsqlItem } from '@kbn/investigation-shared'; +import { InvestigationItems, esqlItemSchema } from '@kbn/investigation-shared'; import type { Suggestion } from '@kbn/lens-plugin/public'; import { useAbortableAsync } from '@kbn/observability-ai-assistant-plugin/public'; import React, { useMemo } from 'react'; @@ -212,7 +212,11 @@ export function registerEsqlItem({ }: Options) { investigate.registerItemDefinition({ type: 'esql', - generate: async (option: { item: EsqlItem; params: GlobalWidgetParameters }) => { + generate: async (option: { item: InvestigationItems; params: GlobalWidgetParameters }) => { + if (!esqlItemSchema.is(option.item)) { + return {}; + } + const controller = new AbortController(); const { esql: esqlQuery, suggestion: suggestionFromParameters } = option.item.params; const { timeRange } = option.params; @@ -255,7 +259,10 @@ export function registerEsqlItem({ dateHistoResponse, }; }, - render: (option: { item: EsqlItem; data: Record }) => { + render: (option: { item: InvestigationItems; data: Record }) => { + if (!esqlItemSchema.is(option.item)) { + return null; + } const { item, data = {} } = option; return ( Date: Fri, 23 Aug 2024 10:53:54 -0400 Subject: [PATCH 08/21] wip --- .../public/investigation/item_definition_registry.ts | 4 ++-- .../observability_solution/investigate/public/plugin.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts b/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts index 05d227616639c..c445b7c54996a 100644 --- a/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts +++ b/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { InvestigationItemType, InvestigationItems } from '@kbn/investigation-shared'; +import { InvestigationItems } from '@kbn/investigation-shared'; import { GlobalWidgetParameters } from '../../common/types'; type ItemDefinitionGenerateData = Record; @@ -35,7 +35,7 @@ export class ItemDefinitionRegistry { return this.definitions; } - public getItemDefinitionByType(type: InvestigationItemType): ItemDefinition | undefined { + public getItemDefinitionByType(type: string): ItemDefinition | undefined { return this.definitions.find((definition) => definition.type === type); } } diff --git a/x-pack/plugins/observability_solution/investigate/public/plugin.tsx b/x-pack/plugins/observability_solution/investigate/public/plugin.tsx index 19457946d0ef0..54f8f6f457401 100644 --- a/x-pack/plugins/observability_solution/investigate/public/plugin.tsx +++ b/x-pack/plugins/observability_solution/investigate/public/plugin.tsx @@ -11,7 +11,7 @@ import type { Plugin, PluginInitializerContext, } from '@kbn/core/public'; -import { GetInvestigationResponse, InvestigationItemType } from '@kbn/investigation-shared'; +import { GetInvestigationResponse } from '@kbn/investigation-shared'; import type { Logger } from '@kbn/logging'; import { useMemo } from 'react'; import { createUseInvestigation } from './hooks/use_investigation'; @@ -71,7 +71,7 @@ export class InvestigatePlugin return { // new getItemDefinitions: () => this.itemDefinitionRegistry.getItemDefinitions(), - getItemDefinitionByType: (type: InvestigationItemType) => + getItemDefinitionByType: (type: string) => this.itemDefinitionRegistry.getItemDefinitionByType(type), // old getWidgetDefinitions: this.widgetRegistry.getWidgetDefinitions, From 49f86337d1ee150670213cb7518b22f449811e73 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Fri, 23 Aug 2024 11:11:33 -0400 Subject: [PATCH 09/21] Remove item types --- .../src/rest_specs/create_item.ts | 4 +- .../src/schema/investigation_item.ts | 46 +++++-------------- .../investigation/item_definition_registry.ts | 14 +++--- .../register_embeddable_item.tsx | 20 ++++---- .../items/esql_item/register_esql_item.tsx | 13 ++---- 5 files changed, 31 insertions(+), 66 deletions(-) diff --git a/packages/kbn-investigation-shared/src/rest_specs/create_item.ts b/packages/kbn-investigation-shared/src/rest_specs/create_item.ts index c94673313a50c..a0696df4040d8 100644 --- a/packages/kbn-investigation-shared/src/rest_specs/create_item.ts +++ b/packages/kbn-investigation-shared/src/rest_specs/create_item.ts @@ -7,14 +7,14 @@ */ import * as t from 'io-ts'; -import { investigationItemsSchema } from '../schema'; +import { itemSchema } from '../schema'; import { investigationItemResponseSchema } from './investigation_item'; const createInvestigationItemParamsSchema = t.type({ path: t.type({ investigationId: t.string, }), - body: investigationItemsSchema, + body: itemSchema, }); const createInvestigationItemResponseSchema = investigationItemResponseSchema; diff --git a/packages/kbn-investigation-shared/src/schema/investigation_item.ts b/packages/kbn-investigation-shared/src/schema/investigation_item.ts index 60cc380d5e389..717bf246e3590 100644 --- a/packages/kbn-investigation-shared/src/schema/investigation_item.ts +++ b/packages/kbn-investigation-shared/src/schema/investigation_item.ts @@ -8,45 +8,23 @@ import * as t from 'io-ts'; -const esqlItemSchema = t.type({ +const itemSchema = t.type({ title: t.string, - type: t.literal('esql'), - params: t.type({ - esql: t.string, - suggestion: t.any, - }), -}); - -const embeddableItemSchema = t.type({ - title: t.string, - type: t.literal('embeddable'), - params: t.type({ - type: t.string, - savedObjectId: t.union([t.string, t.undefined]), - config: t.record(t.string, t.any), - }), + type: t.string, + params: t.record(t.string, t.any), }); -const investigationItemsSchema = t.union([esqlItemSchema, embeddableItemSchema]); // replace with union with various item types -const investigationItemTypeSchema = t.union([t.literal('esql'), t.literal('embeddable')]); - const investigationItemSchema = t.intersection([ - t.type({ id: t.string, createdAt: t.number, createdBy: t.string }), - investigationItemsSchema, + t.type({ + id: t.string, + createdAt: t.number, + createdBy: t.string, + }), + itemSchema, ]); -type EsqlItem = t.TypeOf; -type EmbeddableItem = t.TypeOf; -type InvestigationItems = t.TypeOf; -type InvestigationItemType = t.TypeOf; - +type Item = t.TypeOf; type InvestigationItem = t.TypeOf; -export type { - InvestigationItem, - InvestigationItems, - InvestigationItemType, - EsqlItem, - EmbeddableItem, -}; -export { investigationItemSchema, investigationItemsSchema, esqlItemSchema, embeddableItemSchema }; +export type { Item, InvestigationItem }; +export { investigationItemSchema, itemSchema }; diff --git a/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts b/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts index c445b7c54996a..33b1e408968f6 100644 --- a/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts +++ b/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts @@ -5,21 +5,19 @@ * 2.0. */ -import { InvestigationItems } from '@kbn/investigation-shared'; +import { InvestigationItem } from '@kbn/investigation-shared'; import { GlobalWidgetParameters } from '../../common/types'; -type ItemDefinitionGenerateData = Record; +type ItemDefinitionData = Record; +type ItemDefinitionParams = Record; export interface ItemDefinition { type: string; generate: (option: { - item: InvestigationItems; + item: InvestigationItem; params: GlobalWidgetParameters; - }) => Promise; - render: (option: { - data: ItemDefinitionGenerateData; - item: InvestigationItems; - }) => React.ReactNode; + }) => Promise; + render: (option: { data: ItemDefinitionData; item: InvestigationItem }) => React.ReactNode; } export class ItemDefinitionRegistry { diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx b/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx index 301e4328b3a82..b0e250c4e1c71 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx @@ -8,11 +8,7 @@ import { EuiLoadingSpinner } from '@elastic/eui'; import { css } from '@emotion/css'; import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public'; import type { GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; -import { - EmbeddableItem, - InvestigationItems, - embeddableItemSchema, -} from '@kbn/investigation-shared'; +import { InvestigationItem } from '@kbn/investigation-shared'; import { useAbortableAsync } from '@kbn/observability-ai-assistant-plugin/public'; import React, { useEffect, useMemo, useRef, useState } from 'react'; import { v4 } from 'uuid'; @@ -27,7 +23,11 @@ const embeddableClassName = css` } `; -type Props = EmbeddableItem['params'] & GlobalWidgetParameters; +type Props = { + type: string; + config: Record; + savedObjectId?: string; +} & GlobalWidgetParameters; type ParentApi = ReturnType['getParentApi']>; @@ -166,16 +166,12 @@ export function registerEmbeddableItem({ }: Options) { investigate.registerItemDefinition({ type: 'esql', - generate: async (option: { item: InvestigationItems; params: GlobalWidgetParameters }) => { + generate: async (option: { item: InvestigationItem; params: GlobalWidgetParameters }) => { return { timeRange: option.params.timeRange, }; }, - render: (option: { item: InvestigationItems; data: Record }) => { - if (!embeddableItemSchema.is(option.item)) { - return null; - } - + render: (option: { item: InvestigationItem; data: Record }) => { const parameters = { type: option.item.params.type, config: option.item.params.config, diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx index f7f4aa51977e1..8e9127b1e2780 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx @@ -11,7 +11,7 @@ import type { ESQLSearchResponse } from '@kbn/es-types'; import { ESQLDataGrid } from '@kbn/esql-datagrid/public'; import { i18n } from '@kbn/i18n'; import { type GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; -import { InvestigationItems, esqlItemSchema } from '@kbn/investigation-shared'; +import { InvestigationItem } from '@kbn/investigation-shared'; import type { Suggestion } from '@kbn/lens-plugin/public'; import { useAbortableAsync } from '@kbn/observability-ai-assistant-plugin/public'; import React, { useMemo } from 'react'; @@ -212,11 +212,7 @@ export function registerEsqlItem({ }: Options) { investigate.registerItemDefinition({ type: 'esql', - generate: async (option: { item: InvestigationItems; params: GlobalWidgetParameters }) => { - if (!esqlItemSchema.is(option.item)) { - return {}; - } - + generate: async (option: { item: InvestigationItem; params: GlobalWidgetParameters }) => { const controller = new AbortController(); const { esql: esqlQuery, suggestion: suggestionFromParameters } = option.item.params; const { timeRange } = option.params; @@ -259,10 +255,7 @@ export function registerEsqlItem({ dateHistoResponse, }; }, - render: (option: { item: InvestigationItems; data: Record }) => { - if (!esqlItemSchema.is(option.item)) { - return null; - } + render: (option: { item: InvestigationItem; data: Record }) => { const { item, data = {} } = option; return ( Date: Fri, 23 Aug 2024 11:41:08 -0400 Subject: [PATCH 10/21] Introduce generics --- .../investigation/item_definition_registry.ts | 26 ++++++---- .../investigate/public/plugin.tsx | 14 +++++- .../investigate/public/types.ts | 13 ++++- .../register_embeddable_item.tsx | 37 ++++++++------ .../items/esql_item/register_esql_item.tsx | 50 ++++++++++++++----- .../investigation_details.tsx | 27 +++++----- 6 files changed, 113 insertions(+), 54 deletions(-) diff --git a/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts b/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts index 33b1e408968f6..6fcb8308e7161 100644 --- a/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts +++ b/x-pack/plugins/observability_solution/investigate/public/investigation/item_definition_registry.ts @@ -5,19 +5,22 @@ * 2.0. */ -import { InvestigationItem } from '@kbn/investigation-shared'; import { GlobalWidgetParameters } from '../../common/types'; -type ItemDefinitionData = Record; -type ItemDefinitionParams = Record; +export type ItemDefinitionData = Record; +export type ItemDefinitionParams = Record; -export interface ItemDefinition { +export interface ItemDefinition< + Params extends ItemDefinitionParams = {}, + Data extends ItemDefinitionData = {} +> { type: string; - generate: (option: { - item: InvestigationItem; - params: GlobalWidgetParameters; - }) => Promise; - render: (option: { data: ItemDefinitionData; item: InvestigationItem }) => React.ReactNode; + generate: (option: { itemParams: Params; globalParams: GlobalWidgetParameters }) => Promise; + render: (option: { + data: Data; + itemParams: Params; + globalParams: GlobalWidgetParameters; + }) => React.ReactNode; } export class ItemDefinitionRegistry { @@ -25,7 +28,10 @@ export class ItemDefinitionRegistry { constructor() {} - public registerItem(definition: ItemDefinition) { + public registerItem( + definition: ItemDefinition + ) { + // @ts-ignore TODO fix this type issue with generics this.definitions.push(definition); } diff --git a/x-pack/plugins/observability_solution/investigate/public/plugin.tsx b/x-pack/plugins/observability_solution/investigate/public/plugin.tsx index 54f8f6f457401..a94dd4e41744f 100644 --- a/x-pack/plugins/observability_solution/investigate/public/plugin.tsx +++ b/x-pack/plugins/observability_solution/investigate/public/plugin.tsx @@ -15,7 +15,12 @@ import { GetInvestigationResponse } from '@kbn/investigation-shared'; import type { Logger } from '@kbn/logging'; import { useMemo } from 'react'; import { createUseInvestigation } from './hooks/use_investigation'; -import { ItemDefinition, ItemDefinitionRegistry } from './investigation/item_definition_registry'; +import { + ItemDefinition, + ItemDefinitionData, + ItemDefinitionParams, + ItemDefinitionRegistry, +} from './investigation/item_definition_registry'; import type { ConfigSchema, InvestigatePublicSetup, @@ -45,7 +50,12 @@ export class InvestigatePlugin setup(coreSetup: CoreSetup, pluginsSetup: InvestigateSetupDependencies): InvestigatePublicSetup { return { // new - registerItemDefinition: (definition: ItemDefinition) => { + registerItemDefinition: < + Params extends ItemDefinitionParams, + Data extends ItemDefinitionData + >( + definition: ItemDefinition + ) => { this.itemDefinitionRegistry.registerItem(definition); }, // old diff --git a/x-pack/plugins/observability_solution/investigate/public/types.ts b/x-pack/plugins/observability_solution/investigate/public/types.ts index b2bf3a3384f15..ad50f983e152a 100644 --- a/x-pack/plugins/observability_solution/investigate/public/types.ts +++ b/x-pack/plugins/observability_solution/investigate/public/types.ts @@ -13,7 +13,11 @@ import type { FromSchema } from 'json-schema-to-ts'; import type { InvestigateWidget } from '../common'; import type { GlobalWidgetParameters, InvestigateWidgetCreate } from '../common/types'; import type { UseInvestigationApi } from './hooks/use_investigation'; -import { ItemDefinition } from './investigation/item_definition_registry'; +import { + ItemDefinition, + ItemDefinitionData, + ItemDefinitionParams, +} from './investigation/item_definition_registry'; export type OnWidgetAdd = (create: InvestigateWidgetCreate) => Promise; @@ -64,7 +68,12 @@ export interface InvestigateStartDependencies {} export interface InvestigatePublicSetup { // new - registerItemDefinition: (itemDefinition: ItemDefinition) => void; + registerItemDefinition: < + Params extends ItemDefinitionParams = {}, + Data extends ItemDefinitionData = {} + >( + itemDefinition: ItemDefinition + ) => void; // old register: (callback: (registerWidget: RegisterWidget) => Promise) => void; } diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx b/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx index b0e250c4e1c71..e07c940c8ca5f 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx @@ -8,7 +8,6 @@ import { EuiLoadingSpinner } from '@elastic/eui'; import { css } from '@emotion/css'; import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public'; import type { GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; -import { InvestigationItem } from '@kbn/investigation-shared'; import { useAbortableAsync } from '@kbn/observability-ai-assistant-plugin/public'; import React, { useEffect, useMemo, useRef, useState } from 'react'; import { v4 } from 'uuid'; @@ -23,11 +22,7 @@ const embeddableClassName = css` } `; -type Props = { - type: string; - config: Record; - savedObjectId?: string; -} & GlobalWidgetParameters; +type Props = EmbeddableItemParams & GlobalWidgetParameters; type ParentApi = ReturnType['getParentApi']>; @@ -158,25 +153,35 @@ function EmbeddableWidget(props: Props) { return ; } +interface EmbeddableItemParams { + type: string; + config: Record; + savedObjectId?: string; +} + export function registerEmbeddableItem({ dependencies: { setup: { investigate }, }, services, }: Options) { - investigate.registerItemDefinition({ + investigate.registerItemDefinition({ type: 'esql', - generate: async (option: { item: InvestigationItem; params: GlobalWidgetParameters }) => { - return { - timeRange: option.params.timeRange, - }; + generate: async (option: { + itemParams: EmbeddableItemParams; + globalParams: GlobalWidgetParameters; + }) => { + return {}; }, - render: (option: { item: InvestigationItem; data: Record }) => { + render: (option: { + itemParams: EmbeddableItemParams; + globalParams: GlobalWidgetParameters; + }) => { const parameters = { - type: option.item.params.type, - config: option.item.params.config, - savedObjectId: option.item.params.savedObjectId, - timeRange: option.data.timeRange, + type: option.itemParams.type, + config: option.itemParams.config, + savedObjectId: option.itemParams.savedObjectId, + timeRange: option.globalParams.timeRange, }; return ; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx index 8e9127b1e2780..1b62b5476f021 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/items/esql_item/register_esql_item.tsx @@ -11,7 +11,6 @@ import type { ESQLSearchResponse } from '@kbn/es-types'; import { ESQLDataGrid } from '@kbn/esql-datagrid/public'; import { i18n } from '@kbn/i18n'; import { type GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; -import { InvestigationItem } from '@kbn/investigation-shared'; import type { Suggestion } from '@kbn/lens-plugin/public'; import { useAbortableAsync } from '@kbn/observability-ai-assistant-plugin/public'; import React, { useMemo } from 'react'; @@ -42,6 +41,24 @@ interface Props { }; } +interface EsqlItemParams { + esql: string; + suggestion?: Suggestion; +} + +interface EsqlItemData { + dataView: DataView; + columns: ESQLSearchResponse['columns']; + values: ESQLSearchResponse['values']; + suggestion: Suggestion; + dateHistoResponse?: { + query: string; + columns: ESQLSearchResponse['columns']; + values: ESQLSearchResponse['values']; + groupingExpression: string; + }; +} + export function EsqlWidget({ suggestion, dataView, @@ -210,12 +227,15 @@ export function registerEsqlItem({ }, services, }: Options) { - investigate.registerItemDefinition({ + investigate.registerItemDefinition({ type: 'esql', - generate: async (option: { item: InvestigationItem; params: GlobalWidgetParameters }) => { + generate: async (option: { + itemParams: EsqlItemParams; + globalParams: GlobalWidgetParameters; + }) => { const controller = new AbortController(); - const { esql: esqlQuery, suggestion: suggestionFromParameters } = option.item.params; - const { timeRange } = option.params; + const { esql: esqlQuery, suggestion: suggestionFromParameters } = option.itemParams; + const { timeRange } = option.globalParams; const esql = await services.esql; @@ -250,21 +270,27 @@ export function registerEsqlItem({ }); return { - mainResponse, + dataView: mainResponse.meta.dataView, + columns: mainResponse.query.columns, + values: mainResponse.query.values, suggestion, dateHistoResponse, }; }, - render: (option: { item: InvestigationItem; data: Record }) => { - const { item, data = {} } = option; + render: (option: { + itemParams: EsqlItemParams; + globalParams: GlobalWidgetParameters; + data: EsqlItemData; + }) => { + const { itemParams, data } = option; return ( ); diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx index 880003dfc9919..80633265f3320 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx @@ -54,18 +54,20 @@ export function InvestigationDetails({ user, investigationId }: Props) { }); } - const data = await itemDefinition.generate({ - item, - params: { - timeRange: { - from: investigation - ? new Date(investigation.params.timeRange.from).toISOString() - : new Date().toISOString(), - to: investigation - ? new Date(investigation.params.timeRange.to).toISOString() - : new Date().toISOString(), - }, + const globalParams = { + timeRange: { + from: investigation + ? new Date(investigation.params.timeRange.from).toISOString() + : new Date().toISOString(), + to: investigation + ? new Date(investigation.params.timeRange.to).toISOString() + : new Date().toISOString(), }, + }; + + const data = await itemDefinition.generate({ + itemParams: item.params, + globalParams, }); return Promise.resolve({ @@ -73,7 +75,8 @@ export function InvestigationDetails({ user, investigationId }: Props) { loading: false, element: itemDefinition.render({ data, - item, + globalParams, + itemParams: item.params, }), }); }) From 0755f8c8c546605b45b3de6b821714eb44d7eac9 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Fri, 23 Aug 2024 15:50:14 -0400 Subject: [PATCH 11/21] extract render logic to hook --- .../investigation_details.tsx | 72 +---------------- .../pages/details/hooks/use_render_items.tsx | 81 +++++++++++++++++++ 2 files changed, 84 insertions(+), 69 deletions(-) create mode 100644 x-pack/plugins/observability_solution/investigate_app/public/pages/details/hooks/use_render_items.tsx diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx index 80633265f3320..84baec4824978 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx @@ -6,15 +6,13 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { InvestigationItem } from '@kbn/investigation-shared'; import { AuthenticatedUser } from '@kbn/security-plugin/common'; import { noop } from 'lodash'; -import React, { useEffect } from 'react'; +import React from 'react'; import { InvestigateSearchBar } from '../../../../components/investigate_search_bar'; import { InvestigateWidgetGrid } from '../../../../components/investigate_widget_grid'; import { useFetchInvestigation } from '../../../../hooks/use_fetch_investigation'; -import { useKibana } from '../../../../hooks/use_kibana'; +import { useRenderItems } from '../../hooks/use_render_items'; import { InvestigationNotes } from '../investigation_notes/investigation_notes'; interface Props { @@ -23,72 +21,8 @@ interface Props { } export function InvestigationDetails({ user, investigationId }: Props) { - const { - dependencies: { - start: { investigate }, - }, - } = useKibana(); const { data: investigation } = useFetchInvestigation({ id: investigationId }); - - const [renderableItems, setRenderableItems] = React.useState< - Array - >([]); - - useEffect(() => { - async function renderItems(items: InvestigationItem[]) { - return await Promise.all( - items.map(async (item) => { - const itemDefinition = investigate.getItemDefinitionByType(item.type); - if (!itemDefinition) { - return Promise.resolve({ - ...item, - loading: false, - element: ( -
- {i18n.translate('xpack.investigateApp.renderableItems.div.notFoundLabel', { - defaultMessage: 'Not found for type {type}', - values: { type: item.type }, - })} -
- ), - }); - } - - const globalParams = { - timeRange: { - from: investigation - ? new Date(investigation.params.timeRange.from).toISOString() - : new Date().toISOString(), - to: investigation - ? new Date(investigation.params.timeRange.to).toISOString() - : new Date().toISOString(), - }, - }; - - const data = await itemDefinition.generate({ - itemParams: item.params, - globalParams, - }); - - return Promise.resolve({ - ...item, - loading: false, - element: itemDefinition.render({ - data, - globalParams, - itemParams: item.params, - }), - }); - }) - ); - } - - if (investigation) { - renderItems(investigation.items).then((nextRenderableItems) => - setRenderableItems(nextRenderableItems) - ); - } - }, [investigation]); + const renderableItems = useRenderItems({ investigation }); if (!investigation || !renderableItems) { return ; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/hooks/use_render_items.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/hooks/use_render_items.tsx new file mode 100644 index 0000000000000..491db61cb7c1e --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/hooks/use_render_items.tsx @@ -0,0 +1,81 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { GetInvestigationResponse, InvestigationItem } from '@kbn/investigation-shared'; +import React, { useEffect, useState } from 'react'; +import { useKibana } from '../../../hooks/use_kibana'; + +export function useRenderItems({ investigation }: { investigation?: GetInvestigationResponse }) { + const { + dependencies: { + start: { investigate }, + }, + } = useKibana(); + + const [renderableItems, setRenderableItems] = useState< + Array + >([]); + + useEffect(() => { + async function renderItems(items: InvestigationItem[]) { + return await Promise.all( + items.map(async (item) => { + const itemDefinition = investigate.getItemDefinitionByType(item.type); + if (!itemDefinition) { + return Promise.resolve({ + ...item, + loading: false, + element: ( +
+ {i18n.translate('xpack.investigateApp.renderableItems.div.notFoundLabel', { + defaultMessage: 'Not found for type {type}', + values: { type: item.type }, + })} +
+ ), + }); + } + + const globalParams = { + timeRange: { + from: investigation + ? new Date(investigation.params.timeRange.from).toISOString() + : new Date().toISOString(), + to: investigation + ? new Date(investigation.params.timeRange.to).toISOString() + : new Date().toISOString(), + }, + }; + + const data = await itemDefinition.generate({ + itemParams: item.params, + globalParams, + }); + + return Promise.resolve({ + ...item, + loading: false, + element: itemDefinition.render({ + data, + globalParams, + itemParams: item.params, + }), + }); + }) + ); + } + + if (investigation) { + renderItems(investigation.items).then((nextRenderableItems) => + setRenderableItems(nextRenderableItems) + ); + } + }, [investigation, investigate]); + + return renderableItems; +} From ded1144ab0a5651ebf962c4217eaf757e742cc12 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Fri, 23 Aug 2024 16:03:39 -0400 Subject: [PATCH 12/21] Create items mutation and query hooks --- .../src/rest_specs/index.ts | 2 + .../investigate_app/kibana.jsonc | 1 + .../investigate_widget_grid/index.stories.tsx | 4 +- .../investigate_widget_grid/index.tsx | 8 +- .../public/hooks/query_key_factory.ts | 3 + .../hooks/use_add_investigation_item.ts | 49 ++++++++++++ .../hooks/use_delete_investigation_item.ts | 44 +++++++++++ .../hooks/use_fetch_investigation_items.ts | 76 +++++++++++++++++++ .../investigation_details.tsx | 59 +++++++------- 9 files changed, 212 insertions(+), 34 deletions(-) create mode 100644 x-pack/plugins/observability_solution/investigate_app/public/hooks/use_add_investigation_item.ts create mode 100644 x-pack/plugins/observability_solution/investigate_app/public/hooks/use_delete_investigation_item.ts create mode 100644 x-pack/plugins/observability_solution/investigate_app/public/hooks/use_fetch_investigation_items.ts diff --git a/packages/kbn-investigation-shared/src/rest_specs/index.ts b/packages/kbn-investigation-shared/src/rest_specs/index.ts index 50c1e300cd96a..cb13c11886481 100644 --- a/packages/kbn-investigation-shared/src/rest_specs/index.ts +++ b/packages/kbn-investigation-shared/src/rest_specs/index.ts @@ -17,6 +17,7 @@ export type * from './investigation_note'; export type * from './create_item'; export type * from './delete_item'; export type * from './get_items'; +export type * from './investigation_item'; export * from './create'; export * from './create_note'; @@ -29,3 +30,4 @@ export * from './investigation_note'; export * from './create_item'; export * from './delete_item'; export * from './get_items'; +export * from './investigation_item'; diff --git a/x-pack/plugins/observability_solution/investigate_app/kibana.jsonc b/x-pack/plugins/observability_solution/investigate_app/kibana.jsonc index 19861110a579e..c7e860a047366 100644 --- a/x-pack/plugins/observability_solution/investigate_app/kibana.jsonc +++ b/x-pack/plugins/observability_solution/investigate_app/kibana.jsonc @@ -21,6 +21,7 @@ "security", ], "requiredBundles": [ + "esql", "kibanaReact", "kibanaUtils", "esqlDataGrid", diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.stories.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.stories.tsx index 072d25b1e5526..f3919b8f98506 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.stories.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.stories.tsx @@ -8,7 +8,7 @@ import { ComponentMeta, ComponentStoryObj } from '@storybook/react'; import React, { useState } from 'react'; import { v4 } from 'uuid'; -import { InvestigateWidgetGrid as Component, InvestigateWidgetGridItem } from '.'; +import { InvestigateWidgetGrid as Component, RenderedInvestigationItem } from '.'; import { KibanaReactStorybookDecorator } from '../../../.storybook/storybook_decorator'; const meta: ComponentMeta = { @@ -50,7 +50,7 @@ const defaultProps: ComponentStoryObj = { ), }; -function createItem>(overrides: T) { +function createItem>(overrides: T) { return { ...overrides, id: v4(), diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.tsx index 9b6198d01c13a..73b8346dcc0b2 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.tsx @@ -12,15 +12,15 @@ import 'react-resizable/css/styles.css'; import { GridItem } from '../grid_item'; import './styles.scss'; -export type InvestigateWidgetGridItem = InvestigationItem & { +export type RenderedInvestigationItem = InvestigationItem & { loading: boolean; element: React.ReactNode; }; interface InvestigateWidgetGridProps { - items: InvestigateWidgetGridItem[]; - onItemCopy: (item: InvestigateWidgetGridItem) => Promise; - onItemDelete: (item: InvestigateWidgetGridItem) => Promise; + items: RenderedInvestigationItem[]; + onItemCopy: (item: RenderedInvestigationItem) => Promise; + onItemDelete: (item: RenderedInvestigationItem) => Promise; } export function InvestigateWidgetGrid({ diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts b/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts index d2f6bc9060e43..62078d7d55bca 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts @@ -13,6 +13,9 @@ export const investigationKeys = { notes: ['investigation', 'notes'] as const, fetchNotes: (params: { investigationId: string }) => [...investigationKeys.notes, 'fetch', params] as const, + items: ['investigation', 'items'] as const, + fetchItems: (params: { investigationId: string }) => + [...investigationKeys.items, 'fetch', params] as const, }; export type InvestigationKeys = typeof investigationKeys; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_add_investigation_item.ts b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_add_investigation_item.ts new file mode 100644 index 0000000000000..a11b5d976fe00 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_add_investigation_item.ts @@ -0,0 +1,49 @@ +/* + * 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 { IHttpFetchError, ResponseErrorBody } from '@kbn/core/public'; +import { + CreateInvestigationItemParams, + CreateInvestigationItemResponse, +} from '@kbn/investigation-shared'; +import { useMutation } from '@tanstack/react-query'; +import { useKibana } from './use_kibana'; + +type ServerError = IHttpFetchError; + +export function useAddInvestigationItem() { + const { + core: { + http, + notifications: { toasts }, + }, + } = useKibana(); + + return useMutation< + CreateInvestigationItemResponse, + ServerError, + { investigationId: string; item: CreateInvestigationItemParams }, + { investigationId: string } + >( + ['addInvestigationItem'], + ({ investigationId, item }) => { + const body = JSON.stringify(item); + return http.post( + `/api/observability/investigations/${investigationId}/items`, + { body, version: '2023-10-31' } + ); + }, + { + onSuccess: (response, {}) => { + toasts.addSuccess('Item saved'); + }, + onError: (error, {}, context) => { + toasts.addError(new Error(error.body?.message ?? 'An error occurred'), { title: 'Error' }); + }, + } + ); +} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_delete_investigation_item.ts b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_delete_investigation_item.ts new file mode 100644 index 0000000000000..9c94f5f705533 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_delete_investigation_item.ts @@ -0,0 +1,44 @@ +/* + * 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 { IHttpFetchError, ResponseErrorBody } from '@kbn/core/public'; +import { useMutation } from '@tanstack/react-query'; +import { useKibana } from './use_kibana'; + +type ServerError = IHttpFetchError; + +export function useDeleteInvestigationItem() { + const { + core: { + http, + notifications: { toasts }, + }, + } = useKibana(); + + return useMutation< + void, + ServerError, + { investigationId: string; itemId: string }, + { investigationId: string } + >( + ['addInvestigationNote'], + ({ investigationId, itemId }) => { + return http.delete( + `/api/observability/investigations/${investigationId}/items/${itemId}`, + { version: '2023-10-31' } + ); + }, + { + onSuccess: (response, {}) => { + toasts.addSuccess('Item deleted'); + }, + onError: (error, {}, context) => { + toasts.addError(new Error(error.body?.message ?? 'An error occurred'), { title: 'Error' }); + }, + } + ); +} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_fetch_investigation_items.ts b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_fetch_investigation_items.ts new file mode 100644 index 0000000000000..4b13a363b408f --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_fetch_investigation_items.ts @@ -0,0 +1,76 @@ +/* + * 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 { + GetInvestigationItemsResponse, + InvestigationItemResponse, +} from '@kbn/investigation-shared'; +import { + QueryObserverResult, + RefetchOptions, + RefetchQueryFilters, + useQuery, +} from '@tanstack/react-query'; +import { investigationKeys } from './query_key_factory'; +import { useKibana } from './use_kibana'; + +export interface Params { + investigationId: string; + initialItems?: InvestigationItemResponse[]; +} + +export interface Response { + isInitialLoading: boolean; + isLoading: boolean; + isRefetching: boolean; + isSuccess: boolean; + isError: boolean; + refetch: ( + options?: (RefetchOptions & RefetchQueryFilters) | undefined + ) => Promise>; + data: GetInvestigationItemsResponse | undefined; +} + +export function useFetchInvestigationNotes({ investigationId, initialItems }: Params): Response { + const { + core: { + http, + notifications: { toasts }, + }, + } = useKibana(); + + const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data, refetch } = useQuery( + { + queryKey: investigationKeys.fetchNotes({ investigationId }), + queryFn: async ({ signal }) => { + return await http.get( + `/api/observability/investigations/${investigationId}/items`, + { version: '2023-10-31', signal } + ); + }, + initialData: initialItems, + refetchOnWindowFocus: false, + refetchInterval: 10 * 1000, + refetchIntervalInBackground: true, + onError: (error: Error) => { + toasts.addError(error, { + title: 'Something went wrong while fetching investigation items', + }); + }, + } + ); + + return { + data, + isInitialLoading, + isLoading, + isRefetching, + isSuccess, + isError, + refetch, + }; +} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx index 84baec4824978..90fa835551693 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx @@ -14,6 +14,7 @@ import { InvestigateWidgetGrid } from '../../../../components/investigate_widget import { useFetchInvestigation } from '../../../../hooks/use_fetch_investigation'; import { useRenderItems } from '../../hooks/use_render_items'; import { InvestigationNotes } from '../investigation_notes/investigation_notes'; +import { AddObservationUI } from '../../../../components/add_observation_ui'; interface Props { user: AuthenticatedUser; @@ -33,30 +34,28 @@ export function InvestigationDetails({ user, investigationId }: Props) { - - { - // const nextDateRange = { - // from: datemath.parse(dateRange.from)!.toISOString(), - // to: datemath.parse(dateRange.to)!.toISOString(), - // }; - // await setGlobalParameters({ - // ...renderableInvestigation.parameters, - // timeRange: nextDateRange, - // }); - }} - /> - + { + // const nextDateRange = { + // from: datemath.parse(dateRange.from)!.toISOString(), + // to: datemath.parse(dateRange.to)!.toISOString(), + // }; + // await setGlobalParameters({ + // ...renderableInvestigation.parameters, + // timeRange: nextDateRange, + // }); + }} + /> - {/* { - return addItem(widget); + return Promise.resolve(); + // addWidget(widget); }} - /> */} + /> From deb9190390285ab72e99cde2bd4db1c3559435d5 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Fri, 23 Aug 2024 16:31:07 -0400 Subject: [PATCH 13/21] Extract items to component --- .../hooks/use_delete_investigation_item.ts | 2 +- .../hooks/use_delete_investigation_note.ts | 2 +- .../hooks/use_fetch_investigation_items.ts | 4 +- .../investigation_details.tsx | 63 +------------ .../investigation_items.tsx | 93 +++++++++++++++++++ .../investigation_notes.tsx | 7 +- .../pages/details/hooks/use_render_items.tsx | 28 +++--- 7 files changed, 120 insertions(+), 79 deletions(-) create mode 100644 x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items/investigation_items.tsx diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_delete_investigation_item.ts b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_delete_investigation_item.ts index 9c94f5f705533..41c19013e6b2d 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_delete_investigation_item.ts +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_delete_investigation_item.ts @@ -25,7 +25,7 @@ export function useDeleteInvestigationItem() { { investigationId: string; itemId: string }, { investigationId: string } >( - ['addInvestigationNote'], + ['deleteInvestigationItem'], ({ investigationId, itemId }) => { return http.delete( `/api/observability/investigations/${investigationId}/items/${itemId}`, diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_delete_investigation_note.ts b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_delete_investigation_note.ts index 136387372c581..aed3cc571ec92 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_delete_investigation_note.ts +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_delete_investigation_note.ts @@ -25,7 +25,7 @@ export function useDeleteInvestigationNote() { { investigationId: string; noteId: string }, { investigationId: string } >( - ['addInvestigationNote'], + ['deleteInvestigationNote'], ({ investigationId, noteId }) => { return http.delete( `/api/observability/investigations/${investigationId}/notes/${noteId}`, diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_fetch_investigation_items.ts b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_fetch_investigation_items.ts index 4b13a363b408f..5cc253fc6c44d 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_fetch_investigation_items.ts +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_fetch_investigation_items.ts @@ -35,7 +35,7 @@ export interface Response { data: GetInvestigationItemsResponse | undefined; } -export function useFetchInvestigationNotes({ investigationId, initialItems }: Params): Response { +export function useFetchInvestigationItems({ investigationId, initialItems }: Params): Response { const { core: { http, @@ -45,7 +45,7 @@ export function useFetchInvestigationNotes({ investigationId, initialItems }: Pa const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data, refetch } = useQuery( { - queryKey: investigationKeys.fetchNotes({ investigationId }), + queryKey: investigationKeys.fetchItems({ investigationId }), queryFn: async ({ signal }) => { return await http.get( `/api/observability/investigations/${investigationId}/items`, diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx index 90fa835551693..5f6e1ca4515d3 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/investigation_details.tsx @@ -7,14 +7,10 @@ import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; import { AuthenticatedUser } from '@kbn/security-plugin/common'; -import { noop } from 'lodash'; import React from 'react'; -import { InvestigateSearchBar } from '../../../../components/investigate_search_bar'; -import { InvestigateWidgetGrid } from '../../../../components/investigate_widget_grid'; import { useFetchInvestigation } from '../../../../hooks/use_fetch_investigation'; -import { useRenderItems } from '../../hooks/use_render_items'; +import { InvestigationItems } from '../investigation_items/investigation_items'; import { InvestigationNotes } from '../investigation_notes/investigation_notes'; -import { AddObservationUI } from '../../../../components/add_observation_ui'; interface Props { user: AuthenticatedUser; @@ -22,69 +18,20 @@ interface Props { } export function InvestigationDetails({ user, investigationId }: Props) { - const { data: investigation } = useFetchInvestigation({ id: investigationId }); - const renderableItems = useRenderItems({ investigation }); + const { data: investigation, isLoading } = useFetchInvestigation({ id: investigationId }); - if (!investigation || !renderableItems) { + if (isLoading || !investigation) { return ; } return ( - - - { - // const nextDateRange = { - // from: datemath.parse(dateRange.from)!.toISOString(), - // to: datemath.parse(dateRange.to)!.toISOString(), - // }; - // await setGlobalParameters({ - // ...renderableInvestigation.parameters, - // timeRange: nextDateRange, - // }); - }} - /> - - - { - return noop(); // copyItem(copiedItem.id); - }} - onItemDelete={async (deletedItem) => { - return noop(); // deleteItem(deletedItem.id); - }} - /> - - - - { - return Promise.resolve(); - // addWidget(widget); - }} - /> - + - + ); diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items/investigation_items.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items/investigation_items.tsx new file mode 100644 index 0000000000000..f71cace434e0b --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items/investigation_items.tsx @@ -0,0 +1,93 @@ +/* + * 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 { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { GetInvestigationResponse, Item } from '@kbn/investigation-shared'; +import { noop } from 'lodash'; +import React from 'react'; +import { AddObservationUI } from '../../../../components/add_observation_ui'; +import { InvestigateSearchBar } from '../../../../components/investigate_search_bar'; +import { InvestigateWidgetGrid } from '../../../../components/investigate_widget_grid'; +import { useAddInvestigationItem } from '../../../../hooks/use_add_investigation_item'; +import { useDeleteInvestigationItem } from '../../../../hooks/use_delete_investigation_item'; +import { useFetchInvestigationItems } from '../../../../hooks/use_fetch_investigation_items'; +import { useRenderItems } from '../../hooks/use_render_items'; + +export interface Props { + investigationId: string; + investigation: GetInvestigationResponse; +} + +export function InvestigationItems({ investigationId, investigation }: Props) { + const { data: items, refetch } = useFetchInvestigationItems({ + investigationId, + initialItems: investigation.items, + }); + const renderableItems = useRenderItems({ items, params: investigation.params }); + + const { mutateAsync: addInvestigationItem, isLoading: isAdding } = useAddInvestigationItem(); + const { mutateAsync: deleteInvestigationItem, isLoading: isDeleting } = + useDeleteInvestigationItem(); + + const onAddItem = async (item: Item) => { + await addInvestigationItem({ investigationId, item }); + refetch(); + }; + + const onDeleteItem = async (itemId: string) => { + await deleteInvestigationItem({ investigationId, itemId }); + refetch(); + }; + + return ( + + + { + // const nextDateRange = { + // from: datemath.parse(dateRange.from)!.toISOString(), + // to: datemath.parse(dateRange.to)!.toISOString(), + // }; + // await setGlobalParameters({ + // ...renderableInvestigation.parameters, + // timeRange: nextDateRange, + // }); + }} + /> + + + { + return noop(); // copyItem(copiedItem.id); + }} + onItemDelete={async (deletedItem) => { + return noop(); // deleteItem(deletedItem.id); + }} + /> + + + + { + return Promise.resolve(); + // addWidget(widget); + }} + /> + + ); +} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_notes/investigation_notes.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_notes/investigation_notes.tsx index 0f03a9f374ac3..0c58c2d26b9c2 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_notes/investigation_notes.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_notes/investigation_notes.tsx @@ -17,6 +17,7 @@ import { import { css } from '@emotion/css'; import { i18n } from '@kbn/i18n'; import { InvestigationNote } from '@kbn/investigate-plugin/common'; +import { GetInvestigationResponse } from '@kbn/investigation-shared'; import React, { useState } from 'react'; import { useAddInvestigationNote } from '../../../../hooks/use_add_investigation_note'; import { useDeleteInvestigationNote } from '../../../../hooks/use_delete_investigation_note'; @@ -27,16 +28,16 @@ import { TimelineMessage } from './timeline_message'; export interface Props { investigationId: string; - initialNotes: InvestigationNote[]; + investigation: GetInvestigationResponse; } -export function InvestigationNotes({ investigationId, initialNotes }: Props) { +export function InvestigationNotes({ investigationId, investigation }: Props) { const theme = useTheme(); const [noteInput, setNoteInput] = useState(''); const { data: notes, refetch } = useFetchInvestigationNotes({ investigationId, - initialNotes, + initialNotes: investigation.notes, }); const { mutateAsync: addInvestigationNote, isLoading: isAdding } = useAddInvestigationNote(); const { mutateAsync: deleteInvestigationNote, isLoading: isDeleting } = diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/hooks/use_render_items.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/hooks/use_render_items.tsx index 491db61cb7c1e..11c156b965b11 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/hooks/use_render_items.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/hooks/use_render_items.tsx @@ -10,7 +10,13 @@ import { GetInvestigationResponse, InvestigationItem } from '@kbn/investigation- import React, { useEffect, useState } from 'react'; import { useKibana } from '../../../hooks/use_kibana'; -export function useRenderItems({ investigation }: { investigation?: GetInvestigationResponse }) { +export function useRenderItems({ + items, + params, +}: { + items?: InvestigationItem[]; + params: GetInvestigationResponse['params']; +}) { const { dependencies: { start: { investigate }, @@ -22,9 +28,9 @@ export function useRenderItems({ investigation }: { investigation?: GetInvestiga >([]); useEffect(() => { - async function renderItems(items: InvestigationItem[]) { + async function renderItems(currItems: InvestigationItem[]) { return await Promise.all( - items.map(async (item) => { + currItems.map(async (item) => { const itemDefinition = investigate.getItemDefinitionByType(item.type); if (!itemDefinition) { return Promise.resolve({ @@ -43,12 +49,8 @@ export function useRenderItems({ investigation }: { investigation?: GetInvestiga const globalParams = { timeRange: { - from: investigation - ? new Date(investigation.params.timeRange.from).toISOString() - : new Date().toISOString(), - to: investigation - ? new Date(investigation.params.timeRange.to).toISOString() - : new Date().toISOString(), + from: new Date(params.timeRange.from).toISOString(), + to: new Date(params.timeRange.to).toISOString(), }, }; @@ -70,12 +72,10 @@ export function useRenderItems({ investigation }: { investigation?: GetInvestiga ); } - if (investigation) { - renderItems(investigation.items).then((nextRenderableItems) => - setRenderableItems(nextRenderableItems) - ); + if (items) { + renderItems(items).then((nextRenderableItems) => setRenderableItems(nextRenderableItems)); } - }, [investigation, investigate]); + }, [items, investigate, params]); return renderableItems; } From 35e3470e0fd8a3f67f43595feb87fd6782383fbd Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Fri, 23 Aug 2024 16:56:08 -0400 Subject: [PATCH 14/21] cleanup methods --- .../esql_widget_preview.tsx | 27 ++++++++----------- .../components/add_observation_ui/index.tsx | 11 ++++---- .../investigation_items.tsx | 5 +--- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/esql_widget_preview.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/esql_widget_preview.tsx index 2d1e1f1506797..89b11aff850da 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/esql_widget_preview.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/esql_widget_preview.tsx @@ -8,13 +8,8 @@ import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; import { css } from '@emotion/css'; import type { DataView } from '@kbn/data-views-plugin/common'; import type { ESQLColumn, ESQLRow } from '@kbn/es-types'; -import { - ESQL_WIDGET_NAME, - GlobalWidgetParameters, - InvestigateWidgetCreate, - OnWidgetAdd, - createEsqlWidget, -} from '@kbn/investigate-plugin/public'; +import { GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; +import { Item } from '@kbn/investigation-shared'; import type { Suggestion } from '@kbn/lens-plugin/public'; import { useAbortableAsync } from '@kbn/observability-ai-assistant-plugin/public'; import React, { useEffect, useMemo, useState } from 'react'; @@ -25,21 +20,21 @@ import { EsqlWidget } from '../../widgets/esql_widget/register_esql_widget'; import { ErrorMessage } from '../error_message'; import { SuggestVisualizationList } from '../suggest_visualization_list'; -function getWidgetFromSuggestion({ +function getItemFromSuggestion({ query, suggestion, }: { query: string; suggestion: Suggestion; -}): InvestigateWidgetCreate { - return createEsqlWidget({ +}): Item { + return { title: suggestion.title, - type: ESQL_WIDGET_NAME, - parameters: { + type: 'esql', + params: { esql: query, suggestion, }, - }); + }; } function PreviewContainer({ children }: { children: React.ReactNode }) { @@ -64,11 +59,11 @@ function PreviewContainer({ children }: { children: React.ReactNode }) { export function EsqlWidgetPreview({ esqlQuery, - onWidgetAdd, + onItemAdd, timeRange, }: { esqlQuery: string; - onWidgetAdd: OnWidgetAdd; + onItemAdd: (item: Item) => void; } & GlobalWidgetParameters) { const { services: { esql }, @@ -199,7 +194,7 @@ export function EsqlWidgetPreview({ { - onWidgetAdd(getWidgetFromSuggestion({ query: esqlQuery, suggestion })); + onItemAdd(getItemFromSuggestion({ query: esqlQuery, suggestion })); }} loading={queryResult.loading} onMouseLeave={() => {}} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/index.tsx index 69f43ef515146..b15f2dc386e2e 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/index.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/index.tsx @@ -9,19 +9,20 @@ import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiPanel, EuiTitle } fro import { css } from '@emotion/css'; import { TextBasedLangEditor } from '@kbn/esql/public'; import { i18n } from '@kbn/i18n'; -import { GlobalWidgetParameters, OnWidgetAdd } from '@kbn/investigate-plugin/public'; +import { GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; +import { Item } from '@kbn/investigation-shared'; import React from 'react'; import { EsqlWidgetPreview } from './esql_widget_preview'; type Props = { - onWidgetAdd: OnWidgetAdd; + onItemAdd: (item: Item) => void; } & GlobalWidgetParameters; const emptyPreview = css` padding: 36px 0px 36px 0px; `; -export function AddObservationUI({ onWidgetAdd, timeRange }: Props) { +export function AddObservationUI({ onItemAdd: onItemAdd, timeRange }: Props) { const [isOpen, setIsOpen] = React.useState(false); const [query, setQuery] = React.useState({ esql: '' }); @@ -113,9 +114,9 @@ export function AddObservationUI({ onWidgetAdd, timeRange }: Props) { { + onItemAdd={(item) => { resetState(); - return onWidgetAdd(widget); + return onItemAdd(item); }} /> )} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items/investigation_items.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items/investigation_items.tsx index f71cace434e0b..055a2b6548c3a 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items/investigation_items.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items/investigation_items.tsx @@ -83,10 +83,7 @@ export function InvestigationItems({ investigationId, investigation }: Props) { from: new Date(investigation.params.timeRange.from).toISOString(), to: new Date(investigation.params.timeRange.to).toISOString(), }} - onWidgetAdd={(widget) => { - return Promise.resolve(); - // addWidget(widget); - }} + onItemAdd={onAddItem} /> ); From adf3c20b8e48f9c4d8042e9b9ae6ffbe97624b22 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Mon, 26 Aug 2024 09:50:58 -0400 Subject: [PATCH 15/21] Move and rename components into details page --- .../investigate_widget_grid/index.stories.tsx | 112 ------------------ .../investigate_widget_grid/styles.scss | 1 - .../add_investigation_item.tsx} | 2 +- .../esql_widget_preview.tsx | 12 +- .../components/grid_item/index.stories.tsx | 4 +- .../details}/components/grid_item/index.tsx | 4 +- .../investigation_details/index.stories.tsx | 5 +- .../investigation_items.tsx | 19 +-- .../investigation_items_list.tsx} | 7 +- .../investigation_search_bar.tsx} | 4 +- 10 files changed, 30 insertions(+), 140 deletions(-) delete mode 100644 x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.stories.tsx delete mode 100644 x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/styles.scss rename x-pack/plugins/observability_solution/investigate_app/public/{components/add_observation_ui/index.tsx => pages/details/components/add_investigation_item/add_investigation_item.tsx} (98%) rename x-pack/plugins/observability_solution/investigate_app/public/{components/add_observation_ui => pages/details/components/add_investigation_item}/esql_widget_preview.tsx (91%) rename x-pack/plugins/observability_solution/investigate_app/public/{ => pages/details}/components/grid_item/index.stories.tsx (90%) rename x-pack/plugins/observability_solution/investigate_app/public/{ => pages/details}/components/grid_item/index.tsx (95%) rename x-pack/plugins/observability_solution/investigate_app/public/{components/investigate_widget_grid/index.tsx => pages/details/components/investigation_items_list/investigation_items_list.tsx} (92%) rename x-pack/plugins/observability_solution/investigate_app/public/{components/investigate_search_bar/index.tsx => pages/details/components/investigation_search_bar/investigation_search_bar.tsx} (93%) diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.stories.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.stories.tsx deleted file mode 100644 index f3919b8f98506..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/index.stories.tsx +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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 { ComponentMeta, ComponentStoryObj } from '@storybook/react'; -import React, { useState } from 'react'; -import { v4 } from 'uuid'; -import { InvestigateWidgetGrid as Component, RenderedInvestigationItem } from '.'; -import { KibanaReactStorybookDecorator } from '../../../.storybook/storybook_decorator'; - -const meta: ComponentMeta = { - component: Component, - title: 'app/Organisms/InvestigateWidgetGrid', - decorators: [KibanaReactStorybookDecorator], -}; - -export default meta; - -function WithPersistedChanges(props: React.ComponentProps) { - const [items, setItems] = useState(props.items); - - return ( - { - setItems((prevItems) => - prevItems.concat({ - ...item, - id: v4(), - }) - ); - }} - onItemDelete={async (item) => { - setItems((prevItems) => prevItems.filter((currentItem) => currentItem.id !== item.id)); - }} - items={items} - /> - ); -} - -const defaultProps: ComponentStoryObj = { - args: {}, - render: (props) => ( -
- -
- ), -}; - -function createItem>(overrides: T) { - return { - ...overrides, - id: v4(), - columns: 4, - rows: 2, - description: '', - loading: false, - overrides: [], - }; -} - -export const InvestigateWidgetGridStory: ComponentStoryObj = { - ...defaultProps, - args: { - ...defaultProps.args, - items: [ - createItem({ - title: '1', - element: ( -
- This should not overflow -
- ), - columns: 4, - rows: 12, - }), - - createItem({ - title: '2', - element: <>TODO, - columns: 2, - rows: 3, - overrides: [ - { - id: v4(), - label: '4 hours earlier', - }, - { - id: v4(), - label: 'service.name:opbeans-java AND service.enviroment:(production OR development)', - }, - ], - }), - createItem({ - title: '3', - element: <>TODO, - columns: 2, - rows: 3, - }), - createItem({ - title: '4', - element: <>TODO, - columns: 4, - rows: 3, - }), - ], - }, - name: 'default', -}; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/styles.scss b/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/styles.scss deleted file mode 100644 index 5528e053f84aa..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_widget_grid/styles.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../../../../../../../src/plugins/dashboard/public/dashboard_container/dashboard_container'; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_investigation_item/add_investigation_item.tsx similarity index 98% rename from x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/index.tsx rename to x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_investigation_item/add_investigation_item.tsx index b15f2dc386e2e..e4dcd2fe2000d 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/index.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_investigation_item/add_investigation_item.tsx @@ -22,7 +22,7 @@ const emptyPreview = css` padding: 36px 0px 36px 0px; `; -export function AddObservationUI({ onItemAdd: onItemAdd, timeRange }: Props) { +export function AddInvestigationItem({ onItemAdd: onItemAdd, timeRange }: Props) { const [isOpen, setIsOpen] = React.useState(false); const [query, setQuery] = React.useState({ esql: '' }); diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/esql_widget_preview.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_investigation_item/esql_widget_preview.tsx similarity index 91% rename from x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/esql_widget_preview.tsx rename to x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_investigation_item/esql_widget_preview.tsx index 89b11aff850da..793a83cf59afd 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/esql_widget_preview.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_investigation_item/esql_widget_preview.tsx @@ -13,12 +13,12 @@ import { Item } from '@kbn/investigation-shared'; import type { Suggestion } from '@kbn/lens-plugin/public'; import { useAbortableAsync } from '@kbn/observability-ai-assistant-plugin/public'; import React, { useEffect, useMemo, useState } from 'react'; -import { useKibana } from '../../hooks/use_kibana'; -import { getEsFilterFromOverrides } from '../../utils/get_es_filter_from_overrides'; -import { getDateHistogramResults } from '../../widgets/esql_widget/get_date_histogram_results'; -import { EsqlWidget } from '../../widgets/esql_widget/register_esql_widget'; -import { ErrorMessage } from '../error_message'; -import { SuggestVisualizationList } from '../suggest_visualization_list'; +import { useKibana } from '../../../../hooks/use_kibana'; +import { getEsFilterFromOverrides } from '../../../../utils/get_es_filter_from_overrides'; +import { getDateHistogramResults } from '../../../../widgets/esql_widget/get_date_histogram_results'; +import { EsqlWidget } from '../../../../widgets/esql_widget/register_esql_widget'; +import { ErrorMessage } from '../../../../components/error_message'; +import { SuggestVisualizationList } from '../../../../components/suggest_visualization_list'; function getItemFromSuggestion({ query, diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/grid_item/index.stories.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/grid_item/index.stories.tsx similarity index 90% rename from x-pack/plugins/observability_solution/investigate_app/public/components/grid_item/index.stories.tsx rename to x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/grid_item/index.stories.tsx index 6111d0181ccbb..54b13f1eea29d 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/grid_item/index.stories.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/grid_item/index.stories.tsx @@ -9,8 +9,8 @@ import { Meta, StoryObj } from '@storybook/react'; import React from 'react'; import { v4 } from 'uuid'; import { GridItem as Component } from '.'; -import { extendProps } from '../../../.storybook/extend_props'; -import { KibanaReactStorybookDecorator } from '../../../.storybook/storybook_decorator'; +import { extendProps } from '../../../../../.storybook/extend_props'; +import { KibanaReactStorybookDecorator } from '../../../../../.storybook/storybook_decorator'; type Props = React.ComponentProps; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/grid_item/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/grid_item/index.tsx similarity index 95% rename from x-pack/plugins/observability_solution/investigate_app/public/components/grid_item/index.tsx rename to x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/grid_item/index.tsx index 465f6f803edd9..91f7a58b43b5e 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/grid_item/index.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/grid_item/index.tsx @@ -7,8 +7,8 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui'; import { css } from '@emotion/css'; import React from 'react'; -import { useTheme } from '../../hooks/use_theme'; -import { InvestigateTextButton } from '../investigate_text_button'; +import { useTheme } from '../../../../hooks/use_theme'; +import { InvestigateTextButton } from '../../../../components/investigate_text_button'; export const GRID_ITEM_HEADER_HEIGHT = 40; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/index.stories.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/index.stories.tsx index 0db6f0fc5b71c..83b61c331843f 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/index.stories.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_details/index.stories.tsx @@ -5,10 +5,11 @@ * 2.0. */ +import { mockAuthenticatedUser } from '@kbn/core-security-common/mocks'; import { ComponentMeta, ComponentStoryObj } from '@storybook/react'; import React from 'react'; -import { InvestigationDetails as Component } from './investigation_details'; import { KibanaReactStorybookDecorator } from '../../../../../.storybook/storybook_decorator'; +import { InvestigationDetails as Component } from './investigation_details'; const meta: ComponentMeta = { component: Component, @@ -20,7 +21,7 @@ export default meta; const defaultProps: ComponentStoryObj = { args: {}, - render: (props) => , + render: (props) => , }; export const InvestigateViewStory: ComponentStoryObj = { diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items/investigation_items.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items/investigation_items.tsx index 055a2b6548c3a..dcc83eb968344 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items/investigation_items.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items/investigation_items.tsx @@ -7,15 +7,15 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { GetInvestigationResponse, Item } from '@kbn/investigation-shared'; -import { noop } from 'lodash'; +import { pick } from 'lodash'; import React from 'react'; -import { AddObservationUI } from '../../../../components/add_observation_ui'; -import { InvestigateSearchBar } from '../../../../components/investigate_search_bar'; -import { InvestigateWidgetGrid } from '../../../../components/investigate_widget_grid'; import { useAddInvestigationItem } from '../../../../hooks/use_add_investigation_item'; import { useDeleteInvestigationItem } from '../../../../hooks/use_delete_investigation_item'; import { useFetchInvestigationItems } from '../../../../hooks/use_fetch_investigation_items'; import { useRenderItems } from '../../hooks/use_render_items'; +import { AddInvestigationItem } from '../add_investigation_item/add_investigation_item'; +import { InvestigationItemsList } from '../investigation_items_list/investigation_items_list'; +import { InvestigationSearchBar } from '../investigation_search_bar/investigation_search_bar'; export interface Props { investigationId: string; @@ -46,7 +46,7 @@ export function InvestigationItems({ investigationId, investigation }: Props) { return ( - - { - return noop(); // copyItem(copiedItem.id); + await onAddItem(pick(copiedItem, ['title', 'type', 'params'])); }} onItemDelete={async (deletedItem) => { - return noop(); // deleteItem(deletedItem.id); + await onDeleteItem(deletedItem.id); }} /> - Promise; onItemDelete: (item: RenderedInvestigationItem) => Promise; } -export function InvestigateWidgetGrid({ +export function InvestigationItemsList({ items, + isLoading, onItemDelete, onItemCopy, }: InvestigateWidgetGridProps) { @@ -40,7 +41,7 @@ export function InvestigateWidgetGrid({ { return onItemCopy(item); }} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_search_bar/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_search_bar/investigation_search_bar.tsx similarity index 93% rename from x-pack/plugins/observability_solution/investigate_app/public/components/investigate_search_bar/index.tsx rename to x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_search_bar/investigation_search_bar.tsx index 45519f2e799be..a6ad73bc67d0d 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_search_bar/index.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_search_bar/investigation_search_bar.tsx @@ -8,7 +8,7 @@ import { css } from '@emotion/css'; import type { TimeRange } from '@kbn/es-query'; import { SearchBar } from '@kbn/unified-search-plugin/public'; import React from 'react'; -import { useKibana } from '../../hooks/use_kibana'; +import { useKibana } from '../../../../hooks/use_kibana'; const parentClassName = css` width: 100%; @@ -21,7 +21,7 @@ interface Props { onRefresh?: Required>['onRefresh']; } -export function InvestigateSearchBar({ +export function InvestigationSearchBar({ dateRangeFrom, dateRangeTo, onQuerySubmit, From 11f664af8c18bfe7f5f86acf67297003ab5e5e0e Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Mon, 26 Aug 2024 10:50:15 -0400 Subject: [PATCH 16/21] Move type --- .../investigation_items_list.tsx | 7 +------ .../public/pages/details/hooks/use_render_items.tsx | 9 ++++++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items_list/investigation_items_list.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items_list/investigation_items_list.tsx index c700a35927332..8ec5bf3ffef98 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items_list/investigation_items_list.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_items_list/investigation_items_list.tsx @@ -5,17 +5,12 @@ * 2.0. */ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { InvestigationItem } from '@kbn/investigation-shared'; import React from 'react'; import 'react-grid-layout/css/styles.css'; import 'react-resizable/css/styles.css'; +import { RenderedInvestigationItem } from '../../hooks/use_render_items'; import { GridItem } from '../grid_item'; -export type RenderedInvestigationItem = InvestigationItem & { - loading: boolean; - element: React.ReactNode; -}; - interface InvestigateWidgetGridProps { items: RenderedInvestigationItem[]; isLoading: boolean; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/hooks/use_render_items.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/hooks/use_render_items.tsx index 11c156b965b11..dc2c1c029bccd 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/hooks/use_render_items.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/hooks/use_render_items.tsx @@ -10,6 +10,11 @@ import { GetInvestigationResponse, InvestigationItem } from '@kbn/investigation- import React, { useEffect, useState } from 'react'; import { useKibana } from '../../../hooks/use_kibana'; +export type RenderedInvestigationItem = InvestigationItem & { + loading: boolean; + element: React.ReactNode; +}; + export function useRenderItems({ items, params, @@ -23,9 +28,7 @@ export function useRenderItems({ }, } = useKibana(); - const [renderableItems, setRenderableItems] = useState< - Array - >([]); + const [renderableItems, setRenderableItems] = useState([]); useEffect(() => { async function renderItems(currItems: InvestigationItem[]) { From 953fa357942a39604b732ef456c96d2ea4c88f69 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Mon, 26 Aug 2024 11:03:10 -0400 Subject: [PATCH 17/21] Remove previous widget registry --- .../investigate/common/index.ts | 6 - .../investigate/common/types.ts | 38 --- .../investigate/public/create_widget.ts | 35 -- .../public/esql_widget/constants.ts | 8 - .../public/esql_widget/create_esql_widget.ts | 12 - .../investigate/public/esql_widget/types.ts | 34 -- .../create_new_investigation.ts | 47 --- .../public/hooks/use_investigation/index.tsx | 166 ---------- .../use_investigation/investigation_store.ts | 152 --------- .../use_investigation/regenerate_item.ts | 52 --- .../investigate/public/index.ts | 15 +- .../investigate/public/plugin.tsx | 56 +--- .../investigate/public/types.ts | 58 ---- .../investigate/public/widget_registry.ts | 26 -- .../esql_widget_preview.tsx | 8 +- .../investigation_notes.tsx | 5 +- .../investigation_notes/timeline_message.tsx | 4 +- .../investigate_app/public/plugin.tsx | 24 -- .../create_embeddable_widget.ts | 13 - .../register_embeddable_widget.tsx | 194 ------------ .../public/widgets/embeddable_widget/types.ts | 18 -- .../esql_widget/get_date_histogram_results.ts | 54 ---- .../esql_widget/register_esql_widget.tsx | 299 ------------------ .../public/widgets/register_widgets.ts | 26 -- 24 files changed, 12 insertions(+), 1338 deletions(-) delete mode 100644 x-pack/plugins/observability_solution/investigate/public/create_widget.ts delete mode 100644 x-pack/plugins/observability_solution/investigate/public/esql_widget/constants.ts delete mode 100644 x-pack/plugins/observability_solution/investigate/public/esql_widget/create_esql_widget.ts delete mode 100644 x-pack/plugins/observability_solution/investigate/public/esql_widget/types.ts delete mode 100644 x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/create_new_investigation.ts delete mode 100644 x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/index.tsx delete mode 100644 x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/investigation_store.ts delete mode 100644 x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/regenerate_item.ts delete mode 100644 x-pack/plugins/observability_solution/investigate/public/widget_registry.ts delete mode 100644 x-pack/plugins/observability_solution/investigate_app/public/widgets/embeddable_widget/create_embeddable_widget.ts delete mode 100644 x-pack/plugins/observability_solution/investigate_app/public/widgets/embeddable_widget/register_embeddable_widget.tsx delete mode 100644 x-pack/plugins/observability_solution/investigate_app/public/widgets/embeddable_widget/types.ts delete mode 100644 x-pack/plugins/observability_solution/investigate_app/public/widgets/esql_widget/get_date_histogram_results.ts delete mode 100644 x-pack/plugins/observability_solution/investigate_app/public/widgets/esql_widget/register_esql_widget.tsx delete mode 100644 x-pack/plugins/observability_solution/investigate_app/public/widgets/register_widgets.ts diff --git a/x-pack/plugins/observability_solution/investigate/common/index.ts b/x-pack/plugins/observability_solution/investigate/common/index.ts index 541e2d7206bf3..47b5ad6ed2318 100644 --- a/x-pack/plugins/observability_solution/investigate/common/index.ts +++ b/x-pack/plugins/observability_solution/investigate/common/index.ts @@ -4,11 +4,5 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -export type { - Investigation, - InvestigateWidget, - InvestigateWidgetCreate, - InvestigationNote, -} from './types'; export { mergePlainObjects } from './utils/merge_plain_objects'; diff --git a/x-pack/plugins/observability_solution/investigate/common/types.ts b/x-pack/plugins/observability_solution/investigate/common/types.ts index 8a2bba966ed7e..55eab5836ce5b 100644 --- a/x-pack/plugins/observability_solution/investigate/common/types.ts +++ b/x-pack/plugins/observability_solution/investigate/common/types.ts @@ -5,47 +5,9 @@ * 2.0. */ -import type { DeepPartial } from 'utility-types'; - export interface GlobalWidgetParameters { timeRange: { from: string; to: string; }; } - -export interface Investigation { - id: string; - createdAt: number; - title: string; - items: InvestigateWidget[]; - notes: InvestigationNote[]; - parameters: GlobalWidgetParameters; -} - -export interface InvestigationNote { - id: string; - createdAt: number; - createdBy: string; - content: string; -} - -export interface InvestigateWidget< - TParameters extends Record = {}, - TData extends Record = {} -> { - id: string; - createdAt: number; - createdBy: string; - title: string; - type: string; - parameters: GlobalWidgetParameters & TParameters; - data: TData; -} - -export type InvestigateWidgetCreate = {}> = Pick< - InvestigateWidget, - 'title' | 'type' -> & { - parameters: DeepPartial & TParameters; -}; diff --git a/x-pack/plugins/observability_solution/investigate/public/create_widget.ts b/x-pack/plugins/observability_solution/investigate/public/create_widget.ts deleted file mode 100644 index 697202ac42d2b..0000000000000 --- a/x-pack/plugins/observability_solution/investigate/public/create_widget.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 { DeepPartial } from 'utility-types'; -import { InvestigateWidgetCreate } from '../common'; -import { GlobalWidgetParameters } from '../common/types'; - -type MakePartial, K extends keyof T> = Omit & - DeepPartial>; - -type PredefinedKeys = 'type'; - -export type WidgetFactory> = < - T extends MakePartial, PredefinedKeys> ->( - widgetCreate: T -) => Pick, PredefinedKeys> & - Omit & { parameters: T['parameters'] & DeepPartial }; - -export function createWidgetFactory>( - type: string -): WidgetFactory { - const createWidget: WidgetFactory = (widgetCreate) => { - return { - type, - ...widgetCreate, - }; - }; - - return createWidget; -} diff --git a/x-pack/plugins/observability_solution/investigate/public/esql_widget/constants.ts b/x-pack/plugins/observability_solution/investigate/public/esql_widget/constants.ts deleted file mode 100644 index 068d4b49fcf80..0000000000000 --- a/x-pack/plugins/observability_solution/investigate/public/esql_widget/constants.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * 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 const ESQL_WIDGET_NAME = 'esql'; diff --git a/x-pack/plugins/observability_solution/investigate/public/esql_widget/create_esql_widget.ts b/x-pack/plugins/observability_solution/investigate/public/esql_widget/create_esql_widget.ts deleted file mode 100644 index f3226afd14198..0000000000000 --- a/x-pack/plugins/observability_solution/investigate/public/esql_widget/create_esql_widget.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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 { createWidgetFactory } from '../create_widget'; -import { ESQL_WIDGET_NAME } from './constants'; -import type { EsqlWidgetParameters } from './types'; - -export const createEsqlWidget = createWidgetFactory(ESQL_WIDGET_NAME); diff --git a/x-pack/plugins/observability_solution/investigate/public/esql_widget/types.ts b/x-pack/plugins/observability_solution/investigate/public/esql_widget/types.ts deleted file mode 100644 index 764daedc9c5ed..0000000000000 --- a/x-pack/plugins/observability_solution/investigate/public/esql_widget/types.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 { IconType } from '@elastic/eui'; -import type { Ast } from '@kbn/interpreter'; - -// copied over from the Lens plugin to prevent dependency hell -type TableChangeType = 'initial' | 'unchanged' | 'reduced' | 'extended' | 'reorder' | 'layers'; - -interface Suggestion { - visualizationId: string; - datasourceState?: V; - datasourceId?: string; - columns: number; - score: number; - title: string; - visualizationState: T; - previewExpression?: Ast | string; - previewIcon: IconType; - hide?: boolean; - // flag to indicate if the visualization is incomplete - incomplete?: boolean; - changeType: TableChangeType; - keptLayerIds: string[]; -} - -export interface EsqlWidgetParameters { - esql: string; - suggestion?: Suggestion; -} diff --git a/x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/create_new_investigation.ts b/x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/create_new_investigation.ts deleted file mode 100644 index af6227e552115..0000000000000 --- a/x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/create_new_investigation.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 { i18n } from '@kbn/i18n'; -import { GetInvestigationResponse } from '@kbn/investigation-shared'; -import { v4 } from 'uuid'; -import type { Investigation } from '../../../common'; - -export function createNewInvestigation(): Investigation { - return { - id: v4(), - createdAt: new Date().getTime(), - title: i18n.translate('xpack.investigate.newInvestigationTitle', { - defaultMessage: 'New investigation', - }), - items: [], - notes: [], - parameters: { - timeRange: { - from: new Date(Date.now() - 15 * 60 * 1000).toISOString(), - to: new Date().toISOString(), - }, - }, - }; -} - -export function fromInvestigationResponse( - investigationData: GetInvestigationResponse -): Investigation { - return { - id: investigationData.id, - createdAt: investigationData.createdAt, - title: investigationData.title, - items: [], - notes: investigationData.notes, - parameters: { - timeRange: { - from: new Date(investigationData.params.timeRange.from).toISOString(), - to: new Date(investigationData.params.timeRange.to).toISOString(), - }, - }, - }; -} diff --git a/x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/index.tsx b/x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/index.tsx deleted file mode 100644 index fd3c50cdb80ac..0000000000000 --- a/x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/index.tsx +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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 { AuthenticatedUser, NotificationsStart } from '@kbn/core/public'; -import { i18n } from '@kbn/i18n'; -import { GetInvestigationResponse } from '@kbn/investigation-shared'; -import { pull } from 'lodash'; -import React, { useMemo, useRef, useState } from 'react'; -import useObservable from 'react-use/lib/useObservable'; -import { v4 } from 'uuid'; -import type { GlobalWidgetParameters } from '../..'; -import type { InvestigateWidget, InvestigateWidgetCreate } from '../../../common'; -import type { WidgetDefinition } from '../../types'; -import { createNewInvestigation, fromInvestigationResponse } from './create_new_investigation'; -import { StatefulInvestigation, createInvestigationStore } from './investigation_store'; - -export type RenderableInvestigateWidget = InvestigateWidget & { - loading: boolean; - element: React.ReactNode; -}; - -export type RenderableInvestigation = Omit & { - items: RenderableInvestigateWidget[]; -}; - -export interface UseInvestigationApi { - investigation?: StatefulInvestigation; - renderableInvestigation?: RenderableInvestigation; - copyItem: (id: string) => Promise; - deleteItem: (id: string) => Promise; - addItem: (options: InvestigateWidgetCreate) => Promise; - setGlobalParameters: (parameters: GlobalWidgetParameters) => Promise; - setTitle: (title: string) => Promise; -} - -function useInvestigationWithoutContext({ - user, - notifications, - widgetDefinitions, - investigationData, -}: { - user: AuthenticatedUser; - notifications: NotificationsStart; - widgetDefinitions: WidgetDefinition[]; - investigationData?: GetInvestigationResponse; -}): UseInvestigationApi { - const [investigationStore, _] = useState(() => - createInvestigationStore({ - user, - widgetDefinitions, - investigation: investigationData - ? fromInvestigationResponse(investigationData) - : createNewInvestigation(), - }) - ); - - const investigation$ = investigationStore.asObservable(); - const investigation = useObservable(investigation$)?.investigation; - - const addItem = async (widget: InvestigateWidgetCreate) => { - try { - const id = v4(); - await investigationStore.addItem(id, widget); - } catch (error) { - notifications.showErrorDialog({ - title: i18n.translate('xpack.investigate.failedToAddWidget', { - defaultMessage: 'Failed to add widget', - }), - error, - }); - } - }; - - const deleteItem = async (id: string) => { - return investigationStore.deleteItem(id); - }; - - const widgetComponentsById = useRef< - Record> - >({}); - - const itemsWithContext = useMemo(() => { - const unusedComponentIds = Object.keys(widgetComponentsById); - - const nextItemsWithContext = - investigation?.items.map((item) => { - let Component = widgetComponentsById.current[item.id]; - if (!Component) { - const id = item.id; - const widgetDefinition = widgetDefinitions.find( - (definition) => definition.type === item.type - )!; - - Component = widgetComponentsById.current[id] = (props) => { - return <>{widgetDefinition?.render({ widget: props.widget })}; - }; - } - - pull(unusedComponentIds, item.id); - - return { - ...item, - Component, - }; - }) ?? []; - - unusedComponentIds.forEach((id) => { - delete widgetComponentsById.current[id]; - }); - - return nextItemsWithContext; - }, [investigation?.items, widgetDefinitions]); - - const renderableInvestigation = useMemo(() => { - return investigation - ? { - ...investigation, - items: itemsWithContext.map((item) => { - const { Component, ...rest } = item; - return { - ...rest, - element: , - }; - }), - } - : undefined; - }, [investigation, itemsWithContext]); - - const { copyItem, setGlobalParameters, setTitle } = investigationStore; - - return { - addItem, - copyItem, - deleteItem, - investigation, - renderableInvestigation, - setGlobalParameters, - setTitle, - }; -} - -export function createUseInvestigation({ - notifications, - widgetDefinitions, -}: { - notifications: NotificationsStart; - widgetDefinitions: WidgetDefinition[]; -}) { - return ({ - user, - investigationData, - }: { - user: AuthenticatedUser; - investigationData?: GetInvestigationResponse; - }) => { - return useInvestigationWithoutContext({ - user, - notifications, - widgetDefinitions, - investigationData, - }); - }; -} diff --git a/x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/investigation_store.ts b/x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/investigation_store.ts deleted file mode 100644 index be2da347f995a..0000000000000 --- a/x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/investigation_store.ts +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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 { AuthenticatedUser } from '@kbn/security-plugin/common'; -import { MaybePromise } from '@kbn/utility-types'; -import { BehaviorSubject, Observable } from 'rxjs'; -import { v4 } from 'uuid'; -import { InvestigateWidget } from '../../../common'; -import { - GlobalWidgetParameters, - InvestigateWidgetCreate, - Investigation, -} from '../../../common/types'; -import { WidgetDefinition } from '../../types'; -import { regenerateItem } from './regenerate_item'; - -export type StatefulInvestigateWidget = InvestigateWidget & { - loading: boolean; -}; - -export type StatefulInvestigation = Omit & { - items: StatefulInvestigateWidget[]; -}; - -interface InvestigationStore { - copyItem: (id: string) => Promise; - deleteItem: (id: string) => Promise; - addItem: (id: string, item: InvestigateWidgetCreate) => Promise; - asObservable: () => Observable<{ - investigation: StatefulInvestigation; - }>; - setGlobalParameters: (globalWidgetParameters: GlobalWidgetParameters) => Promise; - setTitle: (title: string) => Promise; - destroy: () => void; -} - -export function createInvestigationStore({ - investigation, - user, - widgetDefinitions, -}: { - investigation: Investigation; - user: AuthenticatedUser; - widgetDefinitions: WidgetDefinition[]; -}): InvestigationStore { - const controller = new AbortController(); - - const observable$ = new BehaviorSubject<{ investigation: StatefulInvestigation }>({ - investigation: { - ...investigation, - items: investigation.items.map((item) => ({ ...item, loading: false })), - }, - }); - - async function updateInvestigationInPlace( - cb: (prevInvestigation: StatefulInvestigation) => MaybePromise - ) { - observable$.next({ investigation: await cb(observable$.value.investigation) }); - } - - const asObservable = observable$.asObservable(); - - return { - addItem: (itemId, item) => { - return updateInvestigationInPlace(async (prevInvestigation) => { - return { - ...prevInvestigation, - items: prevInvestigation.items.concat({ - ...(await regenerateItem({ - user, - widgetDefinitions, - signal: controller.signal, - widget: { - ...item, - id: itemId, - }, - globalWidgetParameters: prevInvestigation.parameters, - })), - loading: false, - }), - }; - }); - }, - copyItem: (itemId) => { - return updateInvestigationInPlace((prevInvestigation) => { - const itemToCopy = prevInvestigation.items.find((item) => item.id === itemId); - if (!itemToCopy) { - throw new Error('Cannot find item for id ' + itemId); - } - return { - ...prevInvestigation, - items: prevInvestigation.items.concat({ - ...itemToCopy, - id: v4(), - }), - }; - }); - }, - deleteItem: (itemId) => { - return updateInvestigationInPlace((prevInvestigation) => { - return { - ...prevInvestigation, - items: prevInvestigation.items.filter((item) => item.id !== itemId), - }; - }); - }, - asObservable: () => asObservable, - destroy: () => { - return controller.abort(); - }, - setGlobalParameters: async (parameters) => { - await updateInvestigationInPlace((prevInvestigation) => { - return { - ...prevInvestigation, - items: prevInvestigation.items.map((item) => { - return { ...item, loading: true }; - }), - }; - }); - - await updateInvestigationInPlace(async (prevInvestigation) => { - return { - ...prevInvestigation, - parameters, - items: await Promise.all( - prevInvestigation.items.map(async (item) => { - return { - ...(await regenerateItem({ - widget: item, - globalWidgetParameters: parameters, - signal: controller.signal, - user, - widgetDefinitions, - })), - loading: false, - }; - }) - ), - }; - }); - }, - setTitle: async (title: string) => { - return updateInvestigationInPlace((prevInvestigation) => { - return { ...prevInvestigation, title }; - }); - }, - }; -} diff --git a/x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/regenerate_item.ts b/x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/regenerate_item.ts deleted file mode 100644 index 7f7d6208ed9eb..0000000000000 --- a/x-pack/plugins/observability_solution/investigate/public/hooks/use_investigation/regenerate_item.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 { AuthenticatedUser } from '@kbn/core-security-common'; -import { v4 } from 'uuid'; -import { InvestigateWidget, InvestigateWidgetCreate, mergePlainObjects } from '../../../common'; -import { GlobalWidgetParameters } from '../../../common/types'; -import { WidgetDefinition } from '../../types'; - -export async function regenerateItem({ - user, - widgetDefinitions, - signal, - widget, - globalWidgetParameters, -}: { - user: AuthenticatedUser; - widgetDefinitions: WidgetDefinition[]; - widget: InvestigateWidgetCreate | InvestigateWidget; - signal: AbortSignal; - globalWidgetParameters: GlobalWidgetParameters; -}): Promise { - const now = Date.now(); - - const definition = widgetDefinitions.find( - (currentDefinition) => currentDefinition.type === widget.type - ); - - if (!definition) { - throw new Error(`Definition for widget ${widget.type} not found`); - } - - const nextParameters = mergePlainObjects(widget.parameters, globalWidgetParameters); - - const widgetData = await definition.generate({ - parameters: nextParameters, - signal, - }); - - return { - createdAt: now, - id: v4(), - ...widget, - parameters: nextParameters, - data: widgetData, - createdBy: user.username, - }; -} diff --git a/x-pack/plugins/observability_solution/investigate/public/index.ts b/x-pack/plugins/observability_solution/investigate/public/index.ts index 2f55a27ef1c27..07493d8360552 100644 --- a/x-pack/plugins/observability_solution/investigate/public/index.ts +++ b/x-pack/plugins/observability_solution/investigate/public/index.ts @@ -13,27 +13,16 @@ import type { InvestigateSetupDependencies, InvestigateStartDependencies, ConfigSchema, - OnWidgetAdd, } from './types'; -export type { InvestigatePublicSetup, InvestigatePublicStart, OnWidgetAdd }; +export type { InvestigatePublicSetup, InvestigatePublicStart }; -export { - type Investigation, - type InvestigateWidget, - type InvestigateWidgetCreate, - type GlobalWidgetParameters, -} from '../common/types'; +export { type GlobalWidgetParameters } from '../common/types'; export { mergePlainObjects } from '../common/utils/merge_plain_objects'; -export { createWidgetFactory } from './create_widget'; export { getEsFilterFromGlobalParameters } from './util/get_es_filters_from_global_parameters'; -export { ESQL_WIDGET_NAME } from './esql_widget/constants'; -export { createEsqlWidget } from './esql_widget/create_esql_widget'; -export type { EsqlWidgetParameters } from './esql_widget/types'; - export const plugin: PluginInitializer< InvestigatePublicSetup, InvestigatePublicStart, diff --git a/x-pack/plugins/observability_solution/investigate/public/plugin.tsx b/x-pack/plugins/observability_solution/investigate/public/plugin.tsx index a94dd4e41744f..9429383d851a8 100644 --- a/x-pack/plugins/observability_solution/investigate/public/plugin.tsx +++ b/x-pack/plugins/observability_solution/investigate/public/plugin.tsx @@ -4,17 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { - AuthenticatedUser, - CoreSetup, - CoreStart, - Plugin, - PluginInitializerContext, -} from '@kbn/core/public'; -import { GetInvestigationResponse } from '@kbn/investigation-shared'; -import type { Logger } from '@kbn/logging'; -import { useMemo } from 'react'; -import { createUseInvestigation } from './hooks/use_investigation'; +import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; import { ItemDefinition, ItemDefinitionData, @@ -28,7 +18,6 @@ import type { InvestigateSetupDependencies, InvestigateStartDependencies, } from './types'; -import { WidgetRegistry } from './widget_registry'; export class InvestigatePlugin implements @@ -39,17 +28,12 @@ export class InvestigatePlugin InvestigateStartDependencies > { - private logger: Logger; - private widgetRegistry: WidgetRegistry = new WidgetRegistry(); private itemDefinitionRegistry: ItemDefinitionRegistry = new ItemDefinitionRegistry(); - constructor(context: PluginInitializerContext) { - this.logger = context.logger.get(); - } + constructor(context: PluginInitializerContext) {} setup(coreSetup: CoreSetup, pluginsSetup: InvestigateSetupDependencies): InvestigatePublicSetup { return { - // new registerItemDefinition: < Params extends ItemDefinitionParams, Data extends ItemDefinitionData @@ -58,50 +42,14 @@ export class InvestigatePlugin ) => { this.itemDefinitionRegistry.registerItem(definition); }, - // old - register: (callback) => { - Promise.race([ - callback(this.widgetRegistry.registerWidget), - new Promise((resolve, reject) => { - setTimeout(() => { - reject(new Error('Timed out running registration function')); - }, 30000); - }), - ]).catch((error) => { - this.logger.error( - new Error('Encountered an error during widget registration', { cause: error }) - ); - return Promise.resolve(); - }); - }, }; } start(coreStart: CoreStart, pluginsStart: InvestigateStartDependencies): InvestigatePublicStart { return { - // new getItemDefinitions: () => this.itemDefinitionRegistry.getItemDefinitions(), getItemDefinitionByType: (type: string) => this.itemDefinitionRegistry.getItemDefinitionByType(type), - // old - getWidgetDefinitions: this.widgetRegistry.getWidgetDefinitions, - useInvestigation: ({ - user, - investigationData, - }: { - user: AuthenticatedUser; - investigationData?: GetInvestigationResponse; - }) => { - const widgetDefinitions = useMemo(() => this.widgetRegistry.getWidgetDefinitions(), []); - - return createUseInvestigation({ - notifications: coreStart.notifications, - widgetDefinitions, - })({ - user, - investigationData, - }); - }, }; } } diff --git a/x-pack/plugins/observability_solution/investigate/public/types.ts b/x-pack/plugins/observability_solution/investigate/public/types.ts index ad50f983e152a..36a87759c2711 100644 --- a/x-pack/plugins/observability_solution/investigate/public/types.ts +++ b/x-pack/plugins/observability_solution/investigate/public/types.ts @@ -6,60 +6,12 @@ */ /* eslint-disable @typescript-eslint/no-empty-interface*/ -import type { AuthenticatedUser } from '@kbn/core/public'; -import type { GetInvestigationResponse } from '@kbn/investigation-shared'; -import type { CompatibleJSONSchema } from '@kbn/observability-ai-assistant-plugin/public'; -import type { FromSchema } from 'json-schema-to-ts'; -import type { InvestigateWidget } from '../common'; -import type { GlobalWidgetParameters, InvestigateWidgetCreate } from '../common/types'; -import type { UseInvestigationApi } from './hooks/use_investigation'; import { ItemDefinition, ItemDefinitionData, ItemDefinitionParams, } from './investigation/item_definition_registry'; -export type OnWidgetAdd = (create: InvestigateWidgetCreate) => Promise; - -interface WidgetRenderOptions { - widget: TInvestigateWidget; -} - -export interface WidgetDefinition { - type: string; - description: string; - schema: CompatibleJSONSchema; - generate: (options: { - parameters: GlobalWidgetParameters; - signal: AbortSignal; - }) => Promise>; - render: (options: WidgetRenderOptions) => React.ReactNode; -} - -type RegisterWidgetOptions = Omit; - -type MaybeSchemaFrom = - {} & (TSchema extends CompatibleJSONSchema ? FromSchema : {}); - -type GenerateCallback< - TSchema extends CompatibleJSONSchema | undefined, - TData extends Record | undefined -> = (options: { - parameters: MaybeSchemaFrom & GlobalWidgetParameters; - signal: AbortSignal; -}) => Promise; - -export type RegisterWidget = < - TSchema extends CompatibleJSONSchema, - TData extends Record ->( - definition: Omit & { schema: TSchema }, - generateCallback: GenerateCallback, - renderCallback: ( - options: WidgetRenderOptions, TData>> - ) => React.ReactNode -) => void; - export interface ConfigSchema {} export interface InvestigateSetupDependencies {} @@ -67,25 +19,15 @@ export interface InvestigateSetupDependencies {} export interface InvestigateStartDependencies {} export interface InvestigatePublicSetup { - // new registerItemDefinition: < Params extends ItemDefinitionParams = {}, Data extends ItemDefinitionData = {} >( itemDefinition: ItemDefinition ) => void; - // old - register: (callback: (registerWidget: RegisterWidget) => Promise) => void; } export interface InvestigatePublicStart { - // new: getItemDefinitions: () => ItemDefinition[]; getItemDefinitionByType: (type: string) => ItemDefinition | undefined; - // old: - getWidgetDefinitions: () => WidgetDefinition[]; - useInvestigation: ({}: { - user: AuthenticatedUser; - investigationData?: GetInvestigationResponse; - }) => UseInvestigationApi; } diff --git a/x-pack/plugins/observability_solution/investigate/public/widget_registry.ts b/x-pack/plugins/observability_solution/investigate/public/widget_registry.ts deleted file mode 100644 index f76adf5a72506..0000000000000 --- a/x-pack/plugins/observability_solution/investigate/public/widget_registry.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 { RegisterWidget, WidgetDefinition } from './types'; - -export class WidgetRegistry { - private readonly definitions: WidgetDefinition[] = []; - - constructor() {} - - registerWidget: RegisterWidget = (definition, generateCallback, renderCallback) => { - this.definitions.push({ - ...definition, - generate: generateCallback as WidgetDefinition['generate'], - render: renderCallback as WidgetDefinition['render'], - }); - }; - - getWidgetDefinitions = (): WidgetDefinition[] => { - return this.definitions; - }; -} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_investigation_item/esql_widget_preview.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_investigation_item/esql_widget_preview.tsx index 793a83cf59afd..c865dfcf91826 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_investigation_item/esql_widget_preview.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/add_investigation_item/esql_widget_preview.tsx @@ -13,12 +13,12 @@ import { Item } from '@kbn/investigation-shared'; import type { Suggestion } from '@kbn/lens-plugin/public'; import { useAbortableAsync } from '@kbn/observability-ai-assistant-plugin/public'; import React, { useEffect, useMemo, useState } from 'react'; -import { useKibana } from '../../../../hooks/use_kibana'; -import { getEsFilterFromOverrides } from '../../../../utils/get_es_filter_from_overrides'; -import { getDateHistogramResults } from '../../../../widgets/esql_widget/get_date_histogram_results'; -import { EsqlWidget } from '../../../../widgets/esql_widget/register_esql_widget'; import { ErrorMessage } from '../../../../components/error_message'; import { SuggestVisualizationList } from '../../../../components/suggest_visualization_list'; +import { useKibana } from '../../../../hooks/use_kibana'; +import { getDateHistogramResults } from '../../../../items/esql_item/get_date_histogram_results'; +import { EsqlWidget } from '../../../../items/esql_item/register_esql_item'; +import { getEsFilterFromOverrides } from '../../../../utils/get_es_filter_from_overrides'; function getItemFromSuggestion({ query, diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_notes/investigation_notes.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_notes/investigation_notes.tsx index 0c58c2d26b9c2..8406ba8fe3f03 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_notes/investigation_notes.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/components/investigation_notes/investigation_notes.tsx @@ -16,8 +16,7 @@ import { } from '@elastic/eui'; import { css } from '@emotion/css'; import { i18n } from '@kbn/i18n'; -import { InvestigationNote } from '@kbn/investigate-plugin/common'; -import { GetInvestigationResponse } from '@kbn/investigation-shared'; +import { InvestigationNoteResponse, GetInvestigationResponse } from '@kbn/investigation-shared'; import React, { useState } from 'react'; import { useAddInvestigationNote } from '../../../../hooks/use_add_investigation_note'; import { useDeleteInvestigationNote } from '../../../../hooks/use_delete_investigation_note'; @@ -71,7 +70,7 @@ export function InvestigationNotes({ investigationId, investigation }: Props) { - {notes?.map((currNote: InvestigationNote) => { + {notes?.map((currNote: InvestigationNoteResponse) => { return ( void; isDeleting: boolean; }) { diff --git a/x-pack/plugins/observability_solution/investigate_app/public/plugin.tsx b/x-pack/plugins/observability_solution/investigate_app/public/plugin.tsx index 6309f41b26229..abbe762562541 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/plugin.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/plugin.tsx @@ -146,30 +146,6 @@ export class InvestigateAppPlugin }); }); - // old - pluginsSetup.investigate.register((registerWidget) => - Promise.all([ - pluginsStartPromise, - import('./widgets/register_widgets').then((m) => m.registerWidgets), - getCreateEsqlService(), - ]).then(([pluginsStart, registerWidgets, createEsqlService]) => { - registerWidgets({ - dependencies: { - setup: pluginsSetup, - start: pluginsStart, - }, - services: { - esql: createEsqlService({ - data: pluginsStart.data, - dataViews: pluginsStart.dataViews, - lens: pluginsStart.lens, - }), - }, - registerWidget, - }); - }) - ); - return {}; } diff --git a/x-pack/plugins/observability_solution/investigate_app/public/widgets/embeddable_widget/create_embeddable_widget.ts b/x-pack/plugins/observability_solution/investigate_app/public/widgets/embeddable_widget/create_embeddable_widget.ts deleted file mode 100644 index 61e99df8b28b2..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/widgets/embeddable_widget/create_embeddable_widget.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * 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 { createWidgetFactory } from '@kbn/investigate-plugin/public'; -import { EMBEDDABLE_WIDGET_NAME } from '../../constants'; -import { EmbeddableWidgetParameters } from './types'; - -export const createEmbeddableWidget = - createWidgetFactory(EMBEDDABLE_WIDGET_NAME); diff --git a/x-pack/plugins/observability_solution/investigate_app/public/widgets/embeddable_widget/register_embeddable_widget.tsx b/x-pack/plugins/observability_solution/investigate_app/public/widgets/embeddable_widget/register_embeddable_widget.tsx deleted file mode 100644 index 779fb9c5301b9..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/widgets/embeddable_widget/register_embeddable_widget.tsx +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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 { EuiLoadingSpinner } from '@elastic/eui'; -import { css } from '@emotion/css'; -import type { GlobalWidgetParameters } from '@kbn/investigate-plugin/public'; -import { useAbortableAsync } from '@kbn/observability-ai-assistant-plugin/public'; -import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { v4 } from 'uuid'; -import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public'; -import { EMBEDDABLE_WIDGET_NAME } from '../../constants'; -import { useKibana } from '../../hooks/use_kibana'; -import { RegisterWidgetOptions } from '../register_widgets'; -import { EmbeddableWidgetParameters } from './types'; -import { ErrorMessage } from '../../components/error_message'; - -const embeddableClassName = css` - height: 100%; - > [data-shared-item] { - height: 100%; - } -`; - -type Props = EmbeddableWidgetParameters & GlobalWidgetParameters; - -type ParentApi = ReturnType['getParentApi']>; - -function ReactEmbeddable({ type, config, timeRange: { from, to }, savedObjectId }: Props) { - const configWithOverrides = useMemo(() => { - return { - ...config, - timeRange: { - from, - to, - }, - }; - }, [config, from, to]); - - const configWithOverridesRef = useRef(configWithOverrides); - - configWithOverridesRef.current = configWithOverrides; - - const api = useMemo(() => { - return { - getSerializedStateForChild: () => ({ rawState: configWithOverridesRef.current }), - }; - }, []); - - return ( - api} - maybeId={savedObjectId} - onAnyStateChange={(state) => { - // console.log('onAnyStateChange', state); - }} - onApiAvailable={(childApi) => { - // console.log('onApiAvailable', childApi); - }} - hidePanelChrome - /> - ); -} - -function LegacyEmbeddable({ type, config, timeRange: { from, to }, savedObjectId }: Props) { - const { - dependencies: { - start: { embeddable }, - }, - } = useKibana(); - - const [targetElement, setTargetElement] = useState(null); - - const embeddableInstanceAsync = useAbortableAsync(async () => { - const factory = embeddable.getEmbeddableFactory(type); - - if (!factory) { - throw new Error(`Cannot find embeddable factory for ${type}`); - } - - const configWithId = { - id: savedObjectId ?? v4(), - ...config, - }; - - const configWithOverrides = { - ...configWithId, - timeRange: { - from, - to, - }, - }; - - if (savedObjectId) { - return factory.createFromSavedObject(configWithOverrides.id, configWithOverrides); - } - - const instance = await factory.create(configWithOverrides); - - return instance; - }, [type, savedObjectId, config, from, to, embeddable]); - - const embeddableInstance = embeddableInstanceAsync.value; - - useEffect(() => { - if (!targetElement || !embeddableInstance) { - return; - } - - embeddableInstance.render(targetElement); - - return () => {}; - }, [embeddableInstance, targetElement]); - - useEffect(() => { - return () => { - if (embeddableInstance) { - embeddableInstance.destroy(); - } - }; - }, [embeddableInstance]); - - if (embeddableInstanceAsync.error) { - return ; - } - - if (!embeddableInstance) { - return ; - } - - return ( -
{ - setTargetElement(element); - }} - /> - ); -} - -function EmbeddableWidget(props: Props) { - const { - dependencies: { - start: { embeddable }, - }, - } = useKibana(); - - if (embeddable.reactEmbeddableRegistryHasKey(props.type)) { - return ; - } - - return ; -} - -export function registerEmbeddableWidget({ registerWidget }: RegisterWidgetOptions) { - registerWidget( - { - type: EMBEDDABLE_WIDGET_NAME, - description: 'Display a saved embeddable', - schema: { - type: 'object', - properties: { - type: { - type: 'string', - }, - config: { - type: 'object', - }, - savedObjectId: { - type: 'string', - }, - }, - required: ['type', 'config'], - } as const, - }, - async ({ parameters, signal }) => { - return {}; - }, - ({ widget }) => { - const parameters = { - type: widget.parameters.type, - config: widget.parameters.config, - savedObjectId: widget.parameters.savedObjectId, - timeRange: widget.parameters.timeRange, - query: widget.parameters.query, - }; - - return ; - } - ); -} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/widgets/embeddable_widget/types.ts b/x-pack/plugins/observability_solution/investigate_app/public/widgets/embeddable_widget/types.ts deleted file mode 100644 index d3ecd0379c716..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/widgets/embeddable_widget/types.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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 { InvestigateWidget, InvestigateWidgetCreate } from '@kbn/investigate-plugin/common'; - -export interface EmbeddableWidgetParameters { - type: string; - savedObjectId?: string; - config: Record; -} - -export type EmbeddableWidgetCreate = InvestigateWidgetCreate; - -export type EmbeddableWidget = InvestigateWidget; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/widgets/esql_widget/get_date_histogram_results.ts b/x-pack/plugins/observability_solution/investigate_app/public/widgets/esql_widget/get_date_histogram_results.ts deleted file mode 100644 index 0ddfe6e38b887..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/widgets/esql_widget/get_date_histogram_results.ts +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 { Suggestion } from '@kbn/lens-plugin/public'; -import type { ESQLColumn } from '@kbn/es-types'; -import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import type { EsqlService } from '../../services/esql'; - -export async function getDateHistogramResults({ - query, - esql, - timeRange, - filter, - suggestion, - signal, - columns, -}: { - query: string; - esql: EsqlService; - timeRange: { - from: string; - to: string; - }; - filter: QueryDslQueryContainer; - suggestion: Suggestion; - signal: AbortSignal; - columns: ESQLColumn[]; -}) { - const groupingExpression = `BUCKET(@timestamp, 50, "${timeRange.from}", "${timeRange.to}")`; - const dateHistoQuery = `${query} | STATS count = COUNT(*) BY ${groupingExpression}`; - - const dateHistoResponse = - suggestion.visualizationId === 'lnsDatatable' && - columns.find((column) => column.name === '@timestamp') - ? await esql.queryWithMeta({ - query: dateHistoQuery, - signal, - filter, - }) - : undefined; - - return dateHistoResponse - ? { - columns: dateHistoResponse.query.columns, - values: dateHistoResponse.query.values, - query: dateHistoQuery, - groupingExpression, - } - : undefined; -} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/widgets/esql_widget/register_esql_widget.tsx b/x-pack/plugins/observability_solution/investigate_app/public/widgets/esql_widget/register_esql_widget.tsx deleted file mode 100644 index 84818c758ffe1..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/widgets/esql_widget/register_esql_widget.tsx +++ /dev/null @@ -1,299 +0,0 @@ -/* - * 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 { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; -import { css } from '@emotion/css'; -import type { DataView } from '@kbn/data-views-plugin/common'; -import type { ESQLSearchResponse } from '@kbn/es-types'; -import { ESQLDataGrid } from '@kbn/esql-datagrid/public'; -import { i18n } from '@kbn/i18n'; -import { - type EsqlWidgetParameters, - type GlobalWidgetParameters, -} from '@kbn/investigate-plugin/public'; -import type { Suggestion } from '@kbn/lens-plugin/public'; -import { useAbortableAsync } from '@kbn/observability-ai-assistant-plugin/public'; -import React, { useMemo } from 'react'; -import { ErrorMessage } from '../../components/error_message'; -import { ESQL_WIDGET_NAME } from '../../constants'; -import { useKibana } from '../../hooks/use_kibana'; -import { getDatatableFromEsqlResponse } from '../../utils/get_data_table_from_esql_response'; -import { getEsFilterFromOverrides } from '../../utils/get_es_filter_from_overrides'; -import { getLensAttrsForSuggestion } from '../../utils/get_lens_attrs_for_suggestion'; -import type { RegisterWidgetOptions } from '../register_widgets'; -import { getDateHistogramResults } from './get_date_histogram_results'; - -const lensClassName = css` - height: 100%; -`; - -interface Props { - suggestion: Suggestion; - dataView: DataView; - esqlQuery: string; - columns: ESQLSearchResponse['columns']; - allColumns: ESQLSearchResponse['all_columns']; - values: ESQLSearchResponse['values']; - dateHistogramResults?: { - query: string; - columns: ESQLSearchResponse['columns']; - values: ESQLSearchResponse['values']; - groupingExpression: string; - }; -} - -export function EsqlWidget({ - suggestion, - dataView, - esqlQuery, - columns, - allColumns, - values, - dateHistogramResults, -}: Props) { - const { - dependencies: { - start: { lens }, - }, - } = useKibana(); - - const datatable = useMemo(() => { - return getDatatableFromEsqlResponse({ - columns, - values, - all_columns: allColumns, - }); - }, [columns, values, allColumns]); - - const input = useMemo(() => { - return getLensAttrsForSuggestion({ - suggestion, - dataView, - query: esqlQuery, - table: datatable, - }); - }, [suggestion, dataView, esqlQuery, datatable]); - - const memoizedQueryObject = useMemo(() => { - return { esql: esqlQuery }; - }, [esqlQuery]); - - const initialColumns = useMemo(() => { - const timestampColumn = datatable.columns.find((column) => column.name === '@timestamp'); - const messageColumn = datatable.columns.find((column) => column.name === 'message'); - - if (datatable.columns.length > 20 && timestampColumn && messageColumn) { - const hasDataForBothColumns = datatable.rows.every((row) => { - const timestampValue = row['@timestamp']; - const messageValue = row.message; - - return timestampValue !== null && timestampValue !== undefined && !!messageValue; - }); - - if (hasDataForBothColumns) { - return [timestampColumn, messageColumn]; - } - } - return datatable.columns; - }, [datatable.columns, datatable.rows]); - - const previewInput = useAbortableAsync( - async ({ signal }) => { - if (!dateHistogramResults) { - return undefined; - } - - const lensHelper = await lens.stateHelperApi(); - - const suggestionsFromLensHelper = await lensHelper.suggestions( - { - dataViewSpec: dataView.toSpec(), - fieldName: '', - textBasedColumns: [ - { - id: dateHistogramResults.groupingExpression, - name: i18n.translate('xpack.investigateApp.esqlWidget.groupedByDateLabel', { - defaultMessage: '@timestamp', - }), - meta: { - type: 'date', - }, - }, - { - id: 'count', - name: 'count', - meta: { - type: 'number', - }, - }, - ], - query: { - esql: dateHistogramResults.query, - }, - }, - dataView, - ['lnsDatatable'] - ); - - const suggestionForHistogram = suggestionsFromLensHelper?.[0]; - - if (!suggestionForHistogram) { - return undefined; - } - - return getLensAttrsForSuggestion({ - suggestion: suggestionForHistogram, - dataView, - query: dateHistogramResults.query, - table: getDatatableFromEsqlResponse({ - columns: dateHistogramResults.columns, - values: dateHistogramResults.values, - }), - }); - }, - [dataView, lens, dateHistogramResults] - ); - - if (input.attributes.visualizationType === 'lnsDatatable') { - let innerElement: React.ReactElement; - if (previewInput.error) { - innerElement = ; - } else if (previewInput.value) { - innerElement = ; - } else { - innerElement = ; - } - return ( - - div { - height: 128px; - } - `} - > - {innerElement} - - - - - - ); - } - - return ( - div { - height: 128px; - } - `} - > - - - ); -} - -export function registerEsqlWidget({ - dependencies: { - setup: { investigate }, - }, - services, - registerWidget, -}: RegisterWidgetOptions) { - registerWidget( - { - type: ESQL_WIDGET_NAME, - description: 'Visualize an ES|QL query', - schema: { - type: 'object', - properties: { - esql: { - description: 'The ES|QL query', - type: 'string', - }, - }, - required: ['esql'], - } as const, - }, - async ({ parameters, signal }) => { - const { - esql: esqlQuery, - timeRange, - suggestion: suggestionFromParameters, - } = parameters as EsqlWidgetParameters & GlobalWidgetParameters; - - const esql = await services.esql; - - const esFilters = [ - getEsFilterFromOverrides({ - timeRange, - }), - ]; - - const getFilter = () => ({ - bool: { - filter: [...esFilters], - }, - }); - - const mainResponse = await esql.queryWithMeta({ - query: esqlQuery, - signal, - filter: getFilter(), - }); - - const suggestion = suggestionFromParameters || mainResponse.meta.suggestions[0]; - - const dateHistoResponse = await getDateHistogramResults({ - query: esqlQuery, - columns: mainResponse.query.columns, - esql, - filter: getFilter(), - signal, - suggestion, - timeRange, - }); - - return { - main: { - columns: mainResponse.query.columns, - values: mainResponse.query.values, - suggestion, - dataView: mainResponse.meta.dataView, - }, - dateHistogram: dateHistoResponse, - }; - }, - ({ widget }) => { - const { - main: { dataView, columns, values, suggestion }, - dateHistogram, - } = widget.data; - return ( - - ); - } - ); -} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/widgets/register_widgets.ts b/x-pack/plugins/observability_solution/investigate_app/public/widgets/register_widgets.ts deleted file mode 100644 index fd2e2b9728176..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/widgets/register_widgets.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 { RegisterWidget } from '@kbn/investigate-plugin/public/types'; -import type { InvestigateAppServices } from '../services/types'; -import type { InvestigateAppSetupDependencies, InvestigateAppStartDependencies } from '../types'; -import { registerEmbeddableWidget } from './embeddable_widget/register_embeddable_widget'; -import { registerEsqlWidget } from './esql_widget/register_esql_widget'; - -export interface RegisterWidgetOptions { - dependencies: { - setup: InvestigateAppSetupDependencies; - start: InvestigateAppStartDependencies; - }; - services: InvestigateAppServices; - registerWidget: RegisterWidget; -} - -export function registerWidgets(options: RegisterWidgetOptions) { - registerEsqlWidget(options); - registerEmbeddableWidget(options); -} From 8b53e808cb82e32d90394d14c49067f8865edaca Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 26 Aug 2024 15:29:40 +0000 Subject: [PATCH 18/21] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- .../observability_solution/investigate/tsconfig.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/x-pack/plugins/observability_solution/investigate/tsconfig.json b/x-pack/plugins/observability_solution/investigate/tsconfig.json index d48acf4a215ad..e2e39f527c2e1 100644 --- a/x-pack/plugins/observability_solution/investigate/tsconfig.json +++ b/x-pack/plugins/observability_solution/investigate/tsconfig.json @@ -14,14 +14,7 @@ "@kbn/core", "@kbn/logging", "@kbn/config-schema", - "@kbn/observability-ai-assistant-plugin", "@kbn/es-query", - "@kbn/interpreter", - "@kbn/security-plugin", - "@kbn/i18n", - "@kbn/utility-types", - "@kbn/core-security-common", - "@kbn/investigation-shared", ], "exclude": ["target/**/*"] } From ed819d2dc190a584961e26c4a5d5c11a78cb4b9e Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 26 Aug 2024 16:52:17 +0000 Subject: [PATCH 19/21] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../scripts/fix-location-collection.ts | 2 -- .buildkite/pipeline-utils/agent_images.ts | 1 - .buildkite/pipeline-utils/buildkite/client.ts | 1 - .buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts | 1 - 4 files changed, 5 deletions(-) diff --git a/.buildkite/pipeline-resource-definitions/scripts/fix-location-collection.ts b/.buildkite/pipeline-resource-definitions/scripts/fix-location-collection.ts index 8080c8f7d1d70..1173cddeb15aa 100755 --- a/.buildkite/pipeline-resource-definitions/scripts/fix-location-collection.ts +++ b/.buildkite/pipeline-resource-definitions/scripts/fix-location-collection.ts @@ -36,7 +36,6 @@ async function main() { const preamble = locationFileLines.slice(0, 1); - // eslint-disable-next-line @kbn/eslint/no_unsafe_js_yaml const locationObj = jsYaml.load( locationFileLines.slice(1).join('\n') ) as BackstageLocationResource; @@ -44,7 +43,6 @@ async function main() { (fileName) => `${resourceDefinitionsBaseUrl}/${fileName}` ); - // eslint-disable-next-line @kbn/eslint/no_unsafe_js_yaml const locationYaml = jsYaml.dump(locationObj, { lineWidth: 400 }); fs.writeFileSync(locationFile, `${preamble.join('\n')}\n${locationYaml}`); diff --git a/.buildkite/pipeline-utils/agent_images.ts b/.buildkite/pipeline-utils/agent_images.ts index 85aa4bd6fb33c..d139f7953e00f 100644 --- a/.buildkite/pipeline-utils/agent_images.ts +++ b/.buildkite/pipeline-utils/agent_images.ts @@ -6,7 +6,6 @@ * Side Public License, v 1. */ -// eslint-disable-next-line @kbn/eslint/no_unsafe_js_yaml import { dump } from 'js-yaml'; import { BuildkiteClient, BuildkiteCommandStep } from './buildkite'; diff --git a/.buildkite/pipeline-utils/buildkite/client.ts b/.buildkite/pipeline-utils/buildkite/client.ts index a0232d90e8e07..c6766c34252b1 100644 --- a/.buildkite/pipeline-utils/buildkite/client.ts +++ b/.buildkite/pipeline-utils/buildkite/client.ts @@ -9,7 +9,6 @@ import axios, { AxiosInstance } from 'axios'; import { execSync, ExecSyncOptions } from 'child_process'; -// eslint-disable-next-line @kbn/eslint/no_unsafe_js_yaml import { dump } from 'js-yaml'; import { parseLinkHeader } from './parse_link_header'; diff --git a/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts b/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts index 5aa5655014dab..21fbca3aff229 100644 --- a/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts +++ b/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts @@ -11,7 +11,6 @@ import * as Fs from 'fs'; import * as globby from 'globby'; import minimatch from 'minimatch'; -// eslint-disable-next-line @kbn/eslint/no_unsafe_js_yaml import { load as loadYaml } from 'js-yaml'; import { BuildkiteClient, BuildkiteStep } from '../buildkite'; From f90db589f7be1ae7407f4a9223b6176d9c45fb25 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Mon, 26 Aug 2024 14:06:47 -0400 Subject: [PATCH 20/21] revert eslint change --- packages/kbn-eslint-config/.eslintrc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/kbn-eslint-config/.eslintrc.js b/packages/kbn-eslint-config/.eslintrc.js index a68dc6ecd949e..de3bb8e313ccc 100644 --- a/packages/kbn-eslint-config/.eslintrc.js +++ b/packages/kbn-eslint-config/.eslintrc.js @@ -314,6 +314,7 @@ module.exports = { '@kbn/eslint/no_constructor_args_in_property_initializers': 'error', '@kbn/eslint/no_this_in_property_initializers': 'error', '@kbn/eslint/no_unsafe_console': 'error', + '@kbn/eslint/no_unsafe_js_yaml': 'error', '@kbn/imports/no_unresolvable_imports': 'error', '@kbn/imports/uniform_imports': 'error', '@kbn/imports/no_unused_imports': 'error', From d81127fd0415f09f47c83bbd7346b9311b3423d8 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Mon, 26 Aug 2024 15:09:03 -0400 Subject: [PATCH 21/21] revert change --- .../scripts/fix-location-collection.ts | 2 ++ .buildkite/pipeline-utils/agent_images.ts | 1 + .buildkite/pipeline-utils/buildkite/client.ts | 1 + .buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts | 1 + 4 files changed, 5 insertions(+) diff --git a/.buildkite/pipeline-resource-definitions/scripts/fix-location-collection.ts b/.buildkite/pipeline-resource-definitions/scripts/fix-location-collection.ts index 1173cddeb15aa..8080c8f7d1d70 100755 --- a/.buildkite/pipeline-resource-definitions/scripts/fix-location-collection.ts +++ b/.buildkite/pipeline-resource-definitions/scripts/fix-location-collection.ts @@ -36,6 +36,7 @@ async function main() { const preamble = locationFileLines.slice(0, 1); + // eslint-disable-next-line @kbn/eslint/no_unsafe_js_yaml const locationObj = jsYaml.load( locationFileLines.slice(1).join('\n') ) as BackstageLocationResource; @@ -43,6 +44,7 @@ async function main() { (fileName) => `${resourceDefinitionsBaseUrl}/${fileName}` ); + // eslint-disable-next-line @kbn/eslint/no_unsafe_js_yaml const locationYaml = jsYaml.dump(locationObj, { lineWidth: 400 }); fs.writeFileSync(locationFile, `${preamble.join('\n')}\n${locationYaml}`); diff --git a/.buildkite/pipeline-utils/agent_images.ts b/.buildkite/pipeline-utils/agent_images.ts index d139f7953e00f..85aa4bd6fb33c 100644 --- a/.buildkite/pipeline-utils/agent_images.ts +++ b/.buildkite/pipeline-utils/agent_images.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +// eslint-disable-next-line @kbn/eslint/no_unsafe_js_yaml import { dump } from 'js-yaml'; import { BuildkiteClient, BuildkiteCommandStep } from './buildkite'; diff --git a/.buildkite/pipeline-utils/buildkite/client.ts b/.buildkite/pipeline-utils/buildkite/client.ts index c6766c34252b1..a0232d90e8e07 100644 --- a/.buildkite/pipeline-utils/buildkite/client.ts +++ b/.buildkite/pipeline-utils/buildkite/client.ts @@ -9,6 +9,7 @@ import axios, { AxiosInstance } from 'axios'; import { execSync, ExecSyncOptions } from 'child_process'; +// eslint-disable-next-line @kbn/eslint/no_unsafe_js_yaml import { dump } from 'js-yaml'; import { parseLinkHeader } from './parse_link_header'; diff --git a/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts b/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts index 21fbca3aff229..5aa5655014dab 100644 --- a/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts +++ b/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts @@ -11,6 +11,7 @@ import * as Fs from 'fs'; import * as globby from 'globby'; import minimatch from 'minimatch'; +// eslint-disable-next-line @kbn/eslint/no_unsafe_js_yaml import { load as loadYaml } from 'js-yaml'; import { BuildkiteClient, BuildkiteStep } from '../buildkite';