Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions workspaces/quay/.changeset/quiet-maps-dream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@backstage-community/plugin-quay': patch
---

Migrated the Quay plugin and dev app from Material UI v4 to MUI v5. Replaced `@material-ui/*` with `@mui/material` and `@mui/icons-material`; migrated plugin styling to the `sx` prop and dev app `makeStyles` to `tss-react/mui`. Existing `@backstage/ui` CSS imports are unchanged. No breaking API changes.
2 changes: 2 additions & 0 deletions workspaces/quay/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ coverage
knip-report.md
.vscode
.eslintrc.js
report.api.md
report-alpha.api.md
23 changes: 23 additions & 0 deletions workspaces/quay/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2026 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/** @type {import('prettier').Config} */
module.exports = {
...require('@backstage/cli/config/prettier'),
// api-reports formats report.api.md from the workspace root; disable
// auto-loading prettier-plugin-sort-imports (declaration-only TS blocks).
pluginSearchDirs: false,
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It fixes a failure on pre-commit for prettier issue. The same solution has found in other plugins such as rbac or ocm as well.

1 change: 0 additions & 1 deletion workspaces/quay/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
"@types/react-dom": "^18",
"refractor@npm:3.6.0/prismjs": "^1.30.0"
},
"prettier": "@backstage/cli/config/prettier",
"lint-staged": {
"*.{js,jsx,ts,tsx,mjs,cjs}": [
"eslint --fix",
Expand Down
9 changes: 6 additions & 3 deletions workspaces/quay/packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,14 @@
"@backstage/plugin-user-settings": "^0.9.3",
"@backstage/theme": "^0.7.3",
"@backstage/ui": "^0.15.0",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
"@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0",
"@mui/icons-material": "^5.16.7",
"@mui/material": "^5.16.7",
"react": "^18.0.2",
"react-dom": "^18.0.2",
"react-router-dom": "^6.3.0"
"react-router-dom": "^6.3.0",
"tss-react": "^4.9.10"
},
"devDependencies": {
"@testing-library/dom": "^10.4.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ import {
import { EntityTechdocsContent } from '@backstage/plugin-techdocs';
import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib';
import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
import { Button, Grid } from '@material-ui/core';
import Button from '@mui/material/Button';
import Grid from '@mui/material/Grid';

const techdocsContent = (
<EntityTechdocsContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { makeStyles } from '@material-ui/core';
import { makeStyles } from 'tss-react/mui';

const useStyles = makeStyles({
const useStyles = makeStyles()({
svg: {
width: 'auto',
height: 30,
Expand All @@ -24,8 +24,9 @@ const useStyles = makeStyles({
fill: '#7df3e1',
},
});

const LogoFull = () => {
const classes = useStyles();
const { classes } = useStyles();

return (
<svg
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { makeStyles } from '@material-ui/core';
import { makeStyles } from 'tss-react/mui';

const useStyles = makeStyles({
const useStyles = makeStyles()({
svg: {
width: 'auto',
height: 28,
Expand All @@ -26,7 +26,7 @@ const useStyles = makeStyles({
});

const LogoIcon = () => {
const classes = useStyles();
const { classes } = useStyles();

return (
<svg
Expand Down
31 changes: 15 additions & 16 deletions workspaces/quay/packages/app/src/components/Root/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { PropsWithChildren } from 'react';

import {
Link,
Sidebar,
Expand All @@ -31,19 +33,20 @@ import {
Settings as SidebarSettings,
UserSettingsSignInAvatar,
} from '@backstage/plugin-user-settings';
import { makeStyles } from '@material-ui/core';
import CreateComponentIcon from '@material-ui/icons/AddCircleOutline';
import ExtensionIcon from '@material-ui/icons/Extension';
import HomeIcon from '@material-ui/icons/Home';
import LibraryBooks from '@material-ui/icons/LibraryBooks';
import MenuIcon from '@material-ui/icons/Menu';
import GroupIcon from '@material-ui/icons/People';
import SearchIcon from '@material-ui/icons/Search';
import { PropsWithChildren } from 'react';

import CreateComponentIcon from '@mui/icons-material/AddCircleOutline';
import ExtensionIcon from '@mui/icons-material/Extension';
import HomeIcon from '@mui/icons-material/Home';
import LibraryBooks from '@mui/icons-material/LibraryBooks';
import MenuIcon from '@mui/icons-material/Menu';
import GroupIcon from '@mui/icons-material/People';
import SearchIcon from '@mui/icons-material/Search';
import { makeStyles } from 'tss-react/mui';

import LogoFull from './LogoFull';
import LogoIcon from './LogoIcon';

const useSidebarLogoStyles = makeStyles({
const useSidebarLogoStyles = makeStyles()({
root: {
width: sidebarConfig.drawerWidthClosed,
height: 3 * sidebarConfig.logoHeight,
Expand All @@ -59,7 +62,7 @@ const useSidebarLogoStyles = makeStyles({
});

const SidebarLogo = () => {
const classes = useSidebarLogoStyles();
const { classes } = useSidebarLogoStyles();
const { isOpen } = useSidebarOpenState();

return (
Expand All @@ -80,7 +83,6 @@ export const Root = ({ children }: PropsWithChildren<{}>) => (
</SidebarGroup>
<SidebarDivider />
<SidebarGroup label="Menu" icon={<MenuIcon />}>
{/* Global nav, not org-specific */}
<SidebarItem icon={HomeIcon} to="catalog" text="Home" />
<MyGroupsSidebarItem
singularTitle="My Group"
Expand All @@ -90,11 +92,8 @@ export const Root = ({ children }: PropsWithChildren<{}>) => (
<SidebarItem icon={ExtensionIcon} to="api-docs" text="APIs" />
<SidebarItem icon={LibraryBooks} to="docs" text="Docs" />
<SidebarItem icon={CreateComponentIcon} to="create" text="Create..." />
{/* End global nav */}
<SidebarDivider />
<SidebarScrollWrapper>
{/* Items in this group will be scrollable if they run out of space */}
</SidebarScrollWrapper>
<SidebarScrollWrapper />
</SidebarGroup>
<SidebarSpace />
<SidebarDivider />
Expand Down
11 changes: 7 additions & 4 deletions workspaces/quay/packages/app/src/components/SearchPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,13 @@ import {
useSearch,
} from '@backstage/plugin-search-react';
import { TechDocsSearchResultListItem } from '@backstage/plugin-techdocs';
import { Grid, makeStyles, Paper, Theme } from '@material-ui/core';

const useStyles = makeStyles((theme: Theme) => ({
import Grid from '@mui/material/Grid';
import Paper from '@mui/material/Paper';
import { Theme } from '@mui/material/styles';
import { makeStyles } from 'tss-react/mui';

const useStyles = makeStyles()((theme: Theme) => ({
bar: {
padding: theme.spacing(1, 0),
},
Expand All @@ -53,7 +57,7 @@ const useStyles = makeStyles((theme: Theme) => ({
}));

const SearchPage = () => {
const classes = useStyles();
const { classes } = useStyles();
const { types } = useSearch();
const catalogApi = useApi(catalogApiRef);

Expand Down Expand Up @@ -91,7 +95,6 @@ const SearchPage = () => {
label="Entity"
name="name"
values={async () => {
// Return a list of entities which are documented.
const { items } = await catalogApi.getEntities({
fields: ['metadata.name'],
filter: {
Expand Down
2 changes: 2 additions & 0 deletions workspaces/quay/plugins/quay-actions/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ renovate.json
dist-dynamic
dist-scalprum
playwright-report
report.api.md
report-alpha.api.md
2 changes: 2 additions & 0 deletions workspaces/quay/plugins/quay-backend/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ renovate.json
dist-dynamic
dist-scalprum
playwright-report
report.api.md
report-alpha.api.md
2 changes: 2 additions & 0 deletions workspaces/quay/plugins/quay-common/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ renovate.json
dist-dynamic
dist-scalprum
playwright-report
report.api.md
report-alpha.api.md
6 changes: 5 additions & 1 deletion workspaces/quay/plugins/quay/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
rules: {
'@backstage/no-top-level-material-ui-4-imports': 'error',
},
});
2 changes: 2 additions & 0 deletions workspaces/quay/plugins/quay/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ renovate.json
dist-dynamic
dist-scalprum
playwright-report
report.api.md
report-alpha.api.md
7 changes: 4 additions & 3 deletions workspaces/quay/plugins/quay/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@
"@backstage/plugin-catalog-react": "^3.0.0",
"@backstage/plugin-permission-react": "^0.5.1",
"@backstage/theme": "^0.7.3",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.11.3",
"@material-ui/lab": "4.0.0-alpha.61",
"@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0",

Can we remove these as the plugin source has zero imports from @emotion/*

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They’re there because MUI v5 uses Emotion as its styling engine. The code never imports them directly, but sx on MUI components (and tss-react in the app) depends on them at runtime.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for explaining! You're right that MUI v5 uses Emotion under the hood for sx — but in the Backstage plugin ecosystem, @emotion/react and @emotion/styled are peer dependencies of @mui/material and are provided by the host Backstage app, not by individual plugins.

Please check the possibility of removing it.

"@mui/icons-material": "^5.16.7",
"@mui/material": "^5.16.7",
"filesize": "^11.0.0",
"luxon": "^3.6.1",
"react-use": "^17.4.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Alert, AlertTitle } from '@material-ui/lab';
import Alert from '@mui/material/Alert';
import AlertTitle from '@mui/material/AlertTitle';

const PermissionAlert = () => {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
import { Link, Progress, Table } from '@backstage/core-components';
import { useApi } from '@backstage/core-plugin-api';

import { Box, Typography } from '@material-ui/core';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';

import { quayApiRef } from '../../api';
import { DOC_LINKS } from '../../doc-links';
Expand Down Expand Up @@ -68,15 +69,15 @@ export function QuayRepository(_props: QuayRepositoryProps) {
data={data}
columns={columns}
emptyContent={
<Box data-testid="quay-repo-table-empty" padding={2}>
<Box data-testid="quay-repo-table-empty" p={2}>
<Typography component="h3" align="center" variant="h6" gutterBottom>
No container images found
</Typography>
<Typography
component="p"
align="center"
variant="body1"
color="textSecondary"
color="text.secondary"
gutterBottom
>
This repository doesn't contain any images yet, or there might be
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ import type { ReactNode } from 'react';

import { Link, Progress, TableColumn } from '@backstage/core-components';

import { Tooltip } from '@material-ui/core';
import makeStyles from '@material-ui/core/styles/makeStyles';
import Tooltip from '@mui/material/Tooltip';

import { securityScanComparator, vulnerabilitySummary } from '../../lib/utils';
import type { QuayTagData } from '../../types';
Expand Down Expand Up @@ -83,7 +82,7 @@ export const columns: TableColumn<QuayTagData>[] = [
{
title: 'Size',
field: 'size',
type: 'numeric',
type: 'string',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we are changing from numeric to string ?

@ciiay ciiay Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's numeric type, the sorting arrow icon will be placed on left of the header "Size" which is opposite to other headers. Made this change to make it consistent for all headers.

customSort: (a: QuayTagData, b: QuayTagData) => a.rawSize - b.rawSize,
},
{
Expand All @@ -100,11 +99,3 @@ export const columns: TableColumn<QuayTagData>[] = [
a.manifest_digest_raw.localeCompare(b.manifest_digest_raw),
},
];

export const useStyles = makeStyles(theme => ({
empty: {
padding: theme.spacing(2),
display: 'flex',
justifyContent: 'center',
},
}));
Loading
Loading