Skip to content

Commit

Permalink
Lazy load reporting (#80492)
Browse files Browse the repository at this point in the history
* perf: ⚡️ load dynamically reporting management section

* refactor: 💡 remove JSX from main plugin entry file

* perf: ⚡️ lazy-load CSV sharing panel React component

* perf: ⚡️ lazy-load screen capture sharing panel React components

* feat: 🎸 show spinner while shring panels are loading
  • Loading branch information
streamich committed Oct 16, 2020
1 parent fd5e8cf commit fe654ba
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 42 deletions.
22 changes: 22 additions & 0 deletions x-pack/plugins/reporting/public/components/panel_spinner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import * as React from 'react';
import { EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';

export const PanelSpinner: React.FC = (props) => {
return (
<>
<EuiSpacer />
<EuiFlexGroup justifyContent="spaceAround">
<EuiFlexItem grow={false}>
<EuiLoadingSpinner size="l" />
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer />
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { toMountPoint } from '../../../../../src/plugins/kibana_react/public';
import { BaseParams } from '../../common/types';
import { ReportingAPIClient } from '../lib/reporting_api_client';

interface Props {
export interface Props {
apiClient: ReportingAPIClient;
toasts: ToastsSetup;
reportType: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import * as React from 'react';
import { lazy, Suspense, FC } from 'react';
import { PanelSpinner } from './panel_spinner';
import type { Props } from './reporting_panel_content';

const LazyComponent = lazy(() =>
import('./reporting_panel_content').then(({ ReportingPanelContent }) => ({
default: ReportingPanelContent,
}))
);

export const ReportingPanelContent: FC<Omit<Props, 'intl'>> = (props) => {
return (
<Suspense fallback={<PanelSpinner />}>
<LazyComponent {...props} />
</Suspense>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { BaseParams } from '../../common/types';
import { ReportingAPIClient } from '../lib/reporting_api_client';
import { ReportingPanelContent } from './reporting_panel_content';

interface Props {
export interface Props {
apiClient: ReportingAPIClient;
toasts: ToastsSetup;
reportType: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import * as React from 'react';
import { lazy, Suspense, FC } from 'react';
import { PanelSpinner } from './panel_spinner';
import type { Props } from './screen_capture_panel_content';

const LazyComponent = lazy(() =>
import('./screen_capture_panel_content').then(({ ScreenCapturePanelContent }) => ({
default: ScreenCapturePanelContent,
}))
);

export const ScreenCapturePanelContent: FC<Props> = (props) => {
return (
<Suspense fallback={<PanelSpinner />}>
<LazyComponent {...props} />
</Suspense>
);
};
42 changes: 42 additions & 0 deletions x-pack/plugins/reporting/public/mount_management_section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import * as React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { I18nProvider } from '@kbn/i18n/react';
import { CoreSetup, CoreStart } from 'src/core/public';
import { Observable } from 'rxjs';
import { ReportListing } from './components/report_listing';
import { ManagementAppMountParams } from '../../../../src/plugins/management/public';
import { ILicense } from '../../licensing/public';
import { ClientConfigType } from './plugin';
import { ReportingAPIClient } from './lib/reporting_api_client';

export async function mountManagementSection(
coreSetup: CoreSetup,
coreStart: CoreStart,
license$: Observable<ILicense>,
pollConfig: ClientConfigType['poll'],
apiClient: ReportingAPIClient,
params: ManagementAppMountParams
) {
render(
<I18nProvider>
<ReportListing
toasts={coreSetup.notifications.toasts}
license$={license$}
pollConfig={pollConfig}
redirect={coreStart.application.navigateToApp}
apiClient={apiClient}
/>
</I18nProvider>,
params.element
);

return () => {
unmountComponentAtNode(params.element);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
*/

import { i18n } from '@kbn/i18n';
import { I18nProvider } from '@kbn/i18n/react';
import React from 'react';
import ReactDOM from 'react-dom';
import * as Rx from 'rxjs';
import { catchError, filter, map, mergeMap, takeUntil } from 'rxjs/operators';
import {
Expand All @@ -17,21 +14,21 @@ import {
Plugin,
PluginInitializerContext,
} from 'src/core/public';
import { UiActionsSetup } from 'src/plugins/ui_actions/public';
import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public';
import { CONTEXT_MENU_TRIGGER } from '../../../../src/plugins/embeddable/public';
import {
FeatureCatalogueCategory,
HomePublicPluginSetup,
HomePublicPluginStart,
} from '../../../../src/plugins/home/public';
import { ManagementSetup } from '../../../../src/plugins/management/public';
import { SharePluginSetup } from '../../../../src/plugins/share/public';
import { LicensingPluginSetup } from '../../licensing/public';
import { ManagementSetup, ManagementStart } from '../../../../src/plugins/management/public';
import { SharePluginSetup, SharePluginStart } from '../../../../src/plugins/share/public';
import { LicensingPluginSetup, LicensingPluginStart } from '../../licensing/public';
import { durationToNumber } from '../common/schema_utils';
import { JobId, ReportingConfigType } from '../common/types';
import { JOB_COMPLETION_NOTIFICATIONS_SESSION_KEY } from '../constants';
import { JobSummarySet } from './';
import { getGeneralErrorToast } from './components';
import { ReportListing } from './components/report_listing';
import { ReportingAPIClient } from './lib/reporting_api_client';
import { ReportingNotifierStreamHandler as StreamHandler } from './lib/stream_handler';
import { GetCsvReportPanelAction } from './panel_actions/get_csv_panel_action';
Expand Down Expand Up @@ -60,7 +57,25 @@ function handleError(notifications: NotificationsSetup, err: Error): Rx.Observab
return Rx.of({ completed: [], failed: [] });
}

export class ReportingPublicPlugin implements Plugin<void, void> {
export interface ReportingPublicPluginSetupDendencies {
home: HomePublicPluginSetup;
management: ManagementSetup;
licensing: LicensingPluginSetup;
uiActions: UiActionsSetup;
share: SharePluginSetup;
}

export interface ReportingPublicPluginStartDendencies {
home: HomePublicPluginStart;
management: ManagementStart;
licensing: LicensingPluginStart;
uiActions: UiActionsStart;
share: SharePluginStart;
}

export class ReportingPublicPlugin
implements
Plugin<void, void, ReportingPublicPluginSetupDendencies, ReportingPublicPluginStartDendencies> {
private config: ClientConfigType;
private readonly stop$ = new Rx.ReplaySubject(1);
private readonly title = i18n.translate('xpack.reporting.management.reportingTitle', {
Expand All @@ -76,19 +91,7 @@ export class ReportingPublicPlugin implements Plugin<void, void> {

public setup(
core: CoreSetup,
{
home,
management,
licensing,
uiActions,
share,
}: {
home: HomePublicPluginSetup;
management: ManagementSetup;
licensing: LicensingPluginSetup;
uiActions: UiActionsSetup;
share: SharePluginSetup;
}
{ home, management, licensing, uiActions, share }: ReportingPublicPluginSetupDendencies
) {
const {
http,
Expand Down Expand Up @@ -119,24 +122,19 @@ export class ReportingPublicPlugin implements Plugin<void, void> {
title: this.title,
order: 1,
mount: async (params) => {
const [start] = await getStartServices();
params.setBreadcrumbs([{ text: this.breadcrumbText }]);
ReactDOM.render(
<I18nProvider>
<ReportListing
toasts={toasts}
license$={license$}
pollConfig={this.config.poll}
redirect={start.application.navigateToApp}
apiClient={apiClient}
/>
</I18nProvider>,
params.element
const [[start], { mountManagementSection }] = await Promise.all([
getStartServices(),
import('./mount_management_section'),
]);
return await mountManagementSection(
core,
start,
license$,
this.config.poll,
apiClient,
params
);

return () => {
ReactDOM.unmountComponentAtNode(params.element);
};
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { IUiSettingsClient, ToastsSetup } from 'src/core/public';
import { ShareContext } from '../../../../../src/plugins/share/public';
import { LicensingPluginSetup } from '../../../licensing/public';
import { JobParamsCSV, SearchRequest } from '../../server/export_types/csv/types';
import { ReportingPanelContent } from '../components/reporting_panel_content';
import { ReportingPanelContent } from '../components/reporting_panel_content_lazy';
import { checkLicense } from '../lib/license_check';
import { ReportingAPIClient } from '../lib/reporting_api_client';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { LicensingPluginSetup } from '../../../licensing/public';
import { LayoutParams } from '../../common/types';
import { JobParamsPNG } from '../../server/export_types/png/types';
import { JobParamsPDF } from '../../server/export_types/printable_pdf/types';
import { ScreenCapturePanelContent } from '../components/screen_capture_panel_content';
import { ScreenCapturePanelContent } from '../components/screen_capture_panel_content_lazy';
import { checkLicense } from '../lib/license_check';
import { ReportingAPIClient } from '../lib/reporting_api_client';

Expand Down

0 comments on commit fe654ba

Please sign in to comment.