IconName: Move to grafana/data and use type on NavModelItem (#55013)

* IconName: Allow strings

* Moving to grafana/data and adding type to NavModelItem

* Removed any type

* ts fix
This commit is contained in:
Torkel Ödegaard 2022-09-12 20:09:33 +02:00 committed by GitHub
parent 64869e3d90
commit d59bb1e4c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 262 additions and 261 deletions

View File

@ -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<Record<OAuth, { name: string; icon?: string }>>;
export type OAuthSettings = Partial<Record<OAuth, { name: string; icon?: IconName }>>;
/** Current user info included in bootData
*

View File

@ -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;
}

View File

@ -50,3 +50,4 @@ export type { FeatureToggles } from './featureToggles.gen';
export * from './alerts';
export * from './slider';
export * from './accesscontrol';
export * from './icon';

View File

@ -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;

View File

@ -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<T extends PluginMeta> {
export interface PluginConfigPage<T extends PluginMeta> {
title: string; // Display
icon?: string;
icon?: IconName;
id: string; // Unique, in URL
body: ComponentType<PluginConfigPageProps<T>>;

View File

@ -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<T>({
{options.map((opt, i) => {
const isItemDisabled = disabledOptions && opt.value && disabledOptions.includes(opt.value);
const icon = opt.icon ? toIconName(opt.icon) : undefined;
return (
<RadioButton
size={size}

View File

@ -2,10 +2,11 @@ import { css } from '@emotion/css';
import { ComponentMeta } from '@storybook/react';
import React, { ChangeEvent, useState } from 'react';
import { toIconName, IconName } from '@grafana/data';
import { Input, Field, Icon } from '@grafana/ui';
import { useTheme2 } from '../../themes';
import { getAvailableIcons, IconName } from '../../types';
import { getAvailableIcons } from '../../types';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import mdx from './Icon.mdx';
@ -90,7 +91,7 @@ export const IconsOverview = () => {
{icons
.filter((val) => val.includes(filter))
.map((i) => {
return <IconWrapper name={i} key={i} />;
return <IconWrapper name={toIconName(i)!} key={i} />;
})}
</div>
</div>

View File

@ -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<HTMLDivElement, IconProps>(
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;

View File

@ -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, ''));

View File

@ -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';

View File

@ -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';

View File

@ -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 <Icon name={iconName} size="lg" />;
if (isIconName(icon)) {
return <Icon name={icon} size="lg" />;
}
return icon;

View File

@ -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';

View File

@ -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<typeof getAvailableIcons>[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;
}

View File

@ -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',

View File

@ -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) {
<NavLandingPageCard
key={child.id}
description={child.description}
icon={child.icon ? toIconName(child.icon) : undefined}
icon={child.icon}
text={child.text}
url={child.url ?? ''}
/>
@ -46,7 +46,7 @@ export function NavLandingPage({ navId }: Props) {
<NavLandingPageCard
key={child.id}
description={child.description}
icon={child.icon ? toIconName(child.icon) : undefined}
icon={child.icon}
text={child.text}
url={child.url ?? ''}
/>

View File

@ -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 (
<div className={styles.container}>
@ -78,7 +77,7 @@ export function TopSearchBar() {
{signInNode && (
<Tooltip placement="bottom" content="Sign in">
<a className={styles.actionItem} href={signInNode.url} target={signInNode.target}>
{signInIconName && <Icon name={signInIconName} size="lg" />}
{signInNode.icon && <Icon name={signInNode.icon} size="lg" />}
</a>
</Tooltip>
)}

View File

@ -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',
},
};

View File

@ -57,14 +57,13 @@ const Navigation = ({ children }: { children: NavModelItem[] }) => {
<SelectNav customCss="page-header__select-nav">{children}</SelectNav>
<TabsBar className="page-header__tabs" hideBorder={true}>
{children.map((child, index) => {
const icon = child.icon ? toIconName(child.icon) : undefined;
return (
!child.hideFromTabs && (
<Tab
label={child.text}
active={child.active}
key={`${child.url}-${index}`}
icon={icon}
icon={child.icon}
href={child.url}
suffix={child.tabSuffix}
/>

View File

@ -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,

View File

@ -1458,7 +1458,7 @@ export const navIndex: NavIndex = {
},
{
text: 'Configuration',
icon: 'fa fa-cog',
icon: 'cog',
url: '/plugins/basic-app',
},
],

View File

@ -1454,7 +1454,7 @@ export const navIndex: NavIndex = {
},
{
text: 'Configuration',
icon: 'fa fa-cog',
icon: 'cog',
url: '/plugins/basic-app',
},
],

View File

@ -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,

View File

@ -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}`,

View File

@ -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' }],

View File

@ -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',
},

View File

@ -13,7 +13,6 @@ export type Props = DataSourcePluginOptionsEditorProps<AlertManagerDataSourceJso
const IMPL_OPTIONS: Array<SelectableValue<AlertManagerImplementation>> = [
{
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.`,
},

View File

@ -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,