mirror of
https://github.com/grafana/grafana.git
synced 2024-11-22 08:56:43 -06:00
Dashboards: Auto-generate dashboard title and description from settings (#75240)
Co-authored-by: nmarrs <nathanielmarrs@gmail.com>
This commit is contained in:
parent
b5da762477
commit
d531f5ab42
@ -1,13 +1,25 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { ChangeEvent, useState } from 'react';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
|
||||
import { TimeZone } from '@grafana/data';
|
||||
import { CollapsableSection, Field, Input, RadioButtonGroup, TagsInput } from '@grafana/ui';
|
||||
import { config } from '@grafana/runtime';
|
||||
import {
|
||||
CollapsableSection,
|
||||
Field,
|
||||
Input,
|
||||
RadioButtonGroup,
|
||||
TagsInput,
|
||||
Label,
|
||||
HorizontalGroup,
|
||||
TextArea,
|
||||
} from '@grafana/ui';
|
||||
import { Page } from 'app/core/components/Page/Page';
|
||||
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
|
||||
import { updateTimeZoneDashboard, updateWeekStartDashboard } from 'app/features/dashboard/state/actions';
|
||||
|
||||
import { DeleteDashboardButton } from '../DeleteDashboard/DeleteDashboardButton';
|
||||
import { GenAIDashDescriptionButton } from '../GenAI/GenAIDashDescriptionButton';
|
||||
import { GenAIDashTitleButton } from '../GenAI/GenAIDashTitleButton';
|
||||
|
||||
import { TimePickerSettings } from './TimePickerSettings';
|
||||
import { SettingsPageProps } from './types';
|
||||
@ -27,6 +39,8 @@ export function GeneralSettingsUnconnected({
|
||||
sectionNav,
|
||||
}: Props): JSX.Element {
|
||||
const [renderCounter, setRenderCounter] = useState(0);
|
||||
const [dashboardTitle, setDashboardTitle] = useState(dashboard.title);
|
||||
const [dashboardDescription, setDashboardDescription] = useState(dashboard.description);
|
||||
|
||||
const onFolderChange = (newUID: string, newTitle: string) => {
|
||||
dashboard.meta.folderUid = newUID;
|
||||
@ -35,11 +49,21 @@ export function GeneralSettingsUnconnected({
|
||||
setRenderCounter(renderCounter + 1);
|
||||
};
|
||||
|
||||
const onBlur = (event: React.FocusEvent<HTMLInputElement>) => {
|
||||
if (event.currentTarget.name === 'title' || event.currentTarget.name === 'description') {
|
||||
dashboard[event.currentTarget.name] = event.currentTarget.value;
|
||||
}
|
||||
};
|
||||
const onTitleChange = React.useCallback(
|
||||
(title: string) => {
|
||||
dashboard.title = title;
|
||||
setDashboardTitle(title);
|
||||
},
|
||||
[setDashboardTitle, dashboard]
|
||||
);
|
||||
|
||||
const onDescriptionChange = React.useCallback(
|
||||
(description: string) => {
|
||||
dashboard.description = description;
|
||||
setDashboardDescription(description);
|
||||
},
|
||||
[setDashboardDescription, dashboard]
|
||||
);
|
||||
|
||||
const onTooltipChange = (graphTooltip: number) => {
|
||||
dashboard.graphTooltip = graphTooltip;
|
||||
@ -95,11 +119,39 @@ export function GeneralSettingsUnconnected({
|
||||
<Page navModel={sectionNav}>
|
||||
<div style={{ maxWidth: '600px' }}>
|
||||
<div className="gf-form-group">
|
||||
<Field label="Name">
|
||||
<Input id="title-input" name="title" onBlur={onBlur} defaultValue={dashboard.title} />
|
||||
<Field
|
||||
label={
|
||||
<HorizontalGroup justify="space-between">
|
||||
<Label htmlFor="title-input">Title</Label>
|
||||
{config.featureToggles.dashgpt && (
|
||||
<GenAIDashTitleButton onGenerate={onTitleChange} dashboard={dashboard} />
|
||||
)}
|
||||
</HorizontalGroup>
|
||||
}
|
||||
>
|
||||
<Input
|
||||
id="title-input"
|
||||
name="title"
|
||||
value={dashboardTitle}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => onTitleChange(e.target.value)}
|
||||
/>
|
||||
</Field>
|
||||
<Field label="Description">
|
||||
<Input id="description-input" name="description" onBlur={onBlur} defaultValue={dashboard.description} />
|
||||
<Field
|
||||
label={
|
||||
<HorizontalGroup justify="space-between">
|
||||
<Label htmlFor="description-input">Description</Label>
|
||||
{config.featureToggles.dashgpt && (
|
||||
<GenAIDashDescriptionButton onGenerate={onDescriptionChange} dashboard={dashboard} />
|
||||
)}
|
||||
</HorizontalGroup>
|
||||
}
|
||||
>
|
||||
<TextArea
|
||||
id="description-input"
|
||||
name="description"
|
||||
value={dashboardDescription}
|
||||
onChange={(e: ChangeEvent<HTMLTextAreaElement>) => onDescriptionChange(e.target.value)}
|
||||
/>
|
||||
</Field>
|
||||
<Field label="Tags">
|
||||
<TagsInput id="tags-input" tags={dashboard.tags} onChange={onTagsChange} width={40} />
|
||||
|
@ -0,0 +1,45 @@
|
||||
import React from 'react';
|
||||
|
||||
import { DashboardModel } from '../../state';
|
||||
|
||||
import { GenAIButton } from './GenAIButton';
|
||||
import { Message, Role } from './utils';
|
||||
|
||||
interface GenAIDashDescriptionButtonProps {
|
||||
onGenerate: (description: string, isDone: boolean) => void;
|
||||
dashboard: DashboardModel;
|
||||
}
|
||||
|
||||
const DESCRIPTION_GENERATION_STANDARD_PROMPT =
|
||||
'You are an expert in Grafana dashboards.' +
|
||||
'Your goal is to write short, descriptive, and concise dashboards description using the dashboard panels title and descriptions. ' +
|
||||
'The description should be shorter than 140 characters.';
|
||||
|
||||
export const GenAIDashDescriptionButton = ({ onGenerate, dashboard }: GenAIDashDescriptionButtonProps) => {
|
||||
const messages = React.useMemo(() => getMessages(dashboard), [dashboard]);
|
||||
|
||||
return <GenAIButton messages={messages} onReply={onGenerate} loadingText={'Generating description'} />;
|
||||
};
|
||||
|
||||
function getMessages(dashboard: DashboardModel): Message[] {
|
||||
return [
|
||||
{
|
||||
content: DESCRIPTION_GENERATION_STANDARD_PROMPT,
|
||||
role: Role.system,
|
||||
},
|
||||
{
|
||||
content: `The title of the dashboard is "${
|
||||
dashboard.title
|
||||
}" and the the panels in the dashboard are: ${dashboard.panels
|
||||
.map(
|
||||
(panel, idx) => `
|
||||
- Panel ${idx}
|
||||
- Title: ${panel.title}
|
||||
${panel.description ? `- Description: ${panel.description}` : ''}
|
||||
`
|
||||
)
|
||||
.join('\n')}`,
|
||||
role: Role.system,
|
||||
},
|
||||
];
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
|
||||
import { DashboardModel } from '../../state';
|
||||
|
||||
import { GenAIButton } from './GenAIButton';
|
||||
import { Message, Role } from './utils';
|
||||
|
||||
interface GenAIDashTitleButtonProps {
|
||||
dashboard: DashboardModel;
|
||||
onGenerate: (description: string, isDone: boolean) => void;
|
||||
}
|
||||
|
||||
const DESCRIPTION_GENERATION_STANDARD_PROMPT =
|
||||
'You are an expert in Grafana dashboards.' +
|
||||
'Your goal is to write the dashboard title inspired by the title and descriptions for the dashboard panels. ' +
|
||||
'The title must be shorter than 50 characters.';
|
||||
|
||||
export const GenAIDashTitleButton = ({ onGenerate, dashboard }: GenAIDashTitleButtonProps) => {
|
||||
const messages = React.useMemo(() => getMessages(dashboard), [dashboard]);
|
||||
|
||||
return <GenAIButton messages={messages} onReply={onGenerate} loadingText={'Generating title'} />;
|
||||
};
|
||||
|
||||
function getMessages(dashboard: DashboardModel): Message[] {
|
||||
return [
|
||||
{
|
||||
content: DESCRIPTION_GENERATION_STANDARD_PROMPT,
|
||||
role: Role.system,
|
||||
},
|
||||
{
|
||||
content: `The panels in the dashboard are: ${dashboard.panels
|
||||
.map(
|
||||
(panel, idx) => `
|
||||
- Panel ${idx}
|
||||
- Title: ${panel.title}
|
||||
${panel.description ? `- Description: ${panel.description}` : ''}
|
||||
`
|
||||
)
|
||||
.join('\n')}`,
|
||||
role: Role.system,
|
||||
},
|
||||
];
|
||||
}
|
Loading…
Reference in New Issue
Block a user