diff --git a/public/app/features/alerting/unified/components/rules/state-history/ErrorMessageRow.tsx b/public/app/features/alerting/unified/components/rules/state-history/ErrorMessageRow.tsx
new file mode 100644
index 00000000000..35c5a6b50da
--- /dev/null
+++ b/public/app/features/alerting/unified/components/rules/state-history/ErrorMessageRow.tsx
@@ -0,0 +1,36 @@
+import { t } from '@grafana/i18n';
+import { Box, Stack, Text } from '@grafana/ui';
+
+interface ErrorMessageRowProps {
+ message: string;
+}
+
+export function ErrorMessageRow({ message }: ErrorMessageRowProps) {
+ return (
+
+
+
+
+
+ {t('alerting.state-history.error-message-prefix', 'Error message:')}
+
+
+
+
+ {message}
+
+
+
+
+
+ );
+}
diff --git a/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.test.tsx b/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.test.tsx
index b94e535c70c..a90e9dc52a8 100644
--- a/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.test.tsx
+++ b/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.test.tsx
@@ -1,4 +1,4 @@
-import { render, screen } from '@testing-library/react';
+import { render, screen, within } from '@testing-library/react';
import { byRole } from 'testing-library-selector';
import { LogRecordViewerByTimestamp } from './LogRecordViewer';
@@ -31,4 +31,33 @@ describe('LogRecordViewerByTimestamp', () => {
expect(entry2).toHaveTextContent('foo=bar');
expect(entry2).toHaveTextContent('severity=warning');
});
+
+ it('renders error row only when current state is Error and shows message', () => {
+ const ts = 1681739700000;
+ const records: LogRecord[] = [
+ {
+ timestamp: ts,
+ line: { current: 'Error (timeout)', previous: 'Pending', labels: { foo: 'bar' }, error: 'timeout' },
+ },
+ { timestamp: ts, line: { current: 'Normal', previous: 'Alerting', labels: { foo: 'baz' } } },
+ {
+ timestamp: ts,
+ line: {
+ current: 'Error',
+ previous: 'Pending',
+ labels: { error: 'explicit message' },
+ error: 'explicit message',
+ },
+ },
+ ];
+
+ render();
+
+ const errorRows = screen.getAllByTestId('state-history-error');
+ expect(errorRows).toHaveLength(2);
+ expect(within(errorRows[0]).getByText(/Error message:/)).toBeInTheDocument();
+ expect(within(errorRows[0]).getByText(/timeout/)).toBeInTheDocument();
+ expect(within(errorRows[1]).getByText(/Error message:/)).toBeInTheDocument();
+ expect(within(errorRows[1]).getByText(/explicit message/)).toBeInTheDocument();
+ });
});
diff --git a/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.tsx b/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.tsx
index 6337b89bb0f..288af1dd2f9 100644
--- a/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.tsx
+++ b/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.tsx
@@ -1,15 +1,17 @@
import { css } from '@emotion/css';
import { formatDistanceToNowStrict } from 'date-fns';
import { groupBy, uniqueId } from 'lodash';
-import { Fragment, memo, useEffect } from 'react';
+import { Fragment, memo, useEffect, useRef } from 'react';
import { GrafanaTheme2, dateTimeFormat } from '@grafana/data';
import { Trans, t } from '@grafana/i18n';
import { Icon, Stack, TagList, useStyles2 } from '@grafana/ui';
+import { GrafanaAlertState, mapStateWithReasonToBaseState } from 'app/types/unified-alerting-dto';
import { Label } from '../../Label';
import { AlertStateTag } from '../AlertStateTag';
+import { ErrorMessageRow } from './ErrorMessageRow';
import { LogRecord, omitLabels } from './common';
type LogRecordViewerProps = {
@@ -49,10 +51,10 @@ export const LogRecordViewerByTimestamp = memo(
const groupedLines = groupRecordsByTimestamp(records);
- const timestampRefs = new Map();
+ const timestampRefs = useRef