chiark / gitweb /
Report posting errors in a way that allows retries.
authorSimon Tatham <anakin@pobox.com>
Sat, 27 Jan 2024 11:13:17 +0000 (11:13 +0000)
committerSimon Tatham <anakin@pobox.com>
Sat, 27 Jan 2024 11:40:11 +0000 (11:40 +0000)
Having written that into TODO.md in the previous commit, let's
immediately polish it off, because I already know how to do it - the
login workflow has exactly that kind of error report already.

TODO.md
src/posting.rs

diff --git a/TODO.md b/TODO.md
index 6929698a36d5babc584befc7339ff79964350fc7..1838cd41dbcde183d36cd743c2a2bfecddc32f57 100644 (file)
--- a/TODO.md
+++ b/TODO.md
@@ -32,15 +32,12 @@ Error Log entries could usefully include various extra detail:
   context, like 'I was trying to fetch this status because this other
   one was replying to it'.
 
-Some error situations could be handled in a less generic way:
-
-* in `PostMenu::post`, if the server refuses the post, we should
-  display the error in the posting menu and let the user modify and
-  retry, similar to the way the login/registration flow does it. But
-  any error weirder than that should still go to the Error Log.
-* similarly, in the `get_user_to_examine` and `get_post_id_to_read`
-  overlay activities, we should respond to 'no such thing' by letting
-  the user re-edit and try again, in case it was just a typo
+In the `get_user_to_examine` and `get_post_id_to_read` overlay
+activities, a simple 'not found' error shouldn't throw the user into
+the Error Log. That's overkill. We should instead toggle to an overlay
+activity showing a friendlier bottom-line error message, and abort the
+attempt. (Then the user can try again via line recall if it was just a
+typo – at least, once we implement line recall.)
 
 We don't have good handling for I/O errors while saving the user's
 LDB. That's not a _client_ error, but we could make an extra enum
index e4d51554b659cb07c2cb870660f7a648d9a2eefb..82ba71b2f46b5c3a12aa1ad9879cd7ba1340bab3 100644 (file)
@@ -2,7 +2,7 @@ use std::iter::once;
 use sys_locale::get_locale;
 
 use super::client::{Client, ClientError};
-use super::coloured_string::ColouredString;
+use super::coloured_string::{ColouredString, ColouredStringCommon};
 use super::editor::EditableMenuLine;
 use super::text::*;
 use super::tui::{
@@ -137,6 +137,7 @@ struct PostMenu {
     cl_sensitive: CyclingMenuLine<bool>,
     el_content_warning: EditableMenuLine<Option<String>>,
     el_language: EditableMenuLine<String>,
+    para_post_outcome: Paragraph,
 }
 
 impl PostMenu {
@@ -190,6 +191,9 @@ impl PostMenu {
             post.m.language.clone(),
         );
 
+        let para_post_outcome =
+            Paragraph::new().set_centred(true).set_indent(10, 10);
+
         let mut pm = PostMenu {
             post,
             title,
@@ -202,6 +206,7 @@ impl PostMenu {
             cl_sensitive,
             el_content_warning,
             el_language,
+            para_post_outcome,
         };
         pm.fix_widths();
         pm
@@ -252,10 +257,23 @@ impl PostMenu {
 
         match client.post_status(&self.post) {
             Ok(_) => LogicalAction::Pop,
-
-            // FIXME: if we can identify errors of the form "refusal
-            // to post because of something the user can reasonably
-            // fix", we should stay in this menu and let them retry
+            Err(
+                err @ ClientError::UrlFetchHTTPRich(
+                    _,
+                    reqwest::StatusCode::UNPROCESSABLE_ENTITY,
+                    _,
+                ),
+            ) => {
+                self.para_post_outcome.clear();
+                self.para_post_outcome.push_text(
+                    ColouredString::uniform(
+                        &format!("Posting error: {err}"),
+                        'r',
+                    ),
+                    false,
+                );
+                LogicalAction::Beep
+            }
             Err(err) => LogicalAction::Error(err),
         }
     }
@@ -267,6 +285,15 @@ impl ActivityState for PostMenu {
         w: usize,
         h: usize,
     ) -> (Vec<ColouredString>, CursorPosition) {
+        let push_split_lines =
+            |lines: &mut Vec<ColouredString>, output: Vec<ColouredString>| {
+                for line in output {
+                    for frag in line.split(w.saturating_sub(1)) {
+                        lines.push(frag.into());
+                    }
+                }
+            };
+
         let mut lines = Vec::new();
         let mut cursorpos = CursorPosition::End;
         lines.extend_from_slice(&self.title.render(w));
@@ -284,6 +311,9 @@ impl ActivityState for PostMenu {
         ));
         lines.push(self.el_language.render(w, &mut cursorpos, lines.len()));
 
+        lines.extend_from_slice(&BlankLine::render_static());
+        push_split_lines(&mut lines, self.para_post_outcome.render(w));
+
         while lines.len() + 1 < h {
             lines.extend_from_slice(&BlankLine::render_static());
         }