mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
27
public/app/core/components/Card/Card.tsx
Normal file
27
public/app/core/components/Card/Card.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
@@ -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};
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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>
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user