diff --git a/hamstertools/app.py b/hamstertools/app.py index 3836cc7..d595795 100644 --- a/hamstertools/app.py +++ b/hamstertools/app.py @@ -1,16 +1,15 @@ from textual.app import App, ComposeResult -from textual.widgets import Header, Footer, DataTable +from textual.widgets import Header, Footer, DataTable, Placeholder from textual.coordinate import Coordinate +from textual.screen import Screen -class HamsterToolsApp(App): - """A Textual app to manage stopwatches.""" - +class ActivitiesScreen(Screen): BINDINGS = [ ("q", "quit", "Quit"), ("s", "sort", "Sort"), ("r", "refresh", "Refresh"), - ("d", "delete_activity", "Delete activity"), + ("d", "delete", "Delete activity"), ] def __init__(self, db_cursor, db_connection): @@ -22,28 +21,28 @@ class HamsterToolsApp(App): self.table.clear() sql = ''' - SELECT - categories.id AS category_id, - COALESCE(categories.name, '') AS category_name, - activities.id AS activity_id, - activities.name AS activity_name, - COALESCE(facts_count, 0) AS total_facts - FROM + select + categories.id as category_id, + coalesce(categories.name, '') as category_name, + activities.id as activity_id, + activities.name as activity_name, + coalesce(facts_count, 0) as total_facts + from activities - LEFT JOIN + left join categories - ON + on activities.category_id = categories.id - LEFT JOIN ( - SELECT + left join ( + select activity_id, - COUNT(*) AS facts_count - FROM + count(*) as facts_count + from facts - GROUP BY + group by activity_id - ) AS facts_count_subquery - ON + ) as facts_count_subquery + on activities.id = facts_count_subquery.activity_id; ''' @@ -54,7 +53,7 @@ class HamsterToolsApp(App): self.table.sort(self.columns[1], self.columns[3]) def compose(self) -> ComposeResult: - """Create child widgets for the app.""" + """create child widgets for the app.""" yield Header() yield DataTable() yield Footer() @@ -62,36 +61,152 @@ class HamsterToolsApp(App): def on_mount(self) -> None: self.table = self.query_one(DataTable) self.table.cursor_type = "row" - self.columns = self.table.add_columns("category id","category","activity ID","activity","entries") + self.columns = self.table.add_columns("category id","category","activity id","activity","entries") self._refresh() - def action_quit(self) -> None: - self.exit() - def action_refresh(self) -> None: self._refresh() def action_sort(self) -> None: self.table.cursor_type = "column" - def action_delete_activity(self) -> None: - # Get the keys for the row and column under the cursor. + def action_delete(self) -> None: + # get the keys for the row and column under the cursor. row_key, _ = self.table.coordinate_to_cell_key(self.table.cursor_coordinate) activity_id = self.table.get_cell_at( Coordinate(self.table.cursor_coordinate.row, 2), ) - sql = 'DELETE FROM activities WHERE id = ?' + sql = 'delete from activities where id = ?' print(Coordinate(2, self.table.cursor_coordinate.row),) print(activity_id) self.db_cursor.execute(sql, (activity_id,)) self.db_connection.commit() - # Supply the row key to `remove_row` to delete the row. + # supply the row key to `remove_row` to delete the row. self.table.remove_row(row_key) def on_data_table_column_selected(self, event): event.data_table.sort(event.column_key) event.data_table.cursor_type = "row" + + +class CategoriesScreen(Screen): + BINDINGS = [ + ("s", "sort", "Sort"), + ("r", "refresh", "Refresh"), + ("d", "delete", "Delete category"), + ] + + def __init__(self, db_cursor, db_connection): + self.db_cursor = db_cursor + self.db_connection = db_connection + super().__init__() + + def _refresh(self): + self.table.clear() + + sql = ''' + select + categories.id as category_id, + coalesce(categories.name, '') as category_name, + coalesce(activities_count, 0) as total_activities + from + categories + left join ( + select + category_id, + count(*) as activities_count + from + activities + group by + category_id + ) as activities_count_subquery + on + categories.id = activities_count_subquery.category_id; + ''' + + results = self.db_cursor.execute(sql) + # results = [[cell or "" for cell in row] for row in self.db_cursor.fetchall()] + + self.table.add_rows(results) + self.table.sort(self.columns[1]) + + def compose(self) -> ComposeResult: + """create child widgets for the app.""" + yield Header() + yield DataTable() + yield Footer() + + def on_mount(self) -> None: + self.table = self.query_one(DataTable) + self.table.cursor_type = "row" + self.columns = self.table.add_columns("category id","category","activities") + self._refresh() + + def action_refresh(self) -> None: + self._refresh() + + def action_sort(self) -> None: + self.table.cursor_type = "column" + + def action_delete(self) -> None: + # get the keys for the row and column under the cursor. + row_key, _ = self.table.coordinate_to_cell_key(self.table.cursor_coordinate) + + category_id = self.table.get_cell_at( + Coordinate(self.table.cursor_coordinate.row, 0), + ) + + sql = 'delete from categories where id = ?' + print(Coordinate(2, self.table.cursor_coordinate.row),) + print(category_id) + + self.db_cursor.execute(sql, (category_id,)) + self.db_connection.commit() + + # supply the row key to `remove_row` to delete the row. + self.table.remove_row(row_key) + + def on_data_table_column_selected(self, event): + event.data_table.sort(event.column_key) + event.data_table.cursor_type = "row" + +# class KimaiScreen(Screen): +# def compose(self) -> ComposeResult: +# yield Placeholder("Help Screen") +# yield Footer() +# +# def __init__(self, db_cursor, db_connection): +# self.db_cursor = db_cursor +# self.db_connection = db_connection +# super().__init__() + + +class HamsterToolsApp(App): + BINDINGS = [ + ("a", "switch_mode('activities')", "Activities"), + ("c", "switch_mode('categories')", "Categories"), + # ("k", "switch_mode('kimai')", "Kimai"), + ("q", "quit", "Quit"), + ] + def __init__(self, db_cursor, db_connection): + self.db_cursor = db_cursor + self.db_connection = db_connection + + self.MODES = { + "categories": CategoriesScreen(db_cursor, db_connection), + "activities": ActivitiesScreen(db_cursor, db_connection), + # "kimai": KimaiScreen, + } + + super().__init__() + + def on_mount(self) -> None: + self.switch_mode("activities") + + def action_quit(self) -> None: + self.exit() +