diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/EmptyTransformationsMessage.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/EmptyTransformationsMessage.tsx index eab5f3e9c58..1e8ff639785 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/EmptyTransformationsMessage.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/EmptyTransformationsMessage.tsx @@ -4,7 +4,7 @@ import { DataFrame, DataTransformerID, standardTransformersRegistry, Transformer import { selectors } from '@grafana/e2e-selectors'; import { t, Trans } from '@grafana/i18n'; import { reportInteraction } from '@grafana/runtime'; -import { Box, Button, Grid, Stack, Text } from '@grafana/ui'; +import { Box, Button, Stack, Text } from '@grafana/ui'; import config from 'app/core/config'; import { SqlExpressionCard } from '../../../dashboard/components/TransformationsEditor/SqlExpressionCard'; @@ -26,9 +26,6 @@ const TRANSFORMATION_IDS = [ DataTransformerID.filterByValue, ]; -const GRID_COLUMNS_WITH_SQL = 5; -const GRID_COLUMNS_WITHOUT_SQL = 4; - export function LegacyEmptyTransformationsMessage({ onShowPicker }: { onShowPicker: () => void }) { return ( @@ -94,13 +91,25 @@ export function NewEmptyTransformationsMessage(props: EmptyTransformationsProps) }; const showSqlCard = hasGoToQueries && config.featureToggles.sqlExpressions; - const gridColumns = showSqlCard ? GRID_COLUMNS_WITH_SQL : GRID_COLUMNS_WITHOUT_SQL; return ( - - + + + + + Add a Transformation + + + + Transformations allow data to be changed in various ways before your visualization is shown. +
+ This includes joining data together, renaming fields, making calculations, formatting data for display, + and more. +
+
+
{(hasAddTransformation || hasGoToQueries) && ( - + {showSqlCard && ( ))} - +
)} - - - +
); diff --git a/public/app/features/dashboard/components/TransformationsEditor/SqlExpressionCard.tsx b/public/app/features/dashboard/components/TransformationsEditor/SqlExpressionCard.tsx index 0cb9302df2e..5f9712897b8 100644 --- a/public/app/features/dashboard/components/TransformationsEditor/SqlExpressionCard.tsx +++ b/public/app/features/dashboard/components/TransformationsEditor/SqlExpressionCard.tsx @@ -1,7 +1,6 @@ -import { css } from '@emotion/css'; +import { Card, Text, useStyles2 } from '@grafana/ui'; -import { GrafanaTheme2 } from '@grafana/data'; -import { Card, useStyles2 } from '@grafana/ui'; +import { getCardStyles } from './getCardStyles'; export interface SqlExpressionCardProps { name: string; @@ -12,60 +11,15 @@ export interface SqlExpressionCardProps { } export function SqlExpressionCard({ name, description, imageUrl, onClick, testId }: SqlExpressionCardProps) { - const styles = useStyles2(getSqlExpressionCardStyles); + const styles = useStyles2(getCardStyles); return ( - - -
- {name} -
-
- - {description} - {imageUrl && ( - - {name} - - )} + + {name} + + {description} + {imageUrl && {name}} ); } - -function getSqlExpressionCardStyles(theme: GrafanaTheme2) { - return { - card: css({ - gridTemplateRows: 'min-content 0 1fr 0', - marginBottom: 0, - }), - heading: css({ - fontWeight: 400, - '> button': { - width: '100%', - display: 'flex', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(1), - }, - }), - titleRow: css({ - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - flexWrap: 'nowrap', - width: '100%', - }), - description: css({ - fontSize: theme.typography.bodySmall.fontSize, - display: 'flex', - flexDirection: 'column', - justifyContent: 'space-between', - }), - image: css({ - display: 'block', - maxWidth: '100%', - marginTop: theme.spacing(2), - }), - }; -} diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationCard.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationCard.tsx index ad113f1b227..8e909480f74 100644 --- a/public/app/features/dashboard/components/TransformationsEditor/TransformationCard.tsx +++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationCard.tsx @@ -1,35 +1,38 @@ -import { cx, css } from '@emotion/css'; +import { cx } from '@emotion/css'; import { DataFrame, - GrafanaTheme2, TransformerRegistryItem, TransformationApplicabilityLevels, standardTransformersRegistry, } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; -import { Badge, Card, IconButton, useStyles2, useTheme2 } from '@grafana/ui'; +import { Badge, Card, IconButton, Stack, Text, useStyles2, useTheme2 } from '@grafana/ui'; import { PluginStateInfo } from 'app/features/plugins/components/PluginStateInfo'; +import { getCardStyles } from './getCardStyles'; + export interface TransformationCardProps { - transform: TransformerRegistryItem; + data?: DataFrame[]; + fullWidth?: boolean; onClick: (id: string) => void; showIllustrations?: boolean; - data?: DataFrame[]; showPluginState?: boolean; showTags?: boolean; + transform: TransformerRegistryItem; } export function TransformationCard({ - transform, - showIllustrations, - onClick, data = [], + fullWidth = false, + onClick, + showIllustrations, showPluginState = true, showTags = true, + transform, }: TransformationCardProps) { const theme = useTheme2(); - const styles = useStyles2(getTransformationCardStyles); + const styles = useStyles2(getCardStyles, fullWidth); // Check to see if the transform is applicable to the given data let applicabilityScore = TransformationApplicabilityLevels.Applicable; @@ -47,7 +50,7 @@ export function TransformationCard({ } } - const cardClasses = !isApplicable && data.length > 0 ? cx(styles.newCard, styles.cardDisabled) : styles.newCard; + const cardClasses = cx(styles.baseCard, { [styles.cardDisabled]: !isApplicable }); const imageUrl = theme.isDark ? transform.imageDark : transform.imageLight; const description = standardTransformersRegistry.getIfExists(transform.id)?.description; @@ -58,15 +61,11 @@ export function TransformationCard({ onClick={() => onClick(transform.id)} noMargin > - -
- {transform.name} - {showPluginState && ( - - - - )} -
+ + + {transform.name} + {showPluginState && } + {showTags && transform.tags && transform.tags.size > 0 && (
{Array.from(transform.tags).map((tag) => ( @@ -75,74 +74,13 @@ export function TransformationCard({
)}
- - {description} - {showIllustrations && imageUrl && ( - - {transform.name} - - )} + + {description || ''} + {showIllustrations && imageUrl && {transform.name}} {!isApplicable && applicabilityDescription !== null && ( - + )}
); } - -function getTransformationCardStyles(theme: GrafanaTheme2) { - return { - heading: css({ - fontWeight: 400, - '> button': { - width: '100%', - display: 'flex', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(1), - }, - }), - titleRow: css({ - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - flexWrap: 'nowrap', - width: '100%', - }), - description: css({ - fontSize: theme.typography.bodySmall.fontSize, - display: 'flex', - flexDirection: 'column', - justifyContent: 'space-between', - }), - image: css({ - display: 'block', - maxWidth: '100%', - marginTop: theme.spacing(2), - }), - cardDisabled: css({ - backgroundColor: theme.colors.action.disabledBackground, - img: { - filter: 'grayscale(100%)', - opacity: 0.33, - }, - }), - cardApplicableInfo: css({ - position: 'absolute', - bottom: theme.spacing(1), - right: theme.spacing(1), - }), - newCard: css({ - gridTemplateRows: 'min-content 0 1fr 0', - marginBottom: 0, - }), - pluginStateInfoWrapper: css({ - marginLeft: theme.spacing(0.5), - }), - tagsWrapper: css({ - display: 'flex', - flexWrap: 'wrap', - gap: theme.spacing(0.5), - }), - }; -} diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.tsx index fb0be6864f5..e27e554fada 100644 --- a/public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.tsx +++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.tsx @@ -165,11 +165,12 @@ function TransformationsGrid({ showIllustrations, transformations, onClick, data {transformations.map((transform) => ( ))} diff --git a/public/app/features/dashboard/components/TransformationsEditor/getCardStyles.ts b/public/app/features/dashboard/components/TransformationsEditor/getCardStyles.ts new file mode 100644 index 00000000000..b3989282ee2 --- /dev/null +++ b/public/app/features/dashboard/components/TransformationsEditor/getCardStyles.ts @@ -0,0 +1,34 @@ +import { css } from '@emotion/css'; + +import { GrafanaTheme2 } from '@grafana/data'; + +export const getCardStyles = (theme: GrafanaTheme2, fullWidth?: boolean) => ({ + baseCard: css({ + maxWidth: fullWidth ? 'none' : '200px', + width: fullWidth ? '100%' : 'auto', + marginBottom: 0, + }), + image: css({ + display: 'block', + maxWidth: '100%', + marginTop: theme.spacing(2), + }), + cardDisabled: css({ + backgroundColor: theme.colors.action.disabledBackground, + img: { + filter: 'grayscale(100%)', + opacity: 0.33, + }, + }), + applicableInfoButton: css({ + position: 'absolute', + bottom: theme.spacing(1), + right: theme.spacing(1), + }), + tagsWrapper: css({ + display: 'flex', + flexWrap: 'wrap', + gap: theme.spacing(0.5), + marginTop: theme.spacing(0.5), + }), +});