Commit 963b10b7 authored by Yakubov, Sergey's avatar Yakubov, Sergey
Browse files

add tool components

parent 86f88198
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.2"
version = "0.20.0"
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"
+105 −0
Original line number Diff line number Diff line
"""Module for the Progress Tab."""

from nova.mvvm.trame_binding import TrameBinding
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.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",
                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",
                    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",
                click=self.cancel,
            )
            if self.download_btn:
                vuetify.VBtn(
                    "Download Results",
                    disabled=(f"{self.id}.download_disabled",),
                    loading=(f"{self.id}.download_in_progress",),
                    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()
+59 −0
Original line number Diff line number Diff line
"""Module for the Progress Tab."""

from nova.mvvm.trame_binding import TrameBinding
from trame.app import get_server
from trame.widgets import vuetify3 as vuetify
from trame_client.widgets import html

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,
                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",
                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",
                v_show=(f"{self.id}.show_ok",),
        ):
            html.H5(v_text=f"{self.id}.details", classes="text-white")
+57 −0
Original line number Diff line number Diff line
"""Module for the Tool outputs."""

from nova.mvvm.trame_binding import TrameBinding
from nova.trame.view.components import InputField
from trame.app import get_server
from trame.widgets import vuetify3 as vuetify

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 vuetify.VContainer(classes="d-flex", fluid=True):
            with vuetify.VTabs(v_model=(f"{self.id}_active_output_tab", "0"), direction="vertical"):
                vuetify.VTab("Console output", value=1)
                vuetify.VTab("Console error", value=2)
            with vuetify.VWindow(v_model=f"{self.id}_active_output_tab", classes="flex-grow-1"):
                with vuetify.VWindowItem(value=1, reverse_transition="false", transition="false"):
                    InputField(
                        v_model=f"{self.id}.stdout",
                        type="autoscroll",
                        auto_grow=True,
                        readonly=True,
                        max_rows="30",
                    )
                with vuetify.VWindowItem(value=2, reverse_transition="false", transition="false"):
                    InputField(
                        v_model=f"{self.id}.stderr",
                        type="autoscroll",
                        auto_grow=True,
                        readonly=True,
                        max_rows="30",
                    )
Loading