@skyhook-io/k8s-ui 1.17.0 → 1.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/README.md +41 -0
  2. package/package.json +3 -3
  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 +6 -2
  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 +115 -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 +24 -71
  67. package/src/components/gitops/tree/GitOpsTreeGraph.test.ts +26 -1
  68. package/src/components/gitops/tree/GitOpsTreeGraph.tsx +38 -55
  69. package/src/components/gitops/tree/layout.test.ts +111 -0
  70. package/src/components/gitops/tree/layout.ts +128 -0
  71. package/src/components/gitops/tree/tree-helpers.test.ts +17 -0
  72. package/src/components/gitops/tree/tree-helpers.ts +7 -1
  73. package/src/components/issues/ConditionalCleanup.test.tsx +82 -0
  74. package/src/components/issues/IssuesView.tsx +40 -5
  75. package/src/components/issues/ResourceIssuesSection.test.tsx +28 -0
  76. package/src/components/issues/ResourceIssuesSection.tsx +3 -0
  77. package/src/components/issues/index.ts +3 -1
  78. package/src/components/issues/issue-timing.ts +12 -1
  79. package/src/components/issues/issues.test.ts +49 -1
  80. package/src/components/issues/severity.ts +21 -0
  81. package/src/components/issues/types.ts +23 -0
  82. package/src/components/logs/LogCore.theme.test.tsx +81 -3
  83. package/src/components/logs/LogCore.tsx +25 -17
  84. package/src/components/logs/LogToolbarSelects.tsx +3 -1
  85. package/src/components/logs/LogsViewer.test.tsx +291 -0
  86. package/src/components/logs/LogsViewer.tsx +72 -11
  87. package/src/components/logs/StructuredLogLine.test.tsx +76 -0
  88. package/src/components/logs/StructuredLogLine.tsx +22 -30
  89. package/src/components/logs/WorkloadLogsViewer.test.tsx +65 -0
  90. package/src/components/logs/WorkloadLogsViewer.tsx +39 -10
  91. package/src/components/logs/useLogBuffer.test.ts +8 -0
  92. package/src/components/logs/useLogStream.ts +17 -1
  93. package/src/components/problems/index.ts +1 -0
  94. package/src/components/problems/problems.test.tsx +63 -0
  95. package/src/components/problems/problems.tsx +165 -0
  96. package/src/components/resources/ActiveFilterBar.test.tsx +78 -0
  97. package/src/components/resources/ActiveFilterBar.tsx +86 -0
  98. package/src/components/resources/ResourcesSidebar.keyboard.test.tsx +42 -0
  99. package/src/components/resources/ResourcesSidebar.test.tsx +36 -2
  100. package/src/components/resources/ResourcesSidebar.tsx +92 -41
  101. package/src/components/resources/ResourcesView.kind-filter-memory.test.ts +52 -0
  102. package/src/components/resources/ResourcesView.kind-view.test.tsx +149 -0
  103. package/src/components/resources/ResourcesView.per-container.test.ts +56 -1
  104. package/src/components/resources/ResourcesView.tsx +302 -109
  105. package/src/components/resources/curated-column-ownership.test.ts +3 -3
  106. package/src/components/resources/renderers/AutoscalingReferences.test.tsx +286 -0
  107. package/src/components/resources/renderers/CAPIClusterRenderer.tsx +3 -2
  108. package/src/components/resources/renderers/CAPIExactReferenceNavigation.test.tsx +27 -0
  109. package/src/components/resources/renderers/CNPGBackupRenderer.test.tsx +23 -0
  110. package/src/components/resources/renderers/CNPGBackupRenderer.tsx +8 -19
  111. package/src/components/resources/renderers/CNPGClusterRenderer.tsx +5 -7
  112. package/src/components/resources/renderers/CNPGDeclarativeRenderer.tsx +25 -0
  113. package/src/components/resources/renderers/CNPGScheduledBackupRenderer.test.tsx +32 -0
  114. package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +7 -15
  115. package/src/components/resources/renderers/CompositeRenderer.navigation.test.tsx +35 -0
  116. package/src/components/resources/renderers/CompositeRenderer.tsx +3 -3
  117. package/src/components/resources/renderers/CompositionRenderer.tsx +3 -3
  118. package/src/components/resources/renderers/ContourExactReferenceNavigation.test.tsx +34 -0
  119. package/src/components/resources/renderers/ContourHTTPProxyRenderer.tsx +11 -10
  120. package/src/components/resources/renderers/EndpointSliceRenderer.test.tsx +39 -1
  121. package/src/components/resources/renderers/EndpointSliceRenderer.tsx +14 -13
  122. package/src/components/resources/renderers/HPARenderer.tsx +56 -16
  123. package/src/components/resources/renderers/IngressRenderer.defaultBackend.test.tsx +33 -0
  124. package/src/components/resources/renderers/IngressRenderer.tsx +30 -3
  125. package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +9 -9
  126. package/src/components/resources/renderers/IstioExactReferenceNavigation.test.tsx +34 -0
  127. package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +5 -8
  128. package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +13 -11
  129. package/src/components/resources/renderers/KnativeEventingRenderer.tsx +24 -31
  130. package/src/components/resources/renderers/KnativeExactReferenceNavigation.test.tsx +47 -0
  131. package/src/components/resources/renderers/KnativeFlowRenderer.tsx +6 -7
  132. package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +7 -9
  133. package/src/components/resources/renderers/KnativeReferenceLink.tsx +14 -0
  134. package/src/components/resources/renderers/KnativeReferenceLinks.test.tsx +60 -0
  135. package/src/components/resources/renderers/KnativeSourceRenderer.tsx +9 -11
  136. package/src/components/resources/renderers/ManagedResourceRenderer.tsx +2 -2
  137. package/src/components/resources/renderers/MetricsUnavailableNotice.tsx +3 -2
  138. package/src/components/resources/renderers/PodRenderer.test.tsx +32 -0
  139. package/src/components/resources/renderers/PodRenderer.tsx +41 -29
  140. package/src/components/resources/renderers/SimpleRouteRenderer.tsx +1 -1
  141. package/src/components/resources/renderers/VPARenderer.tsx +17 -11
  142. package/src/components/resources/resource-utils-capi.ts +1 -1
  143. package/src/components/resources/resource-utils-cnpg.test.ts +35 -10
  144. package/src/components/resources/resource-utils-cnpg.ts +51 -20
  145. package/src/components/resources/resource-utils-contour.test.ts +44 -0
  146. package/src/components/resources/resource-utils-contour.ts +16 -0
  147. package/src/components/resources/resource-utils-istio.ts +12 -8
  148. package/src/components/resources/resource-utils-knative.ts +18 -0
  149. package/src/components/resources/resource-utils.ts +82 -6
  150. package/src/components/resources/rules-column-width.test.ts +1 -1
  151. package/src/components/resources/summarize-scheduler-message.test.ts +30 -0
  152. package/src/components/shared/ActionConfirmDialog.test.tsx +154 -0
  153. package/src/components/shared/ActionConfirmDialog.tsx +246 -0
  154. package/src/components/shared/CreateResourceDialog.test.tsx +330 -0
  155. package/src/components/shared/CreateResourceDialog.tsx +126 -80
  156. package/src/components/shared/DetailShell.test.tsx +80 -0
  157. package/src/components/shared/DetailShell.tsx +85 -10
  158. package/src/components/shared/EditableYamlView.test.tsx +7 -0
  159. package/src/components/shared/EditableYamlView.tsx +1 -1
  160. package/src/components/shared/ResourceActionsBar.tsx +11 -4
  161. package/src/components/shared/ResourceRendererDispatch.tsx +12 -9
  162. package/src/components/shared/index.ts +2 -0
  163. package/src/components/timeline/TimelineSwimlanes.tsx +1 -1
  164. package/src/components/timeline/timeline-filters.ts +1 -0
  165. package/src/components/topology/K8sResourceNode.test.ts +18 -1
  166. package/src/components/topology/K8sResourceNode.tsx +44 -2
  167. package/src/components/topology/TopologyFilterSidebar.tsx +1 -0
  168. package/src/components/topology/TopologyGraph.tsx +3 -71
  169. package/src/components/topology/TopologySearch.tsx +1 -0
  170. package/src/components/topology/internet-groups.test.ts +35 -0
  171. package/src/components/topology/internet-groups.ts +55 -0
  172. package/src/components/topology/layout.ts +1 -1
  173. package/src/components/ui/Badge.tsx +1 -0
  174. package/src/components/ui/FoldSection.tsx +68 -0
  175. package/src/components/ui/ForceDeleteConfirmDialog.test.tsx +62 -0
  176. package/src/components/ui/ForceDeleteConfirmDialog.tsx +24 -12
  177. package/src/components/ui/RefLink.tsx +20 -0
  178. package/src/components/ui/RowActionMenu.tsx +8 -3
  179. package/src/components/ui/crd-definition-navigation.test.tsx +160 -0
  180. package/src/components/ui/drawer-components.test.tsx +110 -1
  181. package/src/components/ui/drawer-components.tsx +62 -9
  182. package/src/components/ui/index.ts +3 -1
  183. package/src/components/ui/monacoEditorFeatures.ts +77 -0
  184. package/src/components/ui/monacoRuntime.ts +14 -19
  185. package/src/components/ui/status-tone.test.ts +10 -1
  186. package/src/components/ui/status-tone.tsx +29 -0
  187. package/src/components/workload/WorkloadView.deleted.test.tsx +43 -0
  188. package/src/components/workload/WorkloadView.relationships.test.tsx +37 -0
  189. package/src/components/workload/WorkloadView.spec.test.tsx +149 -0
  190. package/src/components/workload/WorkloadView.tsx +180 -64
  191. package/src/index.ts +14 -1
  192. package/src/monaco-deep.d.ts +19 -12
  193. package/src/theme/components.css +13 -0
  194. package/src/types/capacity.ts +11 -2
  195. package/src/types/core.ts +29 -2
  196. package/src/types/gitops-flux-status.test.ts +32 -1
  197. package/src/types/gitops-insights.ts +19 -2
  198. package/src/types/gitops-tree.ts +10 -0
  199. package/src/types/gitops.ts +26 -6
  200. package/src/utils/api-resources.ts +7 -0
  201. package/src/utils/application-history.ts +1 -0
  202. package/src/utils/cnpg-backup.test.ts +26 -0
  203. package/src/utils/cnpg-backup.ts +70 -0
  204. package/src/utils/format.test.ts +9 -0
  205. package/src/utils/format.ts +4 -0
  206. package/src/utils/gitops-owner.ts +3 -2
  207. package/src/utils/grant.test.ts +19 -0
  208. package/src/utils/grant.ts +35 -0
  209. package/src/utils/index.ts +4 -0
  210. package/src/utils/k8s-errors.ts +7 -7
  211. package/src/utils/log-format.test.ts +41 -0
  212. package/src/utils/log-format.ts +71 -15
  213. package/src/utils/log-level.ts +12 -8
  214. package/src/utils/navigation.test.ts +57 -0
  215. package/src/utils/navigation.ts +86 -8
  216. package/src/utils/object-reference-navigation.test.ts +43 -0
  217. package/src/utils/resource-hierarchy.test.ts +37 -0
  218. package/src/utils/resource-hierarchy.ts +15 -7
  219. package/src/utils/resource-icons.ts +2 -0
  220. package/src/utils/skeleton-yaml.test.ts +21 -0
  221. package/src/utils/skeleton-yaml.ts +16 -0
  222. package/src/utils/url-path.test.ts +35 -0
  223. package/src/utils/url-path.ts +21 -0
  224. package/src/utils/validators.test.ts +4 -13
  225. package/src/utils/validators.ts +5 -19
  226. package/src/utils/view-transition.test.ts +35 -1
  227. package/src/utils/view-transition.ts +16 -1
@@ -0,0 +1,77 @@
1
+ // Every editor feature monaco-editor's editor.main entry registers (context menu,
2
+ // comments, multi-cursor, line operations, bracket matching, sticky scroll, quick
3
+ // access, ...), without its language definitions and the TS/JSON/CSS/HTML language
4
+ // services, whose workers this runtime does not ship. editor.api alone registers none
5
+ // of these, so dropping this import silently strips them from every editor.
6
+ import 'monaco-editor/editor/contrib/anchorSelect/browser/anchorSelect.js'
7
+ import 'monaco-editor/editor/contrib/bracketMatching/browser/bracketMatching.js'
8
+ import 'monaco-editor/editor/contrib/caretOperations/browser/transpose.js'
9
+ import 'monaco-editor/editor/contrib/clipboard/browser/clipboard.js'
10
+ import 'monaco-editor/editor/contrib/codeAction/browser/codeActionContributions.js'
11
+ import 'monaco-editor/editor/browser/widget/codeEditor/codeEditorWidget.js'
12
+ import 'monaco-editor/editor/contrib/codelens/browser/codelensController.js'
13
+ import 'monaco-editor/editor/contrib/colorPicker/browser/colorPickerContribution.js'
14
+ import 'monaco-editor/editor/contrib/comment/browser/comment.js'
15
+ import 'monaco-editor/editor/contrib/contextmenu/browser/contextmenu.js'
16
+ import 'monaco-editor/editor/contrib/cursorUndo/browser/cursorUndo.js'
17
+ import 'monaco-editor/editor/browser/widget/diffEditor/diffEditor.contribution.js'
18
+ import 'monaco-editor/editor/contrib/diffEditorBreadcrumbs/browser/contribution.js'
19
+ import 'monaco-editor/editor/contrib/dnd/browser/dnd.js'
20
+ import 'monaco-editor/editor/contrib/documentSymbols/browser/documentSymbols.js'
21
+ import 'monaco-editor/editor/contrib/dropOrPasteInto/browser/dropIntoEditorContribution.js'
22
+ import 'monaco-editor/features/find/register.js'
23
+ import 'monaco-editor/editor/contrib/floatingMenu/browser/floatingMenu.contribution.js'
24
+ import 'monaco-editor/editor/contrib/folding/browser/folding.js'
25
+ import 'monaco-editor/editor/contrib/fontZoom/browser/fontZoom.js'
26
+ import 'monaco-editor/editor/contrib/format/browser/formatActions.js'
27
+ import 'monaco-editor/editor/contrib/gotoError/browser/gotoError.js'
28
+ import 'monaco-editor/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess.js'
29
+ import 'monaco-editor/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition.js'
30
+ import 'monaco-editor/editor/contrib/gpu/browser/gpuActions.js'
31
+ import 'monaco-editor/editor/contrib/hover/browser/hoverContribution.js'
32
+ import 'monaco-editor/editor/contrib/indentation/browser/indentation.js'
33
+ import 'monaco-editor/editor/contrib/inlayHints/browser/inlayHintsContribution.js'
34
+ import 'monaco-editor/editor/contrib/inlineCompletions/browser/inlineCompletions.contribution.js'
35
+ import 'monaco-editor/editor/contrib/inlineProgress/browser/inlineProgress.js'
36
+ import 'monaco-editor/editor/contrib/inPlaceReplace/browser/inPlaceReplace.js'
37
+ import 'monaco-editor/editor/contrib/insertFinalNewLine/browser/insertFinalNewLine.js'
38
+ import 'monaco-editor/editor/standalone/browser/inspectTokens/inspectTokens.js'
39
+ import 'monaco-editor/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.js'
40
+ import 'monaco-editor/editor/contrib/lineSelection/browser/lineSelection.js'
41
+ import 'monaco-editor/editor/contrib/linesOperations/browser/linesOperations.js'
42
+ import 'monaco-editor/editor/contrib/linkedEditing/browser/linkedEditing.js'
43
+ import 'monaco-editor/editor/contrib/links/browser/links.js'
44
+ import 'monaco-editor/editor/contrib/longLinesHelper/browser/longLinesHelper.js'
45
+ import 'monaco-editor/editor/contrib/middleScroll/browser/middleScroll.contribution.js'
46
+ import 'monaco-editor/editor/contrib/multicursor/browser/multicursor.js'
47
+ import 'monaco-editor/editor/contrib/parameterHints/browser/parameterHints.js'
48
+ import 'monaco-editor/editor/contrib/placeholderText/browser/placeholderText.contribution.js'
49
+ import 'monaco-editor/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess.js'
50
+ import 'monaco-editor/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess.js'
51
+ import 'monaco-editor/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess.js'
52
+ import 'monaco-editor/editor/contrib/readOnlyMessage/browser/contribution.js'
53
+ import 'monaco-editor/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.js'
54
+ import 'monaco-editor/editor/contrib/rename/browser/rename.js'
55
+ import 'monaco-editor/editor/contrib/sectionHeaders/browser/sectionHeaders.js'
56
+ import 'monaco-editor/editor/contrib/semanticTokens/browser/viewportSemanticTokens.js'
57
+ import 'monaco-editor/editor/contrib/smartSelect/browser/smartSelect.js'
58
+ import 'monaco-editor/editor/contrib/snippet/browser/snippetController2.js'
59
+ import 'monaco-editor/editor/contrib/stickyScroll/browser/stickyScrollContribution.js'
60
+ import 'monaco-editor/editor/contrib/suggest/browser/suggestInlineCompletions.js'
61
+ import 'monaco-editor/editor/standalone/browser/toggleHighContrast/toggleHighContrast.js'
62
+ import 'monaco-editor/editor/contrib/toggleTabFocusMode/browser/toggleTabFocusMode.js'
63
+ import 'monaco-editor/editor/contrib/tokenization/browser/tokenization.js'
64
+ import 'monaco-editor/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter.js'
65
+ import 'monaco-editor/editor/contrib/unusualLineTerminators/browser/unusualLineTerminators.js'
66
+ import 'monaco-editor/editor/contrib/wordHighlighter/browser/wordHighlighter.js'
67
+ import 'monaco-editor/editor/contrib/wordOperations/browser/wordOperations.js'
68
+ import 'monaco-editor/editor/contrib/wordPartOperations/browser/wordPartOperations.js'
69
+ import 'monaco-editor/editor/browser/coreCommands.js'
70
+ import 'monaco-editor/editor/contrib/caretOperations/browser/caretOperations.js'
71
+ import 'monaco-editor/editor/contrib/dropOrPasteInto/browser/copyPasteContribution.js'
72
+ import 'monaco-editor/editor/contrib/find/browser/findController.js'
73
+ import 'monaco-editor/editor/contrib/gotoSymbol/browser/goToCommands.js'
74
+ import 'monaco-editor/editor/contrib/gotoError/browser/markerSelectionStatus.js'
75
+ import 'monaco-editor/editor/contrib/semanticTokens/browser/documentSemanticTokens.js'
76
+ import 'monaco-editor/editor/contrib/suggest/browser/suggestController.js'
77
+ import 'monaco-editor/editor/common/standaloneStrings.js'
@@ -1,28 +1,23 @@
1
1
  /// <reference path="../../monaco-deep.d.ts" />
2
2
 
3
3
  import { loader } from '@monaco-editor/react'
4
- import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'
4
+ import * as monaco from 'monaco-editor/editor/editor.api'
5
5
  // Tokenizers only — the set the YAML editor and the pod file viewer hand to
6
6
  // Monaco. JSON deliberately absent: its language lives in vs/language/json and
7
7
  // spawns a validation worker this runtime does not ship; viewers highlight
8
8
  // JSON with the YAML tokenizer, which covers it.
9
- import 'monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution'
10
- import 'monaco-editor/esm/vs/basic-languages/xml/xml.contribution'
11
- import 'monaco-editor/esm/vs/basic-languages/html/html.contribution'
12
- import 'monaco-editor/esm/vs/basic-languages/css/css.contribution'
13
- import 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution'
14
- import 'monaco-editor/esm/vs/basic-languages/typescript/typescript.contribution'
15
- import 'monaco-editor/esm/vs/basic-languages/python/python.contribution'
16
- import 'monaco-editor/esm/vs/basic-languages/shell/shell.contribution'
17
- import 'monaco-editor/esm/vs/basic-languages/markdown/markdown.contribution'
18
- import 'monaco-editor/esm/vs/basic-languages/ini/ini.contribution'
19
- import 'monaco-editor/esm/vs/basic-languages/dockerfile/dockerfile.contribution'
20
- import 'monaco-editor/esm/vs/editor/contrib/find/browser/findController.js'
21
- import 'monaco-editor/esm/vs/editor/contrib/folding/browser/folding.js'
22
- import 'monaco-editor/esm/vs/editor/contrib/format/browser/formatActions.js'
23
- import 'monaco-editor/esm/vs/editor/contrib/gotoError/browser/gotoError.js'
24
- import 'monaco-editor/esm/vs/editor/contrib/hover/browser/hoverContribution.js'
25
- import 'monaco-editor/esm/vs/editor/contrib/suggest/browser/suggestController.js'
9
+ import 'monaco-editor/languages/definitions/yaml/register'
10
+ import 'monaco-editor/languages/definitions/xml/register'
11
+ import 'monaco-editor/languages/definitions/html/register'
12
+ import 'monaco-editor/languages/definitions/css/register'
13
+ import 'monaco-editor/languages/definitions/javascript/register'
14
+ import 'monaco-editor/languages/definitions/typescript/register'
15
+ import 'monaco-editor/languages/definitions/python/register'
16
+ import 'monaco-editor/languages/definitions/shell/register'
17
+ import 'monaco-editor/languages/definitions/markdown/register'
18
+ import 'monaco-editor/languages/definitions/ini/register'
19
+ import 'monaco-editor/languages/definitions/dockerfile/register'
20
+ import './monacoEditorFeatures'
26
21
 
27
22
  type MonacoGlobal = typeof globalThis & {
28
23
  MonacoEnvironment?: {
@@ -37,7 +32,7 @@ export async function ensureMonaco() {
37
32
  ;(globalThis as MonacoGlobal).MonacoEnvironment = {
38
33
  getWorker() {
39
34
  return new Worker(
40
- new URL('monaco-editor/esm/vs/editor/editor.worker.js', import.meta.url),
35
+ new URL('monaco-editor/editor/editor.worker.js', import.meta.url),
41
36
  {
42
37
  name: 'radar-monaco-editor',
43
38
  type: 'module',
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest'
2
- import { mapHealthToTone } from './status-tone'
2
+ import { mapHealthToTone, worseTone } from './status-tone'
3
3
 
4
4
  // Inputs flow in from heterogeneous sources (Problems API, Audit findings,
5
5
  // multi-cluster aggregation). A regression here is a silent visual
@@ -51,3 +51,12 @@ describe('mapHealthToTone', () => {
51
51
  expect(mapHealthToTone('HIGH')).toBe('alert')
52
52
  })
53
53
  })
54
+
55
+ describe('worseTone', () => {
56
+ it('never reads calmer than a part that could not be read', () => {
57
+ expect(worseTone('healthy', 'unknown')).toBe('unknown')
58
+ expect(worseTone('unknown', 'degraded')).toBe('degraded')
59
+ expect(worseTone('alert', 'unhealthy')).toBe('unhealthy')
60
+ expect(worseTone('neutral', 'healthy')).toBe('neutral')
61
+ })
62
+ })
@@ -1,4 +1,5 @@
1
1
  import { type HealthLevel } from '../resources/resource-utils';
2
+ import { TONE_TEXT_CLASS } from './severity-tone';
2
3
 
3
4
  // StatusDot + mapHealthToTone are typed helpers over the canonical OSS
4
5
  // status vocabulary defined in `packages/k8s-ui/src/theme/components.css`.
@@ -48,6 +49,34 @@ const DOT_CLASS: Record<StatusTone, string> = {
48
49
  unknown: 'bg-slate-400',
49
50
  };
50
51
 
52
+ /** Solid fill for a tone, e.g. a bar or meter segment. */
53
+ export function toneFillClass(tone: StatusTone): string {
54
+ return DOT_CLASS[tone]
55
+ }
56
+
57
+ // Text for a value read in a tone. Healthy reads as plain primary text: only
58
+ // what needs a look is coloured.
59
+ const TEXT_CLASS: Record<StatusTone, string> = {
60
+ healthy: 'text-theme-text-primary',
61
+ degraded: TONE_TEXT_CLASS.amber,
62
+ alert: TONE_TEXT_CLASS.orange,
63
+ unhealthy: TONE_TEXT_CLASS.red,
64
+ unknown: 'text-theme-text-tertiary',
65
+ neutral: 'text-theme-text-secondary',
66
+ }
67
+
68
+ export function toneTextClass(tone: StatusTone): string {
69
+ return TEXT_CLASS[tone]
70
+ }
71
+
72
+ // Unknown ranks above healthy: a combined reading never looks calmer than a
73
+ // part that could not be read.
74
+ const TONE_RANK: Record<StatusTone, number> = { healthy: 0, neutral: 1, unknown: 2, degraded: 3, alert: 4, unhealthy: 5 }
75
+
76
+ export function worseTone(a: StatusTone, b: StatusTone): StatusTone {
77
+ return TONE_RANK[b] > TONE_RANK[a] ? b : a
78
+ }
79
+
51
80
  // Normalize the variety of severity / health vocabularies that flow in
52
81
  // from APIs (Problems, Audit, multi-cluster aggregation endpoints) onto
53
82
  // a single tone. Inputs are case-insensitive. Returns 'unknown' for
@@ -56,3 +56,46 @@ describe('WorkloadView for an object deleted while open', () => {
56
56
  expect(html).toContain('Reachability')
57
57
  })
58
58
  })
59
+
60
+ function renderHosted(resourceError: unknown, activeTab: string) {
61
+ return renderToStaticMarkup(
62
+ <WorkloadView
63
+ kind="clusters"
64
+ group="postgresql.cnpg.io"
65
+ namespace="db"
66
+ name="pg"
67
+ expanded
68
+ activeTab={activeTab as never}
69
+ onBack={vi.fn()}
70
+ resource={{ apiVersion: 'postgresql.cnpg.io/v1', kind: 'Cluster', metadata: { name: 'pg', namespace: 'db' }, spec: {} }}
71
+ resourceError={resourceError}
72
+ renderSummary={() => 'Host summary action'}
73
+ extraTabs={[{ id: 'backups', label: 'Host backups', render: () => 'Host backups action' }]}
74
+ subheader="Host subheader action"
75
+ renderHeaderActions={() => 'Host header action'}
76
+ renderStatusBadge={() => 'Host phase'}
77
+ statusNote="Host verdict"
78
+ specTab={{ render: () => 'Host spec action' }}
79
+ />,
80
+ )
81
+ }
82
+
83
+ describe('a host page for an object deleted while open', () => {
84
+ it('drops the host summary, tabs, subheader and actions, which act on the live object', () => {
85
+ const gone = Object.assign(new Error('clusters "pg" not found'), { status: 404 })
86
+ for (const tab of ['overview', 'backups', 'spec']) {
87
+ const html = renderHosted(gone, tab)
88
+ expect(html).toContain('>Deleted<')
89
+ for (const host of ['Host summary action', 'Host backups', 'Host subheader action', 'Host header action', 'Host phase', 'Host verdict', 'Host spec action']) {
90
+ expect(html, `${tab}: ${host}`).not.toContain(host)
91
+ }
92
+ }
93
+ })
94
+
95
+ it('keeps them while the object exists', () => {
96
+ const html = renderHosted(Object.assign(new Error('boom'), { status: 500 }), 'overview')
97
+ for (const host of ['Host summary action', 'Host backups', 'Host subheader action', 'Host header action', 'Host phase', 'Host verdict']) {
98
+ expect(html).toContain(host)
99
+ }
100
+ })
101
+ })
@@ -0,0 +1,37 @@
1
+ import { renderToStaticMarkup } from 'react-dom/server'
2
+ import { describe, expect, it } from 'vitest'
3
+ import { WorkloadView } from './WorkloadView'
4
+
5
+ const workload = {
6
+ apiVersion: 'apps/v1', kind: 'Deployment', metadata: { name: 'web', namespace: 'demo' },
7
+ spec: { replicas: 1, selector: { matchLabels: { app: 'web' } }, template: { metadata: { labels: { app: 'web' } }, spec: { containers: [{ name: 'app', image: 'nginx' }] } } },
8
+ status: { replicas: 1, availableReplicas: 1, readyReplicas: 1, updatedReplicas: 1 },
9
+ }
10
+
11
+
12
+ describe('workload monitoring projection', () => {
13
+ it('renders monitors in the related dependency card', () => {
14
+ const html = renderToStaticMarkup(<WorkloadView kind="deployments" namespace="demo" name="web" onBack={() => {}} resource={workload} relationships={{ monitors: [{ kind: 'PodMonitor', group: 'monitoring.coreos.com', namespace: 'demo', name: 'scraper' }] }} />)
15
+ expect(html).toContain('Monitored By')
16
+ expect(html).toContain('scraper')
17
+ })
18
+ })
19
+
20
+
21
+ describe('workload upstream projection', () => {
22
+ it('keeps other routing sources visible as entrypoints', () => {
23
+ const html = renderToStaticMarkup(<WorkloadView kind="deployments" namespace="demo" name="web" onBack={() => {}} resource={workload} relationships={{ routedFrom: [{ kind: 'Broker', group: 'eventing.knative.dev', namespace: 'demo', name: 'messages' }] }} />)
24
+ expect(html).toContain('Entry point resources')
25
+ expect(html).toContain('messages')
26
+ })
27
+ })
28
+
29
+
30
+ describe('workload staged-policy projection', () => {
31
+ it('shows staging without calling it an enforcing network policy', () => {
32
+ const html = renderToStaticMarkup(<WorkloadView kind="deployments" namespace="demo" name="web" onBack={() => {}} resource={workload} relationships={{ stagedPolicies: [{ kind: 'StagedNetworkPolicy', group: 'projectcalico.org', namespace: 'demo', name: 'preview' }] }} />)
33
+ expect(html).toContain('Staged Policies')
34
+ expect(html).toContain('preview')
35
+ expect(html).not.toContain('Network policies')
36
+ })
37
+ })
@@ -0,0 +1,149 @@
1
+ // @vitest-environment jsdom
2
+ import { act } from 'react'
3
+ import { createRoot } from 'react-dom/client'
4
+ import { renderToStaticMarkup } from 'react-dom/server'
5
+ import type { ReactNode } from 'react'
6
+ import { expect, it, vi } from 'vitest'
7
+ import { WorkloadView } from './WorkloadView'
8
+
9
+ const renderer = vi.hoisted(() => vi.fn(({ mainFooter }: { mainFooter?: ReactNode }) => <div>Generic renderer and Conditions{mainFooter}</div>))
10
+ vi.mock('../shared/ResourceRendererDispatch', async (original) => ({ ...await original<typeof import('../shared/ResourceRendererDispatch')>(), ResourceRendererDispatch: renderer }))
11
+
12
+ const resource = { apiVersion: 'postgresql.cnpg.io/v1', kind: 'Cluster', metadata: { name: 'pg', namespace: 'db', labels: { app: 'postgres' } }, spec: { instances: 2 }, status: {} }
13
+ const props = { kind: 'clusters', namespace: 'db', name: 'pg', group: 'postgresql.cnpg.io', resource, onBack: () => {}, activeTab: 'spec' as const, renderSummary: () => <div>Composed Overview</div>, renderOverviewExtra: () => <div>Audit Findings</div> }
14
+
15
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
16
+
17
+ it('replaces the entire expanded spec body, including its generic sections and lead', () => {
18
+ renderer.mockClear()
19
+ const html = renderToStaticMarkup(<WorkloadView {...props} specTab={{ label: 'Configuration', lead: <div>Old lead</div>, render: () => <div>Purpose-built configuration</div> }} />)
20
+ expect(html).toContain('Purpose-built configuration')
21
+ expect(html).toContain('Configuration')
22
+ for (const text of ['Generic renderer', 'Conditions', 'Audit Findings', 'Labels (1)', 'Metadata', 'Recent Events', 'Old lead']) expect(html).not.toContain(text)
23
+ expect(renderer).not.toHaveBeenCalled()
24
+ })
25
+
26
+ it('preserves the generic spec body and lead when no replacement is supplied', () => {
27
+ const html = renderToStaticMarkup(<WorkloadView {...props} specTab={{ label: 'Settings', lead: <div>Existing lead</div> }} />)
28
+ for (const text of ['Settings', 'Existing lead', 'Generic renderer and Conditions', 'Audit Findings']) expect(html).toContain(text)
29
+ })
30
+
31
+ it('does not use the spec replacement in a drawer or on Overview', () => {
32
+ const replacement = vi.fn(() => <div>Purpose-built configuration</div>)
33
+ let html = renderToStaticMarkup(<WorkloadView {...props} expanded={false} specTab={{ render: replacement }} />)
34
+ expect(html).toContain('Composed Overview')
35
+ html = renderToStaticMarkup(<WorkloadView {...props} activeTab="overview" specTab={{ render: replacement }} />)
36
+ expect(html).toContain('Composed Overview')
37
+ expect(replacement).not.toHaveBeenCalled()
38
+ })
39
+
40
+ it('still opens the original Spec & status in a drawer when a page replacement is provided', () => {
41
+ const replacement = vi.fn(() => <div>Purpose-built configuration</div>)
42
+ const host = document.createElement('div')
43
+ const root = createRoot(host)
44
+ act(() => root.render(<WorkloadView {...props} expanded={false} specTab={{ label: 'Configuration', render: replacement }} />))
45
+ const tab = [...host.querySelectorAll<HTMLButtonElement>('[role="tab"]')].find((b) => b.textContent === 'Spec & status')!
46
+ act(() => tab.click())
47
+ expect(tab.getAttribute('aria-selected')).toBe('true')
48
+ expect(host.textContent).toContain('Generic renderer and Conditions')
49
+ expect(host.textContent).toContain('Audit Findings')
50
+ expect(replacement).not.toHaveBeenCalled()
51
+ act(() => root.unmount())
52
+ })
53
+
54
+ it('lets a host render the reported phase while preserving the default derived badge', () => {
55
+ const instance = { ...resource, status: { phase: 'Cluster in healthy state', readyInstances: 1 } }
56
+ for (const expanded of [true, false]) {
57
+ const html = renderToStaticMarkup(<WorkloadView {...props} expanded={expanded} resource={instance} renderStatusBadge={(r) => <span>Phase: {r.status.phase}</span>} />)
58
+ expect(html).toContain('Phase: Cluster in healthy state')
59
+ expect(html).not.toMatch(/badge[^>]*>Degraded/)
60
+ expect(renderToStaticMarkup(<WorkloadView {...props} expanded={expanded} resource={instance} />)).toMatch(/badge[^>]*>Degraded/)
61
+ }
62
+ })
63
+
64
+ it('waits for the resource before asking a host for its status badge', () => {
65
+ const badge = vi.fn((r: any) => <span>Phase: {r.status.phase}</span>)
66
+ for (const expanded of [true, false]) {
67
+ expect(() => renderToStaticMarkup(<WorkloadView {...props} expanded={expanded} resource={undefined} renderStatusBadge={badge} />)).not.toThrow()
68
+ }
69
+ expect(badge).not.toHaveBeenCalled()
70
+ })
71
+
72
+ it.each(['ScheduledBackup', 'Database', 'Publication', 'ClusterImageCatalog', 'Deployment', 'Pod', 'Pooler'])('keeps %s drawer utilities apart from identity and object actions', (kind) => {
73
+ const host = document.createElement('div')
74
+ const root = createRoot(host)
75
+ const name = 'a-long-object-name-that-needs-the-full-drawer-width'
76
+ act(() => root.render(<WorkloadView {...props} name={name} resource={{ ...resource, kind }} expanded={false} onExpand={() => {}} onClose={() => {}} renderStatusBadge={() => <span>Reported status</span>} renderHeaderActions={() => <button>Object action</button>} />))
77
+ const expand = host.querySelector('[aria-label="Open full view"]')!
78
+ const utilityRow = expand.parentElement!.parentElement!
79
+ expect(utilityRow.classList.contains('shrink-0')).toBe(true)
80
+ expect(utilityRow.classList.contains('flex-nowrap')).toBe(true)
81
+ expect(utilityRow.querySelector('[aria-label="Refresh"]')).not.toBeNull()
82
+ expect(utilityRow.querySelector('[aria-label="Close"]')).not.toBeNull()
83
+ expect(utilityRow.textContent).not.toContain('Object action')
84
+ // The name has its own line under the badges and controls, so a long one gets the drawer's full width.
85
+ const title = host.querySelector('h2')!
86
+ expect(title.textContent).toBe(name)
87
+ const topRow = utilityRow.parentElement!
88
+ expect(topRow.contains(title)).toBe(false)
89
+ expect(topRow.textContent).toContain('Reported status')
90
+ const action = [...host.querySelectorAll('button')].find((b) => b.textContent === 'Object action')!
91
+ expect(topRow.contains(action)).toBe(false)
92
+ expect(title.parentElement!.contains(action)).toBe(false)
93
+ act(() => root.unmount())
94
+ })
95
+
96
+ it('preserves Diagnose before the resource loads while deferring resource-dependent actions', () => {
97
+ const header = vi.fn(() => <button>Resource action</button>)
98
+ const html = renderToStaticMarkup(<WorkloadView {...props} resource={undefined} expanded={false} renderHeaderActions={header} actionsBarProps={{ renderDiagnose: () => <button>Diagnose this object</button> }} />)
99
+ expect(html).toContain('Diagnose this object')
100
+ expect(header).not.toHaveBeenCalled()
101
+ })
102
+
103
+ it.each(['Deployment', 'Pod', 'ScheduledBackup', 'Database', 'Pooler'])('groups Diagnose with %s drawer utilities and omits empty object actions', (kind) => {
104
+ const host = document.createElement('div')
105
+ const root = createRoot(host)
106
+ const header = vi.fn(() => null)
107
+ const group = kind === 'Deployment' ? 'apps' : kind === 'Pod' ? '' : 'postgresql.cnpg.io'
108
+ const data = { ...resource, kind, apiVersion: group ? `${group}/v1` : 'v1' }
109
+ act(() => root.render(<WorkloadView {...props} kind={`${kind.toLowerCase()}s`} group={group} resource={data} expanded={false} onExpand={() => {}} onClose={() => {}} renderHeaderActions={header} actionsBarProps={{ renderDiagnose: () => <button>Diagnose</button> }} />))
110
+ const utility = host.querySelector('[aria-label="Open full view"]')!.parentElement!.parentElement!
111
+ expect(utility.textContent).toContain('Diagnose')
112
+ expect(host.querySelector('[data-action-group=object]')!.matches(':empty')).toBe(true)
113
+ expect(header).toHaveBeenCalledTimes(1)
114
+ act(() => root.render(<WorkloadView {...props} kind={`${kind.toLowerCase()}s`} group={group} resource={data} expanded renderHeaderActions={header} actionsBarProps={{ renderDiagnose: () => <button>Diagnose</button> }} />))
115
+ const refresh = host.querySelector('[aria-label="Refresh"]')!
116
+ expect(refresh.parentElement!.parentElement!.textContent).toContain('Diagnose')
117
+ act(() => root.unmount())
118
+ })
119
+
120
+ it('hides the object action band when a host action component has no content yet', () => {
121
+ const EmptyAction = () => null
122
+ const host = document.createElement('div'); const root = createRoot(host)
123
+ act(() => root.render(<WorkloadView {...props} expanded={false} renderHeaderActions={() => <EmptyAction />} />))
124
+ const row = host.querySelector('[data-action-group=object]')!
125
+ expect(row.matches(':empty')).toBe(true)
126
+ expect(row.classList.contains('empty:hidden')).toBe(true)
127
+ act(() => root.render(<WorkloadView {...props} expanded={false} renderHeaderActions={() => <button>Run now</button>} />))
128
+ expect(row.matches(':empty')).toBe(false)
129
+ act(() => root.unmount())
130
+ })
131
+
132
+ it.each(['Deployment', 'Pod', 'Pooler', 'ScheduledBackup'])('groups %s drawer actions with utilities in one toolbar', (kind) => {
133
+ const host = document.createElement('div'); const root = createRoot(host)
134
+ const apiKind = kind === 'Deployment' ? 'deployments' : kind === 'Pod' ? 'pods' : kind === 'Pooler' ? 'poolers' : 'scheduledbackups'
135
+ const group = kind === 'Deployment' ? 'apps' : kind === 'Pod' ? '' : 'postgresql.cnpg.io'
136
+ const data = { ...resource, kind, apiVersion: group ? `${group}/v1` : 'v1', spec: { containers: [{ name: 'postgres', image: 'postgres' }] }, status: { phase: 'Running' } }
137
+ act(() => root.render(<WorkloadView {...props} kind={apiKind} group={group} expanded={false} resource={data} actionsBarProps={{ canExec: true, onOpenTerminal: () => {}, onRestart: () => {} }} renderHeaderActions={() => kind === 'ScheduledBackup' ? <><div><button>Suspend</button><button>Run now</button><button>Edit schedule</button></div><div>Run blocked: no backup destination</div></> : <button>{kind === 'Pooler' ? 'Pause' : 'Object action'}</button>} />))
138
+ const object = host.querySelector('[data-action-group=object]')!
139
+ const utility = host.querySelector('[data-action-group=utility]')!
140
+ expect(object.parentElement).toBe(utility.parentElement)
141
+ expect(object.parentElement!.classList.contains('flex-wrap')).toBe(true)
142
+ expect(utility.classList.contains('ml-auto')).toBe(true)
143
+ expect(object.querySelector('button')).not.toBeNull()
144
+ expect(utility.textContent).toContain('YAML')
145
+ if (kind === 'Pod') expect(object.textContent).toContain('Terminal')
146
+ if (kind === 'Deployment') expect(object.textContent).toContain('Restart')
147
+ if (kind === 'ScheduledBackup') { expect(object.querySelectorAll('button')).toHaveLength(3); expect(object.textContent).toContain('Run blocked: no backup destination') }
148
+ act(() => root.unmount())
149
+ })