= () => (
+
}
/>
} />
-
+ }
+ />
{deprecatedAppRoutes}
diff --git a/packages/create-app/templates/default-app/packages/app/src/apis.ts b/packages/create-app/templates/default-app/packages/app/src/apis.ts
index 14351eaba7..e0503e504f 100644
--- a/packages/create-app/templates/default-app/packages/app/src/apis.ts
+++ b/packages/create-app/templates/default-app/packages/app/src/apis.ts
@@ -1,89 +1,17 @@
import {
- ApiRegistry,
- alertApiRef,
- errorApiRef,
- AlertApiForwarder,
- ConfigApi,
- ErrorApiForwarder,
- ErrorAlerter,
discoveryApiRef,
UrlPatternDiscovery,
- oauthRequestApiRef,
- OAuthRequestManager,
- storageApiRef,
- WebStorage,
+ createApiFactory,
+ configApiRef,
} from '@backstage/core';
-import {
- lighthouseApiRef,
- LighthouseRestApi,
-} from '@backstage/plugin-lighthouse';
-
-import {
- GithubActionsClient,
- githubActionsApiRef,
-} from '@backstage/plugin-github-actions';
-
-import {
- techdocsStorageApiRef,
- TechDocsStorageApi,
-} from '@backstage/plugin-techdocs';
-
-import { techRadarApiRef, TechRadar } from '@backstage/plugin-tech-radar';
-
-import { catalogApiRef, CatalogClient } from '@backstage/plugin-catalog';
-import { CircleCIApi, circleCIApiRef } from '@backstage/plugin-circleci';
-
-import { scaffolderApiRef, ScaffolderApi } from '@backstage/plugin-scaffolder';
-
-
-
-export const apis = (config: ConfigApi) => {
- // eslint-disable-next-line no-console
- console.log(`Creating APIs for ${config.getString('app.title')}`);
-
- const backendUrl = config.getString('backend.baseUrl');
- const techdocsStorageUrl = config.getString('techdocs.storageUrl');
-
- const builder = ApiRegistry.builder();
-
- const discoveryApi = builder.add(
- discoveryApiRef,
- UrlPatternDiscovery.compile(`${backendUrl}/{{ pluginId }}`),
- );
- const alertApi = builder.add(alertApiRef, new AlertApiForwarder());
- const errorApi = builder.add(
- errorApiRef,
- new ErrorAlerter(alertApi, new ErrorApiForwarder()),
- );
-
- builder.add(storageApiRef, WebStorage.create({ errorApi }));
- builder.add(oauthRequestApiRef, new OAuthRequestManager());
-
- builder.add(catalogApiRef, new CatalogClient({ discoveryApi }));
- builder.add(githubActionsApiRef, new GithubActionsClient());
-
- builder.add(lighthouseApiRef, new LighthouseRestApi('http://localhost:3003'));
-
- builder.add(
- circleCIApiRef,
- new CircleCIApi(`${backendUrl}/proxy/circleci/api`),
- );
-
- builder.add(scaffolderApiRef, new ScaffolderApi({ discoveryApi }));
-
- builder.add(
- techRadarApiRef,
- new TechRadar({
- width: 1500,
- height: 800,
- }),
- );
-
- builder.add(
- techdocsStorageApiRef,
- new TechDocsStorageApi({ apiOrigin: techdocsStorageUrl }),
- );
-
- return builder.build();
-};
+export const apis = [
+ createApiFactory({
+ api: discoveryApiRef,
+ deps: { configApi: configApiRef },
+ factory: ({ configApi }) =>
+ UrlPatternDiscovery.compile(
+ `${configApi.getString('backend.baseUrl')}/{{ pluginId }}`,
+ ),
+ }),
+];
diff --git a/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx b/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx
index fa9a397751..9e343b86ac 100644
--- a/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx
+++ b/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx
@@ -2,7 +2,6 @@ import React from 'react';
import HomeIcon from '@material-ui/icons/Home';
import LibraryBooks from '@material-ui/icons/LibraryBooks';
import CreateComponentIcon from '@material-ui/icons/AddCircleOutline';
-import ExploreIcon from '@material-ui/icons/Explore';
import BuildIcon from '@material-ui/icons/BuildRounded';
import RuleIcon from '@material-ui/icons/AssignmentTurnedIn';
import MapIcon from '@material-ui/icons/MyLocation';
@@ -23,7 +22,6 @@ export const AppSidebar = () => (
{/* Global nav, not org-specific */}
-
diff --git a/packages/dev-utils/src/devApp/apiFactories.ts b/packages/dev-utils/src/devApp/apiFactories.ts
deleted file mode 100644
index 4cf208f5d2..0000000000
--- a/packages/dev-utils/src/devApp/apiFactories.ts
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2020 Spotify AB
- *
- * 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 {
- alertApiRef,
- errorApiRef,
- ErrorApiForwarder,
- AlertApi,
- createApiFactory,
- ErrorAlerter,
- AlertApiForwarder,
- oauthRequestApiRef,
- OAuthRequestManager,
- UrlPatternDiscovery,
- discoveryApiRef,
- GoogleAuth,
- googleAuthApiRef,
- GithubAuth,
- githubAuthApiRef,
- GitlabAuth,
- gitlabAuthApiRef,
- Auth0Auth,
- auth0AuthApiRef,
-} from '@backstage/core';
-
-// TODO(rugvip): We should likely figure out how to reuse all of these between apps
-// and plugin serve with minimal boilerplate. For example we might move everything
-// to DI, and provide factories for the default implementations, so this just becomes
-// a list of things like `[ErrorApiForwarder.factory, AlertApiDialog.factory]`.
-
-export const alertApiFactory = createApiFactory({
- implements: alertApiRef,
- deps: {},
- factory: (): AlertApi => new AlertApiForwarder(),
-});
-
-export const errorApiFactory = createApiFactory({
- implements: errorApiRef,
- deps: { alertApi: alertApiRef },
- factory: ({ alertApi }) =>
- new ErrorAlerter(alertApi, new ErrorApiForwarder()),
-});
-
-export const oauthRequestApiFactory = createApiFactory({
- implements: oauthRequestApiRef,
- deps: {},
- factory: () => new OAuthRequestManager(),
-});
-
-export const discoveryApiFactory = createApiFactory({
- implements: discoveryApiRef,
- deps: {},
- factory: () =>
- UrlPatternDiscovery.compile(`http://localhost:7000/{{ pluginId }}`),
-});
-
-export const googleAuthApiFactory = createApiFactory({
- implements: googleAuthApiRef,
- deps: { discoveryApi: discoveryApiRef, oauthRequestApi: oauthRequestApiRef },
- factory: ({ discoveryApi, oauthRequestApi }) =>
- GoogleAuth.create({
- discoveryApi,
- oauthRequestApi,
- }),
-});
-
-export const githubAuthApiFactory = createApiFactory({
- implements: githubAuthApiRef,
- deps: { discoveryApi: discoveryApiRef, oauthRequestApi: oauthRequestApiRef },
- factory: ({ discoveryApi, oauthRequestApi }) =>
- GithubAuth.create({
- discoveryApi,
- oauthRequestApi,
- }),
-});
-
-export const gitlabAuthApiFactory = createApiFactory({
- implements: gitlabAuthApiRef,
- deps: { discoveryApi: discoveryApiRef, oauthRequestApi: oauthRequestApiRef },
- factory: ({ discoveryApi, oauthRequestApi }) =>
- GitlabAuth.create({
- discoveryApi,
- oauthRequestApi,
- }),
-});
-
-export const auth0AuthApiFactory = createApiFactory({
- implements: auth0AuthApiRef,
- deps: { discoveryApi: discoveryApiRef, oauthRequestApi: oauthRequestApiRef },
- factory: ({ discoveryApi, oauthRequestApi }) =>
- Auth0Auth.create({
- discoveryApi,
- oauthRequestApi,
- }),
-});
diff --git a/packages/dev-utils/src/devApp/render.test.tsx b/packages/dev-utils/src/devApp/render.test.tsx
new file mode 100644
index 0000000000..fbebf2039b
--- /dev/null
+++ b/packages/dev-utils/src/devApp/render.test.tsx
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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 { render } from '@testing-library/react';
+import { useApi, configApiRef } from '@backstage/core';
+import { createDevApp } from './render';
+
+const anyEnv = (process.env = { ...process.env }) as any;
+
+describe('DevAppBuilder', () => {
+ it('should be able to render a component in a dev app', async () => {
+ anyEnv.APP_CONFIG = [
+ { context: 'test', data: { app: { title: 'Test App' } } },
+ ];
+
+ const MyComponent = () => {
+ const configApi = useApi(configApiRef);
+ return My App: {configApi.getString('app.title')}
;
+ };
+
+ const DevApp = createDevApp()
+ .addRootChild()
+ .build();
+
+ const rendered = render();
+
+ expect(await rendered.findByText('My App: Test App')).toBeInTheDocument();
+ });
+});
diff --git a/packages/dev-utils/src/devApp/render.tsx b/packages/dev-utils/src/devApp/render.tsx
index cde39fdd05..f223fcd4e7 100644
--- a/packages/dev-utils/src/devApp/render.tsx
+++ b/packages/dev-utils/src/devApp/render.tsx
@@ -26,12 +26,10 @@ import {
SidebarSpacer,
ApiFactory,
createPlugin,
- ApiTestRegistry,
- ApiHolder,
AlertDisplay,
OAuthRequestDialog,
+ AnyApiFactory,
} from '@backstage/core';
-import * as defaultApiFactories from './apiFactories';
import SentimentDissatisfiedIcon from '@material-ui/icons/SentimentDissatisfied';
// TODO(rugvip): export proper plugin type from core that isn't the plugin class
@@ -43,7 +41,7 @@ type BackstagePlugin = ReturnType;
*/
class DevAppBuilder {
private readonly plugins = new Array();
- private readonly factories = new Array>();
+ private readonly apis = new Array();
private readonly rootChildren = new Array();
/**
@@ -57,10 +55,10 @@ class DevAppBuilder {
/**
* Register an API factory to add to the app
*/
- registerApiFactory(
- factory: ApiFactory,
+ registerApi(
+ factory: ApiFactory,
): DevAppBuilder {
- this.factories.push(factory);
+ this.apis.push(factory);
return this;
}
@@ -79,7 +77,7 @@ class DevAppBuilder {
*/
build(): ComponentType<{}> {
const app = createApp({
- apis: this.setupApiRegistry(this.factories),
+ apis: this.apis,
plugins: this.plugins,
});
@@ -170,30 +168,6 @@ class DevAppBuilder {
);
}
- // Set up an API registry that merges together default implementations with ones provided through config.
- private setupApiRegistry(
- providedFactories: ApiFactory[],
- ): ApiHolder {
- const providedApis = new Set(
- providedFactories.map(factory => factory.implements),
- );
-
- // Exlude any default API factory that we receive a factory for in the config
- const defaultFactories = Object.values(defaultApiFactories).filter(
- factory => !providedApis.has(factory.implements),
- );
- const allFactories = [...defaultFactories, ...providedFactories];
-
- // Use a test registry with dependency injection so that the consumer
- // can override APIs but still depend on the default implementations.
- const registry = new ApiTestRegistry();
- for (const factory of allFactories) {
- registry.register(factory);
- }
-
- return registry;
- }
-
private findPluginPaths(plugins: BackstagePlugin[]) {
const paths = new Array();
diff --git a/packages/test-utils/src/testUtils/apis/ErrorApi/MockErrorApi.ts b/packages/test-utils/src/testUtils/apis/ErrorApi/MockErrorApi.ts
index 9b22a352e8..7bf50314d0 100644
--- a/packages/test-utils/src/testUtils/apis/ErrorApi/MockErrorApi.ts
+++ b/packages/test-utils/src/testUtils/apis/ErrorApi/MockErrorApi.ts
@@ -14,12 +14,7 @@
* limitations under the License.
*/
-import {
- ErrorApi,
- ErrorContext,
- errorApiRef,
- Observable,
-} from '@backstage/core-api';
+import { ErrorApi, ErrorContext, Observable } from '@backstage/core-api';
type Options = {
collect?: boolean;
@@ -40,12 +35,6 @@ const nullObservable = {
};
export class MockErrorApi implements ErrorApi {
- static factory = {
- implements: errorApiRef,
- deps: {},
- factory: () => new MockErrorApi(),
- };
-
private readonly errors = new Array();
private readonly waiters = new Set();
diff --git a/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts b/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts
index a3a4ef16d6..006b44a49c 100644
--- a/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts
+++ b/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts
@@ -17,7 +17,6 @@
import {
Observable,
StorageApi,
- storageApiRef,
StorageValueChange,
} from '@backstage/core-api';
import ObservableImpl from 'zen-observable';
@@ -25,12 +24,6 @@ import ObservableImpl from 'zen-observable';
export type MockStorageBucket = { [key: string]: any };
export class MockStorageApi implements StorageApi {
- static factory = {
- implements: storageApiRef,
- deps: {},
- factory: () => MockStorageApi.create(),
- };
-
private readonly namespace: string;
private readonly data: MockStorageBucket;
diff --git a/packages/test-utils/src/testUtils/appWrappers.test.tsx b/packages/test-utils/src/testUtils/appWrappers.test.tsx
index 19c02c2158..464c547ecc 100644
--- a/packages/test-utils/src/testUtils/appWrappers.test.tsx
+++ b/packages/test-utils/src/testUtils/appWrappers.test.tsx
@@ -49,9 +49,6 @@ describe('wrapInTestApp', () => {
expect.stringMatching(
/^Warning: An update to %s inside a test was not wrapped in act\(...\)/,
),
- expect.stringMatching(
- /^Warning: An update to %s inside a test was not wrapped in act\(...\)/,
- ),
]);
});
diff --git a/packages/test-utils/src/testUtils/appWrappers.tsx b/packages/test-utils/src/testUtils/appWrappers.tsx
index 2e3a73e346..182de1ef63 100644
--- a/packages/test-utils/src/testUtils/appWrappers.tsx
+++ b/packages/test-utils/src/testUtils/appWrappers.tsx
@@ -24,7 +24,7 @@ import privateExports, {
} from '@backstage/core-api';
import { RenderResult } from '@testing-library/react';
import { renderWithEffects } from '@backstage/test-utils-core';
-import { createMockApiRegistry } from './mockApiRegistry';
+import { mockApis } from './mockApis';
const { PrivateAppImpl } = privateExports;
@@ -58,10 +58,9 @@ export function wrapInTestApp(
options: TestAppOptions = {},
): ReactElement {
const { routeEntries = ['/'] } = options;
- const apis = createMockApiRegistry();
const app = new PrivateAppImpl({
- apis,
+ apis: [],
components: {
NotFoundErrorPage,
BootErrorPage,
@@ -80,6 +79,7 @@ export function wrapInTestApp(
variant: 'light',
},
],
+ defaultApis: mockApis,
});
let Wrapper: ComponentType;
diff --git a/packages/test-utils/src/testUtils/mockApiRegistry.ts b/packages/test-utils/src/testUtils/mockApis.ts
similarity index 70%
rename from packages/test-utils/src/testUtils/mockApiRegistry.ts
rename to packages/test-utils/src/testUtils/mockApis.ts
index 15733ead88..e05a8e6cac 100644
--- a/packages/test-utils/src/testUtils/mockApiRegistry.ts
+++ b/packages/test-utils/src/testUtils/mockApis.ts
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-import { ApiTestRegistry } from '@backstage/core-api';
+import {
+ storageApiRef,
+ errorApiRef,
+ createApiFactory,
+} from '@backstage/core-api';
import { MockErrorApi, MockStorageApi } from './apis';
-export function createMockApiRegistry(): ApiTestRegistry {
- const registry = new ApiTestRegistry();
-
- registry.register(MockErrorApi.factory);
- registry.register(MockStorageApi.factory);
-
- return registry;
-}
+export const mockApis = [
+ createApiFactory(errorApiRef, new MockErrorApi()),
+ createApiFactory(storageApiRef, MockStorageApi.create()),
+];
diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json
index e6c3dde7b6..f4080abc42 100644
--- a/plugins/app-backend/package.json
+++ b/plugins/app-backend/package.json
@@ -4,7 +4,7 @@
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
- "private": true,
+ "private": false,
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts
index 4bfbf2453b..dfe12fd500 100644
--- a/plugins/catalog/src/plugin.ts
+++ b/plugins/catalog/src/plugin.ts
@@ -14,8 +14,21 @@
* limitations under the License.
*/
-import { createPlugin } from '@backstage/core';
+import {
+ createPlugin,
+ createApiFactory,
+ discoveryApiRef,
+} from '@backstage/core';
+import { catalogApiRef } from './api/types';
+import { CatalogClient } from './api/CatalogClient';
export const plugin = createPlugin({
id: 'catalog',
+ apis: [
+ createApiFactory({
+ api: catalogApiRef,
+ deps: { discoveryApi: discoveryApiRef },
+ factory: ({ discoveryApi }) => new CatalogClient({ discoveryApi }),
+ }),
+ ],
});
diff --git a/plugins/circleci/dev/index.tsx b/plugins/circleci/dev/index.tsx
index ed7dd5de9c..4bf67d5cb2 100644
--- a/plugins/circleci/dev/index.tsx
+++ b/plugins/circleci/dev/index.tsx
@@ -20,9 +20,9 @@ import { circleCIApiRef, CircleCIApi } from '../src/api';
createDevApp()
.registerPlugin(plugin)
- .registerApiFactory({
+ .registerApi({
+ api: circleCIApiRef,
deps: {},
factory: () => new CircleCIApi(),
- implements: circleCIApiRef,
})
.render();
diff --git a/plugins/circleci/src/plugin.ts b/plugins/circleci/src/plugin.ts
index 78f92000e3..f966caa383 100644
--- a/plugins/circleci/src/plugin.ts
+++ b/plugins/circleci/src/plugin.ts
@@ -13,8 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { createPlugin } from '@backstage/core';
+
+import { createPlugin, createApiFactory, configApiRef } from '@backstage/core';
+import { circleCIApiRef, CircleCIApi } from './api';
export const plugin = createPlugin({
id: 'circleci',
+ apis: [
+ createApiFactory({
+ api: circleCIApiRef,
+ deps: { configApi: configApiRef },
+ factory: ({ configApi }) =>
+ new CircleCIApi(
+ `${configApi.getString('backend.baseUrl')}/proxy/circleci/api`,
+ ),
+ }),
+ ],
});
diff --git a/plugins/explore/package.json b/plugins/explore/package.json
index 42176c45cf..1a4a44b9cd 100644
--- a/plugins/explore/package.json
+++ b/plugins/explore/package.json
@@ -29,7 +29,8 @@
"classnames": "^2.2.6",
"react": "^16.13.1",
"react-dom": "^16.13.1",
- "react-use": "^15.3.3"
+ "react-use": "^15.3.3",
+ "react-router": "6.0.0-beta.0"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.21",
diff --git a/plugins/explore/src/components/ExplorePluginPage.tsx b/plugins/explore/src/components/ExplorePluginPage.tsx
index 3e073ad322..4365157f62 100644
--- a/plugins/explore/src/components/ExplorePluginPage.tsx
+++ b/plugins/explore/src/components/ExplorePluginPage.tsx
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import React, { FC } from 'react';
+import React from 'react';
import { makeStyles, Typography } from '@material-ui/core';
import {
Content,
@@ -107,7 +107,7 @@ const toolsCards = [
},
];
-const ExplorePluginPage: FC<{}> = () => {
+export const ExplorePluginPage = () => {
const classes = useStyles();
return (
@@ -130,5 +130,3 @@ const ExplorePluginPage: FC<{}> = () => {
);
};
-
-export default ExplorePluginPage;
diff --git a/packages/dev-utils/src/devApp/apiFactories.test.ts b/plugins/explore/src/components/Router.tsx
similarity index 50%
rename from packages/dev-utils/src/devApp/apiFactories.test.ts
rename to plugins/explore/src/components/Router.tsx
index be3ae2cdbe..becb2522d0 100644
--- a/packages/dev-utils/src/devApp/apiFactories.test.ts
+++ b/plugins/explore/src/components/Router.tsx
@@ -14,23 +14,13 @@
* limitations under the License.
*/
-import * as apiFactories from './apiFactories';
-import { ApiTestRegistry, ApiFactory } from '@backstage/core';
+import React from 'react';
+import { Route, Routes } from 'react-router';
+import { ExplorePluginPage } from './ExplorePluginPage';
+import { rootRouteRef } from '../plugin';
-describe('apiFactories', () => {
- it('should be possible to get an instance of each API', () => {
- const registry = new ApiTestRegistry();
- const factories: ApiFactory[] = Object.values(
- apiFactories,
- );
-
- for (const factory of factories) {
- registry.register(factory);
- }
-
- for (const factory of factories) {
- const api = registry.get(factory.implements);
- expect(api).toBeDefined();
- }
- });
-});
+export const Router = () => (
+
+ } />
+
+);
diff --git a/plugins/explore/src/index.ts b/plugins/explore/src/index.ts
index 3a0a0fe2d3..ff7857cacd 100644
--- a/plugins/explore/src/index.ts
+++ b/plugins/explore/src/index.ts
@@ -15,3 +15,4 @@
*/
export { plugin } from './plugin';
+export { Router } from './components/Router';
diff --git a/plugins/explore/src/plugin.ts b/plugins/explore/src/plugin.ts
index 66e48a9b15..75ea892242 100644
--- a/plugins/explore/src/plugin.ts
+++ b/plugins/explore/src/plugin.ts
@@ -14,12 +14,9 @@
* limitations under the License.
*/
-import { createPlugin } from '@backstage/core';
-import ExplorePluginPage from './components/ExplorePluginPage';
+import { createPlugin, createRouteRef } from '@backstage/core';
+export const rootRouteRef = createRouteRef({ path: '', title: 'Explore' });
export const plugin = createPlugin({
id: 'explore',
- register({ router }) {
- router.registerRoute('/explore', ExplorePluginPage);
- },
});
diff --git a/plugins/gcp-projects/src/plugin.ts b/plugins/gcp-projects/src/plugin.ts
index 29c7d74434..41aacde597 100644
--- a/plugins/gcp-projects/src/plugin.ts
+++ b/plugins/gcp-projects/src/plugin.ts
@@ -14,10 +14,15 @@
* limitations under the License.
*/
-import { createPlugin, createRouteRef } from '@backstage/core';
+import {
+ createPlugin,
+ createRouteRef,
+ createApiFactory,
+} from '@backstage/core';
import { ProjectListPage } from './components/ProjectListPage';
import { ProjectDetailsPage } from './components/ProjectDetailsPage';
import { NewProjectPage } from './components/NewProjectPage';
+import { GCPApiRef, GCPClient } from './api';
export const rootRouteRef = createRouteRef({
path: '/gcp-projects',
@@ -34,6 +39,7 @@ export const NewProjectRouteRef = createRouteRef({
export const plugin = createPlugin({
id: 'gcp-projects',
+ apis: [createApiFactory(GCPApiRef, new GCPClient())],
register({ router }) {
router.addRoute(rootRouteRef, ProjectListPage);
router.addRoute(ProjectRouteRef, ProjectDetailsPage);
diff --git a/plugins/github-actions/src/plugin.ts b/plugins/github-actions/src/plugin.ts
index 7e08229d6d..9e3c965d46 100644
--- a/plugins/github-actions/src/plugin.ts
+++ b/plugins/github-actions/src/plugin.ts
@@ -14,7 +14,12 @@
* limitations under the License.
*/
-import { createPlugin, createRouteRef } from '@backstage/core';
+import {
+ createPlugin,
+ createRouteRef,
+ createApiFactory,
+} from '@backstage/core';
+import { githubActionsApiRef, GithubActionsClient } from './api';
// TODO(freben): This is just a demo route for now
export const rootRouteRef = createRouteRef({
@@ -29,4 +34,5 @@ export const buildRouteRef = createRouteRef({
export const plugin = createPlugin({
id: 'github-actions',
+ apis: [createApiFactory(githubActionsApiRef, new GithubActionsClient())],
});
diff --git a/plugins/gitops-profiles/src/plugin.ts b/plugins/gitops-profiles/src/plugin.ts
index af180aff20..45820644f7 100644
--- a/plugins/gitops-profiles/src/plugin.ts
+++ b/plugins/gitops-profiles/src/plugin.ts
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import { createPlugin } from '@backstage/core';
+import { createPlugin, createApiFactory } from '@backstage/core';
import ProfileCatalog from './components/ProfileCatalog';
import ClusterPage from './components/ClusterPage';
import ClusterList from './components/ClusterList';
@@ -23,9 +23,13 @@ import {
gitOpsClusterDetailsRoute,
gitOpsClusterCreateRoute,
} from './routes';
+import { gitOpsApiRef, GitOpsRestApi } from './api';
export const plugin = createPlugin({
id: 'gitops-profiles',
+ apis: [
+ createApiFactory(gitOpsApiRef, new GitOpsRestApi('http://localhost:3008')),
+ ],
register({ router }) {
router.addRoute(gitOpsClusterListRoute, ClusterList);
router.addRoute(gitOpsClusterDetailsRoute, ClusterPage);
diff --git a/plugins/graphiql/dev/index.tsx b/plugins/graphiql/dev/index.tsx
index efcf19a89d..b93995a5dc 100644
--- a/plugins/graphiql/dev/index.tsx
+++ b/plugins/graphiql/dev/index.tsx
@@ -20,8 +20,8 @@ import { plugin, GraphQLEndpoints, graphQlBrowseApiRef } from '../src';
createDevApp()
.registerPlugin(plugin)
- .registerApiFactory({
- implements: graphQlBrowseApiRef,
+ .registerApi({
+ api: graphQlBrowseApiRef,
deps: {
errorApi: errorApiRef,
githubAuthApi: githubAuthApiRef,
diff --git a/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.tsx b/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.tsx
index a16fdf3ee6..7eb91b59d8 100644
--- a/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.tsx
+++ b/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.tsx
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import React, { FC } from 'react';
+import React from 'react';
import {
Content,
Header,
@@ -30,7 +30,7 @@ import { graphQlBrowseApiRef } from '../../lib/api';
import { GraphiQLBrowser } from '../GraphiQLBrowser';
import { Typography } from '@material-ui/core';
-export const GraphiQLPage: FC<{}> = () => {
+export const GraphiQLPage = () => {
const graphQlBrowseApi = useApi(graphQlBrowseApiRef);
const endpoints = useAsync(() => graphQlBrowseApi.getEndpoints());
diff --git a/plugins/graphiql/src/index.ts b/plugins/graphiql/src/index.ts
index e7614aba81..50698cdb4c 100644
--- a/plugins/graphiql/src/index.ts
+++ b/plugins/graphiql/src/index.ts
@@ -15,5 +15,6 @@
*/
export { plugin } from './plugin';
+export { GraphiQLPage as Router } from './components';
export * from './lib/api';
export * from './route-refs';
diff --git a/plugins/graphiql/src/plugin.ts b/plugins/graphiql/src/plugin.ts
index f118faf871..28d27802d0 100644
--- a/plugins/graphiql/src/plugin.ts
+++ b/plugins/graphiql/src/plugin.ts
@@ -14,13 +14,22 @@
* limitations under the License.
*/
-import { createPlugin } from '@backstage/core';
-import { GraphiQLPage } from './components';
-import { graphiQLRouteRef } from './route-refs';
+import { createPlugin, createApiFactory } from '@backstage/core';
+import { graphQlBrowseApiRef, GraphQLEndpoints } from './lib/api';
export const plugin = createPlugin({
id: 'graphiql',
- register({ router }) {
- router.addRoute(graphiQLRouteRef, GraphiQLPage);
- },
+ apis: [
+ // GitLab is used as an example endpoint, but most plug
+ createApiFactory(
+ graphQlBrowseApiRef,
+ GraphQLEndpoints.from([
+ GraphQLEndpoints.create({
+ id: 'gitlab',
+ title: 'GitLab',
+ url: 'https://gitlab.com/api/graphql',
+ }),
+ ]),
+ ),
+ ],
});
diff --git a/plugins/jenkins/src/plugin.ts b/plugins/jenkins/src/plugin.ts
index 979b0a31cf..4d1af322c4 100644
--- a/plugins/jenkins/src/plugin.ts
+++ b/plugins/jenkins/src/plugin.ts
@@ -14,8 +14,14 @@
* limitations under the License.
*/
-import { createPlugin, createRouteRef } from '@backstage/core';
+import {
+ createPlugin,
+ createRouteRef,
+ createApiFactory,
+ configApiRef,
+} from '@backstage/core';
import { DetailedViewPage } from './pages/BuildWithStepsPage';
+import { jenkinsApiRef, JenkinsApi } from './api';
export const buildRouteRef = createRouteRef({
path: '/jenkins/job',
@@ -24,6 +30,16 @@ export const buildRouteRef = createRouteRef({
export const plugin = createPlugin({
id: 'jenkins',
+ apis: [
+ createApiFactory({
+ api: jenkinsApiRef,
+ deps: { configApi: configApiRef },
+ factory: ({ configApi }) =>
+ new JenkinsApi(
+ `${configApi.getString('backend.baseUrl')}/proxy/jenkins/api`,
+ ),
+ }),
+ ],
register({ router }) {
router.addRoute(buildRouteRef, DetailedViewPage);
},
diff --git a/plugins/lighthouse/dev/index.tsx b/plugins/lighthouse/dev/index.tsx
index 6496fb658a..bf761965f1 100644
--- a/plugins/lighthouse/dev/index.tsx
+++ b/plugins/lighthouse/dev/index.tsx
@@ -20,8 +20,8 @@ import { lighthouseApiRef, LighthouseRestApi } from '../src';
createDevApp()
.registerPlugin(plugin)
- .registerApiFactory({
- implements: lighthouseApiRef,
+ .registerApi({
+ api: lighthouseApiRef,
deps: {},
factory: () => new LighthouseRestApi('http://localhost:3003'),
})
diff --git a/plugins/lighthouse/src/plugin.ts b/plugins/lighthouse/src/plugin.ts
index f8da8d84ed..677b5f682a 100644
--- a/plugins/lighthouse/src/plugin.ts
+++ b/plugins/lighthouse/src/plugin.ts
@@ -14,13 +14,21 @@
* limitations under the License.
*/
-import { createPlugin } from '@backstage/core';
+import { createPlugin, createApiFactory, configApiRef } from '@backstage/core';
import AuditList from './components/AuditList';
import AuditView from './components/AuditView';
import CreateAudit from './components/CreateAudit';
+import { lighthouseApiRef, LighthouseRestApi } from './api';
export const plugin = createPlugin({
id: 'lighthouse',
+ apis: [
+ createApiFactory({
+ api: lighthouseApiRef,
+ deps: { configApi: configApiRef },
+ factory: ({ configApi }) => LighthouseRestApi.fromConfig(configApi),
+ }),
+ ],
register({ router }) {
router.registerRoute('/lighthouse', AuditList);
router.registerRoute('/lighthouse/audit/:id', AuditView);
diff --git a/plugins/rollbar/src/plugin.ts b/plugins/rollbar/src/plugin.ts
index 2cf464a8f6..c3ca6173ff 100644
--- a/plugins/rollbar/src/plugin.ts
+++ b/plugins/rollbar/src/plugin.ts
@@ -14,13 +14,26 @@
* limitations under the License.
*/
-import { createPlugin } from '@backstage/core';
+import {
+ createPlugin,
+ createApiFactory,
+ discoveryApiRef,
+} from '@backstage/core';
import { rootRouteRef, entityRouteRef } from './routes';
import { RollbarHome } from './components/RollbarHome/RollbarHome';
import { RollbarProjectPage } from './components/RollbarProjectPage/RollbarProjectPage';
+import { rollbarApiRef } from './api/RollbarApi';
+import { RollbarClient } from './api/RollbarClient';
export const plugin = createPlugin({
id: 'rollbar',
+ apis: [
+ createApiFactory({
+ api: rollbarApiRef,
+ deps: { discoveryApi: discoveryApiRef },
+ factory: ({ discoveryApi }) => new RollbarClient({ discoveryApi }),
+ }),
+ ],
register({ router }) {
router.addRoute(rootRouteRef, RollbarHome);
router.addRoute(entityRouteRef, RollbarProjectPage);
diff --git a/plugins/scaffolder/src/plugin.ts b/plugins/scaffolder/src/plugin.ts
index 8c4ed5badd..41f7a03249 100644
--- a/plugins/scaffolder/src/plugin.ts
+++ b/plugins/scaffolder/src/plugin.ts
@@ -14,13 +14,25 @@
* limitations under the License.
*/
-import { createPlugin } from '@backstage/core';
+import {
+ createPlugin,
+ createApiFactory,
+ discoveryApiRef,
+} from '@backstage/core';
import { ScaffolderPage } from './components/ScaffolderPage';
import { TemplatePage } from './components/TemplatePage';
import { rootRoute, templateRoute } from './routes';
+import { scaffolderApiRef, ScaffolderApi } from './api';
export const plugin = createPlugin({
id: 'scaffolder',
+ apis: [
+ createApiFactory({
+ api: scaffolderApiRef,
+ deps: { discoveryApi: discoveryApiRef },
+ factory: ({ discoveryApi }) => new ScaffolderApi({ discoveryApi }),
+ }),
+ ],
register({ router }) {
router.addRoute(rootRoute, ScaffolderPage);
router.addRoute(templateRoute, TemplatePage);
diff --git a/plugins/tech-radar/README.md b/plugins/tech-radar/README.md
index fb9d220b8c..cbe4dd22eb 100644
--- a/plugins/tech-radar/README.md
+++ b/plugins/tech-radar/README.md
@@ -29,71 +29,34 @@ For either simple or advanced installations, you'll need to add the dependency u
yarn add @backstage/plugin-tech-radar
```
-### Simple Configuration
+### Configuration
-In your `apis.ts` set up the simple "out of the box" implementation for Tech Radar:
-
-```ts
-import { ApiHolder, ApiRegistry } from '@backstage/core';
-import {
- techRadarApiRef,
- TechRadar,
-} from '@backstage/plugin-tech-radar';
-
-const builder = ApiRegistry.builder();
-
-builder.add(techRadarApiRef, new TechRadar({
- width: 1400,
- height: 800
-));
-
-export default builder.build() as ApiHolder;
-```
-
-Congrats, you're done! We'll just load it with [example data](src/sampleData.ts) to get you started. Just go to to see it live in action.
-
-And if you'd like to configure it more, such as providing it with your own data, see the `TechRadarApi` TypeScript interface below for the options:
-
-```ts
-export interface TechRadarComponentProps {
- width: number;
- height: number;
- getData?: () => Promise;
- svgProps?: object;
-}
-
-export interface TechRadarApi extends TechRadarComponentProps {
- title?: string;
- subtitle?: string;
-}
-```
-
-You can see the API directly over at [src/api.ts](./src/api.ts).
-
-### Advanced Configuration
-
-This way won't expose an `/tech-radar` path. Instead, you'll need to create your own Backstage plugin and use the Tech Radar as any other React UI component.
-
-In your Backstage app, run the following command:
-
-```sh
-yarn create-plugin
-```
-
-In your plugin, in any React component you'd like to import the Tech Radar, do the following:
+Modify your app routes to include the Router component exported from the tech radar, for example:
```tsx
-import { TechRadarComponent } from '@backstage/plugin-tech-radar';
+import { Router as TechRadarRouter } from '@backstage/plugin-tech-radar';
-function MyCustomRadar() {
- return ;
-}
+// Inside App component
+
+ {/* other routes ... */}
+ }
+ />
+ {/* other routes ... */}
+;
```
-If you'd like to configure it more, see the `TechRadarComponentProps` TypeScript interface for options:
+If you'd like to configure it more, see the `TechRadarPageProps` and `TechRadarComponentProps` types for options:
```ts
-export interface TechRadarComponentProps {
+export type TechRadarPageProps = TechRadarComponentProps & {
+ title?: string;
+ subtitle?: string;
+ pageTitle?: string;
+};
+
+export interface TechRadarPageProps {
width: number;
height: number;
getData?: () => Promise;
@@ -101,8 +64,6 @@ export interface TechRadarComponentProps {
}
```
-You can see the API directly over at [src/api.ts](./src/api.ts).
-
## Frequently Asked Questions
### Who created the Tech Radar?
@@ -111,7 +72,7 @@ You can see the API directly over at [src/api.ts](./src/api.ts).
### How do I load in my own data?
-It's simple. In both the Simple (Backstage plugin) and Advanced (React component) configurations, you can pass through a `getData` prop which expects a `Promise` signature. See more in [src/api.ts](./src/api.ts).
+It's simple, you can pass through a `getData` prop which expects a `Promise` signature.
Here's an example:
@@ -133,42 +94,21 @@ const getHardCodedData = () =>
],
});
-// Simple
-builder.add(techRadarApiRef, new TechRadar({
- width: 1400,
- height: 800,
- getData: getHardCodedData
-));
-
-// Advanced
-
+;
```
### How do I write tests?
You can use the `svgProps` option to pass custom React props to the `