[i18n] Translations for Monitoring: Cluster and Alerts (#24736)

* Translations for Cluster and Alerts

* Translations for cluster and alerts

* Translations for cluster and alerts

* Fix typos

* Update id

* Update Notification snapshot

* Translate lastEvent label

* Revert changes for untranslated label.
This commit is contained in:
Maryia Lapata 2018-11-16 15:03:17 +03:00 committed by GitHub
parent e44609753f
commit 11cda77d82
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 658 additions and 174 deletions

View file

@ -25,8 +25,6 @@
},
"exclude": [
"src/ui/ui_render/bootstrap/app_bootstrap.js",
"src/ui/ui_render/ui_render_mixin.js",
"x-pack/plugins/monitoring/public/components/cluster/overview/alerts_panel.js",
"x-pack/plugins/monitoring/public/directives/alerts/index.js"
"src/ui/ui_render/ui_render_mixin.js"
]
}

View file

@ -3,23 +3,25 @@
exports[`#start() renders the GlobalToastList into the targetDomElement param 1`] = `
Array [
Array [
<GlobalToastList
dismissToast={[Function]}
toasts$={
Observable {
"_isScalar": false,
"source": BehaviorSubject {
<I18nProvider>
<GlobalToastList
dismissToast={[Function]}
toasts$={
Observable {
"_isScalar": false,
"_value": Array [],
"closed": false,
"hasError": false,
"isStopped": false,
"observers": Array [],
"thrownError": null,
},
"source": BehaviorSubject {
"_isScalar": false,
"_value": Array [],
"closed": false,
"hasError": false,
"isStopped": false,
"observers": Array [],
"thrownError": null,
},
}
}
}
/>,
/>
</I18nProvider>,
<div
test="target-dom-element"
/>,

View file

@ -21,6 +21,7 @@ import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { Toast } from '@elastic/eui';
import { I18nProvider } from '@kbn/i18n/react';
import { GlobalToastList } from './global_toast_list';
import { ToastsStartContract } from './toasts_start_contract';
@ -35,10 +36,12 @@ export class ToastsService {
const toasts = new ToastsStartContract();
render(
<GlobalToastList
dismissToast={(toast: Toast) => toasts.remove(toast)}
toasts$={toasts.get$()}
/>,
<I18nProvider>
<GlobalToastList
dismissToast={(toast: Toast) => toasts.remove(toast)}
toasts$={toasts.get$()}
/>
</I18nProvider>,
this.params.targetDomElement
);

View file

@ -29,24 +29,41 @@ import { capitalize } from 'lodash';
* @param {Number} severity The number representing the severity. Higher is "worse".
* @return {Object} An object containing details about the severity.
*/
import { i18n } from '@kbn/i18n';
export function mapSeverity(severity) {
const floor = Math.floor(severity / 1000);
let mapped;
switch (floor) {
case 0:
mapped = { value: 'low', color: 'warning', iconType: 'dot' };
mapped = {
value: i18n.translate('xpack.monitoring.alerts.lowSeverityName', { defaultMessage: 'low' }),
color: 'warning',
iconType: 'dot'
};
break;
case 1:
mapped = { value: 'medium', color: 'warning', iconType: 'dot' };
mapped = {
value: i18n.translate('xpack.monitoring.alerts.mediumSeverityName', { defaultMessage: 'medium' }),
color: 'warning',
iconType: 'dot'
};
break;
default: // severity >= 2000
mapped = { value: 'high', color: 'danger', iconType: 'dot' };
mapped = {
value: i18n.translate('xpack.monitoring.alerts.highSeverityName', { defaultMessage: 'high' }),
color: 'danger',
iconType: 'dot'
};
break;
}
return {
title: `${capitalize(mapped.value)} severity alert`,
title: i18n.translate('xpack.monitoring.alerts.severityTitle',
{ defaultMessage: '{severity} severity alert', values: { severity: capitalize(mapped.value) } }
),
...mapped
};
}
}

View file

@ -8,12 +8,13 @@ import React from 'react';
import { Tooltip } from 'plugins/monitoring/components/tooltip';
import { mapSeverity } from 'plugins/monitoring/components/alerts/map_severity';
import { EuiHealth } from '@elastic/eui';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
const HIGH_SEVERITY = 2000;
const MEDIUM_SEVERITY = 1000;
const LOW_SEVERITY = 0;
export function AlertsIndicator({ alerts }) {
function AlertsIndicatorUi({ alerts, intl }) {
if (alerts && alerts.count > 0) {
const severity = (() => {
if (alerts.high > 0) { return HIGH_SEVERITY; }
@ -24,29 +25,49 @@ export function AlertsIndicator({ alerts }) {
const tooltipText = (() => {
switch (severity) {
case HIGH_SEVERITY:
return 'There are some critical cluster issues that require your immediate attention!';
return intl.formatMessage({
id: 'xpack.monitoring.cluster.listing.alertsInticator.highSeverityTooltip',
defaultMessage: 'There are some critical cluster issues that require your immediate attention!' });
case MEDIUM_SEVERITY:
return 'There are some issues that might have impact on your cluster.';
return intl.formatMessage({
id: 'xpack.monitoring.cluster.listing.alertsInticator.mediumSeverityTooltip',
defaultMessage: 'There are some issues that might have impact on your cluster.' });
default:
// might never show
return 'There are some low-severity cluster issues';
return intl.formatMessage({
id: 'xpack.monitoring.cluster.listing.alertsInticator.lowSeverityTooltip',
defaultMessage: 'There are some low-severity cluster issues' });
}
})();
return (
<Tooltip text={tooltipText} placement="bottom" trigger="hover">
<EuiHealth color={severityIcon.color} data-test-subj="alertIcon">
Alerts
<FormattedMessage
id="xpack.monitoring.cluster.listing.alertsInticator.alertsTooltip"
defaultMessage="Alerts"
/>
</EuiHealth>
</Tooltip>
);
}
return (
<Tooltip text="Cluster status is clear!" placement="bottom" trigger="hover">
<Tooltip
text={intl.formatMessage({
id: 'xpack.monitoring.cluster.listing.alertsInticator.clearStatusTooltip',
defaultMessage: 'Cluster status is clear!' })}
placement="bottom"
trigger="hover"
>
<EuiHealth color="success" data-test-subj="alertIcon">
Clear
<FormattedMessage
id="xpack.monitoring.cluster.listing.alertsInticator.clearTooltip"
defaultMessage="Clear"
/>
</EuiHealth>
</Tooltip>
);
}
export const AlertsIndicator = injectI18n(AlertsIndicatorUi);

View file

@ -10,6 +10,7 @@ import { mapSeverity } from 'plugins/monitoring/components/alerts/map_severity';
import { formatTimestampToDuration } from '../../../../common/format_timestamp_to_duration';
import { CALCULATE_DURATION_SINCE } from '../../../../common/constants';
import { formatDateTimeLocal } from '../../../../common/formatting';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
import {
EuiFlexGroup,
@ -22,7 +23,7 @@ import {
EuiCallOut,
} from '@elastic/eui';
export function AlertsPanel({ alerts, changeUrl }) {
function AlertsPanelUi({ alerts, changeUrl, intl }) {
const goToAlerts = () => changeUrl('/alerts');
if (!alerts || !alerts.length) {
@ -35,8 +36,11 @@ export function AlertsPanel({ alerts, changeUrl }) {
const severityIcon = mapSeverity(item.metadata.severity);
if (item.resolved_timestamp) {
severityIcon.title =
`${severityIcon.title} (resolved ${formatTimestampToDuration(item.resolved_timestamp, CALCULATE_DURATION_SINCE)} ago)`;
severityIcon.title = intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.alertsPanel.severityIconTitle',
defaultMessage: '{severityIconTitle} (resolved {time} ago)' },
{ severityIconTitle: severityIcon.title, time: formatTimestampToDuration(item.resolved_timestamp, CALCULATE_DURATION_SINCE)
});
severityIcon.color = "success";
severityIcon.iconType = "check";
}
@ -60,11 +64,14 @@ export function AlertsPanel({ alerts, changeUrl }) {
<EuiText size="xs">
<p data-test-subj="alertMeta">
<EuiTextColor color="subdued">
Last checked {
formatDateTimeLocal(item.update_timestamp)
} (triggered {
formatTimestampToDuration(item.timestamp, CALCULATE_DURATION_SINCE)
} ago)
<FormattedMessage
id="xpack.monitoring.cluster.overview.alertsPanel.lastCheckedTimeText"
defaultMessage="Last checked {updateDateTime} (triggered {duration} ago)"
values={{
updateDateTime: formatDateTimeLocal(item.update_timestamp),
duration: formatTimestampToDuration(item.timestamp, CALCULATE_DURATION_SINCE)
}}
/>
</EuiTextColor>
</p>
</EuiText>
@ -80,13 +87,19 @@ export function AlertsPanel({ alerts, changeUrl }) {
<EuiFlexItem grow={false}>
<EuiTitle>
<h2>
Top cluster alerts
<FormattedMessage
id="xpack.monitoring.cluster.overview.alertsPanel.topClusterTitle"
defaultMessage="Top cluster alerts"
/>
</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton size="s" onClick={goToAlerts} data-test-subj="viewAllAlerts">
View all alerts
<FormattedMessage
id="xpack.monitoring.cluster.overview.alertsPanel.viewAllButtonLabel"
defaultMessage="View all alerts"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
@ -96,3 +109,5 @@ export function AlertsPanel({ alerts, changeUrl }) {
</div>
);
}
export const AlertsPanel = injectI18n(AlertsPanelUi);

View file

@ -9,6 +9,7 @@ import moment from 'moment';
import { get } from 'lodash';
import { formatMetric } from 'plugins/monitoring/lib/format_number';
import { ClusterItemContainer, BytesPercentageUsage } from './helpers';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
import {
EuiFlexGrid,
@ -22,8 +23,9 @@ import {
EuiHorizontalRule,
} from '@elastic/eui';
import { formatTimestampToDuration } from '../../../../common';
import { CALCULATE_DURATION_SINCE } from '../../../../common/constants';
export function ApmPanel(props) {
function ApmPanelUi(props) {
if (!get(props, 'apms.total', 0) > 0) {
return null;
}
@ -32,7 +34,11 @@ export function ApmPanel(props) {
const goToInstances = () => props.changeUrl('apm/instances');
return (
<ClusterItemContainer {...props} url="apm" title="APM">
<ClusterItemContainer
{...props}
url="apm"
title={props.intl.formatMessage({ id: 'xpack.monitoring.cluster.overview.apmPanel.apmTitle', defaultMessage: 'APM' })}
>
<EuiFlexGrid columns={2}>
<EuiFlexItem>
<EuiPanel paddingSize="m">
@ -40,22 +46,40 @@ export function ApmPanel(props) {
<h3>
<EuiLink
onClick={goToApm}
aria-label="APM Overview"
aria-label={props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.apmPanel.overviewLinkAriaLabel', defaultMessage: 'APM Overview' })}
data-test-subj="apmOverview"
>
Overview
<FormattedMessage
id="xpack.monitoring.cluster.overview.apmPanel.overviewLinkLabel"
defaultMessage="Overview"
/>
</EuiLink>
</h3>
</EuiTitle>
<EuiHorizontalRule margin="m" />
<EuiDescriptionList type="column">
<EuiDescriptionListTitle>Processed Events</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.apmPanel.processedEventsLabel"
defaultMessage="Processed Events"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="apmsTotalEvents">
{formatMetric(props.totalEvents, '0.[0]a')}
</EuiDescriptionListDescription>
<EuiDescriptionListTitle>Last Event</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.apmPanel.lastEventLabel"
defaultMessage="Last Event"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="apmsBytesSent">
{formatTimestampToDuration(+moment(props.timeOfLastEvent), 'since') + ' ago'}
<FormattedMessage
id="xpack.monitoring.cluster.overview.apmPanel.lastEventDescription"
defaultMessage="{timeOfLastEvent} ago"
values={{ timeOfLastEvent: formatTimestampToDuration(+moment(props.timeOfLastEvent), CALCULATE_DURATION_SINCE) }}
/>
</EuiDescriptionListDescription>
</EuiDescriptionList>
</EuiPanel>
@ -66,16 +90,28 @@ export function ApmPanel(props) {
<h3>
<EuiLink
onClick={goToInstances}
aria-label={`Apm Instances: ${props.apms.total}`}
aria-label={props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.apmPanel.instancesTotalLinkAriaLabel',
defaultMessage: 'Apm Instances: {apmsTotal}' },
{ apmsTotal: props.apms.total })}
data-test-subj="apmListing"
>
APM Servers: <span data-test-subj="apmsTotal">{props.apms.total}</span>
<FormattedMessage
id="xpack.monitoring.cluster.overview.apmPanel.serversTotalLinkLabel"
defaultMessage="APM Servers: {apmsTotal}"
values={{ apmsTotal: (<span data-test-subj="apmsTotal">{props.apms.total}</span>) }}
/>
</EuiLink>
</h3>
</EuiTitle>
<EuiHorizontalRule margin="m" />
<EuiDescriptionList type="column">
<EuiDescriptionListTitle>Memory Usage</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.apmPanel.memoryUsageLabel"
defaultMessage="Memory Usage"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="apmMemoryUsage">
<BytesPercentageUsage usedBytes={props.memRss} maxBytes={props.memTotal} />
</EuiDescriptionListDescription>
@ -86,3 +122,5 @@ export function ApmPanel(props) {
</ClusterItemContainer>
);
}
export const ApmPanel = injectI18n(ApmPanelUi);

View file

@ -19,8 +19,9 @@ import {
EuiHorizontalRule,
} from '@elastic/eui';
import { ClusterItemContainer } from './helpers';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
export function BeatsPanel(props) {
function BeatsPanelUi(props) {
if (!get(props, 'beats.total', 0) > 0) {
return null;
}
@ -46,7 +47,11 @@ export function BeatsPanel(props) {
});
return (
<ClusterItemContainer {...props} url="beats" title="Beats">
<ClusterItemContainer
{...props}
url="beats"
title={props.intl.formatMessage({ id: 'xpack.monitoring.cluster.overview.beatsPanel.beatsTitle', defaultMessage: 'Beats' })}
>
<EuiFlexGrid columns={2}>
<EuiFlexItem>
<EuiPanel paddingSize="m">
@ -54,20 +59,34 @@ export function BeatsPanel(props) {
<h3>
<EuiLink
onClick={goToBeats}
aria-label="Beats Overview"
aria-label={props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.beatsPanel.overviewLinkAriaLabel', defaultMessage: 'Beats Overview' })}
data-test-subj="beatsOverview"
>
Overview
<FormattedMessage
id="xpack.monitoring.cluster.overview.beatsPanel.overviewLinkLabel"
defaultMessage="Overview"
/>
</EuiLink>
</h3>
</EuiTitle>
<EuiHorizontalRule margin="m" />
<EuiDescriptionList type="column">
<EuiDescriptionListTitle>Total Events</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.beatsPanel.totalEventsLabel"
defaultMessage="Total Events"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="beatsTotalEvents">
{formatMetric(props.totalEvents, '0.[0]a')}
</EuiDescriptionListDescription>
<EuiDescriptionListTitle>Bytes Sent</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.beatsPanel.bytesSentLabel"
defaultMessage="Bytes Sent"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="beatsBytesSent">
{formatMetric(props.bytesSent, 'byte')}
</EuiDescriptionListDescription>
@ -80,10 +99,17 @@ export function BeatsPanel(props) {
<h3>
<EuiLink
onClick={goToInstances}
aria-label={`Beats Instances: ${props.beats.total}`}
aria-label={props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.beatsPanel.instancesTotalLinkAriaLabel',
defaultMessage: 'Beats Instances: {beatsTotal}' },
{ beatsTotal: props.beats.total })}
data-test-subj="beatsListing"
>
Beats: <span data-test-subj="beatsTotal">{props.beats.total}</span>
<FormattedMessage
id="xpack.monitoring.cluster.overview.beatsPanel.beatsTotalLinkLabel"
defaultMessage="Beats: {beatsTotal}"
values={{ beatsTotal: (<span data-test-subj="beatsTotal">{props.beats.total}</span>) }}
/>
</EuiLink>
</h3>
</EuiTitle>
@ -97,3 +123,5 @@ export function BeatsPanel(props) {
</ClusterItemContainer>
);
}
export const BeatsPanel = injectI18n(BeatsPanelUi);

View file

@ -20,6 +20,7 @@ import {
EuiHorizontalRule,
} from '@elastic/eui';
import { LicenseText } from './license_text';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
const calculateShards = shards => {
const total = get(shards, 'total', 0);
@ -39,7 +40,7 @@ const calculateShards = shards => {
};
};
export function ElasticsearchPanel(props) {
function ElasticsearchPanelUi(props) {
const clusterStats = props.cluster_stats || {};
const nodes = clusterStats.nodes;
@ -59,7 +60,12 @@ export function ElasticsearchPanel(props) {
// if license doesn't support ML, then `ml === null`
if (props.ml) {
return [
<EuiDescriptionListTitle key="mlJobsListTitle">Jobs</EuiDescriptionListTitle>,
<EuiDescriptionListTitle key="mlJobsListTitle">
<FormattedMessage
id="xpack.monitoring.cluster.overview.esPanel.jobsLabel"
defaultMessage="Jobs"
/>
</EuiDescriptionListTitle>,
<EuiDescriptionListDescription key="mlJobsCount" data-test-subj="esMlJobs">{ props.ml.jobs }</EuiDescriptionListDescription>
];
}
@ -69,7 +75,13 @@ export function ElasticsearchPanel(props) {
const licenseText = <LicenseText license={props.license} showLicenseExpiration={props.showLicenseExpiration} />;
return (
<ClusterItemContainer {...props} statusIndicator={statusIndicator} url="elasticsearch" title="Elasticsearch" extras={licenseText}>
<ClusterItemContainer
{...props}
statusIndicator={statusIndicator}
url="elasticsearch"
title="Elasticsearch"
extras={licenseText}
>
<EuiFlexGrid columns={3}>
<EuiFlexItem>
@ -78,20 +90,35 @@ export function ElasticsearchPanel(props) {
<h3>
<EuiLink
onClick={goToElasticsearch}
aria-label="Elasticsearch Overview"
aria-label={props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.esPanel.overviewLinkAriaLabel', defaultMessage: 'Elasticsearch Overview' })}
data-test-subj="esOverview"
>
Overview
<FormattedMessage
id="xpack.monitoring.cluster.overview.esPanel.overviewLinkLabel"
defaultMessage="Overview"
/>
</EuiLink>
</h3>
</EuiTitle>
<EuiHorizontalRule margin="m" />
<EuiDescriptionList type="column">
<EuiDescriptionListTitle>Version</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.esPanel.versionLabel"
defaultMessage="Version"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="esVersion">
{ props.version || 'N/A' }
{ props.version || props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.esPanel.versionNotAvailableDescription', defaultMessage: 'N/A' }) }
</EuiDescriptionListDescription>
<EuiDescriptionListTitle>Uptime</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.esPanel.uptimeLabel"
defaultMessage="Uptime"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="esUptime">
{ formatNumber(get(nodes, 'jvm.max_uptime_in_millis'), 'time_since') }
</EuiDescriptionListDescription>
@ -108,20 +135,35 @@ export function ElasticsearchPanel(props) {
data-test-subj="esNumberOfNodes"
onClick={goToNodes}
>
Nodes: { formatNumber(get(nodes, 'count.total'), 'int_commas') }
<FormattedMessage
id="xpack.monitoring.cluster.overview.esPanel.nodesTotalLinkLabel"
defaultMessage="Nodes: {nodesTotal}"
values={{ nodesTotal: formatNumber(get(nodes, 'count.total'), 'int_commas') }}
/>
</EuiLink>
</h3>
</EuiTitle>
<EuiHorizontalRule margin="m" />
<EuiDescriptionList type="column">
<EuiDescriptionListTitle>Disk Available</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.esPanel.diskAvailableLabel"
defaultMessage="Disk Available"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="esDiskAvailable">
<BytesUsage
usedBytes={get(nodes, 'fs.available_in_bytes')}
maxBytes={get(nodes, 'fs.total_in_bytes')}
/>
</EuiDescriptionListDescription>
<EuiDescriptionListTitle>JVM Heap</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.esPanel.jvmHeapLabel"
defaultMessage="{javaVirtualMachine} Heap"
values={{ javaVirtualMachine: 'JVM' }}
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="esJvmHeap">
<BytesPercentageUsage
usedBytes={get(nodes, 'jvm.mem.heap_used_in_bytes')}
@ -139,37 +181,56 @@ export function ElasticsearchPanel(props) {
<EuiLink
onClick={goToIndices}
data-test-subj="esNumberOfIndices"
aria-label={`Elasticsearch Indices: ${ formatNumber(get(indices, 'count'), 'int_commas') }`}
aria-label={props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.esPanel.indicesCountLinkAriaLabel',
defaultMessage: 'Elasticsearch Indices: {indicesCount}' },
{ indicesCount: formatNumber(get(indices, 'count'), 'int_commas') })}
>
Indices: { formatNumber(get(indices, 'count'), 'int_commas') }
<FormattedMessage
id="xpack.monitoring.cluster.overview.esPanel.indicesCountLinkLabel"
defaultMessage="Indices: {indicesCount}"
values={{ indicesCount: formatNumber(get(indices, 'count'), 'int_commas') }}
/>
</EuiLink>
</h3>
</EuiTitle>
<EuiHorizontalRule margin="m" />
<EuiDescriptionList type="column">
<EuiDescriptionListTitle>
Documents
<FormattedMessage
id="xpack.monitoring.cluster.overview.esPanel.documentsLabel"
defaultMessage="Documents"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="esDocumentsCount">
{ formatNumber(get(indices, 'docs.count'), 'int_commas') }
</EuiDescriptionListDescription>
<EuiDescriptionListTitle>
Disk Usage
<FormattedMessage
id="xpack.monitoring.cluster.overview.esPanel.diskUsageLabel"
defaultMessage="Disk Usage"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="esDiskUsage">
{ formatNumber(get(indices, 'store.size_in_bytes'), 'byte') }
</EuiDescriptionListDescription>
<EuiDescriptionListTitle>
Primary Shards
<FormattedMessage
id="xpack.monitoring.cluster.overview.esPanel.primaryShardsLabel"
defaultMessage="Primary Shards"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="esPrimaryShards">
{ primaries }
</EuiDescriptionListDescription>
<EuiDescriptionListTitle>
Replica Shards
<FormattedMessage
id="xpack.monitoring.cluster.overview.esPanel.replicaShardsLabel"
defaultMessage="Replica Shards"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="esReplicaShards">
{ replicas }
@ -182,3 +243,5 @@ export function ElasticsearchPanel(props) {
</ClusterItemContainer>
);
}
export const ElasticsearchPanel = injectI18n(ElasticsearchPanelUi);

View file

@ -16,6 +16,7 @@ import {
EuiHealth,
EuiText,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
export function HealthStatusIndicator(props) {
@ -29,7 +30,11 @@ export function HealthStatusIndicator(props) {
return (
<EuiHealth color={statusColor} data-test-subj="statusIcon">
Health is {props.status}
<FormattedMessage
id="xpack.monitoring.cluster.overview.healthStatusDescription"
defaultMessage="Health is {status}"
values={{ status: props.status }}
/>
</EuiHealth>
);
}

View file

@ -19,8 +19,9 @@ import {
EuiDescriptionListDescription,
EuiHorizontalRule,
} from '@elastic/eui';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
export function KibanaPanel(props) {
function KibanaPanelUi(props) {
if (!props.count) {
return null;
}
@ -33,7 +34,13 @@ export function KibanaPanel(props) {
const goToInstances = () => props.changeUrl('kibana/instances');
return (
<ClusterItemContainer {...props} statusIndicator={statusIndicator} url="kibana" title="Kibana">
<ClusterItemContainer
{...props}
statusIndicator={statusIndicator}
url="kibana"
title={props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.kibanaPanel.kibanaTitle', defaultMessage: 'Kibana' })}
>
<EuiFlexGrid columns={2}>
<EuiFlexItem>
<EuiPanel paddingSize="m">
@ -41,22 +48,40 @@ export function KibanaPanel(props) {
<h3>
<EuiLink
onClick={goToKibana}
aria-label="Kibana Overview"
aria-label={props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.kibanaPanel.overviewLinkAriaLabel', defaultMessage: 'Kibana Overview' })}
data-test-subj="kbnOverview"
>
Overview
<FormattedMessage
id="xpack.monitoring.cluster.overview.kibanaPanel.overviewLinkLabel"
defaultMessage="Overview"
/>
</EuiLink>
</h3>
</EuiTitle>
<EuiHorizontalRule margin="m" />
<EuiDescriptionList type="column" data-test-subj="kibana_overview" data-overview-status={props.status}>
<EuiDescriptionListTitle>Requests</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.kibanaPanel.requestsLabel"
defaultMessage="Requests"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="kbnRequests">
{ props.requests_total }
</EuiDescriptionListDescription>
<EuiDescriptionListTitle>Max. Response Time</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.kibanaPanel.maxResponseTimeLabel"
defaultMessage="Max. Response Time"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="kbnMaxResponseTime">
{ props.response_time_max } ms
<FormattedMessage
id="xpack.monitoring.cluster.overview.kibanaPanel.maxResponseTimeDescription"
defaultMessage="{maxTime} ms"
values={{ maxTime: props.response_time_max }}
/>
</EuiDescriptionListDescription>
</EuiDescriptionList>
</EuiPanel>
@ -68,19 +93,36 @@ export function KibanaPanel(props) {
<EuiLink
onClick={goToInstances}
data-test-subj="kbnInstances"
aria-label={`Kibana Instances: ${ props.count }`}
aria-label={props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.kibanaPanel.instancesCountLinkAriaLabel',
defaultMessage: 'Kibana Instances: {instancesCount}' },
{ instancesCount: props.count })}
>
Instances: <span data-test-subj="number_of_kibana_instances">{ props.count }</span>
<FormattedMessage
id="xpack.monitoring.cluster.overview.kibanaPanel.instancesCountLinkLabel"
defaultMessage="Instances: {instancesCount}"
values={{ instancesCount: (<span data-test-subj="number_of_kibana_instances">{ props.count }</span>) }}
/>
</EuiLink>
</h3>
</EuiTitle>
<EuiHorizontalRule margin="m" />
<EuiDescriptionList type="column">
<EuiDescriptionListTitle>Connections</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.kibanaPanel.connectionsLabel"
defaultMessage="Connections"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="kbnConnections">
{ formatNumber(props.concurrent_connections, 'int_commas') }
</EuiDescriptionListDescription>
<EuiDescriptionListTitle>Memory Usage</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.kibanaPanel.memoryUsageLabel"
defaultMessage="Memory Usage"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="kbnMemoryUsage">
<BytesPercentageUsage usedBytes={props.memory_size} maxBytes={props.memory_limit} />
</EuiDescriptionListDescription>
@ -91,3 +133,5 @@ export function KibanaPanel(props) {
</ClusterItemContainer>
);
}
export const KibanaPanel = injectI18n(KibanaPanelUi);

View file

@ -4,21 +4,14 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { Fragment } from 'react';
import React from 'react';
import moment from 'moment-timezone';
import { capitalize } from 'lodash';
import { EuiLink } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
const formatDateLocal = input => moment.tz(input, moment.tz.guess()).format('LL');
const WillExpireOn = ({ expiryDate }) => {
if (expiryDate === undefined) {
return null;
}
return <Fragment> will expire on {formatDateLocal(expiryDate)}</Fragment>;
};
export function LicenseText({ license, showLicenseExpiration }) {
if (!showLicenseExpiration) {
return null;
@ -26,7 +19,20 @@ export function LicenseText({ license, showLicenseExpiration }) {
return (
<EuiLink href="#/license">
{capitalize(license.type)} license <WillExpireOn expiryDate={license.expiry_date_in_millis} />
<FormattedMessage
id="xpack.monitoring.cluster.overview.licenseText.toLicensePageLinkLabel"
defaultMessage="{licenseType} license {willExpireOn}"
values={{
licenseType: capitalize(license.type),
willExpireOn: license.expiry_date_in_millis === undefined ? '' : (
<FormattedMessage
id="xpack.monitoring.cluster.overview.licenseText.expireDateText"
defaultMessage="will expire on {expiryDate}"
values={{ expiryDate: formatDateLocal(license.expiry_date_in_millis) }}
/>
)
}}
/>
</EuiLink>
);
}

View file

@ -21,8 +21,9 @@ import {
EuiDescriptionListDescription,
EuiHorizontalRule,
} from '@elastic/eui';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
export function LogstashPanel(props) {
function LogstashPanelUi(props) {
if (!props.node_count) {
return null;
}
@ -32,7 +33,12 @@ export function LogstashPanel(props) {
const goToPipelines = () => props.changeUrl('logstash/pipelines');
return (
<ClusterItemContainer {...props} url="logstash" title="Logstash">
<ClusterItemContainer
{...props}
url="logstash"
title={props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.logstashPanel.logstashTitle', defaultMessage: 'Logstash' })}
>
<EuiFlexGrid columns={3}>
<EuiFlexItem>
<EuiPanel paddingSize="m">
@ -40,19 +46,33 @@ export function LogstashPanel(props) {
<h3>
<EuiLink
onClick={goToLogstash}
aria-label="Logstash Overview"
aria-label={props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.logstashPanel.overviewLinkAriaLabel', defaultMessage: 'Logstash Overview' })}
>
Overview
<FormattedMessage
id="xpack.monitoring.cluster.overview.logstashPanel.overviewLinkLabel"
defaultMessage="Overview"
/>
</EuiLink>
</h3>
</EuiTitle>
<EuiHorizontalRule margin="m" />
<EuiDescriptionList type="column" data-test-subj="logstash_overview">
<EuiDescriptionListTitle>Events Received</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.logstashPanel.eventsReceivedLabel"
defaultMessage="Events Received"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="lsEventsReceived">
{ formatNumber(props.events_in_total, '0.[0]a') }
</EuiDescriptionListDescription>
<EuiDescriptionListTitle>Events Emitted</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.logstashPanel.eventsEmittedLabel"
defaultMessage="Events Emitted"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="lsEventsEmitted">
{ formatNumber(props.events_out_total, '0.[0]a') }
</EuiDescriptionListDescription>
@ -67,19 +87,38 @@ export function LogstashPanel(props) {
<EuiLink
onClick={goToNodes}
data-test-subj="lsNodes"
aria-label={`Logstash Nodes: ${ props.node_count}`}
aria-label={props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.logstashPanel.nodesCountLinkAriaLabel',
defaultMessage: 'Logstash Nodes: {nodesCount}' },
{ nodesCount: props.node_count }
)}
>
Nodes: <span data-test-subj="number_of_logstash_instances">{ props.node_count }</span>
<FormattedMessage
id="xpack.monitoring.cluster.overview.logstashPanel.nodesCountLinkLabel"
defaultMessage="Nodes: {nodesCount}"
values={{ nodesCount: (<span data-test-subj="number_of_logstash_instances">{ props.node_count }</span>) }}
/>
</EuiLink>
</h3>
</EuiTitle>
<EuiHorizontalRule margin="m" />
<EuiDescriptionList type="column">
<EuiDescriptionListTitle>Uptime</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.logstashPanel.uptimeLabel"
defaultMessage="Uptime"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="lsUptime">
{ formatNumber(props.max_uptime, 'time_since') }
</EuiDescriptionListDescription>
<EuiDescriptionListTitle>JVM Heap</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.logstashPanel.jvmHeapLabel"
defaultMessage="{javaVirtualMachine} Heap"
values={{ javaVirtualMachine: 'JVM' }}
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="lsJvmHeap">
<BytesPercentageUsage usedBytes={props.avg_memory_used} maxBytes={props.avg_memory} />
</EuiDescriptionListDescription>
@ -94,24 +133,44 @@ export function LogstashPanel(props) {
<EuiLink
onClick={goToPipelines}
data-test-subj="lsPipelines"
aria-label={`Logstash Pipelines (beta feature): ${ props.pipeline_count }`}
aria-label={props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.logstashPanel.pipelineCountLinkAriaLabel',
defaultMessage: 'Logstash Pipelines (beta feature): {pipelineCount}' },
{ pipelineCount: props.pipeline_count }
)}
>
<Tooltip
text="Beta Feature"
text={props.intl.formatMessage({
id: 'xpack.monitoring.cluster.overview.logstashPanel.betaFeatureTooltip',
defaultMessage: 'Beta Feature' })}
placement="bottom"
trigger="hover"
>
<span className="kuiIcon fa-flask betaIcon" />
</Tooltip>
Pipelines: <span data-test-subj="number_of_logstash_pipelines">{ props.pipeline_count }</span>
<FormattedMessage
id="xpack.monitoring.cluster.overview.logstashPanel.pipelinesCountLinkLabel"
defaultMessage="Pipelines: {pipelineCount}"
values={{ pipelineCount: (<span data-test-subj="number_of_logstash_pipelines">{ props.pipeline_count }</span>) }}
/>
</EuiLink>
</h3>
</EuiTitle>
<EuiHorizontalRule margin="m" />
<EuiDescriptionList type="column">
<EuiDescriptionListTitle>With Memory Queues</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.logstashPanel.withMemoryQueuesLabel"
defaultMessage="With Memory Queues"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription>{ props.queue_types[LOGSTASH.QUEUE_TYPES.MEMORY] }</EuiDescriptionListDescription>
<EuiDescriptionListTitle>With Persistent Queues</EuiDescriptionListTitle>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.monitoring.cluster.overview.logstashPanel.withPersistentQueuesLabel"
defaultMessage="With Persistent Queues"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription>{ props.queue_types[LOGSTASH.QUEUE_TYPES.PERSISTED] }</EuiDescriptionListDescription>
</EuiDescriptionList>
</EuiPanel>
@ -120,3 +179,5 @@ export function LogstashPanel(props) {
</ClusterItemContainer>
);
}
export const LogstashPanel = injectI18n(LogstashPanelUi);

View file

@ -17,25 +17,65 @@ import { FormattedAlert } from 'plugins/monitoring/components/alerts/formatted_a
import { mapSeverity } from 'plugins/monitoring/components/alerts/map_severity';
import { formatTimestampToDuration } from '../../../common/format_timestamp_to_duration';
import { formatDateTimeLocal } from '../../../common/formatting';
import { I18nProvider } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { injectI18n, I18nProvider, FormattedMessage } from '@kbn/i18n/react';
const linkToCategories = {
'elasticsearch/nodes': 'Elasticsearch Nodes',
'elasticsearch/indices': 'Elasticsearch Indices',
'kibana/instances': 'Kibana Instances',
'logstash/instances': 'Logstash Nodes',
'elasticsearch/nodes': i18n.translate('xpack.monitoring.alerts.esNodesCategoryLabel', {
defaultMessage: 'Elasticsearch Nodes',
}),
'elasticsearch/indices': i18n.translate('xpack.monitoring.alerts.esIndicesCategoryLabel', {
defaultMessage: 'Elasticsearch Indices',
}),
'kibana/instances': i18n.translate('xpack.monitoring.alerts.kibanaInstancesCategoryLabel', {
defaultMessage: 'Kibana Instances',
}),
'logstash/instances': i18n.translate('xpack.monitoring.alerts.logstashNodesCategoryLabel', {
defaultMessage: 'Logstash Nodes',
}),
};
const filterFields = [ 'message', 'severity_group', 'prefix', 'suffix', 'metadata.link', 'since', 'timestamp', 'update_timestamp' ];
const columns = [
{ title: 'Status', sortKey: 'metadata.severity', sortOrder: SORT_DESCENDING },
{ title: 'Resolved', sortKey: 'resolved_timestamp' },
{ title: 'Message', sortKey: 'message' },
{ title: 'Category', sortKey: 'metadata.link' },
{ title: 'Last Checked', sortKey: 'update_timestamp' },
{ title: 'Triggered', sortKey: 'timestamp' },
{
title: i18n.translate('xpack.monitoring.alerts.statusColumnTitle', {
defaultMessage: 'Status',
}),
sortKey: 'metadata.severity',
sortOrder: SORT_DESCENDING
},
{
title: i18n.translate('xpack.monitoring.alerts.resolvedColumnTitle', {
defaultMessage: 'Resolved',
}),
sortKey: 'resolved_timestamp'
},
{
title: i18n.translate('xpack.monitoring.alerts.messageColumnTitle', {
defaultMessage: 'Message',
}),
sortKey: 'message'
},
{
title: i18n.translate('xpack.monitoring.alerts.categoryColumnTitle', {
defaultMessage: 'Category',
}),
sortKey: 'metadata.link'
},
{
title: i18n.translate('xpack.monitoring.alerts.lastCheckedColumnTitle', {
defaultMessage: 'Last Checked',
}),
sortKey: 'update_timestamp'
},
{
title: i18n.translate('xpack.monitoring.alerts.triggeredColumnTitle', {
defaultMessage: 'Triggered',
}),
sortKey: 'timestamp'
},
];
const alertRowFactory = (scope, kbnUrl) => {
return props => {
return injectI18n(props => {
const changeUrl = target => {
scope.$evalAsync(() => {
kbnUrl.changePath(target);
@ -44,13 +84,24 @@ const alertRowFactory = (scope, kbnUrl) => {
const severityIcon = mapSeverity(props.metadata.severity);
const resolution = {
icon: null,
text: 'Not Resolved'
text: props.intl.formatMessage({ id: 'xpack.monitoring.alerts.notResolvedDescription',
defaultMessage: 'Not Resolved',
})
};
if (props.resolved_timestamp) {
resolution.text = `${formatTimestampToDuration(props.resolved_timestamp, CALCULATE_DURATION_SINCE)} ago`;
resolution.text = props.intl.formatMessage({ id: 'xpack.monitoring.alerts.resolvedAgoDescription',
defaultMessage: '{duration} ago',
}, { duration: formatTimestampToDuration(props.resolved_timestamp, CALCULATE_DURATION_SINCE) }
);
} else {
resolution.icon = <EuiIcon type="alert" size="m" aria-label="Not Resolved" />;
resolution.icon = (
<EuiIcon
type="alert"
size="m"
aria-label={props.intl.formatMessage({ id: 'xpack.monitoring.alerts.notResolvedAriaLabel', defaultMessage: 'Not Resolved', })}
/>
);
}
return (
@ -75,25 +126,31 @@ const alertRowFactory = (scope, kbnUrl) => {
/>
</KuiTableRowCell>
<KuiTableRowCell tabIndex="0">
{ linkToCategories[props.metadata.link] ? linkToCategories[props.metadata.link] : 'General' }
{ linkToCategories[props.metadata.link] ? linkToCategories[props.metadata.link] :
props.intl.formatMessage({ id: 'xpack.monitoring.alerts.generalCategoryLabel', defaultMessage: 'General', }) }
</KuiTableRowCell>
<KuiTableRowCell tabIndex="0">
{ formatDateTimeLocal(props.update_timestamp) }
</KuiTableRowCell>
<KuiTableRowCell tabIndex="0">
{ formatTimestampToDuration(props.timestamp, CALCULATE_DURATION_SINCE) } ago
<FormattedMessage
id="xpack.monitoring.alerts.triggeredAgoDescription"
defaultMessage="{duration} ago"
values={{ duration: formatTimestampToDuration(props.timestamp, CALCULATE_DURATION_SINCE) }}
/>
</KuiTableRowCell>
</KuiTableRow>
);
};
});
};
const uiModule = uiModules.get('monitoring/directives', []);
uiModule.directive('monitoringClusterAlertsListing', kbnUrl => {
uiModule.directive('monitoringClusterAlertsListing', (kbnUrl, i18n) => {
return {
restrict: 'E',
scope: { alerts: '=' },
link(scope, $el) {
const filterAlertsPlaceholder = i18n('xpack.monitoring.alerts.filterAlertsPlaceholder', { defaultMessage: 'Filter Alerts…' });
scope.$watch('alerts', (alerts = []) => {
const alertsTable = (
@ -101,7 +158,7 @@ uiModule.directive('monitoringClusterAlertsListing', kbnUrl => {
<MonitoringTable
className="alertsTable"
rows={alerts}
placeholder="Filter Alerts..."
placeholder={filterAlertsPlaceholder}
filterFields={filterFields}
columns={columns}
rowComponent={alertRowFactory(scope, kbnUrl)}

View file

@ -24,18 +24,59 @@ import { MonitoringTable } from 'plugins/monitoring/components/table';
import { Tooltip } from 'plugins/monitoring/components/tooltip';
import { AlertsIndicator } from 'plugins/monitoring/components/cluster/listing/alerts_indicator';
import { SORT_ASCENDING } from '../../../../common/constants';
import { I18nProvider } from '@kbn/i18n/react';
import { I18nProvider, FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
const filterFields = [ 'cluster_name', 'status', 'license.type' ];
const columns = [
{ title: 'Name', sortKey: 'cluster_name', sortOrder: SORT_ASCENDING },
{ title: 'Status', sortKey: 'status' },
{ title: 'Nodes', sortKey: 'elasticsearch.cluster_stats.nodes.count.total' },
{ title: 'Indices', sortKey: 'elasticsearch.cluster_stats.indices.count' },
{ title: 'Data', sortKey: 'elasticsearch.cluster_stats.indices.store.size_in_bytes' },
{ title: 'Logstash', sortKey: 'logstash.node_count' },
{ title: 'Kibana', sortKey: 'kibana.count' },
{ title: 'License', sortKey: 'license.type' }
{
title: i18n.translate('xpack.monitoring.cluster.listing.nameColumnTitle', {
defaultMessage: 'Name',
}),
sortKey: 'cluster_name', sortOrder: SORT_ASCENDING
},
{
title: i18n.translate('xpack.monitoring.cluster.listing.statusColumnTitle', {
defaultMessage: 'Status',
}),
sortKey: 'status'
},
{
title: i18n.translate('xpack.monitoring.cluster.listing.nodesColumnTitle', {
defaultMessage: 'Nodes',
}),
sortKey: 'elasticsearch.cluster_stats.nodes.count.total'
},
{
title: i18n.translate('xpack.monitoring.cluster.listing.indicesColumnTitle', {
defaultMessage: 'Indices',
}),
sortKey: 'elasticsearch.cluster_stats.indices.count'
},
{
title: i18n.translate('xpack.monitoring.cluster.listing.dataColumnTitle', {
defaultMessage: 'Data',
}),
sortKey: 'elasticsearch.cluster_stats.indices.store.size_in_bytes'
},
{
title: i18n.translate('xpack.monitoring.cluster.listing.logstashColumnTitle', {
defaultMessage: 'Logstash',
}),
sortKey: 'logstash.node_count'
},
{
title: i18n.translate('xpack.monitoring.cluster.listing.kibanaColumnTitle', {
defaultMessage: 'Kibana',
}),
sortKey: 'kibana.count'
},
{
title: i18n.translate('xpack.monitoring.cluster.listing.licenseColumnTitle', {
defaultMessage: 'License',
}),
sortKey: 'license.type'
}
];
const clusterRowFactory = (scope, globalState, kbnUrl, showLicenseExpiration) => {
@ -61,14 +102,36 @@ const clusterRowFactory = (scope, globalState, kbnUrl, showLicenseExpiration) =>
handleClickIncompatibleLicense() {
this.licenseWarning({
title: `You can't view the "${this.props.cluster_name}" cluster`,
title: (
<FormattedMessage
id="xpack.monitoring.cluster.listing.incompatibleLicense.warningMessageTitle"
defaultMessage="You can't view the {clusterName} cluster"
values={{ clusterName: '"' + this.props.cluster_name + '"' }}
/>
),
text: (
<Fragment>
<p>The Basic license does not support multi-cluster monitoring.</p>
<p>
Need to monitor multiple clusters?{' '}
<a href="https://www.elastic.co/subscriptions/xpack" target="_blank">Get a license with full functionality</a>{' '}
to enjoy multi-cluster monitoring.
<FormattedMessage
id="xpack.monitoring.cluster.listing.incompatibleLicense.noMultiClusterSupportMessage"
defaultMessage="The Basic license does not support multi-cluster monitoring."
/>
</p>
<p>
<FormattedMessage
id="xpack.monitoring.cluster.listing.incompatibleLicense.infoMessage"
defaultMessage="Need to monitor multiple clusters? {getLicenseInfoLink} to enjoy multi-cluster monitoring."
values={{
getLicenseInfoLink: (
<a href="https://www.elastic.co/subscriptions/xpack" target="_blank">
<FormattedMessage
id="xpack.monitoring.cluster.listing.incompatibleLicense.getLicenseLinkLabel"
defaultMessage="Get a license with full functionality"
/>
</a>
)
}}
/>
</p>
</Fragment>
),
@ -79,15 +142,44 @@ const clusterRowFactory = (scope, globalState, kbnUrl, showLicenseExpiration) =>
const licensingPath = `${chrome.getBasePath()}/app/kibana#/management/elasticsearch/license_management/home`;
this.licenseWarning({
title: `You can't view the "${this.props.cluster_name}" cluster`,
title: (
<FormattedMessage
id="xpack.monitoring.cluster.listing.invalidLicense.warningMessageTitle"
defaultMessage="You can't view the {clusterName} cluster"
values={{ clusterName: '"' + this.props.cluster_name + '"' }}
/>
),
text: (
<Fragment>
<p>The license information is invalid.</p>
<p>
Need a license?{' '}
<a href={licensingPath}>Get a free Basic license</a> or{' '}
<a href="https://www.elastic.co/subscriptions/xpack" target="_blank">get a license with full functionality</a>{' '}
to enjoy multi-cluster monitoring.
<FormattedMessage
id="xpack.monitoring.cluster.listing.invalidLicense.invalidInfoMessage"
defaultMessage="The license information is invalid."
/>
</p>
<p>
<FormattedMessage
id="xpack.monitoring.cluster.listing.invalidLicense.infoMessage"
defaultMessage="Need a license? {getBasicLicenseLink} or {getLicenseInfoLink} to enjoy multi-cluster monitoring."
values={{
getBasicLicenseLink: (
<a href={licensingPath}>
<FormattedMessage
id="xpack.monitoring.cluster.listing.invalidLicense.getBasicLicenseLinkLabel"
defaultMessage="Get a free Basic license"
/>
</a>
),
getLicenseInfoLink: (
<a href="https://www.elastic.co/subscriptions/xpack" target="_blank">
<FormattedMessage
id="xpack.monitoring.cluster.listing.invalidLicense.getLicenseLinkLabel"
defaultMessage="get a license with full functionality"
/>
</a>
)
}}
/>
</p>
</Fragment>
),
@ -136,7 +228,10 @@ const clusterRowFactory = (scope, globalState, kbnUrl, showLicenseExpiration) =>
// license is expired
return (
<span className="monTableCell__clusterCellExpired">
Expired
<FormattedMessage
id="xpack.monitoring.cluster.listing.licenseInfo.expiredLabel"
defaultMessage="Expired"
/>
</span>
);
}
@ -144,7 +239,11 @@ const clusterRowFactory = (scope, globalState, kbnUrl, showLicenseExpiration) =>
// license is fine
return (
<span>
Expires { moment(this.props.license.expiry_date_in_millis).format('D MMM YY') }
<FormattedMessage
id="xpack.monitoring.cluster.listing.licenseInfo.expiresLabel"
defaultMessage="Expires {date}"
values={{ date: moment(this.props.license.expiry_date_in_millis).format('D MMM YY') }}
/>
</span>
);
};
@ -167,7 +266,10 @@ const clusterRowFactory = (scope, globalState, kbnUrl, showLicenseExpiration) =>
onClick={this.handleClickInvalidLicense.bind(this)}
>
<EuiHealth color="subdued" data-test-subj="alertIcon">
N/A
<FormattedMessage
id="xpack.monitoring.cluster.listing.licenseInfo.notAvailableDescription"
defaultMessage="N/A"
/>
</EuiHealth>
</EuiLink>
);
@ -212,7 +314,10 @@ const clusterRowFactory = (scope, globalState, kbnUrl, showLicenseExpiration) =>
trigger="hover"
>
<EuiHealth color="subdued" data-test-subj="alertIcon">
N/A
<FormattedMessage
id="xpack.monitoring.cluster.listing.alerts.notAvailableLabel"
defaultMessage="N/A"
/>
</EuiHealth>
</Tooltip>
);
@ -268,7 +373,7 @@ const clusterRowFactory = (scope, globalState, kbnUrl, showLicenseExpiration) =>
};
const uiModule = uiModules.get('monitoring/directives', []);
uiModule.directive('monitoringClusterListing', ($injector) => {
uiModule.directive('monitoringClusterListing', ($injector, i18n) => {
return {
restrict: 'E',
scope: {
@ -283,6 +388,9 @@ uiModule.directive('monitoringClusterListing', ($injector) => {
const globalState = $injector.get('globalState');
const kbnUrl = $injector.get('kbnUrl');
const showLicenseExpiration = $injector.get('showLicenseExpiration');
const filterClustersPlaceholder = i18n('xpack.monitoring.cluster.listing.filterClustersPlaceholder',
{ defaultMessage: 'Filter Clusters…' }
);
scope.$watch('clusters', (clusters = []) => {
const clusterTable = (
@ -295,7 +403,7 @@ uiModule.directive('monitoringClusterListing', ($injector) => {
sortKey={scope.sortKey}
sortOrder={scope.sortOrder}
onNewState={scope.onNewState}
placeholder="Filter Clusters..."
placeholder={filterClustersPlaceholder}
filterFields={filterFields}
columns={columns}
rowComponent={clusterRowFactory(scope, globalState, kbnUrl, showLicenseExpiration)}

View file

@ -8,6 +8,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { Overview } from 'plugins/monitoring/components/cluster/overview';
import { uiModules } from 'ui/modules';
import { I18nProvider } from '@kbn/i18n/react';
const uiModule = uiModules.get('monitoring/directives', []);
uiModule.directive('monitoringClusterOverview', (kbnUrl, showLicenseExpiration) => {
@ -24,11 +25,13 @@ uiModule.directive('monitoringClusterOverview', (kbnUrl, showLicenseExpiration)
scope.$watch('cluster', cluster => {
ReactDOM.render((
<Overview
cluster={cluster}
changeUrl={changeUrl}
showLicenseExpiration={showLicenseExpiration}
/>
<I18nProvider>
<Overview
cluster={cluster}
changeUrl={changeUrl}
showLicenseExpiration={showLicenseExpiration}
/>
</I18nProvider>
), $el[0]);
});

View file

@ -6,13 +6,23 @@
</div>
<div class="page-row">
<h3 class="kuiScreenReaderOnly">Alerts</h3>
<h3
class="kuiScreenReaderOnly"
i18n-id="xpack.monitoring.alerts.alertsTitle"
i18n-default-message="Alerts"
>
</h3>
<monitoring-cluster-alerts-listing alerts="alerts.data"></monitoring-cluster-alerts-listing>
</div>
<div class="page-row">
<p>
<a kbn-href="#/overview">« Cluster Overview</a>
<a
kbn-href="#/overview"
i18n-id="xpack.monitoring.alerts.clusterOverviewLinkLabel"
i18n-default-message="« Cluster Overview"
>
</a>
</p>
</div>
</monitoring-main>

View file

@ -45,7 +45,7 @@ uiRoutes.when('/alerts', {
},
controllerAs: 'alerts',
controller: class AlertsView extends MonitoringViewBaseController {
constructor($injector, $scope) {
constructor($injector, $scope, i18n) {
const $route = $injector.get('$route');
const globalState = $injector.get('globalState');
@ -53,7 +53,7 @@ uiRoutes.when('/alerts', {
$scope.cluster = find($route.current.locals.clusters, { cluster_uuid: globalState.cluster_uuid });
super({
title: 'Cluster Alerts',
title: i18n('xpack.monitoring.alerts.clusterAlertsTitle', { defaultMessage: 'Cluster Alerts' }),
getPageData,
$scope,
$injector

View file

@ -1,6 +1,11 @@
<monitoring-main name="listing">
<div class="page-row">
<h3 class="kuiScreenReaderOnly">Clusters</h3>
<h3
class="kuiScreenReaderOnly"
i18n-id="xpack.monitoring.cluster.listing.clustersTitle"
i18n-default-message="Clusters"
>
</h3>
<monitoring-cluster-listing
page-index="clusters.pageIndex"
filter-text="clusters.filterText"

View file

@ -21,7 +21,7 @@ uiRoutes.when('/overview', {
return monitoringClusters(globalState.cluster_uuid, globalState.ccs);
}
},
controller($injector, $scope) {
controller($injector, $scope, i18n) {
timefilter.enableTimeRangeSelector();
timefilter.enableAutoRefreshSelector();
@ -29,7 +29,7 @@ uiRoutes.when('/overview', {
$scope.cluster = $route.current.locals.cluster;
const title = $injector.get('title');
title($scope.cluster, 'Overview');
title($scope.cluster, i18n('xpack.monitoring.cluster.overviewTitle', { defaultMessage: 'Overview' }));
const $executor = $injector.get('$executor');
const monitoringClusters = $injector.get('monitoringClusters');