Dashboard-Scene: Show empty state after removing last panel (#83114)
* Show empty state after removing last panel * betterer * Refactor isEmpty state update in DashboardScene.tsx * don't need viewPanelScene check * track isEmpty through a behavior * Fix test * Add test for empty state * minor fix * Refactor isEmpty check * Don't use const * clean up
This commit is contained in:
@@ -194,6 +194,13 @@ describe('DashboardScenePage', () => {
|
||||
expect(screen.queryByTitle('Panel A')).not.toBeInTheDocument();
|
||||
expect(await screen.findByTitle('Panel B')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Shows empty state when dashboard is empty', async () => {
|
||||
loadDashboardMock.mockResolvedValue({ dashboard: { panels: [] }, meta: {} });
|
||||
setup();
|
||||
|
||||
expect(await screen.findByText('Start your new dashboard by adding a visualization')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
interface VizOptions {
|
||||
|
||||
@@ -94,6 +94,7 @@ export interface DashboardSceneState extends SceneObjectState {
|
||||
editPanel?: PanelEditor;
|
||||
/** Scene object that handles the current drawer or modal */
|
||||
overlay?: SceneObject;
|
||||
isEmpty?: boolean;
|
||||
}
|
||||
|
||||
export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
|
||||
@@ -522,20 +523,6 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
|
||||
locationService.partial({ editview: 'settings' });
|
||||
};
|
||||
|
||||
public isEmpty = (): boolean => {
|
||||
const { body, viewPanelScene } = this.state;
|
||||
|
||||
if (!!viewPanelScene) {
|
||||
return !!viewPanelScene.state.body;
|
||||
}
|
||||
|
||||
if (body instanceof SceneFlexLayout || body instanceof SceneGridLayout) {
|
||||
return body.state.children.length === 0;
|
||||
}
|
||||
|
||||
throw new Error('Invalid body type');
|
||||
};
|
||||
|
||||
/**
|
||||
* Called by the SceneQueryRunner to privide contextural parameters (tracking) props for the request
|
||||
*/
|
||||
|
||||
@@ -14,7 +14,7 @@ import { DashboardScene } from './DashboardScene';
|
||||
import { NavToolbarActions } from './NavToolbarActions';
|
||||
|
||||
export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardScene>) {
|
||||
const { controls, overlay, editview, editPanel } = model.useState();
|
||||
const { controls, overlay, editview, editPanel, isEmpty } = model.useState();
|
||||
const styles = useStyles2(getStyles);
|
||||
const location = useLocation();
|
||||
const navIndex = useSelector((state) => state.navIndex);
|
||||
@@ -34,12 +34,9 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
|
||||
const emptyState = <DashboardEmpty dashboard={model} canCreate={!!model.state.meta.canEdit} />;
|
||||
|
||||
const withPanels = (
|
||||
<>
|
||||
{controls && <controls.Component model={controls} />}
|
||||
<div className={cx(styles.body)}>
|
||||
<bodyToRender.Component model={bodyToRender} />
|
||||
</div>
|
||||
</>
|
||||
<div className={cx(styles.body)}>
|
||||
<bodyToRender.Component model={bodyToRender} />
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -49,7 +46,8 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
|
||||
<CustomScrollbar autoHeightMin={'100%'}>
|
||||
<div className={styles.canvasContent}>
|
||||
<NavToolbarActions dashboard={model} />
|
||||
{model.isEmpty() ? emptyState : withPanels}
|
||||
{controls && <controls.Component model={controls} />}
|
||||
{isEmpty ? emptyState : withPanels}
|
||||
</div>
|
||||
</CustomScrollbar>
|
||||
)}
|
||||
|
||||
@@ -417,9 +417,7 @@ export function removePanel(dashboard: DashboardScene, panel: VizPanel, ask: boo
|
||||
const layout = dashboard.state.body;
|
||||
|
||||
if (layout instanceof SceneGridLayout || SceneFlexLayout) {
|
||||
layout.setState({
|
||||
children: panels,
|
||||
});
|
||||
layout.setState({ children: panels });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ describe('transformSaveModelToScene', () => {
|
||||
|
||||
const scene = createDashboardSceneFromDashboardModel(oldModel);
|
||||
|
||||
expect(scene.state.$behaviors).toHaveLength(5);
|
||||
expect(scene.state.$behaviors).toHaveLength(6);
|
||||
expect(scene.state.$behaviors![0]).toBeInstanceOf(behaviors.CursorSync);
|
||||
expect((scene.state.$behaviors![0] as behaviors.CursorSync).state.sync).toEqual(DashboardCursorSync.Crosshair);
|
||||
});
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
UserActionEvent,
|
||||
GroupByVariable,
|
||||
AdHocFiltersVariable,
|
||||
SceneFlexLayout,
|
||||
} from '@grafana/scenes';
|
||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||
import { trackDashboardLoaded } from 'app/features/dashboard/utils/tracking';
|
||||
@@ -266,6 +267,7 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel)
|
||||
registerDashboardMacro,
|
||||
registerDashboardSceneTracking(oldModel),
|
||||
registerPanelInteractionsReporter,
|
||||
trackIfIsEmpty,
|
||||
],
|
||||
$data:
|
||||
layers.length > 0
|
||||
@@ -535,6 +537,21 @@ function registerPanelInteractionsReporter(scene: DashboardScene) {
|
||||
});
|
||||
}
|
||||
|
||||
export function trackIfIsEmpty(parent: DashboardScene) {
|
||||
updateIsEmpty(parent);
|
||||
|
||||
parent.state.body.subscribeToState(() => {
|
||||
updateIsEmpty(parent);
|
||||
});
|
||||
}
|
||||
|
||||
function updateIsEmpty(parent: DashboardScene) {
|
||||
const { body } = parent.state;
|
||||
if (body instanceof SceneFlexLayout || body instanceof SceneGridLayout) {
|
||||
parent.setState({ isEmpty: body.state.children.length === 0 });
|
||||
}
|
||||
}
|
||||
|
||||
const convertSnapshotData = (snapshotData: DataFrameDTO[]): DataFrameJSON[] => {
|
||||
return snapshotData.map((data) => {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user