Commit bfadcd29 by Torkel Ödegaard Committed by GitHub

Merge branch 'master' into page-layout-component

parents 1dfabf49 9ecfc39b
......@@ -38,7 +38,7 @@ Name | Description
### IAM Roles
Currently all access to CloudWatch is done server side by the Grafana backend using the official AWS SDK. If you grafana
Currently all access to CloudWatch is done server side by the Grafana backend using the official AWS SDK. If your Grafana
server is running on AWS you can use IAM Roles and authentication will be handled automatically.
Checkout AWS docs on [IAM Roles](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)
......
import React from 'react';
import { shallow } from 'enzyme';
import { FormField, Props } from './FormField';
const setup = (propOverrides?: object) => {
const props: Props = {
label: 'Test',
labelWidth: 11,
value: 10,
onChange: jest.fn(),
};
Object.assign(props, propOverrides);
return shallow(<FormField {...props} />);
};
describe('Render', () => {
it('should render component', () => {
const wrapper = setup();
expect(wrapper).toMatchSnapshot();
});
});
import React, { InputHTMLAttributes, FunctionComponent } from 'react';
import { FormLabel } from '..';
export interface Props extends InputHTMLAttributes<HTMLInputElement> {
label: string;
labelWidth?: number;
inputWidth?: number;
}
const defaultProps = {
labelWidth: 6,
inputWidth: 12,
};
const FormField: FunctionComponent<Props> = ({ label, labelWidth, inputWidth, ...inputProps }) => {
return (
<div className="form-field">
<FormLabel width={labelWidth}>{label}</FormLabel>
<input type="text" className={`gf-form-input width-${inputWidth}`} {...inputProps} />
</div>
);
};
FormField.defaultProps = defaultProps;
export { FormField };
.form-field {
margin-bottom: $gf-form-margin;
display: flex;
flex-direction: row;
align-items: center;
text-align: left;
position: relative;
&--grow {
flex-grow: 1;
}
}
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Render should render component 1`] = `
<div
className="form-field"
>
<Component
width={11}
>
Test
</Component>
<input
className="gf-form-input width-12"
onChange={[MockFunction]}
type="text"
value={10}
/>
</div>
`;
import React, { SFC, ReactNode } from 'react';
import React, { FunctionComponent, ReactNode } from 'react';
import classNames from 'classnames';
import { Tooltip } from '..';
interface Props {
children: ReactNode;
htmlFor?: string;
className?: string;
htmlFor?: string;
isFocused?: boolean;
isInvalid?: boolean;
tooltip?: string;
width?: number;
}
export const GfFormLabel: SFC<Props> = ({ children, isFocused, isInvalid, className, htmlFor, ...rest }) => {
const classes = classNames('gf-form-label', className, {
export const FormLabel: FunctionComponent<Props> = ({
children,
isFocused,
isInvalid,
className,
htmlFor,
tooltip,
width,
...rest
}) => {
const classes = classNames(`gf-form-label width-${width ? width : '10'}`, className, {
'gf-form-label--is-focused': isFocused,
'gf-form-label--is-invalid': isInvalid,
});
......@@ -18,6 +30,13 @@ export const GfFormLabel: SFC<Props> = ({ children, isFocused, isInvalid, classN
return (
<label className={classes} {...rest} htmlFor={htmlFor}>
{children}
{tooltip && (
<Tooltip placement="auto" content={tooltip}>
<div className="gf-form-help-icon--right-normal">
<i className="gicon gicon-question gicon--has-hover" />
</div>
</Tooltip>
)}
</label>
);
};
import React, { SFC, ReactNode } from 'react';
import { Tooltip } from '../Tooltip/Tooltip';
interface Props {
tooltip?: string;
for?: string;
children: ReactNode;
width?: number;
className?: string;
}
export const Label: SFC<Props> = props => {
return (
<span className={`gf-form-label width-${props.width ? props.width : '10'}`}>
<span>{props.children}</span>
{props.tooltip && (
<Tooltip placement="auto" content={props.tooltip}>
<div className="gf-form-help-icon--right-normal">
<i className="gicon gicon-question gicon--has-hover" />
</div>
</Tooltip>
)}
</span>
);
};
......@@ -16,7 +16,7 @@ import SelectOptionGroup from './SelectOptionGroup';
import IndicatorsContainer from './IndicatorsContainer';
import NoOptionsMessage from './NoOptionsMessage';
import resetSelectStyles from './resetSelectStyles';
import { CustomScrollbar } from '@grafana/ui';
import { CustomScrollbar } from '..';
export interface SelectOptionItem {
label?: string;
......
......@@ -102,6 +102,7 @@ $select-input-bg-disabled: $input-bg-disabled;
.gf-form-select-box__value-container {
display: table-cell;
padding: 6px 10px;
vertical-align: middle;
> div {
display: inline-block;
}
......
import React, { PureComponent } from 'react';
import React, { ChangeEvent, PureComponent } from 'react';
import { MappingType, ValueMapping } from '../../types/panel';
import { Label } from '../Label/Label';
import { Select } from '../Select/Select';
import { MappingType, ValueMapping } from '../../types';
import { FormField, FormLabel, Select } from '..';
export interface Props {
valueMapping: ValueMapping;
......@@ -32,19 +31,19 @@ export default class MappingRow extends PureComponent<Props, State> {
this.state = { ...props.valueMapping };
}
onMappingValueChange = (event: React.ChangeEvent<HTMLInputElement>) => {
onMappingValueChange = (event: ChangeEvent<HTMLInputElement>) => {
this.setState({ value: event.target.value });
};
onMappingFromChange = (event: React.ChangeEvent<HTMLInputElement>) => {
onMappingFromChange = (event: ChangeEvent<HTMLInputElement>) => {
this.setState({ from: event.target.value });
};
onMappingToChange = (event: React.ChangeEvent<HTMLInputElement>) => {
onMappingToChange = (event: ChangeEvent<HTMLInputElement>) => {
this.setState({ to: event.target.value });
};
onMappingTextChange = (event: React.ChangeEvent<HTMLInputElement>) => {
onMappingTextChange = (event: ChangeEvent<HTMLInputElement>) => {
this.setState({ text: event.target.value });
};
......@@ -62,30 +61,28 @@ export default class MappingRow extends PureComponent<Props, State> {
if (type === MappingType.RangeToText) {
return (
<>
<div className="gf-form">
<Label width={4}>From</Label>
<input
className="gf-form-input width-8"
value={from}
onBlur={this.updateMapping}
onChange={this.onMappingFromChange}
/>
</div>
<div className="gf-form">
<Label width={4}>To</Label>
<FormField
label="From"
labelWidth={4}
inputWidth={8}
onBlur={this.updateMapping}
onChange={this.onMappingFromChange}
value={from}
/>
<FormField
label="To"
labelWidth={4}
inputWidth={8}
onBlur={this.updateMapping}
onChange={this.onMappingToChange}
value={to}
/>
<div className="gf-form gf-form--grow">
<FormLabel width={4}>Text</FormLabel>
<input
className="gf-form-input width-8"
value={to}
className="gf-form-input"
onBlur={this.updateMapping}
onChange={this.onMappingToChange}
/>
</div>
<div className="gf-form">
<Label width={4}>Text</Label>
<input
className="gf-form-input width-10"
value={text}
onBlur={this.updateMapping}
onChange={this.onMappingTextChange}
/>
</div>
......@@ -95,17 +92,16 @@ export default class MappingRow extends PureComponent<Props, State> {
return (
<>
<div className="gf-form">
<Label width={4}>Value</Label>
<input
className="gf-form-input width-8"
onBlur={this.updateMapping}
onChange={this.onMappingValueChange}
value={value}
/>
</div>
<FormField
label="Value"
labelWidth={4}
onBlur={this.updateMapping}
onChange={this.onMappingValueChange}
value={value}
inputWidth={8}
/>
<div className="gf-form gf-form--grow">
<Label width={4}>Text</Label>
<FormLabel width={4}>Text</FormLabel>
<input
className="gf-form-input"
onBlur={this.updateMapping}
......@@ -123,7 +119,7 @@ export default class MappingRow extends PureComponent<Props, State> {
return (
<div className="gf-form-inline">
<div className="gf-form">
<Label width={5}>Type</Label>
<FormLabel width={5}>Type</FormLabel>
<Select
placeholder="Choose type"
isSearchable={false}
......
......@@ -7,3 +7,4 @@
@import 'PanelOptionsGrid/PanelOptionsGrid';
@import 'ColorPicker/ColorPicker';
@import 'ValueMappingsEditor/ValueMappingsEditor';
@import "FormField/FormField";
......@@ -2,7 +2,6 @@ export { DeleteButton } from './DeleteButton/DeleteButton';
export { Tooltip } from './Tooltip/Tooltip';
export { Portal } from './Portal/Portal';
export { CustomScrollbar } from './CustomScrollbar/CustomScrollbar';
export { Label } from './Label/Label';
// Select
export { Select, AsyncSelect, SelectOptionItem } from './Select/Select';
......@@ -10,12 +9,15 @@ export { IndicatorsContainer } from './Select/IndicatorsContainer';
export { NoOptionsMessage } from './Select/NoOptionsMessage';
export { default as resetSelectStyles } from './Select/resetSelectStyles';
// Forms
export { FormLabel } from './FormLabel/FormLabel';
export { FormField } from './FormField/FormField';
export { LoadingPlaceholder } from './LoadingPlaceholder/LoadingPlaceholder';
export { ColorPicker } from './ColorPicker/ColorPicker';
export { SeriesColorPickerPopover } from './ColorPicker/SeriesColorPickerPopover';
export { SeriesColorPicker } from './ColorPicker/SeriesColorPicker';
export { ThresholdsEditor } from './ThresholdsEditor/ThresholdsEditor';
export { GfFormLabel } from './GfFormLabel/GfFormLabel';
export { Graph } from './Graph/Graph';
export { PanelOptionsGroup } from './PanelOptionsGroup/PanelOptionsGroup';
export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid';
......
import React, { PureComponent } from 'react';
import { Select, Label } from '@grafana/ui';
import { FormLabel, Select } from '@grafana/ui';
import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv';
import { DashboardSearchHit } from 'app/types';
......@@ -99,12 +99,12 @@ export class SharedPreferences extends PureComponent<Props, State> {
/>
</div>
<div className="gf-form">
<Label
<FormLabel
width={11}
tooltip="Not finding dashboard you want? Star it first, then it should appear in this select box."
>
Home Dashboard
</Label>
</FormLabel>
<Select
value={dashboards.find(dashboard => dashboard.id === homeDashboardId)}
getOptionValue={i => i.id}
......
......@@ -10,7 +10,7 @@ import { Input } from 'app/core/components/Form';
import { EventsWithValidation } from 'app/core/components/Form/Input';
import { InputStatus } from 'app/core/components/Form/Input';
import DataSourceOption from './DataSourceOption';
import { GfFormLabel } from '@grafana/ui';
import { FormLabel } from '@grafana/ui';
// Types
import { PanelModel } from '../panel_model';
......@@ -164,7 +164,7 @@ export class QueryOptions extends PureComponent<Props, State> {
{this.renderOptions()}
<div className="gf-form">
<GfFormLabel>Relative time</GfFormLabel>
<FormLabel>Relative time</FormLabel>
<Input
type="text"
className="width-6"
......
import React, { FC } from 'react';
import { Label } from '@grafana/ui';
import { FormLabel } from '@grafana/ui';
import { Switch } from '../../../core/components/Switch/Switch';
export interface Props {
......@@ -15,14 +14,14 @@ const BasicSettings: FC<Props> = ({ dataSourceName, isDefault, onDefaultChange,
<div className="gf-form-group">
<div className="gf-form-inline">
<div className="gf-form max-width-30" style={{ marginRight: '3px' }}>
<Label
<FormLabel
tooltip={
'The name is used when you select the data source in panels. The Default data source is ' +
'preselected in new panels.'
}
>
Name
</Label>
</FormLabel>
<input
className="gf-form-input max-width-23"
type="text"
......
import React from 'react';
import { connect } from 'react-redux';
import { Label } from '@grafana/ui';
import { FormLabel } from '@grafana/ui';
import { SharedPreferences } from 'app/core/components/SharedPreferences/SharedPreferences';
import { updateTeam } from './state/actions';
......@@ -51,7 +51,7 @@ export class TeamSettings extends React.Component<Props, State> {
<h3 className="page-sub-heading">Team Settings</h3>
<form name="teamDetailsForm" className="gf-form-group" onSubmit={this.onUpdate}>
<div className="gf-form max-width-30">
<Label>Name</Label>
<FormLabel>Name</FormLabel>
<input
type="text"
required
......@@ -62,9 +62,9 @@ export class TeamSettings extends React.Component<Props, State> {
</div>
<div className="gf-form max-width-30">
<Label tooltip="This is optional and is primarily used to set the team profile avatar (via gravatar service)">
<FormLabel tooltip="This is optional and is primarily used to set the team profile avatar (via gravatar service)">
Email
</Label>
</FormLabel>
<input
type="email"
className="gf-form-input max-width-22"
......
import React, { PureComponent } from 'react';
import { PanelOptionsProps, PanelOptionsGroup, Label } from '@grafana/ui';
import { FormField, PanelOptionsProps, PanelOptionsGroup } from '@grafana/ui';
import { Switch } from 'app/core/components/Switch/Switch';
import { GaugeOptions } from './types';
......@@ -21,14 +21,8 @@ export default class GaugeOptionsEditor extends PureComponent<PanelOptionsProps<
return (
<PanelOptionsGroup title="Gauge">
<div className="gf-form">
<Label width={8}>Min value</Label>
<input type="text" className="gf-form-input width-12" onChange={this.onMinValueChange} value={minValue} />
</div>
<div className="gf-form">
<Label width={8}>Max value</Label>
<input type="text" className="gf-form-input width-12" onChange={this.onMaxValueChange} value={maxValue} />
</div>
<FormField label="Min value" labelWidth={8} onChange={this.onMinValueChange} value={minValue} />
<FormField label="Max value" labelWidth={8} onChange={this.onMaxValueChange} value={maxValue} />
<Switch
label="Show labels"
labelClass="width-8"
......
import React, { PureComponent } from 'react';
import { PanelOptionsProps, PanelOptionsGroup, Label, Select } from '@grafana/ui';
import { FormField, FormLabel, PanelOptionsProps, PanelOptionsGroup, Select } from '@grafana/ui';
import UnitPicker from 'app/core/components/Select/UnitPicker';
import { GaugeOptions } from './types';
......@@ -41,7 +40,7 @@ export default class ValueOptions extends PureComponent<PanelOptionsProps<GaugeO
return (
<PanelOptionsGroup title="Value">
<div className="gf-form">
<Label width={labelWidth}>Stat</Label>
<FormLabel width={labelWidth}>Stat</FormLabel>
<Select
width={12}
options={statOptions}
......@@ -50,27 +49,19 @@ export default class ValueOptions extends PureComponent<PanelOptionsProps<GaugeO
/>
</div>
<div className="gf-form">
<Label width={labelWidth}>Unit</Label>
<FormLabel width={labelWidth}>Unit</FormLabel>
<UnitPicker defaultValue={unit} onChange={this.onUnitChange} />
</div>
<div className="gf-form">
<Label width={labelWidth}>Decimals</Label>
<input
className="gf-form-input width-12"
type="number"
placeholder="auto"
value={decimals || ''}
onChange={this.onDecimalChange}
/>
</div>
<div className="gf-form">
<Label width={labelWidth}>Prefix</Label>
<input className="gf-form-input width-12" type="text" value={prefix || ''} onChange={this.onPrefixChange} />
</div>
<div className="gf-form">
<Label width={labelWidth}>Suffix</Label>
<input className="gf-form-input width-12" type="text" value={suffix || ''} onChange={this.onSuffixChange} />
</div>
<FormField
label="Decimals"
labelWidth={labelWidth}
placeholder="auto"
onChange={this.onDecimalChange}
value={decimals || ''}
type="number"
/>
<FormField label="Prefix" labelWidth={labelWidth} onChange={this.onPrefixChange} value={prefix || ''} />
<FormField label="Suffix" labelWidth={labelWidth} onChange={this.onSuffixChange} value={suffix || ''} />
</PanelOptionsGroup>
);
}
......
......@@ -8,8 +8,6 @@ RUN git clone https://github.com/aptly-dev/aptly $GOPATH/src/github.com/aptly-de
FROM circleci/python:2.7-stretch
ENV PATH=$PATH:/opt/google-cloud-sdk/bin
USER root
RUN pip install awscli && \
......@@ -18,7 +16,9 @@ RUN pip install awscli && \
apt update && \
apt install -y createrepo expect && \
apt-get autoremove -y && \
rm -rf /var/lib/apt/lists/*
rm -rf /var/lib/apt/lists/* && \
ln -s /opt/google-cloud-sdk/bin/gsutil /usr/bin/gsutil && \
ln -s /opt/google-cloud-sdk/bin/gcloud /usr/bin/gcloud
COPY --from=0 /go/bin/aptly /usr/local/bin/aptly
......
#!/bin/bash
_version="1.1.0"
_version="1.2.0"
_tag="grafana/grafana-ci-deploy:${_version}"
docker build -t $_tag .
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment