@skyhook-io/k8s-ui 1.1.1 → 1.2.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.
- package/package.json +6 -2
- package/src/components/dock/BottomDock.tsx +14 -15
- package/src/components/dock/DockContext.tsx +40 -1
- package/src/components/dock/LocalTerminalTab.tsx +241 -0
- package/src/components/dock/NodeTerminalTab.tsx +129 -0
- package/src/components/dock/TerminalTab.tsx +1 -1
- package/src/components/dock/index.ts +2 -0
- package/src/components/gitops/GitOpsStatusBadge.tsx +18 -67
- package/src/components/logs/LogCore.tsx +30 -4
- package/src/components/logs/StructuredLogLine.tsx +168 -0
- package/src/components/logs/index.ts +1 -1
- package/src/components/logs/useLogBuffer.ts +16 -10
- package/src/components/resources/ResourcesView.tsx +136 -24
- package/src/components/resources/renderers/ContourHTTPProxyRenderer.tsx +207 -0
- package/src/components/resources/renderers/PodRenderer.tsx +164 -8
- package/src/components/resources/renderers/contour-cells.tsx +48 -0
- package/src/components/resources/renderers/index.ts +2 -0
- package/src/components/resources/renderers/trivy-shared.tsx +9 -25
- package/src/components/resources/resource-utils-contour.ts +34 -0
- package/src/components/resources/resource-utils.ts +91 -0
- package/src/components/shared/ResourceActionsBar.tsx +135 -2
- package/src/components/shared/ResourceRendererDispatch.tsx +23 -5
- package/src/components/timeline/shared.tsx +8 -10
- package/src/components/topology/K8sResourceNode.tsx +1 -0
- package/src/components/topology/TopologyFilterSidebar.tsx +3 -0
- package/src/components/topology/layout.ts +1 -0
- package/src/components/topology/topology.css +1 -0
- package/src/components/ui/CodeViewer.tsx +1 -2
- package/src/components/ui/ForceDeleteConfirmDialog.tsx +84 -10
- package/src/components/ui/Toast.tsx +5 -5
- package/src/components/ui/drawer-components.tsx +28 -22
- package/src/components/workload/WorkloadView.tsx +11 -3
- package/src/theme/index.ts +3 -0
- package/src/theme/tailwind-theme.css +61 -0
- package/src/theme/variables.css +121 -0
- package/src/types/core.ts +12 -0
- package/src/utils/animation.ts +1 -1
- package/src/utils/badge-colors.ts +158 -123
- package/src/utils/log-format.ts +127 -35
- package/src/utils/resource-hierarchy.ts +5 -0
- package/src/utils/resource-icons.ts +3 -0
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
X,
|
|
18
18
|
BarChart3,
|
|
19
19
|
} from 'lucide-react'
|
|
20
|
-
import type { TimelineEvent, ResourceRef, Relationships, SelectedResource } from '../../types'
|
|
20
|
+
import type { TimelineEvent, ResourceRef, Relationships, SelectedResource, ResolvedEnvFrom } from '../../types'
|
|
21
21
|
import type { NavigateToResource } from '../../utils/navigation'
|
|
22
22
|
import { refToSelectedResource, pluralToKind } from '../../utils/navigation'
|
|
23
23
|
import { isChangeEvent, isHistoricalEvent } from '../../types'
|
|
@@ -125,10 +125,10 @@ interface WorkloadViewProps {
|
|
|
125
125
|
// ── ResourceActionsBar props (passed through) ────────────────────────────
|
|
126
126
|
/** All props for the actions bar (forwarded as-is) */
|
|
127
127
|
actionsBarProps?: Record<string, any>
|
|
128
|
-
|
|
129
|
-
// ── Renderer overrides ──────────────────────────────────────────────────
|
|
130
128
|
/** Platform-specific renderer overrides (e.g. with hooks for metrics, exec, port-forward) */
|
|
131
129
|
rendererOverrides?: RendererOverrides
|
|
130
|
+
/** Resolved ConfigMap/Secret data for envFrom expansion in PodRenderer */
|
|
131
|
+
resolvedEnvFrom?: ResolvedEnvFrom
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
export function WorkloadView({
|
|
@@ -170,6 +170,8 @@ export function WorkloadView({
|
|
|
170
170
|
actionsBarProps,
|
|
171
171
|
// Renderer overrides
|
|
172
172
|
rendererOverrides,
|
|
173
|
+
// Pod env expansion
|
|
174
|
+
resolvedEnvFrom,
|
|
173
175
|
}: WorkloadViewProps) {
|
|
174
176
|
// Normalize kind: URL has plural lowercase, internal logic uses singular PascalCase
|
|
175
177
|
const kind = pluralToKind(kindProp)
|
|
@@ -441,6 +443,8 @@ export function WorkloadView({
|
|
|
441
443
|
onSaveSecretValue={canUpdateSecrets ? handleSaveSecretValue : undefined}
|
|
442
444
|
isSavingSecret={isUpdatingResource}
|
|
443
445
|
rendererOverrides={rendererOverrides}
|
|
446
|
+
resolvedEnvFrom={resolvedEnvFrom}
|
|
447
|
+
renderMetrics={renderMetricsTab}
|
|
444
448
|
/>
|
|
445
449
|
)}
|
|
446
450
|
</div>
|
|
@@ -580,6 +584,7 @@ export function WorkloadView({
|
|
|
580
584
|
onOpenLogs={handleOpenLogs}
|
|
581
585
|
onSwitchToTimeline={() => handleSetTab('timeline')}
|
|
582
586
|
rendererOverrides={rendererOverrides}
|
|
587
|
+
resolvedEnvFrom={resolvedEnvFrom}
|
|
583
588
|
/>
|
|
584
589
|
)}
|
|
585
590
|
{activeTab === 'timeline' && (
|
|
@@ -1062,6 +1067,7 @@ function InfoTab({
|
|
|
1062
1067
|
onOpenLogs,
|
|
1063
1068
|
onSwitchToTimeline,
|
|
1064
1069
|
rendererOverrides,
|
|
1070
|
+
resolvedEnvFrom,
|
|
1065
1071
|
}: {
|
|
1066
1072
|
resource: any
|
|
1067
1073
|
selectedResource: SelectedResource
|
|
@@ -1075,6 +1081,7 @@ function InfoTab({
|
|
|
1075
1081
|
onOpenLogs?: (podName: string, containerName: string) => void
|
|
1076
1082
|
onSwitchToTimeline?: () => void
|
|
1077
1083
|
rendererOverrides?: RendererOverrides
|
|
1084
|
+
resolvedEnvFrom?: ResolvedEnvFrom
|
|
1078
1085
|
}) {
|
|
1079
1086
|
if (isLoading) {
|
|
1080
1087
|
return (
|
|
@@ -1108,6 +1115,7 @@ function InfoTab({
|
|
|
1108
1115
|
showMetrics={false}
|
|
1109
1116
|
onOpenLogs={onOpenLogs}
|
|
1110
1117
|
rendererOverrides={rendererOverrides}
|
|
1118
|
+
resolvedEnvFrom={resolvedEnvFrom}
|
|
1111
1119
|
eventsHint={onSwitchToTimeline && (
|
|
1112
1120
|
<button
|
|
1113
1121
|
onClick={onSwitchToTimeline}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @skyhook-io/k8s-ui Tailwind Theme
|
|
3
|
+
*
|
|
4
|
+
* Maps CSS variables to Tailwind v4 @theme tokens.
|
|
5
|
+
* Enables utility classes: bg-theme-surface, text-theme-text-primary, border-accent, etc.
|
|
6
|
+
* Import after variables.css.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
@theme inline {
|
|
10
|
+
/* Backgrounds */
|
|
11
|
+
--color-theme-base: var(--bg-base);
|
|
12
|
+
--color-theme-surface: var(--bg-surface);
|
|
13
|
+
--color-theme-elevated: var(--bg-elevated);
|
|
14
|
+
--color-theme-hover: var(--bg-hover);
|
|
15
|
+
--color-theme-active: var(--bg-active);
|
|
16
|
+
|
|
17
|
+
/* Text */
|
|
18
|
+
--color-theme-text-primary: var(--text-primary);
|
|
19
|
+
--color-theme-text-secondary: var(--text-secondary);
|
|
20
|
+
--color-theme-text-tertiary: var(--text-tertiary);
|
|
21
|
+
--color-theme-text-disabled: var(--text-disabled);
|
|
22
|
+
|
|
23
|
+
/* Borders */
|
|
24
|
+
--color-theme-border: var(--border-default);
|
|
25
|
+
--color-theme-border-light: var(--border-light);
|
|
26
|
+
--color-theme-border-subtle: var(--border-subtle);
|
|
27
|
+
|
|
28
|
+
/* Accent */
|
|
29
|
+
--color-accent: var(--accent);
|
|
30
|
+
--color-accent-light: var(--accent-light);
|
|
31
|
+
--color-accent-muted: var(--accent-muted);
|
|
32
|
+
--color-accent-text: var(--accent-text);
|
|
33
|
+
|
|
34
|
+
/* Skyhook brand */
|
|
35
|
+
--color-skyhook: #2D7AFF;
|
|
36
|
+
--color-skyhook-50: #E6F0FF;
|
|
37
|
+
--color-skyhook-100: #CCE0FF;
|
|
38
|
+
--color-skyhook-200: #99C2FF;
|
|
39
|
+
--color-skyhook-300: #66A3FF;
|
|
40
|
+
--color-skyhook-400: #3385FF;
|
|
41
|
+
--color-skyhook-500: #2D7AFF;
|
|
42
|
+
--color-skyhook-600: #0052CC;
|
|
43
|
+
--color-skyhook-700: #003D99;
|
|
44
|
+
--color-skyhook-800: #002966;
|
|
45
|
+
--color-skyhook-900: #001433;
|
|
46
|
+
|
|
47
|
+
/* K8s resource type colors */
|
|
48
|
+
--color-k8s-internet: #2D7AFF;
|
|
49
|
+
--color-k8s-ingress: #8b5cf6;
|
|
50
|
+
--color-k8s-service: #3b82f6;
|
|
51
|
+
--color-k8s-deployment: #10b981;
|
|
52
|
+
--color-k8s-daemonset: #14b8a6;
|
|
53
|
+
--color-k8s-statefulset: #06b6d4;
|
|
54
|
+
--color-k8s-replicaset: #22c55e;
|
|
55
|
+
--color-k8s-pod: #84cc16;
|
|
56
|
+
--color-k8s-configmap: #f59e0b;
|
|
57
|
+
--color-k8s-secret: #ef4444;
|
|
58
|
+
--color-k8s-hpa: #ec4899;
|
|
59
|
+
--color-k8s-job: #a855f7;
|
|
60
|
+
--color-k8s-cronjob: #d946ef;
|
|
61
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @skyhook-io/k8s-ui Theme Variables
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for the theme contract.
|
|
5
|
+
* Uses light-dark() for dual-value definitions.
|
|
6
|
+
* Consumers @import this file, then override any variables via CSS cascade.
|
|
7
|
+
*
|
|
8
|
+
* Toggle mechanism:
|
|
9
|
+
* document.documentElement.classList.toggle('dark', isDark)
|
|
10
|
+
* document.documentElement.style.colorScheme = isDark ? 'dark' : 'light'
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
:root {
|
|
14
|
+
color-scheme: light dark;
|
|
15
|
+
|
|
16
|
+
/* ── Brand ── */
|
|
17
|
+
--color-brand: #2D7AFF;
|
|
18
|
+
--color-brand-light: light-dark(#1A5FCC, #5A9AFF);
|
|
19
|
+
|
|
20
|
+
/* ── Semantic status (theme-independent) ── */
|
|
21
|
+
--color-success: #22C55E;
|
|
22
|
+
--color-success-light: #4ADE80;
|
|
23
|
+
--color-success-dark: #16A34A;
|
|
24
|
+
--color-warning: #F59E0B;
|
|
25
|
+
--color-warning-light: #FBBF24;
|
|
26
|
+
--color-warning-dark: #D97706;
|
|
27
|
+
--color-error: #EF4444;
|
|
28
|
+
--color-error-light: #F87171;
|
|
29
|
+
--color-error-dark: #DC2626;
|
|
30
|
+
--color-info: #3B82F6;
|
|
31
|
+
|
|
32
|
+
/* ── Backgrounds ── */
|
|
33
|
+
--bg-base: light-dark(#f7f9fc, #0c1425);
|
|
34
|
+
--bg-surface: light-dark(#ffffff, #162033);
|
|
35
|
+
--bg-elevated: light-dark(#edf2f8, #1e2d45);
|
|
36
|
+
--bg-hover: light-dark(#e2e8f0, #2a3d58);
|
|
37
|
+
--bg-active: light-dark(#dbeafe, #1e3a5f);
|
|
38
|
+
|
|
39
|
+
/* ── Text ── */
|
|
40
|
+
--text-primary: light-dark(#0f172a, #f8fafc);
|
|
41
|
+
--text-secondary: light-dark(#475569, #cbd5e1);
|
|
42
|
+
--text-tertiary: light-dark(#64748b, #94a3b8);
|
|
43
|
+
--text-disabled: light-dark(#94a3b8, #64748b);
|
|
44
|
+
|
|
45
|
+
/* ── Borders ── */
|
|
46
|
+
--border-default: light-dark(#e2e8f0, #1e2d45);
|
|
47
|
+
--border-light: light-dark(#cbd5e1, #2a3d58);
|
|
48
|
+
--border-subtle: light-dark(rgba(0, 0, 0, 0.06), rgba(255, 255, 255, 0.02));
|
|
49
|
+
--border-focus: var(--color-brand);
|
|
50
|
+
|
|
51
|
+
/* ── Accent ── */
|
|
52
|
+
--accent: var(--color-brand);
|
|
53
|
+
--accent-light: var(--color-brand-light);
|
|
54
|
+
--accent-muted: light-dark(rgba(45, 122, 255, 0.1), rgba(45, 122, 255, 0.2));
|
|
55
|
+
--accent-text: light-dark(#1d4ed8, #93c5fd);
|
|
56
|
+
|
|
57
|
+
/* ── Shadows (light defaults — can't use light-dark() for comma-separated values) ── */
|
|
58
|
+
--shadow-sm: 0 1px 3px rgba(0,0,0,0.04), 0 1px 2px rgba(0,0,0,0.02);
|
|
59
|
+
--shadow-md: 0 4px 12px -2px rgba(0,0,0,0.06), 0 2px 4px rgba(0,0,0,0.03);
|
|
60
|
+
--shadow-lg: 0 12px 32px -6px rgba(0,0,0,0.08), 0 4px 8px rgba(0,0,0,0.04);
|
|
61
|
+
|
|
62
|
+
/* ── Topology ── */
|
|
63
|
+
--topology-node-border: light-dark(rgba(0, 0, 0, 0.10), rgba(255, 255, 255, 0.08));
|
|
64
|
+
--topology-node-shadow: 0 2px 6px rgba(0,0,0,0.05), 0 6px 16px rgba(0,0,0,0.04);
|
|
65
|
+
--topology-bg-dots: light-dark(rgba(148, 163, 184, 0.25), #1e2d45);
|
|
66
|
+
|
|
67
|
+
/* Topology edge colors (theme-independent identity colors) */
|
|
68
|
+
--edge-routes-to: #22c55e;
|
|
69
|
+
--edge-exposes: #3b82f6;
|
|
70
|
+
--edge-manages: #64748b;
|
|
71
|
+
--edge-configures: #f59e0b;
|
|
72
|
+
--edge-uses: #ec4899;
|
|
73
|
+
|
|
74
|
+
/* ── Group styling ── */
|
|
75
|
+
--group-border-namespace: light-dark(rgba(59, 130, 246, 0.3), rgba(59, 130, 246, 0.4));
|
|
76
|
+
--group-border-app: light-dark(rgba(16, 185, 129, 0.3), rgba(16, 185, 129, 0.4));
|
|
77
|
+
--group-border-label: light-dark(rgba(245, 158, 11, 0.3), rgba(245, 158, 11, 0.4));
|
|
78
|
+
|
|
79
|
+
--group-header-namespace: light-dark(rgba(59, 130, 246, 0.15), rgba(59, 130, 246, 0.2));
|
|
80
|
+
--group-header-app: light-dark(rgba(16, 185, 129, 0.15), rgba(16, 185, 129, 0.2));
|
|
81
|
+
--group-header-label: light-dark(rgba(245, 158, 11, 0.15), rgba(245, 158, 11, 0.2));
|
|
82
|
+
|
|
83
|
+
--group-label-namespace: light-dark(#1d4ed8, #93c5fd);
|
|
84
|
+
--group-label-app: light-dark(#047857, #6ee7b7);
|
|
85
|
+
--group-label-label: light-dark(#b45309, #fcd34d);
|
|
86
|
+
|
|
87
|
+
--group-icon-namespace: light-dark(#2563eb, #60a5fa);
|
|
88
|
+
--group-icon-app: light-dark(#059669, #34d399);
|
|
89
|
+
--group-icon-label: light-dark(#d97706, #fbbf24);
|
|
90
|
+
|
|
91
|
+
/* ── ANSI terminal colors (theme-aware for log viewer) ── */
|
|
92
|
+
--ansi-black: light-dark(#3b3b3b, #4c4c4c);
|
|
93
|
+
--ansi-red: light-dark(#cd3131, #cd3131);
|
|
94
|
+
--ansi-green: light-dark(#00a854, #0dbc79);
|
|
95
|
+
--ansi-yellow: light-dark(#b8860b, #e5e510);
|
|
96
|
+
--ansi-blue: light-dark(#2472c8, #2472c8);
|
|
97
|
+
--ansi-magenta: light-dark(#bc3fbc, #bc3fbc);
|
|
98
|
+
--ansi-cyan: light-dark(#11a8cd, #11a8cd);
|
|
99
|
+
--ansi-white: light-dark(#e5e5e5, #e5e5e5);
|
|
100
|
+
--ansi-bright-black: light-dark(#555555, #767676);
|
|
101
|
+
--ansi-bright-red: light-dark(#f14c4c, #f14c4c);
|
|
102
|
+
--ansi-bright-green: light-dark(#17b96a, #23d18b);
|
|
103
|
+
--ansi-bright-yellow: light-dark(#c49700, #f5f543);
|
|
104
|
+
--ansi-bright-blue: light-dark(#3b8eea, #3b8eea);
|
|
105
|
+
--ansi-bright-magenta: light-dark(#d670d6, #d670d6);
|
|
106
|
+
--ansi-bright-cyan: light-dark(#29b8db, #29b8db);
|
|
107
|
+
--ansi-bright-white: light-dark(#e5e5e5, #e5e5e5);
|
|
108
|
+
|
|
109
|
+
/* ── Scrollbar ── */
|
|
110
|
+
--scrollbar-track: light-dark(#f1f5f9, #162033);
|
|
111
|
+
--scrollbar-thumb: light-dark(#cbd5e1, #2a3d58);
|
|
112
|
+
--scrollbar-thumb-hover: light-dark(#94a3b8, #3d5474);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Dark overrides for comma-separated values that can't use light-dark() */
|
|
116
|
+
.dark {
|
|
117
|
+
--shadow-sm: 0 1px 3px rgba(0,0,0,0.2), 0 1px 2px rgba(0,0,0,0.1);
|
|
118
|
+
--shadow-md: 0 4px 12px -2px rgba(0,0,0,0.25), 0 2px 4px rgba(0,0,0,0.1);
|
|
119
|
+
--shadow-lg: 0 12px 32px -6px rgba(0,0,0,0.3), 0 4px 8px rgba(0,0,0,0.1);
|
|
120
|
+
--topology-node-shadow: 0 2px 6px rgba(0,0,0,0.2), 0 6px 16px rgba(0,0,0,0.15);
|
|
121
|
+
}
|
package/src/types/core.ts
CHANGED
|
@@ -25,11 +25,13 @@ export interface ResourcePermissions {
|
|
|
25
25
|
// Feature capabilities based on RBAC permissions
|
|
26
26
|
export interface Capabilities {
|
|
27
27
|
exec: boolean // Terminal feature (pods/exec)
|
|
28
|
+
localTerminal: boolean // Local terminal available (not in-cluster, not disabled)
|
|
28
29
|
logs: boolean // Log viewer (pods/log)
|
|
29
30
|
portForward: boolean // Port forwarding (pods/portforward)
|
|
30
31
|
secrets: boolean // List secrets
|
|
31
32
|
secretsUpdate: boolean // Update secrets (inline editing)
|
|
32
33
|
helmWrite: boolean // Helm write operations (install, upgrade, rollback, uninstall, apply values)
|
|
34
|
+
nodeWrite: boolean // Node write operations (cordon, uncordon, drain)
|
|
33
35
|
mcpEnabled: boolean // MCP server is running
|
|
34
36
|
resources?: ResourcePermissions // Per-resource-type permissions
|
|
35
37
|
}
|
|
@@ -95,6 +97,7 @@ export type CoreNodeKind =
|
|
|
95
97
|
| 'ServersTransportTCP' // Traefik ServersTransportTCP
|
|
96
98
|
| 'TLSOption' // Traefik TLSOption
|
|
97
99
|
| 'TLSStore' // Traefik TLSStore
|
|
100
|
+
| 'HTTPProxy' // Contour HTTPProxy
|
|
98
101
|
|
|
99
102
|
// NodeKind can be a core kind or any arbitrary CRD kind string
|
|
100
103
|
export type NodeKind = CoreNodeKind | (string & {})
|
|
@@ -328,6 +331,14 @@ export interface SelectedResource {
|
|
|
328
331
|
group?: string // API group for CRDs (e.g., 'metrics.k8s.io')
|
|
329
332
|
}
|
|
330
333
|
|
|
334
|
+
// Resolved envFrom ConfigMap/Secret data for pod env var expansion
|
|
335
|
+
export interface ResolvedEnvFromEntry {
|
|
336
|
+
keys: string[]
|
|
337
|
+
values: Record<string, string>
|
|
338
|
+
isSecret: boolean
|
|
339
|
+
}
|
|
340
|
+
export type ResolvedEnvFrom = Record<string, ResolvedEnvFromEntry>
|
|
341
|
+
|
|
331
342
|
// Resource reference (for relationships)
|
|
332
343
|
export interface ResourceRef {
|
|
333
344
|
kind: string
|
|
@@ -744,6 +755,7 @@ export interface TrafficHelmChartInfo {
|
|
|
744
755
|
repoUrl: string
|
|
745
756
|
chartName: string
|
|
746
757
|
version?: string
|
|
758
|
+
defaultValues?: Record<string, unknown>
|
|
747
759
|
}
|
|
748
760
|
|
|
749
761
|
// Recommendation for installing a traffic source
|
package/src/utils/animation.ts
CHANGED
|
@@ -18,7 +18,7 @@ export const CSS_EASE = 'cubic-bezier(0.32, 0.72, 0, 1)'
|
|
|
18
18
|
/** Standard UI transitions: overlays, panels, toasts */
|
|
19
19
|
export const DURATION_NORMAL = 300
|
|
20
20
|
/** Dock height, subtle layout shifts */
|
|
21
|
-
export const DURATION_DOCK =
|
|
21
|
+
export const DURATION_DOCK = 150
|
|
22
22
|
/** Toast exit animation */
|
|
23
23
|
export const DURATION_TOAST_EXIT = 200
|
|
24
24
|
|