From bf0d4599d61207e9563536467c64e5e10ae347e6 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Jun 2026 16:31:23 +0900 Subject: [PATCH] feat: restore st.dataframe for report list with sorting and filtering, and add selectbox back with bidirectional sync --- app.py | 90 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 32 deletions(-) diff --git a/app.py b/app.py index 78d1cac..3fc5946 100644 --- a/app.py +++ b/app.py @@ -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("
", 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']}๋Œ€" - ) - - # ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ•ด๋‹น ๋ณด๊ณ ์„œ 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() + # 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 ๊ฐฑ์‹  + 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: