diff --git a/hamstertools/app.py b/hamstertools/app.py index cb07d49..e429a41 100644 --- a/hamstertools/app.py +++ b/hamstertools/app.py @@ -1,3 +1,5 @@ +from datetime import datetime + from textual import on from textual.app import App, ComposeResult from textual.binding import Binding @@ -33,12 +35,13 @@ from .kimai import ( class ListScreen(Screen): def compose(self) -> ComposeResult: - """create child widgets for the app.""" yield Header() with Vertical(): yield DataTable() - with Horizontal(): - yield Input(id="filter") + with Horizontal(id="filter"): + yield Input(id="search", placeholder="Category/activity name contains text") + yield Input(id="date", + placeholder='After date, in {0} format'.format(datetime.now().strftime('%Y-%m-%d'))) yield Footer() def action_refresh(self) -> None: @@ -53,23 +56,24 @@ class ListScreen(Screen): event.data_table.cursor_type = "row" def action_filter(self) -> None: - filter_input = self.query_one("#filter") - filter_input.display = True - self._refresh(filter_input.value) - filter_input.focus() + self.query_one("#filter").display = True + self._refresh() + self.query_one("#filter #search").focus() def on_input_submitted(self, event): self.table.focus() def action_cancelfilter(self) -> None: - filter_input = self.query_one("#filter") - filter_input.display = False - filter_input.clear() + self.query_one("#filter").display = False + self.query_one("#filter #search").clear() + self.query_one("#filter #date").clear() self.table.focus() self._refresh() - def on_input_changed(self, event): - self._refresh(event.value) + @on(Input.Changed, '#filter Input') + def filter(self, event): + self._refresh() + class ActivityEditScreen(ModalScreen): @@ -244,7 +248,7 @@ class ActivityListScreen(ListScreen): Binding(key="escape", action="cancelfilter", show=False), ] - def _refresh(self, filter_query=None): + def _refresh(self): self.table.clear() facts_count_query = ( @@ -268,6 +272,7 @@ class ActivityListScreen(ListScreen): HamsterActivity.select( HamsterActivity, HamsterCategory.id, + HamsterFact.start_time, fn.COALESCE(HamsterCategory.name, "None").alias("category_name"), fn.COALESCE(facts_count_query.c.facts_count, 0).alias("facts_count"), fn.COALESCE(mappings_count_query.c.mappings_count, 0).alias( @@ -276,6 +281,8 @@ class ActivityListScreen(ListScreen): ) .join(HamsterCategory, JOIN.LEFT_OUTER) .switch(HamsterActivity) + .join(HamsterFact, JOIN.LEFT_OUTER) + .switch(HamsterActivity) .join( facts_count_query, JOIN.LEFT_OUTER, @@ -290,12 +297,22 @@ class ActivityListScreen(ListScreen): .group_by(HamsterActivity) ) - if filter_query: + filter_search = self.query_one('#filter #search').value + if filter_search is not None: activities = activities.where( - HamsterActivity.name.contains(filter_query) - | HamsterCategory.name.contains(filter_query) + HamsterActivity.name.contains(filter_search) + | HamsterCategory.name.contains(filter_search) ) + filter_date = self.query_one('#filter #date').value + if filter_date is not None: + try: + activities = activities.where( + HamsterFact.start_time > datetime.strptime(filter_date, '%Y-%m-%d') + ) + except ValueError: + pass + self.table.add_rows( [ [ @@ -355,8 +372,7 @@ class ActivityListScreen(ListScreen): HamsterFact.update({HamsterFact.activity: move_to_activity}).where( HamsterFact.activity == self.move_from_activity ).execute() - filter_input = self.query_one("#filter") - self._refresh(filter_input.value) + self._refresh() del self.move_from_activity def action_edit(self): @@ -388,8 +404,8 @@ class ActivityListScreen(ListScreen): hamster_activity=selected_activity, **mapping ) m.save() - filter_input = self.query_one("#filter") - self._refresh(filter_input.value) + filter_search = self.query_one("#search") + self._refresh() self.app.push_screen( ActivityMappingScreen( @@ -409,19 +425,34 @@ class CategoryListScreen(ListScreen): Binding(key="escape", action="cancelfilter", show=False), ] - def _refresh(self, filter_query=None): + def _refresh(self): self.table.clear() categories = ( HamsterCategory.select( - HamsterCategory, fn.Count(HamsterActivity.id).alias("activities_count") + HamsterCategory, + fn.Count(HamsterActivity.id).alias("activities_count"), + HamsterFact.start_time ) .join(HamsterActivity, JOIN.LEFT_OUTER) + .join(HamsterFact, JOIN.LEFT_OUTER) .group_by(HamsterCategory) ) - if filter_query: - categories = categories.where(HamsterCategory.name.contains(filter_query)) + filter_search = self.query_one('#filter #search').value + if filter_search is not None: + categories = categories.where( + HamsterCategory.name.contains(filter_search) + ) + + filter_date = self.query_one('#filter #date').value + if filter_date is not None: + try: + categories = categories.where( + HamsterFact.start_time > datetime.strptime(filter_date, '%Y-%m-%d') + ) + except ValueError: + pass self.table.add_rows( [ diff --git a/hamstertools/app.tcss b/hamstertools/app.tcss index e6e8785..e36a803 100644 --- a/hamstertools/app.tcss +++ b/hamstertools/app.tcss @@ -14,6 +14,10 @@ DataTable:focus .datatable--cursor { display: none; } +#filter Input { + width: 50%; +} + ActivityEditScreen, ActivityMappingScreen { align: center middle; }