mirror of https://github.com/grafana/grafana.git
				
				
				
			Buttons: replace usage of .btn classnames (#33226)
* refactor(loginpage): migrate custom button styles to use Button component * refactor(certificationkey): prefer grafana-ui form elements over html elements and classnames * refactor(axisselector): prefer grafana-ui Button component over html button element * refactor(input-datasource): replace use of btn class with grafana-ui components * chore(grafana-ui): delete deprecated ToggleButtonGroup component * refactor: replace btn and cta-form__close class usage with IconButton * chore(closebutton): post master merge use v2 theme * refactor(permissionlist): remove usage of .btn classname * Wip * docs(styling): update styling and theme docs import paths * refactor(alerting): remote btn classnames from TestRuleResult * refactor(apikeys): prefer grafana-ui Button components over btn classNames * refactor(folders): prefer grafana-ui Button components over btn classNames * refactor(teams): prefer grafana-ui Button components over btn classNames * refactor(datasources): prefer grafana-ui Button components over btn classNames * refactor: prefer grafana-ui Button components over btn classNames * Minor style tweak to service buttons * test: update snapshots related to button changes * chore(input-datasource): remove unused import declaration * refactor(loginservicebuttons): rename theme.palette to theme.colors Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
		
							parent
							
								
									6034bf37c6
								
							
						
					
					
						commit
						c809d63065
					
				| 
						 | 
				
			
			@ -10,7 +10,7 @@ For styling components, use [Emotion's `css` function](https://emotion.sh/docs/e
 | 
			
		|||
 | 
			
		||||
```tsx
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { css } from 'emotion';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
 | 
			
		||||
const ComponentA = () => (
 | 
			
		||||
  <div
 | 
			
		||||
| 
						 | 
				
			
			@ -33,14 +33,13 @@ To access the theme in your styles, use the `useStyles` hook. It provides basic
 | 
			
		|||
import React, { FC } from 'react';
 | 
			
		||||
import { GrafanaTheme } from '@grafana/data';
 | 
			
		||||
import { useStyles } from '@grafana/ui';
 | 
			
		||||
import { css } from 'emotion';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
 | 
			
		||||
const Foo: FC<FooProps> = () => {
 | 
			
		||||
  const styles = useStyles(getStyles);
 | 
			
		||||
 | 
			
		||||
  // Use styles with classNames
 | 
			
		||||
  return <div className={styles}>...</div>
 | 
			
		||||
 | 
			
		||||
  return <div className={styles}>...</div>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getStyles = (theme: GrafanaTheme) => css`
 | 
			
		||||
| 
						 | 
				
			
			@ -56,12 +55,12 @@ Let's say you need to style a component that has a different background dependin
 | 
			
		|||
 | 
			
		||||
```tsx
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { css } from 'emotion';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { GrafanaTheme } from '@grafana/data';
 | 
			
		||||
import { selectThemeVariant, stylesFactory, useTheme } from '@grafana/ui';
 | 
			
		||||
 | 
			
		||||
interface ComponentAProps {
 | 
			
		||||
  isActive: boolean
 | 
			
		||||
  isActive: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ComponentA: React.FC<ComponentAProps> = ({ isActive }) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +75,6 @@ const ComponentA: React.FC<ComponentAProps> = ({isActive}) => {
 | 
			
		|||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Mind, that you can pass multiple arguments, theme included
 | 
			
		||||
const getStyles = stylesFactory((theme: GrafanaTheme, isActive: boolean) => {
 | 
			
		||||
  const backgroundColor = isActive ? theme.colors.red : theme.colors.blue;
 | 
			
		||||
| 
						 | 
				
			
			@ -100,7 +98,7 @@ For class composition, use [Emotion's `cx` function](https://emotion.sh/docs/emo
 | 
			
		|||
 | 
			
		||||
```tsx
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { css, cx } from 'emotion';
 | 
			
		||||
import { css, cx } from '@emotion/css';
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  className?: string;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ Here's how to use Grafana themes in React components.
 | 
			
		|||
import React, { FC } from 'react';
 | 
			
		||||
import { GrafanaTheme } from '@grafana/data';
 | 
			
		||||
import { useStyles } from '@grafana/ui';
 | 
			
		||||
import { css } from 'emotion';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
 | 
			
		||||
const getComponentStyles = (theme: GrafanaTheme) => css`
 | 
			
		||||
  padding: ${theme.spacing.md};
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +57,7 @@ const Foo: FC<FooProps> = () => {
 | 
			
		|||
```tsx
 | 
			
		||||
import { ThemeContext } from '@grafana/ui';
 | 
			
		||||
 | 
			
		||||
<ThemeContext.Consumer>{theme => <Foo theme={theme} />}</ThemeContext.Consumer>;
 | 
			
		||||
<ThemeContext.Consumer>{(theme) => <Foo theme={theme} />}</ThemeContext.Consumer>;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Using `withTheme` higher-order component (HOC)
 | 
			
		||||
| 
						 | 
				
			
			@ -97,9 +97,8 @@ describe('MyComponent', () => {
 | 
			
		|||
    restoreThemeContext();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  it('renders correctly', () => {
 | 
			
		||||
    const wrapper = mount(<MyComponent />)
 | 
			
		||||
    const wrapper = mount(<MyComponent />);
 | 
			
		||||
    expect(wrapper).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ import { PopoverContentProps } from '../Tooltip/Tooltip';
 | 
			
		|||
import { Switch } from '../Forms/Legacy/Switch/Switch';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { withTheme, useStyles } from '../../themes';
 | 
			
		||||
import { Button } from '../Button';
 | 
			
		||||
 | 
			
		||||
export interface SeriesColorPickerPopoverProps extends ColorPickerProps, PopoverContentProps {
 | 
			
		||||
  yaxis?: number;
 | 
			
		||||
| 
						 | 
				
			
			@ -70,18 +71,18 @@ export class AxisSelector extends React.PureComponent<AxisSelectorProps, AxisSel
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  render() {
 | 
			
		||||
    const leftButtonClass = this.state.yaxis === 1 ? 'btn-primary' : 'btn-inverse';
 | 
			
		||||
    const rightButtonClass = this.state.yaxis === 2 ? 'btn-primary' : 'btn-inverse';
 | 
			
		||||
    const leftButtonVariant = this.state.yaxis === 1 ? 'primary' : 'secondary';
 | 
			
		||||
    const rightButtonVariant = this.state.yaxis === 2 ? 'primary' : 'secondary';
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div className="p-b-1">
 | 
			
		||||
        <label className="small p-r-1">Y Axis:</label>
 | 
			
		||||
        <button onClick={this.onToggleAxis} className={'btn btn-small ' + leftButtonClass}>
 | 
			
		||||
        <Button onClick={this.onToggleAxis} size="sm" variant={leftButtonVariant}>
 | 
			
		||||
          Left
 | 
			
		||||
        </button>
 | 
			
		||||
        <button onClick={this.onToggleAxis} className={'btn btn-small ' + rightButtonClass}>
 | 
			
		||||
        </Button>
 | 
			
		||||
        <Button onClick={this.onToggleAxis} size="sm" variant={rightButtonVariant}>
 | 
			
		||||
          Right
 | 
			
		||||
        </button>
 | 
			
		||||
        </Button>
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,8 @@
 | 
			
		|||
import React, { ChangeEvent, MouseEvent, FC } from 'react';
 | 
			
		||||
import { Input } from '../Input/Input';
 | 
			
		||||
import { Button } from '../Button';
 | 
			
		||||
import { TextArea } from '../TextArea/TextArea';
 | 
			
		||||
import { InlineField } from '../Forms/InlineField';
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  label: string;
 | 
			
		||||
| 
						 | 
				
			
			@ -6,35 +10,22 @@ interface Props {
 | 
			
		|||
  placeholder: string;
 | 
			
		||||
 | 
			
		||||
  onChange: (event: ChangeEvent<HTMLTextAreaElement>) => void;
 | 
			
		||||
  onClick: (event: MouseEvent<HTMLAnchorElement>) => void;
 | 
			
		||||
  onClick: (event: MouseEvent<HTMLButtonElement>) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const CertificationKey: FC<Props> = ({ hasCert, label, onChange, onClick, placeholder }) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="gf-form-inline">
 | 
			
		||||
      <div className="gf-form gf-form--v-stretch">
 | 
			
		||||
        <label className="gf-form-label width-7">{label}</label>
 | 
			
		||||
      </div>
 | 
			
		||||
      {!hasCert && (
 | 
			
		||||
        <div className="gf-form gf-form--grow">
 | 
			
		||||
          <textarea
 | 
			
		||||
            rows={7}
 | 
			
		||||
            className="gf-form-input gf-form-textarea"
 | 
			
		||||
            onChange={onChange}
 | 
			
		||||
            placeholder={placeholder}
 | 
			
		||||
            required
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
    <InlineField label={label} labelWidth={14}>
 | 
			
		||||
      {hasCert ? (
 | 
			
		||||
        <>
 | 
			
		||||
          <Input type="text" disabled value="configured" width={24} />
 | 
			
		||||
          <Button variant="secondary" onClick={onClick} style={{ marginLeft: 4 }}>
 | 
			
		||||
            Reset
 | 
			
		||||
          </Button>
 | 
			
		||||
        </>
 | 
			
		||||
      ) : (
 | 
			
		||||
        <TextArea rows={7} onChange={onChange} placeholder={placeholder} required />
 | 
			
		||||
      )}
 | 
			
		||||
 | 
			
		||||
      {hasCert && (
 | 
			
		||||
        <div className="gf-form">
 | 
			
		||||
          <input type="text" className="gf-form-input max-width-12" disabled value="configured" />
 | 
			
		||||
          <a className="btn btn-secondary gf-form-btn" onClick={onClick}>
 | 
			
		||||
            reset
 | 
			
		||||
          </a>
 | 
			
		||||
        </div>
 | 
			
		||||
      )}
 | 
			
		||||
    </div>
 | 
			
		||||
    </InlineField>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ export const TLSAuthSettings: React.FC<HttpSettingsBaseProps> = ({ dataSourceCon
 | 
			
		|||
  const hasTLSClientKey = dataSourceConfig.secureJsonFields && dataSourceConfig.secureJsonFields.tlsClientKey;
 | 
			
		||||
  const hasServerName = dataSourceConfig.jsonData && dataSourceConfig.jsonData.serverName;
 | 
			
		||||
 | 
			
		||||
  const onResetClickFactory = (field: string) => (event: React.MouseEvent<HTMLAnchorElement>) => {
 | 
			
		||||
  const onResetClickFactory = (field: string) => (event: React.MouseEvent<HTMLButtonElement>) => {
 | 
			
		||||
    event.preventDefault();
 | 
			
		||||
    const newSecureJsonFields: KeyValue<boolean> = { ...dataSourceConfig.secureJsonFields };
 | 
			
		||||
    newSecureJsonFields[field] = false;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,50 +0,0 @@
 | 
			
		|||
import React from 'react';
 | 
			
		||||
import { action } from '@storybook/addon-actions';
 | 
			
		||||
 | 
			
		||||
import { ToggleButton, ToggleButtonGroup } from './ToggleButtonGroup';
 | 
			
		||||
import { UseState } from '../../utils/storybook/UseState';
 | 
			
		||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  title: 'Forms/Legacy/ToggleButtonGroup',
 | 
			
		||||
  component: ToggleButtonGroup,
 | 
			
		||||
  decorators: [withCenteredStory],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const options = [
 | 
			
		||||
  { value: 'first', label: 'First' },
 | 
			
		||||
  { value: 'second', label: 'Second' },
 | 
			
		||||
  { value: 'third', label: 'Third' },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export const basic = () => {
 | 
			
		||||
  return (
 | 
			
		||||
    <UseState
 | 
			
		||||
      initialState={{
 | 
			
		||||
        value: 'first',
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      {(value, updateValue) => {
 | 
			
		||||
        return (
 | 
			
		||||
          <ToggleButtonGroup label="Options">
 | 
			
		||||
            {options.map((option, index) => {
 | 
			
		||||
              return (
 | 
			
		||||
                <ToggleButton
 | 
			
		||||
                  key={`${option.value}-${index}`}
 | 
			
		||||
                  value={option.value}
 | 
			
		||||
                  onChange={(newValue) => {
 | 
			
		||||
                    action('on change')(newValue);
 | 
			
		||||
                    updateValue({ value: newValue });
 | 
			
		||||
                  }}
 | 
			
		||||
                  selected={value.value === option.value}
 | 
			
		||||
                >
 | 
			
		||||
                  {option.label}
 | 
			
		||||
                </ToggleButton>
 | 
			
		||||
              );
 | 
			
		||||
            })}
 | 
			
		||||
          </ToggleButtonGroup>
 | 
			
		||||
        );
 | 
			
		||||
      }}
 | 
			
		||||
    </UseState>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,77 +0,0 @@
 | 
			
		|||
import React, { FC, ReactNode, PureComponent } from 'react';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import { Tooltip } from '../Tooltip/Tooltip';
 | 
			
		||||
import { deprecationWarning } from '@grafana/data';
 | 
			
		||||
 | 
			
		||||
interface ToggleButtonGroupProps {
 | 
			
		||||
  label?: string;
 | 
			
		||||
  children: JSX.Element[];
 | 
			
		||||
  transparent?: boolean;
 | 
			
		||||
  width?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @deprecated */
 | 
			
		||||
export class ToggleButtonGroup extends PureComponent<ToggleButtonGroupProps> {
 | 
			
		||||
  render() {
 | 
			
		||||
    const { children, label, transparent, width } = this.props;
 | 
			
		||||
    const labelClasses = classNames('gf-form-label', {
 | 
			
		||||
      'gf-form-label--transparent': transparent,
 | 
			
		||||
      [`width-${width}`]: width,
 | 
			
		||||
    });
 | 
			
		||||
    const buttonGroupClasses = classNames('toggle-button-group', {
 | 
			
		||||
      'toggle-button-group--transparent': transparent,
 | 
			
		||||
      'toggle-button-group--padded': width, // Add extra padding to compensate for buttons border
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    deprecationWarning('ToggleButtonGroup', 'ToggleButtonGroup', 'RadioButtonGroup');
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div className="gf-form gf-form--align-center">
 | 
			
		||||
        {label && <label className={labelClasses}>{label}</label>}
 | 
			
		||||
        <div className={buttonGroupClasses}>{children}</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface ToggleButtonProps {
 | 
			
		||||
  onChange?: (value: any) => void;
 | 
			
		||||
  selected?: boolean;
 | 
			
		||||
  value: any;
 | 
			
		||||
  className?: string;
 | 
			
		||||
  children: ReactNode;
 | 
			
		||||
  tooltip?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const ToggleButton: FC<ToggleButtonProps> = ({
 | 
			
		||||
  children,
 | 
			
		||||
  selected,
 | 
			
		||||
  className = '',
 | 
			
		||||
  value = null,
 | 
			
		||||
  tooltip,
 | 
			
		||||
  onChange,
 | 
			
		||||
}) => {
 | 
			
		||||
  const onClick = (event: React.SyntheticEvent) => {
 | 
			
		||||
    event.stopPropagation();
 | 
			
		||||
    if (!selected && onChange) {
 | 
			
		||||
      onChange(value);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const btnClassName = `btn ${className}${selected ? ' active' : ''}`;
 | 
			
		||||
  const button = (
 | 
			
		||||
    <button className={btnClassName} onClick={onClick}>
 | 
			
		||||
      <span>{children}</span>
 | 
			
		||||
    </button>
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  if (tooltip) {
 | 
			
		||||
    return (
 | 
			
		||||
      <Tooltip content={tooltip} placement="bottom">
 | 
			
		||||
        {button}
 | 
			
		||||
      </Tooltip>
 | 
			
		||||
    );
 | 
			
		||||
  } else {
 | 
			
		||||
    return button;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +110,6 @@ export { LogRows } from './Logs/LogRows';
 | 
			
		|||
export { getLogRowStyles } from './Logs/getLogRowStyles';
 | 
			
		||||
export { DataLinkButton } from './DataLinks/DataLinkButton';
 | 
			
		||||
export { FieldLinkList } from './DataLinks/FieldLinkList';
 | 
			
		||||
export { ToggleButtonGroup, ToggleButton } from './ToggleButtonGroup/ToggleButtonGroup';
 | 
			
		||||
// Panel editors
 | 
			
		||||
export { FullWidthButtonContainer } from './Button/FullWidthButtonContainer';
 | 
			
		||||
export { ClickOutsideWrapper } from './ClickOutsideWrapper/ClickOutsideWrapper';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,8 +76,11 @@ export type IconName =
 | 
			
		|||
  | 'gf-interpolation-step-after'
 | 
			
		||||
  | 'gf-interpolation-step-before'
 | 
			
		||||
  | 'gf-logs'
 | 
			
		||||
  | 'github'
 | 
			
		||||
  | 'gitlab'
 | 
			
		||||
  | 'grafana'
 | 
			
		||||
  | 'graph-bar'
 | 
			
		||||
  | 'google'
 | 
			
		||||
  | 'heart-break'
 | 
			
		||||
  | 'heart'
 | 
			
		||||
  | 'history'
 | 
			
		||||
| 
						 | 
				
			
			@ -90,10 +93,12 @@ export type IconName =
 | 
			
		|||
  | 'link'
 | 
			
		||||
  | 'list-ul'
 | 
			
		||||
  | 'lock'
 | 
			
		||||
  | 'microsoft'
 | 
			
		||||
  | 'minus-circle'
 | 
			
		||||
  | 'minus'
 | 
			
		||||
  | 'mobile-android'
 | 
			
		||||
  | 'monitor'
 | 
			
		||||
  | 'okta'
 | 
			
		||||
  | 'palette'
 | 
			
		||||
  | 'panel-add'
 | 
			
		||||
  | 'pause'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,8 +5,7 @@ import React, { PureComponent } from 'react';
 | 
			
		|||
import { InputDatasource, describeDataFrame } from './InputDatasource';
 | 
			
		||||
import { InputQuery, InputOptions } from './types';
 | 
			
		||||
 | 
			
		||||
import { InlineFormLabel, LegacyForms, TableInputCSV, Icon } from '@grafana/ui';
 | 
			
		||||
const { Select } = LegacyForms;
 | 
			
		||||
import { Select, TableInputCSV, LinkButton, Icon, InlineField } from '@grafana/ui';
 | 
			
		||||
import { DataFrame, toCSV, SelectableValue, MutableDataFrame, QueryEditorProps } from '@grafana/data';
 | 
			
		||||
 | 
			
		||||
import { dataFrameToCSV } from './utils';
 | 
			
		||||
| 
						 | 
				
			
			@ -68,21 +67,19 @@ export class InputQueryEditor extends PureComponent<Props, State> {
 | 
			
		|||
    const selected = query.data ? options[0] : options[1];
 | 
			
		||||
    return (
 | 
			
		||||
      <div>
 | 
			
		||||
        <div className="gf-form">
 | 
			
		||||
          <InlineFormLabel width={4}>Data</InlineFormLabel>
 | 
			
		||||
          <Select width={6} options={options} value={selected} onChange={this.onSourceChange} />
 | 
			
		||||
 | 
			
		||||
          <div className="btn btn-link">
 | 
			
		||||
        <InlineField label="Data" labelWidth={8}>
 | 
			
		||||
          <>
 | 
			
		||||
            <Select width={20} options={options} value={selected} onChange={this.onSourceChange} />
 | 
			
		||||
            {query.data ? (
 | 
			
		||||
              describeDataFrame(query.data)
 | 
			
		||||
              <div style={{ alignSelf: 'center' }}>{describeDataFrame(query.data)}</div>
 | 
			
		||||
            ) : (
 | 
			
		||||
              <a href={`datasources/edit/${id}/`}>
 | 
			
		||||
              <LinkButton variant="link" href={`datasources/edit/${id}/`}>
 | 
			
		||||
                {name}: {describeDataFrame(datasource.data)}   
 | 
			
		||||
                <Icon name="pen" />
 | 
			
		||||
              </a>
 | 
			
		||||
              </LinkButton>
 | 
			
		||||
            )}
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
          </>
 | 
			
		||||
        </InlineField>
 | 
			
		||||
        {query.data && <TableInputCSV text={text} onSeriesParsed={this.onSeriesParsed} width={'100%'} height={200} />}
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
import React from 'react';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { IconButton, useStyles2 } from '@grafana/ui';
 | 
			
		||||
import { GrafanaThemeV2 } from '@grafana/data';
 | 
			
		||||
 | 
			
		||||
type Props = {
 | 
			
		||||
  onClick: () => void;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const CloseButton: React.FC<Props> = ({ onClick }) => {
 | 
			
		||||
  const styles = useStyles2(getStyles);
 | 
			
		||||
  return <IconButton className={styles} name="times" onClick={onClick} />;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getStyles = (theme: GrafanaThemeV2) =>
 | 
			
		||||
  css`
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    right: ${theme.spacing(0.5)};
 | 
			
		||||
    top: ${theme.spacing(1)};
 | 
			
		||||
  `;
 | 
			
		||||
| 
						 | 
				
			
			@ -40,7 +40,6 @@ export const LoginPage: FC = () => {
 | 
			
		|||
            {!isChangingPassword && (
 | 
			
		||||
              <InnerBox>
 | 
			
		||||
                {!disableLoginForm && (
 | 
			
		||||
                  <>
 | 
			
		||||
                  <LoginForm
 | 
			
		||||
                    onSubmit={login}
 | 
			
		||||
                    loginHint={loginHint}
 | 
			
		||||
| 
						 | 
				
			
			@ -61,7 +60,6 @@ export const LoginPage: FC = () => {
 | 
			
		|||
                      <></>
 | 
			
		||||
                    )}
 | 
			
		||||
                  </LoginForm>
 | 
			
		||||
                  </>
 | 
			
		||||
                )}
 | 
			
		||||
                <LoginServiceButtons />
 | 
			
		||||
                {!disableUserSignUp && <UserSignup />}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,89 +1,99 @@
 | 
			
		|||
import React from 'react';
 | 
			
		||||
import config from 'app/core/config';
 | 
			
		||||
import { css, cx } from '@emotion/css';
 | 
			
		||||
import { useStyles } from '@grafana/ui';
 | 
			
		||||
import { GrafanaTheme } from '@grafana/data';
 | 
			
		||||
 | 
			
		||||
const loginServices: () => LoginServices = () => {
 | 
			
		||||
  const oauthEnabled = !!config.oauth;
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    saml: {
 | 
			
		||||
      enabled: config.samlEnabled,
 | 
			
		||||
      name: 'SAML',
 | 
			
		||||
      className: 'github',
 | 
			
		||||
      icon: 'key',
 | 
			
		||||
    },
 | 
			
		||||
    google: {
 | 
			
		||||
      enabled: oauthEnabled && config.oauth.google,
 | 
			
		||||
      name: 'Google',
 | 
			
		||||
    },
 | 
			
		||||
    azuread: {
 | 
			
		||||
      enabled: oauthEnabled && config.oauth.azuread,
 | 
			
		||||
      name: 'Microsoft',
 | 
			
		||||
    },
 | 
			
		||||
    github: {
 | 
			
		||||
      enabled: oauthEnabled && config.oauth.github,
 | 
			
		||||
      name: 'GitHub',
 | 
			
		||||
    },
 | 
			
		||||
    gitlab: {
 | 
			
		||||
      enabled: oauthEnabled && config.oauth.gitlab,
 | 
			
		||||
      name: 'GitLab',
 | 
			
		||||
    },
 | 
			
		||||
    grafanacom: {
 | 
			
		||||
      enabled: oauthEnabled && config.oauth.grafana_com,
 | 
			
		||||
      name: 'Grafana.com',
 | 
			
		||||
      hrefName: 'grafana_com',
 | 
			
		||||
      icon: 'grafana_com',
 | 
			
		||||
    },
 | 
			
		||||
    okta: {
 | 
			
		||||
      enabled: oauthEnabled && config.oauth.okta,
 | 
			
		||||
      name: 'Okta',
 | 
			
		||||
    },
 | 
			
		||||
    oauth: {
 | 
			
		||||
      enabled: oauthEnabled && config.oauth.generic_oauth,
 | 
			
		||||
      name: oauthEnabled && config.oauth.generic_oauth ? config.oauth.generic_oauth.name : 'OAuth',
 | 
			
		||||
      icon: 'sign-in',
 | 
			
		||||
      hrefName: 'generic_oauth',
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
import { Icon, IconName, LinkButton, useStyles, useTheme2, VerticalGroup } from '@grafana/ui';
 | 
			
		||||
import { GrafanaTheme, GrafanaThemeV2 } from '@grafana/data';
 | 
			
		||||
import { pickBy } from 'lodash';
 | 
			
		||||
 | 
			
		||||
export interface LoginService {
 | 
			
		||||
  bgColor: string;
 | 
			
		||||
  enabled: boolean;
 | 
			
		||||
  name: string;
 | 
			
		||||
  hrefName?: string;
 | 
			
		||||
  icon?: string;
 | 
			
		||||
  className?: string;
 | 
			
		||||
  icon: IconName;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface LoginServices {
 | 
			
		||||
  [key: string]: LoginService;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const loginServices: () => LoginServices = () => {
 | 
			
		||||
  const oauthEnabled = !!config.oauth;
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    saml: {
 | 
			
		||||
      bgColor: '#464646',
 | 
			
		||||
      enabled: config.samlEnabled,
 | 
			
		||||
      name: 'SAML',
 | 
			
		||||
      icon: 'key-skeleton-alt',
 | 
			
		||||
    },
 | 
			
		||||
    google: {
 | 
			
		||||
      bgColor: '#e84d3c',
 | 
			
		||||
      enabled: oauthEnabled && config.oauth.google,
 | 
			
		||||
      name: 'Google',
 | 
			
		||||
      icon: 'google',
 | 
			
		||||
    },
 | 
			
		||||
    azuread: {
 | 
			
		||||
      bgColor: '#2f2f2f',
 | 
			
		||||
      enabled: oauthEnabled && config.oauth.azuread,
 | 
			
		||||
      name: 'Microsoft',
 | 
			
		||||
      icon: 'microsoft',
 | 
			
		||||
    },
 | 
			
		||||
    github: {
 | 
			
		||||
      bgColor: '#464646',
 | 
			
		||||
      enabled: oauthEnabled && config.oauth.github,
 | 
			
		||||
      name: 'GitHub',
 | 
			
		||||
      icon: 'github',
 | 
			
		||||
    },
 | 
			
		||||
    gitlab: {
 | 
			
		||||
      bgColor: '#fc6d26',
 | 
			
		||||
      enabled: oauthEnabled && config.oauth.gitlab,
 | 
			
		||||
      name: 'GitLab',
 | 
			
		||||
      icon: 'gitlab',
 | 
			
		||||
    },
 | 
			
		||||
    grafanacom: {
 | 
			
		||||
      bgColor: '#262628',
 | 
			
		||||
      enabled: oauthEnabled && config.oauth.grafana_com,
 | 
			
		||||
      name: 'Grafana.com',
 | 
			
		||||
      hrefName: 'grafana_com',
 | 
			
		||||
      icon: 'grafana',
 | 
			
		||||
    },
 | 
			
		||||
    okta: {
 | 
			
		||||
      bgColor: '#2f2f2f',
 | 
			
		||||
      enabled: oauthEnabled && config.oauth.okta,
 | 
			
		||||
      name: 'Okta',
 | 
			
		||||
      icon: 'okta',
 | 
			
		||||
    },
 | 
			
		||||
    oauth: {
 | 
			
		||||
      bgColor: '#262628',
 | 
			
		||||
      enabled: oauthEnabled && config.oauth.generic_oauth,
 | 
			
		||||
      name: oauthEnabled && config.oauth.generic_oauth ? config.oauth.generic_oauth.name : 'OAuth',
 | 
			
		||||
      icon: 'signin',
 | 
			
		||||
      hrefName: 'generic_oauth',
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getServiceStyles = (theme: GrafanaTheme) => {
 | 
			
		||||
  return {
 | 
			
		||||
    container: css`
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
    `,
 | 
			
		||||
    button: css`
 | 
			
		||||
      color: #d8d9da;
 | 
			
		||||
      margin: 0 0 ${theme.spacing.md};
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      &:hover {
 | 
			
		||||
        color: #fff;
 | 
			
		||||
      }
 | 
			
		||||
      position: relative;
 | 
			
		||||
    `,
 | 
			
		||||
    buttonIcon: css`
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      left: ${theme.spacing.sm};
 | 
			
		||||
      top: 50%;
 | 
			
		||||
      transform: translateY(-50%);
 | 
			
		||||
    `,
 | 
			
		||||
    divider: {
 | 
			
		||||
      base: css`
 | 
			
		||||
        float: left;
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        margin: 0 25% ${theme.spacing.md} 25%;
 | 
			
		||||
        color: ${theme.colors.text};
 | 
			
		||||
        display: flex;
 | 
			
		||||
        margin-bottom: ${theme.spacing.sm};
 | 
			
		||||
        justify-content: space-between;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        color: ${theme.colors.text};
 | 
			
		||||
        width: 100%;
 | 
			
		||||
      `,
 | 
			
		||||
      line: css`
 | 
			
		||||
        width: 100px;
 | 
			
		||||
| 
						 | 
				
			
			@ -114,38 +124,46 @@ const LoginDivider = () => {
 | 
			
		|||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const LoginServiceButtons = () => {
 | 
			
		||||
  const styles = useStyles(getServiceStyles);
 | 
			
		||||
  const keyNames = Object.keys(loginServices());
 | 
			
		||||
  const serviceElementsEnabled = keyNames.filter((key) => {
 | 
			
		||||
    const service: LoginService = loginServices()[key];
 | 
			
		||||
    return service.enabled;
 | 
			
		||||
  });
 | 
			
		||||
function getButtonStyleFor(service: LoginService, styles: ReturnType<typeof getServiceStyles>, theme: GrafanaThemeV2) {
 | 
			
		||||
  return cx(
 | 
			
		||||
    styles.button,
 | 
			
		||||
    css`
 | 
			
		||||
      background-color: ${service.bgColor};
 | 
			
		||||
      color: ${theme.colors.getContrastText(service.bgColor)};
 | 
			
		||||
 | 
			
		||||
  if (serviceElementsEnabled.length === 0) {
 | 
			
		||||
    return null;
 | 
			
		||||
      &:hover {
 | 
			
		||||
        background-color: ${theme.colors.emphasize(service.bgColor, 0.15)};
 | 
			
		||||
        box-shadow: ${theme.shadows.z1};
 | 
			
		||||
      }
 | 
			
		||||
    `
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  const serviceElements = serviceElementsEnabled.map((key) => {
 | 
			
		||||
    const service: LoginService = loginServices()[key];
 | 
			
		||||
export const LoginServiceButtons = () => {
 | 
			
		||||
  const enabledServices = pickBy(loginServices(), (service) => service.enabled);
 | 
			
		||||
  const hasServices = Object.keys(enabledServices).length > 0;
 | 
			
		||||
  const theme = useTheme2();
 | 
			
		||||
  const styles = useStyles(getServiceStyles);
 | 
			
		||||
 | 
			
		||||
  if (hasServices) {
 | 
			
		||||
    return (
 | 
			
		||||
      <a
 | 
			
		||||
      <VerticalGroup>
 | 
			
		||||
        <LoginDivider />
 | 
			
		||||
        {Object.entries(enabledServices).map(([key, service]) => (
 | 
			
		||||
          <LinkButton
 | 
			
		||||
            key={key}
 | 
			
		||||
        className={cx(`btn btn-medium btn-service btn-service--${service.className || key}`, styles.button)}
 | 
			
		||||
            className={getButtonStyleFor(service, styles, theme)}
 | 
			
		||||
            href={`login/${service.hrefName ? service.hrefName : key}`}
 | 
			
		||||
            target="_self"
 | 
			
		||||
            fullWidth
 | 
			
		||||
          >
 | 
			
		||||
        <i className={`btn-service-icon fa fa-${service.icon ? service.icon : key}`} />
 | 
			
		||||
            <Icon className={styles.buttonIcon} name={service.icon} />
 | 
			
		||||
            Sign in with {service.name}
 | 
			
		||||
      </a>
 | 
			
		||||
          </LinkButton>
 | 
			
		||||
        ))}
 | 
			
		||||
      </VerticalGroup>
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const divider = LoginDivider();
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      {divider}
 | 
			
		||||
      <div className={styles.container}>{serviceElements}</div>
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
  return null;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ export const UserSignup: FC<{}> = () => {
 | 
			
		|||
  return (
 | 
			
		||||
    <VerticalGroup
 | 
			
		||||
      className={css`
 | 
			
		||||
        margin-top: 8px;
 | 
			
		||||
        margin-top: 16px;
 | 
			
		||||
      `}
 | 
			
		||||
    >
 | 
			
		||||
      <span>New to Grafana?</span>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@ import { css } from '@emotion/css';
 | 
			
		|||
import config from 'app/core/config';
 | 
			
		||||
import { UserPicker } from 'app/core/components/Select/UserPicker';
 | 
			
		||||
import { TeamPicker, Team } from 'app/core/components/Select/TeamPicker';
 | 
			
		||||
import { Button, Form, HorizontalGroup, Icon, Select, stylesFactory } from '@grafana/ui';
 | 
			
		||||
import { Button, Form, HorizontalGroup, Select, stylesFactory } from '@grafana/ui';
 | 
			
		||||
import { GrafanaTheme, SelectableValue } from '@grafana/data';
 | 
			
		||||
import { User } from 'app/types';
 | 
			
		||||
import {
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ import {
 | 
			
		|||
  NewDashboardAclItem,
 | 
			
		||||
  OrgRole,
 | 
			
		||||
} from 'app/types/acl';
 | 
			
		||||
import { CloseButton } from '../CloseButton/CloseButton';
 | 
			
		||||
 | 
			
		||||
export interface Props {
 | 
			
		||||
  onAddPermission: (item: NewDashboardAclItem) => void;
 | 
			
		||||
| 
						 | 
				
			
			@ -93,9 +94,7 @@ class AddPermissions extends Component<Props, NewDashboardAclItem> {
 | 
			
		|||
 | 
			
		||||
    return (
 | 
			
		||||
      <div className="cta-form">
 | 
			
		||||
        <button className="cta-form__close btn btn-transparent" onClick={onCancel}>
 | 
			
		||||
          <Icon name="times" />
 | 
			
		||||
        </button>
 | 
			
		||||
        <CloseButton onClick={onCancel} />
 | 
			
		||||
        <h5>Add Permission For</h5>
 | 
			
		||||
        <Form maxWidth="none" onSubmit={this.onSubmit}>
 | 
			
		||||
          {() => (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import React, { Component } from 'react';
 | 
			
		||||
import { Select, Icon } from '@grafana/ui';
 | 
			
		||||
import { Select, Icon, Button } from '@grafana/ui';
 | 
			
		||||
import { dashboardPermissionLevels } from 'app/types/acl';
 | 
			
		||||
 | 
			
		||||
export interface Props {
 | 
			
		||||
| 
						 | 
				
			
			@ -33,9 +33,7 @@ export default class DisabledPermissionListItem extends Component<Props, any> {
 | 
			
		|||
          </div>
 | 
			
		||||
        </td>
 | 
			
		||||
        <td>
 | 
			
		||||
          <button className="btn btn-inverse btn-small">
 | 
			
		||||
            <Icon name="lock" />
 | 
			
		||||
          </button>
 | 
			
		||||
          <Button size="sm" disabled icon="lock" />
 | 
			
		||||
        </td>
 | 
			
		||||
      </tr>
 | 
			
		||||
    );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import React, { PureComponent } from 'react';
 | 
			
		||||
import { Select, Icon } from '@grafana/ui';
 | 
			
		||||
import { Select, Icon, Button } from '@grafana/ui';
 | 
			
		||||
import { SelectableValue } from '@grafana/data';
 | 
			
		||||
import { dashboardPermissionLevels, DashboardAcl, PermissionLevel } from 'app/types/acl';
 | 
			
		||||
import { FolderInfo } from 'app/types';
 | 
			
		||||
| 
						 | 
				
			
			@ -85,13 +85,9 @@ export default class PermissionsListItem extends PureComponent<Props> {
 | 
			
		|||
        </td>
 | 
			
		||||
        <td>
 | 
			
		||||
          {!item.inherited ? (
 | 
			
		||||
            <a className="btn btn-danger btn-small" onClick={this.onRemoveItem}>
 | 
			
		||||
              <Icon name="times" style={{ marginBottom: 0 }} />
 | 
			
		||||
            </a>
 | 
			
		||||
            <Button size="sm" variant="destructive" icon="times" onClick={this.onRemoveItem} />
 | 
			
		||||
          ) : (
 | 
			
		||||
            <button className="btn btn-inverse btn-small">
 | 
			
		||||
              <Icon name="lock" style={{ marginBottom: '3px' }} />
 | 
			
		||||
            </button>
 | 
			
		||||
            <Button size="sm" disabled icon="times" />
 | 
			
		||||
          )}
 | 
			
		||||
        </td>
 | 
			
		||||
      </tr>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ import React, { PureComponent } from 'react';
 | 
			
		|||
import { hot } from 'react-hot-loader';
 | 
			
		||||
import { connect } from 'react-redux';
 | 
			
		||||
import { NavModel } from '@grafana/data';
 | 
			
		||||
import { Alert, LegacyForms } from '@grafana/ui';
 | 
			
		||||
import { Alert, Button, LegacyForms } from '@grafana/ui';
 | 
			
		||||
const { FormField } = LegacyForms;
 | 
			
		||||
import { getNavModel } from 'app/core/selectors/navModel';
 | 
			
		||||
import config from 'app/core/config';
 | 
			
		||||
| 
						 | 
				
			
			@ -122,9 +122,7 @@ export class LdapPage extends PureComponent<Props, State> {
 | 
			
		|||
                      name="username"
 | 
			
		||||
                      defaultValue={queryParams.username}
 | 
			
		||||
                    />
 | 
			
		||||
                    <button type="submit" className="btn btn-primary">
 | 
			
		||||
                      Run
 | 
			
		||||
                    </button>
 | 
			
		||||
                    <Button type="submit">Run</Button>
 | 
			
		||||
                  </form>
 | 
			
		||||
                </div>
 | 
			
		||||
                {userError && userError.title && (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
import React, { PureComponent } from 'react';
 | 
			
		||||
import { dateTimeFormat } from '@grafana/data';
 | 
			
		||||
import { Spinner } from '@grafana/ui';
 | 
			
		||||
import { Button, Spinner } from '@grafana/ui';
 | 
			
		||||
import { SyncInfo } from 'app/types';
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
| 
						 | 
				
			
			@ -31,10 +31,10 @@ export class LdapSyncInfo extends PureComponent<Props, State> {
 | 
			
		|||
      <>
 | 
			
		||||
        <h3 className="page-heading">
 | 
			
		||||
          LDAP Synchronisation
 | 
			
		||||
          <button className={`btn btn-secondary pull-right`} onClick={this.handleSyncClick} hidden={true}>
 | 
			
		||||
          <Button className="pull-right" onClick={this.handleSyncClick} hidden>
 | 
			
		||||
            <span className="btn-title">Bulk-sync now</span>
 | 
			
		||||
            {isSyncing && <Spinner inline={true} />}
 | 
			
		||||
          </button>
 | 
			
		||||
          </Button>
 | 
			
		||||
        </h3>
 | 
			
		||||
        <div className="gf-form-group">
 | 
			
		||||
          <div className="gf-form">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,5 @@
 | 
			
		|||
import React, { PureComponent } from 'react';
 | 
			
		||||
import { LoadingPlaceholder, JSONFormatter, Icon } from '@grafana/ui';
 | 
			
		||||
 | 
			
		||||
import { LoadingPlaceholder, JSONFormatter, Icon, HorizontalGroup } from '@grafana/ui';
 | 
			
		||||
import appEvents from 'app/core/app_events';
 | 
			
		||||
import { CopyToClipboard } from 'app/core/components/CopyToClipboard/CopyToClipboard';
 | 
			
		||||
import { DashboardModel, PanelModel } from '../dashboard/state';
 | 
			
		||||
| 
						 | 
				
			
			@ -106,16 +105,12 @@ export class TestRuleResult extends PureComponent<Props, State> {
 | 
			
		|||
    return (
 | 
			
		||||
      <>
 | 
			
		||||
        <div className="pull-right">
 | 
			
		||||
          <button className="btn btn-transparent btn-p-x-0 m-r-1" onClick={this.onToggleExpand}>
 | 
			
		||||
            {this.renderExpandCollapse()}
 | 
			
		||||
          </button>
 | 
			
		||||
          <CopyToClipboard
 | 
			
		||||
            className="btn btn-transparent btn-p-x-0"
 | 
			
		||||
            text={this.getTextForClipboard}
 | 
			
		||||
            onSuccess={this.onClipboardSuccess}
 | 
			
		||||
          >
 | 
			
		||||
          <HorizontalGroup spacing="md">
 | 
			
		||||
            <div onClick={this.onToggleExpand}>{this.renderExpandCollapse()}</div>
 | 
			
		||||
            <CopyToClipboard elType="div" text={this.getTextForClipboard} onSuccess={this.onClipboardSuccess}>
 | 
			
		||||
              <Icon name="copy" /> Copy to Clipboard
 | 
			
		||||
            </CopyToClipboard>
 | 
			
		||||
          </HorizontalGroup>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <JSONFormatter json={testRuleResponse} open={openNodes} onDidRender={this.setFormattedJson} />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import React, { FC } from 'react';
 | 
			
		||||
 | 
			
		||||
import { Button } from '@grafana/ui';
 | 
			
		||||
import { FilterInput } from '../../core/components/FilterInput/FilterInput';
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
| 
						 | 
				
			
			@ -17,9 +17,9 @@ export const ApiKeysActionBar: FC<Props> = ({ searchQuery, disabled, onAddClick,
 | 
			
		|||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div className="page-action-bar__spacer" />
 | 
			
		||||
      <button className="btn btn-primary pull-right" onClick={onAddClick} disabled={disabled}>
 | 
			
		||||
      <Button className="pull-right" onClick={onAddClick} disabled={disabled}>
 | 
			
		||||
        Add API key
 | 
			
		||||
      </button>
 | 
			
		||||
      </Button>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,9 @@
 | 
			
		|||
import React, { ChangeEvent, FC, FormEvent, useEffect, useState } from 'react';
 | 
			
		||||
import { EventsWithValidation, Icon, InlineFormLabel, LegacyForms, ValidationEvents } from '@grafana/ui';
 | 
			
		||||
import { EventsWithValidation, InlineFormLabel, LegacyForms, ValidationEvents, Button } from '@grafana/ui';
 | 
			
		||||
import { NewApiKey, OrgRole } from '../../types';
 | 
			
		||||
import { rangeUtil } from '@grafana/data';
 | 
			
		||||
import { SlideDown } from '../../core/components/Animations/SlideDown';
 | 
			
		||||
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
 | 
			
		||||
 | 
			
		||||
const { Input } = LegacyForms;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -65,9 +66,7 @@ export const ApiKeysForm: FC<Props> = ({ show, onClose, onKeyAdded }) => {
 | 
			
		|||
  return (
 | 
			
		||||
    <SlideDown in={show}>
 | 
			
		||||
      <div className="gf-form-inline cta-form">
 | 
			
		||||
        <button className="cta-form__close btn btn-transparent" onClick={onClose}>
 | 
			
		||||
          <Icon name="times" />
 | 
			
		||||
        </button>
 | 
			
		||||
        <CloseButton onClick={onClose} />
 | 
			
		||||
        <form className="gf-form-group" onSubmit={onSubmit}>
 | 
			
		||||
          <h5>Add API Key</h5>
 | 
			
		||||
          <div className="gf-form-inline">
 | 
			
		||||
| 
						 | 
				
			
			@ -101,7 +100,7 @@ export const ApiKeysForm: FC<Props> = ({ show, onClose, onKeyAdded }) => {
 | 
			
		|||
              />
 | 
			
		||||
            </div>
 | 
			
		||||
            <div className="gf-form">
 | 
			
		||||
              <button className="btn gf-form-btn btn-primary">Add</button>
 | 
			
		||||
              <Button>Add</Button>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </form>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
import React, { FC } from 'react';
 | 
			
		||||
import { PluginDashboard } from '../../types';
 | 
			
		||||
import { Icon } from '@grafana/ui';
 | 
			
		||||
import { Button, Icon } from '@grafana/ui';
 | 
			
		||||
 | 
			
		||||
export interface Props {
 | 
			
		||||
  dashboards: PluginDashboard[];
 | 
			
		||||
| 
						 | 
				
			
			@ -31,18 +31,16 @@ const DashboardsTable: FC<Props> = ({ dashboards, onImport, onRemove }) => {
 | 
			
		|||
              </td>
 | 
			
		||||
              <td style={{ textAlign: 'right' }}>
 | 
			
		||||
                {!dashboard.imported ? (
 | 
			
		||||
                  <button className="btn btn-secondary btn-small" onClick={() => onImport(dashboard, false)}>
 | 
			
		||||
                  <Button variant="secondary" size="sm" onClick={() => onImport(dashboard, false)}>
 | 
			
		||||
                    Import
 | 
			
		||||
                  </button>
 | 
			
		||||
                  </Button>
 | 
			
		||||
                ) : (
 | 
			
		||||
                  <button className="btn btn-secondary btn-small" onClick={() => onImport(dashboard, true)}>
 | 
			
		||||
                  <Button variant="secondary" size="sm" onClick={() => onImport(dashboard, true)}>
 | 
			
		||||
                    {buttonText(dashboard)}
 | 
			
		||||
                  </button>
 | 
			
		||||
                  </Button>
 | 
			
		||||
                )}
 | 
			
		||||
                {dashboard.imported && (
 | 
			
		||||
                  <button className="btn btn-danger btn-small" onClick={() => onRemove(dashboard)}>
 | 
			
		||||
                    <Icon name="trash-alt" />
 | 
			
		||||
                  </button>
 | 
			
		||||
                  <Button icon="trash-alt" variant="destructive" size="sm" onClick={() => onRemove(dashboard)} />
 | 
			
		||||
                )}
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,12 +35,13 @@ exports[`Render should render table 1`] = `
 | 
			
		|||
          }
 | 
			
		||||
        }
 | 
			
		||||
      >
 | 
			
		||||
        <button
 | 
			
		||||
          className="btn btn-secondary btn-small"
 | 
			
		||||
        <Button
 | 
			
		||||
          onClick={[Function]}
 | 
			
		||||
          size="sm"
 | 
			
		||||
          variant="secondary"
 | 
			
		||||
        >
 | 
			
		||||
          Import
 | 
			
		||||
        </button>
 | 
			
		||||
        </Button>
 | 
			
		||||
      </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr
 | 
			
		||||
| 
						 | 
				
			
			@ -67,20 +68,19 @@ exports[`Render should render table 1`] = `
 | 
			
		|||
          }
 | 
			
		||||
        }
 | 
			
		||||
      >
 | 
			
		||||
        <button
 | 
			
		||||
          className="btn btn-secondary btn-small"
 | 
			
		||||
        <Button
 | 
			
		||||
          onClick={[Function]}
 | 
			
		||||
          size="sm"
 | 
			
		||||
          variant="secondary"
 | 
			
		||||
        >
 | 
			
		||||
          Update
 | 
			
		||||
        </button>
 | 
			
		||||
        <button
 | 
			
		||||
          className="btn btn-danger btn-small"
 | 
			
		||||
        </Button>
 | 
			
		||||
        <Button
 | 
			
		||||
          icon="trash-alt"
 | 
			
		||||
          onClick={[Function]}
 | 
			
		||||
        >
 | 
			
		||||
          <Icon
 | 
			
		||||
            name="trash-alt"
 | 
			
		||||
          size="sm"
 | 
			
		||||
          variant="destructive"
 | 
			
		||||
        />
 | 
			
		||||
        </button>
 | 
			
		||||
      </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
  </tbody>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ import { getNavModel } from 'app/core/selectors/navModel';
 | 
			
		|||
// Types
 | 
			
		||||
import { StoreState } from 'app/types/';
 | 
			
		||||
import { DataSourceSettings } from '@grafana/data';
 | 
			
		||||
import { Alert, InfoBox } from '@grafana/ui';
 | 
			
		||||
import { Alert, Button, InfoBox, LinkButton } from '@grafana/ui';
 | 
			
		||||
import { getDataSourceLoadingNav } from '../state/navModel';
 | 
			
		||||
import PluginStateinfo from 'app/features/plugins/PluginStateInfo';
 | 
			
		||||
import { dataSourceLoaded, setDataSourceName, setIsDefault } from '../state/reducers';
 | 
			
		||||
| 
						 | 
				
			
			@ -170,13 +170,13 @@ export class DataSourceSettingsPage extends PureComponent<Props> {
 | 
			
		|||
          <div>
 | 
			
		||||
            <div className="gf-form-button-row">
 | 
			
		||||
              {showDelete && (
 | 
			
		||||
                <button type="submit" className="btn btn-danger" onClick={this.onDelete}>
 | 
			
		||||
                <Button type="submit" variant="destructive" onClick={this.onDelete}>
 | 
			
		||||
                  Delete
 | 
			
		||||
                </button>
 | 
			
		||||
                </Button>
 | 
			
		||||
              )}
 | 
			
		||||
              <a className="btn btn-inverse" href="datasources">
 | 
			
		||||
              <LinkButton variant="link" href="datasources">
 | 
			
		||||
                Back
 | 
			
		||||
              </a>
 | 
			
		||||
              </LinkButton>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </Page.Contents>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ import React, { PureComponent } from 'react';
 | 
			
		|||
import { css, cx } from '@emotion/css';
 | 
			
		||||
import tinycolor from 'tinycolor2';
 | 
			
		||||
 | 
			
		||||
import { LogMessageAnsi, Themeable, withTheme, getLogRowStyles, Icon } from '@grafana/ui';
 | 
			
		||||
import { LogMessageAnsi, Themeable, withTheme, getLogRowStyles, Icon, Button } from '@grafana/ui';
 | 
			
		||||
import { GrafanaTheme, LogRowModel, TimeZone, dateTimeFormat } from '@grafana/data';
 | 
			
		||||
 | 
			
		||||
import { ElapsedTime } from './ElapsedTime';
 | 
			
		||||
| 
						 | 
				
			
			@ -142,16 +142,16 @@ class LiveLogs extends PureComponent<Props, State> {
 | 
			
		|||
            />
 | 
			
		||||
          </tbody>
 | 
			
		||||
        </table>
 | 
			
		||||
        <div className={cx([styles.logsRowsIndicator])}>
 | 
			
		||||
          <button onClick={isPaused ? onResume : onPause} className={cx('btn btn-secondary', styles.button)}>
 | 
			
		||||
        <div className={styles.logsRowsIndicator}>
 | 
			
		||||
          <Button variant="secondary" onClick={isPaused ? onResume : onPause} className={styles.button}>
 | 
			
		||||
            <Icon name={isPaused ? 'play' : 'pause'} />
 | 
			
		||||
             
 | 
			
		||||
            {isPaused ? 'Resume' : 'Pause'}
 | 
			
		||||
          </button>
 | 
			
		||||
          <button onClick={this.props.stopLive} className={cx('btn btn-inverse', styles.button)}>
 | 
			
		||||
          </Button>
 | 
			
		||||
          <Button variant="secondary" onClick={this.props.stopLive} className={styles.button}>
 | 
			
		||||
            <Icon name="square-shape" size="lg" type="mono" />
 | 
			
		||||
              Exit live mode
 | 
			
		||||
          </button>
 | 
			
		||||
          </Button>
 | 
			
		||||
          {isPaused || (
 | 
			
		||||
            <span>
 | 
			
		||||
              Last line received: <ElapsedTime resetKey={this.props.logRows} humanize={true} /> ago
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
import React, { PureComponent } from 'react';
 | 
			
		||||
import { connect, ConnectedProps } from 'react-redux';
 | 
			
		||||
import Page from 'app/core/components/Page/Page';
 | 
			
		||||
import { Tooltip, Icon } from '@grafana/ui';
 | 
			
		||||
import { Tooltip, Icon, Button } from '@grafana/ui';
 | 
			
		||||
import { SlideDown } from 'app/core/components/Animations/SlideDown';
 | 
			
		||||
import { getNavModel } from 'app/core/selectors/navModel';
 | 
			
		||||
import { StoreState } from 'app/types';
 | 
			
		||||
| 
						 | 
				
			
			@ -105,9 +105,9 @@ export class FolderPermissions extends PureComponent<Props, State> {
 | 
			
		|||
              <Icon className="icon--has-hover page-sub-heading-icon" name="question-circle" />
 | 
			
		||||
            </Tooltip>
 | 
			
		||||
            <div className="page-action-bar__spacer" />
 | 
			
		||||
            <button className="btn btn-primary pull-right" onClick={this.onOpenAddPermissions} disabled={isAdding}>
 | 
			
		||||
            <Button className="pull-right" onClick={this.onOpenAddPermissions} disabled={isAdding}>
 | 
			
		||||
              Add Permission
 | 
			
		||||
            </button>
 | 
			
		||||
            </Button>
 | 
			
		||||
          </div>
 | 
			
		||||
          <SlideDown in={isAdding}>
 | 
			
		||||
            <AddPermission onAddPermission={this.onAddPermission} onCancel={this.onCancelAddPermission} />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
import React, { PureComponent } from 'react';
 | 
			
		||||
import { connect, ConnectedProps } from 'react-redux';
 | 
			
		||||
import { LegacyForms } from '@grafana/ui';
 | 
			
		||||
import { Button, LegacyForms } from '@grafana/ui';
 | 
			
		||||
const { Input } = LegacyForms;
 | 
			
		||||
import Page from 'app/core/components/Page/Page';
 | 
			
		||||
import appEvents from 'app/core/app_events';
 | 
			
		||||
| 
						 | 
				
			
			@ -99,12 +99,12 @@ export class FolderSettingsPage extends PureComponent<Props, State> {
 | 
			
		|||
                />
 | 
			
		||||
              </div>
 | 
			
		||||
              <div className="gf-form-button-row">
 | 
			
		||||
                <button type="submit" className="btn btn-primary" disabled={!folder.canSave || !folder.hasChanged}>
 | 
			
		||||
                <Button type="submit" disabled={!folder.canSave || !folder.hasChanged}>
 | 
			
		||||
                  Save
 | 
			
		||||
                </button>
 | 
			
		||||
                <button className="btn btn-danger" onClick={this.onDelete} disabled={!folder.canSave}>
 | 
			
		||||
                </Button>
 | 
			
		||||
                <Button variant="destructive" onClick={this.onDelete} disabled={!folder.canSave}>
 | 
			
		||||
                  Delete
 | 
			
		||||
                </button>
 | 
			
		||||
                </Button>
 | 
			
		||||
              </div>
 | 
			
		||||
            </form>
 | 
			
		||||
          </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,20 +37,19 @@ exports[`Render should enable save button 1`] = `
 | 
			
		|||
        <div
 | 
			
		||||
          className="gf-form-button-row"
 | 
			
		||||
        >
 | 
			
		||||
          <button
 | 
			
		||||
            className="btn btn-primary"
 | 
			
		||||
          <Button
 | 
			
		||||
            disabled={false}
 | 
			
		||||
            type="submit"
 | 
			
		||||
          >
 | 
			
		||||
            Save
 | 
			
		||||
          </button>
 | 
			
		||||
          <button
 | 
			
		||||
            className="btn btn-danger"
 | 
			
		||||
          </Button>
 | 
			
		||||
          <Button
 | 
			
		||||
            disabled={false}
 | 
			
		||||
            onClick={[Function]}
 | 
			
		||||
            variant="destructive"
 | 
			
		||||
          >
 | 
			
		||||
            Delete
 | 
			
		||||
          </button>
 | 
			
		||||
          </Button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -95,20 +94,19 @@ exports[`Render should render component 1`] = `
 | 
			
		|||
        <div
 | 
			
		||||
          className="gf-form-button-row"
 | 
			
		||||
        >
 | 
			
		||||
          <button
 | 
			
		||||
            className="btn btn-primary"
 | 
			
		||||
          <Button
 | 
			
		||||
            disabled={true}
 | 
			
		||||
            type="submit"
 | 
			
		||||
          >
 | 
			
		||||
            Save
 | 
			
		||||
          </button>
 | 
			
		||||
          <button
 | 
			
		||||
            className="btn btn-danger"
 | 
			
		||||
          </Button>
 | 
			
		||||
          <Button
 | 
			
		||||
            disabled={false}
 | 
			
		||||
            onClick={[Function]}
 | 
			
		||||
            variant="destructive"
 | 
			
		||||
          >
 | 
			
		||||
            Delete
 | 
			
		||||
          </button>
 | 
			
		||||
          </Button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,7 +44,9 @@ export class UserOrganizations extends PureComponent<Props> {
 | 
			
		|||
                        <td>{org.role}</td>
 | 
			
		||||
                        <td className="text-right">
 | 
			
		||||
                          {org.orgId === user.orgId ? (
 | 
			
		||||
                            <span className="btn btn-primary btn-small">Current</span>
 | 
			
		||||
                            <Button variant="secondary" size="sm" disabled>
 | 
			
		||||
                              Current
 | 
			
		||||
                            </Button>
 | 
			
		||||
                          ) : (
 | 
			
		||||
                            <Button
 | 
			
		||||
                              variant="secondary"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,13 +2,14 @@ import React, { PureComponent } from 'react';
 | 
			
		|||
import { connect } from 'react-redux';
 | 
			
		||||
 | 
			
		||||
import { SlideDown } from 'app/core/components/Animations/SlideDown';
 | 
			
		||||
import { LegacyForms, Tooltip, Icon } from '@grafana/ui';
 | 
			
		||||
import { LegacyForms, Tooltip, Icon, Button } from '@grafana/ui';
 | 
			
		||||
const { Input } = LegacyForms;
 | 
			
		||||
 | 
			
		||||
import { TeamGroup } from '../../types';
 | 
			
		||||
import { addTeamGroup, loadTeamGroups, removeTeamGroup } from './state/actions';
 | 
			
		||||
import { getTeamGroups } from './state/selectors';
 | 
			
		||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
 | 
			
		||||
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
 | 
			
		||||
 | 
			
		||||
export interface Props {
 | 
			
		||||
  groups: TeamGroup[];
 | 
			
		||||
| 
						 | 
				
			
			@ -65,9 +66,9 @@ export class TeamGroupSync extends PureComponent<Props, State> {
 | 
			
		|||
      <tr key={group.groupId}>
 | 
			
		||||
        <td>{group.groupId}</td>
 | 
			
		||||
        <td style={{ width: '1%' }}>
 | 
			
		||||
          <a className="btn btn-danger btn-small" onClick={() => this.onRemoveGroup(group)}>
 | 
			
		||||
            <Icon name="times" style={{ marginBottom: 0 }} />
 | 
			
		||||
          </a>
 | 
			
		||||
          <Button size="sm" variant="destructive" onClick={() => this.onRemoveGroup(group)}>
 | 
			
		||||
            <Icon name="times" />
 | 
			
		||||
          </Button>
 | 
			
		||||
        </td>
 | 
			
		||||
      </tr>
 | 
			
		||||
    );
 | 
			
		||||
| 
						 | 
				
			
			@ -86,17 +87,15 @@ export class TeamGroupSync extends PureComponent<Props, State> {
 | 
			
		|||
          </Tooltip>
 | 
			
		||||
          <div className="page-action-bar__spacer" />
 | 
			
		||||
          {groups.length > 0 && (
 | 
			
		||||
            <button className="btn btn-primary pull-right" onClick={this.onToggleAdding}>
 | 
			
		||||
            <Button className="pull-right" onClick={this.onToggleAdding}>
 | 
			
		||||
              <Icon name="plus" /> Add group
 | 
			
		||||
            </button>
 | 
			
		||||
            </Button>
 | 
			
		||||
          )}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <SlideDown in={isAdding}>
 | 
			
		||||
          <div className="cta-form">
 | 
			
		||||
            <button className="cta-form__close btn btn-transparent" onClick={this.onToggleAdding}>
 | 
			
		||||
              <Icon name="times" />
 | 
			
		||||
            </button>
 | 
			
		||||
            <CloseButton onClick={this.onToggleAdding} />
 | 
			
		||||
            <h5>Add External Group</h5>
 | 
			
		||||
            <form className="gf-form-inline" onSubmit={this.onAddGroup}>
 | 
			
		||||
              <div className="gf-form">
 | 
			
		||||
| 
						 | 
				
			
			@ -110,9 +109,9 @@ export class TeamGroupSync extends PureComponent<Props, State> {
 | 
			
		|||
              </div>
 | 
			
		||||
 | 
			
		||||
              <div className="gf-form">
 | 
			
		||||
                <button className="btn btn-primary gf-form-btn" type="submit" disabled={!this.isNewGroupValid()}>
 | 
			
		||||
                <Button type="submit" disabled={!this.isNewGroupValid()}>
 | 
			
		||||
                  Add group
 | 
			
		||||
                </button>
 | 
			
		||||
                </Button>
 | 
			
		||||
              </div>
 | 
			
		||||
            </form>
 | 
			
		||||
          </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,5 @@
 | 
			
		|||
import React, { PureComponent } from 'react';
 | 
			
		||||
import { connect } from 'react-redux';
 | 
			
		||||
import { Icon } from '@grafana/ui';
 | 
			
		||||
import { SlideDown } from 'app/core/components/Animations/SlideDown';
 | 
			
		||||
import { UserPicker } from 'app/core/components/Select/UserPicker';
 | 
			
		||||
import { TagBadge } from 'app/core/components/TagFilter/TagBadge';
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +12,8 @@ import { config } from 'app/core/config';
 | 
			
		|||
import { contextSrv, User as SignedInUser } from 'app/core/services/context_srv';
 | 
			
		||||
import TeamMemberRow from './TeamMemberRow';
 | 
			
		||||
import { setSearchMemberQuery } from './state/reducers';
 | 
			
		||||
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
 | 
			
		||||
import { Button } from '@grafana/ui';
 | 
			
		||||
 | 
			
		||||
export interface Props {
 | 
			
		||||
  members: TeamMember[];
 | 
			
		||||
| 
						 | 
				
			
			@ -79,28 +80,21 @@ export class TeamMembers extends PureComponent<Props, State> {
 | 
			
		|||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div className="page-action-bar__spacer" />
 | 
			
		||||
 | 
			
		||||
          <button
 | 
			
		||||
            className="btn btn-primary pull-right"
 | 
			
		||||
            onClick={this.onToggleAdding}
 | 
			
		||||
            disabled={isAdding || !isTeamAdmin}
 | 
			
		||||
          >
 | 
			
		||||
          <Button className="pull-right" onClick={this.onToggleAdding} disabled={isAdding || !isTeamAdmin}>
 | 
			
		||||
            Add member
 | 
			
		||||
          </button>
 | 
			
		||||
          </Button>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <SlideDown in={isAdding}>
 | 
			
		||||
          <div className="cta-form">
 | 
			
		||||
            <button className="cta-form__close btn btn-transparent" onClick={this.onToggleAdding}>
 | 
			
		||||
              <Icon name="times" />
 | 
			
		||||
            </button>
 | 
			
		||||
            <CloseButton onClick={this.onToggleAdding} />
 | 
			
		||||
            <h5>Add team member</h5>
 | 
			
		||||
            <div className="gf-form-inline">
 | 
			
		||||
              <UserPicker onSelected={this.onUserSelected} className="min-width-30" />
 | 
			
		||||
              {this.state.newTeamMember && (
 | 
			
		||||
                <button className="btn btn-primary gf-form-btn" type="submit" onClick={this.onAddUserToTeam}>
 | 
			
		||||
                <Button type="submit" onClick={this.onAddUserToTeam}>
 | 
			
		||||
                  Add to team
 | 
			
		||||
                </button>
 | 
			
		||||
                </Button>
 | 
			
		||||
              )}
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,14 +29,9 @@ exports[`Render should render component 1`] = `
 | 
			
		|||
    <div
 | 
			
		||||
      className="cta-form"
 | 
			
		||||
    >
 | 
			
		||||
      <button
 | 
			
		||||
        className="cta-form__close btn btn-transparent"
 | 
			
		||||
      <CloseButton
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
      >
 | 
			
		||||
        <Icon
 | 
			
		||||
          name="times"
 | 
			
		||||
      />
 | 
			
		||||
      </button>
 | 
			
		||||
      <h5>
 | 
			
		||||
        Add External Group
 | 
			
		||||
      </h5>
 | 
			
		||||
| 
						 | 
				
			
			@ -58,13 +53,12 @@ exports[`Render should render component 1`] = `
 | 
			
		|||
        <div
 | 
			
		||||
          className="gf-form"
 | 
			
		||||
        >
 | 
			
		||||
          <button
 | 
			
		||||
            className="btn btn-primary gf-form-btn"
 | 
			
		||||
          <Button
 | 
			
		||||
            disabled={true}
 | 
			
		||||
            type="submit"
 | 
			
		||||
          >
 | 
			
		||||
            Add group
 | 
			
		||||
          </button>
 | 
			
		||||
          </Button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -104,15 +98,15 @@ exports[`Render should render groups table 1`] = `
 | 
			
		|||
    <div
 | 
			
		||||
      className="page-action-bar__spacer"
 | 
			
		||||
    />
 | 
			
		||||
    <button
 | 
			
		||||
      className="btn btn-primary pull-right"
 | 
			
		||||
    <Button
 | 
			
		||||
      className="pull-right"
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
    >
 | 
			
		||||
      <Icon
 | 
			
		||||
        name="plus"
 | 
			
		||||
      />
 | 
			
		||||
       Add group
 | 
			
		||||
    </button>
 | 
			
		||||
    </Button>
 | 
			
		||||
  </div>
 | 
			
		||||
  <SlideDown
 | 
			
		||||
    in={false}
 | 
			
		||||
| 
						 | 
				
			
			@ -120,14 +114,9 @@ exports[`Render should render groups table 1`] = `
 | 
			
		|||
    <div
 | 
			
		||||
      className="cta-form"
 | 
			
		||||
    >
 | 
			
		||||
      <button
 | 
			
		||||
        className="cta-form__close btn btn-transparent"
 | 
			
		||||
      <CloseButton
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
      >
 | 
			
		||||
        <Icon
 | 
			
		||||
          name="times"
 | 
			
		||||
      />
 | 
			
		||||
      </button>
 | 
			
		||||
      <h5>
 | 
			
		||||
        Add External Group
 | 
			
		||||
      </h5>
 | 
			
		||||
| 
						 | 
				
			
			@ -149,13 +138,12 @@ exports[`Render should render groups table 1`] = `
 | 
			
		|||
        <div
 | 
			
		||||
          className="gf-form"
 | 
			
		||||
        >
 | 
			
		||||
          <button
 | 
			
		||||
            className="btn btn-primary gf-form-btn"
 | 
			
		||||
          <Button
 | 
			
		||||
            disabled={true}
 | 
			
		||||
            type="submit"
 | 
			
		||||
          >
 | 
			
		||||
            Add group
 | 
			
		||||
          </button>
 | 
			
		||||
          </Button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -194,19 +182,15 @@ exports[`Render should render groups table 1`] = `
 | 
			
		|||
              }
 | 
			
		||||
            }
 | 
			
		||||
          >
 | 
			
		||||
            <a
 | 
			
		||||
              className="btn btn-danger btn-small"
 | 
			
		||||
            <Button
 | 
			
		||||
              onClick={[Function]}
 | 
			
		||||
              size="sm"
 | 
			
		||||
              variant="destructive"
 | 
			
		||||
            >
 | 
			
		||||
              <Icon
 | 
			
		||||
                name="times"
 | 
			
		||||
                style={
 | 
			
		||||
                  Object {
 | 
			
		||||
                    "marginBottom": 0,
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              />
 | 
			
		||||
            </a>
 | 
			
		||||
            </Button>
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr
 | 
			
		||||
| 
						 | 
				
			
			@ -222,19 +206,15 @@ exports[`Render should render groups table 1`] = `
 | 
			
		|||
              }
 | 
			
		||||
            }
 | 
			
		||||
          >
 | 
			
		||||
            <a
 | 
			
		||||
              className="btn btn-danger btn-small"
 | 
			
		||||
            <Button
 | 
			
		||||
              onClick={[Function]}
 | 
			
		||||
              size="sm"
 | 
			
		||||
              variant="destructive"
 | 
			
		||||
            >
 | 
			
		||||
              <Icon
 | 
			
		||||
                name="times"
 | 
			
		||||
                style={
 | 
			
		||||
                  Object {
 | 
			
		||||
                    "marginBottom": 0,
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              />
 | 
			
		||||
            </a>
 | 
			
		||||
            </Button>
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr
 | 
			
		||||
| 
						 | 
				
			
			@ -250,19 +230,15 @@ exports[`Render should render groups table 1`] = `
 | 
			
		|||
              }
 | 
			
		||||
            }
 | 
			
		||||
          >
 | 
			
		||||
            <a
 | 
			
		||||
              className="btn btn-danger btn-small"
 | 
			
		||||
            <Button
 | 
			
		||||
              onClick={[Function]}
 | 
			
		||||
              size="sm"
 | 
			
		||||
              variant="destructive"
 | 
			
		||||
            >
 | 
			
		||||
              <Icon
 | 
			
		||||
                name="times"
 | 
			
		||||
                style={
 | 
			
		||||
                  Object {
 | 
			
		||||
                    "marginBottom": 0,
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              />
 | 
			
		||||
            </a>
 | 
			
		||||
            </Button>
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      </tbody>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,13 +17,13 @@ exports[`Render should render component 1`] = `
 | 
			
		|||
    <div
 | 
			
		||||
      className="page-action-bar__spacer"
 | 
			
		||||
    />
 | 
			
		||||
    <button
 | 
			
		||||
      className="btn btn-primary pull-right"
 | 
			
		||||
    <Button
 | 
			
		||||
      className="pull-right"
 | 
			
		||||
      disabled={false}
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
    >
 | 
			
		||||
      Add member
 | 
			
		||||
    </button>
 | 
			
		||||
    </Button>
 | 
			
		||||
  </div>
 | 
			
		||||
  <SlideDown
 | 
			
		||||
    in={false}
 | 
			
		||||
| 
						 | 
				
			
			@ -31,14 +31,9 @@ exports[`Render should render component 1`] = `
 | 
			
		|||
    <div
 | 
			
		||||
      className="cta-form"
 | 
			
		||||
    >
 | 
			
		||||
      <button
 | 
			
		||||
        className="cta-form__close btn btn-transparent"
 | 
			
		||||
      <CloseButton
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
      >
 | 
			
		||||
        <Icon
 | 
			
		||||
          name="times"
 | 
			
		||||
      />
 | 
			
		||||
      </button>
 | 
			
		||||
      <h5>
 | 
			
		||||
        Add team member
 | 
			
		||||
      </h5>
 | 
			
		||||
| 
						 | 
				
			
			@ -109,13 +104,13 @@ exports[`Render should render team members 1`] = `
 | 
			
		|||
    <div
 | 
			
		||||
      className="page-action-bar__spacer"
 | 
			
		||||
    />
 | 
			
		||||
    <button
 | 
			
		||||
      className="btn btn-primary pull-right"
 | 
			
		||||
    <Button
 | 
			
		||||
      className="pull-right"
 | 
			
		||||
      disabled={false}
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
    >
 | 
			
		||||
      Add member
 | 
			
		||||
    </button>
 | 
			
		||||
    </Button>
 | 
			
		||||
  </div>
 | 
			
		||||
  <SlideDown
 | 
			
		||||
    in={false}
 | 
			
		||||
| 
						 | 
				
			
			@ -123,14 +118,9 @@ exports[`Render should render team members 1`] = `
 | 
			
		|||
    <div
 | 
			
		||||
      className="cta-form"
 | 
			
		||||
    >
 | 
			
		||||
      <button
 | 
			
		||||
        className="cta-form__close btn btn-transparent"
 | 
			
		||||
      <CloseButton
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
      >
 | 
			
		||||
        <Icon
 | 
			
		||||
          name="times"
 | 
			
		||||
      />
 | 
			
		||||
      </button>
 | 
			
		||||
      <h5>
 | 
			
		||||
        Add team member
 | 
			
		||||
      </h5>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import React, { MouseEvent, PureComponent } from 'react';
 | 
			
		||||
import { Icon } from '@grafana/ui';
 | 
			
		||||
import { Icon, LinkButton } from '@grafana/ui';
 | 
			
		||||
import { selectors } from '@grafana/e2e-selectors';
 | 
			
		||||
 | 
			
		||||
import { toVariableIdentifier, toVariablePayload, VariableIdentifier } from '../state/types';
 | 
			
		||||
| 
						 | 
				
			
			@ -98,14 +98,13 @@ class VariableEditorContainerUnconnected extends PureComponent<Props> {
 | 
			
		|||
          {this.props.variables.length > 0 && variableToEdit === null && (
 | 
			
		||||
            <>
 | 
			
		||||
              <VariablesDependenciesButton variables={this.props.variables} />
 | 
			
		||||
              <a
 | 
			
		||||
              <LinkButton
 | 
			
		||||
                type="button"
 | 
			
		||||
                className="btn btn-primary"
 | 
			
		||||
                onClick={this.onNewVariable}
 | 
			
		||||
                aria-label={selectors.pages.Dashboard.Settings.Variables.List.newButton}
 | 
			
		||||
              >
 | 
			
		||||
                New
 | 
			
		||||
              </a>
 | 
			
		||||
              </LinkButton>
 | 
			
		||||
            </>
 | 
			
		||||
          )}
 | 
			
		||||
        </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
// Libraries
 | 
			
		||||
import React, { PureComponent } from 'react';
 | 
			
		||||
import { LinkButton } from '@grafana/ui';
 | 
			
		||||
 | 
			
		||||
// Types
 | 
			
		||||
import { PluginConfigPageProps, DataSourcePluginMeta, DataSourceJsonData } from '@grafana/data';
 | 
			
		||||
| 
						 | 
				
			
			@ -17,14 +18,14 @@ export class TestInfoTab extends PureComponent<Props> {
 | 
			
		|||
        See github for more information about setting up a reproducible test environment.
 | 
			
		||||
        <br />
 | 
			
		||||
        <br />
 | 
			
		||||
        <a
 | 
			
		||||
          className="btn btn-inverse"
 | 
			
		||||
        <LinkButton
 | 
			
		||||
          variant="secondary"
 | 
			
		||||
          href="https://github.com/grafana/grafana/tree/master/devenv"
 | 
			
		||||
          target="_blank"
 | 
			
		||||
          rel="noopener noreferrer"
 | 
			
		||||
        >
 | 
			
		||||
          GitHub
 | 
			
		||||
        </a>
 | 
			
		||||
        </LinkButton>
 | 
			
		||||
        <br />
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue