improved overview
This commit is contained in:
parent
ccd0178de1
commit
9de289d43b
@ -5,8 +5,9 @@ from typing_extensions import Annotated
|
||||
from .controller.tasks import add_task
|
||||
from .import_csv import import_tasks_from_csv
|
||||
from .db import initialize_db
|
||||
from .tui import tasks
|
||||
from .tui import recurring
|
||||
from .tui.tasks import run as tasks_tui
|
||||
from .tui.overview import run as overview_tui
|
||||
from .tui.recurring import run as recurring_tui
|
||||
|
||||
app = typer.Typer()
|
||||
|
||||
@ -42,17 +43,23 @@ def new(
|
||||
|
||||
|
||||
@app.command()
|
||||
def browse(
|
||||
def tasks(
|
||||
view: Annotated[str, typer.Option("-v", "--view", help="saved view")] = "default",
|
||||
):
|
||||
initialize_db()
|
||||
tasks.run(view)
|
||||
tasks_tui(view)
|
||||
|
||||
|
||||
@app.command()
|
||||
def generators():
|
||||
initialize_db()
|
||||
recurring.run()
|
||||
recurring_tui()
|
||||
|
||||
|
||||
@app.command()
|
||||
def overview():
|
||||
initialize_db()
|
||||
overview_tui()
|
||||
|
||||
|
||||
@app.command()
|
||||
|
@ -140,28 +140,31 @@ def get_due_soon(
|
||||
"""
|
||||
now = datetime.now()
|
||||
|
||||
# Base query
|
||||
# unfinished tasks w/ due date
|
||||
query = (
|
||||
Task.select(Task, Category.name.alias("category_name"))
|
||||
Task.select(Task)
|
||||
.join(Category, JOIN.LEFT_OUTER)
|
||||
.where(
|
||||
(~Task.deleted)
|
||||
& (Task.due.is_null(False))
|
||||
& (Task.due != "")
|
||||
& (Task.status != TaskStatus.DONE.value)
|
||||
)
|
||||
)
|
||||
|
||||
# filter by category
|
||||
if category:
|
||||
query = query.where(Category.name == category)
|
||||
|
||||
# Handle overdue tasks based on all_overdue parameter
|
||||
if all_overdue:
|
||||
# grab all overdue & append a few more on
|
||||
overdue_tasks = list(query.where(Task.due < now).order_by(Task.due))
|
||||
upcoming_tasks = list(
|
||||
query.where(Task.due >= now).order_by(Task.due).limit(num)
|
||||
)
|
||||
tasks = overdue_tasks + upcoming_tasks
|
||||
else:
|
||||
# just most due tasks
|
||||
tasks = list(query.order_by(Task.due).limit(num))
|
||||
|
||||
return [
|
||||
|
@ -1,6 +1,6 @@
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.containers import ScrollableContainer, Horizontal
|
||||
from textual.widgets import DataTable, Static
|
||||
from textual.widgets import DataTable, Static, Label
|
||||
from textual.binding import Binding
|
||||
from datetime import datetime
|
||||
|
||||
@ -10,6 +10,16 @@ from ..controller.summaries import (
|
||||
get_due_soon,
|
||||
)
|
||||
|
||||
####
|
||||
# Due Soon # Task Summary
|
||||
# #
|
||||
# #
|
||||
##################################
|
||||
# WIP # Recently active
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
|
||||
|
||||
class CategoryTable(DataTable):
|
||||
"""Table showing category summaries"""
|
||||
@ -35,54 +45,46 @@ class CategoryTable(DataTable):
|
||||
)
|
||||
|
||||
|
||||
class TaskList(DataTable):
|
||||
"""Base class for task list tables"""
|
||||
|
||||
def on_mount(self):
|
||||
self.add_columns("Task", "Status", "Category", "Due Date")
|
||||
|
||||
def format_due_date(self, due_date: datetime | None) -> str:
|
||||
if not due_date:
|
||||
return "No due date"
|
||||
return due_date.strftime("%Y-%m-%d")
|
||||
def format_due_date(due_date: datetime | None) -> str:
|
||||
if not due_date:
|
||||
return "No due date"
|
||||
return due_date.strftime("%Y-%m-%d")
|
||||
|
||||
|
||||
class DueTaskList(TaskList):
|
||||
class DueTaskList(DataTable):
|
||||
"""Table showing upcoming and overdue tasks"""
|
||||
|
||||
def on_mount(self):
|
||||
super().on_mount()
|
||||
self.add_columns("Task", "Category", "Due Date")
|
||||
self.refresh_data()
|
||||
|
||||
def refresh_data(self):
|
||||
self.clear()
|
||||
tasks = get_due_soon(10, all_overdue=True) # Show all overdue + next 10
|
||||
tasks = get_due_soon(10, all_overdue=True)
|
||||
for task in tasks:
|
||||
self.add_row(
|
||||
task["text"],
|
||||
task["status"],
|
||||
task["category"] or "No category",
|
||||
self.format_due_date(task["due"]),
|
||||
task["category"],
|
||||
format_due_date(task["due"]),
|
||||
key=str(task["id"]),
|
||||
)
|
||||
|
||||
|
||||
class RecentTaskList(TaskList):
|
||||
class RecentTaskList(DataTable):
|
||||
"""Table showing recently active tasks"""
|
||||
|
||||
def on_mount(self):
|
||||
super().on_mount()
|
||||
self.add_columns("Task", "Category", "Due Date")
|
||||
self.refresh_data()
|
||||
|
||||
def refresh_data(self):
|
||||
self.clear()
|
||||
tasks = get_recently_active(10) # Show 10 most recent
|
||||
tasks = get_recently_active(10)
|
||||
for task in tasks:
|
||||
self.add_row(
|
||||
task["text"],
|
||||
task["status"],
|
||||
task["category"] or "No category",
|
||||
self.format_due_date(task["due"]),
|
||||
task["category"] or "-",
|
||||
format_due_date(task["due"]),
|
||||
key=str(task["id"]),
|
||||
)
|
||||
|
||||
@ -90,27 +92,20 @@ class RecentTaskList(TaskList):
|
||||
class Overview(App):
|
||||
"""Task overview application"""
|
||||
|
||||
TITLE = "Task Overview"
|
||||
CSS = """
|
||||
CategoryTable {
|
||||
height: 40%;
|
||||
margin: 1 1;
|
||||
}
|
||||
|
||||
Label {
|
||||
align: center middle;
|
||||
background: purple;
|
||||
}
|
||||
|
||||
#lists {
|
||||
height: 60%;
|
||||
}
|
||||
|
||||
TaskList {
|
||||
width: 50%;
|
||||
margin: 1 1;
|
||||
}
|
||||
|
||||
Static {
|
||||
content-align: center middle;
|
||||
background: $panel;
|
||||
padding: 1;
|
||||
}
|
||||
"""
|
||||
|
||||
BINDINGS = [
|
||||
@ -119,12 +114,14 @@ class Overview(App):
|
||||
]
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield CategoryTable()
|
||||
yield Static("Upcoming and Recent Tasks")
|
||||
with Horizontal(id="top"):
|
||||
yield CategoryTable()
|
||||
with Horizontal(id="lists"):
|
||||
with ScrollableContainer():
|
||||
yield Label("Due Soon")
|
||||
yield DueTaskList()
|
||||
with ScrollableContainer():
|
||||
yield Label("Activity")
|
||||
yield RecentTaskList()
|
||||
|
||||
def action_refresh(self):
|
||||
@ -134,6 +131,6 @@ class Overview(App):
|
||||
self.query_one(RecentTaskList).refresh_data()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
def run():
|
||||
app = Overview()
|
||||
app.run()
|
||||
|
Loading…
Reference in New Issue
Block a user