diff --git a/.changeset/famous-swans-smile.md b/.changeset/famous-swans-smile.md
new file mode 100644
index 000000000..1a75f5f7d
--- /dev/null
+++ b/.changeset/famous-swans-smile.md
@@ -0,0 +1,5 @@
+---
+'@roadiehq/backstage-plugin-argo-cd': minor
+---
+
+Adds support for Backstage's new frontend system, available via the `/alpha` sub-path export.
diff --git a/plugins/frontend/backstage-plugin-argo-cd/package.json b/plugins/frontend/backstage-plugin-argo-cd/package.json
index 8d8ae3848..5fd6cd6c4 100644
--- a/plugins/frontend/backstage-plugin-argo-cd/package.json
+++ b/plugins/frontend/backstage-plugin-argo-cd/package.json
@@ -23,9 +23,25 @@
"role": "frontend-plugin",
"pluginId": "backstage-plugin-argo-cd",
"pluginPackages": [
- "@roadiehq/backstage-plugin-argo-cd"
+ "@roadiehq/backstage-plugin-argo-cd",
+ "@roadiehq/backstage-plugin-argo-cd-backend"
]
},
+ "exports": {
+ ".": "./src/index.ts",
+ "./alpha": "./src/alpha.ts",
+ "./package.json": "./package.json"
+ },
+ "typesVersions": {
+ "*": {
+ "alpha": [
+ "src/alpha.ts"
+ ],
+ "package.json": [
+ "package.json"
+ ]
+ }
+ },
"sideEffects": false,
"scripts": {
"build": "backstage-cli package build",
@@ -39,8 +55,10 @@
},
"dependencies": {
"@backstage/catalog-model": "^1.6.0",
+ "@backstage/core-compat-api": "^0.2.8",
"@backstage/core-components": "^0.14.10",
"@backstage/core-plugin-api": "^1.9.3",
+ "@backstage/frontend-plugin-api": "^0.7.0",
"@backstage/plugin-catalog-react": "^1.12.3",
"@backstage/theme": "^0.5.6",
"@material-ui/core": "^4.12.2",
@@ -71,6 +89,7 @@
"@rollup/plugin-node-resolve": "^15.0.1",
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^14.0.0",
+ "@backstage/frontend-test-utils": "^0.1.12",
"esbuild": "^0.11.13",
"jest-environment-jsdom": "^29.2.1",
"msw": "^1.0.1",
diff --git a/plugins/frontend/backstage-plugin-argo-cd/src/alpha.ts b/plugins/frontend/backstage-plugin-argo-cd/src/alpha.ts
new file mode 100644
index 000000000..de7705b2d
--- /dev/null
+++ b/plugins/frontend/backstage-plugin-argo-cd/src/alpha.ts
@@ -0,0 +1,2 @@
+export * from './alpha/index';
+export { default } from './alpha/index';
diff --git a/plugins/frontend/backstage-plugin-argo-cd/src/alpha/apis.tsx b/plugins/frontend/backstage-plugin-argo-cd/src/alpha/apis.tsx
new file mode 100644
index 000000000..9490f30f7
--- /dev/null
+++ b/plugins/frontend/backstage-plugin-argo-cd/src/alpha/apis.tsx
@@ -0,0 +1,33 @@
+import {
+ createApiExtension,
+ createApiFactory,
+ discoveryApiRef,
+} from '@backstage/frontend-plugin-api';
+import { ArgoCDApiClient, argoCDApiRef } from '../api';
+import { configApiRef, identityApiRef } from '@backstage/core-plugin-api';
+
+/**
+ * @alpha
+ */
+export const argoCDApiExtension = createApiExtension({
+ factory: createApiFactory({
+ api: argoCDApiRef,
+ deps: {
+ discoveryApi: discoveryApiRef,
+ identityApi: identityApiRef,
+ configApi: configApiRef,
+ },
+ factory: ({ discoveryApi, identityApi, configApi }) =>
+ new ArgoCDApiClient({
+ discoveryApi,
+ identityApi,
+ backendBaseUrl: configApi.getString('backend.baseUrl'),
+ useNamespacedApps: Boolean(
+ configApi.getOptionalBoolean('argocd.namespacedApps'),
+ ),
+ searchInstances: Boolean(
+ configApi.getOptionalConfigArray('argocd.appLocatorMethods')?.length,
+ ),
+ }),
+ }),
+});
diff --git a/plugins/frontend/backstage-plugin-argo-cd/src/alpha/entityCards.test.tsx b/plugins/frontend/backstage-plugin-argo-cd/src/alpha/entityCards.test.tsx
new file mode 100644
index 000000000..cf00b92f1
--- /dev/null
+++ b/plugins/frontend/backstage-plugin-argo-cd/src/alpha/entityCards.test.tsx
@@ -0,0 +1,47 @@
+import { screen, waitFor } from '@testing-library/react';
+import {
+ createExtensionTester,
+ TestApiProvider,
+ renderInTestApp,
+} from '@backstage/frontend-test-utils';
+import {
+ entityArgoCDOverviewCard,
+ entityArgoCDHistoryCard,
+} from './entityCards';
+import { ArgoCDApiClient, argoCDApiRef } from '../api';
+import { getEntityStub } from '../mocks/mocks';
+import React from 'react';
+import { EntityProvider } from '@backstage/plugin-catalog-react';
+
+describe('Entity cards extensions', () => {
+ const mockArgocdApi = {} as unknown as ArgoCDApiClient;
+ const mockedEntity = getEntityStub;
+
+ it('should render the overview card on an entity', async () => {
+ renderInTestApp(
+
+
+ {createExtensionTester(entityArgoCDOverviewCard).reactElement()}
+
+ ,
+ );
+
+ await waitFor(() => {
+ expect(screen.getByText('ArgoCD overview')).toBeInTheDocument();
+ });
+ });
+
+ it('should render the history card on an entity', async () => {
+ renderInTestApp(
+
+
+ {createExtensionTester(entityArgoCDHistoryCard).reactElement()}
+
+ ,
+ );
+
+ await waitFor(() => {
+ expect(screen.getByText('ArgoCD history')).toBeInTheDocument();
+ });
+ });
+});
diff --git a/plugins/frontend/backstage-plugin-argo-cd/src/alpha/entityCards.tsx b/plugins/frontend/backstage-plugin-argo-cd/src/alpha/entityCards.tsx
new file mode 100644
index 000000000..91cfaac1a
--- /dev/null
+++ b/plugins/frontend/backstage-plugin-argo-cd/src/alpha/entityCards.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { EntityCardBlueprint } from '@backstage/plugin-catalog-react/alpha';
+
+/**
+ * @alpha
+ */
+export const entityArgoCDOverviewCard = EntityCardBlueprint.make({
+ name: 'overviewCard',
+ params: {
+ filter: 'kind:component',
+ loader: () =>
+ import('../components/ArgoCDDetailsCard').then(m => (
+
+ )),
+ },
+});
+
+/**
+ * @alpha
+ */
+export const entityArgoCDHistoryCard: any = EntityCardBlueprint.make({
+ name: 'historyCard',
+ params: {
+ filter: 'kind:component',
+ loader: () =>
+ import('../components/ArgoCDHistoryCard').then(m => (
+
+ )),
+ },
+});
diff --git a/plugins/frontend/backstage-plugin-argo-cd/src/alpha/index.ts b/plugins/frontend/backstage-plugin-argo-cd/src/alpha/index.ts
new file mode 100644
index 000000000..b68aea57f
--- /dev/null
+++ b/plugins/frontend/backstage-plugin-argo-cd/src/alpha/index.ts
@@ -0,0 +1 @@
+export { default } from './plugin';
diff --git a/plugins/frontend/backstage-plugin-argo-cd/src/alpha/pages.tsx b/plugins/frontend/backstage-plugin-argo-cd/src/alpha/pages.tsx
new file mode 100644
index 000000000..e87f6060c
--- /dev/null
+++ b/plugins/frontend/backstage-plugin-argo-cd/src/alpha/pages.tsx
@@ -0,0 +1,22 @@
+import React from 'react'; // Add this line to import React
+
+import { createPageExtension } from '@backstage/frontend-plugin-api';
+import {
+ compatWrapper,
+ convertLegacyRouteRef,
+} from '@backstage/core-compat-api';
+import { entityContentRouteRef } from '../plugin';
+
+/**
+ * @alpha
+ */
+export const argoCdPage = createPageExtension({
+ name: 'ArgoCdPage',
+ namespace: 'argocd',
+ defaultPath: '/',
+ // you can reuse the existing routeRef
+ // by wrapping into the convertLegacyRouteRef.
+ routeRef: convertLegacyRouteRef(entityContentRouteRef),
+ // these inputs usually match the props required by the component.
+ loader: () => import('../Router').then(m => compatWrapper()),
+});
diff --git a/plugins/frontend/backstage-plugin-argo-cd/src/alpha/plugin.tsx b/plugins/frontend/backstage-plugin-argo-cd/src/alpha/plugin.tsx
new file mode 100644
index 000000000..f1cb46706
--- /dev/null
+++ b/plugins/frontend/backstage-plugin-argo-cd/src/alpha/plugin.tsx
@@ -0,0 +1,26 @@
+import { convertLegacyRouteRefs } from '@backstage/core-compat-api';
+import { createPlugin, BackstagePlugin } from '@backstage/frontend-plugin-api';
+import {
+ entityArgoCDOverviewCard,
+ entityArgoCDHistoryCard,
+} from './entityCards';
+import { argoCDApiExtension } from './apis';
+
+import { entityContentRouteRef } from '../plugin';
+import { argoCdPage } from './pages';
+
+/**
+ * @alpha
+ */
+const plugin: BackstagePlugin = createPlugin({
+ id: 'argocd',
+ extensions: [
+ argoCdPage,
+ entityArgoCDOverviewCard,
+ entityArgoCDHistoryCard,
+ argoCDApiExtension,
+ ],
+ routes: convertLegacyRouteRefs({ argocd: entityContentRouteRef }),
+});
+
+export default plugin;
diff --git a/plugins/frontend/backstage-plugin-argo-cd/src/components/ArgoCDDetailsCard.tsx b/plugins/frontend/backstage-plugin-argo-cd/src/components/ArgoCDDetailsCard.tsx
index 3d0db4269..31b344eb2 100644
--- a/plugins/frontend/backstage-plugin-argo-cd/src/components/ArgoCDDetailsCard.tsx
+++ b/plugins/frontend/backstage-plugin-argo-cd/src/components/ArgoCDDetailsCard.tsx
@@ -32,7 +32,6 @@ import {
import {
ErrorBoundary,
InfoCard,
- MissingAnnotationEmptyState,
Table,
TableColumn,
} from '@backstage/core-components';
@@ -41,7 +40,10 @@ import { isArgocdAvailable } from '../conditions';
import { ArgoCDAppDetails, ArgoCDAppList } from '../types';
import { useAppDetails } from './useAppDetails';
import SyncIcon from '@material-ui/icons/Sync';
-import { useEntity } from '@backstage/plugin-catalog-react';
+import {
+ MissingAnnotationEmptyState,
+ useEntity,
+} from '@backstage/plugin-catalog-react';
import { DetailsDrawerComponent as detailsDrawerComponent } from './DetailsDrawer';
interface Condition {
diff --git a/plugins/frontend/backstage-plugin-argo-cd/src/components/ArgoCDHistoryCard.tsx b/plugins/frontend/backstage-plugin-argo-cd/src/components/ArgoCDHistoryCard.tsx
index f819e1843..a484d109b 100644
--- a/plugins/frontend/backstage-plugin-argo-cd/src/components/ArgoCDHistoryCard.tsx
+++ b/plugins/frontend/backstage-plugin-argo-cd/src/components/ArgoCDHistoryCard.tsx
@@ -15,13 +15,12 @@
*/
import { Entity } from '@backstage/catalog-model';
+import { ErrorBoundary, InfoCard } from '@backstage/core-components';
+import { configApiRef, useApi } from '@backstage/core-plugin-api';
import {
- ErrorBoundary,
- InfoCard,
MissingAnnotationEmptyState,
-} from '@backstage/core-components';
-import { configApiRef, useApi } from '@backstage/core-plugin-api';
-import { useEntity } from '@backstage/plugin-catalog-react';
+ useEntity,
+} from '@backstage/plugin-catalog-react';
import { LinearProgress } from '@material-ui/core';
import React, { useEffect, useState } from 'react';
import { isArgocdAvailable } from '../conditions';
diff --git a/yarn.lock b/yarn.lock
index 687997bc0..41ab51f19 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -30572,16 +30572,7 @@ string-length@^4.0.1:
char-regex "^1.0.2"
strip-ansi "^6.0.0"
-"string-width-cjs@npm:string-width@^4.2.0":
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
- integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.1"
-
-"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -30655,7 +30646,7 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -30669,13 +30660,6 @@ strip-ansi@5.2.0:
dependencies:
ansi-regex "^4.1.0"
-strip-ansi@^6.0.0, strip-ansi@^6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
- integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
- dependencies:
- ansi-regex "^5.0.1"
-
strip-ansi@^7.0.1:
version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@@ -32801,7 +32785,7 @@ wordwrap@^1.0.0:
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
-"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -32819,15 +32803,6 @@ wrap-ansi@^6.0.1, wrap-ansi@^6.2.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
-wrap-ansi@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
- integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
- dependencies:
- ansi-styles "^4.0.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
-
wrap-ansi@^8.0.1, wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"