mirror of
https://github.com/grafana/grafana.git
synced 2024-11-22 08:56:43 -06:00
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,15 +55,15 @@ 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}) => {
|
||||
const ComponentA: React.FC<ComponentAProps> = ({ isActive }) => {
|
||||
const theme = useTheme();
|
||||
const styles = getStyles(theme, 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>
|
||||
);
|
||||
|
20
public/app/core/components/CloseButton/CloseButton.tsx
Normal file
20
public/app/core/components/CloseButton/CloseButton.tsx
Normal file
@ -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,28 +40,26 @@ export const LoginPage: FC = () => {
|
||||
{!isChangingPassword && (
|
||||
<InnerBox>
|
||||
{!disableLoginForm && (
|
||||
<>
|
||||
<LoginForm
|
||||
onSubmit={login}
|
||||
loginHint={loginHint}
|
||||
passwordHint={passwordHint}
|
||||
isLoggingIn={isLoggingIn}
|
||||
>
|
||||
{!(ldapEnabled || authProxyEnabled) ? (
|
||||
<HorizontalGroup justify="flex-end">
|
||||
<LinkButton
|
||||
className={forgottenPasswordStyles}
|
||||
variant="link"
|
||||
href={`${config.appSubUrl}/user/password/send-reset-email`}
|
||||
>
|
||||
Forgot your password?
|
||||
</LinkButton>
|
||||
</HorizontalGroup>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</LoginForm>
|
||||
</>
|
||||
<LoginForm
|
||||
onSubmit={login}
|
||||
loginHint={loginHint}
|
||||
passwordHint={passwordHint}
|
||||
isLoggingIn={isLoggingIn}
|
||||
>
|
||||
{!(ldapEnabled || authProxyEnabled) ? (
|
||||
<HorizontalGroup justify="flex-end">
|
||||
<LinkButton
|
||||
className={forgottenPasswordStyles}
|
||||
variant="link"
|
||||
href={`${config.appSubUrl}/user/password/send-reset-email`}
|
||||
>
|
||||
Forgot your password?
|
||||
</LinkButton>
|
||||
</HorizontalGroup>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</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};
|
||||
}
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<VerticalGroup>
|
||||
<LoginDivider />
|
||||
{Object.entries(enabledServices).map(([key, service]) => (
|
||||
<LinkButton
|
||||
key={key}
|
||||
className={getButtonStyleFor(service, styles, theme)}
|
||||
href={`login/${service.hrefName ? service.hrefName : key}`}
|
||||
target="_self"
|
||||
fullWidth
|
||||
>
|
||||
<Icon className={styles.buttonIcon} name={service.icon} />
|
||||
Sign in with {service.name}
|
||||
</LinkButton>
|
||||
))}
|
||||
</VerticalGroup>
|
||||
);
|
||||
}
|
||||
|
||||
const serviceElements = serviceElementsEnabled.map((key) => {
|
||||
const service: LoginService = loginServices()[key];
|
||||
return (
|
||||
<a
|
||||
key={key}
|
||||
className={cx(`btn btn-medium btn-service btn-service--${service.className || key}`, styles.button)}
|
||||
href={`login/${service.hrefName ? service.hrefName : key}`}
|
||||
target="_self"
|
||||
>
|
||||
<i className={`btn-service-icon fa fa-${service.icon ? service.icon : key}`} />
|
||||
Sign in with {service.name}
|
||||
</a>
|
||||
);
|
||||
});
|
||||
|
||||
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}
|
||||
>
|
||||
<Icon name="copy" /> Copy to Clipboard
|
||||
</CopyToClipboard>
|
||||
<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"
|
||||
/>
|
||||
</button>
|
||||
size="sm"
|
||||
variant="destructive"
|
||||
/>
|
||||
</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
Block a user