mirror of https://github.com/linkerd/linkerd2.git
Add es translations and docs instructions to dashboard (#4866)
* Adding es translations Signed-off-by: Carol Scott carol@buoyant.io
This commit is contained in:
parent
c1fd6c3cae
commit
0ffc44ad2e
18
BUILD.md
18
BUILD.md
|
@ -340,6 +340,24 @@ cd web/app
|
|||
yarn add [dep]
|
||||
```
|
||||
|
||||
#### Translations
|
||||
|
||||
To add a locale:
|
||||
|
||||
```bash
|
||||
cd web/app
|
||||
yarn lingui add-locale [locales...] # will create a messages.json file for new locale(s)
|
||||
```
|
||||
|
||||
To extract message keys from existing components:
|
||||
|
||||
```bash
|
||||
cd web/app
|
||||
yarn lingui extract
|
||||
...
|
||||
yarn lingui compile # done automatically in bin/web run
|
||||
```
|
||||
|
||||
### Rust
|
||||
|
||||
All Rust development happens in the
|
||||
|
|
|
@ -261,10 +261,10 @@ BaseTable.propTypes = {
|
|||
isNumeric: PropTypes.bool,
|
||||
render: PropTypes.func,
|
||||
sorter: PropTypes.func,
|
||||
title: PropTypes.string,
|
||||
title: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
})).isRequired,
|
||||
tableRows: PropTypes.arrayOf(PropTypes.shape({})),
|
||||
title: PropTypes.string,
|
||||
title: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
};
|
||||
|
||||
BaseTable.defaultProps = {
|
||||
|
|
|
@ -14,6 +14,7 @@ import PropTypes from 'prop-types';
|
|||
import React from 'react';
|
||||
import SimpleChip from './util/Chip.jsx';
|
||||
import Slide from '@material-ui/core/Slide';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import withMobileDialog from '@material-ui/core/withMobileDialog';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
@ -254,7 +255,7 @@ class CheckModal extends React.Component {
|
|||
color="primary"
|
||||
disabled={running}
|
||||
onClick={this.runCheck}>
|
||||
Run Linkerd Check
|
||||
<Trans>buttonRunLinkerdCheck</Trans>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
|
|
@ -3,6 +3,7 @@ import CheckCircleOutline from '@material-ui/icons/CheckCircleOutline';
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import WarningIcon from '@material-ui/icons/Warning';
|
||||
import { directionColumn } from './util/TapUtils.jsx';
|
||||
import { processedEdgesPropType } from './util/EdgesUtils.jsx';
|
||||
|
@ -25,7 +26,7 @@ const edgesColumnDefinitions = (PrefixedLink, namespace, type, classes) => {
|
|||
render: d => directionColumn(d.direction),
|
||||
},
|
||||
{
|
||||
title: 'Namespace',
|
||||
title: <Trans>columnTitleNamespace</Trans>,
|
||||
dataIndex: 'namespace',
|
||||
isNumeric: false,
|
||||
filter: d => d.namespace,
|
||||
|
@ -37,7 +38,7 @@ const edgesColumnDefinitions = (PrefixedLink, namespace, type, classes) => {
|
|||
sorter: d => d.namespace,
|
||||
},
|
||||
{
|
||||
title: 'Name',
|
||||
title: <Trans>columnTitleName</Trans>,
|
||||
dataIndex: 'name',
|
||||
isNumeric: false,
|
||||
filter: d => d.name,
|
||||
|
@ -56,7 +57,7 @@ const edgesColumnDefinitions = (PrefixedLink, namespace, type, classes) => {
|
|||
sorter: d => d.name,
|
||||
},
|
||||
{
|
||||
title: 'Identity',
|
||||
title: <Trans>columnTitleIdentity</Trans>,
|
||||
dataIndex: 'identity',
|
||||
isNumeric: false,
|
||||
filter: d => d.identity,
|
||||
|
@ -64,7 +65,7 @@ const edgesColumnDefinitions = (PrefixedLink, namespace, type, classes) => {
|
|||
sorter: d => d.identity,
|
||||
},
|
||||
{
|
||||
title: 'Secured',
|
||||
title: <Trans>columnTitleSecured</Trans>,
|
||||
dataIndex: 'message',
|
||||
isNumeric: true,
|
||||
render: d => {
|
||||
|
@ -83,12 +84,12 @@ const edgesColumnDefinitions = (PrefixedLink, namespace, type, classes) => {
|
|||
};
|
||||
|
||||
const generateEdgesTableTitle = edges => {
|
||||
let title = 'Edges';
|
||||
let title = <Trans>tableTitleEdgesEmpty</Trans>;
|
||||
if (edges.length > 0) {
|
||||
let identity = edges[0].direction === 'INBOUND' ? edges[0].serverId : edges[0].clientId;
|
||||
if (identity) {
|
||||
identity = `${identity.split('.')[0]}.${identity.split('.')[1]}`;
|
||||
title = `${title} (Identity: ${identity})`;
|
||||
title = <Trans>tableTitleEdgesWithIdentity {identity}</Trans>;
|
||||
}
|
||||
}
|
||||
return title;
|
||||
|
|
|
@ -17,7 +17,7 @@ const EmptyCard = ({ classes }) => {
|
|||
<Card className={classes.card} elevation={3}>
|
||||
<CardContent>
|
||||
<Typography>
|
||||
<Trans>No data to display</Trans>
|
||||
<Trans>NoDataToDisplayMsg</Trans>
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
|
@ -10,6 +10,7 @@ import PropTypes from 'prop-types';
|
|||
import React from 'react';
|
||||
import Switch from '@material-ui/core/Switch';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import _each from 'lodash/each';
|
||||
import _get from 'lodash/get';
|
||||
|
@ -150,7 +151,9 @@ class ErrorModal extends React.Component {
|
|||
|
||||
if (showInit) {
|
||||
return (
|
||||
<Tooltip title="Pods are initializing"><CircularProgress size={20} thickness={4} /></Tooltip>
|
||||
<Tooltip title={<Trans>podsAreInitializingMsg</Trans>}>
|
||||
<CircularProgress size={20} thickness={4} />
|
||||
</Tooltip>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
|
|
|
@ -148,7 +148,7 @@ ExpandableTable.propTypes = {
|
|||
expandedRowRender: PropTypes.func.isRequired,
|
||||
tableClassName: PropTypes.string,
|
||||
tableColumns: PropTypes.arrayOf(PropTypes.shape({
|
||||
title: PropTypes.string,
|
||||
title: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
isNumeric: PropTypes.bool,
|
||||
render: PropTypes.func,
|
||||
})).isRequired,
|
||||
|
|
|
@ -4,6 +4,7 @@ import MetricsTable from './MetricsTable.jsx';
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Spinner from './util/Spinner.jsx';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import _isEmpty from 'lodash/isEmpty';
|
||||
import { processGatewayResults } from './util/MetricUtils.jsx';
|
||||
import { withContext } from './util/AppContext.jsx';
|
||||
|
@ -102,7 +103,7 @@ class Gateways extends React.Component {
|
|||
{noMetrics ? null : (
|
||||
<div className="page-section">
|
||||
<MetricsTable
|
||||
title="Gateways"
|
||||
title={<Trans>tableTitleGateways</Trans>}
|
||||
resource="gateway"
|
||||
metrics={metrics} />
|
||||
</div>
|
||||
|
|
|
@ -5,6 +5,7 @@ import PropTypes from 'prop-types';
|
|||
import React from 'react';
|
||||
import { StyledProgress } from './util/Progress.jsx';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import _isEmpty from 'lodash/isEmpty';
|
||||
import { withContext } from './util/AppContext.jsx';
|
||||
|
||||
|
@ -20,7 +21,7 @@ const getClassification = (meshedPodCount, failedPodCount) => {
|
|||
|
||||
const namespacesColumns = PrefixedLink => [
|
||||
{
|
||||
title: 'Namespace',
|
||||
title: <Trans>columnTitleNamespace</Trans>,
|
||||
dataIndex: 'namespace',
|
||||
sorter: d => d.namespace,
|
||||
render: d => {
|
||||
|
@ -37,12 +38,12 @@ const namespacesColumns = PrefixedLink => [
|
|||
},
|
||||
},
|
||||
{
|
||||
title: 'Meshed pods',
|
||||
title: <Trans>columnTitleMeshedPods</Trans>,
|
||||
dataIndex: 'meshedPodsStr',
|
||||
isNumeric: true,
|
||||
},
|
||||
{
|
||||
title: 'Meshed Status',
|
||||
title: <Trans>columnTitleMeshedStatus</Trans>,
|
||||
key: 'meshification',
|
||||
render: row => {
|
||||
const percent = row.meshedPercent.get();
|
||||
|
|
|
@ -7,6 +7,7 @@ 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';
|
||||
|
@ -16,21 +17,21 @@ import { withContext } from './util/AppContext.jsx';
|
|||
|
||||
const tcpStatColumns = [
|
||||
{
|
||||
title: 'Connections',
|
||||
title: <Trans>columnTitleOpenConnections</Trans>,
|
||||
dataIndex: 'tcp.openConnections',
|
||||
isNumeric: true,
|
||||
render: d => metricToFormatter.NO_UNIT(d.tcp.openConnections),
|
||||
sorter: d => d.tcp.openConnections,
|
||||
},
|
||||
{
|
||||
title: 'Read Bytes / sec',
|
||||
title: <Trans>columnTitleReadRate</Trans>,
|
||||
dataIndex: 'tcp.readRate',
|
||||
isNumeric: true,
|
||||
render: d => metricToFormatter.BYTES(d.tcp.readRate),
|
||||
sorter: d => d.tcp.readRate,
|
||||
},
|
||||
{
|
||||
title: 'Write Bytes / sec',
|
||||
title: <Trans>columnTitleWriteRate</Trans>,
|
||||
dataIndex: 'tcp.writeRate',
|
||||
isNumeric: true,
|
||||
render: d => metricToFormatter.BYTES(d.tcp.writeRate),
|
||||
|
@ -40,35 +41,35 @@ const tcpStatColumns = [
|
|||
|
||||
const httpStatColumns = [
|
||||
{
|
||||
title: 'Success Rate',
|
||||
title: <Trans>columnTitleSuccessRate</Trans>,
|
||||
dataIndex: 'successRate',
|
||||
isNumeric: true,
|
||||
render: d => <SuccessRateMiniChart sr={d.successRate} />,
|
||||
sorter: d => d.successRate,
|
||||
},
|
||||
{
|
||||
title: 'RPS',
|
||||
title: <Trans>columnTitleRPS</Trans>,
|
||||
dataIndex: 'requestRate',
|
||||
isNumeric: true,
|
||||
render: d => metricToFormatter.NO_UNIT(d.requestRate),
|
||||
sorter: d => d.requestRate,
|
||||
},
|
||||
{
|
||||
title: 'P50 Latency',
|
||||
title: <Trans>columnTitleP50Latency</Trans>,
|
||||
dataIndex: 'P50',
|
||||
isNumeric: true,
|
||||
render: d => metricToFormatter.LATENCY(d.P50),
|
||||
sorter: d => d.P50,
|
||||
},
|
||||
{
|
||||
title: 'P95 Latency',
|
||||
title: <Trans>columnTitleP95Latency</Trans>,
|
||||
dataIndex: 'P95',
|
||||
isNumeric: true,
|
||||
render: d => metricToFormatter.LATENCY(d.P95),
|
||||
sorter: d => d.P95,
|
||||
},
|
||||
{
|
||||
title: 'P99 Latency',
|
||||
title: <Trans>columnTitleP99Latency</Trans>,
|
||||
dataIndex: 'P99',
|
||||
isNumeric: true,
|
||||
render: d => metricToFormatter.LATENCY(d.P99),
|
||||
|
@ -79,7 +80,7 @@ const httpStatColumns = [
|
|||
|
||||
const trafficSplitDetailColumns = [
|
||||
{
|
||||
title: 'Apex Service',
|
||||
title: <Trans>columnTitleApexService</Trans>,
|
||||
dataIndex: 'apex',
|
||||
isNumeric: false,
|
||||
filter: d => !d.tsStats ? null : d.tsStats.apex,
|
||||
|
@ -87,7 +88,7 @@ const trafficSplitDetailColumns = [
|
|||
sorter: d => !d.tsStats ? null : d.tsStats.apex,
|
||||
},
|
||||
{
|
||||
title: 'Leaf Service',
|
||||
title: <Trans>columnTitleLeafService</Trans>,
|
||||
dataIndex: 'leaf',
|
||||
isNumeric: false,
|
||||
filter: d => !d.tsStats ? null : d.tsStats.leaf,
|
||||
|
@ -95,7 +96,7 @@ const trafficSplitDetailColumns = [
|
|||
sorter: d => !d.tsStats ? null : d.tsStats.leaf,
|
||||
},
|
||||
{
|
||||
title: 'Weight',
|
||||
title: <Trans>columnTitleWeight</Trans>,
|
||||
dataIndex: 'weight',
|
||||
isNumeric: true,
|
||||
filter: d => !d.tsStats ? null : d.tsStats.weight,
|
||||
|
@ -113,42 +114,42 @@ const trafficSplitDetailColumns = [
|
|||
|
||||
const gatewayColumns = [
|
||||
{
|
||||
title: 'ClusterName',
|
||||
title: <Trans>columnTitleClusterName</Trans>,
|
||||
dataIndex: 'clusterName',
|
||||
isNumeric: false,
|
||||
render: d => !d.clusterName ? '---' : d.clusterName,
|
||||
sorter: d => !d.clusterName ? '---' : d.clusterName,
|
||||
},
|
||||
{
|
||||
title: 'Alive',
|
||||
title: <Trans>columnTitleAlive</Trans>,
|
||||
dataIndex: 'alive',
|
||||
isNumeric: false,
|
||||
render: d => !d.alive ? 'FALSE' : 'TRUE',
|
||||
sorter: d => d.alive,
|
||||
},
|
||||
{
|
||||
title: 'Paired Services',
|
||||
title: <Trans>columnTitlePairedServices</Trans>,
|
||||
dataIndex: 'pairedServices',
|
||||
isNumeric: false,
|
||||
render: d => d.pairedServices,
|
||||
sorter: d => d.pairedServices,
|
||||
},
|
||||
{
|
||||
title: 'P50 Latency',
|
||||
title: <Trans>columnTitleP50Latency</Trans>,
|
||||
dataIndex: 'P50',
|
||||
isNumeric: true,
|
||||
render: d => metricToFormatter.LATENCY(d.P50),
|
||||
sorter: d => d.P50,
|
||||
},
|
||||
{
|
||||
title: 'P95 Latency',
|
||||
title: <Trans>columnTitleP95Latency</Trans>,
|
||||
dataIndex: 'P95',
|
||||
isNumeric: true,
|
||||
render: d => metricToFormatter.LATENCY(d.P95),
|
||||
sorter: d => d.P95,
|
||||
},
|
||||
{
|
||||
title: 'P99 Latency',
|
||||
title: <Trans>columnTitleP99Latency</Trans>,
|
||||
dataIndex: 'P99',
|
||||
isNumeric: true,
|
||||
render: d => metricToFormatter.LATENCY(d.P99),
|
||||
|
@ -165,7 +166,7 @@ const columnDefinitions = (resource, showNamespaceColumn, showNameColumn, Prefix
|
|||
|
||||
const nsColumn = [
|
||||
{
|
||||
title: 'Namespace',
|
||||
title: <Trans>columnTitleNamespace</Trans>,
|
||||
dataIndex: 'namespace',
|
||||
filter: d => d.namespace,
|
||||
isNumeric: false,
|
||||
|
@ -175,7 +176,7 @@ const columnDefinitions = (resource, showNamespaceColumn, showNameColumn, Prefix
|
|||
];
|
||||
|
||||
const meshedColumn = {
|
||||
title: 'Meshed',
|
||||
title: <Trans>columnTitleMeshed</Trans>,
|
||||
dataIndex: 'pods.totalPods',
|
||||
isNumeric: true,
|
||||
render: d => !d.pods ? null : `${d.pods.meshedPods}/${d.pods.totalPods}`,
|
||||
|
@ -183,7 +184,7 @@ const columnDefinitions = (resource, showNamespaceColumn, showNameColumn, Prefix
|
|||
};
|
||||
|
||||
const grafanaColumn = {
|
||||
title: 'Grafana',
|
||||
title: <Trans>columnTitleGrafana</Trans>,
|
||||
key: 'grafanaDashboard',
|
||||
isNumeric: true,
|
||||
render: row => {
|
||||
|
@ -203,7 +204,7 @@ const columnDefinitions = (resource, showNamespaceColumn, showNameColumn, Prefix
|
|||
|
||||
|
||||
const jaegerColumn = {
|
||||
title: 'Jaeger',
|
||||
title: <Trans>columnTitleJaeger</Trans>,
|
||||
key: 'JaegerDashboard',
|
||||
isNumeric: true,
|
||||
render: row => {
|
||||
|
@ -327,7 +328,7 @@ MetricsTable.propTypes = {
|
|||
selectedNamespace: PropTypes.string.isRequired,
|
||||
showName: PropTypes.bool,
|
||||
showNamespaceColumn: PropTypes.bool,
|
||||
title: PropTypes.string,
|
||||
title: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
grafana: PropTypes.string,
|
||||
jaeger: PropTypes.string,
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@ import NetworkGraph from './NetworkGraph.jsx';
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Spinner from './util/Spinner.jsx';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import _filter from 'lodash/filter';
|
||||
import _get from 'lodash/get';
|
||||
import _isEmpty from 'lodash/isEmpty';
|
||||
|
@ -147,7 +148,7 @@ class Namespaces extends React.Component {
|
|||
{!error ? null : <ErrorBanner message={error} />}
|
||||
{!loaded ? <Spinner /> : (
|
||||
<div>
|
||||
{noMetrics ? <div>No resources detected.</div> : null}
|
||||
{noMetrics ? <div><Trans>noResourcesDetectedMsg</Trans></div> : null}
|
||||
{
|
||||
_isEmpty(deploymentsWithMetrics) ? null :
|
||||
<NetworkGraph namespace={ns} deployments={metrics.deployment} />
|
||||
|
@ -166,7 +167,7 @@ class Namespaces extends React.Component {
|
|||
noMetrics ? null :
|
||||
<div className="page-section">
|
||||
<MetricsTable
|
||||
title="TCP"
|
||||
title={<Trans>tableTitleTCP</Trans>}
|
||||
resource="pod"
|
||||
metrics={metrics.pod}
|
||||
isTcpTable />
|
||||
|
|
|
@ -22,6 +22,7 @@ import React from 'react';
|
|||
import ReactRouterPropTypes from 'react-router-prop-types';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Toolbar from '@material-ui/core/Toolbar';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Version from './Version.jsx';
|
||||
import _maxBy from 'lodash/maxBy';
|
||||
|
@ -450,15 +451,15 @@ class NavigationBase extends React.Component {
|
|||
<Divider />
|
||||
<MenuList>
|
||||
<Typography variant="button" component="div" className={classes.sidebarHeading}>
|
||||
Cluster
|
||||
<Trans>sidebarHeadingCluster</Trans>
|
||||
</Typography>
|
||||
{ this.menuItem('/namespaces', 'Namespaces', namespaceIcon) }
|
||||
{ this.menuItem('/namespaces', <Trans>menuItemNamespaces</Trans>, namespaceIcon) }
|
||||
|
||||
|
||||
{ this.menuItem('/controlplane', 'Control Plane',
|
||||
{ this.menuItem('/controlplane', <Trans>menuItemControlPlane</Trans>,
|
||||
<FontAwesomeIcon icon={faCloud} className={classes.shrinkCloudIcon} />) }
|
||||
|
||||
{ this.menuItem('/gateways', 'Gateway',
|
||||
{ this.menuItem('/gateways', <Trans>menuItemGateway</Trans>,
|
||||
<FontAwesomeIcon icon={faDungeon} className={classes.shrinkIcon} />) }
|
||||
|
||||
</MenuList>
|
||||
|
@ -500,48 +501,48 @@ class NavigationBase extends React.Component {
|
|||
|
||||
<MenuList>
|
||||
<Typography variant="button" component="div" className={classes.sidebarHeading}>
|
||||
Workloads
|
||||
<Trans>sidebarHeadingWorkloads</Trans>
|
||||
</Typography>
|
||||
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/cronjobs`, 'Cron Jobs', cronJobIcon) }
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/cronjobs`, <Trans>menuItemCronJobs</Trans>, cronJobIcon) }
|
||||
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/daemonsets`, 'Daemon Sets', daemonsetIcon) }
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/daemonsets`, <Trans>menuItemDaemonSets</Trans>, daemonsetIcon) }
|
||||
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/deployments`, 'Deployments', deploymentIcon) }
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/deployments`, <Trans>menuItemDeployments</Trans>, deploymentIcon) }
|
||||
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/jobs`, 'Jobs', jobIcon) }
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/jobs`, <Trans>menuItemJobs</Trans>, jobIcon) }
|
||||
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/pods`, 'Pods', podIcon) }
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/pods`, <Trans>menuItemPods</Trans>, podIcon) }
|
||||
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/replicasets`, 'Replica Sets', replicaSetIcon) }
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/replicasets`, <Trans>menuItemReplicaSets</Trans>, replicaSetIcon) }
|
||||
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/replicationcontrollers`, 'Replication Controllers', replicaSetIcon) }
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/replicationcontrollers`, <Trans>menuItemReplicationControllers</Trans>, replicaSetIcon) }
|
||||
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/statefulsets`, 'Stateful Sets', statefulSetIcon) }
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/statefulsets`, <Trans>menuItemStatefulSets</Trans>, statefulSetIcon) }
|
||||
</MenuList>
|
||||
|
||||
<MenuList>
|
||||
<Typography variant="button" component="div" className={classes.sidebarHeading}>
|
||||
Configuration
|
||||
<Trans>sidebarHeadingConfiguration</Trans>
|
||||
</Typography>
|
||||
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/trafficsplits`, 'Traffic Splits', <FontAwesomeIcon icon={faFilter} className={classes.shrinkIcon} />) }
|
||||
{ this.menuItem(`/namespaces/${selectedNamespace}/trafficsplits`, <Trans>menuItemTrafficSplits</Trans>, <FontAwesomeIcon icon={faFilter} className={classes.shrinkIcon} />) }
|
||||
|
||||
</MenuList>
|
||||
<Divider />
|
||||
<MenuList>
|
||||
<Typography variant="button" component="div" className={classes.sidebarHeading}>
|
||||
Tools
|
||||
<Trans>sidebarHeadingTools</Trans>
|
||||
</Typography>
|
||||
|
||||
{ this.menuItem('/tap', 'Tap', <FontAwesomeIcon icon={faMicroscope} className={classes.shrinkIcon} />) }
|
||||
{ this.menuItem('/top', 'Top', <FontAwesomeIcon icon={faStream} className={classes.shrinkIcon} />) }
|
||||
{ this.menuItem('/routes', 'Routes', <FontAwesomeIcon icon={faRandom} className={classes.shrinkIcon} />) }
|
||||
{ this.menuItem('/tap', <Trans>menuItemTap</Trans>, <FontAwesomeIcon icon={faMicroscope} className={classes.shrinkIcon} />) }
|
||||
{ this.menuItem('/top', <Trans>menuItemTop</Trans>, <FontAwesomeIcon icon={faStream} className={classes.shrinkIcon} />) }
|
||||
{ this.menuItem('/routes', <Trans>menuItemRoutes</Trans>, <FontAwesomeIcon icon={faRandom} className={classes.shrinkIcon} />) }
|
||||
|
||||
</MenuList>
|
||||
<Divider />
|
||||
<MenuList>
|
||||
{ this.menuItem('/community', 'Community',
|
||||
{ this.menuItem('/community', <Trans>menuItemCommunity</Trans>,
|
||||
<Badge
|
||||
classes={{ badge: classes.badge }}
|
||||
invisible={hideUpdateBadge}
|
||||
|
@ -551,25 +552,25 @@ class NavigationBase extends React.Component {
|
|||
|
||||
<MenuItem component="a" href="https://linkerd.io/2/overview/" target="_blank" className={classes.navMenuItem}>
|
||||
<ListItemIcon><LibraryBooksIcon className={classes.shrinkIcon} /></ListItemIcon>
|
||||
<ListItemText primary="Documentation" />
|
||||
<ListItemText primary={<Trans>menuItemDocumentation</Trans>} />
|
||||
<FontAwesomeIcon icon={faExternalLinkAlt} className={classes.externalLinkIcon} size="xs" />
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem component="a" href="https://github.com/linkerd/linkerd2/issues/new/choose" target="_blank" className={classes.navMenuItem}>
|
||||
<ListItemIcon>{githubIcon}</ListItemIcon>
|
||||
<ListItemText primary="GitHub" />
|
||||
<ListItemText primary={<Trans>menuItemGitHub</Trans>} />
|
||||
<FontAwesomeIcon icon={faExternalLinkAlt} className={classes.externalLinkIcon} size="xs" />
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem component="a" href="https://lists.cncf.io/g/cncf-linkerd-users" target="_blank" className={classes.navMenuItem}>
|
||||
<ListItemIcon><EmailIcon className={classes.shrinkIcon} /></ListItemIcon>
|
||||
<ListItemText primary="Mailing List" />
|
||||
<ListItemText primary={<Trans>menuItemMailingList</Trans>} />
|
||||
<FontAwesomeIcon icon={faExternalLinkAlt} className={classes.externalLinkIcon} size="xs" />
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem component="a" href="https://slack.linkerd.io" target="_blank" className={classes.navMenuItem}>
|
||||
<ListItemIcon>{slackIcon}</ListItemIcon>
|
||||
<ListItemText primary="Slack" />
|
||||
<ListItemText primary={<Trans>menuItemSlack</Trans>} />
|
||||
<FontAwesomeIcon icon={faExternalLinkAlt} className={classes.externalLinkIcon} size="xs" />
|
||||
</MenuItem>
|
||||
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
import React from 'react';
|
||||
import { Trans } from '@lingui/macro';
|
||||
|
||||
const NoMatch = () => (
|
||||
<div>
|
||||
<h3>404</h3>
|
||||
<div>Page not found.</div>
|
||||
<div>
|
||||
<Trans>
|
||||
404Msg
|
||||
</Trans>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import SimpleChip from './util/Chip.jsx';
|
|||
import Spinner from './util/Spinner.jsx';
|
||||
import TopRoutesTabs from './TopRoutesTabs.jsx';
|
||||
import TrafficSplitDetail from './TrafficSplitDetail.jsx';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import _filter from 'lodash/filter';
|
||||
import _get from 'lodash/get';
|
||||
|
@ -402,14 +403,14 @@ export class ResourceDetailBase extends React.Component {
|
|||
{_isEmpty(upstreams) ? null :
|
||||
<MetricsTable
|
||||
resource="multi_resource"
|
||||
title="Inbound"
|
||||
title={<Trans>tableTitleInbound</Trans>}
|
||||
metrics={upstreamDisplayMetrics} />
|
||||
}
|
||||
|
||||
{_isEmpty(downstreamDisplayMetrics) ? null :
|
||||
<MetricsTable
|
||||
resource="multi_resource"
|
||||
title="Outbound"
|
||||
title={<Trans>tableTitleOutbound</Trans>}
|
||||
metrics={downstreamDisplayMetrics} />
|
||||
}
|
||||
|
||||
|
@ -417,13 +418,13 @@ export class ResourceDetailBase extends React.Component {
|
|||
resourceType === 'pod' || isTcpOnly ? null :
|
||||
<MetricsTable
|
||||
resource="pod"
|
||||
title="Pods"
|
||||
title={<Trans>tableTitlePods</Trans>}
|
||||
metrics={podMetrics} />
|
||||
}
|
||||
|
||||
<MetricsTable
|
||||
resource="pod"
|
||||
title="TCP"
|
||||
title={<Trans>tableTitleTCP</Trans>}
|
||||
isTcpTable
|
||||
metrics={podMetrics} />
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import MetricsTable from './MetricsTable.jsx';
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Spinner from './util/Spinner.jsx';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { apiErrorPropType } from './util/ApiHelpers.jsx';
|
||||
import withREST from './util/withREST.jsx';
|
||||
|
||||
|
@ -33,14 +34,14 @@ export class ResourceListBase extends React.Component {
|
|||
<MetricsTable
|
||||
resource={resource}
|
||||
metrics={processedMetrics}
|
||||
title="HTTP metrics" />
|
||||
title={<Trans>tableTitleHTTPMetrics</Trans>} />
|
||||
|
||||
{resource !== 'trafficsplit' &&
|
||||
<MetricsTable
|
||||
resource={resource}
|
||||
isTcpTable
|
||||
metrics={processedMetrics}
|
||||
title="TCP metrics" />
|
||||
title={<Trans>tableTitleTCPMetrics</Trans>} />
|
||||
}
|
||||
</React.Fragment>
|
||||
);
|
||||
|
|
|
@ -13,6 +13,7 @@ import PropTypes from 'prop-types';
|
|||
import React from 'react';
|
||||
import Spinner from './util/Spinner.jsx';
|
||||
import StatusTable from './StatusTable.jsx';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import _compact from 'lodash/compact';
|
||||
import _countBy from 'lodash/countBy';
|
||||
|
@ -35,11 +36,11 @@ const styles = {
|
|||
|
||||
const serviceMeshDetailsColumns = [
|
||||
{
|
||||
title: 'Name',
|
||||
title: <Trans>columnTitleName</Trans>,
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: 'Value',
|
||||
title: <Trans>columnTitleValue</Trans>,
|
||||
dataIndex: 'value',
|
||||
isNumeric: true,
|
||||
},
|
||||
|
@ -107,9 +108,9 @@ class ServiceMesh extends React.Component {
|
|||
|
||||
return [
|
||||
{ key: 1, name: `${productName} version`, value: releaseVersion },
|
||||
{ key: 2, name: `${productName} namespace`, value: controllerNamespace },
|
||||
{ key: 3, name: 'Control plane components', value: components.length },
|
||||
{ key: 4, name: 'Data plane proxies', value: this.proxyCount() },
|
||||
{ key: 2, name: <Trans>{productName} namespace</Trans>, value: controllerNamespace },
|
||||
{ key: 3, name: <Trans>Control plane components</Trans>, value: components.length },
|
||||
{ key: 4, name: <Trans>Data plane proxies</Trans>, value: this.proxyCount() },
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -225,7 +226,7 @@ class ServiceMesh extends React.Component {
|
|||
<Typography variant="h6">Control plane</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography align="right">Components</Typography>
|
||||
<Typography align="right"><Trans>componentsMsg</Trans></Typography>
|
||||
<Typography align="right">{components.length}</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
|
|
@ -2,6 +2,7 @@ import BaseTable from './BaseTable.jsx';
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import _get from 'lodash/get';
|
||||
import _merge from 'lodash/merge';
|
||||
import classNames from 'classnames';
|
||||
|
@ -75,18 +76,18 @@ StatusDot.propTypes = {
|
|||
|
||||
const columns = {
|
||||
resourceName: {
|
||||
title: 'Deployment',
|
||||
title: <Trans>columnTitleDeployment</Trans>,
|
||||
dataIndex: 'name',
|
||||
},
|
||||
pods: {
|
||||
title: 'Pods',
|
||||
title: <Trans>columnTitlePods</Trans>,
|
||||
key: 'numEntities',
|
||||
isNumeric: true,
|
||||
render: d => d.pods.length,
|
||||
},
|
||||
status: (name, classes) => {
|
||||
return {
|
||||
title: name,
|
||||
title: <Trans>columnTitlePodStatus</Trans>,
|
||||
key: 'status',
|
||||
render: d => {
|
||||
return d.pods.map(status => (
|
||||
|
|
|
@ -11,6 +11,7 @@ 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';
|
||||
|
@ -53,7 +54,7 @@ const formatTapLatency = str => {
|
|||
};
|
||||
|
||||
const httpStatusCol = {
|
||||
title: 'HTTP status',
|
||||
title: <Trans>columnTitleHTTPStatus</Trans>,
|
||||
key: 'http-status',
|
||||
render: datum => {
|
||||
const d = _get(datum, 'responseInit.http.responseInit');
|
||||
|
@ -62,7 +63,7 @@ const httpStatusCol = {
|
|||
};
|
||||
|
||||
const responseInitLatencyCol = {
|
||||
title: 'Latency',
|
||||
title: <Trans>columnTitleLatency</Trans>,
|
||||
key: 'rsp-latency',
|
||||
isNumeric: true,
|
||||
render: datum => {
|
||||
|
@ -72,7 +73,7 @@ const responseInitLatencyCol = {
|
|||
};
|
||||
|
||||
const grpcStatusCol = {
|
||||
title: 'GRPC status',
|
||||
title: <Trans>columnTitleGRPCStatus</Trans>,
|
||||
key: 'grpc-status',
|
||||
render: datum => {
|
||||
const d = _get(datum, 'responseEnd.http.responseEnd');
|
||||
|
@ -82,7 +83,7 @@ const grpcStatusCol = {
|
|||
};
|
||||
|
||||
const pathCol = {
|
||||
title: 'Path',
|
||||
title: <Trans>columnTitlePath</Trans>,
|
||||
key: 'path',
|
||||
render: datum => {
|
||||
const d = _get(datum, 'requestInit.http.requestInit');
|
||||
|
@ -91,7 +92,7 @@ const pathCol = {
|
|||
};
|
||||
|
||||
const methodCol = {
|
||||
title: 'Method',
|
||||
title: <Trans>columnTitleMethod</Trans>,
|
||||
key: 'method',
|
||||
render: datum => {
|
||||
const d = _get(datum, 'requestInit.http.requestInit');
|
||||
|
@ -101,12 +102,12 @@ const methodCol = {
|
|||
|
||||
const topLevelColumns = (resourceType, ResourceLink) => [
|
||||
{
|
||||
title: 'Direction',
|
||||
title: <Trans>columnTitleDirection</Trans>,
|
||||
key: 'direction',
|
||||
render: d => directionColumn(d.base.proxyDirection),
|
||||
},
|
||||
{
|
||||
title: 'Name',
|
||||
title: <Trans>columnTitleName</Trans>,
|
||||
key: 'src-dst',
|
||||
render: d => {
|
||||
const datum = {
|
||||
|
|
|
@ -24,6 +24,7 @@ import QueryToCliCmd from './QueryToCliCmd.jsx';
|
|||
import React from 'react';
|
||||
import Select from '@material-ui/core/Select';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import _flatten from 'lodash/flatten';
|
||||
import _isEmpty from 'lodash/isEmpty';
|
||||
|
@ -287,9 +288,17 @@ class TapQueryForm extends React.Component {
|
|||
const { handleTapStart, handleTapStop } = this.props;
|
||||
|
||||
if (tapIsClosing) {
|
||||
return (<Button variant="outlined" color="primary" className="tap-ctrl tap-stop" disabled>Stop</Button>);
|
||||
return (
|
||||
<Button variant="outlined" color="primary" className="tap-ctrl tap-stop" disabled>
|
||||
<Trans>buttonStop</Trans>
|
||||
</Button>
|
||||
);
|
||||
} else if (tapInProgress) {
|
||||
return (<Button variant="outlined" color="primary" className="tap-ctrl tap-stop" onClick={handleTapStop}>Stop</Button>);
|
||||
return (
|
||||
<Button variant="outlined" color="primary" className="tap-ctrl tap-stop" onClick={handleTapStop}>
|
||||
<Trans>buttonStop</Trans>
|
||||
</Button>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Button
|
||||
|
@ -298,7 +307,7 @@ class TapQueryForm extends React.Component {
|
|||
className="tap-ctrl tap-start"
|
||||
disabled={!query.namespace || !query.resource}
|
||||
onClick={handleTapStart}>
|
||||
Start
|
||||
<Trans>buttonStart</Trans>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
@ -330,7 +339,7 @@ class TapQueryForm extends React.Component {
|
|||
<Grid container spacing={3}>
|
||||
<Grid item xs={6} md={3} className={classes.formControlWrapper}>
|
||||
<FormControl className={classes.formControl}>
|
||||
{this.renderNamespaceSelect('To Namespace', 'toNamespace', 'toResource')}
|
||||
{this.renderNamespaceSelect(<Trans>formToNamespace</Trans>, 'toNamespace', 'toResource')}
|
||||
</FormControl>
|
||||
</Grid>
|
||||
<Grid item xs={6} md={3} className={classes.formControlWrapper}>
|
||||
|
@ -343,7 +352,7 @@ class TapQueryForm extends React.Component {
|
|||
<Grid container spacing={3}>
|
||||
<Grid item xs={6} md={3} classes={{ item: classes.formControlWrapper }}>
|
||||
<FormControl className={classes.formControl}>
|
||||
<InputLabel htmlFor="authority">Authority</InputLabel>
|
||||
<InputLabel htmlFor="authority"><Trans>formAuthority</Trans></InputLabel>
|
||||
<Select
|
||||
value={query.authority}
|
||||
onChange={this.handleFormChange('authority')}
|
||||
|
@ -359,20 +368,20 @@ class TapQueryForm extends React.Component {
|
|||
</FormControl>
|
||||
</Grid>
|
||||
<Grid item xs={6} md={3} className={classes.formControlWrapper}>
|
||||
{ this.renderTextInput('Path', 'path', 'Display requests with paths that start with this prefix') }
|
||||
{ this.renderTextInput(<Trans>formPath</Trans>, 'path', 'Display requests with paths that start with this prefix') }
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={6} md={3} className={classes.formControlWrapper}>
|
||||
{ this.renderTextInput('Scheme', 'scheme', 'Display requests with this scheme') }
|
||||
{ this.renderTextInput(<Trans>formScheme</Trans>, 'scheme', 'Display requests with this scheme') }
|
||||
</Grid>
|
||||
<Grid item xs={6} md={3} className={classes.formControlWrapper}>
|
||||
{ this.renderTextInput('Max RPS', 'maxRps', `Maximum requests per second to tap. Default ${defaultMaxRps}`) }
|
||||
{ this.renderTextInput(<Trans>formMaxRPS</Trans>, 'maxRps', `Maximum requests per second to tap. Default ${defaultMaxRps}`) }
|
||||
</Grid>
|
||||
<Grid item xs={6} md={3} className={classes.formControlWrapper}>
|
||||
<FormControl className={classes.formControl}>
|
||||
<InputLabel htmlFor="method">HTTP method</InputLabel>
|
||||
<InputLabel htmlFor="method"><Trans>formHTTPMethod</Trans></InputLabel>
|
||||
<Select
|
||||
value={query.method}
|
||||
onChange={this.handleFormChange('method')}
|
||||
|
@ -400,7 +409,7 @@ class TapQueryForm extends React.Component {
|
|||
<ExpansionPanel expanded={advancedFormExpanded} onChange={this.handleAdvancedFormExpandClick} elevation={3}>
|
||||
<ExpansionPanelSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<Typography variant="caption" gutterBottom>
|
||||
{advancedFormExpanded ? 'Hide filters' : 'Show more filters'}
|
||||
{advancedFormExpanded ? <Trans>formHideFilters</Trans> : <Trans>formShowFilters</Trans>}
|
||||
</Typography>
|
||||
</ExpansionPanelSummary>
|
||||
|
||||
|
@ -421,7 +430,7 @@ class TapQueryForm extends React.Component {
|
|||
<Grid container spacing={3}>
|
||||
<Grid item xs={6} md="auto" className={classes.formControlWrapper}>
|
||||
<FormControl className={classes.formControl} fullWidth>
|
||||
{this.renderNamespaceSelect('Namespace', 'namespace', 'resource')}
|
||||
{this.renderNamespaceSelect(<Trans>formNamespace</Trans>, 'namespace', 'resource')}
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
|
@ -433,7 +442,9 @@ class TapQueryForm extends React.Component {
|
|||
|
||||
<Grid item>
|
||||
{ this.renderTapButton(tapRequestInProgress, tapIsClosing) }
|
||||
<Button onClick={this.resetTapForm} disabled={tapRequestInProgress} className={classes.resetButton}>Reset</Button>
|
||||
<Button onClick={this.resetTapForm} disabled={tapRequestInProgress} className={classes.resetButton}>
|
||||
<Trans>buttonReset</Trans>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
|
|
|
@ -5,6 +5,7 @@ import BaseTable from './BaseTable.jsx';
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import SuccessRateMiniChart from './util/SuccessRateMiniChart.jsx';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import _isEmpty from 'lodash/isEmpty';
|
||||
import _isNil from 'lodash/isNil';
|
||||
import { withContext } from './util/AppContext.jsx';
|
||||
|
@ -16,7 +17,7 @@ const topColumns = (resourceType, ResourceLink, PrefixedLink) => [
|
|||
render: d => directionColumn(d.direction),
|
||||
},
|
||||
{
|
||||
title: 'Name',
|
||||
title: <Trans>columnTitleName</Trans>,
|
||||
filter: d => {
|
||||
const [labels, display] = extractDisplayName(d);
|
||||
return _isEmpty(labels[resourceType]) ?
|
||||
|
@ -27,33 +28,33 @@ const topColumns = (resourceType, ResourceLink, PrefixedLink) => [
|
|||
render: d => srcDstColumn(d, resourceType, ResourceLink),
|
||||
},
|
||||
{
|
||||
title: 'Method',
|
||||
title: <Trans>columnTitleMethod</Trans>,
|
||||
dataIndex: 'httpMethod',
|
||||
filter: d => d.httpMethod,
|
||||
sorter: d => d.httpMethod,
|
||||
},
|
||||
{
|
||||
title: 'Path',
|
||||
title: <Trans>columnTitlePath</Trans>,
|
||||
dataIndex: 'path',
|
||||
filter: d => d.path,
|
||||
sorter: d => d.path,
|
||||
},
|
||||
{
|
||||
title: 'Count',
|
||||
title: <Trans>columnTitleCount</Trans>,
|
||||
dataIndex: 'count',
|
||||
isNumeric: true,
|
||||
defaultSortOrder: 'desc',
|
||||
sorter: d => d.count,
|
||||
},
|
||||
{
|
||||
title: 'Best',
|
||||
title: <Trans>columnTitleBest</Trans>,
|
||||
dataIndex: 'best',
|
||||
isNumeric: true,
|
||||
render: d => formatLatencySec(d.best),
|
||||
sorter: d => d.best,
|
||||
},
|
||||
{
|
||||
title: 'Worst',
|
||||
title: <Trans>columnTitleWorst</Trans>,
|
||||
dataIndex: 'worst',
|
||||
isNumeric: true,
|
||||
defaultSortOrder: 'desc',
|
||||
|
@ -61,14 +62,14 @@ const topColumns = (resourceType, ResourceLink, PrefixedLink) => [
|
|||
sorter: d => d.worst,
|
||||
},
|
||||
{
|
||||
title: 'Last',
|
||||
title: <Trans>columnTitleLast</Trans>,
|
||||
dataIndex: 'last',
|
||||
isNumeric: true,
|
||||
render: d => formatLatencySec(d.last),
|
||||
sorter: d => d.last,
|
||||
},
|
||||
{
|
||||
title: 'Success Rate',
|
||||
title: <Trans>columnTitleSuccessRate</Trans>,
|
||||
dataIndex: 'successRate',
|
||||
isNumeric: true,
|
||||
render: d => _isNil(d) || _isNil(d.successRate) ? '---' :
|
||||
|
@ -76,7 +77,7 @@ const topColumns = (resourceType, ResourceLink, PrefixedLink) => [
|
|||
sorter: d => d.successRate.get(),
|
||||
},
|
||||
{
|
||||
title: 'Tap',
|
||||
title: <Trans>columnTitleTap</Trans>,
|
||||
key: 'tap',
|
||||
isNumeric: true,
|
||||
render: d => tapLink(d, resourceType, PrefixedLink),
|
||||
|
|
|
@ -17,6 +17,7 @@ import QueryToCliCmd from './QueryToCliCmd.jsx';
|
|||
import React from 'react';
|
||||
import Select from '@material-ui/core/Select';
|
||||
import TopRoutesModule from './TopRoutesModule.jsx';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import _get from 'lodash/get';
|
||||
import _isEmpty from 'lodash/isEmpty';
|
||||
|
@ -232,11 +233,11 @@ class TopRoutes extends React.Component {
|
|||
|
||||
<Grid item container spacing={4} alignItems="center" justify="flex-start">
|
||||
<Grid item>
|
||||
{ this.renderNamespaceDropdown('To Namespace', 'to_namespace', 'Namespace of target resource') }
|
||||
{ this.renderNamespaceDropdown(<Trans>formToNamespace</Trans>, 'to_namespace', 'Namespace of target resource') }
|
||||
</Grid>
|
||||
|
||||
<Grid item>
|
||||
{ this.renderResourceDropdown('To Resource', 'to_name', 'to_type', 'Target resource') }
|
||||
{ this.renderResourceDropdown(<Trans>formToResource</Trans>, 'to_name', 'to_type', 'Target resource') }
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
|
|
@ -2,52 +2,53 @@ import BaseTable from './BaseTable.jsx';
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import SuccessRateMiniChart from './util/SuccessRateMiniChart.jsx';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { metricToFormatter } from './util/Utils.js';
|
||||
|
||||
const routesColumns = [
|
||||
{
|
||||
title: 'Route',
|
||||
title: <Trans>columnTitleRoute</Trans>,
|
||||
dataIndex: 'route',
|
||||
filter: d => d.route,
|
||||
sorter: d => d.route,
|
||||
},
|
||||
{
|
||||
title: 'Service',
|
||||
title: <Trans>columnTitleService</Trans>,
|
||||
tooltip: 'hostname:port used when communicating with this target',
|
||||
dataIndex: 'authority',
|
||||
filter: d => d.authority,
|
||||
sorter: d => d.authority,
|
||||
},
|
||||
{
|
||||
title: 'Success Rate',
|
||||
title: <Trans>columnTitleSuccessRate</Trans>,
|
||||
dataIndex: 'successRate',
|
||||
isNumeric: true,
|
||||
render: d => <SuccessRateMiniChart sr={d.successRate} />,
|
||||
sorter: d => d.successRate,
|
||||
},
|
||||
{
|
||||
title: 'RPS',
|
||||
title: <Trans>columnTitleRPS</Trans>,
|
||||
dataIndex: 'requestRate',
|
||||
isNumeric: true,
|
||||
render: d => metricToFormatter.NO_UNIT(d.requestRate),
|
||||
sorter: d => d.requestRate,
|
||||
},
|
||||
{
|
||||
title: 'P50 Latency',
|
||||
title: <Trans>columnTitleP50Latency</Trans>,
|
||||
dataIndex: 'latency.P50',
|
||||
isNumeric: true,
|
||||
render: d => metricToFormatter.LATENCY(d.latency.P50),
|
||||
sorter: d => d.latency.P50,
|
||||
},
|
||||
{
|
||||
title: 'P95 Latency',
|
||||
title: <Trans>columnTitleP95Latency</Trans>,
|
||||
dataIndex: 'latency.P95',
|
||||
isNumeric: true,
|
||||
render: d => metricToFormatter.LATENCY(d.latency.P95),
|
||||
sorter: d => d.latency.P95,
|
||||
},
|
||||
{
|
||||
title: 'P99 Latency',
|
||||
title: <Trans>columnTitleP99Latency</Trans>,
|
||||
dataIndex: 'latency.P99',
|
||||
isNumeric: true,
|
||||
render: d => metricToFormatter.LATENCY(d.latency.P99),
|
||||
|
|
|
@ -3,6 +3,7 @@ import MetricsTable from './MetricsTable.jsx';
|
|||
import Octopus from './Octopus.jsx';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import _each from 'lodash/each';
|
||||
import _isNil from 'lodash/isNil';
|
||||
|
@ -73,7 +74,7 @@ const TrafficSplitDetail = ({ resourceMetrics, resourceName, resourceRsp, resour
|
|||
metrics={resourceMetrics}
|
||||
showName={false}
|
||||
showNamespaceColumn={false}
|
||||
title="Leaf Services" />
|
||||
title={<Trans>tableTitleLeafServices</Trans>} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@ import Typography from '@material-ui/core/Typography';
|
|||
* Instructions for adding resources to service mesh
|
||||
*/
|
||||
export const incompleteMeshMessage = name => {
|
||||
const unspecifiedResources = <Trans>one or more resources</Trans>;
|
||||
const unspecifiedResources = <Trans>unspecifiedResourcesMsg</Trans>;
|
||||
const inject = <code>linkerd inject k8s.yml | kubectl apply -f -</code>;
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,5 +1,104 @@
|
|||
{
|
||||
"404Msg": "Page not found.",
|
||||
"Add {0} to the k8s.yml file<0/><1/>Then run {inject} to add it to the service mesh": "Add {0} to the k8s.yml file<0/><1/>Then run {inject} to add it to the service mesh",
|
||||
"No data to display": "No data to display",
|
||||
"one or more resources": "one or more resources"
|
||||
"All namespaces have a {productName} install.": "All namespaces have a {productName} install.",
|
||||
"Control plane components": "Control plane components",
|
||||
"Data plane proxies": "Data plane proxies",
|
||||
"NoDataToDisplayMsg": "No data to display",
|
||||
"buttonReset": "Reset",
|
||||
"buttonRunLinkerdCheck": "Run Linkerd Check",
|
||||
"buttonStart": "Start",
|
||||
"buttonStop": "Stop",
|
||||
"columnTitleAlive": "Alive",
|
||||
"columnTitleApexService": "Apex Service",
|
||||
"columnTitleBest": "Best",
|
||||
"columnTitleClusterName": "Cluster Name",
|
||||
"columnTitleCount": "Count",
|
||||
"columnTitleDeployment": "Deployment",
|
||||
"columnTitleDirection": "Direction",
|
||||
"columnTitleGRPCStatus": "GRPC Status",
|
||||
"columnTitleGrafana": "Grafana",
|
||||
"columnTitleHTTPStatus": "HTTP Status",
|
||||
"columnTitleIdentity": "Identity",
|
||||
"columnTitleJaeger": "Jaeger",
|
||||
"columnTitleLast": "Last",
|
||||
"columnTitleLatency": "Latency",
|
||||
"columnTitleLeafService": "Leaf Service",
|
||||
"columnTitleMeshed": "Meshed",
|
||||
"columnTitleMeshedPods": "Meshed Pods",
|
||||
"columnTitleMeshedStatus": "Meshed Status",
|
||||
"columnTitleMethod": "Method",
|
||||
"columnTitleName": "Name",
|
||||
"columnTitleNamespace": "Namespace",
|
||||
"columnTitleOpenConnections": "Connections",
|
||||
"columnTitleP50Latency": "P50 Latency",
|
||||
"columnTitleP95Latency": "P95 Latency",
|
||||
"columnTitleP99Latency": "P99 Latency",
|
||||
"columnTitlePairedServices": "Paired Services",
|
||||
"columnTitlePath": "Path",
|
||||
"columnTitlePodStatus": "Pod Status",
|
||||
"columnTitlePods": "Pods",
|
||||
"columnTitleRPS": "RPS",
|
||||
"columnTitleReadRate": "Read Bytes / sec",
|
||||
"columnTitleRoute": "Route",
|
||||
"columnTitleSecured": "Secured",
|
||||
"columnTitleService": "Service",
|
||||
"columnTitleSuccessRate": "Success Rate",
|
||||
"columnTitleTap": "Tap",
|
||||
"columnTitleValue": "Value",
|
||||
"columnTitleWeight": "Weight",
|
||||
"columnTitleWorst": "Worst",
|
||||
"columnTitleWriteRate": "Write Bytes / sec",
|
||||
"componentsMsg": "Components",
|
||||
"formAuthority": "Authority",
|
||||
"formHTTPMethod": "HTTP Method",
|
||||
"formHideFilters": "Hide filters",
|
||||
"formMaxRPS": "Max RPS",
|
||||
"formNamespace": "Namespace",
|
||||
"formPath": "Path",
|
||||
"formScheme": "Scheme",
|
||||
"formShowFilters": "Show more filters",
|
||||
"formToNamespace": "To Namespace",
|
||||
"formToResource": "To Resource",
|
||||
"menuItemCommunity": "Community",
|
||||
"menuItemControlPlane": "Control Plane",
|
||||
"menuItemCronJobs": "Cron Jobs",
|
||||
"menuItemDaemonSets": "Daemon Sets",
|
||||
"menuItemDeployments": "Deployments",
|
||||
"menuItemDocumentation": "Documentation",
|
||||
"menuItemGateway": "Gateway",
|
||||
"menuItemGitHub": "GitHub",
|
||||
"menuItemJobs": "Jobs",
|
||||
"menuItemMailingList": "Mailing List",
|
||||
"menuItemNamespaces": "Namespaces",
|
||||
"menuItemPods": "Pods",
|
||||
"menuItemReplicaSets": "Replica Sets",
|
||||
"menuItemReplicationControllers": "Replication Controllers",
|
||||
"menuItemRoutes": "Routes",
|
||||
"menuItemSlack": "Slack",
|
||||
"menuItemStatefulSets": "Stateful Sets",
|
||||
"menuItemTap": "Tap",
|
||||
"menuItemTop": "Top",
|
||||
"menuItemTrafficSplits": "Traffic Splits",
|
||||
"noResourcesDetectedMsg": "No resources detected.",
|
||||
"podsAreInitializingMsg": "Pods are initializing",
|
||||
"sidebarHeadingCluster": "Cluster",
|
||||
"sidebarHeadingConfiguration": "Configuration",
|
||||
"sidebarHeadingTools": "Tools",
|
||||
"sidebarHeadingWorkloads": "Workloads",
|
||||
"tableTitleEdgesEmpty": "Edges",
|
||||
"tableTitleEdgesWithIdentity {identity}": "Edges (Identity: {identity})",
|
||||
"tableTitleGateways": "Gateways",
|
||||
"tableTitleHTTPMetrics": "HTTP Metrics",
|
||||
"tableTitleInbound": "Inbound",
|
||||
"tableTitleLeafServices": "Leaf Services",
|
||||
"tableTitleOutbound": "Outbound",
|
||||
"tableTitlePods": "Pods",
|
||||
"tableTitleTCP": "TCP",
|
||||
"tableTitleTCPMetrics": "TCP Metrics",
|
||||
"unspecifiedResourcesMsg": "one or more resources",
|
||||
"{numUnadded} namespace has no meshed resources.": "{numUnadded} namespace has no meshed resources.",
|
||||
"{numUnadded} namespaces have no meshed resources.": "{numUnadded} namespaces have no meshed resourcesß",
|
||||
"{productName} namespace": "{productName} namespace",
|
||||
"{productName} version": "{productName} version"
|
||||
}
|
||||
|
|
|
@ -1,5 +1,104 @@
|
|||
{
|
||||
"Add {0} to the k8s.yml file<0/><1/>Then run {inject} to add it to the service mesh": "Agregue {0} a la k8s.yml file<0/><1/>Luego ejecuta {inject} para inyectarla en la malla de servicios",
|
||||
"No data to display": "No hay datos que mostrar",
|
||||
"one or more resources": "uno más recursos más"
|
||||
"404Msg": "Página no encontrada.",
|
||||
"Add {0} to the k8s.yml file<0/><1/>Then run {inject} to add it to the service mesh": "Agrega {0} al archivo k8s.yml<0/><1/>Luego ejecuta {inject} para inyectarlo en la malla de servicios",
|
||||
"All namespaces have a {productName} install.": "Todos los namespaces tienen una instalación de {productName}.",
|
||||
"Control plane components": "Componentes del plano de control",
|
||||
"Data plane proxies": "Proxies del plano de datos",
|
||||
"NoDataToDisplayMsg": "No hay datos que mostrar",
|
||||
"buttonReset": "Restablecer",
|
||||
"buttonRunLinkerdCheck": "Ejecutar Linkerd Check",
|
||||
"buttonStart": "Empezar",
|
||||
"buttonStop": "Terminar",
|
||||
"columnTitleAlive": "Vivo",
|
||||
"columnTitleApexService": "Servicio Apice",
|
||||
"columnTitleBest": "Mejor",
|
||||
"columnTitleClusterName": "Nombre del Clúster",
|
||||
"columnTitleCount": "Total",
|
||||
"columnTitleDeployment": "Deployment",
|
||||
"columnTitleDirection": "Dirección",
|
||||
"columnTitleGRPCStatus": "Estado GRPC",
|
||||
"columnTitleGrafana": "Grafana",
|
||||
"columnTitleHTTPStatus": "Estado HTTP",
|
||||
"columnTitleIdentity": "Identidad",
|
||||
"columnTitleJaeger": "Jaeger",
|
||||
"columnTitleLast": "Último",
|
||||
"columnTitleLatency": "Latencia",
|
||||
"columnTitleLeafService": "Servicio Hoja",
|
||||
"columnTitleMeshed": "En la malla de servicios",
|
||||
"columnTitleMeshedPods": "Pods en la malla de servicios",
|
||||
"columnTitleMeshedStatus": "Estado de la malla de servicios",
|
||||
"columnTitleMethod": "Método",
|
||||
"columnTitleName": "Nombre",
|
||||
"columnTitleNamespace": "Namespace",
|
||||
"columnTitleOpenConnections": "Conexiones",
|
||||
"columnTitleP50Latency": "Latencia P50",
|
||||
"columnTitleP95Latency": "Latencia P95",
|
||||
"columnTitleP99Latency": "Latencia P99",
|
||||
"columnTitlePairedServices": "Servicios Emparejados",
|
||||
"columnTitlePath": "Ruta",
|
||||
"columnTitlePodStatus": "Estado del Pod",
|
||||
"columnTitlePods": "Pods",
|
||||
"columnTitleRPS": "PPS",
|
||||
"columnTitleReadRate": "Lectura Bytes / seg",
|
||||
"columnTitleRoute": "Ruta",
|
||||
"columnTitleSecured": "Asegurado",
|
||||
"columnTitleService": "Servicio",
|
||||
"columnTitleSuccessRate": "Tasa de éxito",
|
||||
"columnTitleTap": "Tap",
|
||||
"columnTitleValue": "Valor",
|
||||
"columnTitleWeight": "Peso",
|
||||
"columnTitleWorst": "Peor",
|
||||
"columnTitleWriteRate": "Escritura Bytes / seg",
|
||||
"componentsMsg": "Componentes",
|
||||
"formAuthority": "Authority",
|
||||
"formHTTPMethod": "Método HTTP",
|
||||
"formHideFilters": "Ocultar filtros",
|
||||
"formMaxRPS": "Max PPS",
|
||||
"formNamespace": "Namespace",
|
||||
"formPath": "Ruta",
|
||||
"formScheme": "Esquema",
|
||||
"formShowFilters": "Mostrar más filtros",
|
||||
"formToNamespace": "Al Namespace",
|
||||
"formToResource": "Al Recurso",
|
||||
"menuItemCommunity": "Comunidad",
|
||||
"menuItemControlPlane": "Plano de Control",
|
||||
"menuItemCronJobs": "Cron Jobs",
|
||||
"menuItemDaemonSets": "Daemon Sets",
|
||||
"menuItemDeployments": "Deployments",
|
||||
"menuItemDocumentation": "Documentación",
|
||||
"menuItemGateway": "Gateway",
|
||||
"menuItemGitHub": "GitHub",
|
||||
"menuItemJobs": "Jobs",
|
||||
"menuItemMailingList": "Lista de Correo",
|
||||
"menuItemNamespaces": "Namespaces",
|
||||
"menuItemPods": "Pods",
|
||||
"menuItemReplicaSets": "Replica Sets",
|
||||
"menuItemReplicationControllers": "Replication Controllers",
|
||||
"menuItemRoutes": "Rutas",
|
||||
"menuItemSlack": "Slack",
|
||||
"menuItemStatefulSets": "Stateful Sets",
|
||||
"menuItemTap": "Tap",
|
||||
"menuItemTop": "Top",
|
||||
"menuItemTrafficSplits": "Traffic Splits",
|
||||
"noResourcesDetectedMsg": "No se han encontrado recursos.",
|
||||
"podsAreInitializingMsg": "Los pods se están inicializando",
|
||||
"sidebarHeadingCluster": "Clúster",
|
||||
"sidebarHeadingConfiguration": "Configuración",
|
||||
"sidebarHeadingTools": "Herramientas",
|
||||
"sidebarHeadingWorkloads": "Cargas de trabajo",
|
||||
"tableTitleEdgesEmpty": "Bordes",
|
||||
"tableTitleEdgesWithIdentity {identity}": "Bordes (Identidad: {identity})",
|
||||
"tableTitleGateways": "Gateways",
|
||||
"tableTitleHTTPMetrics": "Métricas HTTP",
|
||||
"tableTitleInbound": "Entrada",
|
||||
"tableTitleLeafServices": "Servicios Hoja",
|
||||
"tableTitleOutbound": "Salida",
|
||||
"tableTitlePods": "Pods",
|
||||
"tableTitleTCP": "TCP",
|
||||
"tableTitleTCPMetrics": "Métricas TCP",
|
||||
"unspecifiedResourcesMsg": "uno o más recursos",
|
||||
"{numUnadded} namespace has no meshed resources.": "El namespace {numUnadded} no tiene recursos en la malla de servicios.",
|
||||
"{numUnadded} namespaces have no meshed resources.": "Los namespaces {numUnadded} no tienen recursos en la malla de servicios.",
|
||||
"{productName} namespace": "Namespace de {productName}",
|
||||
"{productName} version": "Versión de {productName}"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue