From 142797032b337812e2a2cff1170dc3c5b8c5b962 Mon Sep 17 00:00:00 2001 From: Matias Chomicki Date: Thu, 24 Oct 2024 12:15:52 +0200 Subject: [PATCH] Logs Volume: update timeout message (#95277) * Logs Volume: update timeout message * SupplementaryResultError: add list styles * Address lint issues * Update public/app/features/explore/Logs/LogsVolumePanelList.tsx Co-authored-by: Sven Grossmann --------- Co-authored-by: Sven Grossmann --- .../explore/Logs/LogsVolumePanelList.test.tsx | 10 ++- .../explore/Logs/LogsVolumePanelList.tsx | 24 ++++++- .../explore/SupplementaryResultError.test.tsx | 6 ++ .../explore/SupplementaryResultError.tsx | 65 ++++++++++++------- public/locales/en-US/grafana.json | 5 ++ public/locales/pseudo-LOCALE/grafana.json | 5 ++ 6 files changed, 87 insertions(+), 28 deletions(-) diff --git a/public/app/features/explore/Logs/LogsVolumePanelList.test.tsx b/public/app/features/explore/Logs/LogsVolumePanelList.test.tsx index b411fcc83cd..de08a6095d3 100644 --- a/public/app/features/explore/Logs/LogsVolumePanelList.test.tsx +++ b/public/app/features/explore/Logs/LogsVolumePanelList.test.tsx @@ -52,7 +52,7 @@ describe('LogsVolumePanelList', () => { expect(screen.getByText(message)).toBeInTheDocument(); }); - it('a custom message for timeout errors', async () => { + it('has a custom message for timeout errors', async () => { const onLoadCallback = jest.fn(); renderPanel( { @@ -62,7 +62,8 @@ describe('LogsVolumePanelList', () => { }, onLoadCallback ); - expect(screen.getByText('The logs volume query has timed out')).toBeInTheDocument(); + expect(screen.getByText('Unable to show log volume')).toBeInTheDocument(); + expect(screen.getByText(/The query is trying to access too much data/)).toBeInTheDocument(); await userEvent.click(screen.getByRole('button', { name: 'Retry' })); expect(onLoadCallback).toHaveBeenCalled(); }); @@ -72,4 +73,9 @@ describe('LogsVolumePanelList', () => { expect(screen.getByRole('status')).toBeInTheDocument(); expect(screen.getByText('No logs volume available')).toBeInTheDocument(); }); + + it('does not show an info message with empty responses when the current state is streaming', async () => { + renderPanel({ state: LoadingState.Streaming, data: [] }); + expect(screen.queryByText('No logs volume available')).not.toBeInTheDocument(); + }); }); diff --git a/public/app/features/explore/Logs/LogsVolumePanelList.tsx b/public/app/features/explore/Logs/LogsVolumePanelList.tsx index 01390d46c37..b9b788a42f8 100644 --- a/public/app/features/explore/Logs/LogsVolumePanelList.tsx +++ b/public/app/features/explore/Logs/LogsVolumePanelList.tsx @@ -17,6 +17,7 @@ import { TimeZone, } from '@grafana/data'; import { Button, InlineField, Alert, useStyles2, SeriesVisibilityChangeMode } from '@grafana/ui'; +import { Trans } from 'app/core/internationalization'; import { mergeLogsVolumeDataFrames, isLogsVolumeLimited, getLogsVolumeMaximumRange } from '../../logs/utils'; import { SupplementaryResultError } from '../SupplementaryResultError'; @@ -97,8 +98,29 @@ export const LogsVolumePanelList = ({ } else if (timeoutError) { return ( +

+ + The query is trying to access too much data. Try one or more of the following: + +

+
    +
  • + + Add more labels to your query to narrow down your search. + +
  • +
  • + + Decrease the time range of your query. + +
  • +
+ + } severity="info" suggestedAction="Retry" onSuggestedAction={onLoadLogsVolume} diff --git a/public/app/features/explore/SupplementaryResultError.test.tsx b/public/app/features/explore/SupplementaryResultError.test.tsx index 5bc62688279..704c0d01ccc 100644 --- a/public/app/features/explore/SupplementaryResultError.test.tsx +++ b/public/app/features/explore/SupplementaryResultError.test.tsx @@ -27,4 +27,10 @@ describe('SupplementaryResultError', () => { await userEvent.click(button); expect(screen.getByText(message)).toBeInTheDocument(); }); + + it('allows arbitrary components in the message', async () => { + const error = { data: { message: 'error' } }; + render(} title={'Error'} />); + expect(screen.getByTestId('custom-stuff')).toBeInTheDocument(); + }); }); diff --git a/public/app/features/explore/SupplementaryResultError.tsx b/public/app/features/explore/SupplementaryResultError.tsx index e2064cedc0a..1a1785aac40 100644 --- a/public/app/features/explore/SupplementaryResultError.tsx +++ b/public/app/features/explore/SupplementaryResultError.tsx @@ -1,53 +1,59 @@ import { css } from '@emotion/css'; -import { useState } from 'react'; +import { ReactNode, useState } from 'react'; import { DataQueryError, GrafanaTheme2 } from '@grafana/data'; import { Alert, AlertVariant, Button, useTheme2 } from '@grafana/ui'; type Props = { error?: DataQueryError; + message?: ReactNode; title: string; severity?: AlertVariant; suggestedAction?: string; onSuggestedAction?(): void; onRemove?(): void; }; +const SHORT_ERROR_MESSAGE_LIMIT = 100; export function SupplementaryResultError(props: Props) { const [isOpen, setIsOpen] = useState(false); - const SHORT_ERROR_MESSAGE_LIMIT = 100; + const { error, title, suggestedAction, onSuggestedAction, onRemove, severity = 'warning' } = props; // generic get-error-message-logic, taken from // /public/app/features/explore/ErrorContainer.tsx - const message = error?.message || error?.data?.message || ''; - const showButton = !isOpen && message.length > SHORT_ERROR_MESSAGE_LIMIT; + const message = props.message ?? error?.message ?? error?.data?.message ?? ''; + const showButton = typeof message === 'string' && message.length > SHORT_ERROR_MESSAGE_LIMIT; const theme = useTheme2(); const styles = getStyles(theme); return (
-
- {showButton ? ( - - ) : ( - message - )} - {suggestedAction && onSuggestedAction && ( -
+ {showButton ? ( +
+ {!isOpen ? ( + + ) : ( + message + )} +
+ ) : ( +
+ {message} + {suggestedAction && onSuggestedAction && ( -
- )} -
+ )} +
+ )}
); @@ -59,13 +65,22 @@ const getStyles = (theme: GrafanaTheme2) => { width: '50%', minWidth: `${theme.breakpoints.values.sm}px`, margin: '0 auto', + [theme.breakpoints.down('lg')]: { + width: '70%', + }, + [theme.breakpoints.down('md')]: { + width: '100%', + }, }), suggestedActionWrapper: css({ - height: theme.spacing(6), + minHeight: theme.spacing(3), ['button']: { position: 'absolute', right: theme.spacing(2), - top: theme.spacing(7), + bottom: theme.spacing(2), + }, + ['ul']: { + paddingLeft: theme.spacing(2), }, }), }; diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 46c91cab42a..29ed9464d08 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -856,6 +856,11 @@ "explore": { "add-to-dashboard": "Add to dashboard", "logs": { + "logs-volume": { + "add-filters": "Add more labels to your query to narrow down your search.", + "decrease-timerange": "Decrease the time range of your query.", + "much-data": "The query is trying to access too much data. Try one or more of the following:" + }, "maximum-pinned-logs": "Maximum of {{PINNED_LOGS_LIMIT}} pinned logs reached. Unpin a log to add another.", "no-logs-found": "No logs found.", "scan-for-older-logs": "Scan for older logs", diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index df37041278f..b41dcb052cb 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -856,6 +856,11 @@ "explore": { "add-to-dashboard": "Åđđ ŧő đäşĥþőäřđ", "logs": { + "logs-volume": { + "add-filters": "Åđđ mőřę ľäþęľş ŧő yőūř qūęřy ŧő ʼnäřřőŵ đőŵʼn yőūř şęäřčĥ.", + "decrease-timerange": "Đęčřęäşę ŧĥę ŧįmę řäʼnģę őƒ yőūř qūęřy.", + "much-data": "Ŧĥę qūęřy įş ŧřyįʼnģ ŧő äččęşş ŧőő mūčĥ đäŧä. Ŧřy őʼnę őř mőřę őƒ ŧĥę ƒőľľőŵįʼnģ:" + }, "maximum-pinned-logs": "Mäχįmūm őƒ {{PINNED_LOGS_LIMIT}} pįʼnʼnęđ ľőģş řęäčĥęđ. Ůʼnpįʼn ä ľőģ ŧő äđđ äʼnőŧĥęř.", "no-logs-found": "Ńő ľőģş ƒőūʼnđ.", "scan-for-older-logs": "Ŝčäʼn ƒőř őľđęř ľőģş",