feat: Add inline oneliner editing

Introduces inline editing for oneliner text within the case list. This
feature allows users to directly modify oneliner entries in the UI, with
changes being optimistically applied locally and then asynchronously
sent to the server.

Includes:
- New `OnelinerEditState` to manage the editing buffer and focus.
- `SaveResult` struct to communicate the outcome of background save
  operations.
- UI logic to toggle between read and edit modes for oneliner entries.
- Handling of keyboard inputs (Enter, Esc) and button clicks for saving
  or canceling edits.
- Toast banner to display save errors to the user.
- Asynchronous `put_oneliner` calls for background server updates.
- Local storage update for optimistic UI updates.
This commit is contained in:
2026-04-26 16:35:14 +02:00
parent d5e6c334c9
commit d732fdd8ec
3 changed files with 254 additions and 24 deletions
+4 -1
View File
@@ -1098,7 +1098,10 @@ mod tests {
let path = tmp.path().join(format!("{id}.json"));
let bytes = tokio::fs::read(&path).await.unwrap();
let on_disk: CaseMarker = serde_json::from_slice(&bytes).unwrap();
assert!(matches!(on_disk.oneliner, Some(OnelinerState::Manual { .. })));
assert!(matches!(
on_disk.oneliner,
Some(OnelinerState::Manual { .. })
));
}
#[tokio::test]
+12 -4
View File
@@ -71,7 +71,9 @@ pub async fn put_oneliner(
}
} else if status.as_u16() == 408 || status.as_u16() == 429 || status.is_server_error() {
let body = resp.text().await.unwrap_or_default();
Err(PutOnelinerError::Transient(format!("HTTP {status}: {body}")))
Err(PutOnelinerError::Transient(format!(
"HTTP {status}: {body}"
)))
} else {
let body = resp.text().await.unwrap_or_default();
Err(PutOnelinerError::Terminal {
@@ -115,9 +117,15 @@ mod tests {
let http = reqwest::Client::new();
let case_id = Uuid::new_v4();
let result = put_oneliner(&http, &server.uri(), TEST_API_KEY, case_id, "55 J., Knieschmerz")
.await
.expect("ok");
let result = put_oneliner(
&http,
&server.uri(),
TEST_API_KEY,
case_id,
"55 J., Knieschmerz",
)
.await
.expect("ok");
match result {
OnelinerState::Manual { text, set_at } => {
assert_eq!(text, "55 J., Knieschmerz");