This commit is contained in:
jpt 2025-05-04 19:56:35 -05:00
parent 4f408d7ceb
commit a72c6fbaab
2 changed files with 95 additions and 2 deletions

View File

@ -3,7 +3,7 @@ from ..utils import (
get_color_enum, get_color_enum,
get_colored_date, get_colored_date,
) )
from .modals import ChoiceModal, DateModal from .modals import ChoiceModal, DateModal, TagModal
class NotifyValidationError(Exception): class NotifyValidationError(Exception):
@ -32,6 +32,7 @@ class TableColumnConfig:
self.read_only = read_only self.read_only = read_only
def preprocess(self, val): def preprocess(self, val):
"""from UI -> DB"""
return val # no-op return val # no-op
def start_change(self, app, current_value): def start_change(self, app, current_value):
@ -42,6 +43,7 @@ class TableColumnConfig:
app._show_input("edit", current_value) app._show_input("edit", current_value)
def format_for_display(self, val): def format_for_display(self, val):
"""from DB -> UI"""
val = str(val) val = str(val)
if "\n" in val: if "\n" in val:
val = val.split("\n")[0] + ELLIPSIS val = val.split("\n")[0] + ELLIPSIS
@ -67,6 +69,20 @@ class EnumColumnConfig(TableColumnConfig):
app.push_screen(ChoiceModal(self.enum, current_value), app.apply_change) app.push_screen(ChoiceModal(self.enum, current_value), app.apply_change)
class TagColumnConfig(TableColumnConfig):
def __init__(self, field: str, display_name: str, **kwargs):
super().__init__(field, display_name, **kwargs)
def preprocess(self, val):
return val
def format_for_display(self, val):
return ", ".join(val)
def start_change(self, app, current_value):
app.push_screen(TagModal(current_value), app.apply_change)
class DateColumnConfig(TableColumnConfig): class DateColumnConfig(TableColumnConfig):
def preprocess(self, val): def preprocess(self, val):
try: try:
@ -88,4 +104,5 @@ def get_col_cls(field_type):
"text": TableColumnConfig, "text": TableColumnConfig,
"enum": EnumColumnConfig, "enum": EnumColumnConfig,
"date": DateColumnConfig, "date": DateColumnConfig,
"tag": TagColumnConfig,
}[field_type] }[field_type]

View File

@ -1,7 +1,7 @@
import datetime import datetime
from textual.screen import ModalScreen from textual.screen import ModalScreen
from textual.binding import Binding from textual.binding import Binding
from textual.widgets import Label from textual.widgets import Label, Input
from textual.containers import Horizontal, Vertical from textual.containers import Horizontal, Vertical
from textual.reactive import reactive from textual.reactive import reactive
from ..utils import get_color_enum from ..utils import get_color_enum
@ -132,6 +132,82 @@ class ChoiceModal(ModalScreen):
self.dismiss(self.enum_by_idx[idx]) self.dismiss(self.enum_by_idx[idx])
class TagModal(ModalScreen):
CSS = """
TagModal {
align: center middle;
background: $primary 30%;
}
TagModal Vertical {
border: double teal;
width: 38;
}
TagModal Label.hints {
border: solid grey;
height: 4;
}
TagModal Label {
height: 1;
}
TagEditor #tageditor {
width: 100%;
}
TagModal Label#selected {
background: white;
}
"""
# TODO: float hints to bottom
BINDINGS = [
# ("j,tab", "cursor_down", "Down"),
# ("k,shift+tab", "cursor_up", "Up"),
# TODO: add clear
Binding("enter", "select", "Select", priority=True),
("escape", "cancel", "cancel"),
]
def __init__(self, current_val):
if isinstance(current_val, str):
# FIXME: shouldn't happen
current_val = current_val.split(", ")
self._tags = current_val
self.sel_idx = 0
super().__init__()
def compose(self):
self.input = Input()
with Vertical():
yield self.input
for tag in self._tags:
yield Label(" - " + tag)
yield Label(
"""(h/j/k/l) move
(enter) confirm (esc) quit""",
classes="hints",
)
def action_cursor_down(self):
self._move_cursor(1)
def action_cursor_up(self):
self._move_cursor(-1)
async def action_select(self):
# on first submit: add, second: submit
if tag := self.input.value:
if tag in self._tags:
self._tags.remove(tag)
else:
self._tags.append(self.input.value)
await self.recompose()
self.input.focus()
else:
self.dismiss(self._tags)
def action_cancel(self):
self.app.pop_screen()
class DateModal(ModalScreen): class DateModal(ModalScreen):
CSS = """ CSS = """
DateModal { DateModal {