Package: a failed package keeps the dialog open; the ink table's Type column; no document is an error

- When `file.package` fails, the Package or Printing Instructions dialog
  comes back with its options and instructions, and the status line says
  why. Before, they were lost.
- The Colors and Inks table heads its kind column with the "Type:" key
  (without its colon). The "Type" key is the menu's and reads Text in
  most languages.
- `app.packageDialog` with no document open is an error rather than a
  silent success.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
moppeeerandClaude Opus 5.5 committed 2026-10-22 00:53:21 +02:00
1 parent d21459ff3e
commit c04fa61d17
3 files changed
+47 -10

No files matched your search

+16 -2
View File
@@ -3581,8 +3581,22 @@ pub fn confirm(app: &mut DesignApp) -> Result<Value, String> {
}
"alert" => Ok(Value::Null),
crate::effects_dialog::ID => crate::effects_dialog::confirm(app, &d),
crate::package_dialog::ID => crate::package_dialog::confirm(app, &d),
crate::package_dialog::INSTRUCTIONS => crate::package_dialog::confirm_instructions(app, &d),
crate::package_dialog::ID | crate::package_dialog::INSTRUCTIONS => {
let r = if d.id == crate::package_dialog::ID {
crate::package_dialog::confirm(app, &d)
} else {
crate::package_dialog::confirm_instructions(app, &d)
};
// Packaging failed: the dialog stays open with its options and instructions, and the
// status line says why.
if let Err(e) = &r
&& app.ui.dialog.is_none()
{
app.status(e.clone());
app.ui.dialog = Some(d);
}
r
}
"findChange" => {
let result = if d.b("objectMode") { Ok(Value::Null) } else { app.run("find.change", find_change_params(&d)) };
// Confirmation consumes retained bounds before closing, even on an error.
+1 -4
View File
@@ -1149,10 +1149,7 @@ fn run_ui_inner(app: &mut DesignApp, id: &str, p: &Value) -> Option<Result<Value
Ok(Value::Null)
}
"app.exportText" => export_bytes(app, p, "rtf", "file.exportText"),
"app.packageDialog" => {
crate::package_dialog::open(app);
Ok(Value::Null)
}
"app.packageDialog" => crate::package_dialog::open(app).map(|()| Value::Null),
"app.language" => {
let Some(v) = p.get("lang").and_then(Value::as_str) else { return Some(app.run("app.preferences", json!({}))) };
if !crate::i18n::LANGUAGES.iter().any(|(c, _)| *c == v) {
+30 -4
View File
@@ -33,9 +33,9 @@ const INSTRUCTION_FIELDS: [(&str, &str, usize); 7] = [
];
/// Open the Package dialog on its Summary, with the document's fonts, links and spot inks.
pub fn open(app: &mut DesignApp) {
pub fn open(app: &mut DesignApp) -> Result<(), String> {
if app.session.active().is_none() {
return;
return Err("no document open".into());
}
let fonts: Vec<Value> = app
.session
@@ -85,6 +85,7 @@ pub fn open(app: &mut DesignApp) {
ID,
json!({"page": "summary", "fonts": fonts, "links": links, "spot": spot, "instructions": false, "idml": true, "pdf": false, "problemsOnly": false}),
));
Ok(())
}
fn rows(d: &Dialog, key: &str) -> Vec<Value> {
@@ -228,7 +229,9 @@ pub fn show(app: &DesignApp, ui: &mut egui::Ui, d: &mut Dialog) {
"inks" => {
let mut cells: Vec<_> = PROCESS_INKS.iter().map(|n| (vec![tr(n), tr("Process")], None)).collect();
cells.extend(rows(d, "spot").iter().filter_map(Value::as_str).map(|n| (vec![n.to_string(), tr("Spot")], None)));
table(ui, "package_inks", &[tr("Name"), tr("Type")], &cells);
// The ink's kind: the "Type:" key (the "Type" key is the menu's, which reads Text).
let kind = tr("Type:").trim_end_matches([':', ':']).trim_end().to_string();
table(ui, "package_inks", &[tr("Name"), kind], &cells);
}
_ => {
ui.horizontal(|ui| {
@@ -441,7 +444,7 @@ mod tests {
let out = dir.join("Packed Folder");
let picked = out.to_string_lossy().to_string();
app.services.pick_save = Some(Box::new(move |_| Some(picked.clone())));
open(&mut app);
open(&mut app).unwrap();
let mut h = harness(app);
h.run_steps(3);
h.get_by_label("Include IDML").click();
@@ -454,4 +457,27 @@ mod tests {
assert!(out.join("Packed.pdf").exists() && !out.join("Packed.idml").exists());
std::fs::remove_dir_all(dir).unwrap();
}
/// Packaging that fails (here, into a folder under a file) keeps the dialog open with its
/// options, and the status line says why. Without a document there's nothing to open.
#[test]
fn a_failed_package_keeps_the_dialog_open() {
let dir = temp_dir("fails");
let mut app = app_with_missing_link(&dir);
let blocker = dir.join("blocker");
std::fs::write(&blocker, b"a file, not a folder").unwrap();
let picked = blocker.join("Packed Folder").to_string_lossy().to_string();
app.services.pick_save = Some(Box::new(move |_| Some(picked.clone())));
open(&mut app).unwrap();
app.ui.dialog.as_mut().unwrap().fields.insert("pdf".into(), json!(true));
assert!(crate::dialogs::confirm(&mut app).is_err());
let d = app.ui.dialog.as_ref().expect("the dialog stays open");
assert_eq!((d.id.as_str(), d.b("pdf")), (ID, true), "with its options");
assert!(!app.ui.status.is_empty());
app.run("file.close", json!({})).unwrap();
app.ui.dialog = None;
assert!(app.run("app.packageDialog", json!({})).is_err());
assert!(app.ui.dialog.is_none());
std::fs::remove_dir_all(dir).unwrap();
}
}