diff --git a/workspaces/homepage/.changeset/mui-v5-homepage.md b/workspaces/homepage/.changeset/mui-v5-homepage.md new file mode 100644 index 0000000000..fa160df564 --- /dev/null +++ b/workspaces/homepage/.changeset/mui-v5-homepage.md @@ -0,0 +1,6 @@ +--- +'@red-hat-developer-hub/backstage-plugin-dynamic-home-page': patch +--- + +Replace Material UI v4 with MUI v5 and scope JSS class names to prevent style collisions. +Fix double border issue in the widgets diff --git a/workspaces/homepage/docs/cards/jokes.md b/workspaces/homepage/docs/cards/jokes.md deleted file mode 100644 index a28d260a7a..0000000000 --- a/workspaces/homepage/docs/cards/jokes.md +++ /dev/null @@ -1,22 +0,0 @@ -# Jokes - -A card that shows a random joke loaded from [official-joke-api.appspot.com](https://official-joke-api.appspot.com/). - -The sourcecode and jokes of the Joke API are available on [GitHub](https://github.com/15Dkatz/official_joke_api). - -![Home page with a joke card](jokes.png) - -## Example - -```yaml -dynamicPlugins: - frontend: - red-hat-developer-hub.backstage-plugin-dynamic-home-page: - mountPoints: - - mountPoint: home.page/cards - importName: JokeCard -``` - -## Contributions - -The dynamic home page plugin reexports the [`HomePageRandomJoke`](https://github.com/backstage/backstage/tree/master/plugins/home/src/homePageComponents/RandomJoke) from the [home plugin](https://github.com/backstage/backstage/tree/master/plugins/home). diff --git a/workspaces/homepage/e2e-tests/homepageCards.test.ts b/workspaces/homepage/e2e-tests/homepageCards.test.ts index 752397aca9..082ca8b3e8 100644 --- a/workspaces/homepage/e2e-tests/homepageCards.test.ts +++ b/workspaces/homepage/e2e-tests/homepageCards.test.ts @@ -49,8 +49,8 @@ test.describe('Homepage Card Individual Tests', () => { const actualHeadingText = await greetingHeading.textContent(); // Use the full greeting phrase (e.g. "Good afternoon") to locate the card. - // Using only the first word ("Good") would be too broad — other cards like - // Random Joke can contain that word and match first (hasText is case-insensitive). + // Using only the first word ("Good") would be too broad — other cards can + // contain that word and match first (hasText is case-insensitive). const cardHeading = actualHeadingText ? actualHeadingText.split(',')[0].trim() : translations.onboarding.greeting.goodMorning; diff --git a/workspaces/homepage/e2e-tests/homepageCustomizable.test.ts b/workspaces/homepage/e2e-tests/homepageCustomizable.test.ts index cb51c16158..2cbe1785b4 100644 --- a/workspaces/homepage/e2e-tests/homepageCustomizable.test.ts +++ b/workspaces/homepage/e2e-tests/homepageCustomizable.test.ts @@ -47,8 +47,7 @@ test.describe.serial('Dynamic Home Page Customization', () => { await runAccessibilityTests(sharedPage, testInfo); }); - // Skipping as of now; re-enable after https://github.com/backstage/backstage/issues/33317 is fixed - test.skip('Verify All Cards Can Be Resized in Edit Mode', async ({ + test('Verify All Cards Can Be Resized in Edit Mode', async ({ browser: _browser, }, testInfo) => { await homePageCustomization.enterEditMode(); @@ -86,7 +85,7 @@ test.describe.serial('Dynamic Home Page Customization', () => { sharedPage.getByText(/Good (morning|afternoon|evening)/), ).toBeVisible(); - await homePageCustomization.addWidget('Quick Access Card'); + await homePageCustomization.addWidget('Quick Access'); await expect(sharedPage.getByText('Quick Access')).toBeVisible(); }); diff --git a/workspaces/homepage/eslint.frontend-shared.cjs b/workspaces/homepage/eslint.frontend-shared.cjs new file mode 100644 index 0000000000..f829cdf078 --- /dev/null +++ b/workspaces/homepage/eslint.frontend-shared.cjs @@ -0,0 +1,40 @@ +/* + * Copyright Red Hat, Inc. + * + * 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. + */ + +module.exports = function materialUiMigrationEslintConfig(packageDir) { + return require('@backstage/cli/config/eslint-factory')(packageDir, { + restrictedImports: [ + { + name: '@material-ui/core', + message: 'Use @mui/material instead of Material UI v4.', + }, + { + name: '@material-ui/lab', + message: 'Use @mui/material or @mui/lab instead of Material UI v4.', + }, + { + name: 'makeStyles', + message: + 'Use @mui/material sx/styled, or Backstage UI instead makeStyles.', + }, + { + name: '@material-ui/icons', + message: + "Use '@mui/icons-material/' instead of Material UI v4 (e.g. import MenuIcon from '@mui/icons-material/Menu').", + }, + ], + }); +}; diff --git a/workspaces/homepage/mkdocs.yaml b/workspaces/homepage/mkdocs.yaml index 224ea405ea..deaabfdafd 100644 --- a/workspaces/homepage/mkdocs.yaml +++ b/workspaces/homepage/mkdocs.yaml @@ -20,7 +20,6 @@ nav: - Recently visited: cards/recently-visited.md - Top visited: cards/top-visited.md - Featured docs: cards/featured-docs.md - - Jokes: cards/jokes.md - World clock: cards/worldclock.md - Extend with plugins: - Create a new card: create-a-new-card.md diff --git a/workspaces/homepage/packages/app-legacy/src/App.tsx b/workspaces/homepage/packages/app-legacy/src/App.tsx index f2411c41ce..77a4bdc809 100644 --- a/workspaces/homepage/packages/app-legacy/src/App.tsx +++ b/workspaces/homepage/packages/app-legacy/src/App.tsx @@ -81,7 +81,6 @@ import { RecentlyVisitedCard, TopVisitedCard, FeaturedDocsCard, - JokeCard, WorldClock, HomePageCardMountPoint, } from '@red-hat-developer-hub/backstage-plugin-dynamic-home-page'; @@ -221,6 +220,7 @@ const cardMountPoints: HomePageCardMountPoint[] = [ Component: EntitySection, config: { id: 'rhdh-entity-section', + titleKey: 'entities.title', priority: 201, layouts: layouts.entity, }, @@ -229,6 +229,7 @@ const cardMountPoints: HomePageCardMountPoint[] = [ Component: TemplateSection, config: { id: 'rhdh-template-section', + titleKey: 'templates.title', priority: 200, layouts: layouts.template, }, @@ -239,7 +240,7 @@ const cardMountPoints: HomePageCardMountPoint[] = [ config: { priority: 202, id: 'quickaccess-card', - title: 'Quick Access Card', + titleKey: 'quickAccess.title', layouts: layouts.quickAccessCard, }, }, @@ -321,35 +322,28 @@ const cardMountPoints: HomePageCardMountPoint[] = [ Component: CatalogStarredEntitiesCard, config: { id: 'catalog-starred-entities-card', - title: 'Starred catalog entities', + titleKey: 'starredEntities.title', }, }, { Component: RecentlyVisitedCard as ComponentType, config: { id: 'recently-visited-card', - title: 'Recently visited', + titleKey: 'recentlyVisited.title', }, }, { Component: TopVisitedCard as ComponentType, config: { id: 'top-visited-card', - title: 'Top visited', + titleKey: 'topVisited.title', }, }, { Component: FeaturedDocsCard as ComponentType, config: { id: 'featured-docs-card', - title: 'Featured docs', - }, - }, - { - Component: JokeCard, - config: { - id: 'joke-card', - title: 'Random joke', + titleKey: 'featuredDocs.title', }, }, { diff --git a/workspaces/homepage/packages/app/.eslintrc.js b/workspaces/homepage/packages/app/.eslintrc.js index e2a53a6ad2..493ce7565d 100644 --- a/workspaces/homepage/packages/app/.eslintrc.js +++ b/workspaces/homepage/packages/app/.eslintrc.js @@ -1 +1,18 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +/* + * Copyright Red Hat, Inc. + * + * 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. + */ + +// eslint-disable-next-line @backstage/no-relative-monorepo-imports -- workspace ESLint shared config +module.exports = require('../../eslint.frontend-shared.cjs')(__dirname); diff --git a/workspaces/homepage/packages/app/package.json b/workspaces/homepage/packages/app/package.json index 153a5a5956..e3030c4425 100644 --- a/workspaces/homepage/packages/app/package.json +++ b/workspaces/homepage/packages/app/package.json @@ -44,8 +44,8 @@ "@backstage/plugin-techdocs-module-addons-contrib": "^1.1.36", "@backstage/plugin-user-settings": "^0.9.3", "@backstage/ui": "^0.15.0", - "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", + "@mui/icons-material": "5.18.0", + "@mui/material": "5.18.0", "@red-hat-developer-hub/backstage-plugin-dynamic-home-page": "workspace:^", "@red-hat-developer-hub/backstage-plugin-theme": "^0.14.1", "react": "^18.0.2", diff --git a/workspaces/homepage/packages/app/src/modules/nav/Sidebar.tsx b/workspaces/homepage/packages/app/src/modules/nav/Sidebar.tsx index 3cbd80131a..eec1e8b739 100644 --- a/workspaces/homepage/packages/app/src/modules/nav/Sidebar.tsx +++ b/workspaces/homepage/packages/app/src/modules/nav/Sidebar.tsx @@ -23,8 +23,8 @@ import { } from '@backstage/core-components'; import { NavContentBlueprint } from '@backstage/plugin-app-react'; import { SidebarLogo } from './SidebarLogo'; -import MenuIcon from '@material-ui/icons/Menu'; -import SearchIcon from '@material-ui/icons/Search'; +import MenuIcon from '@mui/icons-material/Menu'; +import SearchIcon from '@mui/icons-material/Search'; import { SidebarSearchModal } from '@backstage/plugin-search'; import { UserSettingsSignInAvatar } from '@backstage/plugin-user-settings'; // import { NotificationsSidebarItem } from '@backstage/plugin-notifications'; diff --git a/workspaces/homepage/packages/app/src/modules/nav/SidebarLogo.tsx b/workspaces/homepage/packages/app/src/modules/nav/SidebarLogo.tsx index b93dcabc74..61ac7325b0 100644 --- a/workspaces/homepage/packages/app/src/modules/nav/SidebarLogo.tsx +++ b/workspaces/homepage/packages/app/src/modules/nav/SidebarLogo.tsx @@ -13,43 +13,45 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import { Link, sidebarConfig, useSidebarOpenState, } from '@backstage/core-components'; -import { makeStyles } from '@material-ui/core'; - +import Box from '@mui/material/Box'; import { LogoFull, LogoIcon, } from '@red-hat-developer-hub/backstage-plugin-theme'; -const useSidebarLogoStyles = makeStyles({ - root: { - width: sidebarConfig.drawerWidthClosed, - height: 3 * sidebarConfig.logoHeight, - display: 'flex', - flexFlow: 'row nowrap', - alignItems: 'center', - marginBottom: -14, - }, - link: { - width: sidebarConfig.drawerWidthClosed, - marginLeft: 24, - }, -}); - export const SidebarLogo = () => { - const classes = useSidebarLogoStyles(); const { isOpen } = useSidebarOpenState(); + const drawerWidth = isOpen + ? sidebarConfig.drawerWidthOpen + : sidebarConfig.drawerWidthClosed; return ( -
- + + {isOpen ? : } -
+ ); }; diff --git a/workspaces/homepage/plugins/dynamic-home-page/.eslintrc.js b/workspaces/homepage/plugins/dynamic-home-page/.eslintrc.js index e2a53a6ad2..493ce7565d 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/.eslintrc.js +++ b/workspaces/homepage/plugins/dynamic-home-page/.eslintrc.js @@ -1 +1,18 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +/* + * Copyright Red Hat, Inc. + * + * 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. + */ + +// eslint-disable-next-line @backstage/no-relative-monorepo-imports -- workspace ESLint shared config +module.exports = require('../../eslint.frontend-shared.cjs')(__dirname); diff --git a/workspaces/homepage/plugins/dynamic-home-page/dev/legacy.tsx b/workspaces/homepage/plugins/dynamic-home-page/dev/legacy.tsx index 9b37ceb358..a4e5dba0bc 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/dev/legacy.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/dev/legacy.tsx @@ -43,7 +43,6 @@ import { DynamicHomePageProps, FeaturedDocsCard, Headline, - JokeCard, Markdown, MarkdownCard, Placeholder, @@ -178,13 +177,6 @@ const defaultMountPoints: HomePageCardMountPoint[] = [ title: 'Featured docs card', }, }, - { - Component: JokeCard, - config: { - id: 'JokeCard', - title: 'Joke card', - }, - }, ]; const createHeadline = ({ @@ -724,17 +716,6 @@ createDevApp() ], }), ) - .addPage( - createPage({ - navTitle: 'JokeCard', - pageTitle: 'JokeCard', - mountPoints: [ - { - Component: JokeCard, - }, - ], - }), - ) .addPage( createPage({ navTitle: 'WorldClock', diff --git a/workspaces/homepage/plugins/dynamic-home-page/package.json b/workspaces/homepage/plugins/dynamic-home-page/package.json index 88f714ed85..6d1db160fa 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/package.json +++ b/workspaces/homepage/plugins/dynamic-home-page/package.json @@ -50,6 +50,7 @@ "dependencies": { "@backstage/catalog-client": "^1.15.1", "@backstage/catalog-model": "^1.9.0", + "@backstage/core-compat-api": "^0.5.11", "@backstage/core-components": "^0.18.10", "@backstage/core-plugin-api": "^1.12.6", "@backstage/frontend-plugin-api": "^0.17.0", @@ -66,8 +67,7 @@ "@red-hat-developer-hub/backstage-plugin-homepage-common": "workspace:^", "@scalprum/react-core": "0.11.1", "react-grid-layout": "1.5.3", - "react-use": "17.6.0", - "tss-react": "4.9.20" + "react-use": "17.6.0" }, "peerDependencies": { "react": "16.13.1 || ^17.0.0 || ^18.2.0", diff --git a/workspaces/homepage/plugins/dynamic-home-page/report-alpha.api.md b/workspaces/homepage/plugins/dynamic-home-page/report-alpha.api.md index 92e412f846..2c601214a5 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/report-alpha.api.md +++ b/workspaces/homepage/plugins/dynamic-home-page/report-alpha.api.md @@ -22,7 +22,11 @@ export const homepageTranslationRef: TranslationRef< readonly 'quickAccess.title': string; readonly 'quickAccess.error': string; readonly 'quickAccess.fetchError': string; + readonly 'featuredDocs.title': string; readonly 'featuredDocs.learnMore': string; + readonly 'starredEntities.title': string; + readonly 'recentlyVisited.title': string; + readonly 'topVisited.title': string; readonly 'templates.title': string; readonly 'templates.error': string; readonly 'templates.empty': string; @@ -48,12 +52,12 @@ export const homepageTranslationRef: TranslationRef< readonly 'onboarding.learn.ariaLabel': string; readonly 'entities.title': string; readonly 'entities.error': string; - readonly 'entities.description': string; readonly 'entities.close': string; readonly 'entities.empty': string; readonly 'entities.fetchError': string; readonly 'entities.emptyDescription': string; readonly 'entities.register': string; + readonly 'entities.description': string; readonly 'entities.browseTheCatalog': string; } >; diff --git a/workspaces/homepage/plugins/dynamic-home-page/report.api.md b/workspaces/homepage/plugins/dynamic-home-page/report.api.md index 9ad29bc63f..a3b09a8580 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/report.api.md +++ b/workspaces/homepage/plugins/dynamic-home-page/report.api.md @@ -144,11 +144,6 @@ export interface HomePageCardMountPointConfig { titleKey?: string; } -// @public (undocumented) -export const JokeCard: ComponentType<{ - defaultCategory?: 'any' | 'programming'; -}>; - // @public (undocumented) export interface Layout { // (undocumented) @@ -223,6 +218,8 @@ export interface QuickAccessCardProps { path?: string; // (undocumented) title?: string; + // (undocumented) + titleKey?: string; } // @public (undocumented) @@ -260,4 +257,6 @@ export interface WorldClockProps { // (undocumented) worldClocks: ClockConfig[]; } + +// (No @packageDocumentation comment for this package) ``` diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/alpha/components/CustomizableGridLayout.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/alpha/components/CustomizableGridLayout.tsx index 3ed6593374..2b33370f08 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/alpha/components/CustomizableGridLayout.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/alpha/components/CustomizableGridLayout.tsx @@ -28,6 +28,8 @@ import { } from '@backstage/plugin-home'; import { useTheme } from '@mui/material/styles'; import GlobalStyles from '@mui/material/GlobalStyles'; + +import { cardWrapperSx } from '../../styles/cardWrapperSx'; import { HomePageCardConfig } from '../../types'; import { useContainerQuery } from '../../hooks/useContainerQuery'; @@ -91,6 +93,7 @@ export const CustomizableGridLayout = ({ ? 'rgba(20, 20, 20, 0.95) !important' : 'rgba(40, 40, 40, 0.93) !important', }, + '[class*="widgetWrapper"]': cardWrapperSx, }} />
{ } return ( - -
- {content} - + + +
+ {content} + + ); }; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/alpha/components/ReadOnlyGirdLayout.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/alpha/components/ReadOnlyGirdLayout.tsx index dfea7cc16e..f24d9a2f30 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/alpha/components/ReadOnlyGirdLayout.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/alpha/components/ReadOnlyGirdLayout.tsx @@ -32,7 +32,7 @@ import { import { ErrorBoundary } from '@backstage/core-components'; -import { makeStyles } from 'tss-react/mui'; +import Box from '@mui/material/Box'; // Removes the doubled scrollbar import 'react-grid-layout/css/styles.css'; @@ -79,19 +79,7 @@ const defaultProps: ResponsiveProps = { compactType: null, }; -const useStyles = makeStyles()({ - // Make card content scrollable (so that cards don't overlap) - cardWrapper: { - '& > div[class*="MuiCard-root"]': { - width: '100%', - height: '100%', - }, - '& div[class*="MuiCardContent-root"]': { - overflow: 'auto', - }, - }, -}); - +import { cardWrapperSx } from '../../styles/cardWrapperSx'; /** * Props for the read-only grid layout. * @alpha @@ -109,7 +97,6 @@ export interface ReadOnlyGridLayoutProps { export const ReadOnlyGridLayout = ({ homepageCards, }: ReadOnlyGridLayoutProps) => { - const { classes } = useStyles(); const [measureRef, measureRect] = useMeasure(); const cards = useMemo(() => { @@ -181,12 +168,12 @@ export const ReadOnlyGridLayout = ({ const children = useMemo(() => { return cards.map(card => ( -
{typeof card.Component === 'function' ? ( @@ -195,9 +182,9 @@ export const ReadOnlyGridLayout = ({ card.Component )} -
+ )); - }, [cards, classes.cardWrapper]); + }, [cards]); return (
diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/alpha/extensions/homePageCards.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/alpha/extensions/homePageCards.tsx index 9ca0d62b4e..51690f5a21 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/alpha/extensions/homePageCards.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/alpha/extensions/homePageCards.tsx @@ -17,6 +17,8 @@ import { HomePageWidgetBlueprint } from '@backstage/plugin-home-react/alpha'; import homePlugin from '@backstage/plugin-home/alpha'; import { compatWrapper } from '@backstage/core-compat-api'; +import { homepageMessages } from '../../translations/ref'; +import { createTranslatedCardRenderer } from '../../utils/translatedCardRenderer'; const defaultCardLayout = { width: { @@ -41,9 +43,11 @@ export const onboardingSectionWidget = HomePageWidgetBlueprint.make({ name: 'Red Hat Developer Hub - Onboarding', layout: defaultCardLayout, components: () => - import('../../components/OnboardingSection').then(m => ({ - Content: m.OnboardingSection, - })), + import('../../components/OnboardingSection/OnboardingSection').then( + m => ({ + Content: m.OnboardingSectionContent, + }), + ), }, }); @@ -55,10 +59,12 @@ export const entitySectionWidget = HomePageWidgetBlueprint.make({ name: 'rhdh-entity-section', params: { name: 'Red Hat Developer Hub - Software Catalog', + title: homepageMessages.entities.title, layout: defaultCardLayout, components: () => - import('../../components/EntitySection').then(m => ({ - Content: () => compatWrapper(), + import('../../components/EntitySection/EntitySection').then(m => ({ + Content: m.EntitySectionContent, + Renderer: createTranslatedCardRenderer('entities.title'), })), }, }); @@ -71,10 +77,12 @@ export const templateSectionWidget = HomePageWidgetBlueprint.make({ name: 'rhdh-template-section', params: { name: 'Red Hat Developer Hub - Explore templates', + title: homepageMessages.templates.title, layout: defaultCardLayout, components: () => - import('../../components/TemplateSection').then(m => ({ - Content: m.TemplateSection, + import('../../components/TemplateSection/TemplateSection').then(m => ({ + Content: m.TemplateSectionContent, + Renderer: createTranslatedCardRenderer('templates.title'), })), }, }); @@ -87,10 +95,14 @@ export const quickAccessCardWidget = HomePageWidgetBlueprint.make({ name: 'quick-access-card', params: { name: 'Quick Access Card', + title: homepageMessages.quickAccess.title, layout: defaultCardLayout, components: () => import('../../components/QuickAccessCard').then(m => ({ - Content: () => compatWrapper(), + Content: m.QuickAccessCardContent, + Renderer: createTranslatedCardRenderer('quickAccess.title', { + quickAccessStyle: true, + }), })), }, }); @@ -114,11 +126,23 @@ export const searchBarWidget = HomePageWidgetBlueprint.make({ }, components: () => import('../../components/SearchBar').then(m => ({ - Content: () => compatWrapper(), + Content: m.SearchBar, + Renderer: ({ Content }: { Content: React.ComponentType }) => + compatWrapper(), })), }, }); +/** + * Renders upstream home cards that include their own InfoCard shell. + * @alpha + */ +const upstreamHomeCardRenderer = ({ + Content, +}: { + Content: React.ComponentType; +}) => ; + /** * NFS widget: FeaturedDocsCard (migrated from mountPoint home.page/cards). * @alpha @@ -127,10 +151,12 @@ export const featuredDocsCardWidget = HomePageWidgetBlueprint.make({ name: 'featured-docs-card', params: { name: 'Featured docs', + title: homepageMessages.featuredDocs.title, layout: defaultCardLayout, components: () => import('../../components/FeaturedDocsCard').then(m => ({ Content: m.FeaturedDocsCard, + Renderer: upstreamHomeCardRenderer, })), }, }); @@ -144,7 +170,14 @@ export const catalogStarredWidget = homePlugin .override({ params: { name: 'CatalogStarred', - title: 'Starred catalog entities', + title: homepageMessages.starredEntities.title, + components: () => + import('../../components/legacy/TranslatedUpstreamHomePageCards').then( + m => ({ + Content: m.CatalogStarredEntitiesCard, + Renderer: upstreamHomeCardRenderer, + }), + ), }, }); @@ -167,10 +200,14 @@ export const RecentlyVisitedWidget = HomePageWidgetBlueprint.make({ params: { layout: defaultCardLayout, name: 'Recently visited', + title: homepageMessages.recentlyVisited.title, components: () => - import('@backstage/plugin-home').then(m => ({ - Content: m.HomePageRecentlyVisited, - })), + import('../../components/legacy/TranslatedUpstreamHomePageCards').then( + m => ({ + Content: m.RecentlyVisitedCard, + Renderer: upstreamHomeCardRenderer, + }), + ), }, }); @@ -183,9 +220,13 @@ export const TopVisitedWidget = HomePageWidgetBlueprint.make({ params: { layout: defaultCardLayout, name: 'Top visited', + title: homepageMessages.topVisited.title, components: () => - import('@backstage/plugin-home').then(m => ({ - Content: () => , - })), + import('../../components/legacy/TranslatedUpstreamHomePageCards').then( + m => ({ + Content: m.TopVisitedCard, + Renderer: upstreamHomeCardRenderer, + }), + ), }, }); diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/DefaultWidgetsReadOnlyGrid.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/DefaultWidgetsReadOnlyGrid.tsx index 6e0e75c252..5877bf00ea 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/DefaultWidgetsReadOnlyGrid.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/DefaultWidgetsReadOnlyGrid.tsx @@ -26,7 +26,7 @@ import { import { ErrorBoundary } from '@backstage/core-components'; -import { makeStyles } from 'tss-react/mui'; +import Box from '@mui/material/Box'; import 'react-grid-layout/css/styles.css'; @@ -70,17 +70,15 @@ const defaultProps: ResponsiveProps = { compactType: null, }; -const useStyles = makeStyles()({ - cardWrapper: { - '& > div[class*="MuiCard-root"]': { - width: '100%', - height: '100%', - }, - '& div[class*="MuiCardContent-root"]': { - overflow: 'auto', - }, +const cardWrapperSx = { + '& > div[class*="MuiCard-root"]': { + width: '100%', + height: '100%', }, -}); + '& div[class*="MuiCardContent-root"]': { + overflow: 'auto', + }, +}; export interface DefaultWidgetsReadOnlyGridProps { defaultWidgets: VisibleDefaultWidget[]; @@ -91,7 +89,6 @@ export const DefaultWidgetsReadOnlyGrid = ({ defaultWidgets, mountPoints, }: DefaultWidgetsReadOnlyGridProps) => { - const { classes } = useStyles(); const [measureRef, measureRect] = useMeasure(); const mountPointsByRef = useMemo(() => { @@ -175,19 +172,19 @@ export const DefaultWidgetsReadOnlyGrid = ({ const children = useMemo(() => { return cards.map(card => ( -
-
+ )); - }, [cards, classes.cardWrapper]); + }, [cards]); return (
diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/EntitySection/EntitySection.test.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/EntitySection/EntitySection.test.tsx index 5572b57872..d001acfc33 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/EntitySection/EntitySection.test.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/EntitySection/EntitySection.test.tsx @@ -19,7 +19,7 @@ import { render, screen } from '@testing-library/react'; import { MemoryRouter } from 'react-router-dom'; import { ThemeProvider, createTheme } from '@mui/material/styles'; -import { EntitySection } from './EntitySection'; +import { EntitySection } from '../legacy/HomePageLegacyCards'; import { useEntities } from '../../hooks/useEntities'; // jsdom does not provide ResizeObserver; required by useContainerQuery in EntitySection diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/EntitySection/EntitySection.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/EntitySection/EntitySection.tsx index f93cceb7bc..2204ba4b76 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/EntitySection/EntitySection.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/EntitySection/EntitySection.tsx @@ -49,6 +49,7 @@ import { useContainerQuery, type ContainerSize, } from '../../hooks/useContainerQuery'; +import { sectionContentContainerSx } from '../../styles/sectionCardSx'; const StyledLink = styled(BackstageLink)(({ theme }) => ({ textDecoration: 'none', @@ -59,7 +60,7 @@ const StyledLink = styled(BackstageLink)(({ theme }) => ({ borderRadius: 4, })); -export const EntitySection = () => { +export const EntitySectionContent = () => { const theme = useTheme(); const { t } = useTranslation(); const { displayName, loading: profileLoading } = useUserProfile(); @@ -285,46 +286,15 @@ export const EntitySection = () => { } return ( - `1px solid ${muitheme.palette.grey[300]}`, - containerType: 'inline-size', - display: 'flex', - flexDirection: 'column', - }} - > - - {t('entities.title')} - - - {content} - {entities?.length > 0 && ( - - - {t('entities.browseTheCatalog')} - - - )} - - + + {content} + {entities?.length > 0 && ( + + + {t('entities.browseTheCatalog')} + + + )} + ); }; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/EntitySection/index.ts b/workspaces/homepage/plugins/dynamic-home-page/src/components/EntitySection/index.ts index 6c2759fb1f..6e6ec736d3 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/EntitySection/index.ts +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/EntitySection/index.ts @@ -13,5 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { EntitySection } from './EntitySection'; -export { EntitySection as default } from './EntitySection'; +export { EntitySectionContent } from './EntitySection'; +export { EntitySection } from '../legacy/HomePageLegacyCards'; +export { EntitySection as default } from '../legacy/HomePageLegacyCards'; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/FeaturedDocsCard.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/FeaturedDocsCard.tsx index 5b00672eb6..f540aa9f97 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/FeaturedDocsCard.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/FeaturedDocsCard.tsx @@ -20,6 +20,14 @@ import { } from '@backstage/plugin-home'; import { useTranslation } from '../hooks/useTranslation'; +import { + TranslatableCardTitleProps, + useHomePageCardTitle, +} from '../utils/useHomePageCardTitle'; + +/** @public */ +export type FeaturedDocsCardComponentProps = FeaturedDocsCardProps & + TranslatableCardTitleProps; /** * Overrides `FeaturedDocsCard` from the home plugin, but overrides the @@ -27,13 +35,19 @@ import { useTranslation } from '../hooks/useTranslation'; * * 1. To fix the all uppercase that is used in home plugin * 2. To add a small missing gap between the title and the button + * + * @public */ -export const FeaturedDocsCard = (props: FeaturedDocsCardProps) => { +export const FeaturedDocsCard = (props: FeaturedDocsCardComponentProps) => { const { t } = useTranslation(); + const { titleKey: _titleKey, title: _title, ...cardProps } = props; + const title = useHomePageCardTitle('featuredDocs.title', props); + return ( ); }; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/HomePage.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/HomePage.tsx index eac2acb94e..c7f2ef532c 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/HomePage.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/HomePage.tsx @@ -28,6 +28,7 @@ import { CustomizableGrid } from './CustomizableGrid'; import { DefaultWidgetsCustomizableGrid } from './DefaultWidgetsCustomizableGrid'; import { DefaultWidgetsReadOnlyGrid } from './DefaultWidgetsReadOnlyGrid'; import { Header, HeaderProps } from './Header'; +import { HomePageStylesProvider } from './HomePageStylesProvider'; import { ReadOnlyGrid } from './ReadOnlyGrid'; export interface HomePageProps extends HeaderProps { @@ -73,9 +74,11 @@ export const HomePage = ({ } return ( - -
- {content} - + + +
+ {content} + + ); }; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/HomePageStylesProvider.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/HomePageStylesProvider.tsx new file mode 100644 index 0000000000..8a72d3c159 --- /dev/null +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/HomePageStylesProvider.tsx @@ -0,0 +1,29 @@ +/* + * Copyright Red Hat, Inc. + * + * 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. + */ + +import { PropsWithChildren } from 'react'; + +import { createGenerateClassName, StylesProvider } from '@mui/styles'; + +const generateClassName = createGenerateClassName({ + seed: 'homepage', +}); + +export const HomePageStylesProvider = ({ children }: PropsWithChildren) => ( + + {children} + +); diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/Markdown.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/Markdown.tsx index b9dad0f07c..1ce9ddf5e0 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/Markdown.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/Markdown.tsx @@ -16,7 +16,7 @@ import { MarkdownContent } from '@backstage/core-components'; -import { makeStyles } from 'tss-react/mui'; +import Box from '@mui/material/Box'; /** * @public @@ -26,32 +26,23 @@ export interface MarkdownProps { content?: string; } -const useStyles = makeStyles()({ - // Make card content scrollable (so that cards don't overlap) - card: { - display: 'flex', - flexDirection: 'column', - width: '100%', - height: '100%', - }, - content: { - overflow: 'auto', - }, -}); - /** * @public */ export const Markdown = (props: MarkdownProps) => { - const { classes } = useStyles(); return ( -
+ {props.title ?

{props.title}

: null} - -
+ + + + ); }; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/OnboardingSection/OnboardingSection.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/OnboardingSection/OnboardingSection.tsx index 3501149339..e090febe2a 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/OnboardingSection/OnboardingSection.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/OnboardingSection/OnboardingSection.tsx @@ -23,7 +23,6 @@ import { catalogApiRef } from '@backstage/plugin-catalog-react'; import Grid from '@mui/material/Grid'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; -import Card from '@mui/material/Card'; import { useTheme } from '@mui/material/styles'; import OnboardingCard from './OnboardingCard'; @@ -34,8 +33,12 @@ import useGreeting from '../../hooks/useGreeting'; import { LearningSectionItem } from '../../types'; import { useTranslation } from '../../hooks/useTranslation'; import { containerGridItemSx } from '../../utils/GridItem'; +import { + sectionTitleSx, + sectionContentContainerSx, +} from '../../styles/sectionCardSx'; -export const OnboardingSection = () => { +export function useOnboardingSection() { const [user, setUser] = useState(); const theme = useTheme(); const isDarkMode = theme.palette.mode === 'dark'; @@ -80,7 +83,13 @@ export const OnboardingSection = () => { return name; }; - const content = ( + const greetingLine = !profileLoading ? ( + + {`${greeting}, ${profileDisplayName() || t('onboarding.guest')}!`} + + ) : null; + + const body = ( { ); + return { greetingLine, body }; +} + +/** @public */ +export const OnboardingSectionContent = () => { + const { greetingLine, body } = useOnboardingSection(); + return ( - `1px solid ${muiTheme.palette.grey[300]}`, - containerType: 'inline-size', - display: 'flex', - flexDirection: 'column', - }} - > - {!profileLoading && ( - - {`${greeting}, ${profileDisplayName() || t('onboarding.guest')}!`} - - )} - - {content} - - + + {greetingLine} + {body} + ); }; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/OnboardingSection/index.ts b/workspaces/homepage/plugins/dynamic-home-page/src/components/OnboardingSection/index.ts index 0278bcb020..adfcf61001 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/OnboardingSection/index.ts +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/OnboardingSection/index.ts @@ -13,5 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { OnboardingSection } from './OnboardingSection'; -export { OnboardingSection as default } from './OnboardingSection'; +export { OnboardingSectionContent } from './OnboardingSection'; +export { OnboardingSection } from '../legacy/HomePageLegacyCards'; +export { OnboardingSection as default } from '../legacy/HomePageLegacyCards'; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/Placeholder.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/Placeholder.tsx index f6a9a5b8e3..3cd4291e7c 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/Placeholder.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/Placeholder.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { makeStyles } from 'tss-react/mui'; +import Box from '@mui/material/Box'; /** * @public @@ -24,35 +24,28 @@ export interface PlaceholderProps { debugContent?: string; } -const useStyles = makeStyles()({ - centerDebugContent: { - height: '100%', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }, - // Make card content scrollable (so that cards don't overlap) - showBorder: { - border: '1px solid gray', - width: '100%', - height: '100%', - }, -}); - /** * @public */ export const Placeholder = (props: PlaceholderProps) => { - const { classes } = useStyles(); - const className = [ - props.debugContent ? classes.centerDebugContent : undefined, - props.showBorder ? classes.showBorder : undefined, - ] - .filter(Boolean) - .join(' '); return ( -
+ {props.debugContent} -
+ ); }; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/QuickAccessCard.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/QuickAccessCard.tsx index c50da5288f..702f3a2b46 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/QuickAccessCard.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/QuickAccessCard.tsx @@ -16,57 +16,44 @@ import type { ReactNode } from 'react'; -import { - CodeSnippet, - InfoCard, - WarningPanel, -} from '@backstage/core-components'; +import { CodeSnippet, WarningPanel } from '@backstage/core-components'; import { ComponentAccordion, HomePageToolkit } from '@backstage/plugin-home'; +import Box from '@mui/material/Box'; import CircularProgress from '@mui/material/CircularProgress'; -import { makeStyles } from 'tss-react/mui'; import { useQuickAccessLinks } from '../hooks/useQuickAccessLinks'; import { useTranslation } from '../hooks/useTranslation'; import { QuickAccessIcon } from './QuickAccessIcon'; -const useStyles = makeStyles()({ - center: { - height: '100%', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }, - title: { - '& div > div > div > div > p': { - textTransform: 'uppercase', - }, - }, -}); - -/** - * @public - */ +/** @public */ export interface QuickAccessCardProps { title?: string; + titleKey?: string; path?: string; } -/** - * @public - */ -export const QuickAccessCard = (props: QuickAccessCardProps) => { - const { classes } = useStyles(); +/** @public */ +export const QuickAccessCardContent = ({ + path, +}: Pick) => { const { t } = useTranslation(); - const { data, error, isLoading } = useQuickAccessLinks(props.path); + const { data, error, isLoading } = useQuickAccessLinks(path); let content: ReactNode; if (isLoading) { content = ( -
+ -
+ ); } else if (!data) { content = ( @@ -88,9 +75,6 @@ export const QuickAccessCard = (props: QuickAccessCardProps) => { ...link, icon: , }))} - // Component creation is allowed inside component props only - // if prop name starts with `render`. - // We accept it here since the upstream package use `Renderer` instead. Renderer={( renderProps, // NOSONAR ) => ( @@ -102,13 +86,7 @@ export const QuickAccessCard = (props: QuickAccessCardProps) => { ); } - return ( - - {content} - - ); + return content; }; + +export { QuickAccessCard } from './legacy/QuickAccessCardLegacy'; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/QuickAccessIcon.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/QuickAccessIcon.tsx index aded4672d5..4a5f308bbf 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/QuickAccessIcon.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/QuickAccessIcon.tsx @@ -15,19 +15,13 @@ */ import type { ReactElement } from 'react'; -import { makeStyles } from 'tss-react/mui'; - import { isValidElement } from 'react'; import { useApp } from '@backstage/core-plugin-api'; +import Box from '@mui/material/Box'; import MuiIcon from '@mui/material/Icon'; -const useStyles = makeStyles()({ - img: { - height: '40px', - width: 'auto', - }, -}); +const iconSx = { height: '40px', width: 'auto' }; export const QuickAccessIcon = ({ icon, @@ -36,7 +30,6 @@ export const QuickAccessIcon = ({ icon: string | ReactElement; alt: string; }) => { - const { classes } = useStyles(); const app = useApp(); if (!icon) { @@ -57,7 +50,7 @@ export const QuickAccessIcon = ({ if (strIcon.startsWith('; + return ; } if ( @@ -66,7 +59,7 @@ export const QuickAccessIcon = ({ strIcon.startsWith('/') || strIcon.startsWith('data:image/') ) { - return {alt}; + return ; } return {strIcon}; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/ReadOnlyGrid.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/ReadOnlyGrid.tsx index af30714e9c..939fe651b1 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/ReadOnlyGrid.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/ReadOnlyGrid.tsx @@ -32,7 +32,7 @@ import { import { ErrorBoundary } from '@backstage/core-components'; -import { makeStyles } from 'tss-react/mui'; +import Box from '@mui/material/Box'; // Removes the doubled scrollbar import 'react-grid-layout/css/styles.css'; @@ -81,18 +81,15 @@ const defaultProps: ResponsiveProps = { compactType: null, }; -const useStyles = makeStyles()({ - // Make card content scrollable (so that cards don't overlap) - cardWrapper: { - '& > div[class*="MuiCard-root"]': { - width: '100%', - height: '100%', - }, - '& div[class*="MuiCardContent-root"]': { - overflow: 'auto', - }, +const cardWrapperSx = { + '& > div[class*="MuiCard-root"]': { + width: '100%', + height: '100%', }, -}); + '& div[class*="MuiCardContent-root"]': { + overflow: 'auto', + }, +}; /** * @public @@ -105,7 +102,6 @@ export interface ReadOnlyGridProps { * @public */ export const ReadOnlyGrid = ({ mountPoints }: ReadOnlyGridProps) => { - const { classes } = useStyles(); const [measureRef, measureRect] = useMeasure(); const cards = useMemo(() => { @@ -170,19 +166,19 @@ export const ReadOnlyGrid = ({ mountPoints }: ReadOnlyGridProps) => { const children = useMemo(() => { return cards.map(card => ( -
-
+
)); - }, [cards, classes.cardWrapper]); + }, [cards]); return (
diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/SearchBar.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/SearchBar.tsx index 31debec9cf..c4b1b27f6e 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/SearchBar.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/SearchBar.tsx @@ -19,26 +19,26 @@ import { useNavigate } from 'react-router-dom'; import { SearchBarBase } from '@backstage/plugin-search-react'; -import { makeStyles } from 'tss-react/mui'; +import { styled } from '@mui/material/styles'; import { useTranslation } from '../hooks/useTranslation'; -const useStyles = makeStyles()(theme => ({ - searchBar: { - '&&': { - backgroundColor: theme.palette.mode === 'dark' ? '#36373A' : '#FFFFFF', - boxShadow: 'none', - border: `1px solid ${ - theme.palette.mode === 'dark' ? '#57585a' : '#E4E4E4' - }`, - borderRadius: '50px', - margin: 0, - }, +const StyledSearchBar = styled(SearchBarBase)(({ theme }) => ({ + '&&': { + backgroundColor: theme.palette.mode === 'dark' ? '#36373A' : '#FFFFFF', + boxShadow: 'none', + border: `1px solid ${ + theme.palette.mode === 'dark' ? '#57585a' : '#E4E4E4' + }`, + borderRadius: '50px', + margin: 0, + overflow: 'hidden', }, - notchedOutline: { - '&&': { - borderStyle: 'none', - }, + '& .MuiOutlinedInput-root': { + borderRadius: '50px', + }, + '& .MuiOutlinedInput-notchedOutline, & fieldset': { + border: 'none', }, })); @@ -54,7 +54,6 @@ export interface SearchBarProps { * @public */ export const SearchBar = ({ path, queryParam }: SearchBarProps) => { - const { classes } = useStyles(); const { t } = useTranslation(); const [value, setValue] = useState(''); const ref = useRef(null); @@ -73,20 +72,13 @@ export const SearchBar = ({ path, queryParam }: SearchBarProps) => { }, [navigate, path, queryParam]); return ( - ); }; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/TemplateSection/TemplateSection.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/TemplateSection/TemplateSection.tsx index bb1db9644b..f7f61402f1 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/TemplateSection/TemplateSection.tsx +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/TemplateSection/TemplateSection.tsx @@ -25,7 +25,6 @@ import { import Grid from '@mui/material/Grid'; import Box from '@mui/material/Box'; -import Card from '@mui/material/Card'; import CircularProgress from '@mui/material/CircularProgress'; import CardContent from '@mui/material/CardContent'; import { styled } from '@mui/material/styles'; @@ -37,6 +36,7 @@ import { ViewMoreLink } from './ViewMoreLink'; import { useTranslation } from '../../hooks/useTranslation'; import { Trans } from '../Trans'; import { containerGridItemSx } from '../../utils/GridItem'; +import { sectionContentContainerSx } from '../../styles/sectionCardSx'; const StyledLink = styled(BackstageLink)(({ theme }) => ({ textDecoration: 'none', @@ -47,7 +47,7 @@ const StyledLink = styled(BackstageLink)(({ theme }) => ({ borderRadius: 4, })); -export const TemplateSection = () => { +export const TemplateSectionContent = () => { const { t } = useTranslation(); const { data: templates, @@ -161,48 +161,18 @@ export const TemplateSection = () => { } return ( - `1px solid ${muiTheme.palette.grey[300]}`, - containerType: 'inline-size', - display: 'flex', - flexDirection: 'column', - }} - > - - {t('templates.title')} - - - {content} - {templates?.items && templates?.items.length > 0 && ( - - - - - - )} - - + + {content} + {templates?.items && templates?.items.length > 0 && ( + + + + + + )} + ); }; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/TemplateSection/index.ts b/workspaces/homepage/plugins/dynamic-home-page/src/components/TemplateSection/index.ts index 93f4a48539..8f67864941 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/components/TemplateSection/index.ts +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/TemplateSection/index.ts @@ -13,5 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { TemplateSection } from './TemplateSection'; -export { TemplateSection as default } from './TemplateSection'; +export { TemplateSectionContent } from './TemplateSection'; +export { TemplateSection } from '../legacy/HomePageLegacyCards'; +export { TemplateSection as default } from '../legacy/HomePageLegacyCards'; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/legacy/HomePageLegacyCards.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/legacy/HomePageLegacyCards.tsx new file mode 100644 index 0000000000..8a5d2a98f5 --- /dev/null +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/legacy/HomePageLegacyCards.tsx @@ -0,0 +1,78 @@ +/* + * Copyright Red Hat, Inc. + * + * 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. + */ + +import Box from '@mui/material/Box'; +import Card from '@mui/material/Card'; +import Typography from '@mui/material/Typography'; + +import { useOnboardingSection } from '../OnboardingSection/OnboardingSection'; +import { EntitySectionContent } from '../EntitySection/EntitySection'; +import { TemplateSectionContent } from '../TemplateSection/TemplateSection'; +import { useTranslation } from '../../hooks/useTranslation'; +import { + sectionCardSx, + sectionScrollSx, + sectionTitleSx, +} from '../../styles/sectionCardSx'; + +/** + * Legacy dynamic-plugin card with its own MUI Card shell (ReadOnlyGrid does not + * wrap mount points in InfoCard). + * + * @public + */ +export const OnboardingSection = () => { + const { greetingLine, body } = useOnboardingSection(); + + return ( + + {greetingLine} + {body} + + ); +}; + +/** @public */ +export const EntitySection = () => { + const { t } = useTranslation(); + + return ( + + + {t('entities.title')} + + + + + + ); +}; + +/** @public */ +export const TemplateSection = () => { + const { t } = useTranslation(); + + return ( + + + {t('templates.title')} + + + + + + ); +}; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/legacy/QuickAccessCardLegacy.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/legacy/QuickAccessCardLegacy.tsx new file mode 100644 index 0000000000..5cdde9940c --- /dev/null +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/legacy/QuickAccessCardLegacy.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Red Hat, Inc. + * + * 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. + */ + +import { InfoCard } from '@backstage/core-components'; + +import { styled } from '@mui/material/styles'; + +import { + QuickAccessCardContent, + type QuickAccessCardProps, +} from '../QuickAccessCard'; +import { useTranslation } from '../../hooks/useTranslation'; +import { getTranslatedTextWithFallback } from '../../translations/utils'; + +const QuickAccessInfoCard = styled(InfoCard)({ + '& div > div > div > div > p': { + textTransform: 'uppercase', + }, +}); + +/** @public */ +export const QuickAccessCard = (props: QuickAccessCardProps) => { + const { t } = useTranslation(); + + const title = + getTranslatedTextWithFallback(t, props.titleKey, props.title) ?? + t('quickAccess.title'); + + return ( + + + + ); +}; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/components/legacy/TranslatedUpstreamHomePageCards.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/components/legacy/TranslatedUpstreamHomePageCards.tsx new file mode 100644 index 0000000000..b82651cf59 --- /dev/null +++ b/workspaces/homepage/plugins/dynamic-home-page/src/components/legacy/TranslatedUpstreamHomePageCards.tsx @@ -0,0 +1,63 @@ +/* + * Copyright Red Hat, Inc. + * + * 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. + */ + +import { + HomePageRecentlyVisited, + HomePageStarredEntities, + HomePageTopVisited, + StarredEntitiesProps, + VisitedByTypeProps, +} from '@backstage/plugin-home'; + +import { + TranslatableCardTitleProps, + useHomePageCardTitle, +} from '../../utils/useHomePageCardTitle'; + +/** @public */ +export type CatalogStarredEntitiesCardProps = StarredEntitiesProps & + TranslatableCardTitleProps; + +/** @public */ +export const CatalogStarredEntitiesCard = ( + props: CatalogStarredEntitiesCardProps, +) => { + const { titleKey: _titleKey, title: _title, ...cardProps } = props; + const title = useHomePageCardTitle('starredEntities.title', props); + return ; +}; + +/** @public */ +export type RecentlyVisitedCardProps = VisitedByTypeProps & + TranslatableCardTitleProps; + +/** @public */ +export const RecentlyVisitedCard = (props: RecentlyVisitedCardProps) => { + const { titleKey: _titleKey, title: _title, ...cardProps } = props; + const title = useHomePageCardTitle('recentlyVisited.title', props); + return ; +}; + +/** @public */ +export type TopVisitedCardProps = VisitedByTypeProps & + TranslatableCardTitleProps; + +/** @public */ +export const TopVisitedCard = (props: TopVisitedCardProps) => { + const { titleKey: _titleKey, title: _title, ...cardProps } = props; + const title = useHomePageCardTitle('topVisited.title', props); + return ; +}; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/index.ts b/workspaces/homepage/plugins/dynamic-home-page/src/index.ts index 265e180cf8..2ac7613f90 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/index.ts +++ b/workspaces/homepage/plugins/dynamic-home-page/src/index.ts @@ -20,4 +20,12 @@ * @packageDocumentation */ +import { unstable_ClassNameGenerator as ClassNameGenerator } from '@mui/material/className'; + +ClassNameGenerator.configure(componentName => { + return componentName.startsWith('v5-') + ? componentName + : `v5-${componentName}`; +}); + export * from './plugin'; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/plugin.ts b/workspaces/homepage/plugins/dynamic-home-page/src/plugin.ts index f4d208a91e..06cff81c81 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/plugin.ts +++ b/workspaces/homepage/plugins/dynamic-home-page/src/plugin.ts @@ -233,7 +233,9 @@ export const CatalogStarredEntitiesCard: ComponentType = name: 'CatalogStarredEntitiesCard', component: { lazy: () => - import('@backstage/plugin-home').then(m => m.HomePageStarredEntities), + import('./components/legacy/TranslatedUpstreamHomePageCards').then( + m => m.CatalogStarredEntitiesCard, + ), }, }), ); @@ -247,7 +249,9 @@ export const RecentlyVisitedCard: ComponentType = name: 'RecentlyVisitedCard', component: { lazy: () => - import('@backstage/plugin-home').then(m => m.HomePageRecentlyVisited), + import('./components/legacy/TranslatedUpstreamHomePageCards').then( + m => m.RecentlyVisitedCard, + ), }, }), ); @@ -261,7 +265,9 @@ export const TopVisitedCard: ComponentType = name: 'TopVisitedCard', component: { lazy: () => - import('@backstage/plugin-home').then(m => m.HomePageTopVisited), + import('./components/legacy/TranslatedUpstreamHomePageCards').then( + m => m.TopVisitedCard, + ), }, }), ); @@ -280,21 +286,6 @@ export const FeaturedDocsCard: ComponentType = }), ); -/** - * @public - */ -export const JokeCard: ComponentType<{ - defaultCategory?: 'any' | 'programming'; -}> = dynamicHomePagePlugin.provide( - createComponentExtension({ - name: 'JokeCard', - component: { - lazy: () => - import('@backstage/plugin-home').then(m => m.HomePageRandomJoke), - }, - }), -); - /** * @public */ diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/styles/cardWrapperSx.ts b/workspaces/homepage/plugins/dynamic-home-page/src/styles/cardWrapperSx.ts new file mode 100644 index 0000000000..9bef7bd2bf --- /dev/null +++ b/workspaces/homepage/plugins/dynamic-home-page/src/styles/cardWrapperSx.ts @@ -0,0 +1,42 @@ +/* + * Copyright Red Hat, Inc. + * + * 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. + */ + +import type { SxProps, Theme } from '@mui/material/styles'; + +/** Top-level card in a grid item (not nested inside another card). */ +const topLevelCard = + '& [class*="MuiCard-root"]:not([class*="MuiCard-root"] [class*="MuiCard-root"])'; + +/** + * Grid item styles that keep the card title fixed while only the card body scrolls. + */ +export const cardWrapperSx: SxProps = { + height: '100%', + [topLevelCard]: { + width: '100%', + height: '100%', + display: 'flex', + flexDirection: 'column', + }, + [`${topLevelCard} > [class*="MuiCardHeader-root"]`]: { + flexShrink: 0, + }, + [`${topLevelCard} > [class*="MuiCardContent-root"]`]: { + flex: '1 1 auto', + minHeight: 0, + overflow: 'auto', + }, +}; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/styles/sectionCardSx.ts b/workspaces/homepage/plugins/dynamic-home-page/src/styles/sectionCardSx.ts new file mode 100644 index 0000000000..a3e36880b5 --- /dev/null +++ b/workspaces/homepage/plugins/dynamic-home-page/src/styles/sectionCardSx.ts @@ -0,0 +1,47 @@ +/* + * Copyright Red Hat, Inc. + * + * 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. + */ + +import type { SxProps, Theme } from '@mui/material/styles'; + +/** Legacy section card shell used outside NFS CardExtension. */ +export const sectionCardSx: SxProps = { + padding: '24px', + border: theme => `1px solid ${theme.palette.grey[300]}`, + containerType: 'inline-size', + display: 'flex', + flexDirection: 'column', +}; + +export const sectionTitleSx = { + display: 'flex', + alignItems: 'center', + fontWeight: '500', + fontSize: '1.5rem', + flexShrink: 0, +}; + +/** Scrollable body region inside legacy section cards. */ +export const sectionScrollSx = { + flex: 1, + minHeight: 0, + overflowY: 'auto', + mt: 1, +}; + +/** Enables @container breakpoints for section grids inside NFS CardExtension. */ +export const sectionContentContainerSx: SxProps = { + containerType: 'inline-size', +}; diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/translations/de.ts b/workspaces/homepage/plugins/dynamic-home-page/src/translations/de.ts index 7f42210982..584b46b162 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/translations/de.ts +++ b/workspaces/homepage/plugins/dynamic-home-page/src/translations/de.ts @@ -32,7 +32,11 @@ const homepageTranslationDe = createTranslationMessages({ 'quickAccess.title': 'Schnellzugriff', 'quickAccess.fetchError': 'Daten konnten nicht abgerufen werden.', 'quickAccess.error': 'Unbekannter Fehler', + 'featuredDocs.title': 'Empfohlene Dokumentation', 'featuredDocs.learnMore': ' Mehr erfahren', + 'starredEntities.title': 'Markierte Katalogentitäten', + 'recentlyVisited.title': 'Zuletzt besucht', + 'topVisited.title': 'Am häufigsten besucht', 'templates.title': 'Vorlagen erkunden', 'templates.fetchError': 'Daten konnten nicht abgerufen werden.', 'templates.error': 'Unbekannter Fehler', diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/translations/es.ts b/workspaces/homepage/plugins/dynamic-home-page/src/translations/es.ts index b6bc0e1e83..208975942d 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/translations/es.ts +++ b/workspaces/homepage/plugins/dynamic-home-page/src/translations/es.ts @@ -33,7 +33,11 @@ const homepageTranslationEs = createTranslationMessages({ 'quickAccess.title': 'Acceso rápido', 'quickAccess.fetchError': 'No se pudieron obtener los datos.', 'quickAccess.error': 'Error desconocido', + 'featuredDocs.title': 'Documentación destacada', 'featuredDocs.learnMore': ' Saber más', + 'starredEntities.title': 'Entidades del catálogo marcadas', + 'recentlyVisited.title': 'Visitados recientemente', + 'topVisited.title': 'Más visitados', 'templates.title': 'Explorar plantillas', 'templates.fetchError': 'No se pudieron obtener los datos.', 'templates.error': 'Error desconocido', diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/translations/fr.ts b/workspaces/homepage/plugins/dynamic-home-page/src/translations/fr.ts index 05fea460cc..4ecc468db8 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/translations/fr.ts +++ b/workspaces/homepage/plugins/dynamic-home-page/src/translations/fr.ts @@ -32,7 +32,11 @@ const homepageTranslationFr = createTranslationMessages({ 'quickAccess.title': 'Accès rapide', 'quickAccess.fetchError': 'Impossible de récupérer les données.', 'quickAccess.error': 'Erreur inconnue', + 'featuredDocs.title': 'Documentation en vedette', 'featuredDocs.learnMore': ' En savoir plus', + 'starredEntities.title': 'Entités du catalogue favoris', + 'recentlyVisited.title': 'Récemment visités', + 'topVisited.title': 'Les plus visités', 'templates.title': 'Explorer les modèles', 'templates.fetchError': 'Impossible de récupérer les données.', 'templates.error': 'Erreur inconnue', diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/translations/it.ts b/workspaces/homepage/plugins/dynamic-home-page/src/translations/it.ts index ae8b82d8d0..a7fd117d62 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/translations/it.ts +++ b/workspaces/homepage/plugins/dynamic-home-page/src/translations/it.ts @@ -32,7 +32,11 @@ const homepageTranslationIt = createTranslationMessages({ 'quickAccess.title': 'Accesso rapido', 'quickAccess.fetchError': 'Impossibile recuperare i dati.', 'quickAccess.error': 'Errore sconosciuto', + 'featuredDocs.title': 'Documenti in evidenza', 'featuredDocs.learnMore': ' Per saperne di più', + 'starredEntities.title': 'Entità del catalogo preferite', + 'recentlyVisited.title': 'Visitati di recente', + 'topVisited.title': 'I più visitati', 'templates.title': 'Esplora i modelli', 'templates.fetchError': 'Impossibile recuperare i dati.', 'templates.error': 'Errore sconosciuto', diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/translations/ja.ts b/workspaces/homepage/plugins/dynamic-home-page/src/translations/ja.ts index dd6463948a..58169d7f40 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/translations/ja.ts +++ b/workspaces/homepage/plugins/dynamic-home-page/src/translations/ja.ts @@ -32,7 +32,11 @@ const homepageTranslationJa = createTranslationMessages({ 'quickAccess.title': 'クイックアクセス', 'quickAccess.fetchError': 'データを取得できませんでした。', 'quickAccess.error': '不明なエラー', + 'featuredDocs.title': 'おすすめドキュメント', 'featuredDocs.learnMore': ' 詳細', + 'starredEntities.title': 'スター付きカタログエンティティ', + 'recentlyVisited.title': '最近の訪問', + 'topVisited.title': 'よく訪問される項目', 'templates.title': 'テンプレートの探索', 'templates.fetchError': 'データを取得できませんでした。', 'templates.error': '不明なエラー', diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/translations/ref.ts b/workspaces/homepage/plugins/dynamic-home-page/src/translations/ref.ts index 7c5e110c35..76540c14ce 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/src/translations/ref.ts +++ b/workspaces/homepage/plugins/dynamic-home-page/src/translations/ref.ts @@ -40,8 +40,18 @@ export const homepageMessages = { error: 'Unknown error', }, featuredDocs: { + title: 'Featured Docs', learnMore: ' Learn more', }, + starredEntities: { + title: 'Starred catalog entities', + }, + recentlyVisited: { + title: 'Recently Visited', + }, + topVisited: { + title: 'Top Visited', + }, templates: { title: 'Explore Templates', fetchError: 'Could not fetch data.', diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/utils/translatedCardRenderer.tsx b/workspaces/homepage/plugins/dynamic-home-page/src/utils/translatedCardRenderer.tsx new file mode 100644 index 0000000000..b5f2387431 --- /dev/null +++ b/workspaces/homepage/plugins/dynamic-home-page/src/utils/translatedCardRenderer.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Red Hat, Inc. + * + * 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. + */ + +import { InfoCard } from '@backstage/core-components'; +import type { RendererProps } from '@backstage/plugin-home-react'; + +import { styled } from '@mui/material/styles'; + +import { useTranslation } from '../hooks/useTranslation'; +import { getTranslatedTextWithFallback } from '../translations/utils'; + +const QuickAccessInfoCard = styled(InfoCard)({ + '& div > div > div > div > p': { + textTransform: 'uppercase', + }, +}); + +/** + * Creates a home page card Renderer that resolves the title via the plugin + * translation system at render time (for NFS HomePageWidgetBlueprint widgets). + */ +export function createTranslatedCardRenderer( + titleKey: string, + options?: { quickAccessStyle?: boolean }, +) { + return function TranslatedCardRenderer({ Content, title }: RendererProps) { + const { t } = useTranslation(); + const displayTitle = getTranslatedTextWithFallback(t, titleKey, title); + + if (options?.quickAccessStyle) { + return ( + + + + ); + } + + return ( + + + + ); + }; +} diff --git a/workspaces/homepage/plugins/dynamic-home-page/src/utils/useHomePageCardTitle.ts b/workspaces/homepage/plugins/dynamic-home-page/src/utils/useHomePageCardTitle.ts new file mode 100644 index 0000000000..1b6251c1d7 --- /dev/null +++ b/workspaces/homepage/plugins/dynamic-home-page/src/utils/useHomePageCardTitle.ts @@ -0,0 +1,37 @@ +/* + * Copyright Red Hat, Inc. + * + * 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. + */ + +import { useTranslation } from '../hooks/useTranslation'; +import { getTranslatedTextWithFallback } from '../translations/utils'; + +export interface TranslatableCardTitleProps { + title?: string; + titleKey?: string; +} + +export function useHomePageCardTitle( + defaultTitleKey: string, + props: TranslatableCardTitleProps, +): string { + const { t } = useTranslation(); + return ( + getTranslatedTextWithFallback( + t, + props.titleKey ?? defaultTitleKey, + props.title, + ) ?? t(defaultTitleKey as keyof typeof t) + ); +} diff --git a/workspaces/homepage/yarn.lock b/workspaces/homepage/yarn.lock index e03730a029..73a0d56b2a 100644 --- a/workspaces/homepage/yarn.lock +++ b/workspaces/homepage/yarn.lock @@ -5827,7 +5827,7 @@ __metadata: languageName: node linkType: hard -"@emotion/cache@npm:*, @emotion/cache@npm:^11.13.0, @emotion/cache@npm:^11.13.5": +"@emotion/cache@npm:^11.13.0, @emotion/cache@npm:^11.13.5": version: 11.14.0 resolution: "@emotion/cache@npm:11.14.0" dependencies: @@ -5907,7 +5907,7 @@ __metadata: languageName: node linkType: hard -"@emotion/serialize@npm:*, @emotion/serialize@npm:^1.2.0, @emotion/serialize@npm:^1.3.0, @emotion/serialize@npm:^1.3.1, @emotion/serialize@npm:^1.3.3": +"@emotion/serialize@npm:^1.2.0, @emotion/serialize@npm:^1.3.0, @emotion/serialize@npm:^1.3.1, @emotion/serialize@npm:^1.3.3": version: 1.3.3 resolution: "@emotion/serialize@npm:1.3.3" dependencies: @@ -5963,7 +5963,7 @@ __metadata: languageName: node linkType: hard -"@emotion/utils@npm:*, @emotion/utils@npm:^1.4.0, @emotion/utils@npm:^1.4.2": +"@emotion/utils@npm:^1.4.0, @emotion/utils@npm:^1.4.2": version: 1.4.2 resolution: "@emotion/utils@npm:1.4.2" checksum: 10c0/7d0010bf60a2a8c1a033b6431469de4c80e47aeb8fd856a17c1d1f76bbc3a03161a34aeaa78803566e29681ca551e7bf9994b68e9c5f5c796159923e44f78d9a @@ -9697,6 +9697,7 @@ __metadata: "@backstage/catalog-model": "npm:^1.9.0" "@backstage/cli": "npm:^0.36.2" "@backstage/core-app-api": "npm:^1.20.1" + "@backstage/core-compat-api": "npm:^0.5.11" "@backstage/core-components": "npm:^0.18.10" "@backstage/core-plugin-api": "npm:^1.12.6" "@backstage/dev-utils": "npm:^1.1.23" @@ -9728,7 +9729,6 @@ __metadata: react: "npm:^16.13.1 || ^17.0.0 || ^18.0.0" react-grid-layout: "npm:1.5.3" react-use: "npm:17.6.0" - tss-react: "npm:4.9.20" peerDependencies: react: 16.13.1 || ^17.0.0 || ^18.2.0 react-router-dom: 6.30.3 @@ -14922,8 +14922,8 @@ __metadata: "@backstage/plugin-techdocs-module-addons-contrib": "npm:^1.1.36" "@backstage/plugin-user-settings": "npm:^0.9.3" "@backstage/ui": "npm:^0.15.0" - "@material-ui/core": "npm:^4.12.2" - "@material-ui/icons": "npm:^4.9.1" + "@mui/icons-material": "npm:5.18.0" + "@mui/material": "npm:5.18.0" "@playwright/test": "npm:1.60.0" "@red-hat-developer-hub/backstage-plugin-dynamic-home-page": "workspace:^" "@red-hat-developer-hub/backstage-plugin-theme": "npm:^0.14.1" @@ -32967,28 +32967,6 @@ __metadata: languageName: node linkType: hard -"tss-react@npm:4.9.20": - version: 4.9.20 - resolution: "tss-react@npm:4.9.20" - dependencies: - "@emotion/cache": "npm:*" - "@emotion/serialize": "npm:*" - "@emotion/utils": "npm:*" - peerDependencies: - "@emotion/react": ^11.4.1 - "@emotion/server": ^11.4.0 - "@mui/material": ^5.0.0 || ^6.0.0 || ^7.0.0 - "@types/react": ^16.8.0 || ^17.0.2 || ^18.0.0 || ^19.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@emotion/server": - optional: true - "@mui/material": - optional: true - checksum: 10c0/90095c969eaa6db893ea9ddb078b76e9668740a55aa8efc95086097cc818c5fc0b48c003d44892980db7665256487db19a39dad46e2952c3d554f7e1e361e8d9 - languageName: node - linkType: hard - "tsyringe@npm:^4.10.0": version: 4.10.0 resolution: "tsyringe@npm:4.10.0"