@skyhook-io/radar-app 1.17.0 → 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 +1 -1
- package/package.json +3 -3
- package/src/App.tsx +125 -87
- package/src/api/actions.errorCode.test.ts +40 -0
- package/src/api/actions.test.ts +48 -0
- package/src/api/actions.ts +79 -0
- package/src/api/apiResources.navigation.test.tsx +232 -0
- package/src/api/apiResources.ts +46 -3
- package/src/api/client.helmSource.test.ts +39 -0
- package/src/api/client.namespaceSwitch.hook.test.tsx +54 -0
- package/src/api/client.namespaceSwitch.test.ts +107 -0
- package/src/api/client.ts +266 -39
- package/src/api/cnpg-ha.live.test.ts +140 -0
- package/src/api/cnpg-ha.test.ts +78 -0
- package/src/api/cnpg-ha.ts +19 -0
- package/src/api/cnpg-history.ts +123 -0
- package/src/api/cnpg-inspect.ts +102 -0
- package/src/api/cnpg-protection.ts +112 -0
- package/src/api/cnpg-recovery.test.tsx +60 -0
- package/src/api/cnpg-recovery.ts +262 -0
- package/src/api/cnpg-sessions.ts +175 -0
- package/src/api/cnpg-storage.ts +138 -0
- package/src/api/cnpg.legacy-reads.test.ts +43 -0
- package/src/api/cnpg.pooler-runtime.test.ts +15 -0
- package/src/api/cnpg.ts +428 -10
- package/src/api/radarFeatures.render.test.tsx +47 -3
- package/src/api/radarFeatures.ts +4 -1
- package/src/api/reviewedActionMutation.test.tsx +164 -0
- package/src/api/reviewedActionMutation.ts +66 -0
- package/src/api/timelineSource.test.ts +9 -0
- package/src/api/timelineSource.ts +8 -0
- package/src/components/audit/AuditView.tsx +9 -0
- package/src/components/capacity/CapacityActivity.tsx +3 -31
- package/src/components/capacity/CapacityDemand.tsx +4 -36
- package/src/components/capacity/CapacityOverview.tsx +217 -56
- package/src/components/capacity/CapacityPoolDetail.tsx +6 -55
- package/src/components/capacity/CapacityView.test.tsx +323 -0
- package/src/components/capacity/ClusterSchedulingCard.tsx +2 -10
- package/src/components/capacity/certaintyGlyph.test.tsx +2 -9
- package/src/components/capacity/routes.ts +42 -0
- package/src/components/capacity/shared.tsx +11 -129
- package/src/components/capacity/workspaceRoute.ts +18 -0
- package/src/components/cnpg/CNPGActionHost.compatibility.test.tsx +30 -0
- package/src/components/cnpg/CNPGArchivingRepair.tsx +191 -0
- package/src/components/cnpg/CNPGBlockingSessions.test.tsx +50 -0
- package/src/components/cnpg/CNPGBlockingSessions.tsx +333 -0
- package/src/components/cnpg/CNPGClusterActivity.test.tsx +11 -0
- package/src/components/cnpg/CNPGClusterActivity.tsx +18 -9
- package/src/components/cnpg/CNPGClusterLogs.compatibility.test.tsx +130 -0
- package/src/components/cnpg/CNPGClusterLogs.empty.test.tsx +29 -0
- package/src/components/cnpg/CNPGClusterLogs.test.ts +9 -0
- package/src/components/cnpg/CNPGClusterLogs.tsx +81 -24
- package/src/components/cnpg/CNPGClusterTabs.test.tsx +152 -0
- package/src/components/cnpg/CNPGClusterTabs.tsx +187 -0
- package/src/components/cnpg/CNPGClustersKindView.tsx +46 -0
- package/src/components/cnpg/CNPGConfiguration.test.tsx +223 -0
- package/src/components/cnpg/CNPGConfiguration.tsx +190 -0
- package/src/components/cnpg/CNPGCreateClusterDialog.test.tsx +113 -0
- package/src/components/cnpg/CNPGCreateClusterDialog.tsx +74 -0
- package/src/components/cnpg/CNPGDeclarations.test.ts +107 -0
- package/src/components/cnpg/CNPGDeclarations.tsx +236 -78
- package/src/components/cnpg/CNPGDetailPage.test.tsx +62 -0
- package/src/components/cnpg/CNPGDetailPage.tsx +159 -98
- package/src/components/cnpg/CNPGDrawerTrail.tsx +2 -2
- package/src/components/cnpg/CNPGInvestigationAction.test.tsx +30 -0
- package/src/components/cnpg/CNPGOperator.test.tsx +34 -0
- package/src/components/cnpg/CNPGOperator.tsx +78 -30
- package/src/components/cnpg/CNPGOperatorBanner.tsx +39 -0
- package/src/components/cnpg/CNPGOperatorConditions.test.tsx +45 -0
- package/src/components/cnpg/CNPGOperatorConditions.tsx +16 -0
- package/src/components/cnpg/CNPGOperatorConfig.test.tsx +27 -0
- package/src/components/cnpg/CNPGOperatorDiagnosis.tsx +247 -0
- package/src/components/cnpg/CNPGOverview.test.tsx +171 -0
- package/src/components/cnpg/CNPGOverview.tsx +238 -63
- package/src/components/cnpg/CNPGParametersInEffect.test.tsx +51 -0
- package/src/components/cnpg/CNPGParametersInEffect.tsx +120 -0
- package/src/components/cnpg/CNPGPerformance.prerequisite.test.tsx +48 -0
- package/src/components/cnpg/CNPGPerformance.test.tsx +73 -0
- package/src/components/cnpg/CNPGPerformance.tsx +477 -0
- package/src/components/cnpg/CNPGPooling.test.tsx +89 -0
- package/src/components/cnpg/CNPGPooling.tsx +97 -40
- package/src/components/cnpg/CNPGProtection.test.tsx +145 -0
- package/src/components/cnpg/CNPGProtection.tsx +228 -122
- package/src/components/cnpg/CNPGReplicationTab.test.tsx +87 -0
- package/src/components/cnpg/CNPGReplicationTab.tsx +212 -0
- package/src/components/cnpg/CNPGReplicationView.tsx +264 -0
- package/src/components/cnpg/CNPGStorage.test.tsx +140 -0
- package/src/components/cnpg/CNPGStorage.tsx +619 -0
- package/src/components/cnpg/CNPGSummaryHost.overview.test.tsx +44 -0
- package/src/components/cnpg/CNPGSummaryHost.test.tsx +23 -0
- package/src/components/cnpg/CNPGSummaryHost.tsx +228 -54
- package/src/components/cnpg/CNPGTrends.denied.test.tsx +33 -0
- package/src/components/cnpg/CNPGTrends.missing.test.tsx +69 -0
- package/src/components/cnpg/CNPGTrends.test.ts +38 -0
- package/src/components/cnpg/CNPGTrends.tsx +702 -0
- package/src/components/cnpg/CNPGView.tsx +34 -21
- package/src/components/cnpg/CNPGWorkspace.compatibility.test.tsx +90 -0
- package/src/components/cnpg/actions/CNPGClusterActions.dialog.test.tsx +79 -0
- package/src/components/cnpg/actions/CNPGClusterActions.test.tsx +142 -0
- package/src/components/cnpg/actions/CNPGClusterActions.tsx +853 -0
- package/src/components/cnpg/actions/CNPGConnectButton.read.test.tsx +40 -0
- package/src/components/cnpg/actions/CNPGConnectButton.test.ts +25 -0
- package/src/components/cnpg/actions/CNPGConnectButton.tsx +131 -0
- package/src/components/cnpg/actions/CNPGDestroyInstanceDialog.tsx +185 -0
- package/src/components/cnpg/actions/CNPGInstanceActions.test.tsx +38 -0
- package/src/components/cnpg/actions/CNPGInstanceActions.tsx +74 -0
- package/src/components/cnpg/actions/CNPGMaintenanceBanner.tsx +53 -0
- package/src/components/cnpg/actions/CNPGPoolerActions.test.tsx +35 -0
- package/src/components/cnpg/actions/CNPGPoolerActions.tsx +79 -0
- package/src/components/cnpg/actions/CNPGReportDialog.test.tsx +12 -0
- package/src/components/cnpg/actions/CNPGReportDialog.tsx +91 -0
- package/src/components/cnpg/actions/CNPGScheduleActions.run.test.tsx +58 -0
- package/src/components/cnpg/actions/CNPGScheduleActions.test.tsx +54 -0
- package/src/components/cnpg/actions/CNPGScheduleActions.tsx +208 -0
- package/src/components/cnpg/actions/actionModel.test.ts +111 -0
- package/src/components/cnpg/actions/actionModel.ts +127 -0
- package/src/components/cnpg/actions/renderCNPGHeaderActions.tsx +60 -0
- package/src/components/cnpg/actions/useCNPGWriteGuard.tsx +58 -0
- package/src/components/cnpg/actions/useOpenCNPGPsql.ts +22 -0
- package/src/components/cnpg/archivingRepair.test.ts +104 -0
- package/src/components/cnpg/archivingRepair.ts +145 -0
- package/src/components/cnpg/baseBackup.test.ts +36 -0
- package/src/components/cnpg/baseBackup.ts +36 -0
- package/src/components/cnpg/blocking.test.ts +59 -0
- package/src/components/cnpg/blocking.ts +131 -0
- package/src/components/cnpg/coverageText.test.ts +27 -0
- package/src/components/cnpg/creation/CNPGTargetFields.tsx +110 -0
- package/src/components/cnpg/creation/targetModel.test.ts +137 -0
- package/src/components/cnpg/creation/targetModel.ts +149 -0
- package/src/components/cnpg/fleetStatus.test.ts +46 -0
- package/src/components/cnpg/fleetStatus.ts +43 -0
- package/src/components/cnpg/formFields.ts +2 -0
- package/src/components/cnpg/grantText.test.tsx +11 -0
- package/src/components/cnpg/host.test.tsx +24 -0
- package/src/components/cnpg/host.tsx +101 -0
- package/src/components/cnpg/inspectModel.test.ts +120 -0
- package/src/components/cnpg/inspectModel.ts +140 -0
- package/src/components/cnpg/logicalSlots.test.ts +30 -0
- package/src/components/cnpg/logicalSlots.ts +29 -0
- package/src/components/cnpg/lsn.test.ts +40 -0
- package/src/components/cnpg/lsn.ts +43 -0
- package/src/components/cnpg/operations/CNPGFleetOperation.tsx +30 -0
- package/src/components/cnpg/operations/CNPGOperationTracker.test.tsx +247 -0
- package/src/components/cnpg/operations/CNPGOperationTracker.tsx +255 -0
- package/src/components/cnpg/operations/model.test.ts +510 -0
- package/src/components/cnpg/operations/model.ts +499 -0
- package/src/components/cnpg/operations/presentation.test.ts +80 -0
- package/src/components/cnpg/operations/presentation.ts +84 -0
- package/src/components/cnpg/operations/store.ts +98 -0
- package/src/components/cnpg/operatorStatus.test.ts +134 -0
- package/src/components/cnpg/operatorStatus.ts +194 -0
- package/src/components/cnpg/paths.test.ts +54 -0
- package/src/components/cnpg/paths.ts +47 -4
- package/src/components/cnpg/protection/CNPGAttachArchiveDialog.tsx +185 -0
- package/src/components/cnpg/protection/CNPGCreateScheduleDialog.tsx +196 -0
- package/src/components/cnpg/protection/CNPGProtectionSetup.test.tsx +121 -0
- package/src/components/cnpg/protection/CNPGProtectionSetup.tsx +452 -0
- package/src/components/cnpg/protection/CNPGScheduleInput.tsx +115 -0
- package/src/components/cnpg/protection/CNPGScheduleRepairButton.tsx +120 -0
- package/src/components/cnpg/protection/scheduleModel.test.ts +19 -0
- package/src/components/cnpg/protection/scheduleModel.ts +16 -0
- package/src/components/cnpg/recovery/CNPGRecoveryPoint.tsx +220 -0
- package/src/components/cnpg/recovery/CNPGRestoreButton.test.tsx +29 -0
- package/src/components/cnpg/recovery/CNPGRestoreButton.tsx +26 -0
- package/src/components/cnpg/recovery/CNPGRestoreChecks.test.tsx +23 -0
- package/src/components/cnpg/recovery/CNPGRestoreChecks.tsx +153 -0
- package/src/components/cnpg/recovery/CNPGRestoreDialog.back.test.tsx +149 -0
- package/src/components/cnpg/recovery/CNPGRestoreDialog.test.tsx +46 -0
- package/src/components/cnpg/recovery/CNPGRestoreDialog.tsx +333 -0
- package/src/components/cnpg/recovery/CNPGRestoreProgress.tsx +182 -0
- package/src/components/cnpg/recovery/CNPGRestoreValidation.tsx +216 -0
- package/src/components/cnpg/recovery/restoreModel.test.ts +709 -0
- package/src/components/cnpg/recovery/restoreModel.ts +685 -0
- package/src/components/cnpg/recovery/restoreOperation.ts +56 -0
- package/src/components/cnpg/refresh.test.ts +38 -0
- package/src/components/cnpg/refresh.ts +17 -0
- package/src/components/cnpg/refreshNotice.test.tsx +29 -0
- package/src/components/cnpg/routes.test.ts +34 -3
- package/src/components/cnpg/routes.ts +60 -48
- package/src/components/cnpg/runtimeAssessment.ts +198 -0
- package/src/components/cnpg/runtimeModel.test.ts +175 -0
- package/src/components/cnpg/runtimeModel.ts +196 -0
- package/src/components/cnpg/runtimeParts.test.tsx +17 -0
- package/src/components/cnpg/runtimeParts.tsx +79 -0
- package/src/components/cnpg/shared.test.tsx +59 -0
- package/src/components/cnpg/shared.tsx +100 -182
- package/src/components/cnpg/storageModel.test.ts +107 -0
- package/src/components/cnpg/storageModel.ts +101 -0
- package/src/components/cnpg/trendSamples.test.ts +148 -0
- package/src/components/cnpg/trendSamples.ts +222 -0
- package/src/components/cnpg/useCNPGClusterAssessment.ts +30 -0
- package/src/components/cnpg/useCNPGKubectlContext.test.tsx +45 -0
- package/src/components/cnpg/useCNPGKubectlContext.ts +13 -0
- package/src/components/cnpg/useCNPGNavigate.test.tsx +58 -0
- package/src/components/cnpg/useCNPGNavigate.ts +21 -0
- package/src/components/cnpg/useCNPGPoolerLive.ts +46 -0
- package/src/components/cnpg/useCNPGScreenParams.ts +24 -0
- package/src/components/cnpg/useCNPGSidebarWorkspace.ts +66 -16
- package/src/components/cnpg/workspaceRoute.ts +23 -0
- package/src/components/cost/ApplicationCostTab.test.ts +7 -0
- package/src/components/cost/ApplicationCostTab.tsx +7 -7
- package/src/components/cost/CostView.test.ts +2 -1
- package/src/components/cost/CostView.tsx +0 -2
- package/src/components/cost/WorkloadCostTab.tsx +2 -4
- package/src/components/cost/errors.ts +3 -1
- package/src/components/cost/source.test.ts +10 -0
- package/src/components/cost/source.ts +5 -1
- package/src/components/diagnose/investigationEvidence/adapters/issues.ts +8 -0
- package/src/components/diagnose/investigationEvidence/projection.test.ts +16 -0
- package/src/components/dock/BottomDock.tsx +2 -0
- package/src/components/dock/TerminalTab.test.tsx +17 -0
- package/src/components/dock/TerminalTab.tsx +7 -3
- package/src/components/gitops/ArgoResourceDiffLoader.tsx +4 -2
- package/src/components/gitops/GitOpsView.tsx +16 -23
- package/src/components/helm/HelmCompareRoute.test.tsx +59 -0
- package/src/components/helm/HelmCompareRoute.tsx +57 -26
- package/src/components/helm/HelmReleaseDrawer.test.ts +55 -3
- package/src/components/helm/HelmReleaseDrawer.tsx +50 -12
- package/src/components/helm/TrackChartSourceDialog.render.test.tsx +120 -0
- package/src/components/helm/TrackChartSourceDialog.test.ts +50 -0
- package/src/components/helm/TrackChartSourceDialog.tsx +153 -176
- package/src/components/helm/ValuesViewer.test.tsx +301 -0
- package/src/components/helm/ValuesViewer.tsx +169 -78
- package/src/components/home/ActivitySummary.tsx +2 -1
- package/src/components/home/HomeView.tsx +20 -9
- package/src/components/home/ProblemsPanel.test.tsx +81 -0
- package/src/components/home/TopologyPreview.tsx +2 -2
- package/src/components/issues/IssuesPane.render.test.tsx +122 -0
- package/src/components/issues/IssuesPane.test.ts +65 -1
- package/src/components/issues/IssuesPane.tsx +188 -25
- package/src/components/issues/uncheckedSources.ts +21 -0
- package/src/components/resource/PVCUsageBar.render.test.tsx +32 -0
- package/src/components/resource/PVCUsageBar.test.tsx +24 -0
- package/src/components/resource/PVCUsageBar.tsx +15 -6
- package/src/components/resource/WorkloadMetricsHelpDialog.test.tsx +3 -1
- package/src/components/resource/WorkloadMetricsHelpDialog.tsx +1 -1
- package/src/components/resources/CompositeRenderer.tsx +4 -4
- package/src/components/resources/ResourceDetailDrawer.tsx +2 -2
- package/src/components/resources/ResourcesView.tsx +26 -12
- package/src/components/settings/LocalIntegrationStatus.test.tsx +52 -0
- package/src/components/settings/LocalIntegrationStatus.tsx +3 -4
- package/src/components/settings/SettingsDialog.tsx +28 -15
- package/src/components/timeline/TimelineList.tsx +22 -24
- package/src/components/timeline/TimelineLoadError.test.tsx +62 -0
- package/src/components/timeline/TimelineLoadError.tsx +96 -0
- package/src/components/timeline/TimelineView.tsx +18 -45
- package/src/components/timeline/ViewModeToggle.tsx +20 -0
- package/src/components/timeline/useStickyError.test.tsx +47 -0
- package/src/components/timeline/useStickyError.ts +15 -0
- package/src/components/ui/DiagnosticsOverlay.tsx +34 -2
- package/src/components/ui/Markdown.test.tsx +65 -0
- package/src/components/ui/Markdown.tsx +144 -127
- package/src/components/whats-new/releaseNotes.ts +63 -1
- package/src/components/workload/WorkloadView.test.ts +10 -1
- package/src/components/workload/WorkloadView.tsx +27 -239
- package/src/components/workspace/layout.test.tsx +29 -0
- package/src/components/workspace/layout.tsx +259 -0
- package/src/components/workspace/table.ts +7 -0
- package/src/contexts/CapabilitiesContext.tsx +1 -1
- package/src/integrations/resourceHost.test.tsx +55 -0
- package/src/integrations/resourceHost.ts +99 -0
- package/src/integrations/resourceHosts.test.tsx +141 -0
- package/src/integrations/resourceHosts.tsx +119 -0
- package/src/integrations/workspaceRoute.ts +20 -0
- package/src/integrations/workspaceRoutes.test.ts +40 -0
- package/src/integrations/workspaceRoutes.ts +22 -0
- package/src/integrations/workspaceScreens.tsx +14 -0
- package/src/utils/drawer-trail.ts +35 -0
- package/src/utils/kindFilterStore.test.ts +147 -0
- package/src/utils/kindFilterStore.ts +91 -0
- package/src/utils/navigation.test.ts +13 -1
- package/src/utils/navigation.ts +39 -2
- package/src/utils/page-links.ts +21 -0
- package/src/utils/tabStorage.ts +40 -0
- package/src/utils/viewMemory.test.ts +78 -0
- package/src/utils/viewMemory.ts +54 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LucideIcon } from 'lucide-react'
|
|
2
|
-
import { Bot, GitCompareArrows, Layers, Network, RefreshCcw, Scale, ScrollText, SlidersHorizontal } from 'lucide-react'
|
|
2
|
+
import { Bot, Database, GitCompareArrows, HardDrive, Hourglass, Layers, Network, RefreshCcw, Scale, ScrollText, SlidersHorizontal, Undo2 } from 'lucide-react'
|
|
3
3
|
import { compareVersions } from '../../utils/version'
|
|
4
4
|
|
|
5
5
|
export interface ReleaseHighlight {
|
|
@@ -47,6 +47,68 @@ export const CHANGELOG_URL = 'https://radarhq.io/changelog'
|
|
|
47
47
|
// major release must have its own entry: scripts/check-whats-new.sh refuses to
|
|
48
48
|
// release one without it.
|
|
49
49
|
export const RELEASE_NOTES: ReleaseNotes[] = [
|
|
50
|
+
{
|
|
51
|
+
version: 'v1.17.0',
|
|
52
|
+
highlights: [
|
|
53
|
+
{
|
|
54
|
+
id: 'cloudnative-pg',
|
|
55
|
+
icon: Database,
|
|
56
|
+
title: 'CloudNativePG, end to end',
|
|
57
|
+
description: 'See which Postgres cluster needs attention and why, whether its backups would restore, and switch over, fence or restore with a review first.',
|
|
58
|
+
leadDescription: 'New views for CloudNativePG show which Postgres cluster needs attention and why, what each instance is doing, and whether its backups would actually let you restore. Create, restore, back up, switch over, fence and hibernate from Radar: you review exactly what will be written, then Radar follows the operation until it sees the outcome.',
|
|
59
|
+
importance: 9,
|
|
60
|
+
path: '/cnpg',
|
|
61
|
+
cta: 'Open CloudNativePG',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'live-traffic-large-clusters',
|
|
65
|
+
icon: Network,
|
|
66
|
+
title: 'Live Traffic on large Cilium clusters',
|
|
67
|
+
description: 'Traffic is drawn per workload and stays fast on big clusters. Focus on one workload, or get a connection list when the map is too big.',
|
|
68
|
+
importance: 7,
|
|
69
|
+
path: '/traffic',
|
|
70
|
+
cta: 'Open Live Traffic',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: 'gitops-revert-warnings',
|
|
74
|
+
icon: Undo2,
|
|
75
|
+
title: 'Know before an edit gets reverted',
|
|
76
|
+
description: 'Before Radar edits an object owned by Argo CD, Flux or Helm, it tells you whether the owner will undo the change.',
|
|
77
|
+
importance: 6,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: 'stuck-deletion-issues',
|
|
81
|
+
icon: Hourglass,
|
|
82
|
+
title: 'Issues for stuck deletions',
|
|
83
|
+
description: "Helm uninstalls and custom resources stuck deleting raise issues, and so do volumes that can't attach to their node's machine type.",
|
|
84
|
+
importance: 6,
|
|
85
|
+
path: '/issues',
|
|
86
|
+
cta: 'Open Issues',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: 'audit-unused-storage',
|
|
90
|
+
icon: HardDrive,
|
|
91
|
+
title: 'Cluster Audit finds unused storage',
|
|
92
|
+
description: 'Claims nothing uses, claims Pending for over a day, and Released PersistentVolumes, with their size and storage class.',
|
|
93
|
+
// Below v1.16's headline at its 0.75 weight, so an upgrade from v1.15
|
|
94
|
+
// still shows that card.
|
|
95
|
+
importance: 4,
|
|
96
|
+
path: '/checks',
|
|
97
|
+
cta: 'Open Checks',
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
improvements: [
|
|
101
|
+
// The grid fills row by row: pair lines of similar length.
|
|
102
|
+
"Capacity explains why a node pool isn't scaling down",
|
|
103
|
+
'Nodes being removed show as removed, not failed',
|
|
104
|
+
'Helm actions on Flux releases change the right objects',
|
|
105
|
+
'Flux Sync with source matches flux reconcile --with-source',
|
|
106
|
+
'Topology links Services only to the Pods they select',
|
|
107
|
+
'Namespaces stuck Terminating show what holds them',
|
|
108
|
+
'Filters stay put when you switch kinds or sections',
|
|
109
|
+
'Skip an audit check per resource with an annotation',
|
|
110
|
+
],
|
|
111
|
+
},
|
|
50
112
|
{
|
|
51
113
|
version: 'v1.16.0',
|
|
52
114
|
highlights: [
|
|
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'
|
|
|
2
2
|
|
|
3
3
|
import { gitOpsOwnerFromRelationships } from '@skyhook-io/k8s-ui'
|
|
4
4
|
import type { Relationships } from '../../types'
|
|
5
|
-
import { supportsBatchExecution } from './WorkloadView'
|
|
5
|
+
import { collectServingRefs, supportsBatchExecution } from './WorkloadView'
|
|
6
6
|
import { findInheritedGitOpsLookupRef } from '../../hooks/useResolvedGitOpsOwner'
|
|
7
7
|
|
|
8
8
|
describe('findInheritedGitOpsLookupRef', () => {
|
|
@@ -75,3 +75,12 @@ describe('supportsBatchExecution', () => {
|
|
|
75
75
|
expect(supportsBatchExecution('CronJob', 'cronjobs', 'batch')).toBe(true)
|
|
76
76
|
})
|
|
77
77
|
})
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
describe('collectServingRefs', () => {
|
|
81
|
+
it('loads moved upstream resources while retaining exact API groups', () => {
|
|
82
|
+
const broker = { kind: 'Broker', group: 'eventing.knative.dev', namespace: 'demo', name: 'messages' }
|
|
83
|
+
const other = { ...broker, group: 'other.example' }
|
|
84
|
+
expect(collectServingRefs({ routedFrom: [broker, broker, other] })).toEqual([broker, other])
|
|
85
|
+
})
|
|
86
|
+
})
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { JobRenderer, JobSetRenderer } from '../resources/renderers/JobAdmissionRenderers'
|
|
3
|
-
import { RayClusterRenderer } from '../resources/renderers/RayClusterRenderer'
|
|
4
|
-
import { RayServiceRenderer } from '../resources/renderers/RayServiceRenderer'
|
|
5
|
-
import { KueueWorkloadRenderer } from '../resources/renderers/KueueWorkloadRenderer'
|
|
1
|
+
import { decorateResourceDiagnose, resourceDetailRedirect, resourceDetailSlots, resourceLogs, resourceRendererOverrides } from '../../integrations/resourceHosts'
|
|
6
2
|
import { useMemo, useEffect, useCallback, useRef, useState, type ReactNode } from 'react'
|
|
7
3
|
import { useQueries, useQueryClient } from '@tanstack/react-query'
|
|
8
4
|
import { Navigate, useNavigate, useLocation, useSearchParams } from 'react-router-dom'
|
|
@@ -11,13 +7,11 @@ import { clsx } from 'clsx'
|
|
|
11
7
|
import { Terminal, Stethoscope } from 'lucide-react'
|
|
12
8
|
import {
|
|
13
9
|
WorkloadView as BaseWorkloadView,
|
|
14
|
-
isApiGroup,
|
|
15
10
|
EditableYamlView,
|
|
16
11
|
FetchResult,
|
|
17
12
|
Section,
|
|
18
13
|
type WorkloadTabType,
|
|
19
14
|
type WorkloadExtraTab,
|
|
20
|
-
type RendererOverrides,
|
|
21
15
|
type GitOpsOwnerRef,
|
|
22
16
|
type HelmOwnerRef,
|
|
23
17
|
type AppRow,
|
|
@@ -104,7 +98,7 @@ import { WorkloadCostTab } from '../cost/WorkloadCostTab'
|
|
|
104
98
|
import { isOpenCostWorkloadKind } from '../cost/kinds'
|
|
105
99
|
import { isRadarFeatureUnsupported } from '../../api/radarFeatures'
|
|
106
100
|
import { useTrafficAvailable } from '../../api/traffic'
|
|
107
|
-
import { useResourceAudit, useResourceIssues,
|
|
101
|
+
import { useResourceAudit, useResourceIssues, useTrace, fetchTraceWithProbes, fetchInClusterCapability, runInClusterMerged } from '../../api/client'
|
|
108
102
|
import { AuditAlerts, getRadarUpgradeRequirement, ResourceIssuesSection, ReachabilityView, TraceSummary, InClusterConsentDialog, traceFingerprint, staticPollUnreliable, summarizeInClusterTests, type Trace as NetworkTrace, type InClusterCapability, inClusterConsentGiven, consentRequestRows } from '@skyhook-io/k8s-ui'
|
|
109
103
|
import { WorkloadLogsViewer } from '../logs/WorkloadLogsViewer'
|
|
110
104
|
import { ScheduledWorkloadLogsViewer } from '../logs/ScheduledWorkloadLogsViewer'
|
|
@@ -128,38 +122,7 @@ import {
|
|
|
128
122
|
defaultPathForPort,
|
|
129
123
|
} from '../curl/ServiceCurlButton'
|
|
130
124
|
import { useToast } from '../ui/Toast'
|
|
131
|
-
import { Tooltip } from '../ui/Tooltip'
|
|
132
|
-
import { PodRenderer } from '../resources/renderers/PodRenderer'
|
|
133
|
-
import { KarpenterNodePoolRenderer } from '../resources/renderers/KarpenterNodePoolRenderer'
|
|
134
|
-
import { NodeRenderer } from '../resources/renderers/NodeRenderer'
|
|
135
|
-
import { ServiceRenderer } from '../resources/renderers/ServiceRenderer'
|
|
136
|
-
import { WorkloadRenderer } from '../resources/renderers/WorkloadRenderer'
|
|
137
|
-
import { CompositeRenderer } from '../resources/CompositeRenderer'
|
|
138
|
-
import { ServiceAccountRenderer } from '../resources/renderers/ServiceAccountRenderer'
|
|
139
|
-
import { RoleRenderer } from '../resources/renderers/RoleRenderer'
|
|
140
|
-
import { RoleBindingRenderer } from '../resources/renderers/RoleBindingRenderer'
|
|
141
|
-
import { NamespaceRenderer } from '../resources/renderers/NamespaceRenderer'
|
|
142
|
-
import { CAPIClusterRenderer } from '../resources/renderers/CAPIClusterRenderer'
|
|
143
|
-
import { HPARenderer } from '../resources/renderers/HPARenderer'
|
|
144
|
-
import { PVCRenderer } from '../resources/renderers/PVCRenderer'
|
|
145
|
-
import { RolloutRenderer } from '../resources/renderers/RolloutRenderer'
|
|
146
|
-
import { KyvernoPolicyCoverage } from '../resources/renderers/KyvernoPolicyCoverage'
|
|
147
|
-
import { KyvernoPolicyQueued } from '../resources/renderers/KyvernoPolicyQueued'
|
|
148
|
-
import { CNPGObjectStoreRenderer } from '../resources/renderers/CNPGObjectStoreRenderer'
|
|
149
|
-
import { VeleroBSLRenderer } from '../resources/renderers/VeleroBSLRenderer'
|
|
150
|
-
import { VeleroBackupRenderer } from '../resources/renderers/VeleroBackupRenderer'
|
|
151
|
-
import { VeleroRestoreRenderer } from '../resources/renderers/VeleroRestoreRenderer'
|
|
152
|
-
import { CNPGClusterRenderer } from '../resources/renderers/CNPGClusterRenderer'
|
|
153
|
-
import { CNPGImageCatalogRenderer } from '../resources/renderers/CNPGImageCatalogRenderer'
|
|
154
|
-
import {
|
|
155
|
-
CNPGDatabaseRenderer,
|
|
156
|
-
CNPGPublicationRenderer,
|
|
157
|
-
CNPGSubscriptionRenderer,
|
|
158
|
-
} from '../resources/renderers/CNPGDeclarativeRenderer'
|
|
159
125
|
import { CreateResourceDialog } from '../shared/CreateResourceDialog'
|
|
160
|
-
import { renderCNPGSummary } from '../cnpg/CNPGSummaryHost'
|
|
161
|
-
import { CNPGClusterLogs } from '../cnpg/CNPGClusterLogs'
|
|
162
|
-
import { cnpgDetailKindFor, cnpgDetailPath } from '../cnpg/routes'
|
|
163
126
|
import { cleanYamlForDuplicate } from '../../utils/skeleton-yaml'
|
|
164
127
|
import { useDesktopDownload } from '../../hooks/useDesktopDownload'
|
|
165
128
|
import { useCompareLauncher } from '../compare/useCompareLauncher'
|
|
@@ -186,41 +149,6 @@ export function supportsBatchExecution(kind: string, apiKind: string, group?: st
|
|
|
186
149
|
return true
|
|
187
150
|
}
|
|
188
151
|
|
|
189
|
-
// Stable reference — web renderer wrappers inject platform hooks internally
|
|
190
|
-
const rendererOverrides: RendererOverrides = {
|
|
191
|
-
RayJobRenderer,
|
|
192
|
-
JobRenderer,
|
|
193
|
-
JobSetRenderer,
|
|
194
|
-
RayServiceRenderer,
|
|
195
|
-
RayClusterRenderer,
|
|
196
|
-
KueueWorkloadRenderer,
|
|
197
|
-
CAPIClusterRenderer,
|
|
198
|
-
PodRenderer,
|
|
199
|
-
KarpenterNodePoolRenderer,
|
|
200
|
-
NodeRenderer,
|
|
201
|
-
ServiceRenderer,
|
|
202
|
-
WorkloadRenderer,
|
|
203
|
-
CompositeRenderer,
|
|
204
|
-
ServiceAccountRenderer,
|
|
205
|
-
RoleRenderer,
|
|
206
|
-
RoleBindingRenderer,
|
|
207
|
-
NamespaceRenderer,
|
|
208
|
-
HPARenderer,
|
|
209
|
-
PVCRenderer,
|
|
210
|
-
RolloutRenderer,
|
|
211
|
-
KyvernoPolicyCoverage,
|
|
212
|
-
KyvernoPolicyQueued,
|
|
213
|
-
CNPGObjectStoreRenderer,
|
|
214
|
-
VeleroBSLRenderer,
|
|
215
|
-
VeleroBackupRenderer,
|
|
216
|
-
VeleroRestoreRenderer,
|
|
217
|
-
CNPGClusterRenderer,
|
|
218
|
-
CNPGDatabaseRenderer,
|
|
219
|
-
CNPGPublicationRenderer,
|
|
220
|
-
CNPGSubscriptionRenderer,
|
|
221
|
-
CNPGImageCatalogRenderer,
|
|
222
|
-
}
|
|
223
|
-
|
|
224
152
|
// ============================================================================
|
|
225
153
|
// ROUTE WRAPPER — parses kind/ns/name from URL
|
|
226
154
|
// ============================================================================
|
|
@@ -289,16 +217,8 @@ export function WorkloadViewRoute({ onNavigateToResource }: WorkloadViewRoutePro
|
|
|
289
217
|
)
|
|
290
218
|
}
|
|
291
219
|
|
|
292
|
-
const
|
|
293
|
-
if (
|
|
294
|
-
const params = new URLSearchParams(searchParams)
|
|
295
|
-
params.delete('apiGroup')
|
|
296
|
-
const tab = params.get('tab')
|
|
297
|
-
if (cnpgPlural === 'clusters' && (tab === 'timeline' || tab === 'events')) params.set('tab', 'activity')
|
|
298
|
-
const base = cnpgDetailPath({ plural: cnpgPlural, namespace, name })
|
|
299
|
-
const qs = params.toString()
|
|
300
|
-
return <Navigate replace to={qs ? `${base}?${qs}` : base} state={location.state} />
|
|
301
|
-
}
|
|
220
|
+
const detailPath = resourceDetailRedirect({ kind, group, namespace, name }, searchParams)
|
|
221
|
+
if (detailPath) return <Navigate replace to={detailPath} state={location.state} />
|
|
302
222
|
|
|
303
223
|
return (
|
|
304
224
|
<WorkloadView
|
|
@@ -341,6 +261,16 @@ interface WorkloadViewProps {
|
|
|
341
261
|
pushTabHistory?: boolean
|
|
342
262
|
breadcrumb?: ReactNode
|
|
343
263
|
extraTabs?: WorkloadExtraTab[]
|
|
264
|
+
tabOrder?: string[]
|
|
265
|
+
subheader?: ReactNode
|
|
266
|
+
specTab?: { label?: string; icon?: ReactNode; lead?: ReactNode; render?: () => ReactNode }
|
|
267
|
+
titlePrefix?: ReactNode
|
|
268
|
+
inlineBadges?: boolean
|
|
269
|
+
namespaceNote?: ReactNode
|
|
270
|
+
renderStatusBadge?: (resource: any) => ReactNode
|
|
271
|
+
statusNote?: ReactNode
|
|
272
|
+
onRefresh?: () => Promise<unknown>
|
|
273
|
+
hideKindBadge?: boolean
|
|
344
274
|
}
|
|
345
275
|
|
|
346
276
|
interface ImageTargetOwnershipContext {
|
|
@@ -463,7 +393,7 @@ function useActionsBarProps(
|
|
|
463
393
|
name: string
|
|
464
394
|
className?: string
|
|
465
395
|
}) => <PortForwardButton type={type} namespace={ns} name={n} className={className} />,
|
|
466
|
-
renderDiagnose,
|
|
396
|
+
renderDiagnose: decorateResourceDiagnose(renderDiagnose),
|
|
467
397
|
onDelete: (
|
|
468
398
|
params: Parameters<typeof deleteMutation.mutate>[0],
|
|
469
399
|
callbacks?: { onSuccess?: () => void },
|
|
@@ -471,7 +401,8 @@ function useActionsBarProps(
|
|
|
471
401
|
isDeleting: deleteMutation.isPending,
|
|
472
402
|
cascadeDependents: cascadePreview?.dependents,
|
|
473
403
|
cascadeLoading,
|
|
474
|
-
cascadeRootResolved:
|
|
404
|
+
cascadeRootResolved: cascadePreview?.rootResolved,
|
|
405
|
+
cascadePreviewFailed: Boolean(cascadeError),
|
|
475
406
|
onRestart: rolloutAllows('restart')
|
|
476
407
|
? (params: Parameters<typeof restartWorkloadMutation.mutate>[0]) =>
|
|
477
408
|
restartWorkloadMutation.mutate(params)
|
|
@@ -645,9 +576,11 @@ export function WorkloadView({
|
|
|
645
576
|
() => (isDiagnoseKind(apiKind, effectiveGroup) ? [] : (relationships?.services ?? [])),
|
|
646
577
|
[apiKind, effectiveGroup, relationships],
|
|
647
578
|
)
|
|
579
|
+
const onRefresh = rest.onRefresh
|
|
648
580
|
const refetchResourceAndRuns = useCallback(async () => {
|
|
649
581
|
await Promise.all([
|
|
650
582
|
refetchResource(),
|
|
583
|
+
onRefresh?.(),
|
|
651
584
|
...(apiKind === 'rayjobs' && effectiveGroup === 'ray.io' ? [
|
|
652
585
|
queryClient.refetchQueries({ queryKey: ['resource', 'jobs', namespace, name, 'batch'], type: 'active' }),
|
|
653
586
|
...(resource?.spec?.clusterSelector?.['ray.io/cluster'] ? [queryClient.refetchQueries({ queryKey: ['resource', 'rayclusters', namespace, resource.spec.clusterSelector['ray.io/cluster'], 'ray.io'], type: 'active' })] : []),
|
|
@@ -661,7 +594,7 @@ export function WorkloadView({
|
|
|
661
594
|
...(apiKind === 'rayclusters' ? { type: 'active' as const } : {}),
|
|
662
595
|
}),
|
|
663
596
|
])
|
|
664
|
-
}, [apiKind, effectiveGroup, name, namespace, queryClient, refetchResource, resource?.spec?.clusterSelector])
|
|
597
|
+
}, [apiKind, effectiveGroup, name, namespace, queryClient, refetchResource, resource?.spec?.clusterSelector, onRefresh])
|
|
665
598
|
const podWorkloadOwner = useMemo(
|
|
666
599
|
() => podWorkloadOwnerFromRelationships(apiKind, namespace, relationships, resource),
|
|
667
600
|
[apiKind, namespace, relationships, resource],
|
|
@@ -1249,9 +1182,7 @@ export function WorkloadView({
|
|
|
1249
1182
|
onSelectRun={handleSelectedRunChange}
|
|
1250
1183
|
/>
|
|
1251
1184
|
)}
|
|
1252
|
-
|
|
1253
|
-
renderCNPGSummary({ apiKind: ak, namespace: ns, name: n, group: effectiveGroup, resource: res, context, onNavigate })
|
|
1254
|
-
}
|
|
1185
|
+
{...resourceDetailSlots({ kind: apiKind, group: resource?.apiVersion ? resourceGroup : effectiveGroup, namespace, name }, rest.extraTabs)}
|
|
1255
1186
|
renderExpandedOverview={({ kind: k, apiKind, namespace: ns, name: n, resource: res }) =>
|
|
1256
1187
|
supportsBatchExecution(k, apiKind, effectiveGroup, res?.apiVersion) &&
|
|
1257
1188
|
res ? (
|
|
@@ -1316,7 +1247,7 @@ export function WorkloadView({
|
|
|
1316
1247
|
onDuplicate={handleDuplicate}
|
|
1317
1248
|
onDownload={desktopDownload}
|
|
1318
1249
|
actionsBarProps={actionsBarProps}
|
|
1319
|
-
rendererOverrides={
|
|
1250
|
+
rendererOverrides={resourceRendererOverrides}
|
|
1320
1251
|
renderOverviewExtra={({ kind: k, namespace: ns, name: n, group: g, context }) => {
|
|
1321
1252
|
// Network entry kinds (Service/Ingress/Route/Gateway) ARE the diagnosis
|
|
1322
1253
|
// target: DiagnoseInlineSection renders in the drawer, no hint. Workload
|
|
@@ -1334,7 +1265,6 @@ export function WorkloadView({
|
|
|
1334
1265
|
<>
|
|
1335
1266
|
{diagnoseInline}
|
|
1336
1267
|
{diagnoseHint}
|
|
1337
|
-
<FluxSourceConsumersSection kind={k} namespace={ns} name={n} />
|
|
1338
1268
|
<AuditOverviewSection
|
|
1339
1269
|
findings={auditFindings ?? []}
|
|
1340
1270
|
onViewAll={() => navigateRouter('/checks')}
|
|
@@ -1345,6 +1275,7 @@ export function WorkloadView({
|
|
|
1345
1275
|
renderOverviewLead={() => (
|
|
1346
1276
|
<ResourceIssuesSection
|
|
1347
1277
|
issues={liveIssues}
|
|
1278
|
+
compact={!expanded}
|
|
1348
1279
|
subjectResource={{ kind: apiKind, namespace, name, group: rest.group }}
|
|
1349
1280
|
onResourceClick={
|
|
1350
1281
|
rest.onNavigateToResource
|
|
@@ -1393,13 +1324,14 @@ export function WorkloadView({
|
|
|
1393
1324
|
)
|
|
1394
1325
|
}
|
|
1395
1326
|
|
|
1396
|
-
function collectServingRefs(relationships: Relationships | undefined): ResourceRef[] {
|
|
1327
|
+
export function collectServingRefs(relationships: Relationships | undefined): ResourceRef[] {
|
|
1397
1328
|
if (!relationships) return []
|
|
1398
1329
|
return dedupeResourceRefs([
|
|
1399
1330
|
...(relationships.services ?? []),
|
|
1400
1331
|
...(relationships.ingresses ?? []),
|
|
1401
1332
|
...(relationships.gateways ?? []),
|
|
1402
1333
|
...(relationships.routes ?? []),
|
|
1334
|
+
...(relationships.routedFrom ?? []),
|
|
1403
1335
|
])
|
|
1404
1336
|
}
|
|
1405
1337
|
|
|
@@ -1539,9 +1471,8 @@ function LogsTabContent({
|
|
|
1539
1471
|
)
|
|
1540
1472
|
}
|
|
1541
1473
|
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
}
|
|
1474
|
+
const integrationLogs = resourceLogs({ kind, group, namespace, name }, resource)
|
|
1475
|
+
if (integrationLogs) return integrationLogs
|
|
1545
1476
|
|
|
1546
1477
|
// Workload kinds with stable pod selectors use the aggregated workload logs viewer
|
|
1547
1478
|
if (WORKLOAD_LOG_KINDS.has(kind) && (kind !== 'Job' || isCoreBatchJob(apiKind, group))) {
|
|
@@ -2217,137 +2148,6 @@ function DiagnoseInlineSection({ kind, namespace, name, group, onOpenReachabilit
|
|
|
2217
2148
|
)
|
|
2218
2149
|
}
|
|
2219
2150
|
|
|
2220
|
-
// FluxSourceConsumersSection lists the reconcilers (Kustomization, HelmRelease)
|
|
2221
|
-
// that reference this Flux source CR — the inverse of `spec.sourceRef`. Renders
|
|
2222
|
-
// only when the focused resource is a Flux source kind; otherwise null. Sources
|
|
2223
|
-
// can have many consumers (one repo feeding multiple apps), so this answers
|
|
2224
|
-
// "if I edit this source, what gets affected on the next reconcile?".
|
|
2225
|
-
//
|
|
2226
|
-
// Filtering happens client-side off the namespaced reconciler lists — these
|
|
2227
|
-
// are typically small (tens, not thousands) and the dynamic informer cache
|
|
2228
|
-
// makes the request cheap. If a cluster ever has thousands of HelmReleases,
|
|
2229
|
-
// a dedicated /api/gitops/consumers endpoint would be the right move; today
|
|
2230
|
-
// it'd be premature.
|
|
2231
|
-
// Outer component is cheap — it does only the kind check and decides whether
|
|
2232
|
-
// to mount the data-fetching child. Without this split, useResources would
|
|
2233
|
-
// fire two API calls on EVERY workload drawer open (Pod, Deployment, Service,
|
|
2234
|
-
// …), since the hook has no `enabled` flag and can't be conditionally called
|
|
2235
|
-
// (Rules of Hooks). The hooks only need to run when the focused resource is
|
|
2236
|
-
// actually a Flux source CR.
|
|
2237
|
-
function FluxSourceConsumersSection({
|
|
2238
|
-
kind,
|
|
2239
|
-
namespace,
|
|
2240
|
-
name,
|
|
2241
|
-
}: {
|
|
2242
|
-
kind: string
|
|
2243
|
-
namespace: string
|
|
2244
|
-
name: string
|
|
2245
|
-
}) {
|
|
2246
|
-
// The inner WorkloadView de-pluralizes the URL's plural form, which gives
|
|
2247
|
-
// "Gitrepository" (single-uppercase) rather than the wire-correct
|
|
2248
|
-
// "GitRepository" — so we match lowercase. spec.sourceRef.kind on consumers
|
|
2249
|
-
// is always wire-correct, so we look that up separately.
|
|
2250
|
-
const sourceKind = FLUX_SOURCE_KIND_BY_LOWER.get(kind.toLowerCase()) ?? null
|
|
2251
|
-
if (!sourceKind) return null
|
|
2252
|
-
return <FluxSourceConsumersInner sourceKind={sourceKind} namespace={namespace} name={name} />
|
|
2253
|
-
}
|
|
2254
|
-
|
|
2255
|
-
function FluxSourceConsumersInner({
|
|
2256
|
-
sourceKind,
|
|
2257
|
-
namespace,
|
|
2258
|
-
name,
|
|
2259
|
-
}: {
|
|
2260
|
-
sourceKind: string
|
|
2261
|
-
namespace: string
|
|
2262
|
-
name: string
|
|
2263
|
-
}) {
|
|
2264
|
-
const navigate = useNavigate()
|
|
2265
|
-
const { data: kustomizations } = useResources<any>(
|
|
2266
|
-
'kustomizations',
|
|
2267
|
-
undefined,
|
|
2268
|
-
'kustomize.toolkit.fluxcd.io',
|
|
2269
|
-
)
|
|
2270
|
-
const { data: helmReleases } = useResources<any>(
|
|
2271
|
-
'helmreleases',
|
|
2272
|
-
undefined,
|
|
2273
|
-
'helm.toolkit.fluxcd.io',
|
|
2274
|
-
)
|
|
2275
|
-
|
|
2276
|
-
const consumers: Array<{
|
|
2277
|
-
kind: 'Kustomization' | 'HelmRelease'
|
|
2278
|
-
namespace: string
|
|
2279
|
-
name: string
|
|
2280
|
-
plural: string
|
|
2281
|
-
}> = []
|
|
2282
|
-
for (const k of kustomizations ?? []) {
|
|
2283
|
-
const ref = k?.spec?.sourceRef ?? {}
|
|
2284
|
-
const refNs = ref.namespace || k?.metadata?.namespace
|
|
2285
|
-
if (ref.kind === sourceKind && ref.name === name && refNs === namespace) {
|
|
2286
|
-
consumers.push({
|
|
2287
|
-
kind: 'Kustomization',
|
|
2288
|
-
namespace: k.metadata.namespace,
|
|
2289
|
-
name: k.metadata.name,
|
|
2290
|
-
plural: 'kustomizations',
|
|
2291
|
-
})
|
|
2292
|
-
}
|
|
2293
|
-
}
|
|
2294
|
-
for (const h of helmReleases ?? []) {
|
|
2295
|
-
const ref = h?.spec?.chart?.spec?.sourceRef ?? {}
|
|
2296
|
-
const refNs = ref.namespace || h?.metadata?.namespace
|
|
2297
|
-
if (ref.kind === sourceKind && ref.name === name && refNs === namespace) {
|
|
2298
|
-
consumers.push({
|
|
2299
|
-
kind: 'HelmRelease',
|
|
2300
|
-
namespace: h.metadata.namespace,
|
|
2301
|
-
name: h.metadata.name,
|
|
2302
|
-
plural: 'helmreleases',
|
|
2303
|
-
})
|
|
2304
|
-
}
|
|
2305
|
-
}
|
|
2306
|
-
|
|
2307
|
-
if (consumers.length === 0) {
|
|
2308
|
-
return (
|
|
2309
|
-
<section className="rounded-lg border border-theme-border bg-theme-surface p-4 shadow-theme-sm">
|
|
2310
|
-
<h3 className="mb-2 text-sm font-semibold text-theme-text-primary">Consumed by</h3>
|
|
2311
|
-
<p className="text-xs text-theme-text-tertiary">
|
|
2312
|
-
No Kustomization or HelmRelease references this source.
|
|
2313
|
-
</p>
|
|
2314
|
-
</section>
|
|
2315
|
-
)
|
|
2316
|
-
}
|
|
2317
|
-
|
|
2318
|
-
return (
|
|
2319
|
-
<section className="rounded-lg border border-theme-border bg-theme-surface p-4 shadow-theme-sm">
|
|
2320
|
-
<h3 className="mb-3 text-sm font-semibold text-theme-text-primary">
|
|
2321
|
-
Consumed by ({consumers.length})
|
|
2322
|
-
</h3>
|
|
2323
|
-
<div className="flex flex-wrap gap-1.5">
|
|
2324
|
-
{consumers.map((c) => (
|
|
2325
|
-
<Tooltip
|
|
2326
|
-
key={`${c.kind}/${c.namespace}/${c.name}`}
|
|
2327
|
-
content={`${c.kind} ${c.namespace}/${c.name}`}
|
|
2328
|
-
>
|
|
2329
|
-
<button
|
|
2330
|
-
onClick={() =>
|
|
2331
|
-
navigate(
|
|
2332
|
-
`/gitops/detail/${c.plural}/${encodeURIComponent(c.namespace)}/${encodeURIComponent(c.name)}`,
|
|
2333
|
-
)
|
|
2334
|
-
}
|
|
2335
|
-
className="inline-flex items-center gap-1.5 rounded border border-theme-border bg-theme-surface px-1.5 py-0.5 text-[11px] text-theme-text-secondary hover:border-skyhook-500/60 hover:text-skyhook-500 transition-colors"
|
|
2336
|
-
>
|
|
2337
|
-
<span className="text-theme-text-tertiary">
|
|
2338
|
-
{c.kind === 'HelmRelease' ? 'HR' : 'K'}
|
|
2339
|
-
</span>
|
|
2340
|
-
<span>
|
|
2341
|
-
{c.namespace}/{c.name}
|
|
2342
|
-
</span>
|
|
2343
|
-
</button>
|
|
2344
|
-
</Tooltip>
|
|
2345
|
-
))}
|
|
2346
|
-
</div>
|
|
2347
|
-
</section>
|
|
2348
|
-
)
|
|
2349
|
-
}
|
|
2350
|
-
|
|
2351
2151
|
// Drawer mode: single chart + category tabs (compact for ~500px width).
|
|
2352
2152
|
// Full-screen mode: multi-chart grid so CPU + Memory + Network can be
|
|
2353
2153
|
// compared side-by-side without tab switching.
|
|
@@ -2422,18 +2222,6 @@ function DrawerMetricsContent({
|
|
|
2422
2222
|
)
|
|
2423
2223
|
}
|
|
2424
2224
|
|
|
2425
|
-
// FLUX_SOURCE_KIND_BY_LOWER maps lowercase kind (what the inner WorkloadView
|
|
2426
|
-
// produces via its plural-to-singular fallback) to the wire-correct
|
|
2427
|
-
// PascalCase form that consumers carry in spec.sourceRef.kind. HelmChart is
|
|
2428
|
-
// intentionally absent — it's an auto-generated internal CR, not something
|
|
2429
|
-
// users create or point reconcilers at directly.
|
|
2430
|
-
const FLUX_SOURCE_KIND_BY_LOWER = new Map<string, string>([
|
|
2431
|
-
['gitrepository', 'GitRepository'],
|
|
2432
|
-
['helmrepository', 'HelmRepository'],
|
|
2433
|
-
['ocirepository', 'OCIRepository'],
|
|
2434
|
-
['bucket', 'Bucket'],
|
|
2435
|
-
])
|
|
2436
|
-
|
|
2437
2225
|
// Read-only manifest view for an object in the workload's neighborhood (the
|
|
2438
2226
|
// YAML tab's object rail). Read-only by design — editing an arbitrary related
|
|
2439
2227
|
// object belongs on that resource's own page.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { act } from 'react'
|
|
3
|
+
import { createRoot } from 'react-dom/client'
|
|
4
|
+
import { expect, it, vi } from 'vitest'
|
|
5
|
+
import { Mono } from './layout'
|
|
6
|
+
|
|
7
|
+
;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
|
|
8
|
+
|
|
9
|
+
it('uses normal word boundaries with overflow wrapping and keeps the complete value in a hover tooltip', () => {
|
|
10
|
+
vi.useFakeTimers()
|
|
11
|
+
const host = document.createElement('div')
|
|
12
|
+
document.body.append(host)
|
|
13
|
+
const root = createRoot(host)
|
|
14
|
+
const image = 'ghcr.io/cloudnative-pg/postgresql:17.4-standard-bookworm'
|
|
15
|
+
act(() => root.render(<Mono>{image}</Mono>))
|
|
16
|
+
const mono = host.querySelector('.font-mono')!
|
|
17
|
+
expect(mono.classList.contains('break-all')).toBe(false)
|
|
18
|
+
expect(mono.classList.contains('break-normal')).toBe(true)
|
|
19
|
+
expect(mono.textContent).toBe(image)
|
|
20
|
+
expect(mono.classList.contains('[overflow-wrap:anywhere]')).toBe(true)
|
|
21
|
+
const trigger = mono.parentElement!
|
|
22
|
+
act(() => trigger.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true })))
|
|
23
|
+
act(() => trigger.dispatchEvent(new MouseEvent('mouseover', { bubbles: true })))
|
|
24
|
+
act(() => vi.advanceTimersByTime(500))
|
|
25
|
+
expect(document.body.querySelector('.fixed')?.textContent).toBe(image)
|
|
26
|
+
act(() => root.unmount())
|
|
27
|
+
host.remove()
|
|
28
|
+
vi.useRealTimers()
|
|
29
|
+
})
|