Skip to content

Commit 3c8298c

Browse files
RemiBonnetCopilot
andauthored
feat(argocd): add manifest view (#2684)
* feat(argocd): add manifest view * refactor(argocd): streamline ArgoCD manifest handling and improve test coverage * feat(argocd): implement target state switching in ArgoCD manifest view * fix: update input class to use rounded-md for consistency across modal snapshots * feat(argocd): add loading state to ArgoCD manifest view with spinner * refactor(argocd): enhance resource selection logic and improve segmented control styling * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * feat(argocd): implement diff view for ArgoCD manifest comparison * refactor(argocd): update ArgoCD manifest toggle button for improved accessibility and interaction * refactor(argocd): integrate ErrorBoundary and remove serviceId prop from ArgoCdManifest for improved error handling and cleaner API * fix(argocd): ensure serviceId is safely destructured from useParams to prevent potential runtime errors * refactor(argocd): simplify isArgoCd function and enhance service tab logic for better readability --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent e332a45 commit 3c8298c

24 files changed

Lines changed: 541 additions & 125 deletions

File tree

apps/console/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/overview/route.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
useDeploymentStatus,
1818
useEnvironment,
1919
} from '@qovery/domains/environments/feature'
20-
import { isEditableService } from '@qovery/domains/services/data-access'
20+
import { isArgoCd, isEditableService } from '@qovery/domains/services/data-access'
2121
import { ArgoCdServiceList, useServices } from '@qovery/domains/services/feature'
2222
import { Heading, Icon, Link, Navbar, Section, Tooltip } from '@qovery/shared/ui'
2323

@@ -58,10 +58,7 @@ function RouteComponent() {
5858
const activeTabId = tabs.find((tab) => matchRoute({ to: tab.routeId }))?.id
5959
const isServicesListTab = activeTabId === 'services'
6060
const qoveryServicesCount = useMemo(() => services.filter(isEditableService).length, [services])
61-
const argoCdServicesCount = useMemo(
62-
() => services.filter((service) => !isEditableService(service)).length,
63-
[services]
64-
)
61+
const argoCdServicesCount = useMemo(() => services.filter(isArgoCd).length, [services])
6562
const hasQoveryServices = qoveryServicesCount > 0
6663
const hasArgoCdServices = argoCdServicesCount > 0
6764
const shouldDisplayQoveryServicesSubtitle = isServicesListTab && hasArgoCdServices
@@ -129,7 +126,7 @@ function RouteComponent() {
129126
<div className="flex flex-col gap-3">
130127
{shouldDisplayQoveryServicesSubtitle && (
131128
<Heading level={3} className="font-medium text-neutral-subtle">
132-
Qovery native services
129+
Qovery services
133130
</Heading>
134131
)}
135132
{shouldDisplayArgoCdServicesAboveQovery ? (
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { createFileRoute } from '@tanstack/react-router'
1+
import { Navigate, createFileRoute, useParams } from '@tanstack/react-router'
2+
import { Suspense } from 'react'
3+
import { isArgoCd } from '@qovery/domains/services/data-access'
4+
import { ArgoCdManifest, useServiceSummary } from '@qovery/domains/services/feature'
5+
import { ErrorBoundary, LoaderSpinner } from '@qovery/shared/ui'
26
import { useDocumentTitle } from '@qovery/shared/util-hooks'
37

48
export const Route = createFileRoute(
@@ -7,8 +11,44 @@ export const Route = createFileRoute(
711
component: RouteComponent,
812
})
913

10-
function RouteComponent() {
14+
function ManifestLoader() {
15+
return (
16+
<div className="flex min-h-page-container flex-1 items-center justify-center bg-background">
17+
<LoaderSpinner />
18+
</div>
19+
)
20+
}
21+
22+
function ManifestRouteContent() {
23+
const { organizationId = '', projectId = '', environmentId = '', serviceId = '' } = useParams({ strict: false })
24+
const { data: service } = useServiceSummary({
25+
environmentId,
26+
serviceId,
27+
enabled: Boolean(environmentId) && Boolean(serviceId),
28+
suspense: true,
29+
})
30+
1131
useDocumentTitle('Service - Manifest')
1232

13-
return <div className="flex min-h-page-container flex-1 bg-background" />
33+
if (!service || !isArgoCd(service)) {
34+
return (
35+
<Navigate
36+
to="/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/overview"
37+
params={{ organizationId, projectId, environmentId, serviceId }}
38+
replace
39+
/>
40+
)
41+
}
42+
43+
return <ArgoCdManifest />
44+
}
45+
46+
function RouteComponent() {
47+
return (
48+
<ErrorBoundary>
49+
<Suspense fallback={<ManifestLoader />}>
50+
<ManifestRouteContent />
51+
</Suspense>
52+
</ErrorBoundary>
53+
)
1454
}

apps/console/src/routes/_authenticated/organization/route.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Suspense, useEffect, useLayoutEffect, useRef, useState } from 'react'
66
import { useClusters } from '@qovery/domains/clusters/feature'
77
import { useEnvironment } from '@qovery/domains/environments/feature'
88
import { useProject } from '@qovery/domains/projects/feature'
9-
import { type AnyService, isEditableService, isManagedDatabase } from '@qovery/domains/services/data-access'
9+
import { type AnyService, isArgoCd, isEditableService, isManagedDatabase } from '@qovery/domains/services/data-access'
1010
import { useRecentServices, useServiceSummary } from '@qovery/domains/services/feature'
1111
import { AssistantPanelOutlet, AssistantProvider } from '@qovery/shared/assistant/feature'
1212
import { DevopsCopilotContext } from '@qovery/shared/devops-copilot/context'
@@ -252,9 +252,7 @@ function createRoutePatternRegex(routeIdPattern: string): RegExp {
252252
}
253253

254254
function getServiceTabs(service?: AnyService, cluster?: Cluster) {
255-
const isArgoCdService = service ? !isEditableService(service) : false
256-
257-
if (isArgoCdService) {
255+
if (isArgoCd(service)) {
258256
return SERVICE_TABS.filter((tab) => ARGOCD_SERVICE_TAB_IDS.includes(tab.id))
259257
}
260258

libs/domains/organizations/feature/src/lib/container-registry-services-list-modal/__snapshots__/container-registry-services-list-modal.spec.tsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ exports[`ContainerRegistryServicesListModal should match snapshots 1`] = `
2121
class="fa-regular fa-magnifying-glass absolute left-3 top-1/2 block -translate-y-1/2 text-base leading-none text-neutral-subtle"
2222
/>
2323
<input
24-
class="w-full rounded border border-neutral bg-surface-neutral pl-10 pr-6 text-neutral placeholder:text-neutral-subtle focus:border-brand-strong focus:outline-none focus:transition-[border-color] h-9 text-sm"
24+
class="w-full rounded-md border border-neutral bg-surface-neutral pl-10 pr-6 text-neutral placeholder:text-neutral-subtle focus:border-brand-strong focus:outline-none focus:transition-[border-color] h-9 text-sm"
2525
data-testid="input-search"
2626
name="search"
2727
placeholder="Search by project, environment, service name"

libs/domains/organizations/feature/src/lib/git-token-services-list-modal/__snapshots__/git-token-services-list-modal.spec.tsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ exports[`GitTokenServicesListModal should match snapshots 1`] = `
2121
class="fa-regular fa-magnifying-glass absolute left-3 top-1/2 block -translate-y-1/2 text-base leading-none text-neutral-subtle"
2222
/>
2323
<input
24-
class="w-full rounded border border-neutral bg-surface-neutral pl-10 pr-6 text-neutral placeholder:text-neutral-subtle focus:border-brand-strong focus:outline-none focus:transition-[border-color] h-9 text-sm"
24+
class="w-full rounded-md border border-neutral bg-surface-neutral pl-10 pr-6 text-neutral placeholder:text-neutral-subtle focus:border-brand-strong focus:outline-none focus:transition-[border-color] h-9 text-sm"
2525
data-testid="input-search"
2626
name="search"
2727
placeholder="Search by project, environment, service name"

libs/domains/organizations/feature/src/lib/helm-repository-services-list-modal/__snapshots__/helm-repository-services-list-modal.spec.tsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ exports[`HelmRepositoryServicesListModal should match snapshots 1`] = `
2121
class="fa-regular fa-magnifying-glass absolute left-3 top-1/2 block -translate-y-1/2 text-base leading-none text-neutral-subtle"
2222
/>
2323
<input
24-
class="w-full rounded border border-neutral bg-surface-neutral pl-10 pr-6 text-neutral placeholder:text-neutral-subtle focus:border-brand-strong focus:outline-none focus:transition-[border-color] h-9 text-sm"
24+
class="w-full rounded-md border border-neutral bg-surface-neutral pl-10 pr-6 text-neutral placeholder:text-neutral-subtle focus:border-brand-strong focus:outline-none focus:transition-[border-color] h-9 text-sm"
2525
data-testid="input-search"
2626
name="search"
2727
placeholder="Search by project, environment, service name"

libs/domains/organizations/feature/src/lib/label-annotation-items-list-modal/__snapshots__/label-annotation-items-list-modal.spec.tsx.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ exports[`LabelAnnotationItemsListModal should match snapshots with annotation 1`
2323
class="fa-regular fa-magnifying-glass absolute left-3 top-1/2 block -translate-y-1/2 text-base leading-none text-neutral-subtle"
2424
/>
2525
<input
26-
class="w-full rounded border border-neutral bg-surface-neutral pl-10 pr-6 text-neutral placeholder:text-neutral-subtle focus:border-brand-strong focus:outline-none focus:transition-[border-color] h-9 text-sm"
26+
class="w-full rounded-md border border-neutral bg-surface-neutral pl-10 pr-6 text-neutral placeholder:text-neutral-subtle focus:border-brand-strong focus:outline-none focus:transition-[border-color] h-9 text-sm"
2727
data-testid="input-search"
2828
name="search"
2929
placeholder="Search by project, environment, service, or cluster name"
@@ -192,7 +192,7 @@ exports[`LabelAnnotationItemsListModal should match snapshots with label 1`] = `
192192
class="fa-regular fa-magnifying-glass absolute left-3 top-1/2 block -translate-y-1/2 text-base leading-none text-neutral-subtle"
193193
/>
194194
<input
195-
class="w-full rounded border border-neutral bg-surface-neutral pl-10 pr-6 text-neutral placeholder:text-neutral-subtle focus:border-brand-strong focus:outline-none focus:transition-[border-color] h-9 text-sm"
195+
class="w-full rounded-md border border-neutral bg-surface-neutral pl-10 pr-6 text-neutral placeholder:text-neutral-subtle focus:border-brand-strong focus:outline-none focus:transition-[border-color] h-9 text-sm"
196196
data-testid="input-search"
197197
name="search"
198198
placeholder="Search by project, environment, service, or cluster name"

libs/domains/service-terraform/feature/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ export * from './source-setting/source-setting'
22
export * from './lib/hooks/use-terraform-resources/use-terraform-resources'
33
export * from './lib/terraform-resources-section/terraform-resources-section'
44
export * from './lib/resource-details/resource-details'
5-
export * from './lib/resource-tree-list/resource-tree-list'
65
export * from './lib/hooks/use-terraform-available-versions/use-terraform-available-versions'
76
export * from './lib/terraform-configuration-settings/terraform-configuration-settings'
87
export * from './lib/terraform-general-data/terraform-general-data'

libs/domains/service-terraform/feature/src/lib/terraform-resources-section/terraform-resources-section.tsx

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { type ReactElement, useEffect, useMemo, useState } from 'react'
2+
import { ResourceTreeList } from '@qovery/shared/console-shared'
23
import { EmptyState, InputSearch, LoaderSpinner } from '@qovery/shared/ui'
34
import { useTerraformResources } from '../hooks/use-terraform-resources/use-terraform-resources'
45
import { ResourceDetails } from '../resource-details/resource-details'
5-
import { ResourceTreeList } from '../resource-tree-list/resource-tree-list'
66
import { matchesSearch } from '../utils/matches-search'
77

88
export interface TerraformResourcesSectionProps {
@@ -73,17 +73,11 @@ export function TerraformResourcesSection({ terraformId }: TerraformResourcesSec
7373

7474
return (
7575
<div className="flex h-page-container flex-col gap-4">
76-
{/* Split panel: Tree list (with search) and Details */}
7776
<div className="flex h-full">
78-
{/* Left panel: Search + Resource tree list */}
79-
<div className="flex w-1/4 flex-shrink-0 flex-col overflow-y-scroll border-r border-neutral">
80-
{/* Search bar */}
81-
<div className="flex-shrink-0 p-4 pb-0">
82-
<InputSearch placeholder="Search resources…" className="w-full" onChange={setSearchQuery} />
83-
</div>
77+
<div className="flex w-[266px] flex-shrink-0 flex-col gap-4 overflow-x-hidden overflow-y-scroll rounded-r-md border-r border-neutral bg-surface-neutral-subtle p-3">
78+
<InputSearch placeholder="Search resources…" className="w-full" onChange={setSearchQuery} />
8479

85-
{/* Tree list */}
86-
<div className="flex-1 p-4">
80+
<div className="min-h-0 flex-1">
8781
<ResourceTreeList
8882
resources={data}
8983
selectedResourceId={selectedResourceId}
@@ -93,8 +87,7 @@ export function TerraformResourcesSection({ terraformId }: TerraformResourcesSec
9387
</div>
9488
</div>
9589

96-
{/* Right panel: Resource details */}
97-
<div className="w-3/4 flex-1 overflow-y-scroll">
90+
<div className="min-w-0 flex-1 overflow-y-scroll bg-surface-neutral">
9891
<ResourceDetails resource={selectedResource} />
9992
</div>
10093
</div>

libs/domains/services/data-access/src/lib/domains-services-data-access.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,12 @@ export function isHelm(service: AnyService): service is Helm {
218218
return service.service_type === 'HELM'
219219
}
220220

221+
export function isArgoCd(service?: AnyService): service is ArgoCd {
222+
return service?.service_type === 'ARGOCD_APP'
223+
}
224+
221225
export function isEditableService(service: AnyService): service is EditableService {
222-
return service.service_type !== 'ARGOCD_APP'
226+
return !isArgoCd(service)
223227
}
224228

225229
export function isEditableServiceType(serviceType?: ServiceType): serviceType is EditableServiceType {
@@ -270,6 +274,13 @@ export const services = createQueryKeys('services', {
270274
return (response.data.results ?? []).filter((service) => service.service_type === 'ARGOCD_APP')
271275
},
272276
}),
277+
argocdManifest: (serviceId: string) => ({
278+
queryKey: [serviceId],
279+
async queryFn() {
280+
const response = await argoCdApi.getArgoCdAppManifest(serviceId)
281+
return response.data
282+
},
283+
}),
273284
list: (environmentId: string) => ({
274285
queryKey: [environmentId],
275286
async queryFn() {

0 commit comments

Comments
 (0)