diff --git a/public/app/features/dashboard/components/PanelEditor/VisualizationButton.tsx b/public/app/features/dashboard/components/PanelEditor/VisualizationButton.tsx index d5cd4c8f74f..8e705bbd8f2 100644 --- a/public/app/features/dashboard/components/PanelEditor/VisualizationButton.tsx +++ b/public/app/features/dashboard/components/PanelEditor/VisualizationButton.tsx @@ -1,45 +1,31 @@ import React, { FC } from 'react'; import { css } from '@emotion/css'; -import { GrafanaTheme, PanelPlugin } from '@grafana/data'; +import { GrafanaTheme } from '@grafana/data'; import { ToolbarButton, ButtonGroup, useStyles } from '@grafana/ui'; import { StoreState } from 'app/types'; -import { connect, MapStateToProps, MapDispatchToProps } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { setPanelEditorUIState, toggleVizPicker } from './state/reducers'; import { selectors } from '@grafana/e2e-selectors'; import { PanelModel } from '../../state'; +import { getPanelPluginWithFallback } from '../../state/selectors'; -interface OwnProps { +type Props = { panel: PanelModel; -} +}; -interface ConnectedProps { - plugin?: PanelPlugin; - isVizPickerOpen: boolean; - isPanelOptionsVisible: boolean; -} - -interface DispatchProps { - toggleVizPicker: typeof toggleVizPicker; - setPanelEditorUIState: typeof setPanelEditorUIState; -} - -type Props = OwnProps & ConnectedProps & DispatchProps; - -export const VisualizationButtonUnconnected: FC = ({ - plugin, - toggleVizPicker, - isPanelOptionsVisible, - isVizPickerOpen, - setPanelEditorUIState, -}) => { +export const VisualizationButton: FC = ({ panel }) => { const styles = useStyles(getStyles); + const dispatch = useDispatch(); + const plugin = useSelector(getPanelPluginWithFallback(panel.type)); + const isPanelOptionsVisible = useSelector((state: StoreState) => state.panelEditor.ui.isPanelOptionsVisible); + const isVizPickerOpen = useSelector((state: StoreState) => state.panelEditor.isVizPickerOpen); const onToggleOpen = () => { - toggleVizPicker(!isVizPickerOpen); + dispatch(toggleVizPicker(!isVizPickerOpen)); }; const onToggleOptionsPane = () => { - setPanelEditorUIState({ isPanelOptionsVisible: !isPanelOptionsVisible }); + dispatch(setPanelEditorUIState({ isPanelOptionsVisible: !isPanelOptionsVisible })); }; if (!plugin) { @@ -71,7 +57,7 @@ export const VisualizationButtonUnconnected: FC = ({ ); }; -VisualizationButtonUnconnected.displayName = 'VisualizationTabUnconnected'; +VisualizationButton.displayName = 'VisualizationTab'; const getStyles = (theme: GrafanaTheme) => { return { @@ -84,20 +70,3 @@ const getStyles = (theme: GrafanaTheme) => { `, }; }; - -const mapStateToProps: MapStateToProps = (state, props) => { - return { - plugin: state.plugins.panels[props.panel.type], - isPanelOptionsVisible: state.panelEditor.ui.isPanelOptionsVisible, - isVizPickerOpen: state.panelEditor.isVizPickerOpen, - }; -}; - -const mapDispatchToProps: MapDispatchToProps = { - toggleVizPicker, - setPanelEditorUIState, -}; - -export const VisualizationButton = connect(mapStateToProps, mapDispatchToProps, undefined, { forwardRef: true })( - VisualizationButtonUnconnected -); diff --git a/public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.tsx b/public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.tsx index db885fb3deb..61e8bce146e 100644 --- a/public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.tsx +++ b/public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.tsx @@ -3,7 +3,6 @@ import { css } from '@emotion/css'; import { GrafanaTheme, PanelPluginMeta, SelectableValue } from '@grafana/data'; import { Button, CustomScrollbar, Icon, Input, RadioButtonGroup, useStyles } from '@grafana/ui'; import { changePanelPlugin } from '../../state/actions'; -import { StoreState } from 'app/types'; import { PanelModel } from '../../state/PanelModel'; import { useDispatch, useSelector } from 'react-redux'; import { filterPluginList, getAllPanelPluginMeta, VizTypePicker } from '../VizTypePicker/VizTypePicker'; @@ -11,13 +10,14 @@ import { Field } from '@grafana/ui/src/components/Forms/Field'; import { PanelLibraryOptionsGroup } from 'app/features/library-panels/components/PanelLibraryOptionsGroup/PanelLibraryOptionsGroup'; import { toggleVizPicker } from './state/reducers'; import { selectors } from '@grafana/e2e-selectors'; +import { getPanelPluginWithFallback } from '../../state/selectors'; interface Props { panel: PanelModel; } export const VisualizationSelectPane: FC = ({ panel }) => { - const plugin = useSelector((state: StoreState) => state.plugins.panels[panel.type]); + const plugin = useSelector(getPanelPluginWithFallback(panel.type)); const [searchQuery, setSearchQuery] = useState(''); const [listMode, setListMode] = useState(ListMode.Visualizations); const dispatch = useDispatch(); diff --git a/public/app/features/dashboard/dashgrid/PanelPluginError.tsx b/public/app/features/dashboard/dashgrid/PanelPluginError.tsx index fa2b65e64f8..1e001613ffc 100644 --- a/public/app/features/dashboard/dashgrid/PanelPluginError.tsx +++ b/public/app/features/dashboard/dashgrid/PanelPluginError.tsx @@ -74,7 +74,7 @@ export function getPanelPluginNotFound(id: string, silent?: boolean): PanelPlugi links: [], logos: { large: '', - small: '', + small: 'public/img/grafana_icon.svg', }, screenshots: [], updated: '', diff --git a/public/app/features/dashboard/state/selectors.ts b/public/app/features/dashboard/state/selectors.ts index 1f2fd772678..1f788162663 100644 --- a/public/app/features/dashboard/state/selectors.ts +++ b/public/app/features/dashboard/state/selectors.ts @@ -1,4 +1,6 @@ -import { DashboardState, PanelState } from 'app/types'; +import { DashboardState, PanelState, StoreState } from 'app/types'; +import { PanelPlugin } from '@grafana/data'; +import { getPanelPluginNotFound } from '../dashgrid/PanelPluginError'; export function getPanelStateById(state: DashboardState, panelId: number): PanelState { if (!panelId) { @@ -7,3 +9,8 @@ export function getPanelStateById(state: DashboardState, panelId: number): Panel return state.panels[panelId] ?? ({} as PanelState); } + +export const getPanelPluginWithFallback = (panelType: string) => (state: StoreState): PanelPlugin => { + const plugin = state.plugins.panels[panelType]; + return plugin || getPanelPluginNotFound(`Panel plugin not found (${panelType})`, true); +};