[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
193
components/TrafficDiagram.tsx
Normal file
193
components/TrafficDiagram.tsx
Normal file
@@ -0,0 +1,193 @@
|
||||
import React from 'react';
|
||||
import { PortForwardingType } from '../domain/models';
|
||||
import { AppLogo } from './AppLogo';
|
||||
|
||||
// SVG Icon components from public folder
|
||||
const CloudIcon: React.FC<{ className?: string }> = ({ className }) => (
|
||||
<img src="/cloud.svg" alt="cloud" className={className} />
|
||||
);
|
||||
|
||||
const FirewallIcon: React.FC<{ className?: string }> = ({ className }) => (
|
||||
<img src="/firewall.svg" alt="firewall" className={className} />
|
||||
);
|
||||
|
||||
const ServerIcon: React.FC<{ className?: string }> = ({ className }) => (
|
||||
<img src="/server.svg" alt="server" className={className} />
|
||||
);
|
||||
|
||||
// Animated diagram component for port forwarding visualization
|
||||
interface TrafficDiagramProps {
|
||||
type: PortForwardingType;
|
||||
isAnimating?: boolean;
|
||||
/** Which role to highlight: 'app' | 'ssh-server' | 'target' | undefined (all visible) */
|
||||
highlightRole?: 'app' | 'ssh-server' | 'target';
|
||||
}
|
||||
|
||||
// AppLogo is now imported from ./AppLogo to share accent color theming
|
||||
|
||||
// Animated line component
|
||||
const AnimatedLine: React.FC<{
|
||||
x1: number; y1: number; x2: number; y2: number;
|
||||
isAnimating: boolean;
|
||||
reverse?: boolean;
|
||||
isBlocked?: boolean;
|
||||
}> = ({ x1, y1, x2, y2, isAnimating, reverse = false, isBlocked = false }) => {
|
||||
if (isBlocked) {
|
||||
return <line x1={x1} y1={y1} x2={x2} y2={y2} className="stroke-destructive" strokeWidth="2.5" />;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<line x1={x1} y1={y1} x2={x2} y2={y2} stroke="hsl(var(--border))" strokeWidth="2" strokeDasharray="6 4" />
|
||||
<line
|
||||
x1={x1} y1={y1} x2={x2} y2={y2}
|
||||
className="stroke-primary"
|
||||
strokeWidth="3"
|
||||
strokeDasharray="12 12"
|
||||
strokeLinecap="round"
|
||||
>
|
||||
{isAnimating && (
|
||||
<animate
|
||||
attributeName="stroke-dashoffset"
|
||||
values={reverse ? "0;24" : "24;0"}
|
||||
dur="0.6s"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
)}
|
||||
</line>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const TrafficDiagram: React.FC<TrafficDiagramProps> = ({ type, isAnimating = true, highlightRole }) => {
|
||||
// Helper to determine opacity based on highlight role
|
||||
const getOpacity = (role: 'app' | 'ssh-server' | 'target' | 'firewall') => {
|
||||
if (!highlightRole) return 'opacity-100';
|
||||
if (role === 'firewall') return 'opacity-30'; // Firewall always dimmed when highlighting
|
||||
return role === highlightRole ? 'opacity-100' : 'opacity-30';
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative w-full h-48 flex items-center justify-center overflow-hidden rounded-xl bg-secondary/60 border border-border/50">
|
||||
{/* ========== LOCAL FORWARDING ========== */}
|
||||
{type === 'local' && (
|
||||
<div className="relative w-[300px] max-w-full aspect-[300/170]">
|
||||
{/* App Logo - left (same line as firewall) */}
|
||||
<div className={`absolute left-6 top-5 z-10 transition-opacity duration-300 ${getOpacity('app')}`}>
|
||||
<AppLogo className="h-12 w-12" />
|
||||
</div>
|
||||
|
||||
{/* Firewall - center top (same line as app) */}
|
||||
<div className={`absolute left-1/2 -translate-x-1/2 top-4 z-10 transition-opacity duration-300 ${getOpacity('firewall')}`}>
|
||||
<FirewallIcon className="h-14 w-14" />
|
||||
</div>
|
||||
|
||||
{/* Target servers - right (in red border box) */}
|
||||
<div className={`absolute right-4 top-2 z-10 transition-opacity duration-300 ${getOpacity('target')}`}>
|
||||
<div className="p-2 border-2 border-destructive/60 rounded-lg space-y-2">
|
||||
<ServerIcon className="h-8 w-8" />
|
||||
<ServerIcon className="h-8 w-8" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* SSH Server - bottom center */}
|
||||
<div className={`absolute left-1/2 -translate-x-1/2 bottom-4 z-10 transition-opacity duration-300 ${getOpacity('ssh-server')}`}>
|
||||
<ServerIcon className="h-10 w-10" />
|
||||
</div>
|
||||
|
||||
{/* SVG Lines */}
|
||||
<svg className="absolute inset-0 w-full h-full" viewBox="0 0 300 170" preserveAspectRatio="none" style={{ zIndex: 1 }}>
|
||||
{/* App to Firewall - blocked red line (with gap) */}
|
||||
<AnimatedLine x1={78} y1={44} x2={122} y2={44} isAnimating={false} isBlocked />
|
||||
{/* App to SSH Server - blue animated (with gap) */}
|
||||
<AnimatedLine x1={76} y1={64} x2={126} y2={110} isAnimating={isAnimating} />
|
||||
{/* SSH Server to targets - blue animated (with gap) */}
|
||||
<AnimatedLine x1={174} y1={112} x2={242} y2={28} isAnimating={isAnimating} />
|
||||
<AnimatedLine x1={178} y1={120} x2={242} y2={68} isAnimating={isAnimating} />
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ========== REMOTE FORWARDING ========== */}
|
||||
{type === 'remote' && (
|
||||
<div className="relative w-[300px] max-w-full aspect-[300/170]">
|
||||
{/* Left Server - the remote SSH server where port will be opened */}
|
||||
<div className={`absolute left-6 top-5 z-10 transition-opacity duration-300 ${getOpacity('ssh-server')}`}>
|
||||
<ServerIcon className="h-10 w-10" />
|
||||
</div>
|
||||
|
||||
{/* Firewall - center top */}
|
||||
<div className={`absolute left-1/2 -translate-x-1/2 top-4 z-10 transition-opacity duration-300 ${getOpacity('firewall')}`}>
|
||||
<FirewallIcon className="h-14 w-14" />
|
||||
</div>
|
||||
|
||||
{/* Right Server - the destination where traffic will be forwarded */}
|
||||
<div className={`absolute right-6 top-5 z-10 transition-opacity duration-300 ${getOpacity('target')}`}>
|
||||
<ServerIcon className="h-10 w-10" />
|
||||
</div>
|
||||
|
||||
{/* App Logo - bottom center (Netcatty client) */}
|
||||
<div className={`absolute left-1/2 -translate-x-1/2 bottom-4 z-10 transition-opacity duration-300 ${getOpacity('app')}`}>
|
||||
<AppLogo className="h-12 w-12" />
|
||||
</div>
|
||||
|
||||
{/* SVG Lines */}
|
||||
<svg className="absolute inset-0 w-full h-full" viewBox="0 0 300 170" preserveAspectRatio="none" style={{ zIndex: 1 }}>
|
||||
{/* Left server to Firewall - blocked (with gap) */}
|
||||
<AnimatedLine x1={70} y1={40} x2={122} y2={40} isAnimating={false} isBlocked />
|
||||
{/* Left server to App - blue animated (with gap) */}
|
||||
<AnimatedLine x1={68} y1={58} x2={124} y2={128} isAnimating={isAnimating} />
|
||||
{/* Right server to App - blue animated (with gap) */}
|
||||
<AnimatedLine x1={250} y1={58} x2={176} y2={128} isAnimating={isAnimating} reverse />
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ========== DYNAMIC FORWARDING ========== */}
|
||||
{type === 'dynamic' && (
|
||||
<div className="relative w-[300px] max-w-full aspect-[300/170]">
|
||||
{/* App Logo - left (same line as firewall) */}
|
||||
<div className={`absolute left-6 top-5 z-10 transition-opacity duration-300 ${getOpacity('app')}`}>
|
||||
<AppLogo className="h-12 w-12" />
|
||||
</div>
|
||||
|
||||
{/* Firewall - center top (same line as app) */}
|
||||
<div className={`absolute left-1/2 -translate-x-1/2 top-4 z-10 transition-opacity duration-300 ${getOpacity('firewall')}`}>
|
||||
<FirewallIcon className="h-14 w-14" />
|
||||
</div>
|
||||
|
||||
{/* Cloud targets - right (in red border box) */}
|
||||
<div className={`absolute right-4 top-2 z-10 transition-opacity duration-300 ${getOpacity('target')}`}>
|
||||
<div className="p-2 border-2 border-destructive/60 rounded-lg space-y-1">
|
||||
<CloudIcon className="h-7 w-7" />
|
||||
<CloudIcon className="h-7 w-7" />
|
||||
<CloudIcon className="h-7 w-7" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* SSH Server - bottom center */}
|
||||
<div className={`absolute left-1/2 -translate-x-1/2 bottom-4 z-10 transition-opacity duration-300 ${getOpacity('ssh-server')}`}>
|
||||
<ServerIcon className="h-10 w-10" />
|
||||
</div>
|
||||
|
||||
{/* Cloud target - bottom right */}
|
||||
<div className={`absolute right-8 bottom-6 z-10 transition-opacity duration-300 ${getOpacity('target')}`}>
|
||||
<CloudIcon className="h-8 w-8" />
|
||||
</div>
|
||||
|
||||
{/* SVG Lines */}
|
||||
<svg className="absolute inset-0 w-full h-full" viewBox="0 0 300 170" preserveAspectRatio="none" style={{ zIndex: 1 }}>
|
||||
{/* App to Firewall - blocked (with gap) */}
|
||||
<AnimatedLine x1={78} y1={44} x2={122} y2={44} isAnimating={false} isBlocked />
|
||||
{/* App to SSH Server - blue animated (with gap) */}
|
||||
<AnimatedLine x1={76} y1={64} x2={126} y2={110} isAnimating={isAnimating} />
|
||||
{/* SSH Server to clouds - blue animated (with gap) */}
|
||||
<AnimatedLine x1={174} y1={112} x2={246} y2={26} isAnimating={isAnimating} />
|
||||
<AnimatedLine x1={178} y1={120} x2={246} y2={58} isAnimating={isAnimating} />
|
||||
<AnimatedLine x1={178} y1={128} x2={246} y2={90} isAnimating={isAnimating} />
|
||||
<AnimatedLine x1={174} y1={128} x2={234} y2={130} isAnimating={isAnimating} />
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user