Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 41 additions & 16 deletions src/aignostics/gui/_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from loguru import logger

from aignostics.constants import WINDOW_TITLE
from aignostics.platform import API_ROOT_PRODUCTION, API_ROOT_STAGING
from aignostics.utils import __version__, open_user_data_directory

from ._theme import theme
Expand All @@ -29,6 +30,24 @@
CLASSES_FULL_SIZE = f"{CLASSES_FULL_WIDTH} {CLASSES_FULL_HEIGHT}"


def get_status_page_url(api_root: str) -> str | None:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to move this logic to here?

"""Get the status page URL based on the API root environment.

Args:
api_root: The API root URL to determine the environment

Returns:
The status page URL for production/staging, or None for dev/test
"""
if api_root == API_ROOT_PRODUCTION:
return "https://status.platform.aignostics.com"
elif api_root == API_ROOT_STAGING:
return "https://status.platform-staging.aignostics.com"
else:
# No status page for dev and test environments
return None


@contextmanager
def frame( # noqa: C901, PLR0915
navigation_title: str,
Expand Down Expand Up @@ -213,7 +232,9 @@ def _update_health() -> None:
coroutine=_health_load_and_render(),
name="_health_load_and_render",
)
ui.run_javascript("document.getElementById('betterstack').src = document.getElementById('betterstack').src;")
# Only refresh the status iframe if it exists (production/staging)
if get_status_page_url(settings().api_root):
ui.run_javascript("document.getElementById('betterstack').src = document.getElementById('betterstack').src;")
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ui.run_javascript unconditionally dereferences document.getElementById('betterstack') when api_root is prod/staging. On initial page load (or during navigation) the timer callback can run before the iframe is in the DOM, which will cause a JS error (null.src). Consider guarding in the JS itself (check element exists) so the refresh is safe regardless of render timing.

Suggested change
ui.run_javascript("document.getElementById('betterstack').src = document.getElementById('betterstack').src;")
ui.run_javascript(
"var iframe = document.getElementById('betterstack');"
"if (iframe) { iframe.src = iframe.src; }"
)

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure whether this is an actual problem or not. Are you able to start the Launchpad against all environments?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@olivermeyer yes, it looks correct against the branch - no Betterstack status page icon for dev and test, different links for staging and prod.


ui.timer(interval=HEALTH_UPDATE_INTERVAL, callback=_update_health, immediate=True)

Expand Down Expand Up @@ -342,13 +363,15 @@ def toggle_dark_mode() -> None:
ui.link("Get Support", "https://platform.aignostics.com/support", new_tab=True).mark(
"LINK_DOCUMENTATION"
)
with ui.item().props("clickable"):
with ui.item_section().props("avatar"):
ui.icon("check_circle", color="primary")
with ui.item_section():
ui.link("Check Platform Status", "https://status.aignostics.com", new_tab=True).mark(
"LINK_DOCUMENTATION"
)
status_url = get_status_page_url(settings().api_root)
if status_url:
with ui.item().props("clickable"):
with ui.item_section().props("avatar"):
ui.icon("check_circle", color="primary")
with ui.item_section():
ui.link("Check Platform Status", status_url, new_tab=True).mark(
"LINK_DOCUMENTATION"
)
with ui.item().props("clickable"):
with ui.item_section().props("avatar"):
ui.icon("handshake", color="primary")
Expand All @@ -368,14 +391,16 @@ def toggle_dark_mode() -> None:
ui.row(align_items="center").classes("justify-start w-full"),
):
health_link()
with ui.row().style("padding: 0"):
ui.html(
'<iframe id="betterstack" src="https://status.aignostics.com/badge?theme=dark" '
'width="250" height="30" frameborder="0" scrolling="no" '
'style="color-scheme: dark"></iframe>',
sanitize=False,
).style("margin-left: 0px;")
ui.tooltip("Check Platform Status")
status_url = get_status_page_url(settings().api_root)
if status_url:
with ui.row().style("padding: 0"):
ui.html(
f'<iframe id="betterstack" src="{status_url}/badge?theme=dark" '
'width="250" height="30" frameborder="0" scrolling="no" '
'style="color-scheme: dark"></iframe>',
sanitize=False,
).style("margin-left: 0px;")
ui.tooltip("Check Platform Status")
ui.space()
with ui.row():
flavor = " (native)" if getattr(sys, "frozen", False) else ""
Expand Down
1 change: 1 addition & 0 deletions tests/aignostics/gui/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Tests for GUI module."""
71 changes: 71 additions & 0 deletions tests/aignostics/gui/frame_test.py
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we decide to move the status page URL resolution to the existing match..case block in the settings module, we don't need new tests; if we decide otherwise then we do need new tests but these are not in the right place. They should be in tests/aignostics/platform/settings_test.py.

Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""Tests for GUI frame module."""

import pytest

from aignostics.gui._frame import get_status_page_url
from aignostics.platform import (
API_ROOT_DEV,
API_ROOT_PRODUCTION,
API_ROOT_STAGING,
API_ROOT_TEST,
)


@pytest.mark.unit
def test_get_status_page_url_production(record_property) -> None:
"""Test that production environment returns correct status page URL.

Args:
record_property: pytest record_property fixture
"""
record_property("tested-item-id", "SPEC-GUI-FRAME")
url = get_status_page_url(API_ROOT_PRODUCTION)
assert url == "https://status.platform.aignostics.com"


@pytest.mark.unit
def test_get_status_page_url_staging(record_property) -> None:
"""Test that staging environment returns correct status page URL.

Args:
record_property: pytest record_property fixture
"""
record_property("tested-item-id", "SPEC-GUI-FRAME")
url = get_status_page_url(API_ROOT_STAGING)
assert url == "https://status.platform-staging.aignostics.com"


@pytest.mark.unit
def test_get_status_page_url_dev(record_property) -> None:
"""Test that dev environment returns None (no status page).

Args:
record_property: pytest record_property fixture
"""
record_property("tested-item-id", "SPEC-GUI-FRAME")
url = get_status_page_url(API_ROOT_DEV)
assert url is None


@pytest.mark.unit
def test_get_status_page_url_test(record_property) -> None:
"""Test that test environment returns None (no status page).

Args:
record_property: pytest record_property fixture
"""
record_property("tested-item-id", "SPEC-GUI-FRAME")
url = get_status_page_url(API_ROOT_TEST)
assert url is None


@pytest.mark.unit
def test_get_status_page_url_unknown(record_property) -> None:
"""Test that unknown environment returns None (no status page).

Args:
record_property: pytest record_property fixture
"""
record_property("tested-item-id", "SPEC-GUI-FRAME")
url = get_status_page_url("https://custom.example.com")
assert url is None
Loading