Alerting: Add empty state to triage page WIP (#113390)
* add empty state to triage page WIP * tidy up and refactor * generate translations * resolve PR comments * generate translations * resolve PR comment part 2
This commit is contained in:
@@ -4,8 +4,9 @@ import { useState } from 'react';
|
||||
import { useMeasure } from 'react-use';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Trans } from '@grafana/i18n';
|
||||
import { SceneQueryRunner } from '@grafana/scenes';
|
||||
import { ScrollContainer, useSplitter, useStyles2 } from '@grafana/ui';
|
||||
import { Box, EmptyState, ScrollContainer, useSplitter, useStyles2 } from '@grafana/ui';
|
||||
import { DEFAULT_PER_PAGE_PAGINATION } from 'app/core/constants';
|
||||
|
||||
import LoadMoreHelper from '../rule-list/LoadMoreHelper';
|
||||
@@ -26,6 +27,7 @@ type WorkbenchProps = {
|
||||
groupBy?: string[];
|
||||
filterBy?: Filter[];
|
||||
queryRunner: SceneQueryRunner;
|
||||
hasActiveFilters?: boolean;
|
||||
};
|
||||
|
||||
const initialSize = 1 / 3;
|
||||
@@ -116,7 +118,7 @@ function renderWorkbenchRow(
|
||||
│ │ │ │
|
||||
└─────────────────────────┘ └───────────────────────────────────┘
|
||||
*/
|
||||
export function Workbench({ domain, data, queryRunner, groupBy }: WorkbenchProps) {
|
||||
export function Workbench({ domain, data, queryRunner, groupBy, hasActiveFilters = false }: WorkbenchProps) {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
const isLoading = !queryRunner.isDataReadyToDisplay();
|
||||
@@ -124,6 +126,10 @@ export function Workbench({ domain, data, queryRunner, groupBy }: WorkbenchProps
|
||||
|
||||
// Calculate once: show folder metadata only if not grouping by grafana_folder
|
||||
const enableFolderMeta = !groupBy?.includes('grafana_folder');
|
||||
|
||||
// Determine UI state
|
||||
const showEmptyState = !isLoading && data.length === 0;
|
||||
const showData = !isLoading && data.length > 0;
|
||||
// splitter for template and payload editor
|
||||
const splitter = useSplitter({
|
||||
direction: 'row',
|
||||
@@ -149,42 +155,62 @@ export function Workbench({ domain, data, queryRunner, groupBy }: WorkbenchProps
|
||||
<div {...splitter.primaryProps}>
|
||||
<div ref={leftColumnRef} className={cx(styles.flexFull, styles.minColumnWidth)} />
|
||||
</div>
|
||||
<div {...splitter.splitterProps} />
|
||||
{!showEmptyState && <div {...splitter.splitterProps} />}
|
||||
<div {...splitter.secondaryProps}>
|
||||
<div ref={rightColumnRef} className={cx(styles.flexFull, styles.minColumnWidth)} />
|
||||
</div>
|
||||
</div>
|
||||
{/* content goes here */}
|
||||
<div data-testid="groups-container" className={cx(splitter.containerProps.className, styles.groupsContainer)}>
|
||||
<div className={cx(styles.groupItemWrapper(leftColumnWidth), styles.summaryContainer)}>
|
||||
<SummaryStatsReact />
|
||||
<SummaryChartReact />
|
||||
</div>
|
||||
{/* Render actual data */}
|
||||
<div className={styles.virtualizedContainer}>
|
||||
<WorkbenchProvider
|
||||
leftColumnWidth={leftColumnWidth}
|
||||
rightColumnWidth={rightColumnWidth}
|
||||
domain={domain}
|
||||
queryRunner={queryRunner}
|
||||
>
|
||||
<ScrollContainer height="100%" width="100%" scrollbarWidth="none" showScrollIndicators>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<GenericRowSkeleton key="skeleton-1" width={leftColumnWidth} depth={0} />
|
||||
<GenericRowSkeleton key="skeleton-2" width={leftColumnWidth} depth={0} />
|
||||
<GenericRowSkeleton key="skeleton-3" width={leftColumnWidth} depth={0} />
|
||||
</>
|
||||
{showEmptyState ? (
|
||||
<Box display="flex" alignItems="center" justifyContent="center" width="100%" height="100%" minHeight="400px">
|
||||
<EmptyState
|
||||
variant="not-found"
|
||||
message={hasActiveFilters ? 'No matching instances found' : 'No firing or pending instances'}
|
||||
>
|
||||
{hasActiveFilters ? (
|
||||
<Trans i18nKey="alerting.triage.no-matching-instances-with-filters">
|
||||
No alert instances match your current set of filters for the selected time range.
|
||||
</Trans>
|
||||
) : (
|
||||
dataSlice.map((row, index) => {
|
||||
const rowKey = generateRowKey(row, index);
|
||||
return renderWorkbenchRow(row, leftColumnWidth, domain, rowKey, enableFolderMeta);
|
||||
})
|
||||
<Trans i18nKey="alerting.triage.no-firing-or-pending-instances">
|
||||
You have no alert instances in a firing or pending state for the selected time range.
|
||||
</Trans>
|
||||
)}
|
||||
{hasMore && <LoadMoreHelper handleLoad={() => setPageIndex((prevIndex) => prevIndex + 1)} />}
|
||||
</ScrollContainer>
|
||||
</WorkbenchProvider>
|
||||
</div>
|
||||
</EmptyState>
|
||||
</Box>
|
||||
) : (
|
||||
<>
|
||||
<div className={cx(styles.groupItemWrapper(leftColumnWidth), styles.summaryContainer)}>
|
||||
<SummaryStatsReact />
|
||||
<SummaryChartReact />
|
||||
</div>
|
||||
<div className={styles.virtualizedContainer}>
|
||||
<WorkbenchProvider
|
||||
leftColumnWidth={leftColumnWidth}
|
||||
rightColumnWidth={rightColumnWidth}
|
||||
domain={domain}
|
||||
queryRunner={queryRunner}
|
||||
>
|
||||
<ScrollContainer height="100%" width="100%" scrollbarWidth="none" showScrollIndicators={showData}>
|
||||
{isLoading && (
|
||||
<>
|
||||
<GenericRowSkeleton key="skeleton-1" width={leftColumnWidth} depth={0} />
|
||||
<GenericRowSkeleton key="skeleton-2" width={leftColumnWidth} depth={0} />
|
||||
<GenericRowSkeleton key="skeleton-3" width={leftColumnWidth} depth={0} />
|
||||
</>
|
||||
)}
|
||||
{showData &&
|
||||
dataSlice.map((row, index) => {
|
||||
const rowKey = generateRowKey(row, index);
|
||||
return renderWorkbenchRow(row, leftColumnWidth, domain, rowKey, enableFolderMeta);
|
||||
})}
|
||||
{hasMore && <LoadMoreHelper handleLoad={() => setPageIndex((prevIndex) => prevIndex + 1)} />}
|
||||
</ScrollContainer>
|
||||
</WorkbenchProvider>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -34,7 +34,17 @@ export function WorkbenchRenderer() {
|
||||
const { data } = runner.useState();
|
||||
const rows = data ? convertToWorkbenchRows(data, groupByKeys) : [];
|
||||
|
||||
return <Workbench data={rows} domain={domain} queryRunner={runner} groupBy={groupByKeys} />;
|
||||
const hasFiltersApplied = queryFilter.length > 0;
|
||||
|
||||
return (
|
||||
<Workbench
|
||||
data={rows}
|
||||
domain={domain}
|
||||
queryRunner={runner}
|
||||
groupBy={groupByKeys}
|
||||
hasActiveFilters={hasFiltersApplied}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
type DataPoint = Record<ArrayValues<typeof DEFAULT_FIELDS>, string> & Record<string, string | undefined>;
|
||||
|
||||
@@ -2948,8 +2948,10 @@
|
||||
"instance-details-drawer": {
|
||||
"instance-details": "Instance details"
|
||||
},
|
||||
"no-firing-or-pending-instances": "You have no alert instances in a firing or pending state for the selected time range.",
|
||||
"no-instances-found": "No alert instances found for rule: {{ruleUID}}",
|
||||
"no-labels": "No labels",
|
||||
"no-matching-instances-with-filters": "No alert instances match your current set of filters for the selected time range.",
|
||||
"open-in-sidebar": "Open in sidebar",
|
||||
"open-rule-details": "Open rule details",
|
||||
"rule-details": {
|
||||
|
||||
Reference in New Issue
Block a user