1.0 - has search, pulse
Build and Publish Docker Image / Build and Push Docker Image (push) Successful in 1m24s Details

This commit is contained in:
Isaac Johnson 2026-08-01 20:43:09 -05:00
parent 7f3fcd4b50
commit 6d2a5f1a8a
7 changed files with 96 additions and 15 deletions

View File

@ -2,5 +2,5 @@ apiVersion: v2
name: k8s-pulse
description: A Helm chart for k8s-pulse, a Kubernetes cluster resource visualizer.
type: application
version: 0.1.1
appVersion: "1.0.8"
version: 0.1.2
appVersion: "1.1.0"

View File

@ -44,14 +44,18 @@ spec:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 10
periodSeconds: 10
initialDelaySeconds: 15
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 5
readinessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 5
periodSeconds: 10
initialDelaySeconds: 10
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 5
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- if or .Values.persistence.enabled .Values.kubeconfig.enabled }}

View File

@ -65,11 +65,11 @@ ingress:
resources:
limits:
cpu: 200m
memory: 256Mi
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
cpu: 250m
memory: 256Mi
persistence:
enabled: false

View File

@ -151,6 +151,8 @@ let hoveredPod = null;
let maxCpuInCluster = 1;
let maxMemInCluster = 1;
let autoRotateEnabled = false;
let currentSearchTerm = '';
const searchHighlightColor = new THREE.Color(0xffffff);
// Formatters
const formatBytes = (bytes) => {
@ -199,6 +201,39 @@ document.getElementById('btn-auto-rotate').addEventListener('click', () => {
}
});
document.getElementById('pod-search').addEventListener('input', (e) => {
currentSearchTerm = e.target.value.toLowerCase().trim();
podMeshes.forEach(mesh => {
if (mesh !== hoveredPod) {
applySearchStyle(mesh);
}
});
});
function applySearchStyle(mesh) {
mesh.isSearchHighlighted = false;
if (mesh.userData.type === 'unused') {
mesh.material.emissive.setHex(mesh.originalEmissive);
mesh.material.emissiveIntensity = mesh.originalEmissiveIntensity;
return;
}
if (!currentSearchTerm) {
mesh.material.emissive.setHex(mesh.originalEmissive);
mesh.material.emissiveIntensity = mesh.originalEmissiveIntensity;
return;
}
const podName = (mesh.userData.name || '').toLowerCase();
if (podName.includes(currentSearchTerm)) {
mesh.isSearchHighlighted = true;
} else {
mesh.material.emissive.setHex(mesh.originalEmissive);
mesh.material.emissiveIntensity = 0.05;
}
}
document.getElementById('theme-select').addEventListener('change', (e) => {
const theme = e.target.value;
currentTheme = theme;
@ -603,8 +638,11 @@ function build3DCluster(data) {
podMesh.baseCenterZ = centerZ;
podMesh.originalColor = color;
podMesh.originalEmissive = emissive;
podMesh.originalEmissiveColor = new THREE.Color(emissive);
podMesh.originalEmissiveIntensity = p.data.type === 'unused' ? 0.05 : 0.25;
applySearchStyle(podMesh);
scene.add(podMesh);
podMeshes.push(podMesh);
});
@ -637,6 +675,9 @@ function updatePodHeights() {
function animate() {
requestAnimationFrame(animate);
const time = performance.now();
const pulseFactor = (Math.sin(time * 0.005) + 1) / 2;
// Smoothly interpolate pod tower heights (lerp)
podMeshes.forEach(mesh => {
if (Math.abs(mesh.currentHeight - mesh.targetHeight) > 0.01) {
@ -645,6 +686,13 @@ function animate() {
// Keep tower base resting on the node platform at y = 1.5
mesh.position.y = 1.5 + mesh.currentHeight / 2;
}
if (mesh.isSearchHighlighted && mesh !== hoveredPod) {
if (mesh.originalEmissiveColor) {
mesh.material.emissive.copy(mesh.originalEmissiveColor).lerp(searchHighlightColor, pulseFactor);
}
mesh.material.emissiveIntensity = mesh.originalEmissiveIntensity + (0.8 - mesh.originalEmissiveIntensity) * pulseFactor;
}
});
controls.update();
@ -674,8 +722,7 @@ function onPointerMove(event) {
if (hoveredPod !== hitMesh) {
// Reset previous hovered pod
if (hoveredPod && hoveredPod.userData && hoveredPod.userData.type !== 'node' && hoveredPod.material && hoveredPod.material.emissive) {
hoveredPod.material.emissive.setHex(hoveredPod.originalEmissive);
hoveredPod.material.emissiveIntensity = hoveredPod.originalEmissiveIntensity;
applySearchStyle(hoveredPod);
}
hoveredPod = hitMesh;
@ -781,8 +828,7 @@ function onPointerMove(event) {
container.style.cursor = 'grab';
if (hoveredPod) {
if (hoveredPod.userData && hoveredPod.userData.type !== 'node' && hoveredPod.material && hoveredPod.material.emissive) {
hoveredPod.material.emissive.setHex(hoveredPod.originalEmissive);
hoveredPod.material.emissiveIntensity = hoveredPod.originalEmissiveIntensity;
applySearchStyle(hoveredPod);
}
hoveredPod = null;
}

View File

@ -185,6 +185,34 @@ body {
gap: 1rem;
}
.search-container {
display: flex;
align-items: center;
}
.search-input {
background: rgba(15, 23, 42, 0.6);
color: var(--text-main);
border: 1px solid var(--glass-border);
padding: 0.5rem 1rem;
font-size: 0.875rem;
font-weight: 500;
border-radius: 0.5rem;
outline: none;
transition: all 0.2s ease;
width: 220px;
}
.search-input:focus {
background: rgba(30, 41, 59, 0.9);
border-color: var(--accent);
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.3);
}
.search-input::placeholder {
color: var(--text-muted);
}
.toggle-container {
display: flex;
background: rgba(15, 23, 42, 0.6);

View File

@ -22,6 +22,9 @@
<h1>K8s Pulse <span class="badge-3d">3D</span></h1>
</div>
<div class="controls">
<div class="search-container">
<input type="text" id="pod-search" class="search-input glass-panel" placeholder="Search Pods..." autocomplete="off">
</div>
<div class="toggle-container">
<button class="toggle-btn active" id="btn-cpu">CPU Consumption</button>
<button class="toggle-btn" id="btn-mem">Memory Consumption</button>

View File

@ -1,2 +1,2 @@
[metadata]
version = 0.9
version = 1.0