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