@skyhook-io/k8s-ui 1.8.11 → 1.8.13

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 (87) hide show
  1. package/package.json +4 -4
  2. package/src/components/applications/ApplicationDetail.test.tsx +136 -8
  3. package/src/components/applications/ApplicationDetail.tsx +1215 -487
  4. package/src/components/gitops/GitOpsDetailLayout.tsx +13 -3
  5. package/src/components/gitops/GitOpsTableView.tsx +10 -3
  6. package/src/components/gitops/SyncOptionsDialog.test.ts +48 -0
  7. package/src/components/gitops/SyncOptionsDialog.tsx +189 -45
  8. package/src/components/gitops/insights/ArgoResourceDiff.tsx +172 -0
  9. package/src/components/gitops/insights/GitOpsInsightViews.tsx +201 -21
  10. package/src/components/gitops/insights/index.ts +1 -0
  11. package/src/components/gitops/insights/insights-helpers.test.ts +16 -0
  12. package/src/components/gitops/insights/insights-helpers.ts +5 -0
  13. package/src/components/gitops/tree/GitOpsTreeGraph.tsx +5 -0
  14. package/src/components/issues/IssuesView.tsx +55 -29
  15. package/src/components/issues/ResourceIssuesSection.test.tsx +33 -1
  16. package/src/components/issues/ResourceIssuesSection.tsx +21 -1
  17. package/src/components/issues/severity.ts +1 -0
  18. package/src/components/resources/ResourcesView.tsx +109 -19
  19. package/src/components/resources/column-filter-serialization.test.ts +79 -1
  20. package/src/components/resources/renderers/AWSMachineRenderer.tsx +3 -2
  21. package/src/components/resources/renderers/AWSManagedClusterRenderer.tsx +3 -2
  22. package/src/components/resources/renderers/AWSManagedControlPlaneRenderer.tsx +3 -2
  23. package/src/components/resources/renderers/AWSManagedMachinePoolRenderer.tsx +3 -2
  24. package/src/components/resources/renderers/AzureMachineRenderer.tsx +3 -2
  25. package/src/components/resources/renderers/AzureManagedControlPlaneRenderer.tsx +3 -2
  26. package/src/components/resources/renderers/AzureManagedMachinePoolRenderer.tsx +3 -2
  27. package/src/components/resources/renderers/CAPIClusterRenderer.tsx +3 -2
  28. package/src/components/resources/renderers/CAPIKubeadmControlPlaneRenderer.tsx +3 -2
  29. package/src/components/resources/renderers/CAPIMachineDeploymentRenderer.tsx +3 -2
  30. package/src/components/resources/renderers/CAPIMachineHealthCheckRenderer.tsx +3 -2
  31. package/src/components/resources/renderers/CAPIMachinePoolRenderer.tsx +3 -2
  32. package/src/components/resources/renderers/CAPIMachineRenderer.tsx +3 -2
  33. package/src/components/resources/renderers/CAPIMachineSetRenderer.tsx +3 -2
  34. package/src/components/resources/renderers/CertificateRenderer.tsx +3 -2
  35. package/src/components/resources/renderers/CertificateRequestRenderer.tsx +3 -2
  36. package/src/components/resources/renderers/CompositeRenderer.tsx +3 -2
  37. package/src/components/resources/renderers/ExternalSecretRenderer.tsx +3 -2
  38. package/src/components/resources/renderers/GCPMachineRenderer.tsx +3 -2
  39. package/src/components/resources/renderers/GCPManagedControlPlaneRenderer.tsx +3 -2
  40. package/src/components/resources/renderers/GCPManagedMachinePoolRenderer.tsx +3 -2
  41. package/src/components/resources/renderers/GRPCRouteRenderer.tsx +7 -3
  42. package/src/components/resources/renderers/GatewayClassRenderer.tsx +3 -2
  43. package/src/components/resources/renderers/HTTPRouteRenderer.tsx +7 -3
  44. package/src/components/resources/renderers/KarpenterEC2NodeClassRenderer.tsx +3 -2
  45. package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +3 -2
  46. package/src/components/resources/renderers/KarpenterNodePoolRenderer.tsx +3 -2
  47. package/src/components/resources/renderers/KedaScaledJobRenderer.tsx +3 -2
  48. package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +3 -2
  49. package/src/components/resources/renderers/ManagedResourceRenderer.tsx +3 -2
  50. package/src/components/resources/renderers/PVCRenderer.tsx +3 -2
  51. package/src/components/resources/renderers/SealedSecretRenderer.tsx +3 -2
  52. package/src/components/resources/renderers/SecretStoreRenderer.tsx +3 -2
  53. package/src/components/resources/renderers/SimpleRouteRenderer.tsx +7 -3
  54. package/src/components/resources/resource-utils-argo.test.ts +18 -1
  55. package/src/components/resources/resource-utils-argo.ts +8 -0
  56. package/src/components/resources/resource-utils.ts +94 -25
  57. package/src/components/shared/ResourceActionsBar.tsx +54 -22
  58. package/src/components/shared/UnifiedDiff.tsx +51 -0
  59. package/src/components/shared/index.ts +1 -0
  60. package/src/components/timeline/TimelineList.tsx +7 -3
  61. package/src/components/timeline/TimelineToolbarState.test.tsx +24 -0
  62. package/src/components/topology/TopologyBreadcrumb.tsx +30 -0
  63. package/src/components/topology/TopologyControls.tsx +3 -1
  64. package/src/components/topology/TopologyGraph.tsx +76 -90
  65. package/src/components/topology/TopologyOverlayBar.tsx +30 -0
  66. package/src/components/topology/TopologySearch.tsx +23 -15
  67. package/src/components/topology/index.ts +2 -0
  68. package/src/components/ui/Badge.tsx +1 -1
  69. package/src/components/ui/SelectMenu.tsx +81 -0
  70. package/src/components/ui/Tooltip.test.tsx +21 -0
  71. package/src/components/ui/Tooltip.tsx +9 -12
  72. package/src/components/ui/drawer-components.tsx +9 -6
  73. package/src/components/ui/index.ts +2 -0
  74. package/src/components/workload/WorkloadView.tsx +24 -3
  75. package/src/theme/tailwind-theme.css +1 -0
  76. package/src/theme/variables.css +1 -0
  77. package/src/types/gitops-insights.ts +69 -1
  78. package/src/types/gitops.ts +3 -3
  79. package/src/utils/api-resources.test.ts +36 -1
  80. package/src/utils/api-resources.ts +16 -0
  81. package/src/utils/application-history.test.ts +538 -0
  82. package/src/utils/application-history.ts +257 -0
  83. package/src/utils/applications.test.ts +34 -0
  84. package/src/utils/applications.ts +25 -0
  85. package/src/utils/index.ts +1 -0
  86. package/src/utils/resource-hierarchy.test.ts +35 -1
  87. package/src/utils/resource-hierarchy.ts +20 -0
@@ -1,6 +1,6 @@
1
1
  import { useState } from 'react'
2
2
  import { Server, Globe, Network, Layers, Download, CheckCircle, AlertCircle } from 'lucide-react'
3
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink } from '../../ui/drawer-components'
3
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink, useOperationalIssuesShown} from '../../ui/drawer-components'
4
4
  import { kindToPlural } from '../../../utils/navigation'
5
5
  import { formatAge } from '../resource-utils'
6
6
  import { getClusterStatus, getClusterClass, getClusterVersion, getClusterEndpoint, getProviderFromInfraKind, parseCAPIConditionMessage } from '../resource-utils-capi'
@@ -18,6 +18,7 @@ export function CAPIClusterRenderer({ data, onNavigate, apiBase = '' }: Props) {
18
18
 
19
19
  const clusterStatus = getClusterStatus(data)
20
20
  const isFailed = clusterStatus.level === 'unhealthy'
21
+ const operationalIssuesShown = useOperationalIssuesShown()
21
22
  const readyCond = conditions.find((c: any) => c.type === 'Ready' || c.type === 'Available')
22
23
 
23
24
  const phase = status.phase || 'Unknown'
@@ -102,7 +103,7 @@ export function CAPIClusterRenderer({ data, onNavigate, apiBase = '' }: Props) {
102
103
  />
103
104
  )}
104
105
 
105
- {isFailed && (() => {
106
+ {isFailed && !operationalIssuesShown && (() => {
106
107
  const msg = readyCond?.message || `Cluster is in ${phase} state.`
107
108
  const items = parseCAPIConditionMessage(msg)
108
109
  return <AlertBanner variant="error" title="Cluster Not Ready" items={items || undefined} message={items ? undefined : msg} />
@@ -1,5 +1,5 @@
1
1
  import { Server, Shield, Settings } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink, useOperationalIssuesShown} from '../../ui/drawer-components'
3
3
  import { kindToPlural } from '../../../utils/navigation'
4
4
  import { formatAge } from '../resource-utils'
5
5
  import { getKCPStatus, getKCPVersion, getKCPInitialized, getMachineClusterName } from '../resource-utils-capi'
@@ -16,6 +16,7 @@ export function CAPIKubeadmControlPlaneRenderer({ data, onNavigate }: Props) {
16
16
 
17
17
  const kcpStatus = getKCPStatus(data)
18
18
  const isFailed = kcpStatus.level === 'unhealthy'
19
+ const operationalIssuesShown = useOperationalIssuesShown()
19
20
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
20
21
 
21
22
  const clusterName = getMachineClusterName(data)
@@ -33,7 +34,7 @@ export function CAPIKubeadmControlPlaneRenderer({ data, onNavigate }: Props) {
33
34
 
34
35
  return (
35
36
  <>
36
- {isFailed && (
37
+ {isFailed && !operationalIssuesShown && (
37
38
  <AlertBanner
38
39
  variant="error"
39
40
  title="Control Plane Not Ready"
@@ -1,5 +1,5 @@
1
1
  import { Server, Settings } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink, useOperationalIssuesShown} from '../../ui/drawer-components'
3
3
  import { kindToPlural } from '../../../utils/navigation'
4
4
  import { formatAge } from '../resource-utils'
5
5
  import { getMachineDeploymentStatus, getMachineDeploymentVersion, getMachineClusterName } from '../resource-utils-capi'
@@ -16,6 +16,7 @@ export function CAPIMachineDeploymentRenderer({ data, onNavigate }: Props) {
16
16
 
17
17
  const mdStatus = getMachineDeploymentStatus(data)
18
18
  const isFailed = mdStatus.level === 'unhealthy'
19
+ const operationalIssuesShown = useOperationalIssuesShown()
19
20
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
20
21
 
21
22
  const phase = status.phase || 'Unknown'
@@ -40,7 +41,7 @@ export function CAPIMachineDeploymentRenderer({ data, onNavigate }: Props) {
40
41
  />
41
42
  )}
42
43
 
43
- {isFailed && (
44
+ {isFailed && !operationalIssuesShown && (
44
45
  <AlertBanner
45
46
  variant="error"
46
47
  title="MachineDeployment Not Ready"
@@ -1,5 +1,5 @@
1
1
  import { HeartPulse, Settings, Shield } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, LabelSelectorDisplay } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, LabelSelectorDisplay, useOperationalIssuesShown} from '../../ui/drawer-components'
3
3
  import { getMachineHealthCheckStatus, getMachineHealthCheckClusterName } from '../resource-utils-capi'
4
4
 
5
5
  interface Props {
@@ -14,6 +14,7 @@ export function CAPIMachineHealthCheckRenderer({ data }: Props) {
14
14
 
15
15
  const mhcStatus = getMachineHealthCheckStatus(data)
16
16
  const isFailed = mhcStatus.level === 'unhealthy'
17
+ const operationalIssuesShown = useOperationalIssuesShown()
17
18
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
18
19
 
19
20
  const clusterName = getMachineHealthCheckClusterName(data)
@@ -31,7 +32,7 @@ export function CAPIMachineHealthCheckRenderer({ data }: Props) {
31
32
 
32
33
  return (
33
34
  <>
34
- {isFailed && (
35
+ {isFailed && !operationalIssuesShown && (
35
36
  <AlertBanner
36
37
  variant="error"
37
38
  title="MachineHealthCheck Issue"
@@ -1,5 +1,5 @@
1
1
  import { Server, Settings } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink, useOperationalIssuesShown} from '../../ui/drawer-components'
3
3
  import { kindToPlural } from '../../../utils/navigation'
4
4
  import { formatAge } from '../resource-utils'
5
5
  import { getMachinePoolStatus } from '../resource-utils-capi'
@@ -16,6 +16,7 @@ export function CAPIMachinePoolRenderer({ data, onNavigate }: Props) {
16
16
 
17
17
  const mpStatus = getMachinePoolStatus(data)
18
18
  const isFailed = mpStatus.level === 'unhealthy'
19
+ const operationalIssuesShown = useOperationalIssuesShown()
19
20
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
20
21
 
21
22
  const clusterName = spec.clusterName || data.metadata?.labels?.['cluster.x-k8s.io/cluster-name'] || '-'
@@ -27,7 +28,7 @@ export function CAPIMachinePoolRenderer({ data, onNavigate }: Props) {
27
28
 
28
29
  return (
29
30
  <>
30
- {isFailed && (
31
+ {isFailed && !operationalIssuesShown && (
31
32
  <AlertBanner
32
33
  variant="error"
33
34
  title="MachinePool Not Ready"
@@ -1,5 +1,5 @@
1
1
  import { Cpu, Server, Network, Cloud } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink, useOperationalIssuesShown} from '../../ui/drawer-components'
3
3
  import { kindToPlural } from '../../../utils/navigation'
4
4
  import { formatAge } from '../resource-utils'
5
5
  import { getMachineStatus, getMachineRole, getMachineClusterName, getMachineNodeRef, getMachineVersion, getMachineProviderID, parseProviderID, getProviderFromInfraKind, parseCAPIConditionMessage } from '../resource-utils-capi'
@@ -16,6 +16,7 @@ export function CAPIMachineRenderer({ data, onNavigate }: Props) {
16
16
 
17
17
  const machineStatus = getMachineStatus(data)
18
18
  const isFailed = machineStatus.level === 'unhealthy'
19
+ const operationalIssuesShown = useOperationalIssuesShown()
19
20
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
20
21
  // Find the most informative False condition for the alert message
21
22
  const falseCond = conditions.find((c: any) =>
@@ -38,7 +39,7 @@ export function CAPIMachineRenderer({ data, onNavigate }: Props) {
38
39
 
39
40
  return (
40
41
  <>
41
- {isFailed && (() => {
42
+ {isFailed && !operationalIssuesShown && (() => {
42
43
  const msg = falseCond?.message || readyCond?.message || `Machine is in ${phase} state.`
43
44
  const items = parseCAPIConditionMessage(msg)
44
45
  return <AlertBanner variant="error" title="Machine Not Ready" items={items || undefined} message={items ? undefined : msg} />
@@ -1,5 +1,5 @@
1
1
  import { Server, Settings } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink, useOperationalIssuesShown} from '../../ui/drawer-components'
3
3
  import { kindToPlural } from '../../../utils/navigation'
4
4
  import { formatAge } from '../resource-utils'
5
5
  import { getMachineSetStatus, getMachineClusterName } from '../resource-utils-capi'
@@ -16,6 +16,7 @@ export function CAPIMachineSetRenderer({ data, onNavigate }: Props) {
16
16
 
17
17
  const msStatus = getMachineSetStatus(data)
18
18
  const isFailed = msStatus.level === 'unhealthy'
19
+ const operationalIssuesShown = useOperationalIssuesShown()
19
20
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
20
21
 
21
22
  const clusterName = getMachineClusterName(data)
@@ -29,7 +30,7 @@ export function CAPIMachineSetRenderer({ data, onNavigate }: Props) {
29
30
 
30
31
  return (
31
32
  <>
32
- {isFailed && (
33
+ {isFailed && !operationalIssuesShown && (
33
34
  <AlertBanner
34
35
  variant="error"
35
36
  title="MachineSet Not Ready"
@@ -1,6 +1,6 @@
1
1
  import { Shield, Clock, Globe, Key } from 'lucide-react'
2
2
  import { clsx } from 'clsx'
3
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner } from '../../ui/drawer-components'
3
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, useOperationalIssuesShown} from '../../ui/drawer-components'
4
4
  import { pluralize } from '../../../utils/pluralize'
5
5
 
6
6
  interface CertificateRendererProps {
@@ -34,6 +34,7 @@ export function CertificateRenderer({ data }: CertificateRendererProps) {
34
34
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
35
35
  const isReady = readyCond?.status === 'True'
36
36
  const isNotReady = readyCond?.status === 'False'
37
+ const operationalIssuesShown = useOperationalIssuesShown()
37
38
 
38
39
  const notAfter = status.notAfter
39
40
  const notBefore = status.notBefore
@@ -69,7 +70,7 @@ export function CertificateRenderer({ data }: CertificateRendererProps) {
69
70
  return (
70
71
  <>
71
72
  {/* Problem detection alerts */}
72
- {isNotReady && (
73
+ {isNotReady && !operationalIssuesShown && (
73
74
  <AlertBanner
74
75
  variant="error"
75
76
  title="Certificate Not Ready"
@@ -1,6 +1,6 @@
1
1
  import { Shield, FileText, Info } from 'lucide-react'
2
2
  import { clsx } from 'clsx'
3
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner } from '../../ui/drawer-components'
3
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, useOperationalIssuesShown} from '../../ui/drawer-components'
4
4
 
5
5
  interface CertificateRequestRendererProps {
6
6
  data: any
@@ -20,6 +20,7 @@ export function CertificateRequestRenderer({ data }: CertificateRequestRendererP
20
20
 
21
21
  const isReady = readyCond?.status === 'True'
22
22
  const isNotReady = readyCond?.status === 'False'
23
+ const operationalIssuesShown = useOperationalIssuesShown()
23
24
  const isApproved = approvedCond?.status === 'True'
24
25
  const isDenied = deniedCond?.status === 'True'
25
26
 
@@ -28,7 +29,7 @@ export function CertificateRequestRenderer({ data }: CertificateRequestRendererP
28
29
  return (
29
30
  <>
30
31
  {/* Problem detection alerts */}
31
- {isNotReady && (
32
+ {isNotReady && !operationalIssuesShown && (
32
33
  <AlertBanner
33
34
  variant="error"
34
35
  title="Certificate Request Not Ready"
@@ -1,6 +1,6 @@
1
1
  import { clsx } from 'clsx'
2
2
  import { Layers, GitBranch, Box, ChevronRight, Pause } from 'lucide-react'
3
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink } from '../../ui/drawer-components'
3
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink, useOperationalIssuesShown} from '../../ui/drawer-components'
4
4
  import { Tooltip } from '../../ui/Tooltip'
5
5
  import {
6
6
  getCrossplaneStatus,
@@ -78,6 +78,7 @@ export function CompositeRenderer({ data, onNavigate, composedRefStatuses }: Com
78
78
  const boundXR = claim ? getBoundXRRef(data) : null
79
79
  const paused = isCrossplanePaused(data)
80
80
  const alertVariant = status.level === 'unhealthy' || status.level === 'alert' ? status.level : null
81
+ const operationalIssuesShown = useOperationalIssuesShown()
81
82
 
82
83
  return (
83
84
  <>
@@ -90,7 +91,7 @@ export function CompositeRenderer({ data, onNavigate, composedRefStatuses }: Com
90
91
  />
91
92
  )}
92
93
 
93
- {alertVariant && reason && (
94
+ {alertVariant && reason && !operationalIssuesShown && (
94
95
  <AlertBanner
95
96
  variant={alertVariant === 'unhealthy' ? 'error' : 'warning'}
96
97
  title={status.text}
@@ -1,5 +1,5 @@
1
1
  import { KeyRound, RefreshCw, CloudCog } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink, useOperationalIssuesShown } from '../../ui/drawer-components'
3
3
  import {
4
4
  getExternalSecretStatus,
5
5
  getExternalSecretStore,
@@ -30,11 +30,12 @@ export function ExternalSecretRenderer({ data, onNavigate }: ExternalSecretRende
30
30
  // Problem detection
31
31
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
32
32
  const isNotReady = readyCond?.status === 'False'
33
+ const operationalIssuesShown = useOperationalIssuesShown()
33
34
 
34
35
  return (
35
36
  <>
36
37
  {/* Alert if not synced */}
37
- {isNotReady && (
38
+ {isNotReady && !operationalIssuesShown && (
38
39
  <AlertBanner
39
40
  variant="error"
40
41
  title="ExternalSecret Not Synced"
@@ -1,5 +1,5 @@
1
1
  import { Cpu, Cloud } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, useOperationalIssuesShown} from '../../ui/drawer-components'
3
3
  import { getCAPIConditions } from '../resource-utils-capi'
4
4
  import { getGCPMachineStatus, getGCPMachineInstanceType, getGCPMachineZone, getGCPMachineInstanceID } from '../resource-utils-gcp-capi'
5
5
 
@@ -13,11 +13,12 @@ export function GCPMachineRenderer({ data }: Props) {
13
13
  const conditions = getCAPIConditions(data)
14
14
  const machineStatus = getGCPMachineStatus(data)
15
15
  const isFailed = machineStatus.level === 'unhealthy'
16
+ const operationalIssuesShown = useOperationalIssuesShown()
16
17
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
17
18
 
18
19
  return (
19
20
  <>
20
- {isFailed && (
21
+ {isFailed && !operationalIssuesShown && (
21
22
  <AlertBanner variant="error" title="GCP Machine Not Ready" message={readyCond?.message || 'GCPMachine is not ready.'} />
22
23
  )}
23
24
 
@@ -1,5 +1,5 @@
1
1
  import { Globe, Shield, Settings } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, useOperationalIssuesShown} from '../../ui/drawer-components'
3
3
  import { getCAPIConditions } from '../resource-utils-capi'
4
4
  import { getGCPMCPStatus, getGCPMCPClusterName, getGCPMCPProject, getGCPMCPLocation, getGCPMCPVersion, getGCPMCPReleaseChannel, getGCPMCPAutopilot, getGCPMCPEndpoint } from '../resource-utils-gcp-capi'
5
5
 
@@ -13,13 +13,14 @@ export function GCPManagedControlPlaneRenderer({ data }: Props) {
13
13
  const conditions = getCAPIConditions(data)
14
14
  const mcpStatus = getGCPMCPStatus(data)
15
15
  const isFailed = mcpStatus.level === 'unhealthy'
16
+ const operationalIssuesShown = useOperationalIssuesShown()
16
17
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
17
18
  const endpoint = getGCPMCPEndpoint(data)
18
19
  const masterAuth = spec.master_authorized_networks_config
19
20
 
20
21
  return (
21
22
  <>
22
- {isFailed && (
23
+ {isFailed && !operationalIssuesShown && (
23
24
  <AlertBanner variant="error" title="GKE Control Plane Not Ready" message={readyCond?.message || 'GCPManagedControlPlane is not ready.'} />
24
25
  )}
25
26
 
@@ -1,5 +1,5 @@
1
1
  import { Server, Settings } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, useOperationalIssuesShown} from '../../ui/drawer-components'
3
3
  import { getCAPIConditions } from '../resource-utils-capi'
4
4
  import { getGCPMMPStatus, getGCPMMPNodePoolName, getGCPMMPMachineType, getGCPMMPDiskInfo, getGCPMMPScaling, getGCPMMPImageType } from '../resource-utils-gcp-capi'
5
5
 
@@ -14,6 +14,7 @@ export function GCPManagedMachinePoolRenderer({ data }: Props) {
14
14
  const conditions = getCAPIConditions(data)
15
15
  const mmpStatus = getGCPMMPStatus(data)
16
16
  const isFailed = mmpStatus.level === 'unhealthy'
17
+ const operationalIssuesShown = useOperationalIssuesShown()
17
18
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
18
19
  const scaling = getGCPMMPScaling(data)
19
20
  const management = spec.management || {}
@@ -23,7 +24,7 @@ export function GCPManagedMachinePoolRenderer({ data }: Props) {
23
24
 
24
25
  return (
25
26
  <>
26
- {isFailed && (
27
+ {isFailed && !operationalIssuesShown && (
27
28
  <AlertBanner variant="error" title="GKE Node Pool Not Ready" message={readyCond?.message || 'GCPManagedMachinePool is not ready.'} />
28
29
  )}
29
30
 
@@ -1,5 +1,5 @@
1
1
  import { Globe, ArrowRight, Network, Filter } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceRefBadge } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceRefBadge, useOperationalIssuesShown } from '../../ui/drawer-components'
3
3
  import { Badge } from '../../ui/Badge'
4
4
  import type { ResourceRef } from '../../../types'
5
5
 
@@ -23,6 +23,10 @@ export function GRPCRouteRenderer({ data, onNavigate }: GRPCRouteRendererProps)
23
23
  const unresolvedRefsParents = parentStatuses.filter((p: any) =>
24
24
  (p.conditions || []).some((c: any) => c.type === 'ResolvedRefs' && c.status === 'False')
25
25
  )
26
+ // The Operational Issues section (when the host shows it) already reports these
27
+ // Accepted/ResolvedRefs failures with richer cause + next-step context, so drop
28
+ // the renderer's own banners to avoid showing the same failure twice.
29
+ const operationalIssuesShown = useOperationalIssuesShown()
26
30
 
27
31
  const firstParentConditions = parentStatuses.length > 0
28
32
  ? parentStatuses[0].conditions
@@ -47,7 +51,7 @@ export function GRPCRouteRenderer({ data, onNavigate }: GRPCRouteRendererProps)
47
51
 
48
52
  return (
49
53
  <>
50
- {notAcceptedParents.length > 0 && (
54
+ {notAcceptedParents.length > 0 && !operationalIssuesShown && (
51
55
  <AlertBanner
52
56
  variant="error"
53
57
  title="Route Not Accepted"
@@ -61,7 +65,7 @@ export function GRPCRouteRenderer({ data, onNavigate }: GRPCRouteRendererProps)
61
65
  />
62
66
  )}
63
67
 
64
- {unresolvedRefsParents.length > 0 && (
68
+ {unresolvedRefsParents.length > 0 && !operationalIssuesShown && (
65
69
  <AlertBanner
66
70
  variant="warning"
67
71
  title="Unresolved References"
@@ -1,5 +1,5 @@
1
1
  import { Cpu } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, useOperationalIssuesShown } from '../../ui/drawer-components'
3
3
  import { Badge } from '../../ui/Badge'
4
4
 
5
5
  interface GatewayClassRendererProps {
@@ -14,11 +14,12 @@ export function GatewayClassRenderer({ data }: GatewayClassRendererProps) {
14
14
  const acceptedCond = conditions.find((c: any) => c.type === 'Accepted')
15
15
  const isAccepted = acceptedCond?.status === 'True'
16
16
  const isNotAccepted = acceptedCond?.status === 'False'
17
+ const operationalIssuesShown = useOperationalIssuesShown()
17
18
 
18
19
  return (
19
20
  <>
20
21
  {/* Problem detection alert */}
21
- {isNotAccepted && (
22
+ {isNotAccepted && !operationalIssuesShown && (
22
23
  <AlertBanner
23
24
  variant="error"
24
25
  title="GatewayClass Not Accepted"
@@ -1,5 +1,5 @@
1
1
  import { Globe, ArrowRight, Network, Filter } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceRefBadge } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceRefBadge, useOperationalIssuesShown } from '../../ui/drawer-components'
3
3
  import { Badge } from '../../ui/Badge'
4
4
  import type { ResourceRef } from '../../../types'
5
5
 
@@ -23,6 +23,10 @@ export function HTTPRouteRenderer({ data, onNavigate }: HTTPRouteRendererProps)
23
23
  const unresolvedRefsParents = parentStatuses.filter((p: any) =>
24
24
  (p.conditions || []).some((c: any) => c.type === 'ResolvedRefs' && c.status === 'False')
25
25
  )
26
+ // The Operational Issues section (when the host shows it) already reports these
27
+ // Accepted/ResolvedRefs failures with richer cause + next-step context, so drop
28
+ // the renderer's own banners to avoid showing the same failure twice.
29
+ const operationalIssuesShown = useOperationalIssuesShown()
26
30
 
27
31
  const firstParentConditions = parentStatuses.length > 0
28
32
  ? parentStatuses[0].conditions
@@ -47,7 +51,7 @@ export function HTTPRouteRenderer({ data, onNavigate }: HTTPRouteRendererProps)
47
51
 
48
52
  return (
49
53
  <>
50
- {notAcceptedParents.length > 0 && (
54
+ {notAcceptedParents.length > 0 && !operationalIssuesShown && (
51
55
  <AlertBanner
52
56
  variant="error"
53
57
  title="Route Not Accepted"
@@ -61,7 +65,7 @@ export function HTTPRouteRenderer({ data, onNavigate }: HTTPRouteRendererProps)
61
65
  />
62
66
  )}
63
67
 
64
- {unresolvedRefsParents.length > 0 && (
68
+ {unresolvedRefsParents.length > 0 && !operationalIssuesShown && (
65
69
  <AlertBanner
66
70
  variant="warning"
67
71
  title="Unresolved References"
@@ -1,5 +1,5 @@
1
1
  import { Server, HardDrive, Shield, Network, Tag, Image } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, KeyValueBadgeList } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, KeyValueBadgeList, useOperationalIssuesShown } from '../../ui/drawer-components'
3
3
  import { getEC2NodeClassStatus } from '../resource-utils-karpenter'
4
4
 
5
5
  interface KarpenterEC2NodeClassRendererProps {
@@ -13,6 +13,7 @@ export function KarpenterEC2NodeClassRenderer({ data }: KarpenterEC2NodeClassRen
13
13
 
14
14
  const nodeClassStatus = getEC2NodeClassStatus(data)
15
15
  const isNotReady = nodeClassStatus.level === 'unhealthy'
16
+ const operationalIssuesShown = useOperationalIssuesShown()
16
17
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
17
18
 
18
19
  const amiTerms = spec.amiSelectorTerms || []
@@ -28,7 +29,7 @@ export function KarpenterEC2NodeClassRenderer({ data }: KarpenterEC2NodeClassRen
28
29
 
29
30
  return (
30
31
  <>
31
- {isNotReady && (
32
+ {isNotReady && !operationalIssuesShown && (
32
33
  <AlertBanner
33
34
  variant="error"
34
35
  title="EC2NodeClass Not Ready"
@@ -1,6 +1,6 @@
1
1
  import { Server, Cpu, Settings } from 'lucide-react'
2
2
  import { clsx } from 'clsx'
3
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink } from '../../ui/drawer-components'
3
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink, useOperationalIssuesShown } from '../../ui/drawer-components'
4
4
  import { kindToPlural } from '../../../utils/navigation'
5
5
  import { CAPACITY_TYPE_BADGE, BADGE_INACTIVE } from '../../../utils/badge-colors'
6
6
  import {
@@ -40,6 +40,7 @@ export function KarpenterNodeClaimRenderer({ data, onNavigate }: KarpenterNodeCl
40
40
 
41
41
  const claimStatus = getNodeClaimStatus(data)
42
42
  const isNotReady = claimStatus.level === 'unhealthy'
43
+ const operationalIssuesShown = useOperationalIssuesShown()
43
44
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
44
45
  const capacity = getNodeClaimCapacity(data)
45
46
  const requirements = getNodeClaimRequirements(data)
@@ -61,7 +62,7 @@ export function KarpenterNodeClaimRenderer({ data, onNavigate }: KarpenterNodeCl
61
62
  return (
62
63
  <>
63
64
  {/* Problem alert */}
64
- {isNotReady && (
65
+ {isNotReady && !operationalIssuesShown && (
65
66
  <AlertBanner
66
67
  variant="error"
67
68
  title="NodeClaim Not Ready"
@@ -1,5 +1,5 @@
1
1
  import { Server, Settings, Shield, Cpu, Tag, BarChart3 } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink, useOperationalIssuesShown } from '../../ui/drawer-components'
3
3
  import { kindToPlural } from '../../../utils/navigation'
4
4
  import {
5
5
  getNodePoolStatus,
@@ -31,6 +31,7 @@ export function KarpenterNodePoolRenderer({ data, onNavigate }: KarpenterNodePoo
31
31
 
32
32
  const poolStatus = getNodePoolStatus(data)
33
33
  const isNotReady = poolStatus.level === 'unhealthy'
34
+ const operationalIssuesShown = useOperationalIssuesShown()
34
35
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
35
36
  const requirements = getNodePoolRequirements(data)
36
37
  const weight = getNodePoolWeight(data)
@@ -45,7 +46,7 @@ export function KarpenterNodePoolRenderer({ data, onNavigate }: KarpenterNodePoo
45
46
  return (
46
47
  <>
47
48
  {/* Problem alert */}
48
- {isNotReady && (
49
+ {isNotReady && !operationalIssuesShown && (
49
50
  <AlertBanner
50
51
  variant="error"
51
52
  title="NodePool Not Ready"
@@ -1,5 +1,5 @@
1
1
  import { Cpu } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, useOperationalIssuesShown } from '../../ui/drawer-components'
3
3
  import {
4
4
  getScaledJobStatus,
5
5
  getScaledJobTarget,
@@ -18,13 +18,14 @@ export function KedaScaledJobRenderer({ data }: KedaScaledJobRendererProps) {
18
18
 
19
19
  const jobStatus = getScaledJobStatus(data)
20
20
  const isNotReady = jobStatus.level === 'unhealthy'
21
+ const operationalIssuesShown = useOperationalIssuesShown()
21
22
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
22
23
  const triggers = getScaledJobTriggers(data)
23
24
 
24
25
  return (
25
26
  <>
26
27
  {/* Problem alert */}
27
- {isNotReady && (
28
+ {isNotReady && !operationalIssuesShown && (
28
29
  <AlertBanner
29
30
  variant="error"
30
31
  title="ScaledJob Not Ready"
@@ -1,5 +1,5 @@
1
1
  import { Cpu, Settings } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink, useOperationalIssuesShown} from '../../ui/drawer-components'
3
3
  import { kindToPlural } from '../../../utils/navigation'
4
4
  import {
5
5
  getScaledObjectStatus,
@@ -39,6 +39,7 @@ export function KedaScaledObjectRenderer({ data, onNavigate }: KedaScaledObjectR
39
39
  const isPaused = soStatus.text === 'Paused'
40
40
  const isFallback = soStatus.text === 'Fallback'
41
41
  const isNotReady = soStatus.level === 'unhealthy'
42
+ const operationalIssuesShown = useOperationalIssuesShown()
42
43
 
43
44
  const readyCond = conditions.find((c: any) => c.type === 'Ready')
44
45
  const fallbackCond = conditions.find((c: any) => c.type === 'Fallback')
@@ -53,7 +54,7 @@ export function KedaScaledObjectRenderer({ data, onNavigate }: KedaScaledObjectR
53
54
  message={fallbackCond?.message || 'KEDA is using fallback replicas because triggers are failing.'}
54
55
  />
55
56
  )}
56
- {isNotReady && !isFallback && (
57
+ {isNotReady && !isFallback && !operationalIssuesShown && (
57
58
  <AlertBanner
58
59
  variant="error"
59
60
  title="ScaledObject Not Ready"
@@ -1,5 +1,5 @@
1
1
  import { Box, Settings, Cloud, ScrollText, Pause, Layers } from 'lucide-react'
2
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink } from '../../ui/drawer-components'
2
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink, useOperationalIssuesShown} from '../../ui/drawer-components'
3
3
  import { CodeViewer } from '../../ui/CodeViewer'
4
4
  import {
5
5
  getCrossplaneStatus,
@@ -41,6 +41,7 @@ export function ManagedResourceRenderer({ data, onNavigate }: ManagedResourceRen
41
41
  const atProvider = data?.status?.atProvider
42
42
 
43
43
  const alertVariant = status.level === 'unhealthy' || status.level === 'alert' ? status.level : null
44
+ const operationalIssuesShown = useOperationalIssuesShown()
44
45
 
45
46
  return (
46
47
  <>
@@ -53,7 +54,7 @@ export function ManagedResourceRenderer({ data, onNavigate }: ManagedResourceRen
53
54
  />
54
55
  )}
55
56
 
56
- {alertVariant && statusReason && (
57
+ {alertVariant && statusReason && !operationalIssuesShown && (
57
58
  <AlertBanner
58
59
  variant={alertVariant === 'unhealthy' ? 'error' : 'warning'}
59
60
  title={status.text}
@@ -1,7 +1,7 @@
1
1
  import type { ReactNode } from 'react'
2
2
  import { HardDrive } from 'lucide-react'
3
3
  import { clsx } from 'clsx'
4
- import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink } from '../../ui/drawer-components'
4
+ import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink, useOperationalIssuesShown} from '../../ui/drawer-components'
5
5
 
6
6
  interface PVCRendererProps {
7
7
  data: any
@@ -38,11 +38,12 @@ export function PVCRenderer({ data, onNavigate, extraSections }: PVCRendererProp
38
38
  const selectedNode = annotations['volume.kubernetes.io/selected-node']
39
39
  const bindCompleted = annotations['pv.kubernetes.io/bind-completed']
40
40
  const hasProvisionerInfo = provisioner || selectedNode || bindCompleted
41
+ const operationalIssuesShown = useOperationalIssuesShown()
41
42
 
42
43
  return (
43
44
  <>
44
45
  {/* Problem alerts */}
45
- {isLost && (
46
+ {isLost && !operationalIssuesShown && (
46
47
  <AlertBanner
47
48
  variant="error"
48
49
  title="Issues Detected"
@@ -1,6 +1,6 @@
1
1
  import { Lock, Key, FileText } from 'lucide-react'
2
2
  import { clsx } from 'clsx'
3
- import { Section, PropertyList, Property, ConditionsSection, KeyValueBadgeList, AlertBanner, ResourceLink } from '../../ui/drawer-components'
3
+ import { Section, PropertyList, Property, ConditionsSection, KeyValueBadgeList, AlertBanner, ResourceLink, useOperationalIssuesShown } from '../../ui/drawer-components'
4
4
 
5
5
  interface SealedSecretRendererProps {
6
6
  data: any
@@ -32,6 +32,7 @@ export function SealedSecretRenderer({ data, onNavigate }: SealedSecretRendererP
32
32
  const syncedCond = conditions.find((c: any) => c.type === 'Synced')
33
33
  const isSynced = syncedCond?.status === 'True'
34
34
  const isNotSynced = syncedCond?.status === 'False'
35
+ const operationalIssuesShown = useOperationalIssuesShown()
35
36
 
36
37
  const hasTemplateMetadata =
37
38
  (templateLabels && Object.keys(templateLabels).length > 0) ||
@@ -40,7 +41,7 @@ export function SealedSecretRenderer({ data, onNavigate }: SealedSecretRendererP
40
41
  return (
41
42
  <>
42
43
  {/* Problem detection alert */}
43
- {isNotSynced && (
44
+ {isNotSynced && !operationalIssuesShown && (
44
45
  <AlertBanner
45
46
  variant="error"
46
47
  title="Secret is not synced"