Revert NFS page variants, keep only title and icon additions

Roll back the NFS page component changes (BuiHeader, headerVariant,
NfsCatalogGraphPage, NfsDefaultImportPage) from catalog-graph and
catalog-import plugins. Only the title and icon metadata additions to the
new frontend system plugin definitions are retained.

For the kubernetes plugin, replace the generic RiShipLine icon with a
proper Kubernetes helm wheel SVG icon from Simple Icons.

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Made-with: Cursor
This commit is contained in:
Patrik Oldsberg
2026-03-30 00:19:41 +02:00
parent 34f5dc5ae1
commit 3c0b453d7e
10 changed files with 133 additions and 195 deletions
+1 -1
View File
@@ -2,4 +2,4 @@
'@backstage/plugin-catalog-graph': patch
---
The new frontend plugin entry now exposes a display title and icon for navigation, and the catalog graph page uses the Backstage UI header when rendered in the new frontend system.
Added `title` and `icon` to the new frontend system plugin definition.
+1 -1
View File
@@ -2,4 +2,4 @@
'@backstage/plugin-catalog-import': patch
---
Updated the catalog import plugin for the new frontend system with plugin title and icon metadata, and a page layout that uses Backstage UI header instead of legacy page chrome.
Added `title` and `icon` to the new frontend system plugin definition.
+2 -2
View File
@@ -80,8 +80,8 @@ const CatalogGraphPage = PageBlueprint.makeWithOverrides({
path: '/catalog-graph',
routeRef: catalogGraphRouteRef,
loader: () =>
import('./components/CatalogGraphPage/CatalogGraphPage').then(m => (
<m.NfsCatalogGraphPage {...config} />
import('./components/CatalogGraphPage').then(m => (
<m.CatalogGraphPage {...config} />
)),
});
},
@@ -27,7 +27,6 @@ import {
entityRouteRef,
humanizeEntityRef,
} from '@backstage/plugin-catalog-react';
import { Header as BuiHeader } from '@backstage/ui';
import Grid from '@material-ui/core/Grid';
import Paper from '@material-ui/core/Paper';
import Typography from '@material-ui/core/Typography';
@@ -117,27 +116,22 @@ const useStyles = makeStyles(
{ name: 'PluginCatalogGraphCatalogGraphPage' },
);
type CatalogGraphPageProps = {
initialState?: {
selectedRelations?: string[];
selectedKinds?: string[];
rootEntityRefs?: string[];
maxDepth?: number;
unidirectional?: boolean;
mergeRelations?: boolean;
direction?: Direction;
showFilters?: boolean;
curve?: 'curveStepBefore' | 'curveMonotoneX';
};
} & Partial<EntityRelationsGraphProps>;
type CatalogGraphPageContentProps = CatalogGraphPageProps & {
headerVariant: 'legacy' | 'bui';
};
function CatalogGraphPageContent(props: CatalogGraphPageContentProps) {
const { headerVariant, ...graphPageProps } = props;
const { relationPairs, initialState, entityFilter } = graphPageProps;
export const CatalogGraphPage = (
props: {
initialState?: {
selectedRelations?: string[];
selectedKinds?: string[];
rootEntityRefs?: string[];
maxDepth?: number;
unidirectional?: boolean;
mergeRelations?: boolean;
direction?: Direction;
showFilters?: boolean;
curve?: 'curveStepBefore' | 'curveMonotoneX';
};
} & Partial<EntityRelationsGraphProps>,
) => {
const { relationPairs, initialState, entityFilter } = props;
const { t } = useTranslationRef(catalogGraphTranslationRef);
const navigate = useNavigate();
const classes = useStyles();
@@ -191,127 +185,93 @@ function CatalogGraphPageContent(props: CatalogGraphPageContentProps) {
[catalogEntityRoute, navigate, setRootEntityNames, analytics],
);
const subtitle = rootEntityNames.map(e => humanizeEntityRef(e)).join(', ');
const filterToggle = (
<ToggleButton
value="show filters"
selected={showFilters}
onChange={() => toggleShowFilters()}
>
<FilterListIcon /> {t('catalogGraphPage.filterToggleButtonTitle')}
</ToggleButton>
);
const supportButton = (
<SupportButton>
{t('catalogGraphPage.supportButtonDescription')}
</SupportButton>
);
const graphBody = (
<Grid container alignItems="stretch" className={classes.container}>
{showFilters && (
<Grid item xs={12} lg={2} className={classes.filters}>
<MaxDepthFilter value={maxDepth} onChange={setMaxDepth} />
<SelectedKindsFilter
value={selectedKinds}
onChange={setSelectedKinds}
/>
<SelectedRelationsFilter
value={selectedRelations}
onChange={setSelectedRelations}
/>
<DirectionFilter value={direction} onChange={setDirection} />
<CurveFilter value={curve} onChange={setCurve} />
<SwitchFilter
value={unidirectional}
onChange={setUnidirectional}
label={t('catalogGraphPage.simplifiedSwitchLabel')}
/>
<SwitchFilter
value={mergeRelations}
onChange={setMergeRelations}
label={t('catalogGraphPage.mergeRelationsSwitchLabel')}
/>
</Grid>
)}
<Grid item xs className={classes.fullHeight}>
<Paper className={classes.graphWrapper}>
<Typography
variant="caption"
color="textSecondary"
display="block"
className={classes.legend}
>
<ZoomOutMap className="icon" />{' '}
{t('catalogGraphPage.zoomOutDescription')}
</Typography>
<EntityRelationsGraph
{...graphPageProps}
rootEntityNames={rootEntityNames}
maxDepth={maxDepth}
kinds={
selectedKinds && selectedKinds.length > 0
? selectedKinds
: undefined
}
relations={
selectedRelations && selectedRelations.length > 0
? selectedRelations
: undefined
}
mergeRelations={mergeRelations}
unidirectional={unidirectional}
onNodeClick={onNodeClick}
direction={direction}
relationPairs={relationPairs}
entityFilter={entityFilter}
className={classes.graph}
zoom="enabled"
curve={curve}
/>
</Paper>
</Grid>
</Grid>
);
if (headerVariant === 'legacy') {
return (
<Page themeId="home">
<Header title={t('catalogGraphPage.title')} subtitle={subtitle} />
<Content stretch className={classes.content}>
<ContentHeader titleComponent={filterToggle}>
{supportButton}
</ContentHeader>
{graphBody}
</Content>
</Page>
);
}
return (
<>
<BuiHeader
title={subtitle}
customActions={
<>
{filterToggle}
{supportButton}
</>
}
<Page themeId="home">
<Header
title={t('catalogGraphPage.title')}
subtitle={rootEntityNames.map(e => humanizeEntityRef(e)).join(', ')}
/>
<Content stretch className={classes.content}>
{graphBody}
<ContentHeader
titleComponent={
<ToggleButton
value="show filters"
selected={showFilters}
onChange={() => toggleShowFilters()}
>
<FilterListIcon /> {t('catalogGraphPage.filterToggleButtonTitle')}
</ToggleButton>
}
>
<SupportButton>
{t('catalogGraphPage.supportButtonDescription')}
</SupportButton>
</ContentHeader>
<Grid container alignItems="stretch" className={classes.container}>
{showFilters && (
<Grid item xs={12} lg={2} className={classes.filters}>
<MaxDepthFilter value={maxDepth} onChange={setMaxDepth} />
<SelectedKindsFilter
value={selectedKinds}
onChange={setSelectedKinds}
/>
<SelectedRelationsFilter
value={selectedRelations}
onChange={setSelectedRelations}
/>
<DirectionFilter value={direction} onChange={setDirection} />
<CurveFilter value={curve} onChange={setCurve} />
<SwitchFilter
value={unidirectional}
onChange={setUnidirectional}
label={t('catalogGraphPage.simplifiedSwitchLabel')}
/>
<SwitchFilter
value={mergeRelations}
onChange={setMergeRelations}
label={t('catalogGraphPage.mergeRelationsSwitchLabel')}
/>
</Grid>
)}
<Grid item xs className={classes.fullHeight}>
<Paper className={classes.graphWrapper}>
<Typography
variant="caption"
color="textSecondary"
display="block"
className={classes.legend}
>
<ZoomOutMap className="icon" />{' '}
{t('catalogGraphPage.zoomOutDescription')}
</Typography>
<EntityRelationsGraph
{...props}
rootEntityNames={rootEntityNames}
maxDepth={maxDepth}
kinds={
selectedKinds && selectedKinds.length > 0
? selectedKinds
: undefined
}
relations={
selectedRelations && selectedRelations.length > 0
? selectedRelations
: undefined
}
mergeRelations={mergeRelations}
unidirectional={unidirectional}
onNodeClick={onNodeClick}
direction={direction}
relationPairs={relationPairs}
entityFilter={entityFilter}
className={classes.graph}
zoom="enabled"
curve={curve}
/>
</Paper>
</Grid>
</Grid>
</Content>
</>
</Page>
);
}
export const CatalogGraphPage = (props: CatalogGraphPageProps) => {
return <CatalogGraphPageContent headerVariant="legacy" {...props} />;
};
export const NfsCatalogGraphPage = (props: CatalogGraphPageProps) => {
return <CatalogGraphPageContent headerVariant="bui" {...props} />;
};
-1
View File
@@ -66,7 +66,6 @@
"@backstage/plugin-catalog-common": "workspace:^",
"@backstage/plugin-catalog-react": "workspace:^",
"@backstage/plugin-permission-react": "workspace:^",
"@backstage/ui": "workspace:^",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.61",
+2 -2
View File
@@ -51,9 +51,9 @@ const catalogImportPage = PageBlueprint.make({
path: '/catalog-import',
routeRef: rootRouteRef,
loader: () =>
import('./components/DefaultImportPage/DefaultImportPage').then(m => (
import('./components/ImportPage').then(m => (
<RequirePermission permission={catalogEntityCreatePermission}>
<m.NfsDefaultImportPage />
<m.ImportPage />
</RequirePermission>
)),
},
@@ -23,7 +23,6 @@ import {
} from '@backstage/core-components';
import { configApiRef, useApi } from '@backstage/core-plugin-api';
import { useTranslationRef } from '@backstage/frontend-plugin-api';
import { Header as BuiHeader } from '@backstage/ui';
import Grid from '@material-ui/core/Grid';
import { useTheme } from '@material-ui/core/styles';
import useMediaQuery from '@material-ui/core/useMediaQuery';
@@ -32,9 +31,17 @@ import { catalogImportTranslationRef } from '../../translation';
import { ImportInfoCard } from '../ImportInfoCard';
import { ImportStepper } from '../ImportStepper';
const DefaultImportPageGrid = () => {
/**
* The default catalog import page.
*
* @public
*/
export const DefaultImportPage = () => {
const { t } = useTranslationRef(catalogImportTranslationRef);
const theme = useTheme();
const configApi = useApi(configApiRef);
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
const appTitle = configApi.getOptionalString('app.title') || 'Backstage';
const contentItems = [
<Grid key={0} item xs={12} md={4} lg={6} xl={8}>
@@ -46,23 +53,6 @@ const DefaultImportPageGrid = () => {
</Grid>,
];
return (
<Grid container spacing={2}>
{isMobile ? contentItems : [...contentItems].reverse()}
</Grid>
);
};
/**
* The default catalog import page.
*
* @public
*/
export const DefaultImportPage = () => {
const { t } = useTranslationRef(catalogImportTranslationRef);
const configApi = useApi(configApiRef);
const appTitle = configApi.getOptionalString('app.title') || 'Backstage';
return (
<Page themeId="home">
<Header title={t('defaultImportPage.headerTitle')} />
@@ -75,30 +65,10 @@ export const DefaultImportPage = () => {
</SupportButton>
</ContentHeader>
<DefaultImportPageGrid />
<Grid container spacing={2}>
{isMobile ? contentItems : contentItems.reverse()}
</Grid>
</Content>
</Page>
);
};
export const NfsDefaultImportPage = () => {
const { t } = useTranslationRef(catalogImportTranslationRef);
const configApi = useApi(configApiRef);
const appTitle = configApi.getOptionalString('app.title') || 'Backstage';
return (
<>
<BuiHeader
title={t('defaultImportPage.contentHeaderTitle', { appTitle })}
customActions={
<SupportButton>
{t('defaultImportPage.supportTitle', { appTitle })}
</SupportButton>
}
/>
<Content>
<DefaultImportPageGrid />
</Content>
</>
);
};
+1 -2
View File
@@ -66,8 +66,7 @@
"@backstage/plugin-kubernetes-common": "workspace:^",
"@backstage/plugin-kubernetes-react": "workspace:^",
"@backstage/plugin-permission-react": "workspace:^",
"@material-ui/core": "^4.12.2",
"@remixicon/react": "^4.6.0"
"@material-ui/core": "^4.12.2"
},
"devDependencies": {
"@backstage/cli": "workspace:^",
+14 -2
View File
@@ -15,7 +15,6 @@
*/
import { createFrontendPlugin } from '@backstage/frontend-plugin-api';
import { RiShipLine } from '@remixicon/react';
import { kubernetesPage } from './pages';
import { entityKubernetesContent } from './entityContents';
import { rootCatalogKubernetesRouteRef } from '../plugin';
@@ -26,10 +25,23 @@ import {
kubernetesProxyApi,
} from './apis';
// Kubernetes helm wheel from Simple Icons (https://simpleicons.org/?q=kubernetes), licensed under CC0
const KubernetesIcon = () => (
<svg
viewBox="0 0 24 24"
fill="currentColor"
width="1em"
height="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M10.204 14.35l.007.01-.999 2.413a5.171 5.171 0 0 1-2.075-2.597l2.578-.437.004.005a.44.44 0 0 1 .484.606zm-.833-2.129a.44.44 0 0 0 .173-.756l.002-.011L7.585 9.7a5.143 5.143 0 0 0-.73 3.255l2.514-.725.002-.009zm1.145-1.98a.44.44 0 0 0 .699-.337l.01-.005.15-2.62a5.144 5.144 0 0 0-3.01 1.442l2.147 1.523.004-.002zm.76 2.75l.723.349.722-.347.18-.78-.5-.623h-.804l-.5.623.179.779zm1.5-3.095a.44.44 0 0 0 .7.336l.008.003 2.134-1.513a5.188 5.188 0 0 0-2.992-1.442l.148 2.615.002.001zm10.876 5.97l-5.773 7.181a1.6 1.6 0 0 1-1.248.594l-9.261.003a1.6 1.6 0 0 1-1.247-.596l-5.776-7.18a1.583 1.583 0 0 1-.307-1.34L2.1 5.573c.108-.47.425-.864.863-1.073L11.305.513a1.606 1.606 0 0 1 1.385 0l8.345 3.985c.438.209.755.604.863 1.073l2.062 8.955c.108.47-.005.963-.308 1.34zm-3.289-2.057c-.042-.01-.103-.026-.145-.034-.174-.033-.315-.025-.479-.038-.35-.037-.638-.067-.895-.148-.105-.04-.18-.165-.216-.216l-.201-.059a6.45 6.45 0 0 0-.105-2.332 6.465 6.465 0 0 0-.936-2.163c.052-.047.15-.133.177-.159.008-.09.001-.183.094-.282.197-.185.444-.338.743-.522.142-.084.273-.137.415-.242.032-.024.076-.062.11-.089.24-.191.295-.52.123-.736-.172-.216-.506-.236-.745-.045-.034.027-.08.062-.111.088-.134.116-.217.23-.33.35-.246.25-.45.458-.673.609-.097.056-.239.037-.303.033l-.19.135a6.545 6.545 0 0 0-4.146-2.003l-.012-.223c-.065-.062-.143-.115-.163-.25-.022-.268.015-.557.057-.905.023-.163.061-.298.068-.475.001-.04-.001-.099-.001-.142 0-.306-.224-.555-.5-.555-.275 0-.499.249-.499.555l.001.014c0 .041-.002.092 0 .128.006.177.044.312.067.475.042.348.078.637.056.906a.545.545 0 0 1-.162.258l-.012.211a6.424 6.424 0 0 0-4.166 2.003 8.373 8.373 0 0 1-.18-.128c-.09.012-.18.04-.297-.029-.223-.15-.427-.358-.673-.608-.113-.12-.195-.234-.329-.349-.03-.026-.077-.062-.111-.088a.594.594 0 0 0-.348-.132.481.481 0 0 0-.398.176c-.172.216-.117.546.123.737l.007.005.104.083c.142.105.272.159.414.242.299.185.546.338.743.522.076.082.09.226.1.288l.16.143a6.462 6.462 0 0 0-1.02 4.506l-.208.06c-.055.072-.133.184-.215.217-.257.081-.546.11-.895.147-.164.014-.305.006-.48.039-.037.007-.09.02-.133.03l-.004.002-.007.002c-.295.071-.484.342-.423.608.061.267.349.429.645.365l.007-.001.01-.003.129-.029c.17-.046.294-.113.448-.172.33-.118.604-.217.87-.256.112-.009.23.069.288.101l.217-.037a6.5 6.5 0 0 0 2.88 3.596l-.09.218c.033.084.069.199.044.282-.097.252-.263.517-.452.813-.091.136-.185.242-.268.399-.02.037-.045.095-.064.134-.128.275-.034.591.213.71.248.12.556-.007.69-.282v-.002c.02-.039.046-.09.062-.127.07-.162.094-.301.144-.458.132-.332.205-.68.387-.897.05-.06.13-.082.215-.105l.113-.205a6.453 6.453 0 0 0 4.609.012l.106.192c.086.028.18.042.256.155.136.232.229.507.342.84.05.156.074.295.145.457.016.037.043.09.062.129.133.276.442.402.69.282.247-.118.341-.435.213-.71-.02-.039-.045-.096-.065-.134-.083-.156-.177-.261-.268-.398-.19-.296-.346-.541-.443-.793-.04-.13.007-.21.038-.294-.018-.022-.059-.144-.083-.202a6.499 6.499 0 0 0 2.88-3.622c.064.01.176.03.213.038.075-.05.144-.114.28-.104.266.039.54.138.87.256.154.06.277.128.448.173.036.01.088.019.13.028l.009.003.007.001c.297.064.584-.098.645-.365.06-.266-.128-.537-.423-.608zM16.4 9.701l-1.95 1.746v.005a.44.44 0 0 0 .173.757l.003.01 2.526.728a5.199 5.199 0 0 0-.108-1.674A5.208 5.208 0 0 0 16.4 9.7zm-4.013 5.325a.437.437 0 0 0-.404-.232.44.44 0 0 0-.372.233h-.002l-1.268 2.292a5.164 5.164 0 0 0 3.326.003l-1.27-2.296h-.01zm1.888-1.293a.44.44 0 0 0-.27.036.44.44 0 0 0-.214.572l-.003.004 1.01 2.438a5.15 5.15 0 0 0 2.081-2.615l-2.6-.44-.004.005z" />
</svg>
);
export default createFrontendPlugin({
pluginId: 'kubernetes',
title: 'Kubernetes',
icon: <RiShipLine />,
icon: <KubernetesIcon />,
info: { packageJson: () => import('../../package.json') },
extensions: [
kubernetesPage,
-2
View File
@@ -5245,7 +5245,6 @@ __metadata:
"@backstage/plugin-catalog-react": "workspace:^"
"@backstage/plugin-permission-react": "workspace:^"
"@backstage/test-utils": "workspace:^"
"@backstage/ui": "workspace:^"
"@material-ui/core": "npm:^4.12.2"
"@material-ui/icons": "npm:^4.9.1"
"@material-ui/lab": "npm:4.0.0-alpha.61"
@@ -6078,7 +6077,6 @@ __metadata:
"@backstage/plugin-permission-react": "workspace:^"
"@backstage/test-utils": "workspace:^"
"@material-ui/core": "npm:^4.12.2"
"@remixicon/react": "npm:^4.6.0"
"@testing-library/dom": "npm:^10.0.0"
"@testing-library/jest-dom": "npm:^6.0.0"
"@testing-library/react": "npm:^16.0.0"