clusev/app/Livewire/Terminal/Index.php

67 lines
2.0 KiB
PHP

<?php
namespace App\Livewire\Terminal;
use App\Models\Server;
use App\Models\TerminalSession;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Livewire\Attributes\Layout;
use Livewire\Component;
/**
* Terminal page. Lists the targets (the Clusev host + each server) and, on selection, mints a
* single-use session token that the xterm.js island uses to open a WebSocket to the terminal
* sidecar. The component itself never touches the SSH connection or credentials — it only authorizes
* the operator and hands out a short-lived token (resolved server-side over the internal network).
*/
#[Layout('layouts.app')]
class Index extends Component
{
/** 'host' or a server uuid — drives the active-target highlight in the rail. */
public string $activeKey = '';
public function title(): string
{
return __('terminal.title');
}
/** Mint a single-use token for the chosen target and hand it to the xterm island via an event. */
public function open(string $kind, ?string $uuid = null): void
{
$serverId = null;
$label = __('terminal.host_label');
$this->activeKey = 'host';
if ($kind !== 'host') {
$kind = 'server';
$server = Server::where('uuid', $uuid)->first();
if ($server === null) {
return;
}
$serverId = $server->id;
$label = $server->name;
$this->activeKey = $server->uuid;
}
$token = Str::random(48);
TerminalSession::create([
'token' => $token,
'user_id' => Auth::id(),
'kind' => $kind,
'server_id' => $serverId,
'expires_at' => now()->addSeconds(60),
'created_at' => now(),
]);
$this->dispatch('terminal-open', token: $token, title: $label);
}
public function render()
{
return view('livewire.terminal.index', [
'servers' => Server::orderBy('name')->get(['uuid', 'name', 'status']),
])->title($this->title());
}
}