Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@red-hat-developer-hub/backstage-plugin-quickstart': minor
Comment thread
its-mitesh-kumar marked this conversation as resolved.
---

Defer Quickstart NFS drawer content, init snackbar, and help menu item to async chunks so the Module Federation sync graph stays thin. The help menu uses a blueprint `loader` and a local MUI `MenuItem` instead of `global-header/components` to avoid pulling `@backstage/core-components` into the quickstart MF graph.

CTA links use MUI `Button` with `react-router-dom` `Link` (and native anchors for external URLs) instead of `@backstage/ui`. Invalid icon fallbacks use MUI `WidgetsOutlined` instead of a copied `ShapesOutlinedIcon`. Menu-item registration imports `GlobalHeaderMenuItemBlueprint` from `global-header/blueprints` so the critical header / markdown highlight stack stays out of the quickstart async graph.

Bumps `@red-hat-developer-hub/backstage-plugin-global-header` for the `/blueprints` export and loader blueprint API.

Adds public legacy exports `quickstartTranslationRef` and `quickstartTranslations`. Legacy `QuickstartButton` and `QuickstartDrawerProvider` exported types widen from concrete function signatures to `React.ComponentType` because they are now re-exported from lazy component extensions rather than concrete component modules.
18 changes: 10 additions & 8 deletions workspaces/quickstart/e2e-tests/quick-start-admin-guest.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
*/
import { expect, test, TestInfo } from '@playwright/test';
import { UIhelper, switchToLocale } from './utils/helper';
import { getTranslations, QuickstartMessages } from './utils/translations';
import {
getProgressPattern,
getTranslations,
QuickstartMessages,
} from './utils/translations';
import { runAccessibilityTests } from './utils/accessibility';

test.describe('Test Quick Start plugin', () => {
Expand Down Expand Up @@ -103,7 +107,7 @@ test.describe('Test Quick Start plugin', () => {
.locator('..'); // List
// Find the CTA button within this specific List container to avoid matching the setupAuthentication button
const configureGitCta = parentList
.getByRole('button', { name: translations.steps.configureGit.ctaTitle })
.getByRole('link', { name: translations.steps.configureGit.ctaTitle })
.first();
await configureGitCta.waitFor({ state: 'visible' });
const href = await configureGitCta.getAttribute('href');
Expand Down Expand Up @@ -133,7 +137,7 @@ test.describe('Test Quick Start plugin', () => {
.locator('..')
.locator('..');
const setupLightspeedCta = setupLightspeedParentList
.getByRole('button', {
.getByRole('link', {
name: translations.steps.setupLightspeed.ctaTitle,
})
.first();
Expand All @@ -147,13 +151,11 @@ test.describe('Test Quick Start plugin', () => {
translations.steps.managePlugins.ctaTitle,
'/extensions',
);
await uiHelper.clickButtonByText(translations.steps.managePlugins.ctaTitle);
await uiHelper.clickLinkByText(translations.steps.managePlugins.ctaTitle);
await expect(page).toHaveURL(/extensions/);

const progressPattern = new RegExp(
translations.footer.progress.replace('{{progress}}', '\\d+'),
);
await uiHelper.verifyText(progressPattern);
await expect(page.getByRole('progressbar')).toBeVisible();
await uiHelper.verifyText(getProgressPattern(translations.footer.progress));
await uiHelper.clickButtonByText(translations.footer.hide);
await expect(
page.getByRole('button', { name: translations.footer.hide }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ test.describe('Test Quick Start plugin', () => {
translations.steps.importApplication.ctaTitle,
'/bulk-import',
);
await uiHelper.clickButtonByText(
await uiHelper.clickLinkByText(
translations.steps.importApplication.ctaTitle,
{
exact: true,
Expand All @@ -131,7 +131,7 @@ test.describe('Test Quick Start plugin', () => {
translations.steps.learnAboutCatalog.ctaTitle,
'/catalog',
);
await uiHelper.clickButtonByText(
await uiHelper.clickLinkByText(
translations.steps.learnAboutCatalog.ctaTitle,
);
await uiHelper.verifyHeading('My Company Catalog');
Expand All @@ -142,7 +142,7 @@ test.describe('Test Quick Start plugin', () => {
translations.steps.exploreSelfServiceTemplates.ctaTitle,
'/create',
);
await uiHelper.clickButtonByText(
await uiHelper.clickLinkByText(
translations.steps.exploreSelfServiceTemplates.ctaTitle,
);
await expect(page).toHaveURL(/\/create/);
Expand All @@ -151,7 +151,7 @@ test.describe('Test Quick Start plugin', () => {
translations.steps.findAllLearningPaths.ctaTitle,
'/learning-paths',
);
await uiHelper.clickButtonByText(
await uiHelper.clickLinkByText(
translations.steps.findAllLearningPaths.ctaTitle,
);
const progress100Pattern = new RegExp(
Expand Down
10 changes: 9 additions & 1 deletion workspaces/quickstart/e2e-tests/utils/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,16 @@
.first()
.click();
}
async clickLinkByText(
text: string | RegExp,
options: { exact: boolean } = { exact: false },

Check warning on line 56 in workspaces/quickstart/e2e-tests/utils/helper.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not use an object literal as default for parameter `options`.

See more on https://sonarcloud.io/project/issues?id=redhat-developer_rhdh-plugins&issues=AaDDPm-6pmEJXwzy-2MG&open=AaDDPm-6pmEJXwzy-2MG&pullRequest=4897
) {
await this.page
.getByRole('link', { name: text, exact: options?.exact })
.first()
.click();
}
async verifyButtonURL(label: string | RegExp, url: string) {
// Use locator('a') to find the actual anchor tag, not getByRole which may see button role
const anchor = this.page.locator('a').filter({ hasText: label });
expect(await anchor.first().getAttribute('href')).toContain(url);
}
Expand Down
7 changes: 7 additions & 0 deletions workspaces/quickstart/e2e-tests/utils/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@
return messages as QuickstartMessages;
}

/** Matches localized footer progress text, including decimal percentages. */
export function getProgressPattern(footerProgressTemplate: string): RegExp {
return new RegExp(
footerProgressTemplate.replace('{{progress}}', '\\d+(?:\\.\\d+)?'),

Check warning on line 48 in workspaces/quickstart/e2e-tests/utils/translations.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

`String.raw` should be used to avoid escaping `\`.

See more on https://sonarcloud.io/project/issues?id=redhat-developer_rhdh-plugins&issues=AaDDPnOApmEJXwzy-2MH&open=AaDDPnOApmEJXwzy-2MH&pullRequest=4897
);
}

export function getTranslations(locale: string) {
const languageCode = locale.split('-')[0].toLowerCase();

Expand Down
2 changes: 1 addition & 1 deletion workspaces/quickstart/packages/app-legacy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"@mui/icons-material": "5.18.0",
"@mui/material": "5.18.0",
"@mui/styles": "5.18.0",
"@red-hat-developer-hub/backstage-plugin-global-header": "^2.0.1",
"@red-hat-developer-hub/backstage-plugin-global-header": "^3.1.0",
"@red-hat-developer-hub/backstage-plugin-quickstart": "workspace:^",
"@red-hat-developer-hub/backstage-plugin-theme": "^0.14.11",
"react": "^18.0.2",
Expand Down
2 changes: 1 addition & 1 deletion workspaces/quickstart/packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"@mui/icons-material": "5.18.0",
"@mui/material": "5.18.0",
"@red-hat-developer-hub/backstage-plugin-app-react": "^1.0.0",
"@red-hat-developer-hub/backstage-plugin-global-header": "^2.0.1",
"@red-hat-developer-hub/backstage-plugin-global-header": "^3.1.0",
"@red-hat-developer-hub/backstage-plugin-quickstart": "workspace:^",
"@red-hat-developer-hub/backstage-plugin-theme": "^0.14.11",
"material-icons": "^1.13.14",
Expand Down
4 changes: 2 additions & 2 deletions workspaces/quickstart/plugins/quickstart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ Each quickstart item supports the following properties:

- `title` (required): The display title for the quickstart step
- `description` (required): A brief description of what the step covers
- `icon` (optional): Icon identifier (supports Material UI icons)
- `icon` (optional): Step icon. Supported values: built-in ids (`Admin`, `Rbac`, `Git`, `Plugins`, `Import`, `Catalog`, `SelfService`, `Learning`, `Lightspeed`), registered system icon ids, Material Icons ligature names (e.g. `home`, `school`), an image URL, or an inline SVG string
- `roles` (optional): Array of user roles that should see this quickstart item. Supported values: `['admin', 'developer']`. If not specified, defaults to `['admin']`
- `cta` (optional): Call-to-action object with:
- `text`: Button text
- `text`: CTA label text
- `link`: Target URL or route

## Role-Based Access Control (RBAC)
Expand Down
4 changes: 1 addition & 3 deletions workspaces/quickstart/plugins/quickstart/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"@mui/material": "5.18.0",
"@patternfly/react-icons": "^6.5.0",
"@red-hat-developer-hub/backstage-plugin-app-react": "^1.0.0",
"@red-hat-developer-hub/backstage-plugin-global-header": "^2.0.1",
"@red-hat-developer-hub/backstage-plugin-global-header": "^3.1.0",
Comment thread
its-mitesh-kumar marked this conversation as resolved.
"@red-hat-developer-hub/backstage-plugin-theme": "^0.14.11",
"react-use": "^17.6.0"
},
Expand All @@ -57,15 +57,13 @@
},
"devDependencies": {
"@backstage/cli": "^0.36.5",
"@backstage/core-app-api": "^1.20.4",
"@backstage/dev-utils": "^1.1.26",
"@backstage/frontend-defaults": "^0.5.5",
"@backstage/plugin-permission-common": "^0.9.10",
"@backstage/test-utils": "^1.7.21",
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.0.0",
"msw": "^1.0.0",
"react": "^16.13.1 || ^17.0.0 || ^18.0.0",
"react-dom": "16.13.1 || ^17.0.0 || ^18.0.0",
"react-router-dom": "^6.0.0"
Expand Down
78 changes: 72 additions & 6 deletions workspaces/quickstart/plugins/quickstart/report-legacy.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { BackstagePlugin } from '@backstage/core-plugin-api';
import { CSSProperties } from 'react';
import { JSX as JSX_2 } from 'react/jsx-runtime';
import { PropsWithChildren } from 'react';
import { TranslationRef } from '@backstage/frontend-plugin-api';
import { TranslationResource } from '@backstage/frontend-plugin-api';

// @public
export type DrawerPartialState = {
Expand All @@ -29,9 +31,7 @@ export const filterQuickstartItemsByRole: (
) => QuickstartItemData[];

// @public
export const QuickstartButton: (
input: QuickstartButtonProps,
) => JSX_2.Element | null;
export const QuickstartButton: React.ComponentType<QuickstartButtonProps>;
Comment thread
its-mitesh-kumar marked this conversation as resolved.

// @public
export interface QuickstartButtonProps {
Expand All @@ -56,9 +56,7 @@ export interface QuickstartDrawerContextType {
}

// @public
export const QuickstartDrawerProvider: (
input: PropsWithChildren,
) => JSX_2.Element;
export const QuickstartDrawerProvider: React.ComponentType<PropsWithChildren>;

// @public
export const QuickstartDrawerStateExposer: (
Expand Down Expand Up @@ -86,6 +84,74 @@ export interface QuickstartItemData {
// @public
export const quickstartPlugin: BackstagePlugin<{}, {}, {}>;

// @public
export const quickstartTranslationRef: TranslationRef<
'plugin.quickstart',
{
readonly 'header.title': string;
readonly 'header.subtitle': string;
readonly 'steps.setupAuthentication.title': string;
readonly 'steps.setupAuthentication.description': string;
readonly 'steps.setupAuthentication.ctaTitle': string;
readonly 'steps.configureRbac.title': string;
readonly 'steps.configureRbac.description': string;
readonly 'steps.configureRbac.ctaTitle': string;
readonly 'steps.configureGit.title': string;
readonly 'steps.configureGit.description': string;
readonly 'steps.configureGit.ctaTitle': string;
readonly 'steps.managePlugins.title': string;
readonly 'steps.managePlugins.description': string;
readonly 'steps.managePlugins.ctaTitle': string;
readonly 'steps.importApplication.title': string;
readonly 'steps.importApplication.description': string;
readonly 'steps.importApplication.ctaTitle': string;
readonly 'steps.learnAboutCatalog.title': string;
readonly 'steps.learnAboutCatalog.description': string;
readonly 'steps.learnAboutCatalog.ctaTitle': string;
readonly 'steps.exploreSelfServiceTemplates.title': string;
readonly 'steps.exploreSelfServiceTemplates.description': string;
readonly 'steps.exploreSelfServiceTemplates.ctaTitle': string;
readonly 'steps.findAllLearningPaths.title': string;
readonly 'steps.findAllLearningPaths.description': string;
readonly 'steps.findAllLearningPaths.ctaTitle': string;
readonly 'steps.setupLightspeed.title': string;
readonly 'steps.setupLightspeed.description': string;
readonly 'steps.setupLightspeed.ctaTitle': string;
readonly 'steps.getStartedWithLightspeed.title': string;
readonly 'steps.getStartedWithLightspeed.description': string;
readonly 'steps.getStartedWithLightspeed.ctaTitle': string;
readonly 'button.quickstart': string;
readonly 'button.openQuickstartGuide': string;
readonly 'button.closeDrawer': string;
readonly 'button.gotIt': string;
readonly 'snackbar.helpPrompt': string;
readonly 'footer.progress': string;
readonly 'footer.notStarted': string;
readonly 'footer.hide': string;
readonly 'content.loading': string;
readonly 'content.emptyState.title': string;
readonly 'item.expandAriaLabel': string;
readonly 'item.collapseAriaLabel': string;
readonly 'item.expandButtonAriaLabel': string;
readonly 'item.collapseButtonAriaLabel': string;
readonly 'dev.pageTitle': string;
readonly 'dev.pageDescription': string;
readonly 'dev.drawerControls': string;
readonly 'dev.currentState': string;
readonly 'dev.stateOpen': string;
readonly 'dev.stateClosed': string;
readonly 'dev.instructions': string;
readonly 'dev.step1': string;
readonly 'dev.step2': string;
readonly 'dev.step3': string;
readonly 'dev.step4': string;
readonly 'dev.step5': string;
}
>;

// @public
export const quickstartTranslations: TranslationResource<'plugin.quickstart'>;

// @public
export const useQuickstartDrawerContext: () => QuickstartDrawerContextType;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,6 @@ jest.mock('@red-hat-developer-hub/backstage-plugin-app-react', () => ({
}),
}));

jest.mock('@red-hat-developer-hub/backstage-plugin-global-header', () => ({
GlobalHeaderMenuItem: ({
title,
onClick,
}: {
title?: string;
onClick?: () => void;
}) => (
<button type="button" role="menuitem" onClick={onClick}>
{title}
</button>
),
}));

describe('QuickstartHelpMenuItem', () => {
beforeEach(() => {
jest.clearAllMocks();
Expand Down
Loading
Loading