saving and loading views

This commit is contained in:
James Turk 2025-01-04 04:12:02 -06:00
parent 20b95d087b
commit 35aaf17de2
4 changed files with 84 additions and 17 deletions

View File

@ -39,8 +39,10 @@ def new(
@app.command()
def browse():
tui.run()
def browse(
view: Annotated[str, typer.Option("-v", "--view", help="saved view")] = "default",
):
tui.run(view)
@app.command()

View File

@ -1,6 +1,14 @@
import json
from datetime import datetime
from peewee import fn
from .db import Task, Category, TaskStatus, db
from .db import db, Task, Category, TaskStatus, SavedSearch
def category_lookup(category):
category_id = None
if category:
category, _ = Category.get_or_create(name=category)
return category.id
def add_task(
@ -15,10 +23,7 @@ def add_task(
Returns the created task instance.
"""
with db.atomic():
category_id = None
if category:
category, _ = Category.get_or_create(name=category)
category_id = category.id
category_id = category_lookup(category)
task = Task.create(
text=text, type=type, status=status, due=due, category_id=category_id
)
@ -30,6 +35,8 @@ def update_task(
**kwargs,
) -> Task:
with db.atomic():
if category := kwargs.pop("category", None):
kwargs["category_id"] = category_lookup(category)
task = Task.get_by_id(task_id)
query = Task.update(kwargs).where(Task.id == task_id)
query.execute()
@ -84,3 +91,17 @@ def get_tasks(
def get_categories() -> list[Category]:
return list(Category.select().order_by(Category.name))
def save_view(name: str, *, filters: dict, sort_string: str) -> SavedSearch:
filters_json = json.dumps(filters)
return SavedSearch.create(name=name, filters=filters_json, sort_string=sort_string)
def get_saved_view_names() -> list[str]:
return [search.name for search in SavedSearch.select()]
def get_saved_view(name: str) -> SavedSearch:
return SavedSearch.get(SavedSearch.name == name)

View File

@ -58,9 +58,18 @@ class Task(BaseModel):
return super(Task, self).save(*args, **kwargs)
class SavedSearch(BaseModel):
name = CharField(unique=True)
filters = CharField()
sort_string = CharField()
def __str__(self):
return self.name
def initialize_db():
db.connect()
db.create_tables([Category, Task])
db.create_tables([Category, Task, SavedSearch])
if not Category.select().exists():
Category.create(name="default")
db.close()

View File

@ -1,3 +1,4 @@
import json
from textual.app import App
from textual.screen import ModalScreen
from rich.table import Table
@ -10,7 +11,14 @@ from textual.widgets import (
from textual.containers import Container
from datetime import datetime
from .controller import get_tasks, add_task, update_task, TaskStatus
from .controller import (
get_tasks,
add_task,
update_task,
TaskStatus,
save_view,
get_saved_view,
)
from .db import initialize_db
from .utils import (
remove_rich_tag,
@ -97,19 +105,31 @@ class TT(App):
("a", "add_task", "add task"),
("t", "toggle_cell", "toggle status"),
("d", "delete_task", "delete (must be on row mode)"),
# saved views
("ctrl+s", "save_view", "save current view"),
("ctrl+o", "load_view", "load saved view"),
# other
("q", "quit", "quit"),
("?", "show_keys", "show keybindings"),
]
def __init__(self):
def __init__(self, default_view="default"):
super().__init__()
self.search_query = ""
self.filters = {}
self.sort_string = "due,status"
self.saved_cursor_pos = (0, 0)
self._load_view(default_view)
self.search_query = ""
self.saved_cursor_pos = (1, 0)
self.save_on_move = None
def _load_view(self, name):
try:
saved = get_saved_view(name)
self.filters = json.loads(saved.filters)
self.sort_string = saved.sort_string
except Exception:
self.notify(f"Could not load {name}")
def compose(self):
self.header = Header()
self.table = DataTable()
@ -271,6 +291,10 @@ class TT(App):
self.input_label.update("sort: ")
elif mode == "filter":
self.input_label.update("filter: ")
elif mode == "save-view":
self.input_label.update("view name: ")
elif mode == "load-view":
self.input_label.update("view name: ")
else:
raise ValueError(f"unknown mode: {mode}")
self.set_focus(self.input_widget)
@ -286,6 +310,12 @@ class TT(App):
def action_start_search(self):
self._show_input("search", "")
def action_save_view(self):
self._show_input("save-view", "default")
def action_load_view(self):
self._show_input("load-view", "")
def action_start_filter(self):
# filter the currently selected column
cur_col = self.table.cursor_column
@ -330,6 +360,11 @@ class TT(App):
self.right_status.update(self.sort_string)
elif self.mode == "edit":
self.apply_change(event.value)
elif self.mode == "save-view":
save_view(event.value, filters=self.filters, sort_string=self.sort_string)
elif self.mode == "load-view":
self._load_view(event.value)
self.refresh_tasks(restore_cursor=False)
else:
raise ValueError(f"unknown mode: {self.mode}")
self._hide_input()
@ -411,9 +446,9 @@ class KeyBindingsScreen(ModalScreen):
self.app.pop_screen()
def run():
def run(default_view):
initialize_db()
app = TT()
app = TT(default_view)
app.run()