feat(devices): adiciona modais de confirmacao e deteccao em tempo real
All checks were successful
All checks were successful
- Adiciona modais de confirmacao para resetar e desativar dispositivos - Cria query getMachineState no Convex para monitoramento em tempo real - Implementa MachineStateMonitor no desktop para detectar mudancas - Desktop redireciona para tela de registro apos reset - Desktop mostra tela de desativacao imediatamente apos bloqueio 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
cd3305f1e3
commit
0bfe4edc6c
4 changed files with 263 additions and 2 deletions
|
|
@ -3275,6 +3275,8 @@ export function DeviceDetails({ device }: DeviceDetailsProps) {
|
|||
)
|
||||
const [togglingActive, setTogglingActive] = useState(false)
|
||||
const [isResettingAgent, setIsResettingAgent] = useState(false)
|
||||
const [resetConfirmOpen, setResetConfirmOpen] = useState(false)
|
||||
const [deactivateConfirmOpen, setDeactivateConfirmOpen] = useState(false)
|
||||
const [showAllWindowsSoftware, setShowAllWindowsSoftware] = useState(false)
|
||||
const [isUsbModalOpen, setIsUsbModalOpen] = useState(false)
|
||||
const jsonText = useMemo(() => {
|
||||
|
|
@ -4001,7 +4003,7 @@ export function DeviceDetails({ device }: DeviceDetailsProps) {
|
|||
size="sm"
|
||||
variant="outline"
|
||||
className="gap-2 border-dashed"
|
||||
onClick={handleResetAgent}
|
||||
onClick={() => setResetConfirmOpen(true)}
|
||||
disabled={isResettingAgent}
|
||||
>
|
||||
<RefreshCcw className={cn("size-4", isResettingAgent && "animate-spin")} />
|
||||
|
|
@ -4014,7 +4016,7 @@ export function DeviceDetails({ device }: DeviceDetailsProps) {
|
|||
"gap-2 border-dashed",
|
||||
!isActiveLocal && "bg-emerald-600 text-white hover:bg-emerald-600/90"
|
||||
)}
|
||||
onClick={handleToggleActive}
|
||||
onClick={() => isActiveLocal ? setDeactivateConfirmOpen(true) : handleToggleActive()}
|
||||
disabled={togglingActive}
|
||||
>
|
||||
{isActiveLocal ? <Power className="size-4" /> : <PlayCircle className="size-4" />}
|
||||
|
|
@ -5970,6 +5972,80 @@ export function DeviceDetails({ device }: DeviceDetailsProps) {
|
|||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Modal de confirmação - Resetar */}
|
||||
<Dialog open={resetConfirmOpen} onOpenChange={setResetConfirmOpen}>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2 text-amber-700">
|
||||
<RefreshCcw className="size-5" />
|
||||
Resetar dispositivo
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
Esta ação revogará todos os tokens de acesso do dispositivo.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="rounded-lg border border-amber-200 bg-amber-50 p-4">
|
||||
<p className="text-sm text-amber-700">
|
||||
O dispositivo <span className="font-semibold text-amber-800">{device?.displayName ?? device?.hostname}</span> será desconectado imediatamente e precisará ser reprovisionado para voltar a funcionar.
|
||||
</p>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setResetConfirmOpen(false)} disabled={isResettingAgent}>
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
disabled={isResettingAgent}
|
||||
className="gap-2"
|
||||
onClick={async () => {
|
||||
setResetConfirmOpen(false)
|
||||
await handleResetAgent()
|
||||
}}
|
||||
>
|
||||
<RefreshCcw className={cn("size-4", isResettingAgent && "animate-spin")} />
|
||||
{isResettingAgent ? "Resetando..." : "Resetar"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Modal de confirmação - Desativar */}
|
||||
<Dialog open={deactivateConfirmOpen} onOpenChange={setDeactivateConfirmOpen}>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2 text-rose-700">
|
||||
<Power className="size-5" />
|
||||
Desativar dispositivo
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
O dispositivo será bloqueado e não poderá mais acessar o sistema.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="rounded-lg border border-rose-200 bg-rose-50 p-4">
|
||||
<p className="text-sm text-rose-700">
|
||||
O dispositivo <span className="font-semibold text-rose-800">{device?.displayName ?? device?.hostname}</span> será bloqueado imediatamente. O usuário verá uma tela de desativação e não poderá mais abrir chamados ou usar o chat.
|
||||
</p>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setDeactivateConfirmOpen(false)} disabled={togglingActive}>
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
disabled={togglingActive}
|
||||
className="gap-2"
|
||||
onClick={async () => {
|
||||
setDeactivateConfirmOpen(false)
|
||||
await handleToggleActive()
|
||||
}}
|
||||
>
|
||||
<Power className="size-4" />
|
||||
{togglingActive ? "Desativando..." : "Desativar"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue