Skip to content

Commit

Permalink
[dashboard] Lazy DashboardRenderer (elastic#192754)
Browse files Browse the repository at this point in the history
Changes
1. expose DashboardRenderer as lazy loaded component to reduce static
page load size
2. Use `onApiAvailable` prop to pass DashboardApi to parent instead of
`forwardRef`
3. Decouple DashboardApi from legacy embeddable system. This changed
functions such as `updateInput` and using redux `select` to access
state.

---------

Co-authored-by: kibanamachine <[email protected]>
Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
3 people authored Sep 17, 2024
1 parent 2d78f23 commit e2380af
Show file tree
Hide file tree
Showing 45 changed files with 673 additions and 742 deletions.
48 changes: 28 additions & 20 deletions examples/portable_dashboards_example/public/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,55 +12,65 @@ import React, { useMemo } from 'react';
import { useAsync } from 'react-use/lib';
import { Redirect } from 'react-router-dom';
import { Router, Routes, Route } from '@kbn/shared-ux-router';
import { AppMountParameters } from '@kbn/core/public';
import { AppMountParameters, CoreStart } from '@kbn/core/public';
import { EuiButton, EuiCallOut, EuiSpacer } from '@elastic/eui';
import { DashboardListingTable } from '@kbn/dashboard-plugin/public';
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';

import { DualReduxExample } from './dual_redux_example';
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
import { DualDashboardsExample } from './dual_dashboards_example';
import { StartDeps } from './plugin';
import { StaticByValueExample } from './static_by_value_example';
import { StaticByReferenceExample } from './static_by_reference_example';
import { DynamicByReferenceExample } from './dynamically_add_panels_example';
import { DashboardWithControlsExample } from './dashboard_with_controls_example';

const DASHBOARD_DEMO_PATH = '/dashboardDemo';
const DASHBOARD_LIST_PATH = '/listingDemo';

export const renderApp = async (
coreStart: CoreStart,
{ data, dashboard }: StartDeps,
{ element, history }: AppMountParameters
) => {
ReactDOM.render(
<PortableDashboardsDemos data={data} history={history} dashboard={dashboard} />,
<PortableDashboardsDemos
coreStart={coreStart}
data={data}
history={history}
dashboard={dashboard}
/>,
element
);
return () => ReactDOM.unmountComponentAtNode(element);
};

const PortableDashboardsDemos = ({
coreStart,
data,
dashboard,
history,
}: {
coreStart: CoreStart;
data: StartDeps['data'];
dashboard: StartDeps['dashboard'];
history: AppMountParameters['history'];
}) => {
return (
<Router history={history}>
<Routes>
<Route exact path="/">
<Redirect to={DASHBOARD_DEMO_PATH} />
</Route>
<Route path={DASHBOARD_LIST_PATH}>
<PortableDashboardListingDemo history={history} />
</Route>
<Route path={DASHBOARD_DEMO_PATH}>
<DashboardsDemo data={data} dashboard={dashboard} history={history} />
</Route>
</Routes>
</Router>
<KibanaRenderContextProvider i18n={coreStart.i18n} theme={coreStart.theme}>
<Router history={history}>
<Routes>
<Route exact path="/">
<Redirect to={DASHBOARD_DEMO_PATH} />
</Route>
<Route path={DASHBOARD_LIST_PATH}>
<PortableDashboardListingDemo history={history} />
</Route>
<Route path={DASHBOARD_DEMO_PATH}>
<DashboardsDemo data={data} dashboard={dashboard} history={history} />
</Route>
</Routes>
</Router>
</KibanaRenderContextProvider>
);
};

Expand Down Expand Up @@ -91,9 +101,7 @@ const DashboardsDemo = ({
<>
<DashboardWithControlsExample dataView={dataViews[0]} />
<EuiSpacer size="xl" />
<DynamicByReferenceExample />
<EuiSpacer size="xl" />
<DualReduxExample />
<DualDashboardsExample />
<EuiSpacer size="xl" />
<StaticByReferenceExample dashboardId={logsSampleDashboardId} dataView={dataViews[0]} />
<EuiSpacer size="xl" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,41 +14,29 @@ import type { DataView } from '@kbn/data-views-plugin/public';
import { EuiPanel, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
import { controlGroupStateBuilder } from '@kbn/controls-plugin/public';
import {
AwaitingDashboardAPI,
DashboardApi,
DashboardRenderer,
DashboardCreationOptions,
} from '@kbn/dashboard-plugin/public';
import { apiHasUniqueId } from '@kbn/presentation-publishing';
import { FILTER_DEBUGGER_EMBEDDABLE_ID } from './constants';

export const DashboardWithControlsExample = ({ dataView }: { dataView: DataView }) => {
const [dashboard, setDashboard] = useState<AwaitingDashboardAPI>();
const [dashboard, setDashboard] = useState<DashboardApi | undefined>();

// add a filter debugger panel as soon as the dashboard becomes available
useEffect(() => {
if (!dashboard) return;
(async () => {
const api = await dashboard.addNewPanel(
dashboard
.addNewPanel(
{
panelType: FILTER_DEBUGGER_EMBEDDABLE_ID,
initialState: {},
},
true
);
if (!apiHasUniqueId(api)) {
return;
}
const prevPanelState = dashboard.getExplicitInput().panels[api.uuid];
// resize the new panel so that it fills up the entire width of the dashboard
dashboard.updateInput({
panels: {
[api.uuid]: {
...prevPanelState,
gridData: { i: api.uuid, x: 0, y: 0, w: 48, h: 12 },
},
},
)
.catch(() => {
// ignore error - its an example
});
})();
}, [dashboard]);

return (
Expand Down Expand Up @@ -88,7 +76,7 @@ export const DashboardWithControlsExample = ({ dataView }: { dataView: DataView
}),
};
}}
ref={setDashboard}
onApiAvailable={setDashboard}
/>
</EuiPanel>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,16 @@ import {
EuiText,
EuiTitle,
} from '@elastic/eui';
import {
AwaitingDashboardAPI,
DashboardAPI,
DashboardRenderer,
} from '@kbn/dashboard-plugin/public';
import { DashboardApi, DashboardRenderer } from '@kbn/dashboard-plugin/public';
import { ViewMode } from '@kbn/embeddable-plugin/public';
import { useStateFromPublishingSubject } from '@kbn/presentation-publishing';

export const DualReduxExample = () => {
const [firstDashboardContainer, setFirstDashboardContainer] = useState<AwaitingDashboardAPI>();
const [secondDashboardContainer, setSecondDashboardContainer] = useState<AwaitingDashboardAPI>();
export const DualDashboardsExample = () => {
const [firstDashboardApi, setFirstDashboardApi] = useState<DashboardApi | undefined>();
const [secondDashboardApi, setSecondDashboardApi] = useState<DashboardApi | undefined>();

const ButtonControls = ({ dashboard }: { dashboard: DashboardAPI }) => {
const viewMode = dashboard.select((state) => state.explicitInput.viewMode);
const ButtonControls = ({ dashboardApi }: { dashboardApi: DashboardApi }) => {
const viewMode = useStateFromPublishingSubject(dashboardApi.viewMode);

return (
<EuiButtonGroup
Expand All @@ -48,7 +45,7 @@ export const DualReduxExample = () => {
},
]}
idSelected={viewMode}
onChange={(id, value) => dashboard.dispatch.setViewMode(value)}
onChange={(id, value) => dashboardApi.setViewMode(value)}
type="single"
/>
);
Expand All @@ -57,12 +54,12 @@ export const DualReduxExample = () => {
return (
<>
<EuiTitle>
<h2>Dual redux example</h2>
<h2>Dual dashboards example</h2>
</EuiTitle>
<EuiText>
<p>
Use the redux contexts from two different dashboard containers to independently set the
view mode of each dashboard.
Use the APIs from different dashboards to independently set the view mode of each
dashboard.
</p>
</EuiText>
<EuiSpacer size="m" />
Expand All @@ -73,18 +70,18 @@ export const DualReduxExample = () => {
<h3>Dashboard #1</h3>
</EuiTitle>
<EuiSpacer size="m" />
{firstDashboardContainer && <ButtonControls dashboard={firstDashboardContainer} />}
{firstDashboardApi && <ButtonControls dashboardApi={firstDashboardApi} />}
<EuiSpacer size="m" />
<DashboardRenderer ref={setFirstDashboardContainer} />
<DashboardRenderer onApiAvailable={setFirstDashboardApi} />
</EuiFlexItem>
<EuiFlexItem>
<EuiTitle size="xs">
<h3>Dashboard #2</h3>
</EuiTitle>
<EuiSpacer size="m" />
{secondDashboardContainer && <ButtonControls dashboard={secondDashboardContainer} />}
{secondDashboardApi && <ButtonControls dashboardApi={secondDashboardApi} />}
<EuiSpacer size="m" />
<DashboardRenderer ref={setSecondDashboardContainer} />
<DashboardRenderer onApiAvailable={setSecondDashboardApi} />
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
Expand Down

This file was deleted.

Loading

0 comments on commit e2380af

Please sign in to comment.