DashboardScene: Support custom actions in the nav toolbar (#79139)
* DashbaordScene: Support custom nav toolbar actions * Move custom actions to scenes feature dir * Review * betterrerererererer
This commit is contained in:
@@ -6,9 +6,11 @@ import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
|
||||
import { NavToolbarSeparator } from 'app/core/components/AppChrome/NavToolbar/NavToolbarSeparator';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { DashNavButton } from 'app/features/dashboard/components/DashNav/DashNavButton';
|
||||
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||
|
||||
import { ShareModal } from '../sharing/ShareModal';
|
||||
import { DashboardInteractions } from '../utils/interactions';
|
||||
import { dynamicDashNavActions } from '../utils/registerDynamicDashNavAction';
|
||||
|
||||
import { DashboardScene } from './DashboardScene';
|
||||
|
||||
@@ -19,6 +21,8 @@ interface Props {
|
||||
export const NavToolbarActions = React.memo<Props>(({ dashboard }) => {
|
||||
const { actions = [], isEditing, viewPanelScene, isDirty, uid, meta, editview } = dashboard.useState();
|
||||
const toolbarActions = (actions ?? []).map((action) => <action.Component key={action.state.key} model={action} />);
|
||||
const rightToolbarActions: JSX.Element[] = [];
|
||||
const _legacyDashboardModel = getDashboardSrv().getCurrent();
|
||||
|
||||
if (uid && !editview) {
|
||||
if (meta.canStar) {
|
||||
@@ -61,10 +65,31 @@ export const NavToolbarActions = React.memo<Props>(({ dashboard }) => {
|
||||
onClick={() => locationService.push(`/d/${uid}`)}
|
||||
/>
|
||||
);
|
||||
if (dynamicDashNavActions.left.length > 0) {
|
||||
dynamicDashNavActions.left.map((action, index) => {
|
||||
const Component = action.component;
|
||||
const element = <Component dashboard={_legacyDashboardModel} />;
|
||||
typeof action.index === 'number'
|
||||
? toolbarActions.splice(action.index, 0, element)
|
||||
: toolbarActions.push(element);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
toolbarActions.push(<NavToolbarSeparator leftActionsSeparator key="separator" />);
|
||||
|
||||
if (dynamicDashNavActions.right.length > 0) {
|
||||
dynamicDashNavActions.right.map((action, index) => {
|
||||
const Component = action.component;
|
||||
const element = <Component dashboard={_legacyDashboardModel} key={`button-custom-${index}`} />;
|
||||
typeof action.index === 'number'
|
||||
? rightToolbarActions.splice(action.index, 0, element)
|
||||
: rightToolbarActions.push(element);
|
||||
});
|
||||
|
||||
toolbarActions.push(...rightToolbarActions);
|
||||
}
|
||||
|
||||
if (viewPanelScene) {
|
||||
toolbarActions.push(
|
||||
<Button
|
||||
|
||||
+10
-1
@@ -7,6 +7,7 @@ import {
|
||||
SceneQueryRunner,
|
||||
SceneTimeRange,
|
||||
VizPanel,
|
||||
SceneTimePicker,
|
||||
} from '@grafana/scenes';
|
||||
import { DashboardCursorSync } from '@grafana/schema';
|
||||
|
||||
@@ -18,7 +19,7 @@ import { DashboardModelCompatibilityWrapper } from './DashboardModelCompatibilit
|
||||
|
||||
describe('DashboardModelCompatibilityWrapper', () => {
|
||||
it('Provide basic prop and function of compatability', () => {
|
||||
const { wrapper } = setup();
|
||||
const { wrapper, scene } = setup();
|
||||
|
||||
expect(wrapper.uid).toBe('dash-1');
|
||||
expect(wrapper.title).toBe('hello');
|
||||
@@ -30,6 +31,14 @@ describe('DashboardModelCompatibilityWrapper', () => {
|
||||
expect(wrapper.timezone).toBe('America/New_York');
|
||||
expect(wrapper.weekStart).toBe('friday');
|
||||
expect(wrapper.timepicker.refresh_intervals).toEqual(['1s']);
|
||||
expect(wrapper.timepicker.hidden).toEqual(true);
|
||||
|
||||
(scene.state.controls![0] as DashboardControls).setState({
|
||||
timeControls: [new SceneTimePicker({})],
|
||||
});
|
||||
|
||||
const wrapper2 = new DashboardModelCompatibilityWrapper(scene);
|
||||
expect(wrapper2.timepicker.hidden).toEqual(false);
|
||||
});
|
||||
|
||||
it('Shared tooltip functions', () => {
|
||||
|
||||
@@ -63,6 +63,7 @@ export class DashboardModelCompatibilityWrapper {
|
||||
public get timepicker() {
|
||||
return {
|
||||
refresh_intervals: dashboardSceneGraph.getRefreshPicker(this._scene)?.state.intervals,
|
||||
hidden: !Boolean(dashboardSceneGraph.getTimePicker(this._scene)),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
|
||||
import { DashboardModel } from '../../dashboard/state';
|
||||
|
||||
interface ComponentProps {
|
||||
dashboard: DashboardModel;
|
||||
}
|
||||
export interface DynamicDashNavButtonModel {
|
||||
show: (props: ComponentProps) => boolean;
|
||||
component: React.FC<Partial<ComponentProps>>;
|
||||
index?: number | 'end';
|
||||
}
|
||||
|
||||
export const dynamicDashNavActions: { left: DynamicDashNavButtonModel[]; right: DynamicDashNavButtonModel[] } = {
|
||||
left: [],
|
||||
right: [],
|
||||
};
|
||||
|
||||
export function registerDynamicDashNavAction(side: 'left' | 'right', action: DynamicDashNavButtonModel) {
|
||||
dynamicDashNavActions[side].push(action);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React, { FC, ReactNode } from 'react';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
@@ -33,6 +33,12 @@ import { updateTimeZoneForSession } from 'app/features/profile/state/reducers';
|
||||
import { KioskMode } from 'app/types';
|
||||
import { DashboardMetaChangedEvent, ShowModalReactEvent } from 'app/types/events';
|
||||
|
||||
import {
|
||||
DynamicDashNavButtonModel,
|
||||
dynamicDashNavActions,
|
||||
registerDynamicDashNavAction,
|
||||
} from '../../../dashboard-scene/utils/registerDynamicDashNavAction';
|
||||
|
||||
import { DashNavButton } from './DashNavButton';
|
||||
import { DashNavTimeControls } from './DashNavTimeControls';
|
||||
import { ShareButton } from './ShareButton';
|
||||
@@ -56,21 +62,12 @@ export interface OwnProps {
|
||||
onAddPanel: () => void;
|
||||
}
|
||||
|
||||
interface DashNavButtonModel {
|
||||
show: (props: Props) => boolean;
|
||||
component: FC<Partial<Props>>;
|
||||
index?: number | 'end';
|
||||
export function addCustomLeftAction(content: DynamicDashNavButtonModel) {
|
||||
registerDynamicDashNavAction('left', content);
|
||||
}
|
||||
|
||||
const customLeftActions: DashNavButtonModel[] = [];
|
||||
const customRightActions: DashNavButtonModel[] = [];
|
||||
|
||||
export function addCustomLeftAction(content: DashNavButtonModel) {
|
||||
customLeftActions.push(content);
|
||||
}
|
||||
|
||||
export function addCustomRightAction(content: DashNavButtonModel) {
|
||||
customRightActions.push(content);
|
||||
export function addCustomRightAction(content: DynamicDashNavButtonModel) {
|
||||
registerDynamicDashNavAction('right', content);
|
||||
}
|
||||
|
||||
type Props = OwnProps & ConnectedProps<typeof connector>;
|
||||
@@ -152,7 +149,7 @@ export const DashNav = React.memo<Props>((props) => {
|
||||
forceUpdate();
|
||||
};
|
||||
|
||||
const addCustomContent = (actions: DashNavButtonModel[], buttons: ReactNode[]) => {
|
||||
const addCustomContent = (actions: DynamicDashNavButtonModel[], buttons: ReactNode[]) => {
|
||||
actions.map((action, index) => {
|
||||
const Component = action.component;
|
||||
const element = <Component {...props} key={`button-custom-${index}`} />;
|
||||
@@ -213,7 +210,7 @@ export const DashNav = React.memo<Props>((props) => {
|
||||
);
|
||||
}
|
||||
|
||||
addCustomContent(customLeftActions, buttons);
|
||||
addCustomContent(dynamicDashNavActions.left, buttons);
|
||||
return buttons;
|
||||
};
|
||||
|
||||
@@ -336,7 +333,7 @@ export const DashNav = React.memo<Props>((props) => {
|
||||
);
|
||||
}
|
||||
|
||||
addCustomContent(customRightActions, buttons);
|
||||
addCustomContent(dynamicDashNavActions.right, buttons);
|
||||
|
||||
buttons.push(renderTimeControls());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user