hamster-tools/hamstertools/app.py

219 lines
6.6 KiB
Python
Raw Normal View History

2023-10-27 00:13:08 +00:00
from textual.app import App, ComposeResult
2023-10-27 03:04:30 +00:00
from textual.binding import Binding
from textual.widgets import Header, Footer, DataTable, Input
from textual.containers import Horizontal, Vertical
from textual.coordinate import Coordinate
2023-10-27 01:26:15 +00:00
from textual.screen import Screen
2023-10-27 03:04:30 +00:00
from textual.reactive import reactive
2023-10-27 00:13:08 +00:00
2023-10-27 03:04:30 +00:00
from .db import DatabaseManager, Category, Activity
2023-10-27 00:13:08 +00:00
2023-10-27 01:26:15 +00:00
class ActivitiesScreen(Screen):
2023-10-27 00:13:08 +00:00
BINDINGS = [
("q", "quit", "Quit"),
("s", "sort", "Sort"),
("r", "refresh", "Refresh"),
2023-10-27 01:26:15 +00:00
("d", "delete", "Delete activity"),
2023-10-27 03:04:30 +00:00
("/", "filter", "Search"),
Binding(key="escape", action="cancelfilter", show=False),
2023-10-27 00:13:08 +00:00
]
2023-10-27 03:04:30 +00:00
def __init__(self, db_manager):
self.db_manager = db_manager
2023-10-27 00:13:08 +00:00
super().__init__()
2023-10-27 03:04:30 +00:00
def _refresh(self, filter_query=None):
self.table.clear()
2023-10-27 00:13:08 +00:00
2023-10-27 03:04:30 +00:00
# List activities with the count of facts
activities = Activity.list_activities(self.db_manager, filter_query)
self.table.add_rows([[
activity.category_id,
activity.category_name,
activity.id,
activity.name,
activity.facts_count,
] for activity in activities])
self.table.sort(*self.sort)
def compose(self) -> ComposeResult:
2023-10-27 01:26:15 +00:00
"""create child widgets for the app."""
yield Header()
2023-10-27 03:04:30 +00:00
with Vertical():
yield DataTable()
with Horizontal():
yield Input(id="filter")
yield Footer()
2023-10-27 00:13:08 +00:00
def on_mount(self) -> None:
self.table = self.query_one(DataTable)
self.table.cursor_type = "row"
2023-10-27 01:26:15 +00:00
self.columns = self.table.add_columns("category id","category","activity id","activity","entries")
2023-10-27 03:04:30 +00:00
self.sort = (self.columns[1], self.columns[3])
self._refresh()
2023-10-27 00:13:08 +00:00
def action_refresh(self) -> None:
self._refresh()
def action_sort(self) -> None:
self.table.cursor_type = "column"
2023-10-27 03:04:30 +00:00
def action_filter(self) -> None:
filter_input = self.query_one("#filter")
filter_input.display = True
filter_input.focus()
print(filter_input)
def action_cancelfilter(self) -> None:
filter_input = self.query_one("#filter")
filter_input.display = False
self._refresh()
2023-10-27 01:26:15 +00:00
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),
)
2023-10-27 03:04:30 +00:00
activity = Activity.get_by_id(self.db_manager, activity_id)
activity.delete()
2023-10-27 01:26:15 +00:00
# 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):
2023-10-27 03:04:30 +00:00
self.sort = (event.column_key,)
event.data_table.sort(*self.sort)
event.data_table.cursor_type = "row"
2023-10-27 01:26:15 +00:00
2023-10-27 03:04:30 +00:00
def on_input_changed(self, event):
self._refresh(event.value)
2023-10-27 01:26:15 +00:00
class CategoriesScreen(Screen):
BINDINGS = [
("s", "sort", "Sort"),
("r", "refresh", "Refresh"),
("d", "delete", "Delete category"),
2023-10-27 03:04:30 +00:00
("/", "filter", "Search"),
Binding(key="escape", action="cancelfilter", show=False),
2023-10-27 01:26:15 +00:00
]
2023-10-27 03:04:30 +00:00
filtering = reactive(False)
filter_query = reactive("")
def __init__(self, db_manager):
self.db_manager = db_manager
2023-10-27 01:26:15 +00:00
super().__init__()
2023-10-27 03:04:30 +00:00
def _refresh(self, filter_query=None):
2023-10-27 01:26:15 +00:00
self.table.clear()
2023-10-27 03:04:30 +00:00
categories = Category.list_categories(self.db_manager,
filter_query=filter_query)
self.table.add_rows([[
category.id,
category.name,
category.activity_count,
] for category in categories])
self.table.sort(self.sort)
2023-10-27 01:26:15 +00:00
def compose(self) -> ComposeResult:
"""create child widgets for the app."""
yield Header()
2023-10-27 03:04:30 +00:00
with Vertical():
yield DataTable()
with Horizontal():
yield Input(id="filter")
2023-10-27 01:26:15 +00:00
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")
2023-10-27 03:04:30 +00:00
self.sort = self.columns[1]
2023-10-27 01:26:15 +00:00
self._refresh()
def action_refresh(self) -> None:
self._refresh()
def action_sort(self) -> None:
self.table.cursor_type = "column"
2023-10-27 03:04:30 +00:00
def action_filter(self) -> None:
filter_input = self.query_one("#filter")
filter_input.display = True
filter_input.focus()
print(filter_input)
def action_cancelfilter(self) -> None:
filter_input = self.query_one("#filter")
filter_input.display = False
self._refresh()
def on_input_changed(self, event):
self._refresh(event.value)
2023-10-27 01:26:15 +00:00
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),
)
2023-10-27 03:04:30 +00:00
category = Category.get_by_id(self.db_manager, category_id)
category.delete()
2023-10-27 01:26:15 +00:00
# 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):
2023-10-27 03:04:30 +00:00
""" Handle column selection for sort """
self.sort = event.column_key
event.data_table.sort(self.sort)
2023-10-27 01:26:15 +00:00
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):
2023-10-27 03:04:30 +00:00
CSS_PATH = 'app.tcss'
2023-10-27 01:26:15 +00:00
BINDINGS = [
("a", "switch_mode('activities')", "Activities"),
("c", "switch_mode('categories')", "Categories"),
# ("k", "switch_mode('kimai')", "Kimai"),
("q", "quit", "Quit"),
]
2023-10-27 03:04:30 +00:00
def __init__(self):
self.db_manager = DatabaseManager('hamster-testing.db')
2023-10-27 01:26:15 +00:00
self.MODES = {
2023-10-27 03:04:30 +00:00
"categories": CategoriesScreen(self.db_manager),
"activities": ActivitiesScreen(self.db_manager)
2023-10-27 01:26:15 +00:00
# "kimai": KimaiScreen,
}
super().__init__()
def on_mount(self) -> None:
self.switch_mode("activities")
def action_quit(self) -> None:
self.exit()
2023-10-27 03:04:30 +00:00
self.db_manager.close()