Commit 6a1270ee authored by Duggan, John's avatar Duggan, John
Browse files

Merge remote-tracking branch 'origin/main' into...

Merge remote-tracking branch 'origin/main' into 90-add-flag-to-allow-dataselector-to-browse-user-directories-if-available
parents 9f513de8 26541377
Loading
Loading
Loading
Loading
Loading
+933 −901

File changed.

Preview size limit exceeded, changes collapsed.

+4 −2
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@ Changelog = "https://code.ornl.gov/ndip/public-packages/nova-trame/blob/main/CHA

[tool.poetry]
name = "nova-trame"
version = "0.19.3"
version = "0.20.1"
description = "A Python Package for injecting curated themes and custom components into Trame applications"
authors = ["Duggan, John <dugganjw@ornl.gov>"]
readme = "README.md"
@@ -28,6 +28,8 @@ trame-vega = "*"
trame-vuetify = "*"
nova-mvvm = "*"
pydantic = "*"
nova-common = ">=0.2.0"
blinker = "^1.9.0"

[build-system]
requires = ["poetry-core"]
@@ -84,7 +86,7 @@ omit = [
command_line = "-m pytest --junit-xml=reports/junit.xml"
data_file = "reports/.coverage"

[tool.poetry.dev-dependencies]
[tool.poetry.group.dev.dependencies]
mypy = "^1.10.0"
pre-commit = "^2.20.0"
coverage = "^6.4.3"
+109 −0
Original line number Diff line number Diff line
"""Module for the Progress Tab."""

from trame.app import get_server
from trame.widgets import client
from trame.widgets import vuetify3 as vuetify
from trame_client.widgets import html

from nova.mvvm.trame_binding import TrameBinding
from nova.trame.view_model.execution_buttons import ExecutionButtonsViewModel


class ExecutionButtons:
    """Execution buttons class. Adds Run/Stop/Cancel/Download buttons to the view."""

    def __init__(self, id: str, stop_btn: bool = False, download_btn: bool = False) -> None:
        """Constructor for ExecutionButtons.

        Parameters
        ----------
        id : str
            Component id. Should be used consistently with ToolRunner and other components
        stop_btn: bool
            Display stop button.
        download_btn : bool
            Display download button.

        Returns
        -------
        None
        """
        self.id = f"execution_{id}"

        self.server = get_server(None, client_type="vue3")
        binding = TrameBinding(self.server.state)
        self.ctrl = self.server.controller
        self.stop_btn = stop_btn
        self.download_btn = download_btn
        self.view_model = ExecutionButtonsViewModel(id, binding)
        self.view_model.buttons_state_bind.connect(self.id)
        self._download = client.JSEval(
            exec=(
                "async ($event) => {"
                " const blob = new window.Blob([$event], {type: 'application/zip'});"
                "  const url = window.URL.createObjectURL(blob);"
                "  const anchor = window.document.createElement('a');"
                "  anchor.setAttribute('href', url);"
                "  anchor.setAttribute('download', 'results.zip');"
                "  window.document.body.appendChild(anchor);"
                "  anchor.click();"
                "  window.document.body.removeChild(anchor);"
                "  setTimeout(() => window.URL.revokeObjectURL(url), 1000);"
                "}"
            )
        ).exec

        self.create_ui()

    def create_ui(self) -> None:
        with html.Div(classes="d-flex justify-center my-4 w-100"):
            vuetify.VBtn(
                "Run",
                disabled=(f"{self.id}.run_disabled",),
                prepend_icon="mdi-play",
                classes="mr-4",
                id=f"{self.id}_run",
                click=self.run,
            )
            if self.stop_btn:
                vuetify.VBtn(
                    "Stop",
                    disabled=(f"{self.id}.stop_disabled",),
                    loading=(f"{self.id}.stop_in_progress",),
                    classes="mr-4",
                    id=f"{self.id}_stop",
                    prepend_icon="mdi-stop",
                    click=self.stop,
                )
            vuetify.VBtn(
                "Cancel",
                disabled=(f"{self.id}.cancel_disabled",),
                color="error",
                loading=(f"{self.id}.cancel_in_progress",),
                prepend_icon="mdi-cancel",
                classes="mr-4",
                id=f"{self.id}_cancel",
                click=self.cancel,
            )
            if self.download_btn:
                vuetify.VBtn(
                    "Download Results",
                    disabled=(f"{self.id}.download_disabled",),
                    loading=(f"{self.id}.download_in_progress",),
                    id=f"{self.id}.download",
                    click=self.download,
                )

    async def download(self) -> None:
        content = await self.view_model.prepare_results()
        if content:
            self._download(content)

    async def run(self) -> None:
        await self.view_model.run()

    async def cancel(self) -> None:
        await self.view_model.cancel()

    async def stop(self) -> None:
        await self.view_model.stop()
+62 −0
Original line number Diff line number Diff line
"""Module for the Progress Tab."""

from trame.app import get_server
from trame.widgets import vuetify3 as vuetify
from trame_client.widgets import html

from nova.mvvm.trame_binding import TrameBinding
from nova.trame.view_model.progress_bar import ProgressBarViewModel


class ProgressBar:
    """Progress bar class. Adds progress bar that displays job status to the view."""

    def __init__(self, id: str) -> None:
        """Constructor for ProgressBar.

        Parameters
        ----------
        id : str
            Component id. Should be used consistently with ToolRunner and other components

        Returns
        -------
        None
        """
        self.id = f"progress_bar_{id}"
        self.create_viewmodel(id)
        self.view_model.progress_state_bind.connect(self.id)
        self.create_ui()

    def create_viewmodel(self, id: str) -> None:
        server = get_server(None, client_type="vue3")
        binding = TrameBinding(server.state)
        self.view_model = ProgressBarViewModel(id, binding)

    def create_ui(self) -> None:
        with vuetify.VProgressLinear(
            height="25",
            model_value=(f"{self.id}.progress", "0"),
            striped=True,
            id=f"{self.id}_show_progress",
            v_show=(f"{self.id}.show_progress",),
        ):
            html.H5(v_text=f"{self.id}.details")
        with vuetify.VProgressLinear(
            height="25",
            model_value="100",
            striped=False,
            color="error",
            id=f"{self.id}_show_failed",
            v_show=(f"{self.id}.show_failed",),
        ):
            html.H5(v_text=f"{self.id}.details", classes="text-white")
        with vuetify.VProgressLinear(
            height="25",
            model_value="100",
            striped=False,
            color="primary",
            id=f"{self.id}_show_ok",
            v_show=(f"{self.id}.show_ok",),
        ):
            html.H5(v_text=f"{self.id}.details", classes="text-white")
+60 −0
Original line number Diff line number Diff line
"""Module for the Tool outputs."""

from trame.app import get_server
from trame.widgets import vuetify3 as vuetify

from nova.mvvm.trame_binding import TrameBinding
from nova.trame.view.components import InputField
from nova.trame.view.layouts import HBoxLayout
from nova.trame.view_model.tool_outputs import ToolOutputsViewModel


class ToolOutputWindows:
    """Tool outputs class. Displays windows with tool stdout/stderr."""

    def __init__(self, id: str) -> None:
        """Constructor for ToolOutputWindows.

        Parameters
        ----------
        id : str
            Component id. Should be used consistently with ToolRunner and other components

        Returns
        -------
        None
        """
        self.id = f"tool_outputs_{id}"
        self.create_viewmodel(id)
        self.view_model.tool_outputs_bind.connect(self.id)
        self.create_ui()

    def create_viewmodel(self, id: str) -> None:
        server = get_server(None, client_type="vue3")
        binding = TrameBinding(server.state)
        self.view_model = ToolOutputsViewModel(id, binding)

    def create_ui(self) -> None:
        with HBoxLayout(classes="d-flex", width="100%"):
            with vuetify.VTabs(v_model=(f"{self.id}_active_output_tab", "1"), direction="vertical"):
                vuetify.VTab("Console output", value=1)
                vuetify.VTab("Console error", value=2)
            with HBoxLayout(classes="flex-grow-1"):
                InputField(
                    v_show=f"{self.id}_active_output_tab === '1'",
                    v_model=f"{self.id}.stdout",
                    id=f"{self.id}_outputs",
                    type="autoscroll",
                    auto_grow=True,
                    readonly=True,
                    max_rows="30",
                )
                InputField(
                    v_show=f"{self.id}_active_output_tab === '2'",
                    v_model=f"{self.id}.stderr",
                    id=f"{self.id}_errors",
                    type="autoscroll",
                    auto_grow=True,
                    readonly=True,
                    max_rows="30",
                )
Loading