Skip to content
Open
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/homepage/.changeset/yellow-rings-decide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@red-hat-developer-hub/backstage-plugin-homepage': patch
---

fix missing translations for homepage card widgets
18 changes: 13 additions & 5 deletions workspaces/homepage/e2e-tests/homepageCustomizable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ import { test, expect, BrowserContext, Page } from '@playwright/test';
import { TestUtils } from './utils/testUtils.js';
import { HomePageCustomization } from './pages/homePageCustomization.js';
import { runAccessibilityTests } from './utils/accessibility.js';
import { getTranslations } from './utils/translations.js';

test.describe.serial('Dynamic Home Page Customization', () => {
let testUtils: TestUtils;
let homePageCustomization: HomePageCustomization;
let sharedPage: Page;
let sharedContext: BrowserContext;
const translations = getTranslations('en');

test.beforeAll(async ({ browser }) => {
sharedContext = await browser.newContext();
Expand Down Expand Up @@ -80,13 +82,15 @@ test.describe.serial('Dynamic Home Page Customization', () => {
});

test('Verify Add Widget Button Adds Cards', async () => {
await homePageCustomization.addWidget('Onboarding');
await homePageCustomization.addWidget(translations.onboarding.title);
await expect(
sharedPage.getByText(/Good (morning|afternoon|evening)/),
).toBeVisible();

await homePageCustomization.addWidget('Quick Access');
await expect(sharedPage.getByText('Quick Access')).toBeVisible();
await homePageCustomization.addWidget(translations.quickAccess.title);
await expect(
sharedPage.getByText(translations.quickAccess.title),
).toBeVisible();
});

// ── Persistent storage ────────────────────────────────────────────────
Expand All @@ -103,7 +107,9 @@ test.describe.serial('Dynamic Home Page Customization', () => {
await homePageCustomization.verifyCardHidden(
'Good (morning|afternoon|evening)',
);
await homePageCustomization.verifyCardVisible('Quick Access');
await homePageCustomization.verifyCardVisible(
translations.quickAccess.title,
);
const countAfterReload =
await homePageCustomization.getVisibleCardCount();
expect(countAfterReload).toBe(countBeforeReload);
Expand All @@ -120,7 +126,9 @@ test.describe.serial('Dynamic Home Page Customization', () => {
await homePageCustomization.verifyCardHidden(
'Good (morning|afternoon|evening)',
);
await homePageCustomization.verifyCardVisible('Quick Access');
await homePageCustomization.verifyCardVisible(
translations.quickAccess.title,
);
const countAfterLogout =
await homePageCustomization.getVisibleCardCount();
expect(countAfterLogout).toBe(countBeforeLogout);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ export class HomePageCustomization {
await this.page.waitForTimeout(1000); // Wait for dialog to open

// Select the specific widget type from the dialog
await this.page.getByRole('button', { name: title }).click();
await this.page.getByRole('button', { name: title, exact: true }).click();
await this.page.waitForTimeout(1000);
}

Expand Down
12 changes: 9 additions & 3 deletions workspaces/homepage/packages/app-legacy/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,11 @@ import {
TemplateSection,
SearchBar,
Headline,
// Markdown,
// MarkdownCard,
// Placeholder,
CatalogStarredEntitiesCard,
RecentlyVisitedCard,
TopVisitedCard,
FeaturedDocsCard,
JokeCard,
WorldClock,
HomePageCardMountPoint,
} from '@red-hat-developer-hub/backstage-plugin-homepage';
Expand Down Expand Up @@ -346,6 +344,14 @@ const cardMountPoints: HomePageCardMountPoint[] = [
titleKey: 'featuredDocs.title',
},
},
{
Component: JokeCard as ComponentType,
config: {
id: 'joke-card',
titleKey: 'randomJoke.title',
descriptionKey: 'randomJoke.description',
},
},
{
Component: WorldClock as ComponentType,
config: {
Expand Down
21 changes: 17 additions & 4 deletions workspaces/homepage/plugins/homepage/app-config.dynamic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ dynamicPlugins:
- mountPoint: home.page/widgets
importName: RecentlyVisitedCard
config:
title: 'Recently Visited'
description: 'Quick access to recently viewed entities and pages'
titleKey: recentlyVisited.title
descriptionKey: recentlyVisited.description
priority: 2
layouts:
xl: { w: 4, h: 3 }
Expand All @@ -55,8 +55,8 @@ dynamicPlugins:
- mountPoint: home.page/widgets
importName: TopVisitedCard
config:
title: 'Most Visited'
description: 'Your most frequently accessed entities and services'
titleKey: topVisited.title
descriptionKey: topVisited.description
priority: 1
layouts:
xl: { w: 4, h: 3 }
Expand All @@ -65,3 +65,16 @@ dynamicPlugins:
sm: { w: 12, h: 3 }
xs: { w: 12, h: 3 }
xxs: { w: 12, h: 3 }
- mountPoint: home.page/widgets
importName: JokeCard
config:
titleKey: randomJoke.title
descriptionKey: randomJoke.description
priority: 3
layouts:
xl: { w: 4, h: 4 }
lg: { w: 4, h: 4 }
md: { w: 6, h: 4 }
sm: { w: 12, h: 4 }
xs: { w: 12, h: 4 }
xxs: { w: 12, h: 4 }
9 changes: 8 additions & 1 deletion workspaces/homepage/plugins/homepage/report-alpha.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ export const homepageTranslationRef: TranslationRef<
readonly 'header.local': string;
readonly 'header.welcome': string;
readonly 'header.welcomePersonalized': string;
readonly 'search.title': string;
readonly 'search.placeholder': string;
readonly 'search.clearButton': string;
readonly 'homePage.empty': string;
readonly 'quickAccess.title': string;
readonly 'quickAccess.error': string;
Expand All @@ -26,14 +28,19 @@ export const homepageTranslationRef: TranslationRef<
readonly 'featuredDocs.learnMore': string;
readonly 'starredEntities.title': string;
readonly 'recentlyVisited.title': string;
readonly 'recentlyVisited.description': string;
readonly 'topVisited.title': string;
readonly 'topVisited.description': string;
readonly 'randomJoke.title': string;
readonly 'randomJoke.description': string;
readonly 'templates.title': string;
readonly 'templates.error': string;
readonly 'templates.empty': string;
readonly 'templates.fetchError': string;
readonly 'templates.emptyDescription': string;
readonly 'templates.register': string;
readonly 'templates.viewAll': string;
readonly 'onboarding.title': string;
readonly 'onboarding.guest': string;
readonly 'onboarding.greeting.goodMorning': string;
readonly 'onboarding.greeting.goodAfternoon': string;
Expand All @@ -55,9 +62,9 @@ export const homepageTranslationRef: TranslationRef<
readonly 'entities.close': string;
readonly 'entities.empty': string;
readonly 'entities.fetchError': string;
readonly 'entities.description': string;
readonly 'entities.emptyDescription': string;
readonly 'entities.register': string;
readonly 'entities.description': string;
readonly 'entities.browseTheCatalog': string;
}
>;
Expand Down
16 changes: 16 additions & 0 deletions workspaces/homepage/plugins/homepage/report.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,14 @@ export interface HomePageCardMountPointConfig {
titleKey?: string;
}

// @public (undocumented)
export const JokeCard: (props: JokeCardProps) => JSX_2.Element;

// @public (undocumented)
export type JokeCardProps = TranslatableCardTitleProps & {
defaultCategory?: 'any' | 'programming';
};

// @public (undocumented)
export interface Layout {
// (undocumented)
Expand Down Expand Up @@ -242,6 +250,14 @@ export const TemplateSection: () => JSX_2.Element;
// @public (undocumented)
export const TopVisitedCard: ComponentType<VisitedByTypeProps>;

// @public
export interface TranslatableCardTitleProps {
// (undocumented)
title?: string;
// (undocumented)
titleKey?: string;
}

// @public (undocumented)
export const VisitListener: () => JSX_2.Element | null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import GlobalStyles from '@mui/material/GlobalStyles';
import { cardWrapperSx } from '../../styles/cardWrapperSx';
import { HomePageCardConfig } from '../../types';
import { useContainerQuery } from '../../hooks/useContainerQuery';
import { useTranslation } from '../../hooks/useTranslation';
import { translateHomepageWidget } from '../../utils/translateHomepageWidgets';

import 'react-grid-layout/css/styles.css';
import { isCardADefaultConfiguration } from '../utils';
Expand All @@ -53,13 +55,19 @@ export const CustomizableGridLayout = ({
homepageCards,
}: CustomizableGridLayoutProps) => {
const theme = useTheme();
const { t } = useTranslation();
const gridContainerRef = useRef<HTMLDivElement>(null);
useContainerQuery(gridContainerRef, { notifyWindowResize: true });

const translatedHomepageCards = useMemo(
() => homepageCards.map(card => translateHomepageWidget(card, t)),
[homepageCards, t],
);

const config = useMemo(() => {
const defaultConfig: LayoutConfiguration[] = [];

homepageCards.forEach(homepageCard => {
translatedHomepageCards.forEach(homepageCard => {
if (!homepageCard.node) {
return;
}
Expand All @@ -81,7 +89,7 @@ export const CustomizableGridLayout = ({
});

return defaultConfig;
}, [homepageCards]);
}, [translatedHomepageCards]);

return (
<>
Expand All @@ -106,7 +114,7 @@ export const CustomizableGridLayout = ({
compactType="vertical"
style={{ margin: '-10px' }}
>
{homepageCards.map((card, index) => (
{translatedHomepageCards.map((card, index) => (
<Fragment key={card.name ?? index}>{card.component}</Fragment>
))}
</CustomHomepageGrid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import { HomePageWidgetBlueprint } from '@backstage/plugin-home-react/alpha';
import homePlugin from '@backstage/plugin-home/alpha';
import { compatWrapper } from '@backstage/core-compat-api';
import { InfoCard } from '@backstage/core-components';
import { homepageMessages } from '../../translations/ref';
import { createTranslatedCardRenderer } from '../../utils/translatedCardRenderer';

Expand All @@ -33,6 +34,28 @@ const defaultCardLayout = {
},
} as const;

/**
* Renders widget content without an InfoCard shell (used by Search).
* @alpha
*/
const headlessCardRenderer = ({ Content }: { Content: React.ComponentType }) =>
compatWrapper(<Content />);

/**
* Renders widget content inside an InfoCard without a title header.
* @alpha
*/
const untitledInfoCardRenderer = ({
Content,
}: {
Content: React.ComponentType;
}) =>
compatWrapper(
<InfoCard divider={false}>
<Content />
</InfoCard>,
);

/**
* NFS widget: OnboardingSection (migrated from mountPoint home.page/cards).
* @alpha
Expand All @@ -41,11 +64,13 @@ export const onboardingSectionWidget = HomePageWidgetBlueprint.make({
name: 'rhdh-onboarding-section',
params: {
name: 'Red Hat Developer Hub - Onboarding',
title: homepageMessages.onboarding.title,
layout: defaultCardLayout,
components: () =>
import('../../components/OnboardingSection/OnboardingSection').then(
m => ({
Content: m.OnboardingSectionContent,
Renderer: untitledInfoCardRenderer,
}),
),
},
Expand Down Expand Up @@ -115,6 +140,7 @@ export const searchBarWidget = HomePageWidgetBlueprint.make({
name: 'search-bar',
params: {
name: 'Search',
title: homepageMessages.search.title,
layout: {
...defaultCardLayout,
height: {
Expand All @@ -127,8 +153,7 @@ export const searchBarWidget = HomePageWidgetBlueprint.make({
components: () =>
import('../../components/SearchBar').then(m => ({
Content: m.SearchBar,
Renderer: ({ Content }: { Content: React.ComponentType }) =>
compatWrapper(<Content />),
Renderer: headlessCardRenderer,
})),
},
});
Expand Down Expand Up @@ -201,6 +226,7 @@ export const RecentlyVisitedWidget = HomePageWidgetBlueprint.make({
layout: defaultCardLayout,
name: 'Recently visited',
title: homepageMessages.recentlyVisited.title,
description: homepageMessages.recentlyVisited.description,
components: () =>
import('../../components/legacy/TranslatedUpstreamHomePageCards').then(
m => ({
Expand All @@ -221,6 +247,7 @@ export const TopVisitedWidget = HomePageWidgetBlueprint.make({
layout: defaultCardLayout,
name: 'Top visited',
title: homepageMessages.topVisited.title,
description: homepageMessages.topVisited.description,
components: () =>
import('../../components/legacy/TranslatedUpstreamHomePageCards').then(
m => ({
Expand All @@ -230,3 +257,24 @@ export const TopVisitedWidget = HomePageWidgetBlueprint.make({
),
},
});

/**
* NFS widget: RandomJoke (overrides upstream home plugin widget).
* @alpha
*/
export const randomJokeWidget = homePlugin
.getExtension('home-page-widget:home/random-joke')
.override({
params: {
name: 'HomePageRandomJoke',
title: homepageMessages.randomJoke.title,
description: homepageMessages.randomJoke.description,
components: () =>
import('../../components/legacy/TranslatedUpstreamHomePageCards').then(
m => ({
Content: m.JokeCard,
Renderer: upstreamHomeCardRenderer,
}),
),
},
});
2 changes: 2 additions & 0 deletions workspaces/homepage/plugins/homepage/src/alpha/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
searchBarWidget,
templateSectionWidget,
TopVisitedWidget,
randomJokeWidget,
} from './extensions/homePageCards';
import { homepageTranslations } from '../translations';

Expand Down Expand Up @@ -57,6 +58,7 @@ export const homePageModule = createFrontendModule({
TopVisitedWidget,
RecentlyVisitedWidget,
catalogStarredWidget,
randomJokeWidget,
disableToolkit,
],
});
Expand Down
Loading
Loading