feat: design 2-column layout for report list and details, click report cards to render immediately

This commit is contained in:
unknown
2026-06-24 14:58:54 +09:00
parent 0920680fe9
commit f98c7ff3a2
+60 -67
View File
@@ -773,78 +773,71 @@ def page_history():
st.markdown("---") st.markdown("---")
# 세션 상태에 선택된 분석 ID 저장 및 동기화 초기화 # 세션 상태 보정 (현재 필터링된 목록에 세션 ID가 없으면 첫 번째 항목으로 강제 세팅)
if "selected_analysis_id" not in st.session_state: valid_ids = [r["id"] for r in records]
st.session_state["selected_analysis_id"] = records[0]["id"] if records else 1 if st.session_state["selected_analysis_id"] not in valid_ids and records:
st.session_state["selected_analysis_id"] = records[0]["id"]
# 이력 테이블 # 2컬럼 대시보드 레이아웃 구성
status_emoji = {"critical": "🔴", "warning": "🟡", "healthy": "🟢"} col_list, col_detail = st.columns([1, 2.5])
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]
# st.dataframe의 selection 기능을 사용하여 마우스 행 선택 감지 및 Rerun 트리거 # 1. 왼쪽 컬럼: 분석 이력 카드 버튼 목록 (마우스로 편하게 누르는 영역)
df_display = pd.DataFrame(table_data) with col_list:
selection_event = st.dataframe( st.write("### 📋 보고서 목록")
df_display, st.caption("아래 목록을 클릭하시면 상세 내역이 오른쪽에 즉시 표시됩니다.")
use_container_width=True, status_emoji = {"critical": "🔴", "warning": "🟡", "healthy": "🟢"}
hide_index=True,
selection_mode="single-row", with st.container(height=650):
on_select="rerun", for r in records:
key="history_table" emoji = status_emoji.get(r['overall_status'], '🟢')
) is_selected = (r["id"] == st.session_state["selected_analysis_id"])
# 선택된 보고서는 강조 표시
prefix = "▶️ " if is_selected else ""
btn_label = f"{prefix}{emoji} [ID: {r['id']}] {r['filename'][:23]}\n({r['created_at'].split()[0]})"
# 버튼으로 구현하여 일반 마우스 클릭이 100% 동작하도록 처리
if st.button(
btn_label,
key=f"btn_hist_{r['id']}",
use_container_width=True,
type="primary" if is_selected else "secondary"
):
st.session_state["selected_analysis_id"] = r["id"]
st.rerun()
# 테이블에서 마우스 클릭으로 행을 선택했을 때 세션 상태 ID 갱신 # 2. 오른쪽 컬럼: 선택된 보고서의 상세 분석 내용 렌더링
selected_rows = selection_event.get("selection", {}).get("rows", []) with col_detail:
if selected_rows: selected_id = st.session_state["selected_analysis_id"]
selected_row_idx = selected_rows[0] detail = get_analysis_detail(selected_id)
if selected_row_idx < len(records):
st.session_state["selected_analysis_id"] = records[selected_row_idx]["id"] if not detail:
else: st.warning(f"ID {selected_id}에 해당하는 분석 결과가 없습니다.")
# 선택 해제되었거나 최초 로딩 시, 기본적으로 가장 최근 분석(첫 번째 행)을 기본값으로 세팅 else:
valid_ids = [r["id"] for r in records] st.write(f"### 🔎 상세 분석 결과 (보고서 ID: {selected_id})")
if "selected_analysis_id" not in st.session_state or st.session_state["selected_analysis_id"] not in valid_ids:
st.session_state["selected_analysis_id"] = records[0]["id"] if records else 1 # 메모 편집 (editor/admin만)
perms = get_perms()
current_memo = detail.get("memo", "") or ""
if perms["can_edit_memo"]:
new_memo = st.text_area("📝 메모 수정", value=current_memo, key=f"memo_{selected_id}")
if new_memo != current_memo:
update_memo(selected_id, new_memo)
st.success("메모가 업데이트되었습니다.")
elif current_memo:
st.text_area("📝 메모", value=current_memo, key=f"memo_{selected_id}", disabled=True)
# 상세 조회 # 삭제 버튼 (admin만)
st.markdown("---") if perms["can_delete"]:
selected_id = st.session_state["selected_analysis_id"] if st.button("🗑️ 이 분석 기록 삭제", type="secondary"):
st.subheader(f"🔎 상세 조회 (보고서 ID: {selected_id})") delete_analysis(selected_id)
st.success(f"ID {selected_id} 삭제 완료.")
# 삭제 후 첫 번째 보고서로 세션 초기화 및 리런
st.session_state["selected_analysis_id"] = records[0]["id"] if len(records) > 1 else 1
st.rerun()
detail = get_analysis_detail(selected_id) # 상세 내용 렌더링 시작
if not detail: render_status_badge(detail["overall_status"])
st.warning(f"ID {selected_id}에 해당하는 분석 결과가 없습니다.")
return
# 메모 편집 (editor/admin만)
perms = get_perms()
current_memo = detail.get("memo", "") or ""
if perms["can_edit_memo"]:
new_memo = st.text_area("📝 메모 수정", value=current_memo, key=f"memo_{selected_id}")
if new_memo != current_memo:
update_memo(selected_id, new_memo)
st.success("메모가 업데이트되었습니다.")
elif current_memo:
st.text_area("📝 메모", value=current_memo, key=f"memo_{selected_id}", disabled=True)
# 삭제 버튼 (admin만)
if perms["can_delete"]:
if st.button("🗑️ 이 분석 기록 삭제", type="secondary"):
delete_analysis(selected_id)
st.success(f"ID {selected_id} 삭제 완료. 페이지를 새로고침하세요.")
return
# 상세 내용
render_status_badge(detail["overall_status"])
dc1, dc2, dc3, dc4 = st.columns(4) dc1, dc2, dc3, dc4 = st.columns(4)
dc1.metric("파일명", detail["filename"][:30]) dc1.metric("파일명", detail["filename"][:30])