98 lines
2.7 KiB
Python
98 lines
2.7 KiB
Python
|
from textual.app import ComposeResult
|
||
|
from textual.binding import Binding
|
||
|
from textual.screen import Screen
|
||
|
from textual.widgets import DataTable, TabbedContent, TabPane, Header, Footer
|
||
|
|
||
|
from peewee import fn, JOIN
|
||
|
|
||
|
from ..sync import sync
|
||
|
from ..db import (
|
||
|
KimaiProject,
|
||
|
KimaiCustomer,
|
||
|
KimaiActivity,
|
||
|
)
|
||
|
|
||
|
from .list import ListPane
|
||
|
|
||
|
|
||
|
class KimaiProjectList(ListPane):
|
||
|
BINDINGS = [
|
||
|
("s", "sort", "Sort"),
|
||
|
("r", "refresh", "Refresh"),
|
||
|
("g", "get", "Get data"),
|
||
|
("/", "filter", "Search"),
|
||
|
Binding(key="escape", action="cancelfilter", show=False),
|
||
|
]
|
||
|
|
||
|
def _refresh(self, filter_query=None):
|
||
|
self.table.clear()
|
||
|
|
||
|
projects = (
|
||
|
KimaiProject.select(
|
||
|
KimaiProject,
|
||
|
KimaiCustomer,
|
||
|
fn.Count(KimaiActivity.id).alias("activities_count"),
|
||
|
)
|
||
|
.join(KimaiCustomer, JOIN.LEFT_OUTER)
|
||
|
.switch(KimaiProject)
|
||
|
.join(KimaiActivity, JOIN.LEFT_OUTER)
|
||
|
.where(KimaiActivity.project.is_null(False))
|
||
|
.group_by(KimaiProject)
|
||
|
)
|
||
|
|
||
|
if filter_query:
|
||
|
projects = projects.where(
|
||
|
KimaiProject.name.contains(filter_query)
|
||
|
| KimaiCustomer.name.contains(filter_query)
|
||
|
)
|
||
|
|
||
|
self.table.add_rows(
|
||
|
[
|
||
|
[
|
||
|
project.customer.id,
|
||
|
project.customer.name,
|
||
|
project.id,
|
||
|
project.name,
|
||
|
project.activities_count,
|
||
|
]
|
||
|
for project in projects
|
||
|
]
|
||
|
)
|
||
|
|
||
|
self.table.sort(self.sort)
|
||
|
|
||
|
def action_get(self) -> None:
|
||
|
sync()
|
||
|
self._refresh()
|
||
|
|
||
|
def on_mount(self) -> None:
|
||
|
self.table = self.query_one(DataTable)
|
||
|
self.table.cursor_type = "row"
|
||
|
self.columns = self.table.add_columns(
|
||
|
"customer id", "customer", "project id", "project", "activities"
|
||
|
)
|
||
|
# self.sort = (self.columns[1], self.columns[3])
|
||
|
self.sort = self.columns[1]
|
||
|
self._refresh()
|
||
|
|
||
|
|
||
|
class KimaiScreen(Screen):
|
||
|
BINDINGS = [
|
||
|
("p", "show_tab('projects')", "Projects"),
|
||
|
]
|
||
|
|
||
|
SUB_TITLE = "Kimai"
|
||
|
|
||
|
def compose(self) -> ComposeResult:
|
||
|
yield Header()
|
||
|
with TabbedContent(initial="activities"):
|
||
|
with TabPane("Categories", id="categories"):
|
||
|
yield KimaiProjectList()
|
||
|
with TabPane("Activities", id="activities"):
|
||
|
yield KimaiProjectList()
|
||
|
yield Footer()
|
||
|
|
||
|
def action_show_tab(self, tab: str) -> None:
|
||
|
"""Switch to a new tab."""
|
||
|
self.get_child_by_type(TabbedContent).active = tab
|