mirror of
https://github.com/grafana/grafana.git
synced 2024-11-25 18:30:41 -06:00
Datasources: fixed long error message overflowing container (#29440)
* Fixed: error message overflow container Signed-off-by: Uchechukwu Obasi <obasiuche62@gmail.com> * used min-width property for better styling Signed-off-by: Uchechukwu Obasi <obasiuche62@gmail.com> * Switched to Alert component * Fixed passing aria-label to Alert component * Fixed e2e test (I hope) * another attempt to fix e2e * Fixed display name Co-authored-by: Uchechukwu Obasi <obate@Uchechukwus-MacBook-Pro.local> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
parent
d953a56eb6
commit
53cd59a5a5
@ -14,7 +14,6 @@ export const Pages = {
|
||||
delete: 'Data source settings page Delete button',
|
||||
saveAndTest: 'Data source settings page Save and Test button',
|
||||
alert: 'Data source settings page Alert',
|
||||
alertMessage: 'Data source settings page Alert message',
|
||||
},
|
||||
DataSources: {
|
||||
url: '/datasources',
|
||||
|
@ -85,8 +85,10 @@ export const addDataSource = (config?: Partial<AddDataSourceConfig>) => {
|
||||
form();
|
||||
|
||||
e2e.pages.DataSource.saveAndTest().click();
|
||||
e2e.pages.DataSource.alert().should('exist');
|
||||
e2e.pages.DataSource.alertMessage().contains(expectedAlertMessage); // assertion
|
||||
e2e.pages.DataSource.alert()
|
||||
.should('exist')
|
||||
.contains(expectedAlertMessage); // assertion
|
||||
|
||||
e2e().logToConsole('Added data source with name:', name);
|
||||
|
||||
return e2e()
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { FC, ReactNode } from 'react';
|
||||
import React, { FC, HTMLAttributes, ReactNode } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
@ -9,7 +9,7 @@ import { getColorsFromSeverity } from '../../utils/colors';
|
||||
|
||||
export type AlertVariant = 'success' | 'warning' | 'error' | 'info';
|
||||
|
||||
export interface Props {
|
||||
export interface Props extends HTMLAttributes<HTMLElement> {
|
||||
title: string;
|
||||
/** On click handler for alert button, mostly used for dismissing the alert */
|
||||
onRemove?: (event: React.MouseEvent) => void;
|
||||
@ -39,40 +39,36 @@ function getIconFromSeverity(severity: AlertVariant): string {
|
||||
}
|
||||
}
|
||||
|
||||
export const Alert: FC<Props> = ({
|
||||
title,
|
||||
buttonText,
|
||||
onButtonClick,
|
||||
onRemove,
|
||||
children,
|
||||
buttonContent,
|
||||
severity = 'error',
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const styles = getStyles(theme, severity, !!buttonContent);
|
||||
export const Alert: FC<Props> = React.forwardRef<HTMLElement, Props>(
|
||||
({ title, buttonText, onButtonClick, onRemove, children, buttonContent, severity = 'error', ...restProps }) => {
|
||||
const theme = useTheme();
|
||||
const styles = getStyles(theme, severity, !!buttonContent);
|
||||
|
||||
return (
|
||||
<div className={styles.alert} aria-label={selectors.components.Alert.alert(severity)}>
|
||||
<div className={styles.icon}>
|
||||
<Icon size="xl" name={getIconFromSeverity(severity) as IconName} />
|
||||
return (
|
||||
<div className={styles.alert} aria-label={selectors.components.Alert.alert(severity)} {...restProps}>
|
||||
<div className={styles.icon}>
|
||||
<Icon size="xl" name={getIconFromSeverity(severity) as IconName} />
|
||||
</div>
|
||||
<div className={styles.body}>
|
||||
<div className={styles.title}>{title}</div>
|
||||
{children && <div>{children}</div>}
|
||||
</div>
|
||||
{/* If onRemove is specified, giving preference to onRemove */}
|
||||
{onRemove ? (
|
||||
<button type="button" className={styles.close} onClick={onRemove}>
|
||||
{buttonContent || <Icon name="times" size="lg" />}
|
||||
</button>
|
||||
) : onButtonClick ? (
|
||||
<button type="button" className="btn btn-outline-danger" onClick={onButtonClick}>
|
||||
{buttonText}
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
<div className={styles.body}>
|
||||
<div className={styles.title}>{title}</div>
|
||||
{children && <div>{children}</div>}
|
||||
</div>
|
||||
{/* If onRemove is specified, giving preference to onRemove */}
|
||||
{onRemove ? (
|
||||
<button type="button" className={styles.close} onClick={onRemove}>
|
||||
{buttonContent || <Icon name="times" size="lg" />}
|
||||
</button>
|
||||
) : onButtonClick ? (
|
||||
<button type="button" className="btn btn-outline-danger" onClick={onButtonClick}>
|
||||
{buttonText}
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Alert.displayName = 'Alert';
|
||||
|
||||
const getStyles = (theme: GrafanaTheme, severity: AlertVariant, outline: boolean) => {
|
||||
const { white } = theme.palette;
|
||||
@ -107,6 +103,8 @@ const getStyles = (theme: GrafanaTheme, severity: AlertVariant, outline: boolean
|
||||
body: css`
|
||||
flex-grow: 1;
|
||||
margin: 0 ${theme.spacing.md} 0 0;
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-word;
|
||||
|
||||
a {
|
||||
color: ${white};
|
||||
|
@ -2,8 +2,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import isString from 'lodash/isString';
|
||||
import { Icon } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
// Components
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import { GenericDataSourcePlugin, PluginSettings } from './PluginSettings';
|
||||
@ -25,10 +23,12 @@ import { getRouteParamsId } from 'app/core/selectors/location';
|
||||
// Types
|
||||
import { CoreEvents, StoreState } from 'app/types/';
|
||||
import { DataSourcePluginMeta, DataSourceSettings, NavModel, UrlQueryMap } from '@grafana/data';
|
||||
import { Alert } from '@grafana/ui';
|
||||
import { getDataSourceLoadingNav } from '../state/navModel';
|
||||
import PluginStateinfo from 'app/features/plugins/PluginStateInfo';
|
||||
import { dataSourceLoaded, setDataSourceName, setIsDefault } from '../state/reducers';
|
||||
import { connectWithCleanUp } from 'app/core/components/connectWithCleanUp';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
export interface Props {
|
||||
navModel: NavModel;
|
||||
@ -172,7 +172,7 @@ export class DataSourceSettingsPage extends PureComponent<Props> {
|
||||
}
|
||||
|
||||
renderSettings() {
|
||||
const { dataSourceMeta, setDataSourceName, setIsDefault, dataSource, testingStatus, plugin } = this.props;
|
||||
const { dataSourceMeta, setDataSourceName, setIsDefault, dataSource, plugin, testingStatus } = this.props;
|
||||
|
||||
return (
|
||||
<form onSubmit={this.onSubmit}>
|
||||
@ -204,16 +204,11 @@ export class DataSourceSettingsPage extends PureComponent<Props> {
|
||||
|
||||
<div className="gf-form-group">
|
||||
{testingStatus && testingStatus.message && (
|
||||
<div className={`alert-${testingStatus.status} alert`} aria-label={selectors.pages.DataSource.alert}>
|
||||
<div className="alert-icon">
|
||||
{testingStatus.status === 'error' ? <Icon name="exclamation-triangle" /> : <Icon name="check" />}
|
||||
</div>
|
||||
<div className="alert-body">
|
||||
<div className="alert-title" aria-label={selectors.pages.DataSource.alertMessage}>
|
||||
{testingStatus.message}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Alert
|
||||
severity={testingStatus.status === 'error' ? 'error' : 'success'}
|
||||
title={testingStatus.message}
|
||||
aria-label={selectors.pages.DataSource.alert}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
@ -77,6 +77,8 @@
|
||||
}
|
||||
|
||||
.alert-body {
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-word;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user