Compare commits
No commits in common. "86b80f87f868606e24fbf126ce2ee12a375e9bf7" and "90b4ed7300b5ae57b6d58a8d807ed1a59ce91ba8" have entirely different histories.
86b80f87f8
...
90b4ed7300
@ -4,8 +4,7 @@ import lxml.html
|
|||||||
from typing_extensions import Annotated
|
from typing_extensions import Annotated
|
||||||
from .controller import add_task
|
from .controller 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 . import tui
|
||||||
from .tui import tasks
|
|
||||||
|
|
||||||
app = typer.Typer()
|
app = typer.Typer()
|
||||||
|
|
||||||
@ -17,7 +16,6 @@ def new(
|
|||||||
due: Annotated[str, typer.Option("-d", "--due", help="due")] = "",
|
due: Annotated[str, typer.Option("-d", "--due", help="due")] = "",
|
||||||
url: Annotated[str, typer.Option("-u", "--url", help="URL")] = "",
|
url: Annotated[str, typer.Option("-u", "--url", help="URL")] = "",
|
||||||
):
|
):
|
||||||
initialize_db()
|
|
||||||
required = ["name", "category"]
|
required = ["name", "category"]
|
||||||
|
|
||||||
if url and not name:
|
if url and not name:
|
||||||
@ -44,8 +42,7 @@ def new(
|
|||||||
def browse(
|
def browse(
|
||||||
view: Annotated[str, typer.Option("-v", "--view", help="saved view")] = "default",
|
view: Annotated[str, typer.Option("-v", "--view", help="saved view")] = "default",
|
||||||
):
|
):
|
||||||
initialize_db()
|
tui.run(view)
|
||||||
tasks.run(view)
|
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
|
@ -11,8 +11,8 @@ def category_lookup(category):
|
|||||||
return category.id
|
return category.id
|
||||||
|
|
||||||
|
|
||||||
def get_task(item_id: int) -> Task:
|
def get_task(task_id: int) -> Task:
|
||||||
return Task.get_by_id(item_id)
|
return Task.get_by_id(task_id)
|
||||||
|
|
||||||
|
|
||||||
def add_task(
|
def add_task(
|
||||||
@ -35,15 +35,15 @@ def add_task(
|
|||||||
|
|
||||||
|
|
||||||
def update_task(
|
def update_task(
|
||||||
item_id: int,
|
task_id: int,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> Task:
|
) -> Task:
|
||||||
with db.atomic():
|
with db.atomic():
|
||||||
if category := kwargs.pop("category", None):
|
if category := kwargs.pop("category", None):
|
||||||
kwargs["category_id"] = category_lookup(category)
|
kwargs["category_id"] = category_lookup(category)
|
||||||
query = Task.update(kwargs).where(Task.id == item_id)
|
query = Task.update(kwargs).where(Task.id == task_id)
|
||||||
query.execute()
|
query.execute()
|
||||||
task = Task.get_by_id(item_id)
|
task = Task.get_by_id(task_id)
|
||||||
return task
|
return task
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import json
|
|||||||
from textual.widgets import Input
|
from textual.widgets import Input
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from ..controller import (
|
from .controller import (
|
||||||
get_task,
|
get_task,
|
||||||
get_tasks,
|
get_tasks,
|
||||||
add_task,
|
add_task,
|
||||||
@ -11,12 +11,13 @@ from ..controller import (
|
|||||||
save_view,
|
save_view,
|
||||||
get_saved_view,
|
get_saved_view,
|
||||||
)
|
)
|
||||||
from ..utils import (
|
from .db import initialize_db
|
||||||
|
from .utils import (
|
||||||
get_colored_category,
|
get_colored_category,
|
||||||
get_colored_status,
|
get_colored_status,
|
||||||
get_colored_date,
|
get_colored_date,
|
||||||
)
|
)
|
||||||
from .editor import (
|
from .tui_editor import (
|
||||||
TableEditor,
|
TableEditor,
|
||||||
TableColumnConfig,
|
TableColumnConfig,
|
||||||
NotifyValidationError,
|
NotifyValidationError,
|
||||||
@ -55,6 +56,9 @@ class TT(TableEditor):
|
|||||||
TableColumnConfig("due", "Due", default="", preprocessor=due_preprocessor),
|
TableColumnConfig("due", "Due", default="", preprocessor=due_preprocessor),
|
||||||
TableColumnConfig("category", "Category", default="main"),
|
TableColumnConfig("category", "Category", default="main"),
|
||||||
)
|
)
|
||||||
|
update_item_callback = update_task
|
||||||
|
update_item_callback = add_task
|
||||||
|
get_item_callback = get_task
|
||||||
|
|
||||||
BINDINGS = [
|
BINDINGS = [
|
||||||
# saved views
|
# saved views
|
||||||
@ -65,9 +69,6 @@ class TT(TableEditor):
|
|||||||
def __init__(self, default_view="default"):
|
def __init__(self, default_view="default"):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._load_view(default_view)
|
self._load_view(default_view)
|
||||||
self.update_item_callback = update_task
|
|
||||||
self.add_item_callback = add_task
|
|
||||||
self.get_item_callback = get_task
|
|
||||||
|
|
||||||
def _load_view(self, name):
|
def _load_view(self, name):
|
||||||
try:
|
try:
|
||||||
@ -122,6 +123,7 @@ class TT(TableEditor):
|
|||||||
|
|
||||||
|
|
||||||
def run(default_view):
|
def run(default_view):
|
||||||
|
initialize_db()
|
||||||
app = TT(default_view)
|
app = TT(default_view)
|
||||||
app.run()
|
app.run()
|
||||||
|
|
@ -7,13 +7,13 @@ from textual.widgets import (
|
|||||||
)
|
)
|
||||||
from textual.containers import Container
|
from textual.containers import Container
|
||||||
|
|
||||||
from ..utils import (
|
from .utils import (
|
||||||
remove_rich_tag,
|
remove_rich_tag,
|
||||||
filter_to_string,
|
filter_to_string,
|
||||||
advance_enum_val,
|
advance_enum_val,
|
||||||
get_text_from_editor,
|
get_text_from_editor,
|
||||||
)
|
)
|
||||||
from .keymodal import KeyModal
|
from .tui_keybindings import KeyBindingsScreen
|
||||||
|
|
||||||
|
|
||||||
class NotifyValidationError(Exception):
|
class NotifyValidationError(Exception):
|
||||||
@ -113,7 +113,7 @@ class TableEditor(App):
|
|||||||
def __init__(self, default_view="default"):
|
def __init__(self, default_view="default"):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.filters = {}
|
self.filters = {}
|
||||||
self.sort_string = "" # TODO: default sort
|
self.sort_string = "due,status"
|
||||||
self._load_view(default_view)
|
self._load_view(default_view)
|
||||||
self.search_query = ""
|
self.search_query = ""
|
||||||
self.saved_cursor_pos = (1, 0)
|
self.saved_cursor_pos = (1, 0)
|
||||||
@ -192,23 +192,20 @@ class TableEditor(App):
|
|||||||
if self.table.cursor_column == 0:
|
if self.table.cursor_column == 0:
|
||||||
cur_row = self.table.cursor_row
|
cur_row = self.table.cursor_row
|
||||||
item_id = int(self.table.get_cell_at((cur_row, 0)))
|
item_id = int(self.table.get_cell_at((cur_row, 0)))
|
||||||
# TODO: deletable items need a delete
|
|
||||||
self.update_item_callback(item_id, deleted=True)
|
self.update_item_callback(item_id, deleted=True)
|
||||||
self._save_cursor()
|
self._save_cursor()
|
||||||
self.refresh_data()
|
self.refresh_data()
|
||||||
|
|
||||||
def action_add_item(self):
|
def action_add_item(self):
|
||||||
# the new item should use the selected value if filtered
|
# if filtering on type, status, or category
|
||||||
|
# the new item should use the selected value
|
||||||
|
|
||||||
# prepopulate with either the field default or the current filter
|
# prepopulate with either the field default or the current filter
|
||||||
prepopulated = {}
|
prepopulated = {
|
||||||
for fc in self.TABLE_CONFIG:
|
field.name: self.filters.get(field.name, field.default)
|
||||||
val = self.filters.get(fc.field, fc.default)
|
for field in self.TABLE_CONFIG
|
||||||
if val is not None:
|
}
|
||||||
# enums use comma separated filters
|
# TODO: need to split type_ and status
|
||||||
if fc.enum:
|
|
||||||
prepopulated[fc.field] = val.split(",")[0]
|
|
||||||
else:
|
|
||||||
prepopulated[fc.field] = val
|
|
||||||
|
|
||||||
new_item = self.add_item_callback(**prepopulated)
|
new_item = self.add_item_callback(**prepopulated)
|
||||||
self.refresh_data(restore_cursor=False)
|
self.refresh_data(restore_cursor=False)
|
||||||
@ -235,7 +232,6 @@ class TableEditor(App):
|
|||||||
# trigger item_id to be saved on the next cursor move
|
# trigger item_id to be saved on the next cursor move
|
||||||
# this avoids filtered columns disappearing right away
|
# this avoids filtered columns disappearing right away
|
||||||
# and tons of DB writes
|
# and tons of DB writes
|
||||||
# TODO: status hard coded here
|
|
||||||
self._register_save_on_move(item_id, status=next_val)
|
self._register_save_on_move(item_id, status=next_val)
|
||||||
|
|
||||||
def _register_save_on_move(self, item_id, **kwargs):
|
def _register_save_on_move(self, item_id, **kwargs):
|
||||||
@ -249,6 +245,7 @@ class TableEditor(App):
|
|||||||
self.update_item_callback(**self.save_on_move)
|
self.update_item_callback(**self.save_on_move)
|
||||||
self._save_cursor()
|
self._save_cursor()
|
||||||
self.refresh_data()
|
self.refresh_data()
|
||||||
|
# reset status
|
||||||
self.save_on_move = None
|
self.save_on_move = None
|
||||||
|
|
||||||
def move_cursor_to_item(self, item_id):
|
def move_cursor_to_item(self, item_id):
|
||||||
@ -288,7 +285,7 @@ class TableEditor(App):
|
|||||||
cconf = self._active_column_config()
|
cconf = self._active_column_config()
|
||||||
if cconf.filterable:
|
if cconf.filterable:
|
||||||
return
|
return
|
||||||
cur_filter_val = self.filters.get(cconf.field) or ""
|
cur_filter_val = self.filters.get(cconf.name) or ""
|
||||||
self._show_input("filter", cur_filter_val)
|
self._show_input("filter", cur_filter_val)
|
||||||
self.table.cursor_type = "column"
|
self.table.cursor_type = "column"
|
||||||
|
|
||||||
@ -302,7 +299,7 @@ class TableEditor(App):
|
|||||||
if self.table.cursor_row is None or self.table.cursor_column == 0:
|
if self.table.cursor_row is None or self.table.cursor_column == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
self._save_cursor()
|
self._save_crefresh_data()
|
||||||
current_value = self.table.get_cell_at(
|
current_value = self.table.get_cell_at(
|
||||||
(self.table.cursor_row, self.table.cursor_column)
|
(self.table.cursor_row, self.table.cursor_column)
|
||||||
)
|
)
|
||||||
@ -337,7 +334,7 @@ class TableEditor(App):
|
|||||||
self.refresh_data(restore_cursor=False)
|
self.refresh_data(restore_cursor=False)
|
||||||
elif self.mode == "filter":
|
elif self.mode == "filter":
|
||||||
cconf = self._active_column_config()
|
cconf = self._active_column_config()
|
||||||
self.filters[cconf.field] = event.value
|
self.filters[cconf.name] = event.value
|
||||||
self.refresh_data(restore_cursor=False)
|
self.refresh_data(restore_cursor=False)
|
||||||
self.table.cursor_type = "cel"
|
self.table.cursor_type = "cel"
|
||||||
elif self.mode == "sort":
|
elif self.mode == "sort":
|
||||||
@ -353,13 +350,12 @@ class TableEditor(App):
|
|||||||
row, col = self.saved_cursor_pos
|
row, col = self.saved_cursor_pos
|
||||||
item_id = int(self.table.get_cell_at((row, 0)))
|
item_id = int(self.table.get_cell_at((row, 0)))
|
||||||
cconf = self.TABLE_CONFIG[col]
|
cconf = self.TABLE_CONFIG[col]
|
||||||
field = cconf.field
|
field = cconf.name
|
||||||
update_data = {}
|
update_data = {}
|
||||||
|
|
||||||
# preprocess/validate the field being saved
|
# preprocess/validate the field being saved
|
||||||
try:
|
try:
|
||||||
update_data[field] = cconf.preprocessor(new_value)
|
update_data[field] = cconf.preprocess(new_value)
|
||||||
# raise Exception(update_data)
|
|
||||||
self.update_item_callback(item_id, **update_data)
|
self.update_item_callback(item_id, **update_data)
|
||||||
self.refresh_data()
|
self.refresh_data()
|
||||||
except NotifyValidationError as e:
|
except NotifyValidationError as e:
|
||||||
@ -371,4 +367,4 @@ class TableEditor(App):
|
|||||||
self.action_cancel_edit()
|
self.action_cancel_edit()
|
||||||
|
|
||||||
def action_show_keys(self):
|
def action_show_keys(self):
|
||||||
self.push_screen(KeyModal())
|
self.push_screen(KeyBindingsScreen())
|
@ -3,7 +3,7 @@ from rich.table import Table
|
|||||||
from textual.widgets import Static
|
from textual.widgets import Static
|
||||||
|
|
||||||
|
|
||||||
class KeyModal(ModalScreen):
|
class KeyBindingsScreen(ModalScreen):
|
||||||
CSS = """
|
CSS = """
|
||||||
KeyBindingsScreen {
|
KeyBindingsScreen {
|
||||||
align: center middle;
|
align: center middle;
|
Loading…
Reference in New Issue
Block a user