feat: restore st.dataframe for report list with sorting and filtering, and add selectbox back with bidirectional sync
This commit is contained in:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user