import { displayName, friendlyTitle, metricToFormatter } from './util/Utils.js';
import BaseTable from './BaseTable.jsx';
import ErrorModal from './ErrorModal.jsx';
import GrafanaLink from './GrafanaLink.jsx';
import Grid from '@material-ui/core/Grid';
import JaegerLink from './JaegerLink.jsx';
import PropTypes from 'prop-types';
import React from 'react';
import SuccessRateMiniChart from './util/SuccessRateMiniChart.jsx';
import { Trans } from '@lingui/macro';
import _cloneDeep from 'lodash/cloneDeep';
import _each from 'lodash/each';
import _get from 'lodash/get';
import _isEmpty from 'lodash/isEmpty';
import { processedMetricsPropType } from './util/MetricUtils.jsx';
import { withContext } from './util/AppContext.jsx';
const tcpStatColumns = [
{
title: columnTitleOpenConnections,
dataIndex: 'tcp.openConnections',
isNumeric: true,
render: d => metricToFormatter.NO_UNIT(d.tcp.openConnections),
sorter: d => d.tcp.openConnections,
},
{
title: columnTitleReadRate,
dataIndex: 'tcp.readRate',
isNumeric: true,
render: d => metricToFormatter.BYTES(d.tcp.readRate),
sorter: d => d.tcp.readRate,
},
{
title: columnTitleWriteRate,
dataIndex: 'tcp.writeRate',
isNumeric: true,
render: d => metricToFormatter.BYTES(d.tcp.writeRate),
sorter: d => d.tcp.writeRate,
},
];
const httpStatColumns = [
{
title: columnTitleSuccessRate,
dataIndex: 'successRate',
isNumeric: true,
render: d => ,
sorter: d => d.successRate,
},
{
title: columnTitleRPS,
dataIndex: 'requestRate',
isNumeric: true,
render: d => metricToFormatter.NO_UNIT(d.requestRate),
sorter: d => d.requestRate,
},
{
title: columnTitleP50Latency,
dataIndex: 'P50',
isNumeric: true,
render: d => metricToFormatter.LATENCY(d.P50),
sorter: d => d.P50,
},
{
title: columnTitleP95Latency,
dataIndex: 'P95',
isNumeric: true,
render: d => metricToFormatter.LATENCY(d.P95),
sorter: d => d.P95,
},
{
title: columnTitleP99Latency,
dataIndex: 'P99',
isNumeric: true,
render: d => metricToFormatter.LATENCY(d.P99),
sorter: d => d.P99,
},
];
const trafficSplitDetailColumns = [
{
title: columnTitleApexService,
dataIndex: 'apex',
isNumeric: false,
filter: d => !d.tsStats ? null : d.tsStats.apex,
render: d => !d.tsStats ? null : d.tsStats.apex,
sorter: d => !d.tsStats ? null : d.tsStats.apex,
},
{
title: columnTitleLeafService,
dataIndex: 'leaf',
isNumeric: false,
filter: d => !d.tsStats ? null : d.tsStats.leaf,
render: d => !d.tsStats ? null : d.tsStats.leaf,
sorter: d => !d.tsStats ? null : d.tsStats.leaf,
},
{
title: columnTitleWeight,
dataIndex: 'weight',
isNumeric: true,
filter: d => !d.tsStats ? null : d.tsStats.weight,
render: d => !d.tsStats ? null : d.tsStats.weight,
sorter: d => {
if (!d.tsStats) { return -1; }
if (parseInt(d.tsStats.weight, 10)) {
return parseInt(d.tsStats.weight, 10);
} else {
return d.tsStats.weight;
}
},
},
];
const gatewayColumns = [
{
title: columnTitleClusterName,
dataIndex: 'clusterName',
isNumeric: false,
render: d => !d.clusterName ? '---' : d.clusterName,
sorter: d => !d.clusterName ? '---' : d.clusterName,
},
{
title: columnTitleAlive,
dataIndex: 'alive',
isNumeric: false,
render: d => !d.alive ? 'FALSE' : 'TRUE',
sorter: d => d.alive,
},
{
title: columnTitlePairedServices,
dataIndex: 'pairedServices',
isNumeric: false,
render: d => d.pairedServices,
sorter: d => d.pairedServices,
},
{
title: columnTitleP50Latency,
dataIndex: 'P50',
isNumeric: true,
render: d => metricToFormatter.LATENCY(d.P50),
sorter: d => d.P50,
},
{
title: columnTitleP95Latency,
dataIndex: 'P95',
isNumeric: true,
render: d => metricToFormatter.LATENCY(d.P95),
sorter: d => d.P95,
},
{
title: columnTitleP99Latency,
dataIndex: 'P99',
isNumeric: true,
render: d => metricToFormatter.LATENCY(d.P99),
sorter: d => d.P99,
},
];
const columnDefinitions = (resource, showNamespaceColumn, showNameColumn, PrefixedLink, isTcpTable, grafana, jaeger) => {
const isAuthorityTable = resource === 'authority';
const isTrafficSplitTable = resource === 'trafficsplit';
const isMultiResourceTable = resource === 'multi_resource';
const isGatewayTable = resource === 'gateway';
const getResourceDisplayName = isMultiResourceTable ? displayName : d => d.name;
const nsColumn = [
{
title: columnTitleNamespace,
dataIndex: 'namespace',
filter: d => d.namespace,
isNumeric: false,
render: d => !d.namespace ? '---' : {d.namespace},
sorter: d => !d.namespace ? '---' : d.namespace,
},
];
const meshedColumn = {
title: columnTitleMeshed,
dataIndex: 'pods.totalPods',
isNumeric: true,
render: d => !d.pods ? null : `${d.pods.meshedPods}/${d.pods.totalPods}`,
sorter: d => !d.pods ? -1 : d.pods.totalPods,
};
const grafanaColumn = {
title: columnTitleGrafana,
key: 'grafanaDashboard',
isNumeric: true,
render: row => {
if (!isAuthorityTable && (!row.added || _get(row, 'pods.totalPods') === '0')) {
return null;
}
return (
);
},
};
const jaegerColumn = {
title: columnTitleJaeger,
key: 'JaegerDashboard',
isNumeric: true,
render: row => {
if (!isAuthorityTable && (!row.added || _get(row, 'pods.totalPods') === '0')) {
return null;
}
return (
);
},
};
const nameColumn = {
title: isMultiResourceTable ? 'Resource' : friendlyTitle(resource).singular,
dataIndex: 'name',
isNumeric: false,
filter: d => d.name,
render: d => {
let nameContents;
if (resource === 'namespace') {
nameContents = {d.name};
} else if (!d.added && (!isTrafficSplitTable || isAuthorityTable)) {
nameContents = getResourceDisplayName(d);
} else {
nameContents = (
{getResourceDisplayName(d)}
);
}
return (
{nameContents}
{_isEmpty(d.errors) ? null :
}
);
},
sorter: d => getResourceDisplayName(d) || -1,
};
let columns = [];
if (showNameColumn) {
columns = [nameColumn];
}
if (isTrafficSplitTable) {
columns = columns.concat(trafficSplitDetailColumns);
}
if (isTcpTable) {
columns = columns.concat(tcpStatColumns);
} else if (isGatewayTable) {
columns = columns.concat(gatewayColumns);
} else {
columns = columns.concat(httpStatColumns);
}
if (!isAuthorityTable && !isTrafficSplitTable && !isGatewayTable) {
columns.splice(1, 0, meshedColumn);
}
if (!isTrafficSplitTable) {
if (grafana !== '') {
columns = columns.concat(grafanaColumn);
}
if (jaeger !== '') {
columns = columns.concat(jaegerColumn);
}
}
if (!showNamespaceColumn) {
return columns;
} else {
return nsColumn.concat(columns);
}
};
const preprocessMetrics = metrics => {
const tableData = _cloneDeep(metrics);
_each(tableData, datum => {
_each(datum.latency, (value, quantile) => {
datum[quantile] = value;
});
});
return tableData;
};
const MetricsTable = ({ metrics, resource, showNamespaceColumn, showName, title, api, isTcpTable, selectedNamespace, grafana, jaeger }) => {
const showNsColumn = resource === 'namespace' || selectedNamespace !== '_all' ? false : showNamespaceColumn;
const showNameColumn = resource !== 'trafficsplit' ? true : showName;
let orderBy = 'name';
if (resource === 'trafficsplit' && !showNameColumn) { orderBy = 'leaf'; }
const columns = columnDefinitions(resource, showNsColumn, showNameColumn, api.PrefixedLink, isTcpTable, grafana, jaeger);
const rows = preprocessMetrics(metrics);
return (
);
};
MetricsTable.propTypes = {
api: PropTypes.shape({
PrefixedLink: PropTypes.func.isRequired,
}).isRequired,
isTcpTable: PropTypes.bool,
metrics: PropTypes.arrayOf(processedMetricsPropType),
resource: PropTypes.string.isRequired,
selectedNamespace: PropTypes.string.isRequired,
showName: PropTypes.bool,
showNamespaceColumn: PropTypes.bool,
title: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
grafana: PropTypes.string,
jaeger: PropTypes.string,
};
MetricsTable.defaultProps = {
showNamespaceColumn: true,
showName: true,
title: '',
grafana: '',
jaeger: '',
isTcpTable: false,
metrics: [],
};
export default withContext(MetricsTable);