SQL Expressions: Add SQL banner (#106865)
* prototype: sql expressions discovery work * chore: remove compact view work * chore: cleanup * chore: moar clean * chore: use grid instead * chore: remove no margin + i18n fix * chore: betterer * cleanupz * chore: oh it needs noMargin * feat: convert to alert * chore: i18n extract * i18n * chore: polish * fix: change localstorage provider import * chore: update local storage key name --------- Co-authored-by: Develer <yeryomin.igor@gmail.com>
This commit is contained in:
@@ -2079,9 +2079,6 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"],
|
||||
[0, 0, 0, "Add noMargin prop to Card components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "1"]
|
||||
],
|
||||
"public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.tsx:5381": [
|
||||
[0, 0, 0, "Add noMargin prop to Card components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"]
|
||||
],
|
||||
"public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "1"]
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import { LocalStorageValueProvider } from '@grafana/data';
|
||||
import { Trans, t } from '@grafana/i18n';
|
||||
import { Alert, Stack, TextLink } from '@grafana/ui';
|
||||
|
||||
const LOCAL_STORAGE_KEY = 'grafana.dashboard.sql-expressions-banner.dismissed';
|
||||
|
||||
export const SqlExpressionsBanner = () => (
|
||||
<LocalStorageValueProvider<boolean> storageKey={LOCAL_STORAGE_KEY} defaultValue={false}>
|
||||
{(isDismissed, onDismiss) => {
|
||||
if (isDismissed) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Alert
|
||||
bottomSpacing={1}
|
||||
title={t('dashboard.transformation-picker-ng.sql-expressions-title', 'SQL Expressions')}
|
||||
severity="info"
|
||||
onRemove={() => onDismiss(true)}
|
||||
>
|
||||
<Stack direction="column" gap={1}>
|
||||
<Trans i18nKey="dashboard.transformation-picker-ng.sql-expressions-message-description">
|
||||
A new way to manipulate and transform the results of data source queries using MySQL-like syntax.
|
||||
</Trans>
|
||||
<TextLink
|
||||
href="https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/sql-expressions/"
|
||||
external
|
||||
>
|
||||
<Trans i18nKey="dashboard.transformation-picker-ng.sql-expressions-message-link">Learn more</Trans>
|
||||
</TextLink>
|
||||
</Stack>
|
||||
</Alert>
|
||||
);
|
||||
}}
|
||||
</LocalStorageValueProvider>
|
||||
);
|
||||
+70
-65
@@ -11,10 +11,24 @@ import {
|
||||
} from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { Trans, t } from '@grafana/i18n';
|
||||
import { Badge, Card, Drawer, FilterPill, IconButton, Input, Switch, useStyles2, useTheme2 } from '@grafana/ui';
|
||||
import {
|
||||
Badge,
|
||||
Card,
|
||||
Drawer,
|
||||
FilterPill,
|
||||
Grid,
|
||||
IconButton,
|
||||
Input,
|
||||
Stack,
|
||||
Switch,
|
||||
useStyles2,
|
||||
useTheme2,
|
||||
} from '@grafana/ui';
|
||||
import config from 'app/core/config';
|
||||
import { PluginStateInfo } from 'app/features/plugins/components/PluginStateInfo';
|
||||
import { getCategoriesLabels } from 'app/features/transformers/utils';
|
||||
|
||||
import { SqlExpressionsBanner } from './SqlExpressions/SqlExpressionsBanner';
|
||||
import { FilterCategory } from './TransformationsEditor';
|
||||
|
||||
const VIEW_ALL_VALUE = 'viewAll';
|
||||
@@ -72,68 +86,65 @@ export function TransformationPickerNg(props: TransformationPickerNgProps) {
|
||||
}}
|
||||
title={t('dashboard.transformation-picker-ng.title-add-another-transformation', 'Add another transformation')}
|
||||
>
|
||||
<div className={styles.searchWrapper}>
|
||||
<Input
|
||||
data-testid={selectors.components.Transforms.searchInput}
|
||||
className={styles.searchInput}
|
||||
value={search ?? ''}
|
||||
placeholder={t(
|
||||
'dashboard.transformation-picker-ng.placeholder-search-for-transformation',
|
||||
'Search for transformation'
|
||||
)}
|
||||
onChange={onSearchChange}
|
||||
onKeyDown={onSearchKeyDown}
|
||||
suffix={suffix}
|
||||
ref={searchInputRef}
|
||||
autoFocus={true}
|
||||
/>
|
||||
<div className={styles.showImages}>
|
||||
<span className={styles.illustationSwitchLabel}>
|
||||
<Trans i18nKey="dashboard.transformation-picker-ng.show-images">Show images</Trans>
|
||||
</span>{' '}
|
||||
<Switch
|
||||
value={showIllustrations}
|
||||
onChange={() => onShowIllustrationsChange && onShowIllustrationsChange(!showIllustrations)}
|
||||
<Stack direction="column" gap={2}>
|
||||
{config?.featureToggles?.sqlExpressions && <SqlExpressionsBanner />}
|
||||
<div className={styles.searchWrapper}>
|
||||
<Input
|
||||
data-testid={selectors.components.Transforms.searchInput}
|
||||
className={styles.searchInput}
|
||||
value={search ?? ''}
|
||||
placeholder={t(
|
||||
'dashboard.transformation-picker-ng.placeholder-search-for-transformation',
|
||||
'Search for transformation'
|
||||
)}
|
||||
onChange={onSearchChange}
|
||||
onKeyDown={onSearchKeyDown}
|
||||
suffix={suffix}
|
||||
ref={searchInputRef}
|
||||
autoFocus={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.filterWrapper}>
|
||||
{filterCategoriesLabels.map(([slug, label]) => {
|
||||
return (
|
||||
<FilterPill
|
||||
key={slug}
|
||||
onClick={() => onSelectedFilterChange && onSelectedFilterChange(slug)}
|
||||
label={label}
|
||||
selected={selectedFilter === slug}
|
||||
<Stack direction="row" alignItems="center" gap={0.5}>
|
||||
<span className={styles.switchLabel}>
|
||||
<Trans i18nKey="dashboard.transformation-picker-ng.show-images">Show images</Trans>
|
||||
</span>
|
||||
<Switch
|
||||
value={showIllustrations}
|
||||
onChange={() => onShowIllustrationsChange && onShowIllustrationsChange(!showIllustrations)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Stack>
|
||||
</div>
|
||||
|
||||
<TransformationsGrid
|
||||
showIllustrations={showIllustrations}
|
||||
transformations={xforms}
|
||||
data={data}
|
||||
onClick={(id) => {
|
||||
onTransformationAdd({ value: id });
|
||||
}}
|
||||
/>
|
||||
<Stack direction="row" wrap="wrap" rowGap={1} columnGap={0.5}>
|
||||
{filterCategoriesLabels.map(([slug, label]) => {
|
||||
return (
|
||||
<FilterPill
|
||||
key={slug}
|
||||
onClick={() => onSelectedFilterChange && onSelectedFilterChange(slug)}
|
||||
label={label}
|
||||
selected={selectedFilter === slug}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
|
||||
<TransformationsGrid
|
||||
showIllustrations={showIllustrations}
|
||||
transformations={xforms}
|
||||
data={data}
|
||||
onClick={(id) => {
|
||||
onTransformationAdd({ value: id });
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
|
||||
function getTransformationPickerStyles(theme: GrafanaTheme2) {
|
||||
return {
|
||||
showImages: css({
|
||||
flexBasis: '0',
|
||||
display: 'flex',
|
||||
gap: '8px',
|
||||
alignItems: 'center',
|
||||
}),
|
||||
pickerInformationLine: css({
|
||||
fontSize: '16px',
|
||||
marginBottom: `${theme.spacing(2)}`,
|
||||
marginBottom: theme.spacing(2),
|
||||
}),
|
||||
pickerInformationLineHighlight: css({
|
||||
verticalAlign: 'middle',
|
||||
@@ -141,8 +152,8 @@ function getTransformationPickerStyles(theme: GrafanaTheme2) {
|
||||
searchWrapper: css({
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
columnGap: '27px',
|
||||
rowGap: '16px',
|
||||
columnGap: theme.spacing(2),
|
||||
rowGap: theme.spacing(1),
|
||||
width: '100%',
|
||||
paddingBottom: theme.spacing(1),
|
||||
}),
|
||||
@@ -150,16 +161,9 @@ function getTransformationPickerStyles(theme: GrafanaTheme2) {
|
||||
flexGrow: '1',
|
||||
width: 'initial',
|
||||
}),
|
||||
illustationSwitchLabel: css({
|
||||
switchLabel: css({
|
||||
whiteSpace: 'nowrap',
|
||||
}),
|
||||
filterWrapper: css({
|
||||
padding: `${theme.spacing(1)} 0`,
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
rowGap: `${theme.spacing(1)}`,
|
||||
columnGap: `${theme.spacing(0.5)}`,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -175,7 +179,7 @@ function TransformationsGrid({ showIllustrations, transformations, onClick, data
|
||||
const styles = useStyles2(getTransformationGridStyles);
|
||||
|
||||
return (
|
||||
<div className={styles.grid}>
|
||||
<Grid columns={3} gap={1}>
|
||||
{transformations.map((transform) => {
|
||||
// Check to see if the transform
|
||||
// is applicable to the given data
|
||||
@@ -208,6 +212,7 @@ function TransformationsGrid({ showIllustrations, transformations, onClick, data
|
||||
data-testid={selectors.components.TransformTab.newTransform(transform.name)}
|
||||
onClick={() => onClick(transform.id)}
|
||||
key={transform.id}
|
||||
noMargin
|
||||
>
|
||||
<Card.Heading className={styles.heading}>
|
||||
<div className={styles.titleRow}>
|
||||
@@ -242,7 +247,7 @@ function TransformationsGrid({ showIllustrations, transformations, onClick, data
|
||||
</Card>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -266,7 +271,7 @@ function getTransformationGridStyles(theme: GrafanaTheme2) {
|
||||
width: '100%',
|
||||
}),
|
||||
description: css({
|
||||
fontSize: '12px',
|
||||
fontSize: theme.typography.bodySmall.fontSize,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
|
||||
@@ -5395,6 +5395,9 @@
|
||||
"transformation-picker-ng": {
|
||||
"placeholder-search-for-transformation": "Search for transformation",
|
||||
"show-images": "Show images",
|
||||
"sql-expressions-message-description": "A new way to manipulate and transform the results of data source queries using MySQL-like syntax.",
|
||||
"sql-expressions-message-link": "Learn more",
|
||||
"sql-expressions-title": "SQL Expressions",
|
||||
"title-add-another-transformation": "Add another transformation",
|
||||
"view-all": "View all"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user