@skyhook-io/k8s-ui 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +63 -0
- package/src/components/dock/BottomDock.tsx +204 -0
- package/src/components/dock/DockContext.tsx +212 -0
- package/src/components/dock/TerminalTab.tsx +333 -0
- package/src/components/dock/index.ts +3 -0
- package/src/components/gitops/GitOpsActions.tsx +227 -0
- package/src/components/gitops/GitOpsStatusBadge.tsx +221 -0
- package/src/components/gitops/ManagedResourcesList.tsx +210 -0
- package/src/components/gitops/SyncCountdown.tsx +146 -0
- package/src/components/gitops/index.ts +4 -0
- package/src/components/logs/JsonLogLine.tsx +90 -0
- package/src/components/logs/LogCore.tsx +553 -0
- package/src/components/logs/LogToolbarSelects.tsx +74 -0
- package/src/components/logs/LogsViewer.tsx +146 -0
- package/src/components/logs/WorkloadLogsViewer.tsx +263 -0
- package/src/components/logs/index.ts +13 -0
- package/src/components/logs/useLogBuffer.ts +138 -0
- package/src/components/logs/useLogSearch.ts +151 -0
- package/src/components/logs/useLogStream.ts +61 -0
- package/src/components/resources/ResourcesView.tsx +5494 -0
- package/src/components/resources/index.ts +17 -0
- package/src/components/resources/renderers/AlertRenderer.tsx +166 -0
- package/src/components/resources/renderers/ArgoApplicationRenderer.tsx +233 -0
- package/src/components/resources/renderers/CNPGBackupRenderer.tsx +89 -0
- package/src/components/resources/renderers/CNPGClusterRenderer.tsx +194 -0
- package/src/components/resources/renderers/CNPGPoolerRenderer.tsx +79 -0
- package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +68 -0
- package/src/components/resources/renderers/CertificateRenderer.tsx +209 -0
- package/src/components/resources/renderers/CertificateRequestRenderer.tsx +123 -0
- package/src/components/resources/renderers/ChallengeRenderer.tsx +111 -0
- package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +164 -0
- package/src/components/resources/renderers/ClusterExternalSecretRenderer.tsx +140 -0
- package/src/components/resources/renderers/ClusterIssuerRenderer.tsx +153 -0
- package/src/components/resources/renderers/ConfigAuditReportRenderer.tsx +221 -0
- package/src/components/resources/renderers/ConfigMapRenderer.tsx +124 -0
- package/src/components/resources/renderers/CronJobRenderer.tsx +86 -0
- package/src/components/resources/renderers/EventRenderer.tsx +175 -0
- package/src/components/resources/renderers/ExposedSecretReportRenderer.tsx +119 -0
- package/src/components/resources/renderers/ExternalSecretRenderer.tsx +172 -0
- package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +242 -0
- package/src/components/resources/renderers/GRPCRouteRenderer.tsx +263 -0
- package/src/components/resources/renderers/GatewayClassRenderer.tsx +68 -0
- package/src/components/resources/renderers/GatewayRenderer.tsx +218 -0
- package/src/components/resources/renderers/GenericRenderer.tsx +476 -0
- package/src/components/resources/renderers/GitRepositoryRenderer.tsx +154 -0
- package/src/components/resources/renderers/HPARenderer.tsx +164 -0
- package/src/components/resources/renderers/HTTPRouteRenderer.tsx +303 -0
- package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +167 -0
- package/src/components/resources/renderers/IngressClassRenderer.tsx +49 -0
- package/src/components/resources/renderers/IngressRenderer.tsx +104 -0
- package/src/components/resources/renderers/IstioAuthorizationPolicyRenderer.tsx +175 -0
- package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +176 -0
- package/src/components/resources/renderers/IstioGatewayRenderer.tsx +125 -0
- package/src/components/resources/renderers/IstioPeerAuthenticationRenderer.tsx +84 -0
- package/src/components/resources/renderers/IstioServiceEntryRenderer.tsx +112 -0
- package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +288 -0
- package/src/components/resources/renderers/JobRenderer.tsx +103 -0
- package/src/components/resources/renderers/KarpenterEC2NodeClassRenderer.tsx +157 -0
- package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +188 -0
- package/src/components/resources/renderers/KarpenterNodePoolRenderer.tsx +148 -0
- package/src/components/resources/renderers/KedaScaledJobRenderer.tsx +90 -0
- package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +136 -0
- package/src/components/resources/renderers/KedaTriggerAuthRenderer.tsx +151 -0
- package/src/components/resources/renderers/KnativeConfigurationRenderer.tsx +70 -0
- package/src/components/resources/renderers/KnativeEventingRenderer.tsx +309 -0
- package/src/components/resources/renderers/KnativeFlowRenderer.tsx +142 -0
- package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +232 -0
- package/src/components/resources/renderers/KnativeRevisionRenderer.tsx +97 -0
- package/src/components/resources/renderers/KnativeRouteRenderer.tsx +74 -0
- package/src/components/resources/renderers/KnativeServiceRenderer.tsx +138 -0
- package/src/components/resources/renderers/KnativeSourceRenderer.tsx +220 -0
- package/src/components/resources/renderers/KustomizationRenderer.tsx +151 -0
- package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +352 -0
- package/src/components/resources/renderers/LeaseRenderer.tsx +93 -0
- package/src/components/resources/renderers/NetworkPolicyRenderer.tsx +208 -0
- package/src/components/resources/renderers/NodeRenderer.tsx +282 -0
- package/src/components/resources/renderers/OCIRepositoryRenderer.tsx +153 -0
- package/src/components/resources/renderers/OrderRenderer.tsx +108 -0
- package/src/components/resources/renderers/PVCRenderer.tsx +98 -0
- package/src/components/resources/renderers/PersistentVolumeRenderer.tsx +138 -0
- package/src/components/resources/renderers/PodDisruptionBudgetRenderer.tsx +126 -0
- package/src/components/resources/renderers/PodMonitorRenderer.tsx +63 -0
- package/src/components/resources/renderers/PodRenderer.tsx +677 -0
- package/src/components/resources/renderers/PriorityClassRenderer.tsx +50 -0
- package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +62 -0
- package/src/components/resources/renderers/ReplicaSetRenderer.tsx +71 -0
- package/src/components/resources/renderers/RoleBindingRenderer.tsx +97 -0
- package/src/components/resources/renderers/RoleRenderer.tsx +192 -0
- package/src/components/resources/renderers/RolloutRenderer.tsx +227 -0
- package/src/components/resources/renderers/RuntimeClassRenderer.tsx +75 -0
- package/src/components/resources/renderers/SbomReportRenderer.tsx +98 -0
- package/src/components/resources/renderers/SealedSecretRenderer.tsx +121 -0
- package/src/components/resources/renderers/SecretRenderer.tsx +321 -0
- package/src/components/resources/renderers/SecretStoreRenderer.tsx +111 -0
- package/src/components/resources/renderers/ServiceAccountRenderer.tsx +81 -0
- package/src/components/resources/renderers/ServiceMonitorRenderer.tsx +65 -0
- package/src/components/resources/renderers/ServiceRenderer.tsx +98 -0
- package/src/components/resources/renderers/SimpleRouteRenderer.tsx +195 -0
- package/src/components/resources/renderers/StorageClassRenderer.tsx +82 -0
- package/src/components/resources/renderers/TraefikIngressRouteRenderer.tsx +257 -0
- package/src/components/resources/renderers/VPARenderer.tsx +193 -0
- package/src/components/resources/renderers/VeleroBSLRenderer.tsx +73 -0
- package/src/components/resources/renderers/VeleroBackupRenderer.tsx +193 -0
- package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +161 -0
- package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +134 -0
- package/src/components/resources/renderers/VeleroVSLRenderer.tsx +36 -0
- package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +347 -0
- package/src/components/resources/renderers/WebhookConfigRenderer.tsx +156 -0
- package/src/components/resources/renderers/WorkflowRenderer.tsx +202 -0
- package/src/components/resources/renderers/WorkflowTemplateRenderer.tsx +91 -0
- package/src/components/resources/renderers/WorkloadRenderer.tsx +311 -0
- package/src/components/resources/renderers/argo-cells.tsx +118 -0
- package/src/components/resources/renderers/certmanager-cells.tsx +164 -0
- package/src/components/resources/renderers/cnpg-cells.tsx +161 -0
- package/src/components/resources/renderers/eso-cells.tsx +115 -0
- package/src/components/resources/renderers/flux-cells.tsx +253 -0
- package/src/components/resources/renderers/index.ts +105 -0
- package/src/components/resources/renderers/istio-cells.tsx +210 -0
- package/src/components/resources/renderers/karpenter-cells.tsx +107 -0
- package/src/components/resources/renderers/keda-cells.tsx +94 -0
- package/src/components/resources/renderers/knative-cells.tsx +396 -0
- package/src/components/resources/renderers/kyverno-cells.tsx +85 -0
- package/src/components/resources/renderers/prometheus-cells.tsx +74 -0
- package/src/components/resources/renderers/traefik-cells.tsx +120 -0
- package/src/components/resources/renderers/trivy-cells.tsx +153 -0
- package/src/components/resources/renderers/trivy-shared.tsx +67 -0
- package/src/components/resources/renderers/velero-cells.tsx +164 -0
- package/src/components/resources/resource-utils-argo.ts +155 -0
- package/src/components/resources/resource-utils-certmanager.ts +198 -0
- package/src/components/resources/resource-utils-cnpg.ts +344 -0
- package/src/components/resources/resource-utils-eso.ts +385 -0
- package/src/components/resources/resource-utils-flux.ts +186 -0
- package/src/components/resources/resource-utils-istio.ts +372 -0
- package/src/components/resources/resource-utils-karpenter.ts +150 -0
- package/src/components/resources/resource-utils-keda.ts +203 -0
- package/src/components/resources/resource-utils-knative.ts +218 -0
- package/src/components/resources/resource-utils-kyverno.ts +224 -0
- package/src/components/resources/resource-utils-prometheus.ts +159 -0
- package/src/components/resources/resource-utils-traefik.ts +180 -0
- package/src/components/resources/resource-utils-trivy.ts +146 -0
- package/src/components/resources/resource-utils-velero.ts +293 -0
- package/src/components/resources/resource-utils.ts +1558 -0
- package/src/components/shared/EditableYamlView.tsx +302 -0
- package/src/components/shared/ResourceActionsBar.tsx +924 -0
- package/src/components/shared/ResourceRendererDispatch.tsx +557 -0
- package/src/components/shared/index.ts +3 -0
- package/src/components/timeline/index.ts +1 -0
- package/src/components/timeline/shared.tsx +614 -0
- package/src/components/topology/GroupNode.tsx +198 -0
- package/src/components/topology/K8sResourceNode.tsx +440 -0
- package/src/components/topology/TopologyControls.tsx +62 -0
- package/src/components/topology/TopologyFilterSidebar.tsx +377 -0
- package/src/components/topology/TopologyGraph.tsx +748 -0
- package/src/components/topology/TopologySearch.tsx +304 -0
- package/src/components/topology/index.ts +7 -0
- package/src/components/topology/layout.ts +734 -0
- package/src/components/topology/layout.worker.ts +272 -0
- package/src/components/topology/topology.css +129 -0
- package/src/components/ui/CodeViewer.tsx +451 -0
- package/src/components/ui/ConfirmDialog.tsx +188 -0
- package/src/components/ui/ForceDeleteConfirmDialog.tsx +57 -0
- package/src/components/ui/HealthRing.tsx +72 -0
- package/src/components/ui/MetricsChart.tsx +259 -0
- package/src/components/ui/ResourceBar.tsx +68 -0
- package/src/components/ui/Toast.tsx +225 -0
- package/src/components/ui/Tooltip.tsx +165 -0
- package/src/components/ui/YamlEditor.tsx +280 -0
- package/src/components/ui/drawer-components.tsx +792 -0
- package/src/components/ui/index.ts +10 -0
- package/src/components/workload/ResourceDetailDrawer.tsx +158 -0
- package/src/components/workload/WorkloadView.tsx +1109 -0
- package/src/components/workload/index.ts +2 -0
- package/src/hooks/index.ts +9 -0
- package/src/hooks/useAnimatedUnmount.ts +30 -0
- package/src/hooks/useKeyboardShortcuts.tsx +336 -0
- package/src/hooks/useRefreshAnimation.ts +58 -0
- package/src/index.ts +35 -0
- package/src/types/core.ts +894 -0
- package/src/types/gitops.ts +458 -0
- package/src/types/index.ts +2 -0
- package/src/utils/animation.ts +40 -0
- package/src/utils/api-resources.ts +185 -0
- package/src/utils/badge-colors.ts +399 -0
- package/src/utils/context-name.ts +72 -0
- package/src/utils/download.ts +19 -0
- package/src/utils/format.ts +233 -0
- package/src/utils/index.ts +10 -0
- package/src/utils/log-format.ts +300 -0
- package/src/utils/navigation.ts +119 -0
- package/src/utils/resource-hierarchy.ts +630 -0
- package/src/utils/resource-icons.ts +206 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Globe } from 'lucide-react'
|
|
2
|
+
import { clsx } from 'clsx'
|
|
3
|
+
import { Section, PropertyList, Property } from '../../ui/drawer-components'
|
|
4
|
+
|
|
5
|
+
interface IngressClassRendererProps {
|
|
6
|
+
data: any
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function IngressClassRenderer({ data }: IngressClassRendererProps) {
|
|
10
|
+
const spec = data.spec || {}
|
|
11
|
+
const annotations = data.metadata?.annotations || {}
|
|
12
|
+
|
|
13
|
+
const isDefault = annotations['ingressclass.kubernetes.io/is-default-class'] === 'true'
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<>
|
|
17
|
+
<Section title="Ingress Class" icon={Globe}>
|
|
18
|
+
<PropertyList>
|
|
19
|
+
<Property label="Controller" value={spec.controller} />
|
|
20
|
+
<Property
|
|
21
|
+
label="Default"
|
|
22
|
+
value={
|
|
23
|
+
<span className={clsx(
|
|
24
|
+
'px-2 py-0.5 rounded text-xs font-medium',
|
|
25
|
+
isDefault
|
|
26
|
+
? 'bg-green-500/20 text-green-400'
|
|
27
|
+
: 'bg-gray-500/20 text-gray-400'
|
|
28
|
+
)}>
|
|
29
|
+
{isDefault ? 'Yes' : 'No'}
|
|
30
|
+
</span>
|
|
31
|
+
}
|
|
32
|
+
/>
|
|
33
|
+
</PropertyList>
|
|
34
|
+
</Section>
|
|
35
|
+
|
|
36
|
+
{spec.parameters && (
|
|
37
|
+
<Section title="Parameters Reference">
|
|
38
|
+
<PropertyList>
|
|
39
|
+
{spec.parameters.apiGroup && <Property label="API Group" value={spec.parameters.apiGroup} />}
|
|
40
|
+
<Property label="Kind" value={spec.parameters.kind} />
|
|
41
|
+
<Property label="Name" value={spec.parameters.name} />
|
|
42
|
+
{spec.parameters.namespace && <Property label="Namespace" value={spec.parameters.namespace} />}
|
|
43
|
+
{spec.parameters.scope && <Property label="Scope" value={spec.parameters.scope} />}
|
|
44
|
+
</PropertyList>
|
|
45
|
+
</Section>
|
|
46
|
+
)}
|
|
47
|
+
</>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { Globe, Shield, Clock } from 'lucide-react'
|
|
2
|
+
import { Section, PropertyList, Property, AlertBanner, ResourceLink } from '../../ui/drawer-components'
|
|
3
|
+
|
|
4
|
+
interface IngressRendererProps {
|
|
5
|
+
data: any
|
|
6
|
+
onNavigate?: (ref: { kind: string; namespace: string; name: string }) => void
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function IngressRenderer({ data, onNavigate }: IngressRendererProps) {
|
|
10
|
+
const spec = data.spec || {}
|
|
11
|
+
const rules = spec.rules || []
|
|
12
|
+
const tls = spec.tls || []
|
|
13
|
+
const lbIngress = data.status?.loadBalancer?.ingress || []
|
|
14
|
+
|
|
15
|
+
// Check for issues
|
|
16
|
+
const hasNoAddress = lbIngress.length === 0
|
|
17
|
+
const hasNoClass = !spec.ingressClassName && !data.metadata?.annotations?.['kubernetes.io/ingress.class']
|
|
18
|
+
const hasNoRules = rules.length === 0
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
{/* No address warning */}
|
|
23
|
+
{hasNoAddress && (
|
|
24
|
+
<AlertBanner
|
|
25
|
+
variant="warning"
|
|
26
|
+
icon={Clock}
|
|
27
|
+
title="Address Not Assigned"
|
|
28
|
+
message={hasNoClass
|
|
29
|
+
? 'No ingress class specified — an ingress controller may not pick up this resource.'
|
|
30
|
+
: 'Waiting for ingress controller to provision address. Check Events if this persists.'}
|
|
31
|
+
/>
|
|
32
|
+
)}
|
|
33
|
+
|
|
34
|
+
{/* No rules warning */}
|
|
35
|
+
{hasNoRules && (
|
|
36
|
+
<AlertBanner
|
|
37
|
+
variant="info"
|
|
38
|
+
title="No Routing Rules"
|
|
39
|
+
message="This ingress has no rules defined. Traffic will not be routed."
|
|
40
|
+
/>
|
|
41
|
+
)}
|
|
42
|
+
|
|
43
|
+
<Section title="Ingress" icon={Globe}>
|
|
44
|
+
<PropertyList>
|
|
45
|
+
<Property label="Class" value={spec.ingressClassName || data.metadata?.annotations?.['kubernetes.io/ingress.class']} />
|
|
46
|
+
{lbIngress.length > 0 && (
|
|
47
|
+
<Property label="Address" value={lbIngress[0].ip || lbIngress[0].hostname} />
|
|
48
|
+
)}
|
|
49
|
+
<Property label="TLS" value={tls.length > 0 ? `${tls.length} certificate(s)` : 'None'} />
|
|
50
|
+
</PropertyList>
|
|
51
|
+
</Section>
|
|
52
|
+
|
|
53
|
+
<Section title="Rules" defaultExpanded>
|
|
54
|
+
<div className="space-y-3">
|
|
55
|
+
{rules.map((rule: any, i: number) => (
|
|
56
|
+
<div key={i} className="bg-theme-elevated/30 rounded p-3">
|
|
57
|
+
<div className="flex items-center gap-2 mb-2">
|
|
58
|
+
{tls.some((t: any) => t.hosts?.includes(rule.host)) && (
|
|
59
|
+
<Shield className="w-3.5 h-3.5 text-green-400" />
|
|
60
|
+
)}
|
|
61
|
+
<span className="text-sm font-medium text-theme-text-primary">{rule.host || '*'}</span>
|
|
62
|
+
</div>
|
|
63
|
+
<div className="space-y-1">
|
|
64
|
+
{rule.http?.paths?.map((path: any) => (
|
|
65
|
+
<div key={path.path || '/'} className="text-xs text-theme-text-secondary flex items-center gap-2">
|
|
66
|
+
<span className="text-theme-text-tertiary">{path.pathType || 'Prefix'}:</span>
|
|
67
|
+
<span>{path.path || '/'}</span>
|
|
68
|
+
<span className="text-theme-text-tertiary">→</span>
|
|
69
|
+
{path.backend?.service?.name ? (
|
|
70
|
+
<ResourceLink
|
|
71
|
+
name={path.backend.service.name}
|
|
72
|
+
kind="services"
|
|
73
|
+
namespace={data.metadata?.namespace || ''}
|
|
74
|
+
label={<span className="text-blue-400">{path.backend.service.name}:{path.backend.service.port?.number || path.backend.service.port?.name}</span>}
|
|
75
|
+
onNavigate={onNavigate}
|
|
76
|
+
/>
|
|
77
|
+
) : (
|
|
78
|
+
<span className="text-blue-400">-</span>
|
|
79
|
+
)}
|
|
80
|
+
</div>
|
|
81
|
+
))}
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
))}
|
|
85
|
+
</div>
|
|
86
|
+
</Section>
|
|
87
|
+
|
|
88
|
+
{tls.length > 0 && (
|
|
89
|
+
<Section title="TLS" icon={Shield}>
|
|
90
|
+
<div className="space-y-2">
|
|
91
|
+
{tls.map((t: any) => (
|
|
92
|
+
<div key={t.secretName} className="text-sm">
|
|
93
|
+
<div className="text-theme-text-secondary">Secret: {t.secretName ? (
|
|
94
|
+
<ResourceLink name={t.secretName} kind="secrets" namespace={data.metadata?.namespace || ''} onNavigate={onNavigate} />
|
|
95
|
+
) : '-'}</div>
|
|
96
|
+
<div className="text-xs text-theme-text-tertiary">Hosts: {t.hosts?.join(', ') || '*'}</div>
|
|
97
|
+
</div>
|
|
98
|
+
))}
|
|
99
|
+
</div>
|
|
100
|
+
</Section>
|
|
101
|
+
)}
|
|
102
|
+
</>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { Shield } from 'lucide-react'
|
|
2
|
+
import { clsx } from 'clsx'
|
|
3
|
+
import { Section, PropertyList, Property, ConditionsSection, AlertBanner, KeyValueBadgeList } from '../../ui/drawer-components'
|
|
4
|
+
import {
|
|
5
|
+
getAuthorizationPolicyAction,
|
|
6
|
+
getAuthorizationPolicyRules,
|
|
7
|
+
getAuthorizationPolicySelector,
|
|
8
|
+
} from '../resource-utils-istio'
|
|
9
|
+
|
|
10
|
+
const actionColors: Record<string, string> = {
|
|
11
|
+
ALLOW: 'bg-green-500/20 text-green-400',
|
|
12
|
+
DENY: 'bg-red-500/20 text-red-400',
|
|
13
|
+
CUSTOM: 'bg-blue-500/20 text-blue-400',
|
|
14
|
+
AUDIT: 'bg-yellow-500/20 text-yellow-400',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface IstioAuthorizationPolicyRendererProps {
|
|
18
|
+
data: any
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function IstioAuthorizationPolicyRenderer({ data }: IstioAuthorizationPolicyRendererProps) {
|
|
22
|
+
const action = getAuthorizationPolicyAction(data)
|
|
23
|
+
const rules = getAuthorizationPolicyRules(data)
|
|
24
|
+
const selector = getAuthorizationPolicySelector(data)
|
|
25
|
+
const hasSelector = Object.keys(selector).length > 0
|
|
26
|
+
|
|
27
|
+
// Special case: DENY with no rules = deny all
|
|
28
|
+
const isDenyAll = action === 'DENY' && rules.length === 0
|
|
29
|
+
// Special case: ALLOW with no rules = allow nothing (deny all)
|
|
30
|
+
const isAllowNothing = action === 'ALLOW' && rules.length === 0 && !data.spec?.rules
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<>
|
|
34
|
+
{isDenyAll && (
|
|
35
|
+
<AlertBanner
|
|
36
|
+
variant="error"
|
|
37
|
+
title="Deny All"
|
|
38
|
+
message="This policy denies all traffic to the target workload (DENY action with no rules)."
|
|
39
|
+
/>
|
|
40
|
+
)}
|
|
41
|
+
{isAllowNothing && (
|
|
42
|
+
<AlertBanner
|
|
43
|
+
variant="warning"
|
|
44
|
+
title="Allow Nothing"
|
|
45
|
+
message="This policy has ALLOW action but no rules, which means no traffic is allowed."
|
|
46
|
+
/>
|
|
47
|
+
)}
|
|
48
|
+
|
|
49
|
+
{/* Policy info */}
|
|
50
|
+
<Section title="Authorization Policy" icon={Shield} defaultExpanded>
|
|
51
|
+
<PropertyList>
|
|
52
|
+
<Property label="Action" value={
|
|
53
|
+
<span className={clsx(
|
|
54
|
+
'px-2 py-0.5 rounded text-xs font-medium',
|
|
55
|
+
actionColors[action] || 'bg-gray-500/20 text-gray-400'
|
|
56
|
+
)}>
|
|
57
|
+
{action}
|
|
58
|
+
</span>
|
|
59
|
+
} />
|
|
60
|
+
<Property label="Scope" value={hasSelector ? 'Workload-scoped' : 'Namespace-wide'} />
|
|
61
|
+
<Property label="Rules" value={String(rules.length)} />
|
|
62
|
+
{data.spec?.provider?.name && (
|
|
63
|
+
<Property label="Provider" value={data.spec.provider.name} />
|
|
64
|
+
)}
|
|
65
|
+
</PropertyList>
|
|
66
|
+
</Section>
|
|
67
|
+
|
|
68
|
+
{/* Selector */}
|
|
69
|
+
{hasSelector && (
|
|
70
|
+
<Section title="Workload Selector" defaultExpanded>
|
|
71
|
+
<KeyValueBadgeList items={selector} />
|
|
72
|
+
</Section>
|
|
73
|
+
)}
|
|
74
|
+
|
|
75
|
+
{/* Rules */}
|
|
76
|
+
{rules.length > 0 && (
|
|
77
|
+
<Section title={`Rules (${rules.length})`} defaultExpanded>
|
|
78
|
+
<div className="space-y-3">
|
|
79
|
+
{rules.map((rule: any, i: number) => (
|
|
80
|
+
<div key={i} className="bg-theme-elevated/30 rounded p-3">
|
|
81
|
+
<div className="text-sm font-medium text-theme-text-primary mb-2">Rule {i + 1}</div>
|
|
82
|
+
|
|
83
|
+
{/* From (sources) */}
|
|
84
|
+
{rule.from && rule.from.length > 0 && (
|
|
85
|
+
<div className="mb-2">
|
|
86
|
+
<div className="text-[10px] font-medium text-theme-text-tertiary uppercase tracking-wider mb-1">From (Sources)</div>
|
|
87
|
+
{rule.from.map((f: any, fi: number) => (
|
|
88
|
+
<div key={fi} className="flex flex-wrap gap-1 mb-1">
|
|
89
|
+
{f.source?.principals?.map((p: string, pi: number) => (
|
|
90
|
+
<span key={`p-${pi}`} className="px-1.5 py-0.5 bg-blue-500/10 text-blue-400 rounded text-xs">
|
|
91
|
+
principal: {p}
|
|
92
|
+
</span>
|
|
93
|
+
))}
|
|
94
|
+
{f.source?.namespaces?.map((n: string, ni: number) => (
|
|
95
|
+
<span key={`n-${ni}`} className="px-1.5 py-0.5 bg-purple-500/10 text-purple-400 rounded text-xs">
|
|
96
|
+
namespace: {n}
|
|
97
|
+
</span>
|
|
98
|
+
))}
|
|
99
|
+
{f.source?.ipBlocks?.map((ip: string, ipi: number) => (
|
|
100
|
+
<span key={`ip-${ipi}`} className="px-1.5 py-0.5 bg-orange-500/10 text-orange-400 rounded text-xs">
|
|
101
|
+
IP: {ip}
|
|
102
|
+
</span>
|
|
103
|
+
))}
|
|
104
|
+
{f.source?.requestPrincipals?.map((rp: string, rpi: number) => (
|
|
105
|
+
<span key={`rp-${rpi}`} className="px-1.5 py-0.5 bg-cyan-500/10 text-cyan-400 rounded text-xs">
|
|
106
|
+
reqPrincipal: {rp}
|
|
107
|
+
</span>
|
|
108
|
+
))}
|
|
109
|
+
</div>
|
|
110
|
+
))}
|
|
111
|
+
</div>
|
|
112
|
+
)}
|
|
113
|
+
|
|
114
|
+
{/* To (operations) */}
|
|
115
|
+
{rule.to && rule.to.length > 0 && (
|
|
116
|
+
<div className="mb-2">
|
|
117
|
+
<div className="text-[10px] font-medium text-theme-text-tertiary uppercase tracking-wider mb-1">To (Operations)</div>
|
|
118
|
+
{rule.to.map((t: any, ti: number) => (
|
|
119
|
+
<div key={ti} className="flex flex-wrap gap-1 mb-1">
|
|
120
|
+
{t.operation?.hosts?.map((h: string, hi: number) => (
|
|
121
|
+
<span key={`h-${hi}`} className="px-1.5 py-0.5 bg-blue-500/10 text-blue-400 rounded text-xs">
|
|
122
|
+
host: {h}
|
|
123
|
+
</span>
|
|
124
|
+
))}
|
|
125
|
+
{t.operation?.ports?.map((p: string, pi: number) => (
|
|
126
|
+
<span key={`p-${pi}`} className="px-1.5 py-0.5 bg-orange-500/10 text-orange-400 rounded text-xs">
|
|
127
|
+
port: {p}
|
|
128
|
+
</span>
|
|
129
|
+
))}
|
|
130
|
+
{t.operation?.methods?.map((m: string, mi: number) => (
|
|
131
|
+
<span key={`m-${mi}`} className="px-1.5 py-0.5 bg-green-500/10 text-green-400 rounded text-xs">
|
|
132
|
+
method: {m}
|
|
133
|
+
</span>
|
|
134
|
+
))}
|
|
135
|
+
{t.operation?.paths?.map((p: string, pi: number) => (
|
|
136
|
+
<span key={`path-${pi}`} className="px-1.5 py-0.5 bg-purple-500/10 text-purple-400 rounded text-xs">
|
|
137
|
+
path: {p}
|
|
138
|
+
</span>
|
|
139
|
+
))}
|
|
140
|
+
</div>
|
|
141
|
+
))}
|
|
142
|
+
</div>
|
|
143
|
+
)}
|
|
144
|
+
|
|
145
|
+
{/* When (conditions) */}
|
|
146
|
+
{rule.when && rule.when.length > 0 && (
|
|
147
|
+
<div>
|
|
148
|
+
<div className="text-[10px] font-medium text-theme-text-tertiary uppercase tracking-wider mb-1">When (Conditions)</div>
|
|
149
|
+
{rule.when.map((w: any, wi: number) => (
|
|
150
|
+
<div key={wi} className="flex flex-wrap gap-1 mb-1 text-xs">
|
|
151
|
+
<span className="text-theme-text-secondary font-medium">{w.key}</span>
|
|
152
|
+
{w.values && (
|
|
153
|
+
<span className="text-theme-text-tertiary">
|
|
154
|
+
= [{w.values.join(', ')}]
|
|
155
|
+
</span>
|
|
156
|
+
)}
|
|
157
|
+
{w.notValues && (
|
|
158
|
+
<span className="text-red-400">
|
|
159
|
+
!= [{w.notValues.join(', ')}]
|
|
160
|
+
</span>
|
|
161
|
+
)}
|
|
162
|
+
</div>
|
|
163
|
+
))}
|
|
164
|
+
</div>
|
|
165
|
+
)}
|
|
166
|
+
</div>
|
|
167
|
+
))}
|
|
168
|
+
</div>
|
|
169
|
+
</Section>
|
|
170
|
+
)}
|
|
171
|
+
|
|
172
|
+
<ConditionsSection conditions={data.status?.conditions || []} />
|
|
173
|
+
</>
|
|
174
|
+
)
|
|
175
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { Network } from 'lucide-react'
|
|
2
|
+
import { Section, PropertyList, Property, ConditionsSection, ResourceLink, KeyValueBadgeList } from '../../ui/drawer-components'
|
|
3
|
+
import {
|
|
4
|
+
getDestinationRuleHost,
|
|
5
|
+
getDestinationRuleSubsets,
|
|
6
|
+
getDestinationRuleTrafficPolicy,
|
|
7
|
+
getDestinationRuleLoadBalancer,
|
|
8
|
+
} from '../resource-utils-istio'
|
|
9
|
+
|
|
10
|
+
interface IstioDestinationRuleRendererProps {
|
|
11
|
+
data: any
|
|
12
|
+
onNavigate?: (ref: { kind: string; namespace: string; name: string }) => void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function IstioDestinationRuleRenderer({ data, onNavigate }: IstioDestinationRuleRendererProps) {
|
|
16
|
+
const host = getDestinationRuleHost(data)
|
|
17
|
+
const subsets = getDestinationRuleSubsets(data)
|
|
18
|
+
const trafficPolicy = getDestinationRuleTrafficPolicy(data)
|
|
19
|
+
const loadBalancer = getDestinationRuleLoadBalancer(data)
|
|
20
|
+
const ns = data.metadata?.namespace || ''
|
|
21
|
+
|
|
22
|
+
// Parse host to create service link
|
|
23
|
+
const hostParts = host.split('.')
|
|
24
|
+
const svcName = hostParts[0]
|
|
25
|
+
const svcNs = hostParts.length >= 2 ? hostParts[1] : ns
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<>
|
|
29
|
+
{/* Host reference */}
|
|
30
|
+
<Section title="Destination" icon={Network} defaultExpanded>
|
|
31
|
+
<PropertyList>
|
|
32
|
+
<Property label="Host" value={
|
|
33
|
+
host !== '-' ? (
|
|
34
|
+
<ResourceLink
|
|
35
|
+
name={svcName}
|
|
36
|
+
kind="services"
|
|
37
|
+
namespace={svcNs}
|
|
38
|
+
label={host}
|
|
39
|
+
onNavigate={onNavigate}
|
|
40
|
+
/>
|
|
41
|
+
) : '-'
|
|
42
|
+
} />
|
|
43
|
+
<Property label="Load Balancer" value={loadBalancer} />
|
|
44
|
+
</PropertyList>
|
|
45
|
+
</Section>
|
|
46
|
+
|
|
47
|
+
{/* Traffic Policy */}
|
|
48
|
+
{trafficPolicy && (
|
|
49
|
+
<Section title="Traffic Policy" defaultExpanded>
|
|
50
|
+
<div className="space-y-3">
|
|
51
|
+
{/* Connection Pool */}
|
|
52
|
+
{trafficPolicy.connectionPool && (
|
|
53
|
+
<div>
|
|
54
|
+
<div className="text-xs font-medium text-theme-text-secondary uppercase tracking-wider mb-1">Connection Pool</div>
|
|
55
|
+
<PropertyList>
|
|
56
|
+
{trafficPolicy.connectionPool.tcp && (
|
|
57
|
+
<>
|
|
58
|
+
{trafficPolicy.connectionPool.tcp.maxConnections !== undefined && (
|
|
59
|
+
<Property label="Max TCP Connections" value={String(trafficPolicy.connectionPool.tcp.maxConnections)} />
|
|
60
|
+
)}
|
|
61
|
+
{trafficPolicy.connectionPool.tcp.connectTimeout && (
|
|
62
|
+
<Property label="Connect Timeout" value={trafficPolicy.connectionPool.tcp.connectTimeout} />
|
|
63
|
+
)}
|
|
64
|
+
</>
|
|
65
|
+
)}
|
|
66
|
+
{trafficPolicy.connectionPool.http && (
|
|
67
|
+
<>
|
|
68
|
+
{trafficPolicy.connectionPool.http.h2UpgradePolicy && (
|
|
69
|
+
<Property label="H2 Upgrade" value={trafficPolicy.connectionPool.http.h2UpgradePolicy} />
|
|
70
|
+
)}
|
|
71
|
+
{trafficPolicy.connectionPool.http.http1MaxPendingRequests !== undefined && (
|
|
72
|
+
<Property label="Max Pending Requests" value={String(trafficPolicy.connectionPool.http.http1MaxPendingRequests)} />
|
|
73
|
+
)}
|
|
74
|
+
{trafficPolicy.connectionPool.http.http2MaxRequests !== undefined && (
|
|
75
|
+
<Property label="Max Requests (H2)" value={String(trafficPolicy.connectionPool.http.http2MaxRequests)} />
|
|
76
|
+
)}
|
|
77
|
+
{trafficPolicy.connectionPool.http.maxRequestsPerConnection !== undefined && (
|
|
78
|
+
<Property label="Max Req/Connection" value={String(trafficPolicy.connectionPool.http.maxRequestsPerConnection)} />
|
|
79
|
+
)}
|
|
80
|
+
{trafficPolicy.connectionPool.http.maxRetries !== undefined && (
|
|
81
|
+
<Property label="Max Retries" value={String(trafficPolicy.connectionPool.http.maxRetries)} />
|
|
82
|
+
)}
|
|
83
|
+
</>
|
|
84
|
+
)}
|
|
85
|
+
</PropertyList>
|
|
86
|
+
</div>
|
|
87
|
+
)}
|
|
88
|
+
|
|
89
|
+
{/* Load Balancer */}
|
|
90
|
+
{trafficPolicy.loadBalancer && (
|
|
91
|
+
<div>
|
|
92
|
+
<div className="text-xs font-medium text-theme-text-secondary uppercase tracking-wider mb-1">Load Balancer</div>
|
|
93
|
+
<PropertyList>
|
|
94
|
+
{trafficPolicy.loadBalancer.simple && (
|
|
95
|
+
<Property label="Algorithm" value={trafficPolicy.loadBalancer.simple} />
|
|
96
|
+
)}
|
|
97
|
+
{trafficPolicy.loadBalancer.consistentHash && (
|
|
98
|
+
<Property label="Consistent Hash" value={
|
|
99
|
+
trafficPolicy.loadBalancer.consistentHash.httpHeaderName
|
|
100
|
+
? `Header: ${trafficPolicy.loadBalancer.consistentHash.httpHeaderName}`
|
|
101
|
+
: trafficPolicy.loadBalancer.consistentHash.httpCookie
|
|
102
|
+
? `Cookie: ${trafficPolicy.loadBalancer.consistentHash.httpCookie.name}`
|
|
103
|
+
: trafficPolicy.loadBalancer.consistentHash.useSourceIp
|
|
104
|
+
? 'Source IP'
|
|
105
|
+
: 'Configured'
|
|
106
|
+
} />
|
|
107
|
+
)}
|
|
108
|
+
</PropertyList>
|
|
109
|
+
</div>
|
|
110
|
+
)}
|
|
111
|
+
|
|
112
|
+
{/* Outlier Detection */}
|
|
113
|
+
{trafficPolicy.outlierDetection && (
|
|
114
|
+
<div>
|
|
115
|
+
<div className="text-xs font-medium text-theme-text-secondary uppercase tracking-wider mb-1">Outlier Detection</div>
|
|
116
|
+
<PropertyList>
|
|
117
|
+
{trafficPolicy.outlierDetection.consecutiveErrors !== undefined && (
|
|
118
|
+
<Property label="Consecutive Errors" value={String(trafficPolicy.outlierDetection.consecutiveErrors)} />
|
|
119
|
+
)}
|
|
120
|
+
{trafficPolicy.outlierDetection.consecutive5xxErrors !== undefined && (
|
|
121
|
+
<Property label="Consecutive 5xx" value={String(trafficPolicy.outlierDetection.consecutive5xxErrors)} />
|
|
122
|
+
)}
|
|
123
|
+
{trafficPolicy.outlierDetection.interval && (
|
|
124
|
+
<Property label="Interval" value={trafficPolicy.outlierDetection.interval} />
|
|
125
|
+
)}
|
|
126
|
+
{trafficPolicy.outlierDetection.baseEjectionTime && (
|
|
127
|
+
<Property label="Ejection Time" value={trafficPolicy.outlierDetection.baseEjectionTime} />
|
|
128
|
+
)}
|
|
129
|
+
{trafficPolicy.outlierDetection.maxEjectionPercent !== undefined && (
|
|
130
|
+
<Property label="Max Ejection %" value={`${trafficPolicy.outlierDetection.maxEjectionPercent}%`} />
|
|
131
|
+
)}
|
|
132
|
+
</PropertyList>
|
|
133
|
+
</div>
|
|
134
|
+
)}
|
|
135
|
+
|
|
136
|
+
{/* TLS */}
|
|
137
|
+
{trafficPolicy.tls && (
|
|
138
|
+
<div>
|
|
139
|
+
<div className="text-xs font-medium text-theme-text-secondary uppercase tracking-wider mb-1">TLS</div>
|
|
140
|
+
<PropertyList>
|
|
141
|
+
<Property label="Mode" value={trafficPolicy.tls.mode || '-'} />
|
|
142
|
+
</PropertyList>
|
|
143
|
+
</div>
|
|
144
|
+
)}
|
|
145
|
+
</div>
|
|
146
|
+
</Section>
|
|
147
|
+
)}
|
|
148
|
+
|
|
149
|
+
{/* Subsets */}
|
|
150
|
+
{subsets.length > 0 && (
|
|
151
|
+
<Section title={`Subsets (${subsets.length})`} defaultExpanded>
|
|
152
|
+
<div className="space-y-3">
|
|
153
|
+
{subsets.map((subset, i) => (
|
|
154
|
+
<div key={i} className="bg-theme-elevated/30 rounded p-3">
|
|
155
|
+
<div className="text-sm font-medium text-theme-text-primary mb-2">{subset.name}</div>
|
|
156
|
+
{Object.keys(subset.labels).length > 0 && (
|
|
157
|
+
<div className="mb-2">
|
|
158
|
+
<div className="text-[10px] font-medium text-theme-text-tertiary uppercase tracking-wider mb-1">Labels</div>
|
|
159
|
+
<KeyValueBadgeList items={subset.labels} />
|
|
160
|
+
</div>
|
|
161
|
+
)}
|
|
162
|
+
{subset.trafficPolicy && (
|
|
163
|
+
<div className="text-xs text-theme-text-tertiary">
|
|
164
|
+
Has traffic policy override
|
|
165
|
+
</div>
|
|
166
|
+
)}
|
|
167
|
+
</div>
|
|
168
|
+
))}
|
|
169
|
+
</div>
|
|
170
|
+
</Section>
|
|
171
|
+
)}
|
|
172
|
+
|
|
173
|
+
<ConditionsSection conditions={data.status?.conditions || []} />
|
|
174
|
+
</>
|
|
175
|
+
)
|
|
176
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { Globe, Lock } from 'lucide-react'
|
|
2
|
+
import { clsx } from 'clsx'
|
|
3
|
+
import { Section, PropertyList, Property, ConditionsSection, AlertBanner, KeyValueBadgeList } from '../../ui/drawer-components'
|
|
4
|
+
import {
|
|
5
|
+
getIstioGatewayStatus,
|
|
6
|
+
getIstioGatewayServers,
|
|
7
|
+
getIstioGatewaySelector,
|
|
8
|
+
} from '../resource-utils-istio'
|
|
9
|
+
|
|
10
|
+
const protocolColors: Record<string, string> = {
|
|
11
|
+
HTTP: 'bg-blue-500/20 text-blue-400',
|
|
12
|
+
HTTPS: 'bg-green-500/20 text-green-400',
|
|
13
|
+
HTTP2: 'bg-blue-500/20 text-blue-400',
|
|
14
|
+
GRPC: 'bg-purple-500/20 text-purple-400',
|
|
15
|
+
TCP: 'bg-orange-500/20 text-orange-400',
|
|
16
|
+
TLS: 'bg-green-500/20 text-green-400',
|
|
17
|
+
MONGO: 'bg-emerald-500/20 text-emerald-400',
|
|
18
|
+
MYSQL: 'bg-cyan-500/20 text-cyan-400',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface IstioGatewayRendererProps {
|
|
22
|
+
data: any
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function IstioGatewayRenderer({ data }: IstioGatewayRendererProps) {
|
|
26
|
+
const status = getIstioGatewayStatus(data)
|
|
27
|
+
const servers = getIstioGatewayServers(data)
|
|
28
|
+
const selector = getIstioGatewaySelector(data)
|
|
29
|
+
|
|
30
|
+
const hasNoServers = servers.length === 0
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<>
|
|
34
|
+
{hasNoServers && (
|
|
35
|
+
<AlertBanner
|
|
36
|
+
variant="error"
|
|
37
|
+
title="No Servers Configured"
|
|
38
|
+
message="This Istio Gateway has no server definitions."
|
|
39
|
+
/>
|
|
40
|
+
)}
|
|
41
|
+
|
|
42
|
+
{/* Gateway info */}
|
|
43
|
+
<Section title="Gateway" icon={Globe} defaultExpanded>
|
|
44
|
+
<PropertyList>
|
|
45
|
+
<Property label="Status" value={
|
|
46
|
+
<span className={clsx('px-2 py-0.5 rounded text-xs font-medium', status.color)}>
|
|
47
|
+
{status.text}
|
|
48
|
+
</span>
|
|
49
|
+
} />
|
|
50
|
+
<Property label="Workload Selector" value={
|
|
51
|
+
Object.keys(selector).length > 0 ? (
|
|
52
|
+
<KeyValueBadgeList items={selector} />
|
|
53
|
+
) : '-'
|
|
54
|
+
} />
|
|
55
|
+
</PropertyList>
|
|
56
|
+
</Section>
|
|
57
|
+
|
|
58
|
+
{/* Servers */}
|
|
59
|
+
{servers.length > 0 && (
|
|
60
|
+
<Section title={`Servers (${servers.length})`} defaultExpanded>
|
|
61
|
+
<div className="space-y-3">
|
|
62
|
+
{servers.map((server, i) => {
|
|
63
|
+
const isSecure = server.tls !== undefined
|
|
64
|
+
const protocol = server.port.protocol || 'TCP'
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<div key={i} className="bg-theme-elevated/30 rounded p-3">
|
|
68
|
+
<div className="flex items-center justify-between mb-2">
|
|
69
|
+
<div className="flex items-center gap-2">
|
|
70
|
+
{isSecure && <Lock className="w-3.5 h-3.5 text-green-400" />}
|
|
71
|
+
<span className="text-sm font-medium text-theme-text-primary">
|
|
72
|
+
{server.port.name || `Port ${server.port.number}`}
|
|
73
|
+
</span>
|
|
74
|
+
<span className={clsx(
|
|
75
|
+
'px-1.5 py-0.5 rounded text-[10px] font-medium',
|
|
76
|
+
protocolColors[protocol] || 'bg-gray-500/20 text-gray-400'
|
|
77
|
+
)}>
|
|
78
|
+
{protocol}:{server.port.number}
|
|
79
|
+
</span>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
{/* Hosts */}
|
|
84
|
+
<div className="space-y-1 text-xs text-theme-text-secondary">
|
|
85
|
+
<div>
|
|
86
|
+
<span className="text-theme-text-tertiary">Hosts: </span>
|
|
87
|
+
<span className="break-all">{server.hosts.join(', ')}</span>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
{/* TLS settings */}
|
|
91
|
+
{server.tls && (
|
|
92
|
+
<>
|
|
93
|
+
<div>
|
|
94
|
+
<span className="text-theme-text-tertiary">TLS Mode: </span>
|
|
95
|
+
<span className={clsx(
|
|
96
|
+
'px-1.5 py-0.5 rounded text-[10px] font-medium',
|
|
97
|
+
server.tls.mode === 'SIMPLE' || server.tls.mode === 'MUTUAL'
|
|
98
|
+
? 'bg-green-500/20 text-green-400'
|
|
99
|
+
: server.tls.mode === 'PASSTHROUGH'
|
|
100
|
+
? 'bg-blue-500/20 text-blue-400'
|
|
101
|
+
: 'bg-gray-500/20 text-gray-400'
|
|
102
|
+
)}>
|
|
103
|
+
{server.tls.mode || 'SIMPLE'}
|
|
104
|
+
</span>
|
|
105
|
+
</div>
|
|
106
|
+
{server.tls.credentialName && (
|
|
107
|
+
<div>
|
|
108
|
+
<span className="text-theme-text-tertiary">Credential: </span>
|
|
109
|
+
<span>{server.tls.credentialName}</span>
|
|
110
|
+
</div>
|
|
111
|
+
)}
|
|
112
|
+
</>
|
|
113
|
+
)}
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
)
|
|
117
|
+
})}
|
|
118
|
+
</div>
|
|
119
|
+
</Section>
|
|
120
|
+
)}
|
|
121
|
+
|
|
122
|
+
<ConditionsSection conditions={data.status?.conditions || []} />
|
|
123
|
+
</>
|
|
124
|
+
)
|
|
125
|
+
}
|