mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
GLDS: Text component (#71439)
This commit is contained in:
parent
1c3606cebe
commit
47f70bdb00
packages/grafana-ui/src
public/app
core/components
AppChrome/News
NestedFolderPicker
Page
features
alerting/unified/components
browse-dashboards/components
dashboard/dashgrid
search/page/components
plugins/datasource/alertmanager
@ -125,7 +125,7 @@ export function Drawer({
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.titleWrapper}>
|
||||
<Text as="h3" {...titleProps}>
|
||||
<Text element="h3" {...titleProps}>
|
||||
{title}
|
||||
</Text>
|
||||
{subtitle && <div className={styles.subtitle}>{subtitle}</div>}
|
||||
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||
|
||||
import { StoryExample } from '../../utils/storybook/StoryExample';
|
||||
import { VerticalGroup } from '../Layout/Layout';
|
||||
import { P } from '../Text/TextElements';
|
||||
import { Text } from '../Text/Text';
|
||||
|
||||
import { TextLink } from './TextLink';
|
||||
import mdx from './TextLink.mdx';
|
||||
@ -44,13 +44,13 @@ export const Example: StoryFn = (args) => {
|
||||
return (
|
||||
<VerticalGroup>
|
||||
<StoryExample name="This is a 'inline + external' link with the default behaviour">
|
||||
<P>
|
||||
<Text element="p">
|
||||
To get started with a forever free Grafana Cloud account, sign up at  
|
||||
<TextLink href="https://grafana.com/" {...args} inline>
|
||||
grafana.com
|
||||
</TextLink>
|
||||
.
|
||||
</P>
|
||||
</Text>
|
||||
</StoryExample>
|
||||
<StoryExample name="This is a 'standalone + external' link with the default behaviour">
|
||||
<TextLink href="https://grafana.com/docs/grafana/latest/" {...args}>
|
||||
@ -58,7 +58,9 @@ export const Example: StoryFn = (args) => {
|
||||
</TextLink>
|
||||
</StoryExample>
|
||||
<hr />
|
||||
<P>*The examples cannot contemplate an internal link due to conflicts between Storybook and React Router</P>
|
||||
<Text element="p">
|
||||
*The examples cannot contemplate an internal link due to conflicts between Storybook and React Router
|
||||
</Text>
|
||||
</VerticalGroup>
|
||||
);
|
||||
};
|
||||
|
@ -6,7 +6,6 @@ import { VerticalGroup } from '../Layout/Layout';
|
||||
|
||||
import { Text } from './Text';
|
||||
import mdx from './Text.mdx';
|
||||
import { H1, H2, H3, H4, H5, H6, Span, P, Legend, TextModifier } from './TextElements';
|
||||
|
||||
const meta: Meta = {
|
||||
title: 'General/Text',
|
||||
@ -15,7 +14,6 @@ const meta: Meta = {
|
||||
docs: {
|
||||
page: mdx,
|
||||
},
|
||||
controls: { exclude: ['as'] },
|
||||
},
|
||||
argTypes: {
|
||||
variant: { control: 'select', options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'body', 'bodySmall', undefined] },
|
||||
@ -39,93 +37,73 @@ const meta: Meta = {
|
||||
],
|
||||
},
|
||||
truncate: { control: 'boolean' },
|
||||
italic: { control: 'boolean' },
|
||||
textAlignment: {
|
||||
control: 'select',
|
||||
options: ['inherit', 'initial', 'left', 'right', 'center', 'justify', undefined],
|
||||
},
|
||||
},
|
||||
args: {
|
||||
element: 'h1',
|
||||
variant: undefined,
|
||||
weight: 'light',
|
||||
textAlignment: 'left',
|
||||
truncate: false,
|
||||
italic: false,
|
||||
color: 'primary',
|
||||
children: `This is an example of a Text component`,
|
||||
},
|
||||
};
|
||||
|
||||
export const Example: StoryFn = () => {
|
||||
export const Example: StoryFn = (args) => {
|
||||
return (
|
||||
<VerticalGroup>
|
||||
<StoryExample name="Header, paragraph, span and legend elements">
|
||||
<H1>h1. Heading</H1>
|
||||
<H2>h2. Heading</H2>
|
||||
<H3>h3. Heading</H3>
|
||||
<H4>h4. Heading</H4>
|
||||
<H5>h5. Heading</H5>
|
||||
<H6>h6. Heading</H6>
|
||||
<P>This is a paragraph</P>
|
||||
<Legend>This is a legend</Legend>
|
||||
<Span>This is a span</Span>
|
||||
<StoryExample name="Header, paragraph and span">
|
||||
<Text {...args} element="h1">
|
||||
This is a header
|
||||
</Text>
|
||||
<Text {...args} element="p">
|
||||
This is a paragraph that contains
|
||||
<Text color="success" italic>
|
||||
{' '}
|
||||
a span element with different color and style{' '}
|
||||
</Text>
|
||||
but is comprised within the same block text
|
||||
</Text>
|
||||
</StoryExample>
|
||||
<StoryExample name="Paragraph with truncate set to true and wrapping up a span element">
|
||||
<Text {...args} element="p" truncate>
|
||||
This is a paragraph that contains
|
||||
<Text color="warning" italic>
|
||||
{' '}
|
||||
a span element{' '}
|
||||
</Text>
|
||||
but has truncate set to true
|
||||
</Text>
|
||||
</StoryExample>
|
||||
</VerticalGroup>
|
||||
);
|
||||
};
|
||||
Example.parameters = {
|
||||
controls: {
|
||||
exclude: ['variant', 'weight', 'textAlignment', 'truncate', 'color', 'children'],
|
||||
exclude: ['element', 'variant', 'weight', 'textAlignment', 'truncate', 'italic', 'color', 'children'],
|
||||
},
|
||||
};
|
||||
|
||||
export const HeadingComponent: StoryFn = (args) => {
|
||||
export const Basic: StoryFn = (args) => {
|
||||
return (
|
||||
<div style={{ width: '300px' }}>
|
||||
<H1 variant={args.variant} weight={args.weight} textAlignment={args.textAlignment} {...args}>
|
||||
<Text
|
||||
element={args.element}
|
||||
variant={args.variant}
|
||||
weight={args.weight}
|
||||
textAlignment={args.textAlignment}
|
||||
{...args}
|
||||
>
|
||||
{args.children}
|
||||
</H1>
|
||||
</Text>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
HeadingComponent.args = {
|
||||
variant: undefined,
|
||||
weight: 'light',
|
||||
textAlignment: 'center',
|
||||
truncate: false,
|
||||
color: 'primary',
|
||||
children: 'This is a H1 component',
|
||||
};
|
||||
|
||||
export const LegendComponent: StoryFn = (args) => {
|
||||
return (
|
||||
<div style={{ width: '300px' }}>
|
||||
<Legend variant={args.variant} weight={args.weight} textAlignment={args.textAlignment} {...args}>
|
||||
{args.children}
|
||||
</Legend>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
LegendComponent.args = {
|
||||
variant: undefined,
|
||||
weight: 'bold',
|
||||
textAlignment: 'center',
|
||||
truncate: false,
|
||||
color: 'error',
|
||||
children: 'This is a lengend component',
|
||||
};
|
||||
|
||||
export const TextModifierComponent: StoryFn = (args) => {
|
||||
return (
|
||||
<div style={{ width: '300px' }}>
|
||||
<H6 variant={args.variant} weight={args.weight} textAlignment={args.textAlignment} {...args}>
|
||||
{args.children}{' '}
|
||||
<TextModifier weight="bold" color="error">
|
||||
{' '}
|
||||
with a part of its text modified{' '}
|
||||
</TextModifier>
|
||||
</H6>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
TextModifierComponent.args = {
|
||||
variant: undefined,
|
||||
weight: 'light',
|
||||
textAlignment: 'center',
|
||||
truncate: false,
|
||||
color: 'maxContrast',
|
||||
children: 'This is a H6 component',
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
@ -7,13 +7,13 @@ import { Text } from './Text';
|
||||
|
||||
describe('Text', () => {
|
||||
it('renders correctly', () => {
|
||||
render(<Text as={'h1'}>This is a text component</Text>);
|
||||
render(<Text element={'h1'}>This is a text component</Text>);
|
||||
expect(screen.getByText('This is a text component')).toBeInTheDocument();
|
||||
});
|
||||
it('keeps the element type but changes its styles', () => {
|
||||
const customVariant: keyof ThemeTypographyVariantTypes = 'body';
|
||||
render(
|
||||
<Text as={'h1'} variant={customVariant}>
|
||||
<Text element={'h1'} variant={customVariant}>
|
||||
This is a text component
|
||||
</Text>
|
||||
);
|
||||
@ -26,7 +26,7 @@ describe('Text', () => {
|
||||
const customColor = 'info';
|
||||
const theme = createTheme();
|
||||
render(
|
||||
<Text as={'h1'} color={customColor}>
|
||||
<Text element={'h1'} color={customColor}>
|
||||
This is a text component
|
||||
</Text>
|
||||
);
|
||||
|
@ -5,11 +5,11 @@ import { GrafanaTheme2, ThemeTypographyVariantTypes } from '@grafana/data';
|
||||
|
||||
import { useStyles2 } from '../../themes';
|
||||
|
||||
import { customWeight, customColor } from './utils';
|
||||
import { customWeight, customColor, customVariant } from './utils';
|
||||
|
||||
export interface TextProps {
|
||||
/** Defines what HTML element is defined underneath */
|
||||
as: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'span' | 'p' | 'legend';
|
||||
/** Defines what HTML element is defined underneath. "span" by default */
|
||||
element?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'span' | 'p';
|
||||
/** What typograpy variant should be used for the component. Only use if default variant for the defined element is not what is needed */
|
||||
variant?: keyof ThemeTypographyVariantTypes;
|
||||
/** Override the default weight for the used variant */
|
||||
@ -18,22 +18,24 @@ export interface TextProps {
|
||||
color?: keyof GrafanaTheme2['colors']['text'] | 'error' | 'success' | 'warning' | 'info';
|
||||
/** Use to cut the text off with ellipsis if there isn't space to show all of it. On hover shows the rest of the text */
|
||||
truncate?: boolean;
|
||||
/** If true, show the text as italic. False by default */
|
||||
italic?: boolean;
|
||||
/** Whether to align the text to left, center or right */
|
||||
textAlignment?: CSSProperties['textAlign'];
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const Text = React.forwardRef<HTMLElement, TextProps>(
|
||||
({ as, variant, weight, color, truncate, textAlignment, children }, ref) => {
|
||||
({ element = 'span', variant, weight, color, truncate, italic, textAlignment, children }, ref) => {
|
||||
const styles = useStyles2(
|
||||
useCallback(
|
||||
(theme) => getTextStyles(theme, variant, color, weight, truncate, textAlignment),
|
||||
[color, textAlignment, truncate, weight, variant]
|
||||
(theme) => getTextStyles(theme, element, variant, color, weight, truncate, italic, textAlignment),
|
||||
[color, textAlignment, truncate, italic, weight, variant, element]
|
||||
)
|
||||
);
|
||||
|
||||
return createElement(
|
||||
as,
|
||||
element,
|
||||
{
|
||||
className: styles,
|
||||
ref,
|
||||
@ -47,19 +49,22 @@ Text.displayName = 'Text';
|
||||
|
||||
const getTextStyles = (
|
||||
theme: GrafanaTheme2,
|
||||
element?: TextProps['element'],
|
||||
variant?: keyof ThemeTypographyVariantTypes,
|
||||
color?: TextProps['color'],
|
||||
weight?: TextProps['weight'],
|
||||
truncate?: TextProps['truncate'],
|
||||
italic?: TextProps['italic'],
|
||||
textAlignment?: TextProps['textAlignment']
|
||||
) => {
|
||||
return css([
|
||||
variant && {
|
||||
...theme.typography[variant],
|
||||
},
|
||||
{
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
...customVariant(theme, element, variant),
|
||||
},
|
||||
variant && {
|
||||
...theme.typography[variant],
|
||||
},
|
||||
color && {
|
||||
color: customColor(color, theme),
|
||||
@ -72,6 +77,9 @@ const getTextStyles = (
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
},
|
||||
italic && {
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
textAlignment && {
|
||||
textAlign: textAlignment,
|
||||
},
|
||||
|
@ -1,75 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
import { Text, TextProps } from './Text';
|
||||
|
||||
interface TextElementsProps extends Omit<TextProps, 'as'> {}
|
||||
|
||||
interface TextModifierProps {
|
||||
/** Override the default weight for the used variant */
|
||||
weight?: 'light' | 'regular' | 'medium' | 'bold';
|
||||
/** Color to use for text */
|
||||
color?: keyof GrafanaTheme2['colors']['text'] | 'error' | 'success' | 'warning' | 'info';
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const H1 = React.forwardRef<HTMLHeadingElement, TextElementsProps>((props, ref) => {
|
||||
return <Text as="h1" {...props} variant={props.variant || 'h1'} ref={ref} />;
|
||||
});
|
||||
|
||||
H1.displayName = 'H1';
|
||||
|
||||
export const H2 = React.forwardRef<HTMLHeadingElement, TextElementsProps>((props, ref) => {
|
||||
return <Text as="h2" {...props} variant={props.variant || 'h2'} ref={ref} />;
|
||||
});
|
||||
|
||||
H2.displayName = 'H2';
|
||||
|
||||
export const H3 = React.forwardRef<HTMLHeadingElement, TextElementsProps>((props, ref) => {
|
||||
return <Text as="h3" {...props} variant={props.variant || 'h3'} ref={ref} />;
|
||||
});
|
||||
|
||||
H3.displayName = 'H3';
|
||||
|
||||
export const H4 = React.forwardRef<HTMLHeadingElement, TextElementsProps>((props, ref) => {
|
||||
return <Text as="h4" {...props} variant={props.variant || 'h4'} ref={ref} />;
|
||||
});
|
||||
|
||||
H4.displayName = 'H4';
|
||||
|
||||
export const H5 = React.forwardRef<HTMLHeadingElement, TextElementsProps>((props, ref) => {
|
||||
return <Text as="h5" {...props} variant={props.variant || 'h5'} ref={ref} />;
|
||||
});
|
||||
|
||||
H5.displayName = 'H5';
|
||||
|
||||
export const H6 = React.forwardRef<HTMLHeadingElement, TextElementsProps>((props, ref) => {
|
||||
return <Text as="h6" {...props} variant={props.variant || 'h6'} ref={ref} />;
|
||||
});
|
||||
|
||||
H6.displayName = 'H6';
|
||||
|
||||
export const P = React.forwardRef<HTMLParagraphElement, TextElementsProps>((props, ref) => {
|
||||
return <Text as="p" {...props} variant={props.variant || 'body'} ref={ref} />;
|
||||
});
|
||||
|
||||
P.displayName = 'P';
|
||||
|
||||
export const Span = React.forwardRef<HTMLSpanElement, TextElementsProps>((props, ref) => {
|
||||
return <Text as="span" {...props} variant={props.variant || 'bodySmall'} ref={ref} />;
|
||||
});
|
||||
|
||||
Span.displayName = 'Span';
|
||||
|
||||
export const Legend = React.forwardRef<HTMLLegendElement, TextElementsProps>((props, ref) => {
|
||||
return <Text as="legend" {...props} variant={props.variant || 'bodySmall'} ref={ref} />;
|
||||
});
|
||||
|
||||
Legend.displayName = 'Legend';
|
||||
|
||||
export const TextModifier = React.forwardRef<HTMLSpanElement, TextModifierProps>((props, ref) => {
|
||||
return <Text as="span" {...props} ref={ref} />;
|
||||
});
|
||||
|
||||
TextModifier.displayName = 'TextModifier';
|
@ -1,4 +1,4 @@
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { GrafanaTheme2, ThemeTypographyVariantTypes } from '@grafana/data';
|
||||
|
||||
import { TextProps } from './Text';
|
||||
|
||||
@ -30,3 +30,32 @@ export const customColor = (color: TextProps['color'], theme: GrafanaTheme2): st
|
||||
return color ? theme.colors.text[color] : undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export const customVariant = (
|
||||
theme: GrafanaTheme2,
|
||||
element: TextProps['element'],
|
||||
variant?: keyof ThemeTypographyVariantTypes
|
||||
) => {
|
||||
if (variant) {
|
||||
return theme.typography[variant];
|
||||
}
|
||||
switch (element) {
|
||||
//Span elements does not have a default variant to be able to take the parents style
|
||||
case 'span':
|
||||
return;
|
||||
case 'h1':
|
||||
return theme.typography.h1;
|
||||
case 'h2':
|
||||
return theme.typography.h2;
|
||||
case 'h3':
|
||||
return theme.typography.h3;
|
||||
case 'h4':
|
||||
return theme.typography.h4;
|
||||
case 'h5':
|
||||
return theme.typography.h5;
|
||||
case 'h6':
|
||||
return theme.typography.h6;
|
||||
default:
|
||||
return theme.typography.body;
|
||||
}
|
||||
};
|
||||
|
@ -9,4 +9,4 @@
|
||||
* be subject to the standard policies
|
||||
*/
|
||||
|
||||
export * from './components/Text/TextElements';
|
||||
export * from './components/Text/Text';
|
||||
|
@ -5,7 +5,7 @@ import { useToggle } from 'react-use';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { Button, Drawer, ToolbarButton, useStyles2 } from '@grafana/ui';
|
||||
import { H3 } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/unstable';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { DEFAULT_FEED_URL } from 'app/plugins/panel/news/constants';
|
||||
|
||||
@ -26,7 +26,7 @@ export function NewsContainer({ className }: NewsContainerProps) {
|
||||
<Drawer
|
||||
title={
|
||||
<div className={styles.title}>
|
||||
<H3>{t('news.title', 'Latest from the blog')}</H3>
|
||||
<Text element="h3">{t('news.title', 'Latest from the blog')}</Text>
|
||||
<a
|
||||
href="https://grafana.com/blog/"
|
||||
target="_blank"
|
||||
|
@ -209,9 +209,8 @@ function Row({ index, style: virtualStyles, data }: RowProps) {
|
||||
)}
|
||||
|
||||
<label className={styles.label} id={labelId}>
|
||||
<Text as="span" truncate>
|
||||
{item.title}
|
||||
</Text>
|
||||
{/* TODO: text is not truncated properly, it still overflows the container */}
|
||||
<Text truncate>{item.title}</Text>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,7 +7,7 @@ import { useAsync } from 'react-use';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Alert, Button, Icon, Input, LoadingBar, useStyles2 } from '@grafana/ui';
|
||||
import { Text } from '@grafana/ui/src/components/Text/Text';
|
||||
import { Trans, t } from 'app/core/internationalization';
|
||||
import { t, Trans } from 'app/core/internationalization';
|
||||
import { skipToken, useGetFolderQuery } from 'app/features/browse-dashboards/api/browseDashboardsAPI';
|
||||
import { PAGE_SIZE } from 'app/features/browse-dashboards/api/services';
|
||||
import {
|
||||
@ -209,7 +209,7 @@ export function NestedFolderPicker({ value, onChange }: NestedFolderPickerProps)
|
||||
{selectedFolder.isLoading ? (
|
||||
<Skeleton width={100} />
|
||||
) : (
|
||||
<Text as="span" truncate>
|
||||
<Text truncate>
|
||||
{label ?? <Trans i18nKey="browse-dashboards.folder-picker.button-label">Select folder</Trans>}
|
||||
</Text>
|
||||
)}
|
||||
|
@ -4,7 +4,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { isFetchError } from '@grafana/runtime';
|
||||
import { Field, IconButton, Input, useStyles2 } from '@grafana/ui';
|
||||
import { H1 } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/unstable';
|
||||
|
||||
export interface Props {
|
||||
value: string;
|
||||
@ -61,7 +61,9 @@ export const EditableTitle = ({ value, onEdit }: Props) => {
|
||||
this is to prevent the title from flickering back to the old value after the user has edited
|
||||
caused by the delay between the save completing and the new value being refetched
|
||||
*/}
|
||||
<H1 truncate>{localValue}</H1>
|
||||
<Text element="h1" truncate>
|
||||
{localValue}
|
||||
</Text>
|
||||
<IconButton name="pen" size="lg" tooltip="Edit title" onClick={() => setIsEditing(true)} />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,11 +3,11 @@ import React, { ComponentProps, HTMLAttributes } from 'react';
|
||||
|
||||
import { Stack } from '@grafana/experimental';
|
||||
import { Icon, IconName, useStyles2 } from '@grafana/ui';
|
||||
import { Span } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/unstable';
|
||||
|
||||
interface Props extends HTMLAttributes<HTMLDivElement> {
|
||||
icon?: IconName;
|
||||
color?: ComponentProps<typeof Span>['color'];
|
||||
color?: ComponentProps<typeof Text>['color'];
|
||||
}
|
||||
|
||||
const MetaText = ({ children, icon, color = 'secondary', ...rest }: Props) => {
|
||||
@ -22,12 +22,12 @@ const MetaText = ({ children, icon, color = 'secondary', ...rest }: Props) => {
|
||||
// allow passing ARIA and data- attributes
|
||||
{...rest}
|
||||
>
|
||||
<Span variant="bodySmall" color={color}>
|
||||
<Text color={color}>
|
||||
<Stack direction="row" alignItems="center" gap={0.5}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{children}
|
||||
</Stack>
|
||||
</Span>
|
||||
</Text>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ import React from 'react';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Stack } from '@grafana/experimental';
|
||||
import { Button, Dropdown, Icon, Menu, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
import { Span } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/unstable';
|
||||
import ConditionalWrap from 'app/features/alerting/components/ConditionalWrap';
|
||||
import { GrafanaNotifierType } from 'app/types/alerting';
|
||||
|
||||
@ -104,7 +104,7 @@ const ContactPointHeader = (props: ContactPointHeaderProps) => {
|
||||
<div className={styles.headerWrapper}>
|
||||
<Stack direction="row" alignItems="center" gap={1}>
|
||||
<Stack alignItems="center" gap={1}>
|
||||
<Span variant="body">{name}</Span>
|
||||
<Text variant="body">{name}</Text>
|
||||
</Stack>
|
||||
{policies.length > 0 ? (
|
||||
<MetaText>
|
||||
@ -179,14 +179,14 @@ const ContactPointReceiver = (props: ContactPointReceiverProps) => {
|
||||
<Stack direction="row" alignItems="center" gap={1}>
|
||||
<Stack direction="row" alignItems="center" gap={0.5}>
|
||||
{iconName && <Icon name={iconName} />}
|
||||
<Span variant="body" color="primary">
|
||||
<Text variant="body" color="primary">
|
||||
{type}
|
||||
</Span>
|
||||
</Text>
|
||||
</Stack>
|
||||
{description && (
|
||||
<Span variant="bodySmall" color="secondary">
|
||||
<Text variant="bodySmall" color="secondary">
|
||||
{description}
|
||||
</Span>
|
||||
</Text>
|
||||
)}
|
||||
</Stack>
|
||||
</div>
|
||||
@ -196,7 +196,7 @@ const ContactPointReceiver = (props: ContactPointReceiverProps) => {
|
||||
<>
|
||||
{/* TODO we might need an error variant for MetaText, dito for success */}
|
||||
{/* TODO show error details on hover or elsewhere */}
|
||||
<Span color="error" variant="bodySmall" weight="bold">
|
||||
<Text color="error" variant="bodySmall" weight="bold">
|
||||
<Stack direction="row" alignItems={'center'} gap={0.5}>
|
||||
<Tooltip
|
||||
content={
|
||||
@ -208,7 +208,7 @@ const ContactPointReceiver = (props: ContactPointReceiverProps) => {
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
</Span>
|
||||
</Text>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
|
@ -7,7 +7,7 @@ import { Link } from 'react-router-dom';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Stack } from '@grafana/experimental';
|
||||
import { Badge, Button, Dropdown, getTagColorsFromName, Icon, Menu, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
import { Span } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/unstable';
|
||||
import { contextSrv } from 'app/core/core';
|
||||
import ConditionalWrap from 'app/features/alerting/components/ConditionalWrap';
|
||||
import { RouteWithID, Receiver, ObjectMatcher, AlertmanagerGroup } from 'app/plugins/datasource/alertmanager/types';
|
||||
@ -554,17 +554,17 @@ const routePropertyToValue = (
|
||||
|
||||
if (isNotGrouping) {
|
||||
return (
|
||||
<Span variant="bodySmall" color="secondary">
|
||||
<Text variant="bodySmall" color="secondary">
|
||||
Not grouping
|
||||
</Span>
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
if (isSingleGroup) {
|
||||
return (
|
||||
<Span variant="bodySmall" color="secondary">
|
||||
<Text variant="bodySmall" color="secondary">
|
||||
Single group
|
||||
</Span>
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ import React, { lazy, Suspense } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Button, LoadingPlaceholder, useStyles2 } from '@grafana/ui';
|
||||
import { H4 } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/unstable';
|
||||
import { alertRuleApi } from 'app/features/alerting/unified/api/alertRuleApi';
|
||||
import { Stack } from 'app/plugins/datasource/parca/QueryEditor/Stack';
|
||||
import { AlertQuery } from 'app/types/unified-alerting-dto';
|
||||
@ -67,7 +67,7 @@ export const NotificationPreview = ({
|
||||
<Stack direction="column" gap={2}>
|
||||
<div className={styles.routePreviewHeaderRow}>
|
||||
<div className={styles.previewHeader}>
|
||||
<H4>Alert instance routing preview</H4>
|
||||
<Text element="h4">Alert instance routing preview</Text>
|
||||
</div>
|
||||
<div className={styles.button}>
|
||||
<Button icon="sync" variant="secondary" type="button" onClick={onPreview}>
|
||||
|
@ -8,7 +8,7 @@ import { selectors } from '@grafana/e2e-selectors';
|
||||
import { Stack } from '@grafana/experimental';
|
||||
import { config, getDataSourceSrv } from '@grafana/runtime';
|
||||
import { Alert, Button, Dropdown, Field, Icon, InputControl, Menu, MenuItem, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
import { H5 } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/components/Text/Text';
|
||||
import { isExpressionQuery } from 'app/features/expressions/guards';
|
||||
import { ExpressionDatasourceUID, ExpressionQueryType, expressionTypes } from 'app/features/expressions/types';
|
||||
import { useDispatch } from 'app/types';
|
||||
@ -435,8 +435,8 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P
|
||||
onClickSwitch={onClickSwitch}
|
||||
/>
|
||||
{/* Expression Queries */}
|
||||
<H5>Expressions</H5>
|
||||
<div className={styles.mutedText}>Manipulate data returned from queries with math and other operations.</div>
|
||||
<Text element="h5">Expressions</Text>
|
||||
<div className={styles.mutedText}>Manipulate data returned from queries with math and other operations</div>
|
||||
<ExpressionsEditor
|
||||
queries={queries}
|
||||
panelData={queryPreviewData}
|
||||
|
@ -2,7 +2,7 @@ import React, { useState } from 'react';
|
||||
|
||||
import { Stack } from '@grafana/experimental';
|
||||
import { Alert, Button, Icon, LoadingPlaceholder, Tab, TabContent, TabsBar } from '@grafana/ui';
|
||||
import { H1, Span } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/unstable';
|
||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||
import { GrafanaAlertState } from 'app/types/unified-alerting-dto';
|
||||
|
||||
@ -129,18 +129,18 @@ interface BreadcrumbProps {
|
||||
|
||||
const BreadCrumb = ({ folder, evaluationGroup }: BreadcrumbProps) => (
|
||||
<Stack alignItems="center" gap={0.5}>
|
||||
<Span color="secondary">
|
||||
<Text color="secondary">
|
||||
<Icon name="folder" />
|
||||
</Span>
|
||||
<Span variant="body" color="primary">
|
||||
</Text>
|
||||
<Text variant="body" color="primary">
|
||||
{folder}
|
||||
</Span>
|
||||
<Span variant="body" color="secondary">
|
||||
</Text>
|
||||
<Text variant="body" color="secondary">
|
||||
<Icon name="angle-right" />
|
||||
</Span>
|
||||
<Span variant="body" color="primary">
|
||||
</Text>
|
||||
<Text variant="body" color="primary">
|
||||
{evaluationGroup}
|
||||
</Span>
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@ -154,9 +154,9 @@ const Title = ({ name, state }: TitleProps) => (
|
||||
<Stack alignItems={'center'} gap={1}>
|
||||
<AlertStateDot size="md" state={state} />
|
||||
{/* <Button variant="secondary" fill="outline" icon="angle-left" /> */}
|
||||
<H1 variant="h2" weight="bold">
|
||||
<Text element="h1" variant="h2" weight="bold">
|
||||
{name}
|
||||
</H1>
|
||||
</Text>
|
||||
{/* <Badge color="red" text={state} icon="exclamation-circle" /> */}
|
||||
</Stack>
|
||||
</header>
|
||||
@ -167,9 +167,9 @@ interface SummaryProps {
|
||||
}
|
||||
|
||||
const Summary = ({ text }: SummaryProps) => (
|
||||
<Span variant="body" color="secondary">
|
||||
<Text variant="body" color="secondary">
|
||||
{text}
|
||||
</Span>
|
||||
</Text>
|
||||
);
|
||||
|
||||
export default RuleViewer;
|
||||
|
@ -2,7 +2,7 @@ import React, { useState } from 'react';
|
||||
|
||||
import { Space } from '@grafana/experimental';
|
||||
import { ConfirmModal } from '@grafana/ui';
|
||||
import { P } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/unstable';
|
||||
import { Trans, t } from 'app/core/internationalization';
|
||||
|
||||
import { DashboardTreeSelection } from '../../types';
|
||||
@ -33,11 +33,11 @@ export const DeleteModal = ({ onConfirm, onDismiss, selectedItems, ...props }: P
|
||||
<ConfirmModal
|
||||
body={
|
||||
<>
|
||||
<P>
|
||||
<Text element="p">
|
||||
<Trans i18nKey="browse-dashboards.action.delete-modal-text">
|
||||
This action will delete the following content:
|
||||
</Trans>
|
||||
</P>
|
||||
</Text>
|
||||
<DescendantCount selectedItems={selectedItems} />
|
||||
<Space v={2} />
|
||||
</>
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
|
||||
import { Alert } from '@grafana/ui';
|
||||
import { P } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/unstable';
|
||||
|
||||
import { useGetAffectedItemsQuery } from '../../api/browseDashboardsAPI';
|
||||
import { DashboardTreeSelection } from '../../types';
|
||||
@ -18,10 +18,10 @@ export const DescendantCount = ({ selectedItems }: Props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<P color="secondary">
|
||||
<Text element="p" color="secondary">
|
||||
{data && buildBreakdownString(data.folder, data.dashboard, data.libraryPanel, data.alertRule)}
|
||||
{(isFetching || isLoading) && <Skeleton width={200} />}
|
||||
</P>
|
||||
</Text>
|
||||
{error && <Alert severity="error" title="Unable to retrieve descendant information" />}
|
||||
</>
|
||||
);
|
||||
|
@ -3,7 +3,7 @@ import React, { useState } from 'react';
|
||||
import { Space } from '@grafana/experimental';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { Alert, Button, Field, Modal } from '@grafana/ui';
|
||||
import { P } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/unstable';
|
||||
import { NestedFolderPicker } from 'app/core/components/NestedFolderPicker/NestedFolderPicker';
|
||||
import { FolderChange } from 'app/core/components/NestedFolderPicker/types';
|
||||
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
|
||||
@ -51,9 +51,9 @@ export const MoveModal = ({ onConfirm, onDismiss, selectedItems, ...props }: Pro
|
||||
/>
|
||||
)}
|
||||
|
||||
<P>
|
||||
<Text element="p">
|
||||
<Trans i18nKey="browse-dashboards.action.move-modal-text">This action will move the following content:</Trans>
|
||||
</P>
|
||||
</Text>
|
||||
|
||||
<DescendantCount selectedItems={selectedItems} />
|
||||
|
||||
|
@ -7,7 +7,7 @@ import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { reportInteraction } from '@grafana/runtime';
|
||||
import { Icon, IconButton, Link, Spinner, useStyles2 } from '@grafana/ui';
|
||||
import { getSvgSize } from '@grafana/ui/src/components/Icon/utils';
|
||||
import { Span } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/unstable';
|
||||
import { getIconForKind } from 'app/features/search/service/utils';
|
||||
|
||||
import { useChildrenByParentUIDState } from '../state';
|
||||
@ -36,9 +36,9 @@ export function NameCell({ row: { original: data }, onFolderClick }: NameCellPro
|
||||
<span className={styles.folderButtonSpacer} />
|
||||
{item.uiKind === 'empty-folder' ? (
|
||||
<em className={styles.emptyText}>
|
||||
<Span variant="body" color="secondary" truncate>
|
||||
<Text variant="body" color="secondary" truncate>
|
||||
No items
|
||||
</Span>
|
||||
</Text>
|
||||
</em>
|
||||
) : (
|
||||
<Skeleton width={200} />
|
||||
@ -66,7 +66,7 @@ export function NameCell({ row: { original: data }, onFolderClick }: NameCellPro
|
||||
)}
|
||||
<div className={styles.iconNameContainer}>
|
||||
{isLoading ? <Spinner size={ICON_SIZE} /> : <Icon size={ICON_SIZE} name={iconName} />}
|
||||
<Span variant="body" truncate>
|
||||
<Text variant="body" truncate>
|
||||
{item.url ? (
|
||||
<Link
|
||||
onClick={() => {
|
||||
@ -80,7 +80,7 @@ export function NameCell({ row: { original: data }, onFolderClick }: NameCellPro
|
||||
) : (
|
||||
item.title
|
||||
)}
|
||||
</Span>
|
||||
</Text>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
@ -5,7 +5,7 @@ import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { config, locationService, reportInteraction } from '@grafana/runtime';
|
||||
import { Button, useStyles2 } from '@grafana/ui';
|
||||
import { H1, H3, P } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/unstable';
|
||||
import { Trans } from 'app/core/internationalization';
|
||||
import { DashboardModel } from 'app/features/dashboard/state';
|
||||
import { onAddLibraryPanel, onCreateNewPanel, onCreateNewRow } from 'app/features/dashboard/utils/dashboard';
|
||||
@ -28,19 +28,19 @@ const DashboardEmpty = ({ dashboard, canCreate }: Props) => {
|
||||
<div className={cx(styles.centeredContent, styles.wrapper)}>
|
||||
<div className={cx(styles.containerBox, styles.centeredContent, styles.visualizationContainer)}>
|
||||
<div className={styles.headerBig}>
|
||||
<H1 textAlignment="center" weight="medium">
|
||||
<Text element="h1" textAlignment="center" weight="medium">
|
||||
<Trans i18nKey="dashboard.empty.add-visualization-header">
|
||||
Start your new dashboard by adding a visualization
|
||||
</Trans>
|
||||
</H1>
|
||||
</Text>
|
||||
</div>
|
||||
<div className={styles.bodyBig}>
|
||||
<P textAlignment="center" color="secondary">
|
||||
<Text element="p" textAlignment="center" color="secondary">
|
||||
<Trans i18nKey="dashboard.empty.add-visualization-body">
|
||||
Select a data source and then query and visualize your data with charts, stats and tables or create
|
||||
lists, markdowns and other widgets.
|
||||
</Trans>
|
||||
</P>
|
||||
</Text>
|
||||
</div>
|
||||
<Button
|
||||
size="lg"
|
||||
@ -61,14 +61,14 @@ const DashboardEmpty = ({ dashboard, canCreate }: Props) => {
|
||||
{config.featureToggles.vizAndWidgetSplit && (
|
||||
<div className={cx(styles.containerBox, styles.centeredContent, styles.widgetContainer)}>
|
||||
<div className={styles.headerSmall}>
|
||||
<H3 textAlignment="center" weight="medium">
|
||||
<Text element="h3" textAlignment="center" weight="medium">
|
||||
<Trans i18nKey="dashboard.empty.add-widget-header">Add a widget</Trans>
|
||||
</H3>
|
||||
</Text>
|
||||
</div>
|
||||
<div className={styles.bodySmall}>
|
||||
<P textAlignment="center" color="secondary">
|
||||
<Text element="p" textAlignment="center" color="secondary">
|
||||
<Trans i18nKey="dashboard.empty.add-widget-body">Create lists, markdowns and other widgets</Trans>
|
||||
</P>
|
||||
</Text>
|
||||
</div>
|
||||
<Button
|
||||
icon="plus"
|
||||
@ -86,16 +86,16 @@ const DashboardEmpty = ({ dashboard, canCreate }: Props) => {
|
||||
)}
|
||||
<div className={cx(styles.containerBox, styles.centeredContent, styles.rowContainer)}>
|
||||
<div className={styles.headerSmall}>
|
||||
<H3 textAlignment="center" weight="medium">
|
||||
<Text element="h3" textAlignment="center" weight="medium">
|
||||
<Trans i18nKey="dashboard.empty.add-row-header">Add a row</Trans>
|
||||
</H3>
|
||||
</Text>
|
||||
</div>
|
||||
<div className={styles.bodySmall}>
|
||||
<P textAlignment="center" color="secondary">
|
||||
<Text element="p" textAlignment="center" color="secondary">
|
||||
<Trans i18nKey="dashboard.empty.add-row-body">
|
||||
Group your visualizations into expandable sections.
|
||||
</Trans>
|
||||
</P>
|
||||
</Text>
|
||||
</div>
|
||||
<Button
|
||||
icon="plus"
|
||||
@ -112,16 +112,16 @@ const DashboardEmpty = ({ dashboard, canCreate }: Props) => {
|
||||
</div>
|
||||
<div className={cx(styles.containerBox, styles.centeredContent, styles.libraryContainer)}>
|
||||
<div className={styles.headerSmall}>
|
||||
<H3 textAlignment="center" weight="medium">
|
||||
<Text element="h3" textAlignment="center" weight="medium">
|
||||
<Trans i18nKey="dashboard.empty.add-import-header">Import panel</Trans>
|
||||
</H3>
|
||||
</Text>
|
||||
</div>
|
||||
<div className={styles.bodySmall}>
|
||||
<P textAlignment="center" color="secondary">
|
||||
<Text element="p" textAlignment="center" color="secondary">
|
||||
<Trans i18nKey="dashboard.empty.add-import-body">
|
||||
Import visualizations that are shared with other dashboards.
|
||||
</Trans>
|
||||
</P>
|
||||
</Text>
|
||||
</div>
|
||||
<Button
|
||||
icon="plus"
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
} from '@grafana/data';
|
||||
import { config, getDataSourceSrv } from '@grafana/runtime';
|
||||
import { Checkbox, Icon, IconName, TagList } from '@grafana/ui';
|
||||
import { Span } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/unstable';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { PluginIconName } from 'app/features/plugins/admin/types';
|
||||
@ -179,9 +179,9 @@ export const generateColumns = (
|
||||
return info ? (
|
||||
<a key={p} href={info.url} className={styles.locationItem}>
|
||||
<Icon name={getIconForKind(info.kind)} />
|
||||
<Span variant="body" truncate>
|
||||
<Text variant="body" truncate>
|
||||
{info.name}
|
||||
</Span>
|
||||
</Text>
|
||||
</a>
|
||||
) : (
|
||||
<span key={p}>{p}</span>
|
||||
|
@ -5,7 +5,7 @@ import { Link } from 'react-router-dom';
|
||||
import { SIGV4ConnectionConfig } from '@grafana/aws-sdk';
|
||||
import { DataSourcePluginOptionsEditorProps, SelectableValue } from '@grafana/data';
|
||||
import { DataSourceHttpSettings, InlineField, InlineFormLabel, InlineSwitch, Select } from '@grafana/ui';
|
||||
import { Span } from '@grafana/ui/src/unstable';
|
||||
import { Text } from '@grafana/ui/src/unstable';
|
||||
import { config } from 'app/core/config';
|
||||
|
||||
import { AlertManagerDataSourceJsonData, AlertManagerImplementation } from './types';
|
||||
@ -76,9 +76,9 @@ export const ConfigEditor = (props: Props) => {
|
||||
</InlineField>
|
||||
</div>
|
||||
{options.jsonData.handleGrafanaManagedAlerts && (
|
||||
<Span variant="bodySmall" color="secondary">
|
||||
<Text variant="bodySmall" color="secondary">
|
||||
Make sure to enable the alert forwarding on the <Link to="/alerting/admin">admin page</Link>.
|
||||
</Span>
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
<DataSourceHttpSettings
|
||||
|
Loading…
Reference in New Issue
Block a user