Add OnelinerState::Manual variant
This commit introduces a new `Manual` variant to the `OnelinerState` enum, allowing for manual overrides of the oneliner text. This change affects the client and server components to handle and display this new state. A `OnelinerOverrideRequest` struct is also added for API requests to set manual oneliners. New tests are included to ensure the `Manual` variant serializes and deserializes correctly. The `compute_oneliner_display` function in `server/src/routes/user_web.rs` is updated to treat `Manual` states the same as `Ready` states for display purposes. The `cases_needing_oneliner_in` function in `server/src/transcribe/recovery.rs` is updated to not retry cases that are in a `Manual` state.
This commit is contained in:
@@ -41,6 +41,10 @@ pub enum OnelinerState {
|
||||
/// server logs on purpose; the UI surfaces only "error", and
|
||||
/// startup recovery retries this variant.
|
||||
Error { generated_at: String },
|
||||
/// Manual override set by the doctor via tap-to-edit. Sticky:
|
||||
/// blocks all auto-regeneration until a new manual edit replaces
|
||||
/// it. `set_at` is server-side RFC3339 UTC (avoids client clock skew).
|
||||
Manual { text: String, set_at: String },
|
||||
}
|
||||
|
||||
/// Full response body of `GET /api/oneliners`.
|
||||
@@ -81,3 +85,53 @@ pub struct OnelinerEntry {
|
||||
pub last_recording_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
|
||||
/// HTTP path template for setting a manual oneliner override.
|
||||
/// `{case_id}` is replaced by the actual case id by routers and clients;
|
||||
/// shared so both sides agree on the exact URL shape.
|
||||
pub const ONELINER_OVERRIDE_PATH_TEMPLATE: &str = "/api/cases/{case_id}/oneliner";
|
||||
|
||||
/// Request body for `PUT /api/cases/{case_id}/oneliner`.
|
||||
///
|
||||
/// Only `text` travels over the wire — `set_at` is set server-side from
|
||||
/// the server clock, so clients with skewed/unset clocks (watch on
|
||||
/// battery save, etc.) cannot poison the timestamp.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OnelinerOverrideRequest {
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn manual_variant_roundtrips() {
|
||||
let original = OnelinerState::Manual {
|
||||
text: "55 J., Knieschmerz links".to_owned(),
|
||||
set_at: "2026-04-26T18:33:00Z".to_owned(),
|
||||
};
|
||||
let json = serde_json::to_string(&original).expect("serialize");
|
||||
let parsed: OnelinerState = serde_json::from_str(&json).expect("deserialize");
|
||||
assert_eq!(original, parsed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manual_serializes_with_kind_tag() {
|
||||
let state = OnelinerState::Manual {
|
||||
text: "abc".to_owned(),
|
||||
set_at: "2026-04-26T18:33:00Z".to_owned(),
|
||||
};
|
||||
let json = serde_json::to_value(&state).expect("serialize");
|
||||
assert_eq!(json["kind"], "manual");
|
||||
assert_eq!(json["text"], "abc");
|
||||
assert_eq!(json["set_at"], "2026-04-26T18:33:00Z");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn override_request_deserializes_minimal_body() {
|
||||
let body = r#"{"text":"hello"}"#;
|
||||
let req: OnelinerOverrideRequest = serde_json::from_str(body).expect("deserialize");
|
||||
assert_eq!(req.text, "hello");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user