3
0
mirror of https://github.com/grafana/grafana.git synced 2025-02-25 18:55:37 -06:00

GLDS: Text component ()

This commit is contained in:
Laura Fernández 2023-07-20 12:59:42 +02:00 committed by GitHub
parent 1c3606cebe
commit 47f70bdb00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 185 additions and 242 deletions
packages/grafana-ui/src
public/app
core/components
features
alerting/unified/components
MetaText.tsx
contact-points
notification-policies
rule-editor
notificaton-preview
query-and-alert-condition
rule-viewer/v2
browse-dashboards/components
dashboard/dashgrid
search/page/components
plugins/datasource/alertmanager

View File

@ -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>}

View File

@ -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 &#160;
<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>
);
};

View File

@ -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;

View File

@ -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>
);

View File

@ -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,
},

View File

@ -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';

View File

@ -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;
}
};

View File

@ -9,4 +9,4 @@
* be subject to the standard policies
*/
export * from './components/Text/TextElements';
export * from './components/Text/Text';

View File

@ -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"

View File

@ -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>

View File

@ -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>
)}

View File

@ -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>

View File

@ -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>
);
};

View File

@ -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>
</>
) : (
<>

View File

@ -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>
);
}

View File

@ -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}>

View File

@ -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}

View File

@ -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;

View File

@ -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} />
</>

View File

@ -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" />}
</>
);

View File

@ -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} />

View File

@ -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>
</>
);

View File

@ -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"

View File

@ -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>

View File

@ -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