Add fleet ops dashboard, Calibrate enforcement, and dead-code cleanup.

Ship live alerts, pool status, AI monitor, remote agent commands, build manager, and uninstall flow; wire Calibrate settings (WS ping, pool traffic log, retention limits) at runtime and exclude server/data from git.
This commit is contained in:
drjones
2026-05-27 09:16:04 -07:00
parent 9d223b8137
commit df81eb7744
75 changed files with 8891 additions and 966 deletions

View File

@@ -0,0 +1,137 @@
import { Link } from 'react-router-dom';
import NeonCard from '../NeonCard/NeonCard';
import {
FORGE_VS_CALIBRATE,
PIPELINE_STEPS,
ROADMAP_FEATURES,
} from '../../help/cheatSheetContent';
import './VisualComponents.css';
interface PipelineFlowProps {
activeStep?: string;
compact?: boolean;
}
export function PipelineFlow({ activeStep, compact }: PipelineFlowProps) {
return (
<div className={`pipeline-flow ${compact ? 'pipeline-compact' : ''}`}>
{PIPELINE_STEPS.map((step, i) => (
<div key={step.id} className="pipeline-step-wrap">
<div className={`pipeline-step ${activeStep === step.id ? 'pipeline-active' : ''}`}>
<div className="pipeline-icon">{step.icon}</div>
<div className="pipeline-text">
<strong>{step.title}</strong>
<span>{step.subtitle}</span>
</div>
</div>
{i < PIPELINE_STEPS.length - 1 && <div className="pipeline-connector" aria-hidden />}
</div>
))}
</div>
);
}
interface FleetPipelineStatusProps {
hasBuilds: boolean;
agentCount: number;
onlineCount: number;
hasHashrate: boolean;
hasShares: boolean;
}
export function FleetPipelineStatus({
hasBuilds,
agentCount,
onlineCount,
hasHashrate,
hasShares,
}: FleetPipelineStatusProps) {
const steps = [
{ id: 'forge', label: 'Forged', ok: hasBuilds, hint: 'At least one build exists' },
{ id: 'deploy', label: 'Deployed', ok: agentCount > 0, hint: 'Agent registered on dashboard' },
{ id: 'connect', label: 'Online', ok: onlineCount > 0, hint: `${onlineCount} node(s) live` },
{ id: 'mine', label: 'Hashing', ok: hasHashrate, hint: 'Fleet hashrate > 0' },
{ id: 'shares', label: 'Shares', ok: hasShares, hint: 'Shares submitted to pool' },
];
return (
<div className="fleet-pipeline-status">
{steps.map((s, i) => (
<div key={s.id} className="fleet-pipeline-item">
<div className={`fleet-pipeline-node ${s.ok ? 'ok' : 'pending'}`} title={s.hint}>
<span className="fleet-pipeline-dot" />
<span className="fleet-pipeline-label font-tech">{s.label}</span>
</div>
{i < steps.length - 1 && <div className={`fleet-pipeline-line ${s.ok ? 'lit' : ''}`} />}
</div>
))}
</div>
);
}
interface ActivityPulseProps {
items: { id: string; label: string; ok: boolean; time?: string }[];
}
export function ActivityPulse({ items }: ActivityPulseProps) {
if (items.length === 0) {
return <p className="activity-empty font-tech">Awaiting fleet activity</p>;
}
return (
<div className="activity-pulse">
{items.slice(0, 12).map((item) => (
<div key={item.id} className={`activity-blip ${item.ok ? 'ok' : 'bad'}`} title={item.time || item.label}>
<span className="activity-blip-core" />
<span className="activity-blip-label">{item.label}</span>
</div>
))}
</div>
);
}
interface ForgeCalibrateCompareProps {
compact?: boolean;
}
export function ForgeCalibrateCompare({ compact }: ForgeCalibrateCompareProps) {
return (
<div className={`compare-grid ${compact ? 'compare-compact' : ''}`}>
<NeonCard accent="cyan" className="compare-card">
<h4>{FORGE_VS_CALIBRATE.forge.title}</h4>
<ul>
{FORGE_VS_CALIBRATE.forge.items.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
{!compact && (
<Link to="/forge" className="btn btn-outline btn-sm">Go to Forge</Link>
)}
</NeonCard>
<NeonCard accent="amber" className="compare-card">
<h4>{FORGE_VS_CALIBRATE.calibrate.title}</h4>
<ul>
{FORGE_VS_CALIBRATE.calibrate.items.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
{!compact && (
<Link to="/settings" className="btn btn-outline btn-sm">Go to Calibrate</Link>
)}
</NeonCard>
</div>
);
}
export function RoadmapGrid() {
return (
<div className="roadmap-grid">
{ROADMAP_FEATURES.map((f) => (
<div key={f.title} className={`roadmap-card roadmap-${f.priority}`}>
<span className={`roadmap-priority font-tech`}>{f.priority}</span>
<h4>{f.title}</h4>
<p>{f.desc}</p>
</div>
))}
</div>
);
}