import { css } from '@emotion/css'; import { flatten, groupBy, mapValues, sortBy } from 'lodash'; import React, { useMemo } from 'react'; import { AbsoluteTimeRange, DataFrame, DataQueryResponse, EventBus, GrafanaTheme2, LoadingState, SplitOpen, TimeZone, } from '@grafana/data'; import { Button, InlineField, Alert, useStyles2 } from '@grafana/ui'; import { mergeLogsVolumeDataFrames, isLogsVolumeLimited, getLogsVolumeMaximumRange } from '../../logs/utils'; import { SupplementaryResultError } from '../SupplementaryResultError'; import { LogsVolumePanel } from './LogsVolumePanel'; import { isTimeoutErrorResponse } from './utils/logsVolumeResponse'; type Props = { logsVolumeData: DataQueryResponse | undefined; absoluteRange: AbsoluteTimeRange; timeZone: TimeZone; splitOpen: SplitOpen; width: number; onUpdateTimeRange: (timeRange: AbsoluteTimeRange) => void; onLoadLogsVolume: () => void; onHiddenSeriesChanged: (hiddenSeries: string[]) => void; eventBus: EventBus; onClose?(): void; }; export const LogsVolumePanelList = ({ logsVolumeData, absoluteRange, onUpdateTimeRange, width, onLoadLogsVolume, onHiddenSeriesChanged, eventBus, splitOpen, timeZone, onClose, }: Props) => { const { logVolumes, maximumValue: allLogsVolumeMaximumValue, maximumRange: allLogsVolumeMaximumRange, } = useMemo(() => { let maximumValue = -Infinity; const sorted = sortBy(logsVolumeData?.data || [], 'meta.custom.datasourceName'); const grouped = groupBy(sorted, 'meta.custom.datasourceName'); const logVolumes = mapValues(grouped, (value) => { const mergedData = mergeLogsVolumeDataFrames(value); maximumValue = Math.max(maximumValue, mergedData.maximum); return mergedData.dataFrames; }); const maximumRange = getLogsVolumeMaximumRange(flatten(Object.values(logVolumes))); return { maximumValue, maximumRange, logVolumes, }; }, [logsVolumeData]); const styles = useStyles2(getStyles); const numberOfLogVolumes = Object.keys(logVolumes).length; const containsZoomed = Object.values(logVolumes).some((data: DataFrame[]) => { const zoomRatio = logsLevelZoomRatio(data, absoluteRange); return !isLogsVolumeLimited(data) && zoomRatio && zoomRatio < 1; }); const timeoutError = isTimeoutErrorResponse(logsVolumeData); const visibleRange = { from: Math.max(absoluteRange.from, allLogsVolumeMaximumRange.from), to: Math.min(absoluteRange.to, allLogsVolumeMaximumRange.to), }; if (logsVolumeData?.state === LoadingState.Loading) { return Loading...; } else if (timeoutError) { return ( ); } else if (logsVolumeData?.error !== undefined) { return ; } if (numberOfLogVolumes === 0) { return (
No volume information available for the current queries and time range.
); } return (
{Object.keys(logVolumes).map((name, index) => { const logsVolumeData = { data: logVolumes[name] }; return ( 1 ? () => {} : onHiddenSeriesChanged} eventBus={eventBus} /> ); })} {containsZoomed && (
)}
); }; const getStyles = (theme: GrafanaTheme2) => { return { listContainer: css` padding-top: 10px; `, extraInfoContainer: css` display: flex; justify-content: end; position: absolute; right: 5px; top: 5px; `, oldInfoText: css` font-size: ${theme.typography.bodySmall.fontSize}; color: ${theme.colors.text.secondary}; `, alertContainer: css` width: 50%; min-width: ${theme.breakpoints.values.sm}px; margin: 0 auto; `, }; }; function logsLevelZoomRatio( logsVolumeData: DataFrame[] | undefined, selectedTimeRange: AbsoluteTimeRange ): number | undefined { const dataRange = logsVolumeData && logsVolumeData[0] && logsVolumeData[0].meta?.custom?.absoluteRange; return dataRange ? (selectedTimeRange.from - selectedTimeRange.to) / (dataRange.from - dataRange.to) : undefined; }