Dashgpt: Make generate title and description work in scened dashboard settings (#84649)

* wip

* add GenAI to scenes dashboard settings

* rework title and description into controlled inputs

---------

Co-authored-by: Sergej-Vlasov <sergej.s.vlasov@gmail.com>
This commit is contained in:
Ivan Ortega Alba 2024-03-19 15:06:03 +01:00 committed by GitHub
parent 9dc4221508
commit 74e62ac6fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 45 additions and 54 deletions

View File

@ -1,16 +1,17 @@
import React, { ChangeEvent } from 'react';
import { PageLayoutType } from '@grafana/data';
import { config } from '@grafana/runtime';
import { SceneComponentProps, SceneObjectBase, sceneGraph } from '@grafana/scenes';
import { TimeZone } from '@grafana/schema';
import {
Box,
CollapsableSection,
Field,
HorizontalGroup,
Input,
Label,
RadioButtonGroup,
Stack,
TagsInput,
TextArea,
} from '@grafana/ui';
@ -19,6 +20,8 @@ import { FolderPicker } from 'app/core/components/Select/FolderPicker';
import { t, Trans } from 'app/core/internationalization';
import { TimePickerSettings } from 'app/features/dashboard/components/DashboardSettings/TimePickerSettings';
import { DeleteDashboardButton } from 'app/features/dashboard/components/DeleteDashboard/DeleteDashboardButton';
import { GenAIDashDescriptionButton } from 'app/features/dashboard/components/GenAI/GenAIDashDescriptionButton';
import { GenAIDashTitleButton } from 'app/features/dashboard/components/GenAI/GenAIDashTitleButton';
import { DashboardScene } from '../scene/DashboardScene';
import { NavToolbarActions } from '../scene/NavToolbarActions';
@ -155,42 +158,40 @@ export class GeneralSettingsEditView
<Box marginBottom={5}>
<Field
label={
<HorizontalGroup justify="space-between">
<Stack justifyContent="space-between">
<Label htmlFor="title-input">
<Trans i18nKey="dashboard-settings.general.title-label">Title</Trans>
</Label>
{/* TODO: Make the component use persisted model */}
{/* {config.featureToggles.dashgpt && (
<GenAIDashTitleButton onGenerate={onTitleChange} dashboard={dashboard} />
)} */}
</HorizontalGroup>
{config.featureToggles.dashgpt && (
<GenAIDashTitleButton onGenerate={(title) => model.onTitleChange(title)} />
)}
</Stack>
}
>
<Input
id="title-input"
name="title"
defaultValue={title}
onBlur={(e: ChangeEvent<HTMLInputElement>) => model.onTitleChange(e.target.value)}
value={title}
onChange={(e: ChangeEvent<HTMLInputElement>) => model.onTitleChange(e.target.value)}
/>
</Field>
<Field
label={
<HorizontalGroup justify="space-between">
<Stack justifyContent="space-between">
<Label htmlFor="description-input">
{t('dashboard-settings.general.description-label', 'Description')}
</Label>
{/* {config.featureToggles.dashgpt && (
<GenAIDashDescriptionButton onGenerate={onDescriptionChange} dashboard={dashboard} />
)} */}
</HorizontalGroup>
{config.featureToggles.dashgpt && (
<GenAIDashDescriptionButton onGenerate={(description) => model.onDescriptionChange(description)} />
)}
</Stack>
}
>
<TextArea
id="description-input"
name="description"
defaultValue={description}
onBlur={(e: ChangeEvent<HTMLTextAreaElement>) => model.onDescriptionChange(e.target.value)}
value={description}
onChange={(e: ChangeEvent<HTMLTextAreaElement>) => model.onDescriptionChange(e.target.value)}
/>
</Field>
<Field label={t('dashboard-settings.general.tags-label', 'Tags')}>

View File

@ -10,9 +10,9 @@ import {
RadioButtonGroup,
TagsInput,
Label,
HorizontalGroup,
TextArea,
Box,
Stack,
} from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
@ -124,15 +124,13 @@ export function GeneralSettingsUnconnected({
<Box marginBottom={5}>
<Field
label={
<HorizontalGroup justify="space-between">
<Stack justifyContent="space-between">
<Label htmlFor="title-input">
<Trans i18nKey="dashboard-settings.general.title-label">Title</Trans>
</Label>
{config.featureToggles.dashgpt && (
<GenAIDashTitleButton onGenerate={onTitleChange} dashboard={dashboard} />
)}
</HorizontalGroup>
{config.featureToggles.dashgpt && <GenAIDashTitleButton onGenerate={onTitleChange} />}
</Stack>
}
>
<Input
@ -144,15 +142,13 @@ export function GeneralSettingsUnconnected({
</Field>
<Field
label={
<HorizontalGroup justify="space-between">
<Stack justifyContent="space-between">
<Label htmlFor="description-input">
{t('dashboard-settings.general.description-label', 'Description')}
</Label>
{config.featureToggles.dashgpt && (
<GenAIDashDescriptionButton onGenerate={onDescriptionChange} dashboard={dashboard} />
)}
</HorizontalGroup>
{config.featureToggles.dashgpt && <GenAIDashDescriptionButton onGenerate={onDescriptionChange} />}
</Stack>
}
>
<TextArea

View File

@ -1,6 +1,6 @@
import React from 'react';
import { DashboardModel } from '../../state';
import { getDashboardSrv } from '../../services/DashboardSrv';
import { GenAIButton } from './GenAIButton';
import { EventTrackingSrc } from './tracking';
@ -8,7 +8,6 @@ import { getDashboardPanelPrompt, Message, Role } from './utils';
interface GenAIDashDescriptionButtonProps {
onGenerate: (description: string) => void;
dashboard: DashboardModel;
}
const DASHBOARD_DESCRIPTION_CHAR_LIMIT = 300;
@ -24,12 +23,10 @@ const DESCRIPTION_GENERATION_STANDARD_PROMPT =
`The description should be, at most, ${DASHBOARD_DESCRIPTION_CHAR_LIMIT} characters.\n` +
'Respond with only the description of the dashboard.';
export const GenAIDashDescriptionButton = ({ onGenerate, dashboard }: GenAIDashDescriptionButtonProps) => {
const messages = React.useMemo(() => getMessages(dashboard), [dashboard]);
export const GenAIDashDescriptionButton = ({ onGenerate }: GenAIDashDescriptionButtonProps) => {
return (
<GenAIButton
messages={messages}
messages={getMessages}
onGenerate={onGenerate}
eventTrackingSrc={EventTrackingSrc.dashboardDescription}
toggleTipTitle={'Improve your dashboard description'}
@ -37,7 +34,8 @@ export const GenAIDashDescriptionButton = ({ onGenerate, dashboard }: GenAIDashD
);
};
function getMessages(dashboard: DashboardModel): Message[] {
function getMessages(): Message[] {
const dashboard = getDashboardSrv().getCurrent()!;
const panelPrompt = getDashboardPanelPrompt(dashboard);
return [

View File

@ -1,13 +1,12 @@
import React from 'react';
import { DashboardModel } from '../../state';
import { getDashboardSrv } from '../../services/DashboardSrv';
import { GenAIButton } from './GenAIButton';
import { EventTrackingSrc } from './tracking';
import { getDashboardPanelPrompt, Message, Role } from './utils';
interface GenAIDashTitleButtonProps {
dashboard: DashboardModel;
onGenerate: (description: string) => void;
}
@ -24,12 +23,10 @@ const TITLE_GENERATION_STANDARD_PROMPT =
`The title should be, at most, ${DASH_TITLE_CHAR_LIMIT} characters.\n` +
'Respond with only the title of the dashboard.';
export const GenAIDashTitleButton = ({ onGenerate, dashboard }: GenAIDashTitleButtonProps) => {
const messages = React.useMemo(() => getMessages(dashboard), [dashboard]);
export const GenAIDashTitleButton = ({ onGenerate }: GenAIDashTitleButtonProps) => {
return (
<GenAIButton
messages={messages}
messages={getMessages}
onGenerate={onGenerate}
eventTrackingSrc={EventTrackingSrc.dashboardTitle}
toggleTipTitle={'Improve your dashboard title'}
@ -37,7 +34,9 @@ export const GenAIDashTitleButton = ({ onGenerate, dashboard }: GenAIDashTitleBu
);
};
function getMessages(dashboard: DashboardModel): Message[] {
function getMessages(): Message[] {
const dashboard = getDashboardSrv().getCurrent()!;
return [
{
content: TITLE_GENERATION_STANDARD_PROMPT,

View File

@ -1,7 +1,7 @@
import React, { ChangeEvent } from 'react';
import { config } from '@grafana/runtime';
import { Button, Input, Switch, Form, Field, InputControl, HorizontalGroup, Label, TextArea } from '@grafana/ui';
import { Button, Input, Switch, Form, Field, InputControl, Label, TextArea, Stack } from '@grafana/ui';
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
import { DashboardModel } from 'app/features/dashboard/state';
import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv';
@ -110,12 +110,12 @@ export const SaveDashboardAsForm = ({
render={({ field: { ref, ...field } }) => (
<Field
label={
<HorizontalGroup justify="space-between">
<Stack justifyContent="space-between">
<Label htmlFor="title">Title</Label>
{config.featureToggles.dashgpt && isNew && (
<GenAIDashTitleButton onGenerate={(title) => field.onChange(title)} dashboard={dashboard} />
<GenAIDashTitleButton onGenerate={(title) => field.onChange(title)} />
)}
</HorizontalGroup>
</Stack>
}
invalid={!!errors.title}
error={errors.title?.message}
@ -138,15 +138,12 @@ export const SaveDashboardAsForm = ({
render={({ field: { ref, ...field } }) => (
<Field
label={
<HorizontalGroup justify="space-between">
<Stack justifyContent="space-between">
<Label htmlFor="description">Description</Label>
{config.featureToggles.dashgpt && isNew && (
<GenAIDashDescriptionButton
onGenerate={(description) => field.onChange(description)}
dashboard={dashboard}
/>
<GenAIDashDescriptionButton onGenerate={(description) => field.onChange(description)} />
)}
</HorizontalGroup>
</Stack>
}
invalid={!!errors.description}
error={errors.description?.message}
@ -184,14 +181,14 @@ export const SaveDashboardAsForm = ({
<Switch {...register('copyTags')} />
</Field>
)}
<HorizontalGroup>
<Stack>
<Button type="button" variant="secondary" onClick={onCancel} fill="outline">
Cancel
</Button>
<Button disabled={isLoading} type="submit" aria-label="Save dashboard button">
{isLoading ? 'Saving...' : 'Save'}
</Button>
</HorizontalGroup>
</Stack>
</>
)}
</Form>