diff --git a/x-pack/plugins/observability_solution/investigate/common/types.ts b/x-pack/plugins/observability_solution/investigate/common/types.ts index df015960a7d3d..756e346ffe7af 100644 --- a/x-pack/plugins/observability_solution/investigate/common/types.ts +++ b/x-pack/plugins/observability_solution/investigate/common/types.ts @@ -15,10 +15,6 @@ export interface GlobalWidgetParameters { from: string; to: string; }; - query: { - query: string; - language: 'kuery'; - }; filters: Filter[]; } 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 index 211171a98db73..4bf2e10cad4be 100644 --- 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 @@ -99,10 +99,6 @@ function useInvestigationWithoutContext({ id: v4(), globalWidgetParameters: { filters: [], - query: { - language: 'kuery', - query: '', - }, timeRange: { from, to, diff --git a/x-pack/plugins/observability_solution/investigate/public/util/get_es_filters_from_global_parameters.ts b/x-pack/plugins/observability_solution/investigate/public/util/get_es_filters_from_global_parameters.ts index 19ad31a025769..8d8592bf09a9a 100644 --- a/x-pack/plugins/observability_solution/investigate/public/util/get_es_filters_from_global_parameters.ts +++ b/x-pack/plugins/observability_solution/investigate/public/util/get_es_filters_from_global_parameters.ts @@ -9,11 +9,10 @@ import { type BoolQuery, buildEsQuery } from '@kbn/es-query'; import type { GlobalWidgetParameters } from '../../common/types'; export function getEsFilterFromGlobalParameters({ - query, filters, timeRange, }: Partial): { bool: BoolQuery } { - const esFilter = buildEsQuery(undefined, query ?? [], filters ?? []); + const esFilter = buildEsQuery(undefined, [], filters ?? []); if (timeRange) { esFilter.bool.filter.push({ diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/add_widget_ui/index.stories.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/add_note_ui/index.stories.tsx similarity index 77% rename from x-pack/plugins/observability_solution/investigate_app/public/components/add_widget_ui/index.stories.tsx rename to x-pack/plugins/observability_solution/investigate_app/public/components/add_note_ui/index.stories.tsx index b5e0da6ce1aa6..edb714c6d388e 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/add_widget_ui/index.stories.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/components/add_note_ui/index.stories.tsx @@ -8,8 +8,7 @@ import { Meta, StoryObj } from '@storybook/react'; import moment from 'moment'; import React from 'react'; -import { InvestigationRevision } from '@kbn/investigate-plugin/common'; -import { AddWidgetUI as Component } from '.'; +import { AddNoteUI as Component } from '.'; import { KibanaReactStorybookDecorator } from '../../../.storybook/storybook_decorator'; interface Args { @@ -30,26 +29,16 @@ export default meta; const defaultStory: Story = { args: { props: { - start: moment().subtract(15, 'minutes'), - end: moment(), onWidgetAdd: async () => {}, - revision: { - items: [], - } as unknown as InvestigationRevision, user: { username: 'johndoe', full_name: 'John Doe', }, filters: [], - query: { - language: 'kuery', - query: '', - }, timeRange: { from: moment().subtract(15, 'minutes').toISOString(), to: moment().toISOString(), }, - workflowBlocks: [], }, }, render: function Render(args) { diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/add_note_ui/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/add_note_ui/index.tsx new file mode 100644 index 0000000000000..869724efa2690 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/components/add_note_ui/index.tsx @@ -0,0 +1,26 @@ +/* + * 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 type { AuthenticatedUser } from '@kbn/core/public'; +import type { GlobalWidgetParameters, OnWidgetAdd } from '@kbn/investigate-plugin/public'; +import React from 'react'; +import { NoteWidgetControl } from '../note_widget_control'; + +type AddWidgetUIProps = { + user: Pick; + onWidgetAdd: OnWidgetAdd; +} & GlobalWidgetParameters; + +export function AddNoteUI({ user, onWidgetAdd }: AddWidgetUIProps) { + return ( + + + + + + ); +} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/esql_widget_control/esql_widget_preview.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/esql_widget_preview.tsx similarity index 93% rename from x-pack/plugins/observability_solution/investigate_app/public/components/esql_widget_control/esql_widget_preview.tsx rename to x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/esql_widget_preview.tsx index 078e61fef45cc..2bd84639e67dc 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/esql_widget_control/esql_widget_preview.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/components/add_observation_ui/esql_widget_preview.tsx @@ -5,30 +5,26 @@ * 2.0. */ import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; -import { - InvestigateWidgetColumnSpan, - InvestigateWidgetCreate, - WorkflowBlock, -} from '@kbn/investigate-plugin/public'; +import { css } from '@emotion/css'; +import type { DataView } from '@kbn/data-views-plugin/common'; +import type { ESQLColumn, ESQLRow } from '@kbn/es-types'; import { createEsqlWidget, ESQL_WIDGET_NAME, GlobalWidgetParameters, + InvestigateWidgetColumnSpan, + InvestigateWidgetCreate, OnWidgetAdd, } from '@kbn/investigate-plugin/public'; import type { Suggestion } from '@kbn/lens-plugin/public'; import { useAbortableAsync } from '@kbn/observability-ai-assistant-plugin/public'; -import { noop } from 'lodash'; import React, { useEffect, useMemo, useState } from 'react'; -import type { ESQLColumn, ESQLRow } from '@kbn/es-types'; -import { css } from '@emotion/css'; -import type { DataView } from '@kbn/data-views-plugin/common'; 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 { SuggestVisualizationList } from '../suggest_visualization_list'; import { ErrorMessage } from '../error_message'; -import { getDateHistogramResults } from '../../widgets/esql_widget/get_date_histogram_results'; +import { SuggestVisualizationList } from '../suggest_visualization_list'; function getWidgetFromSuggestion({ query, @@ -67,6 +63,7 @@ function PreviewContainer({ children }: { children: React.ReactNode }) { alignItems="center" justifyContent="center" className={css` + padding: 24px 0px 24px 0px; width: 100%; overflow: auto; > div { @@ -84,7 +81,6 @@ export function EsqlWidgetPreview({ onWidgetAdd, filters, timeRange, - query, }: { esqlQuery: string; onWidgetAdd: OnWidgetAdd; @@ -97,9 +93,8 @@ export function EsqlWidgetPreview({ return getEsFilterFromOverrides({ filters, timeRange, - query, }); - }, [filters, timeRange, query]); + }, [filters, timeRange]); const [selectedSuggestion, setSelectedSuggestion] = useState(undefined); @@ -121,7 +116,7 @@ export function EsqlWidgetPreview({ const dateHistoResponse = useAbortableAsync( ({ signal }) => { - if (!queryResult.value || queryResult.loading || !selectedSuggestion) { + if (!queryResult.value?.query?.values || queryResult.loading || !selectedSuggestion) { return undefined; } return getDateHistogramResults({ @@ -137,16 +132,6 @@ export function EsqlWidgetPreview({ [queryResult, esql, filter, esqlQuery, selectedSuggestion, timeRange] ); - const fakeRenderApi = useMemo(() => { - return { - blocks: { - publish: (_blocks: WorkflowBlock[]) => { - return noop; - }, - }, - }; - }, []); - const [displayedProps, setDisplayedProps] = useState< { error: Error | undefined; @@ -216,7 +201,6 @@ export function EsqlWidgetPreview({ { + setIsExpanded(false); + setIsPreviewOpen(false); + setQuery({ esql: '' }); + setSubmittedQuery({ esql: '' }); + }; + + if (!isOpen) { + return ( + + + setIsOpen(true)} + > + {i18n.translate( + 'xpack.investigateApp.addObservationUI.addAnObservationChartButtonLabel', + { defaultMessage: 'Add an observation chart' } + )} + + + + ); + } + + return ( + + + + +

+ {i18n.translate( + 'xpack.investigateApp.addObservationUI.h2.addAnObservationChartLabel', + { defaultMessage: 'Add an observation chart' } + )} +

+
+
+ + + + + { + if (nextSubmittedQuery) { + setSubmittedQuery(nextSubmittedQuery); + setIsPreviewOpen(true); + } + }} + errors={undefined} + warning={undefined} + expandCodeEditor={(expanded: boolean) => { + setIsExpanded(() => expanded); + }} + isCodeEditorExpanded={isExpanded} + hideMinimizeButton={false} + editorIsInline={false} + hideRunQueryText + isLoading={false} + disableSubmitAction + isDisabled={false} + hideTimeFilterInfo + /> + + + {!isPreviewOpen ? ( + + + + + +

+ {i18n.translate( + 'xpack.investigateApp.addObservationUI.p.selectADataSourceLabel', + { defaultMessage: 'Select a data source to generate a preview chart' } + )} +

+
+
+ ) : ( + { + resetState(); + return onWidgetAdd(widget); + }} + /> + )} +
+
+
+ + + { + resetState(); + setIsOpen(false); + }} + > + {i18n.translate('xpack.investigateApp.addObservationUI.cancelButtonLabel', { + defaultMessage: 'Cancel', + })} + + + +
+
+ ); +} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/add_widget_ui/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/add_widget_ui/index.tsx deleted file mode 100644 index 04f2c5f6a316c..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/add_widget_ui/index.tsx +++ /dev/null @@ -1,111 +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 } from '@elastic/eui'; -import type { AuthenticatedUser } from '@kbn/core/public'; -import type { - GlobalWidgetParameters, - InvestigateWidgetCreate, - InvestigationRevision, - OnWidgetAdd, - WorkflowBlock, -} from '@kbn/investigate-plugin/public'; -import { assertNever } from '@kbn/std'; -import { Moment } from 'moment'; -import React, { useState } from 'react'; -import { AddWidgetMode } from '../../constants/add_widget_mode'; -import { useWorkflowBlocks } from '../../hooks/workflow_blocks/use_workflow_blocks'; -import { EsqlWidgetControl } from '../esql_widget_control'; -import { NoteWidgetControl } from '../note_widget_control'; - -type AddWidgetUIProps = { - user: Pick; - onWidgetAdd: OnWidgetAdd; - revision: InvestigationRevision; - start: Moment; - end: Moment; - workflowBlocks: WorkflowBlock[]; -} & GlobalWidgetParameters; - -function getControlsForMode({ - user, - mode, - onWidgetAdd, - revision, - start, - end, - query, - timeRange, - filters, -}: { - user: Pick; - mode: AddWidgetMode; - onWidgetAdd: (widget: InvestigateWidgetCreate) => Promise; - revision: InvestigationRevision; - start: Moment; - end: Moment; -} & GlobalWidgetParameters) { - switch (mode) { - case AddWidgetMode.Esql: - return ( - - ); - - case AddWidgetMode.Note: - return ; - - default: - assertNever(mode); - } -} - -export function AddWidgetUI({ - user, - onWidgetAdd, - revision, - start, - end, - query, - filters, - timeRange, - workflowBlocks, -}: AddWidgetUIProps) { - const [mode] = useState(AddWidgetMode.Note); - - const workflowBlocksControl = useWorkflowBlocks({ - start: start.toISOString(), - end: end.toISOString(), - dynamicBlocks: workflowBlocks, - isTimelineEmpty: revision.items.length === 0, - onWidgetAdd, - }); - - return ( - - {workflowBlocksControl ? ( - {workflowBlocksControl} - ) : null} - - {getControlsForMode({ - mode, - onWidgetAdd, - revision, - start, - end, - query, - filters, - timeRange, - user, - })} - - - ); -} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/esql_widget_control/index.stories.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/esql_widget_control/index.stories.tsx deleted file mode 100644 index e36c8b6867114..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/esql_widget_control/index.stories.tsx +++ /dev/null @@ -1,36 +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 from 'react'; -import { EsqlWidgetControl as Component } from '.'; -import '../../../.storybook/mock_kibana_services'; -import { KibanaReactStorybookDecorator } from '../../../.storybook/storybook_decorator'; - -const meta: ComponentMeta = { - component: Component, - title: 'app/Organisms/EsqlControlWidget', - decorators: [KibanaReactStorybookDecorator], -}; - -function WithContainer(props: React.ComponentProps) { - return ( -
- -
- ); -} - -export default meta; - -const defaultProps: ComponentStoryObj = { - render: WithContainer, -}; - -export const EsqlControlStory: ComponentStoryObj = { - ...defaultProps, - name: 'default', -}; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/esql_widget_control/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/esql_widget_control/index.tsx deleted file mode 100644 index 789acadc01d14..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/esql_widget_control/index.tsx +++ /dev/null @@ -1,107 +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 { EuiAccordion, EuiFlexGroup, EuiFlexItem, EuiPanel, EuiTitle } from '@elastic/eui'; -import { css } from '@emotion/css'; -import { GlobalWidgetParameters, OnWidgetAdd } from '@kbn/investigate-plugin/public'; -import { TextBasedLangEditor } from '@kbn/esql/public'; -import React, { useState } from 'react'; -import { i18n } from '@kbn/i18n'; -import { EsqlWidgetPreview } from './esql_widget_preview'; - -const editorContainerClassName = css` - .kibanaCodeEditor { - width: 100%; - } - - .monaco-editor { - position: absolute !important; - } - > div { - margin: 0; - } -`; - -type EsqlWidgetControlProps = { - onWidgetAdd: OnWidgetAdd; -} & GlobalWidgetParameters; - -export function EsqlWidgetControl({ - onWidgetAdd, - filters, - timeRange, - query, -}: EsqlWidgetControlProps) { - const [isExpanded, setIsExpanded] = useState(false); - - const [esqlQuery, setEsqlQuery] = useState('FROM *'); - - const [submittedEsqlQuery, setSubmittedEsqlQuery] = useState(esqlQuery); - - const [isPreviewOpen, setIsPreviewOpen] = useState(false); - - return ( - - - - { - setIsPreviewOpen(nextIsOpen); - }} - buttonContent={ - -

- {i18n.translate('xpack.investigateApp.esqlWidgetControl.previewResultsLabel', { - defaultMessage: 'Preview results', - })} -

-
- } - > - { - setIsPreviewOpen(false); - return onWidgetAdd(widget); - }} - /> -
-
-
- - { - setIsPreviewOpen(true); - setEsqlQuery(nextQuery.esql); - }} - onTextLangQuerySubmit={async (nextSubmittedQuery) => { - setSubmittedEsqlQuery(nextSubmittedQuery?.esql ?? ''); - }} - errors={undefined} - warning={undefined} - expandCodeEditor={(expanded: boolean) => { - setIsExpanded(() => expanded); - }} - isCodeEditorExpanded={isExpanded} - hideMinimizeButton={false} - editorIsInline - hideRunQueryText - isLoading={false} - disableSubmitAction - isDisabled={false} - hideQueryHistory - hideTimeFilterInfo - /> - -
- ); -} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_view/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_view/index.tsx index 38d1e8b16e08b..910dcde7a6cee 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_view/index.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/components/investigate_view/index.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; import { css } from '@emotion/css'; import { i18n } from '@kbn/i18n'; import type { InvestigateWidget, InvestigateWidgetCreate } from '@kbn/investigate-plugin/public'; @@ -13,16 +13,16 @@ import { AuthenticatedUser } from '@kbn/security-plugin/common'; import { keyBy, omit, pick } from 'lodash'; import React, { useEffect, useMemo, useRef, useState } from 'react'; import useAsync from 'react-use/lib/useAsync'; -import { AddWidgetMode } from '../../constants/add_widget_mode'; import { useDateRange } from '../../hooks/use_date_range'; import { useKibana } from '../../hooks/use_kibana'; import { getOverridesFromGlobalParameters } from '../../utils/get_overrides_from_global_parameters'; -import { AddWidgetUI } from '../add_widget_ui'; +import { AddNoteUI } from '../add_note_ui'; +import { AddObservationUI } from '../add_observation_ui'; import { InvestigateWidgetGrid } from '../investigate_widget_grid'; const containerClassName = css` overflow: auto; - padding: 24px 24px 0px 24px; + padding: 24px 24px 24px 24px; `; const scrollContainerClassName = css` @@ -48,8 +48,6 @@ function InvestigateViewWithUser({ user }: { user: AuthenticatedUser }) { }, } = useKibana(); - const [_displayedKuery, setDisplayedKuery] = useState(''); - const widgetDefinitions = useMemo(() => investigate.getWidgetDefinitions(), [investigate]); const [range, setRange] = useDateRange(); @@ -58,7 +56,6 @@ function InvestigateViewWithUser({ user }: { user: AuthenticatedUser }) { addItem, setItemPositions, setItemTitle, - blocks, copyItem, deleteItem, investigation, @@ -92,10 +89,6 @@ function InvestigateViewWithUser({ user }: { user: AuthenticatedUser }) { }); }, [revision]); - useEffect(() => { - setDisplayedKuery(revision?.parameters.query.query ?? ''); - }, [revision?.parameters.query.query]); - useEffect(() => { if ( revision?.parameters.timeRange.from && @@ -135,7 +128,7 @@ function InvestigateViewWithUser({ user }: { user: AuthenticatedUser }) { loading: item.loading, overrides: item.locked ? getOverridesFromGlobalParameters( - pick(item.parameters, 'filters', 'query', 'timeRange'), + pick(item.parameters, 'filters', 'timeRange'), revision.parameters, uiSettings.get(DATE_FORMAT_ID) ?? 'Browser' ) @@ -197,14 +190,9 @@ function InvestigateViewWithUser({ user }: { user: AuthenticatedUser }) { />
- { return createWidgetRef.current(widget); @@ -212,14 +200,13 @@ function InvestigateViewWithUser({ user }: { user: AuthenticatedUser }) { /> - - - {i18n.translate( - 'xpack.investigateApp.investigateViewWithUser.addAnObservationChartButtonLabel', - { defaultMessage: 'Add an observation chart' } - )} - - + { + return createWidgetRef.current(widget); + }} + /> diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/investigation_history/index.stories.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/investigation_history/index.stories.tsx deleted file mode 100644 index 3e9941db710f5..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/investigation_history/index.stories.tsx +++ /dev/null @@ -1,96 +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 { Meta, StoryObj } from '@storybook/react'; -import { merge } from 'lodash'; -import React from 'react'; -import { InvestigationHistory as Component } from '.'; -import { KibanaReactStorybookDecorator } from '../../../.storybook/storybook_decorator'; - -interface Args { - props: React.ComponentProps; -} - -type StoryMeta = Meta; -type Story = StoryObj; - -const meta: StoryMeta = { - component: Component, - title: 'app/Molecules/InvestigationHistory', - decorators: [KibanaReactStorybookDecorator], -}; - -export default meta; - -const defaultStory: Story = { - args: { - props: { - investigations: [], - error: undefined, - loading: false, - onDeleteInvestigationClick: () => {}, - onInvestigationClick: () => {}, - onStartNewInvestigationClick: () => {}, - }, - }, - render: function Render(args) { - return ( -
- -
- ); - }, -}; - -export const WithInvestigationsStory: Story = { - ...defaultStory, - args: merge({}, defaultStory.args, { - props: { - loading: false, - investigations: [ - { - id: 'one', - title: 'My previous investigation', - }, - { - id: 'two', - title: 'Another investigation', - }, - { - id: 'three', - title: 'Blabla', - }, - { - id: 'four', - title: 'A really really long title that shows how this component deals with overflow', - }, - ], - }, - }), - name: 'default', -}; - -export const LoadingEmptyStory: Story = { - ...defaultStory, - args: merge({}, defaultStory.args, { - props: { - loading: true, - }, - }), - name: 'loading empty', -}; - -export const ErrorStory: Story = { - ...defaultStory, - args: merge({}, defaultStory.args, { - props: { - loading: false, - error: new Error('Failed to load investigations'), - }, - }), - name: 'error', -}; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/investigation_history/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/investigation_history/index.tsx deleted file mode 100644 index 963464cbc46e9..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/investigation_history/index.tsx +++ /dev/null @@ -1,181 +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 React from 'react'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiHorizontalRule, - EuiIcon, - EuiLink, - EuiLoadingSpinner, - EuiText, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { css } from '@emotion/css'; -import classNames from 'classnames'; -import { Investigation } from '@kbn/investigate-plugin/common'; -import { useTheme } from '../../hooks/use_theme'; -import { InvestigateTextButton } from '../investigate_text_button'; - -const headerClassName = css` - text-transform: uppercase; - font-weight: 600; -`; - -const investigationItemClassName = css` - max-width: 100%; - white-space: normal; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; -`; - -const newInvestigationItemClassName = css` - .euiText { - font-weight: 500 !important; - } -`; - -function WrapWithHeader({ children, loading }: { children: React.ReactElement; loading: boolean }) { - return ( - - - - - - {i18n.translate('xpack.investigateApp.investigationHistory.previously', { - defaultMessage: 'Previously', - })} - - - {loading ? ( - - - - ) : null} - - - {children} - - ); -} - -export function InvestigationHistory({ - investigations, - loading, - error, - onInvestigationClick, - onStartNewInvestigationClick, - onDeleteInvestigationClick, -}: { - investigations?: Array>; - loading: boolean; - error?: Error; - onInvestigationClick: (id: string) => void; - onStartNewInvestigationClick: () => void; - onDeleteInvestigationClick: (id: string) => void; -}) { - const theme = useTheme(); - - const investigationsList = ( - - - {} - { - onStartNewInvestigationClick(); - }} - > - - - - - - - {i18n.translate('xpack.investigateApp.investigationHistory.new', { - defaultMessage: 'New investigation', - })} - - - - - - {investigations?.length ? ( - - - - ) : null} - {investigations?.map((investigation) => ( - - - - { - onInvestigationClick(investigation.id); - }} - > - - {investigation.title} - - - - - { - onDeleteInvestigationClick(investigation.id); - }} - size="xs" - /> - - - - ))} - - ); - - if (error) { - return ( - - - - - - - - - - {error.message} - - - - - {investigationsList} - - - ); - } - - return {investigationsList}; -} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/suggest_visualization_list/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/suggest_visualization_list/index.tsx index a1702cc064f14..17d63f47950db 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/suggest_visualization_list/index.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/components/suggest_visualization_list/index.tsx @@ -40,6 +40,19 @@ const iconContainerClassName = css` width: 16px; `; +interface Props { + suggestions?: Array< + Suggestion & { + id: string; + } + >; + loading: boolean; + error?: Error; + onSuggestionClick: (suggestion: Suggestion) => void; + onSuggestionRollOver: (suggestion: Suggestion) => void; + onMouseLeave: () => void; +} + export function SuggestVisualizationList({ suggestions, loading, @@ -47,14 +60,7 @@ export function SuggestVisualizationList({ onSuggestionClick, onSuggestionRollOver, onMouseLeave, -}: { - suggestions?: Array; - loading: boolean; - error?: Error; - onSuggestionClick: (suggestion: Suggestion) => void; - onSuggestionRollOver: (suggestion: Suggestion) => void; - onMouseLeave: () => void; -}) { +}: Props) { if (error) { return ( = { - component: Component, - title: 'app/Molecules/WorkflowsBlock', - decorators: [KibanaReactStorybookDecorator], -}; - -export default meta; - -function createWorkflowBlocks(): WorkflowBlock[] { - return [ - { - id: '0', - content: 'Investigate alerts', - description: '12 open alerts', - loading: false, - color: 'warning', - }, - { - id: '1', - content: '', - description: '', - loading: true, - onClick: () => {}, - }, - { - id: '2', - content: 'Really really really long content to see how the component deals with wrapping', - description: - 'I need a really long description too, because that one needs to deal with overflow as well, and should stay on a single line', - loading: false, - onClick: () => {}, - }, - ]; -} - -const defaultProps: ComponentStoryObj = { - render: (props) => { - return ( -
- -
- ); - }, -}; - -export const DefaultStory: ComponentStoryObj = { - ...defaultProps, - args: { - ...defaultProps.args, - blocks: createWorkflowBlocks(), - compressed: false, - }, - name: 'default', -}; - -export const CompressedStory: ComponentStoryObj = { - ...defaultProps, - args: { - ...defaultProps.args, - blocks: createWorkflowBlocks(), - compressed: true, - }, - name: 'compressed', -}; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/components/workflow_blocks_control/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/components/workflow_blocks_control/index.tsx deleted file mode 100644 index 8182ebd4a34eb..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/components/workflow_blocks_control/index.tsx +++ /dev/null @@ -1,160 +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 { - EuiErrorBoundary, - EuiFlexGroup, - EuiFlexItem, - EuiLoadingSpinner, - EuiPanel, - EuiText, -} from '@elastic/eui'; -// @ts-expect-error -import { getTextColor } from '@elastic/eui/lib/components/badge/color_utils'; -import { css } from '@emotion/css'; -import { WorkflowBlock } from '@kbn/investigate-plugin/common'; -import classNames from 'classnames'; -import { rgba } from 'polished'; -import React from 'react'; -import { useTheme } from '../../hooks/use_theme'; - -const groupClassName = css` - height: 100%; -`; - -const textItemClassName = css` - max-width: 100%; - text-align: left; -`; - -const descriptionClassName = css` - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -`; - -const itemClassName = css` - max-width: 320px; -`; - -const loadingContainerClassName = css` - height: 100%; -`; - -function WorkflowBlockControl({ - content, - description, - loading, - onClick, - color = 'primary', - children, - compressed, -}: Omit & { compressed: boolean }) { - const theme = useTheme(); - - const actualColor = theme.colors[loading ? 'lightestShade' : color]; - - const panelClassName = css` - background-color: ${rgba(actualColor, 0.75)}; - height: ${compressed ? 32 : 128}px; - transition: all ${theme.animation.fast} ${theme.animation.resistance} !important; - `; - - const contentClassName = css` - overflow: hidden; - text-overflow: ellipsis; - font-weight: 500; - white-space: normal; - display: -webkit-box; - -webkit-line-clamp: ${compressed ? 1 : 2}; - -webkit-box-orient: vertical; - `; - - const panelClickableClassName = onClick - ? classNames( - panelClassName, - css` - cursor: pointer; - &:hover, - &:focus { - box-shadow: none; - background-color: ${rgba(actualColor, 1)}; - transform: none; - border: 1px solid ${theme.colors.darkestShade}; - } - ` - ) - : panelClassName; - - const textColor = getTextColor({ euiTheme: theme }, actualColor); - - if (loading) { - return ( - <> - - - - - - - - {children} - - ); - } - - return ( - <> - - - {description && !compressed && ( - - - {description} - - - )} - - - {content} - - - - - {children} - - ); -} - -export function WorkflowBlocksControl({ - blocks, - compressed, -}: { - blocks: WorkflowBlock[]; - compressed: boolean; -}) { - return ( - - {blocks.map((block) => ( - - - - - - ))} - - ); -} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/workflow_blocks/use_workflow_blocks.tsx b/x-pack/plugins/observability_solution/investigate_app/public/hooks/workflow_blocks/use_workflow_blocks.tsx deleted file mode 100644 index c38051f523ad8..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/workflow_blocks/use_workflow_blocks.tsx +++ /dev/null @@ -1,32 +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 { InvestigateWidgetCreate, WorkflowBlock } from '@kbn/investigate-plugin/common'; -import { compact } from 'lodash'; -import React from 'react'; -import { WorkflowBlocksControl } from '../../components/workflow_blocks_control'; - -export function useWorkflowBlocks({ - isTimelineEmpty, - dynamicBlocks, - start, - end, - onWidgetAdd, -}: { - isTimelineEmpty: boolean; - dynamicBlocks: WorkflowBlock[]; - start: string; - end: string; - onWidgetAdd: (create: InvestigateWidgetCreate) => Promise; -}) { - const blocks = isTimelineEmpty ? compact([]) : dynamicBlocks; - - if (!blocks.length) { - return null; - } - - return ; -} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/services/esql.ts b/x-pack/plugins/observability_solution/investigate_app/public/services/esql.ts index 5cc032f95f054..8d4abadce2bb8 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/services/esql.ts +++ b/x-pack/plugins/observability_solution/investigate_app/public/services/esql.ts @@ -5,13 +5,13 @@ * 2.0. */ -import { lastValueFrom } from 'rxjs'; -import { getESQLAdHocDataview, getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; -import { type DataView, ESQL_SEARCH_STRATEGY } from '@kbn/data-plugin/common'; -import type { DatatableColumnType } from '@kbn/expressions-plugin/common'; +import { ESQL_SEARCH_STRATEGY, type DataView } from '@kbn/data-plugin/common'; import type { ESFilter, ESQLSearchResponse } from '@kbn/es-types'; +import { getESQLAdHocDataview } from '@kbn/esql-utils'; +import type { DatatableColumnType } from '@kbn/expressions-plugin/common'; import { AbortError } from '@kbn/kibana-utils-plugin/common'; import type { Suggestion } from '@kbn/lens-plugin/public'; +import { lastValueFrom } from 'rxjs'; import { v4 } from 'uuid'; import type { InvestigateAppStartDependencies } from '../types'; import { getKibanaColumns } from '../utils/get_kibana_columns'; @@ -92,19 +92,17 @@ export function createEsqlService({ }; }, meta: async ({ query, signal, filter }) => { - const indexPattern = getIndexPatternFromESQLQuery(query); - const [response, lensHelper, dataView] = await Promise.all([ runQuery({ query: `${query} | LIMIT 0`, signal, dropNullColumns: false, filter }), lens.stateHelperApi(), - getESQLAdHocDataview(indexPattern, dataViews), + getESQLAdHocDataview(query, dataViews), ]); const columns = getKibanaColumns(response.columns ?? []); const suggestionsFromLensHelper = await lensHelper.suggestions( { - dataViewSpec: dataView.toSpec(), + dataViewSpec: dataView.toSpec(false), fieldName: '', textBasedColumns: columns, query: { diff --git a/x-pack/plugins/observability_solution/investigate_app/public/utils/get_es_filter_from_overrides.ts b/x-pack/plugins/observability_solution/investigate_app/public/utils/get_es_filter_from_overrides.ts index 483be2f019143..ccc385701fb0f 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/utils/get_es_filter_from_overrides.ts +++ b/x-pack/plugins/observability_solution/investigate_app/public/utils/get_es_filter_from_overrides.ts @@ -5,21 +5,19 @@ * 2.0. */ -import { type BoolQuery, buildEsQuery, type Query, type Filter } from '@kbn/es-query'; +import { type BoolQuery, buildEsQuery, type Filter } from '@kbn/es-query'; export function getEsFilterFromOverrides({ - query, filters, timeRange, }: { - query?: Query; filters?: Filter[]; timeRange?: { from: string; to: string; }; }): { bool: BoolQuery } { - const esFilter = buildEsQuery(undefined, query ?? [], filters ?? []); + const esFilter = buildEsQuery(undefined, [], filters ?? []); if (timeRange) { esFilter.bool.filter.push({ diff --git a/x-pack/plugins/observability_solution/investigate_app/public/utils/get_overrides_from_global_parameters.tsx b/x-pack/plugins/observability_solution/investigate_app/public/utils/get_overrides_from_global_parameters.tsx index 6e46189648d86..8da9daf040e36 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/utils/get_overrides_from_global_parameters.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/utils/get_overrides_from_global_parameters.tsx @@ -14,7 +14,6 @@ import { PrettyDuration } from '@elastic/eui'; import type { InvestigateWidgetGridItemOverride } from '../components/investigate_widget_grid'; enum OverrideType { - query = 'query', timeRange = 'timeRange', filters = 'filters', } @@ -38,15 +37,6 @@ export function getOverridesFromGlobalParameters( ) { const overrides: InvestigateWidgetGridItemOverride[] = []; - if (!isEqual(itemParameters.query, globalParameters.query)) { - overrides.push({ - id: OverrideType.query, - label: itemParameters.query.query - ? itemParameters.query.query - : i18n.translate('xpack.investigateApp.overrides.noQuery', { defaultMessage: 'No query' }), - }); - } - if (!isEqual(itemParameters.timeRange, globalParameters.timeRange)) { overrides.push({ id: OverrideType.timeRange, 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 index 02e69d3226ab8..e4a1ea7e3396d 100644 --- 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 @@ -28,25 +28,17 @@ type Props = EmbeddableWidgetParameters & GlobalWidgetParameters; type ParentApi = ReturnType['getParentApi']>; -function ReactEmbeddable({ - type, - config, - query, - filters, - timeRange: { from, to }, - savedObjectId, -}: Props) { +function ReactEmbeddable({ type, config, filters, timeRange: { from, to }, savedObjectId }: Props) { const configWithOverrides = useMemo(() => { return { ...config, - query, filters, timeRange: { from, to, }, }; - }, [config, query, filters, from, to]); + }, [config, filters, from, to]); const configWithOverridesRef = useRef(configWithOverrides); @@ -77,7 +69,6 @@ function ReactEmbeddable({ function LegacyEmbeddable({ type, config, - query, filters, timeRange: { from, to }, savedObjectId, @@ -104,7 +95,6 @@ function LegacyEmbeddable({ const configWithOverrides = { ...configWithId, - query, filters, timeRange: { from, @@ -119,7 +109,7 @@ function LegacyEmbeddable({ const instance = await factory.create(configWithOverrides); return instance; - }, [type, savedObjectId, config, from, to, embeddable, filters, query]); + }, [type, savedObjectId, config, from, to, embeddable, filters]); const embeddableInstance = embeddableInstanceAsync.value; 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 index c2ba65d19aff9..ea990d4e4ac4c 100644 --- 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 @@ -4,57 +4,53 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useEffect, useMemo } from 'react'; -import type { Suggestion } from '@kbn/lens-plugin/public'; +import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; import { css } from '@emotion/css'; -import type { - EsqlWidgetParameters, - GlobalWidgetParameters, - WidgetRenderAPI, -} from '@kbn/investigate-plugin/public'; 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 { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; +import type { EsqlWidgetParameters, 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 type { RegisterWidgetOptions } from '../register_widgets'; import { useKibana } from '../../hooks/use_kibana'; -import { getLensAttrsForSuggestion } from '../../utils/get_lens_attrs_for_suggestion'; import { getDatatableFromEsqlResponse } from '../../utils/get_data_table_from_esql_response'; import { getEsFilterFromOverrides } from '../../utils/get_es_filter_from_overrides'; -import { ErrorMessage } from '../../components/error_message'; +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%; `; -export function EsqlWidget({ - suggestion, - dataView, - esqlQuery, - columns, - allColumns, - values, - blocks, - dateHistogramResults, -}: { +interface Props { suggestion: Suggestion; dataView: DataView; esqlQuery: string; columns: ESQLSearchResponse['columns']; allColumns: ESQLSearchResponse['all_columns']; values: ESQLSearchResponse['values']; - blocks: WidgetRenderAPI['blocks']; 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 }, @@ -82,25 +78,11 @@ export function EsqlWidget({ return { esql: esqlQuery }; }, [esqlQuery]); - useEffect(() => { - if (datatable.columns.find((column) => column.name === 'message')) { - return blocks.publish([ - { - id: 'pattern_analysis', - loading: false, - content: i18n.translate('xpack.investigateApp.esqlWidget.runPatternAnalysis', { - defaultMessage: 'Analyze log patterns', - }), - }, - ]); - } - }, [blocks, datatable]); - 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 > 10 && timestampColumn && messageColumn) { + if (datatable.columns.length > 100 && timestampColumn && messageColumn) { const hasDataForBothColumns = datatable.rows.every((row) => { const timestampValue = row['@timestamp']; const messageValue = row.message; @@ -112,7 +94,7 @@ export function EsqlWidget({ return [timestampColumn, messageColumn]; } } - return undefined; + return datatable.columns; }, [datatable.columns, datatable.rows]); const previewInput = useAbortableAsync( @@ -235,7 +217,6 @@ export function registerEsqlWidget({ async ({ parameters, signal }) => { const { esql: esqlQuery, - query, filters, timeRange, suggestion: suggestionFromParameters, @@ -245,7 +226,6 @@ export function registerEsqlWidget({ const esFilters = [ getEsFilterFromOverrides({ - query, filters, timeRange, }), @@ -298,7 +278,6 @@ export function registerEsqlWidget({ values={values} suggestion={suggestion} esqlQuery={widget.parameters.esql} - blocks={blocks} dateHistogramResults={dateHistogram} /> ); diff --git a/x-pack/plugins/observability_solution/investigate_app/tsconfig.json b/x-pack/plugins/observability_solution/investigate_app/tsconfig.json index f2ea50270fb4f..7dc7f89ca178b 100644 --- a/x-pack/plugins/observability_solution/investigate_app/tsconfig.json +++ b/x-pack/plugins/observability_solution/investigate_app/tsconfig.json @@ -51,6 +51,5 @@ "@kbn/security-plugin", "@kbn/ui-actions-plugin", "@kbn/esql-datagrid", - "@kbn/std" ], }