mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Synthetics] Test run detail page skeleton (#144715)
This commit is contained in:
parent
c9f0f3e3d4
commit
098b5db77b
20 changed files with 338 additions and 158 deletions
|
@ -431,7 +431,7 @@ describe('Lens Attribute', () => {
|
|||
isVisible: true,
|
||||
showSingleSeries: true,
|
||||
position: 'right',
|
||||
legendSize: 'large',
|
||||
legendSize: 'auto',
|
||||
shouldTruncate: false,
|
||||
},
|
||||
preferredSeriesType: 'line',
|
||||
|
|
|
@ -1060,7 +1060,7 @@ export class LensAttributes {
|
|||
isVisible: true,
|
||||
showSingleSeries: true,
|
||||
position: 'right',
|
||||
legendSize: LegendSize.LARGE,
|
||||
legendSize: LegendSize.AUTO,
|
||||
shouldTruncate: false,
|
||||
},
|
||||
valueLabels: 'hide',
|
||||
|
|
|
@ -66,7 +66,7 @@ export const testMobileKPIAttr = {
|
|||
isVisible: true,
|
||||
showSingleSeries: true,
|
||||
position: 'right',
|
||||
legendSize: 'large',
|
||||
legendSize: 'auto',
|
||||
shouldTruncate: false,
|
||||
},
|
||||
valueLabels: 'hide',
|
||||
|
|
|
@ -325,7 +325,7 @@ export const sampleAttribute = {
|
|||
isVisible: true,
|
||||
position: 'right',
|
||||
showSingleSeries: true,
|
||||
legendSize: 'large',
|
||||
legendSize: 'auto',
|
||||
shouldTruncate: false,
|
||||
},
|
||||
preferredSeriesType: 'line',
|
||||
|
|
|
@ -145,7 +145,7 @@ export const sampleAttributeCoreWebVital = {
|
|||
showSingleSeries: true,
|
||||
position: 'right',
|
||||
shouldTruncate: false,
|
||||
legendSize: 'large',
|
||||
legendSize: 'auto',
|
||||
},
|
||||
preferredSeriesType: 'line',
|
||||
tickLabelsVisibilitySettings: {
|
||||
|
|
|
@ -98,7 +98,7 @@ export const sampleAttributeKpi = {
|
|||
isVisible: true,
|
||||
showSingleSeries: true,
|
||||
position: 'right',
|
||||
legendSize: 'large',
|
||||
legendSize: 'auto',
|
||||
shouldTruncate: false,
|
||||
},
|
||||
preferredSeriesType: 'line',
|
||||
|
|
|
@ -325,7 +325,7 @@ export const sampleAttributeWithReferenceLines = {
|
|||
isVisible: true,
|
||||
position: 'right',
|
||||
showSingleSeries: true,
|
||||
legendSize: 'large',
|
||||
legendSize: 'auto',
|
||||
shouldTruncate: false,
|
||||
},
|
||||
preferredSeriesType: 'line',
|
||||
|
|
|
@ -33,6 +33,8 @@ export const STEP_DETAIL_ROUTE = '/journey/:checkGroupId/step/:stepIndex';
|
|||
|
||||
export const SYNTHETIC_CHECK_STEPS_ROUTE = '/journey/:checkGroupId/steps';
|
||||
|
||||
export const TEST_RUN_DETAILS_ROUTE = '/monitor/:monitorId/test-run/:checkGroupId';
|
||||
|
||||
export const MAPPING_ERROR_ROUTE = '/mapping-error';
|
||||
|
||||
export const ERROR_DETAILS_ROUTE = '/error-details/:errorStateId';
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { EuiLink, EuiText, useEuiTheme } from '@elastic/eui';
|
||||
import { Ping } from '../../../../../../common/runtime_types';
|
||||
import { useSyntheticsSettingsContext } from '../../../contexts';
|
||||
import { useKibanaDateFormat } from '../../../../../hooks/use_kibana_date_format';
|
||||
import { formatTestRunAt } from '../../../utils/monitor_test_result/test_time_formats';
|
||||
|
||||
export const TestDetailsLink = ({
|
||||
isBrowserMonitor,
|
||||
timestamp,
|
||||
ping,
|
||||
}: {
|
||||
isBrowserMonitor: boolean;
|
||||
timestamp: string;
|
||||
ping: Ping;
|
||||
}) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const { basePath } = useSyntheticsSettingsContext();
|
||||
|
||||
const format = useKibanaDateFormat();
|
||||
const timestampText = (
|
||||
<EuiText size="s" css={{ fontWeight: euiTheme.font.weight.medium }}>
|
||||
{formatTestRunAt(timestamp, format)}
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
return isBrowserMonitor ? (
|
||||
<EuiLink
|
||||
href={`${basePath}/app/synthetics/monitor/${ping?.config_id ?? ''}/test-run/${
|
||||
ping.monitor.check_group
|
||||
}`}
|
||||
>
|
||||
{timestampText}
|
||||
</EuiLink>
|
||||
) : (
|
||||
timestampText
|
||||
);
|
||||
};
|
|
@ -16,11 +16,11 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { EuiThemeComputed } from '@elastic/eui/src/services/theme/types';
|
||||
|
||||
import { JourneyStepScreenshotContainer } from '../screenshot/journey_step_screenshot_container';
|
||||
import { useSyntheticsSettingsContext } from '../../../contexts/synthetics_settings_context';
|
||||
import { JourneyStep } from '../../../../../../common/runtime_types';
|
||||
|
||||
import { StatusBadge, parseBadgeStatus, getTextColorForMonitorStatus } from './status_badge';
|
||||
import { JourneyStepScreenshotWithLabel } from './journey_step_screenshot_with_label';
|
||||
import { StepDurationText } from './step_duration_text';
|
||||
|
||||
interface Props {
|
||||
|
@ -28,13 +28,20 @@ interface Props {
|
|||
error?: Error;
|
||||
loading: boolean;
|
||||
showStepNumber: boolean;
|
||||
compressed?: boolean;
|
||||
}
|
||||
|
||||
export function isStepEnd(step: JourneyStep) {
|
||||
return step.synthetics?.type === 'step/end';
|
||||
}
|
||||
|
||||
export const BrowserStepsList = ({ steps, error, loading, showStepNumber = false }: Props) => {
|
||||
export const BrowserStepsList = ({
|
||||
steps,
|
||||
error,
|
||||
loading,
|
||||
showStepNumber = false,
|
||||
compressed = true,
|
||||
}: Props) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const stepEnds: JourneyStep[] = steps.filter(isStepEnd);
|
||||
const stepLabels = stepEnds.map((stepEnd) => stepEnd?.synthetics?.step?.name ?? '');
|
||||
|
@ -56,13 +63,15 @@ export const BrowserStepsList = ({ steps, error, loading, showStepNumber = false
|
|||
{
|
||||
align: 'left',
|
||||
field: 'timestamp',
|
||||
name: STEP_LABEL,
|
||||
render: (_timestamp: string, item) => (
|
||||
<JourneyStepScreenshotWithLabel
|
||||
step={item}
|
||||
stepLabels={stepLabels}
|
||||
compactView={true}
|
||||
name: SCREENSHOT_LABEL,
|
||||
render: (_timestamp: string, step) => (
|
||||
<JourneyStepScreenshotContainer
|
||||
checkGroup={step.monitor.check_group}
|
||||
initialStepNo={step.synthetics?.step?.index}
|
||||
stepStatus={step.synthetics.payload?.status}
|
||||
allStepsLoaded={true}
|
||||
stepLabels={stepLabels}
|
||||
retryFetchOnRevisit={false}
|
||||
/>
|
||||
),
|
||||
mobileOptions: {
|
||||
|
@ -73,10 +82,27 @@ export const BrowserStepsList = ({ steps, error, loading, showStepNumber = false
|
|||
</strong>
|
||||
</EuiText>
|
||||
),
|
||||
header: STEP_LABEL,
|
||||
header: SCREENSHOT_LABEL,
|
||||
enlarge: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'synthetics.step.name',
|
||||
name: STEP_NAME,
|
||||
render: (stepName: string, item) => {
|
||||
const status = parseBadgeStatus(item.synthetics.step?.status ?? '');
|
||||
|
||||
const textColor = euiTheme.colors[
|
||||
getTextColorForMonitorStatus(status)
|
||||
] as CSSProperties['color'];
|
||||
|
||||
return (
|
||||
<EuiText color={textColor} size="m">
|
||||
{stepName}
|
||||
</EuiText>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'synthetics.step.status',
|
||||
name: RESULT_LABEL,
|
||||
|
@ -114,7 +140,7 @@ export const BrowserStepsList = ({ steps, error, loading, showStepNumber = false
|
|||
return (
|
||||
<>
|
||||
<EuiBasicTable
|
||||
compressed={true}
|
||||
compressed={compressed}
|
||||
loading={loading}
|
||||
columns={columns}
|
||||
error={error?.message}
|
||||
|
@ -164,8 +190,12 @@ const RESULT_LABEL = i18n.translate('xpack.synthetics.monitor.result.label', {
|
|||
defaultMessage: 'Result',
|
||||
});
|
||||
|
||||
const STEP_LABEL = i18n.translate('xpack.synthetics.monitor.step.label', {
|
||||
defaultMessage: 'Step',
|
||||
const SCREENSHOT_LABEL = i18n.translate('xpack.synthetics.monitor.screenshot.label', {
|
||||
defaultMessage: 'Screenshot',
|
||||
});
|
||||
|
||||
const STEP_NAME = i18n.translate('xpack.synthetics.monitor.stepName.label', {
|
||||
defaultMessage: 'Step name',
|
||||
});
|
||||
|
||||
const STEP_DURATION = i18n.translate('xpack.synthetics.monitor.step.duration.label', {
|
||||
|
|
|
@ -1,50 +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 React, { CSSProperties } from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiText, useEuiTheme } from '@elastic/eui';
|
||||
import { JourneyStep } from '../../../../../../common/runtime_types';
|
||||
import { JourneyStepScreenshotContainer } from '../screenshot/journey_step_screenshot_container';
|
||||
import { getTextColorForMonitorStatus, parseBadgeStatus } from './status_badge';
|
||||
|
||||
interface Props {
|
||||
step: JourneyStep;
|
||||
stepLabels?: string[];
|
||||
allStepsLoaded?: boolean;
|
||||
compactView?: boolean;
|
||||
}
|
||||
|
||||
export const JourneyStepScreenshotWithLabel = ({
|
||||
step,
|
||||
stepLabels = [],
|
||||
compactView,
|
||||
allStepsLoaded,
|
||||
}: Props) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const status = parseBadgeStatus(step.synthetics.step?.status ?? '');
|
||||
const textColor = euiTheme.colors[getTextColorForMonitorStatus(status)] as CSSProperties['color'];
|
||||
|
||||
return (
|
||||
<EuiFlexGroup alignItems="center" gutterSize="s" wrap>
|
||||
<EuiFlexItem grow={false}>
|
||||
<JourneyStepScreenshotContainer
|
||||
checkGroup={step.monitor.check_group}
|
||||
initialStepNo={step.synthetics?.step?.index}
|
||||
stepStatus={step.synthetics.payload?.status}
|
||||
allStepsLoaded={allStepsLoaded}
|
||||
stepLabels={stepLabels}
|
||||
retryFetchOnRevisit={false}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false} style={{ minWidth: 80 }}>
|
||||
<EuiText color={textColor} size={compactView ? 's' : 'm'}>
|
||||
{step.synthetics?.step?.name}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
|
@ -11,16 +11,19 @@ import { isStepEnd } from '../../common/monitor_test_result/browser_steps_list';
|
|||
import { JourneyStep, SyntheticsJourneyApiResponse } from '../../../../../../common/runtime_types';
|
||||
import { fetchJourneySteps } from '../../../state';
|
||||
|
||||
export const useJourneySteps = (checkGroup: string | undefined) => {
|
||||
export const useJourneySteps = (checkGroup?: string) => {
|
||||
const { stepIndex } = useParams<{ stepIndex: string }>();
|
||||
const { checkGroupId: urlCheckGroup } = useParams<{ checkGroupId: string }>();
|
||||
|
||||
const checkGroupId = checkGroup ?? urlCheckGroup;
|
||||
|
||||
const { data, loading } = useFetcher(() => {
|
||||
if (!checkGroup) {
|
||||
if (!checkGroupId) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return fetchJourneySteps({ checkGroup });
|
||||
}, [checkGroup]);
|
||||
return fetchJourneySteps({ checkGroup: checkGroupId });
|
||||
}, [checkGroupId]);
|
||||
|
||||
const isFailed =
|
||||
data?.steps.some(
|
||||
|
|
|
@ -16,6 +16,8 @@ import {
|
|||
EuiLink,
|
||||
EuiLoadingContent,
|
||||
useEuiTheme,
|
||||
EuiTitle,
|
||||
EuiPanel,
|
||||
} from '@elastic/eui';
|
||||
import { capitalize } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -54,44 +56,49 @@ export const MonitorDetailsPanel = () => {
|
|||
`;
|
||||
|
||||
return (
|
||||
<div css={wrapperStyle}>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiDescriptionList type="column" compressed={true}>
|
||||
<EuiDescriptionListTitle>{ENABLED_LABEL}</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription>
|
||||
{monitor && (
|
||||
<MonitorEnabled
|
||||
initialLoading={loading}
|
||||
id={monitorId}
|
||||
monitor={monitor}
|
||||
reloadPage={() => {
|
||||
dispatch(getMonitorAction.get({ monitorId }));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</EuiDescriptionListDescription>
|
||||
<EuiDescriptionListTitle>{MONITOR_TYPE_LABEL}</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription>
|
||||
<EuiBadge>{capitalize(monitor?.type)}</EuiBadge>
|
||||
</EuiDescriptionListDescription>
|
||||
<EuiDescriptionListTitle>{FREQUENCY_LABEL}</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription>Every 10 mins</EuiDescriptionListDescription>
|
||||
<EuiDescriptionListTitle>{LOCATIONS_LABEL}</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription>
|
||||
<LocationsStatus />
|
||||
</EuiDescriptionListDescription>
|
||||
<EuiDescriptionListTitle>{URL_LABEL}</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription style={{ wordBreak: 'break-all' }}>
|
||||
<EuiLink href={latestPing?.url?.full} external>
|
||||
{latestPing?.url?.full}
|
||||
</EuiLink>
|
||||
</EuiDescriptionListDescription>
|
||||
<EuiDescriptionListTitle>{TAGS_LABEL}</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription>
|
||||
{monitor && <MonitorTags tags={monitor[ConfigKey.TAGS]} />}
|
||||
</EuiDescriptionListDescription>
|
||||
</EuiDescriptionList>
|
||||
</div>
|
||||
<EuiPanel hasShadow={false} hasBorder paddingSize="m">
|
||||
<EuiTitle size="xs">
|
||||
<h3>{MONITOR_DETAILS_LABEL}</h3>
|
||||
</EuiTitle>
|
||||
<div css={wrapperStyle}>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiDescriptionList type="column" compressed={true}>
|
||||
<EuiDescriptionListTitle>{ENABLED_LABEL}</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription>
|
||||
{monitor && (
|
||||
<MonitorEnabled
|
||||
initialLoading={loading}
|
||||
id={monitorId}
|
||||
monitor={monitor}
|
||||
reloadPage={() => {
|
||||
dispatch(getMonitorAction.get({ monitorId }));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</EuiDescriptionListDescription>
|
||||
<EuiDescriptionListTitle>{MONITOR_TYPE_LABEL}</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription>
|
||||
<EuiBadge>{capitalize(monitor?.type)}</EuiBadge>
|
||||
</EuiDescriptionListDescription>
|
||||
<EuiDescriptionListTitle>{FREQUENCY_LABEL}</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription>Every 10 mins</EuiDescriptionListDescription>
|
||||
<EuiDescriptionListTitle>{LOCATIONS_LABEL}</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription>
|
||||
<LocationsStatus />
|
||||
</EuiDescriptionListDescription>
|
||||
<EuiDescriptionListTitle>{URL_LABEL}</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription style={{ wordBreak: 'break-all' }}>
|
||||
<EuiLink href={latestPing?.url?.full} external>
|
||||
{latestPing?.url?.full}
|
||||
</EuiLink>
|
||||
</EuiDescriptionListDescription>
|
||||
<EuiDescriptionListTitle>{TAGS_LABEL}</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription>
|
||||
{monitor && <MonitorTags tags={monitor[ConfigKey.TAGS]} />}
|
||||
</EuiDescriptionListDescription>
|
||||
</EuiDescriptionList>
|
||||
</div>
|
||||
</EuiPanel>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -120,3 +127,7 @@ const MONITOR_TYPE_LABEL = i18n.translate(
|
|||
defaultMessage: 'Monitor type',
|
||||
}
|
||||
);
|
||||
|
||||
const MONITOR_DETAILS_LABEL = i18n.translate('xpack.synthetics.detailsPanel.monitorDetails', {
|
||||
defaultMessage: 'Monitor details',
|
||||
});
|
||||
|
|
|
@ -46,12 +46,7 @@ export const MonitorSummary = () => {
|
|||
<>
|
||||
<EuiFlexGroup gutterSize="m">
|
||||
<EuiFlexItem grow={1}>
|
||||
<EuiPanel hasShadow={false} hasBorder paddingSize="m">
|
||||
<EuiTitle size="xs">
|
||||
<h3>{MONITOR_DETAILS_LABEL}</h3>
|
||||
</EuiTitle>
|
||||
<MonitorDetailsPanel />
|
||||
</EuiPanel>
|
||||
<MonitorDetailsPanel />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={2}>
|
||||
<EuiPanel hasShadow={false} hasBorder paddingSize="m" css={{ height: 120 }}>
|
||||
|
@ -135,10 +130,6 @@ export const MonitorSummary = () => {
|
|||
);
|
||||
};
|
||||
|
||||
const MONITOR_DETAILS_LABEL = i18n.translate('xpack.synthetics.detailsPanel.monitorDetails', {
|
||||
defaultMessage: 'Monitor details',
|
||||
});
|
||||
|
||||
const SUMMARY_LABEL = i18n.translate('xpack.synthetics.detailsPanel.summary', {
|
||||
defaultMessage: 'Summary',
|
||||
});
|
||||
|
|
|
@ -11,10 +11,12 @@ import { useKibana } from '@kbn/kibana-react-plugin/public';
|
|||
import { ReportTypes } from '@kbn/observability-plugin/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { Position } from '@elastic/charts/dist/utils/common';
|
||||
import { useMonitorQueryId } from '../hooks/use_monitor_query_id';
|
||||
import { useSelectedMonitor } from '../hooks/use_selected_monitor';
|
||||
import { ClientPluginsStart } from '../../../../../plugin';
|
||||
export const StepDurationPanel = () => {
|
||||
|
||||
export const StepDurationPanel = ({ legendPosition }: { legendPosition?: Position }) => {
|
||||
const { observability } = useKibana<ClientPluginsStart>().services;
|
||||
|
||||
const { ExploratoryViewEmbeddable } = observability;
|
||||
|
@ -44,6 +46,7 @@ export const StepDurationPanel = () => {
|
|||
axisTitlesVisibility={{ yLeft: false, yRight: false, x: false }}
|
||||
customHeight={'300px'}
|
||||
reportType={ReportTypes.KPI}
|
||||
legendPosition={legendPosition}
|
||||
attributes={[
|
||||
{
|
||||
name: DURATION_BY_STEP_LABEL,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import React, { MouseEvent, useMemo, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
|
@ -14,27 +14,24 @@ import {
|
|||
EuiButtonEmpty,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiLink,
|
||||
EuiPanel,
|
||||
EuiText,
|
||||
EuiTitle,
|
||||
useEuiTheme,
|
||||
} from '@elastic/eui';
|
||||
import { Criteria } from '@elastic/eui/src/components/basic_table/basic_table';
|
||||
import { EuiTableSortingType } from '@elastic/eui/src/components/basic_table/table_types';
|
||||
|
||||
import { useHistory, useParams } from 'react-router-dom';
|
||||
import { MONITOR_TYPES } from '../../../../../../common/constants';
|
||||
import { TestDetailsLink } from '../../common/links/test_details_link';
|
||||
import { ConfigKey, DataStream, Ping } from '../../../../../../common/runtime_types';
|
||||
import {
|
||||
formatTestDuration,
|
||||
formatTestRunAt,
|
||||
} from '../../../utils/monitor_test_result/test_time_formats';
|
||||
import { formatTestDuration } from '../../../utils/monitor_test_result/test_time_formats';
|
||||
import { useSyntheticsSettingsContext } from '../../../contexts/synthetics_settings_context';
|
||||
|
||||
import { sortPings } from '../../../utils/monitor_test_result/sort_pings';
|
||||
import { selectPingsError } from '../../../state';
|
||||
import { parseBadgeStatus, StatusBadge } from '../../common/monitor_test_result/status_badge';
|
||||
|
||||
import { useKibanaDateFormat } from '../../../../../hooks/use_kibana_date_format';
|
||||
import { useSelectedMonitor } from '../hooks/use_selected_monitor';
|
||||
import { useMonitorPings } from '../hooks/use_monitor_pings';
|
||||
import { JourneyScreenshot } from '../../common/screenshot/journey_screenshot';
|
||||
|
@ -48,6 +45,8 @@ interface TestRunsTableProps {
|
|||
}
|
||||
|
||||
export const TestRunsTable = ({ paginable = true, from, to }: TestRunsTableProps) => {
|
||||
const history = useHistory();
|
||||
const { monitorId } = useParams<{ monitorId: string }>();
|
||||
const { basePath } = useSyntheticsSettingsContext();
|
||||
const [page, setPage] = useState({ index: 0, size: 10 });
|
||||
|
||||
|
@ -139,6 +138,24 @@ export const TestRunsTable = ({ paginable = true, from, to }: TestRunsTableProps
|
|||
},
|
||||
];
|
||||
|
||||
const getRowProps = (item: Ping) => {
|
||||
if (item.monitor.type !== MONITOR_TYPES.BROWSER) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
height: '85px',
|
||||
'data-test-subj': `row-${item.monitor.check_group}`,
|
||||
onClick: (evt: MouseEvent) => {
|
||||
const targetElem = evt.target as HTMLElement;
|
||||
|
||||
// we dont want to capture image click event
|
||||
if (targetElem.tagName !== 'IMG' && targetElem.tagName !== 'path') {
|
||||
history.push(`/monitor/${monitorId}/test-run/${item.monitor.check_group}`);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const historyIdParam =
|
||||
monitor?.[ConfigKey.CUSTOM_HEARTBEAT_ID] ?? monitor?.[ConfigKey.MONITOR_QUERY_ID];
|
||||
return (
|
||||
|
@ -183,6 +200,7 @@ export const TestRunsTable = ({ paginable = true, from, to }: TestRunsTableProps
|
|||
tableLayout={'auto'}
|
||||
sorting={sorting}
|
||||
onChange={handleTableChange}
|
||||
rowProps={getRowProps}
|
||||
pagination={
|
||||
paginable
|
||||
? {
|
||||
|
@ -198,34 +216,6 @@ export const TestRunsTable = ({ paginable = true, from, to }: TestRunsTableProps
|
|||
);
|
||||
};
|
||||
|
||||
const TestDetailsLink = ({
|
||||
isBrowserMonitor,
|
||||
timestamp,
|
||||
ping,
|
||||
}: {
|
||||
isBrowserMonitor: boolean;
|
||||
timestamp: string;
|
||||
ping: Ping;
|
||||
}) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const { basePath } = useSyntheticsSettingsContext();
|
||||
|
||||
const format = useKibanaDateFormat();
|
||||
const timestampText = (
|
||||
<EuiText size="s" css={{ fontWeight: euiTheme.font.weight.medium }}>
|
||||
{formatTestRunAt(timestamp, format)}
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
return isBrowserMonitor ? (
|
||||
<EuiLink href={`${basePath}/app/uptime/journey/${ping?.monitor?.check_group ?? ''}/steps`}>
|
||||
{timestampText}
|
||||
</EuiLink>
|
||||
) : (
|
||||
timestampText
|
||||
);
|
||||
};
|
||||
|
||||
const TEST_RUNS = i18n.translate('xpack.synthetics.monitorDetails.summary.testRuns', {
|
||||
defaultMessage: 'Test Runs',
|
||||
});
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { useSelectedMonitor } from '../../monitor_details/hooks/use_selected_monitor';
|
||||
import { useBreadcrumbs } from '../../../hooks/use_breadcrumbs';
|
||||
import { MONITOR_ROUTE, MONITORS_ROUTE } from '../../../../../../common/constants';
|
||||
import { PLUGIN } from '../../../../../../common/constants/plugin';
|
||||
|
||||
export const useTestRunDetailsBreadcrumbs = (
|
||||
extraCrumbs?: Array<{ text: string; href?: string }>
|
||||
) => {
|
||||
const kibana = useKibana();
|
||||
const appPath = kibana.services.application?.getUrlForApp(PLUGIN.SYNTHETICS_PLUGIN_ID) ?? '';
|
||||
|
||||
const { monitor } = useSelectedMonitor();
|
||||
|
||||
useBreadcrumbs([
|
||||
{
|
||||
text: MONITOR_MANAGEMENT_CRUMB,
|
||||
href: `${appPath}${MONITORS_ROUTE}`,
|
||||
},
|
||||
{
|
||||
text: monitor?.name ?? '',
|
||||
href: `${appPath}${MONITOR_ROUTE.replace(':monitorId', monitor?.id ?? '')}`,
|
||||
},
|
||||
...(extraCrumbs ?? []),
|
||||
]);
|
||||
};
|
||||
|
||||
const MONITOR_MANAGEMENT_CRUMB = i18n.translate('xpack.synthetics.monitorsPage.monitorsMCrumb', {
|
||||
defaultMessage: 'Monitors',
|
||||
});
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui';
|
||||
import moment from 'moment';
|
||||
import { MonitorDetailsPanel } from '../monitor_details/monitor_summary/monitor_details_panel';
|
||||
import { useJourneySteps } from '../monitor_details/hooks/use_journey_steps';
|
||||
import { StepDurationPanel } from '../monitor_details/monitor_summary/step_duration_panel';
|
||||
import { TestRunSteps } from './test_run_steps';
|
||||
import { useTestRunDetailsBreadcrumbs } from './hooks/use_test_run_details_breadcrumbs';
|
||||
|
||||
export const TestRunDetails = () => {
|
||||
const { data: stepsData, loading: stepsLoading } = useJourneySteps();
|
||||
|
||||
useTestRunDetailsBreadcrumbs([
|
||||
{ text: stepsData ? moment(stepsData.details?.timestamp).format('LLL') : '' },
|
||||
]);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="m">
|
||||
<EuiFlexItem grow={2}>
|
||||
<EuiPanel hasShadow={false} hasBorder>
|
||||
<EuiTitle size="xs">
|
||||
{/* TODO: Add step detail panel*/}
|
||||
<h3>Step 1 of {stepsData?.steps.length}</h3>
|
||||
</EuiTitle>
|
||||
</EuiPanel>
|
||||
<EuiSpacer size="m" />
|
||||
<TestRunSteps isLoading={stepsLoading} steps={stepsData?.steps ?? []} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={1}>
|
||||
<StepDurationPanel legendPosition="bottom" />
|
||||
<EuiSpacer size="m" />
|
||||
<MonitorDetailsPanel />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiTitle } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { formatTestDuration } from '../../utils/monitor_test_result/test_time_formats';
|
||||
import { JourneyStep } from '../../../../../common/runtime_types';
|
||||
import { BrowserStepsList, isStepEnd } from '../common/monitor_test_result/browser_steps_list';
|
||||
|
||||
export const TestRunSteps = ({
|
||||
isLoading,
|
||||
steps,
|
||||
}: {
|
||||
isLoading: boolean;
|
||||
steps: JourneyStep[];
|
||||
}) => {
|
||||
const totalDuration = steps
|
||||
.filter(isStepEnd)
|
||||
.reduce((acc, step) => acc + (step.synthetics?.step?.duration.us ?? 0), 0);
|
||||
|
||||
return (
|
||||
<EuiPanel hasShadow={false} hasBorder>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={true}>
|
||||
<EuiTitle size="xs">
|
||||
<h2>{STEPS_EXECUTED}</h2>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
{TOTAL_DURATION}
|
||||
{formatTestDuration(totalDuration)}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
<BrowserStepsList
|
||||
steps={steps}
|
||||
loading={isLoading}
|
||||
showStepNumber={true}
|
||||
compressed={false}
|
||||
/>
|
||||
</EuiPanel>
|
||||
);
|
||||
};
|
||||
|
||||
const STEPS_EXECUTED = i18n.translate('xpack.synthetics.testDetails.stepExecuted', {
|
||||
defaultMessage: 'Steps executed',
|
||||
});
|
||||
|
||||
const TOTAL_DURATION = i18n.translate('xpack.synthetics.testDetails.totalDuration', {
|
||||
defaultMessage: 'Total duration: ',
|
||||
});
|
|
@ -24,6 +24,7 @@ import { useKibana } from '@kbn/kibana-react-plugin/public';
|
|||
import { useInspectorContext } from '@kbn/observability-plugin/public';
|
||||
import type { LazyObservabilityPageTemplateProps } from '@kbn/observability-plugin/public';
|
||||
import { getSettingsRouteConfig } from './components/settings/route_config';
|
||||
import { TestRunDetails } from './components/test_run_details/test_run_details';
|
||||
import { ErrorDetailsPage } from './components/error_details/error_details_page';
|
||||
import { StepTitle } from './components/step_details_page/step_title';
|
||||
import { MonitorAddPage } from './components/monitor_add_edit/monitor_add_page';
|
||||
|
@ -51,6 +52,7 @@ import {
|
|||
ERROR_DETAILS_ROUTE,
|
||||
STEP_DETAIL_ROUTE,
|
||||
OVERVIEW_ROUTE,
|
||||
TEST_RUN_DETAILS_ROUTE,
|
||||
} from '../../../common/constants';
|
||||
import { PLUGIN } from '../../../common/constants/plugin';
|
||||
import { MonitorPage } from './components/monitors_page/monitor_page';
|
||||
|
@ -325,6 +327,23 @@ const getRoutes = (
|
|||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18n.translate('xpack.synthetics.testRunDetailsRoute.title', {
|
||||
defaultMessage: 'Test run details | {baseTitle}',
|
||||
values: { baseTitle },
|
||||
}),
|
||||
path: TEST_RUN_DETAILS_ROUTE,
|
||||
component: TestRunDetails,
|
||||
dataTestSubj: 'syntheticsMonitorTestRunDetailsPage',
|
||||
pageHeader: {
|
||||
pageTitle: (
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.testRunDetailsRoute.page.title"
|
||||
defaultMessage="Test run details"
|
||||
/>
|
||||
),
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue