Skip to content

Commit 1c6b97e

Browse files
committed
fix(homepage): fix missing translations for homepage card widgets
1 parent 859ee5a commit 1c6b97e

27 files changed

Lines changed: 652 additions & 26 deletions
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@red-hat-developer-hub/backstage-plugin-homepage': patch
3+
---
4+
5+
fix missing translations for homepage card widgets

workspaces/homepage/packages/app-legacy/src/App.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,11 @@ import {
7474
TemplateSection,
7575
SearchBar,
7676
Headline,
77-
// Markdown,
78-
// MarkdownCard,
79-
// Placeholder,
8077
CatalogStarredEntitiesCard,
8178
RecentlyVisitedCard,
8279
TopVisitedCard,
8380
FeaturedDocsCard,
81+
JokeCard,
8482
WorldClock,
8583
HomePageCardMountPoint,
8684
} from '@red-hat-developer-hub/backstage-plugin-homepage';
@@ -346,6 +344,14 @@ const cardMountPoints: HomePageCardMountPoint[] = [
346344
titleKey: 'featuredDocs.title',
347345
},
348346
},
347+
{
348+
Component: JokeCard as ComponentType,
349+
config: {
350+
id: 'joke-card',
351+
titleKey: 'randomJoke.title',
352+
descriptionKey: 'randomJoke.description',
353+
},
354+
},
349355
{
350356
Component: WorldClock as ComponentType,
351357
config: {

workspaces/homepage/plugins/homepage/app-config.dynamic.yaml

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ dynamicPlugins:
4242
- mountPoint: home.page/widgets
4343
importName: RecentlyVisitedCard
4444
config:
45-
title: 'Recently Visited'
46-
description: 'Quick access to recently viewed entities and pages'
45+
titleKey: recentlyVisited.title
46+
descriptionKey: recentlyVisited.description
4747
priority: 2
4848
layouts:
4949
xl: { w: 4, h: 3 }
@@ -55,8 +55,8 @@ dynamicPlugins:
5555
- mountPoint: home.page/widgets
5656
importName: TopVisitedCard
5757
config:
58-
title: 'Most Visited'
59-
description: 'Your most frequently accessed entities and services'
58+
titleKey: topVisited.title
59+
descriptionKey: topVisited.description
6060
priority: 1
6161
layouts:
6262
xl: { w: 4, h: 3 }
@@ -65,3 +65,16 @@ dynamicPlugins:
6565
sm: { w: 12, h: 3 }
6666
xs: { w: 12, h: 3 }
6767
xxs: { w: 12, h: 3 }
68+
- mountPoint: home.page/widgets
69+
importName: JokeCard
70+
config:
71+
titleKey: randomJoke.title
72+
descriptionKey: randomJoke.description
73+
priority: 3
74+
layouts:
75+
xl: { w: 4, h: 4 }
76+
lg: { w: 4, h: 4 }
77+
md: { w: 6, h: 4 }
78+
sm: { w: 12, h: 4 }
79+
xs: { w: 12, h: 4 }
80+
xxs: { w: 12, h: 4 }

workspaces/homepage/plugins/homepage/report-alpha.api.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ export const homepageTranslationRef: TranslationRef<
1717
readonly 'header.local': string;
1818
readonly 'header.welcome': string;
1919
readonly 'header.welcomePersonalized': string;
20+
readonly 'search.title': string;
2021
readonly 'search.placeholder': string;
22+
readonly 'search.clearButton': string;
2123
readonly 'homePage.empty': string;
2224
readonly 'quickAccess.title': string;
2325
readonly 'quickAccess.error': string;
@@ -26,14 +28,19 @@ export const homepageTranslationRef: TranslationRef<
2628
readonly 'featuredDocs.learnMore': string;
2729
readonly 'starredEntities.title': string;
2830
readonly 'recentlyVisited.title': string;
31+
readonly 'recentlyVisited.description': string;
2932
readonly 'topVisited.title': string;
33+
readonly 'topVisited.description': string;
34+
readonly 'randomJoke.title': string;
35+
readonly 'randomJoke.description': string;
3036
readonly 'templates.title': string;
3137
readonly 'templates.error': string;
3238
readonly 'templates.empty': string;
3339
readonly 'templates.fetchError': string;
3440
readonly 'templates.emptyDescription': string;
3541
readonly 'templates.register': string;
3642
readonly 'templates.viewAll': string;
43+
readonly 'onboarding.title': string;
3744
readonly 'onboarding.guest': string;
3845
readonly 'onboarding.greeting.goodMorning': string;
3946
readonly 'onboarding.greeting.goodAfternoon': string;
@@ -55,9 +62,9 @@ export const homepageTranslationRef: TranslationRef<
5562
readonly 'entities.close': string;
5663
readonly 'entities.empty': string;
5764
readonly 'entities.fetchError': string;
65+
readonly 'entities.description': string;
5866
readonly 'entities.emptyDescription': string;
5967
readonly 'entities.register': string;
60-
readonly 'entities.description': string;
6168
readonly 'entities.browseTheCatalog': string;
6269
}
6370
>;

workspaces/homepage/plugins/homepage/report.api.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ export interface HomePageCardMountPointConfig {
144144
titleKey?: string;
145145
}
146146

147+
// @public (undocumented)
148+
export const JokeCard: (props: JokeCardProps) => JSX_2.Element;
149+
150+
// @public (undocumented)
151+
export type JokeCardProps = TranslatableCardTitleProps & {
152+
defaultCategory?: 'any' | 'programming';
153+
};
154+
147155
// @public (undocumented)
148156
export interface Layout {
149157
// (undocumented)
@@ -242,6 +250,14 @@ export const TemplateSection: () => JSX_2.Element;
242250
// @public (undocumented)
243251
export const TopVisitedCard: ComponentType<VisitedByTypeProps>;
244252

253+
// @public
254+
export interface TranslatableCardTitleProps {
255+
// (undocumented)
256+
title?: string;
257+
// (undocumented)
258+
titleKey?: string;
259+
}
260+
245261
// @public (undocumented)
246262
export const VisitListener: () => JSX_2.Element | null;
247263

workspaces/homepage/plugins/homepage/src/alpha/components/CustomizableGridLayout.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ import GlobalStyles from '@mui/material/GlobalStyles';
3232
import { cardWrapperSx } from '../../styles/cardWrapperSx';
3333
import { HomePageCardConfig } from '../../types';
3434
import { useContainerQuery } from '../../hooks/useContainerQuery';
35+
import { useTranslation } from '../../hooks/useTranslation';
36+
import { translateHomepageWidget } from '../../utils/translateHomepageWidgets';
3537

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

62+
const translatedHomepageCards = useMemo(
63+
() => homepageCards.map(card => translateHomepageWidget(card, t)),
64+
[homepageCards, t],
65+
);
66+
5967
const config = useMemo(() => {
6068
const defaultConfig: LayoutConfiguration[] = [];
6169

62-
homepageCards.forEach(homepageCard => {
70+
translatedHomepageCards.forEach(homepageCard => {
6371
if (!homepageCard.node) {
6472
return;
6573
}
@@ -81,7 +89,7 @@ export const CustomizableGridLayout = ({
8189
});
8290

8391
return defaultConfig;
84-
}, [homepageCards]);
92+
}, [translatedHomepageCards]);
8593

8694
return (
8795
<>
@@ -106,7 +114,7 @@ export const CustomizableGridLayout = ({
106114
compactType="vertical"
107115
style={{ margin: '-10px' }}
108116
>
109-
{homepageCards.map((card, index) => (
117+
{translatedHomepageCards.map((card, index) => (
110118
<Fragment key={card.name ?? index}>{card.component}</Fragment>
111119
))}
112120
</CustomHomepageGrid>

workspaces/homepage/plugins/homepage/src/alpha/extensions/homePageCards.tsx

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import { HomePageWidgetBlueprint } from '@backstage/plugin-home-react/alpha';
1818
import homePlugin from '@backstage/plugin-home/alpha';
1919
import { compatWrapper } from '@backstage/core-compat-api';
20+
import { InfoCard } from '@backstage/core-components';
2021
import { homepageMessages } from '../../translations/ref';
2122
import { createTranslatedCardRenderer } from '../../utils/translatedCardRenderer';
2223

@@ -33,6 +34,28 @@ const defaultCardLayout = {
3334
},
3435
} as const;
3536

37+
/**
38+
* Renders widget content without an InfoCard shell (used by Search).
39+
* @alpha
40+
*/
41+
const headlessCardRenderer = ({ Content }: { Content: React.ComponentType }) =>
42+
compatWrapper(<Content />);
43+
44+
/**
45+
* Renders widget content inside an InfoCard without a title header.
46+
* @alpha
47+
*/
48+
const untitledInfoCardRenderer = ({
49+
Content,
50+
}: {
51+
Content: React.ComponentType;
52+
}) =>
53+
compatWrapper(
54+
<InfoCard divider={false}>
55+
<Content />
56+
</InfoCard>,
57+
);
58+
3659
/**
3760
* NFS widget: OnboardingSection (migrated from mountPoint home.page/cards).
3861
* @alpha
@@ -41,11 +64,13 @@ export const onboardingSectionWidget = HomePageWidgetBlueprint.make({
4164
name: 'rhdh-onboarding-section',
4265
params: {
4366
name: 'Red Hat Developer Hub - Onboarding',
67+
title: homepageMessages.onboarding.title,
4468
layout: defaultCardLayout,
4569
components: () =>
4670
import('../../components/OnboardingSection/OnboardingSection').then(
4771
m => ({
4872
Content: m.OnboardingSectionContent,
73+
Renderer: untitledInfoCardRenderer,
4974
}),
5075
),
5176
},
@@ -115,6 +140,7 @@ export const searchBarWidget = HomePageWidgetBlueprint.make({
115140
name: 'search-bar',
116141
params: {
117142
name: 'Search',
143+
title: homepageMessages.search.title,
118144
layout: {
119145
...defaultCardLayout,
120146
height: {
@@ -127,8 +153,7 @@ export const searchBarWidget = HomePageWidgetBlueprint.make({
127153
components: () =>
128154
import('../../components/SearchBar').then(m => ({
129155
Content: m.SearchBar,
130-
Renderer: ({ Content }: { Content: React.ComponentType }) =>
131-
compatWrapper(<Content />),
156+
Renderer: headlessCardRenderer,
132157
})),
133158
},
134159
});
@@ -201,6 +226,7 @@ export const RecentlyVisitedWidget = HomePageWidgetBlueprint.make({
201226
layout: defaultCardLayout,
202227
name: 'Recently visited',
203228
title: homepageMessages.recentlyVisited.title,
229+
description: homepageMessages.recentlyVisited.description,
204230
components: () =>
205231
import('../../components/legacy/TranslatedUpstreamHomePageCards').then(
206232
m => ({
@@ -221,6 +247,7 @@ export const TopVisitedWidget = HomePageWidgetBlueprint.make({
221247
layout: defaultCardLayout,
222248
name: 'Top visited',
223249
title: homepageMessages.topVisited.title,
250+
description: homepageMessages.topVisited.description,
224251
components: () =>
225252
import('../../components/legacy/TranslatedUpstreamHomePageCards').then(
226253
m => ({
@@ -230,3 +257,24 @@ export const TopVisitedWidget = HomePageWidgetBlueprint.make({
230257
),
231258
},
232259
});
260+
261+
/**
262+
* NFS widget: RandomJoke (overrides upstream home plugin widget).
263+
* @alpha
264+
*/
265+
export const randomJokeWidget = homePlugin
266+
.getExtension('home-page-widget:home/random-joke')
267+
.override({
268+
params: {
269+
name: 'HomePageRandomJoke',
270+
title: homepageMessages.randomJoke.title,
271+
description: homepageMessages.randomJoke.description,
272+
components: () =>
273+
import('../../components/legacy/TranslatedUpstreamHomePageCards').then(
274+
m => ({
275+
Content: m.JokeCard,
276+
Renderer: upstreamHomeCardRenderer,
277+
}),
278+
),
279+
},
280+
});

workspaces/homepage/plugins/homepage/src/alpha/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
searchBarWidget,
2828
templateSectionWidget,
2929
TopVisitedWidget,
30+
randomJokeWidget,
3031
} from './extensions/homePageCards';
3132
import { homepageTranslations } from '../translations';
3233

@@ -57,6 +58,7 @@ export const homePageModule = createFrontendModule({
5758
TopVisitedWidget,
5859
RecentlyVisitedWidget,
5960
catalogStarredWidget,
61+
randomJokeWidget,
6062
disableToolkit,
6163
],
6264
});

workspaces/homepage/plugins/homepage/src/components/SearchBar.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import { useNavigate } from 'react-router-dom';
1919

2020
import { SearchBarBase } from '@backstage/plugin-search-react';
2121

22+
import Button from '@mui/material/Button';
23+
import InputAdornment from '@mui/material/InputAdornment';
2224
import { styled } from '@mui/material/styles';
2325

2426
import { useTranslation } from '../hooks/useTranslation';
@@ -40,6 +42,11 @@ const StyledSearchBar = styled(SearchBarBase)(({ theme }) => ({
4042
'& .MuiOutlinedInput-notchedOutline, & fieldset': {
4143
border: 'none',
4244
},
45+
'& .MuiInputAdornment-positionEnd .MuiButton-root': {
46+
color: theme.palette.text.primary,
47+
fontWeight: theme.typography.fontWeightRegular,
48+
textTransform: 'none',
49+
},
4350
}));
4451

4552
/**
@@ -71,6 +78,12 @@ export const SearchBar = ({ path, queryParam }: SearchBarProps) => {
7178
navigate(`${url.pathname}${search ? '?' : ''}${search}`);
7279
}, [navigate, path, queryParam]);
7380

81+
const handleClear = useCallback(() => {
82+
setValue('');
83+
}, []);
84+
85+
const clearLabel = t('search.clearButton');
86+
7487
return (
7588
<StyledSearchBar
7689
placeholder={t('search.placeholder')}
@@ -79,6 +92,24 @@ export const SearchBar = ({ path, queryParam }: SearchBarProps) => {
7992
onSubmit={handleSubmit}
8093
margin="none"
8194
inputProps={{ ref }}
95+
clearButton={false}
96+
endAdornment={
97+
<InputAdornment position="end">
98+
<Button
99+
aria-label={clearLabel}
100+
color="inherit"
101+
size="small"
102+
onClick={handleClear}
103+
onKeyDown={event => {
104+
if (event.key === 'Enter') {
105+
event.stopPropagation();
106+
}
107+
}}
108+
>
109+
{clearLabel}
110+
</Button>
111+
</InputAdornment>
112+
}
82113
/>
83114
);
84115
};

0 commit comments

Comments
 (0)