[Uptime] Fix/host connected components (#56969) (#57666)

* added test for pages

* fixed types

* moved redux logic to connected

* comment

* update type

* type fix
This commit is contained in:
Shahzad 2020-02-14 14:54:01 +01:00 committed by GitHub
parent ecc03e9468
commit ba8b610424
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 183 additions and 178 deletions

View file

@ -10,3 +10,5 @@ export { KueryBar } from './kuerybar/kuery_bar_container';
export { FilterGroup } from './filter_group/filter_group_container';
export { MonitorStatusDetails } from './monitor/status_details_container';
export { MonitorStatusBar } from './monitor/status_bar_container';
export { MonitorListDrawer } from './monitor/list_drawer_container';
export { MonitorListActionsPopover } from './monitor/drawer_popover_container';

View file

@ -0,0 +1,26 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { connect } from 'react-redux';
import { AppState } from '../../../state';
import { isIntegrationsPopupOpen } from '../../../state/selectors';
import { PopoverState, toggleIntegrationsPopover } from '../../../state/actions';
import { MonitorListActionsPopoverComponent } from '../../functional/monitor_list/monitor_list_drawer';
const mapStateToProps = (state: AppState) => ({
popoverState: isIntegrationsPopupOpen(state),
});
const mapDispatchToProps = (dispatch: any) => ({
togglePopoverIsVisible: (popoverState: PopoverState) => {
return dispatch(toggleIntegrationsPopover(popoverState));
},
});
export const MonitorListActionsPopover = connect(
mapStateToProps,
mapDispatchToProps
)(MonitorListActionsPopoverComponent);

View file

@ -0,0 +1,49 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { AppState } from '../../../state';
import { getMonitorDetails } from '../../../state/selectors';
import { MonitorDetailsActionPayload } from '../../../state/actions/types';
import { fetchMonitorDetails } from '../../../state/actions/monitor';
import { MonitorListDrawerComponent } from '../../functional/monitor_list/monitor_list_drawer/monitor_list_drawer';
import { useUrlParams } from '../../../hooks';
import { MonitorSummary } from '../../../../common/graphql/types';
import { MonitorDetails } from '../../../../common/runtime_types/monitor';
interface ContainerProps {
summary: MonitorSummary;
monitorDetails: MonitorDetails;
loadMonitorDetails: typeof fetchMonitorDetails;
}
const Container: React.FC<ContainerProps> = ({ summary, loadMonitorDetails, monitorDetails }) => {
const monitorId = summary?.monitor_id;
const [getUrlParams] = useUrlParams();
const { dateRangeStart: dateStart, dateRangeEnd: dateEnd } = getUrlParams();
useEffect(() => {
loadMonitorDetails({
dateStart,
dateEnd,
monitorId,
});
}, [dateStart, dateEnd, monitorId, loadMonitorDetails]);
return <MonitorListDrawerComponent monitorDetails={monitorDetails} summary={summary} />;
};
const mapStateToProps = (state: AppState, { summary }: any) => ({
monitorDetails: getMonitorDetails(state, summary),
});
const mapDispatchToProps = (dispatch: any) => ({
loadMonitorDetails: (actionPayload: MonitorDetailsActionPayload) =>
dispatch(fetchMonitorDetails(actionPayload)),
});
export const MonitorListDrawer = connect(mapStateToProps, mapDispatchToProps)(Container);

View file

@ -31,7 +31,7 @@ interface OwnProps {
type Props = OwnProps & StateProps & DispatchProps;
export const Container: React.FC<Props> = ({
const Container: React.FC<Props> = ({
loadMonitorStatus,
monitorId,
monitorStatus,

View file

@ -6,7 +6,6 @@
export { DonutChart } from './charts/donut_chart';
export { EmptyState } from './empty_state';
export { IntegrationLink } from './integration_link';
export { KueryBarComponent } from './kuery_bar/kuery_bar';
export { MonitorCharts } from './monitor_charts';
export { MonitorList } from './monitor_list';

View file

@ -15,7 +15,7 @@ import {
esKuery,
IIndexPattern,
QuerySuggestion,
DataPublicPluginStart,
DataPublicPluginSetup,
} from '../../../../../../../../src/plugins/data/public';
const Container = styled.div`
@ -33,7 +33,7 @@ function convertKueryToEsQuery(kuery: string, indexPattern: IIndexPattern) {
}
interface Props {
autocomplete: DataPublicPluginStart['autocomplete'];
autocomplete: DataPublicPluginSetup['autocomplete'];
loadIndexPattern: any;
indexPattern: any;
}

View file

@ -28,11 +28,11 @@ import {
import { MonitorListStatusColumn } from './monitor_list_status_column';
import { formatUptimeGraphQLErrorList } from '../../../lib/helper/format_error_list';
import { ExpandedRowMap } from './types';
import { MonitorListDrawer } from './monitor_list_drawer';
import { MonitorBarSeries } from '../charts';
import { MonitorPageLink } from './monitor_page_link';
import { OverviewPageLink } from './overview_page_link';
import * as labels from './translations';
import { MonitorListDrawer } from '../../connected';
interface MonitorListQueryResult {
monitorStates?: MonitorSummaryResult;

View file

@ -4,6 +4,15 @@ exports[`IntegrationGroup will not display APM links when APM is unavailable 1`]
<EuiFlexGroup
direction="column"
>
<EuiFlexItem>
<IntegrationLink
ariaLabel="Search APM for this monitor"
href="/app/apm#/services?kuery=url.domain:%20%22undefined%22&rangeFrom=now-15m&rangeTo=now"
iconType="apmApp"
message="Check APM for domain"
tooltipContent="Click here to check APM for the domain \\"\\"."
/>
</EuiFlexItem>
<EuiFlexItem>
<IntegrationLink
ariaLabel="Check Infrastructure UI for this montor's ip address"
@ -62,12 +71,36 @@ exports[`IntegrationGroup will not display infra links when infra is unavailable
<EuiFlexItem>
<IntegrationLink
ariaLabel="Search APM for this monitor"
href="foo/app/apm#/services?kuery=url.domain:%20%22undefined%22&rangeFrom=now-12m&rangeTo=now-1m"
href="/app/apm#/services?kuery=url.domain:%20%22undefined%22&rangeFrom=now-15m&rangeTo=now"
iconType="apmApp"
message="Check APM for domain"
tooltipContent="Click here to check APM for the domain \\"\\"."
/>
</EuiFlexItem>
<EuiFlexItem>
<IntegrationLink
ariaLabel="Check Infrastructure UI for this montor's ip address"
iconType="metricsApp"
message="Show host metrics"
tooltipContent="Check Infrastructure UI for the IP \\"\\""
/>
</EuiFlexItem>
<EuiFlexItem>
<IntegrationLink
ariaLabel="Check Infrastructure UI for this monitor's pod UID"
iconType="metricsApp"
message="Show pod metrics"
tooltipContent="Check Infrastructure UI for pod UID \\"\\"."
/>
</EuiFlexItem>
<EuiFlexItem>
<IntegrationLink
ariaLabel="Check Infrastructure UI for this monitor's container ID"
iconType="metricsApp"
message="Show container metrics"
tooltipContent="Check Infrastructure UI for container ID \\"\\""
/>
</EuiFlexItem>
<EuiFlexItem>
<IntegrationLink
ariaLabel="Check Logging UI for this monitor's ip address"
@ -102,7 +135,7 @@ exports[`IntegrationGroup will not display logging links when logging is unavail
<EuiFlexItem>
<IntegrationLink
ariaLabel="Search APM for this monitor"
href="foo/app/apm#/services?kuery=url.domain:%20%22undefined%22&rangeFrom=now-12m&rangeTo=now-1m"
href="/app/apm#/services?kuery=url.domain:%20%22undefined%22&rangeFrom=now-15m&rangeTo=now"
iconType="apmApp"
message="Check APM for domain"
tooltipContent="Click here to check APM for the domain \\"\\"."
@ -132,5 +165,29 @@ exports[`IntegrationGroup will not display logging links when logging is unavail
tooltipContent="Check Infrastructure UI for container ID \\"\\""
/>
</EuiFlexItem>
<EuiFlexItem>
<IntegrationLink
ariaLabel="Check Logging UI for this monitor's ip address"
iconType="logsApp"
message="Show host logs"
tooltipContent="Check Logging UI for the IP \\"\\""
/>
</EuiFlexItem>
<EuiFlexItem>
<IntegrationLink
ariaLabel="Show pod logs"
iconType="logsApp"
message="Show pod logs"
tooltipContent="Check for logs for pod UID \\"\\""
/>
</EuiFlexItem>
<EuiFlexItem>
<IntegrationLink
ariaLabel="Show container logs"
iconType="logsApp"
message="Show container logs"
tooltipContent="Check Logging UI for container ID \\"\\""
/>
</EuiFlexItem>
</EuiFlexGroup>
`;

View file

@ -52,7 +52,6 @@ exports[`MonitorListDrawer component renders a MonitorListDrawer when there are
}
>
<MonitorListDrawerComponent
loadMonitorDetails={[Function]}
monitorDetails={
Object {
"error": Object {
@ -157,7 +156,6 @@ exports[`MonitorListDrawer component renders a MonitorListDrawer when there is o
}
>
<MonitorListDrawerComponent
loadMonitorDetails={[Function]}
monitorDetails={
Object {
"error": Object {

View file

@ -5,7 +5,7 @@
*/
import React from 'react';
import { MonitorSummary } from '../../../../common/graphql/types';
import { MonitorSummary } from '../../../../../../common/graphql/types';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { IntegrationGroup } from '../integration_group';
@ -24,47 +24,17 @@ describe('IntegrationGroup', () => {
});
it('will not display APM links when APM is unavailable', () => {
const component = shallowWithIntl(
<IntegrationGroup
basePath="foo"
dateRangeStart="now-12m"
dateRangeEnd="now-1m"
isApmAvailable={false}
isInfraAvailable={true}
isLogsAvailable={true}
summary={summary}
/>
);
const component = shallowWithIntl(<IntegrationGroup summary={summary} />);
expect(component).toMatchSnapshot();
});
it('will not display infra links when infra is unavailable', () => {
const component = shallowWithIntl(
<IntegrationGroup
basePath="foo"
dateRangeStart="now-12m"
dateRangeEnd="now-1m"
isApmAvailable={true}
isInfraAvailable={false}
isLogsAvailable={true}
summary={summary}
/>
);
const component = shallowWithIntl(<IntegrationGroup summary={summary} />);
expect(component).toMatchSnapshot();
});
it('will not display logging links when logging is unavailable', () => {
const component = shallowWithIntl(
<IntegrationGroup
basePath="foo"
dateRangeStart="now-12m"
dateRangeEnd="now-1m"
isApmAvailable={true}
isInfraAvailable={true}
isLogsAvailable={false}
summary={summary}
/>
);
const component = shallowWithIntl(<IntegrationGroup summary={summary} />);
expect(component).toMatchSnapshot();
});
});

View file

@ -12,7 +12,6 @@ import { shallowWithRouter } from '../../../../../lib';
describe('MonitorListDrawer component', () => {
let summary: MonitorSummary;
let loadMonitorDetails: any;
let monitorDetails: MonitorDetails;
beforeEach(() => {
@ -47,16 +46,11 @@ describe('MonitorListDrawer component', () => {
'Get https://expired.badssl.com: x509: certificate has expired or is not yet valid',
},
};
loadMonitorDetails = () => null;
});
it('renders nothing when no summary data is present', () => {
const component = shallowWithRouter(
<MonitorListDrawerComponent
loadMonitorDetails={loadMonitorDetails}
summary={summary}
monitorDetails={monitorDetails}
/>
<MonitorListDrawerComponent summary={summary} monitorDetails={monitorDetails} />
);
expect(component).toEqual({});
});
@ -64,22 +58,14 @@ describe('MonitorListDrawer component', () => {
it('renders nothing when no check data is present', () => {
delete summary.state.checks;
const component = shallowWithRouter(
<MonitorListDrawerComponent
summary={summary}
loadMonitorDetails={loadMonitorDetails}
monitorDetails={monitorDetails}
/>
<MonitorListDrawerComponent summary={summary} monitorDetails={monitorDetails} />
);
expect(component).toEqual({});
});
it('renders a MonitorListDrawer when there is only one check', () => {
const component = shallowWithRouter(
<MonitorListDrawerComponent
summary={summary}
loadMonitorDetails={loadMonitorDetails}
monitorDetails={monitorDetails}
/>
<MonitorListDrawerComponent summary={summary} monitorDetails={monitorDetails} />
);
expect(component).toMatchSnapshot();
});
@ -110,11 +96,7 @@ describe('MonitorListDrawer component', () => {
];
summary.state.checks = checks;
const component = shallowWithRouter(
<MonitorListDrawerComponent
summary={summary}
loadMonitorDetails={loadMonitorDetails}
monitorDetails={monitorDetails}
/>
<MonitorListDrawerComponent summary={summary} monitorDetails={monitorDetails} />
);
expect(component).toMatchSnapshot();
});

View file

@ -4,5 +4,5 @@
* you may not use this file except in compliance with the Elastic License.
*/
export { MonitorListDrawer } from './monitor_list_drawer';
export { LocationLink } from './location_link';
export { MonitorListActionsPopoverComponent } from './monitor_list_actions_popover';

View file

@ -5,7 +5,7 @@
*/
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import React from 'react';
import React, { useContext } from 'react';
import { i18n } from '@kbn/i18n';
import { get } from 'lodash';
import { FormattedMessage } from '@kbn/i18n/react';
@ -18,32 +18,29 @@ import {
getLoggingContainerHref,
getLoggingIpHref,
getLoggingKubernetesHref,
} from '../../lib/helper';
import { MonitorSummary } from '../../../common/graphql/types';
} from '../../../../lib/helper';
import { MonitorSummary } from '../../../../../common/graphql/types';
import { UptimeSettingsContext } from '../../../../contexts';
interface IntegrationGroupProps {
basePath: string;
dateRangeStart: string;
dateRangeEnd: string;
isApmAvailable: boolean;
isInfraAvailable: boolean;
isLogsAvailable: boolean;
summary: MonitorSummary;
}
export const IntegrationGroup = ({
basePath,
dateRangeStart,
dateRangeEnd,
isApmAvailable,
isInfraAvailable,
isLogsAvailable,
summary,
}: IntegrationGroupProps) => {
export const IntegrationGroup = ({ summary }: IntegrationGroupProps) => {
const {
basePath,
dateRangeStart,
dateRangeEnd,
isApmAvailable,
isInfraAvailable,
isLogsAvailable,
} = useContext(UptimeSettingsContext);
const domain = get<string>(summary, 'state.url.domain', '');
const podUid = get<string | undefined>(summary, 'state.checks[0].kubernetes.pod.uid', undefined);
const containerId = get<string | undefined>(summary, 'state.checks[0].container.id', undefined);
const ip = get<string | undefined>(summary, 'state.checks[0].monitor.ip', undefined);
return isApmAvailable || isInfraAvailable || isLogsAvailable ? (
<EuiFlexGroup direction="column">
{isApmAvailable ? (

View file

@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, EuiText, EuiToolTip } from '@elastic/eui';
import React from 'react';
import { i18n } from '@kbn/i18n';
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, EuiText, EuiToolTip } from '@elastic/eui';
interface IntegrationLinkProps {
ariaLabel: string;

View file

@ -4,17 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { EuiPopover, EuiButton } from '@elastic/eui';
import React, { useContext } from 'react';
import { i18n } from '@kbn/i18n';
import { get } from 'lodash';
import { connect } from 'react-redux';
import { MonitorSummary } from '../../../../common/graphql/types';
import { IntegrationGroup } from '../integration_group';
import { UptimeSettingsContext } from '../../../contexts';
import { isIntegrationsPopupOpen } from '../../../state/selectors';
import { AppState } from '../../../state';
import { toggleIntegrationsPopover, PopoverState } from '../../../state/actions';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { EuiPopover, EuiButton } from '@elastic/eui';
import { IntegrationGroup } from './integration_group';
import { MonitorSummary } from '../../../../../common/graphql/types';
import { toggleIntegrationsPopover, PopoverState } from '../../../../state/actions';
interface MonitorListActionsPopoverProps {
summary: MonitorSummary;
@ -22,20 +18,12 @@ interface MonitorListActionsPopoverProps {
togglePopoverIsVisible: typeof toggleIntegrationsPopover;
}
const MonitorListActionsPopoverComponent = ({
export const MonitorListActionsPopoverComponent = ({
summary,
popoverState,
togglePopoverIsVisible,
}: MonitorListActionsPopoverProps) => {
const popoverId = `${summary.monitor_id}_popover`;
const {
basePath,
dateRangeStart,
dateRangeEnd,
isApmAvailable,
isInfraAvailable,
isLogsAvailable,
} = useContext(UptimeSettingsContext);
const monitorUrl: string | undefined = get(summary, 'state.url.full', undefined);
const isPopoverOpen: boolean =
@ -64,30 +52,7 @@ const MonitorListActionsPopoverComponent = ({
id={popoverId}
isOpen={isPopoverOpen}
>
<IntegrationGroup
basePath={basePath}
dateRangeStart={dateRangeStart}
dateRangeEnd={dateRangeEnd}
isApmAvailable={isApmAvailable}
isInfraAvailable={isInfraAvailable}
isLogsAvailable={isLogsAvailable}
summary={summary}
/>
<IntegrationGroup summary={summary} />
</EuiPopover>
);
};
const mapStateToProps = (state: AppState) => ({
popoverState: isIntegrationsPopupOpen(state),
});
const mapDispatchToProps = (dispatch: any) => ({
togglePopoverIsVisible: (popoverState: PopoverState) => {
return dispatch(toggleIntegrationsPopover(popoverState));
},
});
export const MonitorListActionsPopover = connect(
mapStateToProps,
mapDispatchToProps
)(MonitorListActionsPopoverComponent);

View file

@ -4,20 +4,14 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { useEffect } from 'react';
import { EuiLink, EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText } from '@elastic/eui';
import React from 'react';
import styled from 'styled-components';
import { connect } from 'react-redux';
import { EuiLink, EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText } from '@elastic/eui';
import { MonitorSummary } from '../../../../../common/graphql/types';
import { AppState } from '../../../../state';
import { fetchMonitorDetails } from '../../../../state/actions/monitor';
import { MostRecentError } from './most_recent_error';
import { getMonitorDetails } from '../../../../state/selectors';
import { MonitorStatusList } from './monitor_status_list';
import { MonitorDetails } from '../../../../../common/runtime_types';
import { useUrlParams } from '../../../../hooks';
import { MonitorDetailsActionPayload } from '../../../../state/actions/types';
import { MonitorListActionsPopover } from '../monitor_list_actions_popover';
import { MonitorListActionsPopover } from '../../../connected';
const ContainerDiv = styled.div`
padding: 10px;
@ -34,34 +28,13 @@ interface MonitorListDrawerProps {
* Monitor details to be fetched from rest api using monitorId
*/
monitorDetails: MonitorDetails;
/**
* Redux action to trigger , loading monitor details
*/
loadMonitorDetails: typeof fetchMonitorDetails;
}
/**
* The elements shown when the user expands the monitor list rows.
*/
export function MonitorListDrawerComponent({
summary,
loadMonitorDetails,
monitorDetails,
}: MonitorListDrawerProps) {
const monitorId = summary?.monitor_id;
const [getUrlParams] = useUrlParams();
const { dateRangeStart: dateStart, dateRangeEnd: dateEnd } = getUrlParams();
useEffect(() => {
loadMonitorDetails({
dateStart,
dateEnd,
monitorId,
});
}, [dateStart, dateEnd, monitorId, loadMonitorDetails]);
export function MonitorListDrawerComponent({ summary, monitorDetails }: MonitorListDrawerProps) {
const monitorUrl = summary?.state?.url?.full || '';
return summary && summary.state.checks ? (
@ -91,17 +64,3 @@ export function MonitorListDrawerComponent({
</ContainerDiv>
) : null;
}
const mapStateToProps = (state: AppState, { summary }: any) => ({
monitorDetails: getMonitorDetails(state, summary),
});
const mapDispatchToProps = (dispatch: any) => ({
loadMonitorDetails: (actionPayload: MonitorDetailsActionPayload) =>
dispatch(fetchMonitorDetails(actionPayload)),
});
export const MonitorListDrawer = connect(
mapStateToProps,
mapDispatchToProps
)(MonitorListDrawerComponent);

View file

@ -54,6 +54,7 @@ exports[`MonitorPage shallow renders expected elements for valid props 1`] = `
<OverviewPageComponent
autocomplete={
Object {
"addQuerySuggestionProvider": [MockFunction],
"getQuerySuggestions": [MockFunction],
"getValueSuggestions": [MockFunction],
"hasQuerySuggestions": [Function],

View file

@ -92,6 +92,7 @@ describe('MonitorPage', () => {
getQuerySuggestions: jest.fn(),
hasQuerySuggestions: () => true,
getValueSuggestions: jest.fn(),
addQuerySuggestionProvider: jest.fn(),
};
it('shallow renders expected elements for valid props', () => {

View file

@ -16,13 +16,13 @@ import {
import { useUrlParams, useUptimeTelemetry, UptimePage } from '../hooks';
import { stringifyUrlParams } from '../lib/helper/stringify_url_params';
import { useTrackPageview } from '../../../infra/public';
import { DataPublicPluginStart, IIndexPattern } from '../../../../../../src/plugins/data/public';
import { DataPublicPluginSetup, IIndexPattern } from '../../../../../../src/plugins/data/public';
import { UptimeThemeContext } from '../contexts';
import { FilterGroup, KueryBar } from '../components/connected';
import { useUpdateKueryString } from '../hooks';
interface OverviewPageProps {
autocomplete: DataPublicPluginStart['autocomplete'];
autocomplete: DataPublicPluginSetup['autocomplete'];
indexPattern: IIndexPattern;
setEsKueryFilters: (esFilters: string) => void;
}

View file

@ -6,13 +6,13 @@
import React, { FC } from 'react';
import { Route, Switch } from 'react-router-dom';
import { DataPublicPluginStart } from '../../../../../src/plugins/data/public';
import { DataPublicPluginSetup } from '../../../../../src/plugins/data/public';
import { OverviewPage } from './components/connected/pages/overview_container';
import { MONITOR_ROUTE, OVERVIEW_ROUTE } from '../common/constants';
import { MonitorPage, NotFoundPage } from './pages';
interface RouterProps {
autocomplete: DataPublicPluginStart['autocomplete'];
autocomplete: DataPublicPluginSetup['autocomplete'];
}
export const PageRouter: FC<RouterProps> = ({ autocomplete }) => (

View file

@ -100,7 +100,6 @@ const Application = (props: UptimeAppProps) => {
<EuiPage className="app-wrapper-panel " data-test-subj="uptimeApp">
<main>
<PageHeader setBreadcrumbs={setBreadcrumbs} />
// @ts-ignore we need to update the type of this prop
<PageRouter autocomplete={plugins.data.autocomplete} />
</main>
</EuiPage>