Transformations: UI tweaks, filter by name regex validation (#23800)

* Add validation to filter by name regex, minor layout tweaks

* Use cards uin for non configured transformations
This commit is contained in:
Dominik Prokop
2020-04-23 10:12:06 +02:00
committed by GitHub
parent 4b42697912
commit fe28e2a6b1
8 changed files with 198 additions and 63 deletions

View File

@@ -0,0 +1,27 @@
import React from 'react';
import { cx } from 'emotion';
export interface CardProps {
logoUrl?: string;
title: string;
description?: string;
actions?: React.ReactNode;
onClick?: () => void;
ariaLabel?: string;
className?: string;
}
export const Card: React.FC<CardProps> = ({ logoUrl, title, description, actions, onClick, ariaLabel, className }) => {
const mainClassName = cx('add-data-source-item', className);
return (
<div className={mainClassName} onClick={onClick} aria-label={ariaLabel}>
{logoUrl && <img className="add-data-source-item-logo" src={logoUrl} />}
<div className="add-data-source-item-text-wrapper">
<span className="add-data-source-item-text">{title}</span>
{description && <span className="add-data-source-item-desc">{description}</span>}
</div>
{actions && <div className="add-data-source-item-actions">{actions}</div>}
</div>
);
};

View File

@@ -1,13 +1,25 @@
import React from 'react';
import { Container, CustomScrollbar, ValuePicker } from '@grafana/ui';
import {
Container,
CustomScrollbar,
InfoBox,
ValuePicker,
Button,
useTheme,
VerticalGroup,
stylesFactory,
} from '@grafana/ui';
import {
DataFrame,
DataTransformerConfig,
GrafanaTheme,
SelectableValue,
standardTransformersRegistry,
transformDataFrame,
} from '@grafana/data';
import { TransformationOperationRow } from './TransformationOperationRow';
import { Card, CardProps } from '../../../../core/components/Card/Card';
import { css } from 'emotion';
interface Props {
onChange: (transformations: DataTransformerConfig[]) => void;
@@ -52,10 +64,10 @@ export class TransformationsEditor extends React.PureComponent<Props> {
return (
<ValuePicker
size="md"
variant="secondary"
label="Add transformation"
options={availableTransformers}
size="lg"
onChange={this.onTransformationAdd}
isFullWidth={false}
/>
@@ -109,17 +121,54 @@ export class TransformationsEditor extends React.PureComponent<Props> {
};
render() {
const hasTransformationsConfigured = this.props.transformations.length > 0;
return (
<CustomScrollbar autoHeightMin="100%">
<Container padding="md">
<p className="muted">
Transformations allow you to combine, re-order, hide and rename specific parts the the data set before being
visualized.
</p>
{this.renderTransformationEditors()}
{this.renderTransformationSelector()}
{!hasTransformationsConfigured && (
<InfoBox>
<p>
Transformations allow you to combine, re-order, hide and rename specific parts the the data set before
being visualized. Choose one of the transformations below to start with:
</p>
<VerticalGroup>
{standardTransformersRegistry.list().map(t => {
return (
<TransformationCard
title={t.name}
description={t.description}
actions={<Button>Select</Button>}
onClick={() => {
this.onTransformationAdd({ value: t.id });
}}
/>
);
})}
</VerticalGroup>
</InfoBox>
)}
{hasTransformationsConfigured && this.renderTransformationEditors()}
{hasTransformationsConfigured && this.renderTransformationSelector()}
</Container>
</CustomScrollbar>
);
}
}
const TransformationCard: React.FC<CardProps> = props => {
const theme = useTheme();
const styles = getTransformationCardStyles(theme);
return <Card {...props} className={styles.card} />;
};
const getTransformationCardStyles = stylesFactory((theme: GrafanaTheme) => {
return {
card: css`
background: ${theme.colors.bg2};
width: 100%;
&:hover {
background: ${theme.colors.bg3};
}
`,
};
});

View File

@@ -1,5 +1,4 @@
import React, { FC, PureComponent } from 'react';
import classNames from 'classnames';
import { connect } from 'react-redux';
import { hot } from 'react-hot-loader';
import { DataSourcePluginMeta, NavModel } from '@grafana/data';
@@ -12,6 +11,7 @@ import { addDataSource, loadDataSourcePlugins } from './state/actions';
import { getDataSourcePlugins } from './state/selectors';
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
import { setDataSourceTypeSearchQuery } from './state/reducers';
import { Card } from 'app/core/components/Card/Card';
export interface Props {
navModel: NavModel;
@@ -120,37 +120,33 @@ const DataSourceTypeCard: FC<DataSourceTypeCardProps> = props => {
// find first plugin info link
const learnMoreLink = plugin.info.links && plugin.info.links.length > 0 ? plugin.info.links[0] : null;
const mainClassName = classNames('add-data-source-item', {
'add-data-source-item--phantom': isPhantom,
});
return (
<div
className={mainClassName}
<Card
title={plugin.name}
description={plugin.info.description}
ariaLabel={e2e.pages.AddDataSource.selectors.dataSourcePlugins(plugin.name)}
logoUrl={plugin.info.logos.small}
actions={
<>
{learnMoreLink && (
<LinkButton
variant="secondary"
href={`${learnMoreLink.url}?utm_source=grafana_add_ds`}
target="_blank"
rel="noopener"
onClick={onLearnMoreClick}
icon="external-link-alt"
>
{learnMoreLink.name}
</LinkButton>
)}
{!isPhantom && <Button>Select</Button>}
</>
}
className={isPhantom && 'add-data-source-item--phantom'}
onClick={onClick}
aria-label={e2e.pages.AddDataSource.selectors.dataSourcePlugins(plugin.name)}
>
<img className="add-data-source-item-logo" src={plugin.info.logos.small} />
<div className="add-data-source-item-text-wrapper">
<span className="add-data-source-item-text">{plugin.name}</span>
{plugin.info.description && <span className="add-data-source-item-desc">{plugin.info.description}</span>}
</div>
<div className="add-data-source-item-actions">
{learnMoreLink && (
<LinkButton
variant="secondary"
href={`${learnMoreLink.url}?utm_source=grafana_add_ds`}
target="_blank"
rel="noopener"
onClick={onLearnMoreClick}
icon="external-link-alt"
>
{learnMoreLink.name}
</LinkButton>
)}
{!isPhantom && <Button>Select</Button>}
</div>
</div>
/>
);
};