@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.
- package/README.md +41 -0
- package/package.json +3 -3
- package/src/components/applications/ApplicationDetail.test.tsx +15 -0
- package/src/components/applications/ApplicationDetail.tsx +17 -15
- package/src/components/charts/AreaChart.interaction.test.tsx +118 -0
- package/src/components/charts/AreaChart.test.tsx +25 -0
- package/src/components/charts/AreaChart.tsx +141 -12
- package/src/components/charts/index.ts +1 -0
- package/src/components/checks/ChecksView.tsx +18 -1
- package/src/components/checks/types.ts +2 -13
- package/src/components/cnpg/CNPGBackupSummary.tsx +57 -9
- package/src/components/cnpg/CNPGClusterHASection.test.tsx +90 -0
- package/src/components/cnpg/CNPGClusterHASection.tsx +331 -0
- package/src/components/cnpg/CNPGClusterSummary.test.tsx +275 -0
- package/src/components/cnpg/CNPGClusterSummary.tsx +310 -96
- package/src/components/cnpg/CNPGConnectSection.test.tsx +64 -0
- package/src/components/cnpg/CNPGConnectSection.tsx +178 -0
- package/src/components/cnpg/CNPGDeclarativeSummary.tsx +157 -26
- package/src/components/cnpg/CNPGImageCatalogSummary.tsx +7 -4
- package/src/components/cnpg/CNPGLogicalPath.test.tsx +22 -0
- package/src/components/cnpg/CNPGLogicalPath.tsx +150 -0
- package/src/components/cnpg/CNPGObjectStoreSummary.tsx +9 -6
- package/src/components/cnpg/CNPGObjectSummary.test.tsx +193 -2
- package/src/components/cnpg/CNPGPoolerScheduling.test.tsx +36 -0
- package/src/components/cnpg/CNPGPoolerSummary.tsx +241 -14
- package/src/components/cnpg/CNPGSharedSummary.tsx +15 -8
- package/src/components/cnpg/CNPGWALArchivingFact.test.tsx +39 -0
- package/src/components/cnpg/backupRuns.test.ts +17 -0
- package/src/components/cnpg/backupRuns.ts +19 -0
- package/src/components/cnpg/connect.test.ts +124 -0
- package/src/components/cnpg/connect.ts +155 -0
- package/src/components/cnpg/databaseRole.test.ts +38 -0
- package/src/components/cnpg/databaseRole.ts +80 -0
- package/src/components/cnpg/ha.test.ts +446 -0
- package/src/components/cnpg/ha.ts +621 -0
- package/src/components/cnpg/index.ts +18 -0
- package/src/components/cnpg/logicalReplication.test.ts +121 -0
- package/src/components/cnpg/logicalReplication.ts +252 -0
- package/src/components/cnpg/pooler.test.ts +84 -0
- package/src/components/cnpg/pooler.ts +225 -0
- package/src/components/cnpg/primitives.tsx +21 -117
- package/src/components/cnpg/problems.ts +12 -0
- package/src/components/cnpg/relations.test.ts +63 -13
- package/src/components/cnpg/relations.ts +61 -52
- package/src/components/cnpg/schedule.ts +35 -0
- package/src/components/cnpg/workspace-disk.test.ts +97 -0
- package/src/components/cnpg/workspace-fleet-metrics.test.ts +250 -0
- package/src/components/cnpg/workspace-problems.test.ts +175 -0
- package/src/components/cnpg/workspace.test.ts +380 -9
- package/src/components/cnpg/workspace.ts +1137 -136
- package/src/components/dock/DockContext.test.tsx +32 -0
- package/src/components/dock/DockContext.tsx +18 -4
- package/src/components/dock/LocalTerminalTab.test.tsx +40 -0
- package/src/components/dock/LocalTerminalTab.tsx +4 -3
- package/src/components/dock/TerminalTab.tsx +20 -8
- package/src/components/facts/certainty.tsx +36 -0
- package/src/components/facts/facts.test.tsx +24 -0
- package/src/components/facts/facts.tsx +62 -0
- package/src/components/facts/index.ts +6 -0
- package/src/components/facts/managed-by.test.tsx +17 -0
- package/src/components/facts/managed-by.tsx +36 -0
- package/src/components/facts/public-exports.test.tsx +35 -0
- package/src/components/gitops/GitOpsGraphFilterRail.tsx +6 -2
- package/src/components/gitops/GitOpsHealthSourceNotice.test.tsx +38 -0
- package/src/components/gitops/GitOpsHealthSourceNotice.tsx +13 -3
- package/src/components/gitops/GitOpsTableView.tsx +9 -24
- package/src/components/gitops/detail-helpers.ts +1 -1
- package/src/components/gitops/insights/ArgoResourceDiff.test.tsx +115 -0
- package/src/components/gitops/insights/ArgoResourceDiff.tsx +22 -5
- package/src/components/gitops/insights/DriftPanel.tsx +62 -0
- package/src/components/gitops/insights/GitOpsInsightViews.tsx +29 -83
- package/src/components/gitops/tree/GitOpsTreeGraph.test.ts +26 -1
- package/src/components/gitops/tree/GitOpsTreeGraph.tsx +40 -60
- package/src/components/gitops/tree/layout.test.ts +111 -0
- package/src/components/gitops/tree/layout.ts +128 -0
- package/src/components/gitops/tree/tree-helpers.test.ts +17 -0
- package/src/components/gitops/tree/tree-helpers.ts +7 -1
- package/src/components/issues/ConditionalCleanup.test.tsx +82 -0
- package/src/components/issues/IssuesView.tsx +40 -5
- package/src/components/issues/ResourceIssuesSection.test.tsx +28 -0
- package/src/components/issues/ResourceIssuesSection.tsx +3 -0
- package/src/components/issues/index.ts +3 -1
- package/src/components/issues/issue-timing.ts +14 -3
- package/src/components/issues/issues.test.ts +50 -2
- package/src/components/issues/severity.ts +21 -0
- package/src/components/issues/types.ts +23 -0
- package/src/components/logs/LogCore.theme.test.tsx +81 -3
- package/src/components/logs/LogCore.tsx +25 -17
- package/src/components/logs/LogToolbarSelects.tsx +3 -1
- package/src/components/logs/LogsViewer.test.tsx +291 -0
- package/src/components/logs/LogsViewer.tsx +72 -11
- package/src/components/logs/StructuredLogLine.test.tsx +76 -0
- package/src/components/logs/StructuredLogLine.tsx +22 -30
- package/src/components/logs/WorkloadLogsViewer.notice.test.tsx +59 -0
- package/src/components/logs/WorkloadLogsViewer.test.tsx +65 -0
- package/src/components/logs/WorkloadLogsViewer.tsx +44 -10
- package/src/components/logs/useLogBuffer.test.ts +8 -0
- package/src/components/logs/useLogStream.ts +28 -1
- package/src/components/problems/index.ts +1 -0
- package/src/components/problems/problems.test.tsx +63 -0
- package/src/components/problems/problems.tsx +165 -0
- package/src/components/resources/ActiveFilterBar.test.tsx +78 -0
- package/src/components/resources/ActiveFilterBar.tsx +86 -0
- package/src/components/resources/ResourcesSidebar.keyboard.test.tsx +42 -0
- package/src/components/resources/ResourcesSidebar.test.tsx +36 -2
- package/src/components/resources/ResourcesSidebar.tsx +92 -41
- package/src/components/resources/ResourcesView.kind-filter-memory.test.ts +52 -0
- package/src/components/resources/ResourcesView.kind-view.test.tsx +149 -0
- package/src/components/resources/ResourcesView.per-container.test.ts +56 -1
- package/src/components/resources/ResourcesView.tsx +309 -117
- package/src/components/resources/curated-column-ownership.test.ts +3 -3
- package/src/components/resources/renderers/AnalysisRunRenderer.tsx +3 -3
- package/src/components/resources/renderers/ArgoApplicationRenderer.tsx +6 -5
- package/src/components/resources/renderers/AutoscalingReferences.test.tsx +286 -0
- package/src/components/resources/renderers/CAPIClusterRenderer.tsx +5 -4
- package/src/components/resources/renderers/CAPIExactReferenceNavigation.test.tsx +27 -0
- package/src/components/resources/renderers/CAPIKubeadmControlPlaneRenderer.tsx +2 -2
- package/src/components/resources/renderers/CAPIMachineDeploymentRenderer.tsx +2 -2
- package/src/components/resources/renderers/CAPIMachinePoolRenderer.tsx +2 -2
- package/src/components/resources/renderers/CAPIMachineRenderer.tsx +2 -2
- package/src/components/resources/renderers/CAPIMachineSetRenderer.tsx +2 -2
- package/src/components/resources/renderers/CNPGBackupRenderer.test.tsx +23 -0
- package/src/components/resources/renderers/CNPGBackupRenderer.tsx +8 -19
- package/src/components/resources/renderers/CNPGClusterRenderer.tsx +7 -8
- package/src/components/resources/renderers/CNPGDeclarativeRenderer.tsx +25 -0
- package/src/components/resources/renderers/CNPGScheduledBackupRenderer.test.tsx +32 -0
- package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +9 -17
- package/src/components/resources/renderers/CNPGShared.tsx +2 -2
- package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +2 -2
- package/src/components/resources/renderers/CompositeRenderer.navigation.test.tsx +35 -0
- package/src/components/resources/renderers/CompositeRenderer.tsx +3 -3
- package/src/components/resources/renderers/CompositionRenderer.tsx +3 -3
- package/src/components/resources/renderers/ConfigAuditReportRenderer.tsx +2 -2
- package/src/components/resources/renderers/ContourExactReferenceNavigation.test.tsx +34 -0
- package/src/components/resources/renderers/ContourHTTPProxyRenderer.tsx +11 -10
- package/src/components/resources/renderers/CronJobRenderer.tsx +6 -4
- package/src/components/resources/renderers/CronWorkflowRenderer.tsx +3 -2
- package/src/components/resources/renderers/EndpointSliceRenderer.test.tsx +62 -0
- package/src/components/resources/renderers/EndpointSliceRenderer.tsx +15 -14
- package/src/components/resources/renderers/EventRenderer.tsx +3 -3
- package/src/components/resources/renderers/ExperimentRenderer.tsx +2 -2
- package/src/components/resources/renderers/ExposedSecretReportRenderer.tsx +2 -2
- package/src/components/resources/renderers/ExternalSecretRenderer.tsx +2 -2
- package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +4 -4
- package/src/components/resources/renderers/GRPCRouteRenderer.tsx +11 -24
- package/src/components/resources/renderers/GatewayRouteReferences.test.tsx +63 -0
- package/src/components/resources/renderers/GitRepositoryRenderer.tsx +3 -3
- package/src/components/resources/renderers/HPARenderer.tsx +57 -17
- package/src/components/resources/renderers/HTTPRouteRenderer.tsx +12 -25
- package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +3 -3
- package/src/components/resources/renderers/IngressClassReferences.test.tsx +52 -0
- package/src/components/resources/renderers/IngressClassRenderer.tsx +10 -3
- package/src/components/resources/renderers/IngressRenderer.defaultBackend.test.tsx +33 -0
- package/src/components/resources/renderers/IngressRenderer.tsx +36 -5
- package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +9 -9
- package/src/components/resources/renderers/IstioExactReferenceNavigation.test.tsx +34 -0
- package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +5 -8
- package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +2 -14
- package/src/components/resources/renderers/KedaCredentials.test.tsx +85 -0
- package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +15 -13
- package/src/components/resources/renderers/KedaTriggerAuthRenderer.tsx +6 -3
- package/src/components/resources/renderers/KnativeEventingRenderer.tsx +24 -31
- package/src/components/resources/renderers/KnativeExactReferenceNavigation.test.tsx +47 -0
- package/src/components/resources/renderers/KnativeFlowRenderer.tsx +6 -7
- package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +7 -9
- package/src/components/resources/renderers/KnativeReferenceLink.tsx +14 -0
- package/src/components/resources/renderers/KnativeReferenceLinks.test.tsx +60 -0
- package/src/components/resources/renderers/KnativeSourceRenderer.tsx +9 -11
- package/src/components/resources/renderers/KustomizationRenderer.tsx +2 -2
- package/src/components/resources/renderers/KyvernoGlobalContextRenderer.tsx +3 -2
- package/src/components/resources/renderers/KyvernoQueueRenderers.tsx +4 -3
- package/src/components/resources/renderers/LeaseRenderer.tsx +3 -15
- package/src/components/resources/renderers/ManagedResourceRenderer.tsx +2 -2
- package/src/components/resources/renderers/MetricsUnavailableNotice.tsx +3 -2
- package/src/components/resources/renderers/NamespaceRenderer.test.ts +69 -2
- package/src/components/resources/renderers/NamespaceRenderer.tsx +6 -1
- package/src/components/resources/renderers/NodeRenderer.test.tsx +81 -1
- package/src/components/resources/renderers/NodeRenderer.tsx +56 -15
- package/src/components/resources/renderers/OCIRepositoryRenderer.tsx +3 -3
- package/src/components/resources/renderers/PodClassReferences.test.tsx +42 -0
- package/src/components/resources/renderers/PodNomination.test.tsx +57 -0
- package/src/components/resources/renderers/PodRenderer.test.tsx +32 -0
- package/src/components/resources/renderers/PodRenderer.tsx +62 -36
- package/src/components/resources/renderers/RolloutRenderer.test.tsx +1 -1
- package/src/components/resources/renderers/RolloutRenderer.tsx +3 -2
- package/src/components/resources/renderers/SbomReportRenderer.tsx +2 -2
- package/src/components/resources/renderers/SecretRenderer.test.tsx +88 -0
- package/src/components/resources/renderers/SecretRenderer.tsx +34 -5
- package/src/components/resources/renderers/ServiceRenderer.test.tsx +43 -0
- package/src/components/resources/renderers/ServiceRenderer.tsx +11 -3
- package/src/components/resources/renderers/SimpleRouteRenderer.tsx +9 -22
- package/src/components/resources/renderers/VPARenderer.tsx +17 -11
- package/src/components/resources/renderers/VeleroBSLRenderer.tsx +5 -7
- package/src/components/resources/renderers/VeleroBackupRenderer.tsx +3 -3
- package/src/components/resources/renderers/VeleroBackupRepositoryRenderer.tsx +2 -2
- package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +3 -3
- package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +2 -2
- package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +2 -2
- package/src/components/resources/renderers/WorkflowRenderer.tsx +4 -3
- package/src/components/resources/renderers/kyverno-modern-cells.tsx +1 -1
- package/src/components/resources/renderers/rollout/ReplicaSetProgression.tsx +2 -2
- package/src/components/resources/resource-utils-capi.ts +1 -1
- package/src/components/resources/resource-utils-cnpg.test.ts +35 -10
- package/src/components/resources/resource-utils-cnpg.ts +51 -24
- package/src/components/resources/resource-utils-contour.test.ts +44 -0
- package/src/components/resources/resource-utils-contour.ts +16 -0
- package/src/components/resources/resource-utils-istio.ts +12 -8
- package/src/components/resources/resource-utils-keda.ts +1 -7
- package/src/components/resources/resource-utils-knative.ts +18 -0
- package/src/components/resources/resource-utils-kyverno.ts +1 -7
- package/src/components/resources/resource-utils-velero.ts +0 -12
- package/src/components/resources/resource-utils.ts +99 -39
- package/src/components/resources/rules-column-width.test.ts +1 -1
- package/src/components/resources/summarize-scheduler-message.test.ts +30 -0
- package/src/components/shared/ActionConfirmDialog.test.tsx +154 -0
- package/src/components/shared/ActionConfirmDialog.tsx +246 -0
- package/src/components/shared/CreateResourceDialog.test.tsx +330 -0
- package/src/components/shared/CreateResourceDialog.tsx +126 -80
- package/src/components/shared/DetailShell.test.tsx +80 -0
- package/src/components/shared/DetailShell.tsx +85 -10
- package/src/components/shared/DrainPlanDialog.tsx +1 -0
- package/src/components/shared/EditableYamlView.test.tsx +7 -0
- package/src/components/shared/EditableYamlView.tsx +1 -1
- package/src/components/shared/GitOpsWriteWarning.test.tsx +86 -0
- package/src/components/shared/GitOpsWriteWarning.tsx +135 -0
- package/src/components/shared/ResourceActionsBar.tsx +20 -24
- package/src/components/shared/ResourceRendererDispatch.tsx +13 -10
- package/src/components/shared/SetImageDialog.test.ts +75 -6
- package/src/components/shared/SetImageDialog.tsx +92 -84
- package/src/components/shared/index.ts +4 -1
- package/src/components/timeline/TimelineList.tsx +2 -15
- package/src/components/timeline/TimelineSwimlanes.tsx +3 -11
- package/src/components/timeline/timeline-filters.ts +1 -0
- package/src/components/topology/K8sResourceNode.test.ts +18 -1
- package/src/components/topology/K8sResourceNode.tsx +44 -2
- package/src/components/topology/TopologyFilterSidebar.tsx +1 -0
- package/src/components/topology/TopologyGraph.tsx +8 -74
- package/src/components/topology/TopologySearch.tsx +1 -0
- package/src/components/topology/internet-groups.test.ts +35 -0
- package/src/components/topology/internet-groups.ts +55 -0
- package/src/components/topology/layout.ts +1 -1
- package/src/components/ui/Badge.tsx +1 -0
- package/src/components/ui/FoldSection.tsx +68 -0
- package/src/components/ui/ForceDeleteConfirmDialog.test.tsx +62 -0
- package/src/components/ui/ForceDeleteConfirmDialog.tsx +24 -12
- package/src/components/ui/RefLink.tsx +20 -0
- package/src/components/ui/RowActionMenu.tsx +8 -3
- package/src/components/ui/ScheduleValue.test.tsx +5 -0
- package/src/components/ui/ScheduleValue.tsx +3 -2
- package/src/components/ui/crd-definition-navigation.test.tsx +160 -0
- package/src/components/ui/drawer-components.test.tsx +175 -1
- package/src/components/ui/drawer-components.tsx +103 -36
- package/src/components/ui/index.ts +3 -1
- package/src/components/ui/monacoEditorFeatures.ts +77 -0
- package/src/components/ui/monacoRuntime.ts +14 -19
- package/src/components/ui/status-tone.test.ts +10 -1
- package/src/components/ui/status-tone.tsx +29 -0
- package/src/components/workload/WorkloadView.deleted.test.tsx +101 -0
- package/src/components/workload/WorkloadView.deletedDialog.test.tsx +45 -0
- package/src/components/workload/WorkloadView.relationships.test.tsx +37 -0
- package/src/components/workload/WorkloadView.secretSave.test.tsx +62 -0
- package/src/components/workload/WorkloadView.spec.test.tsx +149 -0
- package/src/components/workload/WorkloadView.tsx +297 -104
- package/src/index.ts +14 -1
- package/src/monaco-deep.d.ts +19 -12
- package/src/theme/components.css +13 -0
- package/src/types/capacity.ts +21 -2
- package/src/types/core.ts +60 -2
- package/src/types/gitops-flux-status.test.ts +32 -1
- package/src/types/gitops-insights.ts +19 -2
- package/src/types/gitops-tree.ts +10 -0
- package/src/types/gitops.ts +26 -6
- package/src/utils/api-resources.ts +7 -0
- package/src/utils/application-history.ts +1 -0
- package/src/utils/cnpg-backup.test.ts +26 -0
- package/src/utils/cnpg-backup.ts +70 -0
- package/src/utils/format.test.ts +49 -2
- package/src/utils/format.ts +9 -1
- package/src/utils/gateway-references.test.ts +17 -0
- package/src/utils/gateway-references.ts +29 -0
- package/src/utils/gitops-owner.ts +3 -2
- package/src/utils/gitops-write-guard.test.ts +401 -0
- package/src/utils/gitops-write-guard.ts +509 -0
- package/src/utils/grant.test.ts +19 -0
- package/src/utils/grant.ts +35 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/ingress-class-references.ts +22 -0
- package/src/utils/k8s-errors.ts +7 -7
- package/src/utils/log-format.test.ts +41 -0
- package/src/utils/log-format.ts +71 -15
- package/src/utils/log-level.ts +12 -8
- package/src/utils/navigation.test.ts +70 -0
- package/src/utils/navigation.ts +91 -8
- package/src/utils/node-lifecycle.test.ts +36 -0
- package/src/utils/node-lifecycle.ts +77 -0
- package/src/utils/object-reference-navigation.test.ts +43 -0
- package/src/utils/resource-hierarchy.test.ts +69 -0
- package/src/utils/resource-hierarchy.ts +41 -7
- package/src/utils/resource-icons.ts +2 -0
- package/src/utils/resource-refs.test.ts +23 -0
- package/src/utils/resource-refs.ts +30 -0
- package/src/utils/skeleton-yaml.test.ts +21 -0
- package/src/utils/skeleton-yaml.ts +16 -0
- package/src/utils/url-path.test.ts +35 -0
- package/src/utils/url-path.ts +21 -0
- package/src/utils/validators.test.ts +4 -13
- package/src/utils/validators.ts +5 -19
- package/src/utils/view-transition.test.ts +35 -1
- package/src/utils/view-transition.ts +16 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { renderToString } from 'react-dom/server'
|
|
3
|
+
import { IngressRenderer } from './IngressRenderer'
|
|
4
|
+
|
|
5
|
+
describe('IngressRenderer default backend', () => {
|
|
6
|
+
it('shows the default backend and no "not routed" warning', () => {
|
|
7
|
+
const html = renderToString(
|
|
8
|
+
<IngressRenderer data={{
|
|
9
|
+
metadata: { name: 'catch-all', namespace: 'team' },
|
|
10
|
+
spec: { ingressClassName: 'nginx', defaultBackend: { service: { name: 'fallback', port: { number: 80 } } } },
|
|
11
|
+
}} />,
|
|
12
|
+
)
|
|
13
|
+
expect(html).toContain('Default Backend')
|
|
14
|
+
expect(html.replace(/<!-- -->/g, '')).toContain('fallback:80')
|
|
15
|
+
expect(html).not.toContain('Traffic will not be routed')
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('still warns when an Ingress routes nowhere', () => {
|
|
19
|
+
const html = renderToString(<IngressRenderer data={{ metadata: { name: 'empty', namespace: 'team' }, spec: { ingressClassName: 'nginx' } }} />)
|
|
20
|
+
expect(html).toContain('Traffic will not be routed')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('shows a resource default backend', () => {
|
|
24
|
+
const html = renderToString(
|
|
25
|
+
<IngressRenderer data={{
|
|
26
|
+
metadata: { name: 'static', namespace: 'team' },
|
|
27
|
+
spec: { ingressClassName: 'nginx', defaultBackend: { resource: { apiGroup: 'k8s.example.com', kind: 'StorageBucket', name: 'static-assets' } } },
|
|
28
|
+
}} />,
|
|
29
|
+
)
|
|
30
|
+
expect(html).toContain('Default Backend')
|
|
31
|
+
expect(html).toContain('StorageBucket/static-assets')
|
|
32
|
+
})
|
|
33
|
+
})
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Globe, Shield, Clock } from 'lucide-react'
|
|
2
|
+
import type { ResourceRef } from '../../../types'
|
|
2
3
|
import { Section, PropertyList, Property, AlertBanner, ResourceLink } from '../../ui/drawer-components'
|
|
4
|
+
import { kindToPluralWithGroup } from '../../../utils/navigation'
|
|
3
5
|
|
|
4
6
|
interface IngressRendererProps {
|
|
5
7
|
data: any
|
|
6
|
-
onNavigate?: (ref:
|
|
8
|
+
onNavigate?: (ref: ResourceRef) => void
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
export function IngressRenderer({ data, onNavigate }: IngressRendererProps) {
|
|
@@ -15,7 +17,10 @@ export function IngressRenderer({ data, onNavigate }: IngressRendererProps) {
|
|
|
15
17
|
// Check for issues
|
|
16
18
|
const hasNoAddress = lbIngress.length === 0
|
|
17
19
|
const hasNoClass = !spec.ingressClassName && !data.metadata?.annotations?.['kubernetes.io/ingress.class']
|
|
18
|
-
const
|
|
20
|
+
const defaultService = spec.defaultBackend?.service
|
|
21
|
+
const defaultResource = spec.defaultBackend?.resource
|
|
22
|
+
// An Ingress with only a default backend still routes everything to it.
|
|
23
|
+
const hasNoRules = rules.length === 0 && !spec.defaultBackend
|
|
19
24
|
|
|
20
25
|
return (
|
|
21
26
|
<>
|
|
@@ -42,15 +47,41 @@ export function IngressRenderer({ data, onNavigate }: IngressRendererProps) {
|
|
|
42
47
|
|
|
43
48
|
<Section title="Ingress" icon={Globe}>
|
|
44
49
|
<PropertyList>
|
|
45
|
-
<Property label="Class" value={spec.ingressClassName
|
|
50
|
+
<Property label="Class" value={spec.ingressClassName
|
|
51
|
+
? <ResourceLink name={spec.ingressClassName} kind="ingressclasses" group="networking.k8s.io" onNavigate={onNavigate} />
|
|
52
|
+
: data.metadata?.annotations?.['kubernetes.io/ingress.class']
|
|
53
|
+
} />
|
|
46
54
|
{lbIngress.length > 0 && (
|
|
47
55
|
<Property label="Address" value={lbIngress[0].ip || lbIngress[0].hostname} />
|
|
48
56
|
)}
|
|
57
|
+
{defaultService?.name && (
|
|
58
|
+
<Property label="Default Backend" value={
|
|
59
|
+
<ResourceLink
|
|
60
|
+
name={defaultService.name}
|
|
61
|
+
kind="services"
|
|
62
|
+
namespace={data.metadata?.namespace || ''}
|
|
63
|
+
label={<span className="text-blue-400">{defaultService.name}:{defaultService.port?.number || defaultService.port?.name}</span>}
|
|
64
|
+
onNavigate={onNavigate}
|
|
65
|
+
/>
|
|
66
|
+
} />
|
|
67
|
+
)}
|
|
68
|
+
{defaultResource?.name && (
|
|
69
|
+
<Property label="Default Backend" value={
|
|
70
|
+
<ResourceLink
|
|
71
|
+
name={defaultResource.name}
|
|
72
|
+
kind={kindToPluralWithGroup(defaultResource.kind, defaultResource.apiGroup || '')}
|
|
73
|
+
group={defaultResource.apiGroup || ''}
|
|
74
|
+
namespace={data.metadata?.namespace || ''}
|
|
75
|
+
label={<span className="text-blue-400">{`${defaultResource.kind}/${defaultResource.name}`}</span>}
|
|
76
|
+
onNavigate={onNavigate}
|
|
77
|
+
/>
|
|
78
|
+
} />
|
|
79
|
+
)}
|
|
49
80
|
<Property label="TLS" value={tls.length > 0 ? `${tls.length} certificate(s)` : 'None'} />
|
|
50
81
|
</PropertyList>
|
|
51
82
|
</Section>
|
|
52
83
|
|
|
53
|
-
<Section title="Rules" defaultExpanded>
|
|
84
|
+
{rules.length > 0 && <Section title="Rules" defaultExpanded>
|
|
54
85
|
<div className="space-y-3">
|
|
55
86
|
{rules.map((rule: any, i: number) => (
|
|
56
87
|
<div key={i} className="card-inner-lg">
|
|
@@ -83,7 +114,7 @@ export function IngressRenderer({ data, onNavigate }: IngressRendererProps) {
|
|
|
83
114
|
</div>
|
|
84
115
|
))}
|
|
85
116
|
</div>
|
|
86
|
-
</Section>
|
|
117
|
+
</Section>}
|
|
87
118
|
|
|
88
119
|
{tls.length > 0 && (
|
|
89
120
|
<Section title="TLS" icon={Shield}>
|
|
@@ -2,6 +2,7 @@ import { Network } from 'lucide-react'
|
|
|
2
2
|
import { Section, PropertyList, Property, ConditionsSection, ResourceLink, KeyValueBadgeList } from '../../ui/drawer-components'
|
|
3
3
|
import {
|
|
4
4
|
getDestinationRuleHost,
|
|
5
|
+
resolveIstioServiceHost,
|
|
5
6
|
getDestinationRuleSubsets,
|
|
6
7
|
getDestinationRuleTrafficPolicy,
|
|
7
8
|
getDestinationRuleLoadBalancer,
|
|
@@ -9,20 +10,18 @@ import {
|
|
|
9
10
|
|
|
10
11
|
interface IstioDestinationRuleRendererProps {
|
|
11
12
|
data: any
|
|
13
|
+
serviceDomain?: string
|
|
12
14
|
onNavigate?: (ref: { kind: string; namespace: string; name: string }) => void
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
export function IstioDestinationRuleRenderer({ data, onNavigate }: IstioDestinationRuleRendererProps) {
|
|
17
|
+
export function IstioDestinationRuleRenderer({ data, onNavigate, serviceDomain }: IstioDestinationRuleRendererProps) {
|
|
16
18
|
const host = getDestinationRuleHost(data)
|
|
17
19
|
const subsets = getDestinationRuleSubsets(data)
|
|
18
20
|
const trafficPolicy = getDestinationRuleTrafficPolicy(data)
|
|
19
21
|
const loadBalancer = getDestinationRuleLoadBalancer(data)
|
|
20
22
|
const ns = data.metadata?.namespace || ''
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
const hostParts = host.split('.')
|
|
24
|
-
const svcName = hostParts[0]
|
|
25
|
-
const svcNs = hostParts.length >= 2 ? hostParts[1] : ns
|
|
24
|
+
const service = resolveIstioServiceHost(host, ns, serviceDomain)
|
|
26
25
|
|
|
27
26
|
return (
|
|
28
27
|
<>
|
|
@@ -30,15 +29,16 @@ export function IstioDestinationRuleRenderer({ data, onNavigate }: IstioDestinat
|
|
|
30
29
|
<Section title="Destination" icon={Network} defaultExpanded>
|
|
31
30
|
<PropertyList>
|
|
32
31
|
<Property label="Host" value={
|
|
33
|
-
|
|
32
|
+
service ? (
|
|
34
33
|
<ResourceLink
|
|
35
|
-
name={
|
|
34
|
+
name={service.name}
|
|
36
35
|
kind="services"
|
|
37
|
-
|
|
36
|
+
group=""
|
|
37
|
+
namespace={service.namespace}
|
|
38
38
|
label={host}
|
|
39
39
|
onNavigate={onNavigate}
|
|
40
40
|
/>
|
|
41
|
-
) :
|
|
41
|
+
) : host
|
|
42
42
|
} />
|
|
43
43
|
<Property label="Load Balancer" value={loadBalancer} />
|
|
44
44
|
</PropertyList>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { act, type ReactNode } from 'react'
|
|
3
|
+
import { createRoot } from 'react-dom/client'
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
5
|
+
import { IstioDestinationRuleRenderer } from './IstioDestinationRuleRenderer'
|
|
6
|
+
|
|
7
|
+
async function rendered(element: ReactNode, check: (container: HTMLDivElement) => Promise<void> | void) {
|
|
8
|
+
Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true })
|
|
9
|
+
const container = document.createElement('div')
|
|
10
|
+
const root = createRoot(container)
|
|
11
|
+
try { await act(async () => root.render(element)); await check(container) }
|
|
12
|
+
finally { await act(async () => root.unmount()); Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: false }) }
|
|
13
|
+
}
|
|
14
|
+
async function click(container: HTMLDivElement, text: string) {
|
|
15
|
+
const button = [...container.querySelectorAll('button')].find(button => button.textContent === text)
|
|
16
|
+
expect(button, `missing link ${text}`).toBeDefined()
|
|
17
|
+
await act(async () => button!.click())
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('exact reference navigation', () => {
|
|
21
|
+
it.each([
|
|
22
|
+
{host:'api.prod.svc.mesh.internal',domain:'mesh.internal',linked:true},
|
|
23
|
+
{host:'api.prod.svc.cluster.local',domain:undefined,linked:false},
|
|
24
|
+
{host:'api.prod.svc.external.test',domain:'mesh.internal',linked:false},
|
|
25
|
+
{host:'api.prod',domain:'mesh.internal',linked:false},
|
|
26
|
+
])('links only observed Istio service domains: $host',async ({host,domain,linked})=>{
|
|
27
|
+
const navigate=vi.fn()
|
|
28
|
+
await rendered(<IstioDestinationRuleRenderer data={{metadata:{namespace:'app'},spec:{host}}} serviceDomain={domain} onNavigate={navigate}/>,async container=>{
|
|
29
|
+
const link=[...container.querySelectorAll('button')].find(button=>button.textContent===host)
|
|
30
|
+
expect(Boolean(link)).toBe(linked)
|
|
31
|
+
if(link) {await click(container,host);expect(navigate).toHaveBeenCalledWith({kind:'services',group:'',namespace:'prod',name:'api'})}
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
})
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
getVirtualServiceHostsList,
|
|
8
8
|
getVirtualServiceGatewaysList,
|
|
9
9
|
getVirtualServiceHttpRoutes,
|
|
10
|
+
resolveIstioServiceHost,
|
|
10
11
|
getVirtualServiceTcpRoutes,
|
|
11
12
|
getVirtualServiceTlsRoutes,
|
|
12
13
|
getVirtualServiceRouteCount,
|
|
@@ -14,10 +15,11 @@ import {
|
|
|
14
15
|
|
|
15
16
|
interface IstioVirtualServiceRendererProps {
|
|
16
17
|
data: any
|
|
18
|
+
serviceDomain?: string
|
|
17
19
|
onNavigate?: (ref: { kind: string; namespace: string; name: string }) => void
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
export function IstioVirtualServiceRenderer({ data, onNavigate }: IstioVirtualServiceRendererProps) {
|
|
22
|
+
export function IstioVirtualServiceRenderer({ data, onNavigate, serviceDomain }: IstioVirtualServiceRendererProps) {
|
|
21
23
|
const status = getVirtualServiceStatus(data)
|
|
22
24
|
const hosts = getVirtualServiceHostsList(data)
|
|
23
25
|
const gateways = getVirtualServiceGatewaysList(data)
|
|
@@ -148,6 +150,7 @@ export function IstioVirtualServiceRenderer({ data, onNavigate }: IstioVirtualSe
|
|
|
148
150
|
{route.route.map((dest: any, di: number) => {
|
|
149
151
|
const weight = dest.weight ?? (route.route.length === 1 ? 100 : undefined)
|
|
150
152
|
const destHost = dest.destination?.host || ''
|
|
153
|
+
const service = resolveIstioServiceHost(destHost, ns, serviceDomain)
|
|
151
154
|
const destPort = dest.destination?.port?.number
|
|
152
155
|
const destSubset = dest.destination?.subset
|
|
153
156
|
|
|
@@ -164,13 +167,7 @@ export function IstioVirtualServiceRenderer({ data, onNavigate }: IstioVirtualSe
|
|
|
164
167
|
<span className="text-theme-text-secondary font-medium">{weight}%</span>
|
|
165
168
|
</div>
|
|
166
169
|
)}
|
|
167
|
-
<ResourceLink
|
|
168
|
-
name={destHost.split('.')[0]}
|
|
169
|
-
kind="services"
|
|
170
|
-
namespace={destHost.includes('.') ? destHost.split('.')[1] : ns}
|
|
171
|
-
label={destHost}
|
|
172
|
-
onNavigate={onNavigate}
|
|
173
|
-
/>
|
|
170
|
+
{service ? <ResourceLink name={service.name} kind="services" group="" namespace={service.namespace} label={destHost} onNavigate={onNavigate} /> : <span className="text-theme-text-primary break-all">{destHost}</span>}
|
|
174
171
|
{destPort && (
|
|
175
172
|
<span className="text-theme-text-tertiary">:{destPort}</span>
|
|
176
173
|
)}
|
|
@@ -3,6 +3,7 @@ import { clsx } from 'clsx'
|
|
|
3
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
|
+
import { formatRelativeAgeTime } from '../../../utils/format'
|
|
6
7
|
import {
|
|
7
8
|
getNodeClaimStatus,
|
|
8
9
|
getNodeClaimInstanceType,
|
|
@@ -14,19 +15,6 @@ import {
|
|
|
14
15
|
getNodeClaimExpireAfter,
|
|
15
16
|
} from '../resource-utils-karpenter'
|
|
16
17
|
|
|
17
|
-
function formatRelativeTime(isoString: string): string {
|
|
18
|
-
const date = new Date(isoString)
|
|
19
|
-
if (isNaN(date.getTime())) return ''
|
|
20
|
-
const seconds = Math.floor((Date.now() - date.getTime()) / 1000)
|
|
21
|
-
if (seconds < 60) return `${seconds}s ago`
|
|
22
|
-
const minutes = Math.floor(seconds / 60)
|
|
23
|
-
if (minutes < 60) return `${minutes}m ago`
|
|
24
|
-
const hours = Math.floor(minutes / 60)
|
|
25
|
-
if (hours < 24) return `${hours}h ago`
|
|
26
|
-
const days = Math.floor(hours / 24)
|
|
27
|
-
return `${days}d ago`
|
|
28
|
-
}
|
|
29
|
-
|
|
30
18
|
interface KarpenterNodeClaimRendererProps {
|
|
31
19
|
data: any
|
|
32
20
|
onNavigate?: (ref: { kind: string; namespace: string; name: string; group?: string }) => void
|
|
@@ -205,7 +193,7 @@ export function KarpenterNodeClaimRenderer({ data, onNavigate }: KarpenterNodeCl
|
|
|
205
193
|
</span>
|
|
206
194
|
{transitionTime && (
|
|
207
195
|
<span className="text-xs text-theme-text-tertiary shrink-0">
|
|
208
|
-
{
|
|
196
|
+
{formatRelativeAgeTime(transitionTime, '')}
|
|
209
197
|
</span>
|
|
210
198
|
)}
|
|
211
199
|
</div>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { act } from 'react'
|
|
3
|
+
import { createRoot } from 'react-dom/client'
|
|
4
|
+
import { renderToStaticMarkup } from 'react-dom/server'
|
|
5
|
+
import { expect, it, vi } from 'vitest'
|
|
6
|
+
import { KedaTriggerAuthRenderer } from './KedaTriggerAuthRenderer'
|
|
7
|
+
Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true })
|
|
8
|
+
const spec = {
|
|
9
|
+
secretTargetRef: [{ parameter: 'token', name: 'direct', key: 'token' }],
|
|
10
|
+
gcpSecretManager: {
|
|
11
|
+
credentials: {
|
|
12
|
+
clientSecret: {
|
|
13
|
+
valueFrom: { secretKeyRef: { name: 'iam', key: 'credentials.json' } },
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
it('links the actual nested GCP credential Secret in the authentication namespace', async () => {
|
|
20
|
+
const element = document.createElement('div')
|
|
21
|
+
const root = createRoot(element)
|
|
22
|
+
const onNavigate = vi.fn()
|
|
23
|
+
try {
|
|
24
|
+
await act(async () =>
|
|
25
|
+
root.render(
|
|
26
|
+
<KedaTriggerAuthRenderer
|
|
27
|
+
data={{
|
|
28
|
+
kind: 'TriggerAuthentication',
|
|
29
|
+
metadata: { namespace: 'app' },
|
|
30
|
+
spec,
|
|
31
|
+
}}
|
|
32
|
+
onNavigate={onNavigate}
|
|
33
|
+
/>,
|
|
34
|
+
),
|
|
35
|
+
)
|
|
36
|
+
const button = [...element.querySelectorAll('button')].find(b => b.textContent === 'iam')
|
|
37
|
+
expect(button).toBeDefined()
|
|
38
|
+
await act(async () => button!.click())
|
|
39
|
+
expect(onNavigate).toHaveBeenCalledWith({
|
|
40
|
+
kind: 'secrets',
|
|
41
|
+
group: '',
|
|
42
|
+
namespace: 'app',
|
|
43
|
+
name: 'iam',
|
|
44
|
+
})
|
|
45
|
+
expect(element.textContent).toContain('credentials.json')
|
|
46
|
+
} finally {
|
|
47
|
+
await act(async () => root.unmount())
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('retains cluster-auth names without inventing an operator credential namespace', () => {
|
|
52
|
+
const html = renderToStaticMarkup(
|
|
53
|
+
<KedaTriggerAuthRenderer
|
|
54
|
+
data={{
|
|
55
|
+
kind: 'ClusterTriggerAuthentication',
|
|
56
|
+
metadata: { name: 'cluster' },
|
|
57
|
+
spec,
|
|
58
|
+
}}
|
|
59
|
+
onNavigate={() => {}}
|
|
60
|
+
/>,
|
|
61
|
+
)
|
|
62
|
+
const doc = new DOMParser().parseFromString(html, 'text/html')
|
|
63
|
+
expect(doc.body.textContent).toContain('iam')
|
|
64
|
+
expect(doc.body.textContent).toContain('direct')
|
|
65
|
+
expect([...doc.querySelectorAll('button')].some(b => b.textContent === 'iam' || b.textContent === 'direct')).toBe(
|
|
66
|
+
false,
|
|
67
|
+
)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('does not accept the previously invented shallow GCP reference shape', () => {
|
|
71
|
+
const html = renderToStaticMarkup(
|
|
72
|
+
<KedaTriggerAuthRenderer
|
|
73
|
+
data={{
|
|
74
|
+
kind: 'TriggerAuthentication',
|
|
75
|
+
metadata: { namespace: 'app' },
|
|
76
|
+
spec: {
|
|
77
|
+
gcpSecretManager: {
|
|
78
|
+
credentials: { clientSecret: { name: 'fictional' } },
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
}}
|
|
82
|
+
/>,
|
|
83
|
+
)
|
|
84
|
+
expect(html).not.toContain('fictional')
|
|
85
|
+
})
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Cpu, Settings } from 'lucide-react'
|
|
2
2
|
import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink, useOperationalIssuesShown} from '../../ui/drawer-components'
|
|
3
|
-
import {
|
|
3
|
+
import { objectReferenceToResourceRef } from '../../../utils/navigation'
|
|
4
|
+
import type { ResourceRef } from '../../../types'
|
|
5
|
+
import { TimeValue } from '../../ui/ScheduleValue'
|
|
4
6
|
import {
|
|
5
7
|
getScaledObjectStatus,
|
|
6
8
|
getScaledObjectTarget,
|
|
7
9
|
getScaledObjectReplicas,
|
|
8
10
|
getScaledObjectTriggers,
|
|
9
11
|
getScaledObjectHpaName,
|
|
10
|
-
getScaledObjectLastActiveTime,
|
|
11
12
|
getScaledObjectPollingInterval,
|
|
12
13
|
getScaledObjectCooldownPeriod,
|
|
13
14
|
} from '../resource-utils-keda'
|
|
@@ -24,7 +25,7 @@ function summarizeScalingPolicies(policies: any[] | undefined, periodSeconds?: n
|
|
|
24
25
|
|
|
25
26
|
interface KedaScaledObjectRendererProps {
|
|
26
27
|
data: any
|
|
27
|
-
onNavigate?: (ref:
|
|
28
|
+
onNavigate?: (ref: ResourceRef) => void
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
export function KedaScaledObjectRenderer({ data, onNavigate }: KedaScaledObjectRendererProps) {
|
|
@@ -75,18 +76,19 @@ export function KedaScaledObjectRenderer({ data, onNavigate }: KedaScaledObjectR
|
|
|
75
76
|
<Property label="Target" value={(() => {
|
|
76
77
|
const target = data.spec?.scaleTargetRef
|
|
77
78
|
if (target?.name) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
)
|
|
79
|
+
// KEDA documents these defaults for omitted fields; an explicit
|
|
80
|
+
// target API group still belongs to the declared custom resource.
|
|
81
|
+
const ref = objectReferenceToResourceRef({
|
|
82
|
+
...target,
|
|
83
|
+
apiVersion: target.apiVersion || 'apps/v1',
|
|
84
|
+
kind: target.kind || 'Deployment',
|
|
85
|
+
namespace: data.metadata?.namespace,
|
|
86
|
+
})
|
|
87
|
+
return ref ? <ResourceLink {...ref} label={getScaledObjectTarget(data)} onNavigate={onNavigate} /> : getScaledObjectTarget(data)
|
|
87
88
|
}
|
|
88
89
|
return getScaledObjectTarget(data)
|
|
89
90
|
})()} />
|
|
91
|
+
<Property label="Target API" value={data.spec?.scaleTargetRef?.apiVersion || 'apps/v1'} />
|
|
90
92
|
<Property label="Replicas" value={getScaledObjectReplicas(data)} />
|
|
91
93
|
<Property label="Polling Interval" value={`${getScaledObjectPollingInterval(data)}s`} />
|
|
92
94
|
<Property label="Cooldown Period" value={`${getScaledObjectCooldownPeriod(data)}s`} />
|
|
@@ -97,7 +99,7 @@ export function KedaScaledObjectRenderer({ data, onNavigate }: KedaScaledObjectR
|
|
|
97
99
|
}
|
|
98
100
|
return hpaName
|
|
99
101
|
})()} />
|
|
100
|
-
<Property label="Last Active" value={
|
|
102
|
+
<Property label="Last Active" value={<TimeValue timestamp={data.status?.lastActiveTime} />} />
|
|
101
103
|
</PropertyList>
|
|
102
104
|
{fallback && (
|
|
103
105
|
<div className="mt-2 pt-2 border-t border-theme-border">
|
|
@@ -21,6 +21,8 @@ export function KedaTriggerAuthRenderer({ data, onNavigate }: KedaTriggerAuthRen
|
|
|
21
21
|
const awsSecretManager = spec.awsSecretManager
|
|
22
22
|
const gcpSecretManager = spec.gcpSecretManager
|
|
23
23
|
const podIdentity = spec.podIdentity
|
|
24
|
+
const credentialRef = gcpSecretManager?.credentials?.clientSecret?.valueFrom?.secretKeyRef
|
|
25
|
+
const namespace = data.metadata?.namespace
|
|
24
26
|
|
|
25
27
|
return (
|
|
26
28
|
<>
|
|
@@ -48,7 +50,7 @@ export function KedaTriggerAuthRenderer({ data, onNavigate }: KedaTriggerAuthRen
|
|
|
48
50
|
<div className="flex flex-wrap gap-x-4 gap-y-1 text-sm">
|
|
49
51
|
<span className="text-theme-text-primary font-medium">{ref.parameter}</span>
|
|
50
52
|
<span className="text-theme-text-secondary">
|
|
51
|
-
Secret: <ResourceLink name={ref.name} kind="secrets" namespace={
|
|
53
|
+
Secret: {namespace ? <ResourceLink name={ref.name} kind="secrets" group="" namespace={namespace} onNavigate={onNavigate} /> : ref.name} / {ref.key}
|
|
52
54
|
</span>
|
|
53
55
|
</div>
|
|
54
56
|
</div>
|
|
@@ -150,9 +152,10 @@ export function KedaTriggerAuthRenderer({ data, onNavigate }: KedaTriggerAuthRen
|
|
|
150
152
|
{gcpSecretManager && (
|
|
151
153
|
<Section title="GCP Secret Manager" icon={Cloud}>
|
|
152
154
|
<PropertyList>
|
|
153
|
-
{
|
|
154
|
-
<Property label="Credentials Secret" value={
|
|
155
|
+
{credentialRef?.name && (
|
|
156
|
+
<Property label="Credentials Secret" value={namespace ? <ResourceLink name={credentialRef.name} kind="secrets" group="" namespace={namespace} onNavigate={onNavigate} /> : credentialRef.name} />
|
|
155
157
|
)}
|
|
158
|
+
{credentialRef?.key && <Property label="Credentials Key" value={credentialRef.key} />}
|
|
156
159
|
</PropertyList>
|
|
157
160
|
{gcpSecretManager.secrets && gcpSecretManager.secrets.length > 0 && (
|
|
158
161
|
<div className="mt-2 space-y-1">
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import { KnativeReferenceLink } from './KnativeReferenceLink'
|
|
1
2
|
import { Radio, Filter, FileType, Inbox, ArrowRightLeft } from 'lucide-react'
|
|
2
3
|
import { clsx } from 'clsx'
|
|
3
4
|
import { Section, PropertyList, Property, ConditionsSection, KnativeNotReadyBanner, ResourceLink } from '../../ui/drawer-components'
|
|
4
|
-
import { kindToPlural } from '../../../utils/navigation'
|
|
5
5
|
import { getKnativeConditionStatus } from '../resource-utils-knative'
|
|
6
6
|
|
|
7
7
|
interface RendererProps {
|
|
8
8
|
data: any
|
|
9
|
-
onNavigate?: (ref: { kind: string; namespace: string; name: string }) => void
|
|
9
|
+
onNavigate?: (ref: { kind: string; namespace: string; name: string; group?: string }) => void
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
// ============================================================================
|
|
@@ -47,10 +47,9 @@ export function BrokerRenderer({ data, onNavigate }: RendererProps) {
|
|
|
47
47
|
<PropertyList>
|
|
48
48
|
{delivery.deadLetterSink?.ref && (
|
|
49
49
|
<Property label="Dead Letter" value={
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
namespace={delivery.deadLetterSink.ref.namespace || ns}
|
|
50
|
+
<KnativeReferenceLink
|
|
51
|
+
reference={delivery.deadLetterSink.ref}
|
|
52
|
+
namespace={ns}
|
|
54
53
|
onNavigate={onNavigate}
|
|
55
54
|
/>
|
|
56
55
|
} />
|
|
@@ -96,19 +95,17 @@ export function TriggerRenderer({ data, onNavigate }: RendererProps) {
|
|
|
96
95
|
</span>
|
|
97
96
|
} />
|
|
98
97
|
<Property label="Broker" value={
|
|
99
|
-
|
|
100
|
-
name
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
onNavigate={onNavigate}
|
|
104
|
-
/>
|
|
98
|
+
spec.brokerRef
|
|
99
|
+
? (spec.brokerRef.name && spec.brokerRef.namespace
|
|
100
|
+
? <ResourceLink name={spec.brokerRef.name} kind="brokers" group="eventing.knative.dev" namespace={spec.brokerRef.namespace} onNavigate={onNavigate} />
|
|
101
|
+
: <span>{spec.brokerRef.name || '-'}</span>)
|
|
102
|
+
: <ResourceLink name={brokerName} kind="brokers" group="eventing.knative.dev" namespace={ns} onNavigate={onNavigate} />
|
|
105
103
|
} />
|
|
106
104
|
<Property label="Subscriber" value={
|
|
107
105
|
subscriberRef ? (
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
namespace={subscriberRef.namespace || ns}
|
|
106
|
+
<KnativeReferenceLink
|
|
107
|
+
reference={subscriberRef}
|
|
108
|
+
namespace={ns}
|
|
112
109
|
onNavigate={onNavigate}
|
|
113
110
|
/>
|
|
114
111
|
) : subscriberUri ? (
|
|
@@ -247,9 +244,8 @@ export function SubscriptionRenderer({ data, onNavigate }: RendererProps) {
|
|
|
247
244
|
} />
|
|
248
245
|
{channelRef && (
|
|
249
246
|
<Property label="Channel" value={
|
|
250
|
-
<
|
|
251
|
-
|
|
252
|
-
kind={kindToPlural(channelRef.kind || 'Channel')}
|
|
247
|
+
<KnativeReferenceLink
|
|
248
|
+
reference={channelRef}
|
|
253
249
|
namespace={ns}
|
|
254
250
|
onNavigate={onNavigate}
|
|
255
251
|
/>
|
|
@@ -257,10 +253,9 @@ export function SubscriptionRenderer({ data, onNavigate }: RendererProps) {
|
|
|
257
253
|
)}
|
|
258
254
|
<Property label="Subscriber" value={
|
|
259
255
|
subscriberRef ? (
|
|
260
|
-
<
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
namespace={subscriberRef.namespace || ns}
|
|
256
|
+
<KnativeReferenceLink
|
|
257
|
+
reference={subscriberRef}
|
|
258
|
+
namespace={ns}
|
|
264
259
|
onNavigate={onNavigate}
|
|
265
260
|
/>
|
|
266
261
|
) : subscriberUri ? (
|
|
@@ -269,10 +264,9 @@ export function SubscriptionRenderer({ data, onNavigate }: RendererProps) {
|
|
|
269
264
|
} />
|
|
270
265
|
<Property label="Reply" value={
|
|
271
266
|
replyRef ? (
|
|
272
|
-
<
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
namespace={replyRef.namespace || ns}
|
|
267
|
+
<KnativeReferenceLink
|
|
268
|
+
reference={replyRef}
|
|
269
|
+
namespace={ns}
|
|
276
270
|
onNavigate={onNavigate}
|
|
277
271
|
/>
|
|
278
272
|
) : replyUri ? (
|
|
@@ -287,10 +281,9 @@ export function SubscriptionRenderer({ data, onNavigate }: RendererProps) {
|
|
|
287
281
|
<PropertyList>
|
|
288
282
|
{delivery.deadLetterSink.ref && (
|
|
289
283
|
<Property label="Sink" value={
|
|
290
|
-
<
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
namespace={delivery.deadLetterSink.ref.namespace || ns}
|
|
284
|
+
<KnativeReferenceLink
|
|
285
|
+
reference={delivery.deadLetterSink.ref}
|
|
286
|
+
namespace={ns}
|
|
294
287
|
onNavigate={onNavigate}
|
|
295
288
|
/>
|
|
296
289
|
} />
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { act, type ReactNode } from 'react'
|
|
3
|
+
import { createRoot } from 'react-dom/client'
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
5
|
+
import { KnativeReferenceLink } from './KnativeReferenceLink'
|
|
6
|
+
import { TriggerRenderer } from './KnativeEventingRenderer'
|
|
7
|
+
|
|
8
|
+
async function rendered(element: ReactNode, check: (container: HTMLDivElement) => Promise<void> | void) {
|
|
9
|
+
Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true })
|
|
10
|
+
const container = document.createElement('div')
|
|
11
|
+
const root = createRoot(container)
|
|
12
|
+
try { await act(async () => root.render(element)); await check(container) }
|
|
13
|
+
finally { await act(async () => root.unmount()); Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: false }) }
|
|
14
|
+
}
|
|
15
|
+
async function click(container: HTMLDivElement, text: string) {
|
|
16
|
+
const button = [...container.querySelectorAll('button')].find(button => button.textContent === text)
|
|
17
|
+
expect(button, `missing link ${text}`).toBeDefined()
|
|
18
|
+
await act(async () => button!.click())
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('exact reference navigation', () => {
|
|
22
|
+
it('follows the Trigger broker reconciler namespace/name contract',async()=>{
|
|
23
|
+
const navigate=vi.fn()
|
|
24
|
+
await rendered(<TriggerRenderer data={{metadata:{namespace:'app'},spec:{brokerRef:{namespace:'events',name:'actual',kind:'Service',apiVersion:'v1'}}}} onNavigate={navigate}/>,async container=>{
|
|
25
|
+
await click(container,'actual');expect(navigate).toHaveBeenCalledWith({kind:'brokers',group:'eventing.knative.dev',namespace:'events',name:'actual'})
|
|
26
|
+
})
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it.each([
|
|
30
|
+
{apiVersion:'messaging.knative.dev/v1',kind:'InMemoryChannel',name:'events'},
|
|
31
|
+
{group:'messaging.knative.dev',kind:'InMemoryChannel',name:'events'},
|
|
32
|
+
])('uses the actual Knative target group and kind: %j', async reference => {
|
|
33
|
+
const navigate=vi.fn()
|
|
34
|
+
await rendered(<KnativeReferenceLink reference={reference} namespace="app" onNavigate={navigate}/>,async container=>{
|
|
35
|
+
await click(container,'events')
|
|
36
|
+
expect(navigate).toHaveBeenCalledWith({kind:'inmemorychannels',group:'messaging.knative.dev',namespace:'app',name:'events'})
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
it.each([
|
|
40
|
+
{kind:'Service',name:'events'},
|
|
41
|
+
{apiVersion:'v1',group:'serving.knative.dev',kind:'Service',name:'events'},
|
|
42
|
+
])('leaves incomplete or conflicting Knative identity as text: %j', async reference=>{
|
|
43
|
+
await rendered(<KnativeReferenceLink reference={reference} namespace="app" onNavigate={vi.fn()}/>,container=>{
|
|
44
|
+
expect(container.textContent).toContain('events');expect(container.querySelector('button')).toBeNull()
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
})
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import { KnativeReferenceLink } from './KnativeReferenceLink'
|
|
1
2
|
import { ListOrdered, GitFork } from 'lucide-react'
|
|
2
3
|
import { clsx } from 'clsx'
|
|
3
|
-
import { Section, PropertyList, Property, ConditionsSection, KnativeNotReadyBanner
|
|
4
|
-
import { kindToPlural } from '../../../utils/navigation'
|
|
4
|
+
import { Section, PropertyList, Property, ConditionsSection, KnativeNotReadyBanner } from '../../ui/drawer-components'
|
|
5
5
|
import { getKnativeConditionStatus } from '../resource-utils-knative'
|
|
6
6
|
|
|
7
7
|
interface RendererProps {
|
|
8
8
|
data: any
|
|
9
|
-
onNavigate?: (ref: { kind: string; namespace: string; name: string }) => void
|
|
9
|
+
onNavigate?: (ref: { kind: string; namespace: string; name: string; group?: string }) => void
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
function RefDisplay({ ref: destRef, ns, onNavigate }: { ref: any; ns: string; onNavigate?: RendererProps['onNavigate'] }) {
|
|
@@ -14,10 +14,9 @@ function RefDisplay({ ref: destRef, ns, onNavigate }: { ref: any; ns: string; on
|
|
|
14
14
|
|
|
15
15
|
if (destRef.ref) {
|
|
16
16
|
return (
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
namespace={destRef.ref.namespace || ns}
|
|
17
|
+
<KnativeReferenceLink
|
|
18
|
+
reference={destRef.ref}
|
|
19
|
+
namespace={ns}
|
|
21
20
|
onNavigate={onNavigate}
|
|
22
21
|
/>
|
|
23
22
|
)
|