[Infra UI] Fix theme passed in to charts (#162114)

closes [#110217](https://github.com/elastic/kibana/issues/110217)
## Summary

This PR addresses an issue with how the infra sets the theme in charts.
It replaces the previous implementation with the use of
`useChartsBaseTheme` and `useChartsTheme` provided by the charts
service, ensuring consistent behavior for both light and dark modes.
From a UI perspective, this change doesn't introduce any alterations,
but it solves the problem related to dark mode.

### Screenshots

#### Node Details
<img width="899" alt="image"
src="7ec8b9e9-c440-44d1-86ac-45dbab76a8a9">

<img width="899" alt="image"
src="c6aac4a6-8982-47cc-b08e-ee5d8af0391f">


#### Infra
##### Timeline
<img width="720" alt="image"
src="cd4a1a3c-b5a4-47d5-bbde-5bf54dfac262">

<img width="720" alt="image"
src="839ccaf0-02a5-401e-957a-137d0ef25605">


##### Metrics
<img width="541" alt="image"
src="69138a89-21ff-4f17-bcbd-64ac609dd9e7">

<img width="541" alt="image"
src="63b02a7a-397e-451e-b4d7-7b37fdc4f6a9">


##### Processes
<img width="541" alt="image"
src="01e7d050-0103-4de6-8215-e93b9f80751b">

<img width="541" alt="image"
src="bd1ce95a-1944-411f-abc4-8f2a998f7643">


### Metrics Explorer
<img width="720" alt="image"
src="60d2857a-3b97-4fd6-8cc7-8b7ab757b3d5">

<img width="720" alt="image"
src="98bba0ea-27db-48a2-ae20-ff4162212c6e">


### Alert
#### Inventory rule
<img width="450" alt="image"
src="8b787e53-cb47-4254-ab69-69ab22ff0388">

<img width="450" alt="image"
src="a952bf6b-e22f-4753-8db6-f2deb213b22a">


#### Metric Threshold rule
<img width="450" alt="image"
src="db3d1448-5faa-4e20-bda8-7351d9b52144">

<img width="450" alt="image"
src="a11bc2de-f042-4d4f-9adc-d376205bc23f">


#### Logs rule
<img width="450" alt="image"
src="b703e972-2d47-485e-a2f5-4cfca0c982cd">

<img width="450" alt="image"
src="a98d3827-d930-4ef2-90f9-f336583f15da">




### How to tests
- Set up a local Kibana instance.
- Navigate to the pages mentioned above.
  - Change the user settings to both dark and light mode.
- In light mode, ensure that there are no differences in the charts when
compared to the edge cluster.
- In dark mode, confirm that the issue described in the ticket is
resolved (no horizontal line in white).

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Carlos Crespo 2023-07-19 19:09:05 +02:00 committed by GitHub
parent 2152e3949c
commit c2249aa0b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 94 additions and 74 deletions

View file

@ -10,8 +10,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { first, last } from 'lodash';
import moment from 'moment';
import React, { useCallback, useMemo } from 'react';
import { getChartTheme } from '../../../utils/get_chart_theme';
import { useIsDarkMode } from '../../../hooks/use_is_dark_mode';
import { useTimelineChartTheme } from '../../../utils/use_timeline_chart_theme';
import { InventoryMetricConditions } from '../../../../common/alerting/metrics';
import { Color } from '../../../../common/color_palette';
import { MetricsExplorerAggregation, MetricsExplorerRow } from '../../../../common/http_api';
@ -45,6 +44,7 @@ export const ExpressionChart: React.FC<Props> = ({
nodeType,
sourceId,
}) => {
const chartTheme = useTimelineChartTheme();
const timerange = useMemo(
() => ({
interval: `${expression.timeSize || 1}${expression.timeUnit}`,
@ -77,7 +77,6 @@ export const ExpressionChart: React.FC<Props> = ({
region: options.region,
timerange,
});
const isDarkMode = useIsDarkMode();
const metric = {
field: expression.metric,
@ -192,7 +191,7 @@ export const ExpressionChart: React.FC<Props> = ({
tickFormat={dateFormatter}
/>
<Axis id={'values'} position={Position.Left} tickFormat={yAxisFormater} domain={domain} />
<Settings theme={getChartTheme(isDarkMode)} />
<Settings baseTheme={chartTheme.baseTheme} />
<Tooltip {...tooltipProps} />
</Chart>
</ChartContainer>

View file

@ -22,8 +22,7 @@ import {
import { EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { PersistedLogViewReference } from '@kbn/logs-shared-plugin/common';
import { getChartTheme } from '../../../../utils/get_chart_theme';
import { useIsDarkMode } from '../../../../hooks/use_is_dark_mode';
import { useTimelineChartTheme } from '../../../../utils/use_timeline_chart_theme';
import { ExecutionTimeRange } from '../../../../types';
import {
ChartContainer,
@ -143,7 +142,7 @@ const CriterionPreviewChart: React.FC<ChartProps> = ({
annotations,
filterSeriesByGroupName,
}) => {
const isDarkMode = useIsDarkMode();
const chartTheme = useTimelineChartTheme();
const timezone = useKibanaTimeZoneSetting();
const {
@ -331,7 +330,7 @@ const CriterionPreviewChart: React.FC<ChartProps> = ({
tickFormat={yAxisFormatter}
domain={chartDomain}
/>
<Settings theme={getChartTheme(isDarkMode)} />
<Settings baseTheme={chartTheme.baseTheme} />
<Tooltip {...tooltipProps} />
</Chart>
</ChartContainer>

View file

@ -24,6 +24,10 @@ jest.mock('../../../hooks/use_kibana', () => ({
...mockStartServices,
charts: {
activeCursor: jest.fn(),
theme: {
useChartsBaseTheme: jest.fn(() => ({})),
useChartsTheme: jest.fn(() => ({})),
},
},
},
}),

View file

@ -22,8 +22,7 @@ import { useActiveCursor } from '@kbn/charts-plugin/public';
import { DataViewBase } from '@kbn/es-query';
import { first, last } from 'lodash';
import { getChartTheme } from '../../../utils/get_chart_theme';
import { useIsDarkMode } from '../../../hooks/use_is_dark_mode';
import { useTimelineChartTheme } from '../../../utils/use_timeline_chart_theme';
import { MetricsSourceConfiguration } from '../../../../common/metrics_sources';
import { Color } from '../../../../common/color_palette';
import { MetricsExplorerRow, MetricsExplorerAggregation } from '../../../../common/http_api';
@ -72,7 +71,7 @@ export const ExpressionChart: React.FC<Props> = ({
timeRange,
}) => {
const { charts } = useKibanaContextForPlugin().services;
const isDarkMode = useIsDarkMode();
const chartTheme = useTimelineChartTheme();
const { isLoading, data } = useMetricsExplorerChartData(
expression,
@ -200,7 +199,7 @@ export const ExpressionChart: React.FC<Props> = ({
externalPointerEvents={{
tooltip: { visible: true },
}}
theme={getChartTheme(isDarkMode)}
baseTheme={chartTheme.baseTheme}
/>
</Chart>
</ChartContainer>

View file

@ -18,9 +18,8 @@ import {
} from '@elastic/charts';
import moment from 'moment';
import React from 'react';
import { useIsDarkMode } from '../../../../../../../hooks/use_is_dark_mode';
import { useTimelineChartTheme } from '../../../../../../../utils/use_timeline_chart_theme';
import { MetricsExplorerSeries } from '../../../../../../../../common/http_api';
import { getTimelineChartThemes } from '../../../../../../../utils/get_chart_theme';
import { MetricExplorerSeriesChart } from '../../../../../metrics_explorer/components/series_chart';
import {
MetricsExplorerChartType,
@ -58,7 +57,7 @@ export const ChartSection = ({
domain,
stack = false,
}: Props) => {
const isDarkMode = useIsDarkMode();
const chartTheme = useTimelineChartTheme();
const metrics = series.map((chartSeries) => chartSeries.metric);
const tooltipProps: TooltipProps = {
headerFormatter: ({ value }) => moment(value).format('Y-MM-DD HH:mm:ss.SSS'),
@ -93,7 +92,11 @@ export const ChartSection = ({
gridLine={{ visible: true }}
/>
<Tooltip {...tooltipProps} />
<Settings onPointerUpdate={onPointerUpdate} {...getTimelineChartThemes(isDarkMode)} />
<Settings
onPointerUpdate={onPointerUpdate}
baseTheme={chartTheme.baseTheme}
theme={chartTheme.theme}
/>
</Chart>
</>
);

View file

@ -19,11 +19,10 @@ import { euiStyled } from '@kbn/kibana-react-plugin/common';
import { first, last } from 'lodash';
import moment from 'moment';
import React, { useMemo } from 'react';
import { useIsDarkMode } from '../../../../../../../hooks/use_is_dark_mode';
import { useTimelineChartTheme } from '../../../../../../../utils/use_timeline_chart_theme';
import { Color } from '../../../../../../../../common/color_palette';
import { createFormatter } from '../../../../../../../../common/formatters';
import { MetricsExplorerAggregation } from '../../../../../../../../common/http_api';
import { getChartTheme } from '../../../../../../../utils/get_chart_theme';
import { calculateDomain } from '../../../../../metrics_explorer/components/helpers/calculate_domain';
import { MetricExplorerSeriesChart } from '../../../../../metrics_explorer/components/series_chart';
import { MetricsExplorerChartType } from '../../../../../metrics_explorer/hooks/use_metrics_explorer_options';
@ -74,12 +73,12 @@ interface ProcessChartProps {
label: string;
}
const ProcessChart = ({ timeseries, color, label }: ProcessChartProps) => {
const chartTheme = useTimelineChartTheme();
const chartMetric = {
color,
aggregation: 'avg' as MetricsExplorerAggregation,
label,
};
const isDarkMode = useIsDarkMode();
const dateFormatter = useMemo(() => {
if (!timeseries) return () => '';
@ -128,7 +127,7 @@ const ProcessChart = ({ timeseries, color, label }: ProcessChartProps) => {
gridLine={{ visible: true }}
/>
<Tooltip headerFormatter={({ value }) => moment(value).format('Y-MM-DD HH:mm:ss.SSS')} />
<Settings theme={getChartTheme(isDarkMode)} />
<Settings baseTheme={chartTheme.baseTheme} theme={chartTheme.theme} />
</Chart>
</ChartContainer>
);

View file

@ -28,6 +28,7 @@ import { EuiFlexItem } from '@elastic/eui';
import { EuiFlexGroup } from '@elastic/eui';
import { EuiIcon } from '@elastic/eui';
import { euiStyled } from '@kbn/kibana-react-plugin/common';
import { useTimelineChartTheme } from '../../../../../utils/use_timeline_chart_theme';
import { toMetricOpt } from '../../../../../../common/snapshot_metric_i18n';
import { MetricsExplorerAggregation } from '../../../../../../common/http_api';
import { colorTransformer, Color } from '../../../../../../common/color_palette';
@ -38,12 +39,10 @@ import { useWaffleTimeContext } from '../../hooks/use_waffle_time';
import { useWaffleFiltersContext } from '../../hooks/use_waffle_filters';
import { MetricExplorerSeriesChart } from '../../../metrics_explorer/components/series_chart';
import { MetricsExplorerChartType } from '../../../metrics_explorer/hooks/use_metrics_explorer_options';
import { getTimelineChartThemes } from '../../../../../utils/get_chart_theme';
import { calculateDomain } from '../../../metrics_explorer/components/helpers/calculate_domain';
import { InfraFormatter } from '../../../../../lib/lib';
import { useMetricsHostsAnomaliesResults } from '../../hooks/use_metrics_hosts_anomalies';
import { useMetricsK8sAnomaliesResults } from '../../hooks/use_metrics_k8s_anomalies';
import { useIsDarkMode } from '../../../../../hooks/use_is_dark_mode';
interface Props {
interval: string;
@ -57,6 +56,8 @@ export const Timeline: React.FC<Props> = ({ interval, yAxisFormatter, isVisible
const { currentTime, jumpToTime, stopAutoReload } = useWaffleTimeContext();
const { filterQueryAsJson } = useWaffleFiltersContext();
const chartTheme = useTimelineChartTheme();
const { loading, error, startTime, endTime, timeseries, reload } = useTimeline(
filterQueryAsJson,
[metric],
@ -123,7 +124,6 @@ export const Timeline: React.FC<Props> = ({ interval, yAxisFormatter, isVisible
return niceTimeFormatter([firstTimestamp, lastTimestamp]);
}, [timeseries]);
const isDarkMode = useIsDarkMode();
const tooltipProps: TooltipProps = {
headerFormatter: ({ value }) => moment(value).format('Y-MM-DD HH:mm:ss.SSS'),
};
@ -295,7 +295,11 @@ export const Timeline: React.FC<Props> = ({ interval, yAxisFormatter, isVisible
gridLine={{ visible: true }}
/>
<Tooltip {...tooltipProps} />
<Settings onElementClick={onClickPoint} {...getTimelineChartThemes(isDarkMode)} />
<Settings
onElementClick={onClickPoint}
baseTheme={chartTheme.baseTheme}
theme={chartTheme.theme}
/>
</Chart>
</TimelineChartContainer>
</TimelineContainer>

View file

@ -19,7 +19,8 @@ import {
Tooltip,
} from '@elastic/charts';
import { EuiPageContentBody_Deprecated as EuiPageContentBody } from '@elastic/eui';
import { useIsDarkMode } from '../../../../hooks/use_is_dark_mode';
import { useTimelineChartTheme } from '../../../../utils/use_timeline_chart_theme';
import { SeriesChart } from './series_chart';
import {
getFormatter,
@ -30,7 +31,6 @@ import {
seriesHasLessThen2DataPoints,
} from './helpers';
import { ErrorMessage } from './error_message';
import { getChartTheme } from '../../../../utils/get_chart_theme';
import { useKibanaUiSetting } from '../../../../utils/use_kibana_ui_setting';
import { VisSectionProps } from '../types';
@ -46,7 +46,8 @@ export const ChartSectionVis = ({
seriesOverrides,
type,
}: VisSectionProps) => {
const isDarkMode = useIsDarkMode();
const chartTheme = useTimelineChartTheme();
const [dateFormat] = useKibanaUiSetting('dateFormat');
/* eslint-disable-next-line react-hooks/exhaustive-deps */
const valueFormatter = useCallback(getFormatter(formatter, formatterTemplate), [
@ -135,7 +136,7 @@ export const ChartSectionVis = ({
<Tooltip {...tooltipProps} />
<Settings
onBrushEnd={handleTimeChange}
theme={getChartTheme(isDarkMode)}
baseTheme={chartTheme.baseTheme}
showLegend
showLegendExtra
legendPosition="right"

View file

@ -17,14 +17,13 @@ import {
} from '@elastic/charts';
import { EuiFlexGroup, EuiFlexItem, EuiTitle, EuiToolTip } from '@elastic/eui';
import { euiStyled } from '@kbn/kibana-react-plugin/common';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { first, last } from 'lodash';
import moment from 'moment';
import React, { useCallback, useMemo } from 'react';
import { useIsDarkMode } from '../../../../hooks/use_is_dark_mode';
import { useTimelineChartTheme } from '../../../../utils/use_timeline_chart_theme';
import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana';
import { MetricsExplorerSeries } from '../../../../../common/http_api/metrics_explorer';
import { MetricsSourceConfigurationProperties } from '../../../../../common/metrics_sources';
import { getChartTheme } from '../../../../utils/get_chart_theme';
import { useKibanaUiSetting } from '../../../../utils/use_kibana_ui_setting';
import {
MetricsExplorerChartOptions,
@ -65,8 +64,13 @@ export const MetricsExplorerChart = ({
timeRange,
onTimeChange,
}: Props) => {
const uiCapabilities = useKibana().services.application?.capabilities;
const isDarkMode = useIsDarkMode();
const {
services: {
application: { capabilities: uiCapabilities },
},
} = useKibanaContextForPlugin();
const chartTheme = useTimelineChartTheme();
const { metrics } = options;
const [dateFormat] = useKibanaUiSetting('dateFormat');
const handleTimeChange: BrushEndListener = ({ x }) => {
@ -160,7 +164,7 @@ export const MetricsExplorerChart = ({
domain={domain}
/>
<Tooltip {...tooltipProps} />
<Settings onBrushEnd={handleTimeChange} theme={getChartTheme(isDarkMode)} />
<Settings onBrushEnd={handleTimeChange} baseTheme={chartTheme.baseTheme} />
</Chart>
) : options.metrics.length > 0 ? (
<MetricsExplorerEmptyChart />

View file

@ -1,40 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { Theme, PartialTheme, LIGHT_THEME, DARK_THEME, SettingsProps } from '@elastic/charts';
// TODO use the EUI charts theme see src/plugins/charts/public/services/theme/README.md
export function getChartTheme(isDarkMode: boolean): Theme {
return isDarkMode ? DARK_THEME : LIGHT_THEME;
}
const TIMELINE_LIGHT_THEME: PartialTheme = {
crosshair: {
band: {
fill: '#D3DAE6',
},
},
axes: {
gridLine: {
horizontal: {
stroke: '#eaeaea',
},
},
},
};
export const getTimelineChartThemes = (
isDarkMode: boolean
): Pick<SettingsProps, 'baseTheme' | 'theme'> =>
isDarkMode
? {
baseTheme: DARK_THEME,
}
: {
baseTheme: LIGHT_THEME,
theme: TIMELINE_LIGHT_THEME,
};

View file

@ -0,0 +1,48 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { SettingsProps } from '@elastic/charts';
import { useEuiTheme } from '@elastic/eui';
import { useKibanaContextForPlugin } from '../hooks/use_kibana';
export function useTimelineChartTheme(): Pick<SettingsProps, 'baseTheme' | 'theme'> {
const { euiTheme } = useEuiTheme();
const {
services: { charts },
} = useKibanaContextForPlugin();
const baseTheme = charts.theme.useChartsBaseTheme();
const theme = charts.theme.useChartsTheme();
return {
baseTheme,
theme: {
...theme,
background: {
...theme.background,
color: 'transparent',
},
crosshair: {
band: {
...theme.crosshair?.band,
fill: euiTheme.colors.lightShade,
},
},
axes: {
gridLine: {
horizontal: {
visible: false,
},
vertical: {
...theme.axes?.gridLine?.vertical,
dash: undefined,
},
},
},
},
};
}