diff --git a/codex_retry_gateway_tui.py b/codex_retry_gateway_tui.py index 16ab066..d69e231 100644 --- a/codex_retry_gateway_tui.py +++ b/codex_retry_gateway_tui.py @@ -1100,6 +1100,10 @@ def run_textual(api_url: str, status_url: str, refresh_seconds: int, timeout: in ("2", "show_requests", "Requests"), ("3", "show_logs", "Logs"), ("4", "show_profiles", "Profiles"), + ("shift+left", "scroll_table_left", "Scroll Left"), + ("shift+right", "scroll_table_right", "Scroll Right"), + ("[", "narrow_usage_column", "Narrow Usage"), + ("]", "widen_usage_column", "Widen Usage"), ("e", "edit_profile", "Edit Profile"), ("p", "probe_profile", "Probe Profile"), ("s", "switch_profile", "Switch Profile"), @@ -1133,6 +1137,8 @@ def run_textual(api_url: str, status_url: str, refresh_seconds: int, timeout: in "logs": "logs", "profiles": "profiles", } + self.request_table_column_keys: dict[str, Any] = {} + self.request_usage_width = 36 def compose(self) -> ComposeResult: yield Header(show_clock=True) @@ -1152,7 +1158,23 @@ def run_textual(api_url: str, status_url: str, refresh_seconds: int, timeout: in requests = self.query_one("#requests_table", DataTable) requests.cursor_type = "row" requests.zebra_stripes = True - requests.add_columns("Seq", "ID", "Thread", "Started", "Status", "Path", "Model", "Reasoning", "Usage", "Resp", "Chunks", "First", "Duration", "Updated", "Note") + self.request_table_column_keys = { + "seq": requests.add_column("Seq", width=7, key="seq"), + "id": requests.add_column("ID", width=18, key="id"), + "thread": requests.add_column("Thread", width=18, key="thread"), + "started": requests.add_column("Started", width=19, key="started"), + "status": requests.add_column("Status", width=7, key="status"), + "path": requests.add_column("Path", width=22, key="path"), + "model": requests.add_column("Model", width=16, key="model"), + "reasoning": requests.add_column("Reasoning", width=10, key="reasoning"), + "usage": requests.add_column("Usage", width=self.request_usage_width, key="usage"), + "resp": requests.add_column("Resp", width=10, key="resp"), + "chunks": requests.add_column("Chunks", width=14, key="chunks"), + "first": requests.add_column("First", width=8, key="first"), + "duration": requests.add_column("Duration", width=8, key="duration"), + "updated": requests.add_column("Updated", width=8, key="updated"), + "note": requests.add_column("Note", width=22, key="note"), + } logs = self.query_one("#logs_table", DataTable) logs.cursor_type = "row" @@ -1178,7 +1200,7 @@ def run_textual(api_url: str, status_url: str, refresh_seconds: int, timeout: in self.query_one("#logs_table").display = active_table == "logs" self.query_one("#profiles_table").display = active_table == "profiles" self.query_one("#controls", Static).update( - "views: 1 overview | 2 requests | 3 logs | 4 profiles | / filter | r refresh | e edit | p probe | s switch | w save | d delete | u open upstream" + "views: 1 overview | 2 requests | 3 logs | 4 profiles | / filter | r refresh | [ ] usage width | Shift-Left/Right scroll | e edit | p probe | s switch | w save | d delete | u open upstream" ) self._focus_table() self._update_table_headers() @@ -1418,6 +1440,34 @@ def run_textual(api_url: str, status_url: str, refresh_seconds: int, timeout: in def action_focus_profiles(self) -> None: self._set_view("profiles") + def _set_request_usage_width(self, width: int) -> None: + table = self.query_one("#requests_table", DataTable) + key = self.request_table_column_keys.get("usage") + column = table.columns.get(key) if key is not None else None + if column is None: + self._set_status("usage column not ready") + return + self.request_usage_width = max(18, min(80, width)) + column.width = self.request_usage_width + table.refresh(layout=True) + self._set_status(f"usage column width {self.request_usage_width}") + + def action_widen_usage_column(self) -> None: + self._set_request_usage_width(self.request_usage_width + 4) + + def action_narrow_usage_column(self) -> None: + self._set_request_usage_width(self.request_usage_width - 4) + + def action_scroll_table_left(self) -> None: + table = self._current_table_widget() + if table: + table.action_scroll_left() + + def action_scroll_table_right(self) -> None: + table = self._current_table_widget() + if table: + table.action_scroll_right() + def action_open_upstream(self) -> None: row = self._selected_profile_row() if not row: