import { css, cx } from '@emotion/css'; import React, { CSSProperties, useCallback, useMemo, useState } from 'react'; import { useDebounce } from 'react-use'; import AutoSizer from 'react-virtualized-auto-sizer'; import { FixedSizeList } from 'react-window'; import { GrafanaTheme2 } from '@grafana/data/src'; import { FilterInput, LoadingPlaceholder, useStyles2, Icon, Modal, Button, Alert } from '@grafana/ui'; import { dashboardApi } from '../../api/dashboardApi'; export interface PanelDTO { id: number; title?: string; } function panelSort(a: PanelDTO, b: PanelDTO) { if (a.title && b.title) { return a.title.localeCompare(b.title); } if (a.title && !b.title) { return 1; } else if (!a.title && b.title) { return -1; } return 0; } interface DashboardPickerProps { isOpen: boolean; dashboardUid?: string | undefined; panelId?: string | undefined; onChange: (dashboardUid: string, panelId: string) => void; onDismiss: () => void; } export const DashboardPicker = ({ dashboardUid, panelId, isOpen, onChange, onDismiss }: DashboardPickerProps) => { const styles = useStyles2(getPickerStyles); const [selectedDashboardUid, setSelectedDashboardUid] = useState(dashboardUid); const [selectedPanelId, setSelectedPanelId] = useState(panelId); const [dashboardFilter, setDashboardFilter] = useState(''); const [debouncedDashboardFilter, setDebouncedDashboardFilter] = useState(''); const [panelFilter, setPanelFilter] = useState(''); const { useSearchQuery, useDashboardQuery } = dashboardApi; const { currentData: filteredDashboards = [], isFetching: isDashSearchFetching } = useSearchQuery({ query: debouncedDashboardFilter, }); const { currentData: dashboardResult, isFetching: isDashboardFetching } = useDashboardQuery( { uid: selectedDashboardUid ?? '' }, { skip: !selectedDashboardUid } ); const handleDashboardChange = useCallback((dashboardUid: string) => { setSelectedDashboardUid(dashboardUid); setSelectedPanelId(undefined); }, []); const filteredPanels = dashboardResult?.dashboard?.panels ?.filter((panel): panel is PanelDTO => typeof panel.id === 'number') ?.filter((panel) => panel.title?.toLowerCase().includes(panelFilter.toLowerCase())) .sort(panelSort) ?? []; const currentPanel = dashboardResult?.dashboard?.panels?.find((panel) => panel.id.toString() === selectedPanelId); const selectedDashboardIndex = useMemo(() => { return filteredDashboards.map((dashboard) => dashboard.uid).indexOf(selectedDashboardUid ?? ''); }, [filteredDashboards, selectedDashboardUid]); const isDefaultSelection = dashboardUid && dashboardUid === selectedDashboardUid; const selectedDashboardIsInPageResult = selectedDashboardIndex >= 0; const scrollToItem = useCallback( (node) => { const canScroll = selectedDashboardIndex >= 0; if (isDefaultSelection && canScroll) { node?.scrollToItem(selectedDashboardIndex, 'smart'); } }, [isDefaultSelection, selectedDashboardIndex] ); useDebounce( () => { setDebouncedDashboardFilter(dashboardFilter); }, 500, [dashboardFilter] ); const DashboardRow = ({ index, style }: { index: number; style?: CSSProperties }) => { const dashboard = filteredDashboards[index]; const isSelected = selectedDashboardUid === dashboard.uid; return (