Skip to content

Commit bb5968c

Browse files
authored
Lazy load reporting (#80492) (#80805)
* 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
1 parent 1b8c092 commit bb5968c

File tree

9 files changed

+152
-42
lines changed

9 files changed

+152
-42
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import * as React from 'react';
8+
import { EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';
9+
10+
export const PanelSpinner: React.FC = (props) => {
11+
return (
12+
<>
13+
<EuiSpacer />
14+
<EuiFlexGroup justifyContent="spaceAround">
15+
<EuiFlexItem grow={false}>
16+
<EuiLoadingSpinner size="l" />
17+
</EuiFlexItem>
18+
</EuiFlexGroup>
19+
<EuiSpacer />
20+
</>
21+
);
22+
};

x-pack/plugins/reporting/public/components/reporting_panel_content.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { toMountPoint } from '../../../../../src/plugins/kibana_react/public';
1313
import { BaseParams } from '../../common/types';
1414
import { ReportingAPIClient } from '../lib/reporting_api_client';
1515

16-
interface Props {
16+
export interface Props {
1717
apiClient: ReportingAPIClient;
1818
toasts: ToastsSetup;
1919
reportType: string;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import * as React from 'react';
8+
import { lazy, Suspense, FC } from 'react';
9+
import { PanelSpinner } from './panel_spinner';
10+
import type { Props } from './reporting_panel_content';
11+
12+
const LazyComponent = lazy(() =>
13+
import('./reporting_panel_content').then(({ ReportingPanelContent }) => ({
14+
default: ReportingPanelContent,
15+
}))
16+
);
17+
18+
export const ReportingPanelContent: FC<Omit<Props, 'intl'>> = (props) => {
19+
return (
20+
<Suspense fallback={<PanelSpinner />}>
21+
<LazyComponent {...props} />
22+
</Suspense>
23+
);
24+
};

x-pack/plugins/reporting/public/components/screen_capture_panel_content.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { BaseParams } from '../../common/types';
1212
import { ReportingAPIClient } from '../lib/reporting_api_client';
1313
import { ReportingPanelContent } from './reporting_panel_content';
1414

15-
interface Props {
15+
export interface Props {
1616
apiClient: ReportingAPIClient;
1717
toasts: ToastsSetup;
1818
reportType: string;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import * as React from 'react';
8+
import { lazy, Suspense, FC } from 'react';
9+
import { PanelSpinner } from './panel_spinner';
10+
import type { Props } from './screen_capture_panel_content';
11+
12+
const LazyComponent = lazy(() =>
13+
import('./screen_capture_panel_content').then(({ ScreenCapturePanelContent }) => ({
14+
default: ScreenCapturePanelContent,
15+
}))
16+
);
17+
18+
export const ScreenCapturePanelContent: FC<Props> = (props) => {
19+
return (
20+
<Suspense fallback={<PanelSpinner />}>
21+
<LazyComponent {...props} />
22+
</Suspense>
23+
);
24+
};
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import * as React from 'react';
8+
import { render, unmountComponentAtNode } from 'react-dom';
9+
import { I18nProvider } from '@kbn/i18n/react';
10+
import { CoreSetup, CoreStart } from 'src/core/public';
11+
import { Observable } from 'rxjs';
12+
import { ReportListing } from './components/report_listing';
13+
import { ManagementAppMountParams } from '../../../../src/plugins/management/public';
14+
import { ILicense } from '../../licensing/public';
15+
import { ClientConfigType } from './plugin';
16+
import { ReportingAPIClient } from './lib/reporting_api_client';
17+
18+
export async function mountManagementSection(
19+
coreSetup: CoreSetup,
20+
coreStart: CoreStart,
21+
license$: Observable<ILicense>,
22+
pollConfig: ClientConfigType['poll'],
23+
apiClient: ReportingAPIClient,
24+
params: ManagementAppMountParams
25+
) {
26+
render(
27+
<I18nProvider>
28+
<ReportListing
29+
toasts={coreSetup.notifications.toasts}
30+
license$={license$}
31+
pollConfig={pollConfig}
32+
redirect={coreStart.application.navigateToApp}
33+
apiClient={apiClient}
34+
/>
35+
</I18nProvider>,
36+
params.element
37+
);
38+
39+
return () => {
40+
unmountComponentAtNode(params.element);
41+
};
42+
}

x-pack/plugins/reporting/public/plugin.tsx renamed to x-pack/plugins/reporting/public/plugin.ts

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
*/
66

77
import { i18n } from '@kbn/i18n';
8-
import { I18nProvider } from '@kbn/i18n/react';
9-
import React from 'react';
10-
import ReactDOM from 'react-dom';
118
import * as Rx from 'rxjs';
129
import { catchError, filter, map, mergeMap, takeUntil } from 'rxjs/operators';
1310
import {
@@ -17,21 +14,21 @@ import {
1714
Plugin,
1815
PluginInitializerContext,
1916
} from 'src/core/public';
20-
import { UiActionsSetup } from 'src/plugins/ui_actions/public';
17+
import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public';
2118
import { CONTEXT_MENU_TRIGGER } from '../../../../src/plugins/embeddable/public';
2219
import {
2320
FeatureCatalogueCategory,
2421
HomePublicPluginSetup,
22+
HomePublicPluginStart,
2523
} from '../../../../src/plugins/home/public';
26-
import { ManagementSetup } from '../../../../src/plugins/management/public';
27-
import { SharePluginSetup } from '../../../../src/plugins/share/public';
28-
import { LicensingPluginSetup } from '../../licensing/public';
24+
import { ManagementSetup, ManagementStart } from '../../../../src/plugins/management/public';
25+
import { SharePluginSetup, SharePluginStart } from '../../../../src/plugins/share/public';
26+
import { LicensingPluginSetup, LicensingPluginStart } from '../../licensing/public';
2927
import { durationToNumber } from '../common/schema_utils';
3028
import { JobId, ReportingConfigType } from '../common/types';
3129
import { JOB_COMPLETION_NOTIFICATIONS_SESSION_KEY } from '../constants';
3230
import { JobSummarySet } from './';
3331
import { getGeneralErrorToast } from './components';
34-
import { ReportListing } from './components/report_listing';
3532
import { ReportingAPIClient } from './lib/reporting_api_client';
3633
import { ReportingNotifierStreamHandler as StreamHandler } from './lib/stream_handler';
3734
import { GetCsvReportPanelAction } from './panel_actions/get_csv_panel_action';
@@ -60,7 +57,25 @@ function handleError(notifications: NotificationsSetup, err: Error): Rx.Observab
6057
return Rx.of({ completed: [], failed: [] });
6158
}
6259

63-
export class ReportingPublicPlugin implements Plugin<void, void> {
60+
export interface ReportingPublicPluginSetupDendencies {
61+
home: HomePublicPluginSetup;
62+
management: ManagementSetup;
63+
licensing: LicensingPluginSetup;
64+
uiActions: UiActionsSetup;
65+
share: SharePluginSetup;
66+
}
67+
68+
export interface ReportingPublicPluginStartDendencies {
69+
home: HomePublicPluginStart;
70+
management: ManagementStart;
71+
licensing: LicensingPluginStart;
72+
uiActions: UiActionsStart;
73+
share: SharePluginStart;
74+
}
75+
76+
export class ReportingPublicPlugin
77+
implements
78+
Plugin<void, void, ReportingPublicPluginSetupDendencies, ReportingPublicPluginStartDendencies> {
6479
private config: ClientConfigType;
6580
private readonly stop$ = new Rx.ReplaySubject(1);
6681
private readonly title = i18n.translate('xpack.reporting.management.reportingTitle', {
@@ -76,19 +91,7 @@ export class ReportingPublicPlugin implements Plugin<void, void> {
7691

7792
public setup(
7893
core: CoreSetup,
79-
{
80-
home,
81-
management,
82-
licensing,
83-
uiActions,
84-
share,
85-
}: {
86-
home: HomePublicPluginSetup;
87-
management: ManagementSetup;
88-
licensing: LicensingPluginSetup;
89-
uiActions: UiActionsSetup;
90-
share: SharePluginSetup;
91-
}
94+
{ home, management, licensing, uiActions, share }: ReportingPublicPluginSetupDendencies
9295
) {
9396
const {
9497
http,
@@ -119,24 +122,19 @@ export class ReportingPublicPlugin implements Plugin<void, void> {
119122
title: this.title,
120123
order: 1,
121124
mount: async (params) => {
122-
const [start] = await getStartServices();
123125
params.setBreadcrumbs([{ text: this.breadcrumbText }]);
124-
ReactDOM.render(
125-
<I18nProvider>
126-
<ReportListing
127-
toasts={toasts}
128-
license$={license$}
129-
pollConfig={this.config.poll}
130-
redirect={start.application.navigateToApp}
131-
apiClient={apiClient}
132-
/>
133-
</I18nProvider>,
134-
params.element
126+
const [[start], { mountManagementSection }] = await Promise.all([
127+
getStartServices(),
128+
import('./mount_management_section'),
129+
]);
130+
return await mountManagementSection(
131+
core,
132+
start,
133+
license$,
134+
this.config.poll,
135+
apiClient,
136+
params
135137
);
136-
137-
return () => {
138-
ReactDOM.unmountComponentAtNode(params.element);
139-
};
140138
},
141139
});
142140

x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { IUiSettingsClient, ToastsSetup } from 'src/core/public';
1111
import { ShareContext } from '../../../../../src/plugins/share/public';
1212
import { LicensingPluginSetup } from '../../../licensing/public';
1313
import { JobParamsCSV, SearchRequest } from '../../server/export_types/csv/types';
14-
import { ReportingPanelContent } from '../components/reporting_panel_content';
14+
import { ReportingPanelContent } from '../components/reporting_panel_content_lazy';
1515
import { checkLicense } from '../lib/license_check';
1616
import { ReportingAPIClient } from '../lib/reporting_api_client';
1717

x-pack/plugins/reporting/public/share_context_menu/register_pdf_png_reporting.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { LicensingPluginSetup } from '../../../licensing/public';
1313
import { LayoutParams } from '../../common/types';
1414
import { JobParamsPNG } from '../../server/export_types/png/types';
1515
import { JobParamsPDF } from '../../server/export_types/printable_pdf/types';
16-
import { ScreenCapturePanelContent } from '../components/screen_capture_panel_content';
16+
import { ScreenCapturePanelContent } from '../components/screen_capture_panel_content_lazy';
1717
import { checkLicense } from '../lib/license_check';
1818
import { ReportingAPIClient } from '../lib/reporting_api_client';
1919

0 commit comments

Comments
 (0)