wuhp commited on
Commit
8944206
·
verified ·
1 Parent(s): 725f419

Update src/App.tsx

Browse files
Files changed (1) hide show
  1. src/App.tsx +81 -6
src/App.tsx CHANGED
@@ -10,7 +10,8 @@ import {
10
  Play,
11
  Wifi,
12
  Cpu,
13
- Folder
 
14
  } from 'lucide-react';
15
  import { cn } from './lib/utils';
16
 
@@ -455,6 +456,59 @@ function DeployTab() {
455
  );
456
  }
457
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
  function CommandsTab({ category }: { category: 'network' | 'system' | 'file' }) {
459
  // Use state strictly tied to the category if possible, but shared state is fine.
460
  // When category changes, reset command to default of that category.
@@ -492,15 +546,17 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
492
  }, []);
493
 
494
  const requiresTarget = command === 'fetch_http_test' || command === 'socket_tcp_probe';
495
- const requiresHost = command === 'dns_resolve' || command === 'icmp_ping' || command === 'traceroute' || command === 'port_scan' || command === 'dns_mx_records';
496
  const requiresPorts = command === 'port_scan';
497
  const requiresInterval = command === 'change_poll_interval';
498
  const requiresShell = command === 'exec_shell';
499
- const requiresPath = command === 'list_directory' || command === 'read_file' || command === 'delete_file' || command === 'write_file' || command === 'run_file';
 
500
  const requiresContent = command === 'write_file';
501
  const requiresPid = command === 'kill_process';
502
 
503
  const [fileContent, setFileContent] = useState('echo hello');
 
504
 
505
  const issueCommand = async () => {
506
  let payload: any = {};
@@ -510,6 +566,7 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
510
  if (requiresInterval) payload = { interval: parseInt(interval) || 10 };
511
  if (requiresShell) payload = { cmd: shellCmd };
512
  if (requiresPath) payload = { path: filePath };
 
513
  if (requiresContent) payload = { ...payload, content: fileContent };
514
  if (requiresPid) payload = { pid: shellCmd }; // reuse shellCmd/input for PID
515
 
@@ -570,6 +627,9 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
570
  <option value="netstat_connections">Netstat Connections</option>
571
  <option value="ifconfig_ip">Network Interfaces (ifconfig/ipconfig)</option>
572
  <option value="dns_mx_records">DNS MX Records</option>
 
 
 
573
  </optgroup>
574
  )}
575
  {category === 'system' && (
@@ -585,6 +645,8 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
585
  <option value="get_env_vars">Get Env Vars</option>
586
  <option value="get_users">List Users</option>
587
  <option value="get_groups">List Groups</option>
 
 
588
  <option value="exec_shell">Exec Shell Command</option>
589
  <option value="reboot_system">Reboot System (Warning!)</option>
590
  <option value="self_terminate">Terminate Client Process</option>
@@ -593,8 +655,11 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
593
  {category === 'file' && (
594
  <optgroup label="File Commands">
595
  <option value="list_directory">List Directory</option>
 
596
  <option value="read_file">Read/View File</option>
597
  <option value="write_file">Add/Write File</option>
 
 
598
  <option value="delete_file">Delete File</option>
599
  <option value="run_file">Execute/Run File</option>
600
  </optgroup>
@@ -665,6 +730,18 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
665
  </div>
666
  )}
667
 
 
 
 
 
 
 
 
 
 
 
 
 
668
  {requiresContent && (
669
  <div className="border-t border-white/5 pt-5">
670
  <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">File Content</label>
@@ -728,9 +805,7 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
728
  </span>
729
  </div>
730
  <div className="text-white font-medium mb-1">{report.type || 'Unknown Command'}</div>
731
- <pre className="text-xs text-emerald-400 bg-black/40 p-2 rounded-lg break-words whitespace-pre-wrap font-mono">
732
- {JSON.stringify(report.result, null, 2)}
733
- </pre>
734
  </div>
735
  ))}
736
  </div>
 
10
  Play,
11
  Wifi,
12
  Cpu,
13
+ Folder,
14
+ FileText
15
  } from 'lucide-react';
16
  import { cn } from './lib/utils';
17
 
 
456
  );
457
  }
458
 
459
+ function ReportResultViewer({ report }: { report: any }) {
460
+ if (report.type === 'list_directory' && report.result?.files) {
461
+ return (
462
+ <div className="bg-black/40 rounded-lg p-2 border border-white/5">
463
+ <div className="flex items-center gap-2 mb-2 px-2 pb-2 border-b border-white/10">
464
+ <Folder size={14} className="text-indigo-400" />
465
+ <span className="text-xs font-semibold text-white">Directory Contents</span>
466
+ </div>
467
+ <div className="flex flex-col max-h-64 overflow-y-auto pr-1 nice-scrollbar">
468
+ {report.result.files.map((f: string, i: number) => (
469
+ <div key={i} className="text-xs text-slate-300 py-1.5 px-2 hover:bg-white/5 rounded flex items-center transition-colors">
470
+ <span className="mr-2 text-slate-500">{'>'}</span>
471
+ <span className="truncate">{f}</span>
472
+ </div>
473
+ ))}
474
+ {report.result.files.length === 0 && <span className="text-xs text-slate-500 italic p-2">Empty directory</span>}
475
+ </div>
476
+ </div>
477
+ );
478
+ } else if (report.type === 'get_file_info' && report.result?.info !== undefined) {
479
+ return (
480
+ <div className="bg-black/40 rounded-lg p-3 border border-white/5">
481
+ <div className="flex items-center gap-2 mb-2 pb-2 border-b border-white/10">
482
+ <FileText size={14} className="text-indigo-400" />
483
+ <span className="text-xs font-semibold text-white">File Information</span>
484
+ </div>
485
+ <div className="grid grid-cols-2 gap-2 text-xs">
486
+ <div className="text-slate-400">Size: <span className="text-white font-mono">{report.result.info.size} bytes</span></div>
487
+ <div className="text-slate-400">Mode: <span className="text-white font-mono">{report.result.info.mode}</span></div>
488
+ <div className="text-slate-400">Modified: <span className="text-white">{new Date(report.result.info.mtimeMs || report.result.info.mtime * 1000 || Date.now()).toLocaleString()}</span></div>
489
+ </div>
490
+ </div>
491
+ );
492
+ } else if (report.type === 'read_file' && report.result?.content !== undefined) {
493
+ return (
494
+ <div className="bg-black/40 rounded-lg border border-white/5 overflow-hidden">
495
+ <div className="bg-white/5 px-3 py-2 border-b border-white/10 flex items-center gap-2">
496
+ <FileText size={14} className="text-indigo-400" />
497
+ <span className="text-xs font-semibold text-white">File Output</span>
498
+ </div>
499
+ <pre className="text-xs text-emerald-400 p-3 overflow-x-auto whitespace-pre-wrap font-mono">
500
+ {report.result.content}
501
+ </pre>
502
+ </div>
503
+ );
504
+ }
505
+ return (
506
+ <pre className="text-xs text-emerald-400 bg-black/40 p-2 rounded-lg break-words whitespace-pre-wrap font-mono">
507
+ {JSON.stringify(report.result, null, 2)}
508
+ </pre>
509
+ );
510
+ }
511
+
512
  function CommandsTab({ category }: { category: 'network' | 'system' | 'file' }) {
513
  // Use state strictly tied to the category if possible, but shared state is fine.
514
  // When category changes, reset command to default of that category.
 
546
  }, []);
547
 
548
  const requiresTarget = command === 'fetch_http_test' || command === 'socket_tcp_probe';
549
+ const requiresHost = command === 'dns_resolve' || command === 'icmp_ping' || command === 'traceroute' || command === 'port_scan' || command === 'dns_mx_records' || command === 'dns_txt_records';
550
  const requiresPorts = command === 'port_scan';
551
  const requiresInterval = command === 'change_poll_interval';
552
  const requiresShell = command === 'exec_shell';
553
+ const requiresPath = command === 'list_directory' || command === 'read_file' || command === 'delete_file' || command === 'write_file' || command === 'run_file' || command === 'copy_file' || command === 'move_file' || command === 'get_file_info';
554
+ const requiresDestPath = command === 'copy_file' || command === 'move_file';
555
  const requiresContent = command === 'write_file';
556
  const requiresPid = command === 'kill_process';
557
 
558
  const [fileContent, setFileContent] = useState('echo hello');
559
+ const [destPath, setDestPath] = useState('/tmp/dest');
560
 
561
  const issueCommand = async () => {
562
  let payload: any = {};
 
566
  if (requiresInterval) payload = { interval: parseInt(interval) || 10 };
567
  if (requiresShell) payload = { cmd: shellCmd };
568
  if (requiresPath) payload = { path: filePath };
569
+ if (requiresDestPath) payload = { ...payload, destPath };
570
  if (requiresContent) payload = { ...payload, content: fileContent };
571
  if (requiresPid) payload = { pid: shellCmd }; // reuse shellCmd/input for PID
572
 
 
627
  <option value="netstat_connections">Netstat Connections</option>
628
  <option value="ifconfig_ip">Network Interfaces (ifconfig/ipconfig)</option>
629
  <option value="dns_mx_records">DNS MX Records</option>
630
+ <option value="dns_txt_records">DNS TXT Records</option>
631
+ <option value="route_table">Route Table</option>
632
+ <option value="wifi_networks">List WiFi Networks</option>
633
  </optgroup>
634
  )}
635
  {category === 'system' && (
 
645
  <option value="get_env_vars">Get Env Vars</option>
646
  <option value="get_users">List Users</option>
647
  <option value="get_groups">List Groups</option>
648
+ <option value="system_logs">System Logs (dmesg/syslog)</option>
649
+ <option value="list_services">List Services (systemctl/sc)</option>
650
  <option value="exec_shell">Exec Shell Command</option>
651
  <option value="reboot_system">Reboot System (Warning!)</option>
652
  <option value="self_terminate">Terminate Client Process</option>
 
655
  {category === 'file' && (
656
  <optgroup label="File Commands">
657
  <option value="list_directory">List Directory</option>
658
+ <option value="get_file_info">Get File Info</option>
659
  <option value="read_file">Read/View File</option>
660
  <option value="write_file">Add/Write File</option>
661
+ <option value="copy_file">Copy File</option>
662
+ <option value="move_file">Move/Rename File</option>
663
  <option value="delete_file">Delete File</option>
664
  <option value="run_file">Execute/Run File</option>
665
  </optgroup>
 
730
  </div>
731
  )}
732
 
733
+ {requiresDestPath && (
734
+ <div className="border-t border-white/5 pt-5">
735
+ <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Destination Path</label>
736
+ <input
737
+ type="text"
738
+ value={destPath}
739
+ onChange={e => setDestPath(e.target.value)}
740
+ className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono text-sm shadow-inner"
741
+ />
742
+ </div>
743
+ )}
744
+
745
  {requiresContent && (
746
  <div className="border-t border-white/5 pt-5">
747
  <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">File Content</label>
 
805
  </span>
806
  </div>
807
  <div className="text-white font-medium mb-1">{report.type || 'Unknown Command'}</div>
808
+ <ReportResultViewer report={report} />
 
 
809
  </div>
810
  ))}
811
  </div>