dashboard: surface peer questions + operator override
questions pane now shows both operator-targeted threads (target IS NULL) and agent-to-agent threads (target = some agent). filter chips above the list: all / @operator / @peer / per-participant. peer rows get a mauve left rule + a 0V3RR1D3 button that POSTs the same /answer-question endpoint (OperatorQuestions::answer already permits the operator as answerer on any target). wire changes: OperatorQuestions gains pending_all + recent_answered_all; QuestionAdded + QuestionResolved events carry target: Option<String>; emit sites drop their target.is_none() guard. answered-history rows show the answerer prefix so override answers are auditable at a glance.
This commit is contained in:
parent
e7ce35c503
commit
a15fafb5de
9 changed files with 187 additions and 71 deletions
|
|
@ -209,15 +209,15 @@ impl OperatorQuestions {
|
|||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Pending operator-targeted questions only (`target IS NULL`).
|
||||
/// Drives the dashboard's pending-question pane — agent-to-agent
|
||||
/// questions never appear here so the operator's queue stays clean.
|
||||
pub fn pending(&self) -> Result<Vec<OpQuestion>> {
|
||||
/// Every pending question, operator-targeted or peer-to-peer.
|
||||
/// Drives the dashboard's questions pane now that peer threads
|
||||
/// are surfaced for visibility + operator override-answer.
|
||||
pub fn pending_all(&self) -> Result<Vec<OpQuestion>> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
let mut stmt = conn.prepare(
|
||||
"SELECT id, asker, question, options_json, multi, asked_at, answered_at, answer, deadline_at, target
|
||||
FROM operator_questions
|
||||
WHERE answered_at IS NULL AND target IS NULL
|
||||
WHERE answered_at IS NULL
|
||||
ORDER BY id ASC",
|
||||
)?;
|
||||
let rows = stmt.query_map([], row_to_question)?;
|
||||
|
|
@ -225,15 +225,14 @@ impl OperatorQuestions {
|
|||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Last `limit` answered operator-targeted questions, newest-first.
|
||||
/// Same `target IS NULL` filter as `pending()` so the dashboard's
|
||||
/// history view only shows operator-relevant rows.
|
||||
pub fn recent_answered(&self, limit: u64) -> Result<Vec<OpQuestion>> {
|
||||
/// Last `limit` answered questions across both target kinds,
|
||||
/// newest-first. Companion to `pending_all`.
|
||||
pub fn recent_answered_all(&self, limit: u64) -> Result<Vec<OpQuestion>> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
let mut stmt = conn.prepare(
|
||||
"SELECT id, asker, question, options_json, multi, asked_at, answered_at, answer, deadline_at, target
|
||||
FROM operator_questions
|
||||
WHERE answered_at IS NOT NULL AND target IS NULL
|
||||
WHERE answered_at IS NOT NULL
|
||||
ORDER BY answered_at DESC
|
||||
LIMIT ?1",
|
||||
)?;
|
||||
|
|
@ -241,6 +240,7 @@ impl OperatorQuestions {
|
|||
rows.collect::<rusqlite::Result<Vec<_>>>()
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn row_to_question(row: &rusqlite::Row<'_>) -> rusqlite::Result<OpQuestion> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue