diff --git a/.changeset/light-spiders-jog.md b/.changeset/light-spiders-jog.md new file mode 100755 index 000000000..4bb91ba5f --- /dev/null +++ b/.changeset/light-spiders-jog.md @@ -0,0 +1,5 @@ +--- +'@roadiehq/backstage-plugin-argo-cd': patch +--- + +added sorting and pagination to argocd history diff --git a/plugins/frontend/backstage-plugin-argo-cd/dev/index.tsx b/plugins/frontend/backstage-plugin-argo-cd/dev/index.tsx index 8a13acf66..e69c178a8 100644 --- a/plugins/frontend/backstage-plugin-argo-cd/dev/index.tsx +++ b/plugins/frontend/backstage-plugin-argo-cd/dev/index.tsx @@ -1,4 +1,286 @@ +import React from 'react'; + import { createDevApp } from '@backstage/dev-utils'; -import { argocdPlugin } from '../src/plugin'; +import { TestApiProvider } from '@backstage/test-utils'; +import { Entity } from '@backstage/catalog-model'; +import { EntityProvider } from '@backstage/plugin-catalog-react'; +import { ArgoCDApi, argoCDApiRef } from '../src/api'; +import { ConfigReader } from '@backstage/core-app-api'; +import { configApiRef } from '@backstage/core-plugin-api'; +import { EntityArgoCDHistoryCard, argocdPlugin } from '../src/plugin'; + +const mockEntity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'backstage', + description: 'backstage.io', + annotations: { + 'argocd/app-name': 'guestbook', + }, + }, + spec: { + lifecycle: 'production', + type: 'service', + owner: 'user:guest', + }, +}; + +export class MockArgoCDApiClient implements ArgoCDApi { + readonly components; + + constructor(components: any) { + this.components = components; + } + + async listApps(_options: any): Promise { + return { items: [{}] }; + } + + async getRevisionDetails(_options: any): Promise { + return { + author: 'Suzane', + date: '2023-10-10T05:28:38Z', + message: 'successful', + }; + } + + async getAppDetails(_options: any): Promise { + return this.components; + } + async getAppListDetails(_options: any): Promise { + return { + url: 'https://github.com/argoproj/argocd-example-apps.git', + appSelector: 'hkhk', + instance: 'hhiyi', + }; + } + + async serviceLocatorUrl(options: { appName?: string }): Promise { + return [ + { + name: 'argocdinstance', + url: 'https://github.com/argoproj/argocd-example-apps.git', + appName: options.appName, + }, + ]; + } +} + +const mockArgoCDClient = { + metadata: { + name: 'guestbook', + namespace: 'argocd', + uid: '3c948668-090a-4cf7-a9a6-8a944abf8676', + resourceVersion: '1150262', + generation: 696, + creationTimestamp: '2023-10-10T05:28:13Z', + managedFields: [ + { + manager: 'argocd-server', + operation: 'Update', + apiVersion: 'argoproj.io/v1alpha1', + time: '2023-10-10T17:37:31Z', + }, + { + manager: 'argocd-application-controller', + operation: 'Update', + apiVersion: 'argoproj.io/v1alpha1', + time: '2023-10-12T12:48:14Z', + }, + ], + }, + spec: { + source: { + repoURL: 'https://github.com/argoproj/argocd-example-apps.git', + path: 'kustomize-guestbook', + targetRevision: 'HEAD', + }, + destination: { + server: 'https://kubernetes.default.svc', + namespace: 'default', + }, + project: 'default', + }, + status: { + resources: [ + { + version: 'v1', + kind: 'Service', + namespace: 'default', + name: 'kustomize-guestbook-ui', + status: 'Synced', + health: { + status: 'Healthy', + }, + }, + { + group: 'apps', + version: 'v1', + kind: 'Deployment', + namespace: 'default', + name: 'kustomize-guestbook-ui', + status: 'Synced', + health: { + status: 'Healthy', + }, + }, + ], + sync: { + status: 'Synced', + comparedTo: { + source: { + repoURL: 'https://github.com/argoproj/argocd-example-apps.git', + path: 'kustomize-guestbook', + targetRevision: 'HEAD', + }, + destination: { + server: 'https://kubernetes.default.svc', + namespace: 'default', + }, + }, + revision: '53e28ff20cc530b9ada2173fbbd64d48338583ba', + }, + health: { + status: 'Healthy', + }, + history: [ + { + revision: '53e28ff20cc530b9ada2173fbbd64d48338583ba', + deployedAt: '2023-10-10T05:28:38Z', + id: 0, + source: { + repoURL: 'https://github.com/argoproj/argocd-example-apps.git', + path: 'kustomize-guestbook', + targetRevision: 'HEAD', + }, + deployStartedAt: '2023-10-10T05:28:38Z', + }, + { + revision: '53e28ff20cc530b9ada2173fbbd6jd48338583bx', + deployedAt: '2023-10-10T17:37:31Z', + id: 1, + source: { + repoURL: 'https://github.com/argoproj/argocd-example-apps.git', + path: 'kustomize-guestbook', + targetRevision: 'HEAD', + }, + deployStartedAt: '2023-10-10T17:37:31Z', + }, + { + revision: '53e28ff20cc530b9ada2173fbbd64d48338589bx', + deployedAt: '2023-10-09T17:37:31Z', + id: 2, + source: { + repoURL: 'https://github.com/argoproj/argocd-example-apps.git', + path: 'kustomize-guestbook', + targetRevision: 'HEAD', + }, + deployStartedAt: '2023-10-10T17:37:31Z', + }, + ], + reconciledAt: '2023-10-12T12:48:14Z', + operationState: { + operation: { + sync: { + revision: '53e28ff20cc530b9ada2173fbbd64d48338583ba', + syncStrategy: { + hook: {}, + }, + syncOptions: ['CreateNamespace=true'], + }, + initiatedBy: { + username: 'admin', + }, + retry: {}, + }, + phase: 'Succeeded', + message: 'successfully synced (all tasks run)', + syncResult: { + resources: [ + { + group: '', + version: 'v1', + kind: 'Service', + namespace: 'default', + name: 'kustomize-guestbook-ui', + status: 'Synced', + message: 'service/kustomize-guestbook-ui unchanged', + hookPhase: 'Running', + syncPhase: 'Sync', + }, + { + group: 'apps', + version: 'v1', + kind: 'Deployment', + namespace: 'default', + name: 'kustomize-guestbook-ui', + status: 'Synced', + message: 'deployment.apps/kustomize-guestbook-ui unchanged', + hookPhase: 'Running', + syncPhase: 'Sync', + }, + ], + revision: '53e28ff20cc530b9ada2173fbbd64d48338583ba', + source: { + repoURL: 'https://github.com/argoproj/argocd-example-apps.git', + path: 'kustomize-guestbook', + targetRevision: 'HEAD', + }, + }, + startedAt: '2023-10-10T17:37:31Z', + finishedAt: '2023-10-10T17:37:31Z', + }, + sourceType: 'Kustomize', + summary: { + images: ['gcr.io/heptio-images/ks-guestbook-demo:0.1'], + }, + controllerNamespace: 'argocd', + }, +}; -createDevApp().registerPlugin(argocdPlugin).render(); +createDevApp() + .registerPlugin(argocdPlugin) + .addPage({ + element: ( + + + + + + ), + title: 'ArgoCD history', + path: '/argocd', + }) + .render(); 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 6696e6420..873e47f1d 100644 --- a/plugins/frontend/backstage-plugin-argo-cd/src/components/ArgoCDHistoryCard.tsx +++ b/plugins/frontend/backstage-plugin-argo-cd/src/components/ArgoCDHistoryCard.tsx @@ -83,11 +83,11 @@ const HistoryTable = ({ ) : ( row.app ), - highlight: true, }, { title: 'Deploy Details', - sorting: false, + defaultSort: 'desc', + field: 'deployedAt', render: (row: any): React.ReactNode => ( @@ -117,17 +117,17 @@ const HistoryTable = ({ }, { title: 'Author', - sorting: false, + field: 'revision.author', render: (row: any): React.ReactNode =>
{row.revision?.author}
, }, { title: 'Message', - sorting: false, + field: 'revision.message', render: (row: any): React.ReactNode =>
{row.revision?.message}
, }, { title: 'Revision', - sorting: false, + field: 'revision.revisionID', render: (row: any): React.ReactNode => (
{row.revision?.revisionID}
), @@ -137,6 +137,7 @@ const HistoryTable = ({ if (supportsMultipleArgoInstances) { columns.splice(1, 0, { title: 'Instance', + field: 'instance', render: (row: any): React.ReactNode => row.metadata?.instance?.name ? row.metadata?.instance?.name @@ -148,7 +149,7 @@ const HistoryTable = ({ { const promises: Promise[] | undefined = appDetails.status?.history?.map(async (historyRecord: any) => { - const revisionID = historyRecord.revision; + let revisionID = ''; + if (historyRecord.revision.hasOwnProperty('revisionID')) { + revisionID = historyRecord.revision.revisionID; + } else { + revisionID = historyRecord.revision; + } if (historyRecord.source?.chart !== undefined) { historyRecord.revision = { revisionID: revisionID }; return; @@ -71,7 +76,7 @@ export const useAppDetails = ({ appDetails?.status?.history && appDetails?.status?.history.length > 0 ) { - return getRevisionHistroyDetails(appDetails, appName); + return getRevisionHistoryDetails(appDetails, appName); } return appDetails; @@ -105,7 +110,7 @@ export const useAppDetails = ({ apiOut?.status?.history && apiOut?.status?.history.length > 0 ) { - return getRevisionHistroyDetails(apiOut, appName, instance.name); + return getRevisionHistoryDetails(apiOut, appName, instance.name); } return apiOut; }); @@ -133,7 +138,7 @@ export const useAppDetails = ({ const getRevisionHistroyPromises = items.items.map( async (item: any) => { if (item?.status.history && item?.status.history.length > 0) { - return getRevisionHistroyDetails( + return getRevisionHistoryDetails( item, item.metadata.name, item.metadata.instance.name, @@ -155,7 +160,7 @@ export const useAppDetails = ({ const getRevisionHistroyPromises = apps.items.map( async (item: any) => { if (item?.status.history && item?.status.history.length > 0) { - return getRevisionHistroyDetails(item, item.metadata.name); + return getRevisionHistoryDetails(item, item.metadata.name); } return item; },