From c88d5d7b40f8e787c80ecff21f9e7b64985e1f4c Mon Sep 17 00:00:00 2001 From: Ivan Ortega Alba Date: Tue, 3 Oct 2023 23:36:45 +0200 Subject: [PATCH] Auto-generate: Hide the button when LLM plugin is not enabled (#75878) * Auto-generate: Hide the button when LLM plugin is not enabled * Performance: Reduce time to receive the first character of OpenAI --- .../components/GenAI/GenAIButton.test.tsx | 46 ++++++------------- .../components/GenAI/GenAIButton.tsx | 35 +++++--------- .../dashboard/components/GenAI/hooks.ts | 19 ++++---- .../dashboard/components/GenAI/llms/openai.ts | 16 ++----- .../dashboard/components/GenAI/llms/types.ts | 7 +++ 5 files changed, 46 insertions(+), 77 deletions(-) diff --git a/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx b/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx index 1d1c459a877..1682d561470 100644 --- a/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx +++ b/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx @@ -9,11 +9,7 @@ import { locationService } from '@grafana/runtime'; import { GenAIButton, GenAIButtonProps } from './GenAIButton'; import { useOpenAIStream } from './hooks'; -import { Role, isLLMPluginEnabled } from './utils'; - -jest.mock('./utils', () => ({ - isLLMPluginEnabled: jest.fn(), -})); +import { Role } from './utils'; const mockedUseOpenAiStreamState = { setMessages: jest.fn(), @@ -40,40 +36,28 @@ describe('GenAIButton', () => { describe('when LLM plugin is not configured', () => { beforeAll(() => { - jest.mocked(isLLMPluginEnabled).mockResolvedValue(false); + jest.mocked(useOpenAIStream).mockReturnValue({ + error: undefined, + isGenerating: false, + reply: 'Some completed genereated text', + setMessages: jest.fn(), + value: { + enabled: false, + stream: new Observable().subscribe(), + }, + }); }); - it('should render text ', async () => { - const { getByText } = setup(); - waitFor(() => expect(getByText('Auto-generate')).toBeInTheDocument()); - }); + it('should not render anything', async () => { + setup(); - it('should disable the button', async () => { - const { getByRole } = setup(); - waitFor(() => expect(getByRole('button')).toBeDisabled()); - }); - - it('should display an error message when hovering', async () => { - const { getByRole, getByTestId } = setup(); - - // Wait for the check to be completed - const button = getByRole('button'); - await waitFor(() => expect(button).toBeDisabled()); - await userEvent.hover(button); - - const tooltip = await waitFor(() => getByTestId(selectors.components.Tooltip.container)); - expect(tooltip).toBeVisible(); - - // The tooltip keeps interactive to be able to click the link - await userEvent.hover(tooltip); - expect(tooltip).toBeVisible(); + waitFor(async () => expect(await screen.findByText('Auto-generate')).not.toBeInTheDocument()); }); }); describe('when LLM plugin is properly configured, so it is enabled', () => { const setMessagesMock = jest.fn(); beforeEach(() => { - jest.mocked(isLLMPluginEnabled).mockResolvedValue(true); jest.mocked(useOpenAIStream).mockReturnValue({ error: undefined, isGenerating: false, @@ -125,7 +109,6 @@ describe('GenAIButton', () => { describe('when it is generating data', () => { beforeEach(() => { - jest.mocked(isLLMPluginEnabled).mockResolvedValue(true); jest.mocked(useOpenAIStream).mockReturnValue({ error: undefined, isGenerating: true, @@ -171,7 +154,6 @@ describe('GenAIButton', () => { describe('when there is an error generating data', () => { const setMessagesMock = jest.fn(); beforeEach(() => { - jest.mocked(isLLMPluginEnabled).mockResolvedValue(true); jest.mocked(useOpenAIStream).mockReturnValue({ error: new Error('Something went wrong'), isGenerating: false, diff --git a/public/app/features/dashboard/components/GenAI/GenAIButton.tsx b/public/app/features/dashboard/components/GenAI/GenAIButton.tsx index dd44e6d20a0..3e5b0e36ef2 100644 --- a/public/app/features/dashboard/components/GenAI/GenAIButton.tsx +++ b/public/app/features/dashboard/components/GenAI/GenAIButton.tsx @@ -2,7 +2,7 @@ import { css } from '@emotion/css'; import React, { useEffect } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; -import { Button, Spinner, useStyles2, Link, Tooltip } from '@grafana/ui'; +import { Button, Spinner, useStyles2, Tooltip } from '@grafana/ui'; import { useOpenAIStream } from './hooks'; import { OPEN_AI_MODEL, Message } from './utils'; @@ -33,14 +33,8 @@ export const GenAIButton = ({ }: GenAIButtonProps) => { const styles = useStyles2(getStyles); - // TODO: Implement error handling (use error object from hook) const { setMessages, reply, isGenerating, value, error } = useOpenAIStream(OPEN_AI_MODEL, temperature); - const onClick = (e: React.MouseEvent) => { - onClickProp?.(e); - setMessages(messages); - }; - useEffect(() => { // Todo: Consider other options for `"` sanitation if (isGenerating && reply) { @@ -48,6 +42,16 @@ export const GenAIButton = ({ } }, [isGenerating, reply, onGenerate]); + // The button is disabled if the plugin is not installed or enabled + if (!value?.enabled) { + return null; + } + + const onClick = (e: React.MouseEvent) => { + onClickProp?.(e); + setMessages(messages); + }; + const getIcon = () => { if (error || !value?.enabled) { return 'exclamation-circle'; @@ -58,21 +62,6 @@ export const GenAIButton = ({ return 'ai'; }; - const getTooltipContent = () => { - if (error) { - return `Unexpected error: ${error.message}`; - } - if (!value?.enabled) { - return ( - - The LLM plugin is not correctly configured. See your settings{' '} - and enable your plugin. - - ); - } - return ''; - }; - const getText = () => { if (error) { return 'Retry'; @@ -84,7 +73,7 @@ export const GenAIButton = ({ return (
{isGenerating && } - +