DashboardAI: UX improvements (#84934)

pull/85026/head
Adela Almasan 1 year ago committed by GitHub
parent 26473a0074
commit 5b0b8cb4bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      packages/grafana-data/src/types/icon.ts
  2. 21
      public/app/features/dashboard/components/GenAI/GenAIButton.tsx
  3. 46
      public/app/features/dashboard/components/GenAI/GenAIHistory.tsx
  4. 19
      public/app/features/dashboard/components/GenAI/GenerationHistoryCarousel.tsx
  5. 7
      public/app/features/dashboard/components/GenAI/QuickFeedback.tsx

@ -85,10 +85,12 @@ export const availableIconsIndex = {
'dice-three': true,
docker: true,
'document-info': true,
'document-layout-left': true,
'download-alt': true,
draggabledots: true,
edit: true,
'ellipsis-v': true,
enter: true,
envelope: true,
'exchange-alt': true,
'exclamation-triangle': true,
@ -176,6 +178,7 @@ export const availableIconsIndex = {
monitor: true,
palette: true,
'panel-add': true,
paragraph: true,
'pathfinder-unite': true,
pause: true,
pen: true,

@ -43,15 +43,7 @@ export const GenAIButton = ({
}: GenAIButtonProps) => {
const styles = useStyles2(getStyles);
const {
messages: streamMessages,
setMessages,
setStopGeneration,
reply,
value,
error,
streamStatus,
} = useOpenAIStream(model, temperature);
const { setMessages, setStopGeneration, reply, value, error, streamStatus } = useOpenAIStream(model, temperature);
const [history, setHistory] = useState<string[]>([]);
const [showHistory, setShowHistory] = useState(false);
@ -68,7 +60,7 @@ export const GenAIButton = ({
} else {
if (!hasHistory) {
onClickProp?.(e);
setMessages(typeof messages === 'function' ? messages() : messages);
setMessages(getMessages());
} else {
setShowHistory(true);
}
@ -158,6 +150,13 @@ export const GenAIButton = ({
</Button>
);
const getMessages = () => {
if (typeof messages === 'function') {
return messages();
}
return messages;
};
const renderButtonWithToggletip = () => {
if (hasHistory) {
const title = <Text element="p">{toggleTipTitle}</Text>;
@ -168,7 +167,7 @@ export const GenAIButton = ({
content={
<GenAIHistory
history={history}
messages={streamMessages}
messages={getMessages()}
onApplySuggestion={onApplySuggestion}
updateHistory={pushHistoryEntry}
eventTrackingSrc={eventTrackingSrc}

@ -2,7 +2,7 @@ import { css } from '@emotion/css';
import React, { useEffect, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, Button, Icon, IconButton, Input, Stack, Text, TextLink, useStyles2 } from '@grafana/ui';
import { Alert, Button, Icon, Input, Stack, Text, TextLink, useStyles2 } from '@grafana/ui';
import { STOP_GENERATION_TEXT } from './GenAIButton';
import { GenerationHistoryCarousel } from './GenerationHistoryCarousel';
@ -120,31 +120,37 @@ export const GenAIHistory = ({
</Alert>
)}
<GenerationHistoryCarousel
history={history}
index={currentIndex}
onNavigate={onNavigate}
reply={sanitizeReply(reply)}
streamStatus={streamStatus}
/>
<div className={styles.actionButtons}>
<QuickFeedback onSuggestionClick={onGenerateWithFeedback} isGenerating={isStreamGenerating} />
</div>
<Input
placeholder="Tell AI what to do next..."
suffix={
<IconButton
name="corner-down-right-alt"
<Button
icon="enter"
variant="secondary"
fill="text"
aria-label="Send custom feedback"
onClick={onClickSubmitCustomFeedback}
disabled={customFeedback === ''}
/>
>
Send
</Button>
}
value={customFeedback}
onChange={onChangeCustomFeedback}
onKeyDown={onKeyDownCustomFeedbackInput}
/>
<div className={styles.actions}>
<QuickFeedback onSuggestionClick={onGenerateWithFeedback} isGenerating={isStreamGenerating} />
<GenerationHistoryCarousel
history={history}
index={currentIndex}
onNavigate={onNavigate}
reply={sanitizeReply(reply)}
streamStatus={streamStatus}
/>
</div>
<div className={styles.applySuggestion}>
<Stack justifyContent={'flex-end'} direction={'row'}>
<Button icon={!isStreamGenerating ? 'check' : 'fa fa-spinner'} onClick={onApply}>
@ -152,12 +158,14 @@ export const GenAIHistory = ({
</Button>
</Stack>
</div>
<div className={styles.footer}>
<Icon name="exclamation-circle" aria-label="exclamation-circle" className={styles.infoColor} />
<Text variant="bodySmall" color="secondary">
This content is AI-generated using the{' '}
<TextLink
variant="bodySmall"
inline={true}
href="https://grafana.com/docs/grafana-cloud/alerting-and-irm/machine-learning/llm-plugin/"
external
onClick={onClickDocs}
@ -177,10 +185,10 @@ const getStyles = (theme: GrafanaTheme2) => ({
width: 520,
maxHeight: 350,
// This is the space the footer height
paddingBottom: 35,
paddingBottom: 25,
}),
applySuggestion: css({
marginTop: theme.spacing(1),
paddingTop: theme.spacing(2),
}),
actions: css({
display: 'flex',
@ -206,4 +214,10 @@ const getStyles = (theme: GrafanaTheme2) => ({
infoColor: css({
color: theme.colors.info.main,
}),
actionButtons: css({
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
padding: '24px 0 8px 0',
}),
});

@ -35,18 +35,18 @@ export const GenerationHistoryCarousel = ({
return (
<>
<div className={styles.contentWrapper}>
<Text element="p" color="secondary">
{getHistoryText()}
</Text>
</div>
<MinimalisticPagination
currentPage={index}
numberOfPages={historySize}
onNavigate={onNavigate}
hideWhenSinglePage={true}
hideWhenSinglePage={false}
className={styles.paginationWrapper}
/>
<div className={styles.contentWrapper}>
<Text element="p" color="secondary">
{getHistoryText()}
</Text>
</div>
</>
);
};
@ -63,8 +63,11 @@ const getStyles = (theme: GrafanaTheme2) => ({
flexBasis: '100%',
flexGrow: 3,
whiteSpace: 'pre-wrap',
marginTop: 20,
height: 110,
maxHeight: 110,
overflowY: 'scroll',
backgroundColor: theme.colors.background.secondary,
border: `1px solid ${theme.colors.border.weak}`,
padding: theme.spacing(1),
minHeight: 60,
}),
});

@ -20,6 +20,7 @@ export const QuickFeedback = ({ onSuggestionClick, isGenerating }: QuickActionsP
onClick={() => onSuggestionClick(QuickFeedbackType.Shorter)}
size="sm"
variant="secondary"
icon="paragraph"
disabled={isGenerating}
>
{QuickFeedbackType.Shorter}
@ -28,12 +29,14 @@ export const QuickFeedback = ({ onSuggestionClick, isGenerating }: QuickActionsP
onClick={() => onSuggestionClick(QuickFeedbackType.MoreDescriptive)}
size="sm"
variant="secondary"
icon="document-layout-left"
disabled={isGenerating}
>
{QuickFeedbackType.MoreDescriptive}
</Button>
<Button
onClick={() => onSuggestionClick(QuickFeedbackType.Regenerate)}
icon="sync"
size="sm"
variant="secondary"
disabled={isGenerating}
@ -48,10 +51,6 @@ const getStyles = (theme: GrafanaTheme2) => ({
quickSuggestionsWrapper: css({
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
flexWrap: 'wrap',
flexGrow: 1,
gap: 8,
paddingTop: 10,
}),
});

Loading…
Cancel
Save