@skyhook-io/k8s-ui 1.17.0 → 1.18.0

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 (250) hide show
  1. package/README.md +41 -0
  2. package/package.json +6 -6
  3. package/src/components/charts/AreaChart.interaction.test.tsx +118 -0
  4. package/src/components/charts/AreaChart.test.tsx +25 -0
  5. package/src/components/charts/AreaChart.tsx +141 -12
  6. package/src/components/charts/index.ts +1 -0
  7. package/src/components/checks/ChecksView.tsx +18 -1
  8. package/src/components/cnpg/CNPGBackupSummary.tsx +57 -9
  9. package/src/components/cnpg/CNPGClusterHASection.test.tsx +90 -0
  10. package/src/components/cnpg/CNPGClusterHASection.tsx +331 -0
  11. package/src/components/cnpg/CNPGClusterSummary.test.tsx +275 -0
  12. package/src/components/cnpg/CNPGClusterSummary.tsx +310 -96
  13. package/src/components/cnpg/CNPGConnectSection.test.tsx +64 -0
  14. package/src/components/cnpg/CNPGConnectSection.tsx +178 -0
  15. package/src/components/cnpg/CNPGDeclarativeSummary.tsx +157 -26
  16. package/src/components/cnpg/CNPGImageCatalogSummary.tsx +7 -4
  17. package/src/components/cnpg/CNPGLogicalPath.test.tsx +22 -0
  18. package/src/components/cnpg/CNPGLogicalPath.tsx +150 -0
  19. package/src/components/cnpg/CNPGObjectStoreSummary.tsx +9 -6
  20. package/src/components/cnpg/CNPGObjectSummary.test.tsx +193 -2
  21. package/src/components/cnpg/CNPGPoolerScheduling.test.tsx +36 -0
  22. package/src/components/cnpg/CNPGPoolerSummary.tsx +241 -14
  23. package/src/components/cnpg/CNPGSharedSummary.tsx +15 -8
  24. package/src/components/cnpg/CNPGWALArchivingFact.test.tsx +39 -0
  25. package/src/components/cnpg/backupRuns.test.ts +17 -0
  26. package/src/components/cnpg/backupRuns.ts +19 -0
  27. package/src/components/cnpg/connect.test.ts +124 -0
  28. package/src/components/cnpg/connect.ts +155 -0
  29. package/src/components/cnpg/databaseRole.test.ts +38 -0
  30. package/src/components/cnpg/databaseRole.ts +80 -0
  31. package/src/components/cnpg/ha.test.ts +446 -0
  32. package/src/components/cnpg/ha.ts +621 -0
  33. package/src/components/cnpg/index.ts +18 -0
  34. package/src/components/cnpg/logicalReplication.test.ts +121 -0
  35. package/src/components/cnpg/logicalReplication.ts +252 -0
  36. package/src/components/cnpg/pooler.test.ts +84 -0
  37. package/src/components/cnpg/pooler.ts +225 -0
  38. package/src/components/cnpg/primitives.tsx +21 -117
  39. package/src/components/cnpg/problems.ts +12 -0
  40. package/src/components/cnpg/relations.test.ts +63 -13
  41. package/src/components/cnpg/relations.ts +61 -52
  42. package/src/components/cnpg/schedule.ts +35 -0
  43. package/src/components/cnpg/workspace-disk.test.ts +97 -0
  44. package/src/components/cnpg/workspace-fleet-metrics.test.ts +250 -0
  45. package/src/components/cnpg/workspace-problems.test.ts +175 -0
  46. package/src/components/cnpg/workspace.test.ts +380 -9
  47. package/src/components/cnpg/workspace.ts +1137 -136
  48. package/src/components/dock/DockContext.test.tsx +32 -0
  49. package/src/components/dock/DockContext.tsx +18 -4
  50. package/src/components/dock/LocalTerminalTab.test.tsx +40 -0
  51. package/src/components/dock/LocalTerminalTab.tsx +4 -3
  52. package/src/components/dock/TerminalTab.tsx +20 -8
  53. package/src/components/facts/certainty.tsx +36 -0
  54. package/src/components/facts/facts.test.tsx +24 -0
  55. package/src/components/facts/facts.tsx +62 -0
  56. package/src/components/facts/index.ts +6 -0
  57. package/src/components/facts/managed-by.test.tsx +17 -0
  58. package/src/components/facts/managed-by.tsx +36 -0
  59. package/src/components/facts/public-exports.test.tsx +35 -0
  60. package/src/components/gitops/GitOpsGraphFilterRail.tsx +7 -3
  61. package/src/components/gitops/GitOpsHealthSourceNotice.test.tsx +38 -0
  62. package/src/components/gitops/GitOpsHealthSourceNotice.tsx +13 -3
  63. package/src/components/gitops/insights/ArgoResourceDiff.test.tsx +142 -0
  64. package/src/components/gitops/insights/ArgoResourceDiff.tsx +22 -5
  65. package/src/components/gitops/insights/DriftPanel.tsx +62 -0
  66. package/src/components/gitops/insights/GitOpsInsightViews.tsx +40 -81
  67. package/src/components/gitops/insights/insights-helpers.test.ts +18 -0
  68. package/src/components/gitops/insights/insights-helpers.ts +7 -0
  69. package/src/components/gitops/tree/GitOpsTreeGraph.test.ts +91 -2
  70. package/src/components/gitops/tree/GitOpsTreeGraph.tsx +76 -76
  71. package/src/components/gitops/tree/layout.test.ts +111 -0
  72. package/src/components/gitops/tree/layout.ts +128 -0
  73. package/src/components/gitops/tree/tree-helpers.test.ts +23 -0
  74. package/src/components/gitops/tree/tree-helpers.ts +12 -2
  75. package/src/components/issues/ConditionalCleanup.test.tsx +82 -0
  76. package/src/components/issues/IssuesView.tsx +44 -6
  77. package/src/components/issues/ResourceIssuesSection.test.tsx +28 -0
  78. package/src/components/issues/ResourceIssuesSection.tsx +8 -2
  79. package/src/components/issues/diagnostic.ts +2 -0
  80. package/src/components/issues/index.ts +3 -1
  81. package/src/components/issues/issue-timing.ts +12 -1
  82. package/src/components/issues/issues.test.ts +75 -1
  83. package/src/components/issues/severity.ts +30 -2
  84. package/src/components/issues/types.ts +55 -4
  85. package/src/components/logs/LogCore.theme.test.tsx +206 -3
  86. package/src/components/logs/LogCore.tsx +180 -53
  87. package/src/components/logs/LogToolbarSelects.tsx +3 -1
  88. package/src/components/logs/LogsViewer.test.tsx +369 -0
  89. package/src/components/logs/LogsViewer.tsx +91 -13
  90. package/src/components/logs/StructuredLogLine.test.tsx +76 -0
  91. package/src/components/logs/StructuredLogLine.tsx +23 -31
  92. package/src/components/logs/WorkloadLogsViewer.test.tsx +65 -0
  93. package/src/components/logs/WorkloadLogsViewer.tsx +46 -11
  94. package/src/components/logs/useLogBuffer.reading.test.tsx +149 -0
  95. package/src/components/logs/useLogBuffer.test.ts +8 -0
  96. package/src/components/logs/useLogBuffer.ts +48 -18
  97. package/src/components/logs/useLogSearch.ts +3 -1
  98. package/src/components/logs/useLogStream.ts +17 -1
  99. package/src/components/problems/index.ts +1 -0
  100. package/src/components/problems/problems.test.tsx +63 -0
  101. package/src/components/problems/problems.tsx +165 -0
  102. package/src/components/resources/ActiveFilterBar.test.tsx +78 -0
  103. package/src/components/resources/ActiveFilterBar.tsx +86 -0
  104. package/src/components/resources/ColumnPickerList.test.tsx +46 -0
  105. package/src/components/resources/ColumnPickerList.tsx +174 -0
  106. package/src/components/resources/ResourcesSidebar.keyboard.test.tsx +42 -0
  107. package/src/components/resources/ResourcesSidebar.test.tsx +36 -2
  108. package/src/components/resources/ResourcesSidebar.tsx +92 -41
  109. package/src/components/resources/ResourcesView.kind-filter-memory.test.ts +52 -0
  110. package/src/components/resources/ResourcesView.kind-view.test.tsx +296 -0
  111. package/src/components/resources/ResourcesView.per-container.test.ts +56 -1
  112. package/src/components/resources/ResourcesView.tsx +392 -181
  113. package/src/components/resources/column-order.test.ts +104 -0
  114. package/src/components/resources/column-order.ts +64 -0
  115. package/src/components/resources/curated-column-ownership.test.ts +3 -3
  116. package/src/components/resources/renderers/ArgoApplicationRenderer.test.tsx +15 -0
  117. package/src/components/resources/renderers/ArgoApplicationRenderer.tsx +4 -1
  118. package/src/components/resources/renderers/AutoscalingReferences.test.tsx +286 -0
  119. package/src/components/resources/renderers/CAPIClusterRenderer.tsx +3 -2
  120. package/src/components/resources/renderers/CAPIExactReferenceNavigation.test.tsx +27 -0
  121. package/src/components/resources/renderers/CNPGBackupRenderer.test.tsx +23 -0
  122. package/src/components/resources/renderers/CNPGBackupRenderer.tsx +8 -19
  123. package/src/components/resources/renderers/CNPGClusterRenderer.tsx +5 -7
  124. package/src/components/resources/renderers/CNPGDeclarativeRenderer.tsx +25 -0
  125. package/src/components/resources/renderers/CNPGScheduledBackupRenderer.test.tsx +32 -0
  126. package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +7 -15
  127. package/src/components/resources/renderers/CompositeRenderer.navigation.test.tsx +35 -0
  128. package/src/components/resources/renderers/CompositeRenderer.tsx +3 -3
  129. package/src/components/resources/renderers/CompositionRenderer.tsx +3 -3
  130. package/src/components/resources/renderers/ContourExactReferenceNavigation.test.tsx +34 -0
  131. package/src/components/resources/renderers/ContourHTTPProxyRenderer.tsx +11 -10
  132. package/src/components/resources/renderers/CronJobRenderer.test.tsx +31 -0
  133. package/src/components/resources/renderers/CronJobRenderer.tsx +28 -20
  134. package/src/components/resources/renderers/EndpointSliceRenderer.test.tsx +39 -1
  135. package/src/components/resources/renderers/EndpointSliceRenderer.tsx +14 -13
  136. package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +22 -9
  137. package/src/components/resources/renderers/HPARenderer.tsx +56 -16
  138. package/src/components/resources/renderers/IngressRenderer.defaultBackend.test.tsx +33 -0
  139. package/src/components/resources/renderers/IngressRenderer.tsx +30 -3
  140. package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +9 -9
  141. package/src/components/resources/renderers/IstioExactReferenceNavigation.test.tsx +34 -0
  142. package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +5 -8
  143. package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +13 -11
  144. package/src/components/resources/renderers/KnativeEventingRenderer.tsx +24 -31
  145. package/src/components/resources/renderers/KnativeExactReferenceNavigation.test.tsx +47 -0
  146. package/src/components/resources/renderers/KnativeFlowRenderer.tsx +6 -7
  147. package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +7 -9
  148. package/src/components/resources/renderers/KnativeReferenceLink.tsx +14 -0
  149. package/src/components/resources/renderers/KnativeReferenceLinks.test.tsx +60 -0
  150. package/src/components/resources/renderers/KnativeSourceRenderer.tsx +9 -11
  151. package/src/components/resources/renderers/ManagedResourceRenderer.tsx +2 -2
  152. package/src/components/resources/renderers/MetricsUnavailableNotice.tsx +3 -2
  153. package/src/components/resources/renderers/PodRenderer.sidecar-terminal.test.tsx +200 -0
  154. package/src/components/resources/renderers/PodRenderer.test.tsx +32 -0
  155. package/src/components/resources/renderers/PodRenderer.tsx +81 -40
  156. package/src/components/resources/renderers/SimpleRouteRenderer.tsx +1 -1
  157. package/src/components/resources/renderers/VPARenderer.tsx +17 -11
  158. package/src/components/resources/resource-utils-capi.ts +1 -1
  159. package/src/components/resources/resource-utils-cnpg.test.ts +35 -10
  160. package/src/components/resources/resource-utils-cnpg.ts +51 -20
  161. package/src/components/resources/resource-utils-contour.test.ts +44 -0
  162. package/src/components/resources/resource-utils-contour.ts +16 -0
  163. package/src/components/resources/resource-utils-istio.ts +12 -8
  164. package/src/components/resources/resource-utils-knative.ts +18 -0
  165. package/src/components/resources/resource-utils.ts +96 -7
  166. package/src/components/resources/rules-column-width.test.ts +1 -1
  167. package/src/components/resources/summarize-scheduler-message.test.ts +31 -0
  168. package/src/components/shared/ActionConfirmDialog.test.tsx +154 -0
  169. package/src/components/shared/ActionConfirmDialog.tsx +246 -0
  170. package/src/components/shared/CreateResourceDialog.test.tsx +330 -0
  171. package/src/components/shared/CreateResourceDialog.tsx +126 -80
  172. package/src/components/shared/DetailShell.test.tsx +80 -0
  173. package/src/components/shared/DetailShell.tsx +85 -10
  174. package/src/components/shared/DrainPlanDialog.test.tsx +7 -0
  175. package/src/components/shared/DrainPlanDialog.tsx +6 -2
  176. package/src/components/shared/EditableYamlView.test.tsx +7 -0
  177. package/src/components/shared/EditableYamlView.tsx +1 -1
  178. package/src/components/shared/ResourceActionsBar.tsx +14 -7
  179. package/src/components/shared/ResourceRendererDispatch.tsx +15 -10
  180. package/src/components/shared/index.ts +2 -0
  181. package/src/components/timeline/DiffViewer.test.tsx +69 -0
  182. package/src/components/timeline/DiffViewer.tsx +113 -4
  183. package/src/components/timeline/TimelineSwimlanes.tsx +1 -1
  184. package/src/components/timeline/shared.test.tsx +48 -0
  185. package/src/components/timeline/shared.tsx +14 -19
  186. package/src/components/timeline/timeline-filters.ts +1 -0
  187. package/src/components/topology/K8sResourceNode.test.ts +18 -1
  188. package/src/components/topology/K8sResourceNode.tsx +44 -2
  189. package/src/components/topology/TopologyFilterSidebar.tsx +1 -0
  190. package/src/components/topology/TopologyGraph.tsx +3 -71
  191. package/src/components/topology/TopologySearch.tsx +1 -0
  192. package/src/components/topology/internet-groups.test.ts +35 -0
  193. package/src/components/topology/internet-groups.ts +55 -0
  194. package/src/components/topology/layout.ts +1 -1
  195. package/src/components/ui/Badge.tsx +1 -0
  196. package/src/components/ui/FoldSection.tsx +68 -0
  197. package/src/components/ui/ForceDeleteConfirmDialog.test.tsx +62 -0
  198. package/src/components/ui/ForceDeleteConfirmDialog.tsx +24 -12
  199. package/src/components/ui/RefLink.tsx +20 -0
  200. package/src/components/ui/RowActionMenu.tsx +8 -3
  201. package/src/components/ui/Toast.tsx +15 -4
  202. package/src/components/ui/crd-definition-navigation.test.tsx +160 -0
  203. package/src/components/ui/drawer-components.test.tsx +110 -1
  204. package/src/components/ui/drawer-components.tsx +62 -9
  205. package/src/components/ui/index.ts +4 -2
  206. package/src/components/ui/monacoEditorFeatures.ts +77 -0
  207. package/src/components/ui/monacoRuntime.ts +14 -19
  208. package/src/components/ui/status-tone.test.ts +10 -1
  209. package/src/components/ui/status-tone.tsx +29 -0
  210. package/src/components/workload/WorkloadView.deleted.test.tsx +43 -0
  211. package/src/components/workload/WorkloadView.relationships.test.tsx +37 -0
  212. package/src/components/workload/WorkloadView.spec.test.tsx +149 -0
  213. package/src/components/workload/WorkloadView.tsx +193 -71
  214. package/src/index.ts +14 -1
  215. package/src/monaco-deep.d.ts +19 -12
  216. package/src/theme/components.css +13 -0
  217. package/src/types/capacity.ts +11 -2
  218. package/src/types/core.ts +53 -2
  219. package/src/types/gitops-flux-status.test.ts +32 -1
  220. package/src/types/gitops-insights.ts +20 -2
  221. package/src/types/gitops-tree.ts +12 -0
  222. package/src/types/gitops.ts +26 -6
  223. package/src/utils/api-resources.ts +7 -0
  224. package/src/utils/application-history.ts +1 -0
  225. package/src/utils/cnpg-backup.test.ts +26 -0
  226. package/src/utils/cnpg-backup.ts +70 -0
  227. package/src/utils/format.test.ts +9 -0
  228. package/src/utils/format.ts +4 -0
  229. package/src/utils/gitops-owner.ts +3 -2
  230. package/src/utils/grant.test.ts +19 -0
  231. package/src/utils/grant.ts +35 -0
  232. package/src/utils/index.ts +4 -0
  233. package/src/utils/k8s-errors.ts +7 -7
  234. package/src/utils/log-format.test.ts +41 -0
  235. package/src/utils/log-format.ts +71 -15
  236. package/src/utils/log-level.ts +12 -8
  237. package/src/utils/navigation.test.ts +57 -0
  238. package/src/utils/navigation.ts +86 -8
  239. package/src/utils/object-reference-navigation.test.ts +43 -0
  240. package/src/utils/resource-hierarchy.test.ts +37 -0
  241. package/src/utils/resource-hierarchy.ts +15 -7
  242. package/src/utils/resource-icons.ts +2 -0
  243. package/src/utils/skeleton-yaml.test.ts +21 -0
  244. package/src/utils/skeleton-yaml.ts +16 -0
  245. package/src/utils/url-path.test.ts +35 -0
  246. package/src/utils/url-path.ts +21 -0
  247. package/src/utils/validators.test.ts +4 -13
  248. package/src/utils/validators.ts +5 -19
  249. package/src/utils/view-transition.test.ts +35 -1
  250. package/src/utils/view-transition.ts +16 -1
@@ -90,6 +90,8 @@ export interface WorkloadExtraTab {
90
90
  icon?: ReactNode
91
91
  after?: WorkloadTabType
92
92
  replaces?: WorkloadTabType
93
+ /** Trailing adornment after the label, e.g. a status mark. */
94
+ badge?: ReactNode
93
95
  render: () => ReactNode
94
96
  }
95
97
 
@@ -145,6 +147,23 @@ interface WorkloadViewProps {
145
147
  * the Escape shortcut.
146
148
  */
147
149
  breadcrumb?: ReactNode
150
+ /** Where the object lives, shown on the title line before its name (e.g. "Workspace / View /"). */
151
+ titlePrefix?: ReactNode
152
+ /**
153
+ * Kind, status and namespace on the title line, wrapping below the name
154
+ * only when there is no room; other chips (image, owners) keep a second
155
+ * row. The header actions then wrap below the title as a group rather
156
+ * than squeezing it.
157
+ */
158
+ inlineBadges?: boolean
159
+ /** A note right after the namespace, e.g. that it is outside the namespace filter. */
160
+ namespaceNote?: ReactNode
161
+ /** Replaces the derived status badge on the title line, e.g. with the controller's own reported phase. */
162
+ renderStatusBadge?: (resource: any) => ReactNode
163
+ /** A short status right after the controller status on the title line, e.g. a derived health verdict. */
164
+ statusNote?: ReactNode
165
+ /** Leave out the kind badge, for a host whose title prefix already names the kind. */
166
+ hideKindBadge?: boolean
148
167
  /** Suppress the standalone back arrow — for embeddings where "back" has no
149
168
  * meaningful target (a single-workload app has no app graph to return to). */
150
169
  hideBackButton?: boolean
@@ -319,6 +338,14 @@ interface WorkloadViewProps {
319
338
  }) => ReactNode
320
339
  /** Extra tabs for the expanded view (e.g. a domain's own sections). */
321
340
  extraTabs?: WorkloadExtraTab[]
341
+ /** Expanded view: a line under the title, above the tabs, shown on every tab. */
342
+ subheader?: ReactNode
343
+ /** Expanded view: tab ids in display order; tabs not listed follow in their usual order. */
344
+ tabOrder?: string[]
345
+ /** Expanded view: relabel, lead, or replace the whole "Spec & status" body. */
346
+ specTab?: { label?: string; icon?: ReactNode; lead?: ReactNode; render?: () => ReactNode }
347
+ /** Domain actions rendered in the header (drawer and expanded). */
348
+ renderHeaderActions?: (props: { resource: any; context: 'drawer' | 'expanded'; onNavigate?: NavigateToResource }) => ReactNode
322
349
  /** Render a full replacement for the expanded Overview tab. */
323
350
  renderExpandedOverview?: (props: {
324
351
  kind: string
@@ -326,6 +353,8 @@ interface WorkloadViewProps {
326
353
  namespace: string
327
354
  name: string
328
355
  resource: any
356
+ /** Place resource notices within the replacement layout's content area. */
357
+ leadContent?: ReactNode
329
358
  }) => ReactNode
330
359
  /** Render the metrics tab content */
331
360
  renderMetricsTab?: (props: { kind: string; namespace: string; name: string }) => ReactNode
@@ -371,6 +400,8 @@ interface WorkloadViewProps {
371
400
  * live issues for this resource). Avoids showing the same failure twice.
372
401
  * Also gates the `renderOverviewLead` wrapper (see above). */
373
402
  hasOperationalIssues?: boolean
403
+ /** Also show the lead for neutral context without suppressing renderer problems. */
404
+ hasOverviewLead?: boolean
374
405
  /** True while the live-issues fetch is still pending. Renderers suppress their
375
406
  * banners during this window too — a banner whose failure the pipeline covers
376
407
  * would otherwise flash on first paint before the issues arrive and hide it. */
@@ -409,6 +440,12 @@ export function WorkloadView({
409
440
  initialTab,
410
441
  group,
411
442
  breadcrumb,
443
+ titlePrefix,
444
+ inlineBadges = false,
445
+ namespaceNote,
446
+ renderStatusBadge,
447
+ statusNote,
448
+ hideKindBadge = false,
412
449
  hideBackButton,
413
450
  scopeControls,
414
451
  compactHeader,
@@ -469,6 +506,10 @@ export function WorkloadView({
469
506
  renderExpandedOverview,
470
507
  renderSummary,
471
508
  extraTabs,
509
+ tabOrder,
510
+ specTab,
511
+ subheader,
512
+ renderHeaderActions,
472
513
  renderRelatedYaml,
473
514
  renderMetricsTab,
474
515
  renderCostTab,
@@ -481,6 +522,7 @@ export function WorkloadView({
481
522
  renderOverviewIntro,
482
523
  renderOverviewLead,
483
524
  hasOperationalIssues,
525
+ hasOverviewLead,
484
526
  operationalIssuesPending,
485
527
  // Actions bar
486
528
  actionsBarProps,
@@ -794,6 +836,9 @@ export function WorkloadView({
794
836
  const renderOverviewLeadForState = resourceGone ? undefined : renderOverviewLead
795
837
  const renderOverviewExtraForState = resourceGone ? undefined : renderOverviewExtra
796
838
  const renderDiagnoseTabForState = resourceGone ? undefined : renderDiagnoseTab
839
+ // A host's summary, tabs and subheader can hold actions on the live object.
840
+ const renderSummaryForState = resourceGone ? undefined : renderSummary
841
+ const extraTabsForState = resourceGone ? undefined : extraTabs
797
842
  // A remount closes any dialog the bar had open: once its actions are gone,
798
843
  // a confirm button left on screen would do nothing.
799
844
  const actionsBarKey = resourceGone ? 'gone' : 'live'
@@ -830,6 +875,7 @@ export function WorkloadView({
830
875
  const renderDiagnose = actionsBarProps?.renderDiagnose as
831
876
  | ((ctx: { kind: string; group?: string; namespace: string; name: string; health?: DiagnoseHealthHint }) => ReactNode)
832
877
  | undefined
878
+ const headerActions = resource && !resourceGone && renderHeaderActions?.({ resource, context: expanded ? 'expanded' : 'drawer', onNavigate: onNavigateToResource })
833
879
  const diagnoseAction = resourceGone ? null : renderDiagnose?.({
834
880
  kind: resource?.kind ?? knownKindForPluralWithGroup(apiKind, group ?? '') ?? apiKind,
835
881
  group,
@@ -849,11 +895,11 @@ export function WorkloadView({
849
895
  const logsFallbackReady = !renderLogsTab || (!logsTabVisible && !podEvidenceLoading)
850
896
  const requestedTab: TabType = activeTab
851
897
  const summaryContext = { kind, apiKind, namespace, name, group, resource, onNavigate: onNavigateToResource }
852
- const expandedSummary = expanded && resource ? renderSummary?.({ ...summaryContext, context: 'expanded' }) ?? null : null
853
- const drawerSummary = !expanded && resource ? renderSummary?.({ ...summaryContext, context: 'drawer' }) ?? null : null
898
+ const expandedSummary = expanded && resource ? renderSummaryForState?.({ ...summaryContext, context: 'expanded' }) ?? null : null
899
+ const drawerSummary = !expanded && resource ? renderSummaryForState?.({ ...summaryContext, context: 'drawer' }) ?? null : null
854
900
  const tabs: DetailShellTab<TabType>[] = [
855
901
  { id: 'overview', label: 'Overview', icon: <Layers className="w-4 h-4" /> },
856
- { id: 'spec', label: 'Spec & status', icon: <FileText className="w-4 h-4" />, hidden: !expandedSummary },
902
+ { id: 'spec', label: specTab?.label ?? 'Spec & status', icon: specTab?.icon ?? <FileText className="w-4 h-4" />, hidden: !expandedSummary },
857
903
  { id: 'topology', label: 'Topology', icon: <Network className="w-4 h-4" />, hidden: topologyTabHidden },
858
904
  {
859
905
  id: 'timeline',
@@ -872,10 +918,10 @@ export function WorkloadView({
872
918
  { id: 'cost', label: 'Cost', icon: <Coins className="w-4 h-4" />, hidden: !costTabVisible },
873
919
  { id: 'yaml', label: 'YAML', icon: <FileText className="w-4 h-4" /> },
874
920
  ]
875
- const allTabs = mergeExtraTabs(tabs, expanded ? extraTabs : undefined)
921
+ const allTabs = orderTabs(mergeExtraTabs(tabs, expanded ? extraTabsForState : undefined), expanded ? tabOrder : undefined)
876
922
  const requestedTabAvailable = allTabs.some((tab) => tab.id === requestedTab && !tab.hidden)
877
923
  const effectiveTab: TabType = requestedTabAvailable ? requestedTab : 'overview'
878
- const activeExtraTab = expanded ? extraTabs?.find((x) => x.id === effectiveTab) : undefined
924
+ const activeExtraTab = expanded ? extraTabsForState?.find((x) => x.id === effectiveTab) : undefined
879
925
  const shouldCommitFallback =
880
926
  requestedTab !== 'overview' &&
881
927
  !requestedTabAvailable &&
@@ -889,7 +935,12 @@ export function WorkloadView({
889
935
  useEffect(() => {
890
936
  if (shouldCommitFallback && activeTab !== 'overview') onTabChange?.('overview', { replace: true })
891
937
  }, [activeTab, onTabChange, shouldCommitFallback])
892
- const expandedOverview = expanded ? renderExpandedOverview?.({ kind, apiKind, namespace, name, resource }) : null
938
+ const expandedOverview = expanded ? renderExpandedOverview?.({
939
+ kind, apiKind, namespace, name, resource,
940
+ leadContent: (hasOverviewLead ?? hasOperationalIssues) && renderOverviewLeadForState
941
+ ? renderOverviewLeadForState({ kind, namespace, name })
942
+ : undefined,
943
+ }) : null
893
944
  const overviewIntro = renderOverviewIntro?.({ kind, namespace, name })
894
945
 
895
946
  // ── Collapsed (drawer) mode ──────────────────────────────────────────────
@@ -904,13 +955,13 @@ export function WorkloadView({
904
955
  <span className={clsx('badge', getKindColorOutline(apiKind))}>
905
956
  {displayKindName(apiKind, resource?.kind)}
906
957
  </span>
907
- {status && (
958
+ {renderStatusBadge && resource && !resourceGone ? renderStatusBadge(resource) : status && (
908
959
  <span className={clsx('badge', status.color)}>
909
960
  {status.text}
910
961
  </span>
911
962
  )}
912
963
  </div>
913
- <div className="flex items-center gap-1.5">
964
+ <div className="flex shrink-0 flex-nowrap items-center justify-end gap-1.5">
914
965
  {diagnoseAction}
915
966
  {onExpand && (
916
967
  <Tooltip content="Open full view" delay={150} position="bottom">
@@ -982,7 +1033,7 @@ export function WorkloadView({
982
1033
  </div>
983
1034
 
984
1035
  {/* Actions bar */}
985
- <ResourceActionsBar key={actionsBarKey} resource={selectedResource} data={resource} onClose={onClose} showYaml={showYaml} onToggleYaml={() => switchView(!showYaml)} {...actionsBarPropsForState} />
1036
+ <ResourceActionsBar key={actionsBarKey} resource={selectedResource} data={resource} onClose={onClose} showYaml={showYaml} onToggleYaml={() => switchView(!showYaml)} {...actionsBarPropsForState} leadingActions={headerActions} />
986
1037
  </div>
987
1038
 
988
1039
  {/* Success animation overlay */}
@@ -1049,11 +1100,12 @@ export function WorkloadView({
1049
1100
  drawerSummary
1050
1101
  ) : (
1051
1102
  <>
1052
- {renderOverviewLeadForState && hasOperationalIssues && (
1103
+ {renderOverviewLeadForState && (hasOverviewLead ?? hasOperationalIssues) && (
1053
1104
  <div className="px-4 pt-4">
1054
1105
  {renderOverviewLeadForState({ kind, namespace, name })}
1055
1106
  </div>
1056
1107
  )}
1108
+ {overviewIntro && <div className="px-4 pt-4">{overviewIntro}</div>}
1057
1109
  <ResourceRendererDispatch
1058
1110
  resource={selectedResource}
1059
1111
  data={resource}
@@ -1091,6 +1143,8 @@ export function WorkloadView({
1091
1143
  <OperationalIssuesShownContext.Provider value={!!hasOperationalIssues || !!operationalIssuesPending}>
1092
1144
  <DetailShell
1093
1145
  breadcrumb={breadcrumb}
1146
+ wrapHeader={inlineBadges}
1147
+ subheader={resourceGone ? undefined : subheader}
1094
1148
  nav={
1095
1149
  breadcrumb || hideBackButton ? undefined : (
1096
1150
  <Tooltip content="Go back (Esc)" delay={150} position="bottom">
@@ -1104,68 +1158,111 @@ export function WorkloadView({
1104
1158
  </Tooltip>
1105
1159
  )
1106
1160
  }
1107
- identity={
1108
- <>
1109
- {showOwnershipHeading && ownershipContext ? (
1110
- <OwnershipHeading
1111
- podName={name}
1112
- context={ownershipContext}
1113
- copied={copied === 'name'}
1114
- onCopy={() => copyToClipboard(name, 'name')}
1115
- onNavigateToResource={onNavigateToResource}
1116
- onOpenApplication={onOpenApplication}
1117
- />
1118
- ) : (
1119
- <div className="flex items-center gap-3 mb-1">
1120
- <h1 className="text-lg font-semibold text-theme-text-primary truncate">{name}</h1>
1121
- <Tooltip content="Copy name" delay={150}>
1122
- <button
1123
- onClick={() => copyToClipboard(name, 'name')}
1124
- className="p-1 text-theme-text-secondary hover:text-theme-text-primary hover:bg-theme-elevated rounded shrink-0"
1125
- aria-label="Copy name"
1126
- >
1127
- {copied === 'name' ? <Check className="w-3.5 h-3.5 text-green-400" /> : <Copy className="w-3.5 h-3.5" />}
1128
- </button>
1129
- </Tooltip>
1130
- </div>
1131
- )}
1132
- <div className="flex items-center gap-3 text-sm text-theme-text-secondary">
1133
- <span className={clsx('badge', getKindColorOutline(apiKind))}>
1134
- {displayKindName(apiKind, resource?.kind)}
1135
- </span>
1136
- {status && (
1137
- <span className={clsx('badge', status.color)}>
1161
+ identity={(() => {
1162
+ const nameAndCopy = (
1163
+ <>
1164
+ <h1 className="text-lg font-semibold text-theme-text-primary truncate">{name}</h1>
1165
+ <Tooltip content="Copy name" delay={150}>
1166
+ <button
1167
+ onClick={() => copyToClipboard(name, 'name')}
1168
+ className="p-1 text-theme-text-secondary hover:text-theme-text-primary hover:bg-theme-elevated rounded shrink-0"
1169
+ aria-label="Copy name"
1170
+ >
1171
+ {copied === 'name' ? <Check className="w-3.5 h-3.5 text-green-400" /> : <Copy className="w-3.5 h-3.5" />}
1172
+ </button>
1173
+ </Tooltip>
1174
+ </>
1175
+ )
1176
+ const kindAndStatus = (
1177
+ <>
1178
+ {!hideKindBadge && (
1179
+ <span className={clsx('badge whitespace-nowrap', getKindColorOutline(apiKind))}>
1180
+ {displayKindName(apiKind, resource?.kind)}
1181
+ </span>
1182
+ )}
1183
+ {renderStatusBadge && resource && !resourceGone ? renderStatusBadge(resource) : status && (
1184
+ <span className={clsx('badge whitespace-nowrap', status.color)}>
1138
1185
  {status.text}
1139
1186
  </span>
1140
1187
  )}
1188
+ {!resourceGone && statusNote}
1189
+ </>
1190
+ )
1191
+ const coreBadges = (
1192
+ <>
1193
+ {/* On the title line the kind and status wrap together, never apart. */}
1194
+ {inlineBadges ? <span className="inline-flex items-center gap-x-3">{kindAndStatus}</span> : kindAndStatus}
1141
1195
  {namespace && namespace !== '_' && (
1142
- <span>Namespace: <span className="text-theme-text-primary">{namespace}</span></span>
1143
- )}
1144
- {headerImage && (
1145
- <Tooltip content={headerImage} delay={300} wrapperClassName="min-w-0 max-w-md">
1146
- <span className="truncate font-mono text-xs">
1147
- {midTruncate(headerImage, 72)}
1148
- </span>
1149
- </Tooltip>
1150
- )}
1151
- {gitopsOwner && (
1152
- <ManagedByChip owner={gitopsOwner} status={gitOpsOwnerStatus} verified={gitOpsOwnerVerified} pending={gitOpsOwnerPending} source={gitOpsOwnerSource} onOpen={onOpenGitOpsResource} variant="block" />
1153
- )}
1154
- {helmOwner && (
1155
- <HelmManagedByChip owner={helmOwner} source={helmOwnerSource} onOpen={onOpenHelmRelease} variant="block" />
1196
+ <span className="whitespace-nowrap">Namespace: <span className="text-theme-text-primary">{namespace}</span></span>
1156
1197
  )}
1157
- {gitOpsResourcePath && onNavigateGitOpsPath && (
1158
- <OpenInGitOpsChip onClick={() => onNavigateGitOpsPath(gitOpsResourcePath)} />
1159
- )}
1160
- {onOpenLiveTraffic && <LiveTrafficChip onClick={onOpenLiveTraffic} />}
1161
- {relationships?.owner && !showOwnershipHeading && (
1162
- <span>Owner: <button onClick={() => onNavigateToResource?.(refToSelectedResource(relationships.owner!))} className="text-blue-500 hover:underline">{relationships.owner.name}</button></span>
1198
+ {namespace && namespace !== '_' && namespaceNote}
1199
+ </>
1200
+ )
1201
+ const extraChips = [
1202
+ headerImage && (
1203
+ <Tooltip key="image" content={headerImage} delay={300} wrapperClassName="min-w-0 max-w-md">
1204
+ <span className="truncate font-mono text-xs">
1205
+ {midTruncate(headerImage, 72)}
1206
+ </span>
1207
+ </Tooltip>
1208
+ ),
1209
+ gitopsOwner && (
1210
+ <ManagedByChip key="gitops" owner={gitopsOwner} status={gitOpsOwnerStatus} verified={gitOpsOwnerVerified} pending={gitOpsOwnerPending} source={gitOpsOwnerSource} onOpen={onOpenGitOpsResource} variant="block" />
1211
+ ),
1212
+ helmOwner && (
1213
+ <HelmManagedByChip key="helm" owner={helmOwner} source={helmOwnerSource} onOpen={onOpenHelmRelease} variant="block" />
1214
+ ),
1215
+ gitOpsResourcePath && onNavigateGitOpsPath && (
1216
+ <OpenInGitOpsChip key="open-gitops" onClick={() => onNavigateGitOpsPath(gitOpsResourcePath)} />
1217
+ ),
1218
+ onOpenLiveTraffic && <LiveTrafficChip key="live-traffic" onClick={onOpenLiveTraffic} />,
1219
+ relationships?.owner && !showOwnershipHeading && (
1220
+ <span key="owner">Owner: <button onClick={() => onNavigateToResource?.(refToSelectedResource(relationships.owner!))} className="text-blue-500 hover:underline">{relationships.owner.name}</button></span>
1221
+ ),
1222
+ ].filter(Boolean)
1223
+ if (inlineBadges && !(showOwnershipHeading && ownershipContext)) {
1224
+ // The name and its copy button stay together and truncate only when
1225
+ // the line holds nothing else; the badges wrap below before that.
1226
+ return (
1227
+ <>
1228
+ <div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-sm text-theme-text-secondary">
1229
+ {titlePrefix}
1230
+ <div className="flex min-w-0 max-w-full items-center gap-2">{nameAndCopy}</div>
1231
+ {coreBadges}
1232
+ </div>
1233
+ {extraChips.length > 0 && (
1234
+ <div className="mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-sm text-theme-text-secondary">{extraChips}</div>
1235
+ )}
1236
+ </>
1237
+ )
1238
+ }
1239
+ return (
1240
+ <>
1241
+ {showOwnershipHeading && ownershipContext ? (
1242
+ <OwnershipHeading
1243
+ podName={name}
1244
+ context={ownershipContext}
1245
+ copied={copied === 'name'}
1246
+ onCopy={() => copyToClipboard(name, 'name')}
1247
+ onNavigateToResource={onNavigateToResource}
1248
+ onOpenApplication={onOpenApplication}
1249
+ />
1250
+ ) : (
1251
+ <div className="flex items-center gap-3 mb-1">
1252
+ {titlePrefix}
1253
+ {nameAndCopy}
1254
+ </div>
1163
1255
  )}
1164
- </div>
1165
- </>
1166
- }
1256
+ <div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-sm text-theme-text-secondary">
1257
+ {coreBadges}
1258
+ {extraChips}
1259
+ </div>
1260
+ </>
1261
+ )
1262
+ })()}
1167
1263
  headerActions={
1168
1264
  <>
1265
+ {headerActions}
1169
1266
  {diagnoseAction}
1170
1267
  <Tooltip content="Refresh" delay={150} position="bottom">
1171
1268
  <button
@@ -1217,13 +1314,10 @@ export function WorkloadView({
1217
1314
  <div className="h-full min-h-0 overflow-y-auto">{expandedSummary}</div>
1218
1315
  ) : effectiveTab === 'overview' && expandedOverview ? (
1219
1316
  <div className="h-full min-h-0">
1220
- {hasOperationalIssues && renderOverviewLeadForState && (
1221
- <div className="px-4 pt-4">
1222
- {renderOverviewLeadForState({ kind, namespace, name })}
1223
- </div>
1224
- )}
1225
1317
  {expandedOverview}
1226
1318
  </div>
1319
+ ) : effectiveTab === 'spec' && specTab?.render && !resourceGone ? (
1320
+ <div className="h-full min-h-0 overflow-y-auto">{specTab.render()}</div>
1227
1321
  ) : (effectiveTab === 'overview' || effectiveTab === 'spec') && (
1228
1322
  <InfoTab
1229
1323
  resource={resource}
@@ -1258,7 +1352,14 @@ export function WorkloadView({
1258
1352
  updatesError={resourceFocusedUpdatesError}
1259
1353
  extraContent={renderOverviewExtraForState && renderOverviewExtraForState({ kind, namespace, name, group, context: 'expanded' })}
1260
1354
  introContent={overviewIntro}
1261
- leadContent={hasOperationalIssues && renderOverviewLeadForState ? renderOverviewLeadForState({ kind, namespace, name }) : undefined}
1355
+ leadContent={
1356
+ // A host's spec lead replaces the operational issues there: its Overview already leads with them.
1357
+ effectiveTab === 'spec' && specTab?.lead
1358
+ ? specTab.lead
1359
+ : (hasOverviewLead ?? hasOperationalIssues) && renderOverviewLeadForState
1360
+ ? renderOverviewLeadForState({ kind, namespace, name })
1361
+ : undefined
1362
+ }
1262
1363
  onEvaluateCapacity={onEvaluateCapacity}
1263
1364
  recentImageSave={recentImageSave}
1264
1365
  />
@@ -2110,6 +2211,7 @@ function WorkloadOverviewTab({
2110
2211
  const relationshipGroups = buildRelationshipGroups(relationships)
2111
2212
  const servingRelationshipGroups = buildServingRelationshipGroups(relationships)
2112
2213
  const dependencyRelationshipGroups = buildDependencyRelationshipGroups(relationships)
2214
+ const observationGroups = dependencyRelationshipGroups.filter((group) => group.label === 'Monitored By' || group.label === 'Staged Policies')
2113
2215
  const showServingPath = servingRelationshipGroups.length > 0 && overviewShape !== 'job' && overviewShape !== 'cronjob'
2114
2216
  const secondaryRelationshipGroups = showServingPath ? dependencyRelationshipGroups : relationshipGroups
2115
2217
  const relationshipCardTitle =
@@ -2188,6 +2290,14 @@ function WorkloadOverviewTab({
2188
2290
  onNavigate={onNavigate}
2189
2291
  onSwitchToTopology={onSwitchToTopology}
2190
2292
  />
2293
+ {observationGroups.length > 0 && (
2294
+ <ServingDependenciesCard
2295
+ title="Related resources"
2296
+ groups={observationGroups}
2297
+ onNavigate={onNavigate}
2298
+ onSwitchToTopology={onSwitchToTopology}
2299
+ />
2300
+ )}
2191
2301
  {extraContent}
2192
2302
  </div>
2193
2303
  </div>
@@ -3877,6 +3987,7 @@ function buildServingRelationshipGroups(relationships: Relationships | undefined
3877
3987
  ...(relationships.ingresses ?? []),
3878
3988
  ...(relationships.gateways ?? []),
3879
3989
  ...(relationships.routes ?? []),
3990
+ ...(relationships.routedFrom ?? []),
3880
3991
  ])
3881
3992
  return [
3882
3993
  { label: 'Services', refs: dedupeResourceRefs(relationships.services ?? []) },
@@ -3891,6 +4002,8 @@ function buildDependencyRelationshipGroups(relationships: Relationships | undefi
3891
4002
  { label: 'Autoscalers', refs: dedupeResourceRefs(relationships.scalers ?? []) },
3892
4003
  { label: 'Disruption budgets', refs: dedupeResourceRefs(relationships.pdbs ?? []) },
3893
4004
  { label: 'Network policies', refs: dedupeResourceRefs(relationships.networkPolicies ?? []) },
4005
+ { label: 'Staged Policies', refs: dedupeResourceRefs(relationships.stagedPolicies ?? []) },
4006
+ { label: 'Monitored By', refs: dedupeResourceRefs(relationships.monitors ?? []) },
3894
4007
  { label: 'Storage claims', refs: dedupeResourceRefs(relationships.resourceClaims ?? []) },
3895
4008
  ].filter((group) => group.refs.length > 0)
3896
4009
  }
@@ -3990,12 +4103,21 @@ function mergeAndRankEvents(events: TimelineEvent[], updates: TimelineEvent[]):
3990
4103
  })
3991
4104
  }
3992
4105
 
4106
+ function orderTabs(tabs: DetailShellTab<TabType>[], order: string[] | undefined): DetailShellTab<TabType>[] {
4107
+ if (!order || order.length === 0) return tabs
4108
+ const rank = (id: string) => {
4109
+ const i = order.indexOf(id)
4110
+ return i < 0 ? order.length : i
4111
+ }
4112
+ return tabs.map((t, i) => ({ t, i })).sort((a, b) => rank(a.t.id) - rank(b.t.id) || a.i - b.i).map((x) => x.t)
4113
+ }
4114
+
3993
4115
  function mergeExtraTabs(tabs: DetailShellTab<TabType>[], extra: WorkloadExtraTab[] | undefined): DetailShellTab<TabType>[] {
3994
4116
  if (!extra || extra.length === 0) return tabs
3995
4117
  const replaced = new Set(extra.map((x) => x.replaces).filter(Boolean))
3996
4118
  const out = tabs.map((t) => (replaced.has(t.id) ? { ...t, hidden: true } : t))
3997
4119
  for (const x of extra) {
3998
- const tab: DetailShellTab<TabType> = { id: x.id as TabType, label: x.label, icon: x.icon }
4120
+ const tab: DetailShellTab<TabType> = { id: x.id as TabType, label: x.label, icon: x.icon, badge: x.badge }
3999
4121
  const anchor = x.after ?? x.replaces
4000
4122
  const idx = anchor ? out.findIndex((t) => t.id === anchor) : -1
4001
4123
  if (idx >= 0) out.splice(idx + 1, 0, tab)
package/src/index.ts CHANGED
@@ -55,7 +55,7 @@ export * from './components/checks'
55
55
  // queue)
56
56
  export * from './components/issues'
57
57
 
58
- // CloudNativePG workspace model (fleet derivation over /api/cnpg/workspace)
58
+ // CloudNativePG workspace model (fleet derivation over /api/cnpg/workspace) and summaries
59
59
  export * from './components/cnpg'
60
60
 
61
61
  // Cluster switcher (shared trigger+dropdown for OSS Radar and Radar Hub)
@@ -82,3 +82,16 @@ export * from './components/compare'
82
82
 
83
83
  // Perf instrumentation (ELK + structureKey timers, surfaced in diagnostics overlay)
84
84
  export * from './perf'
85
+
86
+ export { CertaintyGlyph, certaintyGlyph, certaintyValueLabel, type Certainty } from './components/facts/certainty'
87
+
88
+ export * from './components/facts'
89
+ export {
90
+ WorkspaceProblemCallout,
91
+ ProblemList,
92
+ ProblemMeta,
93
+ OpenIssueContext,
94
+ problemOriginLabel,
95
+ type WorkspaceProblem,
96
+ type ProblemOrigin,
97
+ } from './components/problems'
@@ -1,15 +1,22 @@
1
+ // @monaco-editor/react and @monaco-editor/loader type monaco through this path,
2
+ // which monaco-editor's exports map does not serve.
1
3
  declare module 'monaco-editor/esm/vs/editor/editor.api' {
2
- export * from 'monaco-editor'
4
+ export * from 'monaco-editor/editor/editor.api'
3
5
  }
4
6
 
5
- declare module 'monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution'
6
- declare module 'monaco-editor/esm/vs/basic-languages/xml/xml.contribution'
7
- declare module 'monaco-editor/esm/vs/basic-languages/html/html.contribution'
8
- declare module 'monaco-editor/esm/vs/basic-languages/css/css.contribution'
9
- declare module 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution'
10
- declare module 'monaco-editor/esm/vs/basic-languages/typescript/typescript.contribution'
11
- declare module 'monaco-editor/esm/vs/basic-languages/python/python.contribution'
12
- declare module 'monaco-editor/esm/vs/basic-languages/shell/shell.contribution'
13
- declare module 'monaco-editor/esm/vs/basic-languages/markdown/markdown.contribution'
14
- declare module 'monaco-editor/esm/vs/basic-languages/ini/ini.contribution'
15
- declare module 'monaco-editor/esm/vs/basic-languages/dockerfile/dockerfile.contribution'
7
+ declare module 'monaco-editor/languages/definitions/yaml/register'
8
+ declare module 'monaco-editor/languages/definitions/xml/register'
9
+ declare module 'monaco-editor/languages/definitions/html/register'
10
+ declare module 'monaco-editor/languages/definitions/css/register'
11
+ declare module 'monaco-editor/languages/definitions/javascript/register'
12
+ declare module 'monaco-editor/languages/definitions/typescript/register'
13
+ declare module 'monaco-editor/languages/definitions/python/register'
14
+ declare module 'monaco-editor/languages/definitions/shell/register'
15
+ declare module 'monaco-editor/languages/definitions/markdown/register'
16
+ declare module 'monaco-editor/languages/definitions/ini/register'
17
+ declare module 'monaco-editor/languages/definitions/dockerfile/register'
18
+ declare module 'monaco-editor/editor/contrib/*'
19
+ declare module 'monaco-editor/editor/standalone/*'
20
+ declare module 'monaco-editor/editor/browser/*'
21
+ declare module 'monaco-editor/editor/common/*'
22
+ declare module 'monaco-editor/features/*'
@@ -35,6 +35,19 @@
35
35
  opacity: 0.5;
36
36
  }
37
37
 
38
+ .btn-secondary {
39
+ border: 1px solid var(--border-default);
40
+ background-color: var(--bg-surface);
41
+ color: var(--text-primary);
42
+ border-radius: 0.625rem;
43
+ }
44
+ .btn-secondary:hover {
45
+ background-color: var(--bg-hover);
46
+ }
47
+ .btn-secondary:disabled {
48
+ opacity: 0.5;
49
+ }
50
+
38
51
  .btn-brand-toggle {
39
52
  background-color: color-mix(in srgb, var(--color-brand) 50%, transparent);
40
53
  color: var(--text-primary);
@@ -1,4 +1,5 @@
1
1
  import type { Issue } from "../components/issues/types";
2
+ import type { Certainty } from "../components/facts/certainty";
2
3
  import type { NodeLifecycleObservation } from "../utils/node-lifecycle";
3
4
 
4
5
  export const CAPACITY_SCHEMA_VERSION = "v1alpha1" as const;
@@ -16,8 +17,7 @@ export interface CapacityResourceIdentity {
16
17
  uid?: string;
17
18
  }
18
19
 
19
- export type CapacityCertainty =
20
- "exact" | "lower_bound" | "upper_bound" | "unknown";
20
+ export type CapacityCertainty = Certainty;
21
21
  export type CapacityGranularity =
22
22
  "aggregate" | "aggregate_not_binpacked" | "per_node";
23
23
  export type CapacityResourceVector = Record<string, string>;
@@ -418,6 +418,14 @@ export interface CapacityScalingFact {
418
418
  summary: string;
419
419
  }
420
420
 
421
+ /** Published scale-down observations; candidates do not imply a removal ETA. */
422
+ export interface CapacityAutoscalerScaleDown {
423
+ status?: string;
424
+ candidates?: number;
425
+ lastTransitionTime?: string;
426
+ asOf?: string;
427
+ }
428
+
421
429
  export interface CapacityAutoscalerBackoff {
422
430
  errorClass?: string;
423
431
  errorCode?: string;
@@ -440,6 +448,7 @@ export interface CapacityAutoscalerChildObservation {
440
448
  readyNodes?: number;
441
449
  totalNodes?: number;
442
450
  backoff?: CapacityAutoscalerBackoff;
451
+ scaleDown?: CapacityAutoscalerScaleDown;
443
452
  asOf?: string;
444
453
  }
445
454