AppPlugins: Expose react-router to apps (#33775)

* Allow Route component usage in app plugins

* i tried

* fix catalog app

* fix catalog app

* remove catalog changes from this PR

* remove extra files

* feat(plugins): expose react-router to plugins rather than export via grafana-ui

* Bring back query and pathname to AppRootPage and add deprecation notice

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com>
This commit is contained in:
Dominik Prokop 2021-05-19 19:10:21 +02:00 committed by GitHub
parent fb9223ab42
commit 4cbffae1b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 28 additions and 8 deletions

View File

@ -12,14 +12,27 @@ export enum CoreApp {
export interface AppRootProps<T = KeyValue> {
meta: AppPluginMeta<T>;
path: string; // The URL path to this page
query: KeyValue; // The URL query parameters
/**
* base URL segment for an app, /app/pluginId
*/
basename: string; // The URL path to this page
/**
* Pass the nav model to the container... is there a better way?
*/
onNavChanged: (nav: NavModel) => void;
/**
* The URL query parameters
* @deprecated Use react-router instead
*/
query: KeyValue;
/**
* The URL path to this page
* @deprecated Use react-router instead
*/
path: string;
}
export interface AppPluginMeta<T = KeyValue> extends PluginMeta<T> {

View File

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

View File

@ -59,7 +59,7 @@ export class AppWrapper extends React.Component<AppWrapperProps, AppWrapperState
return (
<Route
exact
exact={route.exact === undefined ? true : route.exact}
path={route.path}
key={route.path}
render={(props) => {

View File

@ -16,4 +16,5 @@ export interface RouteDescriptor {
pageClass?: string;
/** Can be used like an id for the route if the same component is used by many routes */
routeName?: string;
exact?: boolean;
}

View File

@ -1,6 +1,6 @@
// Libraries
import React, { Component } from 'react';
import { AppEvents, AppPlugin, AppPluginMeta, NavModel, PluginType } from '@grafana/data';
import { AppEvents, AppPlugin, AppPluginMeta, KeyValue, NavModel, PluginType } from '@grafana/data';
import { createHtmlPortalNode, InPortal, OutPortal, HtmlPortalNode } from 'react-reverse-portal';
import Page from 'app/core/components/Page/Page';
@ -10,6 +10,7 @@ import { getNotFoundNav, getWarningNav, getExceptionNav } from 'app/core/nav_mod
import { appEvents } from 'app/core/core';
import PageLoader from 'app/core/components/PageLoader/PageLoader';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { locationSearchToObject } from '@grafana/runtime';
interface RouteParams {
pluginId: string;
@ -91,7 +92,6 @@ class AppRootPage extends Component<Props, State> {
};
render() {
const { location, queryParams } = this.props;
const { loading, plugin, nav, portalNode } = this.state;
if (plugin && !plugin.root) {
@ -105,9 +105,10 @@ class AppRootPage extends Component<Props, State> {
{plugin && plugin.root && (
<plugin.root
meta={plugin.meta}
query={queryParams}
path={location.pathname}
basename={this.props.match.url}
onNavChanged={this.onNavChanged}
query={locationSearchToObject(this.props.location.search) as KeyValue}
path={this.props.location.pathname}
/>
)}
</InPortal>

View File

@ -46,6 +46,8 @@ grafanaUI.DataSourceApi = grafanaData.DataSourceApi;
// rxjs
import * as rxjs from 'rxjs';
import * as rxjsOperators from 'rxjs/operators';
// routing
import * as reactRouter from 'react-router-dom';
// add cache busting
const bust = `?_cache=${Date.now()}`;
@ -92,6 +94,7 @@ exposeToPlugin('angular', angular);
exposeToPlugin('d3', d3);
exposeToPlugin('rxjs', rxjs);
exposeToPlugin('rxjs/operators', rxjsOperators);
exposeToPlugin('react-router-dom', reactRouter);
// Experimental modules
exposeToPlugin('prismjs', prismjs);

View File

@ -149,6 +149,7 @@ export function getAppRoutes(): RouteDescriptor[] {
},
{
path: '/a/:pluginId/',
exact: false,
// Someday * and will get a ReactRouter under that path!
component: SafeDynamicImport(
() => import(/* webpackChunkName: "AppRootPage" */ 'app/features/plugins/AppRootPage')