Skip to content

Commit 6dd9814

Browse files
authored
fix: Load default dashboard data from workspace data (#1810)
- Until we have support for #1746 , load the default dashboard data from workspace - Needed for testing the widget hydration PR - Tested with my changes for widget hydration - Ensured deephaven.ui widgets re-opened upon refresh - Ensured links remained between existing tables
1 parent 67de0e0 commit 6dd9814

6 files changed

Lines changed: 86 additions & 28 deletions

File tree

packages/code-studio/src/main/AppMainContainer.tsx

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
PanelEvent,
4040
setDashboardData as setDashboardDataAction,
4141
setDashboardPluginData as setDashboardPluginDataAction,
42+
stopListenForCreateDashboard,
4243
updateDashboardData as updateDashboardDataAction,
4344
} from '@deephaven/dashboard';
4445
import {
@@ -203,6 +204,8 @@ export class AppMainContainer extends Component<
203204

204205
const { allDashboardData } = this.props;
205206

207+
this.dashboardLayouts = new Map();
208+
206209
this.state = {
207210
contextActions: [
208211
{
@@ -261,6 +264,7 @@ export class AppMainContainer extends Component<
261264

262265
componentDidMount(): void {
263266
this.initWidgets();
267+
this.initDashboardData();
264268
this.startListeningForDisconnect();
265269

266270
window.addEventListener(
@@ -283,13 +287,18 @@ export class AppMainContainer extends Component<
283287
this.deinitWidgets();
284288
this.stopListeningForDisconnect();
285289

290+
this.dashboardLayouts.forEach(layout => {
291+
stopListenForCreateDashboard(layout.eventHub, this.handleCreateDashboard);
292+
});
293+
286294
window.removeEventListener(
287295
'beforeunload',
288296
AppMainContainer.handleWindowBeforeUnload
289297
);
290298
}
291299

292-
goldenLayout?: GoldenLayout;
300+
/** Map from the dashboard ID to the GoldenLayout instance for that dashboard */
301+
dashboardLayouts: Map<string, GoldenLayout>;
293302

294303
importElement: RefObject<HTMLInputElement>;
295304

@@ -337,6 +346,28 @@ export class AppMainContainer extends Component<
337346
this.widgetListenerRemover?.();
338347
}
339348

349+
initDashboardData(): void {
350+
// TODO: #1746 We should be loading data from a dashboard storage store
351+
// For now only the default dashboard data is stored with the workspace and set on the default dashboard
352+
const { setDashboardPluginData, updateDashboardData, workspace } =
353+
this.props;
354+
const { data: workspaceData } = workspace;
355+
const { filterSets, links, pluginDataMap } = workspaceData;
356+
updateDashboardData(DEFAULT_DASHBOARD_ID, {
357+
filterSets,
358+
links,
359+
});
360+
if (pluginDataMap != null) {
361+
const pluginKeys = Object.keys(pluginDataMap);
362+
for (let i = 0; i < pluginKeys.length; i += 1) {
363+
const pluginId = pluginKeys[i];
364+
const pluginData = pluginDataMap[pluginId];
365+
log.debug('initDashboardData plugin data', pluginId, pluginData);
366+
setDashboardPluginData(DEFAULT_DASHBOARD_ID, pluginId, pluginData);
367+
}
368+
}
369+
}
370+
340371
openNotebookFromURL(): void {
341372
const { match } = this.props;
342373
const { notebookPath } = match.params;
@@ -374,7 +405,9 @@ export class AppMainContainer extends Component<
374405
}
375406

376407
emitLayoutEvent(event: string, ...args: unknown[]): void {
377-
this.goldenLayout?.eventHub.emit(event, ...args);
408+
const { activeTabKey } = this.state;
409+
const layout = this.dashboardLayouts.get(activeTabKey);
410+
layout?.eventHub.emit(event, ...args);
378411
}
379412

380413
handleCancelResetLayoutPrompt(): void {
@@ -465,16 +498,25 @@ export class AppMainContainer extends Component<
465498
const { updateWorkspaceData } = this.props;
466499

467500
// Only save the data that is serializable/we want to persist to the workspace
468-
const { closed, filterSets, links } = data;
469-
updateWorkspaceData({ closed, filterSets, links });
501+
const { closed, filterSets, links, pluginDataMap } = data;
502+
updateWorkspaceData({ closed, filterSets, links, pluginDataMap });
470503
}
471504

472-
handleGoldenLayoutChange(goldenLayout: GoldenLayout): void {
473-
this.goldenLayout = goldenLayout;
474-
listenForCreateDashboard(
475-
this.goldenLayout.eventHub,
476-
this.handleCreateDashboard
477-
);
505+
handleGoldenLayoutChange(newLayout: GoldenLayout): void {
506+
const { activeTabKey } = this.state;
507+
const oldLayout = this.dashboardLayouts.get(activeTabKey);
508+
if (oldLayout === newLayout) return;
509+
510+
if (oldLayout != null) {
511+
stopListenForCreateDashboard(
512+
oldLayout.eventHub,
513+
this.handleCreateDashboard
514+
);
515+
}
516+
517+
this.dashboardLayouts.set(activeTabKey, newLayout);
518+
519+
listenForCreateDashboard(newLayout.eventHub, this.handleCreateDashboard);
478520
}
479521

480522
handleCreateDashboard({

packages/code-studio/src/storage/LocalWorkspaceStorage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ export class LocalWorkspaceStorage implements WorkspaceStorage {
137137
closed: [{}],
138138
links,
139139
filterSets,
140+
pluginDataMap: {},
140141
};
141142
}
142143

packages/dashboard/src/DashboardEvents.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,30 @@ import type { EventHub } from '@deephaven/golden-layout';
22

33
export const CREATE_DASHBOARD = 'CREATE_DASHBOARD';
44

5-
export interface CreateDashboardPayload {
5+
export interface CreateDashboardPayload<T = unknown> {
66
pluginId: string;
77
title: string;
8-
data: unknown;
8+
data: T;
99
}
1010

11-
export function listenForCreateDashboard(
11+
export function stopListenForCreateDashboard<T = unknown>(
1212
eventHub: EventHub,
13-
handler: (p: CreateDashboardPayload) => void
13+
handler: (p: CreateDashboardPayload<T>) => void
1414
): void {
15+
eventHub.off(CREATE_DASHBOARD, handler);
16+
}
17+
18+
export function listenForCreateDashboard<T = unknown>(
19+
eventHub: EventHub,
20+
handler: (p: CreateDashboardPayload<T>) => void
21+
): () => void {
1522
eventHub.on(CREATE_DASHBOARD, handler);
23+
return () => stopListenForCreateDashboard(eventHub, handler);
1624
}
1725

18-
export function emitCreateDashboard(
26+
export function emitCreateDashboard<T = unknown>(
1927
eventHub: EventHub,
20-
payload: CreateDashboardPayload
28+
payload: CreateDashboardPayload<T>
2129
): void {
2230
eventHub.emit(CREATE_DASHBOARD, payload);
2331
}

packages/dashboard/src/redux/hooks.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,17 @@ import { setDashboardPluginData } from './actions';
1010
* @param pluginId - The ID of the plugin.
1111
* @returns A tuple containing the plugin data and a function to update the plugin data.
1212
*/
13-
export function useDashboardPluginData(
13+
export function useDashboardPluginData<T = PluginData>(
1414
dashboardId: string,
1515
pluginId: string
16-
): [PluginData, (data: PluginData) => void] {
16+
): [T, (data: T) => void] {
1717
const dispatch = useDispatch();
1818
const data = useSelector((store: RootState) =>
19-
getPluginDataForDashboard(store, dashboardId, pluginId)
19+
getPluginDataForDashboard<T>(store, dashboardId, pluginId)
2020
);
2121
const setData = useCallback(
22-
newData => dispatch(setDashboardPluginData(dashboardId, pluginId, newData)),
22+
(newData: T) =>
23+
dispatch(setDashboardPluginData(dashboardId, pluginId, newData)),
2324
[dashboardId, pluginId, dispatch]
2425
);
2526
return [data, setData];

packages/dashboard/src/redux/selectors.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ export const getOpenedPanelMapForDashboard = (
6161
* @param dashboardId The dashboard ID to get data for
6262
* @returns The map of plugin IDs to data for all plugins on the dashboard
6363
*/
64-
export const getPluginDataMapForDashboard = (
64+
export const getPluginDataMapForDashboard = <T = PluginData>(
6565
store: RootState,
6666
dashboardId: string
67-
): PluginDataMap =>
67+
): PluginDataMap<T> =>
6868
getDashboardData(store, dashboardId).pluginDataMap ?? EMPTY_OBJECT;
6969

7070
/**
@@ -73,8 +73,8 @@ export const getPluginDataMapForDashboard = (
7373
* @param pluginId The plugin ID to get data for
7474
* @returns The plugin data
7575
*/
76-
export const getPluginDataForDashboard = (
76+
export const getPluginDataForDashboard = <T = PluginData>(
7777
store: RootState,
7878
dashboardId: string,
7979
pluginId: string
80-
): PluginData => getPluginDataMapForDashboard(store, dashboardId)[pluginId];
80+
): T => getPluginDataMapForDashboard<T>(store, dashboardId)[pluginId];

packages/redux/src/store.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,14 @@ export interface WorkspaceSettings {
6060
}
6161

6262
export interface WorkspaceData {
63+
settings: WorkspaceSettings;
64+
65+
// TODO: #1746 The rest of these options should not be stored with workspace data, we should have a separate DashboardStorage
6366
closed: unknown[];
6467
filterSets: unknown[];
6568
layoutConfig: unknown[];
6669
links: unknown;
67-
settings: WorkspaceSettings;
70+
pluginDataMap: PluginDataMap;
6871
}
6972

7073
export interface CustomizableWorkspaceData
@@ -82,13 +85,16 @@ export interface Workspace {
8285

8386
export type PluginData = unknown;
8487

85-
export type PluginDataMap = Record<string, PluginData>;
88+
export type PluginDataMap<TData = PluginData> = Record<string, TData>;
8689

87-
export type DashboardData = Record<string, unknown> & {
90+
export type DashboardData<TPluginData = PluginData> = Record<
91+
string,
92+
unknown
93+
> & {
8894
title?: string;
8995
closed?: unknown[];
9096
filterSets?: unknown[];
91-
pluginDataMap?: PluginDataMap;
97+
pluginDataMap?: PluginDataMap<TPluginData>;
9298
};
9399

94100
export type WorkspaceStorageLoadOptions = {

0 commit comments

Comments
 (0)