Add custom alert component (#81012)

Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>
Co-authored-by: Matias Chomicki <matyax@gmail.com>
This commit is contained in:
Fabrizio 2024-01-26 10:32:20 +01:00 committed by GitHub
parent 19194ea122
commit 8761dfcc97
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 126 additions and 69 deletions

View File

@ -0,0 +1,51 @@
import { css } from '@emotion/css';
import React, { useEffect, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, AlertVariant, useTheme2 } from '@grafana/ui';
enum AlertTimeout {
Error = 7000,
Info = 3000,
Success = 3000,
Warning = 5000,
}
const getStyle = (theme: GrafanaTheme2) => {
return css({
position: 'absolute',
zIndex: theme.zIndex.portal,
top: 0,
right: 10,
});
};
const timeoutMap = {
['error']: AlertTimeout.Error,
['info']: AlertTimeout.Info,
['success']: AlertTimeout.Success,
['warning']: AlertTimeout.Warning,
};
export const TemporaryAlert = (props: { severity: AlertVariant; text: string }) => {
const style = getStyle(useTheme2());
const [visible, setVisible] = useState(false);
useEffect(() => {
const timer = setTimeout(() => {
setVisible(false);
}, timeoutMap[props.severity]);
return () => {
clearTimeout(timer);
};
}, [props.severity, visible]);
useEffect(() => {
if (props.text !== '') {
setVisible(true);
}
}, [props.text]);
return <Alert className={style} elevated={true} title={props.text} severity={props.severity} />;
};

View File

@ -7,6 +7,7 @@
export * from './IntervalInput/IntervalInput';
export * from './NodeGraph/NodeGraphSettings';
export * from './SpanBar/SpanBarSettings';
export * from './TemporaryAlert';
export * from './TraceToLogs/TagMappingInput';
export * from './TraceToLogs/TraceToLogsSettings';
export * from './TraceToMetrics/TraceToMetricsSettings';

View File

@ -1,13 +1,11 @@
import { css } from '@emotion/css';
import React, { useEffect, useRef } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { TemporaryAlert } from '@grafana/o11y-ds-frontend';
import { reportInteraction } from '@grafana/runtime';
import { CodeEditor, Monaco, monacoTypes, useTheme2 } from '@grafana/ui';
import { notifyApp } from '../_importedDependencies/actions/appNotification';
import { createErrorNotification } from '../_importedDependencies/core/appNotification';
import { dispatch } from '../_importedDependencies/store';
import { TempoDatasource } from '../datasource';
import { CompletionProvider, CompletionType } from './autocomplete';
@ -24,8 +22,10 @@ interface Props {
}
export function TraceQLEditor(props: Props) {
const [alertText, setAlertText] = useState('error error');
const { onChange, onRunQuery, placeholder } = props;
const setupAutocompleteFn = useAutocomplete(props.datasource);
const setupAutocompleteFn = useAutocomplete(props.datasource, setAlertText);
const theme = useTheme2();
const styles = getStyles(theme, placeholder);
// work around the problem that `onEditorDidMount` is called once
@ -36,6 +36,7 @@ export function TraceQLEditor(props: Props) {
const errorTimeoutId = useRef<number>();
return (
<>
<CodeEditor
value={props.value}
language={langId}
@ -103,6 +104,8 @@ export function TraceQLEditor(props: Props) {
});
}}
/>
{alertText && <TemporaryAlert severity={'error'} text={alertText} />}
</>
);
}
@ -175,9 +178,10 @@ function setupAutoSize(editor: monacoTypes.editor.IStandaloneCodeEditor) {
/**
* Hook that returns function that will set up monaco autocomplete for the label selector
* @param datasource
* @param datasource the Tempo datasource instance
* @param setAlertText setter for alert's text
*/
function useAutocomplete(datasource: TempoDatasource) {
function useAutocomplete(datasource: TempoDatasource, setAlertText: (text: string) => void) {
// We need the provider ref so we can pass it the label/values data later. This is because we run the call for the
// values here but there is additional setup needed for the provider later on. We could run the getSeries() in the
// returned function but that is run after the monaco is mounted so would delay the request a bit when it does not
@ -192,12 +196,13 @@ function useAutocomplete(datasource: TempoDatasource) {
await datasource.languageProvider.start();
} catch (error) {
if (error instanceof Error) {
dispatch(notifyApp(createErrorNotification('Error', error)));
console.error(error);
setAlertText(error.message);
}
}
};
fetchTags();
}, [datasource]);
}, [datasource, setAlertText]);
const autocompleteDisposeFun = useRef<(() => void) | null>(null);
useEffect(() => {