Browse Source

Merge branch 'master' into page-layout-component

Torkel Ödegaard 7 years ago
parent
commit
bfadcd2968

+ 1 - 1
docs/sources/features/datasources/cloudwatch.md

@@ -38,7 +38,7 @@ Name | Description
 
 
 ### IAM Roles
 ### 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.
 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)
 Checkout AWS docs on [IAM Roles](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)

+ 24 - 0
packages/grafana-ui/src/components/FormField/FormField.test.tsx

@@ -0,0 +1,24 @@
+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();
+  });
+});

+ 25 - 0
packages/grafana-ui/src/components/FormField/FormField.tsx

@@ -0,0 +1,25 @@
+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 };

+ 12 - 0
packages/grafana-ui/src/components/FormField/_FormField.scss

@@ -0,0 +1,12 @@
+.form-field {
+  margin-bottom: $gf-form-margin;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  text-align: left;
+  position: relative;
+
+  &--grow {
+    flex-grow: 1;
+  }
+}

+ 19 - 0
packages/grafana-ui/src/components/FormField/__snapshots__/FormField.test.tsx.snap

@@ -0,0 +1,19 @@
+// 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>
+`;

+ 42 - 0
packages/grafana-ui/src/components/FormLabel/FormLabel.tsx

@@ -0,0 +1,42 @@
+import React, { FunctionComponent, ReactNode } from 'react';
+import classNames from 'classnames';
+import { Tooltip } from '..';
+
+interface Props {
+  children: ReactNode;
+  className?: string;
+  htmlFor?: string;
+  isFocused?: boolean;
+  isInvalid?: boolean;
+  tooltip?: string;
+  width?: number;
+}
+
+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,
+  });
+
+  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>
+  );
+};

+ 0 - 23
packages/grafana-ui/src/components/GfFormLabel/GfFormLabel.tsx

@@ -1,23 +0,0 @@
-import React, { SFC, ReactNode } from 'react';
-import classNames from 'classnames';
-
-interface Props {
-  children: ReactNode;
-  htmlFor?: string;
-  className?: string;
-  isFocused?: boolean;
-  isInvalid?: boolean;
-}
-
-export const GfFormLabel: SFC<Props> = ({ children, isFocused, isInvalid, className, htmlFor, ...rest }) => {
-  const classes = classNames('gf-form-label', className, {
-    'gf-form-label--is-focused': isFocused,
-    'gf-form-label--is-invalid': isInvalid,
-  });
-
-  return (
-    <label className={classes} {...rest} htmlFor={htmlFor}>
-      {children}
-    </label>
-  );
-};

+ 0 - 25
packages/grafana-ui/src/components/Label/Label.tsx

@@ -1,25 +0,0 @@
-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>
-  );
-};

+ 1 - 1
packages/grafana-ui/src/components/Select/Select.tsx

@@ -16,7 +16,7 @@ import SelectOptionGroup from './SelectOptionGroup';
 import IndicatorsContainer from './IndicatorsContainer';
 import IndicatorsContainer from './IndicatorsContainer';
 import NoOptionsMessage from './NoOptionsMessage';
 import NoOptionsMessage from './NoOptionsMessage';
 import resetSelectStyles from './resetSelectStyles';
 import resetSelectStyles from './resetSelectStyles';
-import { CustomScrollbar } from '@grafana/ui';
+import { CustomScrollbar } from '..';
 
 
 export interface SelectOptionItem {
 export interface SelectOptionItem {
   label?: string;
   label?: string;

+ 1 - 0
packages/grafana-ui/src/components/Select/_Select.scss

@@ -102,6 +102,7 @@ $select-input-bg-disabled: $input-bg-disabled;
 .gf-form-select-box__value-container {
 .gf-form-select-box__value-container {
   display: table-cell;
   display: table-cell;
   padding: 6px 10px;
   padding: 6px 10px;
+  vertical-align: middle;
   > div {
   > div {
     display: inline-block;
     display: inline-block;
   }
   }

+ 36 - 40
packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx

@@ -1,8 +1,7 @@
-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 {
 export interface Props {
   valueMapping: ValueMapping;
   valueMapping: ValueMapping;
@@ -32,19 +31,19 @@ export default class MappingRow extends PureComponent<Props, State> {
     this.state = { ...props.valueMapping };
     this.state = { ...props.valueMapping };
   }
   }
 
 
-  onMappingValueChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+  onMappingValueChange = (event: ChangeEvent<HTMLInputElement>) => {
     this.setState({ value: event.target.value });
     this.setState({ value: event.target.value });
   };
   };
 
 
-  onMappingFromChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+  onMappingFromChange = (event: ChangeEvent<HTMLInputElement>) => {
     this.setState({ from: event.target.value });
     this.setState({ from: event.target.value });
   };
   };
 
 
-  onMappingToChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+  onMappingToChange = (event: ChangeEvent<HTMLInputElement>) => {
     this.setState({ to: event.target.value });
     this.setState({ to: event.target.value });
   };
   };
 
 
-  onMappingTextChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+  onMappingTextChange = (event: ChangeEvent<HTMLInputElement>) => {
     this.setState({ text: event.target.value });
     this.setState({ text: event.target.value });
   };
   };
 
 
@@ -62,30 +61,28 @@ export default class MappingRow extends PureComponent<Props, State> {
     if (type === MappingType.RangeToText) {
     if (type === MappingType.RangeToText) {
       return (
       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
             <input
-              className="gf-form-input width-8"
-              value={to}
+              className="gf-form-input"
               onBlur={this.updateMapping}
               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}
               value={text}
-              onBlur={this.updateMapping}
               onChange={this.onMappingTextChange}
               onChange={this.onMappingTextChange}
             />
             />
           </div>
           </div>
@@ -95,17 +92,16 @@ export default class MappingRow extends PureComponent<Props, State> {
 
 
     return (
     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">
         <div className="gf-form gf-form--grow">
-          <Label width={4}>Text</Label>
+          <FormLabel width={4}>Text</FormLabel>
           <input
           <input
             className="gf-form-input"
             className="gf-form-input"
             onBlur={this.updateMapping}
             onBlur={this.updateMapping}
@@ -123,7 +119,7 @@ export default class MappingRow extends PureComponent<Props, State> {
     return (
     return (
       <div className="gf-form-inline">
       <div className="gf-form-inline">
         <div className="gf-form">
         <div className="gf-form">
-          <Label width={5}>Type</Label>
+          <FormLabel width={5}>Type</FormLabel>
           <Select
           <Select
             placeholder="Choose type"
             placeholder="Choose type"
             isSearchable={false}
             isSearchable={false}

+ 1 - 0
packages/grafana-ui/src/components/index.scss

@@ -7,3 +7,4 @@
 @import 'PanelOptionsGrid/PanelOptionsGrid';
 @import 'PanelOptionsGrid/PanelOptionsGrid';
 @import 'ColorPicker/ColorPicker';
 @import 'ColorPicker/ColorPicker';
 @import 'ValueMappingsEditor/ValueMappingsEditor';
 @import 'ValueMappingsEditor/ValueMappingsEditor';
+@import "FormField/FormField";

+ 4 - 2
packages/grafana-ui/src/components/index.ts

@@ -2,7 +2,6 @@ export { DeleteButton } from './DeleteButton/DeleteButton';
 export { Tooltip } from './Tooltip/Tooltip';
 export { Tooltip } from './Tooltip/Tooltip';
 export { Portal } from './Portal/Portal';
 export { Portal } from './Portal/Portal';
 export { CustomScrollbar } from './CustomScrollbar/CustomScrollbar';
 export { CustomScrollbar } from './CustomScrollbar/CustomScrollbar';
-export { Label } from './Label/Label';
 
 
 // Select
 // Select
 export { Select, AsyncSelect, SelectOptionItem } from './Select/Select';
 export { Select, AsyncSelect, SelectOptionItem } from './Select/Select';
@@ -10,12 +9,15 @@ export { IndicatorsContainer } from './Select/IndicatorsContainer';
 export { NoOptionsMessage } from './Select/NoOptionsMessage';
 export { NoOptionsMessage } from './Select/NoOptionsMessage';
 export { default as resetSelectStyles } from './Select/resetSelectStyles';
 export { default as resetSelectStyles } from './Select/resetSelectStyles';
 
 
+// Forms
+export { FormLabel } from './FormLabel/FormLabel';
+export { FormField } from './FormField/FormField';
+
 export { LoadingPlaceholder } from './LoadingPlaceholder/LoadingPlaceholder';
 export { LoadingPlaceholder } from './LoadingPlaceholder/LoadingPlaceholder';
 export { ColorPicker } from './ColorPicker/ColorPicker';
 export { ColorPicker } from './ColorPicker/ColorPicker';
 export { SeriesColorPickerPopover } from './ColorPicker/SeriesColorPickerPopover';
 export { SeriesColorPickerPopover } from './ColorPicker/SeriesColorPickerPopover';
 export { SeriesColorPicker } from './ColorPicker/SeriesColorPicker';
 export { SeriesColorPicker } from './ColorPicker/SeriesColorPicker';
 export { ThresholdsEditor } from './ThresholdsEditor/ThresholdsEditor';
 export { ThresholdsEditor } from './ThresholdsEditor/ThresholdsEditor';
-export { GfFormLabel } from './GfFormLabel/GfFormLabel';
 export { Graph } from './Graph/Graph';
 export { Graph } from './Graph/Graph';
 export { PanelOptionsGroup } from './PanelOptionsGroup/PanelOptionsGroup';
 export { PanelOptionsGroup } from './PanelOptionsGroup/PanelOptionsGroup';
 export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid';
 export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid';

+ 3 - 3
public/app/core/components/SharedPreferences/SharedPreferences.tsx

@@ -1,6 +1,6 @@
 import React, { PureComponent } from 'react';
 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 { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv';
 
 
 import { DashboardSearchHit } from 'app/types';
 import { DashboardSearchHit } from 'app/types';
@@ -99,12 +99,12 @@ export class SharedPreferences extends PureComponent<Props, State> {
           />
           />
         </div>
         </div>
         <div className="gf-form">
         <div className="gf-form">
-          <Label
+          <FormLabel
             width={11}
             width={11}
             tooltip="Not finding dashboard you want? Star it first, then it should appear in this select box."
             tooltip="Not finding dashboard you want? Star it first, then it should appear in this select box."
           >
           >
             Home Dashboard
             Home Dashboard
-          </Label>
+          </FormLabel>
           <Select
           <Select
             value={dashboards.find(dashboard => dashboard.id === homeDashboardId)}
             value={dashboards.find(dashboard => dashboard.id === homeDashboardId)}
             getOptionValue={i => i.id}
             getOptionValue={i => i.id}

+ 2 - 2
public/app/features/dashboard/panel_editor/QueryOptions.tsx

@@ -10,7 +10,7 @@ import { Input } from 'app/core/components/Form';
 import { EventsWithValidation } from 'app/core/components/Form/Input';
 import { EventsWithValidation } from 'app/core/components/Form/Input';
 import { InputStatus } from 'app/core/components/Form/Input';
 import { InputStatus } from 'app/core/components/Form/Input';
 import DataSourceOption from './DataSourceOption';
 import DataSourceOption from './DataSourceOption';
-import { GfFormLabel } from '@grafana/ui';
+import { FormLabel } from '@grafana/ui';
 
 
 // Types
 // Types
 import { PanelModel } from '../panel_model';
 import { PanelModel } from '../panel_model';
@@ -164,7 +164,7 @@ export class QueryOptions extends PureComponent<Props, State> {
         {this.renderOptions()}
         {this.renderOptions()}
 
 
         <div className="gf-form">
         <div className="gf-form">
-          <GfFormLabel>Relative time</GfFormLabel>
+          <FormLabel>Relative time</FormLabel>
           <Input
           <Input
             type="text"
             type="text"
             className="width-6"
             className="width-6"

+ 3 - 4
public/app/features/datasources/settings/BasicSettings.tsx

@@ -1,6 +1,5 @@
 import React, { FC } from 'react';
 import React, { FC } from 'react';
-import { Label } from '@grafana/ui';
-
+import { FormLabel } from '@grafana/ui';
 import { Switch } from '../../../core/components/Switch/Switch';
 import { Switch } from '../../../core/components/Switch/Switch';
 
 
 export interface Props {
 export interface Props {
@@ -15,14 +14,14 @@ const BasicSettings: FC<Props> = ({ dataSourceName, isDefault, onDefaultChange,
     <div className="gf-form-group">
     <div className="gf-form-group">
       <div className="gf-form-inline">
       <div className="gf-form-inline">
         <div className="gf-form max-width-30" style={{ marginRight: '3px' }}>
         <div className="gf-form max-width-30" style={{ marginRight: '3px' }}>
-          <Label
+          <FormLabel
             tooltip={
             tooltip={
               'The name is used when you select the data source in panels. The Default data source is ' +
               'The name is used when you select the data source in panels. The Default data source is ' +
               'preselected in new panels.'
               'preselected in new panels.'
             }
             }
           >
           >
             Name
             Name
-          </Label>
+          </FormLabel>
           <input
           <input
             className="gf-form-input max-width-23"
             className="gf-form-input max-width-23"
             type="text"
             type="text"

+ 4 - 4
public/app/features/teams/TeamSettings.tsx

@@ -1,6 +1,6 @@
 import React from 'react';
 import React from 'react';
 import { connect } from 'react-redux';
 import { connect } from 'react-redux';
-import { Label } from '@grafana/ui';
+import { FormLabel } from '@grafana/ui';
 
 
 import { SharedPreferences } from 'app/core/components/SharedPreferences/SharedPreferences';
 import { SharedPreferences } from 'app/core/components/SharedPreferences/SharedPreferences';
 import { updateTeam } from './state/actions';
 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>
         <h3 className="page-sub-heading">Team Settings</h3>
         <form name="teamDetailsForm" className="gf-form-group" onSubmit={this.onUpdate}>
         <form name="teamDetailsForm" className="gf-form-group" onSubmit={this.onUpdate}>
           <div className="gf-form max-width-30">
           <div className="gf-form max-width-30">
-            <Label>Name</Label>
+            <FormLabel>Name</FormLabel>
             <input
             <input
               type="text"
               type="text"
               required
               required
@@ -62,9 +62,9 @@ export class TeamSettings extends React.Component<Props, State> {
           </div>
           </div>
 
 
           <div className="gf-form max-width-30">
           <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
               Email
-            </Label>
+            </FormLabel>
             <input
             <input
               type="email"
               type="email"
               className="gf-form-input max-width-22"
               className="gf-form-input max-width-22"

+ 3 - 9
public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx

@@ -1,5 +1,5 @@
 import React, { PureComponent } from 'react';
 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 { Switch } from 'app/core/components/Switch/Switch';
 import { GaugeOptions } from './types';
 import { GaugeOptions } from './types';
@@ -21,14 +21,8 @@ export default class GaugeOptionsEditor extends PureComponent<PanelOptionsProps<
 
 
     return (
     return (
       <PanelOptionsGroup title="Gauge">
       <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
         <Switch
           label="Show labels"
           label="Show labels"
           labelClass="width-8"
           labelClass="width-8"

+ 13 - 22
public/app/plugins/panel/gauge/ValueOptions.tsx

@@ -1,6 +1,5 @@
 import React, { PureComponent } from 'react';
 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 UnitPicker from 'app/core/components/Select/UnitPicker';
 import { GaugeOptions } from './types';
 import { GaugeOptions } from './types';
 
 
@@ -41,7 +40,7 @@ export default class ValueOptions extends PureComponent<PanelOptionsProps<GaugeO
     return (
     return (
       <PanelOptionsGroup title="Value">
       <PanelOptionsGroup title="Value">
         <div className="gf-form">
         <div className="gf-form">
-          <Label width={labelWidth}>Stat</Label>
+          <FormLabel width={labelWidth}>Stat</FormLabel>
           <Select
           <Select
             width={12}
             width={12}
             options={statOptions}
             options={statOptions}
@@ -50,27 +49,19 @@ export default class ValueOptions extends PureComponent<PanelOptionsProps<GaugeO
           />
           />
         </div>
         </div>
         <div className="gf-form">
         <div className="gf-form">
-          <Label width={labelWidth}>Unit</Label>
+          <FormLabel width={labelWidth}>Unit</FormLabel>
           <UnitPicker defaultValue={unit} onChange={this.onUnitChange} />
           <UnitPicker defaultValue={unit} onChange={this.onUnitChange} />
         </div>
         </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>
       </PanelOptionsGroup>
     );
     );
   }
   }

+ 3 - 3
scripts/build/ci-deploy/Dockerfile

@@ -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
 FROM circleci/python:2.7-stretch
 
 
-ENV PATH=$PATH:/opt/google-cloud-sdk/bin
-
 USER root
 USER root
 
 
 RUN pip install awscli && \
 RUN pip install awscli && \
@@ -18,7 +16,9 @@ RUN pip install awscli && \
     apt update && \
     apt update && \
     apt install -y createrepo expect && \
     apt install -y createrepo expect && \
     apt-get autoremove -y && \
     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
 COPY --from=0 /go/bin/aptly /usr/local/bin/aptly
 
 

+ 1 - 1
scripts/build/ci-deploy/build-deploy.sh

@@ -1,6 +1,6 @@
 #!/bin/bash
 #!/bin/bash
 
 
-_version="1.1.0"
+_version="1.2.0"
 _tag="grafana/grafana-ci-deploy:${_version}"
 _tag="grafana/grafana-ci-deploy:${_version}"
 
 
 docker build -t $_tag .
 docker build -t $_tag .