Skip to content

Commit

Permalink
[UX App] Improve page and filters responsiveness (elastic#91536)
Browse files Browse the repository at this point in the history
  • Loading branch information
shahzad31 authored Feb 17, 2021
1 parent 8f1b395 commit 9c0fdcf
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 172 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import * as React from 'react';
import numeral from '@elastic/numeral';
import styled from 'styled-components';
import { useContext, useEffect } from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiStat,
EuiToolTip,
EuiIconTip,
} from '@elastic/eui';
import { useFetcher } from '../../../../hooks/use_fetcher';
import { I18LABELS } from '../translations';
import { useUxQuery } from '../hooks/useUxQuery';
import { formatToSec } from '../UXMetrics/KeyUXMetrics';
import { CsmSharedContext } from '../CsmSharedContext';

const ClFlexGroup = styled(EuiFlexGroup)`
flex-direction: row;
@media only screen and (max-width: 768px) {
flex-direction: row;
justify-content: space-between;
}
`;

function formatTitle(unit: string, value?: number) {
if (typeof value === 'undefined') return I18LABELS.dataMissing;
return formatToSec(value, unit);
}

function PageViewsTotalTitle({ pageViews }: { pageViews?: number }) {
if (typeof pageViews === 'undefined') {
return <>{I18LABELS.dataMissing}</>;
}
return pageViews < 10000 ? (
<>{numeral(pageViews).format('0,0')}</>
) : (
<EuiToolTip content={numeral(pageViews).format('0,0')}>
<>{numeral(pageViews).format('0 a')}</>
</EuiToolTip>
);
}

export function Metrics() {
const uxQuery = useUxQuery();

const { data, status } = useFetcher(
(callApmApi) => {
if (uxQuery) {
return callApmApi({
endpoint: 'GET /api/apm/rum/client-metrics',
params: {
query: {
...uxQuery,
},
},
});
}
return Promise.resolve(null);
},
[uxQuery]
);

const { setSharedData } = useContext(CsmSharedContext);

useEffect(() => {
setSharedData({ totalPageViews: data?.pageViews?.value ?? 0 });
}, [data, setSharedData]);

const STAT_STYLE = { minWidth: '150px', maxWidth: '250px' };

return (
<ClFlexGroup wrap responsive={false}>
<EuiFlexItem style={STAT_STYLE}>
<EuiStat
titleSize="l"
title={formatTitle('ms', data?.totalPageLoadDuration?.value)}
description={
<>
{I18LABELS.totalPageLoad}
<EuiIconTip
content={I18LABELS.totalPageLoadTooltip}
type="questionInCircle"
/>
</>
}
isLoading={status !== 'success'}
/>
</EuiFlexItem>
<EuiFlexItem style={STAT_STYLE}>
<EuiStat
titleSize="l"
title={formatTitle('ms', data?.backEnd?.value)}
description={
<>
{I18LABELS.backEnd}
<EuiIconTip
content={I18LABELS.backEndTooltip}
type="questionInCircle"
/>
</>
}
isLoading={status !== 'success'}
/>
</EuiFlexItem>
<EuiFlexItem style={STAT_STYLE}>
<EuiStat
titleSize="l"
title={formatTitle('ms', data?.frontEnd?.value)}
description={
<>
{I18LABELS.frontEnd}
<EuiIconTip
content={I18LABELS.frontEndTooltip}
type="questionInCircle"
/>
</>
}
isLoading={status !== 'success'}
/>
</EuiFlexItem>
<EuiFlexItem style={STAT_STYLE}>
<EuiStat
titleSize="l"
title={<PageViewsTotalTitle pageViews={data?.pageViews?.value} />}
description={I18LABELS.pageViews}
isLoading={status !== 'success'}
/>
</EuiFlexItem>
</ClFlexGroup>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,134 +6,36 @@
*/

import * as React from 'react';
import numeral from '@elastic/numeral';
import styled from 'styled-components';
import { useContext, useEffect } from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiStat,
EuiToolTip,
EuiIconTip,
EuiPanel,
EuiTitle,
EuiSpacer,
} from '@elastic/eui';
import { useFetcher } from '../../../../hooks/use_fetcher';
import { I18LABELS } from '../translations';
import { useUxQuery } from '../hooks/useUxQuery';
import { formatToSec } from '../UXMetrics/KeyUXMetrics';
import { CsmSharedContext } from '../CsmSharedContext';

const ClFlexGroup = styled(EuiFlexGroup)`
flex-direction: row;
@media only screen and (max-width: 768px) {
flex-direction: row;
justify-content: space-between;
}
`;

function formatTitle(unit: string, value?: number) {
if (typeof value === 'undefined') return I18LABELS.dataMissing;
return formatToSec(value, unit);
}

function PageViewsTotalTitle({ pageViews }: { pageViews?: number }) {
if (typeof pageViews === 'undefined') {
return <>{I18LABELS.dataMissing}</>;
}
return pageViews < 10000 ? (
<>{numeral(pageViews).format('0,0')}</>
) : (
<EuiToolTip content={numeral(pageViews).format('0,0')}>
<>{numeral(pageViews).format('0 a')}</>
</EuiToolTip>
);
}
import { getPercentileLabel } from '../UXMetrics/translations';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
import { Metrics } from './Metrics';

export function ClientMetrics() {
const uxQuery = useUxQuery();

const { data, status } = useFetcher(
(callApmApi) => {
if (uxQuery) {
return callApmApi({
endpoint: 'GET /api/apm/rum/client-metrics',
params: {
query: {
...uxQuery,
},
},
});
}
return Promise.resolve(null);
},
[uxQuery]
);

const { setSharedData } = useContext(CsmSharedContext);

useEffect(() => {
setSharedData({ totalPageViews: data?.pageViews?.value ?? 0 });
}, [data, setSharedData]);

const STAT_STYLE = { width: '240px' };
const {
urlParams: { percentile },
} = useUrlParams();

return (
<ClFlexGroup responsive={false}>
<EuiFlexItem grow={false} style={STAT_STYLE}>
<EuiStat
titleSize="l"
title={formatTitle('ms', data?.totalPageLoadDuration?.value)}
description={
<>
{I18LABELS.totalPageLoad}
<EuiIconTip
content={I18LABELS.totalPageLoadTooltip}
type="questionInCircle"
/>
</>
}
isLoading={status !== 'success'}
/>
</EuiFlexItem>
<EuiFlexItem grow={false} style={STAT_STYLE}>
<EuiStat
titleSize="l"
title={formatTitle('ms', data?.backEnd?.value)}
description={
<>
{I18LABELS.backEnd}
<EuiIconTip
content={I18LABELS.backEndTooltip}
type="questionInCircle"
/>
</>
}
isLoading={status !== 'success'}
/>
</EuiFlexItem>
<EuiFlexItem grow={false} style={STAT_STYLE}>
<EuiStat
titleSize="l"
title={formatTitle('ms', data?.frontEnd?.value)}
description={
<>
{I18LABELS.frontEnd}
<EuiIconTip
content={I18LABELS.frontEndTooltip}
type="questionInCircle"
/>
</>
}
isLoading={status !== 'success'}
/>
</EuiFlexItem>
<EuiFlexItem grow={false} style={STAT_STYLE}>
<EuiStat
titleSize="l"
title={<PageViewsTotalTitle pageViews={data?.pageViews?.value} />}
description={I18LABELS.pageViews}
isLoading={status !== 'success'}
/>
</EuiFlexItem>
</ClFlexGroup>
<EuiPanel>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={1} data-cy={`client-metrics`}>
<EuiTitle size="xs">
<h3>
{I18LABELS.pageLoad} ({getPercentileLabel(percentile!)})
</h3>
</EuiTitle>
<EuiSpacer size="s" />
<Metrics />
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import {
EuiSpacer,
EuiHorizontalRule,
EuiButtonEmpty,
EuiAccordion,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { euiStyled } from '../../../../../../../../src/plugins/kibana_react/common';
import { Filter } from './Filter';
import { useLocalUIFilters } from '../hooks/useLocalUIFilters';
import { LocalUIFilterName } from '../../../../../common/ui_filter';
import { useBreakPoints } from '../../../../hooks/use_break_points';

interface Props {
filterNames: LocalUIFilterName[];
Expand Down Expand Up @@ -45,16 +47,20 @@ function LocalUIFilters({

const hasValues = filters.some((filter) => filter.value.length > 0);

return (
const { isSmall } = useBreakPoints();

const title = (
<EuiTitle size="s">
<h3>
{i18n.translate('xpack.apm.localFiltersTitle', {
defaultMessage: 'Filters',
})}
</h3>
</EuiTitle>
);

const content = (
<>
<EuiTitle size="s">
<h3>
{i18n.translate('xpack.apm.localFiltersTitle', {
defaultMessage: 'Filters',
})}
</h3>
</EuiTitle>
<EuiSpacer size="s" />
{children}
{filters.map((filter) => {
return (
Expand Down Expand Up @@ -90,6 +96,18 @@ function LocalUIFilters({
) : null}
</>
);

return isSmall ? (
<EuiAccordion id={'uxFilterAccordion'} buttonContent={title}>
{content}
</EuiAccordion>
) : (
<>
{title}
<EuiSpacer size="s" />
{content}
</>
);
}

export { LocalUIFilters };
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { useFetcher } from '../../../../hooks/use_fetcher';
import { RUM_AGENT_NAMES } from '../../../../../common/agent_name';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
import { UserPercentile } from '../UserPercentile';
import { useBreakPoints } from '../../../../hooks/use_break_points';

export function MainFilters() {
const {
Expand All @@ -37,6 +38,11 @@ export function MainFilters() {
[start, end]
);

const { isSmall } = useBreakPoints();

// on mobile we want it to take full width
const envStyle = isSmall ? {} : { maxWidth: 200 };

return (
<>
<EuiFlexItem grow={false}>
Expand All @@ -45,7 +51,7 @@ export function MainFilters() {
serviceNames={data ?? []}
/>
</EuiFlexItem>
<EuiFlexItem grow={false} style={{ maxWidth: 200 }}>
<EuiFlexItem grow={false} style={envStyle}>
<EnvironmentFilter />
</EuiFlexItem>
<EuiFlexItem grow={false}>
Expand Down
Loading

0 comments on commit 9c0fdcf

Please sign in to comment.