diff --git a/packages/grafana-data/src/types/config.ts b/packages/grafana-data/src/types/config.ts index e11886271ff..8c87464f494 100644 --- a/packages/grafana-data/src/types/config.ts +++ b/packages/grafana-data/src/types/config.ts @@ -6,7 +6,7 @@ import { DataSourceInstanceSettings } from './datasource'; import { FeatureToggles } from './featureToggles.gen'; import { PanelPluginMeta } from './panel'; -import { GrafanaTheme, NavLinkDTO, OrgRole } from '.'; +import { GrafanaTheme, IconName, NavLinkDTO, OrgRole } from '.'; /** * Describes the build information that will be available via the Grafana configuration. @@ -104,7 +104,7 @@ export type OAuth = * * @public */ -export type OAuthSettings = Partial>; +export type OAuthSettings = Partial>; /** Current user info included in bootData * diff --git a/packages/grafana-data/src/types/icon.ts b/packages/grafana-data/src/types/icon.ts new file mode 100644 index 00000000000..bbc1d0a0c8f --- /dev/null +++ b/packages/grafana-data/src/types/icon.ts @@ -0,0 +1,205 @@ +export const availableIconsIndex = { + google: true, + microsoft: true, + github: true, + gitlab: true, + okta: true, + anchor: true, + 'angle-double-down': true, + 'angle-double-right': true, + 'angle-double-up': true, + 'angle-down': true, + 'angle-left': true, + 'angle-right': true, + 'angle-up': true, + apps: true, + arrow: true, + 'arrow-down': true, + 'arrow-from-right': true, + 'arrow-left': true, + 'arrow-random': true, + 'arrow-right': true, + 'arrow-up': true, + 'arrows-h': true, + 'arrows-v': true, + backward: true, + bars: true, + bell: true, + 'bell-slash': true, + bolt: true, + book: true, + bookmark: true, + 'book-open': true, + 'brackets-curly': true, + bug: true, + building: true, + 'calculator-alt': true, + 'calendar-alt': true, + camera: true, + capture: true, + 'channel-add': true, + 'chart-line': true, + check: true, + 'check-circle': true, + 'check-square': true, + circle: true, + 'clipboard-alt': true, + 'clock-nine': true, + cloud: true, + 'cloud-download': true, + 'cloud-upload': true, + 'code-branch': true, + cog: true, + columns: true, + 'comment-alt': true, + 'comment-alt-message': true, + 'comment-alt-share': true, + 'comments-alt': true, + compass: true, + copy: true, + 'credit-card': true, + cube: true, + dashboard: true, + database: true, + 'document-info': true, + 'download-alt': true, + draggabledots: true, + edit: true, + 'ellipsis-v': true, + envelope: true, + 'exchange-alt': true, + 'exclamation-triangle': true, + 'exclamation-circle': true, + 'external-link-alt': true, + eye: true, + 'eye-slash': true, + 'ellipsis-h': true, + 'fa fa-spinner': true, + favorite: true, + 'file-alt': true, + 'file-blank': true, + 'file-copy-alt': true, + filter: true, + folder: true, + font: true, + fire: true, + 'folder-open': true, + 'folder-plus': true, + 'folder-upload': true, + forward: true, + 'gf-bar-alignment-after': true, + 'gf-bar-alignment-before': true, + 'gf-bar-alignment-center': true, + 'gf-glue': true, + 'gf-grid': true, + 'gf-interpolation-linear': true, + 'gf-interpolation-smooth': true, + 'gf-interpolation-step-after': true, + 'gf-interpolation-step-before': true, + 'gf-landscape': true, + 'gf-layout-simple': true, + 'gf-logs': true, + 'gf-portrait': true, + 'gf-service-account': true, + grafana: true, + 'graph-bar': true, + heart: true, + 'heart-break': true, + history: true, + home: true, + 'home-alt': true, + 'horizontal-align-center': true, + 'horizontal-align-left': true, + 'horizontal-align-right': true, + hourglass: true, + import: true, + info: true, + 'info-circle': true, + 'key-skeleton-alt': true, + keyboard: true, + 'layer-group': true, + 'library-panel': true, + 'line-alt': true, + link: true, + 'list-ui-alt': true, + 'list-ul': true, + lock: true, + 'map-marker': true, + message: true, + minus: true, + 'minus-circle': true, + 'mobile-android': true, + monitor: true, + palette: true, + 'panel-add': true, + pause: true, + pen: true, + percentage: true, + play: true, + plug: true, + plus: true, + 'plus-circle': true, + 'plus-square': true, + power: true, + 'presentation-play': true, + process: true, + 'question-circle': true, + 'record-audio': true, + repeat: true, + rocket: true, + 'ruler-combined': true, + save: true, + search: true, + 'search-minus': true, + 'search-plus': true, + 'share-alt': true, + shield: true, + 'shield-exclamation': true, + signal: true, + signin: true, + signout: true, + sitemap: true, + slack: true, + 'sliders-v-alt': true, + 'sort-amount-down': true, + 'sort-amount-up': true, + 'square-shape': true, + star: true, + 'step-backward': true, + 'stopwatch-slash': true, + sync: true, + table: true, + 'tag-alt': true, + 'text-fields': true, + times: true, + 'toggle-on': true, + 'trash-alt': true, + unlock: true, + upload: true, + user: true, + 'users-alt': true, + 'vertical-align-bottom': true, + 'vertical-align-center': true, + 'vertical-align-top': true, + 'wrap-text': true, + rss: true, + x: true, +}; + +export type IconName = keyof typeof availableIconsIndex; + +export function isIconName(iconName: unknown): iconName is IconName { + if (!iconName || typeof iconName !== 'string') { + return false; + } + + return iconName in availableIconsIndex; +} + +export function toIconName(iconName: string): IconName | undefined { + if (isIconName(iconName)) { + return iconName; + } + + return undefined; +} diff --git a/packages/grafana-data/src/types/index.ts b/packages/grafana-data/src/types/index.ts index 2fbde4c37fd..0f0c2472485 100644 --- a/packages/grafana-data/src/types/index.ts +++ b/packages/grafana-data/src/types/index.ts @@ -50,3 +50,4 @@ export type { FeatureToggles } from './featureToggles.gen'; export * from './alerts'; export * from './slider'; export * from './accesscontrol'; +export * from './icon'; diff --git a/packages/grafana-data/src/types/navModel.ts b/packages/grafana-data/src/types/navModel.ts index 567cd3e9410..a90815644e2 100644 --- a/packages/grafana-data/src/types/navModel.ts +++ b/packages/grafana-data/src/types/navModel.ts @@ -1,12 +1,14 @@ import { ComponentType } from 'react'; +import { IconName } from './icon'; + export interface NavLinkDTO { id?: string; text: string; description?: string; section?: NavSection; subTitle?: string; - icon?: string; + icon?: IconName; img?: string; url?: string; target?: string; diff --git a/packages/grafana-data/src/types/plugin.ts b/packages/grafana-data/src/types/plugin.ts index c14468083e0..b940ab4ab4b 100644 --- a/packages/grafana-data/src/types/plugin.ts +++ b/packages/grafana-data/src/types/plugin.ts @@ -1,6 +1,7 @@ import { ComponentType } from 'react'; import { KeyValue } from './data'; +import { IconName } from './icon'; /** Describes plugins life cycle status */ export enum PluginState { @@ -158,7 +159,7 @@ export interface PluginConfigPageProps { export interface PluginConfigPage { title: string; // Display - icon?: string; + icon?: IconName; id: string; // Unique, in URL body: ComponentType>; diff --git a/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.tsx b/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.tsx index a97dc1a40d1..576e0d29919 100644 --- a/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.tsx +++ b/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.tsx @@ -2,10 +2,9 @@ import { css, cx } from '@emotion/css'; import { uniqueId } from 'lodash'; import React, { useCallback, useEffect, useRef } from 'react'; -import { GrafanaTheme2, SelectableValue } from '@grafana/data'; +import { GrafanaTheme2, SelectableValue, toIconName } from '@grafana/data'; import { useStyles2 } from '../../../themes'; -import { toIconName } from '../../../types/icon'; import { Icon } from '../../Icon/Icon'; import { RadioButtonSize, RadioButton } from './RadioButton'; @@ -74,6 +73,7 @@ export function RadioButtonGroup({ {options.map((opt, i) => { const isItemDisabled = disabledOptions && opt.value && disabledOptions.includes(opt.value); const icon = opt.icon ? toIconName(opt.icon) : undefined; + return ( { {icons .filter((val) => val.includes(filter)) .map((i) => { - return ; + return ; })} diff --git a/packages/grafana-ui/src/components/Icon/Icon.tsx b/packages/grafana-ui/src/components/Icon/Icon.tsx index 99c2defe8fa..c601c17adc1 100644 --- a/packages/grafana-ui/src/components/Icon/Icon.tsx +++ b/packages/grafana-ui/src/components/Icon/Icon.tsx @@ -2,11 +2,10 @@ import { css, cx } from '@emotion/css'; import React from 'react'; import SVG from 'react-inlinesvg'; -import { GrafanaTheme2 } from '@grafana/data'; +import { GrafanaTheme2, isIconName } from '@grafana/data'; import { useStyles2 } from '../../themes/ThemeContext'; import { IconName, IconType, IconSize } from '../../types/icon'; -export { toIconName } from '../../types/icon'; import { cacheInitialized, initIconCache, iconRoot } from './iconBundle'; import { getIconSubDir, getSvgSize } from './utils'; @@ -54,6 +53,10 @@ export const Icon = React.forwardRef( initIconCache(); } + if (!isIconName(name)) { + console.warn('Icon component passed an invalid icon name', name); + } + const svgSize = getSvgSize(size); const svgHgt = svgSize; const svgWid = name?.startsWith('gf-bar-align') ? 16 : name?.startsWith('gf-interp') ? 30 : svgSize; diff --git a/packages/grafana-ui/src/components/Input/storyUtils.tsx b/packages/grafana-ui/src/components/Input/storyUtils.tsx index 89357296e1d..2ca010b73bc 100644 --- a/packages/grafana-ui/src/components/Input/storyUtils.tsx +++ b/packages/grafana-ui/src/components/Input/storyUtils.tsx @@ -1,6 +1,8 @@ import React from 'react'; -import { Icon, toIconName } from '../Icon/Icon'; +import { toIconName } from '@grafana/data'; + +import { Icon } from '../Icon/Icon'; export function parseAccessory(prefix: string | undefined) { const icon = prefix && prefix.match(/icon-/g) && toIconName(prefix.replace(/icon-/g, '')); diff --git a/packages/grafana-ui/src/components/Select/Select.story.tsx b/packages/grafana-ui/src/components/Select/Select.story.tsx index cbd024f3756..d4fca54b60b 100644 --- a/packages/grafana-ui/src/components/Select/Select.story.tsx +++ b/packages/grafana-ui/src/components/Select/Select.story.tsx @@ -3,10 +3,10 @@ import { action } from '@storybook/addon-actions'; import { Meta, Story } from '@storybook/react'; import React, { useState } from 'react'; -import { SelectableValue } from '@grafana/data'; +import { SelectableValue, toIconName } from '@grafana/data'; import { Icon, Select, AsyncSelect, MultiSelect, AsyncMultiSelect } from '@grafana/ui'; -import { getAvailableIcons, toIconName } from '../../types'; +import { getAvailableIcons } from '../../types'; import { withCenteredStory, withHorizontallyCenteredStory } from '../../utils/storybook/withCenteredStory'; import mdx from './Select.mdx'; diff --git a/packages/grafana-ui/src/components/Select/SelectMenu.tsx b/packages/grafana-ui/src/components/Select/SelectMenu.tsx index 031812b53c5..dcef18531c3 100644 --- a/packages/grafana-ui/src/components/Select/SelectMenu.tsx +++ b/packages/grafana-ui/src/components/Select/SelectMenu.tsx @@ -1,11 +1,11 @@ import { cx } from '@emotion/css'; import React, { FC, RefCallback } from 'react'; -import { SelectableValue } from '@grafana/data'; +import { SelectableValue, toIconName } from '@grafana/data'; import { useTheme2 } from '../../themes/ThemeContext'; import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar'; -import { Icon, toIconName } from '../Icon/Icon'; +import { Icon } from '../Icon/Icon'; import { getSelectStyles } from './getSelectStyles'; diff --git a/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.tsx b/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.tsx index e79bd97af2f..c7739881f59 100644 --- a/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.tsx +++ b/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.tsx @@ -1,13 +1,11 @@ import { cx, css } from '@emotion/css'; -import { isString } from 'lodash'; import React, { forwardRef, ButtonHTMLAttributes } from 'react'; -import { GrafanaTheme2 } from '@grafana/data'; +import { GrafanaTheme2, IconName, isIconName } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { styleMixins, useStyles2 } from '../../themes'; import { getFocusStyles, getMouseFocusStyles } from '../../themes/mixins'; -import { IconName, toIconName } from '../../types/icon'; import { getPropertiesForVariant } from '../Button'; import { Icon } from '../Icon/Icon'; import { Tooltip } from '../Tooltip/Tooltip'; @@ -115,10 +113,8 @@ function renderIcon(icon: IconName | React.ReactNode) { return null; } - const iconName = isString(icon) && toIconName(icon); - - if (iconName) { - return ; + if (isIconName(icon)) { + return ; } return icon; diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index 3b2730c47f5..5e5f3db4781 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -6,7 +6,7 @@ import { AsyncSelect, Select } from './Forms/Legacy/Select/Select'; import { Switch } from './Forms/Legacy/Switch/Switch'; import { SecretFormField } from './SecretFormField/SecretFormField'; -export { Icon, toIconName } from './Icon/Icon'; +export { Icon } from './Icon/Icon'; export { IconButton, type IconButtonVariant } from './IconButton/IconButton'; export { ConfirmButton } from './ConfirmButton/ConfirmButton'; export { DeleteButton } from './ConfirmButton/DeleteButton'; diff --git a/packages/grafana-ui/src/types/icon.ts b/packages/grafana-ui/src/types/icon.ts index b51240b7f1b..ab6313993b8 100644 --- a/packages/grafana-ui/src/types/icon.ts +++ b/packages/grafana-ui/src/types/icon.ts @@ -1,207 +1,16 @@ -import { Field, FieldType } from '@grafana/data'; +import { availableIconsIndex, Field, FieldType, IconName } from '@grafana/data'; import { ComponentSize } from './size'; +// Exported from here for backwards compatibility +export type { IconName } from '@grafana/data'; +export { toIconName } from '@grafana/data'; + export type IconType = 'mono' | 'default' | 'solid'; export type IconSize = ComponentSize | 'xl' | 'xxl' | 'xxxl'; -const avaibleBrandIcons = [ - 'google' as const, - 'microsoft' as const, - 'github' as const, - 'gitlab' as const, - 'okta' as const, -]; - -const availableIcons = [ - 'anchor' as const, - 'angle-double-down' as const, - 'angle-double-right' as const, - 'angle-double-up' as const, - 'angle-down' as const, - 'angle-left' as const, - 'angle-right' as const, - 'angle-up' as const, - 'apps' as const, - 'arrow' as const, - 'arrow-down' as const, - 'arrow-from-right' as const, - 'arrow-left' as const, - 'arrow-random' as const, - 'arrow-right' as const, - 'arrow-up' as const, - 'arrows-h' as const, - 'arrows-v' as const, - 'backward' as const, - 'bars' as const, - 'bell' as const, - 'bell-slash' as const, - 'bolt' as const, - 'book' as const, - 'bookmark' as const, - 'book-open' as const, - 'brackets-curly' as const, - 'building' as const, - 'bug' as const, - 'building' as const, - 'calculator-alt' as const, - 'calendar-alt' as const, - 'camera' as const, - 'capture' as const, - 'channel-add' as const, - 'chart-line' as const, - 'check' as const, - 'check-circle' as const, - 'check-square' as const, - 'circle' as const, - 'clipboard-alt' as const, - 'clock-nine' as const, - 'cloud' as const, - 'cloud-download' as const, - 'cloud-upload' as const, - 'code-branch' as const, - 'cog' as const, - 'columns' as const, - 'comment-alt' as const, - 'comment-alt-message' as const, - 'comment-alt-share' as const, - 'comments-alt' as const, - 'compass' as const, - 'copy' as const, - 'credit-card' as const, - 'cube' as const, - 'dashboard' as const, - 'database' as const, - 'document-info' as const, - 'download-alt' as const, - 'draggabledots' as const, - 'edit' as const, - 'ellipsis-v' as const, - 'envelope' as const, - 'exchange-alt' as const, - 'exclamation-triangle' as const, - 'exclamation-circle' as const, - 'external-link-alt' as const, - 'eye' as const, - 'eye-slash' as const, - 'ellipsis-h' as const, - 'fa fa-spinner' as const, - 'favorite' as const, - 'file-alt' as const, - 'file-blank' as const, - 'file-copy-alt' as const, - 'filter' as const, - 'folder' as const, - 'font' as const, - 'fire' as const, - 'folder-open' as const, - 'folder-plus' as const, - 'folder-upload' as const, - 'forward' as const, - 'gf-bar-alignment-after' as const, - 'gf-bar-alignment-before' as const, - 'gf-bar-alignment-center' as const, - 'gf-glue' as const, - 'gf-grid' as const, - 'gf-interpolation-linear' as const, - 'gf-interpolation-smooth' as const, - 'gf-interpolation-step-after' as const, - 'gf-interpolation-step-before' as const, - 'gf-landscape' as const, - 'gf-layout-simple' as const, - 'gf-logs' as const, - 'gf-portrait' as const, - 'grafana' as const, - 'graph-bar' as const, - 'heart' as const, - 'heart-break' as const, - 'history' as const, - 'home' as const, - 'home-alt' as const, - 'horizontal-align-center' as const, - 'horizontal-align-left' as const, - 'horizontal-align-right' as const, - 'hourglass' as const, - 'import' as const, - 'info' as const, - 'info-circle' as const, - 'key-skeleton-alt' as const, - 'keyboard' as const, - 'layer-group' as const, - 'library-panel' as const, - 'line-alt' as const, - 'link' as const, - 'list-ui-alt' as const, - 'list-ul' as const, - 'lock' as const, - 'map-marker' as const, - 'message' as const, - 'minus' as const, - 'minus-circle' as const, - 'mobile-android' as const, - 'monitor' as const, - 'palette' as const, - 'panel-add' as const, - 'pause' as const, - 'pen' as const, - 'percentage' as const, - 'play' as const, - 'plug' as const, - 'plus' as const, - 'plus-circle' as const, - 'plus-square' as const, - 'power' as const, - 'presentation-play' as const, - 'process' as const, - 'question-circle' as const, - 'record-audio' as const, - 'repeat' as const, - 'rocket' as const, - 'ruler-combined' as const, - 'save' as const, - 'search' as const, - 'search-minus' as const, - 'search-plus' as const, - 'share-alt' as const, - 'shield' as const, - 'shield-exclamation' as const, - 'signal' as const, - 'signin' as const, - 'signout' as const, - 'sitemap' as const, - 'slack' as const, - 'sliders-v-alt' as const, - 'sort-amount-down' as const, - 'sort-amount-up' as const, - 'square-shape' as const, - 'star' as const, - 'step-backward' as const, - 'stopwatch-slash' as const, - 'sync' as const, - 'table' as const, - 'tag-alt' as const, - 'text-fields' as const, - 'times' as const, - 'toggle-on' as const, - 'trash-alt' as const, - 'unlock' as const, - 'upload' as const, - 'user' as const, - 'users-alt' as const, - 'vertical-align-bottom' as const, - 'vertical-align-center' as const, - 'vertical-align-top' as const, - 'wrap-text' as const, - 'rss' as const, - 'x' as const, -]; - // function remains for backwards compatibility -export const getAvailableIcons = () => availableIcons; - -type BrandIconNames = typeof avaibleBrandIcons; - -export type IconName = ReturnType[number] | BrandIconNames[number]; +export const getAvailableIcons = () => Object.keys(availableIconsIndex); /** Get the icon for a given field type */ export function getFieldTypeIcon(field?: Field): IconName { @@ -225,18 +34,3 @@ export function getFieldTypeIcon(field?: Field): IconName { } return 'question-circle'; } - -function isValidIconName(iconName: string): iconName is IconName { - const namedIcons: string[] = availableIcons; - const brandIcons: string[] = avaibleBrandIcons; - - return namedIcons.includes(iconName) || brandIcons.includes(iconName); -} - -export function toIconName(iconName: string): IconName | undefined { - if (isValidIconName(iconName)) { - return iconName; - } - - return undefined; -} diff --git a/public/app/angular/services/nav_model_srv.ts b/public/app/angular/services/nav_model_srv.ts index bf8790e1b3b..38051e4dcd7 100644 --- a/public/app/angular/services/nav_model_srv.ts +++ b/public/app/angular/services/nav_model_srv.ts @@ -65,7 +65,7 @@ export function getNotFoundNav(): NavModel { } export function getWarningNav(text: string, subTitle?: string): NavModel { - const node = { + const node: NavModelItem = { text, subTitle, icon: 'exclamation-triangle', diff --git a/public/app/core/components/AppChrome/NavLandingPage.tsx b/public/app/core/components/AppChrome/NavLandingPage.tsx index 97360816691..12c0c34ba65 100644 --- a/public/app/core/components/AppChrome/NavLandingPage.tsx +++ b/public/app/core/components/AppChrome/NavLandingPage.tsx @@ -2,7 +2,7 @@ import { css } from '@emotion/css'; import React from 'react'; import { GrafanaTheme2 } from '@grafana/data'; -import { toIconName, useStyles2 } from '@grafana/ui'; +import { useStyles2 } from '@grafana/ui'; import { Page } from 'app/core/components/Page/Page'; import { useNavModel } from 'app/core/hooks/useNavModel'; @@ -28,7 +28,7 @@ export function NavLandingPage({ navId }: Props) { @@ -46,7 +46,7 @@ export function NavLandingPage({ navId }: Props) { diff --git a/public/app/core/components/AppChrome/TopSearchBar.tsx b/public/app/core/components/AppChrome/TopSearchBar.tsx index e6e2910e3ef..b0741d83f2f 100644 --- a/public/app/core/components/AppChrome/TopSearchBar.tsx +++ b/public/app/core/components/AppChrome/TopSearchBar.tsx @@ -6,7 +6,7 @@ import { useLocation } from 'react-router-dom'; import { GrafanaTheme2, NavSection } from '@grafana/data'; import { locationService } from '@grafana/runtime'; -import { Dropdown, FilterInput, Icon, Tooltip, useStyles2, toIconName } from '@grafana/ui'; +import { Dropdown, FilterInput, Icon, Tooltip, useStyles2 } from '@grafana/ui'; import { contextSrv } from 'app/core/core'; import { useSearchQuery } from 'app/features/search/hooks/useSearchQuery'; import { StoreState } from 'app/types'; @@ -46,7 +46,6 @@ export function TopSearchBar() { const profileNode = configItems.find((item) => item.id === 'profile'); const signInNode = configItems.find((item) => item.id === 'signin'); - const signInIconName = signInNode?.icon && toIconName(signInNode.icon); return (
@@ -78,7 +77,7 @@ export function TopSearchBar() { {signInNode && ( - {signInIconName && } + {signInNode.icon && } )} diff --git a/public/app/core/components/Login/LoginServiceButtons.tsx b/public/app/core/components/Login/LoginServiceButtons.tsx index 4cdbf6307db..29b5392a337 100644 --- a/public/app/core/components/Login/LoginServiceButtons.tsx +++ b/public/app/core/components/Login/LoginServiceButtons.tsx @@ -3,7 +3,7 @@ import { pickBy } from 'lodash'; import React from 'react'; import { GrafanaTheme, GrafanaTheme2, DEFAULT_SAML_NAME } from '@grafana/data'; -import { Icon, IconName, LinkButton, toIconName, useStyles, useTheme2, VerticalGroup } from '@grafana/ui'; +import { Icon, IconName, LinkButton, useStyles, useTheme2, VerticalGroup } from '@grafana/ui'; import config from 'app/core/config'; export interface LoginService { @@ -63,13 +63,13 @@ const loginServices: () => LoginServices = () => { bgColor: '#2f2f2f', enabled: oauthEnabled && Boolean(config.oauth.okta), name: config.oauth?.okta?.name || 'Okta', - icon: (config.oauth?.okta?.icon && toIconName(config.oauth.okta.icon)) || 'okta', + icon: config.oauth?.okta?.icon ?? ('okta' as const), }, oauth: { bgColor: '#262628', enabled: oauthEnabled && Boolean(config.oauth.generic_oauth), name: config.oauth?.generic_oauth?.name || 'OAuth', - icon: (config.oauth?.generic_oauth?.icon && toIconName(config.oauth?.generic_oauth?.icon)) || 'signin', + icon: config.oauth?.generic_oauth?.icon ?? ('signin' as const), hrefName: 'generic_oauth', }, }; diff --git a/public/app/core/components/PageHeader/PageHeader.tsx b/public/app/core/components/PageHeader/PageHeader.tsx index 7a6c73fa5d0..e9d6d292c03 100644 --- a/public/app/core/components/PageHeader/PageHeader.tsx +++ b/public/app/core/components/PageHeader/PageHeader.tsx @@ -57,14 +57,13 @@ const Navigation = ({ children }: { children: NavModelItem[] }) => { {children} {children.map((child, index) => { - const icon = child.icon ? toIconName(child.icon) : undefined; return ( !child.hideFromTabs && ( diff --git a/public/app/core/reducers/navModel.ts b/public/app/core/reducers/navModel.ts index 4127ce94d3a..7aa5057c4d1 100644 --- a/public/app/core/reducers/navModel.ts +++ b/public/app/core/reducers/navModel.ts @@ -29,7 +29,7 @@ function buildWarningNav(text: string, subTitle?: string): NavModel { const node = { text, subTitle, - icon: 'exclamation-triangle', + icon: 'exclamation-triangle' as const, }; return { node: node, diff --git a/public/app/features/data-connections/__mocks__/store.navIndex.mock.ts b/public/app/features/data-connections/__mocks__/store.navIndex.mock.ts index a6093868d83..ca393c9f96e 100644 --- a/public/app/features/data-connections/__mocks__/store.navIndex.mock.ts +++ b/public/app/features/data-connections/__mocks__/store.navIndex.mock.ts @@ -1458,7 +1458,7 @@ export const navIndex: NavIndex = { }, { text: 'Configuration', - icon: 'fa fa-cog', + icon: 'cog', url: '/plugins/basic-app', }, ], diff --git a/public/app/features/datasources/__mocks__/store.navIndex.mock.ts b/public/app/features/datasources/__mocks__/store.navIndex.mock.ts index 7caaf5ed637..276be9dc342 100644 --- a/public/app/features/datasources/__mocks__/store.navIndex.mock.ts +++ b/public/app/features/datasources/__mocks__/store.navIndex.mock.ts @@ -1454,7 +1454,7 @@ export const navIndex: NavIndex = { }, { text: 'Configuration', - icon: 'fa fa-cog', + icon: 'cog', url: '/plugins/basic-app', }, ], diff --git a/public/app/features/datasources/pages/NewDataSourcePage.tsx b/public/app/features/datasources/pages/NewDataSourcePage.tsx index 8dd9b57cce6..d695309d66e 100644 --- a/public/app/features/datasources/pages/NewDataSourcePage.tsx +++ b/public/app/features/datasources/pages/NewDataSourcePage.tsx @@ -20,7 +20,7 @@ export function NewDataSourcePage() { export function getNavModel(): NavModel { const main = { - icon: 'database', + icon: 'database' as const, id: 'datasource-new', text: 'Add data source', href: DATASOURCES_ROUTES.New, diff --git a/public/app/features/folders/state/navModel.ts b/public/app/features/folders/state/navModel.ts index 887d6c6a17a..4bbcbe7ec6b 100644 --- a/public/app/features/folders/state/navModel.ts +++ b/public/app/features/folders/state/navModel.ts @@ -3,7 +3,7 @@ import { contextSrv } from 'app/core/services/context_srv'; import { AccessControlAction, FolderDTO } from 'app/types'; export function buildNavModel(folder: FolderDTO): NavModelItem { - const model = { + const model: NavModelItem = { icon: 'folder', id: 'manage-folder', subTitle: 'Manage folder dashboards and permissions', @@ -21,7 +21,7 @@ export function buildNavModel(folder: FolderDTO): NavModelItem { ], }; - model.children.push({ + model.children!.push({ active: false, icon: 'library-panel', id: `folder-library-panels-${folder.uid}`, @@ -30,7 +30,7 @@ export function buildNavModel(folder: FolderDTO): NavModelItem { }); if (contextSrv.hasPermission(AccessControlAction.AlertingRuleRead)) { - model.children.push({ + model.children!.push({ active: false, icon: 'bell', id: `folder-alerting-${folder.uid}`, @@ -40,7 +40,7 @@ export function buildNavModel(folder: FolderDTO): NavModelItem { } if (folder.canAdmin) { - model.children.push({ + model.children!.push({ active: false, icon: 'lock', id: `folder-permissions-${folder.uid}`, @@ -50,7 +50,7 @@ export function buildNavModel(folder: FolderDTO): NavModelItem { } if (folder.canSave) { - model.children.push({ + model.children!.push({ active: false, icon: 'cog', id: `folder-settings-${folder.uid}`, diff --git a/public/app/features/invites/SignupInvited.tsx b/public/app/features/invites/SignupInvited.tsx index d12da280e07..446d15a217a 100644 --- a/public/app/features/invites/SignupInvited.tsx +++ b/public/app/features/invites/SignupInvited.tsx @@ -17,7 +17,7 @@ interface FormModel { const navModel = { main: { - icon: 'grafana', + icon: 'grafana' as const, text: 'Invite', subTitle: 'Register your Grafana account', breadcrumbs: [{ title: 'Login', url: 'login' }], diff --git a/public/app/features/org/SelectOrgPage.tsx b/public/app/features/org/SelectOrgPage.tsx index 2d39f619074..42abfab245d 100644 --- a/public/app/features/org/SelectOrgPage.tsx +++ b/public/app/features/org/SelectOrgPage.tsx @@ -11,7 +11,7 @@ import { getUserOrganizations, setUserOrganization } from './state/actions'; const navModel = { main: { - icon: 'grafana', + icon: 'grafana' as const, subTitle: 'Preferences', text: 'Select active organization', }, diff --git a/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx b/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx index d80840b560d..0b87622968d 100644 --- a/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx +++ b/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx @@ -13,7 +13,6 @@ export type Props = DataSourcePluginOptionsEditorProps> = [ { value: AlertManagerImplementation.mimir, - icon: 'public/img/alerting/mimir_logo.svg', label: 'Mimir', description: `https://grafana.com/oss/mimir/. An open source, horizontally scalable, highly available, multi-tenant, long-term storage for Prometheus.`, }, diff --git a/public/test/mocks/common.ts b/public/test/mocks/common.ts index 9eee9d09d3e..5736eae061b 100644 --- a/public/test/mocks/common.ts +++ b/public/test/mocks/common.ts @@ -31,12 +31,11 @@ export function createNavModel(title: string, ...tabs: string[]): NavModel { breadcrumbs: [], }; - const children = []; + const children: NavModelItem[] = []; for (const tab of tabs) { children.push({ id: tab, - icon: 'icon', subTitle: 'subTitle', url: title, text: title,