From 32dde95a7ba1855f1cb5860ffc00af701810df77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Fri, 5 Feb 2021 14:22:22 +0100 Subject: [PATCH 001/157] e2e: extends selector factory to plugins (#30932) --- packages/grafana-e2e/src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grafana-e2e/src/index.ts b/packages/grafana-e2e/src/index.ts index 03143650308..87a0a6a8f25 100644 --- a/packages/grafana-e2e/src/index.ts +++ b/packages/grafana-e2e/src/index.ts @@ -6,7 +6,7 @@ import { e2eScenario, ScenarioArguments } from './support/scenario'; import { getScenarioContext, setScenarioContext } from './support/scenarioContext'; import { e2eFactory } from './support'; -import { selectors } from '@grafana/e2e-selectors'; +import { E2ESelectors, Selectors, selectors } from '@grafana/e2e-selectors'; import * as flows from './flows'; import * as typings from './typings'; @@ -22,6 +22,7 @@ const e2eObject = { flows, getScenarioContext, setScenarioContext, + getSelectors: (selectors: E2ESelectors) => e2eFactory({ selectors }), }; export const e2e: (() => Cypress.cy) & typeof e2eObject = Object.assign(() => cy, e2eObject); From 3cfa8dad487f257b0469304a5d45b836c146c3b2 Mon Sep 17 00:00:00 2001 From: Giordano Ricci Date: Fri, 5 Feb 2021 17:59:06 +0000 Subject: [PATCH 002/157] Docs: Add alias for what's new in 7.4 (#30945) --- docs/sources/whatsnew/whats-new-in-v7-4.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/sources/whatsnew/whats-new-in-v7-4.md b/docs/sources/whatsnew/whats-new-in-v7-4.md index eb58a13a274..cb564fc2456 100644 --- a/docs/sources/whatsnew/whats-new-in-v7-4.md +++ b/docs/sources/whatsnew/whats-new-in-v7-4.md @@ -3,6 +3,7 @@ title = "What's New in Grafana v7.4" description = "Feature and improvement highlights for Grafana v7.4" keywords = ["grafana", "new", "documentation", "7.4", "release notes"] weight = -31 +aliases = ["/docs/grafana/latest/guides/whats-new-in-v7-4/"] [_build] list = false +++ @@ -161,7 +162,7 @@ Google Cloud Monitoring data source ships with pre-configured dashboards for som {{< docs-imagebox img="/img/docs/google-cloud-monitoring/curated-dashboards-7-4.png" max-width= "650px" >}} -If you want to customize a dashboard, we recommend that you save it under a different name. Otherwise the dashboard will be overwritten when a new version of the dashboard is released. +If you want to customize a dashboard, we recommend that you save it under a different name. Otherwise the dashboard will be overwritten when a new version of the dashboard is released. For more information, refer to the [Google Cloud Monitoring docs]({{< relref "../datasources/google-cloud-monitoring/_index.md/#out-of-the-box-dashboards" >}}). From f081df0a4f57961e67b497d35559fd97c03a2200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 6 Feb 2021 18:01:22 +0100 Subject: [PATCH 003/157] Theme: Use higher order theme color variables rather then is light/dark logic (#30939) --- .../src/components/Chart/TooltipContainer.tsx | 30 +++--- .../ColorPicker/NamedColorsGroup.tsx | 11 +-- .../ColorPicker/SpectrumPalettePointer.tsx | 9 +- .../DataLinks/DataLinkSuggestions.tsx | 70 ++------------ .../FieldConfigItemHeaderTitle.tsx | 63 ------------- .../src/components/Icon/Icon.story.tsx | 10 +- .../src/components/Logs/LogLabelStats.tsx | 10 +- .../src/components/Logs/LogLabels.tsx | 3 +- .../src/components/Logs/LogRowContext.tsx | 44 ++------- .../src/components/Logs/LogRowMessage.tsx | 14 +-- .../components/Select/SelectOptionGroup.tsx | 11 +-- .../TimeRangePicker/TimeRangeOption.tsx | 12 +-- .../components/Typeahead/TypeaheadInfo.tsx | 14 +-- .../components/Typeahead/TypeaheadItem.tsx | 3 +- packages/grafana-ui/src/components/index.ts | 1 - .../storybook/CombinationsRowRenderer.tsx | 94 ------------------- public/sass/base/_type.scss | 1 + 17 files changed, 46 insertions(+), 354 deletions(-) delete mode 100644 packages/grafana-ui/src/components/FieldConfigs/FieldConfigItemHeaderTitle.tsx delete mode 100644 packages/grafana-ui/src/utils/storybook/CombinationsRowRenderer.tsx diff --git a/packages/grafana-ui/src/components/Chart/TooltipContainer.tsx b/packages/grafana-ui/src/components/Chart/TooltipContainer.tsx index 1e15fa4d872..3efedc5a846 100644 --- a/packages/grafana-ui/src/components/Chart/TooltipContainer.tsx +++ b/packages/grafana-ui/src/components/Chart/TooltipContainer.tsx @@ -1,6 +1,5 @@ import React, { useState, useLayoutEffect, useRef, HTMLAttributes } from 'react'; import { stylesFactory } from '../../themes/stylesFactory'; -import { selectThemeVariant } from '../../themes/selectThemeVariant'; import { css, cx } from 'emotion'; import { useTheme } from '../../themes/ThemeContext'; import useWindowSize from 'react-use/lib/useWindowSize'; @@ -12,21 +11,6 @@ interface TooltipContainerProps extends HTMLAttributes { children?: JSX.Element; } -const getTooltipContainerStyles = stylesFactory((theme: GrafanaTheme) => { - const bgColor = selectThemeVariant({ light: theme.palette.gray5, dark: theme.palette.dark1 }, theme.type); - return { - wrapper: css` - overflow: hidden; - background: ${bgColor}; - /* max-width is set up based on .grafana-tooltip class that's used in dashboard */ - max-width: 800px; - padding: ${theme.spacing.sm}; - border-radius: ${theme.border.radius.sm}; - z-index: ${theme.zIndex.tooltip}; - `, - }; -}); - export const TooltipContainer: React.FC = ({ position: { x: positionX, y: positionY }, offset: { x: offsetX, y: offsetY }, @@ -85,3 +69,17 @@ export const TooltipContainer: React.FC = ({ }; TooltipContainer.displayName = 'TooltipContainer'; + +const getTooltipContainerStyles = stylesFactory((theme: GrafanaTheme) => { + return { + wrapper: css` + overflow: hidden; + background: ${theme.colors.bg2}; + /* max-width is set up based on .grafana-tooltip class that's used in dashboard */ + max-width: 800px; + padding: ${theme.spacing.sm}; + border-radius: ${theme.border.radius.sm}; + z-index: ${theme.zIndex.tooltip}; + `, + }; +}); diff --git a/packages/grafana-ui/src/components/ColorPicker/NamedColorsGroup.tsx b/packages/grafana-ui/src/components/ColorPicker/NamedColorsGroup.tsx index fd84b14f30b..014d2b25747 100644 --- a/packages/grafana-ui/src/components/ColorPicker/NamedColorsGroup.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/NamedColorsGroup.tsx @@ -4,7 +4,6 @@ import { ColorDefinition } from '@grafana/data'; import { Color } from 'csstype'; import upperFirst from 'lodash/upperFirst'; import find from 'lodash/find'; -import { selectThemeVariant } from '../../themes/selectThemeVariant'; type ColorChangeHandler = (color: ColorDefinition) => void; @@ -31,21 +30,13 @@ export const ColorSwatch: FunctionComponent = ({ const isSmall = variant === ColorSwatchVariant.Small; const swatchSize = isSmall ? '16px' : '32px'; - const selectedSwatchBorder = selectThemeVariant( - { - light: theme.palette.white, - dark: theme.palette.black, - }, - theme.type - ); - const swatchStyles = { width: swatchSize, height: swatchSize, borderRadius: '50%', background: `${color}`, marginRight: isSmall ? '0px' : '8px', - boxShadow: isSelected ? `inset 0 0 0 2px ${color}, inset 0 0 0 4px ${selectedSwatchBorder}` : 'none', + boxShadow: isSelected ? `inset 0 0 0 2px ${color}, inset 0 0 0 4px ${theme.colors.bg1}` : 'none', }; return ( diff --git a/packages/grafana-ui/src/components/ColorPicker/SpectrumPalettePointer.tsx b/packages/grafana-ui/src/components/ColorPicker/SpectrumPalettePointer.tsx index 70250d873d5..99b76a69bd2 100644 --- a/packages/grafana-ui/src/components/ColorPicker/SpectrumPalettePointer.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/SpectrumPalettePointer.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { Themeable } from '../../types'; -import { selectThemeVariant } from '../../themes/selectThemeVariant'; export interface SpectrumPalettePointerProps extends Themeable { direction?: string; @@ -15,13 +14,7 @@ const SpectrumPalettePointer: React.FunctionComponent { - const wrapperBg = selectThemeVariant( - { - light: theme.palette.white, - dark: theme.palette.dark2, - }, - theme.type - ); - - const wrapperShadow = selectThemeVariant( - { - light: theme.palette.gray5, - dark: theme.palette.black, - }, - theme.type - ); - - const itemColor = selectThemeVariant( - { - light: theme.palette.black, - dark: theme.palette.white, - }, - theme.type - ); - - const itemDocsColor = selectThemeVariant( - { - light: theme.palette.dark3, - dark: theme.palette.gray2, - }, - theme.type - ); - - const itemBgHover = selectThemeVariant( - { - light: theme.palette.gray5, - dark: theme.palette.dark7, - }, - theme.type - ); - - const itemBgActive = selectThemeVariant( - { - light: theme.palette.gray6, - dark: theme.palette.dark9, - }, - theme.type - ); - - const separatorColor = selectThemeVariant( - { - light: tinycolor(wrapperBg.toString()).darken(10).toString(), - dark: tinycolor(wrapperBg.toString()).lighten(10).toString(), - }, - theme.type - ); + const wrapperBg = theme.colors.bg1; + const wrapperShadow = theme.colors.dropdownShadow; + const itemColor = theme.colors.text; + const itemBgHover = styleMixins.hoverColor(theme.colors.bg1, theme); + const itemBgActive = theme.colors.bg2; + const separatorColor = theme.colors.border2; return { list: css` @@ -107,10 +57,6 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => { font-family: ${theme.typography.fontFamily.monospace}; font-size: ${theme.typography.size.sm}; `, - itemDocs: css` - margin-top: ${theme.spacing.xs}; - color: ${itemDocsColor}; - `, }; }); diff --git a/packages/grafana-ui/src/components/FieldConfigs/FieldConfigItemHeaderTitle.tsx b/packages/grafana-ui/src/components/FieldConfigs/FieldConfigItemHeaderTitle.tsx deleted file mode 100644 index 6d038c5ad8e..00000000000 --- a/packages/grafana-ui/src/components/FieldConfigs/FieldConfigItemHeaderTitle.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import React from 'react'; -import { GrafanaTheme } from '@grafana/data'; -import { css } from 'emotion'; -import { selectThemeVariant, stylesFactory, useTheme } from '../../themes'; -import { Label } from '../Forms/Label'; -import { Icon } from '../Icon/Icon'; - -interface FieldConfigItemHeaderTitleProps { - title: string; - description?: string; - transparent?: boolean; - onRemove: () => void; -} - -export const FieldConfigItemHeaderTitle: React.FC = ({ - title, - description, - onRemove, - children, - transparent, -}) => { - const theme = useTheme(); - const styles = getFieldConfigItemHeaderTitleStyles(theme); - return ( -
-
- -
onRemove()} aria-label="FieldConfigItemHeaderTitle remove button"> - -
-
- {children} -
- ); -}; - -const getFieldConfigItemHeaderTitleStyles = stylesFactory((theme: GrafanaTheme) => { - const headerBg = selectThemeVariant( - { - light: theme.palette.white, - dark: theme.palette.dark1, - }, - theme.type - ); - - return { - headerWrapper: css` - background: ${headerBg}; - padding: ${theme.spacing.xs} 0; - `, - header: css` - display: flex; - justify-content: space-between; - padding: ${theme.spacing.xs} ${theme.spacing.xs} 0 ${theme.spacing.xs}; - `, - remove: css` - flex-grow: 0; - flex-shrink: 0; - cursor: pointer; - color: ${theme.palette.red88}; - `, - }; -}); diff --git a/packages/grafana-ui/src/components/Icon/Icon.story.tsx b/packages/grafana-ui/src/components/Icon/Icon.story.tsx index cc8b7c3369c..c9672473d9d 100644 --- a/packages/grafana-ui/src/components/Icon/Icon.story.tsx +++ b/packages/grafana-ui/src/components/Icon/Icon.story.tsx @@ -4,7 +4,7 @@ import { css } from 'emotion'; import { Input, Field, Icon } from '@grafana/ui'; import { getAvailableIcons, IconName } from '../../types'; import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; -import { useTheme, selectThemeVariant } from '../../themes'; +import { useTheme } from '../../themes'; import mdx from './Icon.mdx'; export default { @@ -23,13 +23,7 @@ export default { const IconWrapper = ({ name }: { name: IconName }) => { const theme = useTheme(); - const borderColor = selectThemeVariant( - { - light: theme.palette.gray5, - dark: theme.palette.dark6, - }, - theme.type - ); + const borderColor = theme.colors.border2; return (
{ - const borderColor = selectThemeVariant( - { - light: theme.palette.gray5, - dark: theme.palette.dark9, - }, - theme.type - ); return { logsStats: css` label: logs-stats; @@ -30,7 +22,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => { `, logsStatsHeader: css` label: logs-stats__header; - border-bottom: 1px solid ${borderColor}; + border-bottom: 1px solid ${theme.colors.border2}; display: flex; `, logsStatsTitle: css` diff --git a/packages/grafana-ui/src/components/Logs/LogLabels.tsx b/packages/grafana-ui/src/components/Logs/LogLabels.tsx index c9c17ae21d7..44b149a3e27 100644 --- a/packages/grafana-ui/src/components/Logs/LogLabels.tsx +++ b/packages/grafana-ui/src/components/Logs/LogLabels.tsx @@ -5,7 +5,6 @@ import { Labels } from '@grafana/data'; import { stylesFactory } from '../../themes'; import { Themeable } from '../../types/theme'; import { GrafanaTheme } from '@grafana/data'; -import { selectThemeVariant } from '../../themes/selectThemeVariant'; import { withTheme } from '../../themes/ThemeContext'; // Levels are already encoded in color, filename is a Loki-ism @@ -22,7 +21,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => { label: logs-label; display: flex; padding: 0 2px; - background-color: ${selectThemeVariant({ light: theme.palette.gray5, dark: theme.palette.dark6 }, theme.type)}; + background-color: ${theme.colors.bg2}; border-radius: ${theme.border.radius}; margin: 1px 4px 0 0; text-overflow: ellipsis; diff --git a/packages/grafana-ui/src/components/Logs/LogRowContext.tsx b/packages/grafana-ui/src/components/Logs/LogRowContext.tsx index 985ffd67939..e635f8e212c 100644 --- a/packages/grafana-ui/src/components/Logs/LogRowContext.tsx +++ b/packages/grafana-ui/src/components/Logs/LogRowContext.tsx @@ -5,7 +5,6 @@ import { css, cx } from 'emotion'; import { Alert } from '../Alert/Alert'; import { LogRowContextRows, LogRowContextQueryErrors, HasMoreContextRows } from './LogRowContextProvider'; import { GrafanaTheme } from '@grafana/data'; -import { selectThemeVariant } from '../../themes/selectThemeVariant'; import { DataQueryError } from '@grafana/data'; import { ThemeContext } from '../../themes/ThemeContext'; import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar'; @@ -22,48 +21,17 @@ interface LogRowContextProps { } const getLogRowContextStyles = (theme: GrafanaTheme) => { - const gradientTop = selectThemeVariant( - { - light: theme.palette.white, - dark: theme.palette.dark1, - }, - theme.type - ); - const gradientBottom = selectThemeVariant( - { - light: theme.palette.gray7, - dark: theme.palette.dark2, - }, - theme.type - ); - - const boxShadowColor = selectThemeVariant( - { - light: theme.palette.gray5, - dark: theme.palette.black, - }, - theme.type - ); - const borderColor = selectThemeVariant( - { - light: theme.palette.gray5, - dark: theme.palette.dark9, - }, - theme.type - ); - return { commonStyles: css` position: absolute; width: calc(100% + 20px); - left: -10px; + left: -13px; height: 250px; - z-index: 2; + z-index: ${theme.zIndex.dropdown}; overflow: hidden; - background: ${theme.colors.bodyBg}; - background: linear-gradient(180deg, ${gradientTop} 0%, ${gradientBottom} 104.25%); - box-shadow: 0px 2px 4px ${boxShadowColor}, 0px 0px 2px ${boxShadowColor}; - border: 1px solid ${borderColor}; + background: ${theme.colors.bg1}; + box-shadow: 0 0 10px ${theme.colors.dropdownShadow}; + border: 1px solid ${theme.colors.bg2}; border-radius: ${theme.border.radius.md}; `, header: css` @@ -71,7 +39,7 @@ const getLogRowContextStyles = (theme: GrafanaTheme) => { padding: 0 10px; display: flex; align-items: center; - background: ${borderColor}; + background: ${theme.colors.bg2}; `, logs: css` height: 220px; diff --git a/packages/grafana-ui/src/components/Logs/LogRowMessage.tsx b/packages/grafana-ui/src/components/Logs/LogRowMessage.tsx index 01ed886cf4a..5233d5949a1 100644 --- a/packages/grafana-ui/src/components/Logs/LogRowMessage.tsx +++ b/packages/grafana-ui/src/components/Logs/LogRowMessage.tsx @@ -7,7 +7,6 @@ import { LogRowModel, findHighlightChunksInText, GrafanaTheme } from '@grafana/d // @ts-ignore import Highlighter from 'react-highlight-words'; import { LogRowContextQueryErrors, HasMoreContextRows, LogRowContextRows } from './LogRowContextProvider'; -import { selectThemeVariant } from '../../index'; import { Themeable } from '../../types/theme'; import { withTheme } from '../../themes/index'; import { getLogRowStyles } from './getLogRowStyles'; @@ -34,13 +33,7 @@ interface Props extends Themeable { } const getStyles = stylesFactory((theme: GrafanaTheme) => { - const outlineColor = selectThemeVariant( - { - light: theme.palette.white, - dark: theme.palette.black, - }, - theme.type - ); + const outlineColor = tinycolor(theme.colors.dashboardBg).setAlpha(0.7).toRgbString(); return { positionRelative: css` @@ -50,10 +43,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => { rowWithContext: css` label: rowWithContext; z-index: 1; - outline: 9999px solid - ${tinycolor(outlineColor as tinycolor.ColorInput) - .setAlpha(0.7) - .toRgbString()}; + outline: 9999px solid ${outlineColor}; `, horizontalScroll: css` label: verticalScroll; diff --git a/packages/grafana-ui/src/components/Select/SelectOptionGroup.tsx b/packages/grafana-ui/src/components/Select/SelectOptionGroup.tsx index 2e86bd184cc..4afc7e42e1a 100644 --- a/packages/grafana-ui/src/components/Select/SelectOptionGroup.tsx +++ b/packages/grafana-ui/src/components/Select/SelectOptionGroup.tsx @@ -2,7 +2,7 @@ import React, { PureComponent } from 'react'; import { css } from 'emotion'; import { GrafanaTheme } from '@grafana/data'; import { GroupProps } from 'react-select'; -import { stylesFactory, withTheme, selectThemeVariant } from '../../themes'; +import { stylesFactory, withTheme } from '../../themes'; import { Themeable } from '../../types'; import { Icon } from '../Icon/Icon'; @@ -19,13 +19,6 @@ interface State { } const getSelectOptionGroupStyles = stylesFactory((theme: GrafanaTheme) => { - const optionBorder = selectThemeVariant( - { - light: theme.palette.gray4, - dark: theme.palette.dark9, - }, - theme.type - ); return { header: css` display: flex; @@ -35,7 +28,7 @@ const getSelectOptionGroupStyles = stylesFactory((theme: GrafanaTheme) => { cursor: pointer; padding: 7px 10px; width: 100%; - border-bottom: 1px solid ${optionBorder}; + border-bottom: 1px solid ${theme.colors.bg2}; &:hover { color: ${theme.colors.textStrong}; diff --git a/packages/grafana-ui/src/components/TimePicker/TimeRangePicker/TimeRangeOption.tsx b/packages/grafana-ui/src/components/TimePicker/TimeRangePicker/TimeRangeOption.tsx index 726d6dca7ad..b245174ca49 100644 --- a/packages/grafana-ui/src/components/TimePicker/TimeRangePicker/TimeRangeOption.tsx +++ b/packages/grafana-ui/src/components/TimePicker/TimeRangePicker/TimeRangeOption.tsx @@ -1,18 +1,10 @@ import React, { memo } from 'react'; import { css } from 'emotion'; import { GrafanaTheme, TimeOption } from '@grafana/data'; -import { useTheme, stylesFactory, selectThemeVariant } from '../../../themes'; +import { useTheme, stylesFactory, styleMixins } from '../../../themes'; import { Icon } from '../../Icon/Icon'; const getStyles = stylesFactory((theme: GrafanaTheme) => { - const background = selectThemeVariant( - { - light: theme.palette.gray7, - dark: theme.palette.dark3, - }, - theme.type - ); - return { container: css` display: flex; @@ -22,7 +14,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => { border-left: 2px solid rgba(255, 255, 255, 0); &:hover { - background: ${background}; + background: ${styleMixins.hoverColor(theme.colors.bg1, theme)}; border-image: linear-gradient(#f05a28 30%, #fbca0a 99%); border-image-slice: 1; border-style: solid; diff --git a/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.tsx b/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.tsx index aa1f523542a..c63e3ce6964 100644 --- a/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.tsx +++ b/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.tsx @@ -1,7 +1,7 @@ import React, { useContext } from 'react'; import { css, cx } from 'emotion'; -import { CompletionItem, selectThemeVariant, ThemeContext } from '../..'; +import { CompletionItem, ThemeContext } from '../..'; import { GrafanaTheme, renderMarkdown } from '@grafana/data'; const getStyles = (theme: GrafanaTheme, height: number, visible: boolean) => { @@ -11,19 +11,13 @@ const getStyles = (theme: GrafanaTheme, height: number, visible: boolean) => { z-index: 11; padding: ${theme.spacing.sm} ${theme.spacing.sm} ${theme.spacing.sm} ${theme.spacing.md}; border-radius: ${theme.border.radius.md}; - border: ${selectThemeVariant( - { light: `solid 1px ${theme.palette.gray5}`, dark: `solid 1px ${theme.palette.dark1}` }, - theme.type - )}; + border: ${theme.colors.border2}; overflow-y: scroll; overflow-x: hidden; outline: none; - background: ${selectThemeVariant({ light: theme.palette.white, dark: theme.palette.dark4 }, theme.type)}; + background: ${theme.colors.bg2}; color: ${theme.colors.text}; - box-shadow: ${selectThemeVariant( - { light: `0 5px 10px 0 ${theme.palette.gray5}`, dark: `0 5px 10px 0 ${theme.palette.black}` }, - theme.type - )}; + box-shadow: 0 0 20px ${theme.colors.dropdownShadow}; visibility: ${visible === true ? 'visible' : 'hidden'}; width: 250px; height: ${height + parseInt(theme.spacing.xxs, 10)}px; diff --git a/packages/grafana-ui/src/components/Typeahead/TypeaheadItem.tsx b/packages/grafana-ui/src/components/Typeahead/TypeaheadItem.tsx index 3afec001c76..e4b20b0ca33 100644 --- a/packages/grafana-ui/src/components/Typeahead/TypeaheadItem.tsx +++ b/packages/grafana-ui/src/components/Typeahead/TypeaheadItem.tsx @@ -4,7 +4,6 @@ import React, { useContext } from 'react'; import Highlighter from 'react-highlight-words'; import { css, cx } from 'emotion'; import { GrafanaTheme } from '@grafana/data'; -import { selectThemeVariant } from '../../themes/selectThemeVariant'; import { CompletionItem, CompletionItemKind } from '../../types/completion'; import { ThemeContext } from '../../themes/ThemeContext'; @@ -38,7 +37,7 @@ const getStyles = (theme: GrafanaTheme) => ({ typeaheadItemSelected: css` label: type-ahead-item-selected; - background-color: ${selectThemeVariant({ light: theme.palette.gray6, dark: theme.palette.dark9 }, theme.type)}; + background-color: ${theme.colors.bg2}; `, typeaheadItemMatch: css` diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index 126587861b6..f6847e493a3 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -129,7 +129,6 @@ export { StringArrayEditor } from './OptionsUI/strings'; export { NumberValueEditor } from './OptionsUI/number'; export { SliderValueEditor } from './OptionsUI/slider'; export { SelectValueEditor } from './OptionsUI/select'; -export { FieldConfigItemHeaderTitle } from './FieldConfigs/FieldConfigItemHeaderTitle'; // Next-gen forms export { Form } from './Forms/Form'; diff --git a/packages/grafana-ui/src/utils/storybook/CombinationsRowRenderer.tsx b/packages/grafana-ui/src/utils/storybook/CombinationsRowRenderer.tsx deleted file mode 100644 index 00d77c4d2e4..00000000000 --- a/packages/grafana-ui/src/utils/storybook/CombinationsRowRenderer.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import React from 'react'; -import { css } from 'emotion'; -import { withTheme } from '../../themes'; -import { Themeable } from '../../types'; -import { selectThemeVariant } from '../../themes/selectThemeVariant'; -import prettyFormat from 'pretty-format'; - -const detailsRenderer: (combinationProps: any) => JSX.Element = (props) => { - const listStyle = css` - padding: 0; - margin: 0; - list-style: none; - `; - - return ( -
    -
  • - {Object.keys(props).map((key, i) => { - return ( -
  • - {key}: {props[key]} -
  • - ); - })} - -
- ); -}; - -interface CombinationsRowRendererProps extends Themeable { - Component: React.ComponentType; - props: any; - options: any; -} - -const CombinationsRowRenderer: React.FunctionComponent = ({ - Component, - props, - theme, -}) => { - const el = React.createElement(Component, props); - - const borderColor = selectThemeVariant( - { - dark: theme.palette.dark8, - light: theme.palette.gray5, - }, - theme.type - ); - - const rowStyle = css` - display: flex; - width: 100%; - flex-direction: row; - border: 1px solid ${borderColor}; - border-bottom: none; - - &:last-child { - border-bottom: 1px solid ${borderColor}; - } - `; - const cellStyle = css` - padding: 10px; - `; - const previewCellStyle = css` - display: flex; - align-items: center; - justify-content: center; - width: 200px; - flex-shrink: 1; - border-right: 1px solid ${borderColor}; - ${cellStyle}; - `; - const variantsCellStyle = css` - width: 200px; - border-right: 1px solid ${borderColor}; - ${cellStyle}; - `; - - return ( -
-
{el}
-
{detailsRenderer(props)}
-
- {prettyFormat(el, { - plugins: [prettyFormat.plugins.ReactElement], - printFunctionName: true, - })} -
-
- ); -}; - -export const ThemeableCombinationsRowRenderer = withTheme(CombinationsRowRenderer); diff --git a/public/sass/base/_type.scss b/public/sass/base/_type.scss index 0407c059215..3ecb80d49ab 100644 --- a/public/sass/base/_type.scss +++ b/public/sass/base/_type.scss @@ -24,6 +24,7 @@ small { font-size: $font-size-sm; } +b, strong { font-weight: $font-weight-semi-bold; } From 8f691115bc2be265932053686eacd5fec5cf21b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 6 Feb 2021 18:03:35 +0100 Subject: [PATCH 004/157] Table: Updates devenv test dashboard after change to TestData Randrom Table response (#30927) --- .../panel-table/table_tests_new.json | 73 ++++++++++++++----- 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/devenv/dev-dashboards/panel-table/table_tests_new.json b/devenv/dev-dashboards/panel-table/table_tests_new.json index 09e6da02526..31e7d074e25 100644 --- a/devenv/dev-dashboards/panel-table/table_tests_new.json +++ b/devenv/dev-dashboards/panel-table/table_tests_new.json @@ -33,9 +33,13 @@ "datasource": "gdev-testdata", "fieldConfig": { "defaults": { + "color": { + "mode": "thresholds" + }, "custom": { "align": "center", - "displayMode": "color-background" + "displayMode": "color-background", + "filterable": false }, "mappings": [], "thresholds": { @@ -128,7 +132,7 @@ } ] }, - "pluginVersion": "7.1.0-pre", + "pluginVersion": "7.5.0-pre", "targets": [ { "refId": "A", @@ -144,7 +148,11 @@ { "id": "reduce", "options": { - "reducers": ["max", "mean", "last"] + "reducers": [ + "max", + "mean", + "last" + ] } } ], @@ -154,8 +162,12 @@ "datasource": "gdev-testdata", "fieldConfig": { "defaults": { + "color": { + "mode": "thresholds" + }, "custom": { - "align": null + "align": null, + "filterable": false }, "mappings": [], "thresholds": { @@ -176,7 +188,7 @@ { "matcher": { "id": "byName", - "options": "Value" + "options": "A" }, "properties": [ { @@ -251,7 +263,7 @@ } ] }, - "pluginVersion": "7.1.0-pre", + "pluginVersion": "7.5.0-pre", "targets": [ { "refId": "A", @@ -287,8 +299,12 @@ "description": "", "fieldConfig": { "defaults": { + "color": { + "mode": "thresholds" + }, "custom": { - "align": null + "align": null, + "filterable": false }, "mappings": [], "thresholds": { @@ -309,7 +325,7 @@ { "matcher": { "id": "byName", - "options": "Value" + "options": "A" }, "properties": [ { @@ -335,7 +351,7 @@ "showHeader": true, "sortBy": [] }, - "pluginVersion": "7.1.0-pre", + "pluginVersion": "7.5.0-pre", "targets": [ { "refId": "A", @@ -387,9 +403,13 @@ "datasource": "gdev-testdata", "fieldConfig": { "defaults": { + "color": { + "mode": "thresholds" + }, "custom": { "align": "center", - "displayMode": "color-text" + "displayMode": "color-text", + "filterable": false }, "decimals": 2, "mappings": [], @@ -459,7 +479,7 @@ "options": { "showHeader": true }, - "pluginVersion": "7.1.0-pre", + "pluginVersion": "7.5.0-pre", "targets": [ { "alias": "S1", @@ -501,9 +521,13 @@ "datasource": "gdev-testdata", "fieldConfig": { "defaults": { + "color": { + "mode": "thresholds" + }, "custom": { "align": "center", - "displayMode": "auto" + "displayMode": "auto", + "filterable": false }, "mappings": [], "thresholds": { @@ -547,7 +571,7 @@ } ] }, - "pluginVersion": "7.1.0-pre", + "pluginVersion": "7.5.0-pre", "targets": [ { "refId": "A", @@ -582,9 +606,12 @@ "type": "table" } ], - "schemaVersion": 25, + "schemaVersion": 27, "style": "dark", - "tags": ["gdev", "panel-tests"], + "tags": [ + "gdev", + "panel-tests" + ], "templating": { "list": [] }, @@ -593,10 +620,20 @@ "to": "now" }, "timepicker": { - "refresh_intervals": ["10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"] + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] }, "timezone": "", "title": "Panel Tests - React Table", "uid": "U_bZIMRMk", - "version": 17 -} + "version": 1 +} \ No newline at end of file From d824dc8e1c0e6826f0c049ada8ba387af96591e4 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Mon, 8 Feb 2021 07:50:51 +0100 Subject: [PATCH 005/157] assign changes in cloud datasources to the new cloud datasources team (#30645) --- .github/CODEOWNERS | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d9d5447a58d..6360d22fa8c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -22,6 +22,12 @@ go.mod @grafana/backend-platform go.sum @grafana/backend-platform +#Cloud Datasources backend code +/pkg/tsdb/cloudwatch @grafana/cloud-datasources +/pkg/tsdb/azuremonitor @grafana/cloud-datasources +/pkg/tsdb/cloudmonitoring @grafana/cloud-datasources + + # Backend code docs /contribute/style-guides/backend.md @grafana/backend-platform @@ -48,9 +54,9 @@ lerna.json @grafana/grafana-frontend-platform /packages/jaeger-ui-components/ @grafana/observability-squad # Core datasources -/public/app/plugins/datasource/cloudwatch @grafana/backend-platform @grafana/observability-squad +/public/app/plugins/datasource/cloudwatch @grafana/cloud-datasources @grafana/observability-squad /public/app/plugins/datasource/elasticsearch @grafana/observability-squad -/public/app/plugins/datasource/grafana-azure-monitor-datasource @grafana/backend-platform +/public/app/plugins/datasource/grafana-azure-monitor-datasource @grafana/cloud-datasources /public/app/plugins/datasource/graphite @grafana/observability-squad /public/app/plugins/datasource/influxdb @grafana/observability-squad /public/app/plugins/datasource/jaeger @grafana/observability-squad @@ -60,7 +66,7 @@ lerna.json @grafana/grafana-frontend-platform /public/app/plugins/datasource/opentsdb @grafana/backend-platform /public/app/plugins/datasource/postgres @grafana/backend-platform /public/app/plugins/datasource/prometheus @grafana/observability-squad -/public/app/plugins/datasource/cloud-monitoring @grafana/backend-platform +/public/app/plugins/datasource/cloud-monitoring @grafana/cloud-datasources /public/app/plugins/datasource/zipkin @grafana/observability-squad # Cloud middleware From ae64dcf0638e1b860dd3e56cdd97abb7c90833c0 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Mon, 8 Feb 2021 07:51:31 +0100 Subject: [PATCH 006/157] make sure service and slo display name is passed to segment comp (#30900) --- .../cloud-monitoring/components/SLOQueryEditor.tsx | 14 +++++++++----- .../datasource/cloud-monitoring/datasource.ts | 4 ++-- .../plugins/datasource/cloud-monitoring/types.ts | 2 ++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/public/app/plugins/datasource/cloud-monitoring/components/SLOQueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/SLOQueryEditor.tsx index e567da2abd0..d4238b52860 100644 --- a/public/app/plugins/datasource/cloud-monitoring/components/SLOQueryEditor.tsx +++ b/public/app/plugins/datasource/cloud-monitoring/components/SLOQueryEditor.tsx @@ -21,7 +21,9 @@ export const defaultQuery: (dataSource: CloudMonitoringDatasource) => SLOQuery = aliasBy: '', selectorName: 'select_slo_health', serviceId: '', + serviceName: '', sloId: '', + sloName: '', }); export function SLOQueryEditor({ @@ -42,7 +44,7 @@ export function SLOQueryEditor({ datasource.getSLOServices(query.projectName).then((services) => [ @@ -53,14 +55,16 @@ export function SLOQueryEditor({ ...services, ]) } - onChange={({ value: serviceId = '' }) => onChange({ ...query, serviceId, sloId: '' })} + onChange={({ value: serviceId = '', label: serviceName = '' }) => + onChange({ ...query, serviceId, serviceName, sloId: '' }) + } /> datasource.getServiceLevelObjectives(query.projectName, query.serviceId).then((sloIds) => [ @@ -71,10 +75,10 @@ export function SLOQueryEditor({ ...sloIds, ]) } - onChange={async ({ value: sloId = '' }) => { + onChange={async ({ value: sloId = '', label: sloName = '' }) => { const slos = await datasource.getServiceLevelObjectives(query.projectName, query.serviceId); const slo = slos.find(({ value }) => value === datasource.templateSrv.replace(sloId)); - onChange({ ...query, sloId, goal: slo?.goal }); + onChange({ ...query, sloId, sloName, goal: slo?.goal }); }} /> diff --git a/public/app/plugins/datasource/cloud-monitoring/datasource.ts b/public/app/plugins/datasource/cloud-monitoring/datasource.ts index 63ef0db86c7..41bc91442ff 100644 --- a/public/app/plugins/datasource/cloud-monitoring/datasource.ts +++ b/public/app/plugins/datasource/cloud-monitoring/datasource.ts @@ -257,9 +257,9 @@ export default class CloudMonitoringDatasource extends DataSourceWithBackend< async getSLOServices(projectName: string): Promise>> { return this.api.get(`${this.templateSrv.replace(projectName)}/services?pageSize=1000`, { - responseMap: ({ name }: { name: string }) => ({ + responseMap: ({ name, displayName }: { name: string; displayName: string }) => ({ value: name.match(/([^\/]*)\/*$/)![1], - label: name.match(/([^\/]*)\/*$/)![1], + label: displayName || name.match(/([^\/]*)\/*$/)![1], }), }); } diff --git a/public/app/plugins/datasource/cloud-monitoring/types.ts b/public/app/plugins/datasource/cloud-monitoring/types.ts index fb934837c0d..613ae864be8 100644 --- a/public/app/plugins/datasource/cloud-monitoring/types.ts +++ b/public/app/plugins/datasource/cloud-monitoring/types.ts @@ -92,7 +92,9 @@ export interface SLOQuery { aliasBy?: string; selectorName: string; serviceId: string; + serviceName: string; sloId: string; + sloName: string; goal?: number; } From 50da456bd0cbf247afac66c343eac5fb3d0a06ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 8 Feb 2021 10:56:04 +0100 Subject: [PATCH 007/157] Alerts: Dedupe alerts so that we do not fill the screen with the same alert messsage (#30935) --- .../app/core/reducers/appNotification.test.ts | 42 +++++++++++++++++++ public/app/core/reducers/appNotification.ts | 21 ++++++++-- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/public/app/core/reducers/appNotification.test.ts b/public/app/core/reducers/appNotification.test.ts index c868e3910ed..cc072562838 100644 --- a/public/app/core/reducers/appNotification.test.ts +++ b/public/app/core/reducers/appNotification.test.ts @@ -116,4 +116,46 @@ describe('notify', () => { expect(result).toEqual(expectedResult); }); + + it('Dedupe identical alerts', () => { + const initialState = { + appNotifications: [ + { + id: 'id1', + severity: AppNotificationSeverity.Success, + icon: 'success', + title: 'test', + text: 'test alert', + timeout: AppNotificationTimeout.Success, + }, + ], + }; + + const result = appNotificationsReducer( + initialState, + notifyApp({ + id: 'id2', + severity: AppNotificationSeverity.Success, + icon: 'success', + title: 'test', + text: 'test alert', + timeout: AppNotificationTimeout.Success, + }) + ); + + const expectedResult = { + appNotifications: [ + { + id: 'id1', + severity: AppNotificationSeverity.Success, + icon: 'success', + title: 'test', + text: 'test alert', + timeout: AppNotificationTimeout.Success, + }, + ], + }; + + expect(result).toEqual(expectedResult); + }); }); diff --git a/public/app/core/reducers/appNotification.ts b/public/app/core/reducers/appNotification.ts index 6c77b8d4a38..a61782ee730 100644 --- a/public/app/core/reducers/appNotification.ts +++ b/public/app/core/reducers/appNotification.ts @@ -15,10 +15,23 @@ const appNotificationsSlice = createSlice({ name: 'appNotifications', initialState, reducers: { - notifyApp: (state, action: PayloadAction): AppNotificationsState => ({ - ...state, - appNotifications: state.appNotifications.concat([action.payload]), - }), + notifyApp: (state, action: PayloadAction) => { + const newAlert = action.payload; + + for (const existingAlert of state.appNotifications) { + if ( + newAlert.icon === existingAlert.icon && + newAlert.severity === existingAlert.severity && + newAlert.text === existingAlert.text && + newAlert.title === existingAlert.title && + newAlert.component === existingAlert.component + ) { + return; + } + } + + state.appNotifications.push(newAlert); + }, clearAppNotification: (state, action: PayloadAction): AppNotificationsState => ({ ...state, appNotifications: state.appNotifications.filter((appNotification) => appNotification.id !== action.payload), From 0a7c6c689fe3534685a807196e0cfd1c0a8eb89c Mon Sep 17 00:00:00 2001 From: Giordano Ricci Date: Mon, 8 Feb 2021 11:10:52 +0000 Subject: [PATCH 008/157] Elasticsearch: Show Size setting for raw_data metric (#30980) --- .../SettingsEditor/index.test.tsx | 80 +++++++++++++++++++ .../SettingsEditor/index.tsx | 3 + .../MetricAggregationsEditor/utils.ts | 2 +- 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.test.tsx diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.test.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.test.tsx new file mode 100644 index 00000000000..c9018436cf0 --- /dev/null +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.test.tsx @@ -0,0 +1,80 @@ +import React from 'react'; +import { fireEvent, render, screen } from '@testing-library/react'; +import { SettingsEditor } from '.'; +import { ElasticsearchProvider } from '../../ElasticsearchQueryContext'; +import { ElasticDatasource } from 'app/plugins/datasource/elasticsearch/datasource'; +import { ElasticsearchQuery } from 'app/plugins/datasource/elasticsearch/types'; + +describe('Settings Editor', () => { + describe('Raw Data', () => { + it('Should correctly render the settings editor and trigger correct state changes', () => { + const metricId = '1'; + const initialSize = '500'; + const query: ElasticsearchQuery = { + refId: 'A', + metrics: [ + { + id: metricId, + type: 'raw_data', + settings: { + size: initialSize, + }, + }, + ], + }; + + const onChange = jest.fn(); + + const { rerender } = render( + {}} + > + + + ); + + let settingsButtonEl = screen.getByRole('button', { + name: /Size: \d+$/i, + }); + + // The metric row should have a settings button + expect(settingsButtonEl).toBeInTheDocument(); + expect(settingsButtonEl.textContent).toBe(`Size: ${initialSize}`); + + // Open the settings editor + fireEvent.click(settingsButtonEl); + + // The settings editor should have a Size input + const sizeInputEl = screen.getByLabelText('Size'); + expect(sizeInputEl).toBeInTheDocument(); + + // We change value and trigger a blur event to trigger an update + const newSizeValue = '23'; + fireEvent.change(sizeInputEl, { target: { value: newSizeValue } }); + fireEvent.blur(sizeInputEl); + + // the onChange handler should have been called correctly, and the resulting + // query state should match what expected + expect(onChange).toHaveBeenCalledTimes(1); + rerender( + {}} + > + + + ); + + settingsButtonEl = screen.getByRole('button', { + name: /Size: \d+$/i, + }); + expect(settingsButtonEl).toBeInTheDocument(); + expect(settingsButtonEl.textContent).toBe(`Size: ${newSizeValue}`); + }); + }); +}); diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.tsx index 67923530eaa..0c20b134278 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.tsx +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.tsx @@ -16,6 +16,7 @@ import { useDescription } from './useDescription'; import { MovingAverageSettingsEditor } from './MovingAverageSettingsEditor'; import { uniqueId } from 'lodash'; import { metricAggregationConfig } from '../utils'; +import { useQuery } from '../../ElasticsearchQueryContext'; // TODO: Move this somewhere and share it with BucketsAggregation Editor const inlineFieldProps: Partial> = { @@ -30,6 +31,7 @@ interface Props { export const SettingsEditor: FunctionComponent = ({ metric, previousMetrics }) => { const dispatch = useDispatch(); const description = useDescription(metric); + const query = useQuery(); return (