@skyhook-io/k8s-ui 1.8.9 → 1.8.11

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.
Files changed (130) hide show
  1. package/package.json +5 -4
  2. package/src/assets/gitops/argocd.png +0 -0
  3. package/src/assets/gitops/flux.svg +7 -0
  4. package/src/components/applications/AppChips.tsx +10 -0
  5. package/src/components/applications/ApplicationDetail.test.tsx +569 -0
  6. package/src/components/applications/ApplicationDetail.tsx +2517 -450
  7. package/src/components/applications/ApplicationsList.tsx +4 -1
  8. package/src/components/applications/ApplicationsView.tsx +101 -18
  9. package/src/components/applications/applications-view.test.tsx +47 -0
  10. package/src/components/applications/index.ts +1 -1
  11. package/src/components/audit/AuditAlerts.tsx +14 -10
  12. package/src/components/checks/ChecksView.tsx +81 -51
  13. package/src/components/checks/severity.ts +39 -45
  14. package/src/components/cluster-switcher/ClusterSwitcher.tsx +2 -2
  15. package/src/components/compare/CompareResourcePicker.tsx +2 -2
  16. package/src/components/gitops/GitOpsGraphFilterRail.tsx +2 -1
  17. package/src/components/gitops/GitOpsTableView.tsx +14 -59
  18. package/src/components/gitops/ManagedResourcesList.tsx +8 -11
  19. package/src/components/gitops/SyncCountdown.tsx +26 -17
  20. package/src/components/gitops/SyncOptionsDialog.tsx +2 -2
  21. package/src/components/gitops/insights/GitOpsInsightViews.tsx +277 -104
  22. package/src/components/gitops/insights/insights-helpers.test.ts +86 -1
  23. package/src/components/gitops/insights/insights-helpers.ts +69 -1
  24. package/src/components/gitops/tree/GitOpsTreeGraph.tsx +5 -2
  25. package/src/components/issues/IssuesView.tsx +219 -143
  26. package/src/components/issues/ResourceIssuesSection.test.tsx +40 -0
  27. package/src/components/issues/ResourceIssuesSection.tsx +28 -128
  28. package/src/components/issues/index.ts +3 -2
  29. package/src/components/issues/issue-timing.ts +53 -0
  30. package/src/components/issues/issues.test.ts +146 -4
  31. package/src/components/issues/severity.ts +29 -32
  32. package/src/components/logs/LogCore.tsx +14 -4
  33. package/src/components/logs/WorkloadLogsViewer.tsx +31 -6
  34. package/src/components/logs/useLogStream.ts +8 -1
  35. package/src/components/namespace-switcher/NamespacePicker.tsx +86 -107
  36. package/src/components/resources/ResourcesSidebar.test.tsx +107 -0
  37. package/src/components/resources/ResourcesSidebar.tsx +70 -52
  38. package/src/components/resources/ResourcesView.selected-kind.test.ts +143 -0
  39. package/src/components/resources/ResourcesView.tsx +243 -53
  40. package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +2 -2
  41. package/src/components/resources/renderers/CronWorkflowRenderer.tsx +99 -0
  42. package/src/components/resources/renderers/JobRenderer.tsx +3 -1
  43. package/src/components/resources/renderers/MetricsUnavailableNotice.tsx +47 -0
  44. package/src/components/resources/renderers/NodeRenderer.test.tsx +103 -0
  45. package/src/components/resources/renderers/NodeRenderer.tsx +20 -12
  46. package/src/components/resources/renderers/PVCRenderer.test.tsx +23 -0
  47. package/src/components/resources/renderers/PVCRenderer.tsx +2 -2
  48. package/src/components/resources/renderers/PodRenderer.test.tsx +101 -0
  49. package/src/components/resources/renderers/PodRenderer.tsx +81 -70
  50. package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +2 -2
  51. package/src/components/resources/renderers/SbomReportRenderer.tsx +2 -2
  52. package/src/components/resources/renderers/SecretRenderer.tsx +2 -0
  53. package/src/components/resources/renderers/ServiceRenderer.tsx +58 -40
  54. package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +2 -2
  55. package/src/components/resources/renderers/WorkflowRenderer.test.tsx +43 -0
  56. package/src/components/resources/renderers/WorkflowRenderer.tsx +60 -78
  57. package/src/components/resources/renderers/index.ts +1 -0
  58. package/src/components/resources/resource-utils-capi.ts +1 -1
  59. package/src/components/resources/resource-utils.ts +31 -0
  60. package/src/components/shared/DetailShell.tsx +2 -2
  61. package/src/components/shared/ResourceActionsBar.tsx +140 -108
  62. package/src/components/shared/ResourceRendererDispatch.tsx +33 -4
  63. package/src/components/timeline/TimelineList.tsx +371 -354
  64. package/src/components/timeline/TimelineStrip.test.tsx +194 -0
  65. package/src/components/timeline/TimelineStrip.tsx +836 -0
  66. package/src/components/timeline/TimelineSwimlanes.test.tsx +1028 -0
  67. package/src/components/timeline/TimelineSwimlanes.tsx +2498 -593
  68. package/src/components/timeline/TimelineToolbar.test.tsx +320 -0
  69. package/src/components/timeline/TimelineToolbar.tsx +759 -0
  70. package/src/components/timeline/TimelineToolbarState.test.tsx +64 -0
  71. package/src/components/timeline/index.ts +23 -0
  72. package/src/components/timeline/scrubber-math.test.ts +235 -0
  73. package/src/components/timeline/scrubber-math.ts +249 -0
  74. package/src/components/timeline/shared.test.tsx +219 -0
  75. package/src/components/timeline/shared.tsx +232 -447
  76. package/src/components/timeline/timeline-filters.test.ts +196 -0
  77. package/src/components/timeline/timeline-filters.ts +180 -0
  78. package/src/components/timeline/timeline-lane-sort.test.ts +97 -0
  79. package/src/components/timeline/timeline-lane-sort.ts +77 -0
  80. package/src/components/timeline/timeline-live.test.ts +131 -0
  81. package/src/components/timeline/timeline-live.ts +77 -0
  82. package/src/components/topology/GroupNode.tsx +9 -2
  83. package/src/components/topology/K8sResourceNode.test.ts +11 -0
  84. package/src/components/topology/K8sResourceNode.tsx +387 -243
  85. package/src/components/topology/TopologyFilterSidebar.tsx +9 -0
  86. package/src/components/topology/TopologyGraph.tsx +89 -16
  87. package/src/components/topology/TopologySearch.tsx +2 -2
  88. package/src/components/topology/layout.ts +10 -2
  89. package/src/components/topology/topology.css +0 -92
  90. package/src/components/ui/Badge.tsx +5 -0
  91. package/src/components/ui/BoardSkeleton.tsx +47 -0
  92. package/src/components/ui/CardSection.tsx +117 -0
  93. package/src/components/ui/CodeViewer.tsx +2 -2
  94. package/src/components/ui/Collapse.tsx +59 -0
  95. package/src/components/ui/ConfirmDialog.tsx +7 -3
  96. package/src/components/ui/DialogPortal.tsx +31 -9
  97. package/src/components/ui/Input.tsx +24 -0
  98. package/src/components/ui/MultiSelectPicker.test.tsx +101 -0
  99. package/src/components/ui/MultiSelectPicker.tsx +167 -0
  100. package/src/components/ui/PaneLoader.tsx +10 -2
  101. package/src/components/ui/ResourceBar.tsx +68 -25
  102. package/src/components/ui/SearchBox.tsx +18 -4
  103. package/src/components/ui/SearchPillInput.tsx +2 -2
  104. package/src/components/ui/Toast.tsx +1 -1
  105. package/src/components/ui/drawer-components.tsx +39 -26
  106. package/src/components/ui/index.ts +6 -0
  107. package/src/components/ui/severity-tone.ts +63 -0
  108. package/src/components/workload/ResourceDetailDrawer.tsx +6 -2
  109. package/src/components/workload/WorkloadView.tsx +2682 -472
  110. package/src/components/workload/index.ts +1 -1
  111. package/src/theme/variables.css +15 -1
  112. package/src/types/core.ts +57 -4
  113. package/src/utils/api-resources.test.ts +54 -0
  114. package/src/utils/api-resources.ts +68 -1
  115. package/src/utils/application-topology.test.ts +198 -0
  116. package/src/utils/application-topology.ts +261 -0
  117. package/src/utils/applications.test.ts +167 -1
  118. package/src/utils/applications.ts +1157 -393
  119. package/src/utils/index.ts +2 -0
  120. package/src/utils/navigation.test.ts +32 -1
  121. package/src/utils/navigation.ts +70 -0
  122. package/src/utils/resource-hierarchy.test.ts +990 -1
  123. package/src/utils/resource-hierarchy.ts +905 -267
  124. package/src/utils/resource-icons.ts +2 -0
  125. package/src/utils/topology-neighborhood.test.ts +202 -1
  126. package/src/utils/topology-neighborhood.ts +194 -13
  127. package/src/utils/workflow-execution.test.ts +556 -0
  128. package/src/utils/workflow-execution.ts +814 -0
  129. package/src/utils/workload-colors.ts +2 -3
  130. package/tsconfig.json +2 -2
@@ -22,4 +22,6 @@ export * from './rbac-badges'
22
22
  export * from './git-provider-urls'
23
23
  export * from './applications'
24
24
  export * from './topology-neighborhood'
25
+ export * from './application-topology'
25
26
  export * from './bulk-workload-actions'
27
+ export * from './workflow-execution'
@@ -1,5 +1,5 @@
1
1
  import { describe, test, expect, afterEach } from 'vitest'
2
- import { kindToPlural, pluralToKind, refToSelectedResource, initNavigationMap, resetNavigationMap } from './navigation'
2
+ import { kindToPlural, pluralToKind, refToSelectedResource, initNavigationMap, resetNavigationMap, laneId, laneResourceKey, groupQualifiesLaneId, parseLaneId } from './navigation'
3
3
 
4
4
  afterEach(() => {
5
5
  resetNavigationMap()
@@ -190,3 +190,34 @@ describe('refToSelectedResource', () => {
190
190
  })
191
191
  })
192
192
  })
193
+
194
+ describe('lane identity helpers', () => {
195
+ test('groupQualifiesLaneId: only CRD groups qualify', () => {
196
+ expect(groupQualifiesLaneId('')).toBe(false) // core
197
+ expect(groupQualifiesLaneId(undefined)).toBe(false)
198
+ expect(groupQualifiesLaneId('apps')).toBe(false) // built-in
199
+ expect(groupQualifiesLaneId('batch')).toBe(false)
200
+ expect(groupQualifiesLaneId('networking.k8s.io')).toBe(false)
201
+ expect(groupQualifiesLaneId('postgresql.cnpg.io')).toBe(true)
202
+ expect(groupQualifiesLaneId('cluster.x-k8s.io')).toBe(true)
203
+ })
204
+
205
+ test('laneId: bare for core/built-in, qualified for CRD groups', () => {
206
+ expect(laneId('Pod', '', 'team-a', 'x')).toBe('Pod/team-a/x')
207
+ expect(laneId('Deployment', 'apps', 'ns', 'web')).toBe('Deployment/ns/web')
208
+ expect(laneId('Cluster', 'postgresql.cnpg.io', 'prod', 'main-db')).toBe('Cluster.postgresql.cnpg.io/prod/main-db')
209
+ })
210
+
211
+ test('laneResourceKey is always group-less', () => {
212
+ expect(laneResourceKey('Cluster', 'prod', 'main-db')).toBe('Cluster/prod/main-db')
213
+ expect(laneResourceKey('Pod', 'team-a', 'x')).toBe('Pod/team-a/x')
214
+ })
215
+
216
+ test('parseLaneId round-trips both bare and qualified ids', () => {
217
+ expect(parseLaneId('Pod/team-a/x')).toEqual({ kind: 'Pod', group: '', namespace: 'team-a', name: 'x' })
218
+ expect(parseLaneId('Cluster.postgresql.cnpg.io/prod/main-db')).toEqual({
219
+ kind: 'Cluster', group: 'postgresql.cnpg.io', namespace: 'prod', name: 'main-db',
220
+ })
221
+ expect(parseLaneId('bogus')).toBeNull()
222
+ })
223
+ })
@@ -25,6 +25,10 @@ const BUILTIN_PLURAL_TO_KIND: Record<string, string> = {
25
25
  nodes: 'Node',
26
26
  jobs: 'Job',
27
27
  cronjobs: 'CronJob',
28
+ workflows: 'Workflow',
29
+ cronworkflows: 'CronWorkflow',
30
+ workflowtemplates: 'WorkflowTemplate',
31
+ clusterworkflowtemplates: 'ClusterWorkflowTemplate',
28
32
  horizontalpodautoscalers: 'HorizontalPodAutoscaler',
29
33
  persistentvolumeclaims: 'PersistentVolumeClaim',
30
34
  persistentvolumes: 'PersistentVolume',
@@ -158,3 +162,69 @@ export function apiVersionToGroup(apiVersion?: string | null): string {
158
162
  const i = apiVersion.indexOf('/')
159
163
  return i === -1 ? '' : apiVersion.slice(0, i)
160
164
  }
165
+
166
+ // -----------------------------------------------------------------------------
167
+ // Timeline lane identity. A lane's id includes the API group so two CRDs that
168
+ // share a kind name across vendors (CAPI `Cluster` in cluster.x-k8s.io vs CNPG
169
+ // `Cluster` in postgresql.cnpg.io) can never merge into one row. The group is an
170
+ // INTERNAL identity component only — it never surfaces in the UI except the rare
171
+ // on-screen collision chip (see collidingLaneKeys in resource-hierarchy).
172
+ // -----------------------------------------------------------------------------
173
+
174
+ // Built-in Kubernetes API groups. Their kind names are globally reserved and
175
+ // never collide across vendors, so their lanes keep the bare `Kind/ns/name` id.
176
+ // This keeps existing pins, ?event= URLs, and the applications byResource join
177
+ // byte-stable for all core/built-in resources (Pod, Deployment, Job, …) — only
178
+ // CRD-group lanes get a group-qualified id, so ONLY CRD pins are affected.
179
+ const BUILTIN_API_GROUPS: ReadonlySet<string> = new Set([
180
+ '', // core (v1)
181
+ 'apps', 'batch', 'autoscaling', 'policy',
182
+ 'networking.k8s.io', 'storage.k8s.io', 'scheduling.k8s.io',
183
+ 'coordination.k8s.io', 'node.k8s.io', 'discovery.k8s.io',
184
+ 'rbac.authorization.k8s.io', 'admissionregistration.k8s.io',
185
+ 'authentication.k8s.io', 'authorization.k8s.io', 'certificates.k8s.io',
186
+ 'apiextensions.k8s.io', 'apiregistration.k8s.io', 'events.k8s.io',
187
+ 'flowcontrol.apiserver.k8s.io',
188
+ ])
189
+
190
+ /** Whether a resource's API group must appear in its lane id to prevent a
191
+ * cross-group merge. Built-in groups never collide, so they stay bare. */
192
+ export function groupQualifiesLaneId(group: string | undefined): boolean {
193
+ return !!group && !BUILTIN_API_GROUPS.has(group)
194
+ }
195
+
196
+ /** Canonical timeline lane id. Group-qualified only for CRD groups
197
+ * (`Cluster.postgresql.cnpg.io/prod/db`); bare for built-in/core groups
198
+ * (`Pod/team-a/x`, `Deployment/ns/web`) so those ids stay exactly as before. */
199
+ export function laneId(kind: string, group: string | undefined, namespace: string, name: string): string {
200
+ const g = groupQualifiesLaneId(group) ? `.${group}` : ''
201
+ return `${kind}${g}/${namespace}/${name}`
202
+ }
203
+
204
+ /** The group-less resource key (`Kind/ns/name`) — the join key for group-less
205
+ * server payloads (applications byResource, AppRow workloads) and group-less
206
+ * references (owner refs, K8s-event involvedObject, topology node ids). For a
207
+ * built-in-group lane this equals its id; for a CRD lane it's the id minus the
208
+ * `.group` segment. */
209
+ export function laneResourceKey(kind: string, namespace: string, name: string): string {
210
+ return `${kind}/${namespace}/${name}`
211
+ }
212
+
213
+ /** Recover {kind, group, namespace, name} from a lane id. The kind segment may
214
+ * carry a `.group` suffix (CRD lanes). Kind names never contain '.', and a
215
+ * qualifying group always does, so the first '.' in the kind segment splits
216
+ * them; ns and name never contain '/', so the first two '/' bound the rest. */
217
+ export function parseLaneId(id: string): { kind: string; group: string; namespace: string; name: string } | null {
218
+ const s1 = id.indexOf('/')
219
+ if (s1 < 0) return null
220
+ const s2 = id.indexOf('/', s1 + 1)
221
+ if (s2 < 0) return null
222
+ const kindSeg = id.slice(0, s1)
223
+ const dot = kindSeg.indexOf('.')
224
+ return {
225
+ kind: dot < 0 ? kindSeg : kindSeg.slice(0, dot),
226
+ group: dot < 0 ? '' : kindSeg.slice(dot + 1),
227
+ namespace: id.slice(s1 + 1, s2),
228
+ name: id.slice(s2 + 1),
229
+ }
230
+ }