new form page row + import page dialog fix
This commit is contained in:
@@ -295,10 +295,10 @@ pub(crate) async fn import_progress(
|
||||
// is nothing to report, and the alert says so rather than the card polling
|
||||
// a job that will never answer.
|
||||
let Some(snapshot) = state.imports.snapshot(&id, session) else {
|
||||
return reject(&headers, tr!(locale, "import-progress-gone"));
|
||||
return no_store(reject(&headers, tr!(locale, "import-progress-gone")));
|
||||
};
|
||||
|
||||
match &snapshot.outcome {
|
||||
let response = match &snapshot.outcome {
|
||||
None => Html(ui::render_progress(locale, &id, &snapshot)).into_response(),
|
||||
Some(Outcome::Succeeded) => Html(ui::render_success(
|
||||
locale,
|
||||
@@ -336,7 +336,20 @@ pub(crate) async fn import_progress(
|
||||
Html(String::new()),
|
||||
)
|
||||
.into_response(),
|
||||
}
|
||||
};
|
||||
no_store(response)
|
||||
}
|
||||
|
||||
/// A browser or an intermediary caching this poll's answer is exactly how "the
|
||||
/// backend finished" and "what the page shows" come apart: the dialog's whole
|
||||
/// point is that every second's answer is the server's current answer, never
|
||||
/// a replay of an earlier one.
|
||||
fn no_store(mut response: Response) -> Response {
|
||||
response.headers_mut().insert(
|
||||
header::CACHE_CONTROL,
|
||||
HeaderValue::from_static("no-store"),
|
||||
);
|
||||
response
|
||||
}
|
||||
|
||||
/// One spawned import: what the walk through the prepared rows needs, and
|
||||
|
||||
@@ -152,23 +152,35 @@ pub(crate) fn render_import_failure(
|
||||
))
|
||||
}
|
||||
|
||||
/// The confirmation a completed import answers with, once the progress dialog
|
||||
/// stops polling. A blocking dialog rather than `Alert::success`'s toast: the
|
||||
/// toast dismisses itself on a timer, which is the same "did this actually
|
||||
/// finish?" doubt the progress dialog exists to remove.
|
||||
#[derive(Template)]
|
||||
#[template(path = "pages/import_export/import/success_dialog.html")]
|
||||
struct ImportSuccessDialog<'a> {
|
||||
locale: Locale,
|
||||
title: &'a str,
|
||||
message: &'a str,
|
||||
}
|
||||
|
||||
pub(crate) fn render_success(
|
||||
locale: Locale,
|
||||
inserted: usize,
|
||||
prepared_rows: usize,
|
||||
table_name: &str,
|
||||
) -> String {
|
||||
render(&Alert::success(
|
||||
render(&ImportSuccessDialog {
|
||||
locale,
|
||||
&tr!(locale, "import-success-title"),
|
||||
&tr!(
|
||||
title: &tr!(locale, "import-success-title"),
|
||||
message: &tr!(
|
||||
locale,
|
||||
"import-success-message",
|
||||
"inserted" => inserted as i64,
|
||||
"source_rows" => prepared_rows as i64,
|
||||
"table" => table_name.to_string(),
|
||||
),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -414,6 +426,14 @@ mod tests {
|
||||
// 500 rows in 40 seconds, so the 1500 left are about two minutes away.
|
||||
assert!(html.contains("13 rows/s"), "{html}");
|
||||
assert!(html.contains("1 m 56 s"), "{html}");
|
||||
// A running import blocks the page rather than sitting as an inline
|
||||
// card the user can miss or click past.
|
||||
assert!(html.contains(r#"role="dialog""#), "{html}");
|
||||
assert!(html.contains("aria-modal=\"true\""), "{html}");
|
||||
// Unlike ui/dialog.html's dismissible dialogs, this one has no escape
|
||||
// hatch: clicking Import again would send the file a second time.
|
||||
assert!(!html.contains("keydown.esc"), "{html}");
|
||||
assert!(!html.contains("click.self"), "{html}");
|
||||
}
|
||||
|
||||
/// A rate needs rows and time behind it. Before there are either, the card
|
||||
@@ -460,4 +480,21 @@ mod tests {
|
||||
assert!(html.contains("Nothing was imported"), "{html}");
|
||||
assert!(!html.contains("already imported remain"), "{html}");
|
||||
}
|
||||
|
||||
/// The card the progress dialog polls into once the import is done: a
|
||||
/// dialog the user has to actively dismiss, not a toast on its own timer.
|
||||
#[test]
|
||||
fn a_finished_import_answers_with_a_dismissible_dialog_not_a_toast() {
|
||||
let html = render_success(Locale::English, 500, 500, "customers");
|
||||
|
||||
assert!(!html.contains("Template error"), "{html}");
|
||||
assert!(html.contains(r#"role="dialog""#), "{html}");
|
||||
assert!(html.contains("Import complete"), "{html}");
|
||||
assert!(html.contains("500"), "{html}");
|
||||
assert!(html.contains("customers"), "{html}");
|
||||
// The toast fires-and-forgets via a window event; this answers with
|
||||
// the dialog itself instead.
|
||||
assert!(!html.contains("$dispatch('notify'"), "{html}");
|
||||
assert!(html.contains("keydown.esc"), "{html}");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user