mirror of
https://github.com/grafana/grafana.git
synced 2025-09-23 18:52:33 +08:00
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
This commit is contained in:
@ -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());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not mount plugin twice if nav is changed', async () => {
|
const pluginMeta = getMockPlugin({
|
||||||
// reproduces https://github.com/grafana/grafana/pull/28105
|
id: 'my-awesome-plugin',
|
||||||
|
|
||||||
getPluginSettingsMock.mockResolvedValue(
|
|
||||||
getMockPlugin({
|
|
||||||
type: PluginType.app,
|
type: PluginType.app,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
})
|
});
|
||||||
);
|
|
||||||
|
it('should not mount plugin twice if nav is changed', async () => {
|
||||||
|
// reproduces https://github.com/grafana/grafana/pull/28105
|
||||||
|
getPluginSettingsMock.mockResolvedValue(pluginMeta);
|
||||||
|
|
||||||
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,7 +108,6 @@ 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}
|
||||||
@ -108,7 +115,6 @@ class AppRootPage extends Component<Props, State> {
|
|||||||
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}>
|
||||||
|
Reference in New Issue
Block a user