feat: restore st.dataframe for report list with sorting and filtering, and add selectbox back with bidirectional sync

This commit is contained in:
unknown
2026-06-24 16:31:23 +09:00
parent fffa1394c7
commit bf0d4599d6
+56 -30
View File
@@ -782,45 +782,71 @@ def page_history():
if st.session_state["selected_analysis_id"] not in valid_ids and records:
st.session_state["selected_analysis_id"] = records[0]["id"]
st.write("### 📋 분석 이력 목록")
st.caption("💡 아래 목록에서 **원하는 행(보고서 카드)**을 누르시면 하단의 상세 분석 내역이 즉시 갱신됩니다.")
# 이력 테이블 데이터 포맷팅
status_emoji = {"critical": "🔴", "warning": "🟡", "healthy": "🟢"}
table_data = [{
"ID": r["id"],
"분석일시": r["created_at"],
"상태": f"{status_emoji.get(r['overall_status'], '')} {r['overall_status']}",
"파일명": r["filename"][:40],
"GPU 수": r["gpu_count"],
"XID": r["xid_count"],
"심각": r["critical_count"],
"경고": r["warning_count"],
"드라이버": r["driver_version"],
"메모": (r.get("memo") or "")[:50],
} for r in records]
# 1. 표의 각 열 이름(헤더) 배치 (가로 비율 칼정렬)
h_col1, h_col2, h_col3 = st.columns([1.2, 1.0, 1.2])
h_col1.markdown("**🟢 상태 & 보고서 파일명**")
h_col2.markdown("**🕒 분석 일시**")
h_col3.markdown("**📊 요약 통계 (GPU / XID / RMA)**")
st.markdown("<hr style='margin: 0.1rem 0 0.5rem 0; border: 1px dashed #76b900;'>", unsafe_allow_html=True)
st.write("### 📋 분석 이력 테이블 목록")
st.caption("💡 표 왼쪽 끝의 **동그라미 선택항목(라디오 버튼)**을 클릭하시거나, 하단 드롭다운에서 보고서를 선택하시면 상세 내역이 표시됩니다.")
# 2. 스크롤 가능한 컨테이너 내부에 라디오 버튼이 없는 가로형 통짜 클릭 행 렌더링
with st.container(height=380):
for r in records:
emoji = status_emoji.get(r['overall_status'], '🟢')
is_selected = (r["id"] == st.session_state["selected_analysis_id"])
# 행 전체를 하나의 널찍한 버튼으로 구성 (마우스 클릭 영역 극대화)
# 라벨 포맷: 상태이모지 | 파일명 | 분석일시 | 요약통계
btn_label = (
f"{emoji} [ID: {r['id']}] {r['filename'][:30]} | "
f"🕒 {r['created_at']} | "
f"🎮 GPU {r['gpu_count']}개 / ⚠️ XID {r['xid_count']}건 / 🔧 RMA {r['rma_count']}"
# st.dataframe의 selection 기능을 사용하여 마우스 행 선택 감지 및 Rerun 트리거
df_display = pd.DataFrame(table_data)
selection_event = st.dataframe(
df_display,
use_container_width=True,
hide_index=True,
selection_mode="single-row",
on_select="rerun",
key="history_table"
)
# 버튼 클릭 시 해당 보고서 ID로 세션 상태를 저장하고 화면 갱신
if st.button(
btn_label,
key=f"btn_row_{r['id']}",
use_container_width=True,
type="primary" if is_selected else "secondary"
):
st.session_state["selected_analysis_id"] = r["id"]
st.rerun()
# 테이블에서 마우스 클릭으로 행을 선택했을 때 세션 상태 ID 갱신
selected_rows = selection_event.get("selection", {}).get("rows", [])
if selected_rows:
selected_row_idx = selected_rows[0]
if selected_row_idx < len(records):
st.session_state["selected_analysis_id"] = records[selected_row_idx]["id"]
# 상세 조회
st.markdown("---")
st.subheader("🔎 상세 조회")
# 보고서 선택을 돕는 UI 개선: 드롭다운 선택박스 제공
history_options = [
(r["id"], f"[ID: {r['id']}] {status_emoji.get(r['overall_status'], '')} {r['filename'][:30]} ({r['created_at']})")
for r in records
]
# 현재 선택된 ID에 해당하는 옵션의 인덱스 찾기 (양방향 연동용)
default_index = 0
for idx, opt in enumerate(history_options):
if opt[0] == st.session_state["selected_analysis_id"]:
default_index = idx
break
selected_option = st.selectbox(
"조회할 보고서 선택",
options=history_options,
index=default_index,
format_func=lambda x: x[1]
)
if selected_option:
st.session_state["selected_analysis_id"] = selected_option[0]
selected_id = st.session_state["selected_analysis_id"]
detail = get_analysis_detail(selected_id)
if not detail: