From cb4dc26fd12659dfc5c1de0d36aa64d2f20192c6 Mon Sep 17 00:00:00 2001 From: Vlad Babich Date: Wed, 28 Feb 2024 10:22:51 -0700 Subject: [PATCH] Export plotly-express as a dashboard plugin --- .../src/js/src/DashboardPlugin.tsx | 78 +++++++++++++++++++ .../src/js/src/PlotlyExpressChartUtils.ts | 11 ++- plugins/plotly-express/src/js/src/index.ts | 5 +- 3 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 plugins/plotly-express/src/js/src/DashboardPlugin.tsx diff --git a/plugins/plotly-express/src/js/src/DashboardPlugin.tsx b/plugins/plotly-express/src/js/src/DashboardPlugin.tsx new file mode 100644 index 000000000..b60676e78 --- /dev/null +++ b/plugins/plotly-express/src/js/src/DashboardPlugin.tsx @@ -0,0 +1,78 @@ +import { useCallback, DragEvent, useEffect } from 'react'; +import shortid from 'shortid'; +import { + DashboardPluginComponentProps, + LayoutUtils, + PanelEvent, + useListener, +} from '@deephaven/dashboard'; +import type { VariableDefinition } from '@deephaven/jsapi-types'; +import PlotlyExpressChartPanel from './PlotlyExpressChartPanel.js'; +import type { PlotlyChartWidget } from './PlotlyExpressChartUtils.js'; + +export function DashboardPlugin( + props: DashboardPluginComponentProps +): JSX.Element | null { + const { id, layout, registerComponent } = props; + + const handlePanelOpen = useCallback( + async ({ + dragEvent, + fetch, + metadata = {}, + panelId = shortid.generate(), + widget, + }: { + dragEvent?: DragEvent; + fetch: () => Promise; + metadata?: Record; + panelId?: string; + widget: VariableDefinition; + }) => { + const { type, title } = widget; + if (type !== 'deephaven.plot.express.DeephavenFigure') { + return; + } + + const config = { + type: 'react-component' as const, + component: 'PlotlyPanel', + props: { + localDashboardId: id, + id: panelId, + metadata: { + ...metadata, + name: title, + figure: title, + type, + }, + fetch, + }, + title, + id: panelId, + }; + + const { root } = layout; + LayoutUtils.openComponent({ root, config, dragEvent }); + }, + [id, layout] + ); + + useEffect( + function registerComponentsAndReturnCleanup() { + const cleanups = [ + registerComponent('PlotlyPanel', PlotlyExpressChartPanel), + ]; + return () => { + cleanups.forEach(cleanup => cleanup()); + }; + }, + [registerComponent] + ); + + useListener(layout.eventHub, PanelEvent.OPEN, handlePanelOpen); + + return null; +} + +export default DashboardPlugin; diff --git a/plugins/plotly-express/src/js/src/PlotlyExpressChartUtils.ts b/plugins/plotly-express/src/js/src/PlotlyExpressChartUtils.ts index c2b193f98..c91c66f82 100644 --- a/plugins/plotly-express/src/js/src/PlotlyExpressChartUtils.ts +++ b/plugins/plotly-express/src/js/src/PlotlyExpressChartUtils.ts @@ -1,5 +1,14 @@ import type { Data, PlotlyDataLayoutConfig } from 'plotly.js'; -import type { Widget } from '@deephaven/jsapi-types'; +import type { Table, Widget } from '@deephaven/jsapi-types'; + +export interface PlotlyChartWidget { + getDataAsBase64(): string; + exportedObjects: { fetch(): Promise }[]; + addEventListener( + type: string, + fn: (event: CustomEvent) => () => void + ): void; +} export interface PlotlyChartWidgetData { type: string; diff --git a/plugins/plotly-express/src/js/src/index.ts b/plugins/plotly-express/src/js/src/index.ts index 9d83e0884..80db0344d 100644 --- a/plugins/plotly-express/src/js/src/index.ts +++ b/plugins/plotly-express/src/js/src/index.ts @@ -1,6 +1,3 @@ -import { PlotlyExpressPlugin } from './PlotlyExpressPlugin.js'; - +export * from './DashboardPlugin.js'; export * from './PlotlyExpressChartModel.js'; export * from './PlotlyExpressChartUtils.js'; - -export default PlotlyExpressPlugin;