diff --git a/workspaces/scorecard/.changeset/modern-eggs-sink.md b/workspaces/scorecard/.changeset/modern-eggs-sink.md new file mode 100644 index 0000000000..d96fc60270 --- /dev/null +++ b/workspaces/scorecard/.changeset/modern-eggs-sink.md @@ -0,0 +1,5 @@ +--- +'@red-hat-developer-hub/backstage-plugin-scorecard': minor +--- + +Adding scorecardHompage and metric page extension, also added e2e support in nfs diff --git a/workspaces/scorecard/.gitignore b/workspaces/scorecard/.gitignore index 77ad56d128..beec71bb32 100644 --- a/workspaces/scorecard/.gitignore +++ b/workspaces/scorecard/.gitignore @@ -51,4 +51,4 @@ site *.session.sql # E2E test reports -e2e-test-report/ +e2e-test-report*/ diff --git a/workspaces/scorecard/app-config.yaml b/workspaces/scorecard/app-config.yaml index d555ea31f2..565658b69b 100644 --- a/workspaces/scorecard/app-config.yaml +++ b/workspaces/scorecard/app-config.yaml @@ -5,8 +5,13 @@ app: extensions: - api:app/app-language: config: - availableLanguages: ['en', 'de', 'fr'] + availableLanguages: ['en', 'de', 'fr', 'it', 'es', 'ja'] defaultLanguage: 'en' + - api:home/visits: true + - app-root-element:home/visit-listener: true + - page:home: + config: + path: / # Scorecard tab: entity shows tab if it matches any filter below. - entity-content:catalog/entity-content-scorecard: @@ -16,6 +21,28 @@ app: type: website - kind: api # e.g. any API entity - type: service # e.g. Component or System with spec.type: service + - home-page-layout:home/dynamic-homepage-layout: + config: + customizable: true + widgetLayout: + ScorecardJiraHomepage: + priority: 240 + breakpoints: + xl: { w: 4, h: 6 } + lg: { w: 4, h: 6 } + md: { w: 4, h: 6 } + sm: { w: 4, h: 6 } + xs: { w: 4, h: 6 } + xxs: { w: 4, h: 6 } + ScorecardGithubHomepage: + priority: 250 + breakpoints: + xl: { w: 4, h: 6, x: 4 } + lg: { w: 4, h: 6, x: 4 } + md: { w: 4, h: 6, x: 4 } + sm: { w: 4, h: 6, x: 4 } + xs: { w: 4, h: 6, x: 4 } + xxs: { w: 4, h: 6, x: 4 } organization: name: My Company diff --git a/workspaces/scorecard/package.json b/workspaces/scorecard/package.json index d2b2f06137..0c084bdce8 100644 --- a/workspaces/scorecard/package.json +++ b/workspaces/scorecard/package.json @@ -21,6 +21,10 @@ "test": "NODE_OPTIONS='--experimental-vm-modules' backstage-cli repo test", "test:all": "NODE_OPTIONS='--experimental-vm-modules' backstage-cli repo test --coverage", "test:e2e": "playwright test", + "test:e2e:legacy": "APP_MODE=legacy playwright test", + "test:e2e:nfs": "APP_MODE=nfs playwright test", + "test:e2e:all": "yarn test:e2e:legacy && yarn test:e2e:nfs", + "playwright": "bash -c 'if [[ \"$*\" == \"test\" ]]; then yarn test:e2e:all; else npx playwright \"$@\"; fi' _", "fix": "backstage-cli repo fix", "lint": "backstage-cli repo lint --since origin/main", "lint:all": "backstage-cli repo lint", diff --git a/workspaces/scorecard/packages/app-legacy/e2e-tests/pages/HomePage.ts b/workspaces/scorecard/packages/app-legacy/e2e-tests/pages/HomePage.ts index a0244a2510..9057994c79 100644 --- a/workspaces/scorecard/packages/app-legacy/e2e-tests/pages/HomePage.ts +++ b/workspaces/scorecard/packages/app-legacy/e2e-tests/pages/HomePage.ts @@ -22,6 +22,8 @@ import { } from '../utils/translationUtils'; type ThresholdState = 'success' | 'warning' | 'error'; +const escapeRegex = (value: string) => + value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); export class HomePage { readonly page: Page; @@ -48,7 +50,22 @@ export class HomePage { async addCard(cardName: string) { await this.page.getByRole('button', { name: 'Add widget' }).click(); - await this.page.getByRole('button', { name: cardName }).click(); + await expect( + this.page.getByRole('heading', { name: 'Add new widget to dashboard' }), + ).toBeVisible(); + + let cardPattern: RegExp; + if (cardName === 'Onboarding section') { + cardPattern = /Onboarding section|RhdhOnboardingSection/i; + } else if (cardName === 'Scorecard: GitHub open PRs') { + cardPattern = /Scorecard:\s*GitHub open PRs|ScorecardGithubHomepage/i; + } else if (cardName === 'Scorecard: Jira open blocking') { + cardPattern = /Scorecard:\s*Jira open blocking|ScorecardJiraHomepage/i; + } else { + cardPattern = new RegExp(escapeRegex(cardName), 'i'); + } + + await this.page.getByRole('button', { name: cardPattern }).first().click(); } async saveChanges() { @@ -69,8 +86,9 @@ export class HomePage { getCard(metricId: 'github.open_prs' | 'jira.open_issues'): Locator { return this.page - .locator('article') - .filter({ hasText: this.translations.metric[metricId].title }); + .getByText(this.translations.metric[metricId].title, { exact: true }) + .last() + .locator('xpath=ancestor::article[1]'); } async verifyThresholdTooltip( diff --git a/workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts b/workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts index 0fd2f0e865..eab635e782 100644 --- a/workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts +++ b/workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts @@ -79,6 +79,17 @@ test.describe('Scorecard Plugin Tests', () => { test.describe('Entity Scorecards', () => { test('Verify permission required state', async ({ browser }, testInfo) => { + await mockScorecardResponse( + page, + { + error: { + name: 'NotAllowedError', + message: 'Permission denied', + }, + }, + 403, + ); + await catalogPage.openCatalog(); await catalogPage.openComponent('Red Hat Developer Hub'); await page.getByText('Scorecard', { exact: true }).click(); @@ -193,7 +204,30 @@ test.describe('Scorecard Plugin Tests', () => { test.describe('Aggregated Scorecards', () => { test('Verify missing permission state', async () => { + await mockAggregatedScorecardResponse( + page, + { + error: { + name: 'NotAllowedError', + message: 'Permission denied', + }, + }, + { + error: { + name: 'NotAllowedError', + message: 'Permission denied', + }, + }, + 403, + ); + await homePage.navigateToHome(); + await page.reload(); + await homePage.enterEditMode(); + await homePage.clearAllCards(); + await homePage.addCard('Scorecard: GitHub open PRs'); + await homePage.addCard('Scorecard: Jira open blocking'); + await homePage.saveChanges(); const entityCount = getEntityCount(translations, currentLocale, '0'); @@ -277,7 +311,9 @@ test.describe('Scorecard Plugin Tests', () => { ), ); - await runAccessibilityTests(page, testInfo); + await runAccessibilityTests(page, testInfo, undefined, { + includeSelectors: ['[data-chart-container]'], + }); }); test('Verify cards aggregation data is not found when API returns empty aggregated response', async () => { diff --git a/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/accessibility.ts b/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/accessibility.ts index 98c3cbf4a1..bb6865f769 100644 --- a/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/accessibility.ts +++ b/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/accessibility.ts @@ -21,10 +21,20 @@ export async function runAccessibilityTests( page: Page, testInfo: TestInfo, attachName = 'accessibility-scan-results.json', + options?: { + includeSelectors?: string[]; + }, ) { - const accessibilityScanResults = await new AxeBuilder({ page }) - .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']) - .analyze(); + let axeBuilder = new AxeBuilder({ page }).withTags([ + 'wcag2a', + 'wcag2aa', + 'wcag21a', + 'wcag21aa', + ]); + for (const selector of options?.includeSelectors ?? []) { + axeBuilder = axeBuilder.include(selector); + } + const accessibilityScanResults = await axeBuilder.analyze(); await testInfo.attach(attachName, { body: JSON.stringify(accessibilityScanResults, null, 2), diff --git a/workspaces/scorecard/packages/app-legacy/src/App.tsx b/workspaces/scorecard/packages/app-legacy/src/App.tsx index 5a2896d6d8..8ce7385021 100644 --- a/workspaces/scorecard/packages/app-legacy/src/App.tsx +++ b/workspaces/scorecard/packages/app-legacy/src/App.tsx @@ -65,8 +65,8 @@ import { DynamicCustomizableHomePage, OnboardingSection, HomePageCardMountPoint, - homepageTranslations, } from '@red-hat-developer-hub/backstage-plugin-dynamic-home-page'; +import { homepageTranslations } from '@red-hat-developer-hub/backstage-plugin-dynamic-home-page/alpha'; import { ComponentType } from 'react'; const mountPoints: HomePageCardMountPoint[] = [ diff --git a/workspaces/scorecard/packages/app/package.json b/workspaces/scorecard/packages/app/package.json index 2b607ef410..05c60c0d8f 100644 --- a/workspaces/scorecard/packages/app/package.json +++ b/workspaces/scorecard/packages/app/package.json @@ -26,6 +26,7 @@ "@backstage/plugin-api-docs": "^0.13.1", "@backstage/plugin-app-react": "^0.1.0", "@backstage/plugin-catalog": "^1.32.0", + "@backstage/plugin-home": "^0.9.2", "@backstage/plugin-org": "^0.6.46", "@backstage/plugin-scaffolder": "^1.34.3", "@backstage/plugin-search": "^1.5.0", @@ -34,6 +35,7 @@ "@backstage/ui": "^0.9.1", "@material-ui/core": "^4.12.2", "@mui/icons-material": "^5.18.0", + "@red-hat-developer-hub/backstage-plugin-dynamic-home-page": "1.11.0", "@red-hat-developer-hub/backstage-plugin-scorecard": "workspace:^", "@red-hat-developer-hub/backstage-plugin-theme": "^0.13.0", "react": "^18.0.2", diff --git a/workspaces/scorecard/packages/app/src/App.tsx b/workspaces/scorecard/packages/app/src/App.tsx index b2ea400829..e69cf3b0dd 100644 --- a/workspaces/scorecard/packages/app/src/App.tsx +++ b/workspaces/scorecard/packages/app/src/App.tsx @@ -18,6 +18,11 @@ import { createApp } from '@backstage/frontend-defaults'; import { rhdhThemeModule } from '@red-hat-developer-hub/backstage-plugin-theme/alpha'; import { + homePageModule, + homepageTranslationsModule, +} from '@red-hat-developer-hub/backstage-plugin-dynamic-home-page/alpha'; +import { + scorecardHomeModule, scorecardTranslationsModule, scorecardCatalogModule, } from '@red-hat-developer-hub/backstage-plugin-scorecard/alpha'; @@ -30,6 +35,9 @@ import { navModule } from './modules/nav'; const app = createApp({ features: [ rhdhThemeModule, + homePageModule, + homepageTranslationsModule, + scorecardHomeModule, scorecardCatalogModule, scorecardTranslationsModule, signInModule, diff --git a/workspaces/scorecard/packages/app/src/modules/nav/Sidebar.tsx b/workspaces/scorecard/packages/app/src/modules/nav/Sidebar.tsx index fc11bc1274..48e52ace7a 100644 --- a/workspaces/scorecard/packages/app/src/modules/nav/Sidebar.tsx +++ b/workspaces/scorecard/packages/app/src/modules/nav/Sidebar.tsx @@ -39,11 +39,19 @@ import { type NavItem = { to: string; text: string; icon: IconComponent; title: string }; -/** Main nav order: Catalog, My Groups, APIs, Docs, Create, RBAC */ +/** Main nav order: Home, Catalog, My Groups, APIs, Docs, Create, RBAC */ const MAIN_NAV_ORDER: Array<{ match: (path: string) => boolean; order: number; }> = [ + { + match: p => { + const [pathWithoutQuery] = p.split('?'); + const [pathWithoutHash] = pathWithoutQuery.split('#'); + return pathWithoutHash === '/' || pathWithoutHash === '/home'; + }, + order: 0, + }, { match: p => p.includes('/catalog'), order: 1 }, { match: p => p.includes('scorecard') || p.includes('my-groups'), order: 2 }, { match: p => p.includes('/api-docs'), order: 3 }, diff --git a/workspaces/scorecard/playwright.config.ts b/workspaces/scorecard/playwright.config.ts index 8176f5d0d2..dc1e7a0b6f 100644 --- a/workspaces/scorecard/playwright.config.ts +++ b/workspaces/scorecard/playwright.config.ts @@ -17,6 +17,8 @@ import { defineConfig } from '@playwright/test'; const LOCALES = ['en', 'fr', 'it', 'ja', 'de', 'es'] as const; +const appMode = process.env.APP_MODE || 'legacy'; +const startCommand = appMode === 'legacy' ? 'yarn start:legacy' : 'yarn start'; export default defineConfig({ timeout: 2 * 60 * 1000, @@ -28,7 +30,7 @@ export default defineConfig({ webServer: process.env.PLAYWRIGHT_URL ? [] : { - command: 'yarn start:legacy', + command: startCommand, port: 3000, reuseExistingServer: true, env: { @@ -39,7 +41,9 @@ export default defineConfig({ retries: process.env.CI ? 2 : 0, - reporter: [['html', { open: 'never', outputFolder: 'e2e-test-report' }]], + reporter: [ + ['html', { open: 'never', outputFolder: `e2e-test-report-${appMode}` }], + ], use: { baseURL: process.env.PLAYWRIGHT_URL ?? 'http://localhost:3000', @@ -47,7 +51,7 @@ export default defineConfig({ trace: 'on-first-retry', }, - outputDir: 'node_modules/.cache/e2e-test-results', + outputDir: `node_modules/.cache/e2e-test-results-${appMode}`, projects: LOCALES.map(locale => ({ name: locale, diff --git a/workspaces/scorecard/plugins/scorecard/README.md b/workspaces/scorecard/plugins/scorecard/README.md index 9436771b9a..b32edffa63 100644 --- a/workspaces/scorecard/plugins/scorecard/README.md +++ b/workspaces/scorecard/plugins/scorecard/README.md @@ -2,7 +2,7 @@ The Scorecard plugin provides a configurable framework to visualize Key Performance Indicators (KPIs) in Backstage. This frontend plugin integrates with the Scorecard backend to deliver Scorecards. -The plugin supports both the **legacy** Backstage frontend and the **New Frontend System (NFS)**. Use the main package for legacy apps and the `/alpha` export for NFS apps. NFS supports only 1 module as of now (the catalog module that adds the Scorecard entity tab). +The plugin supports both the **legacy** Backstage frontend and the **New Frontend System (NFS)**. Use the main package for legacy apps and the `/alpha` export for NFS apps. For NFS, the plugin currently provides three modules: a catalog module for the Scorecard entity tab, a home module for homepage widgets, and a translations module. **Features:** - **Entity scorecard tab** — View scorecard metrics on catalog entity pages (components, websites, etc.). @@ -49,12 +49,14 @@ yarn workspace app-legacy add @red-hat-developer-hub/backstage-plugin-scorecard // In packages/app/src/App.tsx import { createApp } from '@backstage/frontend-defaults'; import { + scorecardHomeModule, scorecardTranslationsModule, scorecardCatalogModule, } from '@red-hat-developer-hub/backstage-plugin-scorecard/alpha'; const app = createApp({ features: [ + scorecardHomeModule, scorecardCatalogModule, scorecardTranslationsModule, // ... other plugins @@ -120,6 +122,47 @@ To align with the legacy EntityPage (Scorecard on component pages and default en 5. Start the NFS app (e.g. `yarn start`), go to **Catalog**, open an entity. The **Scorecard** tab appears for entities that match your `allowedFilters` (or all entities if the extension config is omitted or empty). +6. (Optional) Enable homepage Scorecard widgets by adding `scorecardHomeModule` to app features (see step 2) and configuring home page extensions in `app-config.yaml`: + + ```yaml + app: + extensions: + - page:home: + config: + path: / + - api:home/visits: true + - app-root-element:home/visit-listener: true + - home-page-layout:home/dynamic-homepage-layout: + config: + customizable: true + widgetLayout: + ScorecardJiraHomepage: + priority: 240 + breakpoints: + xl: { w: 4, h: 6 } + lg: { w: 4, h: 6 } + md: { w: 4, h: 6 } + sm: { w: 4, h: 6 } + xs: { w: 4, h: 6 } + xxs: { w: 4, h: 6 } + ScorecardGithubHomepage: + priority: 250 + breakpoints: + xl: { w: 4, h: 6, x: 4 } + lg: { w: 4, h: 6, x: 4 } + md: { w: 4, h: 6, x: 4 } + sm: { w: 4, h: 6, x: 4 } + xs: { w: 4, h: 6, x: 4 } + xxs: { w: 4, h: 6, x: 4 } + ``` + + The home module contributes two widgets: + + - `ScorecardGithubHomepage` (title: **Scorecard: GitHub open PRs**) + - `ScorecardJiraHomepage` (title: **Scorecard: Jira open blocking tickets**) + + These widgets render the same `ScorecardHomepageCard` component used in legacy apps, preconfigured for `github.open_prs` and `jira.open_issues`. + ##### Modules and extensions (NFS) The following modules and extensions are available from `@red-hat-developer-hub/backstage-plugin-scorecard/alpha` for NFS apps: @@ -128,6 +171,7 @@ The following modules and extensions are available from `@red-hat-developer-hub/ | Module | Description | | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `scorecardHomeModule` | Registers Scorecard homepage widgets for the home plugin (`ScorecardGithubHomepage` and `ScorecardJiraHomepage`). | | `scorecardCatalogModule` | Registers the Scorecard entity tab with the catalog plugin. Add to your app's `features`. Which entities show the tab is configured via `app.extensions` (see step 3). | | `scorecardTranslationsModule` | Registers Scorecard translations with the app. Add to your app's `features`. | @@ -135,6 +179,8 @@ The following modules and extensions are available from `@red-hat-developer-hub/ - `api:scorecard` — Scorecard API (provided by the plugin; auto-discovered when the plugin is installed). - `entity-content:catalog/entity-content-scorecard` — Scorecard tab on catalog entity pages. Configure with `allowedFilters` in `app.extensions` to limit by kind and optionally type. +- `home-page-widget:home/scorecard-github-homepage` — Homepage widget showing GitHub open PR metric. +- `home-page-widget:home/scorecard-jira-homepage` — Homepage widget showing Jira open issues metric. #### Legacy app @@ -189,7 +235,17 @@ The following modules and extensions are available from `@red-hat-developer-hub/ ); ``` -3. Optionally use `ScorecardHomepageCard` and `scorecardTranslations` from the main and alpha packages as needed. +3. (Optional) Add Scorecard homepage cards to your home page: + + ```tsx + import { ScorecardHomepageCard } from '@red-hat-developer-hub/backstage-plugin-scorecard'; + + // GitHub open PRs + + + // Jira open issues + + ``` 4. Ensure the frontend can reach the Scorecard backend by configuring discovery in `app-config.yaml` (see discovery snippet under [NFS](#nfs-new-frontend-system--app)). diff --git a/workspaces/scorecard/plugins/scorecard/dev/index.tsx b/workspaces/scorecard/plugins/scorecard/dev/index.tsx index 058c8f0fbe..6442aacf6e 100644 --- a/workspaces/scorecard/plugins/scorecard/dev/index.tsx +++ b/workspaces/scorecard/plugins/scorecard/dev/index.tsx @@ -52,6 +52,7 @@ import { rhdhThemeModule } from '@red-hat-developer-hub/backstage-plugin-theme/a import scorecardPlugin, { scorecardCatalogModule, + scorecardHomeModule, scorecardTranslationsModule, } from '../src/alpha'; import { scorecardApiRef } from '../src/api'; @@ -139,6 +140,7 @@ const app = createApp({ catalogPlugin, scorecardPlugin, scorecardCatalogModule, + scorecardHomeModule, scorecardTranslationsModule, appDevModule, catalogDevModule, diff --git a/workspaces/scorecard/plugins/scorecard/package.json b/workspaces/scorecard/plugins/scorecard/package.json index d4457aa3b7..ff0b7c88be 100644 --- a/workspaces/scorecard/plugins/scorecard/package.json +++ b/workspaces/scorecard/plugins/scorecard/package.json @@ -6,13 +6,13 @@ "types": "src/index.ts", "exports": { ".": "./src/index.ts", - "./alpha": "./src/alpha.tsx", + "./alpha": "./src/alpha/index.tsx", "./package.json": "./package.json" }, "typesVersions": { "*": { "alpha": [ - "src/alpha.tsx" + "src/alpha/index.tsx" ], "package.json": [ "package.json" @@ -55,6 +55,8 @@ "@backstage/frontend-plugin-api": "^0.13.4", "@backstage/plugin-app-react": "^0.1.0", "@backstage/plugin-catalog-react": "^1.21.3", + "@backstage/plugin-home": "^0.9.2", + "@backstage/plugin-home-react": "^0.1.35", "@backstage/plugin-permission-react": "^0.4.38", "@backstage/theme": "^0.7.0", "@mui/icons-material": "5.18.0", diff --git a/workspaces/scorecard/plugins/scorecard/report-alpha.api.md b/workspaces/scorecard/plugins/scorecard/report-alpha.api.md index 2f1a9e78e7..a962b37073 100644 --- a/workspaces/scorecard/plugins/scorecard/report-alpha.api.md +++ b/workspaces/scorecard/plugins/scorecard/report-alpha.api.md @@ -8,23 +8,24 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/frontend-plugin-api'; -import { Entity } from '@backstage/catalog-model'; -import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; import { FrontendModule } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; -import { RouteRef } from '@backstage/frontend-plugin-api'; -import { RouteRef as RouteRef_2 } from '@backstage/core-plugin-api'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/frontend-plugin-api'; import { TranslationResource } from '@backstage/frontend-plugin-api'; // @alpha const _default: OverridableFrontendPlugin< { - root: RouteRef_2; + root: RouteRef; + metric: RouteRef<{ + metricId: string; + }>; }, {}, { @@ -45,6 +46,33 @@ const _default: OverridableFrontendPlugin< params: ApiFactory, ) => ExtensionBlueprintParams; }>; + 'page:scorecard': OverridableExtensionDefinition<{ + kind: 'page'; + name: undefined; + config: { + path: string | undefined; + }; + configInput: { + path?: string | undefined; + }; + output: + | ExtensionDataRef + | ExtensionDataRef + | ExtensionDataRef< + RouteRef_2, + 'core.routing.ref', + { + optional: true; + } + >; + inputs: {}; + params: { + defaultPath?: [Error: "Use the 'path' param instead"] | undefined; + path: string; + loader: () => Promise; + routeRef?: RouteRef_2 | undefined; + }; + }>; } >; export default _default; @@ -53,94 +81,15 @@ export default _default; export const scorecardCatalogModule: FrontendModule; // @alpha -export const scorecardEntityContent: OverridableExtensionDefinition<{ - config: { - allowedFilters: - | { - kind?: string | undefined; - type?: string | undefined; - }[] - | undefined; - path: string | undefined; - title: string | undefined; - filter: EntityPredicate | undefined; - group: string | false | undefined; - }; - configInput: { - allowedFilters?: - | { - kind?: string | undefined; - type?: string | undefined; - }[] - | undefined; - filter?: EntityPredicate | undefined; - title?: string | undefined; - path?: string | undefined; - group?: string | false | undefined; - }; - output: - | ExtensionDataRef - | ExtensionDataRef - | ExtensionDataRef< - RouteRef, - 'core.routing.ref', - { - optional: true; - } - > - | ExtensionDataRef< - (entity: Entity) => boolean, - 'catalog.entity-filter-function', - { - optional: true; - } - > - | ExtensionDataRef< - string, - 'catalog.entity-filter-expression', - { - optional: true; - } - > - | ExtensionDataRef - | ExtensionDataRef< - string, - 'catalog.entity-content-group', - { - optional: true; - } - >; - inputs: {}; - kind: 'entity-content'; - name: 'entity-content-scorecard'; - params: { - defaultPath?: [Error: "Use the 'path' param instead"] | undefined; - path: string; - defaultTitle?: [Error: "Use the 'title' param instead"] | undefined; - title: string; - defaultGroup?: [Error: "Use the 'group' param instead"] | undefined; - group?: - | (string & {}) - | 'overview' - | 'documentation' - | 'development' - | 'deployment' - | 'operation' - | 'observability' - | undefined; - loader: () => Promise; - routeRef?: RouteRef | undefined; - filter?: EntityPredicate | ((entity: Entity) => boolean) | undefined; - }; -}>; +export const scorecardHomeModule: FrontendModule; // @public export const scorecardTranslationRef: TranslationRef< 'plugin.scorecard', { - readonly 'emptyState.button': string; readonly 'emptyState.title': string; readonly 'emptyState.description': string; + readonly 'emptyState.button': string; readonly 'emptyState.altText': string; readonly 'notFound.title': string; readonly 'notFound.description': string; @@ -148,9 +97,9 @@ export const scorecardTranslationRef: TranslationRef< readonly 'notFound.readMore': string; readonly 'notFound.goBack': string; readonly 'notFound.contactSupport': string; - readonly 'permissionRequired.button': string; readonly 'permissionRequired.title': string; readonly 'permissionRequired.description': string; + readonly 'permissionRequired.button': string; readonly 'permissionRequired.altText': string; readonly 'errors.entityMissingProperties': string; readonly 'errors.invalidApiResponse': string; @@ -174,8 +123,8 @@ export const scorecardTranslationRef: TranslationRef< readonly 'metric.lastUpdatedNotAvailable': string; readonly 'metric.someEntitiesNotReportingValues': string; readonly 'thresholds.success': string; - readonly 'thresholds.error': string; readonly 'thresholds.warning': string; + readonly 'thresholds.error': string; readonly 'thresholds.noEntities': string; readonly 'thresholds.entities_one': string; readonly 'thresholds.entities_other': string; @@ -183,19 +132,19 @@ export const scorecardTranslationRef: TranslationRef< readonly 'entitiesPage.noDataFound': string; readonly 'entitiesPage.unknownMetric': string; readonly 'entitiesPage.metricProviderNotRegistered': string; - readonly 'entitiesPage.entitiesTable.footer.of': string; - readonly 'entitiesPage.entitiesTable.footer.allRows': string; - readonly 'entitiesPage.entitiesTable.footer.rows_one': string; - readonly 'entitiesPage.entitiesTable.footer.rows_other': string; - readonly 'entitiesPage.entitiesTable.header.owner': string; + readonly 'entitiesPage.entitiesTable.title': string; + readonly 'entitiesPage.entitiesTable.unavailable': string; + readonly 'entitiesPage.entitiesTable.titleWithCount': string; readonly 'entitiesPage.entitiesTable.header.metric': string; readonly 'entitiesPage.entitiesTable.header.lastUpdated': string; readonly 'entitiesPage.entitiesTable.header.value': string; readonly 'entitiesPage.entitiesTable.header.entity': string; + readonly 'entitiesPage.entitiesTable.header.owner': string; readonly 'entitiesPage.entitiesTable.header.kind': string; - readonly 'entitiesPage.entitiesTable.title': string; - readonly 'entitiesPage.entitiesTable.unavailable': string; - readonly 'entitiesPage.entitiesTable.titleWithCount': string; + readonly 'entitiesPage.entitiesTable.footer.of': string; + readonly 'entitiesPage.entitiesTable.footer.allRows': string; + readonly 'entitiesPage.entitiesTable.footer.rows_one': string; + readonly 'entitiesPage.entitiesTable.footer.rows_other': string; } >; diff --git a/workspaces/scorecard/plugins/scorecard/report.api.md b/workspaces/scorecard/plugins/scorecard/report.api.md index f6309692a4..fc2c6c05f4 100644 --- a/workspaces/scorecard/plugins/scorecard/report.api.md +++ b/workspaces/scorecard/plugins/scorecard/report.api.md @@ -32,9 +32,9 @@ export const scorecardPlugin: BackstagePlugin<{}, {}, {}>; export const scorecardTranslationRef: TranslationRef< 'plugin.scorecard', { - readonly 'emptyState.button': string; readonly 'emptyState.title': string; readonly 'emptyState.description': string; + readonly 'emptyState.button': string; readonly 'emptyState.altText': string; readonly 'notFound.title': string; readonly 'notFound.description': string; @@ -42,9 +42,9 @@ export const scorecardTranslationRef: TranslationRef< readonly 'notFound.readMore': string; readonly 'notFound.goBack': string; readonly 'notFound.contactSupport': string; - readonly 'permissionRequired.button': string; readonly 'permissionRequired.title': string; readonly 'permissionRequired.description': string; + readonly 'permissionRequired.button': string; readonly 'permissionRequired.altText': string; readonly 'errors.entityMissingProperties': string; readonly 'errors.invalidApiResponse': string; @@ -68,8 +68,8 @@ export const scorecardTranslationRef: TranslationRef< readonly 'metric.lastUpdatedNotAvailable': string; readonly 'metric.someEntitiesNotReportingValues': string; readonly 'thresholds.success': string; - readonly 'thresholds.error': string; readonly 'thresholds.warning': string; + readonly 'thresholds.error': string; readonly 'thresholds.noEntities': string; readonly 'thresholds.entities_one': string; readonly 'thresholds.entities_other': string; @@ -77,19 +77,19 @@ export const scorecardTranslationRef: TranslationRef< readonly 'entitiesPage.noDataFound': string; readonly 'entitiesPage.unknownMetric': string; readonly 'entitiesPage.metricProviderNotRegistered': string; - readonly 'entitiesPage.entitiesTable.footer.of': string; - readonly 'entitiesPage.entitiesTable.footer.allRows': string; - readonly 'entitiesPage.entitiesTable.footer.rows_one': string; - readonly 'entitiesPage.entitiesTable.footer.rows_other': string; - readonly 'entitiesPage.entitiesTable.header.owner': string; + readonly 'entitiesPage.entitiesTable.title': string; + readonly 'entitiesPage.entitiesTable.unavailable': string; + readonly 'entitiesPage.entitiesTable.titleWithCount': string; readonly 'entitiesPage.entitiesTable.header.metric': string; readonly 'entitiesPage.entitiesTable.header.lastUpdated': string; readonly 'entitiesPage.entitiesTable.header.value': string; readonly 'entitiesPage.entitiesTable.header.entity': string; + readonly 'entitiesPage.entitiesTable.header.owner': string; readonly 'entitiesPage.entitiesTable.header.kind': string; - readonly 'entitiesPage.entitiesTable.title': string; - readonly 'entitiesPage.entitiesTable.unavailable': string; - readonly 'entitiesPage.entitiesTable.titleWithCount': string; + readonly 'entitiesPage.entitiesTable.footer.of': string; + readonly 'entitiesPage.entitiesTable.footer.allRows': string; + readonly 'entitiesPage.entitiesTable.footer.rows_one': string; + readonly 'entitiesPage.entitiesTable.footer.rows_other': string; } >; diff --git a/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/api.ts b/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/api.ts new file mode 100644 index 0000000000..830c5540fb --- /dev/null +++ b/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/api.ts @@ -0,0 +1,36 @@ +/* + * 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 { + ApiBlueprint, + createApiFactory, + discoveryApiRef, + fetchApiRef, +} from '@backstage/frontend-plugin-api'; +import { ScorecardApiClient, scorecardApiRef } from '../../api'; + +/** Scorecard API extension. */ +export const scorecardApi = ApiBlueprint.make({ + params: defineParams => + defineParams( + createApiFactory({ + api: scorecardApiRef, + deps: { fetchApi: fetchApiRef, discoveryApi: discoveryApiRef }, + factory: ({ fetchApi, discoveryApi }) => + new ScorecardApiClient({ fetchApi, discoveryApi }), + }), + ), +}); diff --git a/workspaces/scorecard/plugins/scorecard/src/alpha.tsx b/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/entityTab.tsx similarity index 53% rename from workspaces/scorecard/plugins/scorecard/src/alpha.tsx rename to workspaces/scorecard/plugins/scorecard/src/alpha/extensions/entityTab.tsx index 435b528e81..c2fb6d3051 100644 --- a/workspaces/scorecard/plugins/scorecard/src/alpha.tsx +++ b/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/entityTab.tsx @@ -14,45 +14,12 @@ * limitations under the License. */ -import { - createApiFactory, - createFrontendPlugin, - createFrontendModule, - discoveryApiRef, - fetchApiRef, - ApiBlueprint, -} from '@backstage/frontend-plugin-api'; -import { TranslationBlueprint } from '@backstage/plugin-app-react'; -import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha'; -import { rootRouteRef } from './routes'; -import { ScorecardApiClient, scorecardApiRef } from './api'; -import { scorecardTranslations } from './translations'; import { Entity } from '@backstage/catalog-model'; - -/** Scorecard API extension */ -const scorecardApi = ApiBlueprint.make({ - params: defineParams => - defineParams( - createApiFactory({ - api: scorecardApiRef, - deps: { fetchApi: fetchApiRef, discoveryApi: discoveryApiRef }, - factory: ({ fetchApi, discoveryApi }) => - new ScorecardApiClient({ fetchApi, discoveryApi }), - }), - ), -}); - -/** - * Extension for Scorecard translations. - */ -const scorecardTranslation = TranslationBlueprint.make({ - params: { - resource: scorecardTranslations, - }, -}); +import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha'; +import { rootRouteRef } from '../../routes'; /** - * Extension for the Scorecard Tab on Entity pages. + * Extension for the Scorecard tab on Entity pages. * @alpha */ export const scorecardEntityContent = EntityContentBlueprint.makeWithOverrides({ @@ -80,7 +47,6 @@ export const scorecardEntityContent = EntityContentBlueprint.makeWithOverrides({ filter: (entity: Entity): boolean => { const filters = config.allowedFilters; - // Default: If no config is provided, show the tab for everyone if (!filters || filters.length === 0) return true; return filters.some(f => { @@ -96,46 +62,10 @@ export const scorecardEntityContent = EntityContentBlueprint.makeWithOverrides({ }, loader: async () => { const { EntityScorecardContent } = await import( - './components/Scorecard' + '../../components/Scorecard' ); return ; }, }); }, }); - -/** - * The primary Scorecard frontend plugin. - * @alpha - */ -export default createFrontendPlugin({ - pluginId: 'scorecard', - extensions: [scorecardApi], - routes: { - root: rootRouteRef, - }, -}); - -/** - * Catalog module that automatically injects the Scorecard tab into the Catalog. - * @alpha - */ -export const scorecardCatalogModule = createFrontendModule({ - pluginId: 'catalog', - extensions: [scorecardEntityContent], -}); - -/** - * App module that automatically registers Scorecard translations. - * @alpha - */ -export const scorecardTranslationsModule = createFrontendModule({ - pluginId: 'app', - extensions: [scorecardTranslation], -}); - -/** - * Re-exporting translations for external usage. - * @alpha - */ -export * from './translations'; diff --git a/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/homePageCards.tsx b/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/homePageCards.tsx new file mode 100644 index 0000000000..86e484840a --- /dev/null +++ b/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/homePageCards.tsx @@ -0,0 +1,84 @@ +/* + * 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 { HomePageWidgetBlueprint } from '@backstage/plugin-home-react/alpha'; +import type { RendererProps } from '@backstage/plugin-home-react'; +import { ScorecardHomepageCard } from '../../components/ScorecardHomepageSection'; + +const defaultCardLayout = { + width: { + minColumns: 3, + maxColumns: 12, + defaultColumns: 4, + }, + height: { + minRows: 5, + maxRows: 12, + defaultRows: 6, + }, +} as const; + +function ScorecardHomepageContent() { + return ; +} + +function ScorecardJiraHomepageContent() { + return ; +} + +function BorderlessHomeWidgetRenderer({ Content }: RendererProps) { + return ; +} + +/** + * NFS widget: ScorecardHomepageCard. + * @alpha + */ +export const scorecardHomepageWidget = HomePageWidgetBlueprint.make({ + name: 'scorecard-github-homepage', + params: { + name: 'ScorecardGithubHomepage', + title: 'Scorecard: GitHub open PRs', + layout: defaultCardLayout, + componentProps: { + Renderer: BorderlessHomeWidgetRenderer, + }, + components: () => + Promise.resolve({ + Content: ScorecardHomepageContent, + }), + }, +}); + +/** + * NFS widget: ScorecardHomepageCard for Jira open blocking tickets. + * @alpha + */ +export const scorecardJiraHomepageWidget = HomePageWidgetBlueprint.make({ + name: 'scorecard-jira-homepage', + params: { + name: 'ScorecardJiraHomepage', + title: 'Scorecard: Jira open blocking tickets', + layout: defaultCardLayout, + componentProps: { + Renderer: BorderlessHomeWidgetRenderer, + }, + components: () => + Promise.resolve({ + Content: ScorecardJiraHomepageContent, + }), + }, +}); diff --git a/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/metricPage.tsx b/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/metricPage.tsx new file mode 100644 index 0000000000..167b03a456 --- /dev/null +++ b/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/metricPage.tsx @@ -0,0 +1,31 @@ +/* + * 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 { PageBlueprint } from '@backstage/frontend-plugin-api'; +import { metricRouteRef } from '../../routes'; + +/** + * NFS page extension for the Scorecard page. + * @alpha + */ +export const scorecardPage = PageBlueprint.make({ + params: { + path: '/scorecard/metrics/:metricId', + routeRef: metricRouteRef, + loader: () => + import('../../pages/ScorecardPage').then(m => ), + }, +}); diff --git a/workspaces/scorecard/plugins/scorecard/src/alpha/index.tsx b/workspaces/scorecard/plugins/scorecard/src/alpha/index.tsx new file mode 100644 index 0000000000..0d951b8fad --- /dev/null +++ b/workspaces/scorecard/plugins/scorecard/src/alpha/index.tsx @@ -0,0 +1,85 @@ +/* + * 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 { + createFrontendModule, + createFrontendPlugin, +} from '@backstage/frontend-plugin-api'; +import { TranslationBlueprint } from '@backstage/plugin-app-react'; +import { metricRouteRef, rootRouteRef } from '../routes'; +import { scorecardTranslations } from '../translations'; +import { scorecardApi } from './extensions/api'; +import { scorecardEntityContent } from './extensions/entityTab'; +import { + scorecardHomepageWidget, + scorecardJiraHomepageWidget, +} from './extensions/homePageCards'; +import { scorecardPage } from './extensions/metricPage'; + +/** + * Extension for Scorecard translations. + */ +const scorecardTranslation = TranslationBlueprint.make({ + params: { + resource: scorecardTranslations, + }, +}); + +/** + * The primary Scorecard frontend plugin. + * @alpha + */ +export default createFrontendPlugin({ + pluginId: 'scorecard', + extensions: [scorecardApi, scorecardPage], + routes: { + root: rootRouteRef, + metric: metricRouteRef, + }, +}); + +/** + * Catalog module that automatically injects the Scorecard tab into the Catalog. + * @alpha + */ +export const scorecardCatalogModule = createFrontendModule({ + pluginId: 'catalog', + extensions: [scorecardEntityContent], +}); + +/** + * App module that automatically registers Scorecard translations. + * @alpha + */ +export const scorecardTranslationsModule = createFrontendModule({ + pluginId: 'app', + extensions: [scorecardTranslation], +}); + +/** + * Home module that contributes scorecard homepage widget and layout. + * @alpha + */ +export const scorecardHomeModule = createFrontendModule({ + pluginId: 'home', + extensions: [scorecardHomepageWidget, scorecardJiraHomepageWidget], +}); + +/** + * Re-exporting translations for external usage. + * @alpha + */ +export * from '../translations'; diff --git a/workspaces/scorecard/plugins/scorecard/src/components/Common/NoScorecardsState.tsx b/workspaces/scorecard/plugins/scorecard/src/components/Common/NoScorecardsState.tsx index 2cbc8a878b..89d3d02c16 100644 --- a/workspaces/scorecard/plugins/scorecard/src/components/Common/NoScorecardsState.tsx +++ b/workspaces/scorecard/plugins/scorecard/src/components/Common/NoScorecardsState.tsx @@ -57,7 +57,9 @@ const NoScorecardsState: React.FC = () => { ({ fontSize: '1rem', - color: theme.palette.text.secondary, + // Use primary text color to satisfy WCAG AA contrast + // against the light panel background in NFS. + color: theme.palette.text.primary, mb: 3, lineHeight: 1.5, })} diff --git a/workspaces/scorecard/plugins/scorecard/src/components/Common/PermissionRequiredState.tsx b/workspaces/scorecard/plugins/scorecard/src/components/Common/PermissionRequiredState.tsx index 94a6c0ae10..a2f182ae61 100644 --- a/workspaces/scorecard/plugins/scorecard/src/components/Common/PermissionRequiredState.tsx +++ b/workspaces/scorecard/plugins/scorecard/src/components/Common/PermissionRequiredState.tsx @@ -50,7 +50,9 @@ const PermissionRequiredState = () => { ({ fontSize: '1rem', - color: theme.palette.text.secondary, + // Use primary text color to satisfy WCAG AA contrast + // against the light panel background in NFS. + color: theme.palette.text.primary, mb: 3, lineHeight: 1.5, })} diff --git a/workspaces/scorecard/plugins/scorecard/src/routes.ts b/workspaces/scorecard/plugins/scorecard/src/routes.ts index c76e81634f..a6577f1357 100644 --- a/workspaces/scorecard/plugins/scorecard/src/routes.ts +++ b/workspaces/scorecard/plugins/scorecard/src/routes.ts @@ -19,3 +19,8 @@ import { createRouteRef } from '@backstage/core-plugin-api'; export const rootRouteRef = createRouteRef({ id: 'scorecard', }); + +export const metricRouteRef = createRouteRef({ + id: 'scorecard-metric', + params: ['metricId'], +}); diff --git a/workspaces/scorecard/yarn.lock b/workspaces/scorecard/yarn.lock index 1cc8c6eed0..7131601482 100644 --- a/workspaces/scorecard/yarn.lock +++ b/workspaces/scorecard/yarn.lock @@ -2168,29 +2168,29 @@ __metadata: languageName: node linkType: hard -"@backstage/catalog-client@npm:^1.11.0, @backstage/catalog-client@npm:^1.12.1, @backstage/catalog-client@npm:^1.13.0": - version: 1.13.0 - resolution: "@backstage/catalog-client@npm:1.13.0" +"@backstage/catalog-client@npm:^1.11.0, @backstage/catalog-client@npm:^1.12.1, @backstage/catalog-client@npm:^1.13.0, @backstage/catalog-client@npm:^1.14.0": + version: 1.14.0 + resolution: "@backstage/catalog-client@npm:1.14.0" dependencies: - "@backstage/catalog-model": "npm:^1.7.6" + "@backstage/catalog-model": "npm:^1.7.7" "@backstage/errors": "npm:^1.2.7" - "@backstage/filter-predicates": "npm:^0.1.0" + "@backstage/filter-predicates": "npm:^0.1.1" cross-fetch: "npm:^4.0.0" lodash: "npm:^4.17.21" uri-template: "npm:^2.0.0" - checksum: 10c0/aab423490529dbf468b73390aa8fa41e59fe53b651e8fb97dd23f7137ea5cd63b3d8c3708cb5faf52326705ad4d3130bebad6eb736d385fc3f8c022a973e8661 + checksum: 10c0/f54ba5a6c2b375a465693c3efe4593f5e42c3f3a9e8a154d5f68c6db9890d658a5c96934b1260f3cb216da3ddf7e40b39119c9c0b979c469ab32ec4902b29ccf languageName: node linkType: hard -"@backstage/catalog-model@npm:^1.5.0, @backstage/catalog-model@npm:^1.7.4, @backstage/catalog-model@npm:^1.7.5, @backstage/catalog-model@npm:^1.7.6": - version: 1.7.6 - resolution: "@backstage/catalog-model@npm:1.7.6" +"@backstage/catalog-model@npm:^1.5.0, @backstage/catalog-model@npm:^1.7.4, @backstage/catalog-model@npm:^1.7.5, @backstage/catalog-model@npm:^1.7.6, @backstage/catalog-model@npm:^1.7.7": + version: 1.7.7 + resolution: "@backstage/catalog-model@npm:1.7.7" dependencies: "@backstage/errors": "npm:^1.2.7" "@backstage/types": "npm:^1.2.2" ajv: "npm:^8.10.0" lodash: "npm:^4.17.21" - checksum: 10c0/db5f5bb8be2e45a4193cfe868a423991a91909e7750a90566a7147ab43e8e0853023a7d5103544d559d44c4e5c58dde3291a076d272b640574f77e1a19c7d03c + checksum: 10c0/eba74e24a59893f24b35e7d16be2d8c328dde1d87f5c38a14d8b5291e9b4a03bc30d72096b97ff1446ab5d2350bdb3c5ad4f2bf11a6686ed6cb8808dfa2fd1a8 languageName: node linkType: hard @@ -2392,13 +2392,14 @@ __metadata: languageName: node linkType: hard -"@backstage/core-app-api@npm:^1.19.2, @backstage/core-app-api@npm:^1.19.3, @backstage/core-app-api@npm:^1.19.4, @backstage/core-app-api@npm:^1.19.5": - version: 1.19.5 - resolution: "@backstage/core-app-api@npm:1.19.5" +"@backstage/core-app-api@npm:^1.19.2, @backstage/core-app-api@npm:^1.19.3, @backstage/core-app-api@npm:^1.19.4, @backstage/core-app-api@npm:^1.19.5, @backstage/core-app-api@npm:^1.19.6": + version: 1.19.6 + resolution: "@backstage/core-app-api@npm:1.19.6" dependencies: "@backstage/config": "npm:^1.3.6" - "@backstage/core-plugin-api": "npm:^1.12.3" + "@backstage/core-plugin-api": "npm:^1.12.4" "@backstage/types": "npm:^1.2.2" + "@backstage/ui": "npm:^0.13.0" "@backstage/version-bridge": "npm:^1.0.12" "@types/prop-types": "npm:^15.7.3" history: "npm:^5.0.0" @@ -2407,7 +2408,7 @@ __metadata: prop-types: "npm:^15.7.2" react-use: "npm:^17.2.4" zen-observable: "npm:^0.10.0" - zod: "npm:^3.25.76" + zod: "npm:^3.25.76 || ^4.0.0" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 @@ -2416,22 +2417,24 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/545dbcf178ca4b7517eec0792dc6d54ac5ac72f87ac71faae6c345b074e6883c364877346478d4ab6939ec840f5b4f039b9cba5869238ca21d12cb635d3a8444 + checksum: 10c0/5cd60623e09035b1240142941dd336a399e4f2d2455c2e4ad3de5f4e6f641181c000a0a3071c9e0f0af04ef6a68bcd4538fcfaf82b2ca2722d18e28b8f85335c languageName: node linkType: hard -"@backstage/core-compat-api@npm:^0.5.1, @backstage/core-compat-api@npm:^0.5.4, @backstage/core-compat-api@npm:^0.5.5, @backstage/core-compat-api@npm:^0.5.8": - version: 0.5.8 - resolution: "@backstage/core-compat-api@npm:0.5.8" +"@backstage/core-compat-api@npm:^0.5.1, @backstage/core-compat-api@npm:^0.5.4, @backstage/core-compat-api@npm:^0.5.5, @backstage/core-compat-api@npm:^0.5.8, @backstage/core-compat-api@npm:^0.5.9": + version: 0.5.9 + resolution: "@backstage/core-compat-api@npm:0.5.9" dependencies: - "@backstage/core-plugin-api": "npm:^1.12.3" - "@backstage/frontend-plugin-api": "npm:^0.14.0" - "@backstage/plugin-app-react": "npm:^0.2.0" - "@backstage/plugin-catalog-react": "npm:^2.0.0" + "@backstage/core-plugin-api": "npm:^1.12.4" + "@backstage/errors": "npm:^1.2.7" + "@backstage/filter-predicates": "npm:^0.1.1" + "@backstage/frontend-plugin-api": "npm:^0.15.0" + "@backstage/plugin-app-react": "npm:^0.2.1" + "@backstage/plugin-catalog-react": "npm:^2.1.0" "@backstage/types": "npm:^1.2.2" "@backstage/version-bridge": "npm:^1.0.12" lodash: "npm:^4.17.21" - zod: "npm:^3.25.76" + zod: "npm:^3.25.76 || ^4.0.0" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 @@ -2440,7 +2443,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/b41c961c17cc74a8ef112a3b6a123f15e1334dc2a3a36445af865e7b597a4447bc21fb128ba0baebb742f29e5c2ae6e0fa1ccdfa80fd9b1638da1c1b1a10b8ec + checksum: 10c0/b2a57b43c96ee56bfd0eb21779ebc4e8afd836d4e334be6b8c4cdd3b1d744be25da7fbd521ee93ec1fca41d7dd30e47094ae2dfde1e7d4a63f2975f8aee78454 languageName: node linkType: hard @@ -2498,12 +2501,12 @@ __metadata: languageName: node linkType: hard -"@backstage/core-components@npm:^0.18.3, @backstage/core-components@npm:^0.18.4, @backstage/core-components@npm:^0.18.6, @backstage/core-components@npm:^0.18.7": - version: 0.18.7 - resolution: "@backstage/core-components@npm:0.18.7" +"@backstage/core-components@npm:^0.18.3, @backstage/core-components@npm:^0.18.4, @backstage/core-components@npm:^0.18.6, @backstage/core-components@npm:^0.18.7, @backstage/core-components@npm:^0.18.8": + version: 0.18.8 + resolution: "@backstage/core-components@npm:0.18.8" dependencies: "@backstage/config": "npm:^1.3.6" - "@backstage/core-plugin-api": "npm:^1.12.3" + "@backstage/core-plugin-api": "npm:^1.12.4" "@backstage/errors": "npm:^1.2.7" "@backstage/theme": "npm:^0.7.2" "@backstage/version-bridge": "npm:^1.0.12" @@ -2543,7 +2546,7 @@ __metadata: rehype-sanitize: "npm:^5.0.0" remark-gfm: "npm:^3.0.1" zen-observable: "npm:^0.10.0" - zod: "npm:^3.25.76" + zod: "npm:^3.25.76 || ^4.0.0" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 @@ -2552,21 +2555,21 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/c1a826b5e763de7d64c74fc15a1a5e7e9fab3cd5e12de257d749b372f759e2420c511390ad0dcfcb81491acac5a04212fa30941ff01845cf8984895d3350d331 + checksum: 10c0/34ba90ca5c0925fee9f7785f0b23fc45b602c0705889f3a9efb109850298d428e77343b95d9539e043aff303549a65b7a4517e8ff0ddde607441a7d002b8b53d languageName: node linkType: hard -"@backstage/core-plugin-api@npm:^1.10.8, @backstage/core-plugin-api@npm:^1.10.9, @backstage/core-plugin-api@npm:^1.12.0, @backstage/core-plugin-api@npm:^1.12.1, @backstage/core-plugin-api@npm:^1.12.2, @backstage/core-plugin-api@npm:^1.12.3": - version: 1.12.3 - resolution: "@backstage/core-plugin-api@npm:1.12.3" +"@backstage/core-plugin-api@npm:^1.10.8, @backstage/core-plugin-api@npm:^1.10.9, @backstage/core-plugin-api@npm:^1.12.0, @backstage/core-plugin-api@npm:^1.12.1, @backstage/core-plugin-api@npm:^1.12.2, @backstage/core-plugin-api@npm:^1.12.3, @backstage/core-plugin-api@npm:^1.12.4": + version: 1.12.4 + resolution: "@backstage/core-plugin-api@npm:1.12.4" dependencies: "@backstage/config": "npm:^1.3.6" "@backstage/errors": "npm:^1.2.7" - "@backstage/frontend-plugin-api": "npm:^0.14.0" + "@backstage/frontend-plugin-api": "npm:^0.15.0" "@backstage/types": "npm:^1.2.2" "@backstage/version-bridge": "npm:^1.0.12" history: "npm:^5.0.0" - zod: "npm:^3.25.76" + zod: "npm:^3.25.76 || ^4.0.0" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 @@ -2575,7 +2578,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/ed81d3ac4a4d6d893672d76fff6d4764afde7550ff05707320d855e3495051f8eaeaf491b06a61c6efbeff1bdfe436604ee0fbd8f5dcb0d7445df505361b6abf + checksum: 10c0/0226ea1fe27392ce6e66c79453aa17d758341f73b943f87acd04123b38291962ac5350975005cb0b3a5a920073cbfe3d661b8c5332c78835401a5507cb8633bc languageName: node linkType: hard @@ -2642,16 +2645,16 @@ __metadata: languageName: node linkType: hard -"@backstage/filter-predicates@npm:^0.1.0": - version: 0.1.0 - resolution: "@backstage/filter-predicates@npm:0.1.0" +"@backstage/filter-predicates@npm:^0.1.1": + version: 0.1.1 + resolution: "@backstage/filter-predicates@npm:0.1.1" dependencies: "@backstage/config": "npm:^1.3.6" "@backstage/errors": "npm:^1.2.7" "@backstage/types": "npm:^1.2.2" - zod: "npm:^3.25.76" + zod: "npm:^3.25.76 || ^4.0.0" zod-validation-error: "npm:^4.0.2" - checksum: 10c0/af72f6db6d87cf48387040e286214b3f460be6708346bb03962f522fe572339f9af7a1b087bc489e7473cdeac8bd5469cf6166b21a1e491c557a9c36ad8cf85d + checksum: 10c0/f4bce2259af0e953ef30d292394aeea614ae42fbd825678a3abc36a97a6020a9964f40046aa3dc189f040ecf9674fb30dbcbbfd2ff3f807a513ad0353094bea5 languageName: node linkType: hard @@ -2845,6 +2848,28 @@ __metadata: languageName: node linkType: hard +"@backstage/frontend-plugin-api@npm:^0.15.0, @backstage/frontend-plugin-api@npm:^0.15.1": + version: 0.15.1 + resolution: "@backstage/frontend-plugin-api@npm:0.15.1" + dependencies: + "@backstage/errors": "npm:^1.2.7" + "@backstage/filter-predicates": "npm:^0.1.1" + "@backstage/types": "npm:^1.2.2" + "@backstage/version-bridge": "npm:^1.0.12" + zod: "npm:^3.25.76 || ^4.0.0" + zod-to-json-schema: "npm:^3.25.1" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.30.2 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/8064e0845849f7f27af62ff30007bc08a89fc052330e46138735669280e962f2643485a5e2e38dcec16d0ad8a93c150d5fc0b94b9e045106cba11c23bff365dc + languageName: node + linkType: hard + "@backstage/frontend-test-utils@npm:^0.4.2": version: 0.4.2 resolution: "@backstage/frontend-test-utils@npm:0.4.2" @@ -2885,13 +2910,13 @@ __metadata: languageName: node linkType: hard -"@backstage/integration-react@npm:^1.2.12, @backstage/integration-react@npm:^1.2.13, @backstage/integration-react@npm:^1.2.14, @backstage/integration-react@npm:^1.2.15, @backstage/integration-react@npm:^1.2.8, @backstage/integration-react@npm:^1.2.9": - version: 1.2.15 - resolution: "@backstage/integration-react@npm:1.2.15" +"@backstage/integration-react@npm:^1.2.12, @backstage/integration-react@npm:^1.2.13, @backstage/integration-react@npm:^1.2.14, @backstage/integration-react@npm:^1.2.15, @backstage/integration-react@npm:^1.2.16, @backstage/integration-react@npm:^1.2.8, @backstage/integration-react@npm:^1.2.9": + version: 1.2.16 + resolution: "@backstage/integration-react@npm:1.2.16" dependencies: "@backstage/config": "npm:^1.3.6" - "@backstage/core-plugin-api": "npm:^1.12.3" - "@backstage/integration": "npm:^1.20.0" + "@backstage/core-plugin-api": "npm:^1.12.4" + "@backstage/integration": "npm:^2.0.0" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" peerDependencies: @@ -2902,7 +2927,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/86e374021646aa508348237e3d6cde55e8af130d1c11e3840190c24fa7a16084cf3172fb93a9be595663b40b8e4eb05f0a3e8bdcb9c6268777c53592ae885434 + checksum: 10c0/70ff6dca97e1ff797e322771061ad642cd8f138f63fd44b743fd2eab1d975823e55a6bd95a04a4fe05b9974301164ceaae5ff79e91e90520e77710405ddf43ba languageName: node linkType: hard @@ -2924,6 +2949,25 @@ __metadata: languageName: node linkType: hard +"@backstage/integration@npm:^2.0.0": + version: 2.0.0 + resolution: "@backstage/integration@npm:2.0.0" + dependencies: + "@azure/identity": "npm:^4.0.0" + "@azure/storage-blob": "npm:^12.5.0" + "@backstage/config": "npm:^1.3.6" + "@backstage/errors": "npm:^1.2.7" + "@octokit/auth-app": "npm:^4.0.0" + "@octokit/rest": "npm:^19.0.3" + cross-fetch: "npm:^4.0.0" + git-url-parse: "npm:^15.0.0" + lodash: "npm:^4.17.21" + luxon: "npm:^3.0.0" + p-throttle: "npm:^4.1.1" + checksum: 10c0/d7e0e45cc11277ca2b843f98d15df8150b8c264852b734279a1965ccc81ef2724871e048aa1b0c4b3fe656c041d96ab0ca8c97db2bd236582d8f4349a93cd5cd + languageName: node + linkType: hard + "@backstage/plugin-api-docs@npm:^0.13.1": version: 0.13.1 resolution: "@backstage/plugin-api-docs@npm:0.13.1" @@ -3015,12 +3059,12 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-app-react@npm:^0.2.0": - version: 0.2.0 - resolution: "@backstage/plugin-app-react@npm:0.2.0" +"@backstage/plugin-app-react@npm:^0.2.0, @backstage/plugin-app-react@npm:^0.2.1": + version: 0.2.1 + resolution: "@backstage/plugin-app-react@npm:0.2.1" dependencies: - "@backstage/core-plugin-api": "npm:^1.12.3" - "@backstage/frontend-plugin-api": "npm:^0.14.0" + "@backstage/core-plugin-api": "npm:^1.12.4" + "@backstage/frontend-plugin-api": "npm:^0.15.0" "@material-ui/core": "npm:^4.9.13" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 @@ -3030,7 +3074,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/d921dd907ab439792576dd21d0a2cc1959f54a46c3adeda72da45a9fc5cfdb4234c1388532a70a5977a55304379c3ddfc9d3dba80a24121c959fe0de4cbb03cc + checksum: 10c0/e343bc8b67105bd1484824c66628005e8bfc8f5815960a7fd894ddb7ca3c14915c778095c549591f78cbe9a8f3acd4cfed565b5ffc569a2d7f07555ba5ab1886 languageName: node linkType: hard @@ -3368,7 +3412,7 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-catalog-react@npm:^1.19.0, @backstage/plugin-catalog-react@npm:^1.20.1, @backstage/plugin-catalog-react@npm:^1.21.3, @backstage/plugin-catalog-react@npm:^1.21.4": +"@backstage/plugin-catalog-react@npm:^1.19.0, @backstage/plugin-catalog-react@npm:^1.20.1, @backstage/plugin-catalog-react@npm:^1.21.3": version: 1.21.4 resolution: "@backstage/plugin-catalog-react@npm:1.21.4" dependencies: @@ -3409,24 +3453,24 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-catalog-react@npm:^2.0.0": - version: 2.0.0 - resolution: "@backstage/plugin-catalog-react@npm:2.0.0" +"@backstage/plugin-catalog-react@npm:^2.0.0, @backstage/plugin-catalog-react@npm:^2.1.0": + version: 2.1.1 + resolution: "@backstage/plugin-catalog-react@npm:2.1.1" dependencies: - "@backstage/catalog-client": "npm:^1.13.0" - "@backstage/catalog-model": "npm:^1.7.6" - "@backstage/core-compat-api": "npm:^0.5.8" - "@backstage/core-components": "npm:^0.18.7" - "@backstage/core-plugin-api": "npm:^1.12.3" + "@backstage/catalog-client": "npm:^1.14.0" + "@backstage/catalog-model": "npm:^1.7.7" + "@backstage/core-compat-api": "npm:^0.5.9" + "@backstage/core-components": "npm:^0.18.8" + "@backstage/core-plugin-api": "npm:^1.12.4" "@backstage/errors": "npm:^1.2.7" - "@backstage/filter-predicates": "npm:^0.1.0" - "@backstage/frontend-plugin-api": "npm:^0.14.0" - "@backstage/integration-react": "npm:^1.2.15" + "@backstage/filter-predicates": "npm:^0.1.1" + "@backstage/frontend-plugin-api": "npm:^0.15.1" + "@backstage/integration-react": "npm:^1.2.16" "@backstage/plugin-catalog-common": "npm:^1.1.8" - "@backstage/plugin-permission-common": "npm:^0.9.6" - "@backstage/plugin-permission-react": "npm:^0.4.40" + "@backstage/plugin-permission-common": "npm:^0.9.7" + "@backstage/plugin-permission-react": "npm:^0.4.41" "@backstage/types": "npm:^1.2.2" - "@backstage/ui": "npm:^0.12.0" + "@backstage/ui": "npm:^0.13.2" "@backstage/version-bridge": "npm:^1.0.12" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" @@ -3440,7 +3484,7 @@ __metadata: yaml: "npm:^2.0.0" zen-observable: "npm:^0.10.0" peerDependencies: - "@backstage/frontend-test-utils": ^0.5.0 + "@backstage/frontend-test-utils": ^0.5.1 "@types/react": ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 @@ -3450,7 +3494,7 @@ __metadata: optional: true "@types/react": optional: true - checksum: 10c0/a802bc31c07c6c3e052d74b882b2a973b47996153b017eb929d2d9aa4093a8a6e68f01aad9c09a2a8a727e2ac521b6305d81f86eb31429d68d17675184e8158c + checksum: 10c0/3fc2797b86f69a8cdb7118532a91efa6dc1e0188a92e9874f1e413740140328eca0af9ba7e8a0a5766b9f5aee2fd2776789f44de5e1f6c114c69e75146eb79c0 languageName: node linkType: hard @@ -3518,13 +3562,14 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-home-react@npm:^0.1.27, @backstage/plugin-home-react@npm:^0.1.32, @backstage/plugin-home-react@npm:^0.1.33": - version: 0.1.33 - resolution: "@backstage/plugin-home-react@npm:0.1.33" +"@backstage/plugin-home-react@npm:^0.1.27, @backstage/plugin-home-react@npm:^0.1.35, @backstage/plugin-home-react@npm:^0.1.36": + version: 0.1.36 + resolution: "@backstage/plugin-home-react@npm:0.1.36" dependencies: - "@backstage/core-components": "npm:^0.18.4" - "@backstage/core-plugin-api": "npm:^1.12.1" - "@backstage/frontend-plugin-api": "npm:^0.13.2" + "@backstage/core-compat-api": "npm:^0.5.9" + "@backstage/core-components": "npm:^0.18.8" + "@backstage/core-plugin-api": "npm:^1.12.4" + "@backstage/frontend-plugin-api": "npm:^0.15.0" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@rjsf/utils": "npm:5.24.13" @@ -3532,28 +3577,29 @@ __metadata: "@types/react": ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 - react-router-dom: ^6.3.0 + react-router-dom: ^6.30.2 peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/9f30fc6700ac26c709da7595130513d0ebb7139e7e2cef2b0efe6e633e2ef76d72cc2ba7cf7f7052af435a3a612c70adb71308a8580d0db93b53be7f2fa5841f + checksum: 10c0/f603143065aa64b938222291a383c79c15f7c3256ec379dfd0ef8b4642395eef4340e83de7c2baa8eb032eb37634d88ccba42f6ac8ba81418ad2c58c9bd93450 languageName: node linkType: hard -"@backstage/plugin-home@npm:^0.8.14": - version: 0.8.15 - resolution: "@backstage/plugin-home@npm:0.8.15" +"@backstage/plugin-home@npm:^0.9.2": + version: 0.9.3 + resolution: "@backstage/plugin-home@npm:0.9.3" dependencies: - "@backstage/catalog-client": "npm:^1.12.1" - "@backstage/catalog-model": "npm:^1.7.6" + "@backstage/catalog-client": "npm:^1.14.0" + "@backstage/catalog-model": "npm:^1.7.7" "@backstage/config": "npm:^1.3.6" - "@backstage/core-app-api": "npm:^1.19.3" - "@backstage/core-components": "npm:^0.18.4" - "@backstage/core-plugin-api": "npm:^1.12.1" - "@backstage/frontend-plugin-api": "npm:^0.13.2" - "@backstage/plugin-catalog-react": "npm:^1.21.4" - "@backstage/plugin-home-react": "npm:^0.1.33" - "@backstage/theme": "npm:^0.7.1" + "@backstage/core-app-api": "npm:^1.19.6" + "@backstage/core-compat-api": "npm:^0.5.9" + "@backstage/core-components": "npm:^0.18.8" + "@backstage/core-plugin-api": "npm:^1.12.4" + "@backstage/frontend-plugin-api": "npm:^0.15.0" + "@backstage/plugin-catalog-react": "npm:^2.1.0" + "@backstage/plugin-home-react": "npm:^0.1.36" + "@backstage/theme": "npm:^0.7.2" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@material-ui/lab": "npm:4.0.0-alpha.61" @@ -3566,16 +3612,16 @@ __metadata: react-grid-layout: "npm:1.3.4" react-resizable: "npm:^3.0.4" react-use: "npm:^17.2.4" - zod: "npm:^3.22.4" + zod: "npm:^3.25.76 || ^4.0.0" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 - react-router-dom: ^6.3.0 + react-router-dom: ^6.30.2 peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/6e4225cea6be4228ea98aeeb954fb57b402c07a8c7d25012a17caaf452a252e82fe94a9806d031e0fc3b17edc2edc2b7daa3e50a06293a3342a495dba263f20c + checksum: 10c0/b73451bcde69e110a720a0f1950307f589ae323ad99efa55c6ae2f22fc6e74d5781db6f210f6bdf82e4ca45fc99c1f65c90b7ec38824548adeac279fe2b9cde2 languageName: node linkType: hard @@ -3758,18 +3804,18 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-permission-common@npm:^0.9.1, @backstage/plugin-permission-common@npm:^0.9.3, @backstage/plugin-permission-common@npm:^0.9.6": - version: 0.9.6 - resolution: "@backstage/plugin-permission-common@npm:0.9.6" +"@backstage/plugin-permission-common@npm:^0.9.1, @backstage/plugin-permission-common@npm:^0.9.3, @backstage/plugin-permission-common@npm:^0.9.6, @backstage/plugin-permission-common@npm:^0.9.7": + version: 0.9.7 + resolution: "@backstage/plugin-permission-common@npm:0.9.7" dependencies: "@backstage/config": "npm:^1.3.6" "@backstage/errors": "npm:^1.2.7" "@backstage/types": "npm:^1.2.2" cross-fetch: "npm:^4.0.0" uuid: "npm:^11.0.0" - zod: "npm:^3.25.76" + zod: "npm:^3.25.76 || ^4.0.0" zod-to-json-schema: "npm:^3.25.1" - checksum: 10c0/ab68ad13bde01eeca0a7354d4e8b9c0e589c94c690771fddd1928fe66bf2f583aad91d938165b2a4ea20d9f6f74186f698144f1044ea08c7acd8d65cf76b3d56 + checksum: 10c0/577c15e246fc46c7fe1a4868c3765a9c837b86a64d7a3ab75ac76ed443f2ac4e687c37bd11f2e787898ff8909c9206b9285446e956eb9c4313d3818e37fbf64d languageName: node linkType: hard @@ -3791,13 +3837,14 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-permission-react@npm:^0.4.38, @backstage/plugin-permission-react@npm:^0.4.39, @backstage/plugin-permission-react@npm:^0.4.40": - version: 0.4.40 - resolution: "@backstage/plugin-permission-react@npm:0.4.40" +"@backstage/plugin-permission-react@npm:^0.4.38, @backstage/plugin-permission-react@npm:^0.4.39, @backstage/plugin-permission-react@npm:^0.4.40, @backstage/plugin-permission-react@npm:^0.4.41": + version: 0.4.41 + resolution: "@backstage/plugin-permission-react@npm:0.4.41" dependencies: "@backstage/config": "npm:^1.3.6" - "@backstage/core-plugin-api": "npm:^1.12.3" - "@backstage/plugin-permission-common": "npm:^0.9.6" + "@backstage/core-plugin-api": "npm:^1.12.4" + "@backstage/plugin-permission-common": "npm:^0.9.7" + dataloader: "npm:^2.0.0" swr: "npm:^2.0.0" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 @@ -3807,7 +3854,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/6ea737975a7d51b6943c0cb93ba09c07364bc24e230977b9918471ac348dcab2f4dfb9dc3da636f3db167ee19a6263ee42dd1273abbc555b6e33bc23dc676d1c + checksum: 10c0/d04a28f02cd98a0415f0ccc21b755fb88190bf3b1cf61c6f48086f4823d674ac25152fa14a5b273ae4232617e514334198efab670daae06aaa07b5ff1be7f4a6 languageName: node linkType: hard @@ -4809,6 +4856,28 @@ __metadata: languageName: node linkType: hard +"@backstage/ui@npm:^0.13.0, @backstage/ui@npm:^0.13.2": + version: 0.13.2 + resolution: "@backstage/ui@npm:0.13.2" + dependencies: + "@backstage/version-bridge": "npm:^1.0.12" + "@remixicon/react": "npm:^4.6.0" + "@tanstack/react-table": "npm:^8.21.3" + clsx: "npm:^2.1.1" + react-aria-components: "npm:^1.14.0" + use-sync-external-store: "npm:^1.4.0" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.30.2 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/9ece5740c66fe52ff11e6ab4a4942f6720881cf39d510b7db114f7309bc2f6b77e9d74fe7ac45b168dea77ef483f8a383c5c3091a5edd6bd86a0c4a84b58072a + languageName: node + linkType: hard + "@backstage/ui@npm:^0.9.0, @backstage/ui@npm:^0.9.1": version: 0.9.1 resolution: "@backstage/ui@npm:0.9.1" @@ -11346,17 +11415,18 @@ __metadata: languageName: node linkType: hard -"@red-hat-developer-hub/backstage-plugin-dynamic-home-page@npm:^1.10.2": - version: 1.10.2 - resolution: "@red-hat-developer-hub/backstage-plugin-dynamic-home-page@npm:1.10.2" +"@red-hat-developer-hub/backstage-plugin-dynamic-home-page@npm:1.11.0, @red-hat-developer-hub/backstage-plugin-dynamic-home-page@npm:^1.10.2": + version: 1.11.0 + resolution: "@red-hat-developer-hub/backstage-plugin-dynamic-home-page@npm:1.11.0" dependencies: "@backstage/catalog-client": "npm:^1.12.1" "@backstage/catalog-model": "npm:^1.7.6" "@backstage/core-components": "npm:^0.18.3" "@backstage/core-plugin-api": "npm:^1.12.0" + "@backstage/plugin-app-react": "npm:^0.1.0" "@backstage/plugin-catalog-react": "npm:^1.21.3" - "@backstage/plugin-home": "npm:^0.8.14" - "@backstage/plugin-home-react": "npm:^0.1.32" + "@backstage/plugin-home": "npm:^0.9.2" + "@backstage/plugin-home-react": "npm:^0.1.35" "@backstage/plugin-search-react": "npm:^1.10.0" "@backstage/plugin-user-settings": "npm:^0.8.29" "@backstage/theme": "npm:^0.7.0" @@ -11369,8 +11439,8 @@ __metadata: tss-react: "npm:4.9.20" peerDependencies: react: 16.13.1 || ^17.0.0 || ^18.2.0 - react-router-dom: 6.30.2 - checksum: 10c0/a438ff1d030d7b90abc8a123a75f6f23375d5e2faa83e893c968b99dd6d410243e67f1d1c79d5b9fc195d00ef78871e16f681dcc1f564afc8080b8040fe29cfb + react-router-dom: 6.30.3 + checksum: 10c0/877ac23c91d1fe568ebb7a1a3ca64d5655dce91e24e25bd284354276da846d2b32c4f0b912421bc6b734899b8771bc409b6baa69d74d065cb95fa6f966a2880f languageName: node linkType: hard @@ -11508,6 +11578,8 @@ __metadata: "@backstage/plugin-app-react": "npm:^0.1.0" "@backstage/plugin-catalog": "npm:^1.33.1" "@backstage/plugin-catalog-react": "npm:^1.21.3" + "@backstage/plugin-home": "npm:^0.9.2" + "@backstage/plugin-home-react": "npm:^0.1.35" "@backstage/plugin-permission-react": "npm:^0.4.38" "@backstage/plugin-user-settings": "npm:^0.9.0" "@backstage/test-utils": "npm:^1.7.13" @@ -16194,6 +16266,7 @@ __metadata: "@backstage/plugin-api-docs": "npm:^0.13.1" "@backstage/plugin-app-react": "npm:^0.1.0" "@backstage/plugin-catalog": "npm:^1.32.0" + "@backstage/plugin-home": "npm:^0.9.2" "@backstage/plugin-org": "npm:^0.6.46" "@backstage/plugin-scaffolder": "npm:^1.34.3" "@backstage/plugin-search": "npm:^1.5.0" @@ -16202,6 +16275,7 @@ __metadata: "@backstage/ui": "npm:^0.9.1" "@material-ui/core": "npm:^4.12.2" "@mui/icons-material": "npm:^5.18.0" + "@red-hat-developer-hub/backstage-plugin-dynamic-home-page": "npm:1.11.0" "@red-hat-developer-hub/backstage-plugin-scorecard": "workspace:^" "@red-hat-developer-hub/backstage-plugin-theme": "npm:^0.13.0" "@types/react": "npm:^18" @@ -28859,6 +28933,13 @@ __metadata: languageName: node linkType: hard +"p-throttle@npm:^4.1.1": + version: 4.1.1 + resolution: "p-throttle@npm:4.1.1" + checksum: 10c0/c4bfdcd0318d704b446a7af59dd8e0e32e37ba3d9841dd8dfced1c09742bc2f7a95bc0fcf4072030c62abf4533a9a2ef2954e559462052c5f406ae03d195925a + languageName: node + linkType: hard + "p-timeout@npm:^3.2.0": version: 3.2.0 resolution: "p-timeout@npm:3.2.0" @@ -36559,6 +36640,13 @@ __metadata: languageName: node linkType: hard +"zod@npm:^3.25.76 || ^4.0.0": + version: 4.3.6 + resolution: "zod@npm:4.3.6" + checksum: 10c0/860d25a81ab41d33aa25f8d0d07b091a04acb426e605f396227a796e9e800c44723ed96d0f53a512b57be3d1520f45bf69c0cb3b378a232a00787a2609625307 + languageName: node + linkType: hard + "zstd-codec@npm:^0.1.5": version: 0.1.5 resolution: "zstd-codec@npm:0.1.5"