mirror of https://github.com/grafana/grafana.git
				
				
				
			PanelEdit: VisulizationPicker doesn't show if panel has an unknown panel plugin (#35831)
* feat(dashboard): introduce selector with fallback for unknown plugin * refactor(dashboard): replace redux connect with redux hooks * fix(dashboard): add a fallback for vizpicker when a panel plugin cannot be found * feat(dashboard): add an icon for fallback plugins for vizpicker * refactor(dashboard): prefer HOF selector
This commit is contained in:
		
							parent
							
								
									5e534d212c
								
							
						
					
					
						commit
						0fea1cf970
					
				|  | @ -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<Props> = ({ | ||||
|   plugin, | ||||
|   toggleVizPicker, | ||||
|   isPanelOptionsVisible, | ||||
|   isVizPickerOpen, | ||||
|   setPanelEditorUIState, | ||||
| }) => { | ||||
| export const VisualizationButton: FC<Props> = ({ 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<Props> = ({ | |||
|   ); | ||||
| }; | ||||
| 
 | ||||
| VisualizationButtonUnconnected.displayName = 'VisualizationTabUnconnected'; | ||||
| VisualizationButton.displayName = 'VisualizationTab'; | ||||
| 
 | ||||
| const getStyles = (theme: GrafanaTheme) => { | ||||
|   return { | ||||
|  | @ -84,20 +70,3 @@ const getStyles = (theme: GrafanaTheme) => { | |||
|     `,
 | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (state, props) => { | ||||
|   return { | ||||
|     plugin: state.plugins.panels[props.panel.type], | ||||
|     isPanelOptionsVisible: state.panelEditor.ui.isPanelOptionsVisible, | ||||
|     isVizPickerOpen: state.panelEditor.isVizPickerOpen, | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = { | ||||
|   toggleVizPicker, | ||||
|   setPanelEditorUIState, | ||||
| }; | ||||
| 
 | ||||
| export const VisualizationButton = connect(mapStateToProps, mapDispatchToProps, undefined, { forwardRef: true })( | ||||
|   VisualizationButtonUnconnected | ||||
| ); | ||||
|  |  | |||
|  | @ -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<Props> = ({ 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(); | ||||
|  |  | |||
|  | @ -74,7 +74,7 @@ export function getPanelPluginNotFound(id: string, silent?: boolean): PanelPlugi | |||
|       links: [], | ||||
|       logos: { | ||||
|         large: '', | ||||
|         small: '', | ||||
|         small: 'public/img/grafana_icon.svg', | ||||
|       }, | ||||
|       screenshots: [], | ||||
|       updated: '', | ||||
|  |  | |||
|  | @ -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); | ||||
| }; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue