Files
headquarter/apps/web/src/components/icon.tsx
T
Fusion e344e961d6 feat: implement web terminal for tool instances
- Add TerminalSession backend service for docker exec subprocess management
- Add TerminalManager for WebSocket session lifecycle management
- Create WebSocket endpoint at /ws/tool-instances/{id}/terminal
- Add session cookie authentication and instance ownership verification
- Install xterm.js with fit and web-links addons
- Create TerminalComponent with xterm.js integration
- Create TerminalPage with full-screen terminal view
- Add terminal route at /instances/:id/terminal
- Add terminal button to InstanceList for running instances
- Add terminal and arrow-left icons to icon registry
- Add comprehensive terminal CSS styles (dark theme, responsive)

Quality gates: typecheck ✓, lint ✓, build ✓, Python syntax ✓
2026-05-19 21:11:29 +02:00

166 lines
2.7 KiB
TypeScript

import React from "react";
import {
House,
Folder,
GitBranch,
Gear,
User,
SignOut,
Plus,
PencilSimple,
Trash,
FloppyDisk,
X,
ArrowsClockwise,
Copy,
MagnifyingGlass,
List,
Check,
Warning,
Info,
Spinner,
GitCommit,
GitMerge,
ClockCounterClockwise,
ArrowDown,
ArrowUp,
File,
FileText,
Image,
Binary,
Code,
ArrowSquareOut,
Play,
Stop,
Terminal,
ArrowLeft,
} from "@phosphor-icons/react";
export type IconName =
| "dashboard"
| "projects"
| "repositories"
| "settings"
| "profile"
| "logout"
| "add"
| "edit"
| "delete"
| "save"
| "cancel"
| "refresh"
| "copy"
| "search"
| "menu"
| "close"
| "success"
| "error"
| "warning"
| "info"
| "loading"
| "branch"
| "commit"
| "merge"
| "history"
| "pull"
| "push"
| "fetch"
| "file"
| "folder"
| "code"
| "document"
| "image"
| "binary"
| "external"
| "play"
| "stop"
| "terminal"
| "arrow-left";
const iconMap: Record<IconName, React.ComponentType<{ size?: number | string; weight?: "thin" | "light" | "regular" | "bold" | "fill" | "duotone" }>> = {
dashboard: House,
projects: Folder,
repositories: GitBranch,
settings: Gear,
profile: User,
logout: SignOut,
add: Plus,
edit: PencilSimple,
delete: Trash,
save: FloppyDisk,
cancel: X,
refresh: ArrowsClockwise,
copy: Copy,
search: MagnifyingGlass,
menu: List,
close: X,
success: Check,
error: X,
warning: Warning,
info: Info,
loading: Spinner,
branch: GitBranch,
commit: GitCommit,
merge: GitMerge,
history: ClockCounterClockwise,
pull: ArrowDown,
push: ArrowUp,
fetch: ArrowsClockwise,
file: File,
folder: Folder,
code: Code,
document: FileText,
image: Image,
binary: Binary,
external: ArrowSquareOut,
play: Play,
stop: Stop,
terminal: Terminal,
"arrow-left": ArrowLeft,
};
export interface IconProps {
name: IconName;
size?: "sm" | "md" | "lg" | "xl";
color?: string;
weight?: "thin" | "light" | "regular" | "bold" | "fill" | "duotone";
className?: string;
ariaLabel?: string;
}
const sizeMap: Record<NonNullable<IconProps["size"]>, number> = {
sm: 16,
md: 20,
lg: 24,
xl: 32,
};
export const Icon: React.FC<IconProps> = ({
name,
size = "md",
color,
weight = "regular",
className,
ariaLabel,
}) => {
const IconComponent = iconMap[name];
const sizeValue = sizeMap[size];
if (!IconComponent) {
console.warn(`Icon "${name}" not found`);
return null;
}
return (
<span
className={`icon icon-${size}${className ? ` ${className}` : ""}`}
style={{ color }}
aria-label={ariaLabel}
aria-hidden={!ariaLabel}
role="img"
>
<IconComponent size={sizeValue} weight={weight} />
</span>
);
};