fix(content): 重试面板画可读名,不再只有站点 id (M191 r1 P2-1)

复审 P2-1:面板原来只画 `P7dR8mSH` 这种项目键,用户拿到的是一串哈希。
可读名其实都在手边,只是没进 DTO——现在补上,按复审给的**最小修法**做,没扩散:

- `InstallFailureView` 加 `label: String`(**语言中立**:站点标题或文件名),
  配 `line()` 统一决定「名字 (id)」还是「只有 id」(名字为空时不编造)。
  `detail`(core 中文散文)**依旧不进界面**——那会踩 i18n R2。
- `plan::label_of` 三个来源,零额外请求:
  根项目 → 请求里的 `title`;计划里有节点(下载失败)→ `node.file.filename`;
  都没有(解析 404 / 不兼容的前置)→ 空,界面退回只画 id(复审认这条兜底)。
- 计划被记住时连显示名一起记(`plan::remember` 多一个 `title`),于是重试那一轮
  面板头与失败名单沿用的是同一个名字(顺手收掉复审 N5 的「重试时面板头显示 id」)。
- N2:删掉新加的 `ContentInstallDismiss`,复用既有的 `DownloadDismiss`(同一句话不立两条 key)。
- 行数/clippy:`collect` 的参数捆成 `Placement{dir,title}`(9 个参数超限);
  `plan.rs` 加完 `label_of` 到 429 行,把「记住的计划」表纯搬移到 `plan/remembered.rs`(363 + 82)。

守门(真跑红再还原):
- 把 `label_of` 置空 ⇒ `the_retry_list_shows_a_readable_name_not_just_the_project_id` 红
  (三行全变成 `["AANobbMI","P7dR8mSH","1eAoo2KR"]`);
- 审阅指出的另一半判据也补上了:`Done` + 残留名单 ⇒ 必须不画;现在**只去掉**
  `stage != Failed` 那一半就红(之前只去掉它仍是全绿,报告的表述不准,已改)。
This commit is contained in:
AskaEth committed 2026-11-09 05:06:05 +08:00
1 parent 5a52f38f35
commit 961ff453a0
11 files changed
+326 -104

No files matched your search

+30 -2
View File
@@ -76,17 +76,29 @@ impl InstallFailureKind {
pub const ALL: [Self; 2] = [Self::Incompatible, Self::Unreachable];
}
/// 一条「可只重试」的失败项(M191):项目键 + 档位 + core 给的原话。
/// 一条「可只重试」的失败项(M191):项目键 + 可读标签 + 档位 + core 给的原话。
///
/// 这是界面画「可只重试这 N 个」和分组所需的**全部**信息:项目键就是重试时发出去的那个键
/// (`DependencyPlan::retry_request()` 用的同一份)。
///
/// ## 为什么还要 `label`(M191 r1 复审 P2-1)
///
/// `project` 是站点 id(`P7dR8mSH`),直接画在界面上等于给用户一串哈希。可读名其实都在手边,
/// 只是没进 DTO:根项目的名字就在请求的 `title` 里;失败文件的名字在 `PlannedNode.file.filename`
/// 里(下载失败那种)。`label` 收的正是这两个**语言中立**的字符串(站点标题 / 文件名),
/// **不是** `detail` 那种 core 中文散文——那会踩 i18n 的 R2(core 中文不进界面)。
///
/// `label` 为空是合法且**必须**保留的一档:项目不存在(404)时确实没有名字可显示,
/// 那时界面只画 id(评审认这条兜底是合理的)。
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct InstallFailureView {
/// 请求它用的项目键(slug 或 id;重试也用它)
pub project: String,
/// 语言中立的可读标签(站点给的项目标题 / 文件名;空 = 拿不到名字)
pub label: String,
/// 哪一档
pub kind: InstallFailureKind,
/// core 给的人读说明(引擎原话 + 上下文,**不是**界面文案)
/// core 给的人读说明(引擎原话 + 上下文,**不是**界面文案;**不要**画到界面上)
pub detail: String,
}
@@ -95,15 +107,31 @@ impl InstallFailureView {
#[must_use]
pub fn new(
project: impl Into<String>,
label: impl Into<String>,
kind: InstallFailureKind,
detail: impl Into<String>,
) -> Self {
Self {
project: project.into(),
label: label.into(),
kind,
detail: detail.into(),
}
}
/// 界面该画的那一行:有名字就「名字 (id)」,没有就只画 id。
///
/// 界面上**名字优先、id 次要**:名字让人认出是哪个项目,括号里的 id 是给「名字对不上时」
/// 或排查用的。定在这个方法里而不是视图里,是因为「有名字用名字」这条要有用例钉住。
#[must_use]
pub fn line(&self) -> String {
let label = self.label.trim();
if label.is_empty() || label == self.project {
self.project.clone()
} else {
format!("{label} ({})", self.project)
}
}
}
/// 一次安装的进度快照。