Implementado em: 2026-04-02 Status: Ativo
Resumo
O editor visual de fluxos (FlowBuilder) detecta automaticamente quando o usuário fez modificações não salvas e exibe um dialog customizado ao tentar sair, evitando perda acidental de trabalho.
Como Funciona
Dirty State Tracking
O sistema compara o estado atual dos nodes e edges com um snapshot salvo:
// FlowEditor.tsx
const savedSnapshotRef = useRef<string>("")
const [isDirty, setIsDirty] = useState(false)
// Salva snapshot inicial
useEffect(() => {
savedSnapshotRef.current = JSON.stringify({ nodes: flow.nodes, edges: flow.edges })
}, [])
// Detecta mudanças
useEffect(() => {
const current = JSON.stringify({ nodes, edges })
setIsDirty(current !== savedSnapshotRef.current)
}, [nodes, edges])
// Após salvar, reseta dirty
const handleSave = useCallback(async () => {
await onSave({ nodes, edges })
savedSnapshotRef.current = JSON.stringify({ nodes, edges })
setIsDirty(false)
}, [nodes, edges, onSave])
Indicador Visual no Botão Salvar
| Estado | Aparência | Cor |
|---|---|---|
| Sem alterações | "Salvo" | Azul (#1e7fd4) |
| Com alterações | "Salvar*" + ponto vermelho pulsante | Amarelo (#f59e0b) |
| Salvando | Spinner + "Salvar" | Azul |
Dialog de Confirmação
Exibido via createPortal(dialog, document.body) para renderizar fora do ReactFlow e centralizar na tela.
Trigger: Clicar no botão voltar (seta) quando isDirty === true
Opções:
- "Salvar e sair" — Executa
onSave(), depoisrouter.push("/flow-builder") - "Descartar e sair" — Navega direto sem salvar
- "Continuar editando" — Fecha dialog, volta ao editor
Design:
- Backdrop com blur (
bg-black/40 backdrop-blur-sm) - Card branco centralizado (
max-w-sm rounded-2xl) - Ícone de alerta amarelo (AlertTriangleIcon)
- Segue identidade visual ConvertaFlow (sem popup nativo Chrome)
Decisão: Sem beforeunload
O evento beforeunload do navegador foi removido intencionalmente:
| Aspecto | beforeunload (removido) | Dialog customizado (implementado) |
|---|---|---|
| Visual | Popup nativo Chrome (não customizável) | Design ConvertaFlow |
| Trigger | Fechar aba, digitar URL | Botão voltar do editor |
| Opções | "Sair" / "Cancelar" | Salvar e sair / Descartar / Continuar |
| Customização | Impossível | Total |
Arquivos
| Arquivo | Função |
|---|---|
frontend/src/components/flow-builder/FlowEditor.tsx |
Dirty state tracking (savedSnapshotRef, isDirty) |
frontend/src/components/flow-builder/FlowToolbar.tsx |
Dialog via portal, indicador visual, botão voltar |