mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
# Backport This will backport the following commits from `main` to `8.10`: - [[Observability AI Assistant] Save/open Lens embeddable (#165542)](https://github.com/elastic/kibana/pull/165542) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Dario Gieselaar","email":"dario.gieselaar@elastic.co"},"sourceCommit":{"committedDate":"2023-09-03T10:48:15Z","message":"[Observability AI Assistant] Save/open Lens embeddable (#165542)","sha":"1c531919721c463d80b22fb796bba82861508bd6","branchLabelMapping":{"^v8.11.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v8.10.0","v8.11.0"],"number":165542,"url":"https://github.com/elastic/kibana/pull/165542","mergeCommit":{"message":"[Observability AI Assistant] Save/open Lens embeddable (#165542)","sha":"1c531919721c463d80b22fb796bba82861508bd6"}},"sourceBranch":"main","suggestedTargetBranches":["8.10"],"targetPullRequestStates":[{"branch":"8.10","label":"v8.10.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.11.0","labelRegex":"^v8.11.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/165542","number":165542,"mergeCommit":{"message":"[Observability AI Assistant] Save/open Lens embeddable (#165542)","sha":"1c531919721c463d80b22fb796bba82861508bd6"}}]}] BACKPORT--> Co-authored-by: Dario Gieselaar <dario.gieselaar@elastic.co>
This commit is contained in:
parent
a5f3f46f2d
commit
988ac799db
3 changed files with 93 additions and 47 deletions
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { last } from 'lodash';
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
|
@ -104,49 +104,40 @@ export function ChatBody({
|
|||
: '100%'};
|
||||
`;
|
||||
|
||||
const [stickToBottom, setStickToBottom] = useState(true);
|
||||
|
||||
const isAtBottom = (parent: HTMLElement) =>
|
||||
parent.scrollTop + parent.clientHeight >= parent.scrollHeight;
|
||||
|
||||
useEffect(() => {
|
||||
const parent = timelineContainerRef.current?.parentElement;
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
let rafId: number | undefined;
|
||||
|
||||
const isAtBottom = () => parent.scrollTop >= parent.scrollHeight - parent.offsetHeight;
|
||||
|
||||
const stick = () => {
|
||||
if (!isAtBottom()) {
|
||||
parent.scrollTop = parent.scrollHeight - parent.offsetHeight;
|
||||
}
|
||||
rafId = requestAnimationFrame(stick);
|
||||
};
|
||||
|
||||
const unstick = () => {
|
||||
if (rafId) {
|
||||
cancelAnimationFrame(rafId);
|
||||
rafId = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const onScroll = (event: Event) => {
|
||||
if (isAtBottom()) {
|
||||
stick();
|
||||
} else {
|
||||
unstick();
|
||||
}
|
||||
};
|
||||
function onScroll() {
|
||||
setStickToBottom(isAtBottom(parent!));
|
||||
}
|
||||
|
||||
parent.addEventListener('scroll', onScroll);
|
||||
|
||||
stick();
|
||||
|
||||
return () => {
|
||||
unstick();
|
||||
parent.removeEventListener('scroll', onScroll);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [timelineContainerRef.current]);
|
||||
|
||||
useEffect(() => {
|
||||
const parent = timelineContainerRef.current?.parentElement;
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stickToBottom) {
|
||||
parent.scrollTop = parent.scrollHeight;
|
||||
}
|
||||
});
|
||||
|
||||
const handleCopyConversation = () => {
|
||||
const content = JSON.stringify({ title, messages });
|
||||
|
||||
|
@ -210,7 +201,10 @@ export function ChatBody({
|
|||
<ChatPromptEditor
|
||||
loading={isLoading}
|
||||
disabled={!connectors.selectedConnector || !hasCorrectLicense}
|
||||
onSubmit={timeline.onSubmit}
|
||||
onSubmit={(message) => {
|
||||
setStickToBottom(true);
|
||||
return timeline.onSubmit(message);
|
||||
}}
|
||||
/>
|
||||
<EuiSpacer size="s" />
|
||||
</EuiPanel>
|
||||
|
|
|
@ -16,7 +16,6 @@ import classNames from 'classnames';
|
|||
import type { Code, InlineCode, Parent, Text } from 'mdast';
|
||||
import React, { useMemo } from 'react';
|
||||
import type { Node } from 'unist';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
interface Props {
|
||||
content: string;
|
||||
|
@ -48,7 +47,10 @@ const cursorCss = css`
|
|||
|
||||
const Cursor = () => <span key="cursor" className={classNames(cursorCss, 'cursor')} />;
|
||||
|
||||
const CURSOR = `{{${v4()}}}`;
|
||||
// a weird combination of different whitespace chars to make sure it stays
|
||||
// invisible even when we cannot properly parse the text while still being
|
||||
// unique
|
||||
const CURSOR = ` `;
|
||||
|
||||
const loadingCursorPlugin = () => {
|
||||
const visitor = (node: Node, parent?: Parent) => {
|
||||
|
|
|
@ -4,13 +4,15 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { EuiLoadingSpinner } from '@elastic/eui';
|
||||
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';
|
||||
import type { DataViewsServicePublic } from '@kbn/data-views-plugin/public/types';
|
||||
import { FIELD_FORMAT_IDS } from '@kbn/field-formats-plugin/common';
|
||||
import { LensAttributesBuilder, XYChart, XYDataLayer } from '@kbn/lens-embeddable-utils';
|
||||
import type { LensPublicStart } from '@kbn/lens-plugin/public';
|
||||
import React from 'react';
|
||||
import type { LensEmbeddableInput, LensPublicStart } from '@kbn/lens-plugin/public';
|
||||
import React, { useState } from 'react';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Assign } from 'utility-types';
|
||||
import type { RegisterFunctionDefinition } from '../../common/types';
|
||||
import type {
|
||||
ObservabilityAIAssistantPluginStartDependencies,
|
||||
|
@ -56,6 +58,8 @@ function Lens({
|
|||
});
|
||||
}, [indexPattern]);
|
||||
|
||||
const [isSaveModalOpen, setIsSaveModalOpen] = useState(false);
|
||||
|
||||
if (!formulaAsync.value || !dataViewAsync.value) {
|
||||
return <EuiLoadingSpinner />;
|
||||
}
|
||||
|
@ -68,19 +72,65 @@ function Lens({
|
|||
}),
|
||||
}).build();
|
||||
|
||||
const lensEmbeddableInput: Assign<LensEmbeddableInput, { attributes: typeof attributes }> = {
|
||||
id: indexPattern,
|
||||
attributes,
|
||||
timeRange: {
|
||||
from: start,
|
||||
to: end,
|
||||
mode: 'relative' as const,
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<lens.EmbeddableComponent
|
||||
id={indexPattern}
|
||||
attributes={attributes}
|
||||
timeRange={{
|
||||
from: start,
|
||||
to: end,
|
||||
mode: 'relative',
|
||||
}}
|
||||
style={{
|
||||
height: 240,
|
||||
}}
|
||||
/>
|
||||
<>
|
||||
<EuiFlexGroup direction="column">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup direction="row" gutterSize="s" justifyContent="flexEnd">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
iconType="lensApp"
|
||||
onClick={() => {
|
||||
lens.navigateToPrefilledEditor(lensEmbeddableInput);
|
||||
}}
|
||||
>
|
||||
{i18n.translate('xpack.observabilityAiAssistant.lensFunction.openInLens', {
|
||||
defaultMessage: 'Open in Lens',
|
||||
})}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
iconType="save"
|
||||
onClick={() => {
|
||||
setIsSaveModalOpen(() => true);
|
||||
}}
|
||||
>
|
||||
{i18n.translate('xpack.observabilityAiAssistant.lensFunction.save', {
|
||||
defaultMessage: 'Save',
|
||||
})}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<lens.EmbeddableComponent
|
||||
{...lensEmbeddableInput}
|
||||
style={{
|
||||
height: 240,
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
{isSaveModalOpen ? (
|
||||
<lens.SaveModalComponent
|
||||
initialInput={lensEmbeddableInput}
|
||||
onClose={() => {
|
||||
setIsSaveModalOpen(() => false);
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue