Activity editing
This commit is contained in:
		@ -8,7 +8,6 @@ from textual.events import DescendantBlur
 | 
			
		||||
from textual.widgets import Header, Footer, DataTable, Input, Button, Label, Checkbox
 | 
			
		||||
from textual.containers import Horizontal, Vertical
 | 
			
		||||
from textual.coordinate import Coordinate
 | 
			
		||||
from textual.reactive import reactive
 | 
			
		||||
from textual.screen import Screen, ModalScreen
 | 
			
		||||
 | 
			
		||||
from textual_autocomplete import AutoComplete, Dropdown, DropdownItem
 | 
			
		||||
@ -75,21 +74,65 @@ class ListScreen(Screen):
 | 
			
		||||
        self._refresh()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActivityEditScreen(ModalScreen):
 | 
			
		||||
    BINDINGS = [("escape", "cancel", "Cancel")]
 | 
			
		||||
    BINDINGS = [
 | 
			
		||||
        ("escape", "cancel", "Cancel"),
 | 
			
		||||
        ("ctrl+s", "save", "Save"),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    category_id = None
 | 
			
		||||
    category_name = ''
 | 
			
		||||
 | 
			
		||||
    def _get_categories(self, input_state):
 | 
			
		||||
        categories = [DropdownItem(c.name, str(c.id)) for c in HamsterCategory.select()]
 | 
			
		||||
        return ActivityMappingScreen._filter_dropdowns(categories, input_state.value)
 | 
			
		||||
 | 
			
		||||
    def __init__(self, category, activity):
 | 
			
		||||
        if category is not None:
 | 
			
		||||
            self.category_id = category.id
 | 
			
		||||
            self.category_name = category.name
 | 
			
		||||
        self.activity_name = activity.name
 | 
			
		||||
        super().__init__()
 | 
			
		||||
 | 
			
		||||
    def compose(self) -> ComposeResult:
 | 
			
		||||
        yield Grid(
 | 
			
		||||
            Label("Are you sure you want to quit?", id="question"),
 | 
			
		||||
            Button("Quit", variant="error", id="quit"),
 | 
			
		||||
            Button("Cancel", variant="primary", id="cancel"),
 | 
			
		||||
            id="dialog",
 | 
			
		||||
        yield Vertical(
 | 
			
		||||
            Horizontal(Label("Category:"), 
 | 
			
		||||
                AutoComplete(
 | 
			
		||||
                    Input(placeholder="Type to search...", id="category",
 | 
			
		||||
                          value=self.category_name),
 | 
			
		||||
                    Dropdown(items=self._get_categories),
 | 
			
		||||
                ),
 | 
			
		||||
            ),
 | 
			
		||||
            Horizontal(Label("Activity:"), Input(value=self.activity_name,
 | 
			
		||||
                                                 id='activity')),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    @on(Input.Submitted, "#category")
 | 
			
		||||
    def category_submitted(self, event):
 | 
			
		||||
        if event.control.parent.dropdown.selected_item is not None:
 | 
			
		||||
            self.category_id = str(
 | 
			
		||||
                event.control.parent.dropdown.selected_item.left_meta
 | 
			
		||||
            )
 | 
			
		||||
            self.query_one("#activity").focus()
 | 
			
		||||
 | 
			
		||||
    @on(DescendantBlur, "#category")
 | 
			
		||||
    def category_blur(self, event):
 | 
			
		||||
        if event.control.parent.dropdown.selected_item is not None:
 | 
			
		||||
            self.category_id = str(
 | 
			
		||||
                event.control.parent.dropdown.selected_item.left_meta
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
    def action_cancel(self):
 | 
			
		||||
        self.dismiss(None)
 | 
			
		||||
 | 
			
		||||
    def action_save(self):
 | 
			
		||||
        self.dismiss(
 | 
			
		||||
            {
 | 
			
		||||
                "category": self.category_id,
 | 
			
		||||
                "activity": self.query_one('#activity').value,
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActivityMappingScreen(ModalScreen):
 | 
			
		||||
    BINDINGS = [
 | 
			
		||||
@ -376,10 +419,27 @@ class ActivityListScreen(ListScreen):
 | 
			
		||||
            del self.move_from_activity
 | 
			
		||||
 | 
			
		||||
    def action_edit(self):
 | 
			
		||||
        def handle_edit(properties):
 | 
			
		||||
            print(properties)
 | 
			
		||||
        row_idx: int = self.table.cursor_row
 | 
			
		||||
        row_cells = self.table.get_row_at(row_idx)
 | 
			
		||||
 | 
			
		||||
        self.app.push_screen(ActivityEditScreen(), handle_edit)
 | 
			
		||||
        try:
 | 
			
		||||
            category = HamsterCategory.get(id=row_cells[0])
 | 
			
		||||
        except HamsterCategory.DoesNotExist:
 | 
			
		||||
            category = None
 | 
			
		||||
        activity = HamsterActivity.get(id=row_cells[2])
 | 
			
		||||
 | 
			
		||||
        def handle_edit(properties):
 | 
			
		||||
            if properties is None:
 | 
			
		||||
                return
 | 
			
		||||
            activity.name = properties['activity']
 | 
			
		||||
            activity.category_id = properties['category']
 | 
			
		||||
            activity.save()
 | 
			
		||||
            self._refresh()
 | 
			
		||||
 | 
			
		||||
        self.app.push_screen(ActivityEditScreen(
 | 
			
		||||
            category=category,
 | 
			
		||||
            activity=activity
 | 
			
		||||
        ), handle_edit)
 | 
			
		||||
 | 
			
		||||
    def action_mapping(self):
 | 
			
		||||
        selected_activity = (
 | 
			
		||||
 | 
			
		||||
@ -1,50 +1,64 @@
 | 
			
		||||
DataTable {
 | 
			
		||||
	height: 90%;
 | 
			
		||||
    height: 90%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DataTable .datatable--cursor {
 | 
			
		||||
	background: grey;
 | 
			
		||||
    background: grey;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DataTable:focus .datatable--cursor {
 | 
			
		||||
	background: orange;
 | 
			
		||||
    background: orange;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#filter {
 | 
			
		||||
	display: none;
 | 
			
		||||
    display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#filter Input {
 | 
			
		||||
	width: 50%;
 | 
			
		||||
    width: 50%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ActivityEditScreen, ActivityMappingScreen {
 | 
			
		||||
    align: center middle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ActivityEditScreen > Vertical,
 | 
			
		||||
ActivityMappingScreen > Vertical {
 | 
			
		||||
    padding: 0 1;
 | 
			
		||||
		width: auto;
 | 
			
		||||
    width: 80;
 | 
			
		||||
    height: 30;
 | 
			
		||||
    border: thick $background 80%;
 | 
			
		||||
    background: $surface;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ActivityMappingScreen Horizontal {
 | 
			
		||||
		align: left middle;
 | 
			
		||||
		width: auto;
 | 
			
		||||
ActivityEditScreen > Vertical {
 | 
			
		||||
    height: 10;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ActivityMappingScreen Horizontal {
 | 
			
		||||
    align: left middle;
 | 
			
		||||
    width: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ActivityEditScreen Horizontal {
 | 
			
		||||
    width: 80;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ActivityEditScreen Label,
 | 
			
		||||
ActivityMappingScreen Label {
 | 
			
		||||
	padding: 0 1;
 | 
			
		||||
	width: auto;
 | 
			
		||||
	border: blank;
 | 
			
		||||
    padding: 0 1;
 | 
			
		||||
    width: auto;
 | 
			
		||||
    border: blank;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ActivityMappingScreen AutoComplete {
 | 
			
		||||
	width: 80;
 | 
			
		||||
    width: 80;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#description, #tags {
 | 
			
		||||
	width: 30;
 | 
			
		||||
    width: 30;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ActivityEditScreen Input {
 | 
			
		||||
    width: 60;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ class KimaiAPI(object):
 | 
			
		||||
    auth_headers = {"X-AUTH-USER": KIMAI_USERNAME, "X-AUTH-TOKEN": KIMAI_API_KEY}
 | 
			
		||||
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        requests_cache.install_cache("kimai", backend="sqlite", expire_after=1800)
 | 
			
		||||
        # requests_cache.install_cache("kimai", backend="sqlite", expire_after=1800)
 | 
			
		||||
        self.customers_json = requests.get(
 | 
			
		||||
            f"{self.KIMAI_API_URL}/customers?visible=3", headers=self.auth_headers
 | 
			
		||||
        ).json()
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user