mirror of
https://github.com/grafana/grafana.git
synced 2025-02-16 18:34:52 -06:00
* add isPublic to dashboard * refactor routes to use route group and add placeholder method for sharing apii * add sharing pane and utils for public dashboard config to sharing modal * Sharing modal now persists data through the api * moves ShareDashboard endpoint to new file and starts adding tests * generates mocks. Adds tests for public dashboard feature flag * Adds ability to pass in array of features to enable for the test * test to update public flag on dashboard WIP * Adds mock for SaveDashboardSharingConfig * Fixes tests. Had to use FakeDashboardService * Adds React tests for public dashboards toggle * removes semicolons * refactors SharePublic component to use hooks * rename from `share publicly` to `public dashboard config` * checkpoint. debugging tests. need to verify name changes * checkpoint. test bugs fixed. need to finish returning proper response codes * finish renaming. fix test * Update pkg/api/api.go Co-authored-by: Torkel Ödegaard <torkel@grafana.com> * update backend url * rename internal objects and commands. fix configuration modal labels * add endpoint for retrieving public dashboard configuration and populate the frontend state from it * add test for dashboardCanBePublic * adds backend routes * copy DashboardPage component into component for public dashboards. WIP * adds react routes, and doesnt render main nav bar when viewing a public route * removes extra react route from testing * updates component name * Wrap the original dashboard component so we can pass props relevant to public dashboards, turn kiosk mode on/off, etc * Wraps DashboardPage in PublicDashboardPage component. DashboardPage gets rendered in kiosk mode when public prop is passed. * removes commented out code from exploratory work * Makes public dashboard routes require no auth * extracts helper to own util file to check if were viewing a public page * Hides panel dropdown when its being viewed publicly * formatting * use function from utils file for determining if publicly viewed. If public, hides app notifications, searchwrapper, and commandpalette. * adds unit tests for util function used to see if page is being viewed publicly * cant added annotations to panel when being publicly viewed * removes useless comment * hides backend and frontend pubdash routes behind feature flag * consider feature flag when checking url path to see if on public dashboard * renames function * still render app notifications when in public view * Extract pubdash route logic into own file * fixes failing tests * Determines path using location locationUtils. This covers the case when grafana is being hosted on a subpath. Updates tests. * renames pubdash web route to be more understandable * rename route * fixes failing test * fixes failing test. Needed to update pubdash urls * sets flag on grafana boot config for if viewing public dashboard. Removes hacky check that looks at the url * fixes failing tests. Uses config to determine if viewing public dashboard * renders the blue panel timeInfo on public dashboard panel * Extracts conditional logic for rendering components out into their own functions * removes publicDashboardView check, and uses dashboard meta instead * the timeInfo is always displayed on the panel * After fetch of public dashboard dto, the meta isPublic flag gets set and used to determine if viewing public dashboard for child components. Fixes tests for PanelHeader. * Fixes failing test. Needed to add isPublic flag to dashboard meta. Co-authored-by: Jeff Levin <jeff@levinology.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
150 lines
5.1 KiB
TypeScript
150 lines
5.1 KiB
TypeScript
import { Action, KBarProvider } from 'kbar';
|
|
import React, { ComponentType } from 'react';
|
|
import { Provider } from 'react-redux';
|
|
import { Router, Route, Redirect, Switch } from 'react-router-dom';
|
|
|
|
import { config, locationService, navigationLogger, reportInteraction } from '@grafana/runtime';
|
|
import { ErrorBoundaryAlert, GlobalStyles, ModalRoot, ModalsProvider, PortalContainer } from '@grafana/ui';
|
|
import { SearchWrapper } from 'app/features/search';
|
|
import { getAppRoutes } from 'app/routes/routes';
|
|
import { store } from 'app/store/store';
|
|
|
|
import { AngularRoot } from './angular/AngularRoot';
|
|
import { loadAndInitAngularIfEnabled } from './angular/loadAndInitAngularIfEnabled';
|
|
import { GrafanaApp } from './app';
|
|
import { AppNotificationList } from './core/components/AppNotifications/AppNotificationList';
|
|
import { NavBar } from './core/components/NavBar/NavBar';
|
|
import { NavBarNext } from './core/components/NavBar/Next/NavBarNext';
|
|
import { I18nProvider } from './core/localisation';
|
|
import { GrafanaRoute } from './core/navigation/GrafanaRoute';
|
|
import { RouteDescriptor } from './core/navigation/types';
|
|
import { contextSrv } from './core/services/context_srv';
|
|
import { ConfigContext, ThemeProvider } from './core/utils/ConfigProvider';
|
|
import { CommandPalette } from './features/commandPalette/CommandPalette';
|
|
import { LiveConnectionWarning } from './features/live/LiveConnectionWarning';
|
|
|
|
interface AppWrapperProps {
|
|
app: GrafanaApp;
|
|
}
|
|
|
|
interface AppWrapperState {
|
|
ready?: boolean;
|
|
}
|
|
|
|
/** Used by enterprise */
|
|
let bodyRenderHooks: ComponentType[] = [];
|
|
let pageBanners: ComponentType[] = [];
|
|
|
|
export function addBodyRenderHook(fn: ComponentType) {
|
|
bodyRenderHooks.push(fn);
|
|
}
|
|
|
|
export function addPageBanner(fn: ComponentType) {
|
|
pageBanners.push(fn);
|
|
}
|
|
|
|
export class AppWrapper extends React.Component<AppWrapperProps, AppWrapperState> {
|
|
constructor(props: AppWrapperProps) {
|
|
super(props);
|
|
this.state = {};
|
|
}
|
|
|
|
async componentDidMount() {
|
|
await loadAndInitAngularIfEnabled();
|
|
this.setState({ ready: true });
|
|
$('.preloader').remove();
|
|
}
|
|
|
|
renderRoute = (route: RouteDescriptor) => {
|
|
const roles = route.roles ? route.roles() : [];
|
|
|
|
return (
|
|
<Route
|
|
exact={route.exact === undefined ? true : route.exact}
|
|
path={route.path}
|
|
key={route.path}
|
|
render={(props) => {
|
|
navigationLogger('AppWrapper', false, 'Rendering route', route, 'with match', props.location);
|
|
// TODO[Router]: test this logic
|
|
if (roles?.length) {
|
|
if (!roles.some((r: string) => contextSrv.hasRole(r))) {
|
|
return <Redirect to="/" />;
|
|
}
|
|
}
|
|
|
|
return <GrafanaRoute {...props} route={route} />;
|
|
}}
|
|
/>
|
|
);
|
|
};
|
|
|
|
renderRoutes() {
|
|
return <Switch>{getAppRoutes().map((r) => this.renderRoute(r))}</Switch>;
|
|
}
|
|
|
|
render() {
|
|
const { ready } = this.state;
|
|
|
|
navigationLogger('AppWrapper', false, 'rendering');
|
|
|
|
const newNavigationEnabled = Boolean(config.featureToggles.newNavigation);
|
|
|
|
const commandPaletteActionSelected = (action: Action) => {
|
|
reportInteraction('commandPalette_action_selected', {
|
|
actionId: action.id,
|
|
});
|
|
};
|
|
|
|
const commandPaletteEnabled = () => !config.isPublicDashboardView && config.featureToggles.commandPalette;
|
|
|
|
const renderNavBar = () => {
|
|
return !config.isPublicDashboardView && ready && <>{newNavigationEnabled ? <NavBarNext /> : <NavBar />}</>;
|
|
};
|
|
|
|
const searchBarEnabled = () => !config.isPublicDashboardView;
|
|
|
|
return (
|
|
<Provider store={store}>
|
|
<I18nProvider>
|
|
<ErrorBoundaryAlert style="page">
|
|
<ConfigContext.Provider value={config}>
|
|
<ThemeProvider>
|
|
<KBarProvider
|
|
actions={[]}
|
|
options={{ enableHistory: true, callbacks: { onSelectAction: commandPaletteActionSelected } }}
|
|
>
|
|
<ModalsProvider>
|
|
<GlobalStyles />
|
|
{commandPaletteEnabled() && <CommandPalette />}
|
|
<div className="grafana-app">
|
|
<Router history={locationService.getHistory()}>
|
|
{renderNavBar()}
|
|
<main className="main-view">
|
|
{pageBanners.map((Banner, index) => (
|
|
<Banner key={index.toString()} />
|
|
))}
|
|
|
|
<AngularRoot />
|
|
<AppNotificationList />
|
|
{searchBarEnabled() && <SearchWrapper />}
|
|
{ready && this.renderRoutes()}
|
|
{bodyRenderHooks.map((Hook, index) => (
|
|
<Hook key={index.toString()} />
|
|
))}
|
|
</main>
|
|
</Router>
|
|
</div>
|
|
<LiveConnectionWarning />
|
|
<ModalRoot />
|
|
<PortalContainer />
|
|
</ModalsProvider>
|
|
</KBarProvider>
|
|
</ThemeProvider>
|
|
</ConfigContext.Provider>
|
|
</ErrorBoundaryAlert>
|
|
</I18nProvider>
|
|
</Provider>
|
|
);
|
|
}
|
|
}
|