AppRootPage: Fixes issue navigating between two app plugin pages (#54519)

* AppRootPage: Fixes issue where it was not possible to navigate to another plugin

* Externalize react-router

* fixing test
pull/54536/head
Torkel Ödegaard 3 years ago committed by GitHub
parent 713075c494
commit e5fba788d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      packages/grafana-toolkit/src/config/webpack.plugin.config.ts
  2. 29
      public/app/features/plugins/components/AppRootPage.test.tsx
  3. 26
      public/app/features/plugins/components/AppRootPage.tsx

@ -180,6 +180,7 @@ const getBaseWebpackConfig: WebpackConfigurationGetter = async (options) => {
'react-redux', 'react-redux',
'redux', 'redux',
'rxjs', 'rxjs',
'react-router',
'react-router-dom', 'react-router-dom',
'd3', 'd3',
'angular', 'angular',

@ -81,17 +81,18 @@ describe('AppRootPage', () => {
setEchoSrv(new Echo()); setEchoSrv(new Echo());
}); });
const pluginMeta = getMockPlugin({
id: 'my-awesome-plugin',
type: PluginType.app,
enabled: true,
});
it('should not mount plugin twice if nav is changed', async () => { it('should not mount plugin twice if nav is changed', async () => {
// reproduces https://github.com/grafana/grafana/pull/28105 // reproduces https://github.com/grafana/grafana/pull/28105
getPluginSettingsMock.mockResolvedValue(pluginMeta);
getPluginSettingsMock.mockResolvedValue(
getMockPlugin({
type: PluginType.app,
enabled: true,
})
);
const plugin = new AppPlugin(); const plugin = new AppPlugin();
plugin.meta = pluginMeta;
plugin.root = RootComponent; plugin.root = RootComponent;
importAppPluginMock.mockResolvedValue(plugin); importAppPluginMock.mockResolvedValue(plugin);
@ -106,12 +107,7 @@ describe('AppRootPage', () => {
}); });
it('should not render component if not at plugin path', async () => { it('should not render component if not at plugin path', async () => {
getPluginSettingsMock.mockResolvedValue( getPluginSettingsMock.mockResolvedValue(pluginMeta);
getMockPlugin({
type: PluginType.app,
enabled: true,
})
);
class RootComponent extends Component<AppRootProps> { class RootComponent extends Component<AppRootProps> {
static timesRendered = 0; static timesRendered = 0;
@ -122,6 +118,7 @@ describe('AppRootPage', () => {
} }
const plugin = new AppPlugin(); const plugin = new AppPlugin();
plugin.meta = pluginMeta;
plugin.root = RootComponent; plugin.root = RootComponent;
importAppPluginMock.mockResolvedValue(plugin); importAppPluginMock.mockResolvedValue(plugin);
@ -131,18 +128,18 @@ describe('AppRootPage', () => {
expect(await screen.findByText('my great component')).toBeVisible(); expect(await screen.findByText('my great component')).toBeVisible();
// renders the first time // renders the first time
expect(RootComponent.timesRendered).toEqual(1); expect(RootComponent.timesRendered).toEqual(2);
await act(async () => { await act(async () => {
locationService.push('/foo'); locationService.push('/foo');
}); });
expect(RootComponent.timesRendered).toEqual(1); expect(RootComponent.timesRendered).toEqual(2);
await act(async () => { await act(async () => {
locationService.push('/a/my-awesome-plugin'); locationService.push('/a/my-awesome-plugin');
}); });
expect(RootComponent.timesRendered).toEqual(2); expect(RootComponent.timesRendered).toEqual(4);
}); });
}); });

@ -92,7 +92,15 @@ class AppRootPage extends Component<Props, State> {
render() { render() {
const { loading, plugin, nav, portalNode } = this.state; const { loading, plugin, nav, portalNode } = this.state;
if (plugin && !plugin.root) { if (!plugin || this.props.match.params.pluginId !== plugin.meta.id) {
return (
<Page>
<PageLoader />
</Page>
);
}
if (!plugin.root) {
// TODO? redirect to plugin page? // TODO? redirect to plugin page?
return <div>No Root App</div>; return <div>No Root App</div>;
} }
@ -100,15 +108,13 @@ class AppRootPage extends Component<Props, State> {
return ( return (
<> <>
<InPortal node={portalNode}> <InPortal node={portalNode}>
{plugin && plugin.root && ( <plugin.root
<plugin.root meta={plugin.meta}
meta={plugin.meta} basename={this.props.match.url}
basename={this.props.match.url} onNavChanged={this.onNavChanged}
onNavChanged={this.onNavChanged} query={this.props.queryParams as KeyValue}
query={this.props.queryParams as KeyValue} path={this.props.location.pathname}
path={this.props.location.pathname} />
/>
)}
</InPortal> </InPortal>
{nav ? ( {nav ? (
<Page navModel={nav}> <Page navModel={nav}>

Loading…
Cancel
Save