Skip to content

Commit

Permalink
[User Experience App] Improve initial loading time of the app (#136612)
Browse files Browse the repository at this point in the history
* Use local storage

* use local context

* add error boundary

* test

* fix test
  • Loading branch information
shahzad31 authored Jul 22, 2022
1 parent ad8ec92 commit d16a4d8
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 61 deletions.
7 changes: 6 additions & 1 deletion x-pack/plugins/ux/public/application/ux_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
InspectorContextProvider,
useBreadcrumbs,
} from '@kbn/observability-plugin/public';
import { CsmSharedContextProvider } from '../components/app/rum_dashboard/csm_shared_context';
import {
DASHBOARD_LABEL,
RumHome,
Expand Down Expand Up @@ -125,6 +126,8 @@ export function UXAppRoot({
const i18nCore = core.i18n;
const plugins = { ...deps, maps };

createCallApmApi(core);

return (
<RedirectAppLinks
className={APP_WRAPPER_CLASS}
Expand All @@ -148,7 +151,9 @@ export function UXAppRoot({
<InspectorContextProvider>
<UrlParamsProvider>
<EuiErrorBoundary>
<UxApp />
<CsmSharedContextProvider>
<UxApp />
</CsmSharedContextProvider>
</EuiErrorBoundary>
<UXActionMenu appMountParameters={appMountParameters} />
</UrlParamsProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export function PageLoadDistChart({ onPercentileChange, breakdown }: Props) {
},
];

if (!dataViewTitle) {
return null;
}

return (
<ExploratoryViewEmbeddable
customHeight={'300px'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ export function PageViewsChart({ breakdown }: Props) {
});
};

if (!dataViewTitle) {
return null;
}

return (
<ExploratoryViewEmbeddable
customHeight="300px"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,26 @@
* 2.0.
*/

import React, { createContext, useMemo, useState } from 'react';
import React, { createContext, useEffect, useMemo, useState } from 'react';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import {
DataView,
DataViewsPublicPluginStart,
} from '@kbn/data-views-plugin/public';
import { useDynamicDataViewFetcher } from '../../../../hooks/use_dynamic_data_view';
import { useFetcher } from '../../../../hooks/use_fetcher';

interface SharedData {
totalPageViews: number;
}

interface Index {
interface ContextType {
dataView?: DataView;
sharedData: SharedData;
setSharedData: (data: SharedData) => void;
}

const defaultContext: Index = {
const defaultContext: ContextType = {
sharedData: { totalPageViews: 0 },
setSharedData: (d) => {
throw new Error(
Expand All @@ -33,14 +41,33 @@ export function CsmSharedContextProvider({
children: JSX.Element;
}) {
const [newData, setNewData] = useState<SharedData>({ totalPageViews: 0 });
const [dataView, setDataView] = useState<DataView>();

const setSharedData = React.useCallback((data: SharedData) => {
setNewData(data);
}, []);

const {
services: { dataViews },
} = useKibana<{ dataViews: DataViewsPublicPluginStart }>();

const { dataView: uxDataView } = useDynamicDataViewFetcher();

const { data } = useFetcher<Promise<DataView | undefined>>(async () => {
if (uxDataView?.title) {
return dataViews.create({
title: uxDataView?.title,
});
}
}, [uxDataView?.title, dataViews]);

useEffect(() => {
setDataView(data);
}, [data]);

const value = useMemo(() => {
return { sharedData: newData, setSharedData };
}, [newData, setSharedData]);
return { sharedData: newData, setSharedData, dataView };
}, [newData, setSharedData, dataView]);

return <CsmSharedContext.Provider value={value} children={children} />;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@
*/

import { useEsSearch } from '@kbn/observability-plugin/public';
import useLocalStorage from 'react-use/lib/useLocalStorage';
import { useEffect } from 'react';
import {
formatHasRumResult,
hasRumDataQuery,
} from '../../../../services/data/has_rum_data_query';
import { useDataView } from '../local_uifilters/use_data_view';

export function useHasRumData() {
const [hasData, setHasData] = useLocalStorage('uxAppHasDataBoolean', false);

const { dataViewTitle } = useDataView();

const { data: response, loading } = useEsSearch(
{
index: dataViewTitle,
Expand All @@ -25,8 +30,17 @@ export function useHasRumData() {
}
);

useEffect(() => {
if (response) {
const { hasData: hasDataN } = formatHasRumResult(response, dataViewTitle);
setHasData(hasDataN);
}
}, [dataViewTitle, response, setHasData]);

if (!response) return { loading, hasData };

return {
data: formatHasRumResult(response, dataViewTitle),
hasData: formatHasRumResult(response, dataViewTitle).hasData,
loading,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,23 @@
* 2.0.
*/

import { DataView } from '@kbn/data-views-plugin/common';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
import { useFetcher } from '../../../../hooks/use_fetcher';
import { useDynamicDataViewFetcher } from '../../../../hooks/use_dynamic_data_view';
import { useContext, useEffect } from 'react';
import useLocalStorage from 'react-use/lib/useLocalStorage';
import { CsmSharedContext } from '../csm_shared_context';

export function useDataView() {
const { dataView } = useDynamicDataViewFetcher();
const { dataView } = useContext(CsmSharedContext);

const {
services: { dataViews },
} = useKibana<{ dataViews: DataViewsPublicPluginStart }>();
const [dataViewTitle, setDataViewTitle] = useLocalStorage(
'uxAppDataViewTitle',
''
);

const { data } = useFetcher<Promise<DataView | undefined>>(async () => {
if (dataView?.title) {
return dataViews.create({
title: dataView?.title,
});
}
}, [dataView?.title, dataViews]);
const updatedDataViewTitle = dataView?.title;

return { dataViewTitle: dataView?.title, dataView: data };
useEffect(() => {
setDataViewTitle(updatedDataViewTitle);
}, [setDataViewTitle, updatedDataViewTitle]);

return { dataViewTitle, dataView };
}
70 changes: 33 additions & 37 deletions x-pack/plugins/ux/public/components/app/rum_dashboard/rum_home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import React, { Fragment } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiFlexGroup, EuiTitle, EuiFlexItem } from '@elastic/eui';
import { KibanaPageTemplateProps } from '@kbn/shared-ux-components';
import { CsmSharedContextProvider } from './csm_shared_context';
import { WebApplicationSelect } from './panels/web_application_select';
import { UserPercentile } from './user_percentile';
import { useBreakpoints } from '../../../hooks/use_breakpoints';
Expand All @@ -29,47 +28,44 @@ export function RumHome() {

const PageTemplateComponent = observability.navigation.PageTemplate;

const { data: rumHasData, loading: isLoading } = useHasRumData();
const { hasData, loading: isLoading } = useHasRumData();

const noDataConfig: KibanaPageTemplateProps['noDataConfig'] =
!rumHasData?.hasData
? {
solution: i18n.translate('xpack.ux.overview.solutionName', {
defaultMessage: 'Observability',
}),
action: {
elasticAgent: {
title: i18n.translate('xpack.ux.overview.beatsCard.title', {
defaultMessage: 'Add RUM data',
}),
description: i18n.translate(
'xpack.ux.overview.beatsCard.description',
{
defaultMessage:
'Enable RUM with the APM agent to collect user experience data.',
}
),
href: http.basePath.prepend(`/app/home#/tutorial/apm`),
},
const noDataConfig: KibanaPageTemplateProps['noDataConfig'] = !hasData
? {
solution: i18n.translate('xpack.ux.overview.solutionName', {
defaultMessage: 'Observability',
}),
action: {
elasticAgent: {
title: i18n.translate('xpack.ux.overview.beatsCard.title', {
defaultMessage: 'Add RUM data',
}),
description: i18n.translate(
'xpack.ux.overview.beatsCard.description',
{
defaultMessage:
'Enable RUM with the APM agent to collect user experience data.',
}
),
href: http.basePath.prepend(`/app/home#/tutorial/apm`),
},
docsLink: docLinks.links.observability.guide,
}
: undefined;
},
docsLink: docLinks.links.observability.guide,
}
: undefined;

return (
<Fragment>
<CsmSharedContextProvider>
<PageTemplateComponent
noDataConfig={isLoading ? undefined : noDataConfig}
pageHeader={{ children: <PageHeader /> }}
isPageDataLoaded={isLoading === false}
>
{isLoading && <EmptyStateLoading />}
<div style={{ visibility: isLoading ? 'hidden' : 'initial' }}>
<RumOverview />
</div>
</PageTemplateComponent>
</CsmSharedContextProvider>
<PageTemplateComponent
noDataConfig={isLoading ? undefined : noDataConfig}
pageHeader={{ children: <PageHeader /> }}
isPageDataLoaded={isLoading === false}
>
{isLoading && <EmptyStateLoading />}
<div style={{ visibility: isLoading ? 'hidden' : 'initial' }}>
<RumOverview />
</div>
</PageTemplateComponent>
</Fragment>
);
}
Expand Down

0 comments on commit d16a4d8

Please sign in to comment.