aignostics 0.2.23__tar.gz → 0.2.30__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aignostics-0.2.23 → aignostics-0.2.30}/PKG-INFO +1 -1
- {aignostics-0.2.23 → aignostics-0.2.30}/examples/notebook.py +1 -1
- {aignostics-0.2.23 → aignostics-0.2.30}/pyproject.toml +2 -2
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/_page_application_run_describe.py +43 -18
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_service.py +19 -7
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/gui/_frame.py +3 -3
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/notebook/_gui.py +23 -6
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/notebook/_notebook.py +7 -30
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/system/_cli.py +33 -44
- aignostics-0.2.30/src/aignostics/system/_gui.py +93 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/system/_service.py +85 -0
- aignostics-0.2.30/src/aignostics/system/assets/system.lottie +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/__init__.py +3 -0
- aignostics-0.2.30/src/aignostics/utils/_fs.py +74 -0
- aignostics-0.2.23/src/aignostics/system/_gui.py +0 -61
- {aignostics-0.2.23 → aignostics-0.2.30}/.gitignore +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/LICENSE +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/README.md +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/.openapi-generator/FILES +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/.openapi-generator/VERSION +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/api/public_api.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/api_client.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/api_response.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/configuration.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/exceptions.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/__init__.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/application_read_response.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/application_run_status.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/application_version_read_response.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/http_validation_error.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/input_artifact_creation_request.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/input_artifact_read_response.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/item_creation_request.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/item_result_read_response.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/item_status.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/output_artifact_read_response.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/output_artifact_result_read_response.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/output_artifact_scope.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/payload_input_artifact.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/payload_item.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/payload_output_artifact.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/run_creation_request.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/run_creation_response.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/run_read_response.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/transfer_urls.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/user_payload.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/validation_error.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/models/validation_error_loc_inner.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/aignx/codegen/rest.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/codegen/out/docs/PublicApi.md +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/examples/__init__.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/examples/e2e.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/examples/notebook.ipynb +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/examples/script.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/__init__.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/__init__.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_cli.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/_frame.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/_page_application_describe.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/_page_builder.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/_page_index.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/_utils.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/canceled.lottie +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/done.lottie +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/empty.lottie +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/error.lottie +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/error_alt.lottie +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/home-card-1.png +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/home-card-2.png +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/home-card-3.png +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/home-card-4.png +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/home-card-5.png +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/image-not-found.png +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/pending.lottie +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/pending_alt.lottie +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/ruo.png +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_gui/assets/ruo.svg +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_settings.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/application/_utils.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/bucket/__init__.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/bucket/_cli.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/bucket/_gui.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/bucket/_service.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/bucket/_settings.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/bucket/assets/Google-Cloud-logo.png +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/bucket/assets/Google-Cloud-logo.svg +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/cli.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/constants.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/dataset/__init__.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/dataset/_cli.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/dataset/_gui.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/dataset/_idc_index.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/dataset/_service.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/dataset/assets/NIH-IDC-logo.svg +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/gui/__init__.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/gui/_theme.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/gui/assets/cabin-v27-latin-regular.woff2 +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/gui/assets/logo.png +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/notebook/__init__.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/notebook/_service.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/notebook/assets/python.lottie +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/platform/__init__.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/platform/_authentication.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/platform/_client.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/platform/_constants.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/platform/_messages.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/platform/_service.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/platform/_settings.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/platform/_utils.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/platform/resources/__init__.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/platform/resources/applications.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/platform/resources/runs.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/platform/resources/utils.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/qupath/__init__.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/qupath/_cli.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/qupath/_gui.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/qupath/_service.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/qupath/_settings.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/qupath/assets/download.lottie +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/qupath/assets/microscope.lottie +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/system/__init__.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/system/_exceptions.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/system/_settings.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/.vendored/bottle.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/_cli.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/_console.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/_constants.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/_di.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/_gui.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/_health.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/_log.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/_logfire.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/_notebook.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/_process.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/_sentry.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/_service.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/_settings.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/utils/boot.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/wsi/__init__.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/wsi/_cli.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/wsi/_gui.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/wsi/_openslide_handler.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/wsi/_pydicom_handler.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/wsi/_service.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/wsi/_utils.py +0 -0
- {aignostics-0.2.23 → aignostics-0.2.30}/src/aignostics/wsi/assets/fallback.png +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aignostics
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.30
|
|
4
4
|
Summary: 🔬 Python SDK providing access to the Aignostics Platform. Includes Aignostics Launchpad (Desktop Application), Aignostics CLI (Command-Line Interface), example notebooks, and Aignostics Client Library.
|
|
5
5
|
Project-URL: Homepage, https://aignostics.readthedocs.io/en/latest/
|
|
6
6
|
Project-URL: Documentation, https://aignostics.readthedocs.io/en/latest/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "aignostics"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.30"
|
|
4
4
|
description = "🔬 Python SDK providing access to the Aignostics Platform. Includes Aignostics Launchpad (Desktop Application), Aignostics CLI (Command-Line Interface), example notebooks, and Aignostics Client Library."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -355,7 +355,7 @@ source = ["src/"]
|
|
|
355
355
|
|
|
356
356
|
|
|
357
357
|
[tool.bumpversion]
|
|
358
|
-
current_version = "0.2.
|
|
358
|
+
current_version = "0.2.30"
|
|
359
359
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
|
360
360
|
serialize = ["{major}.{minor}.{patch}"]
|
|
361
361
|
search = "{current_version}"
|
|
@@ -4,7 +4,7 @@ from importlib.util import find_spec
|
|
|
4
4
|
from multiprocessing import Manager
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Any
|
|
7
|
-
from urllib.parse import quote
|
|
7
|
+
from urllib.parse import quote
|
|
8
8
|
|
|
9
9
|
from nicegui import run as nicegui_run
|
|
10
10
|
from nicegui import ui # noq
|
|
@@ -87,7 +87,7 @@ async def _page_application_run_describe(application_run_id: str) -> None: # no
|
|
|
87
87
|
return False
|
|
88
88
|
|
|
89
89
|
@ui.refreshable
|
|
90
|
-
def download_run_dialog_content(qupath_project: bool = False) -> None: # noqa: C901, PLR0915
|
|
90
|
+
def download_run_dialog_content(qupath_project: bool = False, marimo: bool = False) -> None: # noqa: C901, PLR0915
|
|
91
91
|
if qupath_project:
|
|
92
92
|
ui.markdown(
|
|
93
93
|
"##### Visualize results in QuPath with one click \n"
|
|
@@ -97,6 +97,13 @@ async def _page_application_run_describe(application_run_id: str) -> None: # no
|
|
|
97
97
|
"4. The QuPath project will reference the input slides and resulting image heatmaps. \n"
|
|
98
98
|
"5. Detected cells will be added as annotations to input slides. \n"
|
|
99
99
|
)
|
|
100
|
+
elif marimo:
|
|
101
|
+
ui.markdown(
|
|
102
|
+
"##### Open results in Marimo with one click \n"
|
|
103
|
+
"1. Use data directory of Launchpad or select a custom folder. \n"
|
|
104
|
+
"2. A subfolder with the application run will be created and all results downloaded there. \n"
|
|
105
|
+
"3. A Marimo notebook will be started pointing to the subfolder. \n"
|
|
106
|
+
)
|
|
100
107
|
else:
|
|
101
108
|
ui.markdown(
|
|
102
109
|
"##### Download all results with one click \n"
|
|
@@ -223,6 +230,10 @@ async def _page_application_run_describe(application_run_id: str) -> None: # no
|
|
|
223
230
|
ui.notify("Download and QuPath project creation completed.", type="positive")
|
|
224
231
|
download_item_status.set_text("Opening QuPath ...")
|
|
225
232
|
await open_qupath(project=results_folder / "qupath", button=download_button)
|
|
233
|
+
elif marimo:
|
|
234
|
+
ui.notify("Download and Notebook preparation completed.", type="positive")
|
|
235
|
+
download_item_status.set_text("Opening Notebook ...")
|
|
236
|
+
open_marimo(results_folder=results_folder, button=download_button)
|
|
226
237
|
else:
|
|
227
238
|
ui.notify("Download completed.", type="positive")
|
|
228
239
|
show_in_file_manager(str(results_folder))
|
|
@@ -238,10 +249,20 @@ async def _page_application_run_describe(application_run_id: str) -> None: # no
|
|
|
238
249
|
|
|
239
250
|
ui.separator()
|
|
240
251
|
with ui.row(align_items="end").classes("w-full justify-end"):
|
|
252
|
+
if qupath_project:
|
|
253
|
+
label = "Visualize with QuPath"
|
|
254
|
+
icon = "zoom_in"
|
|
255
|
+
elif marimo:
|
|
256
|
+
label = "Analyze with Notebook"
|
|
257
|
+
icon = "analytics"
|
|
258
|
+
else:
|
|
259
|
+
label = "Download all results"
|
|
260
|
+
icon = "cloud_download"
|
|
261
|
+
|
|
241
262
|
download_button = (
|
|
242
263
|
ui.button(
|
|
243
|
-
|
|
244
|
-
icon=
|
|
264
|
+
label,
|
|
265
|
+
icon=icon,
|
|
245
266
|
on_click=start_download,
|
|
246
267
|
)
|
|
247
268
|
.props("color=primary")
|
|
@@ -254,9 +275,9 @@ async def _page_application_run_describe(application_run_id: str) -> None: # no
|
|
|
254
275
|
with ui.dialog() as download_run_dialog, ui.card().style(WIDTH_1200px):
|
|
255
276
|
download_run_dialog_content()
|
|
256
277
|
|
|
257
|
-
def download_run_dialog_open(qupath_project: bool = False) -> None:
|
|
278
|
+
def download_run_dialog_open(qupath_project: bool = False, marimo: bool = False) -> None:
|
|
258
279
|
"""Open the CSV dialog."""
|
|
259
|
-
download_run_dialog_content.refresh(qupath_project=qupath_project)
|
|
280
|
+
download_run_dialog_content.refresh(qupath_project=qupath_project, marimo=marimo)
|
|
260
281
|
download_run_dialog.open()
|
|
261
282
|
|
|
262
283
|
@ui.refreshable
|
|
@@ -315,7 +336,7 @@ async def _page_application_run_describe(application_run_id: str) -> None: # no
|
|
|
315
336
|
if url:
|
|
316
337
|
try:
|
|
317
338
|
with ui.scroll_area().classes("w-full h-[calc(100vh-2rem)]"):
|
|
318
|
-
ui.image("/tiff?url=" +
|
|
339
|
+
ui.image("/tiff?url=" + quote(url))
|
|
319
340
|
except Exception as e: # noqa: BLE001
|
|
320
341
|
ui.notify(f"Failed to load CSV: {e!s}", type="negative")
|
|
321
342
|
|
|
@@ -361,11 +382,11 @@ async def _page_application_run_describe(application_run_id: str) -> None: # no
|
|
|
361
382
|
button.enable()
|
|
362
383
|
button.props(remove="loading")
|
|
363
384
|
|
|
364
|
-
def open_marimo() -> None:
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
385
|
+
def open_marimo(results_folder: Path, button: ui.button | None = None) -> None:
|
|
386
|
+
if button:
|
|
387
|
+
button.disable()
|
|
388
|
+
button.props(add="loading")
|
|
389
|
+
ui.navigate.to(f"/notebook/{run.application_run_id}?results_folder={quote(results_folder.as_posix())}")
|
|
369
390
|
|
|
370
391
|
if run_data: # noqa: PLR1702
|
|
371
392
|
with ui.row().classes("w-full justify-center"):
|
|
@@ -399,11 +420,15 @@ async def _page_application_run_describe(application_run_id: str) -> None: # no
|
|
|
399
420
|
):
|
|
400
421
|
ui.tooltip("Open results in QuPath Microscopy Viewer")
|
|
401
422
|
if find_spec("marimo"):
|
|
402
|
-
with
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
423
|
+
with (
|
|
424
|
+
ui.button(
|
|
425
|
+
"Marimo",
|
|
426
|
+
icon="analytics",
|
|
427
|
+
on_click=lambda _: download_run_dialog_open(qupath_project=False, marimo=True),
|
|
428
|
+
)
|
|
429
|
+
.mark("BUTTON_OPEN_NOTEBOOK")
|
|
430
|
+
.props("push")
|
|
431
|
+
):
|
|
407
432
|
ui.tooltip("Open results in Python Notebook served by Marimo")
|
|
408
433
|
if run_data.status.value == ApplicationRunStatus.RUNNING:
|
|
409
434
|
ui.button(
|
|
@@ -434,7 +459,7 @@ async def _page_application_run_describe(application_run_id: str) -> None: # no
|
|
|
434
459
|
):
|
|
435
460
|
image_file: Path | None = Path(item.reference).resolve()
|
|
436
461
|
if image_file and image_file.is_file():
|
|
437
|
-
image_url = "/thumbnail?source=" +
|
|
462
|
+
image_url = "/thumbnail?source=" + quote(image_file.as_posix())
|
|
438
463
|
else:
|
|
439
464
|
image_file = None
|
|
440
465
|
image_url = "/application_assets/image-not-found.png"
|
|
@@ -29,9 +29,9 @@ from aignostics.platform import (
|
|
|
29
29
|
ItemResult,
|
|
30
30
|
ItemStatus,
|
|
31
31
|
NotFoundException,
|
|
32
|
-
|
|
32
|
+
OutputArtifactElement,
|
|
33
33
|
)
|
|
34
|
-
from aignostics.utils import BaseService, Health, get_logger
|
|
34
|
+
from aignostics.utils import BaseService, Health, get_logger, sanitize_path_component
|
|
35
35
|
from aignostics.wsi import Service as WSIService
|
|
36
36
|
|
|
37
37
|
from ._settings import Settings
|
|
@@ -73,7 +73,7 @@ class DownloadProgress(BaseModel):
|
|
|
73
73
|
item_count: int | None = None
|
|
74
74
|
item_index: int | None = None
|
|
75
75
|
item_reference: str | None = None
|
|
76
|
-
artifact:
|
|
76
|
+
artifact: OutputArtifactElement | None = None
|
|
77
77
|
artifact_count: int | None = None
|
|
78
78
|
artifact_index: int | None = None
|
|
79
79
|
artifact_path: Path | None = None
|
|
@@ -705,7 +705,7 @@ class Service(BaseService):
|
|
|
705
705
|
download_progress_queue,
|
|
706
706
|
)
|
|
707
707
|
|
|
708
|
-
def application_run_download( # noqa: C901, PLR0912, PLR0913, PLR0915, PLR0917
|
|
708
|
+
def application_run_download( # noqa: C901, PLR0912, PLR0913, PLR0914, PLR0915, PLR0917
|
|
709
709
|
self,
|
|
710
710
|
run_id: str,
|
|
711
711
|
destination_directory: Path,
|
|
@@ -876,12 +876,19 @@ class Service(BaseService):
|
|
|
876
876
|
get_mime_type_for_artifact(artifact) == "application/geo+json"
|
|
877
877
|
and artifact.name == "cell_classification:geojson_polygons"
|
|
878
878
|
):
|
|
879
|
+
artifact_name = artifact.name
|
|
879
880
|
if create_subdirectory_per_item:
|
|
880
881
|
reference_path = Path(item.reference)
|
|
881
882
|
stem_name = reference_path.stem
|
|
882
|
-
artifact_path =
|
|
883
|
+
artifact_path = (
|
|
884
|
+
final_destination_directory
|
|
885
|
+
/ stem_name
|
|
886
|
+
/ f"{sanitize_path_component(artifact_name)}.json"
|
|
887
|
+
)
|
|
883
888
|
else:
|
|
884
|
-
artifact_path =
|
|
889
|
+
artifact_path = (
|
|
890
|
+
final_destination_directory / f"{sanitize_path_component(artifact_name)}.json"
|
|
891
|
+
)
|
|
885
892
|
message = f"Annotating input slide '{image_path}' with artifact '{artifact_path}' ..."
|
|
886
893
|
logger.debug(message)
|
|
887
894
|
added = QuPathService.annotate(
|
|
@@ -943,6 +950,8 @@ class Service(BaseService):
|
|
|
943
950
|
progress.status = DownloadProgressState.DOWNLOADING
|
|
944
951
|
progress.item_index = item_index
|
|
945
952
|
progress.item = item
|
|
953
|
+
progress.item_reference = item.reference
|
|
954
|
+
|
|
946
955
|
progress.artifact_count = len(item.output_artifacts)
|
|
947
956
|
Service._update_progress(progress, download_progress_callable, download_progress_queue)
|
|
948
957
|
|
|
@@ -1007,7 +1016,10 @@ class Service(BaseService):
|
|
|
1007
1016
|
logger.error(message)
|
|
1008
1017
|
raise ValueError(message)
|
|
1009
1018
|
|
|
1010
|
-
artifact_path =
|
|
1019
|
+
artifact_path = (
|
|
1020
|
+
destination_directory
|
|
1021
|
+
/ f"{prefix}{sanitize_path_component(artifact.name)}{get_file_extension_for_artifact(artifact)}"
|
|
1022
|
+
)
|
|
1011
1023
|
|
|
1012
1024
|
if artifact_path.exists():
|
|
1013
1025
|
checksum = google_crc32c.Checksum() # type: ignore[no-untyped-call]
|
|
@@ -44,9 +44,9 @@ def frame( # noqa: C901, PLR0915
|
|
|
44
44
|
@ui.refreshable
|
|
45
45
|
def health_icon() -> None:
|
|
46
46
|
if launchpad_healthy:
|
|
47
|
-
ui.icon("
|
|
47
|
+
ui.icon("settings", color="positive")
|
|
48
48
|
elif launchpad_healthy is not None:
|
|
49
|
-
ui.icon("
|
|
49
|
+
ui.icon("settings", color="negative")
|
|
50
50
|
|
|
51
51
|
@ui.refreshable
|
|
52
52
|
def health_link() -> None:
|
|
@@ -215,7 +215,7 @@ def frame( # noqa: C901, PLR0915
|
|
|
215
215
|
with ui.item_section().props("avatar"):
|
|
216
216
|
health_icon()
|
|
217
217
|
with ui.item_section():
|
|
218
|
-
ui.label("
|
|
218
|
+
ui.label("Info and Settings").tailwind.font_weight(
|
|
219
219
|
"bold" if context.client.page.path == "/system" else "normal"
|
|
220
220
|
)
|
|
221
221
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"""Notebook GUI."""
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
|
+
from urllib.parse import quote
|
|
4
5
|
|
|
5
6
|
from aignostics.gui import frame, theme
|
|
7
|
+
from aignostics.system import Service as SystemService
|
|
6
8
|
from aignostics.utils import BasePageBuilder, get_logger
|
|
7
9
|
|
|
8
10
|
logger = get_logger(__name__)
|
|
@@ -24,6 +26,14 @@ class PageBuilder(BasePageBuilder):
|
|
|
24
26
|
# Nothing to do here, just to show the page
|
|
25
27
|
pass
|
|
26
28
|
|
|
29
|
+
def launch_marimo() -> None:
|
|
30
|
+
"""Launch QuPath."""
|
|
31
|
+
launch_button.props(add="loading")
|
|
32
|
+
ui.notify("Launching Python Notebook...", color="blue")
|
|
33
|
+
ui.navigate.to(
|
|
34
|
+
f"/notebook/all?results_folder={quote(SystemService.get_user_data_directory('results').as_posix())}"
|
|
35
|
+
)
|
|
36
|
+
|
|
27
37
|
ui.markdown(
|
|
28
38
|
"""
|
|
29
39
|
### Manage your Marimo Extension
|
|
@@ -36,7 +46,12 @@ class PageBuilder(BasePageBuilder):
|
|
|
36
46
|
"Marimo is installed and ready to execute. "
|
|
37
47
|
"Go to a completed application result and click the Notebook button."
|
|
38
48
|
)
|
|
39
|
-
|
|
49
|
+
with ui.row().classes("w-full justify-between items-center"):
|
|
50
|
+
launch_button = ui.button(
|
|
51
|
+
"Open",
|
|
52
|
+
on_click=launch_marimo,
|
|
53
|
+
icon="visibility",
|
|
54
|
+
).mark("BUTTON_NOTEBOOK_LAUNCH")
|
|
40
55
|
ui.markdown(
|
|
41
56
|
"""
|
|
42
57
|
###### What is Marimo?
|
|
@@ -73,23 +88,25 @@ class PageBuilder(BasePageBuilder):
|
|
|
73
88
|
ui.space()
|
|
74
89
|
|
|
75
90
|
@ui.page("/notebook/{application_run_id}")
|
|
76
|
-
def page_application_run_marimo(application_run_id: str) -> None:
|
|
91
|
+
def page_application_run_marimo(application_run_id: str, results_folder: str) -> None:
|
|
77
92
|
"""Inspect Application Run in Marimo."""
|
|
78
93
|
theme()
|
|
79
94
|
|
|
80
95
|
with ui.row().classes("w-full justify-end"):
|
|
81
96
|
ui.button(
|
|
82
|
-
"Back to Application Run",
|
|
97
|
+
"Back to Application Run" if application_run_id != "all" else "Back to Marimo Extension",
|
|
83
98
|
icon="arrow_back",
|
|
84
99
|
on_click=lambda _, application_run_id=application_run_id: ui.navigate.to(
|
|
85
|
-
f"/application/run/{application_run_id}"
|
|
100
|
+
f"/application/run/{application_run_id}" if application_run_id != "all" else "/notebook"
|
|
86
101
|
),
|
|
87
|
-
)
|
|
102
|
+
).mark("BUTTON_NOTEBOOK_BACK")
|
|
88
103
|
|
|
89
104
|
try:
|
|
90
105
|
server_url = Service().start()
|
|
91
106
|
ui.html(
|
|
92
|
-
f'<iframe src="{server_url}?
|
|
107
|
+
f'<iframe src="{server_url}?application_run_id={application_run_id}'
|
|
108
|
+
f'&results_folder={quote(results_folder)}" '
|
|
109
|
+
'width="100%" height="100%"></iframe>'
|
|
93
110
|
).classes("w-full h-[calc(100vh-5rem)]")
|
|
94
111
|
except Exception:
|
|
95
112
|
message = "Failed to start Marimo server."
|
|
@@ -8,22 +8,13 @@
|
|
|
8
8
|
|
|
9
9
|
import marimo
|
|
10
10
|
|
|
11
|
-
__generated_with = "0.13.
|
|
11
|
+
__generated_with = "0.13.15"
|
|
12
12
|
app = marimo.App(width="full")
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
@app.cell
|
|
16
|
-
def _(mo):
|
|
17
|
-
query_params = mo.query_params()
|
|
18
|
-
print(query_params)
|
|
19
|
-
|
|
20
|
-
print("Hallo Test Omid")
|
|
21
|
-
return
|
|
22
|
-
|
|
23
|
-
|
|
24
15
|
@app.cell
|
|
25
16
|
def _():
|
|
26
|
-
"""
|
|
17
|
+
"""Aignostics Notebook
|
|
27
18
|
|
|
28
19
|
Notes:
|
|
29
20
|
- See https://colab.research.google.com/github/ImagingDataCommons/IDC-Tutorials/blob/master/notebooks/pathomics/microscopy_dicom_ann_intro.ipynb#scrollTo=fMRsnFlzinO5
|
|
@@ -39,14 +30,6 @@ def _():
|
|
|
39
30
|
from aignostics import dataset
|
|
40
31
|
from wsidicom import WsiDicom
|
|
41
32
|
|
|
42
|
-
load_dotenv()
|
|
43
|
-
|
|
44
|
-
os.environ
|
|
45
|
-
|
|
46
|
-
print(os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", "default"))
|
|
47
|
-
|
|
48
|
-
print(Path.cwd())
|
|
49
|
-
|
|
50
33
|
mo.sidebar([
|
|
51
34
|
mo.md("# aignostics"),
|
|
52
35
|
mo.nav_menu(
|
|
@@ -61,23 +44,17 @@ def _():
|
|
|
61
44
|
orientation="vertical",
|
|
62
45
|
),
|
|
63
46
|
])
|
|
64
|
-
|
|
65
|
-
mo.vstack([
|
|
66
|
-
mo.ui.file_browser( # type: ignore
|
|
67
|
-
GSPath("gs://aignx-storage-service-dev/sample_data_formatted"), # type: ignore
|
|
68
|
-
filetypes=[".dcm", ".tif", ".tiff", ".svs", ".json"],
|
|
69
|
-
multiple=True,
|
|
70
|
-
restrict_navigation=True,
|
|
71
|
-
)
|
|
72
|
-
]) # type: ignore
|
|
73
47
|
return Path, WsiDicom, dataset, mo, plt
|
|
74
|
-
|
|
48
|
+
|
|
75
49
|
|
|
76
50
|
@app.cell
|
|
77
51
|
def _(Path, mo):
|
|
52
|
+
query_params = mo.query_params()
|
|
53
|
+
application_run_id = query_params["application_run_id"]
|
|
54
|
+
print(f"Application run id '{application_run_id}'")
|
|
78
55
|
mo.vstack([
|
|
79
56
|
mo.ui.file_browser(
|
|
80
|
-
Path("
|
|
57
|
+
Path(query_params["results_folder"]),
|
|
81
58
|
filetypes=[".dcm", ".tif", ".tiff", ".svs"],
|
|
82
59
|
multiple=True,
|
|
83
60
|
restrict_navigation=True,
|
|
@@ -4,14 +4,13 @@ import json
|
|
|
4
4
|
import sys
|
|
5
5
|
from enum import StrEnum
|
|
6
6
|
from importlib.util import find_spec
|
|
7
|
-
from pathlib import Path
|
|
8
7
|
from typing import Annotated
|
|
9
8
|
|
|
10
9
|
import typer
|
|
11
10
|
import yaml
|
|
12
11
|
|
|
13
12
|
from ..constants import API_VERSIONS # noqa: TID252
|
|
14
|
-
from ..utils import
|
|
13
|
+
from ..utils import console, get_logger # noqa: TID252
|
|
15
14
|
from ._service import Service
|
|
16
15
|
|
|
17
16
|
logger = get_logger(__name__)
|
|
@@ -160,7 +159,7 @@ cli.add_typer(config_app, name="config", help="Configure application settings.")
|
|
|
160
159
|
@config_app.command()
|
|
161
160
|
def get(key: Annotated[str, typer.Argument(help="Configuration key to get value for")]) -> None:
|
|
162
161
|
"""Set a configuration key to a value."""
|
|
163
|
-
console.print(Service
|
|
162
|
+
console.print(Service.dotenv_get(key.upper()))
|
|
164
163
|
|
|
165
164
|
|
|
166
165
|
@config_app.command()
|
|
@@ -170,7 +169,11 @@ def set( # noqa: A001
|
|
|
170
169
|
) -> None:
|
|
171
170
|
"""Set a configuration key to a value."""
|
|
172
171
|
key = key.upper()
|
|
173
|
-
|
|
172
|
+
try:
|
|
173
|
+
Service.dotenv_set(key, value)
|
|
174
|
+
except ValueError as e:
|
|
175
|
+
console.print(f"Invalid configuration: {e!s}", style="error")
|
|
176
|
+
sys.exit(2)
|
|
174
177
|
console.print(f"Configuration '{key}' set to '{value}'.", style="success")
|
|
175
178
|
|
|
176
179
|
|
|
@@ -180,24 +183,30 @@ def unset(
|
|
|
180
183
|
) -> None:
|
|
181
184
|
"""Set a configuration key to a value."""
|
|
182
185
|
key = key.upper()
|
|
183
|
-
Service
|
|
186
|
+
Service.dotenv_unset(key)
|
|
184
187
|
console.print(f"Configuration '{key}' unset.", style="success")
|
|
185
188
|
|
|
186
189
|
|
|
187
190
|
@config_app.command()
|
|
188
191
|
def remote_diagnostics_enable() -> None:
|
|
189
192
|
"""Enable remote diagnostics via Sentry and Logfire. Data stored in EU data centers."""
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
+
try:
|
|
194
|
+
Service.remote_diagnostics_enable()
|
|
195
|
+
console.print("Remote diagnostics enabled.", style="success")
|
|
196
|
+
except ValueError as e:
|
|
197
|
+
console.print(f"Invalid diagnostics configuration: {e!s}", style="error")
|
|
198
|
+
sys.exit(2)
|
|
193
199
|
|
|
194
200
|
|
|
195
201
|
@config_app.command()
|
|
196
202
|
def remote_diagnostics_disable() -> None:
|
|
197
203
|
"""Disable remote diagnostics."""
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
204
|
+
try:
|
|
205
|
+
Service.remote_diagnostics_disable()
|
|
206
|
+
console.print("Remote diagnostics disabled.", style="success")
|
|
207
|
+
except ValueError as e:
|
|
208
|
+
console.print(f"Invalid diagnostics configuration: {e!s}", style="error")
|
|
209
|
+
sys.exit(2)
|
|
201
210
|
|
|
202
211
|
|
|
203
212
|
@config_app.command()
|
|
@@ -209,42 +218,22 @@ def http_proxy_enable(
|
|
|
209
218
|
no_ssl_verify: Annotated[bool, typer.Option(help="Disable SSL verification")] = False,
|
|
210
219
|
) -> None:
|
|
211
220
|
"""Enable HTTP proxy."""
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
221
|
+
try:
|
|
222
|
+
Service().http_proxy_enable(
|
|
223
|
+
host=host, port=port, scheme=scheme, ssl_cert_file=ssl_cert_file, no_ssl_verify=no_ssl_verify
|
|
224
|
+
)
|
|
225
|
+
console.print("HTTP proxy enabled.", style="success")
|
|
226
|
+
except ValueError as e:
|
|
227
|
+
console.print(f"Invalid HTTP proxy configuration: {e!s}", style="error")
|
|
218
228
|
sys.exit(2)
|
|
219
|
-
if no_ssl_verify:
|
|
220
|
-
Service().dotenv_set("SSL_NO_VERIFY", "1")
|
|
221
|
-
Service().dotenv_set("SSL_CERT_FILE", "")
|
|
222
|
-
Service().dotenv_set("REQUESTS_CA_BUNDLE", "")
|
|
223
|
-
Service().dotenv_set("CURL_CA_BUNDLE", "")
|
|
224
|
-
else:
|
|
225
|
-
Service().dotenv_unset("SSL_NO_VERIFY")
|
|
226
|
-
Service().dotenv_unset("SSL_CERT_FILE")
|
|
227
|
-
Service().dotenv_unset("REQUESTS_CA_BUNDLE")
|
|
228
|
-
Service().dotenv_unset("CURL_CA_BUNDLE")
|
|
229
|
-
if ssl_cert_file:
|
|
230
|
-
file = Path(ssl_cert_file).resolve()
|
|
231
|
-
if not file.is_file():
|
|
232
|
-
message = f"SSL certificate file '{ssl_cert_file}' does not exist."
|
|
233
|
-
console.print(message, style="error")
|
|
234
|
-
sys.exit(2)
|
|
235
|
-
Service().dotenv_set("SSL_CERT_FILE", str(ssl_cert_file))
|
|
236
|
-
Service().dotenv_set("REQUESTS_CA_BUNDLE", str(ssl_cert_file))
|
|
237
|
-
Service().dotenv_set("CURL_CA_BUNDLE", str(ssl_cert_file))
|
|
238
|
-
console.print("HTTP proxy enabled.", style="success")
|
|
239
229
|
|
|
240
230
|
|
|
241
231
|
@config_app.command()
|
|
242
232
|
def http_proxy_disable() -> None:
|
|
243
233
|
"""Disable HTTP proxy."""
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
console.print("HTTP proxy disabled.", style="success")
|
|
234
|
+
try:
|
|
235
|
+
Service.http_proxy_disable()
|
|
236
|
+
console.print("HTTP proxy disabled.", style="success")
|
|
237
|
+
except ValueError as e:
|
|
238
|
+
console.print(f"Invalid HTTP proxy configuration: {e!s}", style="error")
|
|
239
|
+
sys.exit(2)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Homepage (index) of GUI."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from aignostics.gui import frame
|
|
6
|
+
from aignostics.utils import BaseService, locate_subclasses
|
|
7
|
+
|
|
8
|
+
from ..utils import BasePageBuilder # noqa: TID252
|
|
9
|
+
from ._service import Service
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PageBuilder(BasePageBuilder):
|
|
13
|
+
@staticmethod
|
|
14
|
+
def register_pages() -> None:
|
|
15
|
+
from nicegui import app, run, ui # noqa: PLC0415
|
|
16
|
+
|
|
17
|
+
locate_subclasses(BaseService) # Ensure settings are loaded
|
|
18
|
+
app.add_static_files("/system_assets", Path(__file__).parent / "assets")
|
|
19
|
+
|
|
20
|
+
ui.add_head_html("""
|
|
21
|
+
<style>
|
|
22
|
+
:global(.jse-modal-window.jse-modal-window-jsoneditor)
|
|
23
|
+
{
|
|
24
|
+
width: 100%;
|
|
25
|
+
height: 100%;
|
|
26
|
+
min-height: 900px;
|
|
27
|
+
}
|
|
28
|
+
</style>
|
|
29
|
+
""")
|
|
30
|
+
|
|
31
|
+
@ui.page("/system")
|
|
32
|
+
async def page_system() -> None:
|
|
33
|
+
"""System info and settings page."""
|
|
34
|
+
with frame("Info and Settings", left_sidebar=False):
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
with ui.row().classes("w-full gap-4 flex-nowrap"):
|
|
38
|
+
with ui.column().classes("w-3/5 flex-shrink-0"):
|
|
39
|
+
with ui.tabs().classes("w-full") as tabs:
|
|
40
|
+
tab_health = ui.tab("Health")
|
|
41
|
+
tab_info = ui.tab("Info")
|
|
42
|
+
tab_settings = ui.tab("Settings")
|
|
43
|
+
with ui.tab_panels(tabs, value=tab_health).classes("w-full"):
|
|
44
|
+
with ui.tab_panel(tab_health):
|
|
45
|
+
properties = {
|
|
46
|
+
"content": {"json": Service().health().model_dump()},
|
|
47
|
+
"mode": "tree",
|
|
48
|
+
"readOnly": True,
|
|
49
|
+
"mainMenuBar": False,
|
|
50
|
+
"navigationBar": False,
|
|
51
|
+
"statusBar": False,
|
|
52
|
+
}
|
|
53
|
+
ui.json_editor(properties).style("width: 100%").mark("JSON_EDITOR_INFO")
|
|
54
|
+
with ui.tab_panel(tab_info):
|
|
55
|
+
spinner = ui.spinner("dots", size="lg", color="red")
|
|
56
|
+
properties = {
|
|
57
|
+
"content": {"json": "Loading ..."},
|
|
58
|
+
"mode": "tree",
|
|
59
|
+
"readOnly": True,
|
|
60
|
+
"mainMenuBar": False,
|
|
61
|
+
"navigationBar": False,
|
|
62
|
+
"statusBar": False,
|
|
63
|
+
}
|
|
64
|
+
editor = ui.json_editor(properties).style("width: 100%").mark("JSON_EDITOR_INFO")
|
|
65
|
+
editor.set_visibility(False)
|
|
66
|
+
info = await run.cpu_bound(Service().info, True, True)
|
|
67
|
+
properties["content"] = {"json": info}
|
|
68
|
+
editor.update()
|
|
69
|
+
editor.run_editor_method(":expand", "path => true")
|
|
70
|
+
spinner.delete()
|
|
71
|
+
editor.set_visibility(True)
|
|
72
|
+
with (
|
|
73
|
+
ui.tab_panel(tab_settings),
|
|
74
|
+
ui.card().classes("w-full"),
|
|
75
|
+
ui.row().classes("items-center justify-between"),
|
|
76
|
+
):
|
|
77
|
+
ui.switch(
|
|
78
|
+
value=Service.remote_diagnostics_enabled(),
|
|
79
|
+
on_change=lambda e: (
|
|
80
|
+
Service.remote_diagnostics_enable()
|
|
81
|
+
if e.value
|
|
82
|
+
else Service.remote_diagnostics_disable(),
|
|
83
|
+
ui.notify("Restart the app to apply changes.", color="warning"), # type: ignore[func-returns-value]
|
|
84
|
+
None,
|
|
85
|
+
)[0],
|
|
86
|
+
)
|
|
87
|
+
ui.label("Remote Diagnostics")
|
|
88
|
+
with ui.column().classes("w-2/5 flex-shrink-0 flex items-center justify-start mt-[200px]"):
|
|
89
|
+
ui.html(
|
|
90
|
+
'<dotlottie-player src="/system_assets/system.lottie" '
|
|
91
|
+
'background="transparent" speed="1" style="width: 300px; height: 300px" '
|
|
92
|
+
'direction="1" playMode="normal" loop autoplay></dotlottie-player>'
|
|
93
|
+
)
|