TagModal
This commit is contained in:
parent
4f408d7ceb
commit
a72c6fbaab
@ -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]
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user