Monitoring/directives use react view elasticsearch (#19362) (#19380)

* [Monitoring/React] Make Elasticsearch directives use React component internally

* fix more functional tests

* remove TODO

* lessen loc change
This commit is contained in:
Tim Sullivan 2018-05-24 09:48:49 -07:00 committed by GitHub
parent 5830f9b9a5
commit cbad3cbe4a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 197 additions and 130 deletions

View file

@ -71,7 +71,7 @@ export function ClusterStatus({ stats }) {
children={children}
status={status}
IconComponent={IconComponent}
data-test-subj="elasticsearchSummaryStatus"
data-test-subj="elasticsearchClusterStatus"
/>
);
}

View file

@ -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, { Fragment } from 'react';
import { SummaryStatus } from '../../summary_status';
import { ElasticsearchStatusIcon } from '../status_icon';
import { formatMetric } from '../../../lib/format_number';
export function IndexDetailStatus({ stats }) {
const {
dataSize,
documents: documentCount,
totalShards,
unassignedShards,
status
} = stats;
const children = [
{
label: 'Total',
value: formatMetric(dataSize.total, '0.0 b'),
dataTestSubj: 'dataSize'
},
{
label: 'Primaries',
value: formatMetric(dataSize.primaries, '0.0 b'),
dataTestSubj: 'dataSizePrimaries'
},
{
label: 'Documents',
value: formatMetric(documentCount, '0.[0]a'),
dataTestSubj: 'documentCount'
},
{
label: 'Total Shards',
value: formatMetric(totalShards, 'int_commas'),
dataTestSubj: 'totalShards'
},
{
label: 'Unassigned Shards',
value: formatMetric(unassignedShards, 'int_commas'),
dataTestSubj: 'unassignedShards'
}
];
const IconComponent = ({ status }) => (
<Fragment>
Health: <ElasticsearchStatusIcon status={status} />
</Fragment>
);
return (
<SummaryStatus
children={children}
status={status}
IconComponent={IconComponent}
data-test-subj="elasticsearchIndexDetailStatus"
/>
);
}

View file

@ -0,0 +1,83 @@
/*
* 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, { Fragment } from 'react';
import { SummaryStatus } from '../../summary_status';
import { NodeStatusIcon } from '../node';
import { formatMetric } from '../../../lib/format_number';
export function NodeDetailStatus({ stats }) {
const {
transport_address: transportAddress,
usedHeap,
freeSpace,
documents,
dataSize,
indexCount,
totalShards,
nodeTypeLabel,
status,
isOnline,
} = stats;
const children = [
{
value: transportAddress,
dataTestSubj: 'transportAddress'
},
{
label: 'JVM Heap',
value: formatMetric(usedHeap, '0,0.[00]', '%', { prependSpace: false }),
dataTestSubj: 'jvmHeap'
},
{
label: 'Free Disk Space',
value: formatMetric(freeSpace, '0.0 b'),
dataTestSubj: 'freeDiskSpace'
},
{
label: 'Documents',
value: formatMetric(documents, '0.[0]a'),
dataTestSubj: 'documentCount'
},
{
label: 'Data',
value: formatMetric(dataSize, '0.0 b'),
dataTestSubj: 'dataSize'
},
{
label: 'Indices',
value: formatMetric(indexCount, 'int_commas'),
dataTestSubj: 'indicesCount'
},
{
label: 'Shards',
value: formatMetric(totalShards, 'int_commas'),
dataTestSubj: 'shardsCount'
},
{
label: 'Type',
value: nodeTypeLabel,
dataTestSubj: 'nodeType'
}
];
const IconComponent = ({ status, isOnline }) => (
<Fragment>
Status: <NodeStatusIcon status={status} isOnline={isOnline} />
</Fragment>
);
return (
<SummaryStatus
children={children}
status={status}
isOnline={isOnline}
IconComponent={IconComponent}
data-test-subj="elasticsearchNodeDetailStatus"
/>
);
}

View file

@ -16,7 +16,8 @@ const wrapChild = ({ label, value, dataTestSubj }, index) => (
className="monitoring-summary-status__eui-content"
data-test-subj={dataTestSubj}
>
{label}: <strong>{value}</strong>
{label ? label + ': ' : null}
<strong>{value}</strong>
</EuiFlexItem>
);
@ -28,20 +29,20 @@ const DefaultIconComponent = ({ status }) => (
</Fragment>
);
const StatusIndicator = ({ status, IconComponent }) => {
const StatusIndicator = ({ status, isOnline, IconComponent }) => {
if (isEmpty(status)) {
return null;
}
return (
<div className="monitoring-summary-status__status-indicator">
<IconComponent status={status} />{' '}
<IconComponent status={status} isOnline={isOnline} />{' '}
{capitalize(status)}
</div>
);
};
export function SummaryStatus({ children, status, IconComponent = DefaultIconComponent, ...props }) {
export function SummaryStatus({ children, status, isOnline, IconComponent = DefaultIconComponent, ...props }) {
return (
<div className="monitoring-summary-status" role="status">
<div className="monitoring-summary-status__content" {...props}>
@ -52,7 +53,7 @@ export function SummaryStatus({ children, status, IconComponent = DefaultIconCom
grow={true}
className="monitoring-summary-status__eui-content"
>
<StatusIndicator status={status} IconComponent={IconComponent} />
<StatusIndicator status={status} IconComponent={IconComponent} isOnline={isOnline} />
</EuiFlexItem>
</EuiFlexGroup>
</div>

View file

@ -1,33 +0,0 @@
<div class="monitoring-summary-status" role="status">
<div class="monitoring-summary-status__content" data-test-subj="elasticsearchSummaryStatus">
<div>Nodes:
<strong data-test-subj="nodesCount">{{ status.nodesCount }}</strong>
</div>
<div>Indices:
<strong data-test-subj="indicesCount">{{ status.indicesCount }}</strong>
</div>
<div>Memory:
<strong data-test-subj="memory">{{ status.memUsed|formatNumber:'byte' }} / {{ status.memMax|formatNumber:'byte' }}</strong>
</div>
<div>Total Shards:
<strong data-test-subj="totalShards">{{ status.totalShards }}</strong>
</div>
<div>Unassigned Shards:
<strong data-test-subj="unassignedShards">{{ status.unassignedShards }}</strong>
</div>
<div>Documents:
<strong data-test-subj="documentCount">{{ status.documentCount|formatNumber:'int_commas' }}</strong>
</div>
<div>Data:
<strong data-test-subj="dataSize">{{ status.dataSize|formatNumber:'byte' }}</strong>
</div>
<div class="monitoring-summary-status__status-indicator">
Health:
<monitoring-elasticsearch-status-icon
status="status.status"
title="Status of the Elasticsearch cluster: {{ status.status }}"
></monitoring-elasticsearch-status-icon>
{{ status.status|capitalize }}
</div>
</div>
</div>

View file

@ -4,16 +4,22 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import { render } from 'react-dom';
import { uiModules } from 'ui/modules';
import template from './index.html';
import { ClusterStatus } from 'plugins/monitoring/components/elasticsearch/cluster_status';
const uiModule = uiModules.get('monitoring/directives', []);
uiModule.directive('monitoringClusterStatusElasticsearch', () => {
return {
restrict: 'E',
template,
scope: {
status: '='
},
link(scope, $el) {
scope.$watch('status', status => {
render(<ClusterStatus stats={status} />, $el[0]);
});
}
};
});

View file

@ -1,32 +0,0 @@
<div class="monitoring-summary-status" role="status">
<div class="monitoring-summary-status__content" data-test-subj="elasticsearchIndexSummaryStatus">
<div data-test-subj="dataSize">
Total:
<strong>{{ summary.dataSize.total|formatMetric:'0.0 b' }}</strong>
</div>
<div data-test-subj="dataSizePrimaries">
Primaries:
<strong>{{ summary.dataSize.primaries|formatMetric:'0.0 b' }}</strong>
</div>
<div data-test-subj="documentCount">
Documents:
<strong>{{ summary.documents|formatMetric:'0.[0]a' }}</strong>
</div>
<div data-test-subj="totalShards">
Total Shards:
<strong>{{ summary.totalShards|formatMetric:'0,0' }}</strong>
</div>
<div data-test-subj="unassignedShards">
Unassigned Shards:
<strong>{{ summary.unassignedShards|formatMetric:'0,0' }}</strong>
</div>
<div class="monitoring-summary-status__status-indicator">
Health:
<monitoring-elasticsearch-status-icon
status="summary.status"
title="Status of this index: {{ summary.status }}"
></monitoring-elasticsearch-status-icon>
{{ summary.status|capitalize }}
</div>
</div>
</div>

View file

@ -4,15 +4,21 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import { render } from 'react-dom';
import { uiModules } from 'ui/modules';
import template from './index.html';
import { IndexDetailStatus } from 'plugins/monitoring/components/elasticsearch/index_detail_status';
const uiModule = uiModules.get('monitoring/directives', []);
uiModule.directive('monitoringIndexSummary', () => {
return {
restrict: 'E',
template: template,
scope: { summary: '=' }
scope: { summary: '=' },
link(scope, $el) {
scope.$watch('summary', summary => {
render(<IndexDetailStatus stats={summary} />, $el[0]);
});
}
};
});

View file

@ -1,42 +0,0 @@
<div class="monitoring-summary-status" role="status">
<div class="monitoring-summary-status__content" data-test-subj="elasticsearchNodeSummaryStatus">
<div data-test-subj="transportAddress">
<strong>{{ node.transport_address|extractIp }}</strong>
</div>
<div data-test-subj="jvmHeap">
JVM Heap:
<strong>{{ node.usedHeap|formatMetric:'0,0.[00]':'%' }}</strong>
</div>
<div data-test-subj="freeDiskSpace">
Free Disk Space:
<strong>{{ node.freeSpace|formatMetric:'0.0 b' }}</strong>
</div>
<div data-test-subj="documentCount">
Documents:
<strong>{{ node.documents|formatMetric:'0.[0]a' }}</strong>
</div>
<div data-test-subj="dataSize">
Data: <strong>{{ node.dataSize|formatMetric:'0.0 b' }}</strong>
</div>
<div data-test-subj="indicesCount">
Indices:
<strong>{{ node.indexCount|formatMetric:'0,0' }}</strong>
</div>
<div data-test-subj="shardsCount">
Shards:
<strong>{{ node.totalShards|formatMetric:'0,0' }}</strong>
</div>
<div data-test-subj="nodeType">
Type:
<strong>{{ node.nodeTypeLabel }}</strong>
</div>
<div class="monitoring-summary-status__status-indicator">
Health:
<monitoring-elasticsearch-node-status-icon
status="node.status"
title="Status of this Elasticsearch node: {{ node.status }}"
></monitoring-elasticsearch-node-status-icon>
{{ node.status|capitalize }}
</div>
</div>
</div>

View file

@ -4,16 +4,22 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import { render } from 'react-dom';
import { uiModules } from 'ui/modules';
import template from './index.html';
import { NodeDetailStatus } from 'plugins/monitoring/components/elasticsearch/node_detail_status';
const uiModule = uiModules.get('monitoring/directives', []);
uiModule.directive('monitoringNodeSummary', () => {
return {
restrict: 'E',
template: template,
scope: {
node: '='
},
link(scope, $el) {
scope.$watch('node', node => {
render(<NodeDetailStatus stats={node} />, $el[0]);
});
}
};
});

View file

@ -7,8 +7,8 @@
import expect from 'expect.js';
import { handleResponse } from '../get_node_summary';
describe('get_node_summary handleResponse', () => {
it('default undefined fields in result for empty response', () => {
describe('Elasticsearch Node Summary get_node_summary handleResponse', () => {
it('should return undefined fields in result for empty response', () => {
const clusterState = {};
const shardStats = {};
const resolver = null;
@ -24,13 +24,14 @@ describe('get_node_summary handleResponse', () => {
nodeTypeLabel: 'Offline Node',
node_ids: [],
status: 'Offline',
isOnline: false,
transport_address: '',
type: 'node',
});
});
describe('With node_stats hits', () => {
it('incomplete shardStats data', () => {
it('should handle incomplete shardStats data', () => {
const clusterState = {
nodes: {
fooNode: {}
@ -63,10 +64,11 @@ describe('get_node_summary handleResponse', () => {
nodeTypeClass: 'fa-server',
node_ids: [],
status: 'Online',
isOnline: true,
});
});
it('incomplete shardStats data, master node', () => {
it('should handle incomplete shardStats data, master node', () => {
const clusterState = {
nodes: {
'fooNode-Uuid': {}
@ -140,6 +142,7 @@ describe('get_node_summary handleResponse', () => {
'fooNode-Uuid'
],
status: 'Online',
isOnline: true,
});
});
});

View file

@ -45,9 +45,14 @@ export function handleResponse(clusterState, shardStats, resolver) {
freeSpace: get(sourceStats, 'fs.total.available_in_bytes'),
usedHeap: get(sourceStats, 'jvm.mem.heap_used_percent'),
status: 'Online',
isOnline: true,
};
} else {
nodeSummary = { nodeTypeLabel: 'Offline Node', status: 'Offline', };
nodeSummary = {
nodeTypeLabel: 'Offline Node',
status: 'Offline',
isOnline: false,
};
}
return {

View file

@ -990,6 +990,7 @@
"documents": 24830,
"freeSpace": 186755088384,
"indexCount": 20,
"isOnline": true,
"name": "whatever-01",
"nodeTypeClass": "fa-star",
"nodeTypeLabel": "Master Node",

View file

@ -41,7 +41,7 @@ export default function ({ getService, getPageObjects }) {
expect(await nodeDetail.getSummary()).to.eql({
transportAddress: '127.0.0.1:9300',
jvmHeap: 'JVM Heap: 29 %',
jvmHeap: 'JVM Heap: 29%',
freeDiskSpace: 'Free Disk Space: 173.9 GB',
documentCount: 'Documents: 24.8k',
dataSize: 'Data: 50.4 MB',
@ -57,7 +57,7 @@ export default function ({ getService, getPageObjects }) {
expect(await nodeDetail.getSummary()).to.eql({
transportAddress: '127.0.0.1:9302',
jvmHeap: 'JVM Heap: 17 %',
jvmHeap: 'JVM Heap: 17%',
freeDiskSpace: 'Free Disk Space: 173.9 GB',
documentCount: 'Documents: 240',
dataSize: 'Data: 1.4 MB',

View file

@ -7,7 +7,7 @@
export function MonitoringElasticsearchIndexDetailProvider({ getService }) {
const testSubjects = getService('testSubjects');
const SUBJ_SUMMARY = 'elasticsearchIndexSummaryStatus';
const SUBJ_SUMMARY = 'elasticsearchIndexDetailStatus';
const SUBJ_SUMMARY_DATA_SIZE = `${SUBJ_SUMMARY} dataSize`;
const SUBJ_SUMMARY_DATA_SIZE_PRIMARIES = `${SUBJ_SUMMARY} dataSizePrimaries`;
const SUBJ_SUMMARY_DOCUMENT_COUNT = `${SUBJ_SUMMARY} documentCount`;

View file

@ -7,7 +7,7 @@
export function MonitoringElasticsearchNodeDetailProvider({ getService }) {
const testSubjects = getService('testSubjects');
const SUBJ_SUMMARY = 'elasticsearchNodeSummaryStatus';
const SUBJ_SUMMARY = 'elasticsearchNodeDetailStatus';
const SUBJ_SUMMARY_TRANSPORT_ADDRESS = `${SUBJ_SUMMARY} transportAddress`;
const SUBJ_SUMMARY_JVM_HEAP = `${SUBJ_SUMMARY} jvmHeap`;
const SUBJ_SUMMARY_FREE_DISK_SPACE = `${SUBJ_SUMMARY} freeDiskSpace`;

View file

@ -7,7 +7,7 @@
export function MonitoringElasticsearchSummaryStatusProvider({ getService }) {
const testSubjects = getService('testSubjects');
const SUBJ_SUMMARY = 'elasticsearchSummaryStatus';
const SUBJ_SUMMARY = 'elasticsearchClusterStatus';
const SUBJ_SUMMARY_NODES_COUNT = `${SUBJ_SUMMARY} nodesCount`;
const SUBJ_SUMMARY_INDICES_COUNT = `${SUBJ_SUMMARY} indicesCount`;
const SUBJ_SUMMARY_MEMORY = `${SUBJ_SUMMARY} memory`;