diff --git a/packages/app-next/.eslintrc.js b/packages/app-next/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/packages/app-next/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/packages/app-next/README.md b/packages/app-next/README.md new file mode 100644 index 0000000000..21645609a9 --- /dev/null +++ b/packages/app-next/README.md @@ -0,0 +1,3 @@ +# example-app-next + +This package is an example of a Backstage application. diff --git a/packages/app-next/app-config.yaml b/packages/app-next/app-config.yaml new file mode 100644 index 0000000000..6042c5ce2a --- /dev/null +++ b/packages/app-next/app-config.yaml @@ -0,0 +1,104 @@ + +app: + packages: 'all' # ✨ + extensions: [] + # - core.signInPage: + # props: + # provider: + # id: google + # title: Google + # message: Sign In using Google + # apiRef: googleAuthApiRef # ??? + + # - core.nav: + # config: + # logo: assets/logo.png + # layout: + # - label: Search + # icon: search + # to: /search + # items: + # - point: search + # - type: divider + # - label: Menu + # icon: menu + # items: + # - label: Home + # icon: home + # to: /catalog + # - label: Create... + # icon: create + # to: /create + # - type: divider + # - type: scroll-wrapper + # items: + # - label: Tech Radar + # icon: map + # to: /tech-radar + # - label: GraphiQL + # icon: graphiql + # to: /graphiql + # - type: divider + # - point: shortcuts + # - type: space + # - type: divider + # - label: Settings + # icon: avatar + # to: /settings + # items: + # - point: settings + # - core.nav/search: '@backstage/plugin-search#SidebarSearchModal' + # - core.nav/shortcuts: + # use: '@backstage/plugin-shortcuts#Shortcuts' + # config: + # allowExternalLinks: true + # - core.nav/settings: '@backstage/plugin-user-settings#SidebarSettings' + + # - core.pages.index: + # at: + # point: core.routes + # config: + # path: / + # use: 'react-router-dom#Navigate' + # config: + # to: /catalog + + # - scaffolder.page: + # config: + # groups: + # - title: Recommended + # filter: + # entity.metadata.tags: recommended + # - scaffolder.page/fields: '@backstage/plugin-scaffolder#LowerCaseValuePickerFieldExtension' + # - scaffolder.page/layout: '@backstage/plugin-scaffolder#TwoColumnLayout' + + # - search.page/content: 'app#customSearchPage' # custom search page from somewhere + + # - user-settings.page.routes.advanced: + # at: + # point: user-settings.page/routes + # config: + # title: Advanced + # path: /advanced + # use: '@backstage/plugin-user-settings#AdvancedSettings' + + # - entity.card.orphanWarning + # - entity.card.processingErrors + # - entity.card.about + # - entity.card.catalogGraph + # - entity.card.pagerDuty + # - entity.card.links + # - entity.card.labels + # - entity.card.githubInsightsLanguages + # - entity.card.githubInsightsReleases + # - entity.card.githubInsightsReadme: + # config: + # maxHeight: 350 # Throwing this config in to have an example, but in practice rely on default + # - entity.card.subcomponentsCard + # - entity.card.userProfile + # - entity.card.ownership + # - entity.card.likeDislikeRatings + # - entity.content.dependsOnComponents + # - entity.content.codeInsights + # - entity.content.todo + # - entity.content.feedbackResponse diff --git a/packages/app-next/package.json b/packages/app-next/package.json new file mode 100644 index 0000000000..35a8e02cbc --- /dev/null +++ b/packages/app-next/package.json @@ -0,0 +1,141 @@ +{ + "name": "example-app-next", + "version": "0.0.0", + "private": true, + "backstage": { + "role": "frontend" + }, + "bundled": true, + "dependencies": { + "@backstage/app-defaults": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/integration-react": "workspace:^", + "@backstage/plugin-adr": "workspace:^", + "@backstage/plugin-airbrake": "workspace:^", + "@backstage/plugin-apache-airflow": "workspace:^", + "@backstage/plugin-api-docs": "workspace:^", + "@backstage/plugin-azure-devops": "workspace:^", + "@backstage/plugin-azure-sites": "workspace:^", + "@backstage/plugin-badges": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", + "@backstage/plugin-catalog-graph": "workspace:^", + "@backstage/plugin-catalog-import": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", + "@backstage/plugin-catalog-unprocessed-entities": "workspace:^", + "@backstage/plugin-circleci": "workspace:^", + "@backstage/plugin-cloudbuild": "workspace:^", + "@backstage/plugin-code-coverage": "workspace:^", + "@backstage/plugin-cost-insights": "workspace:^", + "@backstage/plugin-devtools": "workspace:^", + "@backstage/plugin-dynatrace": "workspace:^", + "@backstage/plugin-entity-feedback": "workspace:^", + "@backstage/plugin-explore": "workspace:^", + "@backstage/plugin-gcalendar": "workspace:^", + "@backstage/plugin-gcp-projects": "workspace:^", + "@backstage/plugin-github-actions": "workspace:^", + "@backstage/plugin-gocd": "workspace:^", + "@backstage/plugin-graphiql": "workspace:^", + "@backstage/plugin-home": "workspace:^", + "@backstage/plugin-jenkins": "workspace:^", + "@backstage/plugin-kafka": "workspace:^", + "@backstage/plugin-kubernetes": "workspace:^", + "@backstage/plugin-lighthouse": "workspace:^", + "@backstage/plugin-linguist": "workspace:^", + "@backstage/plugin-linguist-common": "workspace:^", + "@backstage/plugin-microsoft-calendar": "workspace:^", + "@backstage/plugin-newrelic": "workspace:^", + "@backstage/plugin-newrelic-dashboard": "workspace:^", + "@backstage/plugin-octopus-deploy": "workspace:^", + "@backstage/plugin-org": "workspace:^", + "@backstage/plugin-pagerduty": "workspace:^", + "@backstage/plugin-permission-react": "workspace:^", + "@backstage/plugin-playlist": "workspace:^", + "@backstage/plugin-puppetdb": "workspace:^", + "@backstage/plugin-rollbar": "workspace:^", + "@backstage/plugin-scaffolder": "workspace:^", + "@backstage/plugin-scaffolder-react": "workspace:^", + "@backstage/plugin-search": "workspace:^", + "@backstage/plugin-search-common": "workspace:^", + "@backstage/plugin-search-react": "workspace:^", + "@backstage/plugin-sentry": "workspace:^", + "@backstage/plugin-shortcuts": "workspace:^", + "@backstage/plugin-stack-overflow": "workspace:^", + "@backstage/plugin-stackstorm": "workspace:^", + "@backstage/plugin-tech-insights": "workspace:^", + "@backstage/plugin-tech-radar": "workspace:^", + "@backstage/plugin-techdocs": "workspace:^", + "@backstage/plugin-techdocs-module-addons-contrib": "workspace:^", + "@backstage/plugin-techdocs-react": "workspace:^", + "@backstage/plugin-todo": "workspace:^", + "@backstage/plugin-user-settings": "workspace:^", + "@backstage/theme": "workspace:^", + "@internal/plugin-catalog-customized": "workspace:^", + "@material-ui/core": "^4.12.2", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "4.0.0-alpha.61", + "@octokit/rest": "^19.0.3", + "@oriflame/backstage-plugin-score-card": "^0.7.0", + "@roadiehq/backstage-plugin-buildkite": "^2.0.8", + "@roadiehq/backstage-plugin-github-insights": "^2.0.5", + "@roadiehq/backstage-plugin-github-pull-requests": "^2.2.7", + "@roadiehq/backstage-plugin-travis-ci": "^2.0.5", + "history": "^5.0.0", + "lodash": "^4.17.21", + "prop-types": "^15.7.2", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "react-router": "^6.3.0", + "react-router-dom": "^6.3.0", + "react-use": "^17.2.4", + "zen-observable": "^0.10.0" + }, + "devDependencies": { + "@backstage/test-utils": "workspace:^", + "@testing-library/cypress": "^9.0.0", + "@testing-library/dom": "^8.0.0", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^12.1.3", + "@testing-library/user-event": "^14.0.0", + "@types/jquery": "^3.3.34", + "@types/node": "^16.11.26", + "@types/react": "*", + "@types/react-dom": "*", + "@types/zen-observable": "^0.8.0", + "cross-env": "^7.0.0", + "cypress": "^10.0.0", + "eslint-plugin-cypress": "^2.10.3", + "start-server-and-test": "^1.10.11" + }, + "scripts": { + "start": "backstage-cli package start --config app-config.yaml --config packages/app-next/app-config.yaml", + "build": "backstage-cli package build", + "clean": "backstage-cli package clean", + "test": "backstage-cli package test", + "lint": "backstage-cli package lint", + "test:e2e": "start-server-and-test start http://localhost:3000 cy:dev", + "test:e2e:ci": "start-server-and-test start http://localhost:3000 cy:run", + "cy:dev": "cypress open", + "cy:run": "cypress run" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "files": [ + "dist" + ], + "license": "Apache-2.0" +} diff --git a/packages/app-next/public/android-chrome-192x192.png b/packages/app-next/public/android-chrome-192x192.png new file mode 100644 index 0000000000..eec0ae25b9 Binary files /dev/null and b/packages/app-next/public/android-chrome-192x192.png differ diff --git a/packages/app-next/public/android-chrome-512x512.png b/packages/app-next/public/android-chrome-512x512.png new file mode 100644 index 0000000000..ac0578133b Binary files /dev/null and b/packages/app-next/public/android-chrome-512x512.png differ diff --git a/packages/app-next/public/apple-touch-icon.png b/packages/app-next/public/apple-touch-icon.png new file mode 100644 index 0000000000..6a45afb38f Binary files /dev/null and b/packages/app-next/public/apple-touch-icon.png differ diff --git a/packages/app-next/public/favicon-16x16.png b/packages/app-next/public/favicon-16x16.png new file mode 100644 index 0000000000..58cf61a35e Binary files /dev/null and b/packages/app-next/public/favicon-16x16.png differ diff --git a/packages/app-next/public/favicon-32x32.png b/packages/app-next/public/favicon-32x32.png new file mode 100644 index 0000000000..c0915ece75 Binary files /dev/null and b/packages/app-next/public/favicon-32x32.png differ diff --git a/packages/app-next/public/favicon.ico b/packages/app-next/public/favicon.ico new file mode 100644 index 0000000000..5e45e5dfbd Binary files /dev/null and b/packages/app-next/public/favicon.ico differ diff --git a/packages/app-next/public/favicon.svg b/packages/app-next/public/favicon.svg new file mode 100644 index 0000000000..7f2d375cd8 --- /dev/null +++ b/packages/app-next/public/favicon.svg @@ -0,0 +1 @@ +Backstage favicon \ No newline at end of file diff --git a/packages/app-next/public/index.html b/packages/app-next/public/index.html new file mode 100644 index 0000000000..0710a0d69d --- /dev/null +++ b/packages/app-next/public/index.html @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + <%= config.getString('app.title') %> + + <% if (config.has('app.datadogRum')) { %> + + <% } %> + + + + +
+ + + diff --git a/packages/app-next/public/manifest.json b/packages/app-next/public/manifest.json new file mode 100644 index 0000000000..4a7c1b4ec4 --- /dev/null +++ b/packages/app-next/public/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "Backstage", + "name": "Backstage", + "icons": [ + { + "src": "favicon.ico", + "sizes": "48x48", + "type": "image/png" + } + ], + "start_url": "./index.html", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/packages/app-next/public/robots.txt b/packages/app-next/public/robots.txt new file mode 100644 index 0000000000..01b0f9a107 --- /dev/null +++ b/packages/app-next/public/robots.txt @@ -0,0 +1,2 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * diff --git a/packages/app-next/public/safari-pinned-tab.svg b/packages/app-next/public/safari-pinned-tab.svg new file mode 100644 index 0000000000..0f500b3002 --- /dev/null +++ b/packages/app-next/public/safari-pinned-tab.svg @@ -0,0 +1 @@ +Created by potrace 1.11, written by Peter Selinger 2001-2013 \ No newline at end of file diff --git a/packages/app-next/src/App.test.tsx b/packages/app-next/src/App.test.tsx new file mode 100644 index 0000000000..8c7cefeb2c --- /dev/null +++ b/packages/app-next/src/App.test.tsx @@ -0,0 +1,48 @@ +/* + * 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 React from 'react'; +import { renderWithEffects } from '@backstage/test-utils'; +import App from './App'; + +describe('App', () => { + it('should render', async () => { + process.env = { + NODE_ENV: 'test', + APP_CONFIG: [ + { + data: { + app: { + title: 'Test', + support: { url: 'http://localhost:7007/support' }, + }, + backend: { baseUrl: 'http://localhost:7007' }, + lighthouse: { + baseUrl: 'http://localhost:3003', + }, + techdocs: { + storageUrl: 'http://localhost:7007/api/techdocs/static/docs', + }, + }, + context: 'test', + }, + ] as any, + }; + + const rendered = await renderWithEffects(); + expect(rendered.baseElement).toBeInTheDocument(); + }); +}); diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx new file mode 100644 index 0000000000..a93a934301 --- /dev/null +++ b/packages/app-next/src/App.tsx @@ -0,0 +1,205 @@ +/* + * 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 { AppRouter, FlatRoutes } from '@backstage/core-app-api'; + +import { catalogPlugin } from '@internal/plugin-catalog-customized'; + +import { catalogImportPlugin } from '@backstage/plugin-catalog-import'; +import { GraphiQLPage } from '@backstage/plugin-graphiql'; +import { scaffolderPlugin } from '@backstage/plugin-scaffolder'; +import { TechRadarPage } from '@backstage/plugin-tech-radar'; +import React, { ComponentType } from 'react'; +import { Route } from 'react-router-dom'; +import mapValues from 'lodash/mapValues'; + +/* core */ + +const discoverPackages = async () => { + // stub for now, deferring package discovery til later + return ['@backstage/plugin-graphiql']; +}; + +function createApp() {} + +function createPlugin() {} + +type AnyExtensionDataMap = Record>; + +type ExtensionDataBind = { + [K in keyof TData]: (value: TData[K]['T']) => void; +}; + +type ExtensionDataValue = { + [K in keyof TData]: TData[K]['T']; +}; + +interface CreateExtensionOptions< + TData extends AnyExtensionDataMap, + TPoint extends Record, +> { + inputs?: TPoint; + output: TData; + factory(options: { + bind: ExtensionDataBind; + config?: unknown; + inputs: { + [pointName in keyof TPoint]: ExtensionDataValue< + TPoint[pointName]['extensionData'] + >[]; + }; + }): void; +} + +interface Extension { + $$type: 'extension'; + inputs: Record; + output: AnyExtensionDataMap; + factory(options: { + bind: ExtensionDataBind; + config?: unknown; + inputs: Record>>; + }): void; +} + +function createExtension< + TData extends AnyExtensionDataMap, + TPoint extends Record, +>(options: CreateExtensionOptions): Extension { + return { ...options, $$type: 'extension', inputs: options.inputs ?? {} }; +} + +interface ExtensionDataRef { + id: string; + T: T; + $$type: 'extension-data'; +} + +function createExtensionDataRef(id: string) { + return { id, $$type: 'extension-data' } as ExtensionDataRef; +} + +const coreExtensionData = { + reactComponent: createExtensionDataRef('core.reactComponent'), + routePath: createExtensionDataRef('core.routing.path'), +}; + +type ExtensionDataId = string; + +interface ExtensionInstance { + id: string; + data: Map; + $$type: 'extension-instance'; +} + +function createExtensionInstance(options: { + id: string; + extension: Extension; + config: unknown; + attachments: Record; +}): ExtensionInstance { + const { extension, config, attachments } = options; + const extensionData = new Map(); + extension.factory({ + config, + bind: mapValues(extension.output, ref => { + return (value: unknown) => extensionData.set(ref.id, value); + }), + inputs: mapValues( + extension.inputs, + ({ extensionData: pointData }, inputName) => { + // TODO: validation + return (attachments[inputName] ?? []).map(attachment => + mapValues(pointData, ref => attachment.data.get(ref.id)), + ); + }, + ), + }); + return { id: options.id, data: extensionData, $$type: 'extension-instance' }; +} + +/* graphiql package */ + +const GraphiqlRoute = createExtension({ + inputs: { + extensionData: { + component: coreExtensionData.reactComponent, + }, + }, + factory({ bind, points }) { + // ... + }, +}); + +/* app.tsx */ + +const app = createApp({ + // bindRoutes({ bind }) { + // bind(catalogPlugin.externalRoutes, { + // createComponent: scaffolderPlugin.routes.root, + // }); + // bind(scaffolderPlugin.externalRoutes, { + // registerComponent: catalogImportPlugin.routes.importPage, + // }); + // }, +}); + +const routes = ( + + {/* } /> + } /> + } + > + + + + + + + + + + + + + + + + + + + + } + /> */} + {/* } + /> */} + } /> + +); + +export default app.createRoot( + <> + {/* + */} + {routes} + , +); diff --git a/packages/app-next/src/index.tsx b/packages/app-next/src/index.tsx new file mode 100644 index 0000000000..b15bc4c102 --- /dev/null +++ b/packages/app-next/src/index.tsx @@ -0,0 +1,22 @@ +/* + * 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 '@backstage/cli/asset-types'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App'; + +ReactDOM.render(, document.getElementById('root')); diff --git a/packages/app-next/src/setupTests.ts b/packages/app-next/src/setupTests.ts new file mode 100644 index 0000000000..23fcbe9676 --- /dev/null +++ b/packages/app-next/src/setupTests.ts @@ -0,0 +1,21 @@ +/* + * 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. + */ + +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom'; diff --git a/yarn.lock b/yarn.lock index e5c4f02164..af8ced2b00 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19355,6 +19355,7 @@ __metadata: cypress: ^10.0.0 eslint-plugin-cypress: ^2.10.3 history: ^5.0.0 + lodash: ^4.17.21 prop-types: ^15.7.2 react: ^17.0.2 react-dom: ^17.0.2 @@ -19363,6 +19364,7 @@ __metadata: react-use: ^17.2.4 start-server-and-test: ^1.10.11 zen-observable: ^0.10.0 + zod: ^3.21.4 languageName: unknown linkType: soft @@ -25171,6 +25173,114 @@ __metadata: languageName: node linkType: hard +"example-app-next@workspace:packages/app-next": + version: 0.0.0-use.local + resolution: "example-app-next@workspace:packages/app-next" + dependencies: + "@backstage/app-defaults": "workspace:^" + "@backstage/catalog-model": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/core-app-api": "workspace:^" + "@backstage/core-components": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" + "@backstage/integration-react": "workspace:^" + "@backstage/plugin-adr": "workspace:^" + "@backstage/plugin-airbrake": "workspace:^" + "@backstage/plugin-apache-airflow": "workspace:^" + "@backstage/plugin-api-docs": "workspace:^" + "@backstage/plugin-azure-devops": "workspace:^" + "@backstage/plugin-azure-sites": "workspace:^" + "@backstage/plugin-badges": "workspace:^" + "@backstage/plugin-catalog-common": "workspace:^" + "@backstage/plugin-catalog-graph": "workspace:^" + "@backstage/plugin-catalog-import": "workspace:^" + "@backstage/plugin-catalog-react": "workspace:^" + "@backstage/plugin-catalog-unprocessed-entities": "workspace:^" + "@backstage/plugin-circleci": "workspace:^" + "@backstage/plugin-cloudbuild": "workspace:^" + "@backstage/plugin-code-coverage": "workspace:^" + "@backstage/plugin-cost-insights": "workspace:^" + "@backstage/plugin-devtools": "workspace:^" + "@backstage/plugin-dynatrace": "workspace:^" + "@backstage/plugin-entity-feedback": "workspace:^" + "@backstage/plugin-explore": "workspace:^" + "@backstage/plugin-gcalendar": "workspace:^" + "@backstage/plugin-gcp-projects": "workspace:^" + "@backstage/plugin-github-actions": "workspace:^" + "@backstage/plugin-gocd": "workspace:^" + "@backstage/plugin-graphiql": "workspace:^" + "@backstage/plugin-home": "workspace:^" + "@backstage/plugin-jenkins": "workspace:^" + "@backstage/plugin-kafka": "workspace:^" + "@backstage/plugin-kubernetes": "workspace:^" + "@backstage/plugin-lighthouse": "workspace:^" + "@backstage/plugin-linguist": "workspace:^" + "@backstage/plugin-linguist-common": "workspace:^" + "@backstage/plugin-microsoft-calendar": "workspace:^" + "@backstage/plugin-newrelic": "workspace:^" + "@backstage/plugin-newrelic-dashboard": "workspace:^" + "@backstage/plugin-octopus-deploy": "workspace:^" + "@backstage/plugin-org": "workspace:^" + "@backstage/plugin-pagerduty": "workspace:^" + "@backstage/plugin-permission-react": "workspace:^" + "@backstage/plugin-playlist": "workspace:^" + "@backstage/plugin-puppetdb": "workspace:^" + "@backstage/plugin-rollbar": "workspace:^" + "@backstage/plugin-scaffolder": "workspace:^" + "@backstage/plugin-scaffolder-react": "workspace:^" + "@backstage/plugin-search": "workspace:^" + "@backstage/plugin-search-common": "workspace:^" + "@backstage/plugin-search-react": "workspace:^" + "@backstage/plugin-sentry": "workspace:^" + "@backstage/plugin-shortcuts": "workspace:^" + "@backstage/plugin-stack-overflow": "workspace:^" + "@backstage/plugin-stackstorm": "workspace:^" + "@backstage/plugin-tech-insights": "workspace:^" + "@backstage/plugin-tech-radar": "workspace:^" + "@backstage/plugin-techdocs": "workspace:^" + "@backstage/plugin-techdocs-module-addons-contrib": "workspace:^" + "@backstage/plugin-techdocs-react": "workspace:^" + "@backstage/plugin-todo": "workspace:^" + "@backstage/plugin-user-settings": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/theme": "workspace:^" + "@internal/plugin-catalog-customized": "workspace:^" + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.61 + "@octokit/rest": ^19.0.3 + "@oriflame/backstage-plugin-score-card": ^0.7.0 + "@roadiehq/backstage-plugin-buildkite": ^2.0.8 + "@roadiehq/backstage-plugin-github-insights": ^2.0.5 + "@roadiehq/backstage-plugin-github-pull-requests": ^2.2.7 + "@roadiehq/backstage-plugin-travis-ci": ^2.0.5 + "@testing-library/cypress": ^9.0.0 + "@testing-library/dom": ^8.0.0 + "@testing-library/jest-dom": ^5.10.1 + "@testing-library/react": ^12.1.3 + "@testing-library/user-event": ^14.0.0 + "@types/jquery": ^3.3.34 + "@types/node": ^16.11.26 + "@types/react": "*" + "@types/react-dom": "*" + "@types/zen-observable": ^0.8.0 + cross-env: ^7.0.0 + cypress: ^10.0.0 + eslint-plugin-cypress: ^2.10.3 + history: ^5.0.0 + lodash: ^4.17.21 + prop-types: ^15.7.2 + react: ^17.0.2 + react-dom: ^17.0.2 + react-router: ^6.3.0 + react-router-dom: ^6.3.0 + react-use: ^17.2.4 + start-server-and-test: ^1.10.11 + zen-observable: ^0.10.0 + languageName: unknown + linkType: soft + "example-app@link:../app::locator=example-backend%40workspace%3Apackages%2Fbackend": version: 0.0.0-use.local resolution: "example-app@link:../app::locator=example-backend%40workspace%3Apackages%2Fbackend"