@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,178 @@
|
|
|
1
|
+
import type { CNPGClusterHA } from './ha'
|
|
2
|
+
import { useState } from 'react'
|
|
3
|
+
import { Check, Copy } from 'lucide-react'
|
|
4
|
+
import { Tooltip } from '../ui/Tooltip'
|
|
5
|
+
import { CNPG_GROUP } from '../resources/resource-utils-cnpg'
|
|
6
|
+
import { CNPG_DEFAULT_PORT, cnpgEndpointAvailability, cnpgConnectionURI, cnpgConnectInfo, cnpgPsqlCommand, cnpgPortForwardCommand, type CNPGConnectEndpoint } from './connect'
|
|
7
|
+
import { type NavigateToRef, RefLink } from '../ui/RefLink'
|
|
8
|
+
import { FactGrid, FactRow } from '../facts'
|
|
9
|
+
import { SectionHeading } from '../ui/FoldSection'
|
|
10
|
+
import { copyText } from '../../utils/clipboard'
|
|
11
|
+
|
|
12
|
+
function CopyButton({ text, label }: { text: string; label: string }) {
|
|
13
|
+
const [copied, setCopied] = useState(false)
|
|
14
|
+
const copy = () => {
|
|
15
|
+
void copyText(text).then((ok) => {
|
|
16
|
+
if (!ok) return
|
|
17
|
+
setCopied(true)
|
|
18
|
+
setTimeout(() => setCopied(false), 2000)
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
return (
|
|
22
|
+
<Tooltip content={copied ? 'Copied' : `Copy ${label}`} position="top">
|
|
23
|
+
<button
|
|
24
|
+
type="button"
|
|
25
|
+
onClick={copy}
|
|
26
|
+
aria-label={`Copy ${label}`}
|
|
27
|
+
className="rounded p-1 text-theme-text-tertiary hover:bg-theme-hover hover:text-theme-text-primary"
|
|
28
|
+
>
|
|
29
|
+
{copied ? <Check className="h-3.5 w-3.5" /> : <Copy className="h-3.5 w-3.5" />}
|
|
30
|
+
</button>
|
|
31
|
+
</Tooltip>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function Snippet({ text, label }: { text: string; label: string }) {
|
|
36
|
+
return (
|
|
37
|
+
<div className="flex items-center gap-1 rounded-md bg-theme-elevated px-2 py-1">
|
|
38
|
+
<code className="min-w-0 flex-1 break-all font-mono text-xs text-theme-text-primary">{text}</code>
|
|
39
|
+
<CopyButton text={text} label={label} />
|
|
40
|
+
</div>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const ROLE_LABEL: Record<CNPGConnectEndpoint['role'], string> = {
|
|
45
|
+
rw: 'Read-write',
|
|
46
|
+
ro: 'Read-only',
|
|
47
|
+
r: 'Any instance',
|
|
48
|
+
pooler: 'Pooler',
|
|
49
|
+
additional: 'Additional',
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* How applications reach the cluster: Services, application database and
|
|
54
|
+
* owner, and the credentials Secret by name. Never reads the Secret.
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Selects the Connect heading inside one summary. A data attribute, not an
|
|
59
|
+
* id: a drawer summary can sit over a page summary of the same kind, so a host
|
|
60
|
+
* scrolls to it within its own summary's element.
|
|
61
|
+
*/
|
|
62
|
+
export function CNPGConnectSection({
|
|
63
|
+
cluster,
|
|
64
|
+
poolers,
|
|
65
|
+
poolersKnown,
|
|
66
|
+
onNavigate,
|
|
67
|
+
onOpenReachability,
|
|
68
|
+
showHeading = true,
|
|
69
|
+
kubeconfigContext,
|
|
70
|
+
kubeconfigSource,
|
|
71
|
+
ha,
|
|
72
|
+
haUnavailableReason,
|
|
73
|
+
}: {
|
|
74
|
+
cluster: any
|
|
75
|
+
kubeconfigContext?: string
|
|
76
|
+
kubeconfigSource?: string
|
|
77
|
+
ha?: CNPGClusterHA
|
|
78
|
+
haUnavailableReason?: string
|
|
79
|
+
poolers?: any[]
|
|
80
|
+
/** False when Poolers could not be listed, so a Pooler may exist that is not shown. */
|
|
81
|
+
poolersKnown?: boolean
|
|
82
|
+
onNavigate?: NavigateToRef
|
|
83
|
+
/** Opens a host's Service on its Reachability tab; the link shows only when given. */
|
|
84
|
+
onOpenReachability?: (service: { namespace: string; name: string }) => void
|
|
85
|
+
/** False where the host already titles it (e.g. the Connect dialog). */
|
|
86
|
+
showHeading?: boolean
|
|
87
|
+
}) {
|
|
88
|
+
const info = cnpgConnectInfo(cluster, poolers)
|
|
89
|
+
const ns: string = cluster?.metadata?.namespace ?? ''
|
|
90
|
+
const primary = info.endpoints[0]
|
|
91
|
+
const local = { ...primary, host: '127.0.0.1', port: CNPG_DEFAULT_PORT }
|
|
92
|
+
return (
|
|
93
|
+
<>
|
|
94
|
+
{showHeading && <SectionHeading hint="addresses from the Cluster spec · availability from HA evidence · hosts resolve inside Kubernetes">Connect</SectionHeading>}
|
|
95
|
+
<FactGrid>
|
|
96
|
+
<FactRow label="Services">
|
|
97
|
+
<ul className="grid grid-cols-[5rem_minmax(0,1fr)_auto] items-baseline gap-x-2 gap-y-2">
|
|
98
|
+
{info.endpoints.map((ep) => {
|
|
99
|
+
const availability = cnpgEndpointAvailability(ep, ha, haUnavailableReason)
|
|
100
|
+
return (
|
|
101
|
+
<li key={`${ep.role}/${ep.name}`} className="contents">
|
|
102
|
+
<span className="w-20 shrink-0 text-xs text-theme-text-tertiary">{ROLE_LABEL[ep.role]}</span>
|
|
103
|
+
<div className="min-w-0 text-xs [overflow-wrap:anywhere]">
|
|
104
|
+
<RefLink refTo={{ kind: ep.role === 'pooler' ? 'Pooler' : 'Service', group: ep.role === 'pooler' ? CNPG_GROUP : '', namespace: ns, name: ep.name }} onNavigate={onNavigate} mono>
|
|
105
|
+
{`${ep.host}:${ep.port}`}
|
|
106
|
+
</RefLink>
|
|
107
|
+
<div className="mt-0.5 text-xs text-theme-text-secondary">{ep.selects}</div>
|
|
108
|
+
<div className="text-xs text-theme-text-secondary">{availability.text}{availability.source ? ` · ${availability.source}` : ''}</div>
|
|
109
|
+
{ep.portFromTemplate && <div className="text-xs text-theme-text-tertiary">port from serviceTemplate</div>}
|
|
110
|
+
</div>
|
|
111
|
+
{onOpenReachability ? (
|
|
112
|
+
<Tooltip
|
|
113
|
+
content="Radar's check of this Service's path: endpoints, ready Pods and the NetworkPolicy rules in the way. It does not log in to PostgreSQL."
|
|
114
|
+
position="top"
|
|
115
|
+
>
|
|
116
|
+
<button type="button" onClick={() => onOpenReachability({ namespace: ns, name: ep.name })} className="text-xs text-accent-text hover:underline">
|
|
117
|
+
Reachability →
|
|
118
|
+
</button>
|
|
119
|
+
</Tooltip>
|
|
120
|
+
) : <span />}
|
|
121
|
+
</li>
|
|
122
|
+
)
|
|
123
|
+
})}
|
|
124
|
+
</ul>
|
|
125
|
+
{info.disabled.length > 0 && (
|
|
126
|
+
<div className="mt-1 text-[11.5px] text-theme-text-tertiary">
|
|
127
|
+
Disabled in spec.managed.services: {info.disabled.map((t) => `${cluster?.metadata?.name}-${t}`).join(', ')}
|
|
128
|
+
</div>
|
|
129
|
+
)}
|
|
130
|
+
{poolersKnown === false && <div className="mt-1 text-[11.5px] text-theme-text-tertiary">No access to Poolers: one may also front this cluster.</div>}
|
|
131
|
+
{info.replicaCluster && (
|
|
132
|
+
<div className="mt-1 text-[11.5px] text-theme-text-tertiary">A replica cluster: every Service reaches instances that only replay until it is promoted.</div>
|
|
133
|
+
)}
|
|
134
|
+
</FactRow>
|
|
135
|
+
<FactRow label="Database">
|
|
136
|
+
{info.database.value ? <span className="font-mono text-xs">{info.database.value}</span> : <span className="text-theme-text-tertiary">Unknown</span>}
|
|
137
|
+
<div className="mt-0.5 text-[11.5px] text-theme-text-tertiary">{info.database.source}</div>
|
|
138
|
+
</FactRow>
|
|
139
|
+
<FactRow label="Owner">
|
|
140
|
+
{info.owner.value ? <span className="font-mono text-xs">{info.owner.value}</span> : <span className="text-theme-text-tertiary">Unknown</span>}
|
|
141
|
+
<div className="mt-0.5 text-[11.5px] text-theme-text-tertiary">{info.owner.source}</div>
|
|
142
|
+
</FactRow>
|
|
143
|
+
<FactRow label="Credentials">
|
|
144
|
+
<span className="text-xs">
|
|
145
|
+
<RefLink refTo={{ kind: 'Secret', group: '', namespace: ns, name: info.secret.name }} onNavigate={onNavigate} mono>
|
|
146
|
+
{info.secret.name}
|
|
147
|
+
</RefLink>
|
|
148
|
+
</span>
|
|
149
|
+
<div className="mt-0.5 text-[11.5px] text-theme-text-tertiary">
|
|
150
|
+
{info.secret.source} · Radar does not read it; the password is its <span className="font-mono">password</span> key
|
|
151
|
+
</div>
|
|
152
|
+
</FactRow>
|
|
153
|
+
{info.database.value && (
|
|
154
|
+
<FactRow label="Inside Kubernetes">
|
|
155
|
+
<div className="space-y-1">
|
|
156
|
+
<Snippet text={cnpgConnectionURI(primary, info)} label="connection string" />
|
|
157
|
+
<Snippet text={cnpgPsqlCommand(primary, info)} label="psql command" />
|
|
158
|
+
</div>
|
|
159
|
+
<div className="mt-0.5 text-[11.5px] text-theme-text-tertiary">
|
|
160
|
+
Via <span className="font-mono">{primary.name}</span>. Replace <span className="font-mono">{'<password>'}</span>; psql prompts for it.
|
|
161
|
+
</div>
|
|
162
|
+
</FactRow>
|
|
163
|
+
)}
|
|
164
|
+
{info.database.value && (
|
|
165
|
+
<FactRow label="From this computer">
|
|
166
|
+
<div className="space-y-1">
|
|
167
|
+
<Snippet text={cnpgPortForwardCommand(primary, ns, CNPG_DEFAULT_PORT, kubeconfigContext)} label="port-forward command" />
|
|
168
|
+
<div className="text-xs text-theme-text-tertiary">{kubeconfigContext ? `Context as named in your kubeconfig${kubeconfigSource ? ` (${kubeconfigSource})` : ''}; kubectl must read the same kubeconfig file.` : 'uses your current kubectl context'}</div>
|
|
169
|
+
<Snippet text={cnpgConnectionURI(local, info)} label="local connection string" />
|
|
170
|
+
<Snippet text={cnpgPsqlCommand(local, info)} label="local psql command" />
|
|
171
|
+
</div>
|
|
172
|
+
<div className="mt-0.5 text-[11.5px] text-theme-text-tertiary">Keep port-forward running, then connect in another terminal. Local port 5432 must be free. Replace {'<password>'}; psql prompts for it.</div>
|
|
173
|
+
</FactRow>
|
|
174
|
+
)}
|
|
175
|
+
</FactGrid>
|
|
176
|
+
</>
|
|
177
|
+
)
|
|
178
|
+
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import type { ReactNode } from 'react'
|
|
2
2
|
import { getCNPGDeclarativeMessage, getCNPGReclaimPolicy } from '../resources/resource-utils-cnpg'
|
|
3
|
-
import type
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { cnpgManagedBy, type CNPGWorkspaceResponse } from './workspace'
|
|
4
|
+
import { type Fact } from '../facts'
|
|
5
|
+
import { cnpgLogicalPaths, type CNPGLogicalPath } from './logicalReplication'
|
|
6
|
+
import { CNPGLogicalPathView } from './CNPGLogicalPath'
|
|
7
|
+
import { cnpgDatabaseRoleFacts } from './databaseRole'
|
|
8
|
+
import { ClusterLink, NotReported, Note, ObjectProblems, SummaryShell } from './CNPGSharedSummary'
|
|
6
9
|
import {
|
|
7
10
|
appliedFact,
|
|
8
11
|
clustersIn,
|
|
9
12
|
databaseForDeclaration,
|
|
10
|
-
gitopsSourceOf,
|
|
11
13
|
missingManagedRole,
|
|
12
14
|
observedGenerationFact,
|
|
13
15
|
refOf,
|
|
@@ -16,11 +18,15 @@ import {
|
|
|
16
18
|
targetCluster,
|
|
17
19
|
workspaceList,
|
|
18
20
|
} from './relations'
|
|
21
|
+
import { type NavigateToRef, RefLink } from '../ui/RefLink'
|
|
22
|
+
import { toneTextClass } from '../ui/status-tone'
|
|
23
|
+
import { FactGrid, FactRow, FactValue, ManagedByText, managedByLabel } from '../facts'
|
|
24
|
+
import { SectionHeading } from '../ui/FoldSection'
|
|
19
25
|
|
|
20
26
|
interface SummaryProps {
|
|
21
27
|
resource: any
|
|
22
28
|
workspace: CNPGWorkspaceResponse | null
|
|
23
|
-
onNavigate?:
|
|
29
|
+
onNavigate?: NavigateToRef
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
function ReclaimRow({ resource }: { resource: any }) {
|
|
@@ -41,7 +47,7 @@ function Reconciled({ resource, extra }: { resource: any; extra?: ReactNode }) {
|
|
|
41
47
|
const applied = appliedFact(resource)
|
|
42
48
|
return (
|
|
43
49
|
<>
|
|
44
|
-
<
|
|
50
|
+
<SectionHeading>Reconciled</SectionHeading>
|
|
45
51
|
<FactGrid>
|
|
46
52
|
<FactRow label="Applied">
|
|
47
53
|
<FactValue fact={applied} />
|
|
@@ -62,14 +68,10 @@ function Reconciled({ resource, extra }: { resource: any; extra?: ReactNode }) {
|
|
|
62
68
|
)
|
|
63
69
|
}
|
|
64
70
|
|
|
65
|
-
function DeclaredIn({ resource }: { resource: any }) {
|
|
66
|
-
const
|
|
67
|
-
if (!
|
|
68
|
-
return
|
|
69
|
-
<span>
|
|
70
|
-
{src.tool === 'argocd' ? 'Argo CD application' : 'Flux'} <span className="font-mono">{src.namespace ? `${src.namespace}/${src.name}` : src.name}</span>
|
|
71
|
-
</span>
|
|
72
|
-
)
|
|
71
|
+
function DeclaredIn({ resource, workspace, onNavigate }: { resource: any; workspace: CNPGWorkspaceResponse | null; onNavigate?: NavigateToRef }) {
|
|
72
|
+
const manager = cnpgManagedBy(workspace, resource)
|
|
73
|
+
if (!manager || !managedByLabel(manager)) return <NotReported text="GitOps source not recorded" />
|
|
74
|
+
return <ManagedByText refTo={manager} onNavigate={onNavigate} />
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
function DatabaseRef({ resource, workspace, onNavigate }: SummaryProps) {
|
|
@@ -92,7 +94,7 @@ function DatabaseRef({ resource, workspace, onNavigate }: SummaryProps) {
|
|
|
92
94
|
)
|
|
93
95
|
}
|
|
94
96
|
|
|
95
|
-
function LinkList({ items, kind, onNavigate }: { items: any[]; kind: string; onNavigate?:
|
|
97
|
+
function LinkList({ items, kind, onNavigate }: { items: any[]; kind: string; onNavigate?: NavigateToRef }) {
|
|
96
98
|
return (
|
|
97
99
|
<span className="flex flex-wrap gap-x-3">
|
|
98
100
|
{items.map((o) => (
|
|
@@ -114,7 +116,7 @@ export function CNPGDatabaseSummary({ resource, workspace, onNavigate }: Summary
|
|
|
114
116
|
<SummaryShell>
|
|
115
117
|
<ObjectProblems issues={workspace?.issues} subject={refOf(resource, 'Database')} onNavigate={onNavigate} />
|
|
116
118
|
|
|
117
|
-
<
|
|
119
|
+
<SectionHeading>Declared</SectionHeading>
|
|
118
120
|
<FactGrid>
|
|
119
121
|
<FactRow label="PostgreSQL database">
|
|
120
122
|
{resource?.spec?.name ? <span className="font-mono">{resource.spec.name}</span> : <NotReported text="Not set" />}
|
|
@@ -137,10 +139,10 @@ export function CNPGDatabaseSummary({ resource, workspace, onNavigate }: Summary
|
|
|
137
139
|
}
|
|
138
140
|
/>
|
|
139
141
|
|
|
140
|
-
<
|
|
142
|
+
<SectionHeading>Source and target</SectionHeading>
|
|
141
143
|
<FactGrid>
|
|
142
144
|
<FactRow label="Declared in">
|
|
143
|
-
<DeclaredIn resource={resource} />
|
|
145
|
+
<DeclaredIn resource={resource} workspace={workspace} onNavigate={onNavigate} />
|
|
144
146
|
</FactRow>
|
|
145
147
|
<FactRow label="Cluster">
|
|
146
148
|
<ClusterLink resource={resource} workspace={workspace} onNavigate={onNavigate} />
|
|
@@ -149,7 +151,7 @@ export function CNPGDatabaseSummary({ resource, workspace, onNavigate }: Summary
|
|
|
149
151
|
{pubsUnavailable ? (
|
|
150
152
|
<NotReported text={pubsUnavailable} />
|
|
151
153
|
) : related.publications.length === 0 ? (
|
|
152
|
-
<span className="text-theme-text-secondary">
|
|
154
|
+
<span className="text-theme-text-secondary">No visible Publication declarations</span>
|
|
153
155
|
) : (
|
|
154
156
|
<LinkList items={related.publications} kind="Publication" onNavigate={onNavigate} />
|
|
155
157
|
)}
|
|
@@ -158,12 +160,13 @@ export function CNPGDatabaseSummary({ resource, workspace, onNavigate }: Summary
|
|
|
158
160
|
{subsUnavailable ? (
|
|
159
161
|
<NotReported text={subsUnavailable} />
|
|
160
162
|
) : related.subscriptions.length === 0 ? (
|
|
161
|
-
<span className="text-theme-text-secondary">
|
|
163
|
+
<span className="text-theme-text-secondary">No visible Subscription declarations</span>
|
|
162
164
|
) : (
|
|
163
165
|
<LinkList items={related.subscriptions} kind="Subscription" onNavigate={onNavigate} />
|
|
164
166
|
)}
|
|
165
167
|
</FactRow>
|
|
166
168
|
</FactGrid>
|
|
169
|
+
<Note>Objects created in SQL are not shown.</Note>
|
|
167
170
|
</SummaryShell>
|
|
168
171
|
)
|
|
169
172
|
}
|
|
@@ -191,12 +194,39 @@ function publicationTargets(resource: any): ReactNode {
|
|
|
191
194
|
)
|
|
192
195
|
}
|
|
193
196
|
|
|
194
|
-
|
|
197
|
+
function workspacePaths(workspace: CNPGWorkspaceResponse | null | undefined, subscriptions: any[]): CNPGLogicalPath[] {
|
|
198
|
+
return cnpgLogicalPaths(subscriptions, clustersIn(workspace), workspaceList(workspace, 'publications'), workspaceList(workspace, 'poolers'), (ns) =>
|
|
199
|
+
relationUnavailable(workspace, 'publications', ns, 'Publications'),
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export interface CNPGLogicalPathReading {
|
|
204
|
+
path: CNPGLogicalPath
|
|
205
|
+
/** The publisher primary's report of the slot; absent when not read. */
|
|
206
|
+
slot?: Fact
|
|
207
|
+
notice?: ReactNode
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function CNPGPublicationSummary({
|
|
211
|
+
resource,
|
|
212
|
+
workspace,
|
|
213
|
+
onNavigate,
|
|
214
|
+
subscribers,
|
|
215
|
+
}: SummaryProps & {
|
|
216
|
+
/** Subscriptions reading this publication, with their slots; derived from the workspace when omitted. */
|
|
217
|
+
subscribers?: CNPGLogicalPathReading[]
|
|
218
|
+
}) {
|
|
219
|
+
const readings: CNPGLogicalPathReading[] =
|
|
220
|
+
subscribers ??
|
|
221
|
+
workspacePaths(workspace, workspaceList(workspace, 'subscriptions'))
|
|
222
|
+
.filter((p) => p.publication.object?.namespace === resource?.metadata?.namespace && p.publication.object?.name === resource?.metadata?.name)
|
|
223
|
+
.map((path) => ({ path }))
|
|
224
|
+
const subsUnavailable = relationUnavailable(workspace, 'subscriptions', resource?.metadata?.namespace ?? '', 'Subscriptions')
|
|
195
225
|
return (
|
|
196
226
|
<SummaryShell>
|
|
197
227
|
<ObjectProblems issues={workspace?.issues} subject={refOf(resource, 'Publication')} onNavigate={onNavigate} />
|
|
198
228
|
|
|
199
|
-
<
|
|
229
|
+
<SectionHeading>Declared</SectionHeading>
|
|
200
230
|
<FactGrid>
|
|
201
231
|
<FactRow label="Publication">
|
|
202
232
|
{resource?.spec?.name ? <span className="font-mono">{resource.spec.name}</span> : <NotReported text="Not set" />}
|
|
@@ -210,23 +240,117 @@ export function CNPGPublicationSummary({ resource, workspace, onNavigate }: Summ
|
|
|
210
240
|
<FactRow label="Publishes">{publicationTargets(resource)}</FactRow>
|
|
211
241
|
<ReclaimRow resource={resource} />
|
|
212
242
|
<FactRow label="Declared in">
|
|
213
|
-
<DeclaredIn resource={resource} />
|
|
243
|
+
<DeclaredIn resource={resource} workspace={workspace} onNavigate={onNavigate} />
|
|
214
244
|
</FactRow>
|
|
215
245
|
</FactGrid>
|
|
216
246
|
|
|
217
247
|
<Reconciled resource={resource} />
|
|
248
|
+
|
|
249
|
+
<SectionHeading hint="Subscription objects Radar can see">Subscribers</SectionHeading>
|
|
250
|
+
{readings.length === 0 ? (
|
|
251
|
+
<div className="text-sm text-theme-text-tertiary">
|
|
252
|
+
{subsUnavailable ?? 'No visible Subscription object reads this publication. Subscribers outside Radar\'s view, or created in SQL, are not listed.'}
|
|
253
|
+
</div>
|
|
254
|
+
) : (
|
|
255
|
+
<div className="space-y-3">
|
|
256
|
+
{readings.map((r) => (
|
|
257
|
+
<CNPGLogicalPathView key={`${r.path.subscription.namespace}/${r.path.subscription.name}`} path={r.path} slot={r.slot} notice={r.notice} onNavigate={onNavigate} compact />
|
|
258
|
+
))}
|
|
259
|
+
</div>
|
|
260
|
+
)}
|
|
218
261
|
</SummaryShell>
|
|
219
262
|
)
|
|
220
263
|
}
|
|
221
264
|
|
|
222
|
-
export function
|
|
265
|
+
export function CNPGDatabaseRoleSummary({ resource, workspace, onNavigate }: SummaryProps) {
|
|
266
|
+
const ns = resource?.metadata?.namespace ?? ''
|
|
267
|
+
const clusterUnavailable = relationUnavailable(workspace, 'clusters', ns, 'Clusters')
|
|
268
|
+
const cluster = clusterUnavailable ? null : targetCluster(resource, clustersIn(workspace))
|
|
269
|
+
const f = cnpgDatabaseRoleFacts(resource, cluster)
|
|
270
|
+
return (
|
|
271
|
+
<SummaryShell>
|
|
272
|
+
<ObjectProblems issues={workspace?.issues} subject={refOf(resource, 'DatabaseRole')} onNavigate={onNavigate} />
|
|
273
|
+
|
|
274
|
+
<SectionHeading>Declared</SectionHeading>
|
|
275
|
+
<FactGrid>
|
|
276
|
+
<FactRow label="PostgreSQL role">{f.pgName ? <span className="font-mono">{f.pgName}</span> : <NotReported text="Not set" />}</FactRow>
|
|
277
|
+
<FactRow label="Cluster">
|
|
278
|
+
<ClusterLink resource={resource} workspace={workspace} onNavigate={onNavigate} />
|
|
279
|
+
</FactRow>
|
|
280
|
+
<FactRow label="Login">{f.login ? 'Allowed' : 'Not allowed'}{f.superuser ? ' · superuser' : ''}</FactRow>
|
|
281
|
+
<FactRow label="Password">
|
|
282
|
+
{f.passwordDisabled ? (
|
|
283
|
+
'Disabled'
|
|
284
|
+
) : f.passwordSecret ? (
|
|
285
|
+
<span>
|
|
286
|
+
From Secret <span className="font-mono">{f.passwordSecret}</span>
|
|
287
|
+
</span>
|
|
288
|
+
) : (
|
|
289
|
+
<span className="text-theme-text-secondary">No password Secret declared</span>
|
|
290
|
+
)}
|
|
291
|
+
{f.passwordValidUntil && (
|
|
292
|
+
<div className="text-xs text-theme-text-secondary">
|
|
293
|
+
Valid until {f.passwordValidUntil} (PostgreSQL VALID UNTIL; the operator does not rotate it)
|
|
294
|
+
</div>
|
|
295
|
+
)}
|
|
296
|
+
</FactRow>
|
|
297
|
+
<FactRow label="Client certificate">
|
|
298
|
+
{f.clientCertificate ? (
|
|
299
|
+
<span>
|
|
300
|
+
Operator-issued in Secret <span className="font-mono">{f.clientCertificate.secret}</span>
|
|
301
|
+
<span className="text-theme-text-secondary">
|
|
302
|
+
{' · '}
|
|
303
|
+
{f.clientCertificate.expiration ? `expires ${f.clientCertificate.expiration}` : 'expiry not reported yet'}
|
|
304
|
+
</span>
|
|
305
|
+
{f.clientCertificate.message && <div className="text-xs text-theme-text-secondary">{f.clientCertificate.message}</div>}
|
|
306
|
+
</span>
|
|
307
|
+
) : (
|
|
308
|
+
<span className="text-theme-text-secondary">Not requested</span>
|
|
309
|
+
)}
|
|
310
|
+
</FactRow>
|
|
311
|
+
<ReclaimRow resource={resource} />
|
|
312
|
+
<FactRow label="Declared in">
|
|
313
|
+
<DeclaredIn resource={resource} workspace={workspace} onNavigate={onNavigate} />
|
|
314
|
+
</FactRow>
|
|
315
|
+
</FactGrid>
|
|
316
|
+
|
|
317
|
+
<Reconciled
|
|
318
|
+
resource={resource}
|
|
319
|
+
extra={
|
|
320
|
+
<FactRow label="Cluster spec">
|
|
321
|
+
{f.overriddenByCluster === null ? (
|
|
322
|
+
<NotReported text={clusterUnavailable ?? 'Target Cluster not visible, so whether its spec.managed.roles overrides this role is unknown'} />
|
|
323
|
+
) : f.overriddenByCluster ? (
|
|
324
|
+
<span className={toneTextClass('degraded')}>
|
|
325
|
+
The Cluster declares “{f.pgName}” in spec.managed.roles, which takes precedence: this DatabaseRole is not reconciled while that entry exists
|
|
326
|
+
</span>
|
|
327
|
+
) : (
|
|
328
|
+
<span className="text-theme-text-secondary">No spec.managed.roles entry for this role</span>
|
|
329
|
+
)}
|
|
330
|
+
</FactRow>
|
|
331
|
+
}
|
|
332
|
+
/>
|
|
333
|
+
</SummaryShell>
|
|
334
|
+
)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export function CNPGSubscriptionSummary({
|
|
338
|
+
resource,
|
|
339
|
+
workspace,
|
|
340
|
+
onNavigate,
|
|
341
|
+
logicalPath,
|
|
342
|
+
}: SummaryProps & {
|
|
343
|
+
/** The path and slot reading; derived from the workspace (slot not read) when omitted. */
|
|
344
|
+
logicalPath?: CNPGLogicalPathReading
|
|
345
|
+
}) {
|
|
346
|
+
const reading: Partial<CNPGLogicalPathReading> = logicalPath ?? { path: workspacePaths(workspace, [resource])[0] }
|
|
223
347
|
const pub = resource?.spec?.publicationName
|
|
224
348
|
const ext = resource?.spec?.externalClusterName
|
|
225
349
|
return (
|
|
226
350
|
<SummaryShell>
|
|
227
351
|
<ObjectProblems issues={workspace?.issues} subject={refOf(resource, 'Subscription')} onNavigate={onNavigate} />
|
|
228
352
|
|
|
229
|
-
<
|
|
353
|
+
<SectionHeading>Declared</SectionHeading>
|
|
230
354
|
<FactGrid>
|
|
231
355
|
<FactRow label="Subscription">
|
|
232
356
|
{resource?.spec?.name ? <span className="font-mono">{resource.spec.name}</span> : <NotReported text="Not set" />}
|
|
@@ -254,11 +378,18 @@ export function CNPGSubscriptionSummary({ resource, workspace, onNavigate }: Sum
|
|
|
254
378
|
</FactRow>
|
|
255
379
|
<ReclaimRow resource={resource} />
|
|
256
380
|
<FactRow label="Declared in">
|
|
257
|
-
<DeclaredIn resource={resource} />
|
|
381
|
+
<DeclaredIn resource={resource} workspace={workspace} onNavigate={onNavigate} />
|
|
258
382
|
</FactRow>
|
|
259
383
|
</FactGrid>
|
|
260
384
|
|
|
261
385
|
<Reconciled resource={resource} />
|
|
386
|
+
|
|
387
|
+
{reading.path && (
|
|
388
|
+
<>
|
|
389
|
+
<SectionHeading>Replication path</SectionHeading>
|
|
390
|
+
<CNPGLogicalPathView path={reading.path} slot={reading.slot} notice={reading.notice} onNavigate={onNavigate} />
|
|
391
|
+
</>
|
|
392
|
+
)}
|
|
262
393
|
</SummaryShell>
|
|
263
394
|
)
|
|
264
395
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { CNPG_GROUP, getCNPGImageCatalogEntries } from '../resources/resource-utils-cnpg'
|
|
2
2
|
import type { CNPGWorkspaceResponse } from './workspace'
|
|
3
|
-
import { FactGrid, FactRow, RefLink, SummaryHeading, toneTextClass, type CNPGNavigate } from './primitives'
|
|
4
3
|
import { NotReported, Note, ObjectProblems, SummaryShell } from './CNPGSharedSummary'
|
|
5
4
|
import { clustersIn, clustersUsingCatalog, refOf, relationUnavailable } from './relations'
|
|
5
|
+
import { type NavigateToRef, RefLink } from '../ui/RefLink'
|
|
6
|
+
import { toneTextClass } from '../ui/status-tone'
|
|
7
|
+
import { FactGrid, FactRow } from '../facts'
|
|
8
|
+
import { SectionHeading } from '../ui/FoldSection'
|
|
6
9
|
|
|
7
10
|
export function CNPGImageCatalogSummary({
|
|
8
11
|
resource,
|
|
@@ -11,7 +14,7 @@ export function CNPGImageCatalogSummary({
|
|
|
11
14
|
}: {
|
|
12
15
|
resource: any
|
|
13
16
|
workspace: CNPGWorkspaceResponse | null
|
|
14
|
-
onNavigate?:
|
|
17
|
+
onNavigate?: NavigateToRef
|
|
15
18
|
}) {
|
|
16
19
|
const clusterScoped = resource?.kind === 'ClusterImageCatalog'
|
|
17
20
|
const ns = resource?.metadata?.namespace ?? ''
|
|
@@ -27,7 +30,7 @@ export function CNPGImageCatalogSummary({
|
|
|
27
30
|
<SummaryShell>
|
|
28
31
|
<ObjectProblems issues={workspace?.issues} subject={refOf(resource, resource?.kind ?? 'ImageCatalog')} onNavigate={onNavigate} />
|
|
29
32
|
|
|
30
|
-
<
|
|
33
|
+
<SectionHeading>Images</SectionHeading>
|
|
31
34
|
{entries.length === 0 ? (
|
|
32
35
|
<div className="text-sm">
|
|
33
36
|
<NotReported text="No images listed" />
|
|
@@ -42,7 +45,7 @@ export function CNPGImageCatalogSummary({
|
|
|
42
45
|
</FactGrid>
|
|
43
46
|
)}
|
|
44
47
|
|
|
45
|
-
<
|
|
48
|
+
<SectionHeading>Used by</SectionHeading>
|
|
46
49
|
{unavailable ? (
|
|
47
50
|
<div className="text-sm">
|
|
48
51
|
<NotReported text={unavailable} />
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { renderToStaticMarkup } from 'react-dom/server'
|
|
3
|
+
import { CNPGLogicalPathView } from './CNPGLogicalPath'
|
|
4
|
+
import type { CNPGLogicalPath } from './logicalReplication'
|
|
5
|
+
|
|
6
|
+
const path: CNPGLogicalPath = {
|
|
7
|
+
subscription: { namespace: 'db', name: 'sub', cluster: 'pg', applied: true },
|
|
8
|
+
externalCluster: { name: 'upstream', declared: true },
|
|
9
|
+
publisher: { kind: 'external', reason: 'the external cluster names no host' },
|
|
10
|
+
publication: { name: 'pub' },
|
|
11
|
+
slot: { name: 'sub' },
|
|
12
|
+
failover: { text: 'unknown', tone: 'unknown' },
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('CNPGLogicalPathView', () => {
|
|
16
|
+
it('says unknown parts of the path in words, never as "?"', () => {
|
|
17
|
+
const html = renderToStaticMarkup(<CNPGLogicalPathView path={path} />)
|
|
18
|
+
expect(html).toContain('external cluster upstream')
|
|
19
|
+
expect(html).toContain('database unknown')
|
|
20
|
+
expect(html).not.toMatch(/upstream<\/span>\/\?|\/\?/)
|
|
21
|
+
})
|
|
22
|
+
})
|