Files
simple-multimidia-track-aud…/docs/impl-dt10-debug-panel.md
T

6.1 KiB

Implementação — DT-10: Painel de Debug do Comando Gerado

Data: 01/03/2026
Status: Implementado
Prioridade: Baixa — melhoria de DX para usuário técnico
Arquivos afetados:

  • src/ui/components/execution_panel.rs
  • src/ui/app.rs
  • PRD.md (documentação ao concluir)

Objetivo

Exibir, de forma colapsável na ExecutionPanel, o comando exato (ffmpeg … ou mkvmerge …) que foi enviado ao processo externo na última geração. Permite que o usuário técnico inspecione, copie e reproduza o comando manualmente para diagnóstico.


Viabilidade

Ponto Situação
args: Vec<String> já construído antes do spawn start_generation() — linha ~244 de app.rs
ExecutionPanel já usa ui.collapsing() Padrão reutilizado do "Log detalhado"
Nenhuma camada nova necessária Mudanças em 2 arquivos apenas
Sem impacto em testes existentes Campo additive — nenhuma assinatura pública muda
Botão "Copiar" sem dependência adicional `ui.output_mut( o o.copied_text = …)` nativo do egui

Estimativa: ~30 linhas adicionadas. Risco zero de regressão.


Passo 1 — Campo last_command em ExecutionPanel

Arquivo: src/ui/components/execution_panel.rs

Adicionar o campo à struct:

pub struct ExecutionPanel {
    pub state: ExecutionState,
    pub log_lines: Vec<String>,
    /// Comando completo enviado ao FFmpeg/mkvmerge na última geração.
    /// Exemplo: "ffmpeg -i input.mkv -c copy ... output.mkv"
    pub last_command: Option<String>,
}

Inicializar em ExecutionPanel::new():

pub fn new() -> Self {
    ExecutionPanel {
        state: ExecutionState::Idle,
        log_lines: Vec::new(),
        last_command: None,
    }
}

Passo 2 — Formatar e armazenar o comando em app.rs

Arquivo: src/ui/app.rs
Localização: método start_generation(), logo após construir args e antes do thread::spawn

// Formatar comando legível para o painel de debug
let binary = if uses_mkvmerge { "mkvmerge" } else { "ffmpeg" };
let cmd_str = format!(
    "{} {}",
    binary,
    args.iter()
        .map(|a| if a.contains(' ') { format!("\"{}\"", a) } else { a.clone() })
        .collect::<Vec<_>>()
        .join(" ")
);
self.execution_panel.last_command = Some(cmd_str);

Atenção: replicar o mesmo bloco em start_batch_generation() para cobrir o modo Lote (RF-09).


Passo 3 — Renderizar o painel colapsável em ExecutionPanel::ui()

Arquivo: src/ui/components/execution_panel.rs
Localização: após o bloco "Log detalhado", antes do }); de fechamento do ui.group

if let Some(cmd) = &self.last_command {
    ui.collapsing("🛠 Comando gerado", |ui| {
        let mut cmd_str = cmd.as_str();
        ui.add(
            egui::TextEdit::multiline(&mut cmd_str)
                .desired_rows(3)
                .desired_width(f32::INFINITY)
                .font(egui::TextStyle::Monospace),
        );
        if ui.small_button("📋 Copiar").clicked() {
            ui.output_mut(|o| o.copied_text = cmd.clone());
        }
    });
}

Comportamento esperado:

  • Colapsável fechado por padrão — não ocupa espaço visual desnecessário
  • TextEdit somente leitura (variável local imutável no contexto do egui)
  • Botão "📋 Copiar" coloca o comando no clipboard do sistema
  • Argumento com espaço interno é envolvido em aspas para reprodutibilidade no terminal

Passo 4 — Comportamento de limpeza

last_command não é limpo ao iniciar nova geração — ele é sobrescrito. O usuário vê sempre o comando da execução atual.

last_command não é limpo em cancel_generation() — o usuário pode querer inspecionar o comando de uma geração cancelada.

Não há necessidade de resetar em nenhum outro ponto.


Passo 5 — Atualizar PRD e débitos técnicos

Ao concluir a implementação:

  1. Marcar DT-10 como ✅ Resolvido na tabela da seção 10 do PRD.md
  2. Remover o item do backlog da seção 11
  3. Adicionar critério de aceitação na seção 12:
    • [x] O comando FFmpeg/mkvmerge gerado é exibido em painel colapsável na ExecutionPanel (DT-10)

Ordem de execução recomendada

# Passo Testável após
1 Adicionar campo + init em ExecutionPanel cargo check
2 Renderizar painel colapsável (Passo 3) com valor hardcoded temporário cargo run — inspeção visual
3 Wiring em start_generation() (Passo 2) cargo run — geração real
4 Replicar wiring em start_batch_generation() cargo run — modo lote
5 Remover hardcode temporário se usado; cargo test 33 testes devem continuar passando
6 Atualizar PRD (Passo 5)

Critério de aceitação

  • O painel "🛠 Comando gerado" aparece na ExecutionPanel após a primeira geração
  • O painel está colapsado por padrão
  • O conteúdo exibe o binário (ffmpeg ou mkvmerge) seguido de todos os argumentos
  • Argumentos com espaços internos são envolvidos em aspas duplas
  • O botão "📋 Copiar" coloca o texto no clipboard
  • O comando é exibido também para gerações canceladas
  • O painel não aparece antes da primeira geração (estado Idle inicial)
  • Modo Lote exibe o comando do último item processado
  • cargo test — 68 testes passando sem regressão