@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.
Files changed (193) hide show
  1. package/package.json +63 -0
  2. package/src/components/dock/BottomDock.tsx +204 -0
  3. package/src/components/dock/DockContext.tsx +212 -0
  4. package/src/components/dock/TerminalTab.tsx +333 -0
  5. package/src/components/dock/index.ts +3 -0
  6. package/src/components/gitops/GitOpsActions.tsx +227 -0
  7. package/src/components/gitops/GitOpsStatusBadge.tsx +221 -0
  8. package/src/components/gitops/ManagedResourcesList.tsx +210 -0
  9. package/src/components/gitops/SyncCountdown.tsx +146 -0
  10. package/src/components/gitops/index.ts +4 -0
  11. package/src/components/logs/JsonLogLine.tsx +90 -0
  12. package/src/components/logs/LogCore.tsx +553 -0
  13. package/src/components/logs/LogToolbarSelects.tsx +74 -0
  14. package/src/components/logs/LogsViewer.tsx +146 -0
  15. package/src/components/logs/WorkloadLogsViewer.tsx +263 -0
  16. package/src/components/logs/index.ts +13 -0
  17. package/src/components/logs/useLogBuffer.ts +138 -0
  18. package/src/components/logs/useLogSearch.ts +151 -0
  19. package/src/components/logs/useLogStream.ts +61 -0
  20. package/src/components/resources/ResourcesView.tsx +5494 -0
  21. package/src/components/resources/index.ts +17 -0
  22. package/src/components/resources/renderers/AlertRenderer.tsx +166 -0
  23. package/src/components/resources/renderers/ArgoApplicationRenderer.tsx +233 -0
  24. package/src/components/resources/renderers/CNPGBackupRenderer.tsx +89 -0
  25. package/src/components/resources/renderers/CNPGClusterRenderer.tsx +194 -0
  26. package/src/components/resources/renderers/CNPGPoolerRenderer.tsx +79 -0
  27. package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +68 -0
  28. package/src/components/resources/renderers/CertificateRenderer.tsx +209 -0
  29. package/src/components/resources/renderers/CertificateRequestRenderer.tsx +123 -0
  30. package/src/components/resources/renderers/ChallengeRenderer.tsx +111 -0
  31. package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +164 -0
  32. package/src/components/resources/renderers/ClusterExternalSecretRenderer.tsx +140 -0
  33. package/src/components/resources/renderers/ClusterIssuerRenderer.tsx +153 -0
  34. package/src/components/resources/renderers/ConfigAuditReportRenderer.tsx +221 -0
  35. package/src/components/resources/renderers/ConfigMapRenderer.tsx +124 -0
  36. package/src/components/resources/renderers/CronJobRenderer.tsx +86 -0
  37. package/src/components/resources/renderers/EventRenderer.tsx +175 -0
  38. package/src/components/resources/renderers/ExposedSecretReportRenderer.tsx +119 -0
  39. package/src/components/resources/renderers/ExternalSecretRenderer.tsx +172 -0
  40. package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +242 -0
  41. package/src/components/resources/renderers/GRPCRouteRenderer.tsx +263 -0
  42. package/src/components/resources/renderers/GatewayClassRenderer.tsx +68 -0
  43. package/src/components/resources/renderers/GatewayRenderer.tsx +218 -0
  44. package/src/components/resources/renderers/GenericRenderer.tsx +476 -0
  45. package/src/components/resources/renderers/GitRepositoryRenderer.tsx +154 -0
  46. package/src/components/resources/renderers/HPARenderer.tsx +164 -0
  47. package/src/components/resources/renderers/HTTPRouteRenderer.tsx +303 -0
  48. package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +167 -0
  49. package/src/components/resources/renderers/IngressClassRenderer.tsx +49 -0
  50. package/src/components/resources/renderers/IngressRenderer.tsx +104 -0
  51. package/src/components/resources/renderers/IstioAuthorizationPolicyRenderer.tsx +175 -0
  52. package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +176 -0
  53. package/src/components/resources/renderers/IstioGatewayRenderer.tsx +125 -0
  54. package/src/components/resources/renderers/IstioPeerAuthenticationRenderer.tsx +84 -0
  55. package/src/components/resources/renderers/IstioServiceEntryRenderer.tsx +112 -0
  56. package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +288 -0
  57. package/src/components/resources/renderers/JobRenderer.tsx +103 -0
  58. package/src/components/resources/renderers/KarpenterEC2NodeClassRenderer.tsx +157 -0
  59. package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +188 -0
  60. package/src/components/resources/renderers/KarpenterNodePoolRenderer.tsx +148 -0
  61. package/src/components/resources/renderers/KedaScaledJobRenderer.tsx +90 -0
  62. package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +136 -0
  63. package/src/components/resources/renderers/KedaTriggerAuthRenderer.tsx +151 -0
  64. package/src/components/resources/renderers/KnativeConfigurationRenderer.tsx +70 -0
  65. package/src/components/resources/renderers/KnativeEventingRenderer.tsx +309 -0
  66. package/src/components/resources/renderers/KnativeFlowRenderer.tsx +142 -0
  67. package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +232 -0
  68. package/src/components/resources/renderers/KnativeRevisionRenderer.tsx +97 -0
  69. package/src/components/resources/renderers/KnativeRouteRenderer.tsx +74 -0
  70. package/src/components/resources/renderers/KnativeServiceRenderer.tsx +138 -0
  71. package/src/components/resources/renderers/KnativeSourceRenderer.tsx +220 -0
  72. package/src/components/resources/renderers/KustomizationRenderer.tsx +151 -0
  73. package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +352 -0
  74. package/src/components/resources/renderers/LeaseRenderer.tsx +93 -0
  75. package/src/components/resources/renderers/NetworkPolicyRenderer.tsx +208 -0
  76. package/src/components/resources/renderers/NodeRenderer.tsx +282 -0
  77. package/src/components/resources/renderers/OCIRepositoryRenderer.tsx +153 -0
  78. package/src/components/resources/renderers/OrderRenderer.tsx +108 -0
  79. package/src/components/resources/renderers/PVCRenderer.tsx +98 -0
  80. package/src/components/resources/renderers/PersistentVolumeRenderer.tsx +138 -0
  81. package/src/components/resources/renderers/PodDisruptionBudgetRenderer.tsx +126 -0
  82. package/src/components/resources/renderers/PodMonitorRenderer.tsx +63 -0
  83. package/src/components/resources/renderers/PodRenderer.tsx +677 -0
  84. package/src/components/resources/renderers/PriorityClassRenderer.tsx +50 -0
  85. package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +62 -0
  86. package/src/components/resources/renderers/ReplicaSetRenderer.tsx +71 -0
  87. package/src/components/resources/renderers/RoleBindingRenderer.tsx +97 -0
  88. package/src/components/resources/renderers/RoleRenderer.tsx +192 -0
  89. package/src/components/resources/renderers/RolloutRenderer.tsx +227 -0
  90. package/src/components/resources/renderers/RuntimeClassRenderer.tsx +75 -0
  91. package/src/components/resources/renderers/SbomReportRenderer.tsx +98 -0
  92. package/src/components/resources/renderers/SealedSecretRenderer.tsx +121 -0
  93. package/src/components/resources/renderers/SecretRenderer.tsx +321 -0
  94. package/src/components/resources/renderers/SecretStoreRenderer.tsx +111 -0
  95. package/src/components/resources/renderers/ServiceAccountRenderer.tsx +81 -0
  96. package/src/components/resources/renderers/ServiceMonitorRenderer.tsx +65 -0
  97. package/src/components/resources/renderers/ServiceRenderer.tsx +98 -0
  98. package/src/components/resources/renderers/SimpleRouteRenderer.tsx +195 -0
  99. package/src/components/resources/renderers/StorageClassRenderer.tsx +82 -0
  100. package/src/components/resources/renderers/TraefikIngressRouteRenderer.tsx +257 -0
  101. package/src/components/resources/renderers/VPARenderer.tsx +193 -0
  102. package/src/components/resources/renderers/VeleroBSLRenderer.tsx +73 -0
  103. package/src/components/resources/renderers/VeleroBackupRenderer.tsx +193 -0
  104. package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +161 -0
  105. package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +134 -0
  106. package/src/components/resources/renderers/VeleroVSLRenderer.tsx +36 -0
  107. package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +347 -0
  108. package/src/components/resources/renderers/WebhookConfigRenderer.tsx +156 -0
  109. package/src/components/resources/renderers/WorkflowRenderer.tsx +202 -0
  110. package/src/components/resources/renderers/WorkflowTemplateRenderer.tsx +91 -0
  111. package/src/components/resources/renderers/WorkloadRenderer.tsx +311 -0
  112. package/src/components/resources/renderers/argo-cells.tsx +118 -0
  113. package/src/components/resources/renderers/certmanager-cells.tsx +164 -0
  114. package/src/components/resources/renderers/cnpg-cells.tsx +161 -0
  115. package/src/components/resources/renderers/eso-cells.tsx +115 -0
  116. package/src/components/resources/renderers/flux-cells.tsx +253 -0
  117. package/src/components/resources/renderers/index.ts +105 -0
  118. package/src/components/resources/renderers/istio-cells.tsx +210 -0
  119. package/src/components/resources/renderers/karpenter-cells.tsx +107 -0
  120. package/src/components/resources/renderers/keda-cells.tsx +94 -0
  121. package/src/components/resources/renderers/knative-cells.tsx +396 -0
  122. package/src/components/resources/renderers/kyverno-cells.tsx +85 -0
  123. package/src/components/resources/renderers/prometheus-cells.tsx +74 -0
  124. package/src/components/resources/renderers/traefik-cells.tsx +120 -0
  125. package/src/components/resources/renderers/trivy-cells.tsx +153 -0
  126. package/src/components/resources/renderers/trivy-shared.tsx +67 -0
  127. package/src/components/resources/renderers/velero-cells.tsx +164 -0
  128. package/src/components/resources/resource-utils-argo.ts +155 -0
  129. package/src/components/resources/resource-utils-certmanager.ts +198 -0
  130. package/src/components/resources/resource-utils-cnpg.ts +344 -0
  131. package/src/components/resources/resource-utils-eso.ts +385 -0
  132. package/src/components/resources/resource-utils-flux.ts +186 -0
  133. package/src/components/resources/resource-utils-istio.ts +372 -0
  134. package/src/components/resources/resource-utils-karpenter.ts +150 -0
  135. package/src/components/resources/resource-utils-keda.ts +203 -0
  136. package/src/components/resources/resource-utils-knative.ts +218 -0
  137. package/src/components/resources/resource-utils-kyverno.ts +224 -0
  138. package/src/components/resources/resource-utils-prometheus.ts +159 -0
  139. package/src/components/resources/resource-utils-traefik.ts +180 -0
  140. package/src/components/resources/resource-utils-trivy.ts +146 -0
  141. package/src/components/resources/resource-utils-velero.ts +293 -0
  142. package/src/components/resources/resource-utils.ts +1558 -0
  143. package/src/components/shared/EditableYamlView.tsx +302 -0
  144. package/src/components/shared/ResourceActionsBar.tsx +924 -0
  145. package/src/components/shared/ResourceRendererDispatch.tsx +557 -0
  146. package/src/components/shared/index.ts +3 -0
  147. package/src/components/timeline/index.ts +1 -0
  148. package/src/components/timeline/shared.tsx +614 -0
  149. package/src/components/topology/GroupNode.tsx +198 -0
  150. package/src/components/topology/K8sResourceNode.tsx +440 -0
  151. package/src/components/topology/TopologyControls.tsx +62 -0
  152. package/src/components/topology/TopologyFilterSidebar.tsx +377 -0
  153. package/src/components/topology/TopologyGraph.tsx +748 -0
  154. package/src/components/topology/TopologySearch.tsx +304 -0
  155. package/src/components/topology/index.ts +7 -0
  156. package/src/components/topology/layout.ts +734 -0
  157. package/src/components/topology/layout.worker.ts +272 -0
  158. package/src/components/topology/topology.css +129 -0
  159. package/src/components/ui/CodeViewer.tsx +451 -0
  160. package/src/components/ui/ConfirmDialog.tsx +188 -0
  161. package/src/components/ui/ForceDeleteConfirmDialog.tsx +57 -0
  162. package/src/components/ui/HealthRing.tsx +72 -0
  163. package/src/components/ui/MetricsChart.tsx +259 -0
  164. package/src/components/ui/ResourceBar.tsx +68 -0
  165. package/src/components/ui/Toast.tsx +225 -0
  166. package/src/components/ui/Tooltip.tsx +165 -0
  167. package/src/components/ui/YamlEditor.tsx +280 -0
  168. package/src/components/ui/drawer-components.tsx +792 -0
  169. package/src/components/ui/index.ts +10 -0
  170. package/src/components/workload/ResourceDetailDrawer.tsx +158 -0
  171. package/src/components/workload/WorkloadView.tsx +1109 -0
  172. package/src/components/workload/index.ts +2 -0
  173. package/src/hooks/index.ts +9 -0
  174. package/src/hooks/useAnimatedUnmount.ts +30 -0
  175. package/src/hooks/useKeyboardShortcuts.tsx +336 -0
  176. package/src/hooks/useRefreshAnimation.ts +58 -0
  177. package/src/index.ts +35 -0
  178. package/src/types/core.ts +894 -0
  179. package/src/types/gitops.ts +458 -0
  180. package/src/types/index.ts +2 -0
  181. package/src/utils/animation.ts +40 -0
  182. package/src/utils/api-resources.ts +185 -0
  183. package/src/utils/badge-colors.ts +399 -0
  184. package/src/utils/context-name.ts +72 -0
  185. package/src/utils/download.ts +19 -0
  186. package/src/utils/format.ts +233 -0
  187. package/src/utils/index.ts +10 -0
  188. package/src/utils/log-format.ts +300 -0
  189. package/src/utils/navigation.ts +119 -0
  190. package/src/utils/resource-hierarchy.ts +630 -0
  191. package/src/utils/resource-icons.ts +206 -0
  192. package/src/vite-env.d.ts +1 -0
  193. package/tsconfig.json +24 -0
@@ -0,0 +1,138 @@
1
+ import { Globe, Layers, Container } from 'lucide-react'
2
+ import { clsx } from 'clsx'
3
+ import { Section, PropertyList, Property, ConditionsSection, KnativeNotReadyBanner, ResourceLink } from '../../ui/drawer-components'
4
+ import { getKnativeConditionStatus } from '../resource-utils-knative'
5
+
6
+ interface KnativeServiceRendererProps {
7
+ data: any
8
+ onNavigate?: (ref: { kind: string; namespace: string; name: string }) => void
9
+ }
10
+
11
+ export function KnativeServiceRenderer({ data, onNavigate }: KnativeServiceRendererProps) {
12
+ const status = getKnativeConditionStatus(data)
13
+ const ns = data.metadata?.namespace || ''
14
+ const url = data.status?.url
15
+ const traffic = data.status?.traffic || []
16
+ const templateSpec = data.spec?.template?.spec || {}
17
+ const containers = templateSpec.containers || []
18
+ const templateAnnotations = data.spec?.template?.metadata?.annotations || {}
19
+
20
+ const latestReady = data.status?.latestReadyRevisionName
21
+ const latestCreated = data.status?.latestCreatedRevisionName
22
+ const generation = data.metadata?.generation
23
+
24
+ // Autoscaling config from template annotations
25
+ const minScale = templateAnnotations['autoscaling.knative.dev/minScale']
26
+ const maxScale = templateAnnotations['autoscaling.knative.dev/maxScale']
27
+ const concurrency = templateSpec.containerConcurrency
28
+ const timeoutSeconds = templateSpec.timeoutSeconds
29
+
30
+ return (
31
+ <>
32
+ <KnativeNotReadyBanner status={status} data={data} resourceType="Service" />
33
+
34
+ <Section title="Overview" icon={Globe} defaultExpanded>
35
+ <PropertyList>
36
+ <Property label="Status" value={
37
+ <span className={clsx('px-2 py-0.5 rounded text-xs font-medium', status.color)}>
38
+ {status.text}
39
+ </span>
40
+ } />
41
+ <Property label="URL" value={url ? (
42
+ <a href={url} target="_blank" rel="noopener noreferrer" className="text-blue-400 hover:text-blue-300 hover:underline break-all">
43
+ {url}
44
+ </a>
45
+ ) : undefined} />
46
+ <Property label="Latest Ready" value={latestReady ? (
47
+ <ResourceLink
48
+ name={latestReady}
49
+ kind="revisions"
50
+ namespace={ns}
51
+ onNavigate={onNavigate}
52
+ />
53
+ ) : '-'} />
54
+ <Property label="Latest Created" value={latestCreated ? (
55
+ <ResourceLink
56
+ name={latestCreated}
57
+ kind="revisions"
58
+ namespace={ns}
59
+ onNavigate={onNavigate}
60
+ />
61
+ ) : '-'} />
62
+ <Property label="Generation" value={generation} />
63
+ </PropertyList>
64
+ </Section>
65
+
66
+ {(minScale || maxScale || concurrency != null || timeoutSeconds != null) && (
67
+ <Section title="Scaling & Configuration" defaultExpanded>
68
+ <PropertyList>
69
+ {minScale && <Property label="Min Scale" value={minScale} />}
70
+ {maxScale && <Property label="Max Scale" value={maxScale} />}
71
+ <Property label="Concurrency" value={concurrency != null ? (concurrency === 0 ? 'Unlimited' : String(concurrency)) : undefined} />
72
+ <Property label="Timeout" value={timeoutSeconds != null ? `${timeoutSeconds}s` : undefined} />
73
+ </PropertyList>
74
+ </Section>
75
+ )}
76
+
77
+ {traffic.length > 0 && (
78
+ <Section title={`Traffic (${traffic.length} targets)`} icon={Layers} defaultExpanded>
79
+ <div className="space-y-2">
80
+ {traffic.map((t: any, i: number) => (
81
+ <div key={i} className="flex items-center gap-2 text-sm">
82
+ <div className="flex items-center gap-1 w-16 shrink-0">
83
+ <div className="flex-1 h-1.5 bg-theme-hover rounded-full overflow-hidden">
84
+ <div
85
+ className="h-full bg-blue-500 rounded-full"
86
+ style={{ width: `${t.percent || 0}%` }}
87
+ />
88
+ </div>
89
+ <span className="text-theme-text-secondary font-medium text-xs">{t.percent || 0}%</span>
90
+ </div>
91
+ {t.revisionName ? (
92
+ <ResourceLink
93
+ name={t.revisionName}
94
+ kind="revisions"
95
+ namespace={ns}
96
+ onNavigate={onNavigate}
97
+ />
98
+ ) : (
99
+ <span className="text-theme-text-secondary">{t.latestRevision ? '@latest' : '-'}</span>
100
+ )}
101
+ {t.tag && (
102
+ <span className="px-1.5 py-0.5 bg-theme-hover rounded text-[10px] text-theme-text-secondary">
103
+ tag: {t.tag}
104
+ </span>
105
+ )}
106
+ {t.url && (
107
+ <a href={t.url} target="_blank" rel="noopener noreferrer" className="text-blue-400 hover:text-blue-300 text-xs">
108
+ {t.tag || 'link'}
109
+ </a>
110
+ )}
111
+ </div>
112
+ ))}
113
+ </div>
114
+ </Section>
115
+ )}
116
+
117
+ {containers.length > 0 && (
118
+ <Section title="Template" icon={Container} defaultExpanded>
119
+ <div className="space-y-2">
120
+ {containers.map((c: any, i: number) => (
121
+ <div key={i} className="bg-theme-elevated/30 rounded p-2 text-sm">
122
+ <div className="font-medium text-theme-text-primary">{c.name || 'container'}</div>
123
+ <div className="text-xs text-theme-text-secondary truncate" title={c.image}>{c.image}</div>
124
+ {c.ports && c.ports.length > 0 && (
125
+ <div className="text-xs text-theme-text-tertiary mt-1">
126
+ Ports: {c.ports.map((p: any) => `${p.containerPort}/${p.protocol || 'TCP'}`).join(', ')}
127
+ </div>
128
+ )}
129
+ </div>
130
+ ))}
131
+ </div>
132
+ </Section>
133
+ )}
134
+
135
+ <ConditionsSection conditions={data.status?.conditions || []} />
136
+ </>
137
+ )
138
+ }
@@ -0,0 +1,220 @@
1
+ import { Clock, Server, Container, Link2 } from 'lucide-react'
2
+ import { clsx } from 'clsx'
3
+ import { Section, PropertyList, Property, ConditionsSection, KnativeNotReadyBanner, ResourceLink } from '../../ui/drawer-components'
4
+ import { getKnativeConditionStatus } from '../resource-utils-knative'
5
+
6
+ interface RendererProps {
7
+ data: any
8
+ onNavigate?: (ref: { kind: string; namespace: string; name: string }) => void
9
+ }
10
+
11
+ function SinkProperty({ sink, ns, onNavigate }: { sink: any; ns: string; onNavigate?: RendererProps['onNavigate'] }) {
12
+ if (!sink) return <Property label="Sink" value="-" />
13
+
14
+ if (sink.ref) {
15
+ return (
16
+ <Property label="Sink" value={
17
+ <ResourceLink
18
+ name={sink.ref.name}
19
+ kind={(sink.ref.kind?.toLowerCase() || 'services') + (sink.ref.kind?.toLowerCase().endsWith('s') ? '' : 's')}
20
+ namespace={sink.ref.namespace || ns}
21
+ onNavigate={onNavigate}
22
+ />
23
+ } />
24
+ )
25
+ }
26
+
27
+ if (sink.uri) {
28
+ return <Property label="Sink URI" value={
29
+ <span className="text-theme-text-primary break-all">{sink.uri}</span>
30
+ } />
31
+ }
32
+
33
+ return <Property label="Sink" value="-" />
34
+ }
35
+
36
+ // ============================================================================
37
+ // PingSource
38
+ // ============================================================================
39
+
40
+ export function PingSourceRenderer({ data, onNavigate }: RendererProps) {
41
+ const status = getKnativeConditionStatus(data)
42
+ const ns = data.metadata?.namespace || ''
43
+ const spec = data.spec || {}
44
+
45
+ return (
46
+ <>
47
+ <KnativeNotReadyBanner status={status} data={data} resourceType="PingSource" />
48
+
49
+ <Section title="Overview" icon={Clock} defaultExpanded>
50
+ <PropertyList>
51
+ <Property label="Status" value={
52
+ <span className={clsx('px-2 py-0.5 rounded text-xs font-medium', status.color)}>
53
+ {status.text}
54
+ </span>
55
+ } />
56
+ <Property label="Schedule" value={spec.schedule} />
57
+ <Property label="Timezone" value={spec.timezone} />
58
+ <Property label="Content Type" value={spec.contentType} />
59
+ <Property label="Data" value={spec.data ? (
60
+ <span className="font-mono text-xs break-all">{spec.data.length > 200 ? spec.data.slice(0, 200) + '...' : spec.data}</span>
61
+ ) : undefined} />
62
+ <SinkProperty sink={spec.sink} ns={ns} onNavigate={onNavigate} />
63
+ </PropertyList>
64
+ </Section>
65
+
66
+ <ConditionsSection conditions={data.status?.conditions || []} />
67
+ </>
68
+ )
69
+ }
70
+
71
+ // ============================================================================
72
+ // ApiServerSource
73
+ // ============================================================================
74
+
75
+ export function ApiServerSourceRenderer({ data, onNavigate }: RendererProps) {
76
+ const status = getKnativeConditionStatus(data)
77
+ const ns = data.metadata?.namespace || ''
78
+ const spec = data.spec || {}
79
+ const resources = spec.resources || []
80
+
81
+ return (
82
+ <>
83
+ <KnativeNotReadyBanner status={status} data={data} resourceType="ApiServerSource" />
84
+
85
+ <Section title="Overview" icon={Server} defaultExpanded>
86
+ <PropertyList>
87
+ <Property label="Status" value={
88
+ <span className={clsx('px-2 py-0.5 rounded text-xs font-medium', status.color)}>
89
+ {status.text}
90
+ </span>
91
+ } />
92
+ <Property label="Mode" value={spec.mode || spec.eventMode} />
93
+ <Property label="Service Account" value={spec.serviceAccountName} />
94
+ <SinkProperty sink={spec.sink} ns={ns} onNavigate={onNavigate} />
95
+ </PropertyList>
96
+ </Section>
97
+
98
+ {resources.length > 0 && (
99
+ <Section title={`Watched Resources (${resources.length})`} defaultExpanded>
100
+ <div className="space-y-1.5">
101
+ {resources.map((r: any, i: number) => (
102
+ <div key={i} className="bg-theme-elevated/30 rounded p-2 text-sm">
103
+ <span className="text-theme-text-primary">{r.apiVersion}/{r.kind}</span>
104
+ {r.selector && (
105
+ <div className="text-xs text-theme-text-tertiary mt-0.5">
106
+ selector: {typeof r.selector === 'string' ? r.selector : JSON.stringify(r.selector.matchLabels || r.selector)}
107
+ </div>
108
+ )}
109
+ </div>
110
+ ))}
111
+ </div>
112
+ </Section>
113
+ )}
114
+
115
+ <ConditionsSection conditions={data.status?.conditions || []} />
116
+ </>
117
+ )
118
+ }
119
+
120
+ // ============================================================================
121
+ // ContainerSource
122
+ // ============================================================================
123
+
124
+ export function ContainerSourceRenderer({ data, onNavigate }: RendererProps) {
125
+ const status = getKnativeConditionStatus(data)
126
+ const ns = data.metadata?.namespace || ''
127
+ const spec = data.spec || {}
128
+ const template = spec.template?.spec || {}
129
+ const containers = template.containers || []
130
+
131
+ return (
132
+ <>
133
+ <KnativeNotReadyBanner status={status} data={data} resourceType="ContainerSource" />
134
+
135
+ <Section title="Overview" icon={Container} defaultExpanded>
136
+ <PropertyList>
137
+ <Property label="Status" value={
138
+ <span className={clsx('px-2 py-0.5 rounded text-xs font-medium', status.color)}>
139
+ {status.text}
140
+ </span>
141
+ } />
142
+ <SinkProperty sink={spec.sink} ns={ns} onNavigate={onNavigate} />
143
+ </PropertyList>
144
+ </Section>
145
+
146
+ {containers.length > 0 && (
147
+ <Section title={`Containers (${containers.length})`} defaultExpanded>
148
+ <div className="space-y-2">
149
+ {containers.map((c: any, i: number) => (
150
+ <div key={i} className="bg-theme-elevated/30 rounded p-2 text-sm">
151
+ <div className="font-medium text-theme-text-primary">{c.name || 'container'}</div>
152
+ <div className="text-xs text-theme-text-secondary truncate" title={c.image}>{c.image}</div>
153
+ {c.args && c.args.length > 0 && (
154
+ <div className="text-xs text-theme-text-tertiary mt-1 font-mono truncate">
155
+ $ {c.args.join(' ')}
156
+ </div>
157
+ )}
158
+ </div>
159
+ ))}
160
+ </div>
161
+ </Section>
162
+ )}
163
+
164
+ <ConditionsSection conditions={data.status?.conditions || []} />
165
+ </>
166
+ )
167
+ }
168
+
169
+ // ============================================================================
170
+ // SinkBinding
171
+ // ============================================================================
172
+
173
+ export function SinkBindingRenderer({ data, onNavigate }: RendererProps) {
174
+ const status = getKnativeConditionStatus(data)
175
+ const ns = data.metadata?.namespace || ''
176
+ const spec = data.spec || {}
177
+ const subjectRef = spec.subject
178
+
179
+ return (
180
+ <>
181
+ <KnativeNotReadyBanner status={status} data={data} resourceType="SinkBinding" />
182
+
183
+ <Section title="Overview" icon={Link2} defaultExpanded>
184
+ <PropertyList>
185
+ <Property label="Status" value={
186
+ <span className={clsx('px-2 py-0.5 rounded text-xs font-medium', status.color)}>
187
+ {status.text}
188
+ </span>
189
+ } />
190
+ {subjectRef && (
191
+ <>
192
+ <Property label="Subject Kind" value={subjectRef.kind} />
193
+ <Property label="Subject API" value={subjectRef.apiVersion} />
194
+ {subjectRef.name && (
195
+ <Property label="Subject" value={
196
+ <ResourceLink
197
+ name={subjectRef.name}
198
+ kind={(subjectRef.kind?.toLowerCase() || 'deployments') + 's'}
199
+ namespace={subjectRef.namespace || ns}
200
+ onNavigate={onNavigate}
201
+ />
202
+ } />
203
+ )}
204
+ {subjectRef.selector && (
205
+ <Property label="Selector" value={
206
+ <span className="text-xs font-mono">
207
+ {JSON.stringify(subjectRef.selector.matchLabels || subjectRef.selector)}
208
+ </span>
209
+ } />
210
+ )}
211
+ </>
212
+ )}
213
+ <SinkProperty sink={spec.sink} ns={ns} onNavigate={onNavigate} />
214
+ </PropertyList>
215
+ </Section>
216
+
217
+ <ConditionsSection conditions={data.status?.conditions || []} />
218
+ </>
219
+ )
220
+ }
@@ -0,0 +1,151 @@
1
+ import { Layers, FolderTree } from 'lucide-react'
2
+ import { Section, PropertyList, Property, ConditionsSection, ProblemAlerts } from '../../ui/drawer-components'
3
+ import { formatAge } from '../resource-utils'
4
+ import { GitOpsStatusBadge, ManagedResourcesList, SyncCountdown } from '../../gitops'
5
+ import { fluxConditionsToGitOpsStatus, parseFluxInventory, type FluxCondition } from '../../../types/gitops'
6
+
7
+ interface KustomizationRendererProps {
8
+ data: any
9
+ }
10
+
11
+ export function KustomizationRenderer({ data }: KustomizationRendererProps) {
12
+ const status = data.status || {}
13
+ const spec = data.spec || {}
14
+ const conditions = (status.conditions || []) as FluxCondition[]
15
+ const inventoryEntries = status.inventory?.entries || []
16
+
17
+ // Convert to unified GitOps status
18
+ const gitOpsStatus = fluxConditionsToGitOpsStatus(conditions, spec.suspend === true)
19
+
20
+ // Parse inventory to managed resources
21
+ const managedResources = parseFluxInventory(inventoryEntries)
22
+
23
+ // Problem detection for alerts
24
+ const problems: Array<{ color: 'red' | 'yellow'; message: string }> = []
25
+
26
+ if (gitOpsStatus.suspended) {
27
+ problems.push({ color: 'yellow', message: 'Kustomization is suspended' })
28
+ }
29
+
30
+ if (gitOpsStatus.health === 'Degraded' && gitOpsStatus.message) {
31
+ problems.push({ color: 'red', message: gitOpsStatus.message })
32
+ }
33
+
34
+ const healthyCondition = conditions.find(c => c.type === 'Healthy')
35
+ if (healthyCondition?.status === 'False' && healthyCondition.message) {
36
+ problems.push({
37
+ color: 'yellow',
38
+ message: healthyCondition.message || 'Deployed resources are not healthy',
39
+ })
40
+ }
41
+
42
+ // Source reference
43
+ const sourceRef = spec.sourceRef || {}
44
+
45
+ return (
46
+ <>
47
+ <ProblemAlerts problems={problems} />
48
+
49
+ {/* Status section */}
50
+ <Section title="Status">
51
+ <div className="space-y-3">
52
+ <GitOpsStatusBadge status={gitOpsStatus} />
53
+ {spec.interval && (
54
+ <SyncCountdown
55
+ interval={spec.interval}
56
+ lastSyncTime={status.lastHandledReconcileAt}
57
+ suspended={gitOpsStatus.suspended}
58
+ />
59
+ )}
60
+ </div>
61
+ </Section>
62
+
63
+ {/* Source Reference section */}
64
+ <Section title="Source" icon={FolderTree}>
65
+ <PropertyList>
66
+ <Property label="Kind" value={sourceRef.kind} />
67
+ <Property label="Name" value={sourceRef.name} />
68
+ {sourceRef.namespace && (
69
+ <Property label="Namespace" value={sourceRef.namespace} />
70
+ )}
71
+ <Property label="Path" value={spec.path || './'} />
72
+ </PropertyList>
73
+ </Section>
74
+
75
+ {/* Configuration section */}
76
+ <Section title="Configuration" icon={Layers}>
77
+ <PropertyList>
78
+ <Property
79
+ label="Prune"
80
+ value={spec.prune ? 'Enabled' : 'Disabled'}
81
+ />
82
+ <Property label="Target Namespace" value={spec.targetNamespace} />
83
+ <Property label="Service Account" value={spec.serviceAccountName} />
84
+ <Property label="Timeout" value={spec.timeout} />
85
+ {spec.retryInterval && (
86
+ <Property label="Retry Interval" value={spec.retryInterval} />
87
+ )}
88
+ {spec.force !== undefined && (
89
+ <Property label="Force" value={spec.force ? 'Yes' : 'No'} />
90
+ )}
91
+ {spec.wait !== undefined && (
92
+ <Property label="Wait" value={spec.wait ? 'Yes' : 'No'} />
93
+ )}
94
+ </PropertyList>
95
+ </Section>
96
+
97
+ {/* Health checks */}
98
+ {spec.healthChecks && spec.healthChecks.length > 0 && (
99
+ <Section title={`Health Checks (${spec.healthChecks.length})`} defaultExpanded={false}>
100
+ <div className="space-y-1">
101
+ {spec.healthChecks.map((check: any, idx: number) => (
102
+ <div
103
+ key={idx}
104
+ className="text-sm px-2 py-1 bg-theme-elevated/30 rounded"
105
+ >
106
+ <span className="text-theme-text-tertiary">{check.kind}/</span>
107
+ <span className="text-theme-text-primary">{check.name}</span>
108
+ {check.namespace && (
109
+ <span className="text-theme-text-tertiary ml-1">
110
+ ({check.namespace})
111
+ </span>
112
+ )}
113
+ </div>
114
+ ))}
115
+ </div>
116
+ </Section>
117
+ )}
118
+
119
+ {/* Managed Resources (Inventory) */}
120
+ {managedResources.length > 0 && (
121
+ <ManagedResourcesList
122
+ resources={managedResources}
123
+ title={`Inventory (${managedResources.length} resources)`}
124
+ />
125
+ )}
126
+
127
+ {/* Revision info */}
128
+ {(status.lastAppliedRevision || status.lastAttemptedRevision) && (
129
+ <Section title="Revision" defaultExpanded={false}>
130
+ <PropertyList>
131
+ {status.lastAppliedRevision && (
132
+ <Property label="Applied" value={status.lastAppliedRevision} />
133
+ )}
134
+ {status.lastAttemptedRevision && status.lastAttemptedRevision !== status.lastAppliedRevision && (
135
+ <Property label="Attempted" value={status.lastAttemptedRevision} />
136
+ )}
137
+ {status.lastHandledReconcileAt && (
138
+ <Property
139
+ label="Last Reconciled"
140
+ value={formatAge(status.lastHandledReconcileAt)}
141
+ />
142
+ )}
143
+ </PropertyList>
144
+ </Section>
145
+ )}
146
+
147
+ {/* Conditions section */}
148
+ <ConditionsSection conditions={conditions} />
149
+ </>
150
+ )
151
+ }