diff --git a/x-pack/plugins/monitoring/common/constants.js b/x-pack/plugins/monitoring/common/constants.js index 852afe74c461e1..c391f243eaff68 100644 --- a/x-pack/plugins/monitoring/common/constants.js +++ b/x-pack/plugins/monitoring/common/constants.js @@ -51,6 +51,8 @@ export const NORMALIZED_DERIVATIVE_UNIT = '1s'; * Values for column sorting in table options * @type {number} 1 or -1 */ +export const EUI_SORT_ASCENDING = 'asc'; +export const EUI_SORT_DESCENDING = 'desc'; export const SORT_ASCENDING = 1; export const SORT_DESCENDING = -1; diff --git a/x-pack/plugins/monitoring/public/components/alerts/alerts.js b/x-pack/plugins/monitoring/public/components/alerts/alerts.js new file mode 100644 index 00000000000000..7b06dbda9a56f7 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/alerts/alerts.js @@ -0,0 +1,133 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { capitalize } from 'lodash'; +import { formatDateTimeLocal } from '../../../common/formatting'; +import { formatTimestampToDuration } from '../../../common'; +import { CALCULATE_DURATION_SINCE, EUI_SORT_DESCENDING } from '../../../common/constants'; +import { mapSeverity } from './map_severity'; +import { Tooltip } from 'plugins/monitoring/components/tooltip'; +import { FormattedAlert } from 'plugins/monitoring/components/alerts/formatted_alert'; +import { EuiMonitoringTable } from 'plugins/monitoring/components/table'; +import { EuiHealth, EuiIcon } from '@elastic/eui'; +import { injectI18n } from '@kbn/i18n/react'; + +const linkToCategories = { + 'elasticsearch/nodes': 'Elasticsearch Nodes', + 'elasticsearch/indices': 'Elasticsearch Indices', + 'kibana/instances': 'Kibana Instances', + 'logstash/instances': 'Logstash Nodes', +}; +const getColumns = (kbnUrl, scope) => ([ + { + name: 'Status', + field: 'metadata.severity', + sortable: true, + render: severity => { + const severityIcon = mapSeverity(severity); + + return ( + + + { capitalize(severityIcon.value) } + + + ); + } + }, + { + name: 'Resolved', + field: 'resolved_timestamp', + sortable: true, + render: (resolvedTimestamp) => { + const resolution = { + icon: null, + text: 'Not Resolved' + }; + + if (resolvedTimestamp) { + resolution.text = `${formatTimestampToDuration(resolvedTimestamp, CALCULATE_DURATION_SINCE)} ago`; + } else { + resolution.icon = ; + } + + return ( + + { resolution.icon } { resolution.text } + + ); + }, + }, + { + name: 'Message', + field: 'message', + sortable: true, + render: (message, alert) => ( + { + scope.$evalAsync(() => { + kbnUrl.changePath(target); + }); + }} + /> + ) + }, + { + name: 'Category', + field: 'metadata.link', + sortable: true, + render: link => linkToCategories[link] ? linkToCategories[link] : 'General' + }, + { + name: 'Last Checked', + field: 'update_timestamp', + sortable: true, + render: timestamp => formatDateTimeLocal(timestamp) + }, + { + name: 'Triggered', + field: 'timestamp', + sortable: true, + render: timestamp => formatTimestampToDuration(timestamp, CALCULATE_DURATION_SINCE) + ' ago' + }, +]); + +const AlertsUI = ({ alerts, angular, sorting, pagination, onTableChange, intl }) => { + return ( + + ); +}; + +export const Alerts = injectI18n(AlertsUI); diff --git a/x-pack/plugins/monitoring/public/components/alerts/index.js b/x-pack/plugins/monitoring/public/components/alerts/index.js new file mode 100644 index 00000000000000..c4eda37c2b2520 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/alerts/index.js @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { Alerts } from './alerts'; diff --git a/x-pack/plugins/monitoring/public/components/apm/instance/instance.js b/x-pack/plugins/monitoring/public/components/apm/instance/instance.js index c40d19d384a0d1..0e44490ba22814 100644 --- a/x-pack/plugins/monitoring/public/components/apm/instance/instance.js +++ b/x-pack/plugins/monitoring/public/components/apm/instance/instance.js @@ -12,7 +12,8 @@ import { EuiSpacer, EuiPage, EuiPageBody, - EuiFlexGroup + EuiFlexGroup, + EuiPageContent } from '@elastic/eui'; import { Status } from './status'; @@ -46,13 +47,15 @@ export function ApmServerInstance({ summary, metrics, ...props }) { )); return ( - + - - - - {charts} - + + + + + {charts} + + ); diff --git a/x-pack/plugins/monitoring/public/components/apm/instance/status.js b/x-pack/plugins/monitoring/public/components/apm/instance/status.js index 386ddeaa5bc10f..c53339b917c186 100644 --- a/x-pack/plugins/monitoring/public/components/apm/instance/status.js +++ b/x-pack/plugins/monitoring/public/components/apm/instance/status.js @@ -29,7 +29,7 @@ function StatusUI({ stats, intl }) { defaultMessage: 'Name', }), value: name, - dataTestSubj: 'name' + 'data-test-subj': 'name' }, { label: intl.formatMessage({ @@ -37,7 +37,7 @@ function StatusUI({ stats, intl }) { defaultMessage: 'Output', }), value: output, - dataTestSubj: 'output' + 'data-test-subj': 'output' }, { label: intl.formatMessage({ @@ -45,7 +45,7 @@ function StatusUI({ stats, intl }) { defaultMessage: 'Version', }), value: version, - dataTestSubj: 'version' + 'data-test-subj': 'version' }, { label: intl.formatMessage({ @@ -53,7 +53,7 @@ function StatusUI({ stats, intl }) { defaultMessage: 'Uptime', }), value: formatMetric(uptime, 'time_since'), - dataTestSubj: 'uptime' + 'data-test-subj': 'uptime' }, { label: intl.formatMessage({ @@ -65,7 +65,7 @@ function StatusUI({ stats, intl }) { defaultMessage: '{timeOfLastEvent} ago' }, { timeOfLastEvent: formatTimestampToDuration(+moment(timeOfLastEvent), CALCULATE_DURATION_SINCE) }), - dataTestSubj: 'timeOfLastEvent', + 'data-test-subj': 'timeOfLastEvent', } ]; diff --git a/x-pack/plugins/monitoring/public/components/apm/instances/instances.js b/x-pack/plugins/monitoring/public/components/apm/instances/instances.js index 14c2fcb762e111..59ea744622e82b 100644 --- a/x-pack/plugins/monitoring/public/components/apm/instances/instances.js +++ b/x-pack/plugins/monitoring/public/components/apm/instances/instances.js @@ -6,150 +6,126 @@ import React from 'react'; import moment from 'moment'; -import { MonitoringTable } from '../../table'; -import { - KuiTableRowCell, - KuiTableRow -} from '@kbn/ui-framework/components'; -import { EuiLink } from '@elastic/eui'; +import { uniq } from 'lodash'; +import { EuiMonitoringTable } from '../../table'; +import { EuiLink, EuiPage, EuiPageBody, EuiPageContent, EuiSpacer } from '@elastic/eui'; import { Status } from './status'; -import { SORT_ASCENDING, SORT_DESCENDING, TABLE_ACTION_UPDATE_FILTER } from '../../../../common/constants'; import { formatMetric } from '../../../lib/format_number'; import { formatTimestampToDuration } from '../../../../common'; import { i18n } from '@kbn/i18n'; import { injectI18n } from '@kbn/i18n/react'; - -const filterFields = [ 'name', 'type', 'version', 'output' ]; const columns = [ { - title: i18n.translate('xpack.monitoring.apm.instances.nameTitle', { + name: i18n.translate('xpack.monitoring.apm.instances.nameTitle', { defaultMessage: 'Name' }), - sortKey: 'name', - sortOrder: SORT_ASCENDING + field: 'name', + render: (name, instance) => ( + + {name} + + ) }, { - title: i18n.translate('xpack.monitoring.apm.instances.outputEnabledTitle', { + name: i18n.translate('xpack.monitoring.apm.instances.outputEnabledTitle', { defaultMessage: 'Output Enabled' }), - sortKey: 'output' + field: 'output' }, { - title: i18n.translate('xpack.monitoring.apm.instances.totalEventsRateTitle', { + name: i18n.translate('xpack.monitoring.apm.instances.totalEventsRateTitle', { defaultMessage: 'Total Events Rate' }), - sortKey: 'total_events_rate', - secondarySortOrder: SORT_DESCENDING + field: 'total_events_rate', + render: value => formatMetric(value, '', '/s') }, { - title: i18n.translate('xpack.monitoring.apm.instances.bytesSentRateTitle', { + name: i18n.translate('xpack.monitoring.apm.instances.bytesSentRateTitle', { defaultMessage: 'Bytes Sent Rate' }), - sortKey: 'bytes_sent_rate' + field: 'bytes_sent_rate', + render: value => formatMetric(value, 'byte', '/s') }, { - title: i18n.translate('xpack.monitoring.apm.instances.outputErrorsTitle', { + name: i18n.translate('xpack.monitoring.apm.instances.outputErrorsTitle', { defaultMessage: 'Output Errors' }), - sortKey: 'errors' + field: 'errors', + render: value => formatMetric(value, '0') }, { - title: i18n.translate('xpack.monitoring.apm.instances.lastEventTitle', { + name: i18n.translate('xpack.monitoring.apm.instances.lastEventTitle', { defaultMessage: 'Last Event' }), - sortKey: 'time_of_last_event' + field: 'time_of_last_event', + render: value => formatTimestampToDuration(+moment(value), 'since') + ' ago' }, { - title: i18n.translate('xpack.monitoring.apm.instances.allocatedMemoryTitle', { + name: i18n.translate('xpack.monitoring.apm.instances.allocatedMemoryTitle', { defaultMessage: 'Allocated Memory' }), - sortKey: 'memory' + field: 'memory', + render: value => formatMetric(value, 'byte') }, { - title: i18n.translate('xpack.monitoring.apm.instances.versionTitle', { + name: i18n.translate('xpack.monitoring.apm.instances.versionTitle', { defaultMessage: 'Version' }), - sortKey: 'version' + field: 'version' }, ]; -const instanceRowFactory = () => { - return function KibanaRow(props) { - const applyFiltering = filterText => () => { - props.dispatchTableAction(TABLE_ACTION_UPDATE_FILTER, filterText); - }; - - return ( - - -
- - {props.name} - -
-
- - {props.output} - - - {formatMetric(props.total_events_rate, '', '/s')} - - - {formatMetric(props.bytes_sent_rate, 'byte', '/s')} - - - {formatMetric(props.errors, '0')} - - - {formatTimestampToDuration(+moment(props.time_of_last_event), 'since') + ' ago'} - - - {formatMetric(props.memory, 'byte')} - - - - {props.version} - - -
- ); - }; -}; -function ApmServerInstancesUI({ apms, intl }) { +export function ApmServerInstancesUI({ apms, intl }) { const { - pageIndex, - filterText, - sortKey, - sortOrder, - onNewState, + pagination, + sorting, + onTableChange, + data } = apms; + const versions = uniq(data.apms.map(item => item.version)).map(version => { + return { value: version }; + }); + return ( -
- - -
+ + + + + + + + + ); } diff --git a/x-pack/plugins/monitoring/public/components/apm/instances/status.js b/x-pack/plugins/monitoring/public/components/apm/instances/status.js index fd32ce26bb294b..e7cc42e8971f51 100644 --- a/x-pack/plugins/monitoring/public/components/apm/instances/status.js +++ b/x-pack/plugins/monitoring/public/components/apm/instances/status.js @@ -29,7 +29,7 @@ function StatusUI({ stats, intl }) { defaultMessage: 'Servers', }), value: total, - dataTestSubj: 'total' + 'data-test-subj': 'total' }, { label: intl.formatMessage({ @@ -37,7 +37,7 @@ function StatusUI({ stats, intl }) { defaultMessage: 'Total Events', }), value: formatMetric(totalEvents, '0.[0]a'), - dataTestSubj: 'totalEvents' + 'data-test-subj': 'totalEvents' }, { label: intl.formatMessage({ @@ -49,7 +49,7 @@ function StatusUI({ stats, intl }) { defaultMessage: '{timeOfLastEvent} ago' }, { timeOfLastEvent: formatTimestampToDuration(+moment(timeOfLastEvent), CALCULATE_DURATION_SINCE) }), - dataTestSubj: 'timeOfLastEvent', + 'data-test-subj': 'timeOfLastEvent', } ]; diff --git a/x-pack/plugins/monitoring/public/components/apm/overview/index.js b/x-pack/plugins/monitoring/public/components/apm/overview/index.js index 634a5e78127c0a..eb7236d5eea660 100644 --- a/x-pack/plugins/monitoring/public/components/apm/overview/index.js +++ b/x-pack/plugins/monitoring/public/components/apm/overview/index.js @@ -12,7 +12,8 @@ import { EuiFlexGroup, EuiFlexItem, EuiPageBody, - EuiPanel + EuiPanel, + EuiPageContent } from '@elastic/eui'; import { Status } from '../instances/status'; @@ -50,13 +51,15 @@ export function ApmOverview({ )); return ( - + - - - - {charts} - + + + + + {charts} + + ); diff --git a/x-pack/plugins/monitoring/public/components/beats/beat/beat.js b/x-pack/plugins/monitoring/public/components/beats/beat/beat.js index b3c7aaa290facd..bc281c1bb70322 100644 --- a/x-pack/plugins/monitoring/public/components/beats/beat/beat.js +++ b/x-pack/plugins/monitoring/public/components/beats/beat/beat.js @@ -7,8 +7,9 @@ import React from 'react'; import { MonitoringTimeseriesContainer } from '../../chart'; import { formatMetric } from '../../../lib/format_number'; -import { EuiFlexItem, EuiFlexGroup, EuiPage, EuiPageBody, EuiFlexGrid, EuiSpacer } from '@elastic/eui'; +import { EuiFlexItem, EuiPage, EuiPageBody, EuiFlexGrid, EuiSpacer, EuiPageContent } from '@elastic/eui'; import { injectI18n } from '@kbn/i18n/react'; +import { SummaryStatus } from '../../summary_status'; function BeatUi({ summary, metrics, intl, ...props }) { @@ -23,58 +24,41 @@ function BeatUi({ summary, metrics, intl, ...props }) { metrics.beat_handles, ]; - const wrapChild = ({ label, value, dataTestSubj }, index) => ( - - - - {label ? label + ': ' : null} - - - {value} - - - - ); - const summarytStatsTop = [ { label: intl.formatMessage({ id: 'xpack.monitoring.beats.instance.nameLabel', defaultMessage: 'Name' }), value: summary.name, - dataTestSubj: 'name' + 'data-test-subj': 'name' }, { label: intl.formatMessage({ id: 'xpack.monitoring.beats.instance.hostLabel', defaultMessage: 'Host' }), value: summary.transportAddress, - dataTestSubj: 'host' + 'data-test-subj': 'host' }, { label: intl.formatMessage({ id: 'xpack.monitoring.beats.instance.versionLabel', defaultMessage: 'Version' }), value: summary.version, - dataTestSubj: 'version' + 'data-test-subj': 'version' }, { label: intl.formatMessage({ id: 'xpack.monitoring.beats.instance.typeLabel', defaultMessage: 'Type' }), value: summary.type, - dataTestSubj: 'type' + 'data-test-subj': 'type' }, { label: intl.formatMessage({ id: 'xpack.monitoring.beats.instance.outputLabel', defaultMessage: 'Output' }), value: summary.output, - dataTestSubj: 'output' + 'data-test-subj': 'output' }, { label: intl.formatMessage({ id: 'xpack.monitoring.beats.instance.configReloadsLabel', defaultMessage: 'Config reloads' }), value: formatMetric(summary.configReloads, 'int_commas'), - dataTestSubj: 'configReloads' + 'data-test-subj': 'configReloads' }, { label: intl.formatMessage({ id: 'xpack.monitoring.beats.instance.uptimeLabel', defaultMessage: 'Uptime' }), value: formatMetric(summary.uptime, 'time_since'), - dataTestSubj: 'uptime' + 'data-test-subj': 'uptime' }, ]; @@ -82,63 +66,48 @@ function BeatUi({ summary, metrics, intl, ...props }) { { label: intl.formatMessage({ id: 'xpack.monitoring.beats.instance.eventsTotalLabel', defaultMessage: 'Events total' }), value: formatMetric(summary.eventsTotal, 'int_commas'), - dataTestSubj: 'eventsTotal' + 'data-test-subj': 'eventsTotal' }, { label: intl.formatMessage({ id: 'xpack.monitoring.beats.instance.eventsEmittedLabel', defaultMessage: 'Events emitted' }), value: formatMetric(summary.eventsEmitted, 'int_commas'), - dataTestSubj: 'eventsEmitted' + 'data-test-subj': 'eventsEmitted' }, { label: intl.formatMessage({ id: 'xpack.monitoring.beats.instance.eventsDroppedLabel', defaultMessage: 'Events dropped' }), value: formatMetric(summary.eventsDropped, 'int_commas'), - dataTestSubj: 'eventsDropped' + 'data-test-subj': 'eventsDropped' }, { label: intl.formatMessage({ id: 'xpack.monitoring.beats.instance.bytesSentLabel', defaultMessage: 'Bytes sent' }), value: formatMetric(summary.bytesWritten, 'byte'), - dataTestSubj: 'bytesWritten' + 'data-test-subj': 'bytesWritten' }, { label: intl.formatMessage({ id: 'xpack.monitoring.beats.instance.handlesLimitSoftLabel', defaultMessage: 'Handles limit (soft)' }), value: formatMetric(summary.handlesSoftLimit, 'byte'), - dataTestSubj: 'handlesLimitSoft' + 'data-test-subj': 'handlesLimitSoft' }, { label: intl.formatMessage({ id: 'xpack.monitoring.beats.instance.handlesLimitHardLabel', defaultMessage: 'Handles limit (hard)' }), value: formatMetric(summary.handlesHardLimit, 'byte'), - dataTestSubj: 'handlesLimitHard' + 'data-test-subj': 'handlesLimitHard' }, ]; return ( -
-
-
- - - - {summarytStatsTop.map(wrapChild)} - - - -
-
- -
-
- - - - {summarytStatsBot.map(wrapChild)} - - - -
-
- - - + + + + + + {metricsToShow.map((metric, index) => ( @@ -150,9 +119,9 @@ function BeatUi({ summary, metrics, intl, ...props }) { ))} - - -
+ + +
); } diff --git a/x-pack/plugins/monitoring/public/components/beats/listing/index.js b/x-pack/plugins/monitoring/public/components/beats/listing/index.js new file mode 100644 index 00000000000000..6c97a85719b4c1 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/beats/listing/index.js @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { Listing } from './listing'; diff --git a/x-pack/plugins/monitoring/public/components/beats/listing/listing.js b/x-pack/plugins/monitoring/public/components/beats/listing/listing.js new file mode 100644 index 00000000000000..45be036e5bb3b2 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/beats/listing/listing.js @@ -0,0 +1,133 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { PureComponent } from 'react'; +import { uniq } from 'lodash'; +import { EuiPage, EuiPageBody, EuiPageContent, EuiSpacer, EuiLink } from '@elastic/eui'; +import { Stats } from 'plugins/monitoring/components/beats'; +import { formatMetric } from 'plugins/monitoring/lib/format_number'; +import { EuiMonitoringTable } from 'plugins/monitoring/components/table'; +import { i18n } from '@kbn/i18n'; +import { injectI18n } from '@kbn/i18n/react'; + +class ListingUI extends PureComponent { + getColumns() { + const { kbnUrl, scope } = this.props.angular; + + return [ + { + name: i18n.translate('xpack.monitoring.beats.instances.nameTitle', { defaultMessage: 'Name' }), + field: 'name', + render: (name, beat) => ( + { + scope.$evalAsync(() => { + kbnUrl.changePath(`/beats/beat/${beat.uuid}`); + }); + }} + data-test-subj={`beatLink-${name}`} + > + {name} + + ) + }, + { + name: i18n.translate('xpack.monitoring.beats.instances.typeTitle', { defaultMessage: 'Type' }), + field: 'type', + }, + { + name: i18n.translate('xpack.monitoring.beats.instances.outputEnabledTitle', { defaultMessage: 'Output Enabled' }), + field: 'output' + }, + { + name: i18n.translate('xpack.monitoring.beats.instances.totalEventsRateTitle', { defaultMessage: 'Total Events Rate' }), + field: 'total_events_rate', + render: value => formatMetric(value, '', '/s') + }, + { + name: i18n.translate('xpack.monitoring.beats.instances.bytesSentRateTitle', { defaultMessage: 'Bytes Sent Rate' }), + field: 'bytes_sent_rate', + render: value => formatMetric(value, 'byte', '/s') + }, + { + name: i18n.translate('xpack.monitoring.beats.instances.outputErrorsTitle', { defaultMessage: 'Output Errors' }), + field: 'errors', + render: value => formatMetric(value, '0') + }, + { + name: i18n.translate('xpack.monitoring.beats.instances.allocatedMemoryTitle', { defaultMessage: 'Allocated Memory' }), + field: 'memory', + render: value => formatMetric(value, 'byte') + }, + { + name: i18n.translate('xpack.monitoring.beats.instances.versionTitle', { defaultMessage: 'Version' }), + field: 'version', + }, + ]; + } + + render() { + const { + stats, + data, + sorting, + pagination, + onTableChange + } = this.props; + + + const types = uniq(data.map(item => item.type)).map(type => { + return { value: type }; + }); + + const versions = uniq(data.map(item => item.version)).map(version => { + return { value: version }; + }); + + return ( + + + + + + + + + + ); + } +} + +export const Listing = injectI18n(ListingUI); diff --git a/x-pack/plugins/monitoring/public/components/beats/overview/__snapshots__/overview.test.js.snap b/x-pack/plugins/monitoring/public/components/beats/overview/__snapshots__/overview.test.js.snap index 8e3491a8689f15..f1202a53266ff9 100644 --- a/x-pack/plugins/monitoring/public/components/beats/overview/__snapshots__/overview.test.js.snap +++ b/x-pack/plugins/monitoring/public/components/beats/overview/__snapshots__/overview.test.js.snap @@ -3,260 +3,256 @@ exports[`Overview that overview page renders normally 1`] = ` - - + - - -

- -

-
- - -
-
- - +

+ +

+ + + +
+
+ - -

- -

-
- - - -
- - +

+ +

+ + + +
+
+ - -

- -

-
- - - -
-
- - - - - +

+ +

+ + + + +
+
+ + - - - - - - - - - - - + + + + - - - - + + + + - + + + + + - - - - + + + + + +
`; @@ -264,121 +260,117 @@ exports[`Overview that overview page renders normally 1`] = ` exports[`Overview that overview page shows a message if there is no beats data 1`] = ` - - - - - - + + + - - - - - - - - - - - + + + + - - - - + + + + - + + + + + - - - - + + + + + + `; diff --git a/x-pack/plugins/monitoring/public/components/beats/overview/overview.js b/x-pack/plugins/monitoring/public/components/beats/overview/overview.js index 2fa946e1def357..88b801f657570a 100644 --- a/x-pack/plugins/monitoring/public/components/beats/overview/overview.js +++ b/x-pack/plugins/monitoring/public/components/beats/overview/overview.js @@ -10,7 +10,6 @@ import { LatestVersions } from './latest_versions'; import { LatestTypes } from './latest_types'; import { Stats } from '../'; import { MonitoringTimeseriesContainer } from '../../chart'; -import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; import { EuiCallOut, EuiTitle, @@ -19,8 +18,10 @@ import { EuiFlexGroup, EuiFlexItem, EuiPageBody, - EuiPanel + EuiPanel, + EuiPageContent } from '@elastic/eui'; +import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; function renderLatestActive(latestActive, latestTypes, latestVersions, intl) { if (latestTypes && latestTypes.length > 0) { @@ -78,6 +79,7 @@ function renderLatestActive(latestActive, latestTypes, latestVersions, intl) { defaultMessage: `Hi there! This area is where your latest Beats activity would show up, but you don't seem to have any activity within the last day.` }); + return ( + - {renderLatestActive(latestActive, latestTypes, latestVersions, intl)} - - - - - {charts} - + + + {renderLatestActive(latestActive, latestTypes, latestVersions, intl)} + + + {charts} + + ); } -export const BeatsOverview = injectI18n(BeatsOverviewUi); +export const BeatsOverview = injectI18n(BeatsOverviewUI); diff --git a/x-pack/plugins/monitoring/public/components/beats/stats.js b/x-pack/plugins/monitoring/public/components/beats/stats.js index f5fceb04eccdaf..a509a90d01fdfc 100644 --- a/x-pack/plugins/monitoring/public/components/beats/stats.js +++ b/x-pack/plugins/monitoring/public/components/beats/stats.js @@ -4,80 +4,51 @@ * you may not use this file except in compliance with the Elastic License. */ -import { get } from 'lodash'; import React from 'react'; import { formatMetric } from 'plugins/monitoring/lib/format_number'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; +import { SummaryStatus } from '../summary_status'; export function Stats({ stats }) { - const types = stats.types.map(({ type, count }, index) => { - return ( - - - - {type ? type + ': ' : null} - - - {formatMetric(count, 'int_commas')} - - - - ); + const { + total, + types, + stats: { + bytesSent, + totalEvents, + } + } = stats; + + const metrics = [ + { + label: 'Total Beats', + value: formatMetric(total, 'int_commas'), + 'data-test-subj': 'totalBeats' + }, + ]; + + metrics.push(...types.map(({ type, count }) => ({ + label: type, + value: formatMetric(count, 'int_commas'), + 'data-test-subj': 'typeCount', + 'data-test-type-count': `${type}:${count}` + }))); + + metrics.push({ + label: 'Total Events', + value: formatMetric(totalEvents, '0.[0]a'), + 'data-test-subj': 'totalEvents' }); - return ( -
- - - - - :  - - - - {formatMetric(get(stats, 'total'), 'int_commas')} - - - - {types} - - - - :  - - - - - {formatMetric(get(stats, 'stats.totalEvents'), '0.[0]a')} - - - - - - :  - - - - {formatMetric(get(stats, 'stats.bytesSent'), 'byte')} - - - + metrics.push({ + label: 'Bytes Sent', + value: formatMetric(bytesSent, 'byte'), + 'data-test-subj': 'bytesSent' + }); -
+ return ( + ); } diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/status.js b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/status.js index 89da6c6d4fac3d..302aebf4667beb 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/status.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/status.js @@ -29,7 +29,7 @@ function StatusUI({ stat, formattedLeader, oldestStat, intl }) { defaultMessage: 'Follower Index', }), value: followerIndex, - dataTestSubj: 'followerIndex' + 'data-test-subj': 'followerIndex' }, { label: intl.formatMessage({ @@ -37,7 +37,7 @@ function StatusUI({ stat, formattedLeader, oldestStat, intl }) { defaultMessage: 'Shard Id', }), value: shardId, - dataTestSubj: 'shardId' + 'data-test-subj': 'shardId' }, { label: intl.formatMessage({ @@ -45,7 +45,7 @@ function StatusUI({ stat, formattedLeader, oldestStat, intl }) { defaultMessage: 'Leader Index', }), value: formattedLeader, - dataTestSubj: 'leaderIndex' + 'data-test-subj': 'leaderIndex' }, { label: intl.formatMessage({ @@ -53,7 +53,7 @@ function StatusUI({ stat, formattedLeader, oldestStat, intl }) { defaultMessage: 'Ops Synced', }), value: formatMetric(operationsReceived - oldestOperationsReceived, 'int_commas'), - dataTestSubj: 'operationsReceived' + 'data-test-subj': 'operationsReceived' }, { label: intl.formatMessage({ @@ -61,7 +61,7 @@ function StatusUI({ stat, formattedLeader, oldestStat, intl }) { defaultMessage: 'Failed Fetches', }), value: formatMetric(failedFetches - oldestFailedFetches, 'int_commas'), - dataTestSubj: 'failedFetches' + 'data-test-subj': 'failedFetches' }, ]; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/cluster_status/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/cluster_status/index.js index a7d007e4d22f1a..2426b47d1787e0 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/cluster_status/index.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/cluster_status/index.js @@ -30,7 +30,7 @@ function ClusterStatusUI({ stats, intl }) { defaultMessage: 'Nodes', }), value: nodesCount, - dataTestSubj: 'nodesCount' + 'data-test-subj': 'nodesCount' }, { label: intl.formatMessage({ @@ -38,7 +38,7 @@ function ClusterStatusUI({ stats, intl }) { defaultMessage: 'Indices', }), value: indicesCount, - dataTestSubj: 'indicesCount' + 'data-test-subj': 'indicesCount' }, { label: intl.formatMessage({ @@ -46,7 +46,7 @@ function ClusterStatusUI({ stats, intl }) { defaultMessage: 'Memory', }), value: formatMetric(memUsed, 'byte') + ' / ' + formatMetric(memMax, 'byte'), - dataTestSubj: 'memory' + 'data-test-subj': 'memory' }, { label: intl.formatMessage({ @@ -54,7 +54,7 @@ function ClusterStatusUI({ stats, intl }) { defaultMessage: 'Total Shards', }), value: totalShards, - dataTestSubj: 'totalShards' + 'data-test-subj': 'totalShards' }, { label: intl.formatMessage({ @@ -62,7 +62,7 @@ function ClusterStatusUI({ stats, intl }) { defaultMessage: 'Unassigned Shards', }), value: unassignedShards, - dataTestSubj: 'unassignedShards' + 'data-test-subj': 'unassignedShards' }, { label: intl.formatMessage({ @@ -70,7 +70,7 @@ function ClusterStatusUI({ stats, intl }) { defaultMessage: 'Documents', }), value: formatMetric(documentCount, 'int_commas'), - dataTestSubj: 'documentCount' + 'data-test-subj': 'documentCount' }, { label: intl.formatMessage({ @@ -78,7 +78,7 @@ function ClusterStatusUI({ stats, intl }) { defaultMessage: 'Data', }), value: formatMetric(dataSize, 'byte'), - dataTestSubj: 'dataSize' + 'data-test-subj': 'dataSize' } ]; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/index/advanced.js b/x-pack/plugins/monitoring/public/components/elasticsearch/index/advanced.js new file mode 100644 index 00000000000000..e64b488635e9c7 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/index/advanced.js @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { + EuiPage, + EuiPageContent, + EuiPageBody, + EuiSpacer, + EuiFlexGrid, + EuiFlexItem, +} from '@elastic/eui'; +import { IndexDetailStatus } from '../index_detail_status'; +import { MonitoringTimeseriesContainer } from '../../chart'; + +export const AdvancedIndex = ({ + indexSummary, + metrics, + ...props +}) => { + const metricsToShow = [ + metrics.index_1, + metrics.index_2, + metrics.index_3, + metrics.index_4, + metrics.index_total, + metrics.index_time, + metrics.index_refresh, + metrics.index_throttling, + metrics.index_disk, + metrics.index_segment_count, + metrics.index_latency, + ]; + + return ( + + + + + + + {metricsToShow.map((metric, index) => ( + + + + + ))} + + + + + ); +}; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/index/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/index/index.js new file mode 100644 index 00000000000000..8caf0d0b48b430 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/index/index.js @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { + EuiPage, + EuiPageContent, + EuiPageBody, + EuiSpacer, + EuiFlexGrid, + EuiFlexItem, +} from '@elastic/eui'; +import { IndexDetailStatus } from '../index_detail_status'; +import { MonitoringTimeseriesContainer } from '../../chart'; +import { ShardAllocation } from '../shard_allocation/shard_allocation'; + +export const Index = ({ + indexSummary, + metrics, + scope, + kbnUrl, + ...props +}) => { + const metricsToShow = [ + metrics.index_mem, + metrics.index_size, + metrics.index_search_request_rate, + metrics.index_request_rate, + metrics.index_segment_count, + metrics.index_document_count, + ]; + + return ( + + + + + + + {metricsToShow.map((metric, index) => ( + + + + + ))} + + + + + + + ); +}; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/index_detail_status/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/index_detail_status/index.js index 55e65608b81f7f..78e43538eaa91b 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/index_detail_status/index.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/index_detail_status/index.js @@ -26,7 +26,7 @@ function IndexDetailStatusUI({ stats, intl }) { defaultMessage: 'Total', }), value: formatMetric(dataSize.total, '0.0 b'), - dataTestSubj: 'dataSize' + 'data-test-subj': 'dataSize' }, { label: intl.formatMessage({ @@ -34,7 +34,7 @@ function IndexDetailStatusUI({ stats, intl }) { defaultMessage: 'Primaries', }), value: formatMetric(dataSize.primaries, '0.0 b'), - dataTestSubj: 'dataSizePrimaries' + 'data-test-subj': 'dataSizePrimaries' }, { label: intl.formatMessage({ @@ -42,7 +42,7 @@ function IndexDetailStatusUI({ stats, intl }) { defaultMessage: 'Documents', }), value: formatMetric(documentCount, '0.[0]a'), - dataTestSubj: 'documentCount' + 'data-test-subj': 'documentCount' }, { label: intl.formatMessage({ @@ -50,7 +50,7 @@ function IndexDetailStatusUI({ stats, intl }) { defaultMessage: 'Total Shards', }), value: formatMetric(totalShards, 'int_commas'), - dataTestSubj: 'totalShards' + 'data-test-subj': 'totalShards' }, { label: intl.formatMessage({ @@ -58,7 +58,7 @@ function IndexDetailStatusUI({ stats, intl }) { defaultMessage: 'Unassigned Shards', }), value: formatMetric(unassignedShards, 'int_commas'), - dataTestSubj: 'unassignedShards' + 'data-test-subj': 'unassignedShards' } ]; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/indices/indices.js b/x-pack/plugins/monitoring/public/components/elasticsearch/indices/indices.js index ba41ea8fb82d65..dceb2e2ab4e88a 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/indices/indices.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/indices/indices.js @@ -4,133 +4,119 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment } from 'react'; -import { capitalize, get } from 'lodash'; -import { SORT_ASCENDING, SORT_DESCENDING } from '../../../../common/constants'; +import React from 'react'; +import { capitalize } from 'lodash'; import { LARGE_FLOAT, LARGE_BYTES, LARGE_ABBREVIATED } from '../../../../common/formatting'; import { formatMetric } from '../../../lib/format_number'; import { ElasticsearchStatusIcon } from '../status_icon'; import { ClusterStatus } from '../cluster_status'; -import { MonitoringTable } from '../../table'; -import { EuiLink } from '@elastic/eui'; -import { KuiTableRowCell, KuiTableRow } from '@kbn/ui-framework/components'; -import { SystemIndicesCheckbox } from './system_indices_checkbox'; +import { EuiMonitoringTable } from '../../table'; +import { + EuiLink, + EuiPage, + EuiPageContent, + EuiPageBody, + EuiSwitch, + EuiSpacer, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; -const filterFields = ['name', 'status']; const columns = [ { - title: i18n.translate('xpack.monitoring.elasticsearch.indices.nameTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.indices.nameTitle', { defaultMessage: 'Name', }), - sortKey: 'name', - secondarySortOrder: SORT_ASCENDING + field: 'name', + width: '350px', + sortable: true, + render: (value) => ( +
+ + {value} + +
+ ), }, { - title: i18n.translate('xpack.monitoring.elasticsearch.indices.statusTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.indices.statusTitle', { defaultMessage: 'Status', }), - sortKey: 'status_sort', - sortOrder: SORT_DESCENDING // default sort: red, then yellow, then green + field: 'status', + sortable: true, + render: (value) => ( +
+   + {capitalize(value)} +
+ ) }, { - title: i18n.translate('xpack.monitoring.elasticsearch.indices.documentCountTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.indices.documentCountTitle', { defaultMessage: 'Document Count', }), - sortKey: 'doc_count' + field: 'doc_count', + sortable: true, + render: value => ( +
+ {formatMetric(value, LARGE_ABBREVIATED)} +
+ ) }, { - title: i18n.translate('xpack.monitoring.elasticsearch.indices.dataTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.indices.dataTitle', { defaultMessage: 'Data', }), - sortKey: 'data_size' + field: 'data_size', + sortable: true, + render: value => ( +
+ {formatMetric(value, LARGE_BYTES)} +
+ ) }, { - title: i18n.translate('xpack.monitoring.elasticsearch.indices.indexRateTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.indices.indexRateTitle', { defaultMessage: 'Index Rate', }), - sortKey: 'index_rate' + field: 'index_rate', + sortable: true, + render: value => ( +
+ {formatMetric(value, LARGE_FLOAT, '/s')} +
+ ) }, { - title: i18n.translate('xpack.monitoring.elasticsearch.indices.searchRateTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.indices.searchRateTitle', { defaultMessage: 'Search Rate', }), - sortKey: 'search_rate' + field: 'search_rate', + sortable: true, + render: value => ( +
+ {formatMetric(value, LARGE_FLOAT, '/s')} +
+ ) }, { - title: i18n.translate('xpack.monitoring.elasticsearch.indices.unassignedShardsTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.indices.unassignedShardsTitle', { defaultMessage: 'Unassigned Shards', }), - sortKey: 'unassigned_shards' + field: 'unassigned_shards', + sortable: true, + render: value => ( +
+ {formatMetric(value, '0')} +
+ ) } ]; -const IndexRow = injectI18n(({ status, ...props }) => ( - - - - {props.name} - - - -
-   - {capitalize(status)} -
-
- - {formatMetric(get(props, 'doc_count'), LARGE_ABBREVIATED)} - - - {formatMetric(get(props, 'data_size'), LARGE_BYTES)} - - - {formatMetric(get(props, 'index_rate'), LARGE_FLOAT, '/s')} - - - {formatMetric(get(props, 'search_rate'), LARGE_FLOAT, '/s')} - - - {formatMetric(get(props, 'unassigned_shards'), '0')} - -
-)); -const getNoDataMessage = filterText => { - const howToShowSystemIndicesDescription = ( - - ); - if (filterText) { - return ( -
-

- -

-

- {howToShowSystemIndicesDescription} -

-
- ); - } +const getNoDataMessage = () => { return (

@@ -140,46 +126,64 @@ const getNoDataMessage = filterText => { />

- {howToShowSystemIndicesDescription} +

); }; -const renderToolBarSection = ({ showSystemIndices, toggleShowSystemIndices, ...props }) => ( - -); - -function ElasticsearchIndicesUI({ clusterStatus, indices, intl, ...props }) { +const ElasticsearchIndicesUI = ({ + clusterStatus, + indices, + intl, + sorting, + pagination, + onTableChange, + toggleShowSystemIndices, + showSystemIndices, +}) => { return ( - - - - + + + + + + + )} + checked={showSystemIndices} + onChange={e => toggleShowSystemIndices(e.target.checked)} + /> + + + + + ); -} +}; export const ElasticsearchIndices = injectI18n(ElasticsearchIndicesUI); diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/node/advanced.js b/x-pack/plugins/monitoring/public/components/elasticsearch/node/advanced.js new file mode 100644 index 00000000000000..012f7face71be2 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/node/advanced.js @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { + EuiPage, + EuiPageContent, + EuiPageBody, + EuiSpacer, + EuiFlexGrid, + EuiFlexItem, +} from '@elastic/eui'; +import { NodeDetailStatus } from '../node_detail_status'; +import { MonitoringTimeseriesContainer } from '../../chart'; + +export const AdvancedNode = ({ + nodeSummary, + metrics, + ...props +}) => { + const metricsToShow = [ + metrics.node_gc, + metrics.node_gc_time, + metrics.node_jvm_mem, + metrics.node_cpu_utilization, + metrics.node_index_1, + metrics.node_index_2, + metrics.node_index_3, + metrics.node_index_4, + metrics.node_index_time, + metrics.node_request_total, + metrics.node_index_threads, + metrics.node_read_threads, + metrics.node_cgroup_cpu, + metrics.node_cgroup_stats, + metrics.node_latency, + ]; + + return ( + + + + + + + {metricsToShow.map((metric, index) => ( + + + + + ))} + + + + + ); +}; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/node/node.js b/x-pack/plugins/monitoring/public/components/elasticsearch/node/node.js new file mode 100644 index 00000000000000..2cb8db083a8165 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/node/node.js @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { + EuiPage, + EuiPageContent, + EuiPageBody, + EuiSpacer, + EuiFlexGrid, + EuiFlexItem, +} from '@elastic/eui'; +import { NodeDetailStatus } from '../node_detail_status'; +import { MonitoringTimeseriesContainer } from '../../chart'; +import { ShardAllocation } from '../shard_allocation/shard_allocation'; + +export const Node = ({ + nodeSummary, + metrics, + scope, + kbnUrl, + ...props +}) => { + const metricsToShow = [ + metrics.node_jvm_mem, + metrics.node_mem, + metrics.node_cpu_metric, + metrics.node_load_average, + metrics.node_latency, + metrics.node_segment_count, + ]; + + return ( + + + + + + + {metricsToShow.map((metric, index) => ( + + + + + ))} + + + + + + + ); +}; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/node_detail_status/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/node_detail_status/index.js index a901a36c7325a8..9184b45eb159c0 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/node_detail_status/index.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/node_detail_status/index.js @@ -26,8 +26,12 @@ function NodeDetailStatusUI({ stats, intl }) { const metrics = [ { + label: intl.formatMessage({ + id: 'xpack.monitoring.elasticsearch.nodeDetailStatus.transportAddress', + defaultMessage: 'Transport Address', + }), value: transportAddress, - dataTestSubj: 'transportAddress' + 'data-test-subj': 'transportAddress' }, { label: intl.formatMessage({ @@ -36,7 +40,7 @@ function NodeDetailStatusUI({ stats, intl }) { javaVirtualMachine: 'JVM' }), value: formatMetric(usedHeap, '0,0.[00]', '%', { prependSpace: false }), - dataTestSubj: 'jvmHeap' + 'data-test-subj': 'jvmHeap' }, { label: intl.formatMessage({ @@ -44,7 +48,7 @@ function NodeDetailStatusUI({ stats, intl }) { defaultMessage: 'Free Disk Space', }), value: formatMetric(freeSpace, '0.0 b'), - dataTestSubj: 'freeDiskSpace' + 'data-test-subj': 'freeDiskSpace' }, { label: intl.formatMessage({ @@ -52,7 +56,7 @@ function NodeDetailStatusUI({ stats, intl }) { defaultMessage: 'Documents', }), value: formatMetric(documents, '0.[0]a'), - dataTestSubj: 'documentCount' + 'data-test-subj': 'documentCount' }, { label: intl.formatMessage({ @@ -60,7 +64,7 @@ function NodeDetailStatusUI({ stats, intl }) { defaultMessage: 'Data', }), value: formatMetric(dataSize, '0.0 b'), - dataTestSubj: 'dataSize' + 'data-test-subj': 'dataSize' }, { label: intl.formatMessage({ @@ -68,7 +72,7 @@ function NodeDetailStatusUI({ stats, intl }) { defaultMessage: 'Indices', }), value: formatMetric(indexCount, 'int_commas'), - dataTestSubj: 'indicesCount' + 'data-test-subj': 'indicesCount' }, { label: intl.formatMessage({ @@ -76,7 +80,7 @@ function NodeDetailStatusUI({ stats, intl }) { defaultMessage: 'Shards', }), value: formatMetric(totalShards, 'int_commas'), - dataTestSubj: 'shardsCount' + 'data-test-subj': 'shardsCount' }, { label: intl.formatMessage({ @@ -84,7 +88,7 @@ function NodeDetailStatusUI({ stats, intl }) { defaultMessage: 'Type', }), value: nodeTypeLabel, - dataTestSubj: 'nodeType' + 'data-test-subj': 'nodeType' } ]; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/__snapshots__/cells.test.js.snap b/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/__snapshots__/cells.test.js.snap index 900f707856d4e0..f737d2d435c0c1 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/__snapshots__/cells.test.js.snap +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/__snapshots__/cells.test.js.snap @@ -1,75 +1,103 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Node Listing Metric Cell should format N/A as the metric for an offline node 1`] = ` - -
-
- N/A -
-
- + N/A + `; exports[`Node Listing Metric Cell should format a non-percentage metric 1`] = ` -
+

+

+

+

- 206.3 GB +

+ 206.3 GB  + +

-
-
+
206.5 GB max
-
+
206.3 GB min
- +

+

`; exports[`Node Listing Metric Cell should format a percentage metric 1`] = ` -
+

+

+

+

- 0% +

+ 0%  + +

-
-
+
2% max
-
+
0% min
- +

+

`; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/cells.js b/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/cells.js index 8fb336a8fc85e3..4c9144349917cf 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/cells.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/cells.js @@ -7,19 +7,13 @@ import React from 'react'; import { get } from 'lodash'; import { formatMetric } from '../../../lib/format_number'; -import { KuiTableRowCell } from '@kbn/ui-framework/components'; -import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiStat, EuiText, EuiTitle, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; function OfflineCell() { return ( - -
- -
-
+
+ N/A +
); } @@ -43,20 +37,30 @@ function MetricCell({ isOnline, metric = {}, isPercent, ...props }) { const format = get(metric, 'metric.format'); return ( - -
- { metricVal(lastVal, format, isPercent) } -
- -
-
- { metricVal(maxVal, format, isPercent) + ' max' } -
-
- { metricVal(minVal, format, isPercent) + ' min' } -
-
-
+ + + +

+ { metricVal(lastVal, format, isPercent) } +   + +

+
+
+ + + { metricVal(maxVal, format, isPercent) + ' max' } + + + { metricVal(minVal, format, isPercent) + ' min' } + + + + )} + /> ); } diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/nodes.js b/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/nodes.js index 9f05ccf50ed15e..31a8b6bcf0b6b6 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/nodes.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/nodes.js @@ -4,227 +4,228 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment } from 'react'; -import { get } from 'lodash'; -import { SORT_ASCENDING } from '../../../../common/constants'; +import React from 'react'; import { NodeStatusIcon } from '../node'; import { extractIp } from '../../../lib/extract_ip'; // TODO this is only used for elasticsearch nodes summary / node detail, so it should be moved to components/elasticsearch/nodes/lib import { ClusterStatus } from '../cluster_status'; -import { MonitoringTable } from '../../table'; +import { EuiMonitoringTable } from '../../table'; import { MetricCell, OfflineCell } from './cells'; -import { EuiLink, EuiToolTip } from '@elastic/eui'; -import { KuiTableRowCell, KuiTableRow } from '@kbn/ui-framework/components'; +import { + EuiLink, + EuiToolTip, + EuiSpacer, + EuiPage, + EuiPageContent, + EuiPageBody, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { injectI18n } from '@kbn/i18n/react'; -const filterFields = ['name']; const getColumns = showCgroupMetricsElasticsearch => { const cols = []; + + const cpuUsageColumnTitle = i18n.translate('xpack.monitoring.elasticsearch.nodes.cpuUsageColumnTitle', { + defaultMessage: 'CPU Usage', + }); + cols.push({ - title: i18n.translate('xpack.monitoring.elasticsearch.nodes.nameColumnTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.nodes.nameColumnTitle', { defaultMessage: 'Name', }), - sortKey: 'name', - sortOrder: SORT_ASCENDING + field: 'name', + sortable: true, + render: (value, node) => ( +
+
+ + + +   + + + {value} + + +
+
+ {extractIp(node.transport_address)} +
+
+ ) }); + cols.push({ - title: i18n.translate('xpack.monitoring.elasticsearch.nodes.statusColumnTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.nodes.statusColumnTitle', { defaultMessage: 'Status', }), - sortKey: 'isOnline' - }); - const cpuUsageColumnTitle = i18n.translate('xpack.monitoring.elasticsearch.nodes.cpuUsageColumnTitle', { - defaultMessage: 'CPU Usage', + field: 'isOnline', + sortable: true, + render: value => { + const status = value ? 'Online' : 'Offline'; + return ( +
+ {' '} + {status} +
+ ); + } }); + if (showCgroupMetricsElasticsearch) { cols.push({ - title: cpuUsageColumnTitle, - sortKey: 'node_cgroup_quota' + name: cpuUsageColumnTitle, + field: 'node_cgroup_quota', + sortable: true, + render: (value, node) => ( + + ) }); + cols.push({ - title: i18n.translate('xpack.monitoring.elasticsearch.nodes.cpuThrottlingColumnTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.nodes.cpuThrottlingColumnTitle', { defaultMessage: 'CPU Throttling', }), - sortKey: 'node_cgroup_throttled' + field: 'node_cgroup_throttled', + sortable: true, + render: (value, node) => ( + + ) }); } else { cols.push({ - title: cpuUsageColumnTitle, - sortKey: 'node_cpu_utilization' + name: cpuUsageColumnTitle, + field: 'node_cpu_utilization', + sortable: true, + render: (value, node) => ( + + ) }); + cols.push({ - title: i18n.translate('xpack.monitoring.elasticsearch.nodes.loadAverageColumnTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.nodes.loadAverageColumnTitle', { defaultMessage: 'Load Average', }), - sortKey: 'node_load_average' + field: 'node_load_average', + sortable: true, + render: (value, node) => ( + + ) }); } + cols.push({ - title: i18n.translate('xpack.monitoring.elasticsearch.nodes.jvmMemoryColumnTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.nodes.jvmMemoryColumnTitle', { defaultMessage: '{javaVirtualMachine} Memory', values: { javaVirtualMachine: 'JVM' } }), - sortKey: 'node_jvm_mem_percent' + field: 'node_jvm_mem_percent', + sortable: true, + render: (value, node) => ( + + ) }); + cols.push({ - title: i18n.translate('xpack.monitoring.elasticsearch.nodes.diskFreeSpaceColumnTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.nodes.diskFreeSpaceColumnTitle', { defaultMessage: 'Disk Free Space', }), - sortKey: 'node_free_space' + field: 'node_free_space', + sortable: true, + width: '300px', + render: (value, node) => ( + + ) }); + cols.push({ - title: i18n.translate('xpack.monitoring.elasticsearch.nodes.shardsColumnTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.nodes.shardsColumnTitle', { defaultMessage: 'Shards', }), - sortKey: 'shardCount' - }); - return cols; -}; - -const nodeRowFactory = showCgroupMetricsElasticsearch => { - return class NodeRow extends React.Component { - constructor(props) { - super(props); - } - - isOnline() { - return this.props.isOnline === true; - } - - getCpuComponents() { - const isOnline = this.isOnline(); - if (showCgroupMetricsElasticsearch) { - return [ - , - - ]; - } - return [ - , - - ]; - } - - getShardCount() { - if (this.isOnline()) { - return ( - -
- {get(this.props, 'shardCount')} -
-
- ); - } - return ; + field: 'shardCount', + sortable: true, + render: (value, node) => { + return node.isOnline ? ( +
+ {value} +
+ ) : ; } + }); - render() { - const isOnline = this.isOnline(); - const status = this.props.isOnline ? 'Online' : 'Offline'; - - return ( - - -
- - - -   - - - {this.props.name} - - -
-
- {extractIp(this.props.transport_address)} -
-
- -
- {' '} - {status} -
-
- {this.getCpuComponents()} - - - {this.getShardCount()} -
- ); - } - }; + return cols; }; function ElasticsearchNodesUI({ clusterStatus, nodes, showCgroupMetricsElasticsearch, intl, ...props }) { const columns = getColumns(showCgroupMetricsElasticsearch); + const { sorting, pagination, onTableChange } = props; return ( - - - - - + + + + + + + + + ); } diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/overview/overview.js b/x-pack/plugins/monitoring/public/components/elasticsearch/overview/overview.js index 55020955d00f43..3600f9713eae0c 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/overview/overview.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/overview/overview.js @@ -4,11 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment } from 'react'; +import React from 'react'; import { ClusterStatus } from '../cluster_status'; import { ShardActivity } from '../shard_activity'; import { MonitoringTimeseriesContainer } from '../../chart'; -import { EuiPage, EuiFlexGrid, EuiFlexItem, EuiSpacer, EuiPageBody } from '@elastic/eui'; +import { EuiPage, EuiFlexGrid, EuiFlexItem, EuiSpacer, EuiPageBody, EuiPageContent } from '@elastic/eui'; export function ElasticsearchOverview({ clusterStatus, @@ -24,10 +24,11 @@ export function ElasticsearchOverview({ ]; return ( - - - - + + + + + {metricsToShow.map((metric, index) => ( @@ -40,8 +41,8 @@ export function ElasticsearchOverview({ ))} - - - + + + ); } diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/recovery_index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/recovery_index.js index 45c1a432a491d6..58d55d7863ea0e 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/recovery_index.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/recovery_index.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment } from 'react'; +import React from 'react'; import { EuiLink } from '@elastic/eui'; import { Snapshot } from './snapshot'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -13,7 +13,7 @@ export const RecoveryIndex = (props) => { const { name, shard, relocationType } = props; return ( - +
{name}
{
- +
); }; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity.js index b41424bc6620f7..c12b1ed59921cd 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity.js @@ -6,13 +6,7 @@ import React, { Fragment } from 'react'; import { EuiText, EuiTitle, EuiLink, EuiSpacer, EuiSwitch } from '@elastic/eui'; -import { - KuiTableRowCell, - KuiTableRow, - KuiToolBarSection, - KuiToolBarText -} from '@kbn/ui-framework/components'; -import { MonitoringTable } from 'plugins/monitoring/components/table'; +import { EuiMonitoringTable } from 'plugins/monitoring/components/table'; import { RecoveryIndex } from './recovery_index'; import { TotalTime } from './total_time'; import { SourceDestination } from './source_destination'; @@ -23,89 +17,55 @@ import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; const columns = [ { - title: i18n.translate('xpack.monitoring.kibana.shardActivity.indexTitle', { + name: i18n.translate('xpack.monitoring.kibana.shardActivity.indexTitle', { defaultMessage: 'Index' }), - sortKey: null + field: 'name', + render: (_name, shard) => }, { - title: i18n.translate('xpack.monitoring.kibana.shardActivity.stageTitle', { + name: i18n.translate('xpack.monitoring.kibana.shardActivity.stageTitle', { defaultMessage: 'Stage' }), - sortKey: null + field: 'stage' }, { - title: i18n.translate('xpack.monitoring.kibana.shardActivity.totalTimeTitle', { + name: i18n.translate('xpack.monitoring.kibana.shardActivity.totalTimeTitle', { defaultMessage: 'Total Time' }), - sortKey: null + field: null, + render: shard => }, { - title: i18n.translate('xpack.monitoring.kibana.shardActivity.sourceDestinationTitle', { + name: i18n.translate('xpack.monitoring.kibana.shardActivity.sourceDestinationTitle', { defaultMessage: 'Source / Destination' }), - sortKey: null + field: null, + render: shard => }, { - title: i18n.translate('xpack.monitoring.kibana.shardActivity.filesTitle', { + name: i18n.translate('xpack.monitoring.kibana.shardActivity.filesTitle', { defaultMessage: 'Files' }), - sortKey: null + field: null, + render: shard => }, { - title: i18n.translate('xpack.monitoring.kibana.shardActivity.bytesTitle', { + name: i18n.translate('xpack.monitoring.kibana.shardActivity.bytesTitle', { defaultMessage: 'Bytes' }), - sortKey: null + field: null, + render: shard => }, { - title: i18n.translate('xpack.monitoring.kibana.shardActivity.translogTitle', { + name: i18n.translate('xpack.monitoring.kibana.shardActivity.translogTitle', { defaultMessage: 'Translog' }), - sortKey: null + field: null, + render: shard => } ]; -const ActivityRow = props => ( - - - - - {props.stage} - - - - - - - - - - - - - - - - -); -const ToggleCompletedSwitch = ({ toggleHistory, showHistory }) => ( - - - - )} - onChange={toggleHistory} - checked={showHistory} - /> - - -); class ShardActivityUI extends React.Component { constructor(props) { @@ -146,18 +106,20 @@ class ShardActivityUI extends React.Component { render() { // data prop is an array of table row data, or null (which triggers no data message) - const { data: rawData } = this.props; + const { + data: rawData, + sorting, + pagination, + onTableChange, + toggleShardActivityHistory, + showShardActivityHistory + } = this.props; + if (rawData === null) { return null; } - const rows = rawData.map(parseProps); - const renderToolBarSection = props => ( - - ); + const rows = rawData.map(parseProps); return ( @@ -172,15 +134,27 @@ class ShardActivityUI extends React.Component { - + )} + onChange={toggleShardActivityHistory} + checked={showShardActivityHistory} + /> + + ); diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/_index.scss b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/_index.scss similarity index 100% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/_index.scss rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/_index.scss diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/_shard_allocation.scss b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/_shard_allocation.scss similarity index 77% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/_shard_allocation.scss rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/_shard_allocation.scss index 6ccb8f0796ee18..100075f50dba95 100644 --- a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/_shard_allocation.scss +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/_shard_allocation.scss @@ -80,44 +80,18 @@ monitoring-shard-allocation { .shard { align-self: center; padding: 5px 7px; - background-color: $euiColorPrimary; font: 10px sans-serif; border-left: 1px solid $euiColorEmptyShade; position: relative; - color: $euiColorGhost; .shard-tooltip { padding: 5px; bottom: 25px; left: 0; - background-color: $euiColorLightShade; position: absolute; - color: $euiColorDarkShade; border: 1px solid $euiColorLightShade; white-space: nowrap; } - - &.replica { - background-color: tintOrShade($euiColorPrimary, 15%, 15%); - } - - &.unassigned { - background-color: $euiColorMediumShade !important; - color: $euiColorFullShade; - } - - &.emergency { - background-color: $euiColorDanger !important; - color: $euiColorFullShade; - } - - &.relocating { - background-color: $euiColorVis3; - } - - &.initializing { - background-color: tintOrShade($euiColorVis3, 15%, 15%); - } } .legend { diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/assigned.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/assigned.js similarity index 94% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/assigned.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/assigned.js index b63571806a5701..ec1b36837af923 100644 --- a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/assigned.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/assigned.js @@ -9,8 +9,8 @@ import { get, sortBy } from 'lodash'; import React from 'react'; import { Shard } from './shard'; -import { calculateClass } from '../lib/calculateClass'; -import { generateQueryAndLink } from '../lib/generateQueryAndLink'; +import { calculateClass } from '../lib/calculate_class'; +import { generateQueryAndLink } from '../lib/generate_query_and_link'; import { EuiKeyboardAccessible, } from '@elastic/eui'; diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/clusterView.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/cluster_view.js similarity index 89% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/clusterView.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/cluster_view.js index f9cf7d57ac1ac1..8c85c40951777c 100644 --- a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/clusterView.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/cluster_view.js @@ -7,8 +7,8 @@ import React from 'react'; -import { TableHead } from './tableHead'; -import { TableBody } from './tableBody'; +import { TableHead } from './table_head'; +import { TableBody } from './table_body'; import { i18n } from '@kbn/i18n'; export class ClusterView extends React.Component { @@ -24,7 +24,7 @@ export class ClusterView extends React.Component { this.state = { labels: props.scope.labels || [], showing: props.scope.showing || [], - shardStats: props.shardStats, + shardStats: props.scope.pageData.shardStats, showSystemIndices: props.showSystemIndices, toggleShowSystemIndices: props.toggleShowSystemIndices, angularChangeUrl: (url) => { @@ -45,7 +45,7 @@ export class ClusterView extends React.Component { componentWillMount() { this.props.scope.$watch('showing', this.setShowing); - this.props.scope.$watch('shardStats', this.setShardStats); + this.props.scope.$watch(() => this.props.scope.pageData.shardStats, this.setShardStats); } hasUnassigned = () => { diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/shard.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/shard.js similarity index 78% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/shard.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/shard.js index ec41258263ed79..a0fcf36bb03c58 100644 --- a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/shard.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/shard.js @@ -7,9 +7,32 @@ import React from 'react'; -import { calculateClass } from '../lib/calculateClass'; +import { calculateClass } from '../lib/calculate_class'; import { vents } from '../lib/vents'; import { i18n } from '@kbn/i18n'; +import { EuiTextColor } from '@elastic/eui'; + +function getColor(classes) { + return classes.split(' ').reduce((color, cls) => { + if (color) { + return color; + } + + switch (cls) { + case 'primary': + return 'ghost'; + case 'replica': + return 'secondary'; + case 'relocation': + return 'accent'; + case 'initializing': + return 'default'; + case 'emergency': + case 'unassigned': + return 'danger'; + } + }, null); +} export class Shard extends React.Component { static displayName = i18n.translate('xpack.monitoring.elasticsearch.shardAllocation.shardDisplayName', { @@ -71,6 +94,7 @@ export class Shard extends React.Component { } const classes = calculateClass(shard); + const color = getColor(classes); const classification = classes + ' ' + shard.shard; // data attrs for automated testing verification @@ -83,7 +107,9 @@ export class Shard extends React.Component { data-shard-classification={classification} data-test-subj="shardIcon" > - {tooltip}{shard.shard} + + {tooltip}{shard.shard} +
); } diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/tableBody.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/table_body.js similarity index 100% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/tableBody.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/table_body.js diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/tableHead.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/table_head.js similarity index 100% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/tableHead.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/table_head.js diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/unassigned.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/unassigned.js similarity index 100% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/components/unassigned.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/unassigned.js diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/index.js new file mode 100644 index 00000000000000..633c5c74f8b552 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/index.js @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { ShardAllocation } from './shard_allocation'; diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/calculateClass.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/calculate_class.js similarity index 100% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/calculateClass.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/calculate_class.js diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/decorate_shards.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/decorate_shards.js similarity index 100% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/decorate_shards.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/decorate_shards.js diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/decorate_shards.test.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/decorate_shards.test.js similarity index 100% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/decorate_shards.test.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/decorate_shards.test.js diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/generateQueryAndLink.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/generate_query_and_link.js similarity index 100% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/generateQueryAndLink.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/generate_query_and_link.js diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/hasPrimaryChildren.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/has_primary_children.js similarity index 100% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/hasPrimaryChildren.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/has_primary_children.js diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/hasUnassigned.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/has_unassigned.js similarity index 100% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/hasUnassigned.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/has_unassigned.js diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/labels.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/labels.js similarity index 100% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/labels.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/labels.js diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/vents.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/vents.js similarity index 100% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/lib/vents.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/vents.js diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/shard_allocation.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/shard_allocation.js new file mode 100644 index 00000000000000..50ab2653ced37f --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/shard_allocation.js @@ -0,0 +1,91 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { EuiTitle, EuiBadge, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { ClusterView } from './components/cluster_view'; + +export const ShardAllocation = ({ + scope, + kbnUrl, + type, + shardStats, +}) => { + const types = [ + { + label: i18n.translate('xpack.monitoring.elasticsearch.shardAllocation.primaryLabel', { + defaultMessage: 'Primary' + }), + color: 'primary' + }, + { + label: i18n.translate('xpack.monitoring.elasticsearch.shardAllocation.replicaLabel', { + defaultMessage: 'Replica' + }), + color: 'secondary' + }, + { + label: i18n.translate('xpack.monitoring.elasticsearch.shardAllocation.relocatingLabel', { + defaultMessage: 'Relocating' + }), + color: 'accent' + }, + { + label: i18n.translate('xpack.monitoring.elasticsearch.shardAllocation.initializingLabel', { + defaultMessage: 'Initializing' + }), + color: 'default' + }, + { + label: i18n.translate('xpack.monitoring.elasticsearch.shardAllocation.unassignedPrimaryLabel', { + defaultMessage: 'Unassigned Primary' + }), + color: 'danger' + }, + { + label: i18n.translate('xpack.monitoring.elasticsearch.shardAllocation.unassignedReplicaLabel', { + defaultMessage: 'Unassigned Replica' + }), + color: 'warning' + }, + ]; + + return ( +
+ +

+ +

+
+ + + { + types.map(type => ( + + + {type.label} + + + )) + } + + + +
+ ); +}; diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/transformers/indices_by_nodes.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/indices_by_nodes.js similarity index 100% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/transformers/indices_by_nodes.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/indices_by_nodes.js diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/transformers/nodes_by_indices.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/nodes_by_indices.js similarity index 97% rename from x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/transformers/nodes_by_indices.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/nodes_by_indices.js index 30b674550550da..26ad4124c63a00 100644 --- a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/transformers/nodes_by_indices.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/nodes_by_indices.js @@ -7,7 +7,7 @@ import _ from 'lodash'; -import { hasPrimaryChildren } from '../lib/hasPrimaryChildren'; +import { hasPrimaryChildren } from '../lib/has_primary_children'; import { decorateShards } from '../lib/decorate_shards'; export function nodesByIndices() { diff --git a/x-pack/plugins/monitoring/public/components/kibana/cluster_status/index.js b/x-pack/plugins/monitoring/public/components/kibana/cluster_status/index.js index 28b2dbbc87ca67..b1293fdd86388a 100644 --- a/x-pack/plugins/monitoring/public/components/kibana/cluster_status/index.js +++ b/x-pack/plugins/monitoring/public/components/kibana/cluster_status/index.js @@ -28,7 +28,7 @@ function ClusterStatusUI({ stats, intl }) { defaultMessage: 'Instances' }), value: instances, - dataTestSubj: 'instances' + 'data-test-subj': 'instances' }, { label: intl.formatMessage({ @@ -36,7 +36,7 @@ function ClusterStatusUI({ stats, intl }) { defaultMessage: 'Memory' }), value: formatMetric(memSize, 'byte') + ' / ' + formatMetric(memLimit, 'byte'), - dataTestSubj: 'memory' + 'data-test-subj': 'memory' }, { label: intl.formatMessage({ @@ -44,7 +44,7 @@ function ClusterStatusUI({ stats, intl }) { defaultMessage: 'Requests' }), value: requests, - dataTestSubj: 'requests' + 'data-test-subj': 'requests' }, { label: intl.formatMessage({ @@ -52,7 +52,7 @@ function ClusterStatusUI({ stats, intl }) { defaultMessage: 'Connections' }), value: connections, - dataTestSubj: 'connections' + 'data-test-subj': 'connections' }, { label: intl.formatMessage({ @@ -60,7 +60,7 @@ function ClusterStatusUI({ stats, intl }) { defaultMessage: 'Max. Response Time' }), value: formatMetric(maxResponseTime, '0', 'ms'), - dataTestSubj: 'maxResponseTime' + 'data-test-subj': 'maxResponseTime' } ]; diff --git a/x-pack/plugins/monitoring/public/components/kibana/detail_status/index.js b/x-pack/plugins/monitoring/public/components/kibana/detail_status/index.js index b8b4cd2ce498bd..0322f625912828 100644 --- a/x-pack/plugins/monitoring/public/components/kibana/detail_status/index.js +++ b/x-pack/plugins/monitoring/public/components/kibana/detail_status/index.js @@ -22,7 +22,7 @@ function DetailStatusUI({ stats, intl }) { const metrics = [ { value: transportAddress, - dataTestSubj: 'transportAddress' + 'data-test-subj': 'transportAddress' }, { label: intl.formatMessage({ @@ -30,7 +30,7 @@ function DetailStatusUI({ stats, intl }) { defaultMessage: 'OS Free Memory' }), value: formatMetric(osFreeMemory, 'byte'), - dataTestSubj: 'osFreeMemory' + 'data-test-subj': 'osFreeMemory' }, { label: intl.formatMessage({ @@ -38,7 +38,7 @@ function DetailStatusUI({ stats, intl }) { defaultMessage: 'Version' }), value: version, - dataTestSubj: 'version' + 'data-test-subj': 'version' }, { label: intl.formatMessage({ @@ -46,7 +46,7 @@ function DetailStatusUI({ stats, intl }) { defaultMessage: 'Uptime' }), value: formatMetric(uptime, 'time_since'), - dataTestSubj: 'uptime' + 'data-test-subj': 'uptime' } ]; diff --git a/x-pack/plugins/monitoring/public/components/logstash/cluster_status/index.js b/x-pack/plugins/monitoring/public/components/logstash/cluster_status/index.js index 2666924c9e0e8c..e27d57d1a8ff07 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/cluster_status/index.js +++ b/x-pack/plugins/monitoring/public/components/logstash/cluster_status/index.js @@ -24,28 +24,28 @@ function ClusterStatusUi({ stats, intl }) { id: 'xpack.monitoring.logstash.clusterStatus.nodesLabel', defaultMessage: 'Nodes' }), value: nodeCount, - dataTestSubj: 'node_count' + 'data-test-subj': 'node_count' }, { label: intl.formatMessage({ id: 'xpack.monitoring.logstash.clusterStatus.memoryLabel', defaultMessage: 'Memory' }), value: formatMetric(avgMemoryUsed, 'byte') + ' / ' + formatMetric(avgMemory, 'byte'), - dataTestSubj: 'memory_used' + 'data-test-subj': 'memory_used' }, { label: intl.formatMessage({ id: 'xpack.monitoring.logstash.clusterStatus.eventsReceivedLabel', defaultMessage: 'Events Received' }), value: formatMetric(eventsInTotal, '0.[0]a'), - dataTestSubj: 'events_in_total' + 'data-test-subj': 'events_in_total' }, { label: intl.formatMessage({ id: 'xpack.monitoring.logstash.clusterStatus.eventsEmittedLabel', defaultMessage: 'Events Emitted' }), value: formatMetric(eventsOutTotal, '0.[0]a'), - dataTestSubj: 'events_out_total' + 'data-test-subj': 'events_out_total' } ]; diff --git a/x-pack/plugins/monitoring/public/components/logstash/detail_status/index.js b/x-pack/plugins/monitoring/public/components/logstash/detail_status/index.js index c4ec3768dfc0b2..ce95eac5a39ba2 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/detail_status/index.js +++ b/x-pack/plugins/monitoring/public/components/logstash/detail_status/index.js @@ -23,42 +23,42 @@ function DetailStatusUi({ stats, intl }) { const firstMetrics = [ { value: httpAddress, - dataTestSubj: 'httpAddress' + 'data-test-subj': 'httpAddress' }, { label: intl.formatMessage({ id: 'xpack.monitoring.logstash.detailStatus.eventsReceivedLabel', defaultMessage: 'Events Received' }), value: formatMetric(events.in, '0.[0]a'), - dataTestSubj: 'eventsIn' + 'data-test-subj': 'eventsIn' }, { label: intl.formatMessage({ id: 'xpack.monitoring.logstash.detailStatus.eventsEmittedLabel', defaultMessage: 'Events Emitted' }), value: formatMetric(events.out, '0.[0]a'), - dataTestSubj: 'eventsOut' + 'data-test-subj': 'eventsOut' }, { label: intl.formatMessage({ id: 'xpack.monitoring.logstash.detailStatus.configReloadsLabel', defaultMessage: 'Config Reloads' }), value: reloads.successes, - dataTestSubj: 'numReloads' + 'data-test-subj': 'numReloads' }, { label: intl.formatMessage({ id: 'xpack.monitoring.logstash.detailStatus.pipelineWorkersLabel', defaultMessage: 'Pipeline Workers' }), value: pipeline.workers, - dataTestSubj: 'pipelineWorkers' + 'data-test-subj': 'pipelineWorkers' }, { label: intl.formatMessage({ id: 'xpack.monitoring.logstash.detailStatus.batchSizeLabel', defaultMessage: 'Batch Size' }), value: pipeline.batch_size, - dataTestSubj: 'pipelineBatchSize' + 'data-test-subj': 'pipelineBatchSize' } ]; @@ -68,14 +68,14 @@ function DetailStatusUi({ stats, intl }) { id: 'xpack.monitoring.logstash.detailStatus.versionLabel', defaultMessage: 'Version' }), value: version, - dataTestSubj: 'version' + 'data-test-subj': 'version' }, { label: intl.formatMessage({ id: 'xpack.monitoring.logstash.detailStatus.uptimeLabel', defaultMessage: 'Uptime' }), value: formatMetric(uptime, 'time_since'), - dataTestSubj: 'uptime' + 'data-test-subj': 'uptime' } ]; @@ -87,7 +87,7 @@ function DetailStatusUi({ stats, intl }) { id: 'xpack.monitoring.logstash.detailStatus.queueTypeLabel', defaultMessage: 'Queue Type' }), value: queueType, - dataTestSubj: 'queueType' + 'data-test-subj': 'queueType' }); } metrics.push(...lastMetrics); diff --git a/x-pack/plugins/monitoring/public/components/logstash/listing/index.js b/x-pack/plugins/monitoring/public/components/logstash/listing/index.js new file mode 100644 index 00000000000000..6c97a85719b4c1 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/listing/index.js @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { Listing } from './listing'; diff --git a/x-pack/plugins/monitoring/public/components/logstash/listing/listing.js b/x-pack/plugins/monitoring/public/components/logstash/listing/listing.js new file mode 100644 index 00000000000000..652d546057d3d9 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/listing/listing.js @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { PureComponent } from 'react'; +import { EuiPage, EuiLink, EuiPageBody, EuiPageContent, EuiSpacer } from '@elastic/eui'; +import { formatPercentageUsage, formatNumber } from '../../../lib/format_number'; +import { ClusterStatus } from '..//cluster_status'; +import { EuiMonitoringTable } from '../../table'; +import { injectI18n } from '@kbn/i18n/react'; + +class ListingUI extends PureComponent { + getColumns() { + const { kbnUrl, scope } = this.props.angular; + + return [ + { + name: 'Name', + field: 'logstash.name', + render: (name, node) => ( +
+
+ { + scope.$evalAsync(() => { + kbnUrl.changePath(`/logstash/node/${node.logstash.uuid}`); + }); + }} + > + {name} + +
+
+ {node.logstash.http_address} +
+
+ ) + }, + { + name: 'CPU Usage', + field: 'process.cpu.percent', + render: value => formatPercentageUsage(value, 100) + }, + { + name: 'Load Average', + field: 'os.cpu.load_average.1m', + render: value => formatNumber(value, '0.00') + }, + { + name: 'JVM Heap Used', + field: 'jvm.mem.heap_used_percent', + render: value => formatPercentageUsage(value, 100) + }, + { + name: 'Events Ingested', + field: 'events.out', + render: value => formatNumber(value, '0.[0]a') + }, + { + name: 'Config Reloads', + render: node => ( +
+
{ node.reloads.successes } successes
+
{ node.reloads.failures } failures
+
+ ) + }, + { + name: 'Version', + field: 'logstash.version', + render: value => formatNumber(value) + } + ]; + } + render() { + const { data, stats, sorting, pagination, onTableChange, intl } = this.props; + const columns = this.getColumns(); + + return ( + + + + + + + + + + ); + } +} + +export const Listing = injectI18n(ListingUI); diff --git a/x-pack/plugins/monitoring/public/components/logstash/node/index.js b/x-pack/plugins/monitoring/public/components/logstash/node/index.js new file mode 100644 index 00000000000000..b2199922874086 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/node/index.js @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { Node } from './node'; diff --git a/x-pack/plugins/monitoring/public/components/logstash/node/node.js b/x-pack/plugins/monitoring/public/components/logstash/node/node.js new file mode 100644 index 00000000000000..2d747949eb4537 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/node/node.js @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { PureComponent } from 'react'; +import { EuiPage, EuiPageBody, EuiPageContent, EuiSpacer, EuiFlexGrid, EuiFlexItem } from '@elastic/eui'; +import { DetailStatus } from '../detail_status'; +import { MonitoringTimeseriesContainer } from '../../chart'; + +export class Node extends PureComponent { + render() { + const { stats, metrics, ...rest } = this.props; + + const metricsToShow = [ + metrics.logstash_events_input_rate, + metrics.logstash_jvm_usage, + metrics.logstash_events_output_rate, + metrics.logstash_node_cpu_metric, + metrics.logstash_events_latency, + metrics.logstash_os_load, + ]; + + return ( + + + + + + + {metricsToShow.map((metric, index) => ( + + + + + ))} + + + + + ); + } +} diff --git a/x-pack/plugins/monitoring/public/components/logstash/overview/index.js b/x-pack/plugins/monitoring/public/components/logstash/overview/index.js new file mode 100644 index 00000000000000..9ee1b444ee8172 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/overview/index.js @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { Overview } from './overview'; diff --git a/x-pack/plugins/monitoring/public/components/logstash/overview/overview.js b/x-pack/plugins/monitoring/public/components/logstash/overview/overview.js new file mode 100644 index 00000000000000..b669f83803c10c --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/overview/overview.js @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { PureComponent } from 'react'; +import { EuiPage, EuiPageBody, EuiPageContent, EuiSpacer, EuiFlexGrid, EuiFlexItem } from '@elastic/eui'; +import { ClusterStatus } from '../cluster_status'; +import { MonitoringTimeseriesContainer } from '../../chart'; + +export class Overview extends PureComponent { + render() { + const { stats, metrics } = this.props; + const metricsToShow = [ + metrics.logstash_cluster_events_input_rate, + metrics.logstash_cluster_events_output_rate, + metrics.logstash_cluster_events_latency + ]; + + return ( + + + + + + + {metricsToShow.map((metric, index) => ( + + + + + ))} + + + + + ); + } +} diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/index.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/index.js new file mode 100644 index 00000000000000..0de77d851a0114 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/index.js @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { PipelineListing } from './pipeline_listing'; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/pipeline_listing.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/pipeline_listing.js new file mode 100644 index 00000000000000..a50e4edacf2091 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/pipeline_listing.js @@ -0,0 +1,178 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { Component } from 'react'; +import moment from 'moment'; +import { partialRight } from 'lodash'; +import { EuiPage, EuiLink, EuiPageBody, EuiPageContent, EuiSpacer, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { formatMetric } from '../../../lib/format_number'; +import { ClusterStatus } from '../cluster_status'; +import { Sparkline } from 'plugins/monitoring/components/sparkline'; +import { EuiMonitoringTable } from '../../table'; +import { injectI18n } from '@kbn/i18n/react'; + +class PipelineListingUI extends Component { + tooltipXValueFormatter(xValue) { + return moment(xValue).format(this.props.dateFormat); + } + + tooltipYValueFormatter(yValue, format, units) { + return formatMetric(yValue, format, units); + } + + getColumns() { + const { onBrush } = this.props; + const { kbnUrl, scope } = this.props.angular; + + return [ + { + name: 'ID', + field: 'id', + sortable: true, + render: (id) => ( + { + scope.$evalAsync(() => { + kbnUrl.changePath(`/logstash/pipelines/${id}`); + }); + }} + > + {id} + + ) + }, + { + name: 'Events Emitted Rate', + field: 'latestThroughput', + sortable: true, + render: (value, pipeline) => { + const throughput = pipeline.metrics.throughput; + return ( + + + this.tooltipXValueFormatter(value), + yValueFormatter: partialRight(this.tooltipYValueFormatter, throughput.metric.format, throughput.metric.units) + }} + options={{ xaxis: throughput.timeRange }} + /> + + + { formatMetric(value, '0.[0]a', throughput.metric.units) } + + + ); + } + }, + { + name: 'Number of Nodes', + field: 'latestNodesCount', + sortable: true, + render: (value, pipeline) => { + const nodesCount = pipeline.metrics.nodesCount; + return ( + + + + + + { formatMetric(value, '0a') } + + + ); + } + }, + ]; + } + + renderStats() { + if (this.props.statusComponent) { + const Component = this.props.statusComponent; + return ( + + ); + } + + return ( + + ); + } + + render() { + const { + data, + sorting, + pagination, + onTableChange, + upgradeMessage, + className, + intl + } = this.props; + + const columns = this.getColumns(); + + return ( + + + + {this.renderStats()} + + + + + + ); + } +} + +export const PipelineListing = injectI18n(PipelineListingUI); diff --git a/x-pack/plugins/monitoring/public/components/summary_status/__snapshots__/summary_status.test.js.snap b/x-pack/plugins/monitoring/public/components/summary_status/__snapshots__/summary_status.test.js.snap index f55020e03f9633..850ceed807382f 100644 --- a/x-pack/plugins/monitoring/public/components/summary_status/__snapshots__/summary_status.test.js.snap +++ b/x-pack/plugins/monitoring/public/components/summary_status/__snapshots__/summary_status.test.js.snap @@ -2,249 +2,226 @@ exports[`Summary Status Component should allow label to be optional 1`] = `
-
+
-
-
-
-
- - 127.0.0.1:9300 - -
-
-
-
+ Status: +

+
+

+ Status: + -

-
- Documents: -
-
- - 24.8k - -
-
-
+ Status: yellow + +  Yellow +

+
+
+
+
+
+

+

+ 127.0.0.1:9300 +

+
+
-
- Status: - - Status: yellow - - -
-
- Yellow -
+

+ Documents: +

+

+ 24.8k +

+
`; exports[`Summary Status Component should allow status to be optional 1`] = `
-
+
-
-
-
- Free Disk Space: -
-
- - 173.9 GB - -
-
-
-
-
-
- Documents: -
-
- - 24.8k - -
-
-
+

+ Free Disk Space: +

+

+ 173.9 GB +

+
+
+ class="euiStat euiStat--leftAligned" + > +
+

+ Documents: +

+
+

+ 24.8k +

+
+
`; exports[`Summary Status Component should render metrics in a summary bar 1`] = `
-
+
-
-
-
- Free Disk Space: -
-
- - 173.9 GB - -
-
-
-
+ Status: +

+
+

+ Status: + -

-
- Documents: -
-
- - 24.8k - -
-
-
+ Status: green + +  Green +

+
+
+
+
+
+

+ Free Disk Space: +

+

+ 173.9 GB +

+
+
-
- Status: - - Status: green - - -
-
- Green -
+

+ Documents: +

+

+ 24.8k +

+
`; diff --git a/x-pack/plugins/monitoring/public/components/summary_status/summary_status.js b/x-pack/plugins/monitoring/public/components/summary_status/summary_status.js index 268500cb3fa5e8..6aa649457c5cc6 100644 --- a/x-pack/plugins/monitoring/public/components/summary_status/summary_status.js +++ b/x-pack/plugins/monitoring/public/components/summary_status/summary_status.js @@ -7,47 +7,29 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import { isEmpty, capitalize } from 'lodash'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiStat, EuiHorizontalRule } from '@elastic/eui'; import { StatusIcon } from '../status_icon/index.js'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { i18n } from '@kbn/i18n'; -const wrapChild = ({ label, value, dataTestSubj }, index) => ( +const wrapChild = ({ label, value, ...props }, index) => ( - - - {label ? label + ': ' : null} - - - {value} - - + ); const DefaultIconComponent = ({ status }) => ( - - ) - }} - /> + Status: {( + + )} ); @@ -57,33 +39,34 @@ const StatusIndicator = ({ status, isOnline, IconComponent }) => { } return ( - - - {' '} - - - {capitalize(status)} - - + + + +   + {capitalize(status)} + + )} + titleSize="s" + textAlign="left" + description="Status:" + /> + ); }; -// eslint-disable-next-line no-unused-vars -export function SummaryStatus({ metrics, status, isOnline, IconComponent = DefaultIconComponent, intl, ...props }) { +export function SummaryStatus({ metrics, status, isOnline, IconComponent = DefaultIconComponent, ...props }) { return ( -
-
- - - - {metrics.map(wrapChild)} - - - - - - -
+
+ + + {metrics.map(wrapChild)} + +
); } diff --git a/x-pack/plugins/monitoring/public/components/summary_status/summary_status.test.js b/x-pack/plugins/monitoring/public/components/summary_status/summary_status.test.js index d66c1dd54619cd..e48921d4e16f17 100644 --- a/x-pack/plugins/monitoring/public/components/summary_status/summary_status.test.js +++ b/x-pack/plugins/monitoring/public/components/summary_status/summary_status.test.js @@ -15,12 +15,12 @@ describe('Summary Status Component', () => { { label: 'Free Disk Space', value: '173.9 GB', - dataTestSubj: 'freeDiskSpace' + 'data-test-subj': 'freeDiskSpace' }, { label: 'Documents', value: '24.8k', - dataTestSubj: 'documentCount' + 'data-test-subj': 'documentCount' }, ], status: 'green' @@ -34,12 +34,12 @@ describe('Summary Status Component', () => { metrics: [ { value: '127.0.0.1:9300', - dataTestSubj: 'transportAddress' + 'data-test-subj': 'transportAddress' }, { label: 'Documents', value: '24.8k', - dataTestSubj: 'documentCount' + 'data-test-subj': 'documentCount' }, ], status: 'yellow' @@ -54,12 +54,12 @@ describe('Summary Status Component', () => { { label: 'Free Disk Space', value: '173.9 GB', - dataTestSubj: 'freeDiskSpace' + 'data-test-subj': 'freeDiskSpace' }, { label: 'Documents', value: '24.8k', - dataTestSubj: 'documentCount' + 'data-test-subj': 'documentCount' }, ] }; diff --git a/x-pack/plugins/monitoring/public/components/table/eui_table.js b/x-pack/plugins/monitoring/public/components/table/eui_table.js new file mode 100644 index 00000000000000..2cc7154a85c9a2 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/table/eui_table.js @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { + EuiInMemoryTable +} from '@elastic/eui'; + +export class EuiMonitoringTable extends React.PureComponent { + render() { + const { + rows: items, + search = {}, + columns: _columns, + ...props + } = this.props; + + if (search.box && !search.box['data-test-subj']) { + search.box['data-test-subj'] = 'monitoringTableToolBar'; + } + + const columns = _columns.map(column => { + if (!column['data-test-subj']) { + column['data-test-subj'] = 'monitoringTableHasData'; + } + return column; + }); + + return ( +
+ +
+ ); + } +} diff --git a/x-pack/plugins/monitoring/public/components/table/index.js b/x-pack/plugins/monitoring/public/components/table/index.js index 38b972c1b0245e..85900144cd57f7 100644 --- a/x-pack/plugins/monitoring/public/components/table/index.js +++ b/x-pack/plugins/monitoring/public/components/table/index.js @@ -5,4 +5,5 @@ */ export { MonitoringTable } from './table'; -export { tableStorageGetter, tableStorageSetter } from './storage'; +export { EuiMonitoringTable } from './eui_table'; +export { tableStorageGetter, tableStorageSetter, euiTableStorageGetter, euiTableStorageSetter } from './storage'; diff --git a/x-pack/plugins/monitoring/public/components/table/storage.js b/x-pack/plugins/monitoring/public/components/table/storage.js index 576dddbee80988..9ddb611331cd07 100644 --- a/x-pack/plugins/monitoring/public/components/table/storage.js +++ b/x-pack/plugins/monitoring/public/components/table/storage.js @@ -33,3 +33,26 @@ export const tableStorageSetter = keyPrefix => { return localStorageData; }; }; + +export const euiTableStorageGetter = keyPrefix => { + return storage => { + const localStorageData = storage.get(STORAGE_KEY) || {}; + const sort = get(localStorageData, [ keyPrefix, 'sort' ]); + const page = get(localStorageData, [ keyPrefix, 'page' ]); + + return { page, sort }; + }; +}; + +export const euiTableStorageSetter = keyPrefix => { + return (storage, { sort, page }) => { + const localStorageData = storage.get(STORAGE_KEY) || {}; + + set(localStorageData, [ keyPrefix, 'sort' ], sort || undefined); // don`t store empty data + set(localStorageData, [ keyPrefix, 'page' ], page || undefined); + + storage.set(STORAGE_KEY, localStorageData); + + return localStorageData; + }; +}; diff --git a/x-pack/plugins/monitoring/public/directives/alerts/index.js b/x-pack/plugins/monitoring/public/directives/alerts/index.js deleted file mode 100644 index d125b0f1c074b2..00000000000000 --- a/x-pack/plugins/monitoring/public/directives/alerts/index.js +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { capitalize } from 'lodash'; -import React from 'react'; -import { render } from 'react-dom'; -import { EuiIcon, EuiHealth } from '@elastic/eui'; -import { uiModules } from 'ui/modules'; -import { KuiTableRowCell, KuiTableRow } from '@kbn/ui-framework/components'; -import { MonitoringTable } from 'plugins/monitoring/components/table'; -import { CALCULATE_DURATION_SINCE, SORT_DESCENDING } from '../../../common/constants'; -import { Tooltip } from 'plugins/monitoring/components/tooltip'; -import { FormattedAlert } from 'plugins/monitoring/components/alerts/formatted_alert'; -import { mapSeverity } from 'plugins/monitoring/components/alerts/map_severity'; -import { formatTimestampToDuration } from '../../../common/format_timestamp_to_duration'; -import { formatDateTimeLocal } from '../../../common/formatting'; -import { i18n } from '@kbn/i18n'; -import { injectI18n, I18nProvider, FormattedMessage } from '@kbn/i18n/react'; - -const linkToCategories = { - '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: 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 injectI18n(props => { - const changeUrl = target => { - scope.$evalAsync(() => { - kbnUrl.changePath(target); - }); - }; - const severityIcon = mapSeverity(props.metadata.severity); - const resolution = { - icon: null, - text: props.intl.formatMessage({ id: 'xpack.monitoring.alerts.notResolvedDescription', - defaultMessage: 'Not Resolved', - }) - }; - - if (props.resolved_timestamp) { - resolution.text = props.intl.formatMessage({ id: 'xpack.monitoring.alerts.resolvedAgoDescription', - defaultMessage: '{duration} ago', - }, { duration: formatTimestampToDuration(props.resolved_timestamp, CALCULATE_DURATION_SINCE) } - ); - } else { - resolution.icon = ( - - ); - } - - return ( - - - - - { capitalize(severityIcon.value) } - - - - - { resolution.icon } { resolution.text } - - - - - - { linkToCategories[props.metadata.link] ? linkToCategories[props.metadata.link] : - props.intl.formatMessage({ id: 'xpack.monitoring.alerts.generalCategoryLabel', defaultMessage: 'General', }) } - - - { formatDateTimeLocal(props.update_timestamp) } - - - - - - ); - }); -}; - -const uiModule = uiModules.get('monitoring/directives', []); -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 = ( - - - - ); - render(alertsTable, $el[0]); - }); - - } - }; -}); diff --git a/x-pack/plugins/monitoring/public/directives/all.js b/x-pack/plugins/monitoring/public/directives/all.js index 98b3a10237ba2c..4aca3c22fd8afa 100644 --- a/x-pack/plugins/monitoring/public/directives/all.js +++ b/x-pack/plugins/monitoring/public/directives/all.js @@ -7,15 +7,12 @@ import './main'; import './chart'; import './sparkline'; -import './alerts'; import './cluster/overview'; import './cluster/listing'; import './elasticsearch/cluster_status'; import './elasticsearch/index_summary'; import './elasticsearch/node_summary'; import './elasticsearch/ml_job_listing'; -import './elasticsearch/shard_allocation'; -import './elasticsearch/shard_allocation/directives/clusterView'; import './logstash/cluster_status'; import './logstash/listing'; import './logstash/node_summary'; diff --git a/x-pack/plugins/monitoring/public/directives/beats/listing/index.js b/x-pack/plugins/monitoring/public/directives/beats/listing/index.js index 779dffaf2309aa..b2964a28574f92 100644 --- a/x-pack/plugins/monitoring/public/directives/beats/listing/index.js +++ b/x-pack/plugins/monitoring/public/directives/beats/listing/index.js @@ -7,160 +7,40 @@ import React from 'react'; import { render } from 'react-dom'; import { uiModules } from 'ui/modules'; -import { Stats } from 'plugins/monitoring/components/beats'; -import { formatMetric } from 'plugins/monitoring/lib/format_number'; import { I18nProvider } from '@kbn/i18n/react'; -import { i18n } from '@kbn/i18n'; -import { - SORT_ASCENDING, - SORT_DESCENDING, - TABLE_ACTION_UPDATE_FILTER, -} from '../../../../common/constants'; -import { - KuiTableRowCell, - KuiTableRow -} from '@kbn/ui-framework/components'; -import { MonitoringTable } from 'plugins/monitoring/components/table'; - -import { - EuiLink, -} from '@elastic/eui'; - -const filterFields = [ 'name', 'type', 'version', 'output' ]; -const columns = [ - { - title: i18n.translate('xpack.monitoring.beats.instances.nameTitle', { defaultMessage: 'Name' }), - sortKey: 'name', - sortOrder: SORT_ASCENDING - }, - { - title: i18n.translate('xpack.monitoring.beats.instances.typeTitle', { defaultMessage: 'Type' }), - sortKey: 'type' - }, - { - title: i18n.translate('xpack.monitoring.beats.instances.outputEnabledTitle', { defaultMessage: 'Output Enabled' }), - sortKey: 'output' - }, - { - title: i18n.translate('xpack.monitoring.beats.instances.totalEventsRateTitle', { defaultMessage: 'Total Events Rate' }), - sortKey: 'total_events_rate', - secondarySortOrder: SORT_DESCENDING - }, - { - title: i18n.translate('xpack.monitoring.beats.instances.bytesSentRateTitle', { defaultMessage: 'Bytes Sent Rate' }), - sortKey: 'bytes_sent_rate' - }, - { - title: i18n.translate('xpack.monitoring.beats.instances.outputErrorsTitle', { defaultMessage: 'Output Errors' }), - sortKey: 'errors' - }, - { - title: i18n.translate('xpack.monitoring.beats.instances.allocatedMemoryTitle', { defaultMessage: 'Allocated Memory' }), - sortKey: 'memory' - }, - { - title: i18n.translate('xpack.monitoring.beats.instances.versionTitle', { defaultMessage: 'Version' }), - sortKey: 'version' - }, -]; -const beatRowFactory = (scope, kbnUrl) => { - return props => { - const goToBeat = uuid => () => { - scope.$evalAsync(() => { - kbnUrl.changePath(`/beats/beat/${uuid}`); - }); - }; - const applyFiltering = filterText => () => { - props.dispatchTableAction(TABLE_ACTION_UPDATE_FILTER, filterText); - }; - - return ( - - -
- - {props.name} - -
-
- - - {props.type} - - - - {props.output} - - - {formatMetric(props.total_events_rate, '', '/s')} - - - {formatMetric(props.bytes_sent_rate, 'byte', '/s')} - - - {formatMetric(props.errors, '0')} - - - {formatMetric(props.memory, 'byte')} - - - - {props.version} - - -
- ); - }; -}; +import { Listing } from '../../../components/beats/listing/listing'; const uiModule = uiModules.get('monitoring/directives', []); -uiModule.directive('monitoringBeatsListing', (kbnUrl, i18n) => { +uiModule.directive('monitoringBeatsListing', (kbnUrl) => { return { restrict: 'E', scope: { data: '=', - pageIndex: '=', - filterText: '=', - sortKey: '=', - sortOrder: '=', - onNewState: '=', + sorting: '=', + pagination: '=paginationSettings', + onTableChange: '=', }, link(scope, $el) { - - scope.$watch('data', (data = {}) => { - const filterBeatsPlaceholder = i18n('xpack.monitoring.beats.filterBeatsPlaceholder', { defaultMessage: 'Filter Beats…' }); - + function renderReact(data) { render(( -
- -
- -
-
+ ), $el[0]); + } + scope.$watch('data', (data = {}) => { + renderReact(data); }); - } }; }); diff --git a/x-pack/plugins/monitoring/public/directives/cluster/listing/index.js b/x-pack/plugins/monitoring/public/directives/cluster/listing/index.js index c4d2e0bf46d622..f7ce4592a78a7b 100644 --- a/x-pack/plugins/monitoring/public/directives/cluster/listing/index.js +++ b/x-pack/plugins/monitoring/public/directives/cluster/listing/index.js @@ -6,408 +6,403 @@ import React, { Fragment } from 'react'; import { render } from 'react-dom'; -import { capitalize, get } from 'lodash'; +import { capitalize, partial } from 'lodash'; import moment from 'moment'; import numeral from '@elastic/numeral'; import { uiModules } from 'ui/modules'; import chrome from 'ui/chrome'; -import { - KuiTableRowCell, - KuiTableRow -} from '@kbn/ui-framework/components'; import { EuiHealth, EuiLink, + EuiPage, + EuiPageBody, + EuiPageContent, } from '@elastic/eui'; import { toastNotifications } from 'ui/notify'; -import { MonitoringTable } from 'plugins/monitoring/components/table'; +import { EuiMonitoringTable } 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, FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -const filterFields = [ 'cluster_name', 'status', 'license.type' ]; -const columns = [ - { - 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) => { - return class ClusterRow extends React.Component { - constructor(props) { - super(props); - } - - changeCluster() { - scope.$evalAsync(() => { - globalState.cluster_uuid = this.props.cluster_uuid; - globalState.ccs = this.props.ccs; - globalState.save(); - kbnUrl.changePath('/overview'); - }); - } - - licenseWarning({ title, text }) { - scope.$evalAsync(() => { - toastNotifications.addWarning({ title, text, 'data-test-subj': 'monitoringLicenseWarning' }); - }); - } +const IsClusterSupported = ({ isSupported, children }) => { + return isSupported ? children : '-'; +}; - handleClickIncompatibleLicense() { - this.licenseWarning({ - title: ( - - ), - text: ( - -

- -

-

- - - - ) - }} - /> -

-
- ), - }); - } +/* + * This checks if alerts feature is supported via monitoring cluster + * license. If the alerts feature is not supported because the prod cluster + * license is basic, IsClusterSupported makes the status col hidden + * completely + */ +const IsAlertsSupported = (props) => { + const { + alertsMeta = { enabled: true }, + clusterMeta = { enabled: true } + } = props.cluster.alerts; + if (alertsMeta.enabled && clusterMeta.enabled) { + return { props.children }; + } - handleClickInvalidLicense() { - const licensingPath = `${chrome.getBasePath()}/app/kibana#/management/elasticsearch/license_management/home`; + const message = alertsMeta.message || clusterMeta.message; + return ( + + + N/A + + + ); +}; - this.licenseWarning({ - title: ( - - ), - text: ( - -

- -

-

- - - - ), - getLicenseInfoLink: ( - - - - ) - }} - /> -

-
- ), - }); - } +const getColumns = ( + showLicenseExpiration, + changeCluster, + handleClickIncompatibleLicense, + handleClickInvalidLicense +) => { + return [ + { + name: i18n.translate('xpack.monitoring.cluster.listing.nameColumnTitle', { + defaultMessage: 'Name', + }), + field: 'cluster_name', + sortable: true, + render: (value, cluster) => { + if (cluster.isSupported) { + return ( + changeCluster(cluster.cluster_uuid, cluster.ccs)} + data-test-subj="clusterLink" + > + { value } + + ); + } - getClusterAction() { - if (this.props.isSupported) { - return ( - - { this.props.cluster_name } - - ); - } + // not supported because license is basic/not compatible with multi-cluster + if (cluster.license) { + return ( + handleClickIncompatibleLicense(cluster.cluster_name)} + data-test-subj="clusterLink" + > + { value } + + ); + } - // not supported because license is basic/not compatible with multi-cluster - if (this.props.license) { + // not supported because license is invalid return ( handleClickInvalidLicense(cluster.cluster_name)} data-test-subj="clusterLink" > - { this.props.cluster_name } + { value } ); } + }, + { + name: i18n.translate('xpack.monitoring.cluster.listing.statusColumnTitle', { + defaultMessage: 'Status', + }), + field: 'status', + 'data-test-subj': 'alertsStatus', + sortable: true, + render: (_status, cluster) => ( + + + + + + ) + }, + { + name: i18n.translate('xpack.monitoring.cluster.listing.nodesColumnTitle', { + defaultMessage: 'Nodes', + }), + field: 'elasticsearch.cluster_stats.nodes.count.total', + 'data-test-subj': 'nodesCount', + sortable: true, + render: (total, cluster) => ( + + { numeral(total).format('0,0') } + + ) + }, + { + name: i18n.translate('xpack.monitoring.cluster.listing.indicesColumnTitle', { + defaultMessage: 'Indices', + }), + field: 'elasticsearch.cluster_stats.indices.count', + 'data-test-subj': 'indicesCount', + sortable: true, + render: (count, cluster) => ( + + { numeral(count).format('0,0') } + + ) + }, + { + name: i18n.translate('xpack.monitoring.cluster.listing.dataColumnTitle', { + defaultMessage: 'Data', + }), + field: 'elasticsearch.cluster_stats.indices.store.size_in_bytes', + 'data-test-subj': 'dataSize', + sortable: true, + render: (size, cluster) => ( + + { numeral(size).format('0,0[.]0 b')} + + ) + }, + { + name: i18n.translate('xpack.monitoring.cluster.listing.logstashColumnTitle', { + defaultMessage: 'Logstash', + }), + field: 'logstash.node_count', + 'data-test-subj': 'logstashCount', + sortable: true, + render: (count, cluster) => ( + + { numeral(count).format('0,0') } + + ) + }, + { + name: i18n.translate('xpack.monitoring.cluster.listing.kibanaColumnTitle', { + defaultMessage: 'Kibana', + }), + field: 'kibana.count', + 'data-test-subj': 'kibanaCount', + sortable: true, + render: (count, cluster) => ( + + { numeral(count).format('0,0') } + + ) + }, + { + name: i18n.translate('xpack.monitoring.cluster.listing.licenseColumnTitle', { + defaultMessage: 'License', + }), + field: 'license.type', + 'data-test-subj': 'clusterLicense', + sortable: true, + render: (licenseType, cluster) => { + const license = cluster.license; + if (license) { + const licenseExpiry = () => { + if (license.expiry_date_in_millis < moment().valueOf()) { + // license is expired + return ( + + Expired + + ); + } - // not supported because license is invalid - return ( - - { this.props.cluster_name } - - ); - } - - getLicenseInfo() { - if (this.props.license) { - const licenseExpiry = () => { - if (this.props.license.expiry_date_in_millis < moment().valueOf()) { - // license is expired + // license is fine return ( - - + + Expires { moment(license.expiry_date_in_millis).format('D MMM YY') } ); - } + }; - // license is fine return ( - - - +
+
+ { capitalize(licenseType) } +
+
+ { showLicenseExpiration ? licenseExpiry() : null } +
+
); - }; + } + // there is no license! return ( -
-
- { capitalize(this.props.license.type) } -
-
- { showLicenseExpiration ? licenseExpiry() : null } -
-
+ handleClickInvalidLicense(cluster.cluster_name)} + > + + N/A + + ); } - - // there is no license! - return ( - - - - - - ); } + ]; +}; - render() { - const isSupported = this.props.isSupported; - const isClusterSupportedFactory = () => { - return (props) => { - if (isSupported) { - return { props.children }; - } - return -; - }; - }; - const IsClusterSupported = isClusterSupportedFactory(isSupported); - const classes = []; - if (!isSupported) { - classes.push('basic'); - } +const changeCluster = (scope, globalState, kbnUrl, clusterUuid, ccs) => { + scope.$evalAsync(() => { + globalState.cluster_uuid = clusterUuid; + globalState.ccs = ccs; + globalState.save(); + kbnUrl.changePath('/overview'); + }); +}; - /* - * This checks if alerts feature is supported via monitoring cluster - * license. If the alerts feature is not supported because the prod cluster - * license is basic, IsClusterSupported makes the status col hidden - * completely - */ - const IsAlertsSupported = (props) => { - const { - alertsMeta = { enabled: true }, - clusterMeta = { enabled: true } - } = props.cluster.alerts; - if (alertsMeta.enabled && clusterMeta.enabled) { - return { props.children }; - } +const licenseWarning = (scope, { title, text }) => { + scope.$evalAsync(() => { + toastNotifications.addWarning({ title, text, 'data-test-subj': 'monitoringLicenseWarning' }); + }); +}; - const message = alertsMeta.message || clusterMeta.message; - return ( - - - - - - ); - }; +const handleClickIncompatibleLicense = (scope, clusterName) => { + licenseWarning(scope, { + title: ( + + ), + text: ( + +

+ +

+

+ + + + ) + }} + /> +

+
+ ), + }); +}; - return ( - - - - { this.getClusterAction() } - - - - - - - - - - - - { numeral(get(this.props, 'elasticsearch.cluster_stats.nodes.count.total')).format('0,0') } - - - - - { numeral(get(this.props, 'elasticsearch.cluster_stats.indices.count')).format('0,0') } - - - - - { numeral(get(this.props, 'elasticsearch.cluster_stats.indices.store.size_in_bytes')).format('0,0[.]0 b') } - - - - - { numeral(get(this.props, 'logstash.node_count')).format('0,0') } - - - - - { numeral(get(this.props, 'kibana.count')).format('0,0') } - - - - { this.getLicenseInfo() } - - - ); - } +const handleClickInvalidLicense = (scope, clusterName) => { + const licensingPath = `${chrome.getBasePath()}/app/kibana#/management/elasticsearch/license_management/home`; - }; + licenseWarning(scope, { + title: ( + + ), + text: ( + +

+ +

+

+ + + + ), + getLicenseInfoLink: ( + + + + ) + }} + /> +

+
+ ), + }); }; const uiModule = uiModules.get('monitoring/directives', []); -uiModule.directive('monitoringClusterListing', ($injector, i18n) => { +uiModule.directive('monitoringClusterListing', ($injector) => { return { restrict: 'E', scope: { clusters: '=', - pageIndex: '=', + sorting: '=', filterText: '=', - sortKey: '=', - sortOrder: '=', - onNewState: '=', + paginationSettings: '=pagination', + onTableChange: '=', }, link(scope, $el) { 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…' } - ); + + const _changeCluster = partial(changeCluster, scope, globalState, kbnUrl); + const _handleClickIncompatibleLicense = partial(handleClickIncompatibleLicense, scope); + const _handleClickInvalidLicense = partial(handleClickInvalidLicense, scope); + + const { sorting, pagination, onTableChange } = scope; scope.$watch('clusters', (clusters = []) => { const clusterTable = ( - + + + + { + return { + 'data-test-subj': `clusterRow_${item.cluster_uuid}` + }; + }} + sorting={{ + ...sorting, + sort: { + ...sorting.sort, + field: 'cluster_name' + } + }} + pagination={pagination} + search={{ + box: { + incremental: true, + placeholder: scope.filterText + }, + }} + onTableChange={onTableChange} + /> + + + ); render(clusterTable, $el[0]); diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/ml_job_listing/index.js b/x-pack/plugins/monitoring/public/directives/elasticsearch/ml_job_listing/index.js index 2fac710fef7f42..bb63dc321627d7 100644 --- a/x-pack/plugins/monitoring/public/directives/elasticsearch/ml_job_listing/index.js +++ b/x-pack/plugins/monitoring/public/directives/elasticsearch/ml_job_listing/index.js @@ -9,150 +9,156 @@ import numeral from '@elastic/numeral'; import React from 'react'; import { render } from 'react-dom'; import { uiModules } from 'ui/modules'; -import { - KuiTableRowCell, - KuiTableRow -} from '@kbn/ui-framework/components'; -import { MonitoringTable } from 'plugins/monitoring/components/table'; +import { EuiMonitoringTable } from 'plugins/monitoring/components/table'; import { MachineLearningJobStatusIcon } from 'plugins/monitoring/components/elasticsearch/ml_job_listing/status_icon'; -import { SORT_ASCENDING } from '../../../../common/constants'; import { LARGE_ABBREVIATED, LARGE_BYTES } from '../../../../common/formatting'; import { EuiLink, + EuiPage, + EuiPageContent, + EuiPageBody, } from '@elastic/eui'; +import { ClusterStatus } from '../../../components/elasticsearch/cluster_status'; import { i18n } from '@kbn/i18n'; -import { I18nProvider } from '@kbn/i18n/react'; +import { I18nProvider, FormattedMessage } from '@kbn/i18n/react'; -const filterFields = [ 'job_id', 'state', 'node.name' ]; -const columns = [ +const getColumns = (kbnUrl, scope) => ([ { - title: i18n.translate('xpack.monitoring.elasticsearch.mlJobListing.jobIdTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.mlJobListing.jobIdTitle', { defaultMessage: 'Job ID' }), - sortKey: 'job_id', - sortOrder: SORT_ASCENDING + field: 'job_id', + sortable: true }, { - title: i18n.translate('xpack.monitoring.elasticsearch.mlJobListing.stateTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.mlJobListing.stateTitle', { defaultMessage: 'State' }), - sortKey: 'state' + field: 'state', + sortable: true, + render: state => ( +
+   + { capitalize(state) } +
+ ) }, { - title: i18n.translate('xpack.monitoring.elasticsearch.mlJobListing.processedRecordsTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.mlJobListing.processedRecordsTitle', { defaultMessage: 'Processed Records' }), - sortKey: 'data_counts.processed_record_count' + field: 'data_counts.processed_record_count', + sortable: true, + render: value => ( + + {numeral(value).format(LARGE_ABBREVIATED)} + + ) }, { - title: i18n.translate('xpack.monitoring.elasticsearch.mlJobListing.modelSizeTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.mlJobListing.modelSizeTitle', { defaultMessage: 'Model Size' }), - sortKey: 'model_size_stats.model_bytes' + field: 'model_size_stats.model_bytes', + sortable: true, + render: value => ( + + {numeral(value).format(LARGE_BYTES)} + + ) }, { - title: i18n.translate('xpack.monitoring.elasticsearch.mlJobListing.forecastsTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.mlJobListing.forecastsTitle', { defaultMessage: 'Forecasts' }), - sortKey: 'forecasts_stats.total' + field: 'forecasts_stats.total', + sortable: true, + render: value => ( + + {numeral(value).format(LARGE_ABBREVIATED)} + + ) }, { - title: i18n.translate('xpack.monitoring.elasticsearch.mlJobListing.nodeTitle', { + name: i18n.translate('xpack.monitoring.elasticsearch.mlJobListing.nodeTitle', { defaultMessage: 'Node' }), - sortKey: 'node.name' - } -]; -const jobRowFactory = (scope, kbnUrl) => { - const goToNode = nodeId => { - scope.$evalAsync(() => kbnUrl.changePath(`/elasticsearch/nodes/${nodeId}`)); - }; - const getNode = node => { - if (node) { + field: 'node.name', + sortable: true, + render: (name, node) => { + if (node) { + return ( + { + scope.$evalAsync(() => kbnUrl.changePath(`/elasticsearch/nodes/${node.id}`)); + }} + > + { name } + + ); + } + return ( - - { node.name } - + ); } - return i18n.translate('xpack.monitoring.elasticsearch.mlJobListing.noDataLabel', { - defaultMessage: 'N/A' - }); - }; - - return function JobRow(props) { - return ( - - { props.job_id } - -   - { capitalize(props.state) } - - { numeral(props.data_counts.processed_record_count).format(LARGE_ABBREVIATED) } - { numeral(props.model_size_stats.model_bytes).format(LARGE_BYTES) } - { numeral(props.forecasts_stats.total).format(LARGE_ABBREVIATED) } - - { getNode(props.node) } - - - ); - }; -}; + } +]); const uiModule = uiModules.get('monitoring/directives', []); -uiModule.directive('monitoringMlListing', (kbnUrl, i18n) => { +uiModule.directive('monitoringMlListing', kbnUrl => { return { restrict: 'E', scope: { jobs: '=', - pageIndex: '=', - filterText: '=', - sortKey: '=', - sortOrder: '=', - onNewState: '=', + paginationSettings: '=', + sorting: '=', + onTableChange: '=', + status: '=', }, link(scope, $el) { + const columns = getColumns(kbnUrl, scope); - const getNoDataMessage = filterText => { - if (filterText) { - return ( - i18n('xpack.monitoring.elasticsearch.mlJobListing.noFilteredJobsDescription', { - // eslint-disable-next-line max-len - defaultMessage: 'There are no Machine Learning Jobs that match the filter [{filterText}] or the time range. Try changing the filter or time range.', - values: { - filterText: filterText.trim() - } - }) - ); - } - return i18n('xpack.monitoring.elasticsearch.mlJobListing.noJobsDescription', { - defaultMessage: 'There are no Machine Learning Jobs that match your query. Try changing the time range selection.' - }); - }; - - const filterJobsPlaceholder = i18n('xpack.monitoring.elasticsearch.mlJobListing.filterJobsPlaceholder', { + const filterJobsPlaceholder = i18n.translate('xpack.monitoring.elasticsearch.mlJobListing.filterJobsPlaceholder', { defaultMessage: 'Filter Jobs…' }); scope.$watch('jobs', (jobs = []) => { const mlTable = ( - + + + + + + + + ); render(mlTable, $el[0]); diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/directives/clusterView.js b/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/directives/clusterView.js deleted file mode 100644 index 83e052c3f5b523..00000000000000 --- a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/directives/clusterView.js +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - - - -import React from 'react'; -import ReactDOM from 'react-dom'; -import { ClusterView } from '../components/clusterView'; -import { uiModules } from 'ui/modules'; -import { I18nProvider } from '@kbn/i18n/react'; - -const uiModule = uiModules.get('monitoring/directives', []); -uiModule.directive('clusterView', kbnUrl => { - return { - restrict: 'E', - scope: { - totalCount: '=', - filter: '=', - showing: '=', - labels: '=', - shardStats: '=', - showSystemIndices: '=', - toggleShowSystemIndices: '=' - }, - link: function (scope, element) { - ReactDOM.render( - - - , - element[0] - ); - } - }; -}); diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/index.html b/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/index.html deleted file mode 100644 index f62b70882e90f7..00000000000000 --- a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/index.html +++ /dev/null @@ -1,57 +0,0 @@ -
-
-

-
-   - -   - -   - -   - -   - -   - -
- -
-
diff --git a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/index.js b/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/index.js deleted file mode 100644 index 665c19eb1c3912..00000000000000 --- a/x-pack/plugins/monitoring/public/directives/elasticsearch/shard_allocation/index.js +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { uiModules } from 'ui/modules'; -import { labels } from './lib/labels'; -import { indicesByNodes } from './transformers/indices_by_nodes'; -import { nodesByIndices } from './transformers/nodes_by_indices'; -import template from './index.html'; - -const uiModule = uiModules.get('monitoring/directives', []); -uiModule.directive('monitoringShardAllocation', () => { - return { - restrict: 'E', - template, - scope: { - view: '@', - shards: '=', - nodes: '=', - shardStats: '=', - showSystemIndices: '=', - toggleShowSystemIndices: '=' - }, - link: (scope) => { - - const isIndexView = scope.view === 'index'; - const transformer = (isIndexView) ? indicesByNodes() : nodesByIndices(); - - scope.isIndexView = isIndexView; - - scope.$watch('shards', (shards) => { - let view = scope.view; - scope.totalCount = shards.length; - scope.showing = transformer(shards, scope.nodes); - if (isIndexView && shards.some((shard) => shard.state === 'UNASSIGNED')) { - view = 'indexWithUnassigned'; - } - scope.labels = labels[view]; - }); - - } - }; -}); diff --git a/x-pack/plugins/monitoring/public/index.scss b/x-pack/plugins/monitoring/public/index.scss index 67974b71cd72ff..24a577aa0901d8 100644 --- a/x-pack/plugins/monitoring/public/index.scss +++ b/x-pack/plugins/monitoring/public/index.scss @@ -20,4 +20,4 @@ @import 'components/table/index'; @import 'components/logstash/pipeline_viewer/views/index'; @import 'directives/chart/index'; -@import 'directives/elasticsearch/shard_allocation/index'; +@import 'components/elasticsearch/shard_allocation/index'; diff --git a/x-pack/plugins/monitoring/public/views/alerts/index.html b/x-pack/plugins/monitoring/public/views/alerts/index.html index 5ef9cc2b034738..4a764634d86fa3 100644 --- a/x-pack/plugins/monitoring/public/views/alerts/index.html +++ b/x-pack/plugins/monitoring/public/views/alerts/index.html @@ -1,28 +1,3 @@ -
-

- {{ alerts.data.message }} -

-
- -
-

-

- -
- -
-

- - -

-
+
diff --git a/x-pack/plugins/monitoring/public/views/alerts/index.js b/x-pack/plugins/monitoring/public/views/alerts/index.js index 7b85d19bc8be08..ab8b57bff07231 100644 --- a/x-pack/plugins/monitoring/public/views/alerts/index.js +++ b/x-pack/plugins/monitoring/public/views/alerts/index.js @@ -4,13 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ +import React from 'react'; +import { render } from 'react-dom'; import { find, get } from 'lodash'; import uiRoutes from 'ui/routes'; import template from './index.html'; -import { MonitoringViewBaseController } from 'plugins/monitoring/views'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; import { timefilter } from 'ui/timefilter'; +import { Alerts } from '../../components/alerts'; +import { MonitoringViewBaseEuiTableController } from '../base_eui_table_controller'; +import { I18nProvider, FormattedMessage } from '@kbn/i18n/react'; +import { EuiPage, EuiPageBody, EuiPageContent, EuiSpacer, EuiLink } from '@elastic/eui'; function getPageData($injector) { const globalState = $injector.get('globalState'); @@ -44,10 +49,11 @@ uiRoutes.when('/alerts', { alerts: getPageData }, controllerAs: 'alerts', - controller: class AlertsView extends MonitoringViewBaseController { + controller: class AlertsView extends MonitoringViewBaseEuiTableController { constructor($injector, $scope, i18n) { const $route = $injector.get('$route'); const globalState = $injector.get('globalState'); + const kbnUrl = $injector.get('kbnUrl'); // breadcrumbs + page title $scope.cluster = find($route.current.locals.clusters, { cluster_uuid: globalState.cluster_uuid }); @@ -60,6 +66,41 @@ uiRoutes.when('/alerts', { }); this.data = $route.current.locals.alerts; + + const renderReact = data => { + const app = data.message + ? (

{data.message}

) + : (); + + render( + + + + + {app} + + + + + + + + , + document.getElementById('monitoringAlertsApp') + ); + }; + $scope.$watch(() => this.data, data => renderReact(data)); } } }); diff --git a/x-pack/plugins/monitoring/public/views/apm/instances/index.js b/x-pack/plugins/monitoring/public/views/apm/instances/index.js index a49aad8ca912b8..4c6c7ef784f0d2 100644 --- a/x-pack/plugins/monitoring/public/views/apm/instances/index.js +++ b/x-pack/plugins/monitoring/public/views/apm/instances/index.js @@ -10,7 +10,7 @@ import uiRoutes from'ui/routes'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; import template from './index.html'; import { ApmServerInstances } from '../../../components/apm/instances'; -import { MonitoringViewBaseTableController } from '../../base_table_controller'; +import { MonitoringViewBaseEuiTableController } from '../..'; import { I18nProvider } from '@kbn/i18n/react'; uiRoutes.when('/apm/instances', { @@ -21,7 +21,7 @@ uiRoutes.when('/apm/instances', { return routeInit(); }, }, - controller: class extends MonitoringViewBaseTableController { + controller: class extends MonitoringViewBaseEuiTableController { constructor($injector, $scope, i18n) { const $route = $injector.get('$route'); const globalState = $injector.get('globalState'); @@ -51,22 +51,18 @@ uiRoutes.when('/apm/instances', { renderReact(data) { const { - pageIndex, - filterText, - sortKey, - sortOrder, - onNewState, + pagination, + sorting, + onTableChange, } = this; const component = ( diff --git a/x-pack/plugins/monitoring/public/views/base_eui_table_controller.js b/x-pack/plugins/monitoring/public/views/base_eui_table_controller.js new file mode 100644 index 00000000000000..dfc548aeb97f20 --- /dev/null +++ b/x-pack/plugins/monitoring/public/views/base_eui_table_controller.js @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { MonitoringViewBaseController } from './'; +import { euiTableStorageGetter, euiTableStorageSetter } from 'plugins/monitoring/components/table'; +import { EUI_SORT_ASCENDING } from '../../common/constants'; + +/** + * Class to manage common instantiation behaviors in a view controller + * And add persistent state to a table: + * - page index: in table pagination, which page are we looking at + * - filter text: what filter was entered in the table's filter bar + * - sortKey: which column field of table data is used for sorting + * - sortOrder: is sorting ordered ascending or descending + * + * This is expected to be extended, and behavior enabled using super(); + */ +export class MonitoringViewBaseEuiTableController extends MonitoringViewBaseController { + + /** + * Create a table view controller + * - used by parent class: + * @param {String} title - Title of the page + * @param {Function} getPageData - Function to fetch page data + * @param {Service} $injector - Angular dependency injection service + * @param {Service} $scope - Angular view data binding service + * @param {Boolean} options.enableTimeFilter - Whether to show the time filter + * @param {Boolean} options.enableAutoRefresh - Whether to show the auto refresh control + * - specific to this class: + * @param {String} storageKey - the namespace that will be used to keep the state data in the Monitoring localStorage object + * + */ + constructor(args) { + super(args); + const { storageKey, $injector } = args; + const storage = $injector.get('localStorage'); + + const getLocalStorageData = euiTableStorageGetter(storageKey); + const setLocalStorageData = euiTableStorageSetter(storageKey); + const { page, sort } = getLocalStorageData(storage); + + this.pagination = page || { + initialPageSize: 20, + pageSizeOptions: [5, 10, 20, 50] + }; + + this.sorting = sort || { + sort: { + field: 'name', + direction: EUI_SORT_ASCENDING + } + }; + + this.onTableChange = ({ page, sort }) => { + setLocalStorageData(storage, { + page, + sort: { + sort + } + }); + }; + } +} diff --git a/x-pack/plugins/monitoring/public/views/base_table_controller.js b/x-pack/plugins/monitoring/public/views/base_table_controller.js index 175a06aa927220..ad0a9678a36a61 100644 --- a/x-pack/plugins/monitoring/public/views/base_table_controller.js +++ b/x-pack/plugins/monitoring/public/views/base_table_controller.js @@ -50,5 +50,4 @@ export class MonitoringViewBaseTableController extends MonitoringViewBaseControl setLocalStorageData(storage, newState); }; } - } diff --git a/x-pack/plugins/monitoring/public/views/cluster/listing/index.html b/x-pack/plugins/monitoring/public/views/cluster/listing/index.html index 5030a67fe3ec57..4335a2fa282cf8 100644 --- a/x-pack/plugins/monitoring/public/views/cluster/listing/index.html +++ b/x-pack/plugins/monitoring/public/views/cluster/listing/index.html @@ -1,18 +1,8 @@ -
-

-

- -
+
diff --git a/x-pack/plugins/monitoring/public/views/cluster/listing/index.js b/x-pack/plugins/monitoring/public/views/cluster/listing/index.js index 1ac9c633937d82..36bdb06da9fc0c 100644 --- a/x-pack/plugins/monitoring/public/views/cluster/listing/index.js +++ b/x-pack/plugins/monitoring/public/views/cluster/listing/index.js @@ -6,7 +6,7 @@ import uiRoutes from 'ui/routes'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; -import { MonitoringViewBaseTableController } from '../../'; +import { MonitoringViewBaseEuiTableController } from '../../'; import template from './index.html'; const getPageData = $injector => { @@ -35,7 +35,7 @@ uiRoutes.when('/home', { } }, controllerAs: 'clusters', - controller: class ClustersList extends MonitoringViewBaseTableController { + controller: class ClustersList extends MonitoringViewBaseEuiTableController { constructor($injector, $scope) { super({ diff --git a/x-pack/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.js index 554aaaea319696..54164b06ce09be 100644 --- a/x-pack/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.js @@ -50,7 +50,9 @@ uiRoutes.when('/elasticsearch/ccr/:index/shard/:shardId', { this.renderReact = (props) => { super.renderReact( - + + + ); }; } diff --git a/x-pack/plugins/monitoring/public/views/elasticsearch/index/advanced/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/index/advanced/index.html index 72c1b450dd6404..2abb73d52adb68 100644 --- a/x-pack/plugins/monitoring/public/views/elasticsearch/index/advanced/index.html +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/index/advanced/index.html @@ -4,21 +4,5 @@ resolver="{{ indexName }}" page="advanced" > - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/x-pack/plugins/monitoring/public/views/elasticsearch/index/advanced/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/index/advanced/index.js index c011e8540c5f10..8f575b7809e732 100644 --- a/x-pack/plugins/monitoring/public/views/elasticsearch/index/advanced/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/index/advanced/index.js @@ -7,12 +7,17 @@ /** * Controller for Advanced Index Detail */ +import React from 'react'; +import { render } from 'react-dom'; import { find } from 'lodash'; import uiRoutes from 'ui/routes'; import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; import template from './index.html'; import { timefilter } from 'ui/timefilter'; +import { AdvancedIndex } from '../../../../components/elasticsearch/index/advanced'; +import { I18nProvider } from '@kbn/i18n/react'; +import moment from 'moment'; function getPageData($injector) { const globalState = $injector.get('globalState'); @@ -75,5 +80,28 @@ uiRoutes.when('/elasticsearch/indices/:index/advanced', { $executor.start($scope); $scope.$on('$destroy', $executor.destroy); + + function onBrush({ xaxis }) { + timefilter.setTime({ + from: moment(xaxis.from), + to: moment(xaxis.to), + mode: 'absolute', + }); + } + + this.renderReact = () => { + render( + + + , + document.getElementById('monitoringElasticsearchAdvancedIndexApp') + ); + }; + + $scope.$watch('pageData', this.renderReact); } }); diff --git a/x-pack/plugins/monitoring/public/views/elasticsearch/index/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/index/index.html index d7c201da9d0dd5..87bdcd5c160374 100644 --- a/x-pack/plugins/monitoring/public/views/elasticsearch/index/index.html +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/index/index.html @@ -5,24 +5,5 @@ resolver="{{ indexName }}" page="overview" > - - -
-
-
-
-
-
-
-
-
-
- - +
diff --git a/x-pack/plugins/monitoring/public/views/elasticsearch/index/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/index/index.js index 12b2e961ceea95..7727239906af06 100644 --- a/x-pack/plugins/monitoring/public/views/elasticsearch/index/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/index/index.js @@ -7,12 +7,19 @@ /** * Controller for single index detail */ +import React from 'react'; +import { render } from 'react-dom'; import { find } from 'lodash'; +import moment from 'moment'; import uiRoutes from 'ui/routes'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; import template from './index.html'; import { timefilter } from 'ui/timefilter'; +import { I18nProvider } from '@kbn/i18n/react'; +import { labels } from '../../../components/elasticsearch/shard_allocation/lib/labels'; +import { indicesByNodes } from '../../../components/elasticsearch/shard_allocation/transformers/indices_by_nodes'; +import { Index } from '../../../components/elasticsearch/index/index'; function getPageData($injector) { const $http = $injector.get('$http'); @@ -51,6 +58,7 @@ uiRoutes.when('/elasticsearch/indices/:index', { timefilter.enableAutoRefreshSelector(); const $route = $injector.get('$route'); + const kbnUrl = $injector.get('kbnUrl'); const globalState = $injector.get('globalState'); $scope.cluster = find($route.current.locals.clusters, { cluster_uuid: globalState.cluster_uuid }); $scope.pageData = $route.current.locals.pageData; @@ -75,5 +83,39 @@ uiRoutes.when('/elasticsearch/indices/:index', { $executor.start($scope); $scope.$on('$destroy', $executor.destroy); + + function onBrush({ xaxis }) { + timefilter.setTime({ + from: moment(xaxis.from), + to: moment(xaxis.to), + mode: 'absolute', + }); + } + + const transformer = indicesByNodes(); + this.renderReact = () => { + const shards = $scope.pageData.shards; + $scope.totalCount = shards.length; + $scope.showing = transformer(shards, $scope.pageData.nodes); + if (shards.some((shard) => shard.state === 'UNASSIGNED')) { + $scope.labels = labels.indexWithUnassigned; + } else { + $scope.labels = labels.index; + } + + render( + + + , + document.getElementById('monitoringElasticsearchIndexApp') + ); + }; + + $scope.$watch('pageData', this.renderReact); } }); diff --git a/x-pack/plugins/monitoring/public/views/elasticsearch/indices/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/indices/index.js index f8615657500d89..e91cb07169d339 100644 --- a/x-pack/plugins/monitoring/public/views/elasticsearch/indices/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/indices/index.js @@ -8,7 +8,7 @@ import React from 'react'; import { find } from 'lodash'; import uiRoutes from 'ui/routes'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; -import { MonitoringViewBaseTableController } from '../../'; +import { MonitoringViewBaseEuiTableController } from '../../'; import { ElasticsearchIndices } from '../../../components'; import template from './index.html'; import { I18nProvider } from '@kbn/i18n/react'; @@ -22,7 +22,7 @@ uiRoutes.when('/elasticsearch/indices', { } }, controllerAs: 'elasticsearchIndices', - controller: class ElasticsearchIndicesController extends MonitoringViewBaseTableController { + controller: class ElasticsearchIndicesController extends MonitoringViewBaseEuiTableController { constructor($injector, $scope, i18n) { const $route = $injector.get('$route'); const globalState = $injector.get('globalState'); @@ -69,6 +69,9 @@ uiRoutes.when('/elasticsearch/indices', { indices={indices} showSystemIndices={showSystemIndices} toggleShowSystemIndices={toggleShowSystemIndices} + sorting={this.sorting} + pagination={this.pagination} + onTableChange={this.onTableChange} />
); diff --git a/x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.html index 61aa9e49317da9..b20c927841d4fa 100644 --- a/x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.html +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.html @@ -1,18 +1,9 @@ - -
-

- -
+
diff --git a/x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.js index 579b84081c3699..d8b3a7bc7a604b 100644 --- a/x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.js @@ -7,7 +7,7 @@ import { find } from 'lodash'; import uiRoutes from 'ui/routes'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; -import { MonitoringViewBaseTableController } from '../../'; +import { MonitoringViewBaseEuiTableController } from '../../'; import { getPageData } from './get_page_data'; import template from './index.html'; @@ -21,7 +21,7 @@ uiRoutes.when('/elasticsearch/ml_jobs', { pageData: getPageData }, controllerAs: 'mlJobs', - controller: class MlJobsList extends MonitoringViewBaseTableController { + controller: class MlJobsList extends MonitoringViewBaseEuiTableController { constructor($injector, $scope, i18n) { super({ diff --git a/x-pack/plugins/monitoring/public/views/elasticsearch/node/advanced/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/node/advanced/index.html index 4256c5bb5377b1..c79c4eed46bb73 100644 --- a/x-pack/plugins/monitoring/public/views/elasticsearch/node/advanced/index.html +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/node/advanced/index.html @@ -7,25 +7,5 @@ tab-icon-class="{{ pageData.nodeSummary.nodeTypeClass }}" tab-icon-class="{{ pageData.nodeSummary.nodeTypeLabel }}" > - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/x-pack/plugins/monitoring/public/views/elasticsearch/node/advanced/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/node/advanced/index.js index 9a323cd8e5564d..e48c12e06aefa5 100644 --- a/x-pack/plugins/monitoring/public/views/elasticsearch/node/advanced/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/node/advanced/index.js @@ -7,12 +7,17 @@ /** * Controller for Advanced Node Detail */ +import React from 'react'; +import { render } from 'react-dom'; import { find } from 'lodash'; import uiRoutes from 'ui/routes'; import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; import template from './index.html'; import { timefilter } from 'ui/timefilter'; +import { I18nProvider } from '@kbn/i18n/react'; +import { AdvancedNode } from '../../../../components/elasticsearch/node/advanced'; +import moment from 'moment'; function getPageData($injector) { const $http = $injector.get('$http'); @@ -76,5 +81,28 @@ uiRoutes.when('/elasticsearch/nodes/:node/advanced', { $executor.start($scope); $scope.$on('$destroy', $executor.destroy); + + function onBrush({ xaxis }) { + timefilter.setTime({ + from: moment(xaxis.from), + to: moment(xaxis.to), + mode: 'absolute', + }); + } + + this.renderReact = () => { + render( + + + , + document.getElementById('monitoringElasticsearchAdvancedNodeApp') + ); + }; + + $scope.$watch('pageData', this.renderReact); } }); diff --git a/x-pack/plugins/monitoring/public/views/elasticsearch/node/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/node/index.html index 5aca1c9625a150..ce43bed5310110 100644 --- a/x-pack/plugins/monitoring/public/views/elasticsearch/node/index.html +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/node/index.html @@ -7,25 +7,5 @@ tab-icon-class="{{ pageData.nodeSummary.nodeTypeClass }}" tab-icon-class="{{ pageData.nodeSummary.nodeTypeLabel }}" > - - -
-
-
-
-
-
-
-
-
-
- - +
diff --git a/x-pack/plugins/monitoring/public/views/elasticsearch/node/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/node/index.js index 0e6825fefe002b..52c3e310a656d3 100644 --- a/x-pack/plugins/monitoring/public/views/elasticsearch/node/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/node/index.js @@ -7,12 +7,19 @@ /** * Controller for Node Detail */ +import React from 'react'; +import { render } from 'react-dom'; import { find, partial } from 'lodash'; import uiRoutes from 'ui/routes'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; import { getPageData } from './get_page_data'; import template from './index.html'; import { timefilter } from 'ui/timefilter'; +import { Node } from '../../../components/elasticsearch/node/node'; +import { I18nProvider } from '@kbn/i18n/react'; +import { labels } from '../../../components/elasticsearch/shard_allocation/lib/labels'; +import { nodesByIndices } from '../../../components/elasticsearch/shard_allocation/transformers/nodes_by_indices'; +import moment from 'moment'; uiRoutes.when('/elasticsearch/nodes/:node', { template, @@ -28,6 +35,7 @@ uiRoutes.when('/elasticsearch/nodes/:node', { timefilter.enableAutoRefreshSelector(); const $route = $injector.get('$route'); + const kbnUrl = $injector.get('kbnUrl'); const globalState = $injector.get('globalState'); $scope.cluster = find($route.current.locals.clusters, { cluster_uuid: globalState.cluster_uuid }); $scope.pageData = $route.current.locals.pageData; @@ -65,5 +73,35 @@ uiRoutes.when('/elasticsearch/nodes/:node', { $executor.start($scope); $scope.$on('$destroy', $executor.destroy); + + function onBrush({ xaxis }) { + timefilter.setTime({ + from: moment(xaxis.from), + to: moment(xaxis.to), + mode: 'absolute', + }); + } + + const transformer = nodesByIndices(); + this.renderReact = () => { + const shards = $scope.pageData.shards; + $scope.totalCount = shards.length; + $scope.showing = transformer(shards, $scope.pageData.nodes); + $scope.labels = labels.node; + + render( + + + , + document.getElementById('monitoringElasticsearchNodeApp') + ); + }; + + $scope.$watch('pageData', this.renderReact); } }); diff --git a/x-pack/plugins/monitoring/public/views/elasticsearch/nodes/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/nodes/index.js index ba36c490a737c3..472be27a00cbfe 100644 --- a/x-pack/plugins/monitoring/public/views/elasticsearch/nodes/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/nodes/index.js @@ -9,7 +9,7 @@ import { find } from 'lodash'; import uiRoutes from 'ui/routes'; import template from './index.html'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; -import { MonitoringViewBaseTableController } from '../../'; +import { MonitoringViewBaseEuiTableController } from '../../'; import { ElasticsearchNodes } from '../../../components'; import { I18nProvider } from '@kbn/i18n/react'; @@ -22,7 +22,7 @@ uiRoutes.when('/elasticsearch/nodes', { } }, controllerAs: 'elasticsearchNodes', - controller: class ElasticsearchNodesController extends MonitoringViewBaseTableController { + controller: class ElasticsearchNodesController extends MonitoringViewBaseEuiTableController { constructor($injector, $scope, i18n) { const $route = $injector.get('$route'); const globalState = $injector.get('globalState'); @@ -55,6 +55,9 @@ uiRoutes.when('/elasticsearch/nodes', { clusterStatus={clusterStatus} nodes={nodes} showCgroupMetricsElasticsearch={showCgroupMetricsElasticsearch} + sorting={this.sorting} + pagination={this.pagination} + onTableChange={this.onTableChange} /> ); diff --git a/x-pack/plugins/monitoring/public/views/index.js b/x-pack/plugins/monitoring/public/views/index.js index 0e0d9b9a03852a..f696ba42b262fe 100644 --- a/x-pack/plugins/monitoring/public/views/index.js +++ b/x-pack/plugins/monitoring/public/views/index.js @@ -6,3 +6,4 @@ export { MonitoringViewBaseController } from './base_controller'; export { MonitoringViewBaseTableController } from './base_table_controller'; +export { MonitoringViewBaseEuiTableController } from './base_eui_table_controller'; diff --git a/x-pack/plugins/monitoring/public/views/kibana/instance/index.html b/x-pack/plugins/monitoring/public/views/kibana/instance/index.html index 411868ee8a56c5..8bb17839683a89 100644 --- a/x-pack/plugins/monitoring/public/views/kibana/instance/index.html +++ b/x-pack/plugins/monitoring/public/views/kibana/instance/index.html @@ -4,15 +4,5 @@ instance="{{ pageData.kibanaSummary.name }}" data-test-subj="kibanaInstancePage" > - -
-
-
-
-
-
-
-
-
-
+
diff --git a/x-pack/plugins/monitoring/public/views/kibana/instance/index.js b/x-pack/plugins/monitoring/public/views/kibana/instance/index.js index 86199bf5105155..12989568f146c8 100644 --- a/x-pack/plugins/monitoring/public/views/kibana/instance/index.js +++ b/x-pack/plugins/monitoring/public/views/kibana/instance/index.js @@ -7,12 +7,18 @@ /* * Kibana Instance */ +import React from 'react'; +import { render } from 'react-dom'; import { get, find } from 'lodash'; import uiRoutes from'ui/routes'; import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; import template from './index.html'; import { timefilter } from 'ui/timefilter'; +import { EuiPage, EuiPageBody, EuiPageContent, EuiSpacer, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { MonitoringTimeseriesContainer } from '../../../components/chart'; +import { DetailStatus } from 'plugins/monitoring/components/kibana/detail_status'; +import { I18nProvider } from '@kbn/i18n/react'; function getPageData($injector) { const $http = $injector.get('$http'); @@ -45,7 +51,7 @@ uiRoutes.when('/kibana/instances/:uuid', { }, pageData: getPageData }, - controller($injector, $scope, i18n) { + controller($injector, $scope) { timefilter.enableTimeRangeSelector(); timefilter.enableAutoRefreshSelector(); @@ -55,14 +61,7 @@ uiRoutes.when('/kibana/instances/:uuid', { $scope.pageData = $route.current.locals.pageData; const title = $injector.get('title'); - const routeTitle = i18n('xpack.monitoring.kibana.instance.routeTitle', { - defaultMessage: 'Kibana - {kibanaSummaryName}', - values: { - kibanaSummaryName: get($scope.pageData, 'kibanaSummary.name') - } - }); - - title($scope.cluster, routeTitle); + title($scope.cluster, `Kibana - ${get($scope.pageData, 'kibanaSummary.name')}`); const $executor = $injector.get('$executor'); $executor.register({ @@ -73,5 +72,66 @@ uiRoutes.when('/kibana/instances/:uuid', { $executor.start($scope); $scope.$on('$destroy', $executor.destroy); + + $scope.$watch('pageData', renderReact); + renderReact(); + + function renderReact() { + const app = document.getElementById('monitoringKibanaInstanceApp'); + if (!app) { + return; + } + + const overviewPage = ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + + render(overviewPage, app); + } } }); diff --git a/x-pack/plugins/monitoring/public/views/kibana/instances/index.html b/x-pack/plugins/monitoring/public/views/kibana/instances/index.html index dee4f1741ab477..8e1639a2323a50 100644 --- a/x-pack/plugins/monitoring/public/views/kibana/instances/index.html +++ b/x-pack/plugins/monitoring/public/views/kibana/instances/index.html @@ -3,19 +3,5 @@ name="kibanas" data-test-subj="kibanaInstancesPage" > - -
-

- -
+
diff --git a/x-pack/plugins/monitoring/public/views/kibana/instances/index.js b/x-pack/plugins/monitoring/public/views/kibana/instances/index.js index 21e03a37b9be1a..2ace7b3b4f999e 100644 --- a/x-pack/plugins/monitoring/public/views/kibana/instances/index.js +++ b/x-pack/plugins/monitoring/public/views/kibana/instances/index.js @@ -4,12 +4,111 @@ * you may not use this file except in compliance with the Elastic License. */ -import { find } from 'lodash'; +import React from 'react'; +import { render } from 'react-dom'; +import { find, capitalize } from 'lodash'; import uiRoutes from'ui/routes'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; -import { MonitoringViewBaseTableController } from '../../'; +import { MonitoringViewBaseEuiTableController } from '../../'; import { getPageData } from './get_page_data'; import template from './index.html'; +import { EuiPage, EuiPageBody, EuiPageContent, EuiSpacer, EuiLink } from '@elastic/eui'; +import { ClusterStatus } from '../../../components/kibana/cluster_status'; +import { EuiMonitoringTable } from '../../../components/table'; +import { KibanaStatusIcon } from '../../../components/kibana/status_icon'; +import { formatMetric, formatNumber } from '../../../lib/format_number'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; + +const getColumns = (kbnUrl, scope) => ([ + { + name: i18n.translate('xpack.monitoring.kibana.listing.nameColumnTitle', { + defaultMessage: 'Name' + }), + field: 'kibana.name', + render: (name, kibana) => ( + { + scope.$evalAsync(() => { + kbnUrl.changePath(`/kibana/instances/${kibana.kibana.uuid}`); + }); + }} + data-test-subj={`kibanaLink-${name}`} + > + { name } + + ) + }, + { + name: i18n.translate('xpack.monitoring.kibana.listing.statusColumnTitle', { + defaultMessage: 'Status' + }), + field: 'kibana.status', + render: (status, kibana) => ( +
+   + { !kibana.availability ? ( + + ) : capitalize(status) } +
+ ) + }, + { + name: i18n.translate('xpack.monitoring.kibana.listing.loadAverageColumnTitle', { + defaultMessage: 'Load Average' + }), + field: 'os.load.1m', + render: value => ( + + {formatMetric(value, '0.00')} + + ) + }, + { + name: i18n.translate('xpack.monitoring.kibana.listing.memorySizeColumnTitle', { + defaultMessage: 'Memory Size' + }), + field: 'process.memory.resident_set_size_in_bytes', + render: value => ( + + {formatNumber(value, 'byte')} + + ) + }, + { + name: i18n.translate('xpack.monitoring.kibana.listing.requestsColumnTitle', { + defaultMessage: 'Requests' + }), + field: 'requests.total', + render: value => ( + + {formatNumber(value, 'int_commas')} + + ) + }, + { + name: i18n.translate('xpack.monitoring.kibana.listing.responseTimeColumnTitle', { + defaultMessage: 'Response Times' + }), + field: 'response_times.average', + render: (value, kibana) => ( +
+
+ { value && (formatNumber(value, 'int_commas') + ' ms avg') } +
+
+ { formatNumber(kibana.response_times.max, 'int_commas') } ms max +
+
+ ) + } +]); uiRoutes.when('/kibana/instances', { template, @@ -21,13 +120,11 @@ uiRoutes.when('/kibana/instances', { pageData: getPageData, }, controllerAs: 'kibanas', - controller: class KibanaInstancesList extends MonitoringViewBaseTableController { + controller: class KibanaInstancesList extends MonitoringViewBaseEuiTableController { - constructor($injector, $scope, i18n) { + constructor($injector, $scope) { super({ - title: i18n('xpack.monitoring.kibana.instances.routeTitle', { - defaultMessage: 'Kibana Instances' - }), + title: 'Kibana Instances', storageKey: 'kibana.instances', getPageData, $scope, @@ -39,6 +136,56 @@ uiRoutes.when('/kibana/instances', { const globalState = $injector.get('globalState'); $scope.cluster = find($route.current.locals.clusters, { cluster_uuid: globalState.cluster_uuid }); $scope.pageData = $route.current.locals.pageData; + + const kbnUrl = $injector.get('kbnUrl'); + + const renderReact = () => { + const app = document.getElementById('monitoringKibanaInstancesApp'); + if (!app) { + return; + } + + const page = ( + + + + + + + + + + + + + ); + + render(page, app); + }; + + $scope.$watch('data', () => renderReact()); + renderReact(); } } }); diff --git a/x-pack/plugins/monitoring/public/views/kibana/overview/index.html b/x-pack/plugins/monitoring/public/views/kibana/overview/index.html index 46f7174ffd67fd..5b131e113dfa49 100644 --- a/x-pack/plugins/monitoring/public/views/kibana/overview/index.html +++ b/x-pack/plugins/monitoring/public/views/kibana/overview/index.html @@ -3,11 +3,5 @@ name="overview" data-test-subj="kibanaOverviewPage" > - -
-
-
-
-
-
+
diff --git a/x-pack/plugins/monitoring/public/views/kibana/overview/index.js b/x-pack/plugins/monitoring/public/views/kibana/overview/index.js index e9e22d1510fb5a..442822ad04836a 100644 --- a/x-pack/plugins/monitoring/public/views/kibana/overview/index.js +++ b/x-pack/plugins/monitoring/public/views/kibana/overview/index.js @@ -7,12 +7,18 @@ /** * Kibana Overview */ +import React from 'react'; +import { render } from 'react-dom'; import { find } from 'lodash'; import uiRoutes from'ui/routes'; +import { MonitoringTimeseriesContainer } from '../../../components/chart'; import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; import template from './index.html'; import { timefilter } from 'ui/timefilter'; +import { EuiPage, EuiPageBody, EuiPageContent, EuiSpacer, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { ClusterStatus } from '../../../components/kibana/cluster_status'; +import { I18nProvider } from '@kbn/i18n/react'; function getPageData($injector) { const $http = $injector.get('$http'); @@ -44,7 +50,7 @@ uiRoutes.when('/kibana', { }, pageData: getPageData }, - controller($injector, $scope, i18n) { + controller($injector, $scope) { timefilter.enableTimeRangeSelector(); timefilter.enableAutoRefreshSelector(); @@ -54,11 +60,7 @@ uiRoutes.when('/kibana', { $scope.pageData = $route.current.locals.pageData; const title = $injector.get('title'); - const routeTitle = i18n('xpack.monitoring.kibana.overview.routeTitle', { - defaultMessage: 'Kibana' - }); - - title($scope.cluster, routeTitle); + title($scope.cluster, 'Kibana'); const $executor = $injector.get('$executor'); $executor.register({ @@ -69,5 +71,43 @@ uiRoutes.when('/kibana', { $executor.start($scope); $scope.$on('$destroy', $executor.destroy); + + $scope.$watch('pageData', renderReact); + renderReact(); + + function renderReact() { + const app = document.getElementById('monitoringKibanaOverviewApp'); + if (!app) { + return; + } + + const overviewPage = ( + + + + + + + + + + + + + + + + + + + + ); + + render(overviewPage, app); + } } }); diff --git a/x-pack/plugins/monitoring/public/views/logstash/nodes/index.html b/x-pack/plugins/monitoring/public/views/logstash/nodes/index.html index 8385a12a92e839..6da00b1c771b8e 100644 --- a/x-pack/plugins/monitoring/public/views/logstash/nodes/index.html +++ b/x-pack/plugins/monitoring/public/views/logstash/nodes/index.html @@ -1,19 +1,3 @@ - -
-

-

- -
+
diff --git a/x-pack/plugins/monitoring/public/views/logstash/nodes/index.js b/x-pack/plugins/monitoring/public/views/logstash/nodes/index.js index 7f614ab22572e2..c86320491c9160 100644 --- a/x-pack/plugins/monitoring/public/views/logstash/nodes/index.js +++ b/x-pack/plugins/monitoring/public/views/logstash/nodes/index.js @@ -3,13 +3,16 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import React from 'react'; +import { render } from 'react-dom'; import { find } from 'lodash'; import uiRoutes from'ui/routes'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; -import { MonitoringViewBaseTableController } from '../../'; +import { MonitoringViewBaseEuiTableController } from '../../'; import { getPageData } from './get_page_data'; import template from './index.html'; +import { I18nProvider } from '@kbn/i18n/react'; +import { Listing } from '../../../components/logstash/listing'; uiRoutes.when('/logstash/nodes', { template, @@ -21,13 +24,11 @@ uiRoutes.when('/logstash/nodes', { pageData: getPageData }, controllerAs: 'lsNodes', - controller: class LsNodesList extends MonitoringViewBaseTableController { + controller: class LsNodesList extends MonitoringViewBaseEuiTableController { - constructor($injector, $scope, i18n) { + constructor($injector, $scope) { super({ - title: i18n('xpack.monitoring.logstash.nodes.routeTitle', { - defaultMessage: 'Logstash - Nodes' - }), + title: 'Logstash - Nodes', storageKey: 'logstash.nodes', getPageData, $scope, @@ -35,9 +36,34 @@ uiRoutes.when('/logstash/nodes', { }); const $route = $injector.get('$route'); + const kbnUrl = $injector.get('kbnUrl'); this.data = $route.current.locals.pageData; const globalState = $injector.get('globalState'); $scope.cluster = find($route.current.locals.clusters, { cluster_uuid: globalState.cluster_uuid }); + + const renderReact = (data) => { + if (!data) { + return; + } + + render( + + + , + document.getElementById('monitoringLogstashNodesApp') + ); + }; + + $scope.$watch(() => this.data, data => { + renderReact(data); + }); } } }); diff --git a/x-pack/plugins/monitoring/public/views/logstash/overview/index.html b/x-pack/plugins/monitoring/public/views/logstash/overview/index.html index 6c8f53ac5f96bf..088aa35892bbee 100644 --- a/x-pack/plugins/monitoring/public/views/logstash/overview/index.html +++ b/x-pack/plugins/monitoring/public/views/logstash/overview/index.html @@ -1,10 +1,3 @@ - -
-
-
-
-
-
-
+
diff --git a/x-pack/plugins/monitoring/public/views/logstash/overview/index.js b/x-pack/plugins/monitoring/public/views/logstash/overview/index.js index 19ad7fe50c0a87..749f0da9155e8a 100644 --- a/x-pack/plugins/monitoring/public/views/logstash/overview/index.js +++ b/x-pack/plugins/monitoring/public/views/logstash/overview/index.js @@ -7,12 +7,16 @@ /** * Logstash Overview */ +import React from 'react'; +import { render } from 'react-dom'; import { find } from 'lodash'; import uiRoutes from'ui/routes'; import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; import template from './index.html'; import { timefilter } from 'ui/timefilter'; +import { I18nProvider } from '@kbn/i18n/react'; +import { Overview } from '../../../components/logstash/overview'; function getPageData($injector) { const $http = $injector.get('$http'); @@ -44,7 +48,7 @@ uiRoutes.when('/logstash', { }, pageData: getPageData }, - controller($injector, $scope, i18n) { + controller($injector, $scope) { timefilter.enableTimeRangeSelector(); timefilter.enableAutoRefreshSelector(); @@ -54,9 +58,7 @@ uiRoutes.when('/logstash', { $scope.pageData = $route.current.locals.pageData; const title = $injector.get('title'); - title($scope.cluster, i18n('xpack.monitoring.logstash.overview.routeTitle', { - defaultMessage: 'Logstash' - })); + title($scope.cluster, 'Logstash'); const $executor = $injector.get('$executor'); $executor.register({ @@ -65,5 +67,21 @@ uiRoutes.when('/logstash', { }); $executor.start($scope); $scope.$on('$destroy', $executor.destroy); + + function renderReact(pageData) { + render( + + + , + document.getElementById('monitoringLogstashOverviewApp') + ); + } + + $scope.$watch('pageData', pageData => { + renderReact(pageData); + }); } }); diff --git a/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.html b/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.html index 070c7b04cfb73b..bef8a7a4737f3a 100644 --- a/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.html +++ b/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.html @@ -3,11 +3,5 @@ name="pipelines" data-test-subj="logstashPipelinesListing" > - -
- -
+
diff --git a/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.js b/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.js index 27e68ae56976b8..1e88cc678b904a 100644 --- a/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.js +++ b/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.js @@ -4,8 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ +import React from 'react'; import { find } from 'lodash'; +import { render } from 'react-dom'; import uiRoutes from 'ui/routes'; +import moment from 'moment'; import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; import { @@ -13,6 +16,9 @@ import { } from 'plugins/monitoring/lib/logstash/pipelines'; import template from './index.html'; import { timefilter } from 'ui/timefilter'; +import { I18nProvider } from '@kbn/i18n/react'; +import { PipelineListing } from '../../../components/logstash/pipeline_listing/pipeline_listing'; +import { MonitoringViewBaseEuiTableController } from '../..'; /* * Logstash Pipelines Listing page @@ -40,16 +46,14 @@ const getPageData = ($injector) => { }); }; -function makeUpgradeMessage(logstashVersions, i18n) { +function makeUpgradeMessage(logstashVersions) { if (!Array.isArray(logstashVersions) || (logstashVersions.length === 0) || logstashVersions.some(isPipelineMonitoringSupportedInVersion)) { return null; } - return i18n('xpack.monitoring.logstash.pipelines.notAvalibleDescription', { - defaultMessage: 'Pipeline monitoring is only available in Logstash version 6.0.0 or higher.' - }); + return 'Pipeline monitoring is only available in Logstash version 6.0.0 or higher.'; } uiRoutes @@ -62,30 +66,63 @@ uiRoutes }, pageData: getPageData }, - controller($injector, $scope, i18n) { - const $route = $injector.get('$route'); - const globalState = $injector.get('globalState'); - const title = $injector.get('title'); - const $executor = $injector.get('$executor'); + controller: class LogstashPipelinesList extends MonitoringViewBaseEuiTableController { + constructor($injector, $scope, i18n) { + super({ + title: 'Logstash Pipelines', + storageKey: 'logstash.pipelines', + getPageData, + $scope, + $injector + }); - $scope.cluster = find($route.current.locals.clusters, { cluster_uuid: globalState.cluster_uuid }); - $scope.pageData = $route.current.locals.pageData; + const $route = $injector.get('$route'); + const kbnUrl = $injector.get('kbnUrl'); + this.data = $route.current.locals.pageData; + const globalState = $injector.get('globalState'); + $scope.cluster = find($route.current.locals.clusters, { cluster_uuid: globalState.cluster_uuid }); - $scope.upgradeMessage = makeUpgradeMessage($scope.pageData.clusterStatus.versions, i18n); - timefilter.enableTimeRangeSelector(); - timefilter.enableAutoRefreshSelector(); + function onBrush(xaxis) { + timefilter.setTime({ + from: moment(xaxis.from), + to: moment(xaxis.to), + mode: 'absolute' + }); + } - title($scope.cluster, i18n('xpack.monitoring.logstash.pipelines.routeTitle', { - defaultMessage: 'Logstash Pipelines' - })); + const renderReact = (pageData) => { + if (!pageData) { + return; + } - $executor.register({ - execute: () => getPageData($injector), - handleResponse: (response) => $scope.pageData = response - }); + const upgradeMessage = pageData + ? makeUpgradeMessage(pageData.clusterStatus.versions, i18n) + : null; - $executor.start($scope); + render( + + + , + document.getElementById('monitoringLogstashPipelinesApp') + ); + }; - $scope.$on('$destroy', $executor.destroy); + $scope.$watch(() => this.data, pageData => { + renderReact(pageData); + }); + } } }); diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.js b/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.js index fae1a9431135d8..0bd527523ad7dc 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.js +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.js @@ -182,6 +182,7 @@ export function getLogstashForClusters(req, lsIndexPattern, clusters) { const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); return callWithRequest(req, 'search', params) .then(result => { + const aggregations = get(result, 'aggregations', {}); const logstashUuids = get(aggregations, 'logstash_uuids.buckets', []); const logstashVersions = get(aggregations, 'logstash_versions.buckets', []); diff --git a/x-pack/test/functional/apps/monitoring/beats/listing.js b/x-pack/test/functional/apps/monitoring/beats/listing.js index 69c7a8da797c69..0194f1162511d6 100644 --- a/x-pack/test/functional/apps/monitoring/beats/listing.js +++ b/x-pack/test/functional/apps/monitoring/beats/listing.js @@ -39,8 +39,8 @@ export default function ({ getService, getPageObjects }) { duckbeat: 1, sheepbeat: 1, winlogbeat: 1, - totalEvents: '699.9k', - bytesSent: '427.9 MB', + totalEvents: 'Total Events:\n699.9k', + bytesSent: 'Bytes Sent:\n427.9 MB', }); }); diff --git a/x-pack/test/functional/apps/monitoring/beats/overview.js b/x-pack/test/functional/apps/monitoring/beats/overview.js index d0beebce8bf90f..bfd40589395680 100644 --- a/x-pack/test/functional/apps/monitoring/beats/overview.js +++ b/x-pack/test/functional/apps/monitoring/beats/overview.js @@ -43,8 +43,8 @@ export default function ({ getService, getPageObjects }) { duckbeat: 1, sheepbeat: 1, winlogbeat: 1, - totalEvents: '699.9k', - bytesSent: '427.9 MB', + totalEvents: 'Total Events:\n699.9k', + bytesSent: 'Bytes Sent:\n427.9 MB', }); }); diff --git a/x-pack/test/functional/apps/monitoring/elasticsearch/indices.js b/x-pack/test/functional/apps/monitoring/elasticsearch/indices.js index 3c9e4a1e4d0226..58ec00cf6db1a5 100644 --- a/x-pack/test/functional/apps/monitoring/elasticsearch/indices.js +++ b/x-pack/test/functional/apps/monitoring/elasticsearch/indices.js @@ -43,48 +43,8 @@ export default function ({ getService, getPageObjects }) { }); }); - it('should have an indices table with correct rows with default sorting', async () => { - const rows = await indicesList.getRows(); - expect(rows.length).to.be(20); - - const indicesAll = await indicesList.getIndicesAll(); - - const tableData = [ /*eslint-disable max-len*/ - { name: 'many-0007_milycdknpycp', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' }, - { name: 'many-0009_reolfgzjjtvh', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' }, - { name: 'many-0011_xtkcmlwmxcov', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' }, - { name: 'many-0013_smjuwdkhpduv', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' }, - { name: 'many-0015_vwmrucgzvohb', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' }, - { name: 'many-0017_zpyxggzmytun', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' }, - { name: 'many-0019_slpgftmneikv', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' }, - { name: 'many-0021_xjtlceanhvup', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' }, - { name: 'many-0023_hkbvktonytxh', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' }, - { name: 'many-0025_xmvpnfeuqxtp', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' }, - { name: 'phone-home', status: 'Health: yellow', documentCount: '1', dataSize: '66.2 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '5' }, - { name: 'many-0006_gkuqbjonkjmg', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '4.08 /s', unassignedShards: '0' }, - { name: 'many-0008_amnscruqlsnu', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '4.08 /s', unassignedShards: '0' }, - { name: 'many-0010_dgnlpqtstfvi', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' }, - { name: 'many-0012_jwomwdgfpisl', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' }, - { name: 'many-0014_zrukbrvuluby', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' }, - { name: 'many-0016_gyvtsyauoqqg', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' }, - { name: 'many-0018_ipugjcmuagih', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' }, - { name: 'many-0020_fqfovcnznbus', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' }, - { name: 'many-0022_dqbcjopzejlk', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' }, - ]; /*eslint-enable*/ - - // check the all data in the table - indicesAll.forEach((obj, index) => { - expect(indicesAll[index].name).to.be(tableData[index].name); - expect(indicesAll[index].status).to.be(tableData[index].status); - expect(indicesAll[index].documentCount).to.be(tableData[index].documentCount); - expect(indicesAll[index].dataSize).to.be(tableData[index].dataSize); - expect(indicesAll[index].indexRate).to.be(tableData[index].indexRate); - expect(indicesAll[index].searchRate).to.be(tableData[index].searchRate); - expect(indicesAll[index].unassignedShards).to.be(tableData[index].unassignedShards); - }); - }); - - it('should show indices table with correct rows after sorting by Search Rate Desc', async () => { + // Revisit once https://github.com/elastic/eui/issues/1322 is resolved + it.skip('should show indices table with correct rows after sorting by Search Rate Desc', async () => { await indicesList.clickSearchCol(); await indicesList.clickSearchCol(); diff --git a/x-pack/test/functional/apps/monitoring/elasticsearch/node_detail.js b/x-pack/test/functional/apps/monitoring/elasticsearch/node_detail.js index a5ab5a23266733..1bf5dd28277a76 100644 --- a/x-pack/test/functional/apps/monitoring/elasticsearch/node_detail.js +++ b/x-pack/test/functional/apps/monitoring/elasticsearch/node_detail.js @@ -40,7 +40,7 @@ export default function ({ getService, getPageObjects }) { await nodesList.clickRowByResolver('jUT5KdxfRbORSCWkb5zjmA'); expect(await nodeDetail.getSummary()).to.eql({ - transportAddress: '127.0.0.1:9300', + transportAddress: 'Transport Address:\n127.0.0.1:9300', jvmHeap: 'JVM Heap:\n29%', freeDiskSpace: 'Free Disk Space:\n173.9 GB', documentCount: 'Documents:\n24.8k', @@ -56,7 +56,7 @@ export default function ({ getService, getPageObjects }) { await nodesList.clickRowByResolver('bwQWH-7IQY-mFPpfoaoFXQ'); expect(await nodeDetail.getSummary()).to.eql({ - transportAddress: '127.0.0.1:9302', + transportAddress: 'Transport Address:\n127.0.0.1:9302', jvmHeap: 'JVM Heap:\n17%', freeDiskSpace: 'Free Disk Space:\n173.9 GB', documentCount: 'Documents:\n240', @@ -91,7 +91,7 @@ export default function ({ getService, getPageObjects }) { await nodesList.clickRowByResolver('1jxg5T33TWub-jJL4qP0Wg'); expect(await nodeDetail.getSummary()).to.eql({ - transportAddress: '127.0.0.1:9302', + transportAddress: 'Transport Address:\n127.0.0.1:9302', jvmHeap: 'JVM Heap:\nN/A', freeDiskSpace: 'Free Disk Space:\nN/A', documentCount: 'Documents:\nN/A', diff --git a/x-pack/test/functional/apps/monitoring/elasticsearch/nodes.js b/x-pack/test/functional/apps/monitoring/elasticsearch/nodes.js index 1919bca3bffa02..c20050c9b4bc07 100644 --- a/x-pack/test/functional/apps/monitoring/elasticsearch/nodes.js +++ b/x-pack/test/functional/apps/monitoring/elasticsearch/nodes.js @@ -50,8 +50,24 @@ export default function ({ getService, getPageObjects }) { const nodesAll = await nodesList.getNodesAll(); const tableData = [ - { name: 'whatever-01', status: 'Status: Online', cpu: '0%', load: '3.28', memory: '39%', disk: '173.9 GB', shards: '38', }, - { name: 'whatever-02', status: 'Status: Online', cpu: '2%', load: '3.28', memory: '25%', disk: '173.9 GB', shards: '38', }, + { + name: 'whatever-01', + status: 'Status: Online', + cpu: '0% \n3% max\n0% min', + load: '3.28 \n3.71 max\n2.19 min', + memory: '39% \n52% max\n25% min', + disk: '173.9 GB \n173.9 GB max\n173.9 GB min', + shards: '38', + }, + { + name: 'whatever-02', + status: 'Status: Online', + cpu: '2% \n3% max\n0% min', + load: '3.28 \n3.73 max\n2.29 min', + memory: '25% \n49% max\n25% min', + disk: '173.9 GB \n173.9 GB max\n173.9 GB min', + shards: '38', + }, { name: 'whatever-03', status: 'Status: Offline' }, ]; nodesAll.forEach((obj, node) => { @@ -100,7 +116,7 @@ export default function ({ getService, getPageObjects }) { await nodesList.clickCpuCol(); const nodesAll = await nodesList.getNodesAll(); - const tableData = [{ cpu: '0%' }, { cpu: '2%' }, { cpu: undefined }]; + const tableData = [{ cpu: '0% \n3% max\n0% min' }, { cpu: '2% \n3% max\n0% min' }, { cpu: undefined }]; nodesAll.forEach((obj, node) => { expect(nodesAll[node].cpu).to.be(tableData[node].cpu); }); @@ -112,8 +128,8 @@ export default function ({ getService, getPageObjects }) { const nodesAll = await nodesList.getNodesAll(); const tableData = [ - { load: '3.28' }, - { load: '3.28' }, + { load: '3.28 \n3.71 max\n2.19 min' }, + { load: '3.28 \n3.73 max\n2.29 min' }, { load: undefined }, ]; nodesAll.forEach((obj, node) => { @@ -127,8 +143,8 @@ export default function ({ getService, getPageObjects }) { const nodesAll = await nodesList.getNodesAll(); const tableData = [ - { memory: '39%' }, - { memory: '25%' }, + { memory: '39% \n52% max\n25% min' }, + { memory: '25% \n49% max\n25% min' }, { memory: undefined }, ]; nodesAll.forEach((obj, node) => { @@ -142,8 +158,8 @@ export default function ({ getService, getPageObjects }) { const nodesAll = await nodesList.getNodesAll(); const tableData = [ - { disk: '173.9 GB' }, - { disk: '173.9 GB' }, + { disk: '173.9 GB \n173.9 GB max\n173.9 GB min' }, + { disk: '173.9 GB \n173.9 GB max\n173.9 GB min' }, { disk: undefined }, ]; nodesAll.forEach((obj, node) => { @@ -198,7 +214,8 @@ export default function ({ getService, getPageObjects }) { }); }); - it('should filter for specific indices', async () => { + // Skip until https://github.com/elastic/eui/issues/1318 is implemented + it.skip('should filter for specific indices', async () => { await nodesList.setFilter('01'); const rows = await nodesList.getRows(); expect(rows.length).to.be(1); diff --git a/x-pack/test/functional/page_objects/monitoring_page.js b/x-pack/test/functional/page_objects/monitoring_page.js index 12f148d255ebe4..9eef3dff01bbad 100644 --- a/x-pack/test/functional/page_objects/monitoring_page.js +++ b/x-pack/test/functional/page_objects/monitoring_page.js @@ -30,11 +30,25 @@ export function MonitoringPageProvider({ getPageObjects, getService }) { }); } + async assertEuiTableNoData(subj) { + await retry.try(async () => { + if (await testSubjects.exists(subj)) { + throw new Error('Expected to find the no data message'); + } + }); + } + async tableGetRows(subj) { const table = await testSubjects.find(subj); return table.findAllByTagName('tr'); } + async tableGetRowsFromContainer(subj) { + const table = await testSubjects.find(subj); + const tbody = await table.findByTagName('tbody'); + return tbody.findAllByTagName('tr'); + } + async tableSetFilter(subj, text) { return await testSubjects.setValue(subj, text); } diff --git a/x-pack/test/functional/services/monitoring/beats_listing.js b/x-pack/test/functional/services/monitoring/beats_listing.js index 505c0238b54586..3e61f1ea299197 100644 --- a/x-pack/test/functional/services/monitoring/beats_listing.js +++ b/x-pack/test/functional/services/monitoring/beats_listing.js @@ -15,8 +15,7 @@ export function MonitoringBeatsListingProvider({ getService, getPageObjects }) { const SUBJ_TABLE_CONTAINER = 'beatsTableContainer'; const SUBJ_SEARCH_BAR = `${SUBJ_TABLE_CONTAINER} monitoringTableToolBar`; - const SUBJ_TABLE_BODY = 'beatsTableBody'; - const SUBJ_INDEX_LINK_PREFIX = `${SUBJ_TABLE_BODY} beatLink-`; + const SUBJ_INDEX_LINK_PREFIX = `${SUBJ_TABLE_CONTAINER} beatLink-`; return new class BeatsListing { diff --git a/x-pack/test/functional/services/monitoring/cluster_alerts.js b/x-pack/test/functional/services/monitoring/cluster_alerts.js index a47af62bfbdcd4..6b51380600f047 100644 --- a/x-pack/test/functional/services/monitoring/cluster_alerts.js +++ b/x-pack/test/functional/services/monitoring/cluster_alerts.js @@ -23,8 +23,7 @@ export function MonitoringClusterAlertsProvider({ getService, getPageObjects }) const SUBJ_OVERVIEW_ACTIONS = `${SUBJ_OVERVIEW_CLUSTER_ALERTS} alertAction`; const SUBJ_OVERVIEW_VIEW_ALL = `${SUBJ_OVERVIEW_CLUSTER_ALERTS} viewAllAlerts`; - const SUBJ_LISTING_PAGE = 'clusterAlertsListingPage'; - const SUBJ_TABLE_BODY = 'alertsTableBody'; + const SUBJ_TABLE_BODY = 'alertsTableContainer'; const SUBJ_TABLE_ICONS = `${SUBJ_TABLE_BODY} alertIcon`; const SUBJ_TABLE_TEXTS = `${SUBJ_TABLE_BODY} alertText`; const SUBJ_TABLE_ACTIONS = `${SUBJ_TABLE_BODY} alertAction`; @@ -91,12 +90,12 @@ export function MonitoringClusterAlertsProvider({ getService, getPageObjects }) */ async isOnListingPage() { - const pageId = await retry.try(() => testSubjects.find(SUBJ_LISTING_PAGE)); + const pageId = await retry.try(() => testSubjects.find(SUBJ_TABLE_BODY)); return pageId !== null; } getTableAlerts() { - return PageObjects.monitoring.tableGetRows(SUBJ_TABLE_BODY); + return PageObjects.monitoring.tableGetRowsFromContainer(SUBJ_TABLE_BODY); } async getTableAlertsAll() { diff --git a/x-pack/test/functional/services/monitoring/cluster_list.js b/x-pack/test/functional/services/monitoring/cluster_list.js index a4e29c60e4b10e..a157cf97827bb9 100644 --- a/x-pack/test/functional/services/monitoring/cluster_list.js +++ b/x-pack/test/functional/services/monitoring/cluster_list.js @@ -10,7 +10,6 @@ export function MonitoringClusterListProvider({ getService, getPageObjects }) { const PageObjects = getPageObjects(['monitoring']); const SUBJ_TABLE_CONTAINER = 'clusterTableContainer'; - const SUBJ_TABLE_BODY = 'clusterTableBody'; const SUBJ_TABLE_NO_DATA = `${SUBJ_TABLE_CONTAINER} monitoringTableNoData`; const SUBJ_SEARCH_BAR = `${SUBJ_TABLE_CONTAINER} monitoringTableToolBar`; @@ -27,11 +26,11 @@ export function MonitoringClusterListProvider({ getService, getPageObjects }) { } assertNoData() { - return PageObjects.monitoring.assertTableNoData(SUBJ_TABLE_NO_DATA); + return PageObjects.monitoring.assertEuiTableNoData(SUBJ_TABLE_NO_DATA); } getRows() { - return PageObjects.monitoring.tableGetRows(SUBJ_TABLE_BODY); + return PageObjects.monitoring.tableGetRowsFromContainer(SUBJ_TABLE_CONTAINER); } setFilter(text) { diff --git a/x-pack/test/functional/services/monitoring/elasticsearch_indices.js b/x-pack/test/functional/services/monitoring/elasticsearch_indices.js index a57c5883dd8e22..fa1995d61b6b08 100644 --- a/x-pack/test/functional/services/monitoring/elasticsearch_indices.js +++ b/x-pack/test/functional/services/monitoring/elasticsearch_indices.js @@ -17,18 +17,17 @@ export function MonitoringElasticsearchIndicesProvider({ getService, getPageObje const SUBJ_TABLE_NO_DATA = `${SUBJ_TABLE_CONTAINER} monitoringTableNoData`; const SUBJ_SEARCH_BAR = `${SUBJ_TABLE_CONTAINER} monitoringTableToolBar`; - const SUBJ_TABLE_SORT_SEARCH_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell-searchRate`; + const SUBJ_TABLE_SORT_SEARCH_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell_search_rate_5`; - const SUBJ_TABLE_BODY = 'elasticsearchIndicesTableBody'; - const SUBJ_INDICES_NAMES = `${SUBJ_TABLE_BODY} name`; - const SUBJ_INDICES_STATUSES = `${SUBJ_TABLE_BODY} statusIcon`; - const SUBJ_INDICES_DOCUMENT_COUNTS = `${SUBJ_TABLE_BODY} documentCount`; - const SUBJ_INDICES_DATA_SIZES = `${SUBJ_TABLE_BODY} dataSize`; - const SUBJ_INDICES_INDEX_RATES = `${SUBJ_TABLE_BODY} indexRate`; - const SUBJ_INDICES_SEARCH_RATES = `${SUBJ_TABLE_BODY} searchRate`; - const SUBJ_INDICES_UNASSIGNED_SHARD_COUNTS = `${SUBJ_TABLE_BODY} unassignedShards`; + const SUBJ_INDICES_NAMES = `${SUBJ_TABLE_CONTAINER} name`; + const SUBJ_INDICES_STATUSES = `${SUBJ_TABLE_CONTAINER} statusIcon`; + const SUBJ_INDICES_DOCUMENT_COUNTS = `${SUBJ_TABLE_CONTAINER} documentCount`; + const SUBJ_INDICES_DATA_SIZES = `${SUBJ_TABLE_CONTAINER} dataSize`; + const SUBJ_INDICES_INDEX_RATES = `${SUBJ_TABLE_CONTAINER} indexRate`; + const SUBJ_INDICES_SEARCH_RATES = `${SUBJ_TABLE_CONTAINER} searchRate`; + const SUBJ_INDICES_UNASSIGNED_SHARD_COUNTS = `${SUBJ_TABLE_CONTAINER} unassignedShards`; - const SUBJ_INDEX_LINK_PREFIX = `${SUBJ_TABLE_BODY} indexLink-`; + const SUBJ_INDEX_LINK_PREFIX = `${SUBJ_TABLE_CONTAINER} indexLink-`; return new class ElasticsearchIndices { async isOnListing() { @@ -43,11 +42,11 @@ export function MonitoringElasticsearchIndicesProvider({ getService, getPageObje } assertNoData() { - return PageObjects.monitoring.assertTableNoData(SUBJ_TABLE_NO_DATA); + return PageObjects.monitoring.assertEuiTableNoData(SUBJ_TABLE_NO_DATA); } getRows() { - return PageObjects.monitoring.tableGetRows(SUBJ_TABLE_BODY); + return PageObjects.monitoring.tableGetRowsFromContainer(SUBJ_TABLE_CONTAINER); } setFilter(text) { diff --git a/x-pack/test/functional/services/monitoring/elasticsearch_nodes.js b/x-pack/test/functional/services/monitoring/elasticsearch_nodes.js index 6b7f9cdcc2d241..47863a83077d98 100644 --- a/x-pack/test/functional/services/monitoring/elasticsearch_nodes.js +++ b/x-pack/test/functional/services/monitoring/elasticsearch_nodes.js @@ -17,15 +17,15 @@ export function MonitoringElasticsearchNodesProvider({ getService, getPageObject const SUBJ_TABLE_NO_DATA = `${SUBJ_TABLE_CONTAINER} monitoringTableNoData`; const SUBJ_SEARCH_BAR = `${SUBJ_TABLE_CONTAINER} monitoringTableToolBar`; - const SUBJ_TABLE_SORT_NAME_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell-name`; - const SUBJ_TABLE_SORT_STATUS_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell-status`; - const SUBJ_TABLE_SORT_CPU_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell-cpuUsage`; - const SUBJ_TABLE_SORT_LOAD_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell-loadAverage`; - const SUBJ_TABLE_SORT_MEM_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell-jvmMemory`; - const SUBJ_TABLE_SORT_DISK_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell-diskFreeSpace`; - const SUBJ_TABLE_SORT_SHARDS_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell-shards`; - - const SUBJ_TABLE_BODY = 'elasticsearchNodesTableBody'; + const SUBJ_TABLE_SORT_NAME_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell_name_0`; + const SUBJ_TABLE_SORT_STATUS_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell_isOnline_1`; + const SUBJ_TABLE_SORT_CPU_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell_node_cpu_utilization_2`; + const SUBJ_TABLE_SORT_LOAD_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell_node_load_average_3`; + const SUBJ_TABLE_SORT_MEM_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell_node_jvm_mem_percent_4`; + const SUBJ_TABLE_SORT_DISK_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell_node_free_space_5`; + const SUBJ_TABLE_SORT_SHARDS_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell_shardCount_6`; + + const SUBJ_TABLE_BODY = 'elasticsearchNodesTableContainer'; const SUBJ_NODES_NAMES = `${SUBJ_TABLE_BODY} name`; const SUBJ_NODES_STATUSES = `${SUBJ_TABLE_BODY} statusIcon`; const SUBJ_NODES_CPUS = `${SUBJ_TABLE_BODY} cpuUsage`; @@ -89,7 +89,7 @@ export function MonitoringElasticsearchNodesProvider({ getService, getPageObject } getRows() { - return PageObjects.monitoring.tableGetRows(SUBJ_TABLE_BODY); + return PageObjects.monitoring.tableGetRowsFromContainer(SUBJ_TABLE_BODY); } setFilter(text) { @@ -101,7 +101,7 @@ export function MonitoringElasticsearchNodesProvider({ getService, getPageObject } assertNoData() { - return PageObjects.monitoring.assertTableNoData(SUBJ_TABLE_NO_DATA); + return PageObjects.monitoring.assertEuiTableNoData(SUBJ_TABLE_NO_DATA); } async getNodesAll() { diff --git a/x-pack/test/functional/services/monitoring/kibana_instances.js b/x-pack/test/functional/services/monitoring/kibana_instances.js index feffdadbbd9f94..1153227c86751b 100644 --- a/x-pack/test/functional/services/monitoring/kibana_instances.js +++ b/x-pack/test/functional/services/monitoring/kibana_instances.js @@ -10,7 +10,7 @@ export function MonitoringKibanaInstancesProvider({ getService }) { const SUBJ_INSTANCES_PAGE = 'kibanaInstancesPage'; - const SUBJ_TABLE_BODY = 'kibanaInstancesTableBody'; + const SUBJ_TABLE_BODY = 'kibanaInstancesTableContainer'; const SUBJ_INDEX_LINK_PREFIX = `${SUBJ_TABLE_BODY} kibanaLink-`; return new class KibanaInstances { diff --git a/x-pack/test/functional/services/monitoring/logstash_pipelines.js b/x-pack/test/functional/services/monitoring/logstash_pipelines.js index 2a24e2534acbd1..be5251a748c920 100644 --- a/x-pack/test/functional/services/monitoring/logstash_pipelines.js +++ b/x-pack/test/functional/services/monitoring/logstash_pipelines.js @@ -13,16 +13,15 @@ export function MonitoringLogstashPipelinesProvider({ getService, getPageObjects const SUBJ_LISTING_PAGE = 'logstashPipelinesListing'; - const SUBJ_TABLE_CONTAINER = 'logstashPipelinesTableContainer'; + const SUBJ_TABLE_CONTAINER = 'monitoringLogstashPipelinesTableContainer'; const SUBJ_TABLE_NO_DATA = `${SUBJ_TABLE_CONTAINER} monitoringTableNoData`; const SUBJ_SEARCH_BAR = `${SUBJ_TABLE_CONTAINER} monitoringTableToolBar`; - const SUBJ_TABLE_SORT_EVENTS_EMITTED_RATE_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell-eventsEmittedRate`; + const SUBJ_TABLE_SORT_EVENTS_EMITTED_RATE_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell_latestThroughput_1`; - const SUBJ_TABLE_BODY = 'logstashPipelinesTableBody'; - const SUBJ_PIPELINES_IDS = `${SUBJ_TABLE_BODY} id`; - const SUBJ_PIPELINES_EVENTS_EMITTED_RATES = `${SUBJ_TABLE_BODY} eventsEmittedRate`; - const SUBJ_PIPELINES_NODE_COUNTS = `${SUBJ_TABLE_BODY} nodeCount`; + const SUBJ_PIPELINES_IDS = `${SUBJ_TABLE_CONTAINER} id`; + const SUBJ_PIPELINES_EVENTS_EMITTED_RATES = `${SUBJ_TABLE_CONTAINER} eventsEmittedRate`; + const SUBJ_PIPELINES_NODE_COUNTS = `${SUBJ_TABLE_CONTAINER} nodeCount`; return new class LogstashPipelines { async isOnListing() { @@ -31,7 +30,7 @@ export function MonitoringLogstashPipelinesProvider({ getService, getPageObjects } getRows() { - return PageObjects.monitoring.tableGetRows(SUBJ_TABLE_BODY); + return PageObjects.monitoring.tableGetRowsFromContainer(SUBJ_TABLE_CONTAINER); } async getPipelinesAll() { @@ -69,7 +68,7 @@ export function MonitoringLogstashPipelinesProvider({ getService, getPageObjects } assertNoData() { - return PageObjects.monitoring.assertTableNoData(SUBJ_TABLE_NO_DATA); + return PageObjects.monitoring.assertEuiTableNoData(SUBJ_TABLE_NO_DATA); } }; }