handle errors better

This commit is contained in:
Joe Fleming
2026-03-08 13:41:35 -06:00
parent 1af934cc9e
commit d04af8d6dc
3 changed files with 31 additions and 12 deletions

25
app.py
View File

@@ -282,6 +282,12 @@ class SessionMoverApp(App):
color: $text; color: $text;
} }
#current-selection.error {
background: $error;
color: $text;
text-style: bold;
}
#selection-count { #selection-count {
height: auto; height: auto;
padding: 1; padding: 1;
@@ -385,10 +391,13 @@ class SessionMoverApp(App):
self.db.connect() self.db.connect()
self.db.load_reference_data() self.db.load_reference_data()
except FileNotFoundError as e: except FileNotFoundError as e:
self.notify(str(e), severity="error", timeout=10) widget = self.query_one("#current-selection", Static)
self.set_timer(1, self.exit) widget.add_class("error")
widget.update(f"Error: {e}\n\nPress q to quit.")
self._db_error = True
return return
self._db_error = False
self._project_ids: List[str] = [] self._project_ids: List[str] = []
self.refresh_project_list() self.refresh_project_list()
@@ -398,15 +407,14 @@ class SessionMoverApp(App):
self.query_one("#archived-toggle", Button).can_focus = False self.query_one("#archived-toggle", Button).can_focus = False
# Setup sessions table (but don't load data yet) # Setup sessions table (but don't load data yet)
table = self.query_one("#sessions-table") table = self.query_one("#sessions-table", DataTable)
table.zebra_stripes = True table.zebra_stripes = True
table.cursor_type = "row" table.cursor_type = "row"
table.show_cursor = False table.show_cursor = False
table.add_columns(" ", "ID", "Title", "Project", "Workspace", "Msgs", "Created") table.add_columns(" ", "ID", "Title", "Project", "Workspace", "Msgs", "Created")
# Don't load sessions until a project is selected # Don't load sessions until a project is selected
status = self.query_one("#current-selection") self.query_one("#current-selection", Static).update("Select a project from the left")
status.update("Select a project from the left")
def on_input_changed(self, event: Input.Changed) -> None: def on_input_changed(self, event: Input.Changed) -> None:
if event.input.id == "filter-input": if event.input.id == "filter-input":
@@ -655,6 +663,11 @@ class SessionMoverApp(App):
self.refresh_sessions() self.refresh_sessions()
self.notify("Data refreshed", severity="information") self.notify("Data refreshed", severity="information")
async def action_quit(self) -> None:
"""Exit the app, with a non-zero return code if there was a DB error."""
return_code = 1 if getattr(self, "_db_error", False) else 0
self.exit(return_code)
def on_unmount(self) -> None: def on_unmount(self) -> None:
"""Cleanup on exit.""" """Cleanup on exit."""
self.db.close() self.db.close()

View File

@@ -74,7 +74,8 @@ class Database:
def load_reference_data(self): def load_reference_data(self):
"""Load projects and workspaces into memory for fast lookups.""" """Load projects and workspaces into memory for fast lookups."""
assert self.conn is not None if self.conn is None:
raise RuntimeError("Database is not connected. Call connect() first.")
cursor = self.conn.cursor() cursor = self.conn.cursor()
# Load projects # Load projects
@@ -125,7 +126,8 @@ class Database:
Returns: Returns:
List of Session objects with computed counts List of Session objects with computed counts
""" """
assert self.conn is not None, "Database not connected" if self.conn is None:
raise RuntimeError("Database is not connected. Call connect() first.")
cursor = self.conn.cursor() cursor = self.conn.cursor()
query = """ query = """
@@ -205,7 +207,8 @@ class Database:
def get_session_counts_by_project(self) -> dict: def get_session_counts_by_project(self) -> dict:
"""Return a dict of project_id -> active session count.""" """Return a dict of project_id -> active session count."""
assert self.conn is not None if self.conn is None:
raise RuntimeError("Database is not connected. Call connect() first.")
cursor = self.conn.cursor() cursor = self.conn.cursor()
cursor.execute( cursor.execute(
"SELECT project_id, COUNT(*) FROM session WHERE time_archived IS NULL GROUP BY project_id" "SELECT project_id, COUNT(*) FROM session WHERE time_archived IS NULL GROUP BY project_id"
@@ -228,7 +231,8 @@ class Database:
Returns: Returns:
(success, list of SQL statements executed) (success, list of SQL statements executed)
""" """
assert self.conn is not None, "Database not connected" if self.conn is None:
raise RuntimeError("Database is not connected. Call connect() first.")
cursor = self.conn.cursor() cursor = self.conn.cursor()
# Verify target project exists # Verify target project exists
@@ -265,7 +269,8 @@ class Database:
Returns: Returns:
(success, list of SQL statements, list of new session IDs) (success, list of SQL statements, list of new session IDs)
""" """
assert self.conn is not None, "Database not connected" if self.conn is None:
raise RuntimeError("Database is not connected. Call connect() first.")
import uuid import uuid
cursor = self.conn.cursor() cursor = self.conn.cursor()
@@ -355,7 +360,8 @@ class Database:
Returns: Returns:
(success, error_message) (success, error_message)
""" """
assert self.conn is not None, "Database not connected" if self.conn is None:
raise RuntimeError("Database is not connected. Call connect() first.")
cursor = self.conn.cursor() cursor = self.conn.cursor()
try: try:

0
session-mover.py Normal file → Executable file
View File