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:
co-authored by
Ryan McKinley
Jack Westbrook
parent
fb9223ab42
commit
4cbffae1b4
@@ -12,14 +12,27 @@ export enum CoreApp {
|
|||||||
|
|
||||||
export interface AppRootProps<T = KeyValue> {
|
export interface AppRootProps<T = KeyValue> {
|
||||||
meta: AppPluginMeta<T>;
|
meta: AppPluginMeta<T>;
|
||||||
|
/**
|
||||||
path: string; // The URL path to this page
|
* base URL segment for an app, /app/pluginId
|
||||||
query: KeyValue; // The URL query parameters
|
*/
|
||||||
|
basename: string; // The URL path to this page
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pass the nav model to the container... is there a better way?
|
* Pass the nav model to the container... is there a better way?
|
||||||
*/
|
*/
|
||||||
onNavChanged: (nav: NavModel) => void;
|
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> {
|
export interface AppPluginMeta<T = KeyValue> extends PluginMeta<T> {
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ const getBaseWebpackConfig: WebpackConfigurationGetter = async (options) => {
|
|||||||
'react-redux',
|
'react-redux',
|
||||||
'redux',
|
'redux',
|
||||||
'rxjs',
|
'rxjs',
|
||||||
|
'react-router-dom',
|
||||||
'd3',
|
'd3',
|
||||||
'angular',
|
'angular',
|
||||||
'@grafana/ui',
|
'@grafana/ui',
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export class AppWrapper extends React.Component<AppWrapperProps, AppWrapperState
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact={route.exact === undefined ? true : route.exact}
|
||||||
path={route.path}
|
path={route.path}
|
||||||
key={route.path}
|
key={route.path}
|
||||||
render={(props) => {
|
render={(props) => {
|
||||||
|
|||||||
@@ -16,4 +16,5 @@ export interface RouteDescriptor {
|
|||||||
pageClass?: string;
|
pageClass?: string;
|
||||||
/** Can be used like an id for the route if the same component is used by many routes */
|
/** Can be used like an id for the route if the same component is used by many routes */
|
||||||
routeName?: string;
|
routeName?: string;
|
||||||
|
exact?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Libraries
|
// Libraries
|
||||||
import React, { Component } from 'react';
|
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 { createHtmlPortalNode, InPortal, OutPortal, HtmlPortalNode } from 'react-reverse-portal';
|
||||||
|
|
||||||
import Page from 'app/core/components/Page/Page';
|
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 { appEvents } from 'app/core/core';
|
||||||
import PageLoader from 'app/core/components/PageLoader/PageLoader';
|
import PageLoader from 'app/core/components/PageLoader/PageLoader';
|
||||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||||
|
import { locationSearchToObject } from '@grafana/runtime';
|
||||||
|
|
||||||
interface RouteParams {
|
interface RouteParams {
|
||||||
pluginId: string;
|
pluginId: string;
|
||||||
@@ -91,7 +92,6 @@ class AppRootPage extends Component<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { location, queryParams } = this.props;
|
|
||||||
const { loading, plugin, nav, portalNode } = this.state;
|
const { loading, plugin, nav, portalNode } = this.state;
|
||||||
|
|
||||||
if (plugin && !plugin.root) {
|
if (plugin && !plugin.root) {
|
||||||
@@ -105,9 +105,10 @@ class AppRootPage extends Component<Props, State> {
|
|||||||
{plugin && plugin.root && (
|
{plugin && plugin.root && (
|
||||||
<plugin.root
|
<plugin.root
|
||||||
meta={plugin.meta}
|
meta={plugin.meta}
|
||||||
query={queryParams}
|
basename={this.props.match.url}
|
||||||
path={location.pathname}
|
|
||||||
onNavChanged={this.onNavChanged}
|
onNavChanged={this.onNavChanged}
|
||||||
|
query={locationSearchToObject(this.props.location.search) as KeyValue}
|
||||||
|
path={this.props.location.pathname}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</InPortal>
|
</InPortal>
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ grafanaUI.DataSourceApi = grafanaData.DataSourceApi;
|
|||||||
// rxjs
|
// rxjs
|
||||||
import * as rxjs from 'rxjs';
|
import * as rxjs from 'rxjs';
|
||||||
import * as rxjsOperators from 'rxjs/operators';
|
import * as rxjsOperators from 'rxjs/operators';
|
||||||
|
// routing
|
||||||
|
import * as reactRouter from 'react-router-dom';
|
||||||
|
|
||||||
// add cache busting
|
// add cache busting
|
||||||
const bust = `?_cache=${Date.now()}`;
|
const bust = `?_cache=${Date.now()}`;
|
||||||
@@ -92,6 +94,7 @@ exposeToPlugin('angular', angular);
|
|||||||
exposeToPlugin('d3', d3);
|
exposeToPlugin('d3', d3);
|
||||||
exposeToPlugin('rxjs', rxjs);
|
exposeToPlugin('rxjs', rxjs);
|
||||||
exposeToPlugin('rxjs/operators', rxjsOperators);
|
exposeToPlugin('rxjs/operators', rxjsOperators);
|
||||||
|
exposeToPlugin('react-router-dom', reactRouter);
|
||||||
|
|
||||||
// Experimental modules
|
// Experimental modules
|
||||||
exposeToPlugin('prismjs', prismjs);
|
exposeToPlugin('prismjs', prismjs);
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ export function getAppRoutes(): RouteDescriptor[] {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/a/:pluginId/',
|
path: '/a/:pluginId/',
|
||||||
|
exact: false,
|
||||||
// Someday * and will get a ReactRouter under that path!
|
// Someday * and will get a ReactRouter under that path!
|
||||||
component: SafeDynamicImport(
|
component: SafeDynamicImport(
|
||||||
() => import(/* webpackChunkName: "AppRootPage" */ 'app/features/plugins/AppRootPage')
|
() => import(/* webpackChunkName: "AppRootPage" */ 'app/features/plugins/AppRootPage')
|
||||||
|
|||||||
Reference in New Issue
Block a user