Source code for devkit_ui.pages.run.drop_node_card

from collections.abc import Callable

from nicegui import ui

from devkit_ui.constants import NAV_ACTION, ROW_ACTION
from devkit_ui.view_models.run_view_model import RunViewModel


[docs] class DropNodeCard(ui.card):
[docs] def __init__(self, state: RunViewModel.DropNode, topo_state: RunViewModel.Topo, on_drop: Callable[[str, int | None, str], None]): """ Configure the drop-node card with state bindings and a drop action callback. Parameters: state: Drop-node configuration and operation status state. topo_state: Topology state used to display the current node. on_drop: Callback invoked with the node name, row ID, and row role. """ super().__init__() self.classes('flex-1') with self: with ui.row().classes('items-baseline gap-2 mb-2'): # Label ui.label('Drop Node').classes('font-semibold') ui.label('pins at current pose').classes('text-xs').style('color:#8c959f') with ui.row().classes('items-center gap-2 w-full'): # Name ui.input( placeholder='e.g. ROW_D_IN', label='Name', ).classes('flex-1').bind_value(state, 'name') with ui.row().classes('items-center gap-2 w-full mt-1'): # Row id ui.number( label='Row ID', placeholder='blank=standard', min=1, step=1, precision=0, ).classes('w-28').bind_value( state, 'row_id', forward=lambda val: int(val) if val not in (None, '') else None ) # Toggle role ui.toggle( {'entry': 'Entry', 'exit': 'Exit'} ).props('dense').bind_value(state, 'row_role') # Hint label self.row_hint = ui.label('').classes('text-xs font-mono') def sync_hint(row_id: str) -> str: """ Update the row-action hint styling based on whether a row ID is provided. Parameters: row_id (str): The row ID used to determine the hint state. Returns: str: `ROW_ACTION` when a row ID is provided, otherwise `NAV_ACTION`. """ has_row = bool(row_id) self.row_hint.style(f'color:{"#0969da" if has_row else "#8c959f"}') return ROW_ACTION if has_row else NAV_ACTION self.row_hint.bind_text_from(state, 'row_id', backward=sync_hint) with ui.row().classes('items-center gap-2 mt-2'): self.current_node_lbl = ui.label('').classes('text-xs font-mono') def sync_current_node(current_node: str) -> str: """ Update the current-node display and provide its text. Parameters: current_node (str): The current topology node name, or a dash indicating no node. Returns: str: The formatted current-node text. """ has_current = bool(current_node and current_node != '—') self.current_node_lbl.style( f'color:{"#1a7f37" if has_current else "#8c959f"}' ) return f'→ {current_node}' if has_current else 'no current node' self.current_node_lbl.bind_text_from( topo_state, 'current_node', backward=sync_current_node ) ui.button( 'Drop', on_click=lambda: on_drop( state.name, state.row_id, state.row_role, ), ).classes('ml-auto').props('color=positive no-caps dense') self.status_lbl = ui.label('').classes('text-xs font-mono mt-1') def sync_status(status: str) -> str: """ Update the status label color based on the status and return the status text. Parameters: status (str): Operation status text. Returns: str: The unchanged status text. """ self.status_lbl.style(f'color:{"#cf222e" if status.startswith("ERROR") else "#1a7f37"}') return status self.status_lbl.bind_text_from(state, 'status', backward=sync_status)