Port page views migration to separate branch. (#134758)

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Justin Kambic 2022-06-28 12:42:51 -04:00 committed by GitHub
parent b26b73db54
commit 4e3ef399f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 123 additions and 749 deletions

View file

@ -270,51 +270,3 @@ Object {
},
}
`;
exports[`rum client dashboard queries fetches page view trends 1`] = `
Object {
"apm": Object {
"events": Array [
"transaction",
],
},
"body": Object {
"aggs": Object {
"pageViews": Object {
"aggs": undefined,
"auto_date_histogram": Object {
"buckets": 50,
"field": "@timestamp",
},
},
},
"query": Object {
"bool": Object {
"filter": Array [
Object {
"range": Object {
"@timestamp": Object {
"format": "epoch_millis",
"gte": 0,
"lte": 50000,
},
},
},
Object {
"term": Object {
"transaction.type": "page-load",
},
},
Object {
"term": Object {
"service.environment": "staging",
},
},
],
"must_not": Array [],
},
},
"size": 0,
},
}
`;

View file

@ -1,126 +0,0 @@
/*
* 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 { getRumPageLoadTransactionsProjection } from '../../projections/rum_page_load_transactions';
import { mergeProjection } from '../../projections/util/merge_projection';
import { SetupUX } from './route';
export interface BreakdownItem {
name: string;
type: string;
fieldName: string;
selected?: boolean;
}
export async function getPageViewTrends({
setup,
breakdowns,
urlQuery,
start,
end,
}: {
setup: SetupUX;
breakdowns?: string;
urlQuery?: string;
start: number;
end: number;
}) {
const projection = getRumPageLoadTransactionsProjection({
setup,
urlQuery,
checkFetchStartFieldExists: false,
start,
end,
});
let breakdownItem: BreakdownItem | null = null;
if (breakdowns) {
breakdownItem = JSON.parse(breakdowns);
}
const params = mergeProjection(projection, {
body: {
size: 0,
query: {
bool: projection.body.query.bool,
},
aggs: {
pageViews: {
auto_date_histogram: {
field: '@timestamp',
buckets: 50,
},
aggs: breakdownItem
? {
breakdown: {
terms: {
field: breakdownItem.fieldName,
size: 9,
missing: 'Others',
},
},
}
: undefined,
},
...(breakdownItem
? {
topBreakdowns: {
terms: {
field: breakdownItem.fieldName,
size: 9,
},
},
}
: {}),
},
},
});
const { apmEventClient } = setup;
const response = await apmEventClient.search('get_page_view_trends', params);
const { topBreakdowns } = response.aggregations ?? {};
// we are only displaying top 9
const topItems: string[] = (topBreakdowns?.buckets ?? []).map(
({ key }) => key as string
);
const result = response.aggregations?.pageViews.buckets ?? [];
return {
topItems,
items: result.map((bucket) => {
const { key: xVal, doc_count: bCount } = bucket;
const res: Record<string, number> = {
x: xVal,
y: bCount,
};
if ('breakdown' in bucket) {
let top9Count = 0;
const categoryBuckets = bucket.breakdown.buckets;
categoryBuckets.forEach(({ key, doc_count: docCount }) => {
if (topItems.includes(key as string)) {
if (res[key]) {
// if term is already in object, just add it to it
res[key] += docCount;
} else {
res[key] = docCount;
}
top9Count += docCount;
}
});
// Top 9 plus others, get a diff from parent bucket total
if (bCount > top9Count) {
res.Others = bCount - top9Count;
}
}
return res;
}),
};
}

View file

@ -9,7 +9,6 @@ import {
SearchParamsMock,
inspectSearchParams,
} from '../../utils/test_helpers';
import { getPageViewTrends } from './get_page_view_trends';
import { getPageLoadDistribution } from './get_page_load_distribution';
describe('rum client dashboard queries', () => {
@ -19,20 +18,6 @@ describe('rum client dashboard queries', () => {
mock.teardown();
});
it('fetches page view trends', async () => {
mock = await inspectSearchParams(
(setup) =>
getPageViewTrends({
setup,
start: 0,
end: 50000,
}),
{ uiFilters: { environment: 'staging' } }
);
expect(mock.params).toMatchSnapshot();
});
it('fetches page load distribution', async () => {
mock = await inspectSearchParams(
(setup) =>

View file

@ -8,7 +8,6 @@ import * as t from 'io-ts';
import { Logger } from '@kbn/core/server';
import { setupRequest, Setup } from '../../lib/helpers/setup_request';
import { getPageLoadDistribution } from './get_page_load_distribution';
import { getPageViewTrends } from './get_page_view_trends';
import { getPageLoadDistBreakdown } from './get_pl_dist_breakdown';
import { createApmServerRoute } from '../apm_routes/create_apm_server_route';
import { rangeRt } from '../default_api_types';
@ -126,31 +125,6 @@ const rumPageLoadDistBreakdownRoute = createApmServerRoute({
},
});
const rumPageViewsTrendRoute = createApmServerRoute({
endpoint: 'GET /internal/apm/ux/page-view-trends',
params: t.type({
query: t.intersection([uxQueryRt, t.partial({ breakdowns: t.string })]),
}),
options: { tags: ['access:apm'] },
handler: async (
resources
): Promise<{ topItems: string[]; items: Array<Record<string, number>> }> => {
const setup = await setupUXRequest(resources);
const {
query: { breakdowns, urlQuery, start, end },
} = resources.params;
return getPageViewTrends({
setup,
breakdowns,
urlQuery,
start,
end,
});
},
});
function decodeUiFilters(
logger: Logger,
uiFiltersEncoded?: string
@ -183,5 +157,4 @@ async function setupUXRequest<TParams extends SetupUXRequestParams>(
export const rumRouteRepository = {
...rumPageLoadDistributionRoute,
...rumPageLoadDistBreakdownRoute,
...rumPageViewsTrendRoute,
};

View file

@ -169,3 +169,5 @@ export const PERCENTILE_RANKS = [
];
export const LABEL_FIELDS_FILTER = 'LABEL_FIELDS_FILTER';
export const LABEL_FIELDS_BREAKDOWN = 'LABEL_FIELDS_BREAKDOWN';
export const ENVIRONMENT_ALL = 'ENVIRONMENT_ALL';

View file

@ -332,7 +332,7 @@ describe('Lens Attribute', () => {
formulaHelper
).getJSON() as any;
expect(lensAttrWithMultiSeries.state.visualization.axisTitlesVisibilitySettings).toEqual({
x: true,
x: false,
yLeft: false,
yRight: false,
});
@ -345,7 +345,7 @@ describe('Lens Attribute', () => {
formulaHelper
).getJSON() as any;
expect(lensAttrWithMultiSeries.state.visualization.axisTitlesVisibilitySettings).toEqual({
x: true,
x: false,
yLeft: true,
yRight: true,
});
@ -357,10 +357,10 @@ describe('Lens Attribute', () => {
it('should return expected XYState', function () {
expect(lnsAttr.getXyState()).toEqual({
axisTitlesVisibilitySettings: { x: true, yLeft: true, yRight: true },
axisTitlesVisibilitySettings: { x: false, yLeft: true, yRight: true },
curveType: 'CURVE_MONOTONE_X',
fittingFunction: 'Linear',
gridlinesVisibilitySettings: { x: true, yLeft: true, yRight: true },
gridlinesVisibilitySettings: { x: false, yLeft: true, yRight: true },
layers: [
{
accessors: ['y-axis-column-layer0'],

View file

@ -876,12 +876,12 @@ export class LensAttributes {
fittingFunction: 'Linear',
curveType: 'CURVE_MONOTONE_X' as XYCurveType,
axisTitlesVisibilitySettings: {
x: true,
x: false,
yLeft: !this.isMultiSeries,
yRight: !this.isMultiSeries,
},
tickLabelsVisibilitySettings: { x: true, yLeft: true, yRight: true },
gridlinesVisibilitySettings: { x: true, yLeft: true, yRight: true },
gridlinesVisibilitySettings: { x: false, yLeft: true, yRight: true },
preferredSeriesType: 'line',
layers: this.getDataLayers(),
...(this.layerConfigs[0].seriesConfig.yTitle

View file

@ -61,15 +61,16 @@ export const testMobileKPIAttr = {
valueLabels: 'hide',
fittingFunction: 'Linear',
curveType: 'CURVE_MONOTONE_X',
axisTitlesVisibilitySettings: { x: true, yLeft: true, yRight: true },
axisTitlesVisibilitySettings: { x: false, yLeft: true, yRight: true },
tickLabelsVisibilitySettings: { x: true, yLeft: true, yRight: true },
gridlinesVisibilitySettings: { x: true, yLeft: true, yRight: true },
gridlinesVisibilitySettings: { x: false, yLeft: true, yRight: true },
preferredSeriesType: 'line',
layers: [
{
accessors: ['y-axis-column-layer0'],
layerId: 'layer0',
layerType: 'data',
palette: undefined,
seriesType: 'line',
yConfig: [{ forAccessor: 'y-axis-column-layer0', color: 'green', axisMode: 'left' }],
xAccessor: 'x-axis-column-layer0',

View file

@ -98,6 +98,8 @@ export const sampleAttribute = {
},
scale: 'ratio',
sourceField: RECORDS_FIELD,
timeScale: undefined,
timeShift: undefined,
},
'y-axis-column-layer0X1': {
customLabel: true,
@ -115,6 +117,8 @@ export const sampleAttribute = {
},
scale: 'ratio',
sourceField: RECORDS_FIELD,
timeScale: undefined,
timeShift: undefined,
},
'y-axis-column-layer0X2': {
customLabel: true,
@ -122,6 +126,7 @@ export const sampleAttribute = {
isBucketed: false,
label: 'Part of Pages loaded',
operationType: 'overall_sum',
params: undefined,
references: ['y-axis-column-layer0X1'],
scale: 'ratio',
},
@ -232,14 +237,14 @@ export const sampleAttribute = {
},
visualization: {
axisTitlesVisibilitySettings: {
x: true,
x: false,
yLeft: true,
yRight: true,
},
curveType: 'CURVE_MONOTONE_X',
fittingFunction: 'Linear',
gridlinesVisibilitySettings: {
x: true,
x: false,
yLeft: true,
yRight: true,
},
@ -248,6 +253,7 @@ export const sampleAttribute = {
accessors: ['y-axis-column-layer0'],
layerId: 'layer0',
layerType: 'data',
palette: undefined,
seriesType: 'line',
xAccessor: 'x-axis-column-layer0',
yConfig: [

View file

@ -102,14 +102,14 @@ export const sampleAttributeCoreWebVital = {
},
visualization: {
axisTitlesVisibilitySettings: {
x: true,
x: false,
yLeft: true,
yRight: true,
},
curveType: 'CURVE_MONOTONE_X',
fittingFunction: 'Linear',
gridlinesVisibilitySettings: {
x: true,
x: false,
yLeft: true,
yRight: true,
},
@ -118,6 +118,7 @@ export const sampleAttributeCoreWebVital = {
accessors: ['y-axis-column-layer0', 'y-axis-column-1', 'y-axis-column-2'],
layerId: 'layer0',
layerType: 'data',
palette: undefined,
seriesType: 'bar_horizontal_percentage_stacked',
xAccessor: 'x-axis-column-layer0',
yConfig: [

View file

@ -63,14 +63,14 @@ export const sampleAttributeKpi = {
},
visualization: {
axisTitlesVisibilitySettings: {
x: true,
x: false,
yLeft: true,
yRight: true,
},
curveType: 'CURVE_MONOTONE_X',
fittingFunction: 'Linear',
gridlinesVisibilitySettings: {
x: true,
x: false,
yLeft: true,
yRight: true,
},
@ -79,6 +79,7 @@ export const sampleAttributeKpi = {
accessors: ['y-axis-column-layer0'],
layerId: 'layer0',
layerType: 'data',
palette: undefined,
seriesType: 'line',
xAccessor: 'x-axis-column-layer0',
yConfig: [

View file

@ -98,6 +98,8 @@ export const sampleAttributeWithReferenceLines = {
},
scale: 'ratio',
sourceField: RECORDS_FIELD,
timeScale: undefined,
timeShift: undefined,
},
'y-axis-column-layer0X1': {
customLabel: true,
@ -115,6 +117,8 @@ export const sampleAttributeWithReferenceLines = {
},
scale: 'ratio',
sourceField: RECORDS_FIELD,
timeScale: undefined,
timeShift: undefined,
},
'y-axis-column-layer0X2': {
customLabel: true,
@ -122,6 +126,7 @@ export const sampleAttributeWithReferenceLines = {
isBucketed: false,
label: 'Part of Pages loaded',
operationType: 'overall_sum',
params: undefined,
references: ['y-axis-column-layer0X1'],
scale: 'ratio',
},
@ -232,14 +237,14 @@ export const sampleAttributeWithReferenceLines = {
},
visualization: {
axisTitlesVisibilitySettings: {
x: true,
x: false,
yLeft: true,
yRight: true,
},
curveType: 'CURVE_MONOTONE_X',
fittingFunction: 'Linear',
gridlinesVisibilitySettings: {
x: true,
x: false,
yLeft: true,
yRight: true,
},
@ -248,6 +253,7 @@ export const sampleAttributeWithReferenceLines = {
accessors: ['y-axis-column-layer0'],
layerId: 'layer0',
layerType: 'data',
palette: undefined,
seriesType: 'line',
xAccessor: 'x-axis-column-layer0',
yConfig: [

View file

@ -104,6 +104,7 @@ export type { SeriesConfig, ConfigProps } from './components/shared/exploratory_
export {
ReportTypes,
FILTER_RECORDS,
ENVIRONMENT_ALL,
REPORT_METRIC_FIELD,
USE_BREAK_DOWN_COLUMN,
RECORDS_FIELD,

View file

@ -84,7 +84,6 @@ export function BreakdownFilter({
return (
<EuiSuperSelect
fullWidth
compressed
options={options}
valueOfSelected={selectedBreakdown?.fieldName ?? NO_BREAKDOWN}

View file

@ -32,9 +32,9 @@ import { useUiSetting$ } from '@kbn/kibana-react-plugin/public';
import { PercentileAnnotations } from '../page_load_distribution/percentile_annotations';
import { I18LABELS } from '../translations';
import { ChartWrapper } from '../chart_wrapper';
import { PercentileRange } from '../page_load_distribution';
import { BreakdownSeries } from '../page_load_distribution/breakdown_series';
import { BreakdownItem } from '../../../../../typings/ui_filters';
import { PercentileRange } from '../page_load_distribution/types';
interface PageLoadData {
pageLoadDistribution: Array<{ x: number; y: number }>;

View file

@ -5,59 +5,79 @@
* 2.0.
*/
import moment from 'moment';
import React from 'react';
import {
Axis,
BarSeries,
BrushEndListener,
Chart,
DARK_THEME,
LIGHT_THEME,
niceTimeFormatByDay,
ScaleType,
SeriesNameFn,
Settings,
timeFormatter,
Position,
} from '@elastic/charts';
AllSeries,
ALL_VALUES_SELECTED,
fromQuery,
RECORDS_FIELD,
toQuery,
} from '@kbn/observability-plugin/public';
import { useHistory } from 'react-router-dom';
import {
EUI_CHARTS_THEME_DARK,
EUI_CHARTS_THEME_LIGHT,
} from '@elastic/eui/dist/eui_charts_theme';
import numeral from '@elastic/numeral';
import moment from 'moment';
import React from 'react';
import { useHistory } from 'react-router-dom';
import { useUiSetting$ } from '@kbn/kibana-react-plugin/public';
import { fromQuery, toQuery } from '@kbn/observability-plugin/public';
import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values';
import { BreakdownItem, UxUIFilters } from '../../../../../typings/ui_filters';
import { useLegacyUrlParams } from '../../../../context/url_params_context/use_url_params';
import { ChartWrapper } from '../chart_wrapper';
import { I18LABELS } from '../translations';
import { useKibanaServices } from '../../../../hooks/use_kibana_services';
import { useDataView } from '../local_uifilters/use_data_view';
import {
SERVICE_ENVIRONMENT,
SERVICE_NAME,
} from '../../../../../common/elasticsearch_fieldnames';
interface Props {
data?: {
topItems: string[];
items: Array<Record<string, number | null>>;
};
loading: boolean;
breakdown: BreakdownItem | null;
uiFilters: UxUIFilters;
}
export function PageViewsChart({ data, loading }: Props) {
export function PageViewsChart({ breakdown, uiFilters }: Props) {
const { dataViewTitle } = useDataView();
const history = useHistory();
const { urlParams } = useLegacyUrlParams();
const kibana = useKibanaServices();
const { ExploratoryViewEmbeddable } = kibana.observability;
const { start, end } = urlParams;
const diffInDays = moment(new Date(end as string)).diff(
moment(new Date(start as string)),
'day'
);
const formatter = timeFormatter(niceTimeFormatByDay(diffInDays > 1 ? 2 : 1));
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
const onBrushEnd: BrushEndListener = ({ x }) => {
if (!x) {
const euiChartTheme = darkMode
? EUI_CHARTS_THEME_DARK
: EUI_CHARTS_THEME_LIGHT;
const allSeries: AllSeries = [
{
dataType: 'ux',
time: {
from: start ?? '',
to: end ?? '',
},
name: 'ux-series-1',
selectedMetricField: RECORDS_FIELD,
reportDefinitions: {
[SERVICE_ENVIRONMENT]:
!uiFilters?.environment ||
uiFilters.environment === ENVIRONMENT_ALL.value
? [ALL_VALUES_SELECTED]
: [uiFilters.environment],
[SERVICE_NAME]: urlParams.serviceName
? [urlParams.serviceName]
: [ALL_VALUES_SELECTED],
},
breakdown: breakdown?.fieldName,
color: euiChartTheme.theme.colors?.vizColors?.[1],
},
];
const onBrushEnd = ({ range }: { range: number[] }) => {
if (!range) {
return;
}
const [minX, maxX] = x;
const [minX, maxX] = range;
const rangeFrom = moment(minX).toISOString();
const rangeTo = moment(maxX).toISOString();
@ -72,67 +92,15 @@ export function PageViewsChart({ data, loading }: Props) {
});
};
const hasBreakdowns = !!data?.topItems?.length;
const breakdownAccessors = data?.topItems?.length ? data?.topItems : ['y'];
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
const customSeriesNaming: SeriesNameFn = ({ yAccessor }) => {
if (yAccessor === 'y') {
return I18LABELS.overall;
}
return yAccessor;
};
const euiChartTheme = darkMode
? EUI_CHARTS_THEME_DARK
: EUI_CHARTS_THEME_LIGHT;
return (
<ChartWrapper loading={loading} height="250px">
{(!loading || data) && (
<Chart>
<Settings
baseTheme={darkMode ? DARK_THEME : LIGHT_THEME}
theme={euiChartTheme.theme}
showLegend
onBrushEnd={onBrushEnd}
xDomain={{
min: new Date(start as string).valueOf(),
max: new Date(end as string).valueOf(),
}}
/>
<Axis
id="date_time"
position={Position.Bottom}
tickFormat={formatter}
/>
<Axis
id="page_views"
title={I18LABELS.pageViews}
position={Position.Left}
tickFormat={(d) => numeral(d).format('0')}
labelFormat={(d) => numeral(d).format('0a')}
/>
<BarSeries
id={I18LABELS.pageViews}
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor="x"
yAccessors={Array.from(breakdownAccessors)}
stackAccessors={['x']}
data={data?.items ?? []}
name={customSeriesNaming}
color={
!hasBreakdowns
? euiChartTheme.theme.colors?.vizColors?.[1]
: undefined
}
/>
</Chart>
)}
</ChartWrapper>
<ExploratoryViewEmbeddable
customHeight="300px"
attributes={allSeries}
onBrushEnd={onBrushEnd}
reportType="kpi-over-time"
dataTypesIndexPatterns={{ ux: dataViewTitle }}
isSingleMetric={true}
axisTitlesVisibility={{ x: false, yRight: true, yLeft: true }}
/>
);
}

View file

@ -13,7 +13,7 @@ import {
EUI_CHARTS_THEME_LIGHT,
} from '@elastic/eui/dist/eui_charts_theme';
import { useUiSetting$ } from '@kbn/kibana-react-plugin/public';
import { PercentileRange } from '.';
import { PercentileRange } from './types';
import { useBreakdowns } from './use_breakdowns';
interface Props {

View file

@ -23,11 +23,7 @@ import { PageLoadDistChart } from '../charts/page_load_dist_chart';
import { ResetPercentileZoom } from './reset_percentile_zoom';
import { useKibanaServices } from '../../../../hooks/use_kibana_services';
import { BreakdownItem } from '../../../../../typings/ui_filters';
export interface PercentileRange {
min?: number | null;
max?: number | null;
}
import { PercentileRange } from './types';
export function PageLoadDistribution() {
const { http } = useKibanaServices();

View file

@ -14,7 +14,7 @@ import {
EuiFlexItem,
} from '@elastic/eui';
import { I18LABELS } from '../translations';
import { PercentileRange } from '.';
import { PercentileRange } from './types';
interface Props {
percentileRange: PercentileRange;

View file

@ -0,0 +1,11 @@
/*
* 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.
*/
export interface PercentileRange {
min?: number | null;
max?: number | null;
}

View file

@ -7,7 +7,7 @@
import { useFetcher } from '../../../../hooks/use_fetcher';
import { useLegacyUrlParams } from '../../../../context/url_params_context/use_url_params';
import { PercentileRange } from '.';
import { PercentileRange } from './types';
interface Props {
percentileRange?: PercentileRange;

View file

@ -6,59 +6,27 @@
*/
import React, { useState } from 'react';
import {
EuiButton,
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { createExploratoryViewUrl } from '@kbn/observability-plugin/public';
import { useLegacyUrlParams } from '../../../../context/url_params_context/use_url_params';
import { useFetcher } from '../../../../hooks/use_fetcher';
import { I18LABELS } from '../translations';
import { BreakdownFilter } from '../breakdowns/breakdown_filter';
import { PageViewsChart } from '../charts/page_views_chart';
import { useKibanaServices } from '../../../../hooks/use_kibana_services';
import { BreakdownItem } from '../../../../../typings/ui_filters';
import { SERVICE_NAME } from '../../../../../common/elasticsearch_fieldnames';
export function PageViewsTrend() {
const { http } = useKibanaServices();
const { rangeId, urlParams, uxUiFilters } = useLegacyUrlParams();
const { urlParams, uxUiFilters } = useLegacyUrlParams();
const { serviceName } = uxUiFilters;
const { start, end, searchTerm, rangeTo, rangeFrom } = urlParams;
const { rangeTo, rangeFrom } = urlParams;
const [breakdown, setBreakdown] = useState<BreakdownItem | null>(null);
const { data, status } = useFetcher(
(callApmApi) => {
if (start && end && serviceName) {
return callApmApi('GET /internal/apm/ux/page-view-trends', {
params: {
query: {
start,
end,
uiFilters: JSON.stringify(uxUiFilters),
urlQuery: searchTerm,
...(breakdown
? {
breakdowns: JSON.stringify(breakdown),
}
: {}),
},
},
});
}
return Promise.resolve(undefined);
},
// `rangeId` acts as a cache buster for stable ranges like "Today"
// eslint-disable-next-line react-hooks/exhaustive-deps
[start, end, serviceName, uxUiFilters, searchTerm, breakdown, rangeId]
);
const exploratoryViewLink = createExploratoryViewUrl(
{
reportType: 'kpi-over-time',
@ -68,7 +36,7 @@ export function PageViewsTrend() {
dataType: 'ux',
time: { from: rangeFrom!, to: rangeTo! },
reportDefinitions: {
'service.name': serviceName as string[],
[SERVICE_NAME]: serviceName as string[],
},
...(breakdown ? { breakdown: breakdown.fieldName } : {}),
},
@ -80,7 +48,7 @@ export function PageViewsTrend() {
const showAnalyzeButton = false;
return (
<div>
<>
<EuiFlexGroup responsive={false}>
<EuiFlexItem>
<EuiTitle size="xs">
@ -109,8 +77,7 @@ export function PageViewsTrend() {
</EuiFlexItem>
)}
</EuiFlexGroup>
<EuiSpacer size="s" />
<PageViewsChart data={data} loading={status !== 'success'} />
</div>
<PageViewsChart breakdown={breakdown} uiFilters={uxUiFilters} />
</>
);
}

View file

@ -19,7 +19,7 @@ export function PageLoadAndViews() {
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem style={{ flexBasis: 650 }}>
<EuiPanel hasBorder={true}>
<EuiPanel hasBorder={true} style={{ paddingBottom: 0 }}>
<PageViewsTrend />
</EuiPanel>
</EuiFlexItem>

View file

@ -1,280 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`APM API tests trial 8.0.0,rum_8.0.0 CSM page views with data returns page views 1`] = `
Object {
"items": Array [
Object {
"x": 1600149947000,
"y": 1,
},
Object {
"x": 1600149957000,
"y": 0,
},
Object {
"x": 1600149967000,
"y": 0,
},
Object {
"x": 1600149977000,
"y": 0,
},
Object {
"x": 1600149987000,
"y": 0,
},
Object {
"x": 1600149997000,
"y": 0,
},
Object {
"x": 1600150007000,
"y": 0,
},
Object {
"x": 1600150017000,
"y": 0,
},
Object {
"x": 1600150027000,
"y": 1,
},
Object {
"x": 1600150037000,
"y": 0,
},
Object {
"x": 1600150047000,
"y": 0,
},
Object {
"x": 1600150057000,
"y": 0,
},
Object {
"x": 1600150067000,
"y": 0,
},
Object {
"x": 1600150077000,
"y": 1,
},
Object {
"x": 1600150087000,
"y": 0,
},
Object {
"x": 1600150097000,
"y": 0,
},
Object {
"x": 1600150107000,
"y": 0,
},
Object {
"x": 1600150117000,
"y": 0,
},
Object {
"x": 1600150127000,
"y": 0,
},
Object {
"x": 1600150137000,
"y": 0,
},
Object {
"x": 1600150147000,
"y": 0,
},
Object {
"x": 1600150157000,
"y": 0,
},
Object {
"x": 1600150167000,
"y": 0,
},
Object {
"x": 1600150177000,
"y": 1,
},
Object {
"x": 1600150187000,
"y": 0,
},
Object {
"x": 1600150197000,
"y": 0,
},
Object {
"x": 1600150207000,
"y": 1,
},
Object {
"x": 1600150217000,
"y": 0,
},
Object {
"x": 1600150227000,
"y": 0,
},
Object {
"x": 1600150237000,
"y": 1,
},
],
"topItems": Array [],
}
`;
exports[`APM API tests trial 8.0.0,rum_8.0.0 CSM page views with data returns page views with breakdown 1`] = `
Object {
"items": Array [
Object {
"Chrome": 1,
"x": 1600149947000,
"y": 1,
},
Object {
"x": 1600149957000,
"y": 0,
},
Object {
"x": 1600149967000,
"y": 0,
},
Object {
"x": 1600149977000,
"y": 0,
},
Object {
"x": 1600149987000,
"y": 0,
},
Object {
"x": 1600149997000,
"y": 0,
},
Object {
"x": 1600150007000,
"y": 0,
},
Object {
"x": 1600150017000,
"y": 0,
},
Object {
"Chrome": 1,
"x": 1600150027000,
"y": 1,
},
Object {
"x": 1600150037000,
"y": 0,
},
Object {
"x": 1600150047000,
"y": 0,
},
Object {
"x": 1600150057000,
"y": 0,
},
Object {
"x": 1600150067000,
"y": 0,
},
Object {
"Chrome": 1,
"x": 1600150077000,
"y": 1,
},
Object {
"x": 1600150087000,
"y": 0,
},
Object {
"x": 1600150097000,
"y": 0,
},
Object {
"x": 1600150107000,
"y": 0,
},
Object {
"x": 1600150117000,
"y": 0,
},
Object {
"x": 1600150127000,
"y": 0,
},
Object {
"x": 1600150137000,
"y": 0,
},
Object {
"x": 1600150147000,
"y": 0,
},
Object {
"x": 1600150157000,
"y": 0,
},
Object {
"x": 1600150167000,
"y": 0,
},
Object {
"Chrome": 1,
"x": 1600150177000,
"y": 1,
},
Object {
"x": 1600150187000,
"y": 0,
},
Object {
"x": 1600150197000,
"y": 0,
},
Object {
"Chrome Mobile": 1,
"x": 1600150207000,
"y": 1,
},
Object {
"x": 1600150217000,
"y": 0,
},
Object {
"x": 1600150227000,
"y": 0,
},
Object {
"Chrome Mobile": 1,
"x": 1600150237000,
"y": 1,
},
],
"topItems": Array [
"Chrome",
"Chrome Mobile",
],
}
`;
exports[`APM API tests trial no data CSM page views without data returns empty list 1`] = `
Object {
"items": Array [],
"topItems": Array [],
}
`;
exports[`APM API tests trial no data CSM page views without data returns empty list with breakdowns 1`] = `
Object {
"items": Array [],
"topItems": Array [],
}
`;

View file

@ -1,89 +0,0 @@
/*
* 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 expect from '@kbn/expect';
import { FtrProviderContext } from '../../common/ftr_provider_context';
export default function rumServicesApiTests({ getService }: FtrProviderContext) {
const registry = getService('registry');
const apmApiClient = getService('apmApiClient');
registry.when('CSM page views without data', { config: 'trial', archives: [] }, () => {
it('returns empty list', async () => {
const response = await apmApiClient.readUser({
endpoint: 'GET /internal/apm/ux/page-view-trends',
params: {
query: {
start: '2020-09-07T20:35:54.654Z',
end: '2020-09-14T20:35:54.654Z',
uiFilters: '{"serviceName":["elastic-co-rum-test"]}',
},
},
});
expect(response.status).to.be(200);
expectSnapshot(response.body).toMatch();
});
it('returns empty list with breakdowns', async () => {
const response = await apmApiClient.readUser({
endpoint: 'GET /internal/apm/ux/page-view-trends',
params: {
query: {
start: '2020-09-07T20:35:54.654Z',
end: '2020-09-14T20:35:54.654Z',
uiFilters: '{"serviceName":["elastic-co-rum-test"]}',
breakdowns: '{"name":"Browser","fieldName":"user_agent.name","type":"category"}',
},
},
});
expect(response.status).to.be(200);
expectSnapshot(response.body).toMatch();
});
});
registry.when(
'CSM page views with data',
{ config: 'trial', archives: ['8.0.0', 'rum_8.0.0'] },
() => {
it('returns page views', async () => {
const response = await apmApiClient.readUser({
endpoint: 'GET /internal/apm/ux/page-view-trends',
params: {
query: {
start: '2020-09-07T20:35:54.654Z',
end: '2020-09-16T20:35:54.654Z',
uiFilters: '{"serviceName":["kibana-frontend-8_0_0"]}',
},
},
});
expect(response.status).to.be(200);
expectSnapshot(response.body).toMatch();
});
it('returns page views with breakdown', async () => {
const response = await apmApiClient.readUser({
endpoint: 'GET /internal/apm/ux/page-view-trends',
params: {
query: {
start: '2020-09-07T20:35:54.654Z',
end: '2020-09-16T20:35:54.654Z',
uiFilters: '{"serviceName":["kibana-frontend-8_0_0"]}',
breakdowns: '{"name":"Browser","fieldName":"user_agent.name","type":"category"}',
},
},
});
expect(response.status).to.be(200);
expectSnapshot(response.body).toMatch();
});
}
);
}