mirror of https://github.com/grafana/grafana
UI: add InfoBox component (#23701)
* UI: inherit LinkButton props from ButtonHTMLAttributes * Chore: fix implicit any * UI: add InfoBox component * UI: fix InfoBox border color * Chore: use new style for defining stories * Chore: InfoBox refactor * Chore: inherit className attribute from HTMLDivElementpull/23695/head
parent
a9032f9188
commit
e8f4b46aae
@ -0,0 +1,59 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import { number } from '@storybook/addon-knobs'; |
||||||
|
import { InfoBox } from './InfoBox'; |
||||||
|
|
||||||
|
export default { |
||||||
|
title: 'General/InfoBox', |
||||||
|
component: InfoBox, |
||||||
|
decorators: [], |
||||||
|
parameters: { |
||||||
|
docs: {}, |
||||||
|
}, |
||||||
|
}; |
||||||
|
|
||||||
|
const getKnobs = () => { |
||||||
|
const CONTAINER_GROUP = 'Container options'; |
||||||
|
// ---
|
||||||
|
const containerWidth = number( |
||||||
|
'Container width', |
||||||
|
800, |
||||||
|
{ |
||||||
|
range: true, |
||||||
|
min: 100, |
||||||
|
max: 1500, |
||||||
|
step: 100, |
||||||
|
}, |
||||||
|
CONTAINER_GROUP |
||||||
|
); |
||||||
|
|
||||||
|
return { containerWidth }; |
||||||
|
}; |
||||||
|
|
||||||
|
export const basic = () => { |
||||||
|
const { containerWidth } = getKnobs(); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div style={{ width: containerWidth }}> |
||||||
|
<InfoBox |
||||||
|
header="User Permission" |
||||||
|
footer={ |
||||||
|
<> |
||||||
|
Checkout the{' '} |
||||||
|
<a className="external-link" target="_blank" href="http://docs.grafana.org/features/datasources/mysql/"> |
||||||
|
MySQL Data Source Docs |
||||||
|
</a>{' '} |
||||||
|
for more information., |
||||||
|
</> |
||||||
|
} |
||||||
|
> |
||||||
|
<p> |
||||||
|
The database user should only be granted SELECT permissions on the specified database & tables you want to |
||||||
|
query. Grafana does not validate that queries are safe so queries can contain any SQL statement. For example, |
||||||
|
statements like <code>USE otherdb;</code> and <code>DROP TABLE user;</code> would be executed. To protect |
||||||
|
against this we <strong>Highly</strong> recommmend you create a specific MySQL user with restricted |
||||||
|
permissions. |
||||||
|
</p> |
||||||
|
</InfoBox> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
@ -0,0 +1,77 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import { css, cx } from 'emotion'; |
||||||
|
import { GrafanaTheme } from '@grafana/data'; |
||||||
|
import { stylesFactory, useTheme } from '../../themes'; |
||||||
|
|
||||||
|
export interface Props extends React.HTMLAttributes<HTMLDivElement> { |
||||||
|
header?: string | JSX.Element; |
||||||
|
footer?: string | JSX.Element; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This is a simple InfoBox component, the api is not considered stable yet and will likely see breaking changes |
||||||
|
* in future minor releases. |
||||||
|
* @Alpha |
||||||
|
*/ |
||||||
|
export const InfoBox = React.memo( |
||||||
|
React.forwardRef<HTMLDivElement, Props>(({ header, footer, className, children, ...otherProps }, ref) => { |
||||||
|
const theme = useTheme(); |
||||||
|
const css = getInfoBoxStyles(theme); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className={cx([css.wrapper, className])} {...otherProps} ref={ref}> |
||||||
|
{header && ( |
||||||
|
<div className={css.header}> |
||||||
|
<h5>{header}</h5> |
||||||
|
</div> |
||||||
|
)} |
||||||
|
{children} |
||||||
|
{footer && <div className={css.footer}>{footer}</div>} |
||||||
|
</div> |
||||||
|
); |
||||||
|
}) |
||||||
|
); |
||||||
|
|
||||||
|
const getInfoBoxStyles = stylesFactory((theme: GrafanaTheme) => ({ |
||||||
|
wrapper: css` |
||||||
|
position: relative; |
||||||
|
padding: ${theme.spacing.lg}; |
||||||
|
background-color: ${theme.colors.bg2}; |
||||||
|
border-top: 3px solid ${theme.palette.blue80}; |
||||||
|
margin-bottom: ${theme.spacing.md}; |
||||||
|
margin-right: ${theme.spacing.xs}; |
||||||
|
box-shadow: ${theme.shadows.listItem}; |
||||||
|
flex-grow: 1; |
||||||
|
|
||||||
|
ul { |
||||||
|
padding-left: ${theme.spacing.lg}; |
||||||
|
} |
||||||
|
|
||||||
|
code { |
||||||
|
@include font-family-monospace(); |
||||||
|
font-size: ${theme.typography.size.sm}; |
||||||
|
background-color: ${theme.colors.bg1}; |
||||||
|
color: ${theme.colors.text}; |
||||||
|
border: 1px solid ${theme.colors.border2}; |
||||||
|
border-radius: 4px; |
||||||
|
} |
||||||
|
|
||||||
|
p:last-child { |
||||||
|
margin-bottom: 0; |
||||||
|
} |
||||||
|
|
||||||
|
a { |
||||||
|
@extend .external-link; |
||||||
|
} |
||||||
|
|
||||||
|
&--max-lg { |
||||||
|
max-width: ${theme.breakpoints.lg}; |
||||||
|
} |
||||||
|
`,
|
||||||
|
header: css` |
||||||
|
margin-bottom: ${theme.spacing.d}; |
||||||
|
`,
|
||||||
|
footer: css` |
||||||
|
margin-top: ${theme.spacing.d}; |
||||||
|
`,
|
||||||
|
})); |
||||||
Loading…
Reference in new issue