feat(kubernetes): adding localization support
Signed-off-by: its-mitesh-kumar <itsmiteshkumar98@gmail.com>
This commit is contained in:
@@ -42,6 +42,8 @@ import {
|
||||
|
||||
import { StatusError, StatusOK } from '@backstage/core-components';
|
||||
import { PodMetricsContext } from '../../hooks/usePodMetrics';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
type ClusterSummaryProps = {
|
||||
clusterName: string;
|
||||
@@ -55,6 +57,7 @@ const ClusterSummary = ({
|
||||
totalNumberOfPods,
|
||||
numberOfPodsWithErrors,
|
||||
}: ClusterSummaryProps) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
@@ -75,7 +78,7 @@ const ClusterSummary = ({
|
||||
<Grid item xs>
|
||||
<Typography variant="body1">{clusterName}</Typography>
|
||||
<Typography color="textSecondary" variant="subtitle1">
|
||||
Cluster
|
||||
{t('cluster.label')}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
@@ -89,13 +92,17 @@ const ClusterSummary = ({
|
||||
spacing={0}
|
||||
>
|
||||
<Grid item>
|
||||
<StatusOK>{totalNumberOfPods} pods</StatusOK>
|
||||
<StatusOK>
|
||||
{totalNumberOfPods} {t('cluster.pods')}
|
||||
</StatusOK>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
{numberOfPodsWithErrors > 0 ? (
|
||||
<StatusError>{numberOfPodsWithErrors} pods with errors</StatusError>
|
||||
<StatusError>
|
||||
{numberOfPodsWithErrors} {t('cluster.podsWithErrors')}
|
||||
</StatusError>
|
||||
) : (
|
||||
<StatusOK>No pods with errors</StatusOK>
|
||||
<StatusOK>{t('cluster.noPodsWithErrors')}</StatusOK>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -18,6 +18,8 @@ import Typography from '@material-ui/core/Typography';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import type { V1ConfigMap } from '@kubernetes/client-node';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
export const ConfigmapsDrawer = ({
|
||||
configmap,
|
||||
@@ -26,6 +28,7 @@ export const ConfigmapsDrawer = ({
|
||||
configmap: V1ConfigMap;
|
||||
expanded?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const namespace = configmap.metadata?.namespace;
|
||||
return (
|
||||
<KubernetesStructuredMetadataTableDrawer
|
||||
@@ -55,7 +58,7 @@ export const ConfigmapsDrawer = ({
|
||||
</Grid>
|
||||
{namespace && (
|
||||
<Grid item>
|
||||
<Chip size="small" label={`namespace: ${namespace}`} />
|
||||
<Chip size="small" label={`${t('namespace.label')} ${namespace}`} />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
@@ -18,6 +18,8 @@ import { KubernetesStructuredMetadataTableDrawer } from '../KubernetesDrawer';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
export const CronJobDrawer = ({
|
||||
cronJob,
|
||||
@@ -26,6 +28,7 @@ export const CronJobDrawer = ({
|
||||
cronJob: V1CronJob;
|
||||
expanded?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const namespace = cronJob.metadata?.namespace;
|
||||
return (
|
||||
<KubernetesStructuredMetadataTableDrawer
|
||||
@@ -59,7 +62,7 @@ export const CronJobDrawer = ({
|
||||
</Grid>
|
||||
{namespace && (
|
||||
<Grid item>
|
||||
<Chip size="small" label={`namespace: ${namespace}`} />
|
||||
<Chip size="small" label={`${t('namespace.label')} ${namespace}`} />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
@@ -39,6 +39,8 @@ import {
|
||||
} from '../../../utils/owner';
|
||||
import { StatusError, StatusOK } from '@backstage/core-components';
|
||||
import { READY_COLUMNS, RESOURCE_COLUMNS } from '../../Pods/PodsTable';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../../translation';
|
||||
|
||||
type RolloutAccordionsProps = {
|
||||
rollouts: any[];
|
||||
@@ -89,6 +91,7 @@ const RolloutSummary = ({
|
||||
numberOfPodsWithErrors,
|
||||
hpa,
|
||||
}: RolloutSummaryProps) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const pauseTime: string | undefined = rollout.status?.pauseConditions?.find(
|
||||
(p: any) => p.reason === 'CanaryPauseStep',
|
||||
)?.startTime;
|
||||
@@ -125,18 +128,18 @@ const RolloutSummary = ({
|
||||
>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle2">
|
||||
min replicas {hpa.spec?.minReplicas ?? '?'} / max replicas{' '}
|
||||
{hpa.spec?.maxReplicas ?? '?'}
|
||||
{t('hpa.minReplicas')} {hpa.spec?.minReplicas ?? '?'} /{' '}
|
||||
{t('hpa.maxReplicas')} {hpa.spec?.maxReplicas ?? '?'}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle2">
|
||||
current CPU usage: {cpuUtil ?? '?'}%
|
||||
{t('hpa.currentCpuUsage')} {cpuUtil ?? '?'}%
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle2">
|
||||
target CPU usage: {specCpuUtil ?? '?'}%
|
||||
{t('hpa.targetCpuUsage')} {specCpuUtil ?? '?'}%
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
@@ -153,16 +156,15 @@ const RolloutSummary = ({
|
||||
spacing={0}
|
||||
>
|
||||
<Grid item>
|
||||
<StatusOK>{numberOfCurrentPods} pods</StatusOK>
|
||||
<StatusOK>{t('pods.pods', { count: numberOfCurrentPods })}</StatusOK>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
{numberOfPodsWithErrors > 0 ? (
|
||||
<StatusError>
|
||||
{numberOfPodsWithErrors} pod
|
||||
{numberOfPodsWithErrors > 1 ? 's' : ''} with errors
|
||||
{t('cluster.podWithErrors', { count: numberOfPodsWithErrors })}
|
||||
</StatusError>
|
||||
) : (
|
||||
<StatusOK>No pods with errors</StatusOK>
|
||||
<StatusOK>{t('cluster.noPodsWithErrors')}</StatusOK>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
+4
-1
@@ -18,6 +18,8 @@ import { KubernetesStructuredMetadataTableDrawer } from '../../KubernetesDrawer'
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../../translation';
|
||||
|
||||
export const RolloutDrawer = ({
|
||||
rollout,
|
||||
@@ -26,6 +28,7 @@ export const RolloutDrawer = ({
|
||||
rollout: any;
|
||||
expanded?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const namespace = rollout.metadata?.namespace;
|
||||
return (
|
||||
<KubernetesStructuredMetadataTableDrawer
|
||||
@@ -53,7 +56,7 @@ export const RolloutDrawer = ({
|
||||
</Grid>
|
||||
{namespace && (
|
||||
<Grid item>
|
||||
<Chip size="small" label={`namespace: ${namespace}`} />
|
||||
<Chip size="small" label={`${t('namespace.label')} ${namespace}`} />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
+6
-4
@@ -30,6 +30,8 @@ import {
|
||||
} from '../../hooks';
|
||||
import { StatusError, StatusOK } from '@backstage/core-components';
|
||||
import { READY_COLUMNS, RESOURCE_COLUMNS } from '../Pods/PodsTable';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
type DaemonSetsAccordionsProps = {
|
||||
children?: ReactNode;
|
||||
@@ -53,6 +55,7 @@ const DaemonSetSummary = ({
|
||||
numberOfCurrentPods,
|
||||
numberOfPodsWithErrors,
|
||||
}: DaemonSetSummaryProps) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
@@ -74,16 +77,15 @@ const DaemonSetSummary = ({
|
||||
spacing={0}
|
||||
>
|
||||
<Grid item>
|
||||
<StatusOK>{numberOfCurrentPods} pods</StatusOK>
|
||||
<StatusOK>{t('pods.pods', { count: numberOfCurrentPods })}</StatusOK>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
{numberOfPodsWithErrors > 0 ? (
|
||||
<StatusError>
|
||||
{numberOfPodsWithErrors} pod
|
||||
{numberOfPodsWithErrors > 1 ? 's' : ''} with errors
|
||||
{t('cluster.podWithErrors', { count: numberOfPodsWithErrors })}
|
||||
</StatusError>
|
||||
) : (
|
||||
<StatusOK>No pods with errors</StatusOK>
|
||||
<StatusOK>{t('cluster.noPodsWithErrors')}</StatusOK>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -19,6 +19,8 @@ import { KubernetesStructuredMetadataTableDrawer } from '../KubernetesDrawer';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
export const DaemonSetDrawer = ({
|
||||
daemonset,
|
||||
@@ -27,6 +29,7 @@ export const DaemonSetDrawer = ({
|
||||
daemonset: V1DaemonSet;
|
||||
expanded?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const namespace = daemonset.metadata?.namespace;
|
||||
return (
|
||||
<KubernetesStructuredMetadataTableDrawer
|
||||
@@ -68,7 +71,7 @@ export const DaemonSetDrawer = ({
|
||||
</Grid>
|
||||
{namespace && (
|
||||
<Grid item>
|
||||
<Chip size="small" label={`namespace: ${namespace}`} />
|
||||
<Chip size="small" label={`${t('namespace.label')} ${namespace}`} />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
@@ -21,6 +21,8 @@ import { renderCondition } from '../../utils/pod';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
export const DeploymentDrawer = ({
|
||||
deployment,
|
||||
@@ -29,6 +31,7 @@ export const DeploymentDrawer = ({
|
||||
deployment: V1Deployment;
|
||||
expanded?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const namespace = deployment.metadata?.namespace;
|
||||
return (
|
||||
<KubernetesStructuredMetadataTableDrawer
|
||||
@@ -71,7 +74,7 @@ export const DeploymentDrawer = ({
|
||||
</Grid>
|
||||
{namespace && (
|
||||
<Grid item>
|
||||
<Chip size="small" label={`namespace: ${namespace}`} />
|
||||
<Chip size="small" label={`${t('namespace.label')} ${namespace}`} />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
+10
-8
@@ -39,6 +39,8 @@ import {
|
||||
} from '../../hooks';
|
||||
import { StatusError, StatusOK } from '@backstage/core-components';
|
||||
import { READY_COLUMNS, RESOURCE_COLUMNS } from '../Pods/PodsTable';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
type DeploymentsAccordionsProps = {
|
||||
children?: ReactNode;
|
||||
@@ -65,6 +67,7 @@ const DeploymentSummary = ({
|
||||
numberOfPodsWithErrors,
|
||||
hpa,
|
||||
}: DeploymentSummaryProps) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const specCpuUtil = hpa?.spec?.metrics?.find(
|
||||
metric => metric.type === 'Resource' && metric.resource?.name === 'cpu',
|
||||
)?.resource?.target.averageUtilization;
|
||||
@@ -97,18 +100,18 @@ const DeploymentSummary = ({
|
||||
>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle2">
|
||||
min replicas {hpa.spec?.minReplicas ?? '?'} / max replicas{' '}
|
||||
{hpa.spec?.maxReplicas ?? '?'}
|
||||
{t('hpa.minReplicas')} {hpa.spec?.minReplicas ?? '?'} /{' '}
|
||||
{t('hpa.maxReplicas')} {hpa.spec?.maxReplicas ?? '?'}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle2">
|
||||
current CPU usage: {cpuUtil ?? '?'}%
|
||||
{t('hpa.currentCpuUsage')} {cpuUtil ?? '?'}%
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle2">
|
||||
target CPU usage: {specCpuUtil ?? '?'}%
|
||||
{t('hpa.targetCpuUsage')} {specCpuUtil ?? '?'}%
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
@@ -125,16 +128,15 @@ const DeploymentSummary = ({
|
||||
spacing={0}
|
||||
>
|
||||
<Grid item>
|
||||
<StatusOK>{numberOfCurrentPods} pods</StatusOK>
|
||||
<StatusOK>{t('pods.pods', { count: numberOfCurrentPods })}</StatusOK>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
{numberOfPodsWithErrors > 0 ? (
|
||||
<StatusError>
|
||||
{numberOfPodsWithErrors} pod
|
||||
{numberOfPodsWithErrors > 1 ? 's' : ''} with errors
|
||||
{t('cluster.podWithErrors', { count: numberOfPodsWithErrors })}
|
||||
</StatusError>
|
||||
) : (
|
||||
<StatusOK>No pods with errors</StatusOK>
|
||||
<StatusOK>{t('cluster.noPodsWithErrors')}</StatusOK>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -18,22 +18,35 @@ import { ReactNode } from 'react';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { ClusterObjects } from '@backstage/plugin-kubernetes-common';
|
||||
import { WarningPanel } from '@backstage/core-components';
|
||||
import {
|
||||
useTranslationRef,
|
||||
TranslationFunction,
|
||||
} from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
const clustersWithErrorsToErrorMessage = (
|
||||
clustersWithErrors: ClusterObjects[],
|
||||
t: TranslationFunction<typeof kubernetesReactTranslationRef.T>,
|
||||
): ReactNode => {
|
||||
return clustersWithErrors.map((c, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<Typography variant="body2">{`Cluster: ${
|
||||
c.cluster.title || c.cluster.name
|
||||
}`}</Typography>
|
||||
<Typography variant="body2">
|
||||
{t('errorPanel.clusterLabel')}: {c.cluster.title || c.cluster.name}
|
||||
</Typography>
|
||||
{c.errors.map((e, j) => {
|
||||
return (
|
||||
<Typography variant="body2" key={j}>
|
||||
{e.errorType === 'FETCH_ERROR'
|
||||
? `Error communicating with Kubernetes: ${e.errorType}, message: ${e.message}`
|
||||
: `Error fetching Kubernetes resource: '${e.resourcePath}', error: ${e.errorType}, status code: ${e.statusCode}`}
|
||||
? t('errorPanel.fetchError', {
|
||||
errorType: e.errorType,
|
||||
message: e.message,
|
||||
})
|
||||
: t('errorPanel.resourceError', {
|
||||
resourcePath: e.resourcePath ?? '',
|
||||
errorType: e.errorType,
|
||||
statusCode: String(e.statusCode ?? ''),
|
||||
})}
|
||||
</Typography>
|
||||
);
|
||||
})}
|
||||
@@ -64,16 +77,24 @@ export const ErrorPanel = ({
|
||||
entityName,
|
||||
errorMessage,
|
||||
clustersWithErrors,
|
||||
}: ErrorPanelProps) => (
|
||||
<WarningPanel
|
||||
title="There was a problem retrieving Kubernetes objects"
|
||||
message={`There was a problem retrieving some Kubernetes resources for the entity: ${entityName}. This could mean that the Error Reporting card is not completely accurate.`}
|
||||
>
|
||||
{clustersWithErrors && (
|
||||
<div>Errors: {clustersWithErrorsToErrorMessage(clustersWithErrors)}</div>
|
||||
)}
|
||||
{errorMessage && (
|
||||
<Typography variant="body2">Errors: {errorMessage}</Typography>
|
||||
)}
|
||||
</WarningPanel>
|
||||
);
|
||||
}: ErrorPanelProps) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
return (
|
||||
<WarningPanel
|
||||
title={t('errorPanel.title')}
|
||||
message={t('errorPanel.message', { entityName })}
|
||||
>
|
||||
{clustersWithErrors && (
|
||||
<div>
|
||||
{t('errorPanel.errorsLabel')}:{' '}
|
||||
{clustersWithErrorsToErrorMessage(clustersWithErrors, t)}
|
||||
</div>
|
||||
)}
|
||||
{errorMessage && (
|
||||
<Typography variant="body2">
|
||||
{t('errorPanel.errorsLabel')}: {errorMessage}
|
||||
</Typography>
|
||||
)}
|
||||
</WarningPanel>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -19,6 +19,8 @@ import {
|
||||
DetectedErrorsByCluster,
|
||||
} from '@backstage/plugin-kubernetes-common';
|
||||
import { Table, TableColumn } from '@backstage/core-components';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -30,36 +32,6 @@ export type ErrorReportingProps = {
|
||||
clusters: ClusterAttributes[];
|
||||
};
|
||||
|
||||
const columns: TableColumn<Row>[] = [
|
||||
{
|
||||
title: 'cluster',
|
||||
width: '10%',
|
||||
render: (row: Row) => row.cluster.title || row.cluster.name,
|
||||
},
|
||||
{
|
||||
title: 'namespace',
|
||||
width: '10%',
|
||||
render: (row: Row) => row.error.sourceRef.namespace,
|
||||
},
|
||||
{
|
||||
title: 'kind',
|
||||
width: '10%',
|
||||
render: (row: Row) => row.error.sourceRef.kind,
|
||||
},
|
||||
{
|
||||
title: 'name',
|
||||
width: '30%',
|
||||
render: (row: Row) => {
|
||||
return <>{row.error.sourceRef.name} </>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'messages',
|
||||
width: '40%',
|
||||
render: (row: Row) => row.error.message,
|
||||
},
|
||||
];
|
||||
|
||||
interface Row {
|
||||
cluster: ClusterAttributes;
|
||||
error: DetectedError;
|
||||
@@ -83,6 +55,7 @@ export const ErrorReporting = ({
|
||||
detectedErrors,
|
||||
clusters,
|
||||
}: ErrorReportingProps) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const errors = Array.from(detectedErrors.entries())
|
||||
.flatMap(([clusterName, resourceErrors]) => {
|
||||
return resourceErrors.map(e => ({
|
||||
@@ -92,11 +65,41 @@ export const ErrorReporting = ({
|
||||
})
|
||||
.sort(sortBySeverity);
|
||||
|
||||
const columns: TableColumn<Row>[] = [
|
||||
{
|
||||
title: String(t('errorReporting.columns.cluster')),
|
||||
width: '10%',
|
||||
render: (row: Row) => row.cluster.title || row.cluster.name,
|
||||
},
|
||||
{
|
||||
title: String(t('errorReporting.columns.namespace')),
|
||||
width: '10%',
|
||||
render: (row: Row) => row.error.sourceRef.namespace,
|
||||
},
|
||||
{
|
||||
title: String(t('errorReporting.columns.kind')),
|
||||
width: '10%',
|
||||
render: (row: Row) => row.error.sourceRef.kind,
|
||||
},
|
||||
{
|
||||
title: String(t('errorReporting.columns.name')),
|
||||
width: '30%',
|
||||
render: (row: Row) => {
|
||||
return <>{row.error.sourceRef.name} </>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: String(t('errorReporting.columns.messages')),
|
||||
width: '40%',
|
||||
render: (row: Row) => row.error.message,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{errors.length !== 0 && (
|
||||
<Table
|
||||
title="Error Reporting"
|
||||
title={t('errorReporting.title')}
|
||||
data={errors}
|
||||
columns={columns}
|
||||
options={{ paging: true, search: false, emptyRowsWhenPaging: false }}
|
||||
|
||||
@@ -19,6 +19,8 @@ import { KubernetesStructuredMetadataTableDrawer } from '../KubernetesDrawer';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
export const IngressDrawer = ({
|
||||
ingress,
|
||||
@@ -27,6 +29,7 @@ export const IngressDrawer = ({
|
||||
ingress: V1Ingress;
|
||||
expanded?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const namespace = ingress.metadata?.namespace;
|
||||
return (
|
||||
<KubernetesStructuredMetadataTableDrawer
|
||||
@@ -56,7 +59,7 @@ export const IngressDrawer = ({
|
||||
</Grid>
|
||||
{namespace && (
|
||||
<Grid item>
|
||||
<Chip size="small" label={`namespace: ${namespace}`} />
|
||||
<Chip size="small" label={`${t('namespace.label')} ${namespace}`} />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
@@ -22,6 +22,8 @@ import IconButton from '@material-ui/core/IconButton';
|
||||
import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import { ReactNode, useState } from 'react';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -59,6 +61,7 @@ export const KubernetesDialog = ({
|
||||
title,
|
||||
}: KubernetesDialogProps) => {
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const openDialog = () => {
|
||||
@@ -80,7 +83,7 @@ export const KubernetesDialog = ({
|
||||
<DialogTitle id="dialog-title">
|
||||
{title}
|
||||
<IconButton
|
||||
aria-label="close"
|
||||
aria-label={t('kubernetesDialog.closeAriaLabel')}
|
||||
className={classes.closeButton}
|
||||
onClick={closeDialog}
|
||||
>
|
||||
|
||||
@@ -31,6 +31,8 @@ import {
|
||||
} from '@material-ui/core/styles';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import { ManifestYaml } from './ManifestYaml';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
const useDrawerContentStyles = makeStyles((_theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -72,6 +74,7 @@ const KubernetesDrawerContent = ({
|
||||
close,
|
||||
}: KubernetesDrawerContentProps) => {
|
||||
const classes = useDrawerContentStyles();
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const [isYaml, setIsYaml] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
@@ -86,7 +89,7 @@ const KubernetesDrawerContent = ({
|
||||
<Grid item xs={1}>
|
||||
<IconButton
|
||||
key="dismiss"
|
||||
title="Close the drawer"
|
||||
title={t('kubernetesDrawer.closeDrawer')}
|
||||
onClick={() => close()}
|
||||
color="inherit"
|
||||
>
|
||||
@@ -104,10 +107,10 @@ const KubernetesDrawerContent = ({
|
||||
onChange={event => {
|
||||
setIsYaml(event.target.checked);
|
||||
}}
|
||||
name="YAML"
|
||||
name={t('kubernetesDrawer.yaml')}
|
||||
/>
|
||||
}
|
||||
label="YAML"
|
||||
label={t('kubernetesDrawer.yaml')}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
+25
-18
@@ -38,6 +38,8 @@ import { ManifestYaml } from './ManifestYaml';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { kubernetesClusterLinkFormatterApiRef } from '../../api';
|
||||
import useAsync from 'react-use/esm/useAsync';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
const useDrawerStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -102,20 +104,24 @@ export type LinkErrorPanelProps = {
|
||||
export const LinkErrorPanel = ({
|
||||
cluster,
|
||||
errorMessage,
|
||||
}: LinkErrorPanelProps) => (
|
||||
<WarningPanel
|
||||
title="There was a problem formatting the link to the Kubernetes dashboard"
|
||||
message={`Could not format the link to the dashboard of your cluster named '${
|
||||
cluster.name
|
||||
}'. Its dashboardApp property has been set to '${
|
||||
cluster.dashboardApp || 'standard'
|
||||
}.'`}
|
||||
>
|
||||
{errorMessage && (
|
||||
<Typography variant="body2">Errors: {errorMessage}</Typography>
|
||||
)}
|
||||
</WarningPanel>
|
||||
);
|
||||
}: LinkErrorPanelProps) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
return (
|
||||
<WarningPanel
|
||||
title={t('linkErrorPanel.title')}
|
||||
message={t('linkErrorPanel.message', {
|
||||
clusterName: cluster.name,
|
||||
dashboardApp: cluster.dashboardApp || 'standard',
|
||||
})}
|
||||
>
|
||||
{errorMessage && (
|
||||
<Typography variant="body2">
|
||||
{t('linkErrorPanel.errorsLabel')} {errorMessage}
|
||||
</Typography>
|
||||
)}
|
||||
</WarningPanel>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -152,6 +158,7 @@ const KubernetesStructuredMetadataTableDrawerContent = <
|
||||
renderObject,
|
||||
kind,
|
||||
}: KubernetesStructuredMetadataTableDrawerContentProps<T>) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const [isYaml, setIsYaml] = useState<boolean>(false);
|
||||
|
||||
const formatter = useApi(kubernetesClusterLinkFormatterApiRef);
|
||||
@@ -175,13 +182,13 @@ const KubernetesStructuredMetadataTableDrawerContent = <
|
||||
<Grid container justifyContent="flex-start" alignItems="flex-start">
|
||||
<Grid item xs={11}>
|
||||
<Typography variant="h5">
|
||||
{object.metadata?.name ?? 'unknown name'}
|
||||
{object.metadata?.name ?? t('kubernetesDrawer.unknownName')}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={1}>
|
||||
<IconButton
|
||||
key="dismiss"
|
||||
title="Close the drawer"
|
||||
title={t('kubernetesDrawer.closeDrawer')}
|
||||
onClick={e => toggleDrawer(e, false)}
|
||||
color="inherit"
|
||||
>
|
||||
@@ -201,10 +208,10 @@ const KubernetesStructuredMetadataTableDrawerContent = <
|
||||
onChange={event => {
|
||||
setIsYaml(event.target.checked);
|
||||
}}
|
||||
name="YAML"
|
||||
name={t('kubernetesDrawer.yaml')}
|
||||
/>
|
||||
}
|
||||
label="YAML"
|
||||
label={t('kubernetesDrawer.yaml')}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -18,6 +18,8 @@ import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||
import Switch from '@material-ui/core/Switch';
|
||||
import jsyaml from 'js-yaml';
|
||||
import { useState } from 'react';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
/**
|
||||
* Props of ManifestYaml
|
||||
@@ -34,6 +36,7 @@ export interface ManifestYamlProps {
|
||||
* @public
|
||||
*/
|
||||
export const ManifestYaml = ({ object }: ManifestYamlProps) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
// Toggle whether the Kubernetes resource managed fields should be shown in
|
||||
// the YAML display. This toggle is only available when the YAML is being
|
||||
// shown because managed fields are never visible in the structured display.
|
||||
@@ -47,10 +50,10 @@ export const ManifestYaml = ({ object }: ManifestYamlProps) => {
|
||||
onChange={event => {
|
||||
setManagedFields(event.target.checked);
|
||||
}}
|
||||
name="Managed Fields"
|
||||
name={t('kubernetesDrawer.managedFields')}
|
||||
/>
|
||||
}
|
||||
label="Managed Fields"
|
||||
label={t('kubernetesDrawer.managedFields')}
|
||||
/>
|
||||
<CodeSnippet
|
||||
language="yaml"
|
||||
|
||||
@@ -19,6 +19,8 @@ import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser';
|
||||
import { KubernetesDialog } from '../KubernetesDialog';
|
||||
import { useIsPodExecTerminalSupported } from '../../hooks';
|
||||
import { PodExecTerminal, PodExecTerminalProps } from './PodExecTerminal';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
/**
|
||||
* Opens a terminal connected to the given pod's container in a dialog
|
||||
@@ -27,23 +29,25 @@ import { PodExecTerminal, PodExecTerminalProps } from './PodExecTerminal';
|
||||
*/
|
||||
export const PodExecTerminalDialog = (props: PodExecTerminalProps) => {
|
||||
const { cluster, containerName, podName } = props;
|
||||
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const isPodExecTerminalSupported = useIsPodExecTerminalSupported();
|
||||
|
||||
return (
|
||||
!isPodExecTerminalSupported.loading &&
|
||||
isPodExecTerminalSupported.value && (
|
||||
<KubernetesDialog
|
||||
buttonAriaLabel="open terminal"
|
||||
buttonAriaLabel={t('podExecTerminal.buttonAriaLabel')}
|
||||
buttonIcon={<OpenInBrowserIcon />}
|
||||
buttonText="Terminal"
|
||||
buttonText={t('podExecTerminal.buttonText')}
|
||||
disabled={
|
||||
isPodExecTerminalSupported.loading ||
|
||||
!isPodExecTerminalSupported.value
|
||||
}
|
||||
title={`${podName} - ${containerName} terminal shell on cluster ${
|
||||
cluster.title || cluster.name
|
||||
}`}
|
||||
title={t('podExecTerminal.titleTemplate', {
|
||||
podName,
|
||||
containerName,
|
||||
clusterName: cluster.title || cluster.name,
|
||||
})}
|
||||
>
|
||||
<PodExecTerminal {...props} />
|
||||
</KubernetesDialog>
|
||||
|
||||
@@ -31,6 +31,8 @@ import { useEvents } from './useEvents';
|
||||
import Skeleton from '@material-ui/lab/Skeleton';
|
||||
import { DismissableBanner } from '@backstage/core-components';
|
||||
import { Event } from 'kubernetes-models/v1';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../../translation';
|
||||
|
||||
/**
|
||||
* Props for Events
|
||||
@@ -59,8 +61,9 @@ export const EventsContent = ({
|
||||
events,
|
||||
warningEventsOnly,
|
||||
}: EventsContentProps) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
if (events.length === 0) {
|
||||
return <Typography>No events found</Typography>;
|
||||
return <Typography>{t('events.noEventsFound')}</Typography>;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -35,6 +35,8 @@ import { Events } from '../Events';
|
||||
import { LinkButton } from '@backstage/core-components';
|
||||
import List from '@material-ui/core/List';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../../translation';
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -72,6 +74,7 @@ export const FixDialog: FC<FixDialogProps> = ({
|
||||
}: FixDialogProps) => {
|
||||
const [isOpen, setOpen] = useState(!!open);
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
|
||||
const openDialog = () => {
|
||||
setOpen(true);
|
||||
@@ -87,21 +90,27 @@ export const FixDialog: FC<FixDialogProps> = ({
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h6">Detected error:</Typography>
|
||||
<Typography variant="h6">{t('fixDialog.detectedError')}</Typography>
|
||||
<Typography>{error.message}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h6">Cause explanation:</Typography>
|
||||
<Typography variant="h6">
|
||||
{t('fixDialog.causeExplanation')}
|
||||
</Typography>
|
||||
<Typography>
|
||||
{error.proposedFix?.rootCauseExplanation ?? 'unknown'}
|
||||
{error.proposedFix?.rootCauseExplanation ?? t('podsTable.unknown')}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h6">Fix:</Typography>
|
||||
<Typography variant="h6">{t('fixDialog.fix')}</Typography>
|
||||
<List>
|
||||
{(error.proposedFix?.actions ?? []).map((fix, i) => {
|
||||
return (
|
||||
<ListItem key={`${pod.metadata?.name ?? 'unknown'}-pf-${i}`}>
|
||||
<ListItem
|
||||
key={`${
|
||||
pod.metadata?.name ?? t('podsTable.unknown')
|
||||
}-pf-${i}`}
|
||||
>
|
||||
{fix}
|
||||
</ListItem>
|
||||
);
|
||||
@@ -112,14 +121,15 @@ export const FixDialog: FC<FixDialogProps> = ({
|
||||
{pf && pf.type === 'logs' && (
|
||||
<>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h6">Crash logs:</Typography>
|
||||
<Typography variant="h6">{t('fixDialog.crashLogs')}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={9}>
|
||||
<PodLogs
|
||||
previous
|
||||
containerScope={{
|
||||
podName: pod.metadata?.name ?? 'unknown',
|
||||
podNamespace: pod.metadata?.namespace ?? 'unknown',
|
||||
podName: pod.metadata?.name ?? t('podsTable.unknown'),
|
||||
podNamespace:
|
||||
pod.metadata?.namespace ?? t('podsTable.unknown'),
|
||||
cluster: { name: clusterName },
|
||||
containerName: pf.container,
|
||||
}}
|
||||
@@ -130,7 +140,7 @@ export const FixDialog: FC<FixDialogProps> = ({
|
||||
{pf && pf.type === 'events' && (
|
||||
<>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h6">Events:</Typography>
|
||||
<Typography variant="h6">{t('fixDialog.events')}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={9}>
|
||||
<Events
|
||||
@@ -150,18 +160,21 @@ export const FixDialog: FC<FixDialogProps> = ({
|
||||
<>
|
||||
<Button
|
||||
variant="outlined"
|
||||
aria-label="fix issue"
|
||||
aria-label={t('fixDialog.ariaLabels.fixIssue')}
|
||||
component="label"
|
||||
onClick={openDialog}
|
||||
startIcon={<HelpIcon />}
|
||||
>
|
||||
Help
|
||||
{t('fixDialog.helpButton')}
|
||||
</Button>
|
||||
<Dialog maxWidth="xl" fullWidth open={isOpen} onClose={closeDialog}>
|
||||
<DialogTitle id="dialog-title">
|
||||
{pod.metadata?.name} - {error.type}
|
||||
{t('fixDialog.title', {
|
||||
podName: pod.metadata?.name ?? '',
|
||||
errorType: error.type,
|
||||
})}
|
||||
<IconButton
|
||||
aria-label="close"
|
||||
aria-label={t('fixDialog.ariaLabels.close')}
|
||||
className={classes.closeButton}
|
||||
onClick={closeDialog}
|
||||
>
|
||||
@@ -178,7 +191,7 @@ export const FixDialog: FC<FixDialogProps> = ({
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
Open docs
|
||||
{t('fixDialog.openDocs')}
|
||||
</LinkButton>
|
||||
)}
|
||||
</DialogActions>
|
||||
|
||||
@@ -30,6 +30,8 @@ import { bytesToMiB, formatMillicores } from '../../../utils/resources';
|
||||
import { PodExecTerminalDialog } from '../../PodExecTerminal/PodExecTerminalDialog';
|
||||
import { ResourceUtilization } from '../../ResourceUtilization';
|
||||
import { PodLogsDialog, PodScope } from '../PodLogs';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../../translation';
|
||||
|
||||
const getContainerHealthChecks = (
|
||||
containerSpec: IContainer,
|
||||
@@ -112,6 +114,7 @@ export const ContainerCard: FC<ContainerCardProps> = ({
|
||||
containerStatus,
|
||||
containerMetrics,
|
||||
}: ContainerCardProps) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const isPodExecTerminalEnabled = useIsPodExecTerminalEnabled();
|
||||
|
||||
// This should never be undefined
|
||||
@@ -183,13 +186,13 @@ export const ContainerCard: FC<ContainerCardProps> = ({
|
||||
<Grid container item xs={12} spacing={0}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="subtitle1">
|
||||
Resource utilization
|
||||
{t('podDrawer.resourceUtilization')}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} style={{ minHeight: '5rem' }}>
|
||||
<ResourceUtilization
|
||||
compressed
|
||||
title="CPU requests"
|
||||
title={t('podDrawer.cpuRequests')}
|
||||
usage={containerMetrics.cpuUsage.currentUsage}
|
||||
total={containerMetrics.cpuUsage.requestTotal}
|
||||
totalFormatted={formatMillicores(
|
||||
@@ -198,7 +201,7 @@ export const ContainerCard: FC<ContainerCardProps> = ({
|
||||
/>
|
||||
<ResourceUtilization
|
||||
compressed
|
||||
title="CPU limits"
|
||||
title={t('podDrawer.cpuLimits')}
|
||||
usage={containerMetrics.cpuUsage.currentUsage}
|
||||
total={containerMetrics.cpuUsage.limitTotal}
|
||||
totalFormatted={formatMillicores(
|
||||
@@ -207,7 +210,7 @@ export const ContainerCard: FC<ContainerCardProps> = ({
|
||||
/>
|
||||
<ResourceUtilization
|
||||
compressed
|
||||
title="Memory requests"
|
||||
title={t('podDrawer.memoryRequests')}
|
||||
usage={containerMetrics.memoryUsage.currentUsage}
|
||||
total={containerMetrics.memoryUsage.requestTotal}
|
||||
totalFormatted={bytesToMiB(
|
||||
@@ -216,7 +219,7 @@ export const ContainerCard: FC<ContainerCardProps> = ({
|
||||
/>
|
||||
<ResourceUtilization
|
||||
compressed
|
||||
title="Memory limits"
|
||||
title={t('podDrawer.memoryLimits')}
|
||||
usage={containerMetrics.memoryUsage.currentUsage}
|
||||
total={containerMetrics.memoryUsage.limitTotal}
|
||||
totalFormatted={bytesToMiB(
|
||||
|
||||
@@ -32,6 +32,8 @@ import { usePodMetrics } from '../../../hooks/usePodMetrics';
|
||||
import { ResourceUtilization } from '../../ResourceUtilization';
|
||||
import { bytesToMiB, formatMillicores } from '../../../utils/resources';
|
||||
import { useIsPodDeleteEnabled } from '../../../hooks';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../../translation';
|
||||
|
||||
const useDrawerContentStyles = makeStyles((_theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -77,6 +79,7 @@ export const PodDrawer = ({ podAndErrors, open }: PodDrawerProps) => {
|
||||
const classes = useDrawerContentStyles();
|
||||
const podMetrics = usePodMetrics(podAndErrors.cluster.name, podAndErrors.pod);
|
||||
const isPodDeleteEnabled = useIsPodDeleteEnabled();
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
|
||||
return (
|
||||
<KubernetesDrawer
|
||||
@@ -108,17 +111,19 @@ export const PodDrawer = ({ podAndErrors, open }: PodDrawerProps) => {
|
||||
{podMetrics && (
|
||||
<Grid container item xs={12}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h5">Resource utilization</Typography>
|
||||
<Typography variant="h5">
|
||||
{t('podDrawer.resourceUtilization')}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<ResourceUtilization
|
||||
title="CPU requests"
|
||||
title={t('podDrawer.cpuRequests')}
|
||||
usage={podMetrics.cpu.currentUsage}
|
||||
total={podMetrics.cpu.requestTotal}
|
||||
totalFormatted={formatMillicores(podMetrics.cpu.requestTotal)}
|
||||
/>
|
||||
<ResourceUtilization
|
||||
title="CPU limits"
|
||||
title={t('podDrawer.cpuLimits')}
|
||||
usage={podMetrics.cpu.currentUsage}
|
||||
total={podMetrics.cpu.limitTotal}
|
||||
totalFormatted={formatMillicores(podMetrics.cpu.limitTotal)}
|
||||
@@ -126,13 +131,13 @@ export const PodDrawer = ({ podAndErrors, open }: PodDrawerProps) => {
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<ResourceUtilization
|
||||
title="Memory requests"
|
||||
title={t('podDrawer.memoryRequests')}
|
||||
usage={podMetrics.memory.currentUsage}
|
||||
total={podMetrics.memory.requestTotal}
|
||||
totalFormatted={bytesToMiB(podMetrics.memory.requestTotal)}
|
||||
/>
|
||||
<ResourceUtilization
|
||||
title="Memory limits"
|
||||
title={t('podDrawer.memoryLimits')}
|
||||
usage={podMetrics.memory.currentUsage}
|
||||
total={podMetrics.memory.limitTotal}
|
||||
totalFormatted={bytesToMiB(podMetrics.memory.limitTotal)}
|
||||
|
||||
@@ -25,6 +25,8 @@ import Skeleton from '@material-ui/lab/Skeleton';
|
||||
|
||||
import { ContainerScope } from './types';
|
||||
import { usePodLogs } from './usePodLogs';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../../translation';
|
||||
|
||||
/**
|
||||
* Props for PodLogs
|
||||
@@ -45,6 +47,7 @@ export const PodLogs: FC<PodLogsProps> = ({
|
||||
containerScope,
|
||||
previous,
|
||||
}: PodLogsProps) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const { value, error, loading } = usePodLogs({
|
||||
containerScope,
|
||||
previous,
|
||||
@@ -72,8 +75,8 @@ export const PodLogs: FC<PodLogsProps> = ({
|
||||
(value.text === '' ? (
|
||||
<EmptyState
|
||||
missing="data"
|
||||
title="No logs emitted"
|
||||
description="No logs were emitted by the container"
|
||||
title={t('podLogs.title')}
|
||||
description={t('podLogs.description')}
|
||||
/>
|
||||
) : (
|
||||
<LogViewer text={value.text} />
|
||||
|
||||
@@ -18,6 +18,8 @@ import SubjectIcon from '@material-ui/icons/Subject';
|
||||
import { KubernetesDialog } from '../../KubernetesDialog';
|
||||
import { PodLogs } from './PodLogs';
|
||||
import { ContainerScope } from './types';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../../translation';
|
||||
|
||||
/**
|
||||
* Props for PodLogsDialog
|
||||
@@ -34,17 +36,19 @@ export interface PodLogsDialogProps {
|
||||
* @public
|
||||
*/
|
||||
export const PodLogsDialog = ({ containerScope }: PodLogsDialogProps) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
return (
|
||||
<KubernetesDialog
|
||||
buttonAriaLabel="get logs"
|
||||
buttonAriaLabel={t('podLogs.buttonAriaLabel')}
|
||||
buttonIcon={<SubjectIcon />}
|
||||
buttonText="Logs"
|
||||
buttonText={t('podLogs.buttonText')}
|
||||
disabled={false}
|
||||
title={`${containerScope.podName} - ${
|
||||
containerScope.containerName
|
||||
} logs on cluster ${
|
||||
containerScope.cluster.title || containerScope.cluster.name
|
||||
}`}
|
||||
title={t('podLogs.titleTemplate', {
|
||||
podName: containerScope.podName,
|
||||
containerName: containerScope.containerName,
|
||||
clusterName:
|
||||
containerScope.cluster.title || containerScope.cluster.name,
|
||||
})}
|
||||
>
|
||||
<PodLogs containerScope={containerScope} />
|
||||
</KubernetesDialog>
|
||||
|
||||
+31
-25
@@ -30,6 +30,8 @@ import { Pod } from 'kubernetes-models/v1/Pod';
|
||||
import type { V1Pod } from '@kubernetes/client-node';
|
||||
import { usePodMetrics } from '../../hooks/usePodMetrics';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -63,22 +65,6 @@ export type PodsTablesProps = {
|
||||
children?: ReactNode;
|
||||
};
|
||||
|
||||
const READY: TableColumn<Pod>[] = [
|
||||
{
|
||||
title: 'containers ready',
|
||||
align: 'center',
|
||||
render: containersReady,
|
||||
width: 'auto',
|
||||
},
|
||||
{
|
||||
title: 'total restarts',
|
||||
align: 'center',
|
||||
render: totalRestarts,
|
||||
type: 'numeric',
|
||||
width: 'auto',
|
||||
},
|
||||
];
|
||||
|
||||
const PodDrawerTrigger = ({ pod }: { pod: Pod }) => {
|
||||
const errors = useMatchingErrors({
|
||||
kind: 'Pod',
|
||||
@@ -98,9 +84,10 @@ const PodDrawerTrigger = ({ pod }: { pod: Pod }) => {
|
||||
|
||||
const Cpu = ({ clusterName, pod }: { clusterName: string; pod: Pod }) => {
|
||||
const metrics = usePodMetrics(clusterName, pod);
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
|
||||
if (!metrics) {
|
||||
return <Typography>unknown</Typography>;
|
||||
return <Typography>{t('podsTable.unknown')}</Typography>;
|
||||
}
|
||||
|
||||
return <>{podStatusToCpuUtil(metrics)}</>;
|
||||
@@ -108,9 +95,10 @@ const Cpu = ({ clusterName, pod }: { clusterName: string; pod: Pod }) => {
|
||||
|
||||
const Memory = ({ clusterName, pod }: { clusterName: string; pod: Pod }) => {
|
||||
const metrics = usePodMetrics(clusterName, pod);
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
|
||||
if (!metrics) {
|
||||
return <Typography>unknown</Typography>;
|
||||
return <Typography>{t('podsTable.unknown')}</Typography>;
|
||||
}
|
||||
|
||||
return <>{podStatusToMemoryUtil(metrics)}</>;
|
||||
@@ -123,26 +111,44 @@ const Memory = ({ clusterName, pod }: { clusterName: string; pod: Pod }) => {
|
||||
*/
|
||||
export const PodsTable = ({ pods, extraColumns = [] }: PodsTablesProps) => {
|
||||
const cluster = useContext(ClusterContext);
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
|
||||
const READY: TableColumn<Pod>[] = [
|
||||
{
|
||||
title: t('podsTable.columns.containersReady'),
|
||||
align: 'center',
|
||||
render: containersReady,
|
||||
width: 'auto',
|
||||
},
|
||||
{
|
||||
title: t('podsTable.columns.totalRestarts'),
|
||||
align: 'center',
|
||||
render: totalRestarts,
|
||||
type: 'numeric',
|
||||
width: 'auto',
|
||||
},
|
||||
];
|
||||
|
||||
const defaultColumns: TableColumn<Pod>[] = [
|
||||
{
|
||||
title: 'ID',
|
||||
title: t('podsTable.columns.id'),
|
||||
field: 'metadata.uid',
|
||||
hidden: true,
|
||||
},
|
||||
{
|
||||
title: 'name',
|
||||
title: t('podsTable.columns.name'),
|
||||
highlight: true,
|
||||
render: (pod: Pod) => {
|
||||
return <PodDrawerTrigger pod={pod} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'phase',
|
||||
render: (pod: Pod) => pod.status?.phase ?? 'unknown',
|
||||
title: t('podsTable.columns.phase'),
|
||||
render: (pod: Pod) => pod.status?.phase ?? t('podsTable.unknown'),
|
||||
width: 'auto',
|
||||
},
|
||||
{
|
||||
title: 'status',
|
||||
title: t('podsTable.columns.status'),
|
||||
render: containerStatuses,
|
||||
},
|
||||
];
|
||||
@@ -154,14 +160,14 @@ export const PodsTable = ({ pods, extraColumns = [] }: PodsTablesProps) => {
|
||||
if (extraColumns.includes(RESOURCE_COLUMNS)) {
|
||||
const resourceColumns: TableColumn<Pod>[] = [
|
||||
{
|
||||
title: 'CPU usage %',
|
||||
title: t('podsTable.columns.cpuUsage'),
|
||||
render: (pod: Pod) => {
|
||||
return <Cpu clusterName={cluster.name} pod={pod} />;
|
||||
},
|
||||
width: 'auto',
|
||||
},
|
||||
{
|
||||
title: 'Memory usage %',
|
||||
title: t('podsTable.columns.memoryUsage'),
|
||||
render: (pod: Pod) => {
|
||||
return <Memory clusterName={cluster.name} pod={pod} />;
|
||||
},
|
||||
|
||||
@@ -19,6 +19,8 @@ import { KubernetesStructuredMetadataTableDrawer } from '../KubernetesDrawer';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
export const ServiceDrawer = ({
|
||||
service,
|
||||
@@ -27,6 +29,7 @@ export const ServiceDrawer = ({
|
||||
service: V1Service;
|
||||
expanded?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const namespace = service.metadata?.namespace;
|
||||
return (
|
||||
<KubernetesStructuredMetadataTableDrawer
|
||||
@@ -56,7 +59,7 @@ export const ServiceDrawer = ({
|
||||
</Grid>
|
||||
{namespace && (
|
||||
<Grid item>
|
||||
<Chip size="small" label={`namespace: ${namespace}`} />
|
||||
<Chip size="small" label={`${t('namespace.label')} ${namespace}`} />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
+4
-1
@@ -21,6 +21,8 @@ import { renderCondition } from '../../utils/pod';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
export const StatefulSetDrawer = ({
|
||||
statefulset,
|
||||
@@ -29,6 +31,7 @@ export const StatefulSetDrawer = ({
|
||||
statefulset: V1StatefulSet;
|
||||
expanded?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const namespace = statefulset.metadata?.namespace;
|
||||
return (
|
||||
<KubernetesStructuredMetadataTableDrawer
|
||||
@@ -72,7 +75,7 @@ export const StatefulSetDrawer = ({
|
||||
</Grid>
|
||||
{namespace && (
|
||||
<Grid item>
|
||||
<Chip size="small" label={`namespace: ${namespace}`} />
|
||||
<Chip size="small" label={`${t('namespace.label')} ${namespace}`} />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
+10
-8
@@ -36,6 +36,8 @@ import {
|
||||
} from '../../hooks';
|
||||
import { StatusError, StatusOK } from '@backstage/core-components';
|
||||
import { READY_COLUMNS, RESOURCE_COLUMNS } from '../Pods/PodsTable';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { kubernetesReactTranslationRef } from '../../translation';
|
||||
|
||||
type StatefulSetsAccordionsProps = {
|
||||
children?: ReactNode;
|
||||
@@ -62,6 +64,7 @@ const StatefulSetSummary = ({
|
||||
numberOfPodsWithErrors,
|
||||
hpa,
|
||||
}: StatefulSetSummaryProps) => {
|
||||
const { t } = useTranslationRef(kubernetesReactTranslationRef);
|
||||
const specCpuUtil = hpa?.spec?.metrics?.find(
|
||||
metric => metric.type === 'Resource' && metric.resource?.name === 'cpu',
|
||||
)?.resource?.target.averageUtilization;
|
||||
@@ -94,18 +97,18 @@ const StatefulSetSummary = ({
|
||||
>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle2">
|
||||
min replicas {hpa.spec?.minReplicas ?? '?'} / max replicas{' '}
|
||||
{hpa.spec?.maxReplicas ?? '?'}
|
||||
{t('hpa.minReplicas')} {hpa.spec?.minReplicas ?? '?'} /{' '}
|
||||
{t('hpa.maxReplicas')} {hpa.spec?.maxReplicas ?? '?'}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle2">
|
||||
current CPU usage: {cpuUtil ?? '?'}%
|
||||
{t('hpa.currentCpuUsage')} {cpuUtil ?? '?'}%
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle2">
|
||||
target CPU usage: {specCpuUtil ?? '?'}%
|
||||
{t('hpa.targetCpuUsage')} {specCpuUtil ?? '?'}%
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
@@ -122,16 +125,15 @@ const StatefulSetSummary = ({
|
||||
spacing={0}
|
||||
>
|
||||
<Grid item>
|
||||
<StatusOK>{numberOfCurrentPods} pods</StatusOK>
|
||||
<StatusOK>{t('pods.pods', { count: numberOfCurrentPods })}</StatusOK>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
{numberOfPodsWithErrors > 0 ? (
|
||||
<StatusError>
|
||||
{numberOfPodsWithErrors} pod
|
||||
{numberOfPodsWithErrors > 1 ? 's' : ''} with errors
|
||||
{t('cluster.podWithErrors', { count: numberOfPodsWithErrors })}
|
||||
</StatusError>
|
||||
) : (
|
||||
<StatusOK>No pods with errors</StatusOK>
|
||||
<StatusOK>{t('cluster.noPodsWithErrors')}</StatusOK>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -20,10 +20,123 @@ import { createTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
export const kubernetesReactTranslationRef = createTranslationRef({
|
||||
id: 'kubernetes-react',
|
||||
messages: {
|
||||
cluster: {
|
||||
label: 'Cluster',
|
||||
pods: 'pods',
|
||||
podsWithErrors: 'pods with errors',
|
||||
noPodsWithErrors: 'No pods with errors',
|
||||
podWithErrors_one: '{{count}} pod with errors',
|
||||
podWithErrors_other: '{{count}} pods with errors',
|
||||
},
|
||||
podsTable: {
|
||||
columns: {
|
||||
id: 'ID',
|
||||
name: 'name',
|
||||
phase: 'phase',
|
||||
status: 'status',
|
||||
containersReady: 'containers ready',
|
||||
totalRestarts: 'total restarts',
|
||||
cpuUsage: 'CPU usage %',
|
||||
memoryUsage: 'Memory usage %',
|
||||
},
|
||||
unknown: 'unknown',
|
||||
status: {
|
||||
running: 'Running',
|
||||
ok: 'OK',
|
||||
},
|
||||
},
|
||||
errorPanel: {
|
||||
title: 'There was a problem retrieving Kubernetes objects',
|
||||
message:
|
||||
'There was a problem retrieving some Kubernetes resources for the entity: {{entityName}}. This could mean that the Error Reporting card is not completely accurate.',
|
||||
errorsLabel: 'Errors',
|
||||
clusterLabel: 'Cluster',
|
||||
fetchError:
|
||||
'Error communicating with Kubernetes: {{errorType}}, message: {{message}}',
|
||||
resourceError:
|
||||
"Error fetching Kubernetes resource: '{{resourcePath}}', error: {{errorType}}, status code: {{statusCode}}",
|
||||
},
|
||||
fixDialog: {
|
||||
helpButton: 'Help',
|
||||
title: '{{podName}} - {{errorType}}',
|
||||
detectedError: 'Detected error:',
|
||||
causeExplanation: 'Cause explanation:',
|
||||
fix: 'Fix:',
|
||||
crashLogs: 'Crash logs:',
|
||||
events: 'Events:',
|
||||
openDocs: 'Open docs',
|
||||
ariaLabels: {
|
||||
fixIssue: 'fix issue',
|
||||
close: 'close',
|
||||
},
|
||||
},
|
||||
podDrawer: {
|
||||
buttons: {
|
||||
delete: 'Delete Pod',
|
||||
},
|
||||
cpuRequests: 'CPU requests',
|
||||
cpuLimits: 'CPU limits',
|
||||
memoryRequests: 'Memory requests',
|
||||
memoryLimits: 'Memory limits',
|
||||
resourceUtilization: 'Resource utilization',
|
||||
},
|
||||
hpa: {
|
||||
minReplicas: 'min replicas',
|
||||
maxReplicas: 'max replicas',
|
||||
currentCpuUsage: 'current CPU usage:',
|
||||
targetCpuUsage: 'target CPU usage:',
|
||||
},
|
||||
pods: {
|
||||
pods_one: '{{count}} pod',
|
||||
pods_other: '{{count}} pods',
|
||||
},
|
||||
errorReporting: {
|
||||
title: 'Error Reporting',
|
||||
columns: {
|
||||
cluster: 'cluster',
|
||||
namespace: 'namespace',
|
||||
kind: 'kind',
|
||||
name: 'name',
|
||||
messages: 'messages',
|
||||
},
|
||||
},
|
||||
podLogs: {
|
||||
title: 'No logs emitted',
|
||||
description: 'No logs were emitted by the container',
|
||||
buttonText: 'Logs',
|
||||
buttonAriaLabel: 'get logs',
|
||||
titleTemplate:
|
||||
'{{podName}} - {{containerName}} logs on cluster {{clusterName}}',
|
||||
},
|
||||
podExecTerminal: {
|
||||
buttonText: 'Terminal',
|
||||
buttonAriaLabel: 'open terminal',
|
||||
titleTemplate:
|
||||
'{{podName}} - {{containerName}} terminal shell on cluster {{clusterName}}',
|
||||
},
|
||||
events: {
|
||||
noEventsFound: 'No events found',
|
||||
eventTooltip: '{{eventType}} event',
|
||||
firstEvent: 'First event {{timeAgo}} (count: {{count}})',
|
||||
},
|
||||
kubernetesDrawer: {
|
||||
closeDrawer: 'Close the drawer',
|
||||
yaml: 'YAML',
|
||||
managedFields: 'Managed Fields',
|
||||
unknownName: 'unknown name',
|
||||
},
|
||||
linkErrorPanel: {
|
||||
title:
|
||||
'There was a problem formatting the link to the Kubernetes dashboard',
|
||||
message:
|
||||
"Could not format the link to the dashboard of your cluster named '{{clusterName}}'. Its dashboardApp property has been set to '{{dashboardApp}}.'",
|
||||
errorsLabel: 'Errors:',
|
||||
},
|
||||
namespace: {
|
||||
label: 'namespace:',
|
||||
},
|
||||
kubernetesDialog: {
|
||||
closeAriaLabel: 'close',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user