repo: promote app-next to main example app
This renames packages to make the new frontend system the default: - packages/app → packages/app-legacy (example-app-legacy) - packages/app-next → packages/app (example-app) - packages/app-next-example-plugin → packages/app-example-plugin Updated all related configuration, scripts, and documentation. Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com>
@@ -2,10 +2,10 @@
|
||||
"mode": "pre",
|
||||
"tag": "next",
|
||||
"initialVersions": {
|
||||
"example-app": "0.2.117",
|
||||
"example-app-legacy": "0.2.117",
|
||||
"@backstage/app-defaults": "1.7.4",
|
||||
"example-app-next": "0.0.31",
|
||||
"app-next-example-plugin": "0.0.31",
|
||||
"example-app": "0.0.31",
|
||||
"app-example-plugin": "0.0.31",
|
||||
"example-backend": "0.0.46",
|
||||
"@backstage/backend-app-api": "1.4.1",
|
||||
"@backstage/backend-defaults": "0.15.0",
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/repo-tools': patch
|
||||
---
|
||||
|
||||
Updated package-docs exclude list to reflect renamed example app packages.
|
||||
@@ -5,7 +5,8 @@ Backstage is an open platform for building developer portals. This is a TypeScri
|
||||
- `/packages`: Core framework packages (prefixed `@backstage/`)
|
||||
- `/plugins`: Plugin packages (prefixed `@backstage/plugin-*`)
|
||||
- `/packages/app` and `/packages/backend`: Example app for local development
|
||||
- `/packages/app-next`: Example app using the new frontend system (NFS)
|
||||
- `/packages/app`: Main example app using the new frontend system
|
||||
- `/packages/app-legacy`: Example app using the old frontend system
|
||||
- `/docs`: Documentation files
|
||||
|
||||
Packages prefixed with `core-` (e.g., `@backstage/core-plugin-api`) are part of the old frontend system. Packages prefixed with `frontend-` (e.g., `@backstage/frontend-plugin-api`) are part of the new frontend system (NFS). Packages prefixed with `backend-` (e.g., `@backstage/backend-plugin-api`) are part of the backend system.
|
||||
|
||||
@@ -25,7 +25,7 @@ The search plugin is a collection of extensions that implement the search featur
|
||||
|
||||
### Installation
|
||||
|
||||
Only one step is required to start using the `Search` plugin within declarative integration, so all you have to do is to install the `@backstage/plugin-catalog` and `@backstage/plugin-search` packages, (e.g., [app-next](https://github.com/backstage/backstage/tree/master/packages/app-next)):
|
||||
Only one step is required to start using the `Search` plugin within declarative integration, so all you have to do is to install the `@backstage/plugin-catalog` and `@backstage/plugin-search` packages, (e.g., [app](https://github.com/backstage/backstage/tree/master/packages/app)):
|
||||
|
||||
```sh
|
||||
yarn add @backstage/plugin-catalog @backstage/plugin-search
|
||||
|
||||
@@ -9,4 +9,4 @@ description: The Frontend System
|
||||
|
||||
We recommend migrating your frontend plugins to the new frontend system. If you do please do so under an `/alpha` sub-path export.
|
||||
|
||||
You can find an example app setup in the [`app-next` package](https://github.com/backstage/backstage/tree/master/packages/app-next).
|
||||
You can find an example app setup in the [`app` package](https://github.com/backstage/backstage/tree/master/packages/app).
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
"clean": "backstage-cli repo clean",
|
||||
"create-plugin": "echo \"use 'yarn new' instead\"",
|
||||
"dev": "echo \"use 'yarn start' instead\"",
|
||||
"dev:next": "echo \"use 'yarn start:next' instead\"",
|
||||
"docker-build": "yarn tsc && yarn workspace example-backend build && yarn workspace example-backend build-image",
|
||||
"fix": "backstage-cli repo fix --publish",
|
||||
"postinstall": "husky || true",
|
||||
@@ -57,8 +56,8 @@
|
||||
"start": "backstage-cli repo start",
|
||||
"start-backend": "echo \"Use 'yarn start example-backend' instead\"",
|
||||
"start:docker": "docker compose -f docker-compose.deps.yml up --wait && BACKSTAGE_ENV=docker yarn start",
|
||||
"start:legacy": "yarn start example-app-legacy example-backend",
|
||||
"start:microsite": "cd microsite/ && yarn start",
|
||||
"start:next": "yarn start example-app-next example-backend",
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"sync-issue-templates": "node ./.github/ISSUE_TEMPLATE/sync.js",
|
||||
"techdocs-cli": "node scripts/techdocs-cli.js",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# app-next-example-plugin
|
||||
# app-example-plugin
|
||||
|
||||
## 0.0.32-next.0
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: app-next-example-plugin
|
||||
title: app-next-example-plugin
|
||||
name: app-example-plugin
|
||||
title: app-example-plugin
|
||||
description: Backstage internal example plugin
|
||||
spec:
|
||||
lifecycle: experimental
|
||||
@@ -0,0 +1,9 @@
|
||||
# Knip report
|
||||
|
||||
## Unused devDependencies (2)
|
||||
|
||||
| Name | Location | Severity |
|
||||
| :---------- | :----------- | :------- |
|
||||
| cross-fetch | packages/app-example-plugin/package.json | error |
|
||||
| msw | packages/app-example-plugin/package.json | error |
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "app-next-example-plugin",
|
||||
"name": "app-example-plugin",
|
||||
"version": "0.0.32-next.0",
|
||||
"description": "Backstage internal example plugin",
|
||||
"backstage": {
|
||||
"role": "frontend-plugin",
|
||||
"pluginId": "example",
|
||||
"pluginPackages": [
|
||||
"app-next-example-plugin"
|
||||
"app-example-plugin"
|
||||
]
|
||||
},
|
||||
"publishConfig": {
|
||||
@@ -22,7 +22,7 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "packages/app-next-example-plugin"
|
||||
"directory": "packages/app-example-plugin"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"sideEffects": false,
|
||||
@@ -1,4 +1,4 @@
|
||||
## API Report File for "app-next-example-plugin"
|
||||
## API Report File for "app-example-plugin"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'@backstage/no-top-level-material-ui-4-imports': 'error',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
# example-app-legacy
|
||||
|
||||
This package is an example of a Backstage application using the old (legacy) frontend system.
|
||||
|
||||
**NOTE:** This is the legacy frontend system. For new projects, use `packages/app` which uses the new frontend system.
|
||||
@@ -1,8 +1,8 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: example-app-next
|
||||
title: example-app-next
|
||||
name: example-app-legacy
|
||||
title: example-app-legacy
|
||||
spec:
|
||||
lifecycle: experimental
|
||||
type: backstage-frontend
|
||||
@@ -0,0 +1,29 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (8)
|
||||
|
||||
| Name | Location | Severity |
|
||||
| :------------------------------ | :----------- | :------- |
|
||||
| @backstage/plugin-search-common | packages/app-legacy/package.json | error |
|
||||
| @backstage/plugin-auth-react | packages/app-legacy/package.json | error |
|
||||
| @backstage/frontend-app-api | packages/app-legacy/package.json | error |
|
||||
| @material-ui/lab | packages/app-legacy/package.json | error |
|
||||
| zen-observable | packages/app-legacy/package.json | error |
|
||||
| @octokit/rest | packages/app-legacy/package.json | error |
|
||||
| react-router | packages/app-legacy/package.json | error |
|
||||
| history | packages/app-legacy/package.json | error |
|
||||
|
||||
## Unused devDependencies (3)
|
||||
|
||||
| Name | Location | Severity |
|
||||
| :-------------------------- | :----------- | :------- |
|
||||
| @testing-library/user-event | packages/app-legacy/package.json | error |
|
||||
| @types/zen-observable | packages/app-legacy/package.json | error |
|
||||
| @types/jquery | packages/app-legacy/package.json | error |
|
||||
|
||||
## Unlisted dependencies (1)
|
||||
|
||||
| Name | Location | Severity |
|
||||
| :---------- | :------------------------------------------------------- | :------- |
|
||||
| @rjsf/utils | packages/app/src/components/scaffolder/customScaffolderExtensions.tsx | error |
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
{
|
||||
"name": "example-app-next",
|
||||
"version": "0.0.32-next.1",
|
||||
"name": "example-app-legacy",
|
||||
"version": "0.2.118-next.1",
|
||||
"backstage": {
|
||||
"role": "frontend"
|
||||
},
|
||||
"private": true,
|
||||
"homepage": "https://backstage.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "packages/app-next"
|
||||
"directory": "packages/app-legacy"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"files": [
|
||||
@@ -18,7 +19,7 @@
|
||||
"build": "backstage-cli package build",
|
||||
"clean": "backstage-cli package clean",
|
||||
"lint": "backstage-cli package lint",
|
||||
"start": "backstage-cli package start --config ../../app-config.yaml --config app-config.yaml",
|
||||
"start": "cross-env EXPERIMENTAL_LAZY_COMPILATION=1 backstage-cli package start",
|
||||
"test": "backstage-cli package test"
|
||||
},
|
||||
"browserslist": {
|
||||
@@ -39,18 +40,11 @@
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/core-app-api": "workspace:^",
|
||||
"@backstage/core-compat-api": "workspace:^",
|
||||
"@backstage/core-components": "workspace:^",
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/frontend-app-api": "workspace:^",
|
||||
"@backstage/frontend-defaults": "workspace:^",
|
||||
"@backstage/frontend-plugin-api": "workspace:^",
|
||||
"@backstage/integration-react": "workspace:^",
|
||||
"@backstage/plugin-api-docs": "workspace:^",
|
||||
"@backstage/plugin-app": "workspace:^",
|
||||
"@backstage/plugin-app-react": "workspace:^",
|
||||
"@backstage/plugin-app-visualizer": "workspace:^",
|
||||
"@backstage/plugin-auth": "workspace:^",
|
||||
"@backstage/plugin-auth-react": "workspace:^",
|
||||
"@backstage/plugin-catalog": "workspace:^",
|
||||
"@backstage/plugin-catalog-common": "workspace:^",
|
||||
@@ -63,6 +57,7 @@
|
||||
"@backstage/plugin-home-react": "workspace:^",
|
||||
"@backstage/plugin-kubernetes": "workspace:^",
|
||||
"@backstage/plugin-kubernetes-cluster": "workspace:^",
|
||||
"@backstage/plugin-mui-to-bui": "workspace:^",
|
||||
"@backstage/plugin-notifications": "workspace:^",
|
||||
"@backstage/plugin-org": "workspace:^",
|
||||
"@backstage/plugin-permission-react": "workspace:^",
|
||||
@@ -92,6 +87,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/test-utils": "workspace:^",
|
||||
"@playwright/test": "^1.32.3",
|
||||
"@testing-library/dom": "^10.0.0",
|
||||
"@testing-library/jest-dom": "^6.0.0",
|
||||
"@testing-library/react": "^16.0.0",
|
||||
@@ -100,7 +96,9 @@
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"@types/zen-observable": "^0.8.0",
|
||||
"cross-env": "^10.0.0"
|
||||
"axios": "^1.13.0",
|
||||
"cross-env": "^10.0.0",
|
||||
"msw": "^1.0.0"
|
||||
},
|
||||
"bundled": true
|
||||
}
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 883 B After Width: | Height: | Size: 883 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
@@ -42,7 +42,7 @@
|
||||
href="<%= publicPath %>/safari-pinned-tab.svg"
|
||||
color="#5bbad5"
|
||||
/>
|
||||
<title><%= config.getString('app.title') %></title>
|
||||
<title><%= config.getOptionalString('app.title') ?? 'Backstage' %></title>
|
||||
|
||||
<% if (config.has('app.datadogRum')) { %>
|
||||
<script>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -14,11 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { renderWithEffects } from '@backstage/test-utils';
|
||||
|
||||
// Rarely, and only in windows CI, do these tests take slightly more than the
|
||||
// default five seconds
|
||||
jest.setTimeout(15_000);
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
describe('App', () => {
|
||||
it('should render', async () => {
|
||||
@@ -44,8 +41,10 @@ describe('App', () => {
|
||||
] as any,
|
||||
};
|
||||
|
||||
const { default: app } = await import('./App');
|
||||
const rendered = await renderWithEffects(app);
|
||||
expect(rendered.baseElement).toBeInTheDocument();
|
||||
const rendered = render(<App />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(rendered.baseElement).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* 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 { createApp } from '@backstage/app-defaults';
|
||||
import { AppRouter, FeatureFlagged, FlatRoutes } from '@backstage/core-app-api';
|
||||
import {
|
||||
AlertDisplay,
|
||||
OAuthRequestDialog,
|
||||
SignInPage,
|
||||
} from '@backstage/core-components';
|
||||
import { ApiExplorerPage } from '@backstage/plugin-api-docs';
|
||||
import { CatalogEntityPage, CatalogIndexPage } from '@backstage/plugin-catalog';
|
||||
|
||||
import { CatalogGraphPage } from '@backstage/plugin-catalog-graph';
|
||||
import { CatalogImportPage } from '@backstage/plugin-catalog-import';
|
||||
import { HomepageCompositionRoot, VisitListener } from '@backstage/plugin-home';
|
||||
|
||||
import { ScaffolderPage } from '@backstage/plugin-scaffolder';
|
||||
import {
|
||||
ScaffolderFieldExtensions,
|
||||
ScaffolderLayouts,
|
||||
} from '@backstage/plugin-scaffolder-react';
|
||||
import { SearchPage } from '@backstage/plugin-search';
|
||||
import {
|
||||
TechDocsIndexPage,
|
||||
TechDocsReaderPage,
|
||||
} from '@backstage/plugin-techdocs';
|
||||
import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
|
||||
import {
|
||||
ExpandableNavigation,
|
||||
LightBox,
|
||||
ReportIssue,
|
||||
TextSize,
|
||||
} from '@backstage/plugin-techdocs-module-addons-contrib';
|
||||
import {
|
||||
SettingsLayout,
|
||||
UserSettingsPage,
|
||||
} from '@backstage/plugin-user-settings';
|
||||
import { AdvancedSettings } from './components/advancedSettings';
|
||||
import AlarmIcon from '@material-ui/icons/Alarm';
|
||||
import { Navigate, Route } from 'react-router-dom';
|
||||
import { apis } from './apis';
|
||||
import { entityPage } from './components/catalog/EntityPage';
|
||||
import { Root } from './components/Root';
|
||||
import { DelayingComponentFieldExtension } from './components/scaffolder/customScaffolderExtensions';
|
||||
import { defaultPreviewTemplate } from './components/scaffolder/defaultPreviewTemplate';
|
||||
import { searchPage } from './components/search/SearchPage';
|
||||
import { providers } from './identityProviders';
|
||||
import { SignalsDisplay } from '@backstage/plugin-signals';
|
||||
import { techDocsPage } from './components/techdocs/TechDocsPage';
|
||||
import { RequirePermission } from '@backstage/plugin-permission-react';
|
||||
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha';
|
||||
import { TwoColumnLayout } from './components/scaffolder/customScaffolderLayouts';
|
||||
import { customDevToolsPage } from './components/devtools/CustomDevToolsPage';
|
||||
import { DevToolsPage } from '@backstage/plugin-devtools';
|
||||
import { CatalogUnprocessedEntitiesPage } from '@backstage/plugin-catalog-unprocessed-entities';
|
||||
import {
|
||||
NotificationsPage,
|
||||
UserNotificationSettingsCard,
|
||||
} from '@backstage/plugin-notifications';
|
||||
import { CustomizableHomePage } from './components/home/CustomizableHomePage';
|
||||
import { HomePage } from './components/home/HomePage';
|
||||
import { BuiThemerPage } from '@backstage/plugin-mui-to-bui';
|
||||
|
||||
const app = createApp({
|
||||
apis,
|
||||
icons: {
|
||||
// Custom icon example
|
||||
alert: AlarmIcon,
|
||||
},
|
||||
featureFlags: [
|
||||
{
|
||||
name: 'scaffolder-next-preview',
|
||||
description: 'Preview the new Scaffolder Next',
|
||||
pluginId: '',
|
||||
},
|
||||
],
|
||||
components: {
|
||||
SignInPage: props => {
|
||||
return (
|
||||
<SignInPage
|
||||
{...props}
|
||||
providers={['guest', 'custom', ...providers]}
|
||||
title="Select a sign-in method"
|
||||
align="center"
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const routes = (
|
||||
<FlatRoutes>
|
||||
<Route path="/" element={<Navigate to="catalog" />} />
|
||||
|
||||
{/* TODO(rubenl): Move this to / once its more mature and components exist */}
|
||||
|
||||
<FeatureFlagged with="customizable-home-page-preview">
|
||||
<Route path="/home" element={<HomepageCompositionRoot />}>
|
||||
<CustomizableHomePage />
|
||||
</Route>
|
||||
</FeatureFlagged>
|
||||
<FeatureFlagged without="customizable-home-page-preview">
|
||||
<Route path="/home" element={<HomepageCompositionRoot />}>
|
||||
<HomePage />
|
||||
</Route>
|
||||
</FeatureFlagged>
|
||||
|
||||
<Route
|
||||
path="/catalog"
|
||||
element={<CatalogIndexPage pagination={{ mode: 'offset', limit: 20 }} />}
|
||||
/>
|
||||
<Route
|
||||
path="/catalog/:namespace/:kind/:name"
|
||||
element={<CatalogEntityPage />}
|
||||
>
|
||||
{entityPage}
|
||||
</Route>
|
||||
<Route
|
||||
path="/catalog-unprocessed-entities"
|
||||
element={<CatalogUnprocessedEntitiesPage />}
|
||||
/>
|
||||
<Route
|
||||
path="/catalog-import"
|
||||
element={
|
||||
<RequirePermission permission={catalogEntityCreatePermission}>
|
||||
<CatalogImportPage />
|
||||
</RequirePermission>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/catalog-graph"
|
||||
element={
|
||||
<CatalogGraphPage
|
||||
initialState={{
|
||||
selectedKinds: ['component', 'domain', 'system', 'api', 'group'],
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/docs"
|
||||
element={<TechDocsIndexPage pagination={{ mode: 'offset', limit: 20 }} />}
|
||||
/>
|
||||
<Route
|
||||
path="/docs/:namespace/:kind/:name/*"
|
||||
element={<TechDocsReaderPage />}
|
||||
>
|
||||
{techDocsPage}
|
||||
<TechDocsAddons>
|
||||
<ExpandableNavigation />
|
||||
<ReportIssue />
|
||||
<TextSize />
|
||||
<LightBox />
|
||||
</TechDocsAddons>
|
||||
</Route>
|
||||
<Route
|
||||
path="/create"
|
||||
element={
|
||||
<ScaffolderPage
|
||||
defaultPreviewTemplate={defaultPreviewTemplate}
|
||||
groups={[
|
||||
{
|
||||
title: 'Recommended',
|
||||
filter: entity =>
|
||||
entity?.metadata?.tags?.includes('recommended') ?? false,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<ScaffolderFieldExtensions>
|
||||
<DelayingComponentFieldExtension />
|
||||
</ScaffolderFieldExtensions>
|
||||
<ScaffolderLayouts>
|
||||
<TwoColumnLayout />
|
||||
</ScaffolderLayouts>
|
||||
</Route>
|
||||
|
||||
<Route path="/api-docs" element={<ApiExplorerPage />} />
|
||||
<Route path="/search" element={<SearchPage />}>
|
||||
{searchPage}
|
||||
</Route>
|
||||
|
||||
<Route path="/settings" element={<UserSettingsPage />}>
|
||||
<SettingsLayout.Route path="/advanced" title="Advanced">
|
||||
<AdvancedSettings />
|
||||
</SettingsLayout.Route>
|
||||
<SettingsLayout.Route path="/notifications" title="Notifications">
|
||||
<UserNotificationSettingsCard
|
||||
originNames={{ 'plugin:scaffolder': 'Scaffolder' }}
|
||||
/>
|
||||
</SettingsLayout.Route>
|
||||
</Route>
|
||||
<Route path="/devtools" element={<DevToolsPage />}>
|
||||
{customDevToolsPage}
|
||||
</Route>
|
||||
<Route path="/notifications" element={<NotificationsPage />} />
|
||||
<Route path="/mui-to-bui" element={<BuiThemerPage />} />
|
||||
</FlatRoutes>
|
||||
);
|
||||
|
||||
export default app.createRoot(
|
||||
<>
|
||||
<AlertDisplay transientTimeoutMs={2500} />
|
||||
<OAuthRequestDialog />
|
||||
<SignalsDisplay />
|
||||
<AppRouter>
|
||||
<VisitListener />
|
||||
<Root>{routes}</Root>
|
||||
</AppRouter>
|
||||
</>,
|
||||
);
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* 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 { createApp } from '@backstage/app-defaults';
|
||||
import { AppRouter } from '@backstage/core-app-api';
|
||||
import {
|
||||
AlertDisplay,
|
||||
OAuthRequestDialog,
|
||||
SignInPage,
|
||||
} from '@backstage/core-components';
|
||||
import { CookieAuthRedirect } from '@backstage/plugin-auth-react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { providers } from '../src/identityProviders';
|
||||
import {
|
||||
configApiRef,
|
||||
createApiFactory,
|
||||
discoveryApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { AuthProxyDiscoveryApi } from '../src/AuthProxyDiscoveryApi';
|
||||
import '@backstage/ui/css/styles.css';
|
||||
|
||||
const app = createApp({
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: discoveryApiRef,
|
||||
deps: { configApi: configApiRef },
|
||||
factory: ({ configApi }) => AuthProxyDiscoveryApi.fromConfig(configApi),
|
||||
}),
|
||||
],
|
||||
components: {
|
||||
SignInPage: props => {
|
||||
return (
|
||||
<SignInPage
|
||||
{...props}
|
||||
providers={['guest', 'custom', ...providers]}
|
||||
title="Select a sign-in method"
|
||||
align="center"
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const App = app.createRoot(
|
||||
<>
|
||||
<AlertDisplay transientTimeoutMs={2500} />
|
||||
<OAuthRequestDialog />
|
||||
<AppRouter>
|
||||
<CookieAuthRedirect />
|
||||
</AppRouter>
|
||||
</>,
|
||||
);
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import '@backstage/cli/asset-types';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import app from './App';
|
||||
import App from './App';
|
||||
import '@backstage/ui/css/styles.css';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(app);
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
|
||||
@@ -1,9 +0,0 @@
|
||||
# Knip report
|
||||
|
||||
## Unused devDependencies (2)
|
||||
|
||||
| Name | Location | Severity |
|
||||
| :---------- | :----------- | :------- |
|
||||
| cross-fetch | packages/app-next-example-plugin/package.json | error |
|
||||
| msw | packages/app-next-example-plugin/package.json | error |
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'@backstage/no-top-level-material-ui-4-imports': 'error',
|
||||
},
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
# example-app-next
|
||||
|
||||
This package is an example of a Backstage application using the [new frontend](../../docs/frontend-system/index.md).
|
||||
|
||||
To play with it, open a terminal and run the command: `yarn start`
|
||||
|
||||
**NOTE:** Don't forget to open a second terminal and to launch the backend there, using `yarn start`! The frontend requires a backend to connect to.
|
||||
@@ -1,43 +0,0 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (26)
|
||||
|
||||
| Name | Location | Severity |
|
||||
| :----------------------------------------------- | :----------- | :------- |
|
||||
| @backstage/plugin-techdocs-module-addons-contrib | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-catalog-unprocessed-entities | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-kubernetes-cluster | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-permission-react | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-scaffolder-react | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-catalog-common | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-techdocs-react | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-catalog-graph | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-search-common | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-search-react | packages/app-next/package.json | error |
|
||||
| @backstage/integration-react | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-auth-react | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-scaffolder | packages/app-next/package.json | error |
|
||||
| @backstage/core-plugin-api | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-api-docs | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-catalog | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-signals | packages/app-next/package.json | error |
|
||||
| @backstage/app-defaults | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-app | packages/app-next/package.json | error |
|
||||
| @backstage/plugin-org | packages/app-next/package.json | error |
|
||||
| @backstage/config | packages/app-next/package.json | error |
|
||||
| @material-ui/lab | packages/app-next/package.json | error |
|
||||
| zen-observable | packages/app-next/package.json | error |
|
||||
| @octokit/rest | packages/app-next/package.json | error |
|
||||
| react-use | packages/app-next/package.json | error |
|
||||
| history | packages/app-next/package.json | error |
|
||||
|
||||
## Unused devDependencies (5)
|
||||
|
||||
| Name | Location | Severity |
|
||||
| :-------------------------- | :----------- | :------- |
|
||||
| @testing-library/user-event | packages/app-next/package.json | error |
|
||||
| @types/zen-observable | packages/app-next/package.json | error |
|
||||
| @testing-library/dom | packages/app-next/package.json | error |
|
||||
| @types/jquery | packages/app-next/package.json | error |
|
||||
| cross-env | packages/app-next/package.json | error |
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 { createApp } from '@backstage/frontend-defaults';
|
||||
import { pagesPlugin } from './examples/pagesPlugin';
|
||||
import notFoundErrorPage from './examples/notFoundErrorPageExtension';
|
||||
import userSettingsPlugin from '@backstage/plugin-user-settings/alpha';
|
||||
import homePlugin from '@backstage/plugin-home/alpha';
|
||||
|
||||
import { createFrontendModule } from '@backstage/frontend-plugin-api';
|
||||
import {
|
||||
HomePageLayoutBlueprint,
|
||||
type HomePageLayoutProps,
|
||||
} from '@backstage/plugin-home-react/alpha';
|
||||
import { Fragment } from 'react';
|
||||
import { Content, Header, Page } from '@backstage/core-components';
|
||||
import {
|
||||
CustomHomepageGrid,
|
||||
WelcomeTitle,
|
||||
HeaderWorldClock,
|
||||
type ClockConfig,
|
||||
} from '@backstage/plugin-home';
|
||||
import {
|
||||
techdocsPlugin,
|
||||
TechDocsIndexPage,
|
||||
TechDocsReaderPage,
|
||||
EntityTechdocsContent,
|
||||
} from '@backstage/plugin-techdocs';
|
||||
import appVisualizerPlugin from '@backstage/plugin-app-visualizer';
|
||||
import { convertLegacyAppRoot } from '@backstage/core-compat-api';
|
||||
import { FlatRoutes } from '@backstage/core-app-api';
|
||||
import { Route } from 'react-router';
|
||||
import { CatalogImportPage } from '@backstage/plugin-catalog-import';
|
||||
import kubernetesPlugin from '@backstage/plugin-kubernetes/alpha';
|
||||
import { convertLegacyPlugin } from '@backstage/core-compat-api';
|
||||
import { convertLegacyPageExtension } from '@backstage/core-compat-api';
|
||||
import { convertLegacyEntityContentExtension } from '@backstage/plugin-catalog-react/alpha';
|
||||
import { pluginInfoResolver } from './pluginInfoResolver';
|
||||
import { appModuleNav } from './modules/appModuleNav';
|
||||
import devtoolsPlugin from '@backstage/plugin-devtools/alpha';
|
||||
import { unprocessedEntitiesDevToolsContent } from '@backstage/plugin-catalog-unprocessed-entities/alpha';
|
||||
import catalogPlugin from '@backstage/plugin-catalog/alpha';
|
||||
import InfoIcon from '@material-ui/icons/Info';
|
||||
|
||||
/*
|
||||
|
||||
# Notes
|
||||
|
||||
TODO:
|
||||
- proper createApp
|
||||
- connect extensions and plugins, provide method?
|
||||
- higher level API for creating standard extensions + higher order framework API for creating those?
|
||||
- extension config schema + validation
|
||||
- figure out how to resolve configured extension ref to runtime value, e.g. '@backstage/plugin-graphiql#GraphiqlPage'
|
||||
- make sure all shorthands work + tests
|
||||
- figure out package structure / how to ship, frontend-plugin-api/frontend-app-api
|
||||
- figure out routing, useRouteRef in the new system
|
||||
- Legacy plugins / interop
|
||||
- dynamic updates, runtime API
|
||||
|
||||
*/
|
||||
|
||||
/* core */
|
||||
|
||||
// const discoverPackages = async () => {
|
||||
// // stub for now, deferring package discovery til later
|
||||
// return ['@backstage/plugin-graphiql'];
|
||||
// };
|
||||
|
||||
/* graphiql package */
|
||||
|
||||
/* app.tsx */
|
||||
|
||||
/**
|
||||
* TechDocs does support the new frontend system so this conversion is not
|
||||
* strictly necessary, but it's left here to provide a demo of the utilities for
|
||||
* converting legacy plugins.
|
||||
*/
|
||||
const convertedTechdocsPlugin = convertLegacyPlugin(techdocsPlugin, {
|
||||
extensions: [
|
||||
// TODO: We likely also need a way to convert an entire <Route> tree similar to collectLegacyRoutes
|
||||
convertLegacyPageExtension(TechDocsIndexPage, {
|
||||
name: 'index',
|
||||
path: '/docs',
|
||||
}),
|
||||
convertLegacyPageExtension(TechDocsReaderPage, {
|
||||
path: '/docs/:namespace/:kind/:name/*',
|
||||
}),
|
||||
convertLegacyEntityContentExtension(EntityTechdocsContent),
|
||||
],
|
||||
});
|
||||
|
||||
const clockConfigs: ClockConfig[] = [
|
||||
{ label: 'NYC', timeZone: 'America/New_York' },
|
||||
{ label: 'UTC', timeZone: 'UTC' },
|
||||
{ label: 'STO', timeZone: 'Europe/Stockholm' },
|
||||
{ label: 'TYO', timeZone: 'Asia/Tokyo' },
|
||||
];
|
||||
|
||||
const customHomePageModule = createFrontendModule({
|
||||
pluginId: 'home',
|
||||
extensions: [
|
||||
HomePageLayoutBlueprint.make({
|
||||
params: {
|
||||
loader: async () =>
|
||||
function CustomHomePageLayout({ widgets }: HomePageLayoutProps) {
|
||||
return (
|
||||
<Page themeId="home">
|
||||
<Header title={<WelcomeTitle />} pageTitleOverride="Home">
|
||||
<HeaderWorldClock clockConfigs={clockConfigs} />
|
||||
</Header>
|
||||
<Content>
|
||||
<CustomHomepageGrid>
|
||||
{widgets.map((widget, index) => (
|
||||
<Fragment key={widget.name ?? index}>
|
||||
{widget.component}
|
||||
</Fragment>
|
||||
))}
|
||||
</CustomHomepageGrid>
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// customize catalog example
|
||||
const customizedCatalog = catalogPlugin.withOverrides({
|
||||
extensions: [
|
||||
catalogPlugin.getExtension('entity-content:catalog/overview').override({
|
||||
params: {
|
||||
icon: <InfoIcon />,
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const notFoundErrorPageModule = createFrontendModule({
|
||||
pluginId: 'app',
|
||||
extensions: [notFoundErrorPage],
|
||||
});
|
||||
|
||||
const devtoolsPluginUnprocessed = createFrontendModule({
|
||||
pluginId: 'catalog-unprocessed-entities',
|
||||
extensions: [unprocessedEntitiesDevToolsContent],
|
||||
});
|
||||
|
||||
const collectedLegacyPlugins = convertLegacyAppRoot(
|
||||
<FlatRoutes>
|
||||
<Route path="/catalog-import" element={<CatalogImportPage />} />
|
||||
</FlatRoutes>,
|
||||
);
|
||||
|
||||
const app = createApp({
|
||||
features: [
|
||||
customizedCatalog,
|
||||
pagesPlugin,
|
||||
convertedTechdocsPlugin,
|
||||
userSettingsPlugin,
|
||||
homePlugin,
|
||||
appVisualizerPlugin,
|
||||
kubernetesPlugin,
|
||||
notFoundErrorPageModule,
|
||||
appModuleNav,
|
||||
customHomePageModule,
|
||||
devtoolsPlugin,
|
||||
devtoolsPluginUnprocessed,
|
||||
...collectedLegacyPlugins,
|
||||
],
|
||||
advanced: {
|
||||
pluginInfoResolver,
|
||||
},
|
||||
/* Handled through config instead */
|
||||
// bindRoutes({ bind }) {
|
||||
// bind(pagesPlugin.externalRoutes, { pageX: pagesPlugin.routes.pageX });
|
||||
// },
|
||||
});
|
||||
|
||||
// const legacyApp = createLegacyApp({ plugins: [legacyGraphiqlPlugin] });
|
||||
|
||||
export default app.createRoot();
|
||||
|
||||
// const routes = (
|
||||
// <FlatRoutes>
|
||||
// {/* <Route path="/" element={<Navigate to="catalog" />} />
|
||||
// <Route path="/catalog" element={<CatalogIndexPage />} />
|
||||
// <Route
|
||||
// path="/catalog/:namespace/:kind/:name"
|
||||
// element={<CatalogEntityPage />}
|
||||
// >
|
||||
// <EntityLayout>
|
||||
// <EntityLayout.Route path="/" title="Overview">
|
||||
// <Grid container spacing={3} alignItems="stretch">
|
||||
// <Grid item md={6} xs={12}>
|
||||
// <EntityAboutCard variant="gridItem" />
|
||||
// </Grid>
|
||||
|
||||
// <Grid item md={4} xs={12}>
|
||||
// <EntityLinksCard />
|
||||
// </Grid>
|
||||
// </Grid>
|
||||
// </EntityLayout.Route>
|
||||
|
||||
// <EntityLayout.Route path="/todos" title="TODOs">
|
||||
// <EntityTodoContent />
|
||||
// </EntityLayout.Route>
|
||||
// </EntityLayout>
|
||||
// </Route>
|
||||
// <Route
|
||||
// path="/catalog-import"
|
||||
// element={
|
||||
// <CatalogImportPage />
|
||||
// }
|
||||
// /> */}
|
||||
// {/* <Route
|
||||
// path="/tech-radar"
|
||||
// element={<TechRadarPage width={1500} height={800} />}
|
||||
// /> */}
|
||||
// <Route path="/graphiql" element={<GraphiQLPage />} />
|
||||
// </FlatRoutes>
|
||||
// );
|
||||
|
||||
// export default app.createRoot(
|
||||
// <>
|
||||
// {/* <AlertDisplay transientTimeoutMs={2500} />
|
||||
// <OAuthRequestDialog /> */}
|
||||
// <AppRouter>{routes}</AppRouter>
|
||||
// </>,
|
||||
// );
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* 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 ReactDOM from 'react-dom/client';
|
||||
import { createApp } from '@backstage/frontend-defaults';
|
||||
import { appModulePublicSignIn } from '@backstage/plugin-app/alpha';
|
||||
|
||||
import '@backstage/ui/css/styles.css';
|
||||
|
||||
const app = createApp({
|
||||
features: [appModulePublicSignIn],
|
||||
});
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(app.createRoot());
|
||||
@@ -1,5 +1,5 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'@backstage/no-top-level-material-ui-4-imports': 'error',
|
||||
},
|
||||
rules: {
|
||||
'@backstage/no-top-level-material-ui-4-imports': 'error',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
# example-app
|
||||
|
||||
This package is an example of a Backstage application.
|
||||
This package is the main example Backstage application using the [new frontend system](../../docs/frontend-system/index.md).
|
||||
|
||||
To play with it, open a terminal and run the command: `yarn start`
|
||||
|
||||
**NOTE:** Don't forget to open a second terminal and to launch the backend there, using `yarn start`! The frontend requires a backend to connect to.
|
||||
|
||||
@@ -10,7 +10,7 @@ app:
|
||||
- match:
|
||||
pluginId: pages
|
||||
info:
|
||||
description: 'This description was overridden in packages/app-next/app-config.yaml'
|
||||
description: 'This description was overridden in packages/app/app-config.yaml'
|
||||
- match:
|
||||
pluginId: /^catalog(-.*)?$/
|
||||
info:
|
||||
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
@@ -35,14 +35,17 @@ test('Should not throw `ResizeObserver loop completed with undelivered notificat
|
||||
).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('Should render some home page widgets', async ({ page }) => {
|
||||
test('Should render the home page', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const enterButton = page.getByRole('button', { name: 'Enter' });
|
||||
await expect(enterButton).toBeVisible();
|
||||
await enterButton.click();
|
||||
|
||||
// Wait for sign-in to complete
|
||||
await expect(page.getByRole('link', { name: 'Catalog' })).toBeVisible();
|
||||
|
||||
await page.goto('/home');
|
||||
await expect(page.getByText('Top Visited')).toBeVisible();
|
||||
await expect(page.getByText('Recently Visited')).toBeVisible();
|
||||
// The home page should render with the custom homepage grid
|
||||
await expect(page.getByRole('link', { name: 'Home' })).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -23,8 +23,11 @@ test('the results are rendered as expected', async ({ page }) => {
|
||||
await expect(enterButton).toBeVisible();
|
||||
await enterButton.click();
|
||||
|
||||
await page.goto('/search');
|
||||
await page.route(`http://*/api/search/query?term=*`, async route => {
|
||||
// Wait for sign-in to complete before navigating
|
||||
await expect(page.getByRole('link', { name: 'Catalog' })).toBeVisible();
|
||||
|
||||
// Set up route interception BEFORE navigating to the search page
|
||||
await page.route(`**/api/search/query?term=*`, async route => {
|
||||
const results = [
|
||||
{
|
||||
type: 'software-catalog',
|
||||
@@ -38,9 +41,13 @@ test('the results are rendered as expected', async ({ page }) => {
|
||||
await route.fulfill({ json: { results } });
|
||||
});
|
||||
|
||||
await page.goto('/search');
|
||||
|
||||
await expect(
|
||||
page.getByPlaceholder('Search in Backstage Example App'),
|
||||
).toBeVisible();
|
||||
|
||||
// Type a search query to trigger the mocked response
|
||||
await page.getByPlaceholder('Search in Backstage Example App').fill('test');
|
||||
await expect(page.getByText('Backstage system documentation')).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -23,11 +23,7 @@ test('App should render the welcome page', async ({ page }) => {
|
||||
await expect(enterButton).toBeVisible();
|
||||
await enterButton.click();
|
||||
|
||||
await expect(page.getByText('My Company Catalog')).toBeVisible();
|
||||
|
||||
const supportButton = page.getByTestId('support-button');
|
||||
await expect(supportButton).toBeVisible();
|
||||
await supportButton.click();
|
||||
|
||||
await expect(page.getByText('#backstage')).toBeVisible();
|
||||
// Verify the sidebar navigation is visible after sign-in
|
||||
await expect(page.getByRole('link', { name: 'Catalog' })).toBeVisible();
|
||||
await expect(page.getByRole('link', { name: 'APIs' })).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -1,29 +1,43 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (8)
|
||||
## Unused dependencies (26)
|
||||
|
||||
| Name | Location | Severity |
|
||||
| :------------------------------ | :----------- | :------- |
|
||||
| @backstage/plugin-search-common | packages/app/package.json | error |
|
||||
| @backstage/plugin-auth-react | packages/app/package.json | error |
|
||||
| @backstage/frontend-app-api | packages/app/package.json | error |
|
||||
| @material-ui/lab | packages/app/package.json | error |
|
||||
| zen-observable | packages/app/package.json | error |
|
||||
| @octokit/rest | packages/app/package.json | error |
|
||||
| react-router | packages/app/package.json | error |
|
||||
| history | packages/app/package.json | error |
|
||||
| Name | Location | Severity |
|
||||
| :----------------------------------------------- | :----------- | :------- |
|
||||
| @backstage/plugin-techdocs-module-addons-contrib | packages/app/package.json | error |
|
||||
| @backstage/plugin-catalog-unprocessed-entities | packages/app/package.json | error |
|
||||
| @backstage/plugin-kubernetes-cluster | packages/app/package.json | error |
|
||||
| @backstage/plugin-permission-react | packages/app/package.json | error |
|
||||
| @backstage/plugin-scaffolder-react | packages/app/package.json | error |
|
||||
| @backstage/plugin-catalog-common | packages/app/package.json | error |
|
||||
| @backstage/plugin-techdocs-react | packages/app/package.json | error |
|
||||
| @backstage/plugin-catalog-graph | packages/app/package.json | error |
|
||||
| @backstage/plugin-search-common | packages/app/package.json | error |
|
||||
| @backstage/plugin-search-react | packages/app/package.json | error |
|
||||
| @backstage/integration-react | packages/app/package.json | error |
|
||||
| @backstage/plugin-auth-react | packages/app/package.json | error |
|
||||
| @backstage/plugin-scaffolder | packages/app/package.json | error |
|
||||
| @backstage/core-plugin-api | packages/app/package.json | error |
|
||||
| @backstage/plugin-api-docs | packages/app/package.json | error |
|
||||
| @backstage/plugin-catalog | packages/app/package.json | error |
|
||||
| @backstage/plugin-signals | packages/app/package.json | error |
|
||||
| @backstage/app-defaults | packages/app/package.json | error |
|
||||
| @backstage/plugin-app | packages/app/package.json | error |
|
||||
| @backstage/plugin-org | packages/app/package.json | error |
|
||||
| @backstage/config | packages/app/package.json | error |
|
||||
| @material-ui/lab | packages/app/package.json | error |
|
||||
| zen-observable | packages/app/package.json | error |
|
||||
| @octokit/rest | packages/app/package.json | error |
|
||||
| react-use | packages/app/package.json | error |
|
||||
| history | packages/app/package.json | error |
|
||||
|
||||
## Unused devDependencies (3)
|
||||
## Unused devDependencies (5)
|
||||
|
||||
| Name | Location | Severity |
|
||||
| :-------------------------- | :----------- | :------- |
|
||||
| @testing-library/user-event | packages/app/package.json | error |
|
||||
| @types/zen-observable | packages/app/package.json | error |
|
||||
| @testing-library/dom | packages/app/package.json | error |
|
||||
| @types/jquery | packages/app/package.json | error |
|
||||
|
||||
## Unlisted dependencies (1)
|
||||
|
||||
| Name | Location | Severity |
|
||||
| :---------- | :------------------------------------------------------- | :------- |
|
||||
| @rjsf/utils | packages/app/src/components/scaffolder/customScaffolderExtensions.tsx | error |
|
||||
| cross-env | packages/app/package.json | error |
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.2.118-next.1",
|
||||
"version": "0.0.32-next.1",
|
||||
"backstage": {
|
||||
"role": "frontend"
|
||||
},
|
||||
@@ -19,7 +19,7 @@
|
||||
"build": "backstage-cli package build",
|
||||
"clean": "backstage-cli package clean",
|
||||
"lint": "backstage-cli package lint",
|
||||
"start": "cross-env EXPERIMENTAL_LAZY_COMPILATION=1 backstage-cli package start",
|
||||
"start": "backstage-cli package start --config ../../app-config.yaml --config app-config.yaml",
|
||||
"test": "backstage-cli package test"
|
||||
},
|
||||
"browserslist": {
|
||||
@@ -40,11 +40,18 @@
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/core-app-api": "workspace:^",
|
||||
"@backstage/core-compat-api": "workspace:^",
|
||||
"@backstage/core-components": "workspace:^",
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/frontend-app-api": "workspace:^",
|
||||
"@backstage/frontend-defaults": "workspace:^",
|
||||
"@backstage/frontend-plugin-api": "workspace:^",
|
||||
"@backstage/integration-react": "workspace:^",
|
||||
"@backstage/plugin-api-docs": "workspace:^",
|
||||
"@backstage/plugin-app": "workspace:^",
|
||||
"@backstage/plugin-app-react": "workspace:^",
|
||||
"@backstage/plugin-app-visualizer": "workspace:^",
|
||||
"@backstage/plugin-auth": "workspace:^",
|
||||
"@backstage/plugin-auth-react": "workspace:^",
|
||||
"@backstage/plugin-catalog": "workspace:^",
|
||||
"@backstage/plugin-catalog-common": "workspace:^",
|
||||
@@ -56,7 +63,6 @@
|
||||
"@backstage/plugin-home": "workspace:^",
|
||||
"@backstage/plugin-kubernetes": "workspace:^",
|
||||
"@backstage/plugin-kubernetes-cluster": "workspace:^",
|
||||
"@backstage/plugin-mui-to-bui": "workspace:^",
|
||||
"@backstage/plugin-notifications": "workspace:^",
|
||||
"@backstage/plugin-org": "workspace:^",
|
||||
"@backstage/plugin-permission-react": "workspace:^",
|
||||
@@ -86,7 +92,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/test-utils": "workspace:^",
|
||||
"@playwright/test": "^1.32.3",
|
||||
"@playwright/test": "^1.58.2",
|
||||
"@testing-library/dom": "^10.0.0",
|
||||
"@testing-library/jest-dom": "^6.0.0",
|
||||
"@testing-library/react": "^16.0.0",
|
||||
@@ -95,9 +101,7 @@
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"@types/zen-observable": "^0.8.0",
|
||||
"axios": "^1.13.0",
|
||||
"cross-env": "^10.0.0",
|
||||
"msw": "^1.0.0"
|
||||
"cross-env": "^10.0.0"
|
||||
},
|
||||
"bundled": true
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
href="<%= publicPath %>/safari-pinned-tab.svg"
|
||||
color="#5bbad5"
|
||||
/>
|
||||
<title><%= config.getOptionalString('app.title') ?? 'Backstage' %></title>
|
||||
<title><%= config.getString('app.title') %></title>
|
||||
|
||||
<% if (config.has('app.datadogRum')) { %>
|
||||
<script>
|
||||
|
||||
@@ -14,8 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import App from './App';
|
||||
import { renderWithEffects } from '@backstage/test-utils';
|
||||
|
||||
// Rarely, and only in windows CI, do these tests take slightly more than the
|
||||
// default five seconds
|
||||
jest.setTimeout(15_000);
|
||||
|
||||
describe('App', () => {
|
||||
it('should render', async () => {
|
||||
@@ -41,10 +44,8 @@ describe('App', () => {
|
||||
] as any,
|
||||
};
|
||||
|
||||
const rendered = render(<App />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(rendered.baseElement).toBeInTheDocument();
|
||||
});
|
||||
const { default: app } = await import('./App');
|
||||
const rendered = await renderWithEffects(app);
|
||||
expect(rendered.baseElement).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,213 +14,231 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createApp } from '@backstage/app-defaults';
|
||||
import { AppRouter, FeatureFlagged, FlatRoutes } from '@backstage/core-app-api';
|
||||
import {
|
||||
AlertDisplay,
|
||||
OAuthRequestDialog,
|
||||
SignInPage,
|
||||
} from '@backstage/core-components';
|
||||
import { ApiExplorerPage } from '@backstage/plugin-api-docs';
|
||||
import { CatalogEntityPage, CatalogIndexPage } from '@backstage/plugin-catalog';
|
||||
import { createApp } from '@backstage/frontend-defaults';
|
||||
import { pagesPlugin } from './examples/pagesPlugin';
|
||||
import notFoundErrorPage from './examples/notFoundErrorPageExtension';
|
||||
import userSettingsPlugin from '@backstage/plugin-user-settings/alpha';
|
||||
import homePlugin from '@backstage/plugin-home/alpha';
|
||||
|
||||
import { CatalogGraphPage } from '@backstage/plugin-catalog-graph';
|
||||
import { CatalogImportPage } from '@backstage/plugin-catalog-import';
|
||||
import { HomepageCompositionRoot, VisitListener } from '@backstage/plugin-home';
|
||||
|
||||
import { ScaffolderPage } from '@backstage/plugin-scaffolder';
|
||||
import { createFrontendModule } from '@backstage/frontend-plugin-api';
|
||||
import {
|
||||
ScaffolderFieldExtensions,
|
||||
ScaffolderLayouts,
|
||||
} from '@backstage/plugin-scaffolder-react';
|
||||
import { SearchPage } from '@backstage/plugin-search';
|
||||
HomePageLayoutBlueprint,
|
||||
type HomePageLayoutProps,
|
||||
} from '@backstage/plugin-home-react/alpha';
|
||||
import { Fragment } from 'react';
|
||||
import { Content, Header, Page } from '@backstage/core-components';
|
||||
import {
|
||||
CustomHomepageGrid,
|
||||
WelcomeTitle,
|
||||
HeaderWorldClock,
|
||||
type ClockConfig,
|
||||
} from '@backstage/plugin-home';
|
||||
import {
|
||||
techdocsPlugin,
|
||||
TechDocsIndexPage,
|
||||
TechDocsReaderPage,
|
||||
EntityTechdocsContent,
|
||||
} from '@backstage/plugin-techdocs';
|
||||
import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
|
||||
import {
|
||||
ExpandableNavigation,
|
||||
LightBox,
|
||||
ReportIssue,
|
||||
TextSize,
|
||||
} from '@backstage/plugin-techdocs-module-addons-contrib';
|
||||
import {
|
||||
SettingsLayout,
|
||||
UserSettingsPage,
|
||||
} from '@backstage/plugin-user-settings';
|
||||
import { AdvancedSettings } from './components/advancedSettings';
|
||||
import AlarmIcon from '@material-ui/icons/Alarm';
|
||||
import { Navigate, Route } from 'react-router-dom';
|
||||
import { apis } from './apis';
|
||||
import { entityPage } from './components/catalog/EntityPage';
|
||||
import { Root } from './components/Root';
|
||||
import { DelayingComponentFieldExtension } from './components/scaffolder/customScaffolderExtensions';
|
||||
import { defaultPreviewTemplate } from './components/scaffolder/defaultPreviewTemplate';
|
||||
import { searchPage } from './components/search/SearchPage';
|
||||
import { providers } from './identityProviders';
|
||||
import { SignalsDisplay } from '@backstage/plugin-signals';
|
||||
import { techDocsPage } from './components/techdocs/TechDocsPage';
|
||||
import { RequirePermission } from '@backstage/plugin-permission-react';
|
||||
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha';
|
||||
import { TwoColumnLayout } from './components/scaffolder/customScaffolderLayouts';
|
||||
import { customDevToolsPage } from './components/devtools/CustomDevToolsPage';
|
||||
import { DevToolsPage } from '@backstage/plugin-devtools';
|
||||
import { CatalogUnprocessedEntitiesPage } from '@backstage/plugin-catalog-unprocessed-entities';
|
||||
import {
|
||||
NotificationsPage,
|
||||
UserNotificationSettingsCard,
|
||||
} from '@backstage/plugin-notifications';
|
||||
import { CustomizableHomePage } from './components/home/CustomizableHomePage';
|
||||
import { HomePage } from './components/home/HomePage';
|
||||
import { BuiThemerPage } from '@backstage/plugin-mui-to-bui';
|
||||
import appVisualizerPlugin from '@backstage/plugin-app-visualizer';
|
||||
import { convertLegacyAppRoot } from '@backstage/core-compat-api';
|
||||
import { FlatRoutes } from '@backstage/core-app-api';
|
||||
import { Route } from 'react-router';
|
||||
import { CatalogImportPage } from '@backstage/plugin-catalog-import';
|
||||
import kubernetesPlugin from '@backstage/plugin-kubernetes/alpha';
|
||||
import { convertLegacyPlugin } from '@backstage/core-compat-api';
|
||||
import { convertLegacyPageExtension } from '@backstage/core-compat-api';
|
||||
import { convertLegacyEntityContentExtension } from '@backstage/plugin-catalog-react/alpha';
|
||||
import { pluginInfoResolver } from './pluginInfoResolver';
|
||||
import { appModuleNav } from './modules/appModuleNav';
|
||||
import devtoolsPlugin from '@backstage/plugin-devtools/alpha';
|
||||
import { unprocessedEntitiesDevToolsContent } from '@backstage/plugin-catalog-unprocessed-entities/alpha';
|
||||
import catalogPlugin from '@backstage/plugin-catalog/alpha';
|
||||
import InfoIcon from '@material-ui/icons/Info';
|
||||
|
||||
const app = createApp({
|
||||
apis,
|
||||
icons: {
|
||||
// Custom icon example
|
||||
alert: AlarmIcon,
|
||||
},
|
||||
featureFlags: [
|
||||
{
|
||||
name: 'scaffolder-next-preview',
|
||||
description: 'Preview the new Scaffolder Next',
|
||||
pluginId: '',
|
||||
},
|
||||
/*
|
||||
|
||||
# Notes
|
||||
|
||||
TODO:
|
||||
- proper createApp
|
||||
- connect extensions and plugins, provide method?
|
||||
- higher level API for creating standard extensions + higher order framework API for creating those?
|
||||
- extension config schema + validation
|
||||
- figure out how to resolve configured extension ref to runtime value, e.g. '@backstage/plugin-graphiql#GraphiqlPage'
|
||||
- make sure all shorthands work + tests
|
||||
- figure out package structure / how to ship, frontend-plugin-api/frontend-app-api
|
||||
- figure out routing, useRouteRef in the new system
|
||||
- Legacy plugins / interop
|
||||
- dynamic updates, runtime API
|
||||
|
||||
*/
|
||||
|
||||
/* core */
|
||||
|
||||
// const discoverPackages = async () => {
|
||||
// // stub for now, deferring package discovery til later
|
||||
// return ['@backstage/plugin-graphiql'];
|
||||
// };
|
||||
|
||||
/* graphiql package */
|
||||
|
||||
/* app.tsx */
|
||||
|
||||
/**
|
||||
* TechDocs does support the new frontend system so this conversion is not
|
||||
* strictly necessary, but it's left here to provide a demo of the utilities for
|
||||
* converting legacy plugins.
|
||||
*/
|
||||
const convertedTechdocsPlugin = convertLegacyPlugin(techdocsPlugin, {
|
||||
extensions: [
|
||||
// TODO: We likely also need a way to convert an entire <Route> tree similar to collectLegacyRoutes
|
||||
convertLegacyPageExtension(TechDocsIndexPage, {
|
||||
name: 'index',
|
||||
path: '/docs',
|
||||
}),
|
||||
convertLegacyPageExtension(TechDocsReaderPage, {
|
||||
path: '/docs/:namespace/:kind/:name/*',
|
||||
}),
|
||||
convertLegacyEntityContentExtension(EntityTechdocsContent),
|
||||
],
|
||||
components: {
|
||||
SignInPage: props => {
|
||||
return (
|
||||
<SignInPage
|
||||
{...props}
|
||||
providers={['guest', 'custom', ...providers]}
|
||||
title="Select a sign-in method"
|
||||
align="center"
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const routes = (
|
||||
const clockConfigs: ClockConfig[] = [
|
||||
{ label: 'NYC', timeZone: 'America/New_York' },
|
||||
{ label: 'UTC', timeZone: 'UTC' },
|
||||
{ label: 'STO', timeZone: 'Europe/Stockholm' },
|
||||
{ label: 'TYO', timeZone: 'Asia/Tokyo' },
|
||||
];
|
||||
|
||||
const customHomePageModule = createFrontendModule({
|
||||
pluginId: 'home',
|
||||
extensions: [
|
||||
HomePageLayoutBlueprint.make({
|
||||
params: {
|
||||
loader: async () =>
|
||||
function CustomHomePageLayout({ widgets }: HomePageLayoutProps) {
|
||||
return (
|
||||
<Page themeId="home">
|
||||
<Header title={<WelcomeTitle />} pageTitleOverride="Home">
|
||||
<HeaderWorldClock clockConfigs={clockConfigs} />
|
||||
</Header>
|
||||
<Content>
|
||||
<CustomHomepageGrid>
|
||||
{widgets.map((widget, index) => (
|
||||
<Fragment key={widget.name ?? index}>
|
||||
{widget.component}
|
||||
</Fragment>
|
||||
))}
|
||||
</CustomHomepageGrid>
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// customize catalog example
|
||||
const customizedCatalog = catalogPlugin.withOverrides({
|
||||
extensions: [
|
||||
catalogPlugin.getExtension('entity-content:catalog/overview').override({
|
||||
params: {
|
||||
icon: <InfoIcon />,
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const notFoundErrorPageModule = createFrontendModule({
|
||||
pluginId: 'app',
|
||||
extensions: [notFoundErrorPage],
|
||||
});
|
||||
|
||||
const devtoolsPluginUnprocessed = createFrontendModule({
|
||||
pluginId: 'catalog-unprocessed-entities',
|
||||
extensions: [unprocessedEntitiesDevToolsContent],
|
||||
});
|
||||
|
||||
const collectedLegacyPlugins = convertLegacyAppRoot(
|
||||
<FlatRoutes>
|
||||
<Route path="/" element={<Navigate to="catalog" />} />
|
||||
|
||||
{/* TODO(rubenl): Move this to / once its more mature and components exist */}
|
||||
|
||||
<FeatureFlagged with="customizable-home-page-preview">
|
||||
<Route path="/home" element={<HomepageCompositionRoot />}>
|
||||
<CustomizableHomePage />
|
||||
</Route>
|
||||
</FeatureFlagged>
|
||||
<FeatureFlagged without="customizable-home-page-preview">
|
||||
<Route path="/home" element={<HomepageCompositionRoot />}>
|
||||
<HomePage />
|
||||
</Route>
|
||||
</FeatureFlagged>
|
||||
|
||||
<Route
|
||||
path="/catalog"
|
||||
element={<CatalogIndexPage pagination={{ mode: 'offset', limit: 20 }} />}
|
||||
/>
|
||||
<Route
|
||||
path="/catalog/:namespace/:kind/:name"
|
||||
element={<CatalogEntityPage />}
|
||||
>
|
||||
{entityPage}
|
||||
</Route>
|
||||
<Route
|
||||
path="/catalog-unprocessed-entities"
|
||||
element={<CatalogUnprocessedEntitiesPage />}
|
||||
/>
|
||||
<Route
|
||||
path="/catalog-import"
|
||||
element={
|
||||
<RequirePermission permission={catalogEntityCreatePermission}>
|
||||
<CatalogImportPage />
|
||||
</RequirePermission>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/catalog-graph"
|
||||
element={
|
||||
<CatalogGraphPage
|
||||
initialState={{
|
||||
selectedKinds: ['component', 'domain', 'system', 'api', 'group'],
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/docs"
|
||||
element={<TechDocsIndexPage pagination={{ mode: 'offset', limit: 20 }} />}
|
||||
/>
|
||||
<Route
|
||||
path="/docs/:namespace/:kind/:name/*"
|
||||
element={<TechDocsReaderPage />}
|
||||
>
|
||||
{techDocsPage}
|
||||
<TechDocsAddons>
|
||||
<ExpandableNavigation />
|
||||
<ReportIssue />
|
||||
<TextSize />
|
||||
<LightBox />
|
||||
</TechDocsAddons>
|
||||
</Route>
|
||||
<Route
|
||||
path="/create"
|
||||
element={
|
||||
<ScaffolderPage
|
||||
defaultPreviewTemplate={defaultPreviewTemplate}
|
||||
groups={[
|
||||
{
|
||||
title: 'Recommended',
|
||||
filter: entity =>
|
||||
entity?.metadata?.tags?.includes('recommended') ?? false,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<ScaffolderFieldExtensions>
|
||||
<DelayingComponentFieldExtension />
|
||||
</ScaffolderFieldExtensions>
|
||||
<ScaffolderLayouts>
|
||||
<TwoColumnLayout />
|
||||
</ScaffolderLayouts>
|
||||
</Route>
|
||||
|
||||
<Route path="/api-docs" element={<ApiExplorerPage />} />
|
||||
<Route path="/search" element={<SearchPage />}>
|
||||
{searchPage}
|
||||
</Route>
|
||||
|
||||
<Route path="/settings" element={<UserSettingsPage />}>
|
||||
<SettingsLayout.Route path="/advanced" title="Advanced">
|
||||
<AdvancedSettings />
|
||||
</SettingsLayout.Route>
|
||||
<SettingsLayout.Route path="/notifications" title="Notifications">
|
||||
<UserNotificationSettingsCard
|
||||
originNames={{ 'plugin:scaffolder': 'Scaffolder' }}
|
||||
/>
|
||||
</SettingsLayout.Route>
|
||||
</Route>
|
||||
<Route path="/devtools" element={<DevToolsPage />}>
|
||||
{customDevToolsPage}
|
||||
</Route>
|
||||
<Route path="/notifications" element={<NotificationsPage />} />
|
||||
<Route path="/mui-to-bui" element={<BuiThemerPage />} />
|
||||
</FlatRoutes>
|
||||
<Route path="/catalog-import" element={<CatalogImportPage />} />
|
||||
</FlatRoutes>,
|
||||
);
|
||||
|
||||
export default app.createRoot(
|
||||
<>
|
||||
<AlertDisplay transientTimeoutMs={2500} />
|
||||
<OAuthRequestDialog />
|
||||
<SignalsDisplay />
|
||||
<AppRouter>
|
||||
<VisitListener />
|
||||
<Root>{routes}</Root>
|
||||
</AppRouter>
|
||||
</>,
|
||||
);
|
||||
const app = createApp({
|
||||
features: [
|
||||
customizedCatalog,
|
||||
pagesPlugin,
|
||||
convertedTechdocsPlugin,
|
||||
userSettingsPlugin,
|
||||
homePlugin,
|
||||
appVisualizerPlugin,
|
||||
kubernetesPlugin,
|
||||
notFoundErrorPageModule,
|
||||
appModuleNav,
|
||||
customHomePageModule,
|
||||
devtoolsPlugin,
|
||||
devtoolsPluginUnprocessed,
|
||||
...collectedLegacyPlugins,
|
||||
],
|
||||
advanced: {
|
||||
pluginInfoResolver,
|
||||
},
|
||||
/* Handled through config instead */
|
||||
// bindRoutes({ bind }) {
|
||||
// bind(pagesPlugin.externalRoutes, { pageX: pagesPlugin.routes.pageX });
|
||||
// },
|
||||
});
|
||||
|
||||
// const legacyApp = createLegacyApp({ plugins: [legacyGraphiqlPlugin] });
|
||||
|
||||
export default app.createRoot();
|
||||
|
||||
// const routes = (
|
||||
// <FlatRoutes>
|
||||
// {/* <Route path="/" element={<Navigate to="catalog" />} />
|
||||
// <Route path="/catalog" element={<CatalogIndexPage />} />
|
||||
// <Route
|
||||
// path="/catalog/:namespace/:kind/:name"
|
||||
// element={<CatalogEntityPage />}
|
||||
// >
|
||||
// <EntityLayout>
|
||||
// <EntityLayout.Route path="/" title="Overview">
|
||||
// <Grid container spacing={3} alignItems="stretch">
|
||||
// <Grid item md={6} xs={12}>
|
||||
// <EntityAboutCard variant="gridItem" />
|
||||
// </Grid>
|
||||
|
||||
// <Grid item md={4} xs={12}>
|
||||
// <EntityLinksCard />
|
||||
// </Grid>
|
||||
// </Grid>
|
||||
// </EntityLayout.Route>
|
||||
|
||||
// <EntityLayout.Route path="/todos" title="TODOs">
|
||||
// <EntityTodoContent />
|
||||
// </EntityLayout.Route>
|
||||
// </EntityLayout>
|
||||
// </Route>
|
||||
// <Route
|
||||
// path="/catalog-import"
|
||||
// element={
|
||||
// <CatalogImportPage />
|
||||
// }
|
||||
// /> */}
|
||||
// {/* <Route
|
||||
// path="/tech-radar"
|
||||
// element={<TechRadarPage width={1500} height={800} />}
|
||||
// /> */}
|
||||
// <Route path="/graphiql" element={<GraphiQLPage />} />
|
||||
// </FlatRoutes>
|
||||
// );
|
||||
|
||||
// export default app.createRoot(
|
||||
// <>
|
||||
// {/* <AlertDisplay transientTimeoutMs={2500} />
|
||||
// <OAuthRequestDialog /> */}
|
||||
// <AppRouter>{routes}</AppRouter>
|
||||
// </>,
|
||||
// );
|
||||
|
||||
@@ -14,54 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createApp } from '@backstage/app-defaults';
|
||||
import { AppRouter } from '@backstage/core-app-api';
|
||||
import {
|
||||
AlertDisplay,
|
||||
OAuthRequestDialog,
|
||||
SignInPage,
|
||||
} from '@backstage/core-components';
|
||||
import { CookieAuthRedirect } from '@backstage/plugin-auth-react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { providers } from '../src/identityProviders';
|
||||
import {
|
||||
configApiRef,
|
||||
createApiFactory,
|
||||
discoveryApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { AuthProxyDiscoveryApi } from '../src/AuthProxyDiscoveryApi';
|
||||
import { createApp } from '@backstage/frontend-defaults';
|
||||
import { appModulePublicSignIn } from '@backstage/plugin-app/alpha';
|
||||
|
||||
import '@backstage/ui/css/styles.css';
|
||||
|
||||
const app = createApp({
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: discoveryApiRef,
|
||||
deps: { configApi: configApiRef },
|
||||
factory: ({ configApi }) => AuthProxyDiscoveryApi.fromConfig(configApi),
|
||||
}),
|
||||
],
|
||||
components: {
|
||||
SignInPage: props => {
|
||||
return (
|
||||
<SignInPage
|
||||
{...props}
|
||||
providers={['guest', 'custom', ...providers]}
|
||||
title="Select a sign-in method"
|
||||
align="center"
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
features: [appModulePublicSignIn],
|
||||
});
|
||||
|
||||
const App = app.createRoot(
|
||||
<>
|
||||
<AlertDisplay transientTimeoutMs={2500} />
|
||||
<OAuthRequestDialog />
|
||||
<AppRouter>
|
||||
<CookieAuthRedirect />
|
||||
</AppRouter>
|
||||
</>,
|
||||
);
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(app.createRoot());
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import '@backstage/cli/asset-types';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import App from './App';
|
||||
import app from './App';
|
||||
import '@backstage/ui/css/styles.css';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(app);
|
||||
|
||||
@@ -31,8 +31,8 @@ const execAsync = promisify(exec);
|
||||
|
||||
const EXCLUDE = [
|
||||
'packages/app',
|
||||
'packages/app-next',
|
||||
'packages/app-next-example-plugin',
|
||||
'packages/app-legacy',
|
||||
'packages/app-example-plugin',
|
||||
'packages/cli',
|
||||
'packages/cli-common',
|
||||
'packages/cli-node',
|
||||
|
||||