Source code for imednet_streamlit.components.triage_drawer

from __future__ import annotations

from datetime import datetime, timezone
from typing import Sequence

import streamlit as st

from imednet.models.triage import TriageItem, TriageStatus
from imednet_workflows.triage_store import TriageStore

_LAST_ACTION_KEY = "_triage_drawer_last_action"
_TIMELINE_COL_RATIO = 3
_ACTION_COL_RATIO = 2
_DECISION_BUTTON_COLS = [1, 1, 1]


def _record_action(
    *,
    item_id: str,
    action: str,
    status: TriageStatus | None = None,
    assignee: str | None = None,
    comment: str | None = None,
) -> None:
    st.session_state[_LAST_ACTION_KEY] = {
        "item_id": item_id,
        "action": action,
        "status": status.value if status else None,
        "assignee": assignee,
        "comment": comment,
        "timestamp": datetime.now(timezone.utc).isoformat(),
    }


[docs]def render_triage_drawer( *, store: TriageStore, item: TriageItem, assignee_options: Sequence[str], current_user: str, ) -> None: """Render triage detail and actions for a selected item.""" st.subheader(f"Review Item: {item.item_id}") st.caption(f"Study: {item.study_key} • Severity: {item.severity} • Status: {item.status.value}") timeline_entries: list[tuple[datetime, str]] = [] for entry in item.history: detail = f"{entry.from_status.value}{entry.to_status.value} by {entry.user_id}" if entry.comment: detail += f" — {entry.comment}" timeline_entries.append((entry.timestamp, detail)) for annotation in item.annotations: timeline_entries.append( ( annotation.timestamp, f"Annotation by {annotation.user_id}: {annotation.comment}", ) ) timeline_col, action_col = st.columns([_TIMELINE_COL_RATIO, _ACTION_COL_RATIO], gap="large") with timeline_col: st.markdown("### Timeline") for timestamp, message in sorted(timeline_entries, key=lambda record: record[0]): st.write(f"• {timestamp.strftime('%Y-%m-%d %H:%M UTC')}{message}") with action_col: st.markdown("### Actions") current_assignee = item.assignee if item.assignee in assignee_options else None assign_selection = st.selectbox( "Change Assignee", options=list(assignee_options), index=(list(assignee_options).index(current_assignee) if current_assignee else 0), key=f"assignee_{item.item_id}", ) if st.button("Assign", key=f"assign_btn_{item.item_id}"): store.assign_item(item.item_id, assign_selection) _record_action(item_id=item.item_id, action="assign", assignee=assign_selection) st.success("Assignee updated") annotation_text = st.text_area("Annotate", key=f"annotation_{item.item_id}") if st.button("Save Annotation", key=f"annotation_btn_{item.item_id}"): cleaned_annotation = annotation_text.strip() if cleaned_annotation: store.add_annotation(item.item_id, current_user, cleaned_annotation) _record_action(item_id=item.item_id, action="annotate", comment=cleaned_annotation) st.success("Annotation added") else: st.warning("Annotation comment is required.") st.markdown("#### Triage Capture") triage_col, reject_col, approve_col = st.columns(_DECISION_BUTTON_COLS) if triage_col.button("Triage", key=f"triage_btn_{item.item_id}"): cleaned_annotation = annotation_text.strip() store.update_status( item.item_id, TriageStatus.UNDER_REVIEW, current_user, cleaned_annotation or None, ) _record_action( item_id=item.item_id, action="triage", status=TriageStatus.UNDER_REVIEW, comment=cleaned_annotation or None, ) st.success("Item triaged") if reject_col.button("Reject", key=f"reject_btn_{item.item_id}"): cleaned_annotation = annotation_text.strip() decision_comment = ( f"Rejected: {cleaned_annotation}" if cleaned_annotation else "Rejected" ) store.update_status(item.item_id, TriageStatus.RESOLVED, current_user, decision_comment) _record_action( item_id=item.item_id, action="reject", status=TriageStatus.RESOLVED, comment=decision_comment, ) st.success("Item rejected") if approve_col.button("Approve", key=f"approve_btn_{item.item_id}"): cleaned_annotation = annotation_text.strip() decision_comment = ( f"Approved: {cleaned_annotation}" if cleaned_annotation else "Approved" ) store.update_status(item.item_id, TriageStatus.RESOLVED, current_user, decision_comment) _record_action( item_id=item.item_id, action="approve", status=TriageStatus.RESOLVED, comment=decision_comment, ) st.success("Item approved")