Skip to content

Commit

Permalink
refactor(docker): make composition menus responsive: showing spinner,…
Browse files Browse the repository at this point in the history
… etc
  • Loading branch information
sassanh committed Nov 30, 2024
1 parent dc8a42a commit c1e472f
Show file tree
Hide file tree
Showing 13 changed files with 192 additions and 107 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- feat(docker): support docker compositions and add a way to import `docker-compose.yml` files
- feat(docker): add instructions and icon for docker compositions
- refactor(core): rerender screen when rendering on the display is resumed like when returning from viewfinder to avoid artifacts
- refactor(docker): make composition menus responsive: showing spinner, etc

## Version 1.1.0

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ requires-python = ">=3.11"
keywords = ['ubo', 'ubo-pod', 'raspberry pi', 'rpi', 'home assistance']
dependencies = [
"psutil >=6.0.0",
"ubo-gui >=0.13.8",
"ubo-gui >=0.13.10",
"headless-kivy >=0.12.2",
"pyzbar >=0.1.9",
"sdbus-networkmanager >=2.0.0 ; platform_machine=='aarch64'",
Expand Down
4 changes: 3 additions & 1 deletion setup_scm_schemes.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@
def local_scheme(version) -> str: # noqa: ANN001
version.node = re.sub(r'.', lambda match: str(ord(match.group(0))), version.node)
original_local_version = get_local_node_and_date(version)
numeric_version = original_local_version.replace('+', '').replace('.d', '')
if not original_local_version:
return original_local_version
numeric_version = original_local_version.replace('+', '').replace('.d', '')[:12]
return datetime.now(UTC).strftime('%y%m%d') + numeric_version
2 changes: 1 addition & 1 deletion tests/flows/test_wireless.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def store_snapshot_selector(state: RootState) -> WiFiState:

app = MenuApp()
app_context.set_app(app)
load_services(['camera', 'display', 'notifications', 'wifi'])
await load_services(['camera', 'display', 'notifications', 'wifi'], run_async=True)

@wait_for(wait=wait_fixed(1), run_async=True)
def check_icon(expected_icon: str) -> None:
Expand Down
4 changes: 2 additions & 2 deletions ubo_app/menu_app/menu_central.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def select_by_icon(self: MenuAppCentral, event: MenuChooseByIconEvent) -> None:
f'"{len(filtered_items)}"'
)
raise ValueError(msg)
self.menu_widget.select_item(filtered_items[0])
self.menu_widget.select_item(filtered_items[0], parent=self.menu_widget.top)

@mainthread
def select_by_label(
Expand All @@ -241,7 +241,7 @@ def select_by_label(
f'"{len(filtered_items)}"'
)
raise ValueError(msg)
self.menu_widget.select_item(filtered_items[0])
self.menu_widget.select_item(filtered_items[0], parent=self.menu_widget.top)

@mainthread
def select_by_index(
Expand Down
7 changes: 3 additions & 4 deletions ubo_app/menu_app/menu_notification_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from collections.abc import Callable

from ubo_gui.menu.menu_widget import MenuWidget
from ubo_gui.menu.types import PageWidget


class NotificationReference:
Expand Down Expand Up @@ -173,10 +174,8 @@ def run_notification_action(action: NotificationActionItem) -> None:
if notification.value.extra_information:
text = notification.value.extra_information.text

def open_info() -> None:
info_application = NotificationInfo(text=text)

store.dispatch(OpenApplicationAction(application=info_application))
def open_info() -> PageWidget:
return NotificationInfo(text=text)

items.append(
NotificationActionItem(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ async def create_wireless_connection(self: CreateWirelessConnectionPage) -> None
},
)

print(11)
store.dispatch(
WiFiUpdateRequestAction(reset=True),
NotificationsAddAction(
Expand Down
35 changes: 35 additions & 0 deletions ubo_app/services/080-docker/docker_composition.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ def stop_composition(*, id: str) -> None:
"""Stop the composition."""

async def act() -> None:
store.dispatch(
DockerImageSetStatusAction(image=id, status=DockerItemStatus.PROCESSING),
)
stop_process = await asyncio.subprocess.create_subprocess_exec(
'docker',
'compose',
Expand All @@ -43,6 +46,9 @@ def run_composition(*, id: str) -> None:
"""Run the composition."""

async def act() -> None:
store.dispatch(
DockerImageSetStatusAction(image=id, status=DockerItemStatus.PROCESSING),
)
run_process = await asyncio.subprocess.create_subprocess_exec(
'docker',
'compose',
Expand All @@ -63,7 +69,36 @@ async def act() -> None:
create_task(act())


def pull_composition(*, id: str) -> None:
"""Pull the composition images."""

async def act() -> None:
store.dispatch(
DockerImageSetStatusAction(image=id, status=DockerItemStatus.FETCHING),
)
run_process = await asyncio.subprocess.create_subprocess_exec(
'docker',
'compose',
'pull',
cwd=COMPOSITIONS_PATH / id,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
await run_process.wait()
await log_async_process(
run_process,
title='Docker Composition Error',
message='Failed to run composition.',
)
await check_composition(id=id)

create_task(act())


async def _release_composition(id: str) -> None:
store.dispatch(
DockerImageSetStatusAction(image=id, status=DockerItemStatus.PROCESSING),
)
check_process = await asyncio.subprocess.create_subprocess_exec(
'docker',
'compose',
Expand Down
22 changes: 19 additions & 3 deletions ubo_app/services/080-docker/menus.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from docker_composition import (
check_composition,
delete_composition,
pull_composition,
release_composition,
run_composition,
stop_composition,
Expand Down Expand Up @@ -57,7 +58,7 @@


@store.view(lambda state: state.ip.interfaces)
def image_menu(
def image_menu( # noqa: C901
interfaces: Sequence[IpNetworkInterface],
image: ImageState,
) -> HeadedMenu:
Expand Down Expand Up @@ -93,6 +94,17 @@ def action() -> PageWidget:
if image.id.startswith('composition_')
else functools.partial(run_container, image=image),
),
*(
[
ActionItem(
label='Pull Images',
icon='󰇚',
action=functools.partial(pull_composition, id=image.id),
),
]
if image.id.startswith('composition_')
else []
),
ActionItem(
label='Delete Application'
if image.id.startswith('composition_')
Expand Down Expand Up @@ -182,16 +194,19 @@ def action() -> PageWidget:
),
),
)
elif image.status == DockerItemStatus.PROCESSING:
pass

if image.id.startswith('composition_'):
messages = {
DockerItemStatus.NOT_AVAILABLE: 'Need to fetch images',
DockerItemStatus.FETCHING: 'Images is being fetched',
DockerItemStatus.FETCHING: 'Images are being fetched',
DockerItemStatus.AVAILABLE: 'Images are ready but composition is not '
'running',
DockerItemStatus.CREATED: 'Composition is created but not running',
DockerItemStatus.RUNNING: 'Composition is running',
DockerItemStatus.ERROR: 'We have an error, please check the logs',
DockerItemStatus.PROCESSING: 'Waiting...',
}
else:
messages = {
Expand All @@ -201,14 +216,15 @@ def action() -> PageWidget:
DockerItemStatus.CREATED: 'Container is created but not running',
DockerItemStatus.RUNNING: IMAGES[image.id].note or 'Container is running',
DockerItemStatus.ERROR: 'We have an error, please check the logs',
DockerItemStatus.PROCESSING: 'Waiting...',
}

return HeadedMenu(
title=f'Docker - {image.label}',
heading=image.label,
sub_heading=messages[image.status],
items=items,
placeholder='Waiting...',
placeholder='',
)


Expand Down
4 changes: 2 additions & 2 deletions ubo_app/services/090-web-ui/reducer.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def reducer(
actions=[
NotificationsAddAction(
notification=Notification(
id='web_ui:pending',
id=f'web_ui:pending:{action.description.id}',
icon='󱋆',
title='Web UI',
content=f'[size=18dp]{action.description.prompt}[/size]',
Expand Down Expand Up @@ -81,7 +81,7 @@ def reducer(
if description.id != action.id
],
),
actions=[NotificationsClearByIdAction(id='web_ui:pending')],
actions=[NotificationsClearByIdAction(id=f'web_ui:pending:{action.id}')],
)

return state
1 change: 1 addition & 0 deletions ubo_app/store/services/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class DockerItemStatus(StrEnum):
CREATED = auto()
RUNNING = auto()
ERROR = auto()
PROCESSING = auto()


class DockerAction(BaseAction):
Expand Down
4 changes: 2 additions & 2 deletions ubo_app/utils/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,8 @@ def handle_cancel(event: CameraStopViewfinderEvent) -> None:
if selected_input_method is InputMethod.CAMERA
else NotificationExtraInformation(
text=f"""\
Web dashboard is served on port {hostname}:{WEB_UI_LISTEN_PORT} and it provides an \
interface for entering this input.""",
Web dashboard is served on port {hostname}.local:{WEB_UI_LISTEN_PORT} and it provides \
an interface for entering this input.""",
),
id=prompt_id,
pattern=pattern,
Expand Down
Loading

0 comments on commit c1e472f

Please sign in to comment.