diff --git a/crates/app-iced/src/app/view.rs b/crates/app-iced/src/app/view.rs index c3786a2..6df8a19 100644 --- a/crates/app-iced/src/app/view.rs +++ b/crates/app-iced/src/app/view.rs @@ -5,9 +5,7 @@ use iced::{Element, Theme}; use unlucky_i18n::Lang; -use unlucky_presenter::dto::{ - Diagnosis, InstanceRuntime, InstanceSummary, LaunchStage, LogLevel, LogOutcome, -}; +use unlucky_presenter::dto::{InstanceRuntime, InstanceSummary, LaunchStage}; use unlucky_presenter::router::Route; use unlucky_presenter::state::AppState; @@ -20,6 +18,10 @@ use super::message::{nav_item_of, Message}; use super::state::{log_first_frame, App}; use super::APP_TITLE; +mod logs; + +use logs::logs_model; + impl App { /// 主题名(iced 只在 `Theme::name()` 变化时重算受主题影响的缓存)。 pub(super) fn theme(&self) -> Theme { @@ -130,76 +132,6 @@ pub(super) fn model( } } -/// 日志页视图模型(M95):presenter 快照 → 日志行 + 诊断结论。 -/// -/// **页面不读盘**:日志文本只从 `log_lines`(host 尾随 JSONL 后按批次发的事件)来;会话元信息 -/// 从 `log_sessions` 里按「运行中的那一场 → 诊断归属的那一场」找,找不到就不画。 -/// -/// 两处 DTO 侧的**信息丢失**(已报 finding,不在本 scope 修):`dto::Diagnosis` 没有 core 的 -/// `severity`(严重度只能按置信度折算,阈值是债)与 `cause.key`(`title`/`hint` 只能当数据画)。 -fn logs_model(state: &AppState) -> pages::Logs { - let report = state.diagnosis.as_ref(); - let current = state.selected_session.as_deref(); - let session = report - .and_then(|report| state.log_sessions.iter().find(|s| s.id == report.session)) - .or_else(|| { - state - .log_sessions - .iter() - .find(|s| Some(s.id.as_str()) == current) - }); - - pages::Logs { - instance: session.map(|s| s.instance.clone()), - when: session.map(|s| s.when.clone()), - outcome: session.map(|s| log_outcome(s.outcome)), - lines: state - .log_lines - .iter() - .map(|line| pages::Line { - text: line.text.clone(), - level: log_level(line.level), - }) - .collect(), - findings: report - .map(|report| diagnosis_of(&report.diagnosis)) - .into_iter() - .collect(), - ..pages::Logs::default() - } -} - -/// 日志等级:presenter 枚举 → 页面等级(**结构化出口**,不是认字符串)。 -fn log_level(level: LogLevel) -> pages::Level { - match level { - LogLevel::Debug => pages::Level::Debug, - LogLevel::Info => pages::Level::Info, - LogLevel::Warn => pages::Level::Warn, - LogLevel::Error => pages::Level::Error, - } -} - -/// 会话结局:presenter 枚举 → 页面结局(文案走 `LaunchOutcome*` key,页面不画 core 的中文串)。 -fn log_outcome(outcome: LogOutcome) -> pages::Outcome { - match outcome { - LogOutcome::Ok => pages::Outcome::Ok, - LogOutcome::Crashed => pages::Outcome::Crashed, - LogOutcome::SilentFail => pages::Outcome::SilentFail, - } -} - -/// 一条诊断结论 → 页面结论(严重度折算见 [`logs_model`] 的文档)。 -fn diagnosis_of(diagnosis: &Diagnosis) -> pages::Finding { - pages::Finding { - rule: diagnosis.rule.clone(), - severity: pages::Severity::of_confidence(diagnosis.confidence), - title: diagnosis.title.clone(), - hint: diagnosis.hint.clone(), - confidence: diagnosis.confidence, - action: diagnosis.fix.clone(), - } -} - /// 列表行的副文案:`1.20.4 · Fabric 0.16.5`(原版只写「原版」,见 `LoaderInfo::badge`)。 fn supporting_line(instance: &InstanceSummary) -> String { format!("{} · {}", instance.mc_version, instance.loader.badge()) diff --git a/crates/app-iced/src/app/view/logs.rs b/crates/app-iced/src/app/view/logs.rs new file mode 100644 index 0000000..50fc260 --- /dev/null +++ b/crates/app-iced/src/app/view/logs.rs @@ -0,0 +1,80 @@ +//! 日志页的展示转换:presenter 快照 → [`pages::Logs`]。 +//! +//! 从 `app/view.rs` 拆出来(M95 r3):那个文件已经 392 行,贴着全仓 400 行的硬上限, +//! 而这一页的转换还要再加判别与测试。**本次搬运逐行等价**,行为零变化; +//! 跨会话串场的修复在下一个 commit(`state.diagnosis` 只写不清那条)。 + +use unlucky_presenter::dto::{Diagnosis, LogLevel, LogOutcome}; +use unlucky_presenter::state::AppState; + +use crate::pages; + +/// 日志页视图模型(M95):presenter 快照 → 日志行 + 诊断结论。 +/// +/// **页面不读盘**:日志文本只从 `log_lines`(host 尾随 JSONL 后按批次发的事件)来;会话元信息 +/// 从 `log_sessions` 里按「运行中的那一场 → 诊断归属的那一场」找,找不到就不画。 +/// +/// 两处 DTO 侧的**信息丢失**(已报 finding,不在本 scope 修):`dto::Diagnosis` 没有 core 的 +/// `severity`(严重度只能按置信度折算,阈值是债)与 `cause.key`(`title`/`hint` 只能当数据画)。 +pub(super) fn logs_model(state: &AppState) -> pages::Logs { + let report = state.diagnosis.as_ref(); + let current = state.selected_session.as_deref(); + let session = report + .and_then(|report| state.log_sessions.iter().find(|s| s.id == report.session)) + .or_else(|| { + state + .log_sessions + .iter() + .find(|s| Some(s.id.as_str()) == current) + }); + + pages::Logs { + instance: session.map(|s| s.instance.clone()), + when: session.map(|s| s.when.clone()), + outcome: session.map(|s| log_outcome(s.outcome)), + lines: state + .log_lines + .iter() + .map(|line| pages::Line { + text: line.text.clone(), + level: log_level(line.level), + }) + .collect(), + findings: report + .map(|report| diagnosis_of(&report.diagnosis)) + .into_iter() + .collect(), + ..pages::Logs::default() + } +} + +/// 日志等级:presenter 枚举 → 页面等级(**结构化出口**,不是认字符串)。 +fn log_level(level: LogLevel) -> pages::Level { + match level { + LogLevel::Debug => pages::Level::Debug, + LogLevel::Info => pages::Level::Info, + LogLevel::Warn => pages::Level::Warn, + LogLevel::Error => pages::Level::Error, + } +} + +/// 会话结局:presenter 枚举 → 页面结局(文案走 `LaunchOutcome*` key,页面不画 core 的中文串)。 +fn log_outcome(outcome: LogOutcome) -> pages::Outcome { + match outcome { + LogOutcome::Ok => pages::Outcome::Ok, + LogOutcome::Crashed => pages::Outcome::Crashed, + LogOutcome::SilentFail => pages::Outcome::SilentFail, + } +} + +/// 一条诊断结论 → 页面结论(严重度折算见 [`logs_model`] 的文档)。 +fn diagnosis_of(diagnosis: &Diagnosis) -> pages::Finding { + pages::Finding { + rule: diagnosis.rule.clone(), + severity: pages::Severity::of_confidence(diagnosis.confidence), + title: diagnosis.title.clone(), + hint: diagnosis.hint.clone(), + confidence: diagnosis.confidence, + action: diagnosis.fix.clone(), + } +}