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_colored_date,
)
from .modals import ChoiceModal, DateModal
from .modals import ChoiceModal, DateModal, TagModal
class NotifyValidationError(Exception):
@ -32,6 +32,7 @@ class TableColumnConfig:
self.read_only = read_only
def preprocess(self, val):
"""from UI -> DB"""
return val # no-op
def start_change(self, app, current_value):
@ -42,6 +43,7 @@ class TableColumnConfig:
app._show_input("edit", current_value)
def format_for_display(self, val):
"""from DB -> UI"""
val = str(val)
if "\n" in val:
val = val.split("\n")[0] + ELLIPSIS
@ -67,6 +69,20 @@ class EnumColumnConfig(TableColumnConfig):
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):
def preprocess(self, val):
try:
@ -88,4 +104,5 @@ def get_col_cls(field_type):
"text": TableColumnConfig,
"enum": EnumColumnConfig,
"date": DateColumnConfig,
"tag": TagColumnConfig,
}[field_type]

View File

@ -1,7 +1,7 @@
import datetime
from textual.screen import ModalScreen
from textual.binding import Binding
from textual.widgets import Label
from textual.widgets import Label, Input
from textual.containers import Horizontal, Vertical
from textual.reactive import reactive
from ..utils import get_color_enum
@ -132,6 +132,82 @@ class ChoiceModal(ModalScreen):
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):
CSS = """
DateModal {