PublicDashboards: Tag is rerendered when dashboard meta changes in state (#55414)

Can update dashboard meta state using dashboard events.
This commit is contained in:
owensmallwood 2022-09-20 10:42:57 -06:00 committed by GitHub
parent 862a6a2fa6
commit aae2c3c4f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 99 additions and 8 deletions

View File

@ -0,0 +1,17 @@
import { useEffect, useState } from 'react';
import { BusEvent, BusEventType, EventBus } from '@grafana/data';
/**
A bit more efficient than using useObservable(eventBus.getStream(MyEventType)) as that will create a new Observable and subscription every render
*/
export function useBusEvent<T extends BusEvent>(eventBus: EventBus, eventType: BusEventType<T>): T | undefined {
const [event, setEvent] = useState<T | undefined>();
useEffect(() => {
const sub = eventBus.subscribe(eventType, setEvent);
return () => sub.unsubscribe();
}, [eventBus, eventType]);
return event;
}

View File

@ -0,0 +1,54 @@
import { act, render, screen, waitFor } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { locationService } from '@grafana/runtime/src';
import { GrafanaContext } from 'app/core/context/GrafanaContext';
import { getGrafanaContextMock } from '../../../../../test/mocks/getGrafanaContextMock';
import { setStarred } from '../../../../core/reducers/navBarTree';
import { configureStore } from '../../../../store/configureStore';
import { updateTimeZoneForSession } from '../../../profile/state/reducers';
import { DashboardModel } from '../../state';
import { DashNav } from './DashNav';
describe('Public dashboard title tag', () => {
it('will be rendered when publicDashboardEnabled set to true in dashboard meta', async () => {
let dashboard = new DashboardModel({}, { publicDashboardEnabled: false });
const store = configureStore();
const context = getGrafanaContextMock();
const props = {
setStarred: jest.fn() as unknown as typeof setStarred,
updateTimeZoneForSession: jest.fn() as unknown as typeof updateTimeZoneForSession,
};
render(
<Provider store={store}>
<GrafanaContext.Provider value={context}>
<Router history={locationService.getHistory()}>
<DashNav
{...props}
dashboard={dashboard}
hideTimePicker={true}
isFullscreen={false}
onAddPanel={() => {}}
title="test"
/>
</Router>
</GrafanaContext.Provider>
</Provider>
);
const publicTag = screen.queryByText('Public');
expect(publicTag).not.toBeInTheDocument();
act(() => {
dashboard.updateMeta({ publicDashboardEnabled: true });
});
await waitFor(() => screen.getByText('Public'));
});
});

View File

@ -19,12 +19,14 @@ import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
import { NavToolbarSeparator } from 'app/core/components/AppChrome/NavToolbarSeparator';
import config from 'app/core/config';
import { useGrafana } from 'app/core/context/GrafanaContext';
import { useBusEvent } from 'app/core/hooks/useBusEvent';
import { DashboardCommentsModal } from 'app/features/dashboard/components/DashboardComments/DashboardCommentsModal';
import { SaveDashboardDrawer } from 'app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer';
import { ShareModal } from 'app/features/dashboard/components/ShareModal';
import { playlistSrv } from 'app/features/playlist/PlaylistSrv';
import { updateTimeZoneForSession } from 'app/features/profile/state/reducers';
import { KioskMode } from 'app/types';
import { DashboardMetaChangedEvent } from 'app/types/events';
import { setStarred } from '../../../../core/reducers/navBarTree';
import { getDashboardSrv } from '../../services/DashboardSrv';
@ -75,6 +77,9 @@ export const DashNav = React.memo<Props>((props) => {
const forceUpdate = useForceUpdate();
const { chrome } = useGrafana();
// We don't really care about the event payload here only that it triggeres a re-render of this component
useBusEvent(props.dashboard.events, DashboardMetaChangedEvent);
const onStarDashboard = () => {
const dashboardSrv = getDashboardSrv();
const { dashboard, setStarred } = props;

View File

@ -119,6 +119,7 @@ describe('SharePublic', () => {
await screen.findByText('Welcome to Grafana public dashboards alpha!');
expect(screen.getByText('Last 6 hours')).toBeInTheDocument();
});
it('renders default absolute time in input 2', async () => {
config.featureToggles.publicDashboards = true;
const mockDashboard = new DashboardModel({

View File

@ -65,10 +65,7 @@ export const SharePublicDashboard = (props: Props) => {
usage: false,
});
const timeRange = getTimeRange(
{ from: props.dashboard.getDefaultTime().from, to: props.dashboard.getDefaultTime().to },
props.dashboard.timezone
);
const timeRange = getTimeRange(props.dashboard.getDefaultTime(), props.dashboard);
useEffect(() => {
reportInteraction('grafana_dashboards_public_share_viewed');
@ -96,7 +93,7 @@ export const SharePublicDashboard = (props: Props) => {
return;
}
savePublicDashboardConfig(props.dashboard.uid, publicDashboard, setPublicDashboardConfig).catch();
savePublicDashboardConfig(props.dashboard, publicDashboard, setPublicDashboardConfig).catch();
};
const onAcknowledge = useCallback(

View File

@ -6,6 +6,8 @@ import { VariableModel } from 'app/features/variables/types';
import { dispatch } from 'app/store/store';
import { DashboardDataDTO, DashboardMeta } from 'app/types/dashboard';
import { DashboardModel } from '../../state';
export interface PublicDashboard {
accessToken?: string;
isEnabled: boolean;
@ -28,12 +30,12 @@ export const getPublicDashboardConfig = async (
};
export const savePublicDashboardConfig = async (
dashboardUid: string,
dashboard: DashboardModel,
publicDashboardConfig: PublicDashboard,
setPublicDashboard: React.Dispatch<React.SetStateAction<PublicDashboard>>
) => {
const pdResp: PublicDashboard = await getBackendSrv().post(
savePublicDashboardConfigUrl(dashboardUid),
savePublicDashboardConfigUrl(dashboard.uid),
publicDashboardConfig
);
@ -43,6 +45,12 @@ export const savePublicDashboardConfig = async (
dispatch(notifyApp(createSuccessNotification('Dashboard sharing configuration saved')));
setPublicDashboard(pdResp);
// Update runtime emta flag
dashboard.updateMeta({
publicDashboardUid: pdResp.uid,
publicDashboardEnabled: publicDashboardConfig.isEnabled,
});
};
export const getPublicDashboardConfigUrl = (dashboardUid: string) => {

View File

@ -25,7 +25,7 @@ import { variableAdapters } from 'app/features/variables/adapters';
import { onTimeRangeUpdated } from 'app/features/variables/state/actions';
import { GetVariables, getVariablesByKey } from 'app/features/variables/state/selectors';
import { CoreEvents, DashboardMeta, KioskMode } from 'app/types';
import { DashboardPanelsChangedEvent, RenderEvent } from 'app/types/events';
import { DashboardMetaChangedEvent, DashboardPanelsChangedEvent, RenderEvent } from 'app/types/events';
import { appEvents } from '../../../core/core';
import { dispatch } from '../../../store/store';
@ -480,6 +480,11 @@ export class DashboardModel implements TimeModel {
this.events.publish(new DashboardPanelsChangedEvent());
}
updateMeta(updates: Partial<DashboardMeta>) {
this.meta = { ...this.meta, ...updates };
this.events.publish(new DashboardMetaChangedEvent());
}
sortPanelsByGridPos() {
this.panels.sort((panelA, panelB) => {
if (panelA.gridPos.y === panelB.gridPos.y) {

View File

@ -124,6 +124,10 @@ export class DashboardPanelsChangedEvent extends BusEventBase {
static type = 'dashboard-panels-changed';
}
export class DashboardMetaChangedEvent extends BusEventBase {
static type = 'dashboard-meta-changed';
}
export class PanelDirectiveReadyEvent extends BusEventBase {
static type = 'panel-directive-ready';
}