import { directionColumn, srcDstColumn } from './util/TapUtils.jsx';
import { formatLatencySec, formatWithComma } from './util/Utils.js';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import CircularProgress from '@material-ui/core/CircularProgress';
import ExpandableTable from './ExpandableTable.jsx';
import Grid from '@material-ui/core/Grid';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import PropTypes from 'prop-types';
import React from 'react';
import { Trans } from '@lingui/macro';
import Typography from '@material-ui/core/Typography';
import _get from 'lodash/get';
import _isEmpty from 'lodash/isEmpty';
import _isNull from 'lodash/isNull';
import { headersDisplay } from './TapEventHeadersTable.jsx';
import { withContext } from './util/AppContext.jsx';
import { withStyles } from '@material-ui/core/styles';
// https://godoc.org/google.golang.org/grpc/codes#Code
const grpcStatusCodes = {
0: 'OK',
1: 'Canceled',
2: 'Unknown',
3: 'InvalidArgument',
4: 'DeadlineExceeded',
5: 'NotFound',
6: 'AlreadyExists',
7: 'PermissionDenied',
8: 'ResourceExhausted',
9: 'FailedPrecondition',
10: 'Aborted',
11: 'OutOfRange',
12: 'Unimplemented',
13: 'Internal',
14: 'Unavailable',
15: 'DataLoss',
16: 'Unauthenticated',
};
const spinnerStyles = theme => ({
progress: {
margin: theme.spacing(2),
},
});
const SpinnerBase = () => ;
const Spinner = withStyles(spinnerStyles)(SpinnerBase);
const formatTapLatency = str => {
return formatLatencySec(str.replace('s', ''));
};
const httpStatusCol = {
title: columnTitleHTTPStatus,
key: 'http-status',
render: datum => {
const d = _get(datum, 'responseInit.http.responseInit');
return !d ? : d.httpStatus;
},
};
const responseInitLatencyCol = {
title: columnTitleLatency,
key: 'rsp-latency',
isNumeric: true,
render: datum => {
const d = _get(datum, 'responseInit.http.responseInit');
return !d ? : formatTapLatency(d.sinceRequestInit);
},
};
const grpcStatusCol = {
title: columnTitleGRPCStatus,
key: 'grpc-status',
render: datum => {
const d = _get(datum, 'responseEnd.http.responseEnd');
return !d ? :
_isNull(d.eos) ? '---' : grpcStatusCodes[_get(d, 'eos.grpcStatusCode')];
},
};
const pathCol = {
title: columnTitlePath,
key: 'path',
render: datum => {
const d = _get(datum, 'requestInit.http.requestInit');
return !d ? : d.path;
},
};
const methodCol = {
title: columnTitleMethod,
key: 'method',
render: datum => {
const d = _get(datum, 'requestInit.http.requestInit');
return !d ? : _get(d, 'method.registered');
},
};
const topLevelColumns = (resourceType, ResourceLink) => [
{
title: columnTitleDirection,
key: 'direction',
render: d => directionColumn(d.base.proxyDirection),
},
{
title: columnTitleName,
key: 'src-dst',
render: d => {
const datum = {
direction: _get(d, 'base.proxyDirection'),
source: _get(d, 'base.source'),
destination: _get(d, 'base.destination'),
sourceLabels: _get(d, 'base.sourceMeta.labels', {}),
destinationLabels: _get(d, 'base.destinationMeta.labels', {}),
};
return srcDstColumn(datum, resourceType, ResourceLink);
},
},
];
const tapColumns = (resourceType, ResourceLink) => {
return topLevelColumns(resourceType, ResourceLink).concat(
[methodCol, pathCol, responseInitLatencyCol, httpStatusCol, grpcStatusCol],
);
};
const itemDisplay = (title, value) => {
return (
);
};
const requestInitSection = d => (
Request Init
{itemDisplay('Authority', _get(d, 'requestInit.http.requestInit.authority'))}
{itemDisplay('Path', _get(d, 'requestInit.http.requestInit.path'))}
{itemDisplay('Scheme', _get(d, 'requestInit.http.requestInit.scheme.registered'))}
{itemDisplay('Method', _get(d, 'requestInit.http.requestInit.method.registered'))}
{headersDisplay('Headers', _get(d, 'requestInit.http.requestInit.headers'))}
);
const responseInitSection = d => _isEmpty(d.responseInit) ? null : (
Response Init
{itemDisplay('HTTP Status', _get(d, 'responseInit.http.responseInit.httpStatus'))}
{itemDisplay('Latency', formatTapLatency(_get(d, 'responseInit.http.responseInit.sinceRequestInit')))}
{headersDisplay('Headers', _get(d, 'responseInit.http.responseInit.headers'))}
);
const responseEndSection = d => _isEmpty(d.responseEnd) ? null : (
Response End
{itemDisplay('GRPC Status', _isNull(_get(d, 'responseEnd.http.responseEnd.eos')) ? 'N/A' : grpcStatusCodes[_get(d, 'responseEnd.http.responseEnd.eos.grpcStatusCode')])}
{itemDisplay('Latency', formatTapLatency(_get(d, 'responseEnd.http.responseEnd.sinceResponseInit')))}
{itemDisplay('Response Length (B)', formatWithComma(_get(d, 'responseEnd.http.responseEnd.responseBytes')))}
);
// hide verbose information
const expandedRowRender = (d, expandedWrapStyle) => {
return (
{requestInitSection(d)}
{responseInitSection(d)}
{responseEndSection(d)}
);
};
const TapEventTable = ({ tableRows, resource, api }) => {
const resourceType = resource.split('/')[0];
const columns = tapColumns(resourceType, api.ResourceLink);
return (
);
};
TapEventTable.propTypes = {
api: PropTypes.shape({
ResourceLink: PropTypes.func.isRequired,
}).isRequired,
resource: PropTypes.string,
tableRows: PropTypes.arrayOf(PropTypes.shape({})),
};
TapEventTable.defaultProps = {
resource: '',
tableRows: [],
};
export default withContext(TapEventTable);