@skyhook-io/k8s-ui 1.14.3 → 1.14.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/components/charts/AreaChart.test.tsx +160 -0
- package/src/components/charts/AreaChart.tsx +191 -39
- package/src/components/charts/PrometheusChartsView.test.tsx +36 -0
- package/src/components/charts/PrometheusChartsView.tsx +193 -76
- package/src/components/charts/SeriesLegend.tsx +8 -3
- package/src/components/charts/annotations.ts +59 -0
- package/src/components/charts/axis.test.ts +32 -0
- package/src/components/charts/axis.ts +60 -0
- package/src/components/charts/colors.test.ts +27 -0
- package/src/components/charts/colors.ts +23 -0
- package/src/components/charts/format.test.ts +19 -0
- package/src/components/charts/format.ts +17 -1
- package/src/components/charts/index.ts +3 -1
- package/src/components/charts/types.ts +12 -0
- package/src/components/logs/LogCore.tsx +182 -16
- package/src/components/logs/LogsViewer.tsx +4 -21
- package/src/components/logs/WorkloadLogsViewer.tsx +5 -23
- package/src/components/resources/HPADiagnosisSummary.test.tsx +178 -0
- package/src/components/resources/HPADiagnosisSummary.tsx +218 -0
- package/src/components/resources/ResourcesView.tsx +17 -3
- package/src/components/resources/index.ts +7 -0
- package/src/components/resources/renderers/AWSManagedControlPlaneRenderer.tsx +2 -2
- package/src/components/resources/renderers/AlertRenderer.tsx +3 -3
- package/src/components/resources/renderers/ArgoApplicationRenderer.tsx +5 -5
- package/src/components/resources/renderers/CNPGClusterRenderer.tsx +1 -1
- package/src/components/resources/renderers/CertificateRenderer.tsx +3 -3
- package/src/components/resources/renderers/CertificateRequestRenderer.tsx +5 -5
- package/src/components/resources/renderers/ChallengeRenderer.tsx +8 -8
- package/src/components/resources/renderers/CiliumNetworkPolicyRenderer.tsx +3 -3
- package/src/components/resources/renderers/ClusterIssuerRenderer.tsx +2 -2
- package/src/components/resources/renderers/ClusterNetworkPolicyRenderer.tsx +3 -3
- package/src/components/resources/renderers/GatewayRenderer.tsx +2 -2
- package/src/components/resources/renderers/GenericRenderer.tsx +1 -1
- package/src/components/resources/renderers/HPARenderer.tsx +4 -57
- package/src/components/resources/renderers/IngressClassRenderer.tsx +1 -1
- package/src/components/resources/renderers/IstioPeerAuthenticationRenderer.tsx +3 -3
- package/src/components/resources/renderers/IstioServiceEntryRenderer.tsx +2 -2
- package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +3 -3
- package/src/components/resources/renderers/KnativeEventingRenderer.tsx +2 -2
- package/src/components/resources/renderers/KnativeRevisionRenderer.tsx +1 -1
- package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +23 -20
- package/src/components/resources/renderers/NetworkPolicyRenderer.tsx +2 -2
- package/src/components/resources/renderers/NodeRenderer.tsx +3 -3
- package/src/components/resources/renderers/OrderRenderer.tsx +6 -6
- package/src/components/resources/renderers/RoleRenderer.tsx +3 -3
- package/src/components/resources/renderers/RolloutRenderer.tsx +2 -2
- package/src/components/resources/renderers/SealedSecretRenderer.tsx +3 -3
- package/src/components/resources/renderers/SecretStoreRenderer.tsx +8 -8
- package/src/components/resources/renderers/VPARenderer.tsx +1 -1
- package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +1 -1
- package/src/components/resources/renderers/WebhookConfigRenderer.tsx +9 -9
- package/src/components/resources/renderers/WorkloadRenderer.tsx +4 -20
- package/src/components/resources/renderers/badge-no-handrolled.test.tsx +6 -12
- package/src/components/resources/renderers/cnpg-cells.tsx +1 -1
- package/src/components/resources/renderers/eso-cells.tsx +17 -1
- package/src/components/resources/renderers/knative-cells.tsx +1 -1
- package/src/components/resources/renderers/kyverno-cells.tsx +7 -3
- package/src/components/resources/resource-utils-certmanager.ts +2 -2
- package/src/components/resources/resource-utils-eso.test.ts +26 -1
- package/src/components/resources/resource-utils-eso.ts +13 -0
- package/src/components/resources/resource-utils-knative.ts +3 -3
- package/src/components/topology/K8sResourceNode.test.ts +9 -0
- package/src/components/topology/K8sResourceNode.tsx +56 -5
- package/src/components/topology/TopologyGraph.tsx +18 -1
- package/src/components/topology/pod-phase-fallback.test.ts +24 -0
- package/src/components/ui/Badge.tsx +5 -1
- package/src/components/ui/index.ts +5 -0
- package/src/components/ui/monacoRuntime.ts +14 -0
- package/src/monaco-deep.d.ts +10 -0
- package/src/theme/components.css +29 -0
- package/src/types/core.ts +23 -10
- package/src/utils/badge-colors.ts +1 -1
- package/src/utils/index.ts +1 -0
- package/src/utils/log-export.test.ts +225 -0
- package/src/utils/log-export.ts +149 -0
- package/src/utils/navigation.test.ts +10 -0
- package/src/utils/navigation.ts +4 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialization for the log viewer's export popover.
|
|
3
|
+
*
|
|
4
|
+
* Copy and download share this module so the two can never disagree about what
|
|
5
|
+
* a line looks like — the popover's preview is rendered from the same functions
|
|
6
|
+
* that produce the payload.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { stripAnsi } from './log-format'
|
|
10
|
+
|
|
11
|
+
export type LogExportFormat = 'txt' | 'json' | 'csv'
|
|
12
|
+
|
|
13
|
+
export interface ExportableLogEntry {
|
|
14
|
+
timestamp: string
|
|
15
|
+
content: string
|
|
16
|
+
container?: string
|
|
17
|
+
pod?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface LogExportOptions {
|
|
21
|
+
format: LogExportFormat
|
|
22
|
+
/**
|
|
23
|
+
* Mirrors the viewer's timestamp toggle, and applies to `txt` only. JSON and
|
|
24
|
+
* CSV always carry the timestamp: there it is a named field a reader can
|
|
25
|
+
* ignore, not the visual noise the toggle exists to suppress.
|
|
26
|
+
*/
|
|
27
|
+
showTimestamps: boolean
|
|
28
|
+
/**
|
|
29
|
+
* Mirrors the viewer's pod attribution, and — like `showTimestamps` — applies
|
|
30
|
+
* to `txt` only. JSON and CSV carry `pod` whenever the entry has one: a
|
|
31
|
+
* display preference must not silently strip the column that makes a
|
|
32
|
+
* multi-pod export attributable.
|
|
33
|
+
*/
|
|
34
|
+
showPodName: boolean
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface LogExportPayload {
|
|
38
|
+
content: string
|
|
39
|
+
mime: string
|
|
40
|
+
extension: LogExportFormat
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Charset is explicit: log content is arbitrary UTF-8, and Excel on Windows
|
|
44
|
+
// falls back to a legacy code page without it.
|
|
45
|
+
const MIME: Record<LogExportFormat, string> = {
|
|
46
|
+
txt: 'text/plain;charset=utf-8',
|
|
47
|
+
json: 'application/json;charset=utf-8',
|
|
48
|
+
csv: 'text/csv;charset=utf-8',
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Display order for the format picker. */
|
|
52
|
+
export const LOG_EXPORT_FORMATS: readonly LogExportFormat[] = ['txt', 'json', 'csv']
|
|
53
|
+
|
|
54
|
+
export const LOG_EXPORT_FORMAT_LABELS: Record<LogExportFormat, string> = {
|
|
55
|
+
txt: 'Text',
|
|
56
|
+
json: 'JSON',
|
|
57
|
+
csv: 'CSV',
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* One entry as the viewer would read it back: timestamps raw rather than in the
|
|
62
|
+
* display format, since an exported line is correlated against other systems
|
|
63
|
+
* long after the screen that produced it is gone.
|
|
64
|
+
*/
|
|
65
|
+
function textLine(entry: ExportableLogEntry, { showTimestamps, showPodName }: LogExportOptions): string {
|
|
66
|
+
const parts: string[] = []
|
|
67
|
+
if (showTimestamps && entry.timestamp) parts.push(entry.timestamp)
|
|
68
|
+
if (showPodName && entry.pod) parts.push(entry.container ? `[${entry.pod}/${entry.container}]` : `[${entry.pod}]`)
|
|
69
|
+
parts.push(stripAnsi(entry.content))
|
|
70
|
+
return parts.join(' ')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function jsonEntry(entry: ExportableLogEntry): Record<string, string> {
|
|
74
|
+
return {
|
|
75
|
+
timestamp: entry.timestamp,
|
|
76
|
+
...(entry.pod ? { pod: entry.pod } : {}),
|
|
77
|
+
...(entry.container ? { container: entry.container } : {}),
|
|
78
|
+
content: stripAnsi(entry.content),
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Columns follow the data, not a display toggle, so a row can never carry a field the header doesn't name. */
|
|
83
|
+
function csvColumns(entries: readonly ExportableLogEntry[]): string[] {
|
|
84
|
+
return entries.some(e => e.pod)
|
|
85
|
+
? ['timestamp', 'pod', 'container', 'content']
|
|
86
|
+
: ['timestamp', 'container', 'content']
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// A cell opening with one of these is a formula to Excel and Sheets, and quoting
|
|
90
|
+
// does not stop it — the quotes are stripped before evaluation. Log content is
|
|
91
|
+
// whatever a pod chose to print, so the leading apostrophe (which spreadsheets
|
|
92
|
+
// consume on import) is the difference between a CSV and an execution vector.
|
|
93
|
+
const SPREADSHEET_FORMULA_START = /^[=+\-@\t\r]/
|
|
94
|
+
|
|
95
|
+
function csvCell(value: string): string {
|
|
96
|
+
const escaped = (SPREADSHEET_FORMULA_START.test(value) ? `'${value}` : value).replace(/"/g, '""')
|
|
97
|
+
return `"${escaped}"`
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function csvRow(entry: ExportableLogEntry, columns: readonly string[]): string {
|
|
101
|
+
const cells = [
|
|
102
|
+
entry.timestamp,
|
|
103
|
+
...(columns.includes('pod') ? [entry.pod ?? ''] : []),
|
|
104
|
+
entry.container ?? '',
|
|
105
|
+
stripAnsi(entry.content),
|
|
106
|
+
]
|
|
107
|
+
return cells.map(csvCell).join(',')
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function serializeLogEntries(
|
|
111
|
+
entries: readonly ExportableLogEntry[],
|
|
112
|
+
opts: LogExportOptions,
|
|
113
|
+
): LogExportPayload {
|
|
114
|
+
const base = { mime: MIME[opts.format], extension: opts.format }
|
|
115
|
+
switch (opts.format) {
|
|
116
|
+
case 'json':
|
|
117
|
+
return { ...base, content: JSON.stringify(entries.map(jsonEntry), null, 2) }
|
|
118
|
+
case 'csv': {
|
|
119
|
+
const columns = csvColumns(entries)
|
|
120
|
+
return { ...base, content: [columns.join(','), ...entries.map(e => csvRow(e, columns))].join('\n') }
|
|
121
|
+
}
|
|
122
|
+
default:
|
|
123
|
+
return { ...base, content: entries.map(e => textLine(e, opts)).join('\n') }
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Up to two representative lines for the popover's preview box. This is the only
|
|
129
|
+
* thing telling the user which fields their export carries, so it renders the
|
|
130
|
+
* shape of the real output rather than a description of it: for CSV that means
|
|
131
|
+
* the header alongside a row, and for JSON a single compact entry rather than
|
|
132
|
+
* the pretty-printed array the payload actually uses.
|
|
133
|
+
*/
|
|
134
|
+
export function previewLogExport(
|
|
135
|
+
entries: readonly ExportableLogEntry[],
|
|
136
|
+
opts: LogExportOptions,
|
|
137
|
+
): string[] {
|
|
138
|
+
if (entries.length === 0) return []
|
|
139
|
+
switch (opts.format) {
|
|
140
|
+
case 'json':
|
|
141
|
+
return [JSON.stringify(jsonEntry(entries[0]))]
|
|
142
|
+
case 'csv': {
|
|
143
|
+
const columns = csvColumns(entries)
|
|
144
|
+
return [columns.join(','), csvRow(entries[0], columns)]
|
|
145
|
+
}
|
|
146
|
+
default:
|
|
147
|
+
return entries.slice(0, 2).map(e => textLine(e, opts))
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -326,3 +326,13 @@ describe('lane identity helpers', () => {
|
|
|
326
326
|
expect(parseLaneId('bogus')).toBeNull()
|
|
327
327
|
})
|
|
328
328
|
})
|
|
329
|
+
|
|
330
|
+
describe('pluralToKind on absent input', () => {
|
|
331
|
+
// A saved investigation can carry an empty kind. This runs over every row of
|
|
332
|
+
// the run list, so throwing here took the whole investigations panel down and
|
|
333
|
+
// made every other run unopenable — one bad row, no panel.
|
|
334
|
+
test('returns the empty string instead of throwing', () => {
|
|
335
|
+
expect(() => pluralToKind('')).not.toThrow()
|
|
336
|
+
expect(pluralToKind('')).toBe('')
|
|
337
|
+
})
|
|
338
|
+
})
|
package/src/utils/navigation.ts
CHANGED
|
@@ -147,6 +147,10 @@ export function kindToPluralWithGroup(kind: string, group: string): string {
|
|
|
147
147
|
* singular PascalCase form for internal logic (health checks, badge colors, hierarchy matching).
|
|
148
148
|
*/
|
|
149
149
|
export function pluralToKind(plural: string): string {
|
|
150
|
+
// A saved investigation can carry an empty kind, and this runs over every
|
|
151
|
+
// row of the run list — indexing [0] of "" threw and took the whole panel
|
|
152
|
+
// down with it, making every other run unopenable.
|
|
153
|
+
if (!plural) return plural
|
|
150
154
|
const lower = plural.toLowerCase()
|
|
151
155
|
const pluralToKindMap = getPluralToKind()
|
|
152
156
|
|