[Uptime] Localization (#28183)

* Add localization tokens.

* Fix import errors.

* Rename a translation key/message. Fix copy/paste mistake.

* Make i18n provider root element of application.

* Add xpack.uptime to .i18nrc.json.

* Remove icon.

* Update x-pack/plugins/uptime/public/components/functional/snapshot_histogram.tsx

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update x-pack/plugins/uptime/public/components/functional/snapshot_histogram.tsx

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update x-pack/plugins/uptime/public/components/queries/empty_state/empty_state.tsx

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Replace ... with ….

* Update x-pack/plugins/uptime/public/components/queries/empty_state/empty_state.tsx

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update x-pack/plugins/uptime/public/components/queries/empty_state/empty_state.tsx

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update x-pack/plugins/uptime/public/components/queries/empty_state/empty_state.tsx

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Move a link to formatted message value prop.

* Update x-pack/plugins/uptime/public/components/queries/error_list/error_list.tsx

Reformat naming of column localization keys.

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update error list table column localization keys.

* Update x-pack/plugins/uptime/public/components/queries/filter_bar/filter_bar.tsx

Update label key.

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update label localization keys for filter bar.

* Update x-pack/plugins/uptime/public/components/queries/filter_bar/filter_bar.tsx

Update localization key for filter bar tooltip title.

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update x-pack/plugins/uptime/public/components/queries/filter_bar/filter_bar.tsx

Update localization key for filter bar tooltip text.

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update x-pack/plugins/uptime/public/components/queries/monitor_charts/monitor_charts.tsx

Improve RTT Breakdown title localization key.

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Add description and update a localization key.

* Update x-pack/plugins/uptime/public/components/queries/monitor_charts/monitor_charts.tsx

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update x-pack/plugins/uptime/public/components/queries/monitor_list/monitor_list.tsx

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update monitor charts localization keys.

* Extract conditional message values into separate translate calls.

* Update x-pack/plugins/uptime/public/components/queries/monitor_list/monitor_list.tsx

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update monitor list column header localization keys.

* Update x-pack/plugins/uptime/public/components/queries/monitor_list/monitor_list.tsx

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Monitor list update localization key of series label.

* Update x-pack/plugins/uptime/public/components/queries/monitor_list/monitor_list.tsx

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update x-pack/plugins/uptime/public/components/queries/monitor_status_bar/monitor_status_bar.tsx

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Improve destructuring in monitor status bar, extract conditional values to separate translations.

* Update x-pack/plugins/uptime/public/components/queries/monitor_status_bar/monitor_status_bar.tsx

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update x-pack/plugins/uptime/public/components/queries/monitor_status_bar/monitor_status_bar.tsx

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Apply suggestions from code review

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update localization keys for ping list.

* Apply suggestions from code review

Implement PR suggestions for PingList component.

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Apply suggestions from code review

Add PR suggestions for Snapshot component.

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update localization keys for Snapshot component.

* Remove unneeded translation.

* Update x-pack/plugins/uptime/public/register_feature.ts

Implement PR suggestion for register_feature.ts

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Apply suggestions from code review

Implement PR suggestions for uptime app.

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update localization, add translations for UptimeApp.

* Run prettier to fix style problem.

* Fix duplicate localization keys.

* Update x-pack/plugins/uptime/public/uptime_app.tsx

Implement PR feedback.

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update x-pack/plugins/uptime/public/components/queries/snapshot/snapshot.tsx

Implement a PR suggestion.

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Update x-pack/plugins/uptime/public/components/queries/snapshot/snapshot.tsx

Implement a PR change.

Co-Authored-By: justinkambic <justin.kambic@elastic.co>

* Implement PR feedback.
This commit is contained in:
Justin Kambic 2019-01-16 17:03:16 -05:00 committed by GitHub
parent a00d487afe
commit a7f249dc43
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 694 additions and 255 deletions

View file

@ -34,6 +34,7 @@
"xpack.security": "x-pack/plugins/security",
"xpack.spaces": "x-pack/plugins/spaces",
"xpack.upgradeAssistant": "x-pack/plugins/upgrade_assistant",
"xpack.uptime": "x-pack/plugins/uptime",
"xpack.watcher": "x-pack/plugins/watcher"
},
"exclude": [

View file

@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { i18n } from '@kbn/i18n';
import { Server } from 'hapi';
import { resolve } from 'path';
import { PLUGIN } from './common/constants';
@ -17,7 +18,10 @@ export const uptime = (kibana: any) =>
publicDir: resolve(__dirname, 'public'),
uiExports: {
app: {
description: 'Monitor your endpoints',
description: i18n.translate('xpack.uptime.pluginDescription', {
defaultMessage: 'Uptime monitoring',
description: 'The description text that will be shown to users in Kibana',
}),
icon: 'plugins/uptime/icons/heartbeat_white.svg',
title: 'Uptime',
main: 'plugins/uptime/app',

View file

@ -4,17 +4,23 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { i18n } from '@kbn/i18n';
export interface UMBreadcrumb {
text: string;
href?: string;
}
export const monitorBreadcrumb: UMBreadcrumb = {
text: 'Monitor',
text: i18n.translate('xpack.uptime.breadcrumbs.monitorBreadcrumbText', {
defaultMessage: 'Monitor',
}),
};
export const overviewBreadcrumb: UMBreadcrumb = {
text: 'Overview',
text: i18n.translate('xpack.uptime.breadcrumbs.overviewBreadcrumbText', {
defaultMessage: 'Overview',
}),
href: '#/',
};

View file

@ -6,6 +6,7 @@
// @ts-ignore Missing typings for series charts
import { EuiHistogramSeries, EuiSeriesChart, EuiSeriesChartUtils } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { HistogramSeries } from '../../../common/graphql/types';
import { formatHistogramData } from '../../lib/adapters/monitors/format_histogram_data';
@ -19,8 +20,20 @@ export const SnapshotHistogram = ({ histogram }: SnapshotHistogramProps) => {
return (
<EuiSeriesChart width={600} height={107} stackBy="y" xType={EuiSeriesChartUtils.SCALE.TIME}>
<EuiHistogramSeries data={upSeriesData} name="Up" color="green" />
<EuiHistogramSeries data={downSeriesData} name="Down" color="red" />
<EuiHistogramSeries
data={upSeriesData}
name={i18n.translate('xpack.uptime.snapshotHistogram.series.upLabel', {
defaultMessage: 'Up',
})}
color="green"
/>
<EuiHistogramSeries
data={downSeriesData}
name={i18n.translate('xpack.uptime.snapshotHistogram.series.downLabel', {
defaultMessage: 'Down',
})}
color="red"
/>
</EuiSeriesChart>
);
};

View file

@ -5,6 +5,8 @@
*/
import { EuiEmptyPrompt, EuiLink, EuiTitle } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { Fragment } from 'react';
import { Query } from 'react-apollo';
import { getDocCountQuery } from './get_doc_count';
@ -26,10 +28,15 @@ export const EmptyState = ({
>
{({ loading, error, data }) => {
if (loading) {
return 'Loading...';
return i18n.translate('xpack.uptime.emptyState.loadingMessage', {
defaultMessage: 'Loading…',
});
}
if (error) {
return `Error ${error.message}`;
return i18n.translate('xpack.uptime.emptyState.errorMessage', {
values: { message: error.message },
defaultMessage: 'Error {message}',
});
}
const {
@ -41,22 +48,40 @@ export const EmptyState = ({
<EuiEmptyPrompt
title={
<EuiTitle size="l">
<h3>No Uptime Data</h3>
<h3>
<FormattedMessage
id="xpack.uptime.emptyState.noDataTitle"
defaultMessage="No Uptime Data"
/>
</h3>
</EuiTitle>
}
body={
<Fragment>
<p>There is no uptime data available.</p>
<p>
{
<EuiLink
target="_blank"
href="https://www.elastic.co/guide/en/beats/heartbeat/6.5/configuring-howto-heartbeat.html"
>
Configure Heartbeat
</EuiLink>
}
&nbsp;to start logging uptime data.
<FormattedMessage
id="xpack.uptime.emptyState.noDataDescription"
defaultMessage="There is no uptime data available."
/>
</p>
<p>
<FormattedMessage
id="xpack.uptime.emptyState.configureHeartbeatToGetStartedMessage"
defaultMessage="{configureHeartbeatLink} to start logging uptime data."
values={{
configureHeartbeatLink: (
<EuiLink
target="_blank"
href="https://www.elastic.co/guide/en/beats/heartbeat/6.5/configuring-howto-heartbeat.html"
>
<FormattedMessage
id="xpack.uptime.emptyState.configureHeartbeatLinkText"
defaultMessage="Configure Heartbeat"
/>
</EuiLink>
),
}}
/>
</p>
</Fragment>
}

View file

@ -6,6 +6,8 @@
// @ts-ignore missing typings
import { EuiInMemoryTable, EuiPanel, EuiTitle } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import moment from 'moment';
import React, { Fragment } from 'react';
import { Query } from 'react-apollo';
@ -22,36 +24,70 @@ export const ErrorList = ({ dateRangeStart, dateRangeEnd, filters }: ErrorListPr
<Query query={getErrorListQuery} variables={{ dateRangeStart, dateRangeEnd, filters }}>
{({ loading, error, data }) => {
if (error) {
return `Error ${error.message}`;
return i18n.translate('xpack.uptime.errorList.errorMessage', {
values: { message: error.message },
defaultMessage: 'Error {message}',
});
}
const { errorList } = data;
return (
<Fragment>
<EuiTitle size="xs">
<h5>Error list</h5>
<h5>
<FormattedMessage id="xpack.uptime.errorList.title" defaultMessage="Error list" />
</h5>
</EuiTitle>
<EuiPanel>
<EuiInMemoryTable
loading={loading}
items={errorList}
columns={[
{ field: 'type', name: 'Error Type', sortable: true },
{
field: 'type',
name: i18n.translate('xpack.uptime.errorList.errorTypeColumnLabel', {
defaultMessage: 'Error type',
}),
sortable: true,
},
{
field: 'monitorId',
name: 'Monitor ID',
name: i18n.translate('xpack.uptime.errorList.monitorIdColumnLabel', {
defaultMessage: 'Monitor ID',
}),
render: (id: string) => <Link to={`/monitor/${id}`}>{id}</Link>,
sortable: true,
width: '25%',
},
{ field: 'count', name: 'Count', sortable: true },
{
field: 'count',
name: i18n.translate('xpack.uptime.errorList.CountColumnLabel', {
defaultMessage: 'Count',
}),
sortable: true,
},
{
field: 'timestamp',
name: 'Latest error',
name: i18n.translate('xpack.uptime.errorList.latestErrorColumnLabel', {
defaultMessage: 'Latest error',
}),
sortable: true,
render: (timestamp: string) => moment(timestamp).fromNow(),
},
{ field: 'statusCode', name: 'Response code', sortable: true },
{ field: 'latestMessage', name: 'Latest message', sortable: true, width: '40%' },
{
field: 'statusCode',
name: i18n.translate('xpack.uptime.errorList.statusCodeColumnLabel', {
defaultMessage: 'Status code',
}),
sortable: true,
},
{
field: 'latestMessage',
name: i18n.translate('xpack.uptime.errorList.latestMessageColumnLabel', {
defaultMessage: 'Latest message',
}),
sortable: true,
width: '40%',
},
]}
sorting={true}
pagination={{ initialPageSize: 10, pageSizeOptions: [5, 10, 20, 50] }}

View file

@ -6,6 +6,7 @@
// @ts-ignore No typings for EuiSearchBar
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSearchBar, EuiToolTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { take } from 'lodash';
import React from 'react';
import { Query } from 'react-apollo';
@ -25,10 +26,15 @@ export const FilterBar = ({ dateRangeEnd, dateRangeStart, updateQuery }: FilterB
<Query query={getFilterBarQuery} variables={{ dateRangeStart, dateRangeEnd }}>
{({ loading, error, data }) => {
if (loading) {
return 'Loading...';
return i18n.translate('xpack.uptime.filterBar.loadingMessage', {
defaultMessage: 'Loading…',
});
}
if (error) {
return `Error ${error.message}`;
return i18n.translate('xpack.uptime.filterBar.errorMessage', {
values: { message: error.message },
defaultMessage: 'Error {message}',
});
}
const {
filterBar: { port, id, scheme },
@ -45,10 +51,14 @@ export const FilterBar = ({ dateRangeEnd, dateRangeStart, updateQuery }: FilterB
items: [
{
value: 'up',
name: 'Up',
name: i18n.translate('xpack.uptime.filterBar.filterUpLabel', {
defaultMessage: 'Up',
}),
},
{
value: 'down',
value: i18n.translate('xpack.uptime.filterBar.filterDownLabel', {
defaultMessage: 'Down',
}),
name: 'Down',
},
],
@ -57,7 +67,9 @@ export const FilterBar = ({ dateRangeEnd, dateRangeStart, updateQuery }: FilterB
{
type: 'field_value_selection',
field: 'monitor.id',
name: 'Host',
name: i18n.translate('xpack.uptime.filterBar.options.hostLabel', {
defaultMessage: 'Host',
}),
multiSelect: false,
options: take(id, MAX_SELECTION_LENGTH).map((idValue: any) => ({
value: idValue,
@ -68,7 +80,9 @@ export const FilterBar = ({ dateRangeEnd, dateRangeStart, updateQuery }: FilterB
{
type: 'field_value_selection',
field: 'tcp.port',
name: 'Port',
name: i18n.translate('xpack.uptime.filterBar.options.portLabel', {
defaultMessage: 'Port',
}),
multiSelect: false,
options: take(port, MAX_SELECTION_LENGTH).map((portValue: any) => ({
value: portValue,
@ -79,7 +93,9 @@ export const FilterBar = ({ dateRangeEnd, dateRangeStart, updateQuery }: FilterB
{
type: 'field_value_selection',
field: 'monitor.scheme',
name: 'Type',
name: i18n.translate('xpack.uptime.filterBar.options.typeLabel', {
defaultMessage: 'Type',
}),
multiSelect: false,
options: scheme.map((schemeValue: string) => ({ value: schemeValue, view: schemeValue })),
searchThreshold: SEARCH_THRESHOLD,
@ -110,8 +126,14 @@ export const FilterBar = ({ dateRangeEnd, dateRangeStart, updateQuery }: FilterB
<EuiFlexItem grow={false}>
<EuiToolTip
position="left"
title="Filter limitations"
content={`The top ${MAX_SELECTION_LENGTH} filter options for each field are displayed, but you can modify the filters manually or search for additional values.`}
title={i18n.translate('xpack.uptime.filterBar.filterLimitationsTooltipTitle', {
defaultMessage: 'Filter limitations',
})}
content={i18n.translate('xpack.uptime.filterBar.filterLimitationsTooltipText', {
values: { selectionLength: MAX_SELECTION_LENGTH },
defaultMessage:
'The top {selectionLength} filter options for each field are displayed, but you can modify the filters manually or search for additional values.',
})}
>
<EuiIcon type="iInCircle" size="l" />
</EuiToolTip>

View file

@ -21,6 +21,8 @@ import {
// @ts-ignore missing typings
EuiTitle,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { Fragment } from 'react';
import { Query } from 'react-apollo';
import { createGetMonitorChartsQuery } from './get_monitor_charts';
@ -47,10 +49,15 @@ export const MonitorCharts = ({
>
{({ loading, error, data }) => {
if (loading) {
return 'Loading...';
return i18n.translate('xpack.uptime.monitorCharts.loadingMessage', {
defaultMessage: 'Loading…',
});
}
if (error) {
return `Error ${error.message}`;
return i18n.translate('xpack.uptime.monitorCharts.errorMessage', {
values: { message: error.message },
defaultMessage: 'Error {message}',
});
}
// TODO: this should not exist in the UI, update the GQL resolver/schema to return
@ -96,7 +103,13 @@ export const MonitorCharts = ({
<EuiFlexGroup>
<EuiFlexItem>
<EuiTitle size="xs">
<h4>RTT Breakdown ms</h4>
<h4>
<FormattedMessage
id="xpack.uptime.monitorCharts.rttBreakdownTitle"
defaultMessage="RTT Breakdown ms"
description="The 'ms' is an abbreviation for milliseconds."
/>
</h4>
</EuiTitle>
<EuiPanel>
<EuiSeriesChart
@ -107,20 +120,55 @@ export const MonitorCharts = ({
height={200}
>
<EuiAreaSeries
name="Write Request"
name={i18n.translate(
'xpack.uptime.monitorCharts.rtt.series.writeRequestLabel',
{
defaultMessage: 'Write request',
}
)}
data={rttWriteRequestSeries}
curve="curveBasis"
/>
<EuiAreaSeries name="Validate" data={rttValidateSeries} curve="curveBasis" />
<EuiAreaSeries name="Content" data={rttContentSeries} curve="curveBasis" />
<EuiAreaSeries name="Response" data={rttResponseSeries} curve="curveBasis" />
<EuiAreaSeries name="Tcp" data={rttTcpSeries} curve="curveBasis" />
<EuiAreaSeries
name={i18n.translate('xpack.uptime.monitorCharts.rtt.series.validateLabel', {
defaultMessage: 'Validate',
})}
data={rttValidateSeries}
curve="curveBasis"
/>
<EuiAreaSeries
name={i18n.translate('xpack.uptime.monitorCharts.rtt.series.contentLabel', {
defaultMessage: 'Content',
})}
data={rttContentSeries}
curve="curveBasis"
/>
<EuiAreaSeries
name={i18n.translate('xpack.uptime.monitorCharts.rtt.series.responseLabel', {
defaultMessage: 'Response',
})}
data={rttResponseSeries}
curve="curveBasis"
/>
<EuiAreaSeries
name={i18n.translate('xpack.uptime.monitorCharts.rtt.series.tcpLabel', {
defaultMessage: 'Tcp',
})}
data={rttTcpSeries}
curve="curveBasis"
/>
</EuiSeriesChart>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem>
<EuiTitle size="xs">
<h4>Monitor Duration ms</h4>
<h4>
<FormattedMessage
id="xpack.uptime.monitorCharts.monitorDuration.titleLabel"
defaultMessage="Monitor Duration ms"
description="The 'ms' is an abbreviation for milliseconds."
/>
</h4>
</EuiTitle>
<EuiPanel>
<EuiSeriesChart
@ -129,15 +177,37 @@ export const MonitorCharts = ({
height={200}
xType={EuiSeriesChartUtils.SCALE.TIME}
>
<EuiAreaSeries name="Duration Range" data={areaRttSeries} curve="curveBasis" />
<EuiLineSeries name="Mean Duration" data={avgDurationSeries} />
<EuiAreaSeries
name={i18n.translate(
'xpack.uptime.monitorCharts.monitorDuration.series.durationRangeLabel',
{
defaultMessage: 'Duration range',
}
)}
data={areaRttSeries}
curve="curveBasis"
/>
<EuiLineSeries
name={i18n.translate(
'xpack.uptime.monitorCharts.monitorDuration.series.meanDurationLabel',
{
defaultMessage: 'Mean duration',
}
)}
data={avgDurationSeries}
/>
</EuiSeriesChart>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer />
<EuiTitle size="xs">
<h4>Check Status</h4>
<h4>
<FormattedMessage
id="xpack.uptime.monitorCharts.checkStatus.title"
defaultMessage="Check status"
/>
</h4>
</EuiTitle>
<EuiPanel style={{ maxWidth: 520, maxHeight: 220 }}>
<EuiSeriesChart
@ -147,8 +217,23 @@ export const MonitorCharts = ({
xType={EuiSeriesChartUtils.SCALE.TIME}
stackBy="y"
>
<EuiAreaSeries name="Up Count" data={upSeries} color="green" />
<EuiAreaSeries name="Down Count" data={downSeries} color="red" />
<EuiAreaSeries
name={i18n.translate('xpack.uptime.monitorCharts.checkStatus.series.upCountLabel', {
defaultMessage: 'Up count',
})}
data={upSeries}
color="green"
/>
<EuiAreaSeries
name={i18n.translate(
'xpack.uptime.monitorCharts.checkStatus.series.downCountLabel',
{
defaultMessage: 'Down count',
}
)}
data={downSeries}
color="red"
/>
</EuiSeriesChart>
</EuiPanel>
</Fragment>

View file

@ -17,6 +17,8 @@ import {
EuiSeriesChartUtils,
EuiTitle,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { get } from 'lodash';
import moment from 'moment';
import React, { Fragment } from 'react';
@ -38,39 +40,61 @@ const MONITOR_LIST_DEFAULT_PAGINATION = 10;
const monitorListColumns = [
{
field: 'ping.monitor.status',
name: 'Status',
name: i18n.translate('xpack.uptime.monitorList.statusColumnLabel', {
defaultMessage: 'Status',
}),
render: (status: string) => (
<EuiHealth color={status === 'up' ? 'success' : 'danger'}>
{status === 'up' ? 'Up' : 'Down'}
{status === 'up'
? i18n.translate('xpack.uptime.monitorList.statusColumn.upLabel', {
defaultMessage: 'Up',
})
: i18n.translate('xpack.uptime.monitorList.statusColumn.downLabel', {
defaultMessage: 'Down',
})}
</EuiHealth>
),
sortable: true,
},
{
field: 'ping.timestamp',
name: 'Last updated',
name: i18n.translate('xpack.uptime.monitorList.lastUpdatedColumnLabel', {
defaultMessage: 'Last updated',
}),
render: (timestamp: string) => moment(timestamp).fromNow(),
sortable: true,
},
{
field: 'ping.monitor.host',
name: 'Host',
name: i18n.translate('xpack.uptime.monitorList.hostColumnLabel', {
defaultMessage: 'Host',
}),
render: (host: string, monitor: any) => <Link to={`/monitor/${monitor.key.id}`}>{host}</Link>,
},
{
field: 'key.port',
name: 'Port',
name: i18n.translate('xpack.uptime.monitorList.portColumnLabel', {
defaultMessage: 'Port',
}),
sortable: true,
},
{
field: 'ping.monitor.type',
name: 'Type',
name: i18n.translate('xpack.uptime.monitorList.typeColumnLabel', {
defaultMessage: 'Type',
}),
sortable: true,
},
{
field: 'ping.monitor.ip',
name: i18n.translate('xpack.uptime.monitorList.ipColumnLabel', { defaultMessage: 'IP' }),
sortable: true,
},
{ field: 'ping.monitor.ip', name: 'IP', sortable: true },
{
field: 'upSeries',
name: 'Monitor History',
name: i18n.translate('xpack.uptime.monitorList.monitorHistoryColumnLabel', {
defaultMessage: 'Monitor History',
}),
// @ts-ignore TODO fix typing
render: (upSeries, monitor) => {
const { downSeries } = monitor;
@ -84,14 +108,18 @@ const monitorListColumns = [
<EuiLineSeries
lineSize={2}
color="green"
name="Up"
name={i18n.translate('xpack.uptime.monitorList.upLineSeries.upLabel', {
defaultMessage: 'Up',
})}
data={upSeries}
showLineMarks={true}
/>
<EuiLineSeries
lineSize={2}
color="red"
name="Down"
name={i18n.translate('xpack.uptime.monitorList.downLineSeries.downLabel', {
defaultMessage: 'Down',
})}
data={downSeries}
showLineMarks={true}
/>
@ -120,14 +148,22 @@ export const MonitorList = ({
>
{({ loading, error, data }) => {
if (error) {
return `Error ${error.message}`;
return i18n.translate('xpack.uptime.monitorList.errorMessage', {
values: { message: error.message },
defaultMessage: 'Error {message}',
});
}
const monitors: LatestMonitorsResult | undefined = get(data, 'monitorStatus.monitors');
// TODO: add a better loading message than "no items found", which it displays today
return (
<Fragment>
<EuiTitle size="xs">
<h5>Monitor status</h5>
<h5>
<FormattedMessage
id="xpack.uptime.monitorList.monitoringStatusTitle"
defaultMessage="Monitor status"
/>
</h5>
</EuiTitle>
<EuiPanel paddingSize="l">
<EuiInMemoryTable

View file

@ -6,6 +6,7 @@
// @ts-ignore No typing for EuiSuperSelect
import { EuiHealth, EuiSuperSelect } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { Query } from 'react-apollo';
import { Monitor } from '../../../../common/graphql/types';
@ -35,10 +36,15 @@ export const MonitorSelect = ({
>
{({ loading, error, data }) => {
if (loading) {
return 'Loading...';
return i18n.translate('xpack.uptime.monitorSelect.loadingMessage', {
defaultMessage: 'Loading…',
});
}
if (error) {
return `Error ${error.message}`;
return i18n.translate('xpack.uptime.monitorSelect.errorMessage', {
values: { message: error.message },
defaultMessage: 'Error {message}',
});
}
const { latestMonitors } = data;
const options = latestMonitors.map(({ monitor }: { monitor: Monitor }) => ({

View file

@ -5,6 +5,8 @@
*/
import { EuiFlexGroup, EuiFlexItem, EuiHealth, EuiPanel } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import moment from 'moment';
import React from 'react';
import { Query } from 'react-apollo';
@ -32,43 +34,99 @@ export const MonitorStatusBar = ({
>
{({ loading, error, data }) => {
if (loading) {
return 'Loading...';
return i18n.translate('xpack.uptime.monitorStatusBar.loadingMessage', {
defaultMessage: 'Loading…',
});
}
if (error) {
return `Error ${error.message}`;
return i18n.translate('xpack.uptime.monitorStatusBar.errorMessage', {
values: { message: error.message },
defaultMessage: 'Error {message}',
});
}
const { monitorStatus } = data;
if (!monitorStatus.length) {
return `No data found for monitor id ${monitorId}`;
return i18n.translate('xpack.uptime.monitorStatusBar.noDataMessage', {
values: { monitorId },
defaultMessage: 'No data found for monitor id {monitorId}',
});
}
const { monitor, tcp } = monitorStatus[0];
const {
monitor: {
status,
timestamp,
host,
duration: { us },
scheme,
},
tcp: { port },
} = monitorStatus[0];
return (
<EuiPanel>
<EuiFlexGroup gutterSize="l">
<EuiFlexItem grow={false}>
<EuiFlexGroup>
<EuiFlexItem>Status&#58;</EuiFlexItem>
<EuiFlexItem>
<FormattedMessage
id="xpack.uptime.monitorStatusBar.statusLabel"
defaultMessage="Status:"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiHealth
color={monitor.status === 'up' ? 'success' : 'danger'}
color={status === 'up' ? 'success' : 'danger'}
style={{ lineHeight: 'inherit' }}
>
{monitor.status === 'up' ? 'Up' : 'Down'}
{status === 'up'
? i18n.translate(
'xpack.uptime.monitorStatusBar.healthStatusMessage.upLabel',
{ defaultMessage: 'Up' }
)
: i18n.translate(
'xpack.uptime.monitorStatusBar.healthStatusMessage.downLabel',
{ defaultMessage: 'Down' }
)}
</EuiHealth>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
Last update: {moment(monitor.timestamp).fromNow()}
<FormattedMessage
id="xpack.uptime.monitorStatusBar.healthStatus.lastUpdateMessage"
values={{ timeFromNow: moment(timestamp).fromNow() }}
defaultMessage="Last update: {timeFromNow}"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>Host: {monitor.host}</EuiFlexItem>
<EuiFlexItem grow={false}>Port: {tcp.port}</EuiFlexItem>
<EuiFlexItem grow={false}>
Duration: {monitor.duration.us / 1000}
ms
<FormattedMessage
id="xpack.uptime.monitorStatusBar.healthStatus.hostMessage"
values={{ host }}
defaultMessage="Host: {host}"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<FormattedMessage
id="xpack.uptime.monitorStatusBar.healthStatus.portMessage"
values={{ port }}
defaultMessage="Port: {port}"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<FormattedMessage
id="xpack.uptime.monitorStatusBar.healthStatus.durationInMillisecondsMessage"
// TODO: this should not be computed inline
values={{ duration: us / 1000 }}
defaultMessage="Duration: {duration} ms"
/>
</EuiFlexItem>
<EuiFlexItem>
<FormattedMessage
id="xpack.uptime.monitorStatusBar.healthStatus.schemeMessage"
values={{ scheme }}
defaultMessage="Scheme: {scheme}"
/>
</EuiFlexItem>
<EuiFlexItem>Scheme: {monitor.scheme}</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
);

View file

@ -19,6 +19,8 @@ import {
EuiTitle,
EuiToolTip,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { get } from 'lodash';
import moment from 'moment';
import React, { Fragment } from 'react';
@ -48,9 +50,24 @@ export class Pings extends React.Component<PingListProps, PingListState> {
super(props);
const statusOptions = [
{ label: 'All', value: '' },
{ label: 'Up', value: 'up' },
{ label: 'Down', value: 'down' },
{
label: i18n.translate('xpack.uptime.pingList.statusOptions.allStatusOptionLabel', {
defaultMessage: 'All',
}),
value: '',
},
{
label: i18n.translate('xpack.uptime.pingList.statusOptions.upStatusOptionLabel', {
defaultMessage: 'Up',
}),
value: 'up',
},
{
label: i18n.translate('xpack.uptime.pingList.statusOptions.downStatusOptionLabel', {
defaultMessage: 'Down',
}),
value: 'down',
},
];
this.state = {
statusOptions,
@ -80,6 +97,7 @@ export class Pings extends React.Component<PingListProps, PingListState> {
selectedOption.value === 'up' || selectedOption.value === 'down'
? selectedOption.value
: '',
// TODO: get rid of the magic number
size: this.state.maxSearchSize || size || 200,
sort: sort || 'desc',
}}
@ -87,54 +105,87 @@ export class Pings extends React.Component<PingListProps, PingListState> {
>
{({ loading, error, data }) => {
if (error) {
return `Error ${error.message}`;
return i18n.translate('xpack.uptime.pingList.errorMessage', {
values: { message: error.message },
defaultMessage: 'Error {message}',
});
}
const total = get(data, 'allPings.total');
const pings = get(data, 'allPings.pings', []);
const columns = [
{
field: 'monitor.status',
name: 'Status',
name: i18n.translate('xpack.uptime.pingList.statusColumnLabel', {
defaultMessage: 'Status',
}),
render: (pingStatus: string) => (
<EuiHealth color={pingStatus === 'up' ? 'success' : 'danger'}>
{pingStatus === 'up' ? 'Up' : 'Down'}
{pingStatus === 'up'
? i18n.translate('xpack.uptime.pingList.statusColumnHealthUpLabel', {
defaultMessage: 'Up',
})
: i18n.translate('xpack.uptime.pingList.statusColumnHealthDownLabel', {
defaultMessage: 'Down',
})}
</EuiHealth>
),
sortable: true,
},
{
field: 'timestamp',
name: 'Timestamp',
name: i18n.translate('xpack.uptime.pingList.timestampColumnLabel', {
defaultMessage: 'Timestamp',
}),
sortable: true,
render: (timestamp: string) => moment(timestamp).fromNow(),
},
{
field: 'monitor.ip',
name: 'IP',
name: i18n.translate('xpack.uptime.pingList.ipAddressColumnLabel', {
defaultMessage: 'IP',
}),
},
{
field: 'monitor.id',
name: 'Id',
name: i18n.translate('xpack.uptime.pingList.idColumnLabel', {
defaultMessage: 'Id',
}),
dataType: 'string',
width: '20%',
},
{
field: 'monitor.duration.us',
name: 'Duration ms',
name: i18n.translate('xpack.uptime.pingList.durationMsColumnLabel', {
defaultMessage: 'Duration ms',
description: 'The "ms" in the default message is an abbreviation for milliseconds',
}),
render: (duration: number) => duration / 1000,
sortable: true,
},
{
field: 'error.type',
name: 'Error Type',
name: i18n.translate('xpack.uptime.pingList.errorTypeColumnLabel', {
defaultMessage: 'Error type',
}),
},
{
field: 'error.message',
name: 'Error Message',
name: i18n.translate('xpack.uptime.pingList.errorMessageColumnLabel', {
defaultMessage: 'Error message',
}),
render: (message: string) =>
message && message.length > 25 ? (
<EuiToolTip position="top" title="Error Message" content={<p>{message}</p>}>
<div>{message.slice(0, 24)}...</div>
<EuiToolTip
position="top"
title={i18n.translate(
'xpack.uptime.pingList.columns.errorMessageTooltipTitle',
{
defaultMessage: 'Error message',
}
)}
content={<p>{message}</p>}
>
<div>{message.slice(0, 24)}</div>
</EuiToolTip>
) : (
message
@ -147,14 +198,24 @@ export class Pings extends React.Component<PingListProps, PingListState> {
false
);
if (hasStatus) {
columns.push({ field: 'http.response.status_code', name: 'Response Code' });
columns.push({
field: 'http.response.status_code',
name: i18n.translate('xpack.uptime.pingList.responseCodeColumnLabel', {
defaultMessage: 'Response code',
}),
});
}
return (
<Fragment>
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<EuiTitle size="xs">
<h4>Check History</h4>
<h4>
<FormattedMessage
id="xpack.uptime.pingList.checkHistoryTitle"
defaultMessage="Check History"
/>
</h4>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
@ -164,7 +225,11 @@ export class Pings extends React.Component<PingListProps, PingListState> {
<EuiPanel paddingSize="l">
<EuiFlexGroup>
<EuiFlexItem>
<EuiFormRow label="Status">
<EuiFormRow
label={i18n.translate('xpack.uptime.pingList.statusLabel', {
defaultMessage: 'Status',
})}
>
<EuiComboBox
isClearable={false}
singleSelection={{ asPlainText: true }}
@ -179,7 +244,11 @@ export class Pings extends React.Component<PingListProps, PingListState> {
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow label="Max Search Size">
<EuiFormRow
label={i18n.translate('xpack.uptime.pingList.maxSearchSizeLabel', {
defaultMessage: 'Max Search Size',
})}
>
<EuiFieldNumber
defaultValue={this.state.maxSearchSize.toString()}
min={0}

View file

@ -22,6 +22,8 @@ import {
EuiStat,
EuiTitle,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import React from 'react';
import { Query } from 'react-apollo';
import { SnapshotHistogram } from '../../functional/snapshot_histogram';
@ -50,10 +52,15 @@ export const Snapshot = ({
>
{({ loading, error, data }) => {
if (loading) {
return 'Loading...';
return i18n.translate('xpack.uptime.snapshot.loadingMessage', {
defaultMessage: 'Loading…',
});
}
if (error) {
return `Error ${error.message}`;
return i18n.translate('xpack.uptime.snapshot.errorMessage', {
values: { message: error.message },
defaultMessage: 'Error {message}',
});
}
const {
snapshot: { up, down, total, histogram },
@ -63,20 +70,34 @@ export const Snapshot = ({
<EuiFlexGroup alignItems="baseline" gutterSize="xl">
<EuiFlexItem>
<EuiTitle size="xs">
<h5>Endpoint status</h5>
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.endpointStatusTitle"
defaultMessage="Endpoint status"
/>
</h5>
</EuiTitle>
<EuiPanel>
<EuiFlexGroup justifyContent="spaceEvenly" gutterSize="xl">
<EuiFlexItem>
{/* TODO: this is a UI hack that needs to be replaced */}
<EuiPanel>
<EuiStat description="Up" textAlign="center" title={up} titleColor="primary" />
<EuiStat
description={i18n.translate('xpack.uptime.snapshot.stats.upDescription', {
defaultMessage: 'Up',
})}
textAlign="center"
title={up}
titleColor="primary"
/>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem>
<EuiPanel>
<EuiStat
description="Down"
description={i18n.translate('xpack.uptime.snapshot.stats.downDescription', {
defaultMessage: 'Down',
})}
textAlign="center"
title={down}
titleColor="danger"
@ -86,7 +107,9 @@ export const Snapshot = ({
<EuiFlexItem>
<EuiPanel>
<EuiStat
description="Total"
description={i18n.translate('xpack.uptime.snapshot.stats.totalDescription', {
defaultMessage: 'Total',
})}
textAlign="center"
title={total}
titleColor="subdued"
@ -98,7 +121,12 @@ export const Snapshot = ({
</EuiFlexItem>
<EuiFlexItem style={{ paddingTop: '12px' }}>
<EuiTitle size="xs">
<h5>Status over time</h5>
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.statusOverTimeTitle"
defaultMessage="Status over time"
/>
</h5>
</EuiTitle>
{/* TODO: this is a UI hack that should be replaced */}
<EuiPanel paddingSize="s">
@ -107,10 +135,22 @@ export const Snapshot = ({
<EuiEmptyPrompt
title={
<EuiTitle>
<h5>No Histogram Data Available</h5>
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.noDataTitle"
defaultMessage="No histogram data available"
/>
</h5>
</EuiTitle>
}
body={<p>Sorry, there is no data available for the histogram</p>}
body={
<p>
<FormattedMessage
id="xpack.uptime.snapshot.noDataDescription"
defaultMessage="Sorry, there is no data available for the histogram"
/>
</p>
}
/>
)}
</EuiPanel>

View file

@ -13,6 +13,7 @@ import {
EuiSuperSelect,
EuiTitle,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { Fragment } from 'react';
import { getMonitorPageBreadcrumb } from '../breadcrumbs';
import { MonitorCharts } from '../components/queries/monitor_charts';
@ -60,7 +61,12 @@ export class MonitorPage extends React.Component<MonitorPageProps> {
<EuiSpacer size="l" />
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<span>Monitor:</span>
<span>
<FormattedMessage
id="xpack.uptime.monitorPage.header.salutation"
defaultMessage="Monitor:"
/>
</span>
</EuiFlexItem>
<EuiFlexItem>
<MonitorSelect

View file

@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { i18n } from '@kbn/i18n';
import {
FeatureCatalogueCategory,
FeatureCatalogueRegistryProvider,
@ -11,8 +12,10 @@ import {
FeatureCatalogueRegistryProvider.register(() => ({
id: 'uptime',
title: 'Uptime',
description: 'Perform endpoint health checks and uptime monitoring.',
title: i18n.translate('xpack.uptime.uptimeFeatureCatalogueTitle', { defaultMessage: 'Uptime' }),
description: i18n.translate('xpack.uptime.featureCatalogueDescription', {
defaultMessage: 'Perform endpoint health checks and uptime monitoring.',
}),
icon: 'heartbeatApp',
path: `uptime#/`,
showOnHomePage: true,

View file

@ -27,6 +27,8 @@ import {
EuiPopover,
EuiSwitch,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage, I18nProvider } from '@kbn/i18n/react';
import moment, { Moment } from 'moment';
import React from 'react';
import { ApolloProvider } from 'react-apollo';
@ -124,161 +126,188 @@ class Application extends React.Component<UptimeAppProps, UptimeAppState> {
const { isUsingK7Design, routerBasename, graphQLClient } = this.props;
const dateRangeIsInvalid = () => this.state.dateRangeStart > this.state.dateRangeEnd;
return (
<Router basename={routerBasename}>
<ApolloProvider client={graphQLClient}>
<EuiPage className="app-wrapper-panel">
<EuiHeader>
{/*
<I18nProvider>
<Router basename={routerBasename}>
<ApolloProvider client={graphQLClient}>
<EuiPage className="app-wrapper-panel">
<EuiHeader>
{/*
// @ts-ignore TODO no typings for grow prop */}
<EuiHeaderSection grow={true}>
<EuiHeaderSectionItem border="right">
<EuiHeaderLogo
aria-label="Go to Uptime home page"
href="#/"
iconType="heartbeatApp"
iconTitle="Uptime"
>
Uptime
</EuiHeaderLogo>
</EuiHeaderSectionItem>
{!isUsingK7Design && (
<EuiHeaderSectionItem>
<div style={{ paddingTop: '20px', paddingRight: '8px' }}>
<EuiHeaderBreadcrumbs breadcrumbs={this.state.breadcrumbs} />
<EuiHeaderSection grow={true}>
<EuiHeaderSectionItem border="right">
<EuiHeaderLogo
aria-label={i18n.translate('xpack.uptime.appHeader.uptimeLogoAriaLabel', {
defaultMessage: 'Go to Uptime home page',
})}
href="#/"
iconType="heartbeatApp"
iconTitle={i18n.translate('xpack.uptime.appHeader.uptimeLogoTitle', {
defaultMessage: 'Uptime',
})}
>
<FormattedMessage
id="xpack.uptime.appHeader.uptimeLogoText"
defaultMessage="Uptime"
/>
</EuiHeaderLogo>
</EuiHeaderSectionItem>
{!isUsingK7Design && (
<EuiHeaderSectionItem>
<div style={{ paddingTop: '20px', paddingRight: '8px' }}>
<EuiHeaderBreadcrumbs breadcrumbs={this.state.breadcrumbs} />
</div>
</EuiHeaderSectionItem>
)}
</EuiHeaderSection>
<EuiHeaderSection side="right">
<EuiHeaderSectionItem border="none">
<div style={{ marginTop: '10px', marginLeft: '8px' }}>
<EuiDatePickerRange
startDateControl={
<EuiDatePicker
selected={moment(this.state.dateRangeStart)}
isInvalid={dateRangeIsInvalid()}
aria-label={i18n.translate('xpack.uptime.startDateRangeAriaLabel', {
defaultMessage: 'Start date',
})}
onChange={(e: Moment | null) => {
if (e && e.valueOf() < this.state.dateRangeEnd) {
this.setState({ dateRangeStart: e.valueOf() }, this.persistState);
}
}}
showTimeSelect
/>
}
endDateControl={
<EuiDatePicker
selected={moment(this.state.dateRangeEnd)}
isInvalid={dateRangeIsInvalid()}
aria-label={i18n.translate('xpack.uptime.endDateRangeAriaLabel', {
defaultMessage: 'End date',
})}
onChange={(e: Moment | null) => {
if (e && this.state.dateRangeStart < e.valueOf()) {
this.setState({ dateRangeEnd: e.valueOf() }, this.persistState);
}
}}
showTimeSelect
/>
}
/>
</div>
</EuiHeaderSectionItem>
)}
</EuiHeaderSection>
<EuiHeaderSection side="right">
<EuiHeaderSectionItem border="none">
<div style={{ marginTop: '10px', marginLeft: '8px' }}>
<EuiDatePickerRange
startDateControl={
<EuiDatePicker
selected={moment(this.state.dateRangeStart)}
isInvalid={dateRangeIsInvalid()}
aria-label="Start Date"
onChange={(e: Moment | null) => {
if (e && e.valueOf() < this.state.dateRangeEnd) {
this.setState({ dateRangeStart: e.valueOf() }, this.persistState);
}
}}
showTimeSelect
/>
<EuiHeaderSectionItem border="none">
<EuiPopover
id="autorefreshPopover"
button={
<EuiButton
iconType="arrowDown"
iconSide="right"
onClick={() => this.setState({ popoverIsOpen: true })}
>
{this.state.autorefreshEnabled
? i18n.translate('xpack.uptime.autorefreshIntervalSelectedLabel', {
values: { selectedValue: this.state.selectedAutorefresh.label },
defaultMessage: 'Autorefresh every {selectedValue}',
})
: i18n.translate('xpack.uptime.autorefreshIntervalDisabledLabel', {
defaultMessage: 'Autorefresh Disabled',
})}
</EuiButton>
}
endDateControl={
<EuiDatePicker
selected={moment(this.state.dateRangeEnd)}
isInvalid={dateRangeIsInvalid()}
aria-label="End Date"
onChange={(e: Moment | null) => {
if (e && this.state.dateRangeStart < e.valueOf()) {
this.setState({ dateRangeEnd: e.valueOf() }, this.persistState);
}
}}
showTimeSelect
/>
}
/>
</div>
</EuiHeaderSectionItem>
<EuiHeaderSectionItem border="none">
<EuiPopover
id="autorefresPopover"
button={
<EuiButton
iconType="arrowDown"
iconSide="right"
onClick={() => this.setState({ popoverIsOpen: true })}
>
{this.state.autorefreshEnabled
? 'Autorefresh every ' + this.state.selectedAutorefresh.label
: 'Autorefresh Disabled'}
</EuiButton>
}
closePopover={() => this.setState({ popoverIsOpen: false })}
isOpen={this.state.popoverIsOpen}
style={{ paddingLeft: '8px', paddingTop: '10px', paddingRight: '8px' }}
>
<EuiFlexGroup direction="column">
<EuiFlexItem>
<EuiSwitch
label="Auto-refresh"
checked={this.state.autorefreshEnabled}
onChange={e => {
this.setState(
{ autorefreshEnabled: e.target.checked },
this.persistState
);
}}
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiComboBox
onChange={selectedOptions => {
this.setState(
{ selectedAutorefresh: selectedOptions[0] },
this.persistState
);
}}
options={this.state.autorefreshOptions}
isClearable={false}
singleSelection={{ asPlainText: true }}
selectedOptions={[this.state.selectedAutorefresh]}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPopover>
</EuiHeaderSectionItem>
</EuiHeaderSection>
<EuiHeaderSection side="right">
<EuiHeaderSection>
<EuiHeaderLinks>
<EuiHeaderLink
iconType="help"
href="https://discuss.elastic.co/c/beats/heartbeat"
target="_blank"
closePopover={() => this.setState({ popoverIsOpen: false })}
isOpen={this.state.popoverIsOpen}
style={{ paddingLeft: '8px', paddingTop: '10px', paddingRight: '8px' }}
>
Discuss
</EuiHeaderLink>
</EuiHeaderLinks>
<EuiFlexGroup direction="column">
<EuiFlexItem>
<EuiSwitch
label={i18n.translate('xpack.uptime.autoRefreshSwitchLabel', {
defaultMessage: 'Auto-refresh',
})}
checked={this.state.autorefreshEnabled}
onChange={e => {
this.setState(
{ autorefreshEnabled: e.target.checked },
this.persistState
);
}}
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiComboBox
onChange={selectedOptions => {
this.setState(
{ selectedAutorefresh: selectedOptions[0] },
this.persistState
);
}}
options={this.state.autorefreshOptions}
isClearable={false}
singleSelection={{ asPlainText: true }}
selectedOptions={[this.state.selectedAutorefresh]}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPopover>
</EuiHeaderSectionItem>
</EuiHeaderSection>
</EuiHeaderSection>
</EuiHeader>
<EuiPageContent>
<Switch>
<Route
exact
path="/"
render={props => (
<OverviewPage
{...props}
autorefreshEnabled={this.state.autorefreshEnabled}
autorefreshInterval={this.state.selectedAutorefresh.value}
dateRangeStart={this.state.dateRangeStart}
dateRangeEnd={this.state.dateRangeEnd}
setBreadcrumbs={this.setBreadcrumbs}
/>
)}
/>
<Route
path="/monitor/:id"
render={props => (
<MonitorPage
{...props}
dateRangeStart={this.state.dateRangeStart}
dateRangeEnd={this.state.dateRangeEnd}
updateBreadcrumbs={this.setBreadcrumbs}
autorefreshEnabled={this.state.autorefreshEnabled}
autorefreshInterval={this.state.selectedAutorefresh.value}
/>
)}
/>
</Switch>
</EuiPageContent>
</EuiPage>
</ApolloProvider>
</Router>
<EuiHeaderSection side="right">
<EuiHeaderSection>
<EuiHeaderLinks>
<EuiHeaderLink
aria-label={i18n.translate('xpack.uptime.header.helpLinkAriaLabel', {
defaultMessage: 'Go to our discuss page',
})}
iconType="help"
href="https://discuss.elastic.co/c/beats/heartbeat"
target="_blank"
>
<FormattedMessage
id="xpack.uptime.header.helpLinkText"
defaultMessage="Discuss"
description="The link is to a support form called 'Discuss', where users can submit feedback."
/>
</EuiHeaderLink>
</EuiHeaderLinks>
</EuiHeaderSection>
</EuiHeaderSection>
</EuiHeader>
<EuiPageContent>
<Switch>
<Route
exact
path="/"
render={props => (
<OverviewPage
{...props}
autorefreshEnabled={this.state.autorefreshEnabled}
autorefreshInterval={this.state.selectedAutorefresh.value}
dateRangeStart={this.state.dateRangeStart}
dateRangeEnd={this.state.dateRangeEnd}
setBreadcrumbs={this.setBreadcrumbs}
/>
)}
/>
<Route
path="/monitor/:id"
render={props => (
<MonitorPage
{...props}
dateRangeStart={this.state.dateRangeStart}
dateRangeEnd={this.state.dateRangeEnd}
updateBreadcrumbs={this.setBreadcrumbs}
autorefreshEnabled={this.state.autorefreshEnabled}
autorefreshInterval={this.state.selectedAutorefresh.value}
/>
)}
/>
</Switch>
</EuiPageContent>
</EuiPage>
</ApolloProvider>
</Router>
</I18nProvider>
);
}