mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
@grafana/ui: Create Icon component and replace part of the icons (#23402)
* 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>
* Resolve type errors resulted from merge
* 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>
* Part3: Unicons implementation (#23356)
* 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>
* Update icons in Explore
* Update icons in alerting
* Update + and x buttons
* Update icons in configurations and settings
* Update close icons
* Update icons in rich history
* Update alert messages
* Add optional chaining to for isFontAwesome variable
* Remove icon mock, set up jest.config
* Fix navbar plus icon
* Fir enable-bacground to enableBackgournd
Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
* Merge remote branch origin master to icons-unicons
* Revert "Merge remote branch origin master to icons-unicons"
This reverts commit 3f25d50a39
.
* Size-up dashnav icons
* Fix alerting icons, panel headers, update tests
* Fix typecheck error
* Adjustments - add panel icon, spacing
* Set TerserPlugin sourceMap to false to prevent running out of memory when publishing storybook
Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
const esModule = '@iconscout/react-unicons';
|
||||
|
||||
module.exports = {
|
||||
verbose: false,
|
||||
transform: {
|
||||
'^.+\\.(ts|tsx|js|jsx)$': 'ts-jest',
|
||||
[`(${esModule}).+\\.js$`]: 'babel-jest',
|
||||
},
|
||||
transformIgnorePatterns: [`/node_modules/(?!${esModule})`],
|
||||
moduleDirectories: ['node_modules', 'public'],
|
||||
roots: ['<rootDir>/public/app', '<rootDir>/public/test', '<rootDir>/packages', '<rootDir>/scripts'],
|
||||
testRegex: '(\\.|/)(test)\\.(jsx?|tsx?)$',
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { camelCase } from 'lodash';
|
||||
const specialChars = ['(', '[', '{', '}', ']', ')', '|', '*', '+', '-', '.', '?', '<', '>', '#', '&', '^', '$'];
|
||||
|
||||
export const escapeStringForRegex = (value: string) => {
|
||||
@@ -89,3 +90,8 @@ export function toFloatOrUndefined(value: string): number | undefined {
|
||||
const v = parseFloat(value);
|
||||
return isNaN(v) ? undefined : v;
|
||||
}
|
||||
|
||||
export const toPascalCase = (string: string) => {
|
||||
const str = camelCase(string);
|
||||
return str.charAt(0).toUpperCase() + str.substring(1);
|
||||
};
|
||||
|
@@ -82,7 +82,7 @@ module.exports = ({ config, mode }) => {
|
||||
new TerserPlugin({
|
||||
cache: false,
|
||||
parallel: false,
|
||||
sourceMap: true,
|
||||
sourceMap: false,
|
||||
}),
|
||||
new OptimizeCSSAssetsPlugin({}),
|
||||
],
|
||||
|
@@ -31,6 +31,7 @@
|
||||
"@grafana/data": "7.0.0-pre.0",
|
||||
"@grafana/slate-react": "0.22.9-grafana",
|
||||
"@grafana/tsconfig": "^1.0.0-rc1",
|
||||
"@iconscout/react-unicons": "^1.0.0",
|
||||
"@torkelo/react-select": "3.0.8",
|
||||
"@types/react-beautiful-dnd": "12.1.2",
|
||||
"@types/react-color": "3.0.1",
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import React, { FC, ReactNode } from 'react';
|
||||
import { Icon, IconName } from '@grafana/ui';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export type AlertVariant = 'success' | 'warning' | 'error' | 'info';
|
||||
@@ -15,16 +16,16 @@ interface AlertProps {
|
||||
function getIconFromSeverity(severity: AlertVariant): string {
|
||||
switch (severity) {
|
||||
case 'error': {
|
||||
return 'fa fa-exclamation-triangle';
|
||||
return 'exclamation-triangle';
|
||||
}
|
||||
case 'warning': {
|
||||
return 'fa fa-exclamation-triangle';
|
||||
return 'exclamation-triangle';
|
||||
}
|
||||
case 'info': {
|
||||
return 'fa fa-info-circle';
|
||||
return 'info-circle';
|
||||
}
|
||||
case 'success': {
|
||||
return 'fa fa-check';
|
||||
return 'check';
|
||||
}
|
||||
default:
|
||||
return '';
|
||||
@@ -37,7 +38,7 @@ export const Alert: FC<AlertProps> = ({ title, buttonText, onButtonClick, onRemo
|
||||
<div className="alert-container">
|
||||
<div className={alertClass}>
|
||||
<div className="alert-icon">
|
||||
<i className={getIconFromSeverity(severity)} />
|
||||
<Icon size="xl" name={getIconFromSeverity(severity) as IconName} />
|
||||
</div>
|
||||
<div className="alert-body">
|
||||
<div className="alert-title">{title}</div>
|
||||
@@ -46,7 +47,7 @@ export const Alert: FC<AlertProps> = ({ title, buttonText, onButtonClick, onRemo
|
||||
{/* If onRemove is specified , giving preference to onRemove */}
|
||||
{onRemove && (
|
||||
<button type="button" className="alert-close" onClick={onRemove}>
|
||||
<i className="fa fa fa-remove" />
|
||||
<Icon name="times" size="lg" />
|
||||
</button>
|
||||
)}
|
||||
{onButtonClick && (
|
||||
|
@@ -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>
|
||||
);
|
||||
|
||||
|
@@ -40,7 +40,7 @@ export const ButtonCascader: React.FC<ButtonCascaderProps> = props => {
|
||||
expandIcon={null}
|
||||
>
|
||||
<button className="gf-form-label gf-form-label--btn" disabled={props.disabled}>
|
||||
{props.children} <Icon name="caret-down" />
|
||||
{props.children} <Icon name="angle-down" />
|
||||
</button>
|
||||
</RCCascader>
|
||||
);
|
||||
|
@@ -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-circle" onClick={action('cta button clicked')}>
|
||||
Add datasource
|
||||
</Button>
|
||||
),
|
||||
|
@@ -212,7 +212,7 @@ export class Cascader extends React.PureComponent<CascaderProps, CascaderState>
|
||||
value={activeLabel}
|
||||
onKeyDown={this.onInputKeyDown}
|
||||
onChange={() => {}}
|
||||
suffix={focusCascade ? <Icon name="caret-up" /> : <Icon name="caret-down" />}
|
||||
suffix={focusCascade ? <Icon name="angle-up" /> : <Icon name="angle-down" />}
|
||||
/>
|
||||
</div>
|
||||
</RCCascader>
|
||||
|
@@ -123,7 +123,7 @@ export const Collapse: FunctionComponent<Props> = ({ isOpen, label, loading, col
|
||||
<div className={panelClass}>
|
||||
<div className={headerClass} onClick={onClickToggle}>
|
||||
<div className={headerButtonsClass}>
|
||||
<Icon name={isOpen ? 'caret-up' : 'caret-down'} />
|
||||
<Icon name={isOpen ? 'angle-up' : 'angle-down'} />
|
||||
</div>
|
||||
<div className={cx([style.headerLabel])}>{label}</div>
|
||||
</div>
|
||||
|
@@ -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>
|
||||
);
|
||||
};
|
||||
|
@@ -11,7 +11,7 @@ const getKnobs = () => {
|
||||
body: text('Body', 'Are you sure you want to delete this user?'),
|
||||
confirm: text('Confirm', 'Delete'),
|
||||
visible: boolean('Visible', true),
|
||||
icon: select('Icon', ['exclamation-triangle', 'power-off', 'cog', 'lock'], 'exclamation-triangle'),
|
||||
icon: select('Icon', ['exclamation-triangle', 'power', 'cog', 'lock'], 'exclamation-triangle'),
|
||||
};
|
||||
};
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { FC, useContext } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { Modal } from '../Modal/Modal';
|
||||
import { IconType } from '../Icon/types';
|
||||
import { IconName } from '../../types';
|
||||
import { Button } from '../Button';
|
||||
import { stylesFactory, ThemeContext } from '../../themes';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
@@ -22,7 +22,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
|
||||
`,
|
||||
}));
|
||||
|
||||
const defaultIcon: IconType = 'exclamation-triangle';
|
||||
const defaultIcon: IconName = 'exclamation-triangle';
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean;
|
||||
@@ -30,7 +30,7 @@ interface Props {
|
||||
body: React.ReactNode;
|
||||
confirmText: string;
|
||||
dismissText?: string;
|
||||
icon?: IconType;
|
||||
icon?: IconName;
|
||||
onConfirm(): void;
|
||||
onDismiss(): void;
|
||||
}
|
||||
|
@@ -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-circle" 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-circle" onClick={onDataLinkAdd} variant="secondary">
|
||||
Add link
|
||||
</Button>
|
||||
</FullWidthButtonContainer>
|
||||
|
@@ -42,10 +42,10 @@ export const DataLinksListItem: FC<DataLinksListItemProps> = ({
|
||||
|
||||
<HorizontalGroup>
|
||||
<div onClick={onEdit} className={styles.action}>
|
||||
<Icon name="pencil" />
|
||||
<Icon name="pen" />
|
||||
</div>
|
||||
<div onClick={onRemove} className={cx(styles.action, styles.remove)}>
|
||||
<Icon name="trash" />
|
||||
<Icon name="trash-alt" />
|
||||
</div>
|
||||
</HorizontalGroup>
|
||||
</HorizontalGroup>
|
||||
|
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { KeyValue } from '@grafana/data';
|
||||
import { css, cx } from 'emotion';
|
||||
import { Tooltip } from '../Tooltip/Tooltip';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { CertificationKey } from './CertificationKey';
|
||||
import { HttpSettingsBaseProps } from './types';
|
||||
|
||||
@@ -47,7 +48,7 @@ export const TLSAuthSettings: React.FC<HttpSettingsBaseProps> = ({ dataSourceCon
|
||||
theme="info"
|
||||
>
|
||||
<div className="gf-form-help-icon gf-form-help-icon--right-normal">
|
||||
<i className="fa fa-info-circle" />
|
||||
<Icon name="info-circle" size="sm" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
@@ -26,7 +26,7 @@ export const FieldConfigItemHeaderTitle: React.FC<FieldConfigItemHeaderTitleProp
|
||||
<div className={styles.header}>
|
||||
<Forms.Label description={description}>{title}</Forms.Label>
|
||||
<div className={styles.remove} onClick={() => onRemove()} aria-label="FieldConfigItemHeaderTitle remove button">
|
||||
<Icon name="trash" />
|
||||
<Icon name="trash-alt" />
|
||||
</div>
|
||||
</div>
|
||||
{children}
|
||||
|
@@ -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" size="sm" style={{ marginBottom: 0 }} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import React, { PureComponent, ReactElement } from 'react';
|
||||
import Select from './Select';
|
||||
import { PopoverContent } from '../../../Tooltip/Tooltip';
|
||||
import { Icon } from '../../../Icon/Icon';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
interface ButtonComponentProps {
|
||||
@@ -23,8 +24,8 @@ const ButtonComponent = (buttonProps: ButtonComponentProps) => (props: any) => {
|
||||
<div className="select-button">
|
||||
{iconClass && <i className={`select-button-icon ${iconClass}`} />}
|
||||
<span className="select-button-value">{label ? label : ''}</span>
|
||||
{!props.menuIsOpen && <i className="fa fa-caret-down fa-fw" />}
|
||||
{props.menuIsOpen && <i className="fa fa-caret-up fa-fw" />}
|
||||
{!props.menuIsOpen && <Icon name="angle-down" style={{ marginBottom: 0 }} size="lg" />}
|
||||
{props.menuIsOpen && <Icon name="angle-up" style={{ marginBottom: 0 }} size="lg" />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@@ -135,26 +135,11 @@ $select-input-bg-disabled: $input-bg-disabled;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
right: 8px;
|
||||
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;
|
||||
|
@@ -5,7 +5,7 @@ import { Icon } from './Icon';
|
||||
|
||||
# Icon
|
||||
|
||||
Grafana's wrapper component over [Font Awesome](https://fontawesome.com/) icons
|
||||
Grafana's wrapper component over [Font Awesome](https://fontawesome.com/) and Unicons icons
|
||||
|
||||
|
||||
### Changing icon size
|
||||
@@ -15,13 +15,7 @@ By default `Icon` has width and height of `16px` and font-size of `14px`. Pass `
|
||||
```jsx
|
||||
import { css } from 'emotion';
|
||||
|
||||
const customIconSize = css`
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 18px;
|
||||
`;
|
||||
|
||||
<Icon name="check" className={customIconSize} />
|
||||
<Icon name="check" />
|
||||
```
|
||||
|
||||
|
||||
|
@@ -4,7 +4,7 @@ import { css } from 'emotion';
|
||||
import { Input } from '../Input/Input';
|
||||
import { Field } from '../Forms/Field';
|
||||
import { Icon } from './Icon';
|
||||
import { getAvailableIcons, IconType } from './types';
|
||||
import { getAvailableIcons, IconName } from '../../types';
|
||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { useTheme, selectThemeVariant } from '../../themes';
|
||||
import mdx from './Icon.mdx';
|
||||
@@ -20,7 +20,7 @@ export default {
|
||||
},
|
||||
};
|
||||
|
||||
const IconWrapper: React.FC<{ name: IconType }> = ({ name }) => {
|
||||
const IconWrapper: React.FC<{ name: IconName }> = ({ name }) => {
|
||||
const theme = useTheme();
|
||||
const borderColor = selectThemeVariant(
|
||||
{
|
||||
@@ -43,12 +43,7 @@ const IconWrapper: React.FC<{ name: IconType }> = ({ name }) => {
|
||||
}
|
||||
`}
|
||||
>
|
||||
<Icon
|
||||
name={name}
|
||||
className={css`
|
||||
font-size: 18px;
|
||||
`}
|
||||
/>
|
||||
<Icon name={name} />
|
||||
<div
|
||||
className={css`
|
||||
padding-top: 16px;
|
||||
|
@@ -1,36 +1,91 @@
|
||||
import React from 'react';
|
||||
import { cx, css } from 'emotion';
|
||||
import { css, cx } from 'emotion';
|
||||
import { GrafanaTheme, toPascalCase } from '@grafana/data';
|
||||
import { stylesFactory } from '../../themes';
|
||||
import { IconType } from './types';
|
||||
import { useTheme } from '../../themes/ThemeContext';
|
||||
import { IconName, IconType, IconSize } from '../../types';
|
||||
import { ComponentSize } from '../../types/size';
|
||||
//@ts-ignore
|
||||
import * as DefaultIcon from '@iconscout/react-unicons';
|
||||
import * as MonoIcon from './assets';
|
||||
|
||||
export interface IconProps {
|
||||
name: IconType;
|
||||
interface IconProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
name: IconName;
|
||||
size?: IconSize;
|
||||
type?: IconType;
|
||||
}
|
||||
export interface SvgProps extends React.HTMLAttributes<SVGElement> {
|
||||
size: number;
|
||||
secondaryColor?: string;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
onMouseDown?: React.MouseEventHandler;
|
||||
}
|
||||
|
||||
const getIconStyles = stylesFactory(() => {
|
||||
const getIconStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
return {
|
||||
container: css`
|
||||
display: inline-block;
|
||||
`,
|
||||
icon: css`
|
||||
display: inline-flex;
|
||||
width: 16px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 16px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
|
||||
&:before {
|
||||
vertical-align: middle;
|
||||
}
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
margin-bottom: ${theme.spacing.xxs};
|
||||
cursor: pointer;
|
||||
fill: currentColor;
|
||||
`,
|
||||
orange: css`
|
||||
fill: ${theme.colors.orange};
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
export const Icon: React.FC<IconProps> = ({ name, className, onClick, onMouseDown }) => {
|
||||
const styles = getIconStyles();
|
||||
return <i className={cx(styles.icon, 'fa', `fa-${name}`, className)} onClick={onClick} onMouseDown={onMouseDown} />;
|
||||
};
|
||||
export const Icon = React.forwardRef<HTMLDivElement, IconProps>(
|
||||
({ size = 'md', type = 'default', name, className, style, ...divElementProps }, ref) => {
|
||||
const theme = useTheme();
|
||||
const styles = getIconStyles(theme);
|
||||
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 */
|
||||
//@ts-ignore
|
||||
const Component = type === 'default' ? DefaultIcon[iconName] : MonoIcon[iconName];
|
||||
|
||||
if (!Component) {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.container} {...divElementProps} ref={ref}>
|
||||
{type === 'default' && <Component size={svgSize} className={cx(styles.icon, className)} style={style} />}
|
||||
{type === 'mono' && (
|
||||
<Component
|
||||
size={svgSize}
|
||||
className={cx(styles.icon, { [styles.orange]: name === 'favorite' }, className)}
|
||||
style={style}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Icon.displayName = 'Icon';
|
||||
|
||||
/* Transform string with px to number and add 2 pxs as path in svg is 2px smaller */
|
||||
const getSvgSize = (size: ComponentSize | 'xl' | 'xxl', theme: GrafanaTheme) => {
|
||||
let svgSize;
|
||||
if (size === 'xl') {
|
||||
svgSize = Number(theme.typography.heading.h1.slice(0, -2));
|
||||
} else if (size === 'xxl') {
|
||||
svgSize = Number(theme.height.lg.slice(0, -2));
|
||||
} else {
|
||||
svgSize = Number(theme.typography.size[size].slice(0, -2)) + 2;
|
||||
}
|
||||
return svgSize;
|
||||
};
|
||||
|
13
packages/grafana-ui/src/components/Icon/assets/Apps.tsx
Normal file
13
packages/grafana-ui/src/components/Icon/assets/Apps.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { SvgProps } from '../Icon';
|
||||
|
||||
export const Apps: FunctionComponent<SvgProps> = ({ size, ...rest }) => {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width={size} height={size} {...rest}>
|
||||
<rect width="9" height="9" x="2" y="2" rx="1" />
|
||||
<rect width="9" height="9" x="2" y="13" rx="1" opacity="0.6" />
|
||||
<rect width="9" height="9" x="13" y="2" rx="1" opacity="0.6" />
|
||||
<rect width="9" height="9" x="13" y="13" rx="1" opacity="0.6" />
|
||||
</svg>
|
||||
);
|
||||
};
|
21
packages/grafana-ui/src/components/Icon/assets/Bell.tsx
Normal file
21
packages/grafana-ui/src/components/Icon/assets/Bell.tsx
Normal file
@@ -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"
|
||||
enableBackground="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>
|
||||
);
|
||||
};
|
14
packages/grafana-ui/src/components/Icon/assets/Cog.tsx
Normal file
14
packages/grafana-ui/src/components/Icon/assets/Cog.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { SvgProps } from '../Icon';
|
||||
|
||||
export const Cog: 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="M21.31641,9.55176l-1.88672-.62891.88965-1.77832a.99983.99983,0,0,0-.1875-1.1543L18.01025,3.86816a.99981.99981,0,0,0-1.15429-.1875l-1.77832.88965-.62891-1.88672A1,1,0,0,0,13.5,2h-3a1,1,0,0,0-.94873.68359L8.92236,4.57031,7.144,3.68066a.99634.99634,0,0,0-1.15429.1875L3.86816,5.99023a.99983.99983,0,0,0-.1875,1.1543l.88965,1.77832-1.88672.62891A.9989.9989,0,0,0,2,10.5v3a.9989.9989,0,0,0,.68359.94824l1.88672.62891-.88965,1.77832a.99983.99983,0,0,0,.1875,1.1543l2.12159,2.12207a.99813.99813,0,0,0,1.15429.1875l1.77832-.88965.62891,1.88672A1,1,0,0,0,10.5,22h3a1,1,0,0,0,.94873-.68359l.62891-1.88672,1.77832.88965a.99994.99994,0,0,0,1.15429-.1875l2.12159-2.12207a.99983.99983,0,0,0,.1875-1.1543l-.88916-1.77832,1.88623-.62891A.9989.9989,0,0,0,22,13.5v-3A.9989.9989,0,0,0,21.31641,9.55176ZM12,15a3,3,0,1,1,3-3A3.00344,3.00344,0,0,1,12,15Z" />
|
||||
<path
|
||||
opacity="0.6"
|
||||
d="M12,16a4,4,0,1,1,4-4A4.00427,4.00427,0,0,1,12,16Zm0-6a2,2,0,1,0,2,2A2.00229,2.00229,0,0,0,12,10Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
10
packages/grafana-ui/src/components/Icon/assets/Favorite.tsx
Normal file
10
packages/grafana-ui/src/components/Icon/assets/Favorite.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { SvgProps } from '../Icon';
|
||||
|
||||
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" />
|
||||
</svg>
|
||||
);
|
||||
};
|
10
packages/grafana-ui/src/components/Icon/assets/Folder.tsx
Normal file
10
packages/grafana-ui/src/components/Icon/assets/Folder.tsx
Normal file
@@ -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"
|
||||
enableBackground="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>
|
||||
);
|
||||
};
|
70
packages/grafana-ui/src/components/Icon/assets/Grafana.tsx
Normal file
70
packages/grafana-ui/src/components/Icon/assets/Grafana.tsx
Normal file
@@ -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>
|
||||
);
|
||||
};
|
23
packages/grafana-ui/src/components/Icon/assets/Import.tsx
Normal file
23
packages/grafana-ui/src/components/Icon/assets/Import.tsx
Normal file
@@ -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"
|
||||
enableBackground="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>
|
||||
);
|
||||
};
|
49
packages/grafana-ui/src/components/Icon/assets/PanelAdd.tsx
Normal file
49
packages/grafana-ui/src/components/Icon/assets/PanelAdd.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { SvgProps } from '../Icon';
|
||||
|
||||
export const PanelAdd: FunctionComponent<SvgProps> = ({ size, ...rest }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
enableBackground="new 0 0 117.8 64"
|
||||
viewBox="0 0 117.8 64"
|
||||
xmlSpace="preserve"
|
||||
width={size}
|
||||
height={size}
|
||||
{...rest}
|
||||
>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="96.4427" y1="83.7013" x2="96.4427" y2="-9.4831">
|
||||
<stop offset="0" style={{ stopColor: '#FFF23A' }} />
|
||||
<stop offset="4.010540e-02" style={{ stopColor: '#FEE62D' }} />
|
||||
<stop offset="0.1171" style={{ stopColor: '#FED41A' }} />
|
||||
<stop offset="0.1964" style={{ stopColor: '#FDC90F' }} />
|
||||
<stop offset="0.2809" style={{ stopColor: '#FDC60B' }} />
|
||||
<stop offset="0.6685" style={{ stopColor: '#F28F3F' }} />
|
||||
<stop offset="0.8876" style={{ stopColor: '#ED693C' }} />
|
||||
<stop offset="1" style={{ stopColor: '#E83E39' }} />
|
||||
</linearGradient>
|
||||
<path
|
||||
d="M15.2,22.7H1.9c-1.1,0-1.9,0.9-1.9,1.9v37.5C0,63.2,0.9,64,1.9,64h13.3c1.1,0,1.9-0.9,1.9-1.9V24.6
|
||||
C17.1,23.5,16.3,22.7,15.2,22.7z"
|
||||
/>
|
||||
<path
|
||||
d="M36.3,10.2H23c-1.1,0-1.9,0.9-1.9,1.9v50c0,1.1,0.9,1.9,1.9,1.9h13.3c1.1,0,1.9-0.9,1.9-1.9v-50
|
||||
C38.2,11.1,37.3,10.2,36.3,10.2z"
|
||||
/>
|
||||
<path
|
||||
d="M57.3,32H44c-1.1,0-1.9,0.9-1.9,1.9v28.1c0,1.1,0.9,1.9,1.9,1.9h13.3c1.1,0,1.9-0.9,1.9-1.9V34
|
||||
C59.2,32.9,58.4,32,57.3,32z"
|
||||
/>
|
||||
<path
|
||||
d="M70.1,38V26.1c0-3.4,2.7-6.1,6.1-6.1h4.1V2c0-1.1-0.9-1.9-1.9-1.9H65.1C64,0,63.1,0.9,63.1,2v60.1
|
||||
c0,1.1,0.9,1.9,1.9,1.9h13.3c1.1,0,1.9-0.9,1.9-1.9V44.1h-4.1C72.9,44.1,70.1,41.3,70.1,38z"
|
||||
/>
|
||||
<path
|
||||
fill="url(#SVGID_1_)"
|
||||
d="M116.7,24.9h-7.2h-0.5h-5.4V11.8c0-0.6-0.5-1.1-1.1-1.1H90.5c-0.6,0-1.1,0.5-1.1,1.1v13.1h-9.1h-4.1
|
||||
c-0.6,0-1.1,0.5-1.1,1.1V38c0,0.6,0.5,1.1,1.1,1.1h4.1h9.1v4.6v1.9v6.7c0,0.6,0.5,1.1,1.1,1.1h11.9c0.6,0,1.1-0.5,1.1-1.1V39.1
|
||||
h13.1c0.6,0,1.1-0.5,1.1-1.1V26.1C117.8,25.5,117.3,24.9,116.7,24.9z"
|
||||
/>
|
||||
</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"
|
||||
enableBackground="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>
|
||||
);
|
||||
};
|
14
packages/grafana-ui/src/components/Icon/assets/Shield.tsx
Normal file
14
packages/grafana-ui/src/components/Icon/assets/Shield.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { SvgProps } from '../Icon';
|
||||
|
||||
export const Shield: 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="M12,22a.9986.9986,0,0,1-.581-.18652l-3.6504-2.60743A9.01643,9.01643,0,0,1,4,11.88281v-7.457a1.00039,1.00039,0,0,1,1.20605-.97851,8.00088,8.00088,0,0,0,6.22168-1.26758.99888.99888,0,0,1,1.14454,0A7.9976,7.9976,0,0,0,18.794,3.44727,1.00039,1.00039,0,0,1,20,4.42578v7.457a9.01643,9.01643,0,0,1-3.76855,7.32324l-3.6504,2.60743A.9986.9986,0,0,1,12,22Z" />
|
||||
<path
|
||||
opacity="0.6"
|
||||
d="M10.84961,14.7002h0a.99927.99927,0,0,1-.707-.293L8.543,12.80664A.99989.99989,0,0,1,9.957,11.39258l.89258.89355L13.543,9.59277A.99989.99989,0,1,1,14.957,11.00684l-3.40039,3.40039A.99928.99928,0,0,1,10.84961,14.7002Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
11
packages/grafana-ui/src/components/Icon/assets/index.ts
Normal file
11
packages/grafana-ui/src/components/Icon/assets/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
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';
|
||||
export * from './PanelAdd';
|
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
);
|
||||
};
|
||||
|
@@ -4,7 +4,7 @@ import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { Input } from './Input';
|
||||
import { Button } from '../Button';
|
||||
import mdx from './Input.mdx';
|
||||
import { getAvailableIcons, IconType } from '../Icon/types';
|
||||
import { getAvailableIcons, IconName } from '../../types';
|
||||
import { KeyValue } from '@grafana/data';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { Field } from '../Forms/Field';
|
||||
@@ -59,11 +59,11 @@ export const simple = () => {
|
||||
const suffix = select('Suffix', prefixSuffixOpts, null, VISUAL_GROUP);
|
||||
let prefixEl: any = prefix;
|
||||
if (prefix && prefix.match(/icon-/g)) {
|
||||
prefixEl = <Icon name={prefix.replace(/icon-/g, '') as IconType} />;
|
||||
prefixEl = <Icon name={prefix.replace(/icon-/g, '') as IconName} />;
|
||||
}
|
||||
let suffixEl: any = suffix;
|
||||
if (suffix && suffix.match(/icon-/g)) {
|
||||
suffixEl = <Icon name={suffix.replace(/icon-/g, '') as IconType} />;
|
||||
suffixEl = <Icon name={suffix.replace(/icon-/g, '') as IconName} />;
|
||||
}
|
||||
|
||||
const CONTAINER_GROUP = 'Container options';
|
||||
|
@@ -246,7 +246,7 @@ export const Input = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
|
||||
|
||||
{(suffix || loading) && (
|
||||
<div className={styles.suffix} ref={suffixRef}>
|
||||
{loading && <Icon name="spinner" className={cx('fa-spin', styles.loadingIndicator)} />}
|
||||
{loading && <Icon name="fa fa-spinner" className={cx('fa-spin', styles.loadingIndicator)} />}
|
||||
{suffix}
|
||||
</div>
|
||||
)}
|
||||
|
@@ -37,7 +37,7 @@ describe('LogDetails', () => {
|
||||
describe('when labels are present', () => {
|
||||
it('should render heading', () => {
|
||||
const wrapper = setup(undefined, { labels: { key1: 'label1', key2: 'label2' } });
|
||||
expect(wrapper.find({ 'aria-label': 'Log Labels' })).toHaveLength(1);
|
||||
expect(wrapper.find({ 'aria-label': 'Log Labels' }).hostNodes()).toHaveLength(1);
|
||||
});
|
||||
it('should render labels', () => {
|
||||
const wrapper = setup(undefined, { labels: { key1: 'label1', key2: 'label2' } });
|
||||
@@ -47,7 +47,7 @@ describe('LogDetails', () => {
|
||||
describe('when row entry has parsable fields', () => {
|
||||
it('should render heading ', () => {
|
||||
const wrapper = setup(undefined, { entry: 'test=successful' });
|
||||
expect(wrapper.find({ title: 'Ad-hoc statistics' })).toHaveLength(1);
|
||||
expect(wrapper.find({ title: 'Ad-hoc statistics' }).hostNodes()).toHaveLength(1);
|
||||
});
|
||||
it('should render parsed fields', () => {
|
||||
const wrapper = setup(undefined, { entry: 'test=successful' });
|
||||
@@ -116,7 +116,7 @@ describe('LogDetails', () => {
|
||||
expect(wrapper.find(LogDetailsRow).length).toBe(3);
|
||||
const traceIdRow = wrapper.find(LogDetailsRow).filter({ parsedKey: 'traceId' });
|
||||
expect(traceIdRow.length).toBe(1);
|
||||
expect(traceIdRow.find('a').length).toBe(1);
|
||||
expect(traceIdRow.find('a').hostNodes().length).toBe(1);
|
||||
expect((traceIdRow.find('a').getDOMNode() as HTMLAnchorElement).href).toBe('localhost:3210/1234');
|
||||
});
|
||||
});
|
||||
|
@@ -32,16 +32,16 @@ describe('LogDetailsRow', () => {
|
||||
});
|
||||
it('should render metrics button', () => {
|
||||
const wrapper = setup();
|
||||
expect(wrapper.find('i.fa-signal')).toHaveLength(1);
|
||||
expect(wrapper.find({ title: 'Ad-hoc statistics' }).hostNodes()).toHaveLength(1);
|
||||
});
|
||||
describe('if props is a label', () => {
|
||||
it('should render filter label button', () => {
|
||||
const wrapper = setup();
|
||||
expect(wrapper.find('i.fa-search-plus')).toHaveLength(1);
|
||||
expect(wrapper.find({ title: 'Filter for value' }).hostNodes()).toHaveLength(1);
|
||||
});
|
||||
it('should render filter out label button', () => {
|
||||
const wrapper = setup();
|
||||
expect(wrapper.find('i.fa-search-minus')).toHaveLength(1);
|
||||
expect(wrapper.find({ title: 'Filter out value' }).hostNodes()).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -66,7 +66,10 @@ describe('LogDetailsRow', () => {
|
||||
});
|
||||
|
||||
expect(wrapper.find(LogLabelStats).length).toBe(0);
|
||||
wrapper.find({ title: 'Ad-hoc statistics' }).simulate('click');
|
||||
wrapper
|
||||
.find({ title: 'Ad-hoc statistics' })
|
||||
.hostNodes()
|
||||
.simulate('click');
|
||||
expect(wrapper.find(LogLabelStats).length).toBe(1);
|
||||
expect(wrapper.find(LogLabelStats).contains('another value')).toBeTruthy();
|
||||
});
|
||||
|
@@ -10,6 +10,7 @@ import { stylesFactory } from '../../themes/stylesFactory';
|
||||
//Components
|
||||
import { LogLabelStats } from './LogLabelStats';
|
||||
import { LinkButton } from '../Button/Button';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
|
||||
export interface Props extends Themeable {
|
||||
parsedValue: string;
|
||||
@@ -94,24 +95,16 @@ class UnThemedLogDetailsRow extends PureComponent<Props, State> {
|
||||
<tr className={cx(style.logDetailsValue, { [styles.noHoverBackground]: showFieldsStats })}>
|
||||
{/* Action buttons - show stats/filter results */}
|
||||
<td className={style.logsDetailsIcon} colSpan={isLabel ? undefined : 3}>
|
||||
<i title="Ad-hoc statistics" className={`fa fa-signal ${styles.hoverCursor}`} onClick={this.showStats} />
|
||||
<Icon name="signal" title={'Ad-hoc statistics'} onClick={this.showStats} />
|
||||
</td>
|
||||
|
||||
{isLabel && (
|
||||
<>
|
||||
<td className={style.logsDetailsIcon}>
|
||||
<i
|
||||
title="Filter for value"
|
||||
className={`fa fa-search-plus ${styles.hoverCursor}`}
|
||||
onClick={this.filterLabel}
|
||||
/>
|
||||
<Icon name="search-minus" title="Filter for value" onClick={this.filterLabel} />
|
||||
</td>
|
||||
<td className={style.logsDetailsIcon}>
|
||||
<i
|
||||
title="Filter out value"
|
||||
className={`fa fa-search-minus ${styles.hoverCursor}`}
|
||||
onClick={this.filterOutLabel}
|
||||
/>
|
||||
<Icon name="search-plus" title="Filter out value" onClick={this.filterOutLabel} />
|
||||
</td>
|
||||
</>
|
||||
)}
|
||||
@@ -129,7 +122,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={
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Field, LinkModel, LogRowModel, TimeZone, DataQueryResponse, GrafanaTheme } from '@grafana/data';
|
||||
import { Icon } from '@grafana/ui';
|
||||
import { cx, css } from 'emotion';
|
||||
|
||||
import {
|
||||
@@ -48,6 +49,8 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
topVerticalAlign: css`
|
||||
label: topVerticalAlign;
|
||||
vertical-align: top;
|
||||
margin-top: -${theme.spacing.xs};
|
||||
margin-left: -${theme.spacing.xxs};
|
||||
`,
|
||||
hoverBackground: css`
|
||||
label: hoverBackground;
|
||||
@@ -129,9 +132,6 @@ class UnThemedLogRow extends PureComponent<Props, State> {
|
||||
const style = getLogRowStyles(theme, row.logLevel);
|
||||
const styles = getStyles(theme);
|
||||
const showUtc = timeZone === 'utc';
|
||||
const showDetailsClassName = showDetails
|
||||
? cx(['fa fa-chevron-down', styles.topVerticalAlign])
|
||||
: cx(['fa fa-chevron-right', styles.topVerticalAlign]);
|
||||
const hoverBackground = cx(style.logsRow, { [styles.hoverBackground]: hasHoverBackground });
|
||||
|
||||
return (
|
||||
@@ -150,7 +150,7 @@ class UnThemedLogRow extends PureComponent<Props, State> {
|
||||
<td className={style.logsRowLevel} />
|
||||
{!allowDetails && (
|
||||
<td title={showDetails ? 'Hide log details' : 'See log details'} className={style.logsRowToggleDetails}>
|
||||
<i className={showDetailsClassName} />
|
||||
<Icon className={styles.topVerticalAlign} name={showDetails ? 'angle-down' : 'angle-right'} />
|
||||
</td>
|
||||
)}
|
||||
{showTime && showUtc && (
|
||||
|
@@ -158,8 +158,10 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
|
||||
logsDetailsIcon: css`
|
||||
label: logs-row-details__icon;
|
||||
position: relative;
|
||||
padding-right: ${theme.spacing.md};
|
||||
color: ${theme.colors.gray3};
|
||||
svg {
|
||||
margin-right: ${theme.spacing.md};
|
||||
}
|
||||
`,
|
||||
logDetailsLabel: css`
|
||||
label: logs-row-details__label;
|
||||
|
@@ -2,13 +2,14 @@ import React from 'react';
|
||||
import { Portal } from '../Portal/Portal';
|
||||
import { cx } from 'emotion';
|
||||
import { withTheme } from '../../themes';
|
||||
import { IconType } from '../Icon/types';
|
||||
import { IconName } from '../../types';
|
||||
import { Themeable } from '../../types';
|
||||
import { getModalStyles } from './getModalStyles';
|
||||
import { ModalHeader } from './ModalHeader';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
|
||||
interface Props extends Themeable {
|
||||
icon?: IconType;
|
||||
icon?: IconName;
|
||||
title: string | JSX.Element;
|
||||
className?: string;
|
||||
|
||||
@@ -50,7 +51,7 @@ export class UnthemedModal extends React.PureComponent<Props> {
|
||||
<div className={styles.modalHeader}>
|
||||
{typeof title === 'string' ? this.renderDefaultHeader(title) : title}
|
||||
<a className={styles.modalHeaderClose} onClick={this.onDismiss}>
|
||||
<i className="fa fa-remove" />
|
||||
<Icon name="times" />
|
||||
</a>
|
||||
</div>
|
||||
<div className={styles.modalContent}>{this.props.children}</div>
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { getModalStyles } from './getModalStyles';
|
||||
import { IconType } from '../Icon/types';
|
||||
import { IconName } from '../../types';
|
||||
import { ThemeContext } from '../../themes';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
icon?: IconType;
|
||||
icon?: IconName;
|
||||
}
|
||||
|
||||
export const ModalHeader: React.FC<Props> = ({ icon, title, children }) => {
|
||||
@@ -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,26 +1,18 @@
|
||||
import React from 'react';
|
||||
import { IconType } from '../Icon/types';
|
||||
import { cx } from 'emotion';
|
||||
import { IconName } from '../../types';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
|
||||
interface Props {
|
||||
icon?: IconType;
|
||||
icon?: IconName;
|
||||
iconClass?: string;
|
||||
}
|
||||
|
||||
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>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { IconType } from '../Icon/types';
|
||||
import { IconName } from '../../types';
|
||||
import { TabsBar } from '../Tabs/TabsBar';
|
||||
import { Tab } from '../Tabs/Tab';
|
||||
import { ModalHeader } from './ModalHeader';
|
||||
@@ -7,11 +7,11 @@ import { ModalHeader } from './ModalHeader';
|
||||
interface ModalTab {
|
||||
value: string;
|
||||
label: string;
|
||||
icon?: string;
|
||||
icon?: IconName;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
icon: IconType;
|
||||
icon: IconName;
|
||||
title: string;
|
||||
tabs: ModalTab[];
|
||||
activeTab: string;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
// Libraries
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { Icon } from '@grafana/ui';
|
||||
|
||||
interface Props {
|
||||
title?: string | JSX.Element;
|
||||
@@ -26,7 +27,7 @@ export const PanelOptionsGroup: FunctionComponent<Props> = props => {
|
||||
<span className="panel-options-group__title">{props.title}</span>
|
||||
{props.onClose && (
|
||||
<button className="btn btn-link" onClick={props.onClose}>
|
||||
<i className="fa fa-remove" />
|
||||
<Icon name="times" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
@@ -3,6 +3,7 @@ import classNames from 'classnames';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { css } from 'emotion';
|
||||
import { Tooltip } from '../Tooltip/Tooltip';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { ButtonSelect } from '../Forms/Legacy/Select/ButtonSelect';
|
||||
import memoizeOne from 'memoize-one';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
@@ -87,7 +88,7 @@ export class RefreshPickerBase extends PureComponent<Props> {
|
||||
className="btn btn--radius-right-0 navbar-button navbar-button--border-right-0"
|
||||
onClick={onRefresh!}
|
||||
>
|
||||
<i className="fa fa-refresh" />
|
||||
<Icon name="sync" size="lg" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
@@ -8,16 +8,16 @@ import { SelectCommonProps, CustomControlProps } from './types';
|
||||
import { SelectBase } from './SelectBase';
|
||||
import { stylesFactory, useTheme } from '../../themes';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { IconType } from '../Icon/types';
|
||||
import { IconName } from '../../types';
|
||||
|
||||
interface ButtonSelectProps<T> extends Omit<SelectCommonProps<T>, 'renderControl' | 'size' | 'prefix'> {
|
||||
icon?: IconType;
|
||||
icon?: IconName;
|
||||
variant?: ButtonVariant;
|
||||
size?: ComponentSize;
|
||||
}
|
||||
|
||||
interface SelectButtonProps extends Omit<ButtonProps, 'icon'> {
|
||||
icon?: IconType;
|
||||
icon?: IconName;
|
||||
isOpen?: boolean;
|
||||
}
|
||||
|
||||
@@ -42,14 +42,12 @@ const SelectButton = React.forwardRef<HTMLButtonElement, SelectButtonProps>(
|
||||
`,
|
||||
}));
|
||||
const styles = getStyles(useTheme());
|
||||
const buttonIcon = `fa fa-${icon}`;
|
||||
const caretIcon = isOpen ? 'caret-up' : 'caret-down';
|
||||
return (
|
||||
<Button {...buttonProps} ref={ref} icon={buttonIcon}>
|
||||
<Button {...buttonProps} ref={ref} icon={icon}>
|
||||
<span className={styles.wrapper}>
|
||||
<span>{children}</span>
|
||||
<span className={styles.caretWrap}>
|
||||
<Icon name={caretIcon} />
|
||||
<Icon name={isOpen ? 'angle-up' : 'angle-down'} />
|
||||
</span>
|
||||
</span>
|
||||
</Button>
|
||||
|
@@ -6,6 +6,6 @@ interface DropdownIndicatorProps {
|
||||
}
|
||||
|
||||
export const DropdownIndicator: React.FC<DropdownIndicatorProps> = ({ isOpen }) => {
|
||||
const icon = isOpen ? 'caret-up' : 'caret-down';
|
||||
const icon = isOpen ? 'angle-up' : 'angle-down';
|
||||
return <Icon name={icon} />;
|
||||
};
|
||||
|
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
|
||||
import { Select, AsyncSelect, MultiSelect, AsyncMultiSelect } from './Select';
|
||||
import { withCenteredStory, withHorizontallyCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { getAvailableIcons, IconType } from '../Icon/types';
|
||||
import { getAvailableIcons, IconName } from '../../types';
|
||||
import { select, boolean } from '@storybook/addon-knobs';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { Button } from '../Button';
|
||||
@@ -46,7 +46,7 @@ const getKnobs = () => {
|
||||
|
||||
let prefixEl: any = prefix;
|
||||
if (prefix && prefix.match(/icon-/g)) {
|
||||
prefixEl = <Icon name={prefix.replace(/icon-/g, '') as IconType} />;
|
||||
prefixEl = <Icon name={prefix.replace(/icon-/g, '') as IconName} />;
|
||||
}
|
||||
|
||||
return {
|
||||
|
@@ -242,7 +242,7 @@ export function SelectBase<T>({
|
||||
);
|
||||
},
|
||||
LoadingIndicator: (props: any) => {
|
||||
return <Icon name="spinner" className="fa fa-spin" />;
|
||||
return <i className="fa fa-spinner fa-spin" />;
|
||||
},
|
||||
LoadingMessage: (props: any) => {
|
||||
return <div className={styles.loadingMessage}>{loadingMessage}</div>;
|
||||
|
@@ -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>
|
||||
)}
|
||||
|
@@ -132,7 +132,7 @@ function renderHeaderCell(column: any, tableStyles: TableStyles, field?: Field)
|
||||
{column.canSort && (
|
||||
<div {...column.getSortByToggleProps()}>
|
||||
{column.render('Header')}
|
||||
{column.isSorted && (column.isSortedDesc ? <Icon name="caret-down" /> : <Icon name="caret-up" />)}
|
||||
{column.isSorted && (column.isSortedDesc ? <Icon name="angle-down" /> : <Icon name="angle-up" />)}
|
||||
</div>
|
||||
)}
|
||||
{!column.canSort && <div>{column.render('Header')}</div>}
|
||||
|
@@ -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>
|
||||
);
|
||||
|
@@ -182,7 +182,9 @@ export class ThresholdsEditor extends PureComponent<Props, State> {
|
||||
{isPercent && <div className={styles.percentIcon}>%</div>}
|
||||
</div>
|
||||
}
|
||||
suffix={<Icon className={styles.trashIcon} name="trash" onClick={() => this.onRemoveThreshold(threshold)} />}
|
||||
suffix={
|
||||
<Icon className={styles.trashIcon} name="trash-alt" onClick={() => this.onRemoveThreshold(threshold)} />
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -198,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-circle" onClick={() => this.onAddThreshold()} variant="secondary">
|
||||
Add threshold
|
||||
</Button>
|
||||
</FullWidthButtonContainer>
|
||||
|
@@ -111,7 +111,7 @@ interface CaretProps {
|
||||
const Caret: FC<CaretProps> = ({ wrapperStyle = '' }) => {
|
||||
return (
|
||||
<div className={wrapperStyle}>
|
||||
<Icon name="caret-down" />
|
||||
<Icon name="angle-down" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@@ -4,6 +4,7 @@ import { css, cx } from 'emotion';
|
||||
|
||||
// Components
|
||||
import { Tooltip } from '../Tooltip/Tooltip';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { TimePickerContent } from './TimePickerContent/TimePickerContent';
|
||||
import { ClickOutsideWrapper } from '../ClickOutsideWrapper/ClickOutsideWrapper';
|
||||
|
||||
@@ -63,11 +64,10 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
display: flex;
|
||||
`,
|
||||
caretIcon: css`
|
||||
margin-left: 3px;
|
||||
|
||||
i {
|
||||
font-size: ${theme.typography.size.md};
|
||||
}
|
||||
margin-left: ${theme.spacing.xs};
|
||||
`,
|
||||
clockIcon: css`
|
||||
margin-right: ${theme.spacing.xs};
|
||||
`,
|
||||
noRightBorderStyle: css`
|
||||
label: noRightBorderStyle;
|
||||
@@ -144,7 +144,7 @@ export class UnthemedTimePicker extends PureComponent<Props, State> {
|
||||
const styles = getStyles(theme);
|
||||
const hasAbsolute = isDateTime(value.raw.from) || isDateTime(value.raw.to);
|
||||
const syncedTimePicker = timeSyncButton && isSynced;
|
||||
const timePickerIconClass = cx('fa fa-clock-o fa-fw', { ['icon-brand-gradient']: syncedTimePicker });
|
||||
const timePickerIconClass = cx({ ['icon-brand-gradient']: syncedTimePicker });
|
||||
const timePickerButtonClass = cx('btn navbar-button navbar-button--tight', {
|
||||
[`btn--radius-right-0 ${styles.noRightBorderStyle}`]: !!timeSyncButton,
|
||||
[`explore-active-button`]: syncedTimePicker,
|
||||
@@ -155,17 +155,15 @@ export class UnthemedTimePicker extends PureComponent<Props, State> {
|
||||
<div className={styles.buttons}>
|
||||
{hasAbsolute && (
|
||||
<button className="btn navbar-button navbar-button--tight" onClick={onMoveBackward}>
|
||||
<i className="fa fa-chevron-left" />
|
||||
<Icon name="angle-left" />
|
||||
</button>
|
||||
)}
|
||||
<div>
|
||||
<Tooltip content={<TimePickerTooltip timeRange={value} />} placement="bottom">
|
||||
<button aria-label="TimePicker Open Button" className={timePickerButtonClass} onClick={this.onOpen}>
|
||||
<i className={timePickerIconClass} />
|
||||
<Icon name="clock-nine" className={cx(styles.clockIcon, timePickerIconClass)} size="lg" />
|
||||
<TimePickerButtonLabel {...this.props} />
|
||||
<span className={styles.caretIcon}>
|
||||
{isOpen ? <i className="fa fa-caret-up fa-fw" /> : <i className="fa fa-caret-down fa-fw" />}
|
||||
</span>
|
||||
<span className={styles.caretIcon}>{<Icon name={isOpen ? 'angle-up' : 'angle-down'} size="lg" />}</span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
{isOpen && (
|
||||
@@ -186,13 +184,13 @@ export class UnthemedTimePicker extends PureComponent<Props, State> {
|
||||
|
||||
{hasAbsolute && (
|
||||
<button className="btn navbar-button navbar-button--tight" onClick={onMoveForward}>
|
||||
<i className="fa fa-chevron-right" />
|
||||
<Icon name="angle-right" size="lg" />
|
||||
</button>
|
||||
)}
|
||||
|
||||
<Tooltip content={ZoomOutTooltip} placement="bottom">
|
||||
<button className="btn navbar-button navbar-button--zoom" onClick={onZoom}>
|
||||
<i className="fa fa-search-minus" />
|
||||
<Icon name="search-minus" size="lg" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
@@ -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;
|
||||
|
@@ -3,6 +3,7 @@ import { useMedia } from 'react-use';
|
||||
import { css } from 'emotion';
|
||||
import { useTheme, stylesFactory } from '../../../themes';
|
||||
import { GrafanaTheme, TimeOption, TimeRange, TimeZone, isDateTime } from '@grafana/data';
|
||||
import { Icon } from '../../Icon/Icon';
|
||||
import { TimePickerTitle } from './TimePickerTitle';
|
||||
import { TimeRangeForm } from './TimeRangeForm';
|
||||
import { CustomScrollbar } from '../../CustomScrollbar/CustomScrollbar';
|
||||
@@ -193,7 +194,7 @@ const NarrowScreenForm: React.FC<FormProps> = props => {
|
||||
<>
|
||||
<div className={styles.header} onClick={() => setCollapsed(!collapsed)}>
|
||||
<TimePickerTitle>Absolute time range</TimePickerTitle>
|
||||
{collapsed ? <i className="fa fa-caret-up" /> : <i className="fa fa-caret-down" />}
|
||||
{<Icon name={collapsed ? 'angle-up' : 'angle-down'} />}
|
||||
</div>
|
||||
{collapsed && (
|
||||
<div className={styles.body}>
|
||||
|
@@ -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 (
|
||||
<>
|
||||
|
@@ -11,8 +11,8 @@ exports[`TimePicker renders buttons correctly 1`] = `
|
||||
className="btn navbar-button navbar-button--tight"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<i
|
||||
className="fa fa-chevron-left"
|
||||
<Icon
|
||||
name="angle-left"
|
||||
/>
|
||||
</button>
|
||||
<div>
|
||||
@@ -38,8 +38,10 @@ exports[`TimePicker renders buttons correctly 1`] = `
|
||||
className="btn navbar-button navbar-button--tight"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<i
|
||||
className="fa fa-clock-o fa-fw"
|
||||
<Icon
|
||||
className="css-znfyx6"
|
||||
name="clock-nine"
|
||||
size="lg"
|
||||
/>
|
||||
<Memo()
|
||||
onChange={[Function]}
|
||||
@@ -276,10 +278,11 @@ exports[`TimePicker renders buttons correctly 1`] = `
|
||||
}
|
||||
/>
|
||||
<span
|
||||
className="css-6x26ye"
|
||||
className="css-132xth5"
|
||||
>
|
||||
<i
|
||||
className="fa fa-caret-down fa-fw"
|
||||
<Icon
|
||||
name="angle-down"
|
||||
size="lg"
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
@@ -289,8 +292,9 @@ exports[`TimePicker renders buttons correctly 1`] = `
|
||||
className="btn navbar-button navbar-button--tight"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<i
|
||||
className="fa fa-chevron-right"
|
||||
<Icon
|
||||
name="angle-right"
|
||||
size="lg"
|
||||
/>
|
||||
</button>
|
||||
<Component
|
||||
@@ -301,8 +305,9 @@ exports[`TimePicker renders buttons correctly 1`] = `
|
||||
className="btn navbar-button navbar-button--zoom"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<i
|
||||
className="fa fa-search-minus"
|
||||
<Icon
|
||||
name="search-minus"
|
||||
size="lg"
|
||||
/>
|
||||
</button>
|
||||
</Component>
|
||||
@@ -321,8 +326,8 @@ exports[`TimePicker renders content correctly after beeing open 1`] = `
|
||||
className="btn navbar-button navbar-button--tight"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<i
|
||||
className="fa fa-chevron-left"
|
||||
<Icon
|
||||
name="angle-left"
|
||||
/>
|
||||
</button>
|
||||
<div>
|
||||
@@ -348,8 +353,10 @@ exports[`TimePicker renders content correctly after beeing open 1`] = `
|
||||
className="btn navbar-button navbar-button--tight"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<i
|
||||
className="fa fa-clock-o fa-fw"
|
||||
<Icon
|
||||
className="css-znfyx6"
|
||||
name="clock-nine"
|
||||
size="lg"
|
||||
/>
|
||||
<Memo()
|
||||
onChange={[Function]}
|
||||
@@ -586,10 +593,11 @@ exports[`TimePicker renders content correctly after beeing open 1`] = `
|
||||
}
|
||||
/>
|
||||
<span
|
||||
className="css-6x26ye"
|
||||
className="css-132xth5"
|
||||
>
|
||||
<i
|
||||
className="fa fa-caret-up fa-fw"
|
||||
<Icon
|
||||
name="angle-up"
|
||||
size="lg"
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
@@ -804,8 +812,9 @@ exports[`TimePicker renders content correctly after beeing open 1`] = `
|
||||
className="btn navbar-button navbar-button--tight"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<i
|
||||
className="fa fa-chevron-right"
|
||||
<Icon
|
||||
name="angle-right"
|
||||
size="lg"
|
||||
/>
|
||||
</button>
|
||||
<Component
|
||||
@@ -816,8 +825,9 @@ exports[`TimePicker renders content correctly after beeing open 1`] = `
|
||||
className="btn navbar-button navbar-button--zoom"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<i
|
||||
className="fa fa-search-minus"
|
||||
<Icon
|
||||
name="search-minus"
|
||||
size="lg"
|
||||
/>
|
||||
</button>
|
||||
</Component>
|
||||
|
@@ -126,7 +126,7 @@ const DraggableFieldName: React.FC<DraggableFieldProps> = ({
|
||||
className={styles.toggle}
|
||||
variant="link"
|
||||
size="md"
|
||||
icon={visible ? 'fa fa-eye' : 'fa fa-eye-slash'}
|
||||
icon={visible ? 'eye' : 'eye-slash'}
|
||||
onClick={() => onToggleVisibility(fieldName, visible)}
|
||||
/>
|
||||
<span className={styles.name}>{fieldName}</span>
|
||||
|
@@ -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-circle" 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-circle"
|
||||
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-circle"
|
||||
onClick={[Function]}
|
||||
variant="primary"
|
||||
>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { IconType } from '../Icon/types';
|
||||
import { IconName } from '../../types';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Button, ButtonVariant } from '../Button';
|
||||
import { Select } from '../Select/Select';
|
||||
@@ -9,7 +9,7 @@ interface ValuePickerProps<T> {
|
||||
/** Label to display on the picker button */
|
||||
label: string;
|
||||
/** Icon to display on the picker button */
|
||||
icon?: IconType;
|
||||
icon?: IconName;
|
||||
/** ValuePicker options */
|
||||
options: Array<SelectableValue<T>>;
|
||||
onChange: (value: SelectableValue<T>) => void;
|
||||
@@ -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-circle'} onClick={() => setIsPicking(true)} variant={variant}>
|
||||
{label}
|
||||
</Button>
|
||||
</FullWidthButtonContainer>
|
||||
|
191
packages/grafana-ui/src/types/icon.ts
Normal file
191
packages/grafana-ui/src/types/icon.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
import { ComponentSize } from './size';
|
||||
export type IconType = 'mono' | 'default';
|
||||
export type IconSize = ComponentSize | 'xl' | 'xxl';
|
||||
|
||||
export type IconName =
|
||||
| 'fa fa-fw fa-unlock'
|
||||
| 'fa fa-envelope'
|
||||
| 'fa fa-spinner'
|
||||
| 'question-circle'
|
||||
| 'angle-up'
|
||||
| 'history'
|
||||
| 'angle-down'
|
||||
| 'filter'
|
||||
| 'angle-left'
|
||||
| 'angle-right'
|
||||
| 'pen'
|
||||
| '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'
|
||||
| 'share-alt'
|
||||
| 'tag-alt'
|
||||
| 'forward'
|
||||
| 'check'
|
||||
| 'add-panel'
|
||||
| 'copy'
|
||||
| 'lock'
|
||||
| 'panel-add'
|
||||
| 'arrow-random'
|
||||
| 'arrow-down'
|
||||
| 'comment-alt'
|
||||
| 'arrow-right'
|
||||
| 'arrow-up'
|
||||
| 'arrow-from-right'
|
||||
| 'keyboard'
|
||||
| 'search'
|
||||
| 'chart-line'
|
||||
| 'search-minus'
|
||||
| 'clock-nine'
|
||||
| 'sync'
|
||||
| 'signin'
|
||||
| 'cog'
|
||||
| 'bars'
|
||||
| 'save'
|
||||
| 'apps'
|
||||
| 'folder-plus'
|
||||
| 'link'
|
||||
| 'upload'
|
||||
| 'columns'
|
||||
| 'home-alt'
|
||||
| 'channel-add'
|
||||
| 'calendar-alt'
|
||||
| 'play'
|
||||
| 'pause'
|
||||
| 'calculator-alt'
|
||||
| 'compass'
|
||||
| 'sliders-v-alt'
|
||||
| 'bell'
|
||||
| 'database'
|
||||
| 'user'
|
||||
| 'camera'
|
||||
| 'plug'
|
||||
| 'shield'
|
||||
| 'key-skeleton-alt'
|
||||
| 'users-alt'
|
||||
| 'graph-bar'
|
||||
| 'book'
|
||||
| 'bolt'
|
||||
| 'comments-alt'
|
||||
| 'document-info'
|
||||
| 'info-circle'
|
||||
| 'bug'
|
||||
| 'cube'
|
||||
| 'star'
|
||||
| 'list-ul'
|
||||
| 'edit'
|
||||
| 'shield'
|
||||
| 'eye'
|
||||
| 'eye-slash'
|
||||
| 'filter'
|
||||
| 'monitor'
|
||||
| 'plus-circle'
|
||||
| 'arrow-left'
|
||||
| 'repeat'
|
||||
| 'external-link-alt'
|
||||
| 'minus'
|
||||
| 'signal'
|
||||
| 'search-plus'
|
||||
| 'search-minus'
|
||||
| 'table'
|
||||
| 'plus'
|
||||
| 'heart'
|
||||
| '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',
|
||||
'play',
|
||||
'pause',
|
||||
'trash-alt',
|
||||
'exclamation-triangle',
|
||||
'times',
|
||||
'step-backward',
|
||||
'square-shape',
|
||||
'share-alt',
|
||||
'camera',
|
||||
'forward',
|
||||
'check',
|
||||
'add-panel',
|
||||
'copy',
|
||||
'lock',
|
||||
'panel-add',
|
||||
'arrow-random',
|
||||
'arrow-from-right',
|
||||
'arrow-left',
|
||||
'keyboard',
|
||||
'search',
|
||||
'chart-line',
|
||||
'search-minus',
|
||||
'clock-nine',
|
||||
'sync',
|
||||
'signin',
|
||||
'cog',
|
||||
'bars',
|
||||
'save',
|
||||
'apps',
|
||||
'folder-plus',
|
||||
'link',
|
||||
'upload',
|
||||
'home-alt',
|
||||
'compass',
|
||||
'sliders-v-alt',
|
||||
'bell',
|
||||
'database',
|
||||
'user',
|
||||
'plug',
|
||||
'shield',
|
||||
'key-skeleton-alt',
|
||||
'users-alt',
|
||||
'graph-bar',
|
||||
'book',
|
||||
'bolt',
|
||||
'cloud-upload',
|
||||
'comments-alt',
|
||||
'list-ul',
|
||||
'document-info',
|
||||
'info-circle',
|
||||
'bug',
|
||||
'cube',
|
||||
'history',
|
||||
'star',
|
||||
'edit',
|
||||
'columns',
|
||||
'eye',
|
||||
'channel-add',
|
||||
'monitor',
|
||||
'favorite',
|
||||
'folder-plus',
|
||||
'plus-square',
|
||||
'import',
|
||||
'folder-open',
|
||||
'file-copy-alt',
|
||||
'arrow-down',
|
||||
'filter',
|
||||
'arrow-up',
|
||||
'exchange-alt',
|
||||
];
|
@@ -3,3 +3,4 @@ export * from './input';
|
||||
export * from './completion';
|
||||
export * from './storybook';
|
||||
export * from './forms';
|
||||
export * from './icon';
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { select } from '@storybook/addon-knobs';
|
||||
import { getAvailableIcons } from '../../components/Icon/types';
|
||||
import { getAvailableIcons } from '../../types';
|
||||
|
||||
const VISUAL_GROUP = 'Visual options';
|
||||
|
||||
|
@@ -109,19 +109,19 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
|
||||
if hasEditPermissionInFoldersQuery.Result {
|
||||
children := []*dtos.NavLink{
|
||||
{Text: "Dashboard", Icon: "gicon gicon-dashboard-new", Url: setting.AppSubUrl + "/dashboard/new"},
|
||||
{Text: "Dashboard", Icon: "apps", Url: setting.AppSubUrl + "/dashboard/new"},
|
||||
}
|
||||
|
||||
if c.OrgRole == models.ROLE_ADMIN || c.OrgRole == models.ROLE_EDITOR {
|
||||
children = append(children, &dtos.NavLink{Text: "Folder", SubTitle: "Create a new folder to organize your dashboards", Id: "folder", Icon: "gicon gicon-folder-new", Url: setting.AppSubUrl + "/dashboards/folder/new"})
|
||||
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: "gicon gicon-dashboard-import", 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",
|
||||
Id: "create",
|
||||
Icon: "fa fa-fw fa-plus",
|
||||
Icon: "plus",
|
||||
Url: setting.AppSubUrl + "/dashboard/new",
|
||||
Children: children,
|
||||
SortWeight: dtos.WeightCreate,
|
||||
@@ -129,18 +129,18 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
}
|
||||
|
||||
dashboardChildNavs := []*dtos.NavLink{
|
||||
{Text: "Home", Id: "home", Url: setting.AppSubUrl + "/", Icon: "gicon gicon-home", HideFromTabs: true},
|
||||
{Text: "Home", Id: "home", Url: setting.AppSubUrl + "/", Icon: "home-alt", HideFromTabs: true},
|
||||
{Text: "Divider", Divider: true, Id: "divider", HideFromTabs: true},
|
||||
{Text: "Manage", Id: "manage-dashboards", Url: setting.AppSubUrl + "/dashboards", Icon: "gicon gicon-manage"},
|
||||
{Text: "Playlists", Id: "playlists", Url: setting.AppSubUrl + "/playlists", Icon: "gicon gicon-playlists"},
|
||||
{Text: "Snapshots", Id: "snapshots", Url: setting.AppSubUrl + "/dashboard/snapshots", Icon: "gicon gicon-snapshots"},
|
||||
{Text: "Manage", Id: "manage-dashboards", Url: setting.AppSubUrl + "/dashboards", Icon: "sitemap"},
|
||||
{Text: "Playlists", Id: "playlists", Url: setting.AppSubUrl + "/playlists", Icon: "presentation-play"},
|
||||
{Text: "Snapshots", Id: "snapshots", Url: setting.AppSubUrl + "/dashboard/snapshots", Icon: "camera"},
|
||||
}
|
||||
|
||||
data.NavTree = append(data.NavTree, &dtos.NavLink{
|
||||
Text: "Dashboards",
|
||||
Id: "dashboards",
|
||||
SubTitle: "Manage dashboards & folders",
|
||||
Icon: "gicon gicon-dashboard",
|
||||
Icon: "apps",
|
||||
Url: setting.AppSubUrl + "/",
|
||||
SortWeight: dtos.WeightDashboard,
|
||||
Children: dashboardChildNavs,
|
||||
@@ -151,7 +151,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
Text: "Explore",
|
||||
Id: "explore",
|
||||
SubTitle: "Explore your data",
|
||||
Icon: "gicon gicon-explore",
|
||||
Icon: "compass",
|
||||
SortWeight: dtos.WeightExplore,
|
||||
Url: setting.AppSubUrl + "/explore",
|
||||
})
|
||||
@@ -172,8 +172,8 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
HideFromMenu: true,
|
||||
SortWeight: dtos.WeightProfile,
|
||||
Children: []*dtos.NavLink{
|
||||
{Text: "Preferences", Id: "profile-settings", Url: setting.AppSubUrl + "/profile", Icon: "gicon gicon-preferences"},
|
||||
{Text: "Change Password", Id: "change-password", Url: setting.AppSubUrl + "/profile/password", Icon: "fa fa-fw fa-lock", HideFromMenu: true},
|
||||
{Text: "Preferences", Id: "profile-settings", Url: setting.AppSubUrl + "/profile", Icon: "sliders-v-alt"},
|
||||
{Text: "Change Password", Id: "change-password", Url: setting.AppSubUrl + "/profile/password", Icon: "lock", HideFromMenu: true},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
Text: "Sign out",
|
||||
Id: "sign-out",
|
||||
Url: setting.AppSubUrl + "/logout",
|
||||
Icon: "fa fa-fw fa-sign-out",
|
||||
Icon: "arrow-from-right",
|
||||
Target: "_self",
|
||||
HideFromTabs: true,
|
||||
})
|
||||
@@ -194,15 +194,15 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
|
||||
if setting.AlertingEnabled && (c.OrgRole == models.ROLE_ADMIN || c.OrgRole == models.ROLE_EDITOR) {
|
||||
alertChildNavs := []*dtos.NavLink{
|
||||
{Text: "Alert Rules", Id: "alert-list", Url: setting.AppSubUrl + "/alerting/list", Icon: "gicon gicon-alert-rules"},
|
||||
{Text: "Notification channels", Id: "channels", Url: setting.AppSubUrl + "/alerting/notifications", Icon: "gicon gicon-alert-notification-channel"},
|
||||
{Text: "Alert Rules", Id: "alert-list", Url: setting.AppSubUrl + "/alerting/list", Icon: "list-ul"},
|
||||
{Text: "Notification channels", Id: "channels", Url: setting.AppSubUrl + "/alerting/notifications", Icon: "comment-alt-share"},
|
||||
}
|
||||
|
||||
data.NavTree = append(data.NavTree, &dtos.NavLink{
|
||||
Text: "Alerting",
|
||||
SubTitle: "Alert rules & notifications",
|
||||
Id: "alerting",
|
||||
Icon: "gicon gicon-alert",
|
||||
Icon: "bell",
|
||||
Url: setting.AppSubUrl + "/alerting/list",
|
||||
Children: alertChildNavs,
|
||||
SortWeight: dtos.WeightAlerting,
|
||||
@@ -259,7 +259,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
|
||||
if len(appLink.Children) > 0 && c.OrgRole == models.ROLE_ADMIN {
|
||||
appLink.Children = append(appLink.Children, &dtos.NavLink{Divider: true})
|
||||
appLink.Children = append(appLink.Children, &dtos.NavLink{Text: "Plugin Config", Icon: "gicon gicon-cog", Url: setting.AppSubUrl + "/plugins/" + plugin.Id + "/"})
|
||||
appLink.Children = append(appLink.Children, &dtos.NavLink{Text: "Plugin Config", Icon: "cog", Url: setting.AppSubUrl + "/plugins/" + plugin.Id + "/"})
|
||||
}
|
||||
|
||||
if len(appLink.Children) > 0 {
|
||||
@@ -273,7 +273,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
if c.OrgRole == models.ROLE_ADMIN {
|
||||
configNodes = append(configNodes, &dtos.NavLink{
|
||||
Text: "Data Sources",
|
||||
Icon: "gicon gicon-datasources",
|
||||
Icon: "database",
|
||||
Description: "Add and configure data sources",
|
||||
Id: "datasources",
|
||||
Url: setting.AppSubUrl + "/datasources",
|
||||
@@ -282,7 +282,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
Text: "Users",
|
||||
Id: "users",
|
||||
Description: "Manage org members",
|
||||
Icon: "gicon gicon-user",
|
||||
Icon: "user",
|
||||
Url: setting.AppSubUrl + "/org/users",
|
||||
})
|
||||
}
|
||||
@@ -292,7 +292,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
Text: "Teams",
|
||||
Id: "teams",
|
||||
Description: "Manage org groups",
|
||||
Icon: "gicon gicon-team",
|
||||
Icon: "users-alt",
|
||||
Url: setting.AppSubUrl + "/org/teams",
|
||||
})
|
||||
}
|
||||
@@ -302,7 +302,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
Text: "Plugins",
|
||||
Id: "plugins",
|
||||
Description: "View and configure plugins",
|
||||
Icon: "gicon gicon-plugins",
|
||||
Icon: "plug",
|
||||
Url: setting.AppSubUrl + "/plugins",
|
||||
})
|
||||
|
||||
@@ -310,14 +310,14 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
Text: "Preferences",
|
||||
Id: "org-settings",
|
||||
Description: "Organization preferences",
|
||||
Icon: "gicon gicon-preferences",
|
||||
Icon: "sliders-v-alt",
|
||||
Url: setting.AppSubUrl + "/org",
|
||||
})
|
||||
configNodes = append(configNodes, &dtos.NavLink{
|
||||
Text: "API Keys",
|
||||
Id: "apikeys",
|
||||
Description: "Create & manage API keys",
|
||||
Icon: "gicon gicon-apikeys",
|
||||
Icon: "key-skeleton-alt",
|
||||
Url: setting.AppSubUrl + "/org/apikeys",
|
||||
})
|
||||
}
|
||||
@@ -327,7 +327,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
Id: "cfg",
|
||||
Text: "Configuration",
|
||||
SubTitle: "Organization: " + c.OrgName,
|
||||
Icon: "gicon gicon-cog",
|
||||
Icon: "cog",
|
||||
Url: configNodes[0].Url,
|
||||
SortWeight: dtos.WeightConfig,
|
||||
Children: configNodes,
|
||||
@@ -336,15 +336,15 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
|
||||
if c.IsGrafanaAdmin {
|
||||
adminNavLinks := []*dtos.NavLink{
|
||||
{Text: "Users", Id: "global-users", Url: setting.AppSubUrl + "/admin/users", Icon: "gicon gicon-user"},
|
||||
{Text: "Orgs", Id: "global-orgs", Url: setting.AppSubUrl + "/admin/orgs", Icon: "gicon gicon-org"},
|
||||
{Text: "Settings", Id: "server-settings", Url: setting.AppSubUrl + "/admin/settings", Icon: "gicon gicon-preferences"},
|
||||
{Text: "Stats", Id: "server-stats", Url: setting.AppSubUrl + "/admin/stats", Icon: "fa fa-fw fa-bar-chart"},
|
||||
{Text: "Users", Id: "global-users", Url: setting.AppSubUrl + "/admin/users", Icon: "user"},
|
||||
{Text: "Orgs", Id: "global-orgs", Url: setting.AppSubUrl + "/admin/orgs", Icon: "building"},
|
||||
{Text: "Settings", Id: "server-settings", Url: setting.AppSubUrl + "/admin/settings", Icon: "sliders-v-alt"},
|
||||
{Text: "Stats", Id: "server-stats", Url: setting.AppSubUrl + "/admin/stats", Icon: "graph-bar"},
|
||||
}
|
||||
|
||||
if setting.LDAPEnabled {
|
||||
adminNavLinks = append(adminNavLinks, &dtos.NavLink{
|
||||
Text: "LDAP", Id: "ldap", Url: setting.AppSubUrl + "/admin/ldap", Icon: "fa fa-fw fa-address-book-o",
|
||||
Text: "LDAP", Id: "ldap", Url: setting.AppSubUrl + "/admin/ldap", Icon: "book",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
SubTitle: "Manage all users & orgs",
|
||||
HideFromTabs: true,
|
||||
Id: "admin",
|
||||
Icon: "gicon gicon-shield",
|
||||
Icon: "shield",
|
||||
Url: setting.AppSubUrl + "/admin/users",
|
||||
SortWeight: dtos.WeightAdmin,
|
||||
Children: adminNavLinks,
|
||||
@@ -365,7 +365,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
SubTitle: fmt.Sprintf(`%s v%s (%s)`, setting.ApplicationName, setting.BuildVersion, setting.BuildCommit),
|
||||
Id: "help",
|
||||
Url: "#",
|
||||
Icon: "gicon gicon-question",
|
||||
Icon: "question-circle",
|
||||
HideFromMenu: true,
|
||||
SortWeight: dtos.WeightHelp,
|
||||
Children: []*dtos.NavLink{},
|
||||
|
@@ -44,7 +44,7 @@ func (l *OSSLicensingService) Init() error {
|
||||
Text: "Upgrade",
|
||||
Id: "upgrading",
|
||||
Url: l.LicenseURL(req.SignedInUser),
|
||||
Icon: "fa fa-fw fa-unlock-alt",
|
||||
Icon: "unlock",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -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}
|
||||
|
@@ -12,19 +12,19 @@ export let getFooterLinks = (): FooterLink[] => {
|
||||
return [
|
||||
{
|
||||
text: 'Documentation',
|
||||
icon: 'fa fa-file-code-o',
|
||||
icon: 'document-info',
|
||||
url: 'https://grafana.com/docs/grafana/latest/?utm_source=grafana_footer',
|
||||
target: '_blank',
|
||||
},
|
||||
{
|
||||
text: 'Support',
|
||||
icon: 'fa fa-support',
|
||||
icon: 'question-circle',
|
||||
url: 'https://grafana.com/products/enterprise/?utm_source=grafana_footer',
|
||||
target: '_blank',
|
||||
},
|
||||
{
|
||||
text: 'Community',
|
||||
icon: 'fa fa-comments-o',
|
||||
icon: 'comments-alt',
|
||||
url: 'https://community.grafana.com/?utm_source=grafana_footer',
|
||||
target: '_blank',
|
||||
},
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import React, { FC } from 'react';
|
||||
import { Icon } from '@grafana/ui';
|
||||
|
||||
export type LayoutMode = LayoutModes.Grid | LayoutModes.List;
|
||||
|
||||
@@ -22,7 +23,7 @@ const LayoutSelector: FC<Props> = props => {
|
||||
}}
|
||||
className={mode === LayoutModes.List ? 'active' : ''}
|
||||
>
|
||||
<i className="fa fa-list" />
|
||||
<Icon name="list-ul" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
@@ -30,7 +31,7 @@ const LayoutSelector: FC<Props> = props => {
|
||||
}}
|
||||
className={mode === LayoutModes.Grid ? 'active' : ''}
|
||||
>
|
||||
<i className="fa fa-th" />
|
||||
<Icon name="table" />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
@@ -45,7 +45,7 @@ export class OrgSwitcher extends React.PureComponent<Props, State> {
|
||||
const currentOrgId = contextSrv.user.orgId;
|
||||
|
||||
return (
|
||||
<Modal title="Switch Organization" icon="random" onDismiss={onDismiss} isOpen={true}>
|
||||
<Modal title="Switch Organization" icon="arrow-random" onDismiss={onDismiss} isOpen={true}>
|
||||
<table className="filter-table form-inline">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@@ -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" className={iconClassName} />}
|
||||
{main.img && <img className="page-header__img" src={main.img} />}
|
||||
</span>
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
import { UserPicker } from 'app/core/components/Select/UserPicker';
|
||||
import { TeamPicker, Team } from 'app/core/components/Select/TeamPicker';
|
||||
import { LegacyForms } from '@grafana/ui';
|
||||
import { LegacyForms, Icon } from '@grafana/ui';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { User } from 'app/types';
|
||||
import {
|
||||
@@ -91,7 +91,7 @@ class AddPermissions extends Component<Props, NewDashboardAclItem> {
|
||||
return (
|
||||
<div className="gf-form-inline cta-form">
|
||||
<button className="cta-form__close btn btn-transparent" onClick={onCancel}>
|
||||
<i className="fa fa-close" />
|
||||
<Icon name="times" />
|
||||
</button>
|
||||
<form name="addPermission" onSubmit={this.onSubmit}>
|
||||
<h5>Add Permission For</h5>
|
||||
|
@@ -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>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { getTagColorsFromName } from '@grafana/ui';
|
||||
import { getTagColorsFromName, Icon } from '@grafana/ui';
|
||||
|
||||
export interface Props {
|
||||
label: string;
|
||||
@@ -24,7 +24,7 @@ export class TagBadge extends React.Component<Props, any> {
|
||||
|
||||
return (
|
||||
<span className={`label label-tag`} style={tagStyle}>
|
||||
{removeIcon && <i className="fa fa-remove" />}
|
||||
{removeIcon && <Icon name="times" />}
|
||||
{label} {countLabel}
|
||||
</span>
|
||||
);
|
||||
|
@@ -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,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { appEvents } from 'app/core/core';
|
||||
import { Icon } from '@grafana/ui';
|
||||
|
||||
export class HelpModal extends React.PureComponent {
|
||||
static tabIndex = 0;
|
||||
@@ -52,11 +53,11 @@ export class HelpModal extends React.PureComponent {
|
||||
<div className="modal-body">
|
||||
<div className="modal-header">
|
||||
<h2 className="modal-header-title">
|
||||
<i className="fa fa-keyboard-o" />
|
||||
<Icon name="keyboard" size="lg" />
|
||||
<span className="p-l-1">Shortcuts</span>
|
||||
</h2>
|
||||
<a className="modal-header-close" onClick={this.dismiss}>
|
||||
<i className="fa fa-remove" />
|
||||
<Icon name="times" style={{ margin: '3px 0 0 0' }} />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
@@ -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'" style="margin-left: 10px;" size="'xs'"></icon>`,
|
||||
transclude: true,
|
||||
link: (scope: any, elem: any, attrs: any, ctrl: any, transclude: any) => {
|
||||
const offset = attrs.offset || '0 -10px';
|
||||
|
@@ -9,7 +9,7 @@ const template = `
|
||||
<i class="fa fa-list"></i>
|
||||
</button>
|
||||
<button ng-click="ctrl.gridView()" ng-class="{active: ctrl.mode === 'grid'}">
|
||||
<i class="fa fa-th"></i>
|
||||
<icon name="table"></i>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
@@ -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> {{tagName}}
|
||||
<icon name="'times'"></icon> {{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> Clear
|
||||
<icon name="'times'"></icon> 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 ->'"
|
||||
|
@@ -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,7 +1,9 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import appEvents from '../../app_events';
|
||||
import { User } from '../../services/context_srv';
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { Icon, IconName } from '@grafana/ui';
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { OrgSwitcher } from '../OrgSwitcher';
|
||||
import { getFooterLinks } from '../Footer/Footer';
|
||||
@@ -15,7 +17,7 @@ interface State {
|
||||
showSwitcherModal: boolean;
|
||||
}
|
||||
|
||||
class BottomNavLinks extends PureComponent<Props, State> {
|
||||
export default class BottomNavLinks extends PureComponent<Props, State> {
|
||||
state: State = {
|
||||
showSwitcherModal: false,
|
||||
};
|
||||
@@ -35,6 +37,9 @@ class BottomNavLinks extends PureComponent<Props, State> {
|
||||
render() {
|
||||
const { link, user } = this.props;
|
||||
const { showSwitcherModal } = this.state;
|
||||
const subMenuIconClassName = css`
|
||||
margin-right: 8px;
|
||||
`;
|
||||
|
||||
let children = link.children || [];
|
||||
|
||||
@@ -46,7 +51,7 @@ class BottomNavLinks extends PureComponent<Props, State> {
|
||||
<div className="sidemenu-item dropdown dropup">
|
||||
<a href={link.url} className="sidemenu-link" target={link.target}>
|
||||
<span className="icon-circle sidemenu-icon">
|
||||
{link.icon && <i className={link.icon} />}
|
||||
{link.icon && <Icon name={link.icon as IconName} size="xl" />}
|
||||
{link.img && <img src={link.img} />}
|
||||
</span>
|
||||
</a>
|
||||
@@ -64,7 +69,7 @@ class BottomNavLinks extends PureComponent<Props, State> {
|
||||
<div className="sidemenu-org-switcher__org-name">{user.orgName}</div>
|
||||
</div>
|
||||
<div className="sidemenu-org-switcher__switch">
|
||||
<i className="fa fa-fw fa-random" />
|
||||
<Icon name="arrow-random" className={subMenuIconClassName} />
|
||||
Switch
|
||||
</div>
|
||||
</a>
|
||||
@@ -77,7 +82,7 @@ class BottomNavLinks extends PureComponent<Props, State> {
|
||||
return (
|
||||
<li key={`${child.text}-${index}`}>
|
||||
<a href={child.url} target={child.target} rel="noopener">
|
||||
{child.icon && <i className={child.icon} />}
|
||||
{child.icon && <Icon name={child.icon as IconName} className={subMenuIconClassName} />}
|
||||
{child.text}
|
||||
</a>
|
||||
</li>
|
||||
@@ -87,7 +92,7 @@ class BottomNavLinks extends PureComponent<Props, State> {
|
||||
{link.id === 'help' && (
|
||||
<li key="keyboard-shortcuts">
|
||||
<a onClick={() => this.onOpenShortcuts()}>
|
||||
<i className="fa fa-keyboard-o" /> Keyboard shortcuts
|
||||
<Icon name="keyboard" className={subMenuIconClassName} /> Keyboard shortcuts
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
@@ -100,5 +105,3 @@ class BottomNavLinks extends PureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default BottomNavLinks;
|
||||
|
@@ -1,4 +1,6 @@
|
||||
import React, { FC } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { Icon, IconName, useTheme } from '@grafana/ui';
|
||||
|
||||
export interface Props {
|
||||
child: any;
|
||||
@@ -7,11 +9,15 @@ export interface Props {
|
||||
const DropDownChild: FC<Props> = props => {
|
||||
const { child } = props;
|
||||
const listItemClassName = child.divider ? 'divider' : '';
|
||||
const theme = useTheme();
|
||||
const iconClassName = css`
|
||||
margin-right: ${theme.spacing.sm};
|
||||
`;
|
||||
|
||||
return (
|
||||
<li className={listItemClassName}>
|
||||
<a href={child.url}>
|
||||
{child.icon && <i className={child.icon} />}
|
||||
{child.icon && <Icon name={child.icon as IconName} className={iconClassName} />}
|
||||
{child.text}
|
||||
</a>
|
||||
</li>
|
||||
|
@@ -5,6 +5,7 @@ import BottomSection from './BottomSection';
|
||||
import config from 'app/core/config';
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { Branding } from 'app/core/components/Branding/Branding';
|
||||
import { Icon } from '@grafana/ui';
|
||||
|
||||
const homeUrl = config.appSubUrl || '/';
|
||||
|
||||
@@ -19,9 +20,9 @@ export class SideMenu extends PureComponent {
|
||||
<Branding.MenuLogo />
|
||||
</a>,
|
||||
<div className="sidemenu__logo_small_breakpoint" onClick={this.toggleSideMenuSmallBreakpoint} key="hamburger">
|
||||
<i className="fa fa-bars" />
|
||||
<Icon name="bars" />
|
||||
<span className="sidemenu__close">
|
||||
<i className="fa fa-times" />
|
||||
<Icon name="times" />
|
||||
Close
|
||||
</span>
|
||||
</div>,
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import React, { FC } from 'react';
|
||||
import SideMenuDropDown from './SideMenuDropDown';
|
||||
import { Icon } from '@grafana/ui';
|
||||
|
||||
export interface Props {
|
||||
link: any;
|
||||
@@ -11,7 +12,7 @@ const TopSectionItem: FC<Props> = props => {
|
||||
<div className="sidemenu-item dropdown">
|
||||
<a className="sidemenu-link" href={link.url} target={link.target}>
|
||||
<span className="icon-circle sidemenu-icon">
|
||||
<i className={link.icon} />
|
||||
<Icon name={link.icon} size="xl" />
|
||||
{link.img && <img src={link.img} />}
|
||||
</span>
|
||||
</a>
|
||||
|
@@ -118,8 +118,9 @@ exports[`Render should render organization switcher 1`] = `
|
||||
<div
|
||||
className="sidemenu-org-switcher__switch"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-random"
|
||||
<Icon
|
||||
className="css-f8is2k"
|
||||
name="arrow-random"
|
||||
/>
|
||||
Switch
|
||||
</div>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user