diff --git a/src/gui_2.py b/src/gui_2.py index 1e42dc1..c62af10 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -89,6 +89,7 @@ class App: if not hasattr(self.controller, 'PROVIDERS'): self.controller.PROVIDERS = PROVIDERS self.controller.init_state() + self.show_windows.setdefault("Diagnostics", False) self.controller.start_services(self) # Aliases for controller-owned locks self._send_thread_lock = self.controller._send_thread_lock @@ -511,6 +512,9 @@ class App: self._render_log_management() if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_log_management") + if self.show_windows.get("Diagnostics", False): + self._render_diagnostics_panel() + self.perf_monitor.end_frame() # ---- Modals / Popups with self._pending_dialog_lock: @@ -999,170 +1003,176 @@ class App: imgui.end() return - if imgui.begin_tab_bar("log_mgmt_tabs"): - if imgui.begin_tab_item("Sessions")[0]: - if self._log_registry is None: - self._log_registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml")) + if self._log_registry is None: + self._log_registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml")) + else: + if imgui.button("Refresh Registry"): + self._log_registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml")) + imgui.same_line() + if imgui.button("Load Log"): + self.cb_load_prior_log() + imgui.same_line() + if imgui.button("Force Prune Logs"): + self.controller.event_queue.put("gui_task", {"action": "click", "item": "btn_prune_logs"}) + + registry = self._log_registry + sessions = registry.data + if imgui.begin_table("sessions_table", 7, imgui.TableFlags_.borders | imgui.TableFlags_.row_bg | imgui.TableFlags_.resizable): + imgui.table_setup_column("Session ID") + imgui.table_setup_column("Start Time") + imgui.table_setup_column("Star") + imgui.table_setup_column("Reason") + imgui.table_setup_column("Size (KB)") + imgui.table_setup_column("Msgs") + imgui.table_setup_column("Actions") + imgui.table_headers_row() + for session_id, s_data in sessions.items(): + imgui.table_next_row() + imgui.table_next_column() + imgui.text(session_id) + imgui.table_next_column() + imgui.text(s_data.get("start_time", "")) + imgui.table_next_column() + whitelisted = s_data.get("whitelisted", False) + if whitelisted: + imgui.text_colored(vec4(255, 215, 0), "YES") else: - if imgui.button("Refresh Registry"): - self._log_registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml")) - imgui.same_line() - if imgui.button("Load Log"): - self.cb_load_prior_log() + imgui.text("NO") + metadata = s_data.get("metadata") or {} + imgui.table_next_column() + imgui.text(metadata.get("reason", "")) + imgui.table_next_column() + imgui.text(str(metadata.get("size_kb", ""))) + imgui.table_next_column() + imgui.text(str(metadata.get("message_count", ""))) + imgui.table_next_column() + if imgui.button(f"Load##{session_id}"): + self.cb_load_prior_log(s_data.get("path")) imgui.same_line() - if imgui.button("Force Prune Logs"): - self.controller.event_queue.put("gui_task", {"action": "click", "item": "btn_prune_logs"}) - - registry = self._log_registry - sessions = registry.data - if imgui.begin_table("sessions_table", 7, imgui.TableFlags_.borders | imgui.TableFlags_.row_bg | imgui.TableFlags_.resizable): - imgui.table_setup_column("Session ID") - imgui.table_setup_column("Start Time") - imgui.table_setup_column("Star") - imgui.table_setup_column("Reason") - imgui.table_setup_column("Size (KB)") - imgui.table_setup_column("Msgs") - imgui.table_setup_column("Actions") - imgui.table_headers_row() - for session_id, s_data in sessions.items(): - imgui.table_next_row() - imgui.table_next_column() - imgui.text(session_id) - imgui.table_next_column() - imgui.text(s_data.get("start_time", "")) - imgui.table_next_column() - whitelisted = s_data.get("whitelisted", False) - if whitelisted: - imgui.text_colored(vec4(255, 215, 0), "YES") - else: - imgui.text("NO") - metadata = s_data.get("metadata") or {} - imgui.table_next_column() - imgui.text(metadata.get("reason", "")) - imgui.table_next_column() - imgui.text(str(metadata.get("size_kb", ""))) - imgui.table_next_column() - imgui.text(str(metadata.get("message_count", ""))) - imgui.table_next_column() - if imgui.button(f"Load##{session_id}"): - self.cb_load_prior_log(s_data.get("path")) - imgui.same_line() - if whitelisted: - if imgui.button(f"Unstar##{session_id}"): - registry.update_session_metadata( - session_id, - message_count=int(metadata.get("message_count") or 0), - errors=int(metadata.get("errors") or 0), - size_kb=int(metadata.get("size_kb") or 0), - whitelisted=False, - reason=str(metadata.get("reason") or "") - ) - else: - if imgui.button(f"Star##{session_id}"): - registry.update_session_metadata( - session_id, - message_count=int(metadata.get("message_count") or 0), - errors=int(metadata.get("errors") or 0), - size_kb=int(metadata.get("size_kb") or 0), - whitelisted=True, - reason="Manually whitelisted" - ) - imgui.end_table() - imgui.end_tab_item() - - if imgui.begin_tab_item("System Diagnostics")[0]: - metrics = self.perf_monitor.get_metrics() - imgui.text("Performance Telemetry") - imgui.same_line() - _, self.perf_profiling_enabled = imgui.checkbox("Enable Profiling", self.perf_profiling_enabled) - imgui.separator() - - if imgui.begin_table("perf_table", 3, imgui.TableFlags_.borders_inner_h): - imgui.table_setup_column("Metric") - imgui.table_setup_column("Value") - imgui.table_setup_column("Graph") - imgui.table_headers_row() - - for label, key, format_str in [ - ("FPS", "fps", "%.1f"), - ("Frame Time (ms)", "frame_time_ms", "%.2f"), - ("CPU %", "cpu_percent", "%.1f"), - ("Input Lag (ms)", "input_lag_ms", "%.1f") - ]: - imgui.table_next_row() - imgui.table_next_column() - imgui.text(label) - imgui.table_next_column() - if key == "fps": - avg_val = imgui.get_io().framerate - else: - avg_val = metrics.get(f"{key}_avg", metrics.get(key, 0.0)) - imgui.text(format_str % avg_val) - imgui.table_next_column() - self.perf_show_graphs.setdefault(key, False) - _, self.perf_show_graphs[key] = imgui.checkbox(f"##g_{key}", self.perf_show_graphs[key]) - imgui.end_table() - - if self.perf_profiling_enabled: - imgui.separator() - imgui.text("Detailed Component Timings (Moving Average)") - if imgui.begin_table("comp_timings", 3, imgui.TableFlags_.borders): - imgui.table_setup_column("Component") - imgui.table_setup_column("Avg (ms)") - imgui.table_setup_column("Graph") - imgui.table_headers_row() - for key, val in metrics.items(): - if key.startswith("time_") and key.endswith("_ms") and not key.endswith("_avg"): - comp_name = key[5:-3] - avg_val = metrics.get(f"{key}_avg", val) - imgui.table_next_row() - imgui.table_next_column() - imgui.text(comp_name) - imgui.table_next_column() - if avg_val > 10.0: - imgui.text_colored(imgui.ImVec4(1.0, 0.2, 0.2, 1.0), f"{avg_val:.2f}") - else: - imgui.text(f"{avg_val:.2f}") - imgui.table_next_column() - self.perf_show_graphs.setdefault(comp_name, False) - _, self.perf_show_graphs[comp_name] = imgui.checkbox(f"##g_{comp_name}", self.perf_show_graphs[comp_name]) - imgui.end_table() - - imgui.separator() - imgui.text("Performance Graphs") - for key, show in self.perf_show_graphs.items(): - if show: - imgui.text(f"History: {key}") - hist_data = self.perf_monitor.get_history(key) - if hist_data: - import numpy as np - imgui.plot_lines(f"##plot_{key}", np.array(hist_data, dtype=np.float32), graph_size=imgui.ImVec2(-1, 60)) - else: - imgui.text_disabled(f"(no history data for {key})") - - imgui.separator() - imgui.text("Diagnostic Log") - if imgui.begin_table("diag_log_table", 3, imgui.TableFlags_.borders | imgui.TableFlags_.row_bg | imgui.TableFlags_.resizable): - imgui.table_setup_column("Timestamp", imgui.TableColumnFlags_.width_fixed, 150) - imgui.table_setup_column("Type", imgui.TableColumnFlags_.width_fixed, 100) - imgui.table_setup_column("Message") - imgui.table_headers_row() - for entry in reversed(self.controller.diagnostic_log): - imgui.table_next_row() - imgui.table_next_column() - imgui.text(entry.get("ts", "")) - imgui.table_next_column() - imgui.text(entry.get("type", "")) - imgui.table_next_column() - imgui.text_wrapped(entry.get("message", "")) - imgui.end_table() - - imgui.end_tab_item() - imgui.end_tab_bar() + if whitelisted: + if imgui.button(f"Unstar##{session_id}"): + registry.update_session_metadata( + session_id, + message_count=int(metadata.get("message_count") or 0), + errors=int(metadata.get("errors") or 0), + size_kb=int(metadata.get("size_kb") or 0), + whitelisted=False, + reason=str(metadata.get("reason") or "") + ) + else: + if imgui.button(f"Star##{session_id}"): + registry.update_session_metadata( + session_id, + message_count=int(metadata.get("message_count") or 0), + errors=int(metadata.get("errors") or 0), + size_kb=int(metadata.get("size_kb") or 0), + whitelisted=True, + reason="Manually whitelisted" + ) + imgui.end_table() if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_log_management") imgui.end() + def _render_diagnostics_panel(self) -> None: + if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_diagnostics_panel") + exp, opened = imgui.begin("Diagnostics", self.show_windows.get("Diagnostics", False)) + self.show_windows["Diagnostics"] = bool(opened) + if not exp: + imgui.end() + if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_diagnostics_panel") + return + + metrics = self.perf_monitor.get_metrics() + imgui.text("Performance Telemetry") + imgui.same_line() + _, self.perf_profiling_enabled = imgui.checkbox("Enable Profiling", self.perf_profiling_enabled) + imgui.separator() + + if imgui.begin_table("perf_table", 3, imgui.TableFlags_.borders_inner_h): + imgui.table_setup_column("Metric") + imgui.table_setup_column("Value") + imgui.table_setup_column("Graph") + imgui.table_headers_row() + + for label, key, format_str in [ + ("FPS", "fps", "%.1f"), + ("Frame Time (ms)", "frame_time_ms", "%.2f"), + ("CPU %", "cpu_percent", "%.1f"), + ("Input Lag (ms)", "input_lag_ms", "%.1f") + ]: + imgui.table_next_row() + imgui.table_next_column() + imgui.text(label) + imgui.table_next_column() + if key == "fps": + avg_val = imgui.get_io().framerate + else: + avg_val = metrics.get(f"{key}_avg", metrics.get(key, 0.0)) + imgui.text(format_str % avg_val) + imgui.table_next_column() + self.perf_show_graphs.setdefault(key, False) + _, self.perf_show_graphs[key] = imgui.checkbox(f"##g_{key}", self.perf_show_graphs[key]) + imgui.end_table() + + if self.perf_profiling_enabled: + imgui.separator() + imgui.text("Detailed Component Timings (Moving Average)") + if imgui.begin_table("comp_timings", 3, imgui.TableFlags_.borders): + imgui.table_setup_column("Component") + imgui.table_setup_column("Avg (ms)") + imgui.table_setup_column("Graph") + imgui.table_headers_row() + for key, val in metrics.items(): + if key.startswith("time_") and key.endswith("_ms") and not key.endswith("_avg"): + comp_name = key[5:-3] + avg_val = metrics.get(f"{key}_avg", val) + imgui.table_next_row() + imgui.table_next_column() + imgui.text(comp_name) + imgui.table_next_column() + if avg_val > 10.0: + imgui.text_colored(imgui.ImVec4(1.0, 0.2, 0.2, 1.0), f"{avg_val:.2f}") + else: + imgui.text(f"{avg_val:.2f}") + imgui.table_next_column() + self.perf_show_graphs.setdefault(comp_name, False) + _, self.perf_show_graphs[comp_name] = imgui.checkbox(f"##g_{comp_name}", self.perf_show_graphs[comp_name]) + imgui.end_table() + + imgui.separator() + imgui.text("Performance Graphs") + for key, show in self.perf_show_graphs.items(): + if show: + imgui.text(f"History: {key}") + hist_data = self.perf_monitor.get_history(key) + if hist_data: + import numpy as np + imgui.plot_lines(f"##plot_{key}", np.array(hist_data, dtype=np.float32), graph_size=imgui.ImVec2(-1, 60)) + else: + imgui.text_disabled(f"(no history data for {key})") + + imgui.separator() + imgui.text("Diagnostic Log") + if imgui.begin_table("diag_log_table", 3, imgui.TableFlags_.borders | imgui.TableFlags_.row_bg | imgui.TableFlags_.resizable): + imgui.table_setup_column("Timestamp", imgui.TableColumnFlags_.width_fixed, 150) + imgui.table_setup_column("Type", imgui.TableColumnFlags_.width_fixed, 100) + imgui.table_setup_column("Message") + imgui.table_headers_row() + for entry in reversed(self.controller.diagnostic_log): + imgui.table_next_row() + imgui.table_next_column() + imgui.text(entry.get("ts", "")) + imgui.table_next_column() + imgui.text(entry.get("type", "")) + imgui.table_next_column() + imgui.text_wrapped(entry.get("message", "")) + imgui.end_table() + + if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_diagnostics_panel") + imgui.end() + + def _render_files_panel(self) -> None: if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_files_panel") imgui.text("Paths")