@skyhook-io/k8s-ui 1.16.3 → 1.17.1

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 (309) hide show
  1. package/README.md +41 -0
  2. package/package.json +3 -3
  3. package/src/components/applications/ApplicationDetail.test.tsx +15 -0
  4. package/src/components/applications/ApplicationDetail.tsx +17 -15
  5. package/src/components/charts/AreaChart.interaction.test.tsx +118 -0
  6. package/src/components/charts/AreaChart.test.tsx +25 -0
  7. package/src/components/charts/AreaChart.tsx +141 -12
  8. package/src/components/charts/index.ts +1 -0
  9. package/src/components/checks/ChecksView.tsx +18 -1
  10. package/src/components/checks/types.ts +2 -13
  11. package/src/components/cnpg/CNPGBackupSummary.tsx +57 -9
  12. package/src/components/cnpg/CNPGClusterHASection.test.tsx +90 -0
  13. package/src/components/cnpg/CNPGClusterHASection.tsx +331 -0
  14. package/src/components/cnpg/CNPGClusterSummary.test.tsx +275 -0
  15. package/src/components/cnpg/CNPGClusterSummary.tsx +310 -96
  16. package/src/components/cnpg/CNPGConnectSection.test.tsx +64 -0
  17. package/src/components/cnpg/CNPGConnectSection.tsx +178 -0
  18. package/src/components/cnpg/CNPGDeclarativeSummary.tsx +157 -26
  19. package/src/components/cnpg/CNPGImageCatalogSummary.tsx +7 -4
  20. package/src/components/cnpg/CNPGLogicalPath.test.tsx +22 -0
  21. package/src/components/cnpg/CNPGLogicalPath.tsx +150 -0
  22. package/src/components/cnpg/CNPGObjectStoreSummary.tsx +9 -6
  23. package/src/components/cnpg/CNPGObjectSummary.test.tsx +193 -2
  24. package/src/components/cnpg/CNPGPoolerScheduling.test.tsx +36 -0
  25. package/src/components/cnpg/CNPGPoolerSummary.tsx +241 -14
  26. package/src/components/cnpg/CNPGSharedSummary.tsx +15 -8
  27. package/src/components/cnpg/CNPGWALArchivingFact.test.tsx +39 -0
  28. package/src/components/cnpg/backupRuns.test.ts +17 -0
  29. package/src/components/cnpg/backupRuns.ts +19 -0
  30. package/src/components/cnpg/connect.test.ts +124 -0
  31. package/src/components/cnpg/connect.ts +155 -0
  32. package/src/components/cnpg/databaseRole.test.ts +38 -0
  33. package/src/components/cnpg/databaseRole.ts +80 -0
  34. package/src/components/cnpg/ha.test.ts +446 -0
  35. package/src/components/cnpg/ha.ts +621 -0
  36. package/src/components/cnpg/index.ts +18 -0
  37. package/src/components/cnpg/logicalReplication.test.ts +121 -0
  38. package/src/components/cnpg/logicalReplication.ts +252 -0
  39. package/src/components/cnpg/pooler.test.ts +84 -0
  40. package/src/components/cnpg/pooler.ts +225 -0
  41. package/src/components/cnpg/primitives.tsx +21 -117
  42. package/src/components/cnpg/problems.ts +12 -0
  43. package/src/components/cnpg/relations.test.ts +63 -13
  44. package/src/components/cnpg/relations.ts +61 -52
  45. package/src/components/cnpg/schedule.ts +35 -0
  46. package/src/components/cnpg/workspace-disk.test.ts +97 -0
  47. package/src/components/cnpg/workspace-fleet-metrics.test.ts +250 -0
  48. package/src/components/cnpg/workspace-problems.test.ts +175 -0
  49. package/src/components/cnpg/workspace.test.ts +380 -9
  50. package/src/components/cnpg/workspace.ts +1137 -136
  51. package/src/components/dock/DockContext.test.tsx +32 -0
  52. package/src/components/dock/DockContext.tsx +18 -4
  53. package/src/components/dock/LocalTerminalTab.test.tsx +40 -0
  54. package/src/components/dock/LocalTerminalTab.tsx +4 -3
  55. package/src/components/dock/TerminalTab.tsx +20 -8
  56. package/src/components/facts/certainty.tsx +36 -0
  57. package/src/components/facts/facts.test.tsx +24 -0
  58. package/src/components/facts/facts.tsx +62 -0
  59. package/src/components/facts/index.ts +6 -0
  60. package/src/components/facts/managed-by.test.tsx +17 -0
  61. package/src/components/facts/managed-by.tsx +36 -0
  62. package/src/components/facts/public-exports.test.tsx +35 -0
  63. package/src/components/gitops/GitOpsGraphFilterRail.tsx +6 -2
  64. package/src/components/gitops/GitOpsHealthSourceNotice.test.tsx +38 -0
  65. package/src/components/gitops/GitOpsHealthSourceNotice.tsx +13 -3
  66. package/src/components/gitops/GitOpsTableView.tsx +9 -24
  67. package/src/components/gitops/detail-helpers.ts +1 -1
  68. package/src/components/gitops/insights/ArgoResourceDiff.test.tsx +115 -0
  69. package/src/components/gitops/insights/ArgoResourceDiff.tsx +22 -5
  70. package/src/components/gitops/insights/DriftPanel.tsx +62 -0
  71. package/src/components/gitops/insights/GitOpsInsightViews.tsx +29 -83
  72. package/src/components/gitops/tree/GitOpsTreeGraph.test.ts +26 -1
  73. package/src/components/gitops/tree/GitOpsTreeGraph.tsx +40 -60
  74. package/src/components/gitops/tree/layout.test.ts +111 -0
  75. package/src/components/gitops/tree/layout.ts +128 -0
  76. package/src/components/gitops/tree/tree-helpers.test.ts +17 -0
  77. package/src/components/gitops/tree/tree-helpers.ts +7 -1
  78. package/src/components/issues/ConditionalCleanup.test.tsx +82 -0
  79. package/src/components/issues/IssuesView.tsx +40 -5
  80. package/src/components/issues/ResourceIssuesSection.test.tsx +28 -0
  81. package/src/components/issues/ResourceIssuesSection.tsx +3 -0
  82. package/src/components/issues/index.ts +3 -1
  83. package/src/components/issues/issue-timing.ts +14 -3
  84. package/src/components/issues/issues.test.ts +50 -2
  85. package/src/components/issues/severity.ts +21 -0
  86. package/src/components/issues/types.ts +23 -0
  87. package/src/components/logs/LogCore.theme.test.tsx +81 -3
  88. package/src/components/logs/LogCore.tsx +25 -17
  89. package/src/components/logs/LogToolbarSelects.tsx +3 -1
  90. package/src/components/logs/LogsViewer.test.tsx +291 -0
  91. package/src/components/logs/LogsViewer.tsx +72 -11
  92. package/src/components/logs/StructuredLogLine.test.tsx +76 -0
  93. package/src/components/logs/StructuredLogLine.tsx +22 -30
  94. package/src/components/logs/WorkloadLogsViewer.notice.test.tsx +59 -0
  95. package/src/components/logs/WorkloadLogsViewer.test.tsx +65 -0
  96. package/src/components/logs/WorkloadLogsViewer.tsx +44 -10
  97. package/src/components/logs/useLogBuffer.test.ts +8 -0
  98. package/src/components/logs/useLogStream.ts +28 -1
  99. package/src/components/problems/index.ts +1 -0
  100. package/src/components/problems/problems.test.tsx +63 -0
  101. package/src/components/problems/problems.tsx +165 -0
  102. package/src/components/resources/ActiveFilterBar.test.tsx +78 -0
  103. package/src/components/resources/ActiveFilterBar.tsx +86 -0
  104. package/src/components/resources/ResourcesSidebar.keyboard.test.tsx +42 -0
  105. package/src/components/resources/ResourcesSidebar.test.tsx +36 -2
  106. package/src/components/resources/ResourcesSidebar.tsx +92 -41
  107. package/src/components/resources/ResourcesView.kind-filter-memory.test.ts +52 -0
  108. package/src/components/resources/ResourcesView.kind-view.test.tsx +149 -0
  109. package/src/components/resources/ResourcesView.per-container.test.ts +56 -1
  110. package/src/components/resources/ResourcesView.tsx +309 -117
  111. package/src/components/resources/curated-column-ownership.test.ts +3 -3
  112. package/src/components/resources/renderers/AnalysisRunRenderer.tsx +3 -3
  113. package/src/components/resources/renderers/ArgoApplicationRenderer.tsx +6 -5
  114. package/src/components/resources/renderers/AutoscalingReferences.test.tsx +286 -0
  115. package/src/components/resources/renderers/CAPIClusterRenderer.tsx +5 -4
  116. package/src/components/resources/renderers/CAPIExactReferenceNavigation.test.tsx +27 -0
  117. package/src/components/resources/renderers/CAPIKubeadmControlPlaneRenderer.tsx +2 -2
  118. package/src/components/resources/renderers/CAPIMachineDeploymentRenderer.tsx +2 -2
  119. package/src/components/resources/renderers/CAPIMachinePoolRenderer.tsx +2 -2
  120. package/src/components/resources/renderers/CAPIMachineRenderer.tsx +2 -2
  121. package/src/components/resources/renderers/CAPIMachineSetRenderer.tsx +2 -2
  122. package/src/components/resources/renderers/CNPGBackupRenderer.test.tsx +23 -0
  123. package/src/components/resources/renderers/CNPGBackupRenderer.tsx +8 -19
  124. package/src/components/resources/renderers/CNPGClusterRenderer.tsx +7 -8
  125. package/src/components/resources/renderers/CNPGDeclarativeRenderer.tsx +25 -0
  126. package/src/components/resources/renderers/CNPGScheduledBackupRenderer.test.tsx +32 -0
  127. package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +9 -17
  128. package/src/components/resources/renderers/CNPGShared.tsx +2 -2
  129. package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +2 -2
  130. package/src/components/resources/renderers/CompositeRenderer.navigation.test.tsx +35 -0
  131. package/src/components/resources/renderers/CompositeRenderer.tsx +3 -3
  132. package/src/components/resources/renderers/CompositionRenderer.tsx +3 -3
  133. package/src/components/resources/renderers/ConfigAuditReportRenderer.tsx +2 -2
  134. package/src/components/resources/renderers/ContourExactReferenceNavigation.test.tsx +34 -0
  135. package/src/components/resources/renderers/ContourHTTPProxyRenderer.tsx +11 -10
  136. package/src/components/resources/renderers/CronJobRenderer.tsx +6 -4
  137. package/src/components/resources/renderers/CronWorkflowRenderer.tsx +3 -2
  138. package/src/components/resources/renderers/EndpointSliceRenderer.test.tsx +62 -0
  139. package/src/components/resources/renderers/EndpointSliceRenderer.tsx +15 -14
  140. package/src/components/resources/renderers/EventRenderer.tsx +3 -3
  141. package/src/components/resources/renderers/ExperimentRenderer.tsx +2 -2
  142. package/src/components/resources/renderers/ExposedSecretReportRenderer.tsx +2 -2
  143. package/src/components/resources/renderers/ExternalSecretRenderer.tsx +2 -2
  144. package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +4 -4
  145. package/src/components/resources/renderers/GRPCRouteRenderer.tsx +11 -24
  146. package/src/components/resources/renderers/GatewayRouteReferences.test.tsx +63 -0
  147. package/src/components/resources/renderers/GitRepositoryRenderer.tsx +3 -3
  148. package/src/components/resources/renderers/HPARenderer.tsx +57 -17
  149. package/src/components/resources/renderers/HTTPRouteRenderer.tsx +12 -25
  150. package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +3 -3
  151. package/src/components/resources/renderers/IngressClassReferences.test.tsx +52 -0
  152. package/src/components/resources/renderers/IngressClassRenderer.tsx +10 -3
  153. package/src/components/resources/renderers/IngressRenderer.defaultBackend.test.tsx +33 -0
  154. package/src/components/resources/renderers/IngressRenderer.tsx +36 -5
  155. package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +9 -9
  156. package/src/components/resources/renderers/IstioExactReferenceNavigation.test.tsx +34 -0
  157. package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +5 -8
  158. package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +2 -14
  159. package/src/components/resources/renderers/KedaCredentials.test.tsx +85 -0
  160. package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +15 -13
  161. package/src/components/resources/renderers/KedaTriggerAuthRenderer.tsx +6 -3
  162. package/src/components/resources/renderers/KnativeEventingRenderer.tsx +24 -31
  163. package/src/components/resources/renderers/KnativeExactReferenceNavigation.test.tsx +47 -0
  164. package/src/components/resources/renderers/KnativeFlowRenderer.tsx +6 -7
  165. package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +7 -9
  166. package/src/components/resources/renderers/KnativeReferenceLink.tsx +14 -0
  167. package/src/components/resources/renderers/KnativeReferenceLinks.test.tsx +60 -0
  168. package/src/components/resources/renderers/KnativeSourceRenderer.tsx +9 -11
  169. package/src/components/resources/renderers/KustomizationRenderer.tsx +2 -2
  170. package/src/components/resources/renderers/KyvernoGlobalContextRenderer.tsx +3 -2
  171. package/src/components/resources/renderers/KyvernoQueueRenderers.tsx +4 -3
  172. package/src/components/resources/renderers/LeaseRenderer.tsx +3 -15
  173. package/src/components/resources/renderers/ManagedResourceRenderer.tsx +2 -2
  174. package/src/components/resources/renderers/MetricsUnavailableNotice.tsx +3 -2
  175. package/src/components/resources/renderers/NamespaceRenderer.test.ts +69 -2
  176. package/src/components/resources/renderers/NamespaceRenderer.tsx +6 -1
  177. package/src/components/resources/renderers/NodeRenderer.test.tsx +81 -1
  178. package/src/components/resources/renderers/NodeRenderer.tsx +56 -15
  179. package/src/components/resources/renderers/OCIRepositoryRenderer.tsx +3 -3
  180. package/src/components/resources/renderers/PodClassReferences.test.tsx +42 -0
  181. package/src/components/resources/renderers/PodNomination.test.tsx +57 -0
  182. package/src/components/resources/renderers/PodRenderer.test.tsx +32 -0
  183. package/src/components/resources/renderers/PodRenderer.tsx +62 -36
  184. package/src/components/resources/renderers/RolloutRenderer.test.tsx +1 -1
  185. package/src/components/resources/renderers/RolloutRenderer.tsx +3 -2
  186. package/src/components/resources/renderers/SbomReportRenderer.tsx +2 -2
  187. package/src/components/resources/renderers/SecretRenderer.test.tsx +88 -0
  188. package/src/components/resources/renderers/SecretRenderer.tsx +34 -5
  189. package/src/components/resources/renderers/ServiceRenderer.test.tsx +43 -0
  190. package/src/components/resources/renderers/ServiceRenderer.tsx +11 -3
  191. package/src/components/resources/renderers/SimpleRouteRenderer.tsx +9 -22
  192. package/src/components/resources/renderers/VPARenderer.tsx +17 -11
  193. package/src/components/resources/renderers/VeleroBSLRenderer.tsx +5 -7
  194. package/src/components/resources/renderers/VeleroBackupRenderer.tsx +3 -3
  195. package/src/components/resources/renderers/VeleroBackupRepositoryRenderer.tsx +2 -2
  196. package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +3 -3
  197. package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +2 -2
  198. package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +2 -2
  199. package/src/components/resources/renderers/WorkflowRenderer.tsx +4 -3
  200. package/src/components/resources/renderers/kyverno-modern-cells.tsx +1 -1
  201. package/src/components/resources/renderers/rollout/ReplicaSetProgression.tsx +2 -2
  202. package/src/components/resources/resource-utils-capi.ts +1 -1
  203. package/src/components/resources/resource-utils-cnpg.test.ts +35 -10
  204. package/src/components/resources/resource-utils-cnpg.ts +51 -24
  205. package/src/components/resources/resource-utils-contour.test.ts +44 -0
  206. package/src/components/resources/resource-utils-contour.ts +16 -0
  207. package/src/components/resources/resource-utils-istio.ts +12 -8
  208. package/src/components/resources/resource-utils-keda.ts +1 -7
  209. package/src/components/resources/resource-utils-knative.ts +18 -0
  210. package/src/components/resources/resource-utils-kyverno.ts +1 -7
  211. package/src/components/resources/resource-utils-velero.ts +0 -12
  212. package/src/components/resources/resource-utils.ts +99 -39
  213. package/src/components/resources/rules-column-width.test.ts +1 -1
  214. package/src/components/resources/summarize-scheduler-message.test.ts +30 -0
  215. package/src/components/shared/ActionConfirmDialog.test.tsx +154 -0
  216. package/src/components/shared/ActionConfirmDialog.tsx +246 -0
  217. package/src/components/shared/CreateResourceDialog.test.tsx +330 -0
  218. package/src/components/shared/CreateResourceDialog.tsx +126 -80
  219. package/src/components/shared/DetailShell.test.tsx +80 -0
  220. package/src/components/shared/DetailShell.tsx +85 -10
  221. package/src/components/shared/DrainPlanDialog.tsx +1 -0
  222. package/src/components/shared/EditableYamlView.test.tsx +7 -0
  223. package/src/components/shared/EditableYamlView.tsx +1 -1
  224. package/src/components/shared/GitOpsWriteWarning.test.tsx +86 -0
  225. package/src/components/shared/GitOpsWriteWarning.tsx +135 -0
  226. package/src/components/shared/ResourceActionsBar.tsx +20 -24
  227. package/src/components/shared/ResourceRendererDispatch.tsx +13 -10
  228. package/src/components/shared/SetImageDialog.test.ts +75 -6
  229. package/src/components/shared/SetImageDialog.tsx +92 -84
  230. package/src/components/shared/index.ts +4 -1
  231. package/src/components/timeline/TimelineList.tsx +2 -15
  232. package/src/components/timeline/TimelineSwimlanes.tsx +3 -11
  233. package/src/components/timeline/timeline-filters.ts +1 -0
  234. package/src/components/topology/K8sResourceNode.test.ts +18 -1
  235. package/src/components/topology/K8sResourceNode.tsx +44 -2
  236. package/src/components/topology/TopologyFilterSidebar.tsx +1 -0
  237. package/src/components/topology/TopologyGraph.tsx +8 -74
  238. package/src/components/topology/TopologySearch.tsx +1 -0
  239. package/src/components/topology/internet-groups.test.ts +35 -0
  240. package/src/components/topology/internet-groups.ts +55 -0
  241. package/src/components/topology/layout.ts +1 -1
  242. package/src/components/ui/Badge.tsx +1 -0
  243. package/src/components/ui/FoldSection.tsx +68 -0
  244. package/src/components/ui/ForceDeleteConfirmDialog.test.tsx +62 -0
  245. package/src/components/ui/ForceDeleteConfirmDialog.tsx +24 -12
  246. package/src/components/ui/RefLink.tsx +20 -0
  247. package/src/components/ui/RowActionMenu.tsx +8 -3
  248. package/src/components/ui/ScheduleValue.test.tsx +5 -0
  249. package/src/components/ui/ScheduleValue.tsx +3 -2
  250. package/src/components/ui/crd-definition-navigation.test.tsx +160 -0
  251. package/src/components/ui/drawer-components.test.tsx +175 -1
  252. package/src/components/ui/drawer-components.tsx +103 -36
  253. package/src/components/ui/index.ts +3 -1
  254. package/src/components/ui/monacoEditorFeatures.ts +77 -0
  255. package/src/components/ui/monacoRuntime.ts +14 -19
  256. package/src/components/ui/status-tone.test.ts +10 -1
  257. package/src/components/ui/status-tone.tsx +29 -0
  258. package/src/components/workload/WorkloadView.deleted.test.tsx +101 -0
  259. package/src/components/workload/WorkloadView.deletedDialog.test.tsx +45 -0
  260. package/src/components/workload/WorkloadView.relationships.test.tsx +37 -0
  261. package/src/components/workload/WorkloadView.secretSave.test.tsx +62 -0
  262. package/src/components/workload/WorkloadView.spec.test.tsx +149 -0
  263. package/src/components/workload/WorkloadView.tsx +297 -104
  264. package/src/index.ts +14 -1
  265. package/src/monaco-deep.d.ts +19 -12
  266. package/src/theme/components.css +13 -0
  267. package/src/types/capacity.ts +21 -2
  268. package/src/types/core.ts +60 -2
  269. package/src/types/gitops-flux-status.test.ts +32 -1
  270. package/src/types/gitops-insights.ts +19 -2
  271. package/src/types/gitops-tree.ts +10 -0
  272. package/src/types/gitops.ts +26 -6
  273. package/src/utils/api-resources.ts +7 -0
  274. package/src/utils/application-history.ts +1 -0
  275. package/src/utils/cnpg-backup.test.ts +26 -0
  276. package/src/utils/cnpg-backup.ts +70 -0
  277. package/src/utils/format.test.ts +49 -2
  278. package/src/utils/format.ts +9 -1
  279. package/src/utils/gateway-references.test.ts +17 -0
  280. package/src/utils/gateway-references.ts +29 -0
  281. package/src/utils/gitops-owner.ts +3 -2
  282. package/src/utils/gitops-write-guard.test.ts +401 -0
  283. package/src/utils/gitops-write-guard.ts +509 -0
  284. package/src/utils/grant.test.ts +19 -0
  285. package/src/utils/grant.ts +35 -0
  286. package/src/utils/index.ts +6 -0
  287. package/src/utils/ingress-class-references.ts +22 -0
  288. package/src/utils/k8s-errors.ts +7 -7
  289. package/src/utils/log-format.test.ts +41 -0
  290. package/src/utils/log-format.ts +71 -15
  291. package/src/utils/log-level.ts +12 -8
  292. package/src/utils/navigation.test.ts +70 -0
  293. package/src/utils/navigation.ts +91 -8
  294. package/src/utils/node-lifecycle.test.ts +36 -0
  295. package/src/utils/node-lifecycle.ts +77 -0
  296. package/src/utils/object-reference-navigation.test.ts +43 -0
  297. package/src/utils/resource-hierarchy.test.ts +69 -0
  298. package/src/utils/resource-hierarchy.ts +41 -7
  299. package/src/utils/resource-icons.ts +2 -0
  300. package/src/utils/resource-refs.test.ts +23 -0
  301. package/src/utils/resource-refs.ts +30 -0
  302. package/src/utils/skeleton-yaml.test.ts +21 -0
  303. package/src/utils/skeleton-yaml.ts +16 -0
  304. package/src/utils/url-path.test.ts +35 -0
  305. package/src/utils/url-path.ts +21 -0
  306. package/src/utils/validators.test.ts +4 -13
  307. package/src/utils/validators.ts +5 -19
  308. package/src/utils/view-transition.test.ts +35 -1
  309. package/src/utils/view-transition.ts +16 -1
package/src/index.ts CHANGED
@@ -55,7 +55,7 @@ export * from './components/checks'
55
55
  // queue)
56
56
  export * from './components/issues'
57
57
 
58
- // CloudNativePG workspace model (fleet derivation over /api/cnpg/workspace)
58
+ // CloudNativePG workspace model (fleet derivation over /api/cnpg/workspace) and summaries
59
59
  export * from './components/cnpg'
60
60
 
61
61
  // Cluster switcher (shared trigger+dropdown for OSS Radar and Radar Hub)
@@ -82,3 +82,16 @@ export * from './components/compare'
82
82
 
83
83
  // Perf instrumentation (ELK + structureKey timers, surfaced in diagnostics overlay)
84
84
  export * from './perf'
85
+
86
+ export { CertaintyGlyph, certaintyGlyph, certaintyValueLabel, type Certainty } from './components/facts/certainty'
87
+
88
+ export * from './components/facts'
89
+ export {
90
+ WorkspaceProblemCallout,
91
+ ProblemList,
92
+ ProblemMeta,
93
+ OpenIssueContext,
94
+ problemOriginLabel,
95
+ type WorkspaceProblem,
96
+ type ProblemOrigin,
97
+ } from './components/problems'
@@ -1,15 +1,22 @@
1
+ // @monaco-editor/react and @monaco-editor/loader type monaco through this path,
2
+ // which monaco-editor's exports map does not serve.
1
3
  declare module 'monaco-editor/esm/vs/editor/editor.api' {
2
- export * from 'monaco-editor'
4
+ export * from 'monaco-editor/editor/editor.api'
3
5
  }
4
6
 
5
- declare module 'monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution'
6
- declare module 'monaco-editor/esm/vs/basic-languages/xml/xml.contribution'
7
- declare module 'monaco-editor/esm/vs/basic-languages/html/html.contribution'
8
- declare module 'monaco-editor/esm/vs/basic-languages/css/css.contribution'
9
- declare module 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution'
10
- declare module 'monaco-editor/esm/vs/basic-languages/typescript/typescript.contribution'
11
- declare module 'monaco-editor/esm/vs/basic-languages/python/python.contribution'
12
- declare module 'monaco-editor/esm/vs/basic-languages/shell/shell.contribution'
13
- declare module 'monaco-editor/esm/vs/basic-languages/markdown/markdown.contribution'
14
- declare module 'monaco-editor/esm/vs/basic-languages/ini/ini.contribution'
15
- declare module 'monaco-editor/esm/vs/basic-languages/dockerfile/dockerfile.contribution'
7
+ declare module 'monaco-editor/languages/definitions/yaml/register'
8
+ declare module 'monaco-editor/languages/definitions/xml/register'
9
+ declare module 'monaco-editor/languages/definitions/html/register'
10
+ declare module 'monaco-editor/languages/definitions/css/register'
11
+ declare module 'monaco-editor/languages/definitions/javascript/register'
12
+ declare module 'monaco-editor/languages/definitions/typescript/register'
13
+ declare module 'monaco-editor/languages/definitions/python/register'
14
+ declare module 'monaco-editor/languages/definitions/shell/register'
15
+ declare module 'monaco-editor/languages/definitions/markdown/register'
16
+ declare module 'monaco-editor/languages/definitions/ini/register'
17
+ declare module 'monaco-editor/languages/definitions/dockerfile/register'
18
+ declare module 'monaco-editor/editor/contrib/*'
19
+ declare module 'monaco-editor/editor/standalone/*'
20
+ declare module 'monaco-editor/editor/browser/*'
21
+ declare module 'monaco-editor/editor/common/*'
22
+ declare module 'monaco-editor/features/*'
@@ -35,6 +35,19 @@
35
35
  opacity: 0.5;
36
36
  }
37
37
 
38
+ .btn-secondary {
39
+ border: 1px solid var(--border-default);
40
+ background-color: var(--bg-surface);
41
+ color: var(--text-primary);
42
+ border-radius: 0.625rem;
43
+ }
44
+ .btn-secondary:hover {
45
+ background-color: var(--bg-hover);
46
+ }
47
+ .btn-secondary:disabled {
48
+ opacity: 0.5;
49
+ }
50
+
38
51
  .btn-brand-toggle {
39
52
  background-color: color-mix(in srgb, var(--color-brand) 50%, transparent);
40
53
  color: var(--text-primary);
@@ -1,4 +1,6 @@
1
1
  import type { Issue } from "../components/issues/types";
2
+ import type { Certainty } from "../components/facts/certainty";
3
+ import type { NodeLifecycleObservation } from "../utils/node-lifecycle";
2
4
 
3
5
  export const CAPACITY_SCHEMA_VERSION = "v1alpha1" as const;
4
6
 
@@ -15,8 +17,7 @@ export interface CapacityResourceIdentity {
15
17
  uid?: string;
16
18
  }
17
19
 
18
- export type CapacityCertainty =
19
- "exact" | "lower_bound" | "upper_bound" | "unknown";
20
+ export type CapacityCertainty = Certainty;
20
21
  export type CapacityGranularity =
21
22
  "aggregate" | "aggregate_not_binpacked" | "per_node";
22
23
  export type CapacityResourceVector = Record<string, string>;
@@ -232,6 +233,14 @@ export interface CapacityClaimLifecycleSummary {
232
233
  }
233
234
 
234
235
  export interface CapacityNodeLifecycleSummary {
236
+ operational?: {
237
+ total: number;
238
+ ready: number;
239
+ notReady: number;
240
+ cordoned: number;
241
+ removing: number;
242
+ removingUnhealthy: number;
243
+ };
235
244
  total: number;
236
245
  ready: number;
237
246
  notReady: number;
@@ -325,6 +334,7 @@ export type CapacityClaimStage =
325
334
  | "unknown";
326
335
 
327
336
  export interface CapacityNodeMember {
337
+ lifecycle?: NodeLifecycleObservation;
328
338
  ready?: boolean;
329
339
  cordoned: boolean;
330
340
  conditions: CapacityCondition[];
@@ -408,6 +418,14 @@ export interface CapacityScalingFact {
408
418
  summary: string;
409
419
  }
410
420
 
421
+ /** Published scale-down observations; candidates do not imply a removal ETA. */
422
+ export interface CapacityAutoscalerScaleDown {
423
+ status?: string;
424
+ candidates?: number;
425
+ lastTransitionTime?: string;
426
+ asOf?: string;
427
+ }
428
+
411
429
  export interface CapacityAutoscalerBackoff {
412
430
  errorClass?: string;
413
431
  errorCode?: string;
@@ -430,6 +448,7 @@ export interface CapacityAutoscalerChildObservation {
430
448
  readyNodes?: number;
431
449
  totalNodes?: number;
432
450
  backoff?: CapacityAutoscalerBackoff;
451
+ scaleDown?: CapacityAutoscalerScaleDown;
433
452
  asOf?: string;
434
453
  }
435
454
 
package/src/types/core.ts CHANGED
@@ -164,9 +164,15 @@ export interface FeatureCapabilities {
164
164
  yamlSchemas?: boolean
165
165
  workloadImages?: boolean
166
166
  resourceIssues?: boolean
167
+ resourceIssueCoverage?: boolean
167
168
  podEnvironment?: boolean
168
169
  policyResource?: boolean
169
170
  workloadHistory?: boolean
171
+ cnpgWorkspace?: boolean
172
+ cnpgProtectionSetup?: boolean
173
+ gitopsWriteEvidence?: boolean
174
+ serviceEndpointSlices?: boolean
175
+ trafficRecords?: boolean
170
176
  }
171
177
 
172
178
  // DeploymentMode is the closed set of topologies Radar can run in.
@@ -198,6 +204,7 @@ export type CoreNodeKind =
198
204
  | 'HTTPRoute'
199
205
  | 'GRPCRoute'
200
206
  | 'TCPRoute'
207
+ | 'UDPRoute'
201
208
  | 'TLSRoute'
202
209
  | 'Service'
203
210
  | 'Deployment'
@@ -636,6 +643,8 @@ export interface ResourceRef {
636
643
 
637
644
  // Computed relationships for a resource
638
645
  export interface Relationships {
646
+ /** Istio registry domain supplied by the producer; omitted when unknown. */
647
+ istioServiceDomain?: string
639
648
  reflection?: {
640
649
  source?: ResourceRef
641
650
  sourceResourceVersion?: string
@@ -653,6 +662,15 @@ export interface Relationships {
653
662
  consumers?: ResourceRef[]
654
663
  scalers?: ResourceRef[]
655
664
  storageRefs?: ResourceRef[]
665
+ dependencies?: ResourceRef[]
666
+ dependents?: ResourceRef[]
667
+ monitors?: ResourceRef[]
668
+ monitorTargets?: ResourceRef[]
669
+ backends?: ResourceRef[]
670
+ routedFrom?: ResourceRef[]
671
+ protects?: ResourceRef[]
672
+ healthChecks?: ResourceRef[]
673
+ stagedPolicies?: ResourceRef[]
656
674
  scaleTarget?: ResourceRef
657
675
  pdbs?: ResourceRef[] // PodDisruptionBudgets protecting this workload
658
676
  networkPolicies?: ResourceRef[] // NetworkPolicy / CiliumNetworkPolicy / ClusterNetworkPolicy variants selecting this workload
@@ -723,6 +741,7 @@ export interface HPADiagnosis extends HPADiagnosisView {
723
741
  name?: string
724
742
  }
725
743
  bounds: HPABounds
744
+ /** Spec order keeps source references paired with values; unmatched status entries follow. */
726
745
  metrics?: HPAMetricSummary[]
727
746
  }
728
747
 
@@ -780,6 +799,8 @@ export interface APIResource {
780
799
  name: string // Plural name (e.g., "deployments")
781
800
  namespaced: boolean
782
801
  isCrd: boolean
802
+ /** Confirmed, readable cached CRD identity; never inferred from isCrd. */
803
+ definitionName?: string
783
804
  featured?: boolean
784
805
  verbs: string[]
785
806
  observation?: DynamicResourceObservation
@@ -817,6 +838,7 @@ export interface HelmRevision {
817
838
  appVersion: string
818
839
  description: string
819
840
  updated: string // ISO date string
841
+ deleted?: string
820
842
  }
821
843
 
822
844
  export type HelmOperationKind = 'release_failed' | 'upgrade_failed' | 'upgrade_rolled_back' | 'rollback' | 'pending'
@@ -1067,12 +1089,23 @@ export interface UpgradeInfo {
1067
1089
  error?: string
1068
1090
  // Machine-readable source-resolution failure, used to make the Helm drawer
1069
1091
  // explain whether tracking an OCI source can help.
1070
- sourceIssue?: 'untracked' | 'repo_index_error' | 'ambiguous_repository'
1092
+ sourceIssue?: 'untracked' | 'repo_index_error' | 'ambiguous_repository' | 'ambiguous_source' | 'source_unavailable'
1071
1093
  // True only when the error is a genuinely untracked source (registering a
1072
1094
  // chart source could fix it). Kept for compatibility; prefer sourceIssue.
1073
1095
  untracked?: boolean
1074
1096
  }
1075
1097
 
1098
+ export type ChartSourceCandidate =
1099
+ | { type: 'repository'; reference: string; url: string }
1100
+ | { type: 'oci'; reference: string; url?: never }
1101
+
1102
+ export interface ChartSourceStatus {
1103
+ recorded?: ChartSourceCandidate
1104
+ configured: boolean
1105
+ available: boolean
1106
+ candidates?: ChartSourceCandidate[]
1107
+ }
1108
+
1076
1109
  // Batch upgrade info keyed by "storageNamespace/name".
1077
1110
  export interface BatchUpgradeInfo {
1078
1111
  releases: Record<string, UpgradeInfo>
@@ -1284,10 +1317,12 @@ export interface MetricsDataPoint {
1284
1317
  export interface TrafficEndpoint {
1285
1318
  name: string
1286
1319
  namespace: string
1287
- kind: string // Pod, Service, External, Host, Unknown
1320
+ kind: string // Pod, Workload, Service, External, Host, Unknown
1288
1321
  ip?: string
1289
1322
  labels?: Record<string, string>
1290
1323
  workload?: string
1324
+ /** Deployment, StatefulSet, CronJob, … when resolved from the pod's owners. */
1325
+ workloadKind?: string
1291
1326
  port?: number
1292
1327
  }
1293
1328
 
@@ -1453,6 +1488,12 @@ export interface TrafficFlowsResponse {
1453
1488
  * nodeFlowLimit, so older traffic in the window did not fit. */
1454
1489
  coveredSince?: string
1455
1490
  nodeFlowLimit?: number
1491
+ /** Set when the source kept only its newest flowLimit flows in total; the
1492
+ * window is then complete only from coveredSince. */
1493
+ flowLimit?: number
1494
+ /** How many records the aggregation covers. `flows` holds only the newest of
1495
+ * them; a Radar that predates the cap omits this and sends every record. */
1496
+ flowsTotal?: number
1456
1497
  warning?: string // Non-fatal warning (e.g., query errors)
1457
1498
  /** 'transient' (or absent) means the condition may clear on its own and a
1458
1499
  * retry is worthwhile. 'partial' means the flows are correct but some of
@@ -1463,6 +1504,23 @@ export interface TrafficFlowsResponse {
1463
1504
  warningKind?: 'transient' | 'partial' | 'incomplete'
1464
1505
  }
1465
1506
 
1507
+ // Response from GET /api/traffic/flows/records — the newest records behind
1508
+ // one graph selection.
1509
+ export interface TrafficRecordsResponse {
1510
+ source: string
1511
+ timestamp: string
1512
+ /** Newest first, at most the server's records limit. */
1513
+ flows: TrafficFlow[]
1514
+ /** How many records matched; more than flows.length when capped. */
1515
+ matched: number
1516
+ l7ResponsesCallerOriented?: boolean
1517
+ coveredSince?: string
1518
+ nodeFlowLimit?: number
1519
+ flowLimit?: number
1520
+ warning?: string
1521
+ warningKind?: 'transient' | 'partial' | 'incomplete'
1522
+ }
1523
+
1466
1524
  // Wizard state for traffic setup
1467
1525
  export type TrafficWizardState = 'detecting' | 'not_found' | 'wizard' | 'checking' | 'ready'
1468
1526
 
@@ -29,13 +29,44 @@ describe('fluxConditionsToGitOpsStatus truth table', () => {
29
29
  })
30
30
 
31
31
  it('treats the -1 sentinel as drift', () => {
32
- const got = fluxConditionsToGitOpsStatus([c('Ready', 'False'), c('Reconciling', 'True')], false, {
32
+ // A first reconcile reports Ready=Unknown; a reported failure outranks drift.
33
+ const got = fluxConditionsToGitOpsStatus([c('Ready', 'Unknown'), c('Reconciling', 'True')], false, {
33
34
  generation: 1,
34
35
  observedGeneration: -1,
35
36
  })
36
37
  expect(got.sync).toBe('Reconciling')
37
38
  })
38
39
 
40
+ it('a failure while retrying and never reconciled is degraded', () => {
41
+ // Live shape of a GitRepository whose repository doesn't exist.
42
+ const got = fluxConditionsToGitOpsStatus(
43
+ [c('Reconciling', 'True', { reason: 'ProgressingWithRetry' }), c('Ready', 'False', { reason: 'GitOperationFailed', observedGeneration: 1 })],
44
+ false,
45
+ { generation: 1, observedGeneration: -1 },
46
+ )
47
+ expect(got.sync).toBe('OutOfSync')
48
+ expect(got.health).toBe('Degraded')
49
+ })
50
+
51
+ it('a failure about an older generation does not outrank a new spec', () => {
52
+ const got = fluxConditionsToGitOpsStatus([c('Ready', 'False', { reason: 'BuildFailed', observedGeneration: 2 })], false, {
53
+ generation: 3,
54
+ observedGeneration: 1,
55
+ })
56
+ expect(got.sync).toBe('Reconciling')
57
+ expect(got.health).toBe('Progressing')
58
+ })
59
+
60
+ it('a retry while reconciling stays progressing', () => {
61
+ const got = fluxConditionsToGitOpsStatus(
62
+ [c('Reconciling', 'True', { reason: 'Progressing' }), c('Ready', 'False', { reason: 'ProgressingWithRetry' })],
63
+ false,
64
+ { generation: 2, observedGeneration: 1 },
65
+ )
66
+ expect(got.sync).toBe('Reconciling')
67
+ expect(got.health).toBe('Progressing')
68
+ })
69
+
39
70
  it('does not treat an absent observedGeneration as drift', () => {
40
71
  // Kinds and controller versions that never set it must not all read stale.
41
72
  expect(fluxConditionsToGitOpsStatus([c('Ready', 'True')], false, { generation: 3 }).sync).toBe('Synced')
@@ -93,6 +93,12 @@ export interface GitOpsInsightSummary {
93
93
  // The controller's API server was asked and didn't answer usefully — why,
94
94
  // in the user's words. Only set when the integration is configured.
95
95
  resourceHealthApiError?: string
96
+ // The host is still connecting to the controller's API server; ask again
97
+ // shortly.
98
+ resourceHealthApiPending?: boolean
99
+ // The host couldn't reach the controller's API server and is retrying;
100
+ // ask again now and then.
101
+ resourceHealthApiRetrying?: boolean
96
102
  }
97
103
 
98
104
  export interface GitOpsIgnoredDifferences {
@@ -177,6 +183,8 @@ export interface GitOpsChange {
177
183
  recentEvents?: GitOpsEventSummary[]
178
184
  partial: boolean
179
185
  partialNote?: string
186
+ // A Flux source or dependsOn target the root consumes but doesn't manage.
187
+ dependency?: boolean
180
188
  }
181
189
 
182
190
  export interface GitOpsDrift {
@@ -247,6 +255,12 @@ export interface GitOpsCapabilities {
247
255
  // tell "not set up" (offer Connect) from "set up but disconnected" (offer
248
256
  // Reconnect) — instead of advertising a diff that would fail.
249
257
  argoConfigured?: boolean
258
+ // Configured, and the host is still making the first connection; ask
259
+ // again shortly instead of reporting the diff as down.
260
+ argoConnecting?: boolean
261
+ // Configured, the connection failed in a way that may pass on its own, and
262
+ // the host is retrying; ask again now and then.
263
+ argoRetrying?: boolean
250
264
  // True on an Argo CD Application detail when the integration is connected,
251
265
  // meaning the revision-metadata endpoint can resolve Git commit details
252
266
  // (author, message, signature) for this app's deployed revisions.
@@ -269,13 +283,16 @@ export interface ArgoRevisionMetadata {
269
283
  // Response of GET /api/argo/applications/{ns}/{name}/resource-diff. `desired`
270
284
  // is the Git-rendered manifest, `live` the normalized cluster state — both YAML
271
285
  // for the line-by-line view. `fieldEntries` is the same diff structured per
272
- // path for a compact summary. `redacted` is set when Secret values were masked
286
+ // path for a compact summary; Radars before the list was made non-null send
287
+ // null when it is empty. `fieldEntriesTruncated` is set when the list was cut
288
+ // at the server's entry cap. `redacted` is set when Secret values were masked
273
289
  // server-side; `hook` marks Argo sync-hook resources.
274
290
  export interface GitOpsResourceDiff {
275
291
  source: string
276
292
  desired: string
277
293
  live: string
278
- fieldEntries: GitOpsResourceDiffFieldEntry[]
294
+ fieldEntries: GitOpsResourceDiffFieldEntry[] | null
295
+ fieldEntriesTruncated?: boolean
279
296
  redacted: boolean
280
297
  hook: boolean
281
298
  }
@@ -43,6 +43,9 @@ export interface GitOpsTreeNode {
43
43
  // Lives on the destination cluster of a remote tree. This cluster's API
44
44
  // would answer for a different, same-named object.
45
45
  remote?: boolean
46
+ // Reached only through a Flux source, chart or dependsOn declaration: the
47
+ // root consumes it but does not manage it. Not counted as a managed resource.
48
+ dependency?: boolean
46
49
  }
47
50
 
48
51
  // 'controllerApi' is the controller's own verdict read from its API server
@@ -69,6 +72,7 @@ export interface GitOpsTreeSummary {
69
72
  grouped: number
70
73
  degraded: number
71
74
  outOfSync: number
75
+ dependencies?: number
72
76
  }
73
77
 
74
78
  export interface GitOpsResourceTree {
@@ -83,6 +87,12 @@ export interface GitOpsResourceTree {
83
87
  healthFromApi?: boolean
84
88
  // The controller's API server was asked and didn't answer usefully.
85
89
  healthApiError?: string
90
+ // The host is still connecting to the controller's API server; ask again
91
+ // shortly.
92
+ healthApiPending?: boolean
93
+ // The host couldn't reach the controller's API server and is retrying;
94
+ // ask again now and then.
95
+ healthApiRetrying?: boolean
86
96
  // The Application (or Flux object with spec.kubeConfig) deploys to another
87
97
  // cluster; Radar derives nothing about its resources from here.
88
98
  remoteDestination?: boolean
@@ -99,6 +99,7 @@ export interface FluxCondition {
99
99
  reason?: string
100
100
  message?: string
101
101
  lastTransitionTime?: string
102
+ observedGeneration?: number
102
103
  }
103
104
 
104
105
  // ============================================================================
@@ -141,8 +142,11 @@ function hasGenerationDrift(gen?: FluxGeneration): boolean {
141
142
  * - suspend → Suspended (sync from Ready, unless drifted)
142
143
  * - Stalled=True → OutOfSync / Degraded
143
144
  * - Ready=True and no generation drift → Synced, health from Healthy
145
+ * - Ready=False with a failure reason about
146
+ * the current generation → OutOfSync / Degraded
144
147
  * - drift, or Reconciling with Ready not True → Reconciling / Progressing
145
- * - Ready=False → OutOfSync
148
+ * - Ready=False → OutOfSync / Degraded, or
149
+ * Progressing for a retry/wait reason
146
150
  */
147
151
  export function fluxConditionsToGitOpsStatus(
148
152
  conditions: FluxCondition[],
@@ -203,6 +207,25 @@ export function fluxConditionsToGitOpsStatus(
203
207
  }
204
208
  }
205
209
 
210
+ // A failure the controller reported outranks activity too: a source that
211
+ // can't clone keeps Reconciling=True and never records observedGeneration
212
+ // while it retries, and reading that as "in progress" hid it.
213
+ const readyReason = readyCondition?.reason || ''
214
+ const transientReason = readyReason.includes('Progress') || readyReason.includes('Retry') || readyReason.includes('Wait')
215
+ // Only a failure about the current spec counts: after a fix, the old
216
+ // Ready=False describes an older generation until the controller looks again.
217
+ const currentFailure = readyCondition?.observedGeneration !== undefined && readyCondition.observedGeneration === generation?.generation
218
+ if (readyCondition?.status === 'False' && !transientReason && currentFailure) {
219
+ return {
220
+ sync: 'OutOfSync',
221
+ health: 'Degraded',
222
+ message: readyCondition.message,
223
+ lastSyncTime: readyCondition.lastTransitionTime,
224
+ suspended: false,
225
+ ...activity,
226
+ }
227
+ }
228
+
206
229
  // Genuinely not applied: the controller has not observed the current spec, or
207
230
  // it is working and has not reached Ready.
208
231
  if (drifted || isReconciling) {
@@ -216,14 +239,11 @@ export function fluxConditionsToGitOpsStatus(
216
239
  }
217
240
  }
218
241
 
219
- // Handle not ready state
242
+ // A retry or remediation in flight is out of sync, but not a settled failure.
220
243
  if (readyCondition?.status === 'False') {
221
- const reason = readyCondition.reason || ''
222
- const isTransient = reason.includes('Progress') || reason.includes('Retry') || reason.includes('Wait')
223
-
224
244
  return {
225
245
  sync: 'OutOfSync',
226
- health: isTransient ? 'Progressing' : 'Degraded',
246
+ health: transientReason ? 'Progressing' : 'Degraded',
227
247
  message: readyCondition.message,
228
248
  lastSyncTime: readyCondition.lastTransitionTime,
229
249
  suspended: false,
@@ -63,6 +63,13 @@ const ADDITIONAL_BUILTIN_IDENTITIES: Record<string, string> = {
63
63
  deviceclass: 'resource.k8s.io', deviceclasses: 'resource.k8s.io',
64
64
  };
65
65
 
66
+ // Kind spellings only: a resource name such as `services` is not a Kind.
67
+ const ADDITIONAL_CORE_KINDS: ReadonlySet<string> = new Set(['Endpoints'])
68
+
69
+ export function isBuiltinCoreKind(kind: string): boolean {
70
+ return ADDITIONAL_CORE_KINDS.has(kind) || CORE_RESOURCES.some(r => r.group === '' && r.kind === kind)
71
+ }
72
+
66
73
  export function builtinGroupForKind(kindOrResource: string): string | undefined {
67
74
  const value = kindOrResource.toLowerCase()
68
75
  return CORE_RESOURCES.find(resource =>
@@ -38,6 +38,7 @@ const RELATED_RUNTIME_KINDS = new Set([
38
38
  'HTTPRoute',
39
39
  'GRPCRoute',
40
40
  'TCPRoute',
41
+ 'UDPRoute',
41
42
  'TLSRoute',
42
43
  'ConfigMap',
43
44
  'Secret',
@@ -0,0 +1,26 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { describe, expect, it } from 'vitest'
3
+ import { cnpgBackupDeclaration, cnpgBackupDestinationBlocker, cnpgBarmanPlugin, cnpgDestinationPlugin, cnpgHasBackupDestination } from './cnpg-backup'
4
+
5
+ const cases: Array<{
6
+ name: string
7
+ cluster: Parameters<typeof cnpgBackupDeclaration>[0]
8
+ method: string
9
+ plugin: string
10
+ hasDestination: boolean
11
+ destinationPlugin: string
12
+ blockerCode: string
13
+ barman: { objectStore: string; serverName: string } | null
14
+ }> = JSON.parse(readFileSync(new URL('../../../../pkg/cnpg/testdata/backup-declarations.json', import.meta.url), 'utf8'))
15
+
16
+ describe('CNPG backup declarations shared with Go', () => {
17
+ it.each(cases)('$name', (test) => {
18
+ const declaration = cnpgBackupDeclaration(test.cluster)
19
+ expect(cnpgHasBackupDestination(declaration)).toBe(test.hasDestination)
20
+ expect(cnpgDestinationPlugin(declaration)?.name ?? '').toBe(test.destinationPlugin)
21
+ expect(cnpgBackupDestinationBlocker(declaration, test.method || undefined, test.plugin)?.code ?? '').toBe(test.blockerCode)
22
+ const barman = cnpgBarmanPlugin(declaration)
23
+ if (test.barman) expect(barman).toMatchObject({ barmanObjectName: test.barman.objectStore || undefined, serverName: test.barman.serverName })
24
+ else expect(barman).toBeUndefined()
25
+ })
26
+ })
@@ -0,0 +1,70 @@
1
+ export const CNPG_BARMAN_PLUGIN_NAME = 'barman-cloud.cloudnative-pg.io'
2
+
3
+ interface BackupCluster {
4
+ metadata?: { name?: string }
5
+ spec?: {
6
+ backup?: { barmanObjectStore?: { destinationPath?: string }; volumeSnapshot?: unknown }
7
+ plugins?: { name: string; enabled?: boolean; isWALArchiver?: boolean; parameters?: { barmanObjectName?: string; serverName?: string } }[]
8
+ }
9
+ }
10
+
11
+ export interface CNPGBackupPlugin {
12
+ name: string
13
+ enabled: boolean
14
+ isWALArchiver: boolean
15
+ barmanObjectName?: string
16
+ serverName?: string
17
+ }
18
+
19
+ export interface CNPGBackupDeclaration {
20
+ plugins: CNPGBackupPlugin[]
21
+ inTreeConfigured: boolean
22
+ inTreeDestination?: string
23
+ snapshotsConfigured: boolean
24
+ }
25
+
26
+ export function cnpgBackupDeclaration(cluster: BackupCluster): CNPGBackupDeclaration {
27
+ const backup = cluster.spec?.backup
28
+ return {
29
+ inTreeConfigured: !!backup?.barmanObjectStore,
30
+ inTreeDestination: backup?.barmanObjectStore?.destinationPath,
31
+ snapshotsConfigured: backup?.volumeSnapshot != null,
32
+ plugins: (cluster.spec?.plugins ?? []).filter((p) => p?.name).map((p) => ({
33
+ name: p.name,
34
+ enabled: p.enabled !== false,
35
+ isWALArchiver: p.isWALArchiver === true,
36
+ barmanObjectName: p.parameters?.barmanObjectName,
37
+ serverName: p.parameters?.serverName || cluster.metadata?.name,
38
+ })),
39
+ }
40
+ }
41
+
42
+ export function cnpgBarmanPlugin(declaration: CNPGBackupDeclaration): CNPGBackupPlugin | undefined {
43
+ return declaration.plugins.find((p) => p.enabled && p.name === CNPG_BARMAN_PLUGIN_NAME)
44
+ }
45
+
46
+ export function cnpgDestinationPlugin(declaration: CNPGBackupDeclaration): CNPGBackupPlugin | undefined {
47
+ return declaration.plugins.find((p) => p.enabled && (p.name !== CNPG_BARMAN_PLUGIN_NAME || !!p.barmanObjectName))
48
+ }
49
+
50
+ export function cnpgHasBackupDestination(declaration: CNPGBackupDeclaration): boolean {
51
+ return !!declaration.inTreeDestination || declaration.snapshotsConfigured || !!cnpgDestinationPlugin(declaration)
52
+ }
53
+
54
+ export interface CNPGBackupBlocker {
55
+ code: 'no_destination' | 'method_destination_missing'
56
+ method: string
57
+ plugin?: string
58
+ }
59
+
60
+ export function cnpgBackupDestinationBlocker(declaration: CNPGBackupDeclaration, method = 'barmanObjectStore', plugin?: string): CNPGBackupBlocker | null {
61
+ const blocked = method === 'barmanObjectStore' ? !declaration.inTreeDestination
62
+ : method === 'volumeSnapshot' ? !declaration.snapshotsConfigured
63
+ : method === 'plugin' ? !declaration.plugins.some((p) => p.name === plugin && p.enabled && (p.name !== CNPG_BARMAN_PLUGIN_NAME || !!p.barmanObjectName))
64
+ : false
65
+ return blocked ? { code: cnpgHasBackupDestination(declaration) ? 'method_destination_missing' : 'no_destination', method, plugin: cnpgDestinationPlugin(declaration)?.name } : null
66
+ }
67
+
68
+ export function cnpgBackupBlockerText(blocker: CNPGBackupBlocker): string {
69
+ return blocker.code === 'no_destination' ? 'No backup destination' : `No ${blocker.method} destination`
70
+ }