/**
* PermissionDialog Component
*
* Shows permission confirmation dialogs for bash commands, file operations, etc.
* Integrates with WebSocket for real-time permission requests from the server.
*/
import { useState } from 'react';
import {
Shield,
Terminal,
FileEdit,
GitBranch,
Globe,
X,
Check,
AlertTriangle,
} from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { cn } from '../utils/cn';
import { modalOverlay, modalContent, smoothTransition } from '../utils/animations';
import { Button } from '../primitives/Button';
// Permission types
export type PermissionType = 'bash' | 'file' | 'git' | 'web';
// Permission request context
export interface PermissionRequestContext {
command?: string;
operation?: string;
path?: string;
gitOperation?: string;
query?: string;
patterns?: string[];
externalPaths?: string[];
}
// Diff line for file operations
interface DiffLine {
type: 'add' | 'remove' | 'context';
lineNumber: number | null;
content: string;
}
// Diff hunk
interface DiffHunk {
oldStart: number;
oldCount: number;
newStart: number;
newCount: number;
lines: DiffLine[];
}
// Diff info for file operations
export interface DiffInfo {
isNew: boolean;
additions: number;
deletions: number;
hunks: DiffHunk[];
}
// Permission request payload
export interface PermissionRequest {
requestId: string;
permissionType: PermissionType;
context: PermissionRequestContext;
diff?: DiffInfo;
}
interface PermissionDialogProps {
request: PermissionRequest;
onAllow: (requestId: string, remember: boolean) => void;
onDeny: (requestId: string, remember: boolean) => void;
responsive?: boolean;
}
// Icon component based on permission type
function getPermissionIcon(type: PermissionType) {
switch (type) {
case 'bash':
return
{diff.hunks.map((hunk, hunkIndex) => (
@@ -{hunk.oldStart},{hunk.oldCount} +{hunk.newStart},{hunk.newCount} @@
{hunk.lines.map((line, lineIndex) => {
let className = 'px-3 py-0.5 ';
let prefix = ' ';
if (line.type === 'add') {
className += 'bg-green-500/10 text-green-400';
prefix = '+';
} else if (line.type === 'remove') {
className += 'bg-red-500/10 text-red-400';
prefix = '-';
} else {
className += 'text-fg-muted';
}
return (
{prefix}
{line.content}
);
})}
))}
{context.command}
{context.externalPaths && context.externalPaths.length > 0 && (
{context.path}
{diff &&
{context.command}
>
)}
{context.query || context.command}
{JSON.stringify(context, null, 2)}
AI is requesting permission