mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[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:
parent
a00d487afe
commit
a7f249dc43
16 changed files with 694 additions and 255 deletions
|
@ -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": [
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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: '#/',
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
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>
|
||||
}
|
||||
|
|
|
@ -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] }}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }) => ({
|
||||
|
|
|
@ -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:</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>
|
||||
);
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue