Part2: Unicons implementation (#23266)

* Create a new Icon component

* Update icons in main sidebar

* Update icons in Useful links and in react components on  main site

* Update icons in Useful links and in main top navigation

* Adjust sizing

* Update panel navigation and timepicker

* Update icons in Panel menu

* Update icons in add panel widget

* Resolve merge conflict

* Fix part of the test errors and type errors

* Fix storybook errors

* Update getAvailableIcons import in storybook knobs

* Fix import path

* Fix SyntaxError: Cannot use import statement outside a module in test environment error

* Remove dynamic imports

* Remove types as using @ts-ignore

* Update snapshot test

* Add @iconscout/react-unicons to the shouldExclude list as it is blundled with es2015 syntax

* Implment icons in Tabs

* Implement icons in search items and  empty  list

* Update buttons

* Update button-related snapshot tests

* Update icons in modals and page headers

* Create anfular wrapper and update all icons on search screen

* Update sizing, remove colors, update snapshot tests

* Remove color prop from icon, remove color implemetation in mono icons

* Remove color props from monochrome icons

* Complete update of icons for search screen

* Update icons for infor tooltips, playlist, permissions

* Support temporarly font awesome icons used in enterprise grafana

* Part1: Unicons implementation (#23197)

* Create a new Icon component

* Update icons in main sidebar

* Update icons in Useful links and in react components on  main site

* Update icons in Useful links and in main top navigation

* Adjust sizing

* Update panel navigation and timepicker

* Update icons in Panel menu

* NewPanelEditor: Fixed so that test alert rule works in new edit mode (#23179)

* Update icons in add panel widget

* Resolve merge conflict

* Fix part of the test errors and type errors

* Fix storybook errors

* Update getAvailableIcons import in storybook knobs

* Fix import path

* Fix SyntaxError: Cannot use import statement outside a module in test environment error

* Remove dynamic imports

* Remove types as using @ts-ignore

* Update snapshot test

* Add @iconscout/react-unicons to the shouldExclude list as it is blundled with es2015 syntax

* Remove color prop from icon, remove color implemetation in mono icons

* Update navbar styling

* Move toPascalCase to utils/string

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>

* Icons update

* Add optional chaining to for isFontAwesome variable

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
Ivana Huckova
2020-04-07 14:50:49 +02:00
committed by GitHub
co-authored by Torkel Ödegaard
parent 2d48bb8921
commit d2d61d9bc2
103 changed files with 667 additions and 407 deletions
@@ -2,6 +2,7 @@ import React, { AnchorHTMLAttributes, ButtonHTMLAttributes, useContext } from 'r
import { css, cx } from 'emotion';
import tinycolor from 'tinycolor2';
import { selectThemeVariant, stylesFactory, ThemeContext } from '../../themes';
import { IconName } from '../../types';
import { getFocusStyle, getPropertiesForButtonSize } from '../Forms/commonStyles';
import { GrafanaTheme } from '@grafana/data';
import { ButtonContent } from './ButtonContent';
@@ -134,7 +135,7 @@ export type ButtonVariant = 'primary' | 'secondary' | 'destructive' | 'link';
type CommonProps = {
size?: ComponentSize;
variant?: ButtonVariant;
icon?: string;
icon?: IconName;
className?: string;
};
@@ -151,7 +152,9 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
return (
<button className={cx(styles.button, className)} {...otherProps} ref={ref}>
<ButtonContent icon={icon}>{children}</ButtonContent>
<ButtonContent icon={icon} size={otherProps.size}>
{children}
</ButtonContent>
</button>
);
}
@@ -171,7 +174,9 @@ export const LinkButton = React.forwardRef<HTMLAnchorElement, ButtonLinkProps>(
return (
<a className={cx(styles.button, className)} {...otherProps} ref={ref}>
<ButtonContent icon={icon}>{children}</ButtonContent>
<ButtonContent icon={icon} size={otherProps.size}>
{children}
</ButtonContent>
</a>
);
}
@@ -1,6 +1,8 @@
import React from 'react';
import { css } from 'emotion';
import { stylesFactory, useTheme } from '../../themes';
import { IconName } from '../../types';
import { Icon } from '../Icon/Icon';
import { ComponentSize } from '../../types/size';
import { GrafanaTheme } from '@grafana/data';
@@ -14,8 +16,6 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
`,
icon: css`
position: relative;
top: 1px;
& + * {
margin-left: ${theme.spacing.sm};
}
@@ -23,28 +23,24 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
}));
type Props = {
icon?: string;
icon?: IconName;
className?: string;
children: React.ReactNode;
size?: ComponentSize;
};
export function ButtonContent(props: Props) {
const { icon, children } = props;
const { icon, children, size } = props;
const theme = useTheme();
const styles = getStyles(theme);
if (!children) {
return (
<span className={styles.content}>
<i className={icon} />
</span>
);
return <span className={styles.content}>{icon && <Icon name={icon} size={size} />}</span>;
}
const iconElement = icon && (
<span className={styles.icon}>
<i className={icon} />
<Icon name={icon} size={size} />
</span>
);
@@ -12,7 +12,7 @@ CallToActionCardStories.add('default', () => {
const ctaElements: { [key: string]: JSX.Element } = {
custom: <h1>This is just H1 tag, you can any component as CTA element</h1>,
button: (
<Button size="lg" icon="fa fa-plus" onClick={action('cta button clicked')}>
<Button size="lg" icon="plus" onClick={action('cta button clicked')}>
Add datasource
</Button>
),
@@ -65,7 +65,7 @@ storiesOf('General/ConfirmButton', module)
action('Saved')('save!');
}}
>
<Button size={size} variant="secondary" icon="fa fa-pencil">
<Button size={size} variant="secondary" icon="pen">
{buttonText}
</Button>
</ConfirmButton>
@@ -18,7 +18,7 @@ export const DeleteButton: FC<Props> = ({ size, disabled, onConfirm }) => {
disabled={disabled}
onConfirm={onConfirm}
>
<Button variant="destructive" icon="fa fa-remove" size={size || 'sm'} />
<Button variant="destructive" icon="times" size={size || 'sm'} />
</ConfirmButton>
);
};
@@ -73,7 +73,7 @@ export const DataLinksEditor: FC<DataLinksEditorProps> = React.memo(
)}
{(!value || (value && value.length < (maxLinks || Infinity))) && (
<Button variant="secondary" icon="fa fa-plus" onClick={() => onAdd()}>
<Button variant="secondary" icon="plus" onClick={() => onAdd()}>
Add link
</Button>
)}
@@ -100,7 +100,7 @@ export const DataLinksInlineEditor: React.FC<DataLinksInlineEditorProps> = ({ li
)}
<FullWidthButtonContainer>
<Button size="sm" icon="fa fa-plus" onClick={onDataLinkAdd} variant="secondary">
<Button size="sm" icon="plus" onClick={onDataLinkAdd} variant="secondary">
Add link
</Button>
</FullWidthButtonContainer>
@@ -1,6 +1,7 @@
import React, { FunctionComponent, ReactNode } from 'react';
import classNames from 'classnames';
import { Tooltip, PopoverContent } from '../Tooltip/Tooltip';
import { Icon } from '../Icon/Icon';
interface Props {
children: ReactNode;
@@ -33,7 +34,7 @@ export const FormLabel: FunctionComponent<Props> = ({
{tooltip && (
<Tooltip placement="top" content={tooltip} theme={'info'}>
<div className="gf-form-help-icon gf-form-help-icon--right-normal">
<i className="fa fa-info-circle" />
<Icon name="info-circle" />
</div>
</Tooltip>
)}
@@ -135,26 +135,12 @@ $select-input-bg-disabled: $input-bg-disabled;
position: absolute;
height: 100%;
right: 8px;
top: 1px;
margin-top: -1px;
display: inline-block;
text-align: right;
}
.gf-form-select-box__select-arrow {
border-color: $input-color-select-arrow transparent transparent;
border-style: solid;
border-width: 4px 4px 2.5px;
display: inline-block;
position: absolute;
top: 50%;
right: 2px;
margin-top: -2px;
&.gf-form-select-box__select-arrow--reversed {
border-color: transparent transparent $input-color-select-arrow;
border-width: 0 4px 4px;
}
}
.gf-form-input--form-dropdown {
padding: 0;
border: 0;
@@ -43,6 +43,13 @@ export const Icon = React.forwardRef<HTMLDivElement, IconProps>(
const theme = useTheme();
const styles = getIconStyles(theme, type);
const svgSize = getSvgSize(size, theme);
/* Temporary solution to display also font awesome icons */
const isFontAwesome = name?.includes('fa-');
if (isFontAwesome) {
return <i className={cx(name, className)} {...divElementProps} style={style} />;
}
const iconName = type === 'default' ? `Uil${toPascalCase(name)}` : toPascalCase(name);
/* Unicons don't have type definitions */
@@ -0,0 +1,21 @@
import React, { FunctionComponent } from 'react';
import { SvgProps } from '../Icon';
export const Bell: FunctionComponent<SvgProps> = ({ size, ...rest }) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
width={size}
height={size}
{...rest}
>
<path
opacity="0.6"
d="M18,13.18463V10c0-3.31372-2.68628-6-6-6s-6,2.68628-6,6v3.18463C4.83832,13.59863,4.00146,14.69641,4,16v2c0,0.00037,0,0.00073,0,0.00116C4.00031,18.5531,4.44806,19.00031,5,19h14c0.00037,0,0.00073,0,0.00116,0C19.5531,18.99969,20.00031,18.55194,20,18v-2C19.99854,14.69641,19.16168,13.59863,18,13.18463z"
/>
<path d="M8.14233 19c.4472 1.72119 1.99689 2.99817 3.85767 3 1.86078-.00183 3.41046-1.27881 3.85767-3H8.14233zM12 4c.34149 0 .67413.03516 1 .08997V3c0-.55231-.44769-1-1-1s-1 .44769-1 1v1.08997C11.32587 4.03516 11.65851 4 12 4z" />
</svg>
);
};
@@ -1,7 +1,7 @@
import React, { FunctionComponent } from 'react';
import { SvgProps } from '../Icon';
export const Favorite: FunctionComponent<SvgProps> = ({ size, color, secondaryColor, ...rest }) => {
export const Favorite: FunctionComponent<SvgProps> = ({ size, ...rest }) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width={size} height={size} {...rest}>
<path d="M17.56249,21.55957a.99941.99941,0,0,1-.46581-.11523L12,18.76465,6.90332,21.44434a.9999.9999,0,0,1-1.45117-1.05372l.97363-5.67578-4.124-4.01953a.99965.99965,0,0,1,.55469-1.70508l5.69824-.82812,2.54883-5.16406a1.04012,1.04012,0,0,1,1.793,0l2.54883,5.16406,5.69824.82812a.99965.99965,0,0,1,.55469,1.70508l-4.124,4.01953.97363,5.67578a1.00024,1.00024,0,0,1-.98536,1.169Z" />
@@ -0,0 +1,10 @@
import React, { FunctionComponent } from 'react';
import { SvgProps } from '../Icon';
export const Folder: FunctionComponent<SvgProps> = ({ size, ...rest }) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width={size} height={size} {...rest}>
<path d="M19,21.5H5a3.00328,3.00328,0,0,1-3-3V5.5a3.00328,3.00328,0,0,1,3-3H9.55859A2.99629,2.99629,0,0,1,12.4043,4.55078L12.7207,5.5H19a3.00328,3.00328,0,0,1,3,3v10A3.00328,3.00328,0,0,1,19,21.5Z" />
</svg>
);
};
@@ -0,0 +1,21 @@
import React, { FunctionComponent } from 'react';
import { SvgProps } from '../Icon';
export const FolderPlus: FunctionComponent<SvgProps> = ({ size, ...rest }) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
width={size}
height={size}
{...rest}
>
<path
opacity="0.6"
d="M19,21.5H5a3.00328,3.00328,0,0,1-3-3V5.5a3.00328,3.00328,0,0,1,3-3H9.55859A2.99629,2.99629,0,0,1,12.4043,4.55078L12.7207,5.5H19a3.00328,3.00328,0,0,1,3,3v10A3.00328,3.00328,0,0,1,19,21.5Z"
/>
<path d="M14,12.5H13v-1a1,1,0,0,0-2,0v1H10a1,1,0,0,0,0,2h1v1a1,1,0,0,0,2,0v-1h1a1,1,0,0,0,0-2Z" />
</svg>
);
};
@@ -0,0 +1,70 @@
import React, { FunctionComponent } from 'react';
import { SvgProps } from '../Icon';
export const Grafana: FunctionComponent<SvgProps> = ({ size, ...rest }) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 85.12 92.46" height={size} width={size} {...rest}>
<defs>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="42.562" y1="113.2595" x2="42.562" y2="28.7828">
<stop offset="0" style={{ stopColor: '#FFF200' }} />
<stop offset="1" style={{ stopColor: '#F15A29' }} />
</linearGradient>
</defs>
<path
fill="url(#SVGID_1_)"
d="M85.01,40.8c-0.14-1.55-0.41-3.35-0.93-5.32c-0.51-1.97-1.28-4.13-2.39-6.37c-1.12-2.24-2.57-4.57-4.47-6.82
c-0.74-0.88-1.54-1.76-2.42-2.6c1.3-5.17-1.59-9.65-1.59-9.65c-4.98-0.31-8.14,1.54-9.31,2.39c-0.2-0.08-0.39-0.17-0.59-0.25
c-0.85-0.34-1.72-0.66-2.61-0.95c-0.89-0.28-1.81-0.54-2.74-0.76c-0.94-0.22-1.89-0.4-2.86-0.55c-0.17-0.03-0.34-0.05-0.51-0.07
C52.41,2.9,46.18,0,46.18,0c-6.95,4.41-8.27,10.57-8.27,10.57s-0.03,0.14-0.07,0.36c-0.38,0.11-0.77,0.22-1.15,0.34
c-0.53,0.16-1.06,0.36-1.59,0.55c-0.53,0.21-1.06,0.41-1.58,0.64c-1.05,0.45-2.09,0.96-3.1,1.53c-0.99,0.55-1.95,1.16-2.9,1.82
c-0.14-0.06-0.24-0.11-0.24-0.11c-9.62-3.68-18.17,0.75-18.17,0.75c-0.78,10.24,3.84,16.68,4.76,17.86
c-0.23,0.63-0.44,1.27-0.64,1.92c-0.71,2.32-1.24,4.7-1.57,7.16c-0.05,0.35-0.09,0.71-0.13,1.07C2.63,48.84,0,57.84,0,57.84
c7.42,8.53,16.07,9.06,16.07,9.06c0.01-0.01,0.02-0.01,0.02-0.02c1.1,1.96,2.37,3.83,3.8,5.57c0.6,0.73,1.23,1.43,1.88,2.11
c-2.71,7.74,0.38,14.18,0.38,14.18c8.26,0.31,13.69-3.61,14.83-4.52c0.82,0.28,1.66,0.53,2.5,0.74c2.54,0.65,5.14,1.04,7.74,1.15
c0.65,0.03,1.3,0.04,1.95,0.04l0.31,0l0.21-0.01l0.41-0.01l0.4-0.02l0.01,0.01c3.89,5.55,10.74,6.34,10.74,6.34
c4.87-5.13,5.15-10.22,5.15-11.33l0,0c0,0,0-0.04,0-0.07c0-0.09,0-0.15,0-0.15s0,0,0,0c0-0.08-0.01-0.15-0.01-0.23
c1.02-0.72,2-1.49,2.92-2.31c1.95-1.76,3.65-3.77,5.06-5.93c0.13-0.2,0.26-0.41,0.39-0.62c5.51,0.32,9.39-3.41,9.39-3.41
c-0.91-5.74-4.18-8.54-4.87-9.07l0,0c0,0-0.03-0.02-0.07-0.05c-0.04-0.03-0.06-0.05-0.06-0.05l0,0c-0.04-0.02-0.08-0.05-0.12-0.08
c0.03-0.35,0.06-0.69,0.08-1.04c0.04-0.62,0.06-1.24,0.06-1.85l0-0.46l0-0.23l0-0.12c0-0.16,0-0.1,0-0.16l-0.02-0.38l-0.03-0.52
c-0.01-0.18-0.02-0.34-0.04-0.5c-0.01-0.16-0.03-0.32-0.05-0.48l-0.06-0.48l-0.07-0.47c-0.09-0.63-0.21-1.26-0.36-1.88
c-0.58-2.47-1.54-4.82-2.82-6.93c-1.28-2.11-2.86-3.98-4.65-5.56c-1.79-1.58-3.79-2.85-5.9-3.79c-2.1-0.95-4.31-1.55-6.51-1.83
c-1.1-0.14-2.2-0.2-3.28-0.19l-0.41,0.01l-0.1,0c-0.03,0-0.15,0-0.14,0l-0.17,0.01l-0.4,0.03c-0.15,0.01-0.31,0.02-0.45,0.04
c-0.56,0.05-1.11,0.13-1.66,0.23c-2.18,0.41-4.24,1.2-6.06,2.28c-1.82,1.09-3.39,2.45-4.68,3.98c-1.28,1.54-2.28,3.24-2.96,5
c-0.69,1.76-1.07,3.58-1.18,5.35c-0.03,0.44-0.04,0.88-0.03,1.32c0,0.11,0,0.22,0.01,0.33l0.01,0.35c0.02,0.21,0.03,0.42,0.05,0.63
c0.09,0.9,0.25,1.75,0.49,2.58c0.48,1.66,1.25,3.15,2.2,4.43c0.95,1.28,2.08,2.33,3.28,3.15c1.2,0.82,2.49,1.41,3.76,1.79
c1.27,0.38,2.54,0.54,3.74,0.53c0.15,0,0.3,0,0.44-0.01c0.08,0,0.16-0.01,0.24-0.01c0.08,0,0.16-0.01,0.24-0.01
c0.13-0.01,0.25-0.03,0.38-0.04c0.03,0,0.07-0.01,0.11-0.01l0.12-0.02c0.08-0.01,0.15-0.02,0.23-0.03c0.16-0.02,0.29-0.05,0.43-0.08
c0.14-0.03,0.28-0.05,0.42-0.09c0.27-0.06,0.54-0.14,0.8-0.22c0.52-0.17,1.01-0.38,1.46-0.61c0.45-0.23,0.87-0.5,1.26-0.77
c0.11-0.08,0.22-0.16,0.33-0.25c0.42-0.33,0.48-0.94,0.15-1.35c-0.29-0.36-0.79-0.45-1.19-0.23c-0.1,0.05-0.2,0.11-0.3,0.16
c-0.35,0.17-0.71,0.32-1.09,0.45c-0.39,0.12-0.79,0.22-1.2,0.29c-0.21,0.03-0.42,0.06-0.63,0.08c-0.11,0.01-0.21,0.02-0.32,0.02
c-0.11,0-0.22,0.01-0.32,0.01c-0.1,0-0.21,0-0.31-0.01c-0.13-0.01-0.26-0.01-0.39-0.02c0,0-0.07,0-0.01,0l-0.04,0L51.4,61.6
c-0.06-0.01-0.12-0.01-0.17-0.02c-0.12-0.01-0.23-0.03-0.35-0.04c-0.93-0.13-1.88-0.4-2.79-0.82c-0.91-0.41-1.79-0.98-2.57-1.69
c-0.79-0.71-1.48-1.56-2.01-2.52c-0.54-0.96-0.92-2.03-1.09-3.16c-0.09-0.56-0.13-1.14-0.11-1.71c0.01-0.16,0.01-0.31,0.02-0.47
c0,0.04,0-0.02,0-0.03l0-0.06l0.01-0.12c0.01-0.08,0.01-0.15,0.02-0.23c0.03-0.31,0.08-0.62,0.13-0.92
c0.43-2.45,1.65-4.83,3.55-6.65c0.47-0.45,0.98-0.87,1.53-1.25c0.55-0.37,1.12-0.7,1.73-0.98c0.6-0.28,1.23-0.5,1.88-0.68
c0.65-0.17,1.31-0.29,1.98-0.35c0.34-0.03,0.67-0.04,1.01-0.04c0.09,0,0.16,0,0.23,0l0.27,0.01l0.17,0.01c0.07,0,0,0,0.03,0l0.07,0
l0.27,0.02c0.73,0.06,1.46,0.16,2.17,0.32c1.43,0.32,2.83,0.85,4.13,1.57c2.6,1.44,4.81,3.69,6.17,6.4c0.69,1.35,1.16,2.81,1.4,4.31
c0.06,0.38,0.1,0.76,0.13,1.14l0.02,0.29l0.01,0.29c0.01,0.1,0.01,0.19,0.01,0.29c0,0.09,0.01,0.2,0,0.27l0,0.25l-0.01,0.28
c-0.01,0.19-0.02,0.49-0.03,0.67c-0.03,0.42-0.07,0.83-0.12,1.24c-0.05,0.41-0.12,0.82-0.19,1.22c-0.08,0.4-0.17,0.81-0.27,1.21
c-0.2,0.8-0.46,1.59-0.76,2.36c-0.61,1.54-1.42,3-2.4,4.36c-1.96,2.7-4.64,4.9-7.69,6.29c-1.52,0.69-3.13,1.19-4.78,1.47
c-0.82,0.14-1.66,0.22-2.5,0.25l-0.15,0.01l-0.13,0l-0.27,0l-0.41,0l-0.21,0c0.11,0-0.02,0-0.01,0l-0.08,0
c-0.45-0.01-0.9-0.03-1.34-0.07c-1.79-0.13-3.55-0.45-5.27-0.95c-1.71-0.49-3.38-1.16-4.95-2c-3.14-1.68-5.95-3.98-8.15-6.76
c-1.11-1.38-2.07-2.87-2.87-4.43c-0.8-1.56-1.42-3.2-1.89-4.88c-0.46-1.68-0.75-3.39-0.86-5.12l-0.02-0.32l-0.01-0.08l0-0.07l0-0.14
l-0.01-0.28l0-0.07l0-0.1l0-0.2l-0.01-0.4l0-0.08c0,0.01,0,0.01,0-0.03l0-0.16c0-0.21,0.01-0.42,0.01-0.63
c0.03-0.85,0.1-1.73,0.21-2.61c0.11-0.88,0.26-1.76,0.44-2.63c0.18-0.87,0.39-1.74,0.64-2.59c0.49-1.71,1.1-3.36,1.82-4.92
c1.44-3.12,3.34-5.88,5.61-8.09c0.57-0.55,1.16-1.08,1.77-1.57c0.61-0.49,1.25-0.95,1.9-1.37c0.65-0.43,1.32-0.82,2.02-1.18
c0.34-0.19,0.7-0.35,1.05-0.52c0.18-0.08,0.36-0.16,0.53-0.24c0.18-0.08,0.36-0.16,0.54-0.23c0.72-0.3,1.46-0.56,2.21-0.8
c0.19-0.06,0.38-0.11,0.56-0.17c0.19-0.06,0.38-0.1,0.57-0.16c0.38-0.11,0.76-0.2,1.14-0.29c0.19-0.05,0.39-0.08,0.58-0.13
c0.19-0.04,0.38-0.08,0.58-0.12c0.19-0.04,0.39-0.07,0.58-0.11l0.29-0.05l0.29-0.04c0.2-0.03,0.39-0.06,0.59-0.09
c0.22-0.04,0.44-0.05,0.66-0.09c0.18-0.02,0.48-0.06,0.65-0.08c0.14-0.01,0.28-0.03,0.41-0.04l0.28-0.03l0.14-0.01l0.16-0.01
c0.22-0.01,0.44-0.03,0.66-0.04l0.33-0.02c0,0,0.12,0,0.02,0l0.07,0l0.14-0.01c0.19-0.01,0.38-0.02,0.56-0.03
c0.75-0.02,1.5-0.02,2.24,0c1.48,0.06,2.93,0.22,4.34,0.48c2.82,0.53,5.49,1.43,7.89,2.62c2.41,1.18,4.57,2.63,6.44,4.2
c0.12,0.1,0.23,0.2,0.35,0.3c0.11,0.1,0.23,0.2,0.34,0.3c0.23,0.2,0.44,0.41,0.66,0.61c0.22,0.2,0.43,0.41,0.64,0.62
c0.2,0.21,0.41,0.41,0.61,0.63c0.8,0.84,1.53,1.69,2.19,2.55c1.33,1.71,2.39,3.44,3.24,5.07c0.05,0.1,0.11,0.2,0.16,0.3
c0.05,0.1,0.1,0.2,0.15,0.3c0.1,0.2,0.2,0.4,0.29,0.6c0.09,0.2,0.19,0.39,0.27,0.59c0.09,0.2,0.17,0.39,0.25,0.58
c0.32,0.76,0.61,1.49,0.84,2.18c0.39,1.11,0.67,2.11,0.89,2.98c0.09,0.35,0.42,0.58,0.78,0.55c0.37-0.03,0.66-0.34,0.66-0.71
C85.14,43.15,85.11,42.05,85.01,40.8z"
/>
</svg>
);
};
@@ -0,0 +1,23 @@
import React, { FunctionComponent } from 'react';
import { SvgProps } from '../Icon';
export const Import: FunctionComponent<SvgProps> = ({ size, ...rest }) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
width={size}
height={size}
{...rest}
>
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" viewBox="0 0 24 24">
<path d="M19,22H5c-1.65611-0.00181-2.99819-1.34389-3-3v-4c0-0.55229,0.44772-1,1-1s1,0.44771,1,1v4c0.00037,0.55213,0.44787,0.99963,1,1h14c0.55213-0.00037,0.99963-0.44787,1-1v-4c0-0.55229,0.44772-1,1-1s1,0.44771,1,1v4C21.99819,20.65611,20.65611,21.99819,19,22z" />
<path
opacity="0.6"
d="M16.707,10.293c-0.39027-0.39048-1.02319-0.39065-1.41368-0.00038c-0.00013,0.00013-0.00026,0.00026-0.00038,0.00038L13,12.58594V3c0-0.55228-0.44771-1-1-1s-1,0.44772-1,1v9.58594L8.707,10.293c-0.39402-0.38691-1.02709-0.38116-1.414,0.01286c-0.38195,0.38896-0.38195,1.01218,0,1.40114l4,4c0.39028,0.39048,1.02321,0.39065,1.41369,0.00037c0.00012-0.00012,0.00025-0.00025,0.00037-0.00037l4-4c0.39045-0.3903,0.39058-1.02322,0.00028-1.41367C16.70723,10.29322,16.70712,10.29311,16.707,10.293z"
/>
</svg>
</svg>
);
};
@@ -0,0 +1,21 @@
import React, { FunctionComponent } from 'react';
import { SvgProps } from '../Icon';
export const PlusSquare: FunctionComponent<SvgProps> = ({ size, ...rest }) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
width={size}
height={size}
{...rest}
>
<path d="M17,11H13V7a1,1,0,0,0-2,0v4H7a1,1,0,0,0,0,2h4v4a1,1,0,0,0,2,0V13h4a1,1,0,0,0,0-2Z" />
<path
opacity="0.6"
d="M21,2H3A.99974.99974,0,0,0,2,3V21a.99974.99974,0,0,0,1,1H21a.99974.99974,0,0,0,1-1V3A.99974.99974,0,0,0,21,2ZM17,13H13v4a1,1,0,0,1-2,0V13H7a1,1,0,0,1,0-2h4V7a1,1,0,0,1,2,0v4h4a1,1,0,0,1,0,2Z"
/>
</svg>
);
};
@@ -2,3 +2,9 @@ export * from './Apps';
export * from './Cog';
export * from './Shield';
export * from './Favorite';
export * from './Grafana';
export * from './Bell';
export * from './PlusSquare';
export * from './FolderPlus';
export * from './Folder';
export * from './Import';
@@ -1,5 +1,6 @@
import React from 'react';
import { Tooltip, TooltipProps, PopoverContent } from '../Tooltip/Tooltip';
import { Icon } from '../Icon/Icon';
interface InfoTooltipProps extends Omit<TooltipProps, 'children' | 'content'> {
children: PopoverContent;
@@ -8,7 +9,7 @@ interface InfoTooltipProps extends Omit<TooltipProps, 'children' | 'content'> {
export const InfoTooltip = ({ children, ...restProps }: InfoTooltipProps) => {
return (
<Tooltip content={children} {...restProps}>
<i className="fa fa-info-circle" />
<Icon name="info-circle" />
</Tooltip>
);
};
@@ -129,7 +129,7 @@ class UnThemedLogDetailsRow extends PureComponent<Props, State> {
<LinkButton
variant="link"
size={'sm'}
icon={cx('fa', link.onClick ? 'fa-list' : 'fa-external-link')}
icon={link.onClick ? 'list-ul' : 'external-link-alt'}
href={link.href}
target={'_blank'}
onClick={
@@ -16,7 +16,7 @@ export const ModalHeader: React.FC<Props> = ({ icon, title, children }) => {
return (
<>
<h2 className={styles.modalHeaderTitle}>
{icon && <Icon name={icon} className={styles.modalHeaderIcon} />}
{icon && <Icon name={icon} size="lg" className={styles.modalHeaderIcon} />}
{title}
</h2>
{children}
@@ -1,4 +1,5 @@
import React from 'react';
import { cx } from 'emotion';
import { IconName } from '../../types';
import { Icon } from '../Icon/Icon';
@@ -8,19 +9,10 @@ interface Props {
}
export const ModalTabContent: React.FC<Props> = ({ icon, iconClass, children }) => {
let iconElem;
const showIcon = icon || iconClass;
if (iconClass) {
iconElem = <i className={iconClass}></i>;
}
if (icon) {
iconElem = <Icon name={icon} />;
}
return (
<div className="share-modal-body">
<div className="share-modal-header">
{showIcon && <div className="share-modal-big-icon">{iconElem}</div>}
{icon && <Icon name={icon} size="xxl" className={cx(iconClass, 'share-modal-big-icon')} />}
<div className="share-modal-content">{children}</div>
</div>
</div>
@@ -7,7 +7,7 @@ import { ModalHeader } from './ModalHeader';
interface ModalTab {
value: string;
label: string;
icon?: string;
icon?: IconName;
}
interface Props {
@@ -1,6 +1,7 @@
import React, { PureComponent } from 'react';
import uniqueId from 'lodash/uniqueId';
import { Tooltip } from '../Tooltip/Tooltip';
import { Icon } from '../Icon/Icon';
import * as PopperJS from 'popper.js';
export interface Props {
@@ -54,7 +55,7 @@ export class Switch extends PureComponent<Props, State> {
{tooltip && (
<Tooltip placement={tooltipPlacement ? tooltipPlacement : 'auto'} content={tooltip} theme={'info'}>
<div className="gf-form-help-icon gf-form-help-icon--right-normal">
<i className="fa fa-info-circle" />
<Icon name="info-circle" />
</div>
</Tooltip>
)}
@@ -1,12 +1,14 @@
import React, { FC } from 'react';
import { css, cx } from 'emotion';
import { GrafanaTheme } from '@grafana/data';
import { Icon } from '../Icon/Icon';
import { IconName } from '../../types';
import { stylesFactory, useTheme } from '../../themes';
export interface TabProps {
label: string;
active?: boolean;
icon?: string;
icon?: IconName;
onChangeTab: () => void;
}
@@ -26,15 +28,10 @@ const getTabStyles = stylesFactory((theme: GrafanaTheme) => {
color: ${colors.text};
cursor: pointer;
i {
svg {
margin-right: ${theme.spacing.sm};
}
.gicon {
position: relative;
top: -2px;
}
&:hover,
&:focus {
color: ${colors.linkHover};
@@ -67,7 +64,7 @@ export const Tab: FC<TabProps> = ({ label, active, icon, onChangeTab }) => {
return (
<li className={cx(tabsStyles.tabItem, active && tabsStyles.activeStyle)} onClick={onChangeTab}>
{icon && <i className={icon} />}
{icon && <Icon name={icon} />}
{label}
</li>
);
@@ -200,7 +200,7 @@ export class ThresholdsEditor extends PureComponent<Props, State> {
return (
<div className={styles.wrapper}>
<FullWidthButtonContainer className={styles.addButton}>
<Button size="sm" icon="fa fa-plus" onClick={() => this.onAddThreshold()} variant="secondary">
<Button size="sm" icon="plus" onClick={() => this.onAddThreshold()} variant="secondary">
Add threshold
</Button>
</FullWidthButtonContainer>
@@ -82,7 +82,7 @@ const getBodyStyles = stylesFactory((theme: GrafanaTheme) => {
return {
title: css`
color: ${theme.colors.text}
color: ${theme.colors.text};
background-color: ${colors.background};
font-size: ${theme.typography.size.md};
border: 1px solid transparent;
@@ -62,7 +62,7 @@ export const TimeRangeForm: React.FC<Props> = props => {
[timeZone]
);
const icon = isFullscreen ? null : <Button icon="fa fa-calendar" variant="secondary" onClick={onOpen} />;
const icon = isFullscreen ? null : <Button icon="calendar-alt" variant="secondary" onClick={onOpen} />;
return (
<>
@@ -118,7 +118,7 @@ export class TransformationsEditor extends React.PureComponent<TransformationsEd
return (
<>
{this.renderTransformationEditors()}
<Button variant="secondary" icon="fa fa-plus" onClick={this.onTransformationAdd}>
<Button variant="secondary" icon="plus" onClick={this.onTransformationAdd}>
Add transformation
</Button>
</>
@@ -98,7 +98,7 @@ export class LegacyValueMappingsEditor extends PureComponent<Props, State> {
removeValueMapping={() => this.onRemoveMapping(valueMapping.id)}
/>
))}
<Button variant="primary" icon="fa fa-plus" onClick={this.onAddMapping}>
<Button variant="primary" icon="plus" onClick={this.onAddMapping}>
Add mapping
</Button>
</div>
@@ -68,7 +68,7 @@ export const ValueMappingsEditor: React.FC<Props> = ({ valueMappings, onChange,
<FullWidthButtonContainer>
<Button
size="sm"
icon="fa fa-plus"
icon="plus"
onClick={onAdd}
aria-label="ValueMappingsEditor add mapping button"
variant="secondary"
@@ -35,7 +35,7 @@ exports[`Render should render component 1`] = `
}
/>
<Button
icon="fa fa-plus"
icon="plus"
onClick={[Function]}
variant="primary"
>
@@ -23,7 +23,7 @@ export function ValuePicker<T>({ label, icon, options, onChange, variant }: Valu
<>
{!isPicking && (
<FullWidthButtonContainer>
<Button size="sm" icon={`fa fa-${icon || 'plus'}`} onClick={() => setIsPicking(true)} variant={variant}>
<Button size="sm" icon={icon || 'plus'} onClick={() => setIsPicking(true)} variant={variant}>
{label}
</Button>
</FullWidthButtonContainer>
+41 -1
View File
@@ -1,6 +1,8 @@
export type IconType = 'mono' | 'default';
export type IconName =
| 'fa fa-fw fa-unlock'
| 'fa fa-envelope'
| 'question-circle'
| 'plus'
| 'angle-up'
@@ -11,12 +13,19 @@ export type IconName =
| 'plane'
| 'power'
| 'trash-alt'
| 'plus-square'
| 'folder-plus'
| 'folder-open'
| 'file-copy-alt'
| 'exchange-alt'
| 'import'
| 'exclamation-triangle'
| 'times'
| 'cloud-upload'
| 'step-backward'
| 'square-shape'
| 'filter'
| 'share-alt'
| 'tag-alt'
| 'forward'
| 'check'
| 'add-panel'
@@ -24,6 +33,8 @@ export type IconName =
| 'lock'
| 'panel-add'
| 'arrow-random'
| 'arrow-down'
| 'arrow-up'
| 'arrow-from-right'
| 'keyboard'
| 'search'
@@ -40,11 +51,15 @@ export type IconName =
| 'link'
| 'upload'
| 'home-alt'
| 'channel-add'
| 'calendar-alt'
| 'calculator-alt'
| 'compass'
| 'sliders-v-alt'
| 'bell'
| 'database'
| 'user'
| 'camera'
| 'plug'
| 'shield'
| 'key-skeleton-alt'
@@ -58,22 +73,34 @@ export type IconName =
| 'bug'
| 'cube'
| 'star'
| 'list-ul'
| 'edit'
| 'shield'
| 'eye'
| 'filter'
| 'monitor'
| 'plus-circle'
| 'arrow-left'
| 'repeat'
| 'external-link-alt'
| 'favorite';
export const getAvailableIcons = (): IconName[] => [
'question-circle',
'plane',
'plus',
'plus-circle',
'angle-up',
'shield',
'angle-down',
'angle-left',
'angle-right',
'calendar-alt',
'tag-alt',
'calculator-alt',
'pen',
'repeat',
'external-link-alt',
'power',
'trash-alt',
'exclamation-triangle',
@@ -81,6 +108,7 @@ export const getAvailableIcons = (): IconName[] => [
'step-backward',
'square-shape',
'share-alt',
'camera',
'forward',
'check',
'add-panel',
@@ -89,6 +117,7 @@ export const getAvailableIcons = (): IconName[] => [
'panel-add',
'arrow-random',
'arrow-from-right',
'arrow-left',
'keyboard',
'search',
'chart-line',
@@ -116,7 +145,9 @@ export const getAvailableIcons = (): IconName[] => [
'graph-bar',
'book',
'bolt',
'cloud-upload',
'comments-alt',
'list-ul',
'document-info',
'info-circle',
'bug',
@@ -124,6 +155,15 @@ export const getAvailableIcons = (): IconName[] => [
'star',
'edit',
'eye',
'channel-add',
'monitor',
'favorite',
'folder-plus',
'plus-square',
'import',
'folder-open',
'file-copy-alt',
'arrow-down',
'arrow-up',
'exchange-alt',
];
+1 -1
View File
@@ -116,7 +116,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
children = append(children, &dtos.NavLink{Text: "Folder", SubTitle: "Create a new folder to organize your dashboards", Id: "folder", Icon: "folder-plus", Url: setting.AppSubUrl + "/dashboards/folder/new"})
}
children = append(children, &dtos.NavLink{Text: "Import", SubTitle: "Import dashboard from file or Grafana.com", Id: "import", Icon: "upload", Url: setting.AppSubUrl + "/dashboard/import"})
children = append(children, &dtos.NavLink{Text: "Import", SubTitle: "Import dashboard from file or Grafana.com", Id: "import", Icon: "import", Url: setting.AppSubUrl + "/dashboard/import"})
data.NavTree = append(data.NavTree, &dtos.NavLink{
Text: "Create",
+8
View File
@@ -16,6 +16,7 @@ import {
SecretFormField,
SeriesColorPickerPopoverWithTheme,
UnitPicker,
Icon,
} from '@grafana/ui';
import { FunctionEditor } from 'app/plugins/datasource/graphite/FunctionEditor';
import ReactProfileWrapper from 'app/features/profile/ReactProfileWrapper';
@@ -32,6 +33,13 @@ import { SearchField, SearchResults, SearchResultsFilter } from '../features/sea
export function registerAngularDirectives() {
react2AngularDirective('footer', Footer, []);
react2AngularDirective('icon', Icon, [
'color',
'name',
'size',
'type',
['onClick', { watchDepth: 'reference', wrapApply: true }],
]);
react2AngularDirective('helpModal', HelpModal, []);
react2AngularDirective('sidemenu', SideMenu, []);
react2AngularDirective('functionEditor', FunctionEditor, ['func', 'onRemove', 'onMoveLeft', 'onMoveRight']);
@@ -20,7 +20,7 @@ export const ErrorLoadingChunk: FunctionComponent<Props> = ({ error }) => (
<h2 className="page-heading">Grafana has likely been updated. Please try reloading the page.</h2>
<br />
<div className="gf-form-group">
<Button size="md" variant="secondary" icon="fa fa-repeat" onClick={() => window.location.reload()}>
<Button size="md" variant="secondary" icon="repeat" onClick={() => window.location.reload()}>
Reload
</Button>
</div>
@@ -1,10 +1,10 @@
import React, { MouseEvent, useContext } from 'react';
import { CallToActionCard, LinkButton, ThemeContext } from '@grafana/ui';
import { CallToActionCard, LinkButton, ThemeContext, Icon, IconName } from '@grafana/ui';
import { css } from 'emotion';
export interface Props {
title: string;
buttonIcon: string;
buttonIcon: IconName;
buttonLink?: string;
buttonTitle: string;
onClick?: (event: MouseEvent) => void;
@@ -45,7 +45,7 @@ const EmptyListCTA: React.FunctionComponent<Props> = ({
<>
{proTip ? (
<span key="proTipFooter">
<i className="fa fa-rocket" />
<Icon name="plane" />
<> ProTip: {proTip} </>
<a href={proTipLink} target={proTipTarget} className="text-link">
{proTipLinkTitle}
@@ -1,5 +1,6 @@
import React, { FormEvent } from 'react';
import { Tab, TabsBar } from '@grafana/ui';
import { css } from 'emotion';
import { Tab, TabsBar, Icon, IconName } from '@grafana/ui';
import appEvents from 'app/core/app_events';
import { NavModel, NavModelItem, NavModelBreadcrumb } from '@grafana/data';
import { CoreEvents } from 'app/types';
@@ -65,7 +66,7 @@ const Navigation = ({ main }: { main: NavModelItem }) => {
label={child.text}
active={child.active}
key={`${child.url}-${index}`}
icon={child.icon}
icon={child.icon as IconName}
onChangeTab={() => goToUrl(index)}
/>
)
@@ -113,10 +114,19 @@ export default class PageHeader extends React.Component<Props, any> {
}
renderHeaderTitle(main: NavModelItem) {
const iconClassName =
main.icon === 'grafana'
? css`
margin-top: 12px;
`
: css`
margin-top: 14px;
`;
return (
<div className="page-header__inner">
<span className="page-header__logo">
{main.icon && <i className={`page-header__icon ${main.icon}`} />}
{main.icon && <Icon name={main.icon as IconName} size="xxl" type="mono" className={iconClassName} />}
{main.img && <img className="page-header__img" src={main.img} />}
</span>
@@ -1,5 +1,5 @@
import React, { Component } from 'react';
import { LegacyForms } from '@grafana/ui';
import { LegacyForms, Icon } from '@grafana/ui';
import { dashboardPermissionLevels } from 'app/types/acl';
const { Select } = LegacyForms;
@@ -15,7 +15,7 @@ export default class DisabledPermissionListItem extends Component<Props, any> {
return (
<tr className="gf-form-disabled">
<td style={{ width: '1%' }}>
<i style={{ width: '25px', height: '25px' }} className="gicon gicon-shield" />
<Icon size="lg" name="shield" />
</td>
<td style={{ width: '90%' }}>
{item.name}
@@ -36,7 +36,7 @@ export default class DisabledPermissionListItem extends Component<Props, any> {
</td>
<td>
<button className="btn btn-inverse btn-small">
<i className="fa fa-lock" />
<Icon name="lock" />
</button>
</td>
</tr>
@@ -1,5 +1,5 @@
import React, { PureComponent } from 'react';
import { LegacyForms } from '@grafana/ui';
import { LegacyForms, Icon } from '@grafana/ui';
import { SelectableValue } from '@grafana/data';
import { dashboardPermissionLevels, DashboardAcl, PermissionLevel } from 'app/types/acl';
import { FolderInfo } from 'app/types';
@@ -17,10 +17,10 @@ function ItemAvatar({ item }: { item: DashboardAcl }) {
return <img className="filter-table__avatar" src={item.teamAvatarUrl} />;
}
if (item.role === 'Editor') {
return <i style={{ width: '25px', height: '25px' }} className="gicon gicon-editor" />;
return <Icon size="lg" name="edit" />;
}
return <i style={{ width: '25px', height: '25px' }} className="gicon gicon-viewer" />;
return <Icon size="lg" name="eye" />;
}
function ItemDescription({ item }: { item: DashboardAcl }) {
@@ -89,11 +89,11 @@ export default class PermissionsListItem extends PureComponent<Props> {
<td>
{!item.inherited ? (
<a className="btn btn-danger btn-small" onClick={this.onRemoveItem}>
<i className="fa fa-remove" />
<Icon name="times" />
</a>
) : (
<button className="btn btn-inverse btn-small">
<i className="fa fa-lock" />
<Icon name="lock" />
</button>
)}
</td>
@@ -8,7 +8,7 @@ import { escapeStringForRegex } from '@grafana/data';
// Components
import { TagOption } from './TagOption';
import { TagBadge } from './TagBadge';
import { resetSelectStyles, LegacyForms } from '@grafana/ui';
import { resetSelectStyles, LegacyForms, Icon } from '@grafana/ui';
const { IndicatorsContainer, NoOptionsMessage } = LegacyForms;
export interface TermCount {
@@ -90,7 +90,7 @@ export class TagFilter extends React.Component<Props, any> {
<div className="tag-filter">
<AsyncSelect {...selectOptions} />
</div>
<i className="gf-form-input-icon fa fa-tag" />
<Icon className="gf-form-input-icon" name="tag-alt" />
</div>
);
}
+1 -1
View File
@@ -6,7 +6,7 @@ import Drop from 'tether-drop';
export function infoPopover() {
return {
restrict: 'E',
template: '<i class="fa fa-info-circle"></i>',
template: `<icon name="'info-circle'"></icon>`,
transclude: true,
link: (scope: any, elem: any, attrs: any, ctrl: any, transclude: any) => {
const offset = attrs.offset || '0 -10px';
@@ -1,17 +1,38 @@
<div class="dashboard-list">
<div class="page-action-bar page-action-bar--narrow" ng-hide="ctrl.folderId && !ctrl.hasFilters && ctrl.sections.length === 0">
<div
class="page-action-bar page-action-bar--narrow"
ng-hide="ctrl.folderId && !ctrl.hasFilters && ctrl.sections.length === 0"
>
<label class="gf-form gf-form--grow gf-form--has-input-icon">
<input type="text" class="gf-form-input max-width-30" placeholder="Search dashboards by name" tabindex="1" give-focus="true" ng-model="ctrl.query.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.onQueryChange()" />
<i class="gf-form-input-icon fa fa-search"></i>
<input
type="text"
class="gf-form-input max-width-30"
placeholder="Search dashboards by name"
tabindex="1"
give-focus="true"
ng-model="ctrl.query.query"
ng-model-options="{ debounce: 500 }"
spellcheck="false"
ng-change="ctrl.onQueryChange()"
/>
<icon class="gf-form-input-icon" name="'search'"></icon>
</label>
<div class="page-action-bar__spacer"></div>
<a class="btn btn-primary" ng-href="{{ctrl.createDashboardUrl()}}" ng-if="ctrl.hasEditPermissionInFolders || ctrl.canSave">
<a
class="btn btn-primary"
ng-href="{{ctrl.createDashboardUrl()}}"
ng-if="ctrl.hasEditPermissionInFolders || ctrl.canSave"
>
New Dashboard
</a>
<a class="btn btn-primary" href="dashboards/folder/new" ng-if="!ctrl.folderId && ctrl.isEditor">
New Folder
</a>
<a class="btn btn-primary" href="{{ctrl.importDashboardUrl()}}" ng-if="ctrl.hasEditPermissionInFolders || ctrl.canSave">
<a
class="btn btn-primary"
href="{{ctrl.importDashboardUrl()}}"
ng-if="ctrl.hasEditPermissionInFolders || ctrl.canSave"
>
Import
</a>
</div>
@@ -25,22 +46,20 @@
<div class="gf-form-input gf-form-input--plaintext" ng-show="ctrl.query.tag.length > 0">
<span ng-repeat="tagName in ctrl.query.tag">
<a ng-click="ctrl.removeTag(tagName, $event)" tag-color-from-name="tagName" class="tag label label-tag">
<i class="fa fa-remove"></i>&nbsp;{{tagName}}
<icon name="'times'"></icon>&nbsp;{{tagName}}
</a>
</span>
</div>
</div>
<div class="gf-form" ng-show="ctrl.query.starred">
<label class="gf-form-label">
<a class="pointer" ng-click="ctrl.removeStarred()">
<i class="fa fa-fw fa-check"></i> Starred
</a>
<a class="pointer" ng-click="ctrl.removeStarred()"> <icon name="'check'"></icon> Starred </a>
</label>
</div>
<div class="gf-form">
<label class="gf-form-label">
<a class="pointer" ng-click="ctrl.clearFilters()" bs-tooltip="'Clear current search query and filters'">
<i class="fa fa-remove"></i>&nbsp;Clear
<icon name="'times'"></icon>&nbsp;Clear
</a>
</label>
</div>
@@ -53,25 +72,25 @@
</em>
</div>
<div class="search-results" ng-show="!ctrl.folderId && !ctrl.hasFilters && ctrl.sections.length === 0">
<div class="search-results" ng-show="!ctrl.folderId && !ctrl.hasFilters && ctrl.sections.length === 0">
<em class="muted">
No dashboards found.
No dashboards found.
</em>
</div>
<div class="search-results" ng-show="ctrl.sections.length > 0">
<search-filters
on-select-all-changed="ctrl.onSelectAllChanged"
all-checked="ctrl.selectAllChecked"
can-move="ctrl.canMove"
can-delete="ctrl.canDelete"
move-to="ctrl.moveTo"
delete-item="ctrl.delete"
tag-filter-options="ctrl.tagFilterOptions"
selected-starred-filter="ctrl.selectedStarredFilter"
on-starred-filter-change="ctrl.onStarredFilterChange"
selected-tag-filter="ctrl.selectedTagFilter"
on-tagfilter-change="ctrl.onTagFilterChange"
on-select-all-changed="ctrl.onSelectAllChanged"
all-checked="ctrl.selectAllChecked"
can-move="ctrl.canMove"
can-delete="ctrl.canDelete"
move-to="ctrl.moveTo"
delete-item="ctrl.delete"
tag-filter-options="ctrl.tagFilterOptions"
selected-starred-filter="ctrl.selectedStarredFilter"
on-starred-filter-change="ctrl.onStarredFilterChange"
selected-tag-filter="ctrl.selectedTagFilter"
on-tagfilter-change="ctrl.onTagFilterChange"
/>
<div class="search-results-container">
<search-results
@@ -83,13 +102,12 @@
/>
</div>
</div>
</div>
<div ng-if="ctrl.canSave && ctrl.folderId && !ctrl.hasFilters && ctrl.sections.length === 0">
<empty-list-cta
title="'This folder doesn\'t have any dashboards yet'"
buttonIcon="'gicon gicon-dashboard-new'"
buttonIcon="'plus-circle'"
buttonLink="'dashboard/new?folderId={{ctrl.folderId}}'"
buttonTitle="'Create Dashboard'"
proTip="'Add/move dashboards to your folder at ->'"
+18 -15
View File
@@ -1,8 +1,6 @@
<div class="search-backdrop" ng-if="ctrl.isOpen"></div>
<div class="search-container" ng-if="ctrl.isOpen">
<search-field
query="ctrl.query"
autoFocus="ctrl.giveSearchFocus"
@@ -10,8 +8,7 @@
on-key-down="ctrl.onKeyDown"
/>
<div class="search-dropdown">
<div class="search-dropdown">
<div class="search-dropdown__col_1">
<div class="search-results-scroller">
<div class="search-results-container" grafana-scrollbar>
@@ -29,32 +26,38 @@
<div class="search-dropdown__col_2">
<div class="search-filter-box" ng-click="ctrl.onFilterboxClick()">
<div class="search-filter-box__header">
<i class="fa fa-filter"></i>
<icon name="'filter'"></icon>
Filter by:
<a class="pointer pull-right small" ng-click="ctrl.clearSearchFilter()">
<i class="fa fa-remove"></i> Clear
<icon name="'times'" size="'sm'"></icon> Clear
</a>
</div>
<tag-filter tags="ctrl.query.tags" tagOptions="ctrl.getTags" on-change="ctrl.onTagFiltersChanged">
</tag-filter>
<tag-filter tags="ctrl.query.tags" tagOptions="ctrl.getTags" on-change="ctrl.onTagFiltersChanged"> </tag-filter>
</div>
<div class="search-filter-box" ng-if="ctrl.isEditor || ctrl.hasEditPermissionInFolders">
<a href="dashboard/new" class="search-filter-box-link">
<i class="gicon gicon-dashboard-new"></i> New dashboard
<icon name="'plus-square'" size="'xl'" style="margin-right: 8px;"></icon> New dashboard
</a>
<a href="dashboards/folder/new" class="search-filter-box-link" ng-if="ctrl.isEditor">
<i class="gicon gicon-folder-new"></i> New folder
<icon name="'folder-plus'" size="'xl'" style="margin-right: 8px;"></icon> New folder
</a>
<a href="dashboard/import" class="search-filter-box-link" ng-if="ctrl.isEditor || ctrl.hasEditPermissionInFolders">
<i class="gicon gicon-dashboard-import"></i> Import dashboard
<a
href="dashboard/import"
class="search-filter-box-link"
ng-if="ctrl.isEditor || ctrl.hasEditPermissionInFolders"
>
<icon name="'import'" size="'xl'" style="margin-right: 8px;"></icon> Import dashboard
</a>
<a class="search-filter-box-link" target="_blank" href="https://grafana.com/dashboards?utm_source=grafana_search">
<img src="public/img/icn-dashboard-tiny.svg" width="20" /> Find dashboards on Grafana.com
<a
class="search-filter-box-link"
target="_blank"
href="https://grafana.com/dashboards?utm_source=grafana_search"
>
<icon name="'apps'" size="'xl'" style="margin-right: 8px;"></icon> Find dashboards on Grafana.com
</a>
</div>
</div>
</div>
</div>
@@ -1,32 +1,45 @@
<div ng-repeat="section in ctrl.results" class="search-section">
<div class="search-section__header pointer" ng-hide="section.hideHeader" ng-class="{'selected': section.selected}" ng-click="ctrl.toggleFolderExpand(section)">
<div
class="search-section__header pointer"
ng-hide="section.hideHeader"
ng-class="{'selected': section.selected}"
ng-click="ctrl.toggleFolderExpand(section)"
>
<div ng-click="ctrl.toggleSelection(section, $event)" class="center-vh">
<gf-form-checkbox
ng-show="ctrl.editable"
on-change="ctrl.selectionChanged($event)"
checked="section.checked"
switch-class="gf-form-checkbox--transparent">
ng-show="ctrl.editable"
on-change="ctrl.selectionChanged($event)"
checked="section.checked"
switch-class="gf-form-checkbox--transparent"
>
</gf-form-checkbox>
</div>
<i class="search-section__header__icon" ng-class="section.icon"></i>
<span class="search-section__header__text">{{::section.title}}</span>
<a ng-show="section.url" href="{{section.url}}" class="search-section__header__link">
<i class="gicon gicon-cog"></i>
<icon name="'cog'"></icon>
</a>
<i class="fa fa-angle-down search-section__header__toggle" ng-show="section.expanded"></i>
<i class="fa fa-angle-right search-section__header__toggle" ng-hide="section.expanded"></i>
<icon class="search-section__header__toggle" name="'angle-down'" ng-show="section.expanded"></icon>
<icon class="search-section__header__toggle" name="'angle-right'" ng-hide="section.expanded"></icon>
</div>
<div class="search-section__header" ng-show="section.hideHeader"></div>
<div ng-if="section.expanded">
<a ng-repeat="item in section.items" class="search-item search-item--indent" ng-class="{'selected': item.selected}" ng-href="{{::item.url}}" aria-label={{ctrl.selectors.dashboards(item.title)}}>
<a
ng-repeat="item in section.items"
class="search-item search-item--indent"
ng-class="{'selected': item.selected}"
ng-href="{{::item.url}}"
aria-label="{{ctrl.selectors.dashboards(item.title)}}"
>
<div ng-click="ctrl.toggleSelection(item, $event)" class="center-vh">
<gf-form-checkbox
ng-show="ctrl.editable"
on-change="ctrl.selectionChanged()"
checked="item.checked"
switch-class="gf-form-checkbox--transparent">
ng-show="ctrl.editable"
on-change="ctrl.selectionChanged()"
checked="item.checked"
switch-class="gf-form-checkbox--transparent"
>
</gf-form-checkbox>
</div>
<span class="search-item__icon">
@@ -37,11 +50,15 @@
<span class="search-item__body-folder-title">{{::item.folderTitle}}</span>
</span>
<span class="search-item__tags">
<span ng-click="ctrl.selectTag(tag, $event)" ng-repeat="tag in item.tags" tag-color-from-name="tag" class="label label-tag">
<span
ng-click="ctrl.selectTag(tag, $event)"
ng-repeat="tag in item.tags"
tag-color-from-name="tag"
class="label label-tag"
>
{{tag}}
</span>
</span>
</a>
</div>
</div>
+1 -1
View File
@@ -11,7 +11,7 @@ export class InvitedCtrl {
$scope.navModel = {
main: {
icon: 'gicon gicon-branding',
icon: 'grafana',
text: 'Invite',
subTitle: 'Register your Grafana account',
breadcrumbs: [{ title: 'Login', url: 'login' }],
@@ -21,7 +21,7 @@ export class ResetPasswordCtrl {
$scope.navModel = {
main: {
icon: 'gicon gicon-branding',
icon: 'grafana',
text: 'Reset Password',
subTitle: 'Reset your Grafana password',
breadcrumbs: [{ title: 'Login', url: 'login' }],
+1 -1
View File
@@ -29,7 +29,7 @@ export class SignUpCtrl {
$scope.navModel = {
main: {
icon: 'gicon gicon-branding',
icon: 'grafana',
text: 'Sign Up',
subTitle: 'Register your Grafana account',
breadcrumbs: [{ title: 'Login', url: 'login' }],
@@ -3,7 +3,7 @@ import { css, cx } from 'emotion';
import { hot } from 'react-hot-loader';
import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux';
import { NavModel } from '@grafana/data';
import { Pagination, Tooltip, HorizontalGroup, stylesFactory, LinkButton, Input } from '@grafana/ui';
import { Pagination, Tooltip, HorizontalGroup, stylesFactory, LinkButton, Input, Icon } from '@grafana/ui';
import { StoreState, UserDTO } from '../../types';
import Page from 'app/core/components/Page/Page';
import { getNavModel } from '../../core/selectors/navModel';
@@ -51,7 +51,7 @@ const UserListAdminPageUnConnected: React.FC<Props> = props => {
value={props.query}
spellCheck={false}
onChange={event => props.changeQuery(event.currentTarget.value)}
prefix={<i className="fa fa-search" />}
prefix={<Icon name="search" />}
/>
<LinkButton href="admin/users/create" variant="primary">
New user
@@ -1,5 +1,5 @@
import React, { PureComponent } from 'react';
import { ConfirmButton, RadioButtonGroup } from '@grafana/ui';
import { ConfirmButton, RadioButtonGroup, Icon } from '@grafana/ui';
import { cx } from 'emotion';
interface Props {
@@ -73,7 +73,7 @@ export class UserPermissions extends PureComponent<Props, State> {
<td colSpan={2}>
{isGrafanaAdmin ? (
<>
<i className="gicon gicon-shield" /> Yes
<Icon name="shield" /> Yes
</>
) : (
<>No</>
@@ -52,11 +52,7 @@ exports[`ServerStats Should render table with stats 1`] = `
>
<span
className="page-header__logo"
>
<i
className="page-header__icon fa fa-fw fa-warning"
/>
</span>
/>
<div
className="page-header__info-block"
>
@@ -100,12 +96,9 @@ exports[`ServerStats Should render table with stats 1`] = `
className="css-payll4"
>
<li
className="css-1aiaexb"
className="css-vohy86"
onClick={[Function]}
>
<i
className="icon"
/>
Admin
</li>
</ul>
@@ -1,5 +1,6 @@
import React, { FC } from 'react';
import { LdapPermissions } from 'app/types';
import { Icon } from '@grafana/ui';
interface Props {
permissions: LdapPermissions;
@@ -21,7 +22,7 @@ export const LdapUserPermissions: FC<Props> = ({ permissions }) => {
<td>
{permissions.isGrafanaAdmin ? (
<>
<i className="gicon gicon-shield" /> Yes
<Icon name="shield" /> Yes
</>
) : (
'No'
+4 -4
View File
@@ -1,7 +1,7 @@
import React, { PureComponent } from 'react';
import { connect, MapStateToProps, MapDispatchToProps } from 'react-redux';
import { css } from 'emotion';
import { Alert, Button } from '@grafana/ui';
import { Alert, Button, IconName } from '@grafana/ui';
import { AngularComponent, getAngularLoader, getDataSourceSrv } from '@grafana/runtime';
import appEvents from 'app/core/app_events';
@@ -130,7 +130,7 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
title: 'Delete Alert',
text: 'Are you sure you want to delete this alert rule?',
text2: 'You need to save dashboard for the delete to take effect',
icon: 'fa-trash',
icon: 'trash-alt',
yesText: 'Delete',
onConfirm: () => {
delete panel.alert;
@@ -178,7 +178,7 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
<h2>{validatonMessage}</h2>
<br />
<div className="gf-form-group">
<Button size={'md'} variant={'secondary'} icon="fa fa-arrow-left" onClick={this.switchToQueryTab}>
<Button size={'md'} variant={'secondary'} icon="arrow-left" onClick={this.switchToQueryTab}>
Go back to Queries
</Button>
</div>
@@ -199,7 +199,7 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
const model = {
title: 'Panel has no alert rule defined',
buttonIcon: 'gicon gicon-alert',
buttonIcon: 'bell' as IconName,
onClick: this.onAddAlert,
buttonTitle: 'Create Alert',
};
@@ -1,11 +1,9 @@
<page-header model="ctrl.navModel"></page-header>
<div class="page-container page-body">
<div ng-if="ctrl.notifications.length">
<div class="page-action-bar">
<div class="page-action-bar__spacer">
</div>
<div class="page-action-bar__spacer"></div>
<a href="alerting/notification/new" class="btn btn-primary">
New channel
@@ -46,14 +44,14 @@
</div>
<div ng-if="ctrl.notifications.length === 0">
<empty-list-cta
title= "'There are no notification channels defined yet'"
buttonIcon= "'gicon gicon-alert-notification-channel'"
buttonLink= "'alerting/notification/new'"
buttonTitle= "'Add channel'"
proTip= "'You can include images in your alert notifications.'"
proTipLink= "'http://docs.grafana.org/alerting/notifications/'"
proTipLinkTitle= "'Learn more'"
proTipTarget= "'_blank'"
title="'There are no notification channels defined yet'"
buttonIcon="'channel-add'"
buttonLink="'alerting/notification/new'"
buttonTitle="'Add channel'"
proTip="'You can include images in your alert notifications.'"
proTipLink="'http://docs.grafana.org/alerting/notifications/'"
proTipLinkTitle="'Learn more'"
proTipTarget="'_blank'"
/>
</div>
</div>
+1 -1
View File
@@ -151,7 +151,7 @@ export class ApiKeysPage extends PureComponent<Props, any> {
{!isAdding && (
<EmptyListCTA
title="You haven't added any API Keys yet."
buttonIcon="gicon gicon-apikeys"
buttonIcon="key-skeleton-alt"
buttonLink="#"
onClick={this.onToggleAdding}
buttonTitle=" New API Key"
@@ -36,7 +36,7 @@ exports[`Render should render CTA if there are no API keys 1`] = `
isLoading={false}
>
<EmptyListCTA
buttonIcon="gicon gicon-apikeys"
buttonIcon="key-skeleton-alt"
buttonLink="#"
buttonTitle=" New API Key"
onClick={[Function]}
@@ -99,6 +99,10 @@ class DashNav extends PureComponent<Props> {
/* Hard-coded value so we don't have to wrap whole component in withTheme because of 1 variable */
const iconClassName = css`
margin-right: 8px;
margin-bottom: -1px;
`;
const mainIconClassName = css`
margin-right: 8px;
`;
const folderTitle = dashboard.meta.folderTitle;
@@ -108,7 +112,7 @@ class DashNav extends PureComponent<Props> {
<>
<div>
<div className="navbar-page-btn">
{!isFullscreen && <Icon name="apps" size="xl" className={iconClassName} />}
{!isFullscreen && <Icon name="apps" size="xl" className={mainIconClassName} />}
{haveFolder && (
<>
<a className="navbar-page-btn__folder" onClick={this.onFolderNameClick}>
@@ -1,5 +1,5 @@
import React, { PureComponent } from 'react';
import { Tooltip } from '@grafana/ui';
import { Tooltip, Icon } from '@grafana/ui';
import { SlideDown } from 'app/core/components/Animations/SlideDown';
import { StoreState, FolderInfo } from 'app/types';
import { DashboardAcl, PermissionLevel, NewDashboardAclItem } from 'app/types/acl';
@@ -71,9 +71,7 @@ export class DashboardPermissions extends PureComponent<Props, State> {
<div className="page-action-bar">
<h3 className="d-inline-block">Permissions</h3>
<Tooltip placement="auto" content={<PermissionsInfo />}>
<div className="page-sub-heading-icon">
<i className="gicon gicon-question gicon--has-hover" />
</div>
<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}>
@@ -1,7 +1,7 @@
import React from 'react';
import { config } from 'app/core/config';
import { css } from 'emotion';
import { TabsBar, Tab, stylesFactory, TabContent, TransformationsEditor } from '@grafana/ui';
import { TabsBar, Tab, stylesFactory, TabContent, TransformationsEditor, IconName } from '@grafana/ui';
import { DataTransformerConfig, LoadingState, PanelData } from '@grafana/data';
import { PanelEditorTab, PanelEditorTabId } from './types';
import { DashboardModel } from '../../state';
@@ -40,7 +40,7 @@ export const PanelEditorTabs: React.FC<PanelEditorTabsProps> = ({ panel, dashboa
label={tab.text}
active={tab.active}
onChangeTab={() => onChangeTab(tab)}
icon={tab.icon}
icon={tab.icon as IconName}
/>
);
})}
@@ -1,5 +1,5 @@
import React, { PureComponent } from 'react';
import { Switch, LegacyForms } from '@grafana/ui';
import { Switch, LegacyForms, Icon } from '@grafana/ui';
const { Select } = LegacyForms;
import { SelectableValue } from '@grafana/data';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
@@ -79,9 +79,7 @@ export class ShareEmbed extends PureComponent<Props, State> {
return (
<div className="share-modal-body">
<div className="share-modal-header">
<div className="share-modal-big-icon">
<i className="gicon gicon-link"></i>
</div>
<Icon name="link" className="share-modal-big-icon" size="xxl" />
<div className="share-modal-content">
<div className="gf-form-group">
<Switch
@@ -1,6 +1,6 @@
import React, { PureComponent } from 'react';
import { saveAs } from 'file-saver';
import { Button, Switch } from '@grafana/ui';
import { Button, Switch, Icon } from '@grafana/ui';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { DashboardExporter } from 'app/features/dashboard/components/DashExportModal';
import { appEvents } from 'app/core/core';
@@ -90,9 +90,7 @@ export class ShareExport extends PureComponent<Props, State> {
return (
<div className="share-modal-body">
<div className="share-modal-header">
<div className="share-modal-big-icon">
<i className="fa fa-cloud-upload"></i>
</div>
<Icon name="cloud-upload" size="xxl" className="share-modal-big-icon" />
<div className="share-modal-content">
<Switch
labelClass="width-16"
@@ -1,6 +1,6 @@
import React, { PureComponent } from 'react';
import { e2e } from '@grafana/e2e';
import { Switch, LegacyForms, ClipboardButton } from '@grafana/ui';
import { Switch, LegacyForms, ClipboardButton, Icon } from '@grafana/ui';
const { Select } = LegacyForms;
import { SelectableValue, PanelModel, AppEvents } from '@grafana/data';
import { DashboardModel } from 'app/features/dashboard/state';
@@ -90,9 +90,7 @@ export class ShareLink extends PureComponent<Props, State> {
return (
<div className="share-modal-body">
<div className="share-modal-header">
<div className="share-modal-big-icon">
<i className="gicon gicon-link"></i>
</div>
<Icon name="link" className="share-modal-big-icon" size="xxl" />
<div className="share-modal-content">
<p className="share-modal-info-text">
Create a direct link to this dashboard or panel, customized with the options below.
@@ -1,5 +1,5 @@
import React, { PureComponent } from 'react';
import { Button, ClipboardButton, LinkButton, LegacyForms } from '@grafana/ui';
import { Button, ClipboardButton, LinkButton, LegacyForms, Icon } from '@grafana/ui';
const { Select, Input } = LegacyForms;
import { AppEvents, SelectableValue } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
@@ -302,9 +302,13 @@ export class ShareSnapshot extends PureComponent<Props, State> {
return (
<div className="share-modal-body">
<div className="share-modal-header">
<div className="share-modal-big-icon">
{isLoading ? <i className="fa fa-spinner fa-spin"></i> : <i className="gicon gicon-snapshots"></i>}
</div>
{isLoading ? (
<div className="share-modal-big-icon">
<i className="fa fa-spinner fa-spin"></i>
</div>
) : (
<Icon name="camera" className="share-modal-big-icon" size="xxl" />
)}
<div className="share-modal-content">
{step === 1 && this.renderStep1()}
{step === 2 && this.renderStep2()}
@@ -20,7 +20,7 @@ export const PanelHeaderMenuItem: FC<Props & PanelMenuItem> = props => {
`;
const shortcutIconClassName = css`
position: absolute;
margin-top: 3px;
top: 7px;
right: ${theme.spacing.xs};
color: ${theme.colors.textWeak};
`;
@@ -9,6 +9,7 @@ import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
import DataSourcesList from './DataSourcesList';
// Types
import { DataSourceSettings, NavModel } from '@grafana/data';
import { IconName } from '@grafana/ui';
import { StoreState } from 'app/types';
import { LayoutMode } from 'app/core/components/LayoutSelector/LayoutSelector';
// Actions
@@ -37,7 +38,7 @@ export interface Props {
const emptyListModel = {
title: 'There are no data sources defined yet',
buttonIcon: 'gicon gicon-datasources',
buttonIcon: 'database' as IconName,
buttonLink: 'datasources/new',
buttonTitle: 'Add data source',
proTip: 'You can also define data sources through configuration files.',
@@ -143,7 +143,7 @@ const DataSourceTypeCard: FC<DataSourceTypeCardProps> = props => {
target="_blank"
rel="noopener"
onClick={onLearnMoreClick}
icon="fa fa-external-link"
icon="external-link-alt"
>
{learnMoreLink.name}
</LinkButton>
@@ -23,7 +23,7 @@ export const NoDataSourceCallToAction = () => {
);
const ctaElement = (
<LinkButton size="lg" href="/datasources/new" icon="gicon gicon-datasources">
<LinkButton size="lg" href="/datasources/new" icon="database">
Add data source
</LinkButton>
);
@@ -10,7 +10,7 @@ import { stylesFactory, withTheme } from '@grafana/ui';
//Types
import { RichHistoryQuery, ExploreId } from 'app/types/explore';
import { SelectableValue, GrafanaTheme } from '@grafana/data';
import { TabsBar, Tab, TabContent, Themeable, CustomScrollbar } from '@grafana/ui';
import { TabsBar, Tab, TabContent, Themeable, CustomScrollbar, IconName } from '@grafana/ui';
//Components
import { RichHistorySettings } from './RichHistorySettings';
@@ -216,7 +216,7 @@ class UnThemedRichHistory extends PureComponent<RichHistoryProps, RichHistorySta
label={t.label}
active={t.value === activeTab}
onChangeTab={() => this.onSelectTab(t)}
icon={t.icon}
icon={t.icon as IconName}
/>
))}
<div className={styles.close} onClick={onClose}>
@@ -63,7 +63,7 @@ export function RichHistorySettings(props: RichHistorySettingsProps) {
title: 'Delete',
text: 'Are you sure you want to permanently delete your query history?',
yesText: 'Delete',
icon: 'fa-trash',
icon: 'trash-alt',
onConfirm: () => {
deleteRichHistory();
appEvents.emit(AppEvents.alertSuccess, ['Query history deleted']);
@@ -2,7 +2,7 @@ import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
import Page from 'app/core/components/Page/Page';
import { Tooltip } from '@grafana/ui';
import { Tooltip, Icon } from '@grafana/ui';
import { NavModel } from '@grafana/data';
import { SlideDown } from 'app/core/components/Animations/SlideDown';
import { getNavModel } from 'app/core/selectors/navModel';
@@ -91,9 +91,7 @@ export class FolderPermissions extends PureComponent<Props, State> {
<div className="page-action-bar">
<h3 className="page-sub-heading">Folder Permissions</h3>
<Tooltip placement="auto" content={<PermissionsInfo />}>
<div className="page-sub-heading-icon">
<i className="gicon gicon-question gicon--has-hover" />
</div>
<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}>
@@ -4,7 +4,7 @@ export class FolderPageLoader {
load(ctrl: any, uid: any, activeChildId: any) {
ctrl.navModel = {
main: {
icon: 'fa fa-folder-open',
icon: 'folder',
id: 'manage-folder',
subTitle: 'Manage folder dashboards & permissions',
url: '',
@@ -13,21 +13,21 @@ export class FolderPageLoader {
children: [
{
active: activeChildId === 'manage-folder-dashboards',
icon: 'fa fa-fw fa-th-large',
icon: 'apps',
id: 'manage-folder-dashboards',
text: 'Dashboards',
url: 'dashboards',
},
{
active: activeChildId === 'manage-folder-permissions',
icon: 'fa fa-fw fa-lock',
icon: 'lock',
id: 'manage-folder-permissions',
text: 'Permissions',
url: 'dashboards/permissions',
},
{
active: activeChildId === 'manage-folder-settings',
icon: 'gicon gicon-cog',
icon: 'cog',
id: 'manage-folder-settings',
text: 'Settings',
url: 'dashboards/settings',
@@ -3,7 +3,7 @@ import { NavModelItem, NavModel } from '@grafana/data';
export function buildNavModel(folder: FolderDTO): NavModelItem {
return {
icon: 'fa fa-folder-open',
icon: 'folder',
id: 'manage-folder',
subTitle: 'Manage folder dashboards & permissions',
url: '',
@@ -12,21 +12,21 @@ export function buildNavModel(folder: FolderDTO): NavModelItem {
children: [
{
active: false,
icon: 'fa fa-fw fa-th-large',
icon: 'apps',
id: `folder-dashboards-${folder.uid}`,
text: 'Dashboards',
url: folder.url,
},
{
active: false,
icon: 'fa fa-fw fa-lock',
icon: 'lock',
id: `folder-permissions-${folder.uid}`,
text: 'Permissions',
url: `${folder.url}/permissions`,
},
{
active: false,
icon: 'gicon gicon-cog',
icon: 'cog',
id: `folder-settings-${folder.uid}`,
text: 'Settings',
url: `${folder.url}/settings`,
@@ -1,19 +1,19 @@
<page-header model="ctrl.navModel"></page-header>
<div class="page-container page-body">
<table class="filter-table">
<table class="filter-table">
<thead>
<th><strong>Name</strong></th>
<th><strong>Snapshot url</strong></th>
<th style="width: 70px"></th>
<th style="width: 30px"></th>
<th style="width: 25px"></th>
</thead>
<tr ng-repeat="snapshot in ctrl.snapshots">
</thead>
<tr ng-repeat="snapshot in ctrl.snapshots">
<td>
<a href="{{snapshot.url}}">{{snapshot.name}}</a>
</td>
<td >
<td>
<a href="{{snapshot.url}}">{{snapshot.url}}</a>
</td>
<td>
@@ -21,18 +21,17 @@
</td>
<td class="text-center">
<a href="{{snapshot.url}}" class="btn btn-inverse btn-small">
<i class="gicon gicon-viewer"></i>
<icon name="'eye'" style="margin-right: 4px; margin-bottom: 2px;"></icon>
View
</a>
</td>
<td class="text-right">
<td class="text-right">
<a ng-click="ctrl.removeSnapshot(snapshot)" class="btn btn-danger btn-small">
<i class="fa fa-remove"></i>
<icon name="'times'"></icon>
</a>
</td>
</tr>
</table>
</div>
<footer />
+1 -1
View File
@@ -10,7 +10,7 @@ export class SelectOrgCtrl {
$scope.navModel = {
main: {
icon: 'gicon gicon-branding',
icon: 'grafana',
subTitle: 'Preferences',
text: 'Select active organization',
},
@@ -1,104 +1,124 @@
<page-header model="ctrl.navModel"></page-header>
<div class="page-container page-body" ng-form="ctrl.playlistEditForm">
<h3 class="page-sub-heading" ng-hide="ctrl.isNew">Edit Playlist</h3>
<h3 class="page-sub-heading" ng-show="ctrl.isNew">New Playlist</h3>
<h3 class="page-sub-heading" ng-hide="ctrl.isNew">Edit Playlist</h3>
<h3 class="page-sub-heading" ng-show="ctrl.isNew">New Playlist</h3>
<p class="playlist-description">
A playlist rotates through a pre-selected list of Dashboards. A Playlist can be a great way to build situational
awareness, or just show off your metrics to your team or visitors.
</p>
<p class="playlist-description">A playlist rotates through a pre-selected list of Dashboards. A Playlist can be a great way to build situational awareness, or just show off your metrics to your team or visitors.</p>
<div class="gf-form-group">
<div class="gf-form">
<span class="gf-form-label width-7">Name</span>
<input type="text" required ng-model="ctrl.playlist.name" class="gf-form-input max-width-21" />
</div>
<div class="gf-form">
<span class="gf-form-label width-7">Interval</span>
<input
type="text"
required
ng-model="ctrl.playlist.interval"
placeholder="5m"
class="gf-form-input max-width-21"
/>
</div>
</div>
<div class="gf-form-group">
<div class="gf-form">
<span class="gf-form-label width-7">Name</span>
<input type="text" required ng-model="ctrl.playlist.name" class="gf-form-input max-width-21">
</div>
<div class="gf-form">
<span class="gf-form-label width-7">Interval</span>
<input type="text" required ng-model="ctrl.playlist.interval" placeholder="5m" class="gf-form-input max-width-21">
</div>
</div>
<div class="gf-form-group">
<h3 class="page-headering">Dashboards</h3>
<div class="gf-form-group">
<h3 class="page-headering">Dashboards</h3>
<table class="filter-table playlist-available-list">
<tr ng-repeat="playlistItem in ctrl.playlistItems">
<td ng-if="playlistItem.type === 'dashboard_by_id'">
<icon name="'apps'"></icon>&nbsp;&nbsp;{{playlistItem.title}}
</td>
<td ng-if="playlistItem.type === 'dashboard_by_tag'">
<a class="search-result-tag label label-tag" tag-color-from-name="playlistItem.title">
<icon name="'tag-alt'"></icon>
<span>{{playlistItem.title}}</span>
</a>
</td>
<table class="filter-table playlist-available-list">
<tr ng-repeat="playlistItem in ctrl.playlistItems">
<td ng-if="playlistItem.type === 'dashboard_by_id'">
<i class="gicon gicon-dashboard"></i>&nbsp;&nbsp;{{playlistItem.title}}
</td>
<td ng-if="playlistItem.type === 'dashboard_by_tag'">
<a class="search-result-tag label label-tag" tag-color-from-name="playlistItem.title">
<i class="fa fa-tag"></i>
<span>{{playlistItem.title}}</span>
</a>
</td>
<td class="selected-playlistitem-settings">
<button class="btn btn-inverse btn-small" ng-hide="$first" ng-click="ctrl.movePlaylistItemUp(playlistItem)">
<icon name="'arrow-up'"></icon>
</button>
<button class="btn btn-inverse btn-small" ng-hide="$last" ng-click="ctrl.movePlaylistItemDown(playlistItem)">
<icon name="'arrow-down'"></icon>
</button>
<button class="btn btn-inverse btn-small" ng-click="ctrl.removePlaylistItem(playlistItem)">
<icon name="'times'"></icon>
</button>
</td>
</tr>
<tr ng-if="ctrl.playlistItems.length === 0">
<td><em>Playlist is empty, add dashboards below.</em></td>
</tr>
</table>
</div>
<td class="selected-playlistitem-settings">
<button class="btn btn-inverse btn-small" ng-hide="$first" ng-click="ctrl.movePlaylistItemUp(playlistItem)">
<i class="fa fa-arrow-up"></i>
</button>
<button class="btn btn-inverse btn-small" ng-hide="$last" ng-click="ctrl.movePlaylistItemDown(playlistItem)">
<i class="fa fa-arrow-down"></i>
</button>
<button class="btn btn-inverse btn-small" ng-click="ctrl.removePlaylistItem(playlistItem)">
<i class="fa fa-remove"></i>
</button>
</td>
</tr>
<tr ng-if="ctrl.playlistItems.length === 0">
<td><em>Playlist is empty, add dashboards below.</em></td>
</tr>
</table>
</div>
<div class="gf-form-group">
<h3 class="page-headering">Add dashboards</h3>
<playlist-search class="playlist-search-container" search-started="ctrl.searchStarted(promise)"></playlist-search>
<div class="gf-form-group">
<h3 class="page-headering">Add dashboards</h3>
<playlist-search class="playlist-search-container" search-started="ctrl.searchStarted(promise)"></playlist-search>
<div ng-if="ctrl.filteredDashboards.length > 0">
<table class="filter-table playlist-available-list">
<tr ng-repeat="playlistItem in ctrl.filteredDashboards">
<td>
<icon name="'apps'"></icon>
&nbsp;&nbsp;{{playlistItem.title}}
<icon name="'favorite'" type="'mono'" ng-show="playlistItem.isStarred"></icon>
</td>
<td class="add-dashboard">
<button class="btn btn-inverse btn-small pull-right" ng-click="ctrl.addPlaylistItem(playlistItem)">
<icon name="'plus'"></i>
Add to playlist
</button>
</td>
</tr>
</table>
</div>
<div class="playlist-search-results-container" ng-if="ctrl.filteredTags.length > 0;">
<table class="filter-table playlist-available-list">
<tr ng-repeat="tag in ctrl.filteredTags">
<td>
<a class="search-result-tag label label-tag" tag-color-from-name="tag.term">
<icon name="'tag-alt'"></icon>
<span>{{tag.term}} &nbsp;({{tag.count}})</span>
</a>
</td>
<td class="add-dashboard">
<button class="btn btn-inverse btn-small pull-right" ng-click="ctrl.addTagPlaylistItem(tag)">
<icon name="'plus'"></i>
Add to playlist
</button>
</td>
</tr>
</table>
</div>
</div>
<div ng-if="ctrl.filteredDashboards.length > 0">
<table class="filter-table playlist-available-list">
<tr ng-repeat="playlistItem in ctrl.filteredDashboards">
<td>
<i class="gicon gicon-dashboard"></i>
&nbsp;&nbsp;{{playlistItem.title}}
<i class="fa fa-star" ng-show="playlistItem.isStarred"></i>
</td>
<td class="add-dashboard">
<button class="btn btn-inverse btn-small pull-right" ng-click="ctrl.addPlaylistItem(playlistItem)">
<i class="fa fa-plus"></i>
Add to playlist
</button>
</td>
</tr>
</table>
</div>
<div class="playlist-search-results-container" ng-if="ctrl.filteredTags.length > 0;">
<table class="filter-table playlist-available-list">
<tr ng-repeat="tag in ctrl.filteredTags">
<td>
<a class="search-result-tag label label-tag" tag-color-from-name="tag.term">
<i class="fa fa-tag"></i>
<span>{{tag.term}} &nbsp;({{tag.count}})</span>
</a>
</td>
<td class="add-dashboard">
<button class="btn btn-inverse btn-small pull-right" ng-click="ctrl.addTagPlaylistItem(tag)">
<i class="fa fa-plus"></i>
Add to playlist
</button>
</td>
</tr>
</table>
</div>
</div>
<div class="clearfix"></div>
<div class="clearfix"></div>
<div class="gf-form-button-row">
<a class="btn btn-primary" ng-show="ctrl.isNew" ng-disabled="ctrl.playlistEditForm.$invalid || ctrl.isPlaylistEmpty()" ng-click="ctrl.savePlaylist(ctrl.playlist, ctrl.playlistItems)">Create</a>
<a class="btn btn-primary" ng-show="!ctrl.isNew" ng-disabled="ctrl.playlistEditForm.$invalid || ctrl.isPlaylistEmpty()" ng-click="ctrl.savePlaylist(ctrl.playlist, ctrl.playlistItems)">Save</a>
<a class="btn-text" ng-click="ctrl.backToList()">Cancel</a>
</div>
<div class="gf-form-button-row">
<a
class="btn btn-primary"
ng-show="ctrl.isNew"
ng-disabled="ctrl.playlistEditForm.$invalid || ctrl.isPlaylistEmpty()"
ng-click="ctrl.savePlaylist(ctrl.playlist, ctrl.playlistItems)"
>Create</a
>
<a
class="btn btn-primary"
ng-show="!ctrl.isNew"
ng-disabled="ctrl.playlistEditForm.$invalid || ctrl.isPlaylistEmpty()"
ng-click="ctrl.savePlaylist(ctrl.playlist, ctrl.playlistItems)"
>Save</a
>
<a class="btn-text" ng-click="ctrl.backToList()">Cancel</a>
</div>
</div>
<footer />
@@ -1,26 +1,35 @@
<div class="playlist-search-field-wrapper">
<span style="position: relative;">
<input type="text" placeholder="Search dashboards by name" tabindex="1"
ng-keydown="ctrl.keyDown($event)" ng-model="ctrl.query.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.searchDashboards()" />
<div class="playlist-search-switches">
<i class="fa fa-filter"></i>
<a class="pointer" href="javascript:void 0;" ng-click="ctrl.showStarred()" tabindex="2">
<i class="fa fa-remove" ng-show="ctrl.query.starred"></i>
starred
</a> |
<a class="pointer" href="javascript:void 0;" ng-click="ctrl.getTags()" tabindex="3">
<i class="fa fa-remove" ng-show="ctrl.tagsMode"></i>
tags
</a>
<span ng-if="ctrl.query.tag.length">
|
<span ng-repeat="tagName in ctrl.query.tag">
<a ng-click="ctrl.removeTag(tagName, $event)" tag-color-from-name="ctrl.tagName" class="label label-tag">
<i class="fa fa-remove"></i>
{{tagName}}
</a>
</span>
</span>
</div>
</span>
<input
type="text"
placeholder="Find dashboards by name"
tabindex="1"
ng-keydown="ctrl.keyDown($event)"
ng-model="ctrl.query.query"
ng-model-options="{ debounce: 500 }"
spellcheck="false"
ng-change="ctrl.searchDashboards()"
/>
<div class="playlist-search-switches">
<icon name="'filter'"></icon>
<a class="pointer" href="javascript:void 0;" ng-click="ctrl.showStarred()" tabindex="2">
<icon name="'times'" ng-show="ctrl.query.starred"></icon>
starred
</a>
|
<a class="pointer" href="javascript:void 0;" ng-click="ctrl.getTags()" tabindex="3">
<icon name="'times'" ng-show="ctrl.tagsMode"></icon>
tags
</a>
<span ng-if="ctrl.query.tag.length">
|
<span ng-repeat="tagName in ctrl.query.tag">
<a ng-click="ctrl.removeTag(tagName, $event)" tag-color-from-name="ctrl.tagName" class="label label-tag">
<icon name="'times'"></icon>
{{tagName}}
</a>
</span>
</span>
</div>
</span>
</div>
@@ -55,7 +55,7 @@
<div ng-if="ctrl.playlists.length === 0">
<empty-list-cta
title="'There are no playlists created yet'"
buttonIcon="'fa fa-plus'"
buttonIcon="'plus'"
buttonLink="'playlists/create'"
buttonTitle="'Create Playlist'"
proTip="'You can use playlists to cycle dashboards on TVs without user control'"
+1 -1
View File
@@ -8,7 +8,7 @@ import { StoreState } from 'app/types';
const navModel = {
main: {
icon: 'gicon gicon-branding',
icon: 'grafana',
text: 'Sign Up',
subTitle: 'Register your Grafana account',
breadcrumbs: [{ title: 'Login', url: 'login' }],
@@ -1,5 +1,5 @@
import React, { PureComponent, ChangeEvent, MouseEvent } from 'react';
import { Button, FormLabel, LegacyForms, Tooltip } from '@grafana/ui';
import { Button, FormLabel, LegacyForms, Tooltip, Icon } from '@grafana/ui';
const { Input } = LegacyForms;
import { User } from 'app/types';
import config from 'app/core/config';
@@ -73,7 +73,7 @@ export class UserProfileEditForm extends PureComponent<Props, State> {
/>
{disableLoginForm && (
<Tooltip content="Login Details Locked - managed in another system.">
<i className="fa fa-lock gf-form-icon--right-absolute" />
<Icon name="lock" className="gf-form-icon--right-absolute" />
</Tooltip>
)}
</div>
@@ -88,7 +88,7 @@ export class UserProfileEditForm extends PureComponent<Props, State> {
/>
{disableLoginForm && (
<Tooltip content="Login Details Locked - managed in another system.">
<i className="fa fa-lock gf-form-icon--right-absolute" />
<Icon name="lock" className="gf-form-icon--right-absolute" />
</Tooltip>
)}
</div>
@@ -2,7 +2,7 @@ import React, { useContext } from 'react';
import { css, cx } from 'emotion';
// @ts-ignore
import tinycolor from 'tinycolor2';
import { ThemeContext } from '@grafana/ui';
import { ThemeContext, Icon } from '@grafana/ui';
import { GrafanaTheme } from '@grafana/data';
import { SearchQuery } from 'app/core/components/search/search';
@@ -56,7 +56,7 @@ export const SearchField: React.FunctionComponent<SearchFieldProps> = ({ query,
{/* based on it GrafanaCtrl (L256) decides whether or not hide search */}
<div className={`${styles.wrapper} search-field-wrapper`}>
<div className={styles.icon}>
<i className="fa fa-search" />
<Icon name="search" />
</div>
<input
@@ -54,7 +54,7 @@ export const SearchItem: FC<Props> = ({ item, editable, onToggleSelection, onTag
>
<SearchCheckbox editable={editable} checked={item.checked} onClick={toggleItem} />
<a href={item.url} className={styles.link}>
<Icon className={styles.icon} name="apps" />
<Icon className={styles.icon} name="apps" size="lg" />
<div className={styles.body} onClick={onItemClick}>
<span>{item.title}</span>
<span className={styles.folderTitle}>{item.folderTitle}</span>
@@ -99,10 +99,7 @@ const getResultsItemStyles = stylesFactory((theme: GrafanaTheme) => ({
top: -1px;
`,
icon: css`
font-size: ${theme.typography.size.lg};
width: auto;
height: auto;
padding: 1px 2px 0 10px;
margin-left: 10px;
`,
tags: css`
justify-content: flex-end;
@@ -106,7 +106,7 @@ const SectionHeader: FC<SectionHeaderProps> = ({ section, onSectionClick, onTogg
<Icon name="cog" />
</a>
)}
<Icon name={section.expanded ? 'angle-down' : 'angle-right'} className={styles.toggle} />
<Icon name={section.expanded ? 'angle-down' : 'angle-right'} />
</div>
) : (
<div className={styles.wrapper} />
@@ -139,7 +139,6 @@ const getSectionHeaderStyles = stylesFactory((theme: GrafanaTheme, selected = fa
{ selected }
),
icon: css`
padding: 5px 0;
width: 43px;
`,
text: css`
@@ -152,8 +151,5 @@ const getSectionHeaderStyles = stylesFactory((theme: GrafanaTheme, selected = fa
opacity: 0;
transition: opacity 150ms ease-in-out;
`,
toggle: css`
padding: 5px;
`,
};
});
@@ -46,10 +46,10 @@ export const SearchResultsFilter: FC<Props> = ({
<Forms.Checkbox value={allChecked} onChange={onSelectAllChanged} />
{showActions ? (
<HorizontalGroup spacing="md">
<Button disabled={!canMove} onClick={moveTo} icon="fa fa-exchange" variant="secondary">
<Button disabled={!canMove} onClick={moveTo} icon="exchange-alt" variant="secondary">
Move
</Button>
<Button disabled={!canDelete} onClick={deleteItem} icon="fa fa-trash" variant="destructive">
<Button disabled={!canDelete} onClick={deleteItem} icon="trash-alt" variant="destructive">
Delete
</Button>
</HorizontalGroup>
+3 -5
View File
@@ -2,7 +2,7 @@ import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import { SlideDown } from 'app/core/components/Animations/SlideDown';
import { LegacyForms, Tooltip } from '@grafana/ui';
import { LegacyForms, Tooltip, Icon } from '@grafana/ui';
const { Input } = LegacyForms;
import { TeamGroup } from '../../types';
@@ -82,9 +82,7 @@ export class TeamGroupSync extends PureComponent<Props, State> {
<div className="page-action-bar">
<h3 className="page-sub-heading">External group sync</h3>
<Tooltip placement="auto" content={headerTooltip}>
<div className="page-sub-heading-icon">
<i className="gicon gicon-question gicon--has-hover" />
</div>
<Icon className="icon--has-hover page-sub-heading-icon" name="question-circle" />
</Tooltip>
<div className="page-action-bar__spacer" />
{groups.length > 0 && (
@@ -123,7 +121,7 @@ export class TeamGroupSync extends PureComponent<Props, State> {
{groups.length === 0 && !isAdding && (
<EmptyListCTA
onClick={this.onToggleAdding}
buttonIcon="gicon gicon-team"
buttonIcon="users-alt"
title="There are no external groups to sync with"
buttonTitle="Add Group"
proTip={headerTooltip}
+1 -1
View File
@@ -77,7 +77,7 @@ export class TeamList extends PureComponent<Props, any> {
return (
<EmptyListCTA
title="You haven't created any teams yet."
buttonIcon="gicon gicon-team"
buttonIcon="users-alt"
buttonLink="org/teams/new"
buttonTitle=" New team"
proTip="Assign folder and dashboard permissions to teams instead of users to ease administration."
@@ -14,13 +14,10 @@ exports[`Render should render component 1`] = `
content="Sync LDAP or OAuth groups with your Grafana teams."
placement="auto"
>
<div
className="page-sub-heading-icon"
>
<i
className="gicon gicon-question gicon--has-hover"
/>
</div>
<Icon
className="icon--has-hover page-sub-heading-icon"
name="question-circle"
/>
</Component>
<div
className="page-action-bar__spacer"
@@ -73,7 +70,7 @@ exports[`Render should render component 1`] = `
</div>
</Component>
<EmptyListCTA
buttonIcon="gicon gicon-team"
buttonIcon="users-alt"
buttonTitle="Add Group"
onClick={[Function]}
proTip="Sync LDAP or OAuth groups with your Grafana teams."
@@ -99,13 +96,10 @@ exports[`Render should render groups table 1`] = `
content="Sync LDAP or OAuth groups with your Grafana teams."
placement="auto"
>
<div
className="page-sub-heading-icon"
>
<i
className="gicon gicon-question gicon--has-hover"
/>
</div>
<Icon
className="icon--has-hover page-sub-heading-icon"
name="question-circle"
/>
</Component>
<div
className="page-action-bar__spacer"
+1 -1
View File
@@ -27,7 +27,7 @@ interface FormModel {
const navModel = {
main: {
icon: 'gicon gicon-branding',
icon: 'grafana',
text: 'Invite',
subTitle: 'Register your Grafana account',
breadcrumbs: [{ title: 'Login', url: 'login' }],
@@ -47,7 +47,7 @@ export class VariableEditorList extends PureComponent<Props> {
<div>
<EmptyListCTA
title="There are no variables yet"
buttonIcon="gicon gicon-variable"
buttonIcon="calculator-alt"
buttonTitle="Add variable"
infoBox={{
__html: ` <p>
@@ -1,5 +1,5 @@
import React, { PureComponent } from 'react';
import { getTagColorsFromName } from '@grafana/ui';
import { getTagColorsFromName, Icon } from '@grafana/ui';
import { e2e } from '@grafana/e2e';
import { VariableTag } from '../../../templating/types';
@@ -30,12 +30,14 @@ export class VariableLink extends PureComponent<Props> {
return (
<span bs-tooltip="tag.valuesText" data-placement="bottom" key={`${tag.text}`}>
<span className="label-tag" style={{ backgroundColor: color, borderColor }}>
&nbsp;&nbsp;<i className="fa fa-tag"></i>&nbsp; {tag.text}
&nbsp;&nbsp;
<Icon name="tag-alt" />
&nbsp; {tag.text}
</span>
</span>
);
})}
<i className="fa fa-caret-down" style={{ fontSize: '12px' }}></i>
<Icon name="angle-down" size="sm" />
</a>
);
}
@@ -1,5 +1,5 @@
import React, { PureComponent } from 'react';
import { getTagColorsFromName, Tooltip } from '@grafana/ui';
import { getTagColorsFromName, Tooltip, Icon } from '@grafana/ui';
import { e2e } from '@grafana/e2e';
import { VariableOption, VariableTag } from '../../../templating/types';
@@ -79,7 +79,9 @@ export class VariableOptions extends PureComponent<Props> {
>
<span className="fa fa-fw variable-option-icon"></span>
<span className="label-tag" style={{ backgroundColor: color, borderColor }}>
{tag.text}&nbsp;&nbsp;<i className="fa fa-tag"></i>&nbsp;
{tag.text}&nbsp;&nbsp;
<Icon name="tag-alt" />
&nbsp;
</span>
</a>
);
+3 -3
View File
@@ -7,10 +7,10 @@
{{vm.linkText}}
<span ng-repeat="tag in vm.selectedTags" bs-tooltip="tag.valuesText" data-placement="bottom">
<span class="label-tag" tag-color-from-name="tag.text">
&nbsp;&nbsp;<i class="fa fa-tag"></i>&nbsp; {{tag.text}}
&nbsp;&nbsp;<icon name="'tag-alt'"></icon>&nbsp; {{tag.text}}
</span>
</span>
<i class="fa fa-caret-down" style="font-size:12px"></i>
<icon name="'angle-down'"></icon>
</a>
<input
@@ -63,7 +63,7 @@
>
<span class="fa fa-fw variable-option-icon"></span>
<span class="label-tag" tag-color-from-name="tag.text"
>{{tag.text}}&nbsp;&nbsp;<i class="fa fa-tag"></i>&nbsp;</span
>{{tag.text}}&nbsp;&nbsp;<icon name="'tag-alt'"></icon>&nbsp;</span
>
</a>
</div>
@@ -51,7 +51,7 @@ export const DataLink = (props: Props) => {
<Button
variant={'destructive'}
title="Remove field"
icon={'fa fa-times'}
icon="times"
onClick={event => {
event.preventDefault();
onDelete();
@@ -67,7 +67,7 @@ export const DataLinks = (props: Props) => {
className={css`
margin-right: 10px;
`}
icon="fa fa-plus"
icon="plus"
onClick={event => {
event.preventDefault();
const newDataLinks = [...(value || []), { field: '', url: '' }];
@@ -68,7 +68,7 @@ export const DerivedField = (props: Props) => {
<Button
variant="destructive"
title="Remove field"
icon={'fa fa-times'}
icon="times"
onClick={event => {
event.preventDefault();
onDelete();
@@ -70,7 +70,7 @@ export const DerivedFields = (props: Props) => {
className={css`
margin-right: 10px;
`}
icon="fa fa-plus"
icon="plus"
onClick={event => {
event.preventDefault();
const newDerivedFields = [...(value || []), { name: '', matcherRegex: '' }];
@@ -10,7 +10,7 @@
{{dash.title}}
</span>
<span class="dashlist-star" ng-click="ctrl.starDashboard(dash, $event)">
<i class="fa" ng-class="{'fa-star': dash.isStarred, 'fa-star-o': dash.isStarred === false}"></i>
<icon name="dash.isStarred ? 'favorite':'star'" type="dash.isStarred ? 'mono':'default'"></icon>
</span>
</a>
</div>
+1 -1
View File
@@ -11,7 +11,7 @@
vertical-align: middle;
}
.gicon--has-hover {
.icon--has-hover {
opacity: 0.7;
&:hover {
+3
View File
@@ -82,6 +82,9 @@
.btn-small {
@include button-size($btn-padding-y-sm, $space-sm, $font-size-sm, $border-radius-sm);
height: $height-sm;
svg {
margin-bottom: 0;
}
}
// Deprecated, only used by old plugins
+1 -1
View File
@@ -41,7 +41,7 @@ $input-border: 1px solid $input-border-color;
.gf-form-input-icon {
position: absolute;
top: 50%;
margin-top: -9px;
margin-top: -8px;
font-size: $font-size-lg;
left: 10px;
color: $input-color-placeholder;

Some files were not shown because too many files have changed in this diff Show More