fix: add missing i18n support for catalog react plugin
Signed-off-by: Eswaraiahsapram <esapram@redhat.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-react': patch
|
||||
---
|
||||
|
||||
Added missing i18n
|
||||
@@ -45,8 +45,10 @@ export const catalogReactTranslationRef: TranslationRef<
|
||||
readonly 'entityProcessingStatusPicker.title': 'Processing Status';
|
||||
readonly 'entityTagPicker.title': 'Tags';
|
||||
readonly 'entityPeekAheadPopover.title': 'Drill into the entity to see all of the tags.';
|
||||
readonly 'entityPeekAheadPopover.entityCardActionsAriaLabel': 'Show';
|
||||
readonly 'entityPeekAheadPopover.entityCardActionsTitle': 'Show details';
|
||||
readonly 'entityPeekAheadPopover.emailCardAction.title': 'Email {{email}}';
|
||||
readonly 'entityPeekAheadPopover.emailCardAction.ariaLabel': 'Email';
|
||||
readonly 'entityPeekAheadPopover.emailCardAction.subTitle': 'mailto {{email}}';
|
||||
readonly 'entitySearchBar.placeholder': 'Search';
|
||||
readonly 'entityTypePicker.title': 'Type';
|
||||
@@ -56,16 +58,34 @@ export const catalogReactTranslationRef: TranslationRef<
|
||||
readonly 'favoriteEntity.removeFromFavorites': 'Remove from favorites';
|
||||
readonly 'inspectEntityDialog.title': 'Entity Inspector';
|
||||
readonly 'inspectEntityDialog.closeButtonTitle': 'Close';
|
||||
readonly 'inspectEntityDialog.tabsAriaLabel': 'Inspector options';
|
||||
readonly 'inspectEntityDialog.ancestryPage.title': 'Ancestry';
|
||||
readonly 'inspectEntityDialog.ancestryPage.descriptionPart1': 'This is the ancestry of entities above the current one - as in, the chain(s) of entities down to the current one, where';
|
||||
readonly 'inspectEntityDialog.ancestryPage.processorsLink': 'processors emitted';
|
||||
readonly 'inspectEntityDialog.ancestryPage.descriptionPart2': 'child entities that ultimately led to the current one existing. Note that this is a completely different mechanism from relations.';
|
||||
readonly 'inspectEntityDialog.colocatedPage.title': 'Colocated';
|
||||
readonly 'inspectEntityDialog.colocatedPage.description': 'These are the entities that are colocated with this entity - as in, they originated from the same data source (e.g. came from the same YAML file), or from the same origin (e.g. the originally registered URL).';
|
||||
readonly 'inspectEntityDialog.colocatedPage.alertNoLocation': 'Entity had no location information.';
|
||||
readonly 'inspectEntityDialog.colocatedPage.alertNoEntity': 'There were no other entities on this location.';
|
||||
readonly 'inspectEntityDialog.colocatedPage.locationHeader': 'At the same location';
|
||||
readonly 'inspectEntityDialog.colocatedPage.originHeader': 'At the same origin';
|
||||
readonly 'inspectEntityDialog.jsonPage.title': 'Entity as JSON';
|
||||
readonly 'inspectEntityDialog.jsonPage.description': 'This is the raw entity data as received from the catalog, on JSON form.';
|
||||
readonly 'inspectEntityDialog.overviewPage.title': 'Overview';
|
||||
readonly 'inspectEntityDialog.overviewPage.labels': 'Labels';
|
||||
readonly 'inspectEntityDialog.overviewPage.annotations': 'Annotations';
|
||||
readonly 'inspectEntityDialog.overviewPage.tags': 'Tags';
|
||||
readonly 'inspectEntityDialog.overviewPage.relationTitle': 'Relations';
|
||||
readonly 'inspectEntityDialog.overviewPage.statusTitle': 'Status';
|
||||
readonly 'inspectEntityDialog.overviewPage.identityTitle': 'Identity';
|
||||
readonly 'inspectEntityDialog.overviewPage.metadataTitle': 'Metadata';
|
||||
readonly 'inspectEntityDialog.yamlPage.title': 'Entity as YAML';
|
||||
readonly 'inspectEntityDialog.yamlPage.description': 'This is the raw entity data as received from the catalog, on YAML form.';
|
||||
readonly 'inspectEntityDialog.tabNames.json': 'Raw JSON';
|
||||
readonly 'inspectEntityDialog.tabNames.yaml': 'Raw YAML';
|
||||
readonly 'inspectEntityDialog.tabNames.overview': 'Overview';
|
||||
readonly 'inspectEntityDialog.tabNames.ancestry': 'Ancestry';
|
||||
readonly 'inspectEntityDialog.tabNames.colocated': 'Colocated';
|
||||
readonly 'unregisterEntityDialog.title': 'Are you sure you want to unregister this entity?';
|
||||
readonly 'unregisterEntityDialog.cancelButtonTitle': 'Cancel';
|
||||
readonly 'unregisterEntityDialog.deleteButtonTitle': 'Delete Entity';
|
||||
@@ -98,6 +118,11 @@ export const catalogReactTranslationRef: TranslationRef<
|
||||
readonly 'entityTableColumnTitle.lifecycle': 'Lifecycle';
|
||||
readonly 'entityTableColumnTitle.owner': 'Owner';
|
||||
readonly 'entityTableColumnTitle.targets': 'Targets';
|
||||
readonly 'missingAnnotationEmptyState.title': 'Missing Annotation';
|
||||
readonly 'missingAnnotationEmptyState.readMore': 'Read more';
|
||||
readonly 'missingAnnotationEmptyState.annotationYaml': 'Add the annotation to your {{entityKind}} YAML as shown in the highlighted example below:';
|
||||
readonly 'missingAnnotationEmptyState.generateDescription.multiple': 'The annotations {{annotations}} are missing. You need to add the annotations to your {{entityKind}} if you want to enable this tool.';
|
||||
readonly 'missingAnnotationEmptyState.generateDescription.single': 'The annotation {{annotations}} is missing. You need to add the annotation to your {{entityKind}} if you want to enable this tool.';
|
||||
}
|
||||
>;
|
||||
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ export const EmailCardAction = (props: { email: string }) => {
|
||||
return (
|
||||
<IconButton
|
||||
component={Link}
|
||||
aria-label="Email"
|
||||
aria-label={t('entityPeekAheadPopover.emailCardAction.ariaLabel')}
|
||||
title={t('entityPeekAheadPopover.emailCardAction.title', {
|
||||
email: props.email,
|
||||
})}
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ export const EntityCardActions = (props: { entity: Entity }) => {
|
||||
return (
|
||||
<IconButton
|
||||
component={Link}
|
||||
aria-label="Show"
|
||||
aria-label={t('entityPeekAheadPopover.entityCardActionsAriaLabel')}
|
||||
title={t('entityPeekAheadPopover.entityCardActionsTitle')}
|
||||
to={entityRoute(getCompoundEntityRef(props.entity))}
|
||||
>
|
||||
|
||||
@@ -24,7 +24,7 @@ import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import Tab from '@material-ui/core/Tab';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { ComponentProps, useEffect, useState, ReactNode } from 'react';
|
||||
import { ComponentProps, useEffect, useState, ReactNode, useMemo } from 'react';
|
||||
import { AncestryPage } from './components/AncestryPage';
|
||||
import { ColocatedPage } from './components/ColocatedPage';
|
||||
import { JsonPage } from './components/JsonPage';
|
||||
@@ -85,18 +85,12 @@ function a11yProps(index: number) {
|
||||
};
|
||||
}
|
||||
|
||||
const tabNames: Record<
|
||||
type TabKey = 'overview' | 'ancestry' | 'colocated' | 'json' | 'yaml';
|
||||
|
||||
type TabNames = Record<
|
||||
NonNullable<ComponentProps<typeof InspectEntityDialog>['initialTab']>,
|
||||
string
|
||||
> = {
|
||||
overview: 'Overview',
|
||||
ancestry: 'Ancestry',
|
||||
colocated: 'Colocated',
|
||||
json: 'Raw JSON',
|
||||
yaml: 'Raw YAML',
|
||||
} as const;
|
||||
|
||||
const tabs = Object.keys(tabNames) as Array<keyof typeof tabNames>;
|
||||
>;
|
||||
|
||||
/**
|
||||
* A dialog that lets users inspect the low level details of their entities.
|
||||
@@ -106,20 +100,33 @@ const tabs = Object.keys(tabNames) as Array<keyof typeof tabNames>;
|
||||
export function InspectEntityDialog(props: {
|
||||
open: boolean;
|
||||
entity: Entity;
|
||||
initialTab?: 'overview' | 'ancestry' | 'colocated' | 'json' | 'yaml';
|
||||
initialTab?: TabKey;
|
||||
onClose: () => void;
|
||||
onSelect?: (tab: string) => void;
|
||||
}) {
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslationRef(catalogReactTranslationRef);
|
||||
|
||||
const tabNames: TabNames = useMemo(
|
||||
() => ({
|
||||
overview: t('inspectEntityDialog.tabNames.overview'),
|
||||
ancestry: t('inspectEntityDialog.tabNames.ancestry'),
|
||||
colocated: t('inspectEntityDialog.tabNames.colocated'),
|
||||
json: t('inspectEntityDialog.tabNames.json'),
|
||||
yaml: t('inspectEntityDialog.tabNames.yaml'),
|
||||
}),
|
||||
[t],
|
||||
);
|
||||
|
||||
const tabs = Object.keys(tabNames) as TabKey[];
|
||||
|
||||
const [activeTab, setActiveTab] = useState(
|
||||
getTabIndex(tabs, props.initialTab),
|
||||
);
|
||||
const { t } = useTranslationRef(catalogReactTranslationRef);
|
||||
|
||||
useEffect(() => {
|
||||
getTabIndex(tabs, props.initialTab);
|
||||
}, [props.open, props.initialTab]);
|
||||
}, [props.open, props.initialTab, tabs]);
|
||||
|
||||
if (!props.entity) {
|
||||
return null;
|
||||
@@ -147,7 +154,7 @@ export function InspectEntityDialog(props: {
|
||||
setActiveTab(tabIndex);
|
||||
props.onSelect?.(tabs[tabIndex]);
|
||||
}}
|
||||
aria-label="Inspector options"
|
||||
aria-label={t('inspectEntityDialog.tabsAriaLabel')}
|
||||
className={classes.tabs}
|
||||
>
|
||||
{tabs.map((tab, index) => (
|
||||
@@ -181,9 +188,6 @@ export function InspectEntityDialog(props: {
|
||||
);
|
||||
}
|
||||
|
||||
function getTabIndex(
|
||||
allTabs: string[],
|
||||
initialTab: keyof typeof tabNames | undefined,
|
||||
) {
|
||||
function getTabIndex(allTabs: string[], initialTab: TabKey | undefined) {
|
||||
return initialTab ? allTabs.indexOf(initialTab) : 0;
|
||||
}
|
||||
|
||||
+7
-7
@@ -213,13 +213,13 @@ export function AncestryPage(props: { entity: Entity }) {
|
||||
{t('inspectEntityDialog.ancestryPage.title')}
|
||||
</DialogContentText>
|
||||
<DialogContentText gutterBottom>
|
||||
This is the ancestry of entities above the current one - as in, the
|
||||
chain(s) of entities down to the current one, where{' '}
|
||||
<Link to="https://backstage.io/docs/features/software-catalog/life-of-an-entity">
|
||||
processors emitted
|
||||
</Link>{' '}
|
||||
child entities that ultimately led to the current one existing. Note
|
||||
that this is a completely different mechanism from relations.
|
||||
{t('inspectEntityDialog.ancestryPage.description', {
|
||||
processorsLink: (
|
||||
<Link to="https://backstage.io/docs/features/software-catalog/life-of-an-entity">
|
||||
{t('inspectEntityDialog.ancestryPage.processorsLink')}
|
||||
</Link>
|
||||
),
|
||||
})}
|
||||
</DialogContentText>
|
||||
<Box mt={4}>
|
||||
<DependencyGraph
|
||||
|
||||
+8
-2
@@ -137,13 +137,19 @@ function Contents(props: { entity: Entity }) {
|
||||
{atLocation.length > 0 && (
|
||||
<EntityList
|
||||
entities={atLocation}
|
||||
header={['At the same location', location!]}
|
||||
header={[
|
||||
t('inspectEntityDialog.colocatedPage.locationHeader'),
|
||||
location!,
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
{atOrigin.length > 0 && (
|
||||
<EntityList
|
||||
entities={atOrigin}
|
||||
header={['At the same origin', originLocation!]}
|
||||
header={[
|
||||
t('inspectEntityDialog.colocatedPage.originHeader'),
|
||||
originLocation!,
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
+21
-7
@@ -69,7 +69,7 @@ export function OverviewPage(props: { entity: AlphaEntity }) {
|
||||
{t('inspectEntityDialog.overviewPage.title')}
|
||||
</DialogContentText>
|
||||
<div className={classes.root}>
|
||||
<Container title="Identity">
|
||||
<Container title={t('inspectEntityDialog.overviewPage.identity.title')}>
|
||||
<List dense>
|
||||
<ListItem>
|
||||
<ListItemText primary="apiVersion" secondary={apiVersion} />
|
||||
@@ -110,13 +110,13 @@ export function OverviewPage(props: { entity: AlphaEntity }) {
|
||||
</List>
|
||||
</Container>
|
||||
|
||||
<Container title="Metadata">
|
||||
<Container title={t('inspectEntityDialog.overviewPage.metadata.title')}>
|
||||
{!!Object.keys(metadata.annotations || {}).length && (
|
||||
<List
|
||||
dense
|
||||
subheader={
|
||||
<ListSubheader>
|
||||
Annotations
|
||||
{t('inspectEntityDialog.overviewPage.annotations')}
|
||||
<HelpIcon to="https://backstage.io/docs/features/software-catalog/well-known-annotations" />
|
||||
</ListSubheader>
|
||||
}
|
||||
@@ -127,14 +127,28 @@ export function OverviewPage(props: { entity: AlphaEntity }) {
|
||||
</List>
|
||||
)}
|
||||
{!!Object.keys(metadata.labels || {}).length && (
|
||||
<List dense subheader={<ListSubheader>Labels</ListSubheader>}>
|
||||
<List
|
||||
dense
|
||||
subheader={
|
||||
<ListSubheader>
|
||||
{t('inspectEntityDialog.overviewPage.labels')}
|
||||
</ListSubheader>
|
||||
}
|
||||
>
|
||||
{Object.entries(metadata.labels!).map(entry => (
|
||||
<KeyValueListItem key={entry[0]} indent entry={entry} />
|
||||
))}
|
||||
</List>
|
||||
)}
|
||||
{!!metadata.tags?.length && (
|
||||
<List dense subheader={<ListSubheader>Tags</ListSubheader>}>
|
||||
<List
|
||||
dense
|
||||
subheader={
|
||||
<ListSubheader>
|
||||
{t('inspectEntityDialog.overviewPage.tags')}
|
||||
</ListSubheader>
|
||||
}
|
||||
>
|
||||
{metadata.tags.map((tag, index) => (
|
||||
<ListItem key={`${tag}-${index}`}>
|
||||
<ListItemIcon />
|
||||
@@ -147,7 +161,7 @@ export function OverviewPage(props: { entity: AlphaEntity }) {
|
||||
|
||||
{!!relations.length && (
|
||||
<Container
|
||||
title="Relations"
|
||||
title={t('inspectEntityDialog.overviewPage.relation.title')}
|
||||
helpLink="https://backstage.io/docs/features/software-catalog/well-known-relations"
|
||||
>
|
||||
{Object.entries(groupedRelations).map(
|
||||
@@ -172,7 +186,7 @@ export function OverviewPage(props: { entity: AlphaEntity }) {
|
||||
|
||||
{!!status.items?.length && (
|
||||
<Container
|
||||
title="Status"
|
||||
title={t('inspectEntityDialog.overviewPage.status.title')}
|
||||
helpLink="https://backstage.io/docs/features/software-catalog/well-known-statuses"
|
||||
>
|
||||
{status.items.map((item, index) => (
|
||||
|
||||
+29
-22
@@ -20,7 +20,12 @@ import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { CodeSnippet, Link, EmptyState } from '@backstage/core-components';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import {
|
||||
TranslationFunction,
|
||||
useTranslationRef,
|
||||
} from '@backstage/core-plugin-api/alpha';
|
||||
import { useEntity } from '../../hooks';
|
||||
import { catalogReactTranslationRef } from '../../translation';
|
||||
|
||||
/** @public */
|
||||
export type MissingAnnotationEmptyStateClassKey = 'code';
|
||||
@@ -68,23 +73,24 @@ spec:
|
||||
};
|
||||
}
|
||||
|
||||
function generateDescription(annotations: string[], entityKind = 'Component') {
|
||||
const isSingular = annotations.length <= 1;
|
||||
return (
|
||||
<>
|
||||
The {isSingular ? 'annotation' : 'annotations'}{' '}
|
||||
{annotations
|
||||
.map(ann => <code>{ann}</code>)
|
||||
.reduce((prev, curr) => (
|
||||
<>
|
||||
{prev}, {curr}
|
||||
</>
|
||||
))}{' '}
|
||||
{isSingular ? 'is' : 'are'} missing. You need to add the{' '}
|
||||
{isSingular ? 'annotation' : 'annotations'} to your {entityKind} if you
|
||||
want to enable this tool.
|
||||
</>
|
||||
);
|
||||
function generateDescription(
|
||||
annotations: string[],
|
||||
entityKind = 'Component',
|
||||
t: TranslationFunction<typeof catalogReactTranslationRef.T>,
|
||||
) {
|
||||
const annotationList = annotations
|
||||
.map(ann => <code key={ann}>{ann}</code>)
|
||||
.reduce((prev, curr) => (
|
||||
<>
|
||||
{prev}, {curr}
|
||||
</>
|
||||
));
|
||||
|
||||
return t('missingAnnotationEmptyState.generateDescription', {
|
||||
count: annotations.length,
|
||||
entityKind,
|
||||
annotations: annotationList,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,6 +101,8 @@ export function MissingAnnotationEmptyState(props: {
|
||||
annotation: string | string[];
|
||||
readMoreUrl?: string;
|
||||
}) {
|
||||
const { t } = useTranslationRef(catalogReactTranslationRef);
|
||||
|
||||
let entity: Entity | undefined;
|
||||
try {
|
||||
const entityContext = useEntity();
|
||||
@@ -115,13 +123,12 @@ export function MissingAnnotationEmptyState(props: {
|
||||
return (
|
||||
<EmptyState
|
||||
missing="field"
|
||||
title="Missing Annotation"
|
||||
description={generateDescription(annotations, entityKind)}
|
||||
title={t('missingAnnotationEmptyState.title')}
|
||||
description={generateDescription(annotations, entityKind, t)}
|
||||
action={
|
||||
<>
|
||||
<Typography variant="body1">
|
||||
Add the annotation to your {entityKind} YAML as shown in the
|
||||
highlighted example below:
|
||||
{t('missingAnnotationEmptyState.annotationYaml', { entityKind })}
|
||||
</Typography>
|
||||
<Box className={classes.code}>
|
||||
<CodeSnippet
|
||||
@@ -133,7 +140,7 @@ export function MissingAnnotationEmptyState(props: {
|
||||
/>
|
||||
</Box>
|
||||
<Button color="primary" component={Link} to={url}>
|
||||
Read more
|
||||
{t('missingAnnotationEmptyState.readMore')}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
|
||||
@@ -48,7 +48,9 @@ export const catalogReactTranslationRef = createTranslationRef({
|
||||
emailCardAction: {
|
||||
title: 'Email {{email}}',
|
||||
subTitle: 'mailto {{email}}',
|
||||
ariaLabel: 'Email',
|
||||
},
|
||||
entityCardActionsAriaLabel: 'Show',
|
||||
entityCardActionsTitle: 'Show details',
|
||||
},
|
||||
entitySearchBar: {
|
||||
@@ -68,6 +70,9 @@ export const catalogReactTranslationRef = createTranslationRef({
|
||||
closeButtonTitle: 'Close',
|
||||
ancestryPage: {
|
||||
title: 'Ancestry',
|
||||
description:
|
||||
'This is the ancestry of entities above the current one - as in, the chain(s) of entities down to the current one, where {{processorsLink}} child entities that ultimately led to the current one existing. Note that this is a completely different mechanism from relations.',
|
||||
processorsLink: 'processors emitted',
|
||||
},
|
||||
colocatedPage: {
|
||||
title: 'Colocated',
|
||||
@@ -75,6 +80,8 @@ export const catalogReactTranslationRef = createTranslationRef({
|
||||
'These are the entities that are colocated with this entity - as in, they originated from the same data source (e.g. came from the same YAML file), or from the same origin (e.g. the originally registered URL).',
|
||||
alertNoLocation: 'Entity had no location information.',
|
||||
alertNoEntity: 'There were no other entities on this location.',
|
||||
locationHeader: 'At the same location',
|
||||
originHeader: 'At the same origin',
|
||||
},
|
||||
jsonPage: {
|
||||
title: 'Entity as JSON',
|
||||
@@ -83,12 +90,35 @@ export const catalogReactTranslationRef = createTranslationRef({
|
||||
},
|
||||
overviewPage: {
|
||||
title: 'Overview',
|
||||
relation: {
|
||||
title: 'Relations',
|
||||
},
|
||||
status: {
|
||||
title: 'Status',
|
||||
},
|
||||
identity: {
|
||||
title: 'Identity',
|
||||
},
|
||||
metadata: {
|
||||
title: 'Metadata',
|
||||
},
|
||||
annotations: 'Annotations',
|
||||
labels: 'Labels',
|
||||
tags: 'Tags',
|
||||
},
|
||||
yamlPage: {
|
||||
title: 'Entity as YAML',
|
||||
description:
|
||||
'This is the raw entity data as received from the catalog, on YAML form.',
|
||||
},
|
||||
tabNames: {
|
||||
overview: 'Overview',
|
||||
ancestry: 'Ancestry',
|
||||
colocated: 'Colocated',
|
||||
json: 'Raw JSON',
|
||||
yaml: 'Raw YAML',
|
||||
},
|
||||
tabsAriaLabel: 'Inspector options',
|
||||
},
|
||||
unregisterEntityDialog: {
|
||||
title: 'Are you sure you want to unregister this entity?',
|
||||
@@ -138,5 +168,15 @@ export const catalogReactTranslationRef = createTranslationRef({
|
||||
label: 'Label',
|
||||
domain: 'Domain',
|
||||
},
|
||||
missingAnnotationEmptyState: {
|
||||
title: 'Missing Annotation',
|
||||
readMore: 'Read more',
|
||||
annotationYaml:
|
||||
'Add the annotation to your {{entityKind}} YAML as shown in the highlighted example below:',
|
||||
generateDescription_one:
|
||||
'The annotation {{annotations}} is missing. You need to add the annotation to your {{entityKind}} if you want to enable this tool.',
|
||||
generateDescription_other:
|
||||
'The annotations {{annotations}} are missing. You need to add the annotations to your {{entityKind}} if you want to enable this tool.',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user