AppWrapper.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import { Action, KBarProvider } from 'kbar';
  2. import React, { ComponentType } from 'react';
  3. import { Provider } from 'react-redux';
  4. import { Router, Route, Redirect, Switch } from 'react-router-dom';
  5. import { config, locationService, navigationLogger, reportInteraction } from '@grafana/runtime';
  6. import { ErrorBoundaryAlert, GlobalStyles, ModalRoot, ModalsProvider, PortalContainer } from '@grafana/ui';
  7. import { SearchWrapper } from 'app/features/search';
  8. import { getAppRoutes } from 'app/routes/routes';
  9. import { store } from 'app/store/store';
  10. import { AngularRoot } from './angular/AngularRoot';
  11. import { loadAndInitAngularIfEnabled } from './angular/loadAndInitAngularIfEnabled';
  12. import { GrafanaApp } from './app';
  13. import { AppNotificationList } from './core/components/AppNotifications/AppNotificationList';
  14. import { NavBar } from './core/components/NavBar/NavBar';
  15. import { I18nProvider } from './core/localisation';
  16. import { GrafanaRoute } from './core/navigation/GrafanaRoute';
  17. import { RouteDescriptor } from './core/navigation/types';
  18. import { contextSrv } from './core/services/context_srv';
  19. import { ConfigContext, ThemeProvider } from './core/utils/ConfigProvider';
  20. import { CommandPalette } from './features/commandPalette/CommandPalette';
  21. import { LiveConnectionWarning } from './features/live/LiveConnectionWarning';
  22. interface AppWrapperProps {
  23. app: GrafanaApp;
  24. }
  25. interface AppWrapperState {
  26. ready?: boolean;
  27. }
  28. /** Used by enterprise */
  29. let bodyRenderHooks: ComponentType[] = [];
  30. let pageBanners: ComponentType[] = [];
  31. export function addBodyRenderHook(fn: ComponentType) {
  32. bodyRenderHooks.push(fn);
  33. }
  34. export function addPageBanner(fn: ComponentType) {
  35. pageBanners.push(fn);
  36. }
  37. export class AppWrapper extends React.Component<AppWrapperProps, AppWrapperState> {
  38. constructor(props: AppWrapperProps) {
  39. super(props);
  40. this.state = {};
  41. }
  42. async componentDidMount() {
  43. await loadAndInitAngularIfEnabled();
  44. this.setState({ ready: true });
  45. $('.preloader').remove();
  46. }
  47. renderRoute = (route: RouteDescriptor) => {
  48. const roles = route.roles ? route.roles() : [];
  49. return (
  50. <Route
  51. exact={route.exact === undefined ? true : route.exact}
  52. path={route.path}
  53. key={route.path}
  54. render={(props) => {
  55. navigationLogger('AppWrapper', false, 'Rendering route', route, 'with match', props.location);
  56. // TODO[Router]: test this logic
  57. if (roles?.length) {
  58. if (!roles.some((r: string) => contextSrv.hasRole(r))) {
  59. return <Redirect to="/" />;
  60. }
  61. }
  62. return <GrafanaRoute {...props} route={route} />;
  63. }}
  64. />
  65. );
  66. };
  67. renderRoutes() {
  68. return <Switch>{getAppRoutes().map((r) => this.renderRoute(r))}</Switch>;
  69. }
  70. render() {
  71. const { ready } = this.state;
  72. navigationLogger('AppWrapper', false, 'rendering');
  73. const commandPaletteActionSelected = (action: Action) => {
  74. reportInteraction('commandPalette_action_selected', {
  75. actionId: action.id,
  76. });
  77. };
  78. return (
  79. <Provider store={store}>
  80. <I18nProvider>
  81. <ErrorBoundaryAlert style="page">
  82. <ConfigContext.Provider value={config}>
  83. <ThemeProvider>
  84. <KBarProvider
  85. actions={[]}
  86. options={{ enableHistory: true, callbacks: { onSelectAction: commandPaletteActionSelected } }}
  87. >
  88. <ModalsProvider>
  89. <GlobalStyles />
  90. {config.featureToggles.commandPalette && <CommandPalette />}
  91. <div className="grafana-app">
  92. <Router history={locationService.getHistory()}>
  93. {ready && <NavBar />}
  94. <main className="main-view">
  95. {pageBanners.map((Banner, index) => (
  96. <Banner key={index.toString()} />
  97. ))}
  98. <AngularRoot />
  99. <AppNotificationList />
  100. <SearchWrapper />
  101. {ready && this.renderRoutes()}
  102. {bodyRenderHooks.map((Hook, index) => (
  103. <Hook key={index.toString()} />
  104. ))}
  105. </main>
  106. </Router>
  107. </div>
  108. <LiveConnectionWarning />
  109. <ModalRoot />
  110. <PortalContainer />
  111. </ModalsProvider>
  112. </KBarProvider>
  113. </ThemeProvider>
  114. </ConfigContext.Provider>
  115. </ErrorBoundaryAlert>
  116. </I18nProvider>
  117. </Provider>
  118. );
  119. }
  120. }