2024-09-30 16:46:43 +02:00
|
|
|
import { css } from '@emotion/css';
|
|
|
|
|
import classNames from 'classnames';
|
|
|
|
|
import { useEffect } from 'react';
|
|
|
|
|
|
|
|
|
|
import { GrafanaTheme2 } from '@grafana/data';
|
2024-10-01 12:45:31 +03:00
|
|
|
import { VizPanel, sceneGraph } from '@grafana/scenes';
|
2024-09-30 16:46:43 +02:00
|
|
|
import { useStyles2 } from '@grafana/ui';
|
|
|
|
|
import { Trans } from 'app/core/internationalization';
|
|
|
|
|
|
|
|
|
|
import { activateInActiveParents } from '../utils/utils';
|
|
|
|
|
|
|
|
|
|
import { DashboardGridItem } from './DashboardGridItem';
|
|
|
|
|
import { DashboardScene } from './DashboardScene';
|
2024-10-01 12:45:31 +03:00
|
|
|
import { DefaultGridLayoutManager } from './layout-default/DefaultGridLayoutManager';
|
2024-09-30 16:46:43 +02:00
|
|
|
|
|
|
|
|
export interface Props {
|
|
|
|
|
dashboard: DashboardScene;
|
|
|
|
|
panelSearch?: string;
|
|
|
|
|
panelsPerRow?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const panelsPerRowCSSVar = '--panels-per-row';
|
|
|
|
|
|
|
|
|
|
export function PanelSearchLayout({ dashboard, panelSearch = '', panelsPerRow }: Props) {
|
|
|
|
|
const { body } = dashboard.state;
|
2024-10-02 12:27:27 +01:00
|
|
|
const filteredPanels: VizPanel[] = [];
|
2024-09-30 16:46:43 +02:00
|
|
|
const styles = useStyles2(getStyles);
|
|
|
|
|
|
2024-10-01 12:45:31 +03:00
|
|
|
const bodyGrid = body instanceof DefaultGridLayoutManager ? body.state.grid : null;
|
|
|
|
|
|
|
|
|
|
if (!bodyGrid) {
|
2024-09-30 16:46:43 +02:00
|
|
|
return <Trans i18nKey="panel-search.unsupported-layout">Unsupported layout</Trans>;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-01 12:45:31 +03:00
|
|
|
for (const gridItem of bodyGrid.state.children) {
|
2024-09-30 16:46:43 +02:00
|
|
|
if (gridItem instanceof DashboardGridItem) {
|
2024-10-02 12:27:27 +01:00
|
|
|
const panels = gridItem.state.repeatedPanels ?? [gridItem.state.body];
|
|
|
|
|
for (const panel of panels) {
|
|
|
|
|
const interpolatedTitle = panel.interpolate(panel.state.title, undefined, 'text').toLowerCase();
|
|
|
|
|
const interpolatedSearchString = sceneGraph.interpolate(dashboard, panelSearch).toLowerCase();
|
|
|
|
|
if (interpolatedTitle.includes(interpolatedSearchString)) {
|
|
|
|
|
filteredPanels.push(panel);
|
|
|
|
|
}
|
2024-09-30 16:46:43 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className={classNames(styles.grid, { [styles.perRow]: panelsPerRow !== undefined })}
|
|
|
|
|
style={{ [panelsPerRowCSSVar]: panelsPerRow } as Record<string, number>}
|
|
|
|
|
>
|
2024-10-02 12:27:27 +01:00
|
|
|
{filteredPanels.map((panel) => (
|
2024-09-30 16:46:43 +02:00
|
|
|
<PanelSearchHit key={panel.state.key} panel={panel} />
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function PanelSearchHit({ panel }: { panel: VizPanel }) {
|
|
|
|
|
useEffect(() => activateInActiveParents(panel), [panel]);
|
|
|
|
|
|
|
|
|
|
return <panel.Component model={panel} />;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getStyles(theme: GrafanaTheme2) {
|
|
|
|
|
return {
|
|
|
|
|
grid: css({
|
|
|
|
|
display: 'grid',
|
|
|
|
|
gridTemplateColumns: 'repeat(auto-fit, minmax(400px, 1fr))',
|
|
|
|
|
gap: theme.spacing(1),
|
|
|
|
|
gridAutoRows: '320px',
|
|
|
|
|
}),
|
|
|
|
|
perRow: css({
|
|
|
|
|
gridTemplateColumns: `repeat(var(${panelsPerRowCSSVar}, 3), 1fr)`,
|
|
|
|
|
}),
|
|
|
|
|
};
|
|
|
|
|
}
|