148 lines
6.8 KiB
TypeScript
148 lines
6.8 KiB
TypeScript
|
|
import { useState } from 'react'
|
|||
|
|
import { Monitor, Loader2, AlertTriangle, ExternalLink } from 'lucide-react'
|
|||
|
|
import { remoteDesktopApi } from '../api/client'
|
|||
|
|
import type { RemoteSessionInfo } from '../api/types'
|
|||
|
|
import { cn } from '../lib/utils'
|
|||
|
|
|
|||
|
|
interface RemoteDesktopButtonProps {
|
|||
|
|
agentId: string
|
|||
|
|
agentHostname: string
|
|||
|
|
className?: string
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function RemoteDesktopButton({ agentId, agentHostname, className }: RemoteDesktopButtonProps) {
|
|||
|
|
const [loading, setLoading] = useState(false)
|
|||
|
|
const [error, setError] = useState<string | null>(null)
|
|||
|
|
const [sessionInfo, setSessionInfo] = useState<RemoteSessionInfo | null>(null)
|
|||
|
|
const [showModal, setShowModal] = useState(false)
|
|||
|
|
|
|||
|
|
async function handleClick() {
|
|||
|
|
setLoading(true)
|
|||
|
|
setError(null)
|
|||
|
|
try {
|
|||
|
|
const info = await remoteDesktopApi.getSession(agentId)
|
|||
|
|
setSessionInfo(info)
|
|||
|
|
setShowModal(true)
|
|||
|
|
} catch (e) {
|
|||
|
|
setError('Remote-Session konnte nicht geladen werden')
|
|||
|
|
} finally {
|
|||
|
|
setLoading(false)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function handleConnect() {
|
|||
|
|
if (sessionInfo?.sessionUrl) {
|
|||
|
|
window.open(sessionInfo.sessionUrl, `rmm-remote-${agentId}`,
|
|||
|
|
'width=1280,height=800,scrollbars=no,toolbar=no,menubar=no')
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<>
|
|||
|
|
<button
|
|||
|
|
onClick={handleClick}
|
|||
|
|
disabled={loading}
|
|||
|
|
className={cn(
|
|||
|
|
'flex items-center gap-2 px-3 py-2 rounded-lg text-sm transition-colors',
|
|||
|
|
'bg-purple-500/20 text-purple-400 border border-purple-500/30 hover:bg-purple-500/30',
|
|||
|
|
loading && 'opacity-50 cursor-not-allowed',
|
|||
|
|
className,
|
|||
|
|
)}
|
|||
|
|
>
|
|||
|
|
{loading ? <Loader2 size={16} className="animate-spin" /> : <Monitor size={16} />}
|
|||
|
|
Remote Desktop
|
|||
|
|
</button>
|
|||
|
|
|
|||
|
|
{/* Modal */}
|
|||
|
|
{showModal && (
|
|||
|
|
<div className="fixed inset-0 bg-black/60 flex items-center justify-center z-50"
|
|||
|
|
onClick={() => setShowModal(false)}>
|
|||
|
|
<div className="bg-card border border-border rounded-xl p-6 w-full max-w-md shadow-2xl"
|
|||
|
|
onClick={e => e.stopPropagation()}>
|
|||
|
|
<div className="flex items-center gap-3 mb-4">
|
|||
|
|
<div className="w-9 h-9 rounded-lg bg-purple-500/20 flex items-center justify-center">
|
|||
|
|
<Monitor size={18} className="text-purple-400" />
|
|||
|
|
</div>
|
|||
|
|
<div>
|
|||
|
|
<h3 className="font-semibold text-foreground">Remote Desktop</h3>
|
|||
|
|
<p className="text-xs text-muted-foreground">{agentHostname}</p>
|
|||
|
|
</div>
|
|||
|
|
<button onClick={() => setShowModal(false)}
|
|||
|
|
className="ml-auto text-muted-foreground hover:text-foreground text-lg leading-none">×</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Status: nicht konfiguriert */}
|
|||
|
|
{sessionInfo && !sessionInfo.configured && (
|
|||
|
|
<div className="space-y-3">
|
|||
|
|
<div className="flex items-start gap-2 p-3 bg-yellow-500/10 border border-yellow-500/30 rounded-lg">
|
|||
|
|
<AlertTriangle size={16} className="text-yellow-400 mt-0.5 flex-shrink-0" />
|
|||
|
|
<p className="text-sm text-yellow-300">{sessionInfo.message}</p>
|
|||
|
|
</div>
|
|||
|
|
<p className="text-sm text-muted-foreground">
|
|||
|
|
MeshCentral läuft unter{' '}
|
|||
|
|
<a href={sessionInfo.setupUrl} target="_blank" rel="noopener noreferrer"
|
|||
|
|
className="text-primary hover:underline">{sessionInfo.setupUrl}</a>.
|
|||
|
|
Richte MeshCentral ein und setze <code className="text-xs bg-muted px-1 rounded">MeshCentral:Enabled=true</code> in der appsettings.json.
|
|||
|
|
</p>
|
|||
|
|
<button onClick={() => window.open(sessionInfo.setupUrl, '_blank')}
|
|||
|
|
className="flex items-center gap-2 w-full justify-center px-4 py-2 bg-yellow-500/20 text-yellow-400 border border-yellow-500/30 rounded-lg text-sm hover:bg-yellow-500/30">
|
|||
|
|
<ExternalLink size={14} />
|
|||
|
|
MeshCentral öffnen
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{/* Status: Agent nicht installiert */}
|
|||
|
|
{sessionInfo?.configured && !sessionInfo.agentInstalled && (
|
|||
|
|
<div className="space-y-3">
|
|||
|
|
<div className="flex items-start gap-2 p-3 bg-orange-500/10 border border-orange-500/30 rounded-lg">
|
|||
|
|
<AlertTriangle size={16} className="text-orange-400 mt-0.5 flex-shrink-0" />
|
|||
|
|
<p className="text-sm text-orange-300">{sessionInfo.message}</p>
|
|||
|
|
</div>
|
|||
|
|
<p className="text-sm text-muted-foreground">
|
|||
|
|
Der NexusRMM-Agent installiert MeshAgent automatisch wenn{' '}
|
|||
|
|
<code className="text-xs bg-muted px-1 rounded">mesh_enabled: true</code> in der Agent-Config gesetzt ist.
|
|||
|
|
</p>
|
|||
|
|
{sessionInfo.meshAgentDownloadUrl && (
|
|||
|
|
<button onClick={() => window.open(sessionInfo.meshAgentDownloadUrl, '_blank')}
|
|||
|
|
className="flex items-center gap-2 w-full justify-center px-4 py-2 bg-muted border border-border rounded-lg text-sm hover:bg-accent">
|
|||
|
|
<ExternalLink size={14} />
|
|||
|
|
MeshAgent manuell herunterladen
|
|||
|
|
</button>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{/* Status: bereit */}
|
|||
|
|
{sessionInfo?.configured && sessionInfo.agentInstalled && (
|
|||
|
|
<div className="space-y-3">
|
|||
|
|
<div className="p-3 bg-green-500/10 border border-green-500/30 rounded-lg">
|
|||
|
|
<p className="text-sm text-green-400 font-medium">✓ MeshAgent verbunden</p>
|
|||
|
|
<p className="text-xs text-muted-foreground mt-1">Node ID: {sessionInfo.meshNodeId}</p>
|
|||
|
|
</div>
|
|||
|
|
<p className="text-sm text-muted-foreground">
|
|||
|
|
Remote Desktop öffnet sich in einem neuen Fenster. Falls du nach einem Login gefragt wirst, melde dich bei MeshCentral an.
|
|||
|
|
</p>
|
|||
|
|
<button onClick={handleConnect}
|
|||
|
|
className="flex items-center gap-2 w-full justify-center px-4 py-2 bg-purple-500/20 text-purple-400 border border-purple-500/30 rounded-lg text-sm hover:bg-purple-500/30">
|
|||
|
|
<Monitor size={14} />
|
|||
|
|
Remote Desktop öffnen
|
|||
|
|
</button>
|
|||
|
|
<button onClick={() => window.open(sessionInfo.meshCentralBaseUrl, '_blank')}
|
|||
|
|
className="flex items-center gap-2 w-full justify-center px-4 py-2 bg-muted border border-border rounded-lg text-sm hover:bg-accent text-xs">
|
|||
|
|
<ExternalLink size={12} />
|
|||
|
|
MeshCentral Dashboard
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{error && (
|
|||
|
|
<p className="text-sm text-red-400 mt-2">{error}</p>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</>
|
|||
|
|
)
|
|||
|
|
}
|