@skyhook-io/k8s-ui 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +63 -0
- package/src/components/dock/BottomDock.tsx +204 -0
- package/src/components/dock/DockContext.tsx +212 -0
- package/src/components/dock/TerminalTab.tsx +333 -0
- package/src/components/dock/index.ts +3 -0
- package/src/components/gitops/GitOpsActions.tsx +227 -0
- package/src/components/gitops/GitOpsStatusBadge.tsx +221 -0
- package/src/components/gitops/ManagedResourcesList.tsx +210 -0
- package/src/components/gitops/SyncCountdown.tsx +146 -0
- package/src/components/gitops/index.ts +4 -0
- package/src/components/logs/JsonLogLine.tsx +90 -0
- package/src/components/logs/LogCore.tsx +553 -0
- package/src/components/logs/LogToolbarSelects.tsx +74 -0
- package/src/components/logs/LogsViewer.tsx +146 -0
- package/src/components/logs/WorkloadLogsViewer.tsx +263 -0
- package/src/components/logs/index.ts +13 -0
- package/src/components/logs/useLogBuffer.ts +138 -0
- package/src/components/logs/useLogSearch.ts +151 -0
- package/src/components/logs/useLogStream.ts +61 -0
- package/src/components/resources/ResourcesView.tsx +5494 -0
- package/src/components/resources/index.ts +17 -0
- package/src/components/resources/renderers/AlertRenderer.tsx +166 -0
- package/src/components/resources/renderers/ArgoApplicationRenderer.tsx +233 -0
- package/src/components/resources/renderers/CNPGBackupRenderer.tsx +89 -0
- package/src/components/resources/renderers/CNPGClusterRenderer.tsx +194 -0
- package/src/components/resources/renderers/CNPGPoolerRenderer.tsx +79 -0
- package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +68 -0
- package/src/components/resources/renderers/CertificateRenderer.tsx +209 -0
- package/src/components/resources/renderers/CertificateRequestRenderer.tsx +123 -0
- package/src/components/resources/renderers/ChallengeRenderer.tsx +111 -0
- package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +164 -0
- package/src/components/resources/renderers/ClusterExternalSecretRenderer.tsx +140 -0
- package/src/components/resources/renderers/ClusterIssuerRenderer.tsx +153 -0
- package/src/components/resources/renderers/ConfigAuditReportRenderer.tsx +221 -0
- package/src/components/resources/renderers/ConfigMapRenderer.tsx +124 -0
- package/src/components/resources/renderers/CronJobRenderer.tsx +86 -0
- package/src/components/resources/renderers/EventRenderer.tsx +175 -0
- package/src/components/resources/renderers/ExposedSecretReportRenderer.tsx +119 -0
- package/src/components/resources/renderers/ExternalSecretRenderer.tsx +172 -0
- package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +242 -0
- package/src/components/resources/renderers/GRPCRouteRenderer.tsx +263 -0
- package/src/components/resources/renderers/GatewayClassRenderer.tsx +68 -0
- package/src/components/resources/renderers/GatewayRenderer.tsx +218 -0
- package/src/components/resources/renderers/GenericRenderer.tsx +476 -0
- package/src/components/resources/renderers/GitRepositoryRenderer.tsx +154 -0
- package/src/components/resources/renderers/HPARenderer.tsx +164 -0
- package/src/components/resources/renderers/HTTPRouteRenderer.tsx +303 -0
- package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +167 -0
- package/src/components/resources/renderers/IngressClassRenderer.tsx +49 -0
- package/src/components/resources/renderers/IngressRenderer.tsx +104 -0
- package/src/components/resources/renderers/IstioAuthorizationPolicyRenderer.tsx +175 -0
- package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +176 -0
- package/src/components/resources/renderers/IstioGatewayRenderer.tsx +125 -0
- package/src/components/resources/renderers/IstioPeerAuthenticationRenderer.tsx +84 -0
- package/src/components/resources/renderers/IstioServiceEntryRenderer.tsx +112 -0
- package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +288 -0
- package/src/components/resources/renderers/JobRenderer.tsx +103 -0
- package/src/components/resources/renderers/KarpenterEC2NodeClassRenderer.tsx +157 -0
- package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +188 -0
- package/src/components/resources/renderers/KarpenterNodePoolRenderer.tsx +148 -0
- package/src/components/resources/renderers/KedaScaledJobRenderer.tsx +90 -0
- package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +136 -0
- package/src/components/resources/renderers/KedaTriggerAuthRenderer.tsx +151 -0
- package/src/components/resources/renderers/KnativeConfigurationRenderer.tsx +70 -0
- package/src/components/resources/renderers/KnativeEventingRenderer.tsx +309 -0
- package/src/components/resources/renderers/KnativeFlowRenderer.tsx +142 -0
- package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +232 -0
- package/src/components/resources/renderers/KnativeRevisionRenderer.tsx +97 -0
- package/src/components/resources/renderers/KnativeRouteRenderer.tsx +74 -0
- package/src/components/resources/renderers/KnativeServiceRenderer.tsx +138 -0
- package/src/components/resources/renderers/KnativeSourceRenderer.tsx +220 -0
- package/src/components/resources/renderers/KustomizationRenderer.tsx +151 -0
- package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +352 -0
- package/src/components/resources/renderers/LeaseRenderer.tsx +93 -0
- package/src/components/resources/renderers/NetworkPolicyRenderer.tsx +208 -0
- package/src/components/resources/renderers/NodeRenderer.tsx +282 -0
- package/src/components/resources/renderers/OCIRepositoryRenderer.tsx +153 -0
- package/src/components/resources/renderers/OrderRenderer.tsx +108 -0
- package/src/components/resources/renderers/PVCRenderer.tsx +98 -0
- package/src/components/resources/renderers/PersistentVolumeRenderer.tsx +138 -0
- package/src/components/resources/renderers/PodDisruptionBudgetRenderer.tsx +126 -0
- package/src/components/resources/renderers/PodMonitorRenderer.tsx +63 -0
- package/src/components/resources/renderers/PodRenderer.tsx +677 -0
- package/src/components/resources/renderers/PriorityClassRenderer.tsx +50 -0
- package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +62 -0
- package/src/components/resources/renderers/ReplicaSetRenderer.tsx +71 -0
- package/src/components/resources/renderers/RoleBindingRenderer.tsx +97 -0
- package/src/components/resources/renderers/RoleRenderer.tsx +192 -0
- package/src/components/resources/renderers/RolloutRenderer.tsx +227 -0
- package/src/components/resources/renderers/RuntimeClassRenderer.tsx +75 -0
- package/src/components/resources/renderers/SbomReportRenderer.tsx +98 -0
- package/src/components/resources/renderers/SealedSecretRenderer.tsx +121 -0
- package/src/components/resources/renderers/SecretRenderer.tsx +321 -0
- package/src/components/resources/renderers/SecretStoreRenderer.tsx +111 -0
- package/src/components/resources/renderers/ServiceAccountRenderer.tsx +81 -0
- package/src/components/resources/renderers/ServiceMonitorRenderer.tsx +65 -0
- package/src/components/resources/renderers/ServiceRenderer.tsx +98 -0
- package/src/components/resources/renderers/SimpleRouteRenderer.tsx +195 -0
- package/src/components/resources/renderers/StorageClassRenderer.tsx +82 -0
- package/src/components/resources/renderers/TraefikIngressRouteRenderer.tsx +257 -0
- package/src/components/resources/renderers/VPARenderer.tsx +193 -0
- package/src/components/resources/renderers/VeleroBSLRenderer.tsx +73 -0
- package/src/components/resources/renderers/VeleroBackupRenderer.tsx +193 -0
- package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +161 -0
- package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +134 -0
- package/src/components/resources/renderers/VeleroVSLRenderer.tsx +36 -0
- package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +347 -0
- package/src/components/resources/renderers/WebhookConfigRenderer.tsx +156 -0
- package/src/components/resources/renderers/WorkflowRenderer.tsx +202 -0
- package/src/components/resources/renderers/WorkflowTemplateRenderer.tsx +91 -0
- package/src/components/resources/renderers/WorkloadRenderer.tsx +311 -0
- package/src/components/resources/renderers/argo-cells.tsx +118 -0
- package/src/components/resources/renderers/certmanager-cells.tsx +164 -0
- package/src/components/resources/renderers/cnpg-cells.tsx +161 -0
- package/src/components/resources/renderers/eso-cells.tsx +115 -0
- package/src/components/resources/renderers/flux-cells.tsx +253 -0
- package/src/components/resources/renderers/index.ts +105 -0
- package/src/components/resources/renderers/istio-cells.tsx +210 -0
- package/src/components/resources/renderers/karpenter-cells.tsx +107 -0
- package/src/components/resources/renderers/keda-cells.tsx +94 -0
- package/src/components/resources/renderers/knative-cells.tsx +396 -0
- package/src/components/resources/renderers/kyverno-cells.tsx +85 -0
- package/src/components/resources/renderers/prometheus-cells.tsx +74 -0
- package/src/components/resources/renderers/traefik-cells.tsx +120 -0
- package/src/components/resources/renderers/trivy-cells.tsx +153 -0
- package/src/components/resources/renderers/trivy-shared.tsx +67 -0
- package/src/components/resources/renderers/velero-cells.tsx +164 -0
- package/src/components/resources/resource-utils-argo.ts +155 -0
- package/src/components/resources/resource-utils-certmanager.ts +198 -0
- package/src/components/resources/resource-utils-cnpg.ts +344 -0
- package/src/components/resources/resource-utils-eso.ts +385 -0
- package/src/components/resources/resource-utils-flux.ts +186 -0
- package/src/components/resources/resource-utils-istio.ts +372 -0
- package/src/components/resources/resource-utils-karpenter.ts +150 -0
- package/src/components/resources/resource-utils-keda.ts +203 -0
- package/src/components/resources/resource-utils-knative.ts +218 -0
- package/src/components/resources/resource-utils-kyverno.ts +224 -0
- package/src/components/resources/resource-utils-prometheus.ts +159 -0
- package/src/components/resources/resource-utils-traefik.ts +180 -0
- package/src/components/resources/resource-utils-trivy.ts +146 -0
- package/src/components/resources/resource-utils-velero.ts +293 -0
- package/src/components/resources/resource-utils.ts +1558 -0
- package/src/components/shared/EditableYamlView.tsx +302 -0
- package/src/components/shared/ResourceActionsBar.tsx +924 -0
- package/src/components/shared/ResourceRendererDispatch.tsx +557 -0
- package/src/components/shared/index.ts +3 -0
- package/src/components/timeline/index.ts +1 -0
- package/src/components/timeline/shared.tsx +614 -0
- package/src/components/topology/GroupNode.tsx +198 -0
- package/src/components/topology/K8sResourceNode.tsx +440 -0
- package/src/components/topology/TopologyControls.tsx +62 -0
- package/src/components/topology/TopologyFilterSidebar.tsx +377 -0
- package/src/components/topology/TopologyGraph.tsx +748 -0
- package/src/components/topology/TopologySearch.tsx +304 -0
- package/src/components/topology/index.ts +7 -0
- package/src/components/topology/layout.ts +734 -0
- package/src/components/topology/layout.worker.ts +272 -0
- package/src/components/topology/topology.css +129 -0
- package/src/components/ui/CodeViewer.tsx +451 -0
- package/src/components/ui/ConfirmDialog.tsx +188 -0
- package/src/components/ui/ForceDeleteConfirmDialog.tsx +57 -0
- package/src/components/ui/HealthRing.tsx +72 -0
- package/src/components/ui/MetricsChart.tsx +259 -0
- package/src/components/ui/ResourceBar.tsx +68 -0
- package/src/components/ui/Toast.tsx +225 -0
- package/src/components/ui/Tooltip.tsx +165 -0
- package/src/components/ui/YamlEditor.tsx +280 -0
- package/src/components/ui/drawer-components.tsx +792 -0
- package/src/components/ui/index.ts +10 -0
- package/src/components/workload/ResourceDetailDrawer.tsx +158 -0
- package/src/components/workload/WorkloadView.tsx +1109 -0
- package/src/components/workload/index.ts +2 -0
- package/src/hooks/index.ts +9 -0
- package/src/hooks/useAnimatedUnmount.ts +30 -0
- package/src/hooks/useKeyboardShortcuts.tsx +336 -0
- package/src/hooks/useRefreshAnimation.ts +58 -0
- package/src/index.ts +35 -0
- package/src/types/core.ts +894 -0
- package/src/types/gitops.ts +458 -0
- package/src/types/index.ts +2 -0
- package/src/utils/animation.ts +40 -0
- package/src/utils/api-resources.ts +185 -0
- package/src/utils/badge-colors.ts +399 -0
- package/src/utils/context-name.ts +72 -0
- package/src/utils/download.ts +19 -0
- package/src/utils/format.ts +233 -0
- package/src/utils/index.ts +10 -0
- package/src/utils/log-format.ts +300 -0
- package/src/utils/navigation.ts +119 -0
- package/src/utils/resource-hierarchy.ts +630 -0
- package/src/utils/resource-icons.ts +206 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * from './resource-utils'
|
|
2
|
+
export * from './resource-utils-argo'
|
|
3
|
+
export * from './resource-utils-certmanager'
|
|
4
|
+
export * from './resource-utils-cnpg'
|
|
5
|
+
export * from './resource-utils-eso'
|
|
6
|
+
export * from './resource-utils-flux'
|
|
7
|
+
export * from './resource-utils-istio'
|
|
8
|
+
export * from './resource-utils-karpenter'
|
|
9
|
+
export * from './resource-utils-keda'
|
|
10
|
+
export * from './resource-utils-knative'
|
|
11
|
+
export * from './resource-utils-kyverno'
|
|
12
|
+
export * from './resource-utils-prometheus'
|
|
13
|
+
export * from './resource-utils-trivy'
|
|
14
|
+
export * from './resource-utils-traefik'
|
|
15
|
+
export * from './resource-utils-velero'
|
|
16
|
+
export { ResourcesView, ResourcesViewDataContext } from './ResourcesView'
|
|
17
|
+
export type { ResourceQueryResult } from './ResourcesView'
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { Bell, AlertTriangle, Filter, Send } from 'lucide-react'
|
|
2
|
+
import { clsx } from 'clsx'
|
|
3
|
+
import { Section, PropertyList, Property, ConditionsSection } from '../../ui/drawer-components'
|
|
4
|
+
import { GitOpsStatusBadge } from '../../gitops'
|
|
5
|
+
import { fluxConditionsToGitOpsStatus, type FluxCondition } from '../../../types/gitops'
|
|
6
|
+
|
|
7
|
+
interface AlertRendererProps {
|
|
8
|
+
data: any
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function AlertRenderer({ data }: AlertRendererProps) {
|
|
12
|
+
const status = data.status || {}
|
|
13
|
+
const spec = data.spec || {}
|
|
14
|
+
const conditions = (status.conditions || []) as FluxCondition[]
|
|
15
|
+
|
|
16
|
+
// Convert to unified GitOps status
|
|
17
|
+
const gitOpsStatus = fluxConditionsToGitOpsStatus(conditions, spec.suspend === true)
|
|
18
|
+
|
|
19
|
+
// Problem detection
|
|
20
|
+
const problems: Array<{ color: 'red' | 'yellow'; message: string }> = []
|
|
21
|
+
|
|
22
|
+
if (gitOpsStatus.suspended) {
|
|
23
|
+
problems.push({ color: 'yellow', message: 'Alert is suspended' })
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (gitOpsStatus.health === 'Degraded' && gitOpsStatus.message) {
|
|
27
|
+
problems.push({ color: 'red', message: gitOpsStatus.message })
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Event sources
|
|
31
|
+
const eventSources = spec.eventSources || []
|
|
32
|
+
const eventSeverity = spec.eventSeverity || 'info'
|
|
33
|
+
const inclusionList = spec.inclusionList || []
|
|
34
|
+
const exclusionList = spec.exclusionList || []
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<>
|
|
38
|
+
{/* Problem alerts */}
|
|
39
|
+
{problems.map((problem, i) => (
|
|
40
|
+
<div
|
|
41
|
+
key={i}
|
|
42
|
+
className={clsx(
|
|
43
|
+
'mb-4 p-3 border rounded-lg',
|
|
44
|
+
problem.color === 'red'
|
|
45
|
+
? 'bg-red-500/10 border-red-500/30'
|
|
46
|
+
: 'bg-yellow-500/10 border-yellow-500/30'
|
|
47
|
+
)}
|
|
48
|
+
>
|
|
49
|
+
<div className="flex items-start gap-2">
|
|
50
|
+
<AlertTriangle
|
|
51
|
+
className={clsx(
|
|
52
|
+
'w-4 h-4 mt-0.5 shrink-0',
|
|
53
|
+
problem.color === 'red' ? 'text-red-400' : 'text-yellow-400'
|
|
54
|
+
)}
|
|
55
|
+
/>
|
|
56
|
+
<div className="flex-1 min-w-0">
|
|
57
|
+
<div
|
|
58
|
+
className={clsx(
|
|
59
|
+
'text-sm font-medium',
|
|
60
|
+
problem.color === 'red' ? 'text-red-400' : 'text-yellow-400'
|
|
61
|
+
)}
|
|
62
|
+
>
|
|
63
|
+
{problem.color === 'red' ? 'Issue Detected' : 'Warning'}
|
|
64
|
+
</div>
|
|
65
|
+
<div
|
|
66
|
+
className={clsx(
|
|
67
|
+
'text-xs mt-1',
|
|
68
|
+
problem.color === 'red' ? 'text-red-300/80' : 'text-yellow-300/80'
|
|
69
|
+
)}
|
|
70
|
+
>
|
|
71
|
+
{problem.message}
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
))}
|
|
77
|
+
|
|
78
|
+
{/* Status section */}
|
|
79
|
+
<Section title="Status">
|
|
80
|
+
<GitOpsStatusBadge status={gitOpsStatus} showHealth={false} />
|
|
81
|
+
</Section>
|
|
82
|
+
|
|
83
|
+
{/* Provider section */}
|
|
84
|
+
<Section title="Provider" icon={Send}>
|
|
85
|
+
<PropertyList>
|
|
86
|
+
<Property label="Provider Ref" value={spec.providerRef?.name} />
|
|
87
|
+
<Property
|
|
88
|
+
label="Event Severity"
|
|
89
|
+
value={
|
|
90
|
+
<span className={clsx(
|
|
91
|
+
'px-2 py-0.5 rounded text-xs font-medium',
|
|
92
|
+
eventSeverity === 'error' ? 'bg-red-500/20 text-red-400' :
|
|
93
|
+
eventSeverity === 'warning' ? 'bg-yellow-500/20 text-yellow-400' :
|
|
94
|
+
'bg-blue-500/20 text-blue-400'
|
|
95
|
+
)}>
|
|
96
|
+
{eventSeverity}
|
|
97
|
+
</span>
|
|
98
|
+
}
|
|
99
|
+
/>
|
|
100
|
+
{spec.summary && <Property label="Summary" value={spec.summary} />}
|
|
101
|
+
</PropertyList>
|
|
102
|
+
</Section>
|
|
103
|
+
|
|
104
|
+
{/* Event Sources section */}
|
|
105
|
+
{eventSources.length > 0 && (
|
|
106
|
+
<Section title={`Event Sources (${eventSources.length})`} icon={Bell}>
|
|
107
|
+
<div className="space-y-2">
|
|
108
|
+
{eventSources.map((source: any, idx: number) => (
|
|
109
|
+
<div
|
|
110
|
+
key={idx}
|
|
111
|
+
className="p-2 bg-theme-elevated/30 rounded text-sm"
|
|
112
|
+
>
|
|
113
|
+
<div className="flex items-center gap-2">
|
|
114
|
+
<span className="text-theme-text-tertiary">{source.kind}</span>
|
|
115
|
+
<span className="text-theme-text-primary">{source.name || '*'}</span>
|
|
116
|
+
</div>
|
|
117
|
+
{source.namespace && (
|
|
118
|
+
<div className="text-xs text-theme-text-tertiary mt-1">
|
|
119
|
+
Namespace: {source.namespace === '*' ? 'All' : source.namespace}
|
|
120
|
+
</div>
|
|
121
|
+
)}
|
|
122
|
+
{source.matchLabels && Object.keys(source.matchLabels).length > 0 && (
|
|
123
|
+
<div className="text-xs text-theme-text-tertiary mt-1">
|
|
124
|
+
Labels: {Object.entries(source.matchLabels).map(([k, v]) => `${k}=${v}`).join(', ')}
|
|
125
|
+
</div>
|
|
126
|
+
)}
|
|
127
|
+
</div>
|
|
128
|
+
))}
|
|
129
|
+
</div>
|
|
130
|
+
</Section>
|
|
131
|
+
)}
|
|
132
|
+
|
|
133
|
+
{/* Filters section */}
|
|
134
|
+
{(inclusionList.length > 0 || exclusionList.length > 0) && (
|
|
135
|
+
<Section title="Filters" icon={Filter} defaultExpanded={false}>
|
|
136
|
+
<PropertyList>
|
|
137
|
+
{inclusionList.length > 0 && (
|
|
138
|
+
<Property
|
|
139
|
+
label="Include"
|
|
140
|
+
value={inclusionList.join(', ')}
|
|
141
|
+
/>
|
|
142
|
+
)}
|
|
143
|
+
{exclusionList.length > 0 && (
|
|
144
|
+
<Property
|
|
145
|
+
label="Exclude"
|
|
146
|
+
value={exclusionList.join(', ')}
|
|
147
|
+
/>
|
|
148
|
+
)}
|
|
149
|
+
</PropertyList>
|
|
150
|
+
</Section>
|
|
151
|
+
)}
|
|
152
|
+
|
|
153
|
+
{/* Additional Info */}
|
|
154
|
+
{status.observedGeneration !== undefined && (
|
|
155
|
+
<Section title="Additional Info" defaultExpanded={false}>
|
|
156
|
+
<PropertyList>
|
|
157
|
+
<Property label="Observed Generation" value={status.observedGeneration} />
|
|
158
|
+
</PropertyList>
|
|
159
|
+
</Section>
|
|
160
|
+
)}
|
|
161
|
+
|
|
162
|
+
{/* Conditions section */}
|
|
163
|
+
<ConditionsSection conditions={conditions} />
|
|
164
|
+
</>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { GitBranch, FolderTree, Settings, Target, XCircle } from 'lucide-react'
|
|
2
|
+
import { clsx } from 'clsx'
|
|
3
|
+
import { Section, PropertyList, Property, ConditionsSection, ProblemAlerts } from '../../ui/drawer-components'
|
|
4
|
+
import { formatAge } from '../resource-utils'
|
|
5
|
+
import { GitOpsStatusBadge, ManagedResourcesList, SyncCountdown } from '../../gitops'
|
|
6
|
+
import {
|
|
7
|
+
argoStatusToGitOpsStatus,
|
|
8
|
+
parseArgoResources,
|
|
9
|
+
type ArgoAppStatus,
|
|
10
|
+
type ArgoResource,
|
|
11
|
+
} from '../../../types/gitops'
|
|
12
|
+
|
|
13
|
+
interface ArgoApplicationRendererProps {
|
|
14
|
+
data: any
|
|
15
|
+
onTerminate?: (params: { namespace: string; name: string }) => void
|
|
16
|
+
isTerminating?: boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function ArgoApplicationRenderer({ data, onTerminate, isTerminating }: ArgoApplicationRendererProps) {
|
|
20
|
+
const status = (data.status || {}) as ArgoAppStatus & {
|
|
21
|
+
resources?: ArgoResource[]
|
|
22
|
+
conditions?: Array<{ type: string; status: string; message?: string; lastTransitionTime?: string }>
|
|
23
|
+
}
|
|
24
|
+
const spec = data.spec || {}
|
|
25
|
+
|
|
26
|
+
const namespace = data.metadata?.namespace || ''
|
|
27
|
+
const name = data.metadata?.name || ''
|
|
28
|
+
|
|
29
|
+
// Convert to unified GitOps status
|
|
30
|
+
const gitOpsStatus = argoStatusToGitOpsStatus(status)
|
|
31
|
+
|
|
32
|
+
// Parse managed resources from status.resources
|
|
33
|
+
const managedResources = parseArgoResources(status.resources || [])
|
|
34
|
+
|
|
35
|
+
// Problem detection
|
|
36
|
+
const problems: Array<{ color: 'red' | 'yellow'; message: string }> = []
|
|
37
|
+
|
|
38
|
+
if (gitOpsStatus.suspended) {
|
|
39
|
+
problems.push({ color: 'yellow', message: 'Application automated sync is disabled' })
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (gitOpsStatus.health === 'Degraded' && gitOpsStatus.message) {
|
|
43
|
+
problems.push({ color: 'red', message: gitOpsStatus.message })
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (gitOpsStatus.sync === 'OutOfSync') {
|
|
47
|
+
problems.push({ color: 'yellow', message: 'Application is out of sync with git' })
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Extract source info
|
|
51
|
+
const source = spec.source || {}
|
|
52
|
+
const destination = spec.destination || {}
|
|
53
|
+
const syncPolicy = spec.syncPolicy || {}
|
|
54
|
+
const operationState = status.operationState
|
|
55
|
+
|
|
56
|
+
// Check if sync is in progress
|
|
57
|
+
const isSyncing = operationState?.phase === 'Running'
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<>
|
|
61
|
+
<ProblemAlerts problems={problems} />
|
|
62
|
+
|
|
63
|
+
{/* Status section */}
|
|
64
|
+
<Section title="Status">
|
|
65
|
+
<div className="space-y-3">
|
|
66
|
+
<div className="flex items-center justify-between">
|
|
67
|
+
<GitOpsStatusBadge status={gitOpsStatus} />
|
|
68
|
+
{/* Terminate button (only when syncing and handler provided) */}
|
|
69
|
+
{isSyncing && onTerminate && (
|
|
70
|
+
<button
|
|
71
|
+
onClick={() => onTerminate({ namespace, name })}
|
|
72
|
+
disabled={isTerminating}
|
|
73
|
+
className="flex items-center gap-1.5 px-2 py-1 rounded text-xs bg-red-500/20 text-red-400 hover:bg-red-500/30 transition-colors disabled:opacity-50"
|
|
74
|
+
title="Terminate sync"
|
|
75
|
+
>
|
|
76
|
+
<XCircle className="w-3.5 h-3.5" />
|
|
77
|
+
{isTerminating ? 'Terminating...' : 'Terminate'}
|
|
78
|
+
</button>
|
|
79
|
+
)}
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
{/* Sync countdown (only if automated sync is enabled) */}
|
|
83
|
+
{syncPolicy.automated && (
|
|
84
|
+
<SyncCountdown
|
|
85
|
+
interval="5m" // ArgoCD default
|
|
86
|
+
lastSyncTime={status.reconciledAt}
|
|
87
|
+
suspended={gitOpsStatus.suspended}
|
|
88
|
+
/>
|
|
89
|
+
)}
|
|
90
|
+
</div>
|
|
91
|
+
</Section>
|
|
92
|
+
|
|
93
|
+
{/* Source section */}
|
|
94
|
+
<Section title="Source" icon={FolderTree}>
|
|
95
|
+
<PropertyList>
|
|
96
|
+
<Property label="Repository" value={source.repoURL} />
|
|
97
|
+
{source.path && <Property label="Path" value={source.path} />}
|
|
98
|
+
{source.targetRevision && (
|
|
99
|
+
<Property
|
|
100
|
+
label="Target Revision"
|
|
101
|
+
value={
|
|
102
|
+
<span className="flex items-center gap-1">
|
|
103
|
+
<GitBranch className="w-3.5 h-3.5" />
|
|
104
|
+
{source.targetRevision}
|
|
105
|
+
</span>
|
|
106
|
+
}
|
|
107
|
+
/>
|
|
108
|
+
)}
|
|
109
|
+
{source.chart && <Property label="Helm Chart" value={source.chart} />}
|
|
110
|
+
{source.helm?.valueFiles && source.helm.valueFiles.length > 0 && (
|
|
111
|
+
<Property label="Value Files" value={source.helm.valueFiles.join(', ')} />
|
|
112
|
+
)}
|
|
113
|
+
{source.kustomize?.namePrefix && (
|
|
114
|
+
<Property label="Kustomize Prefix" value={source.kustomize.namePrefix} />
|
|
115
|
+
)}
|
|
116
|
+
</PropertyList>
|
|
117
|
+
</Section>
|
|
118
|
+
|
|
119
|
+
{/* Destination section */}
|
|
120
|
+
<Section title="Destination" icon={Target}>
|
|
121
|
+
<PropertyList>
|
|
122
|
+
<Property label="Server" value={destination.server || destination.name || '-'} />
|
|
123
|
+
<Property label="Namespace" value={destination.namespace || 'default'} />
|
|
124
|
+
</PropertyList>
|
|
125
|
+
</Section>
|
|
126
|
+
|
|
127
|
+
{/* Sync Policy section */}
|
|
128
|
+
<Section title="Sync Policy" icon={Settings}>
|
|
129
|
+
<PropertyList>
|
|
130
|
+
<Property
|
|
131
|
+
label="Automated Sync"
|
|
132
|
+
value={
|
|
133
|
+
<span
|
|
134
|
+
className={clsx(
|
|
135
|
+
'px-2 py-0.5 rounded text-xs font-medium',
|
|
136
|
+
syncPolicy.automated ? 'bg-green-500/20 text-green-400' : 'bg-gray-500/20 text-gray-400'
|
|
137
|
+
)}
|
|
138
|
+
>
|
|
139
|
+
{syncPolicy.automated ? 'Enabled' : 'Disabled'}
|
|
140
|
+
</span>
|
|
141
|
+
}
|
|
142
|
+
/>
|
|
143
|
+
{syncPolicy.automated && (
|
|
144
|
+
<>
|
|
145
|
+
<Property
|
|
146
|
+
label="Self Heal"
|
|
147
|
+
value={syncPolicy.automated.selfHeal ? 'Yes' : 'No'}
|
|
148
|
+
/>
|
|
149
|
+
<Property
|
|
150
|
+
label="Prune"
|
|
151
|
+
value={syncPolicy.automated.prune ? 'Yes' : 'No'}
|
|
152
|
+
/>
|
|
153
|
+
</>
|
|
154
|
+
)}
|
|
155
|
+
{syncPolicy.retry && (
|
|
156
|
+
<>
|
|
157
|
+
<Property label="Retry Limit" value={syncPolicy.retry.limit} />
|
|
158
|
+
{syncPolicy.retry.backoff && (
|
|
159
|
+
<Property label="Backoff Duration" value={syncPolicy.retry.backoff.duration} />
|
|
160
|
+
)}
|
|
161
|
+
</>
|
|
162
|
+
)}
|
|
163
|
+
{syncPolicy.syncOptions && syncPolicy.syncOptions.length > 0 && (
|
|
164
|
+
<Property label="Sync Options" value={syncPolicy.syncOptions.join(', ')} />
|
|
165
|
+
)}
|
|
166
|
+
</PropertyList>
|
|
167
|
+
</Section>
|
|
168
|
+
|
|
169
|
+
{/* Operation State (current/last sync) */}
|
|
170
|
+
{operationState && (
|
|
171
|
+
<Section title="Last Operation" defaultExpanded={operationState.phase === 'Running'}>
|
|
172
|
+
<PropertyList>
|
|
173
|
+
<Property
|
|
174
|
+
label="Phase"
|
|
175
|
+
value={
|
|
176
|
+
<span
|
|
177
|
+
className={clsx(
|
|
178
|
+
'px-2 py-0.5 rounded text-xs font-medium',
|
|
179
|
+
operationState.phase === 'Succeeded'
|
|
180
|
+
? 'bg-green-500/20 text-green-400'
|
|
181
|
+
: operationState.phase === 'Running'
|
|
182
|
+
? 'bg-blue-500/20 text-blue-400'
|
|
183
|
+
: operationState.phase === 'Failed' || operationState.phase === 'Error'
|
|
184
|
+
? 'bg-red-500/20 text-red-400'
|
|
185
|
+
: 'bg-gray-500/20 text-gray-400'
|
|
186
|
+
)}
|
|
187
|
+
>
|
|
188
|
+
{operationState.phase}
|
|
189
|
+
</span>
|
|
190
|
+
}
|
|
191
|
+
/>
|
|
192
|
+
{operationState.message && (
|
|
193
|
+
<Property label="Message" value={operationState.message} />
|
|
194
|
+
)}
|
|
195
|
+
{operationState.finishedAt && (
|
|
196
|
+
<Property label="Finished" value={formatAge(operationState.finishedAt)} />
|
|
197
|
+
)}
|
|
198
|
+
{operationState.syncResult?.revision && (
|
|
199
|
+
<Property label="Revision" value={operationState.syncResult.revision} />
|
|
200
|
+
)}
|
|
201
|
+
</PropertyList>
|
|
202
|
+
</Section>
|
|
203
|
+
)}
|
|
204
|
+
|
|
205
|
+
{/* Managed Resources */}
|
|
206
|
+
{managedResources.length > 0 && (
|
|
207
|
+
<ManagedResourcesList
|
|
208
|
+
resources={managedResources}
|
|
209
|
+
title={`Managed Resources (${managedResources.length})`}
|
|
210
|
+
/>
|
|
211
|
+
)}
|
|
212
|
+
|
|
213
|
+
{/* Revision Info */}
|
|
214
|
+
{(status.sync?.revision || status.reconciledAt) && (
|
|
215
|
+
<Section title="Revision Info" defaultExpanded={false}>
|
|
216
|
+
<PropertyList>
|
|
217
|
+
{status.sync?.revision && (
|
|
218
|
+
<Property label="Current Revision" value={status.sync.revision} />
|
|
219
|
+
)}
|
|
220
|
+
{status.reconciledAt && (
|
|
221
|
+
<Property label="Last Reconciled" value={formatAge(status.reconciledAt)} />
|
|
222
|
+
)}
|
|
223
|
+
</PropertyList>
|
|
224
|
+
</Section>
|
|
225
|
+
)}
|
|
226
|
+
|
|
227
|
+
{/* Conditions section */}
|
|
228
|
+
{status.conditions && status.conditions.length > 0 && (
|
|
229
|
+
<ConditionsSection conditions={status.conditions} />
|
|
230
|
+
)}
|
|
231
|
+
</>
|
|
232
|
+
)
|
|
233
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Database, Clock } from 'lucide-react'
|
|
2
|
+
import { Section, PropertyList, Property, AlertBanner, ResourceLink } from '../../ui/drawer-components'
|
|
3
|
+
import {
|
|
4
|
+
getCNPGBackupStatus,
|
|
5
|
+
getCNPGBackupCluster,
|
|
6
|
+
getCNPGBackupMethod,
|
|
7
|
+
getCNPGBackupPhase,
|
|
8
|
+
getCNPGBackupDuration,
|
|
9
|
+
getCNPGBackupName,
|
|
10
|
+
getCNPGBackupDestinationPath,
|
|
11
|
+
getCNPGBackupServerName,
|
|
12
|
+
getCNPGBackupError,
|
|
13
|
+
getCNPGBackupTarget,
|
|
14
|
+
} from '../resource-utils-cnpg'
|
|
15
|
+
|
|
16
|
+
interface CNPGBackupRendererProps {
|
|
17
|
+
data: any
|
|
18
|
+
onNavigate?: (ref: { kind: string; namespace: string; name: string }) => void
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function CNPGBackupRenderer({ data, onNavigate }: CNPGBackupRendererProps) {
|
|
22
|
+
const status = getCNPGBackupStatus(data)
|
|
23
|
+
const error = getCNPGBackupError(data)
|
|
24
|
+
const phase = getCNPGBackupPhase(data)
|
|
25
|
+
const target = getCNPGBackupTarget(data)
|
|
26
|
+
const clusterName = getCNPGBackupCluster(data)
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<>
|
|
30
|
+
{/* Problem alerts */}
|
|
31
|
+
{status.level === 'unhealthy' && error && (
|
|
32
|
+
<AlertBanner
|
|
33
|
+
variant="error"
|
|
34
|
+
title="Backup Failed"
|
|
35
|
+
message={error}
|
|
36
|
+
/>
|
|
37
|
+
)}
|
|
38
|
+
|
|
39
|
+
{/* Status */}
|
|
40
|
+
<Section title="Backup Status" icon={Clock} defaultExpanded>
|
|
41
|
+
<PropertyList>
|
|
42
|
+
<Property label="Phase" value={phase} />
|
|
43
|
+
<Property label="Method" value={getCNPGBackupMethod(data)} />
|
|
44
|
+
<Property label="Duration" value={getCNPGBackupDuration(data)} />
|
|
45
|
+
<Property label="Backup Name" value={getCNPGBackupName(data)} />
|
|
46
|
+
</PropertyList>
|
|
47
|
+
{data.status?.startedAt && (
|
|
48
|
+
<div className="mt-2 pt-2 border-t border-theme-border">
|
|
49
|
+
<PropertyList>
|
|
50
|
+
<Property label="Started" value={data.status.startedAt} />
|
|
51
|
+
{data.status?.stoppedAt && <Property label="Stopped" value={data.status.stoppedAt} />}
|
|
52
|
+
</PropertyList>
|
|
53
|
+
</div>
|
|
54
|
+
)}
|
|
55
|
+
</Section>
|
|
56
|
+
|
|
57
|
+
{/* Backup Details */}
|
|
58
|
+
<Section title="Backup Details" icon={Database} defaultExpanded>
|
|
59
|
+
<PropertyList>
|
|
60
|
+
<Property label="Cluster" value={(() => {
|
|
61
|
+
if (clusterName && clusterName !== '-') {
|
|
62
|
+
return (
|
|
63
|
+
<ResourceLink
|
|
64
|
+
name={clusterName}
|
|
65
|
+
kind="clusters"
|
|
66
|
+
namespace={data.metadata?.namespace || ''}
|
|
67
|
+
group="postgresql.cnpg.io"
|
|
68
|
+
onNavigate={onNavigate}
|
|
69
|
+
/>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
return clusterName
|
|
73
|
+
})()} />
|
|
74
|
+
<Property label="Destination" value={getCNPGBackupDestinationPath(data)} />
|
|
75
|
+
<Property label="Server Name" value={getCNPGBackupServerName(data)} />
|
|
76
|
+
</PropertyList>
|
|
77
|
+
</Section>
|
|
78
|
+
|
|
79
|
+
{/* Target - for PITR backups */}
|
|
80
|
+
{target !== '-' && (
|
|
81
|
+
<Section title="Target" defaultExpanded>
|
|
82
|
+
<PropertyList>
|
|
83
|
+
<Property label="Recovery Target" value={target} />
|
|
84
|
+
</PropertyList>
|
|
85
|
+
</Section>
|
|
86
|
+
)}
|
|
87
|
+
</>
|
|
88
|
+
)
|
|
89
|
+
}
|