@skyhook-io/radar-app 1.12.2 → 1.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/App.tsx +34 -15
- package/src/api/client.images.test.ts +63 -0
- package/src/api/client.ts +208 -33
- package/src/api/client.yaml.test.ts +3 -3
- package/src/api/version-check.test.ts +78 -0
- package/src/components/CloudConnectFlow.tsx +46 -26
- package/src/components/CloudFunnelButton.tsx +166 -129
- package/src/components/ConnectionErrorView.test.tsx +21 -1
- package/src/components/ConnectionErrorView.tsx +7 -8
- package/src/components/applications/ApplicationsView.tsx +10 -9
- package/src/components/audit/AuditView.tsx +6 -3
- package/src/components/audit/UpgradeReadinessView.test.ts +26 -2
- package/src/components/audit/UpgradeReadinessView.tsx +19 -9
- package/src/components/diagnose/DiagnoseSurface.tsx +14 -10
- package/src/components/gitops/GitOpsView.tsx +8 -3
- package/src/components/helm/HelmReleaseDrawer.tsx +4 -3
- package/src/components/helm/OwnedResources.tsx +10 -2
- package/src/components/home/ClusterHealthCard.test.ts +31 -0
- package/src/components/home/ClusterHealthCard.tsx +60 -1
- package/src/components/home/HomeView.tsx +36 -11
- package/src/components/home/MCPSetupDialog.tsx +5 -4
- package/src/components/home/RadarVersionLine.test.tsx +145 -0
- package/src/components/home/RadarVersionLine.tsx +137 -0
- package/src/components/resources/PodFilesystemModal.tsx +54 -2
- package/src/components/resources/ResourcesView.tsx +31 -8
- package/src/components/resources/renderers/WorkloadRenderer.tsx +13 -5
- package/src/components/settings/SettingsDialog.tsx +21 -4
- package/src/components/ui/ErrorBoundary.test.tsx +55 -0
- package/src/components/ui/ErrorBoundary.tsx +17 -2
- package/src/components/ui/UpdateNotification.test.tsx +49 -0
- package/src/components/ui/UpdateNotification.tsx +6 -2
- package/src/components/workload/WorkloadView.test.ts +60 -0
- package/src/components/workload/WorkloadView.tsx +270 -29
- package/src/contexts/CapabilitiesContext.test.tsx +29 -0
- package/src/contexts/CapabilitiesContext.tsx +7 -3
- package/src/utils/navigation.test.ts +45 -0
- package/src/utils/navigation.ts +5 -5
- package/src/utils/topology-selection.ts +3 -2
- package/src/utils/version.test.ts +37 -0
- package/src/utils/version.ts +56 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SelectedResource, Topology, TopologyNode } from '@skyhook-io/k8s-ui/types/core'
|
|
2
|
-
import { apiVersionToGroup,
|
|
2
|
+
import { apiVersionToGroup, kindToPluralWithGroup } from '@skyhook-io/k8s-ui/utils/navigation'
|
|
3
3
|
|
|
4
4
|
function topologyNodeGroup(node: TopologyNode): string | undefined {
|
|
5
5
|
const apiVersionGroup = apiVersionToGroup(node.data.apiVersion as string | undefined)
|
|
@@ -18,10 +18,11 @@ export function findSelectedTopologyNode(
|
|
|
18
18
|
selectedResource: SelectedResource,
|
|
19
19
|
): TopologyNode | undefined {
|
|
20
20
|
const namespace = selectedResource.namespace || ''
|
|
21
|
+
const selectedKind = kindToPluralWithGroup(selectedResource.kind, selectedResource.group ?? '')
|
|
21
22
|
const candidates = topology?.nodes.filter(node =>
|
|
22
23
|
((node.data.namespace as string) || '') === namespace &&
|
|
23
24
|
node.name === selectedResource.name &&
|
|
24
|
-
(
|
|
25
|
+
(kindToPluralWithGroup(node.kind, topologyNodeGroup(node) ?? '') === selectedKind || node.kind === selectedResource.kind),
|
|
25
26
|
) ?? []
|
|
26
27
|
|
|
27
28
|
if (candidates.length === 0) return undefined
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import {
|
|
3
|
+
getVersionUpdateStatus,
|
|
4
|
+
IN_CLUSTER_UPGRADE_URL,
|
|
5
|
+
parseMajorMinor,
|
|
6
|
+
versionUpdateURL,
|
|
7
|
+
} from './version'
|
|
8
|
+
|
|
9
|
+
describe('Radar version helpers', () => {
|
|
10
|
+
it('parses major and minor versions with an optional v prefix', () => {
|
|
11
|
+
expect(parseMajorMinor('v1.12.3')).toEqual({ major: 1, minor: 12 })
|
|
12
|
+
expect(parseMajorMinor('dev')).toBeNull()
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('grades available updates by distance from the latest release', () => {
|
|
16
|
+
expect(getVersionUpdateStatus('1.12.0', '1.12.1')).toEqual({ tier: 'patch' })
|
|
17
|
+
expect(getVersionUpdateStatus('1.11.4', '1.12.1')).toEqual({ tier: 'minor', minorVersionsBehind: 1 })
|
|
18
|
+
expect(getVersionUpdateStatus('1.10.4', '1.12.1')).toEqual({ tier: 'minor', minorVersionsBehind: 2 })
|
|
19
|
+
expect(getVersionUpdateStatus('1.9.4', '1.12.1')).toEqual({ tier: 'stale', minorVersionsBehind: 3 })
|
|
20
|
+
expect(getVersionUpdateStatus('0.12.4', '1.12.1')).toEqual({ tier: 'stale', majorVersionBehind: true })
|
|
21
|
+
expect(getVersionUpdateStatus('1.12.1-rc.1', '1.12.1')).toEqual({ tier: 'patch' })
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('does not flag invalid, current, or newer local builds', () => {
|
|
25
|
+
expect(getVersionUpdateStatus('dev', '1.12.1')).toEqual({ tier: 'none' })
|
|
26
|
+
expect(getVersionUpdateStatus('1.12.1', '1.12.1')).toEqual({ tier: 'none' })
|
|
27
|
+
expect(getVersionUpdateStatus('1.13.0', '1.12.1')).toEqual({ tier: 'none' })
|
|
28
|
+
expect(getVersionUpdateStatus('2.0.0', '1.12.1')).toEqual({ tier: 'none' })
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('routes in-cluster upgrades to instructions instead of release notes', () => {
|
|
32
|
+
const releaseURL = 'https://github.com/skyhook-io/radar/releases/tag/v1.2.4'
|
|
33
|
+
expect(versionUpdateURL('in-cluster', releaseURL)).toBe(IN_CLUSTER_UPGRADE_URL)
|
|
34
|
+
expect(versionUpdateURL('local', releaseURL)).toBe(releaseURL)
|
|
35
|
+
expect(versionUpdateURL('cloud', releaseURL)).toBeUndefined()
|
|
36
|
+
})
|
|
37
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { DeploymentMode } from '../types'
|
|
2
|
+
|
|
3
|
+
export interface MajorMinorVersion {
|
|
4
|
+
major: number
|
|
5
|
+
minor: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type VersionUpdateTier = 'none' | 'patch' | 'minor' | 'stale'
|
|
9
|
+
|
|
10
|
+
export interface VersionUpdateStatus {
|
|
11
|
+
tier: VersionUpdateTier
|
|
12
|
+
minorVersionsBehind?: number
|
|
13
|
+
majorVersionBehind?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const IN_CLUSTER_UPGRADE_URL = 'https://radarhq.io/docs/configuration/in-cluster'
|
|
17
|
+
|
|
18
|
+
export function versionUpdateURL(deploymentMode: DeploymentMode, releaseURL?: string): string | undefined {
|
|
19
|
+
if (deploymentMode === 'cloud') return undefined
|
|
20
|
+
return deploymentMode === 'in-cluster' ? IN_CLUSTER_UPGRADE_URL : releaseURL
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function parseMajorMinor(version: string): MajorMinorVersion | null {
|
|
24
|
+
const match = /^v?(\d+)\.(\d+)/.exec(version.trim())
|
|
25
|
+
if (!match) return null
|
|
26
|
+
return { major: Number(match[1]), minor: Number(match[2]) }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function parseVersion(version: string): [major: number, minor: number, patch: number, prerelease: boolean] | null {
|
|
30
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(version.trim())
|
|
31
|
+
if (!match) return null
|
|
32
|
+
return [Number(match[1]), Number(match[2]), Number(match[3]), !!match[4]]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function getVersionUpdateStatus(current: string, latest?: string): VersionUpdateStatus {
|
|
36
|
+
if (!latest) return { tier: 'none' }
|
|
37
|
+
|
|
38
|
+
const currentVersion = parseVersion(current)
|
|
39
|
+
const latestVersion = parseVersion(latest)
|
|
40
|
+
if (!currentVersion || !latestVersion) return { tier: 'none' }
|
|
41
|
+
|
|
42
|
+
const [currentMajor, currentMinor, currentPatch, currentPrerelease] = currentVersion
|
|
43
|
+
const [latestMajor, latestMinor, latestPatch, latestPrerelease] = latestVersion
|
|
44
|
+
|
|
45
|
+
if (latestMajor < currentMajor) return { tier: 'none' }
|
|
46
|
+
if (latestMajor > currentMajor) return { tier: 'stale', majorVersionBehind: true }
|
|
47
|
+
|
|
48
|
+
const minorVersionsBehind = latestMinor - currentMinor
|
|
49
|
+
if (minorVersionsBehind >= 3) return { tier: 'stale', minorVersionsBehind }
|
|
50
|
+
if (minorVersionsBehind > 0) return { tier: 'minor', minorVersionsBehind }
|
|
51
|
+
if (minorVersionsBehind < 0 || latestPatch < currentPatch) return { tier: 'none' }
|
|
52
|
+
if (latestPatch === currentPatch) {
|
|
53
|
+
return currentPrerelease && !latestPrerelease ? { tier: 'patch' } : { tier: 'none' }
|
|
54
|
+
}
|
|
55
|
+
return { tier: 'patch' }
|
|
56
|
+
}
|