Transaction Method Status Badge#

A minimal Dash app showing how to use the TransactionMethodStatusBadge component to display the status of a SAF transaction method as a compact badge.

See the Transaction Method Status Badge page in the User Guide for the full reference documentation.

In a real SAF solution every step exposes one or more transaction methods (decorated with @transaction). The GLOW REST API exposes their status at:

GET /steps/<step-name>:<method-name>

The TransactionMethodStatusBadge component polls that endpoint at a configurable interval and renders a compact badge showing the current status. This example embeds a minimal Flask server that mimics the GLOW REST API so you can explore the component without a running GLOW server. The mock server listens on http://127.0.0.1:8061. For a detailed example of how to set up this component with a full SAF solution, see the showcase example in the repository.

Note

Run this file directly to launch the app:

pip install ansys-solutions-dash-super-components requests
python example_transaction_method_status_badge.py

Then open http://localhost:8050. Use the switches and the buttons to trigger a successful or failing transaction and watch the status badges update in real time.

Set up imports and the Dash application#

MantineProvider must wrap the entire layout for Mantine-based components to render correctly. The React version must also be set before importing the component library — this is a Dash Mantine Components requirement when using Dash 2.x.

A tiny Flask server is embedded in the same process as the Dash app so the mock GLOW API is ready before the component starts polling. This requires additional imports for the mock server and callbacks.

import threading
import time

from ansys.solutions.dash_super_components import TransactionMethodStatusBadge
from dash import _dash_renderer
from dash.exceptions import PreventUpdate
from dash_extensions.enrich import DashProxy, Input, Output, State, callback, dcc, html
import dash_mantine_components as dmc
from flask import Flask, Response, jsonify, request as flask_request
import requests
from werkzeug.serving import make_server

# Required only for Dash 2.x to use Mantine-based components
_dash_renderer._set_react_version("18.2.0")

app = DashProxy(__name__)

Embedded mock GLOW API server#

TransactionMethodStatusBadge polls {glow_api_url}/steps/{step-name}:{method-name} and expects a JSON body that contains a "status" field. Recognized status values are "run-required", "running", "completed" and "failed".

The mock server stores the current status for each step:method key in a plain Python dict that can be updated from Dash callbacks by POSTing to the mock server’s /steps/<step_method> endpoint.

MOCK_API_PORT = 8061
MOCK_API_URL = f"http://127.0.0.1:{MOCK_API_PORT}"

# Simple dict owned exclusively by the mock server process/thread. Do not access from Dash callbacks
# as this is not thread-safe and is only intended to be updated via the mock server endpoints.
_statuses: dict[str, str] = {}

mock_server = Flask("mock_glow_api_badge")


@mock_server.route("/steps/<path:step_method>", methods=["GET"])
def get_step_status(step_method: str) -> Response:
    """Get the status for *step_method*."""
    return jsonify({"status": _statuses.get(step_method, "run-required")})


@mock_server.route("/steps/<path:step_method>", methods=["POST"])
def set_step_status(step_method: str) -> Response:
    """Set the status for *step_method* (used by Dash callbacks to mock transaction status)."""
    _statuses[step_method] = flask_request.json["status"]
    return jsonify({"ok": True})


def _run_mock_server() -> None:
    server = make_server("127.0.0.1", MOCK_API_PORT, mock_server)
    server.serve_forever()


threading.Thread(target=_run_mock_server, daemon=True).start()

Define the step and methods to monitor#

Each TransactionMethodStatusBadge monitors a single (step, method) pair. Here both badges belong to the same step ("mesher") but monitor different methods. In a real solution they could also belong to different steps.

STEP_NAME = "mesher"
GENERATE_MESH_METHOD = "generate_mesh"
CHECK_QUALITY_METHOD = "check_quality"

Build the layout#

A TransactionMethodStatusBadge cannot be added directly to the layout because in a real SAF-based solution it needs access to the project URL, which is only available through the GLOW DashClient in a callback. Therefore, placeholder html.Div elements are added and populated with badge instances via a callback on page load.

The layout contains two cards — one for Generate Mesh and one for Check Quality — each with a short description, a Simulate failure toggle, a Run button, and a badge placeholder.

app.layout = dmc.MantineProvider(
    html.Div(
        [
            dcc.Location("url", refresh=False),
            dmc.Title("Mesh Generation Workflow", order=2, mb="md"),
            dmc.Text(
                "Run each meshing step independently. "
                "Enable the failure toggle before clicking Run to simulate an error.",
                c="dimmed",
                mb="xl",
            ),
            dmc.Stack(
                [
                    dmc.Paper(
                        dmc.Group(
                            [
                                dmc.Stack(
                                    [
                                        dmc.Text("Generate Mesh", fw=600, size="sm"),
                                        dmc.Text(
                                            "Builds the computational mesh from the geometry.",
                                            c="dimmed",
                                            size="xs",
                                        ),
                                    ],
                                    gap=2,
                                    style={"flex": 1},
                                ),
                                dmc.Switch(
                                    id="switch-generate-mesh",
                                    label="Simulate failure",
                                    color="red",
                                    size="sm",
                                ),
                                dmc.Button("Run", id="btn-generate-mesh", size="sm"),
                                html.Div(
                                    id="badge-placeholder-generate-mesh",
                                    style={"width": "180px"},
                                ),
                            ],
                            align="center",
                        ),
                        p="md",
                        withBorder=True,
                        radius="md",
                    ),
                    dmc.Paper(
                        dmc.Group(
                            [
                                dmc.Stack(
                                    [
                                        dmc.Text("Check Quality", fw=600, size="sm"),
                                        dmc.Text(
                                            "Validates mesh quality metrics against defined "
                                            "thresholds.",
                                            c="dimmed",
                                            size="xs",
                                        ),
                                    ],
                                    gap=2,
                                    style={"flex": 1},
                                ),
                                dmc.Switch(
                                    id="switch-check-quality",
                                    label="Simulate failure",
                                    color="red",
                                    size="sm",
                                ),
                                dmc.Button("Run", id="btn-check-quality", size="sm", disabled=True),
                                html.Div(
                                    id="badge-placeholder-check-quality",
                                    style={"width": "180px"},
                                ),
                            ],
                            align="center",
                        ),
                        p="md",
                        withBorder=True,
                        radius="md",
                    ),
                ],
                gap="sm",
            ),
        ],
        style={"maxWidth": 720, "margin": "40px auto", "padding": "0 16px"},
    )
)

Initialise the badges in a callback#

The badges are created inside a callback so that in a real SAF-based solution the project URL can be injected via the GLOW DashClient. In this example, the MOCK_API_URL is passed directly.

@callback(
    Output("badge-placeholder-generate-mesh", "children"),
    Input("url", "pathname"),
    prevent_initial_call=False,
)
def init_badge_generate_mesh(pathname: str) -> TransactionMethodStatusBadge:
    """Add a TransactionMethodStatusBadge for the Generate Mesh method."""
    return TransactionMethodStatusBadge(
        url=MOCK_API_URL,
        step_name=STEP_NAME,
        method_name=GENERATE_MESH_METHOD,
        aio_id="badge-generate-mesh",
        label_props={"children": "Generate Mesh:"},
        interval_props={"interval": 2000},
    )


@callback(
    Output("badge-placeholder-check-quality", "children"),
    Input("url", "pathname"),
    prevent_initial_call=False,
)
def init_badge_check_quality(pathname: str) -> TransactionMethodStatusBadge:
    """Add a TransactionMethodStatusBadge for the Check Quality method."""
    return TransactionMethodStatusBadge(
        url=MOCK_API_URL,
        step_name=STEP_NAME,
        method_name=CHECK_QUALITY_METHOD,
        aio_id="badge-check-quality",
        label_props={"children": "Check Quality:"},
        interval_props={"interval": 2000},
    )

Enable “Check Quality” only after “Generate Mesh” completes#

The status_badge sub-component of each badge exposes its current status string as its children property (for example, "COMPLETED"). A simple callback reads that value and keeps the Check Quality Run button disabled until the Generate Mesh method has finished successfully.

@callback(
    Output("btn-check-quality", "disabled"),
    Input(TransactionMethodStatusBadge.ids.status_badge("badge-generate-mesh"), "children"),
)
def toggle_check_quality_button(generate_mesh_status: str | None) -> bool:
    """Enable the Check Quality button only when Generate Mesh is completed."""
    return (generate_mesh_status or "").upper() != "COMPLETED"

Add callbacks to simulate transactions#

Each button has its own callback that reads the corresponding switch state, marks the method as "running" immediately, then schedules the final status ("completed" or "failed") after a short delay — just as a real SAF transaction method would. The callback returns True to the badge’s activate_monitoring store, which starts the polling interval.

@callback(
    Output(
        TransactionMethodStatusBadge.ids.activate_monitoring("badge-generate-mesh"),
        "data",
    ),
    Input("btn-generate-mesh", "n_clicks"),
    State("switch-generate-mesh", "checked"),
    prevent_initial_call=True,
)
def run_generate_mesh(n_clicks: int, should_fail: bool) -> bool:
    """Start the Generate Mesh transaction and activate monitoring."""
    if not n_clicks:
        raise PreventUpdate

    # Convert step and method names to the format expected by the mock server endpoint (hyphenated)
    step_name_hyphenated = STEP_NAME.replace("_", "-")
    generate_mesh_method_hyphenated = GENERATE_MESH_METHOD.replace("_", "-")

    requests.post(
        f"{MOCK_API_URL}/steps/{step_name_hyphenated}:{generate_mesh_method_hyphenated}",
        json={"status": "running"},
    )

    def _finish() -> None:
        time.sleep(4)
        status = "failed" if should_fail else "completed"
        requests.post(
            f"{MOCK_API_URL}/steps/{step_name_hyphenated}:{generate_mesh_method_hyphenated}",
            json={"status": status},
        )

    threading.Thread(target=_finish, daemon=True).start()
    return True


@callback(
    Output(
        TransactionMethodStatusBadge.ids.activate_monitoring("badge-check-quality"),
        "data",
    ),
    Input("btn-check-quality", "n_clicks"),
    State("switch-check-quality", "checked"),
    prevent_initial_call=True,
)
def run_check_quality(n_clicks: int, should_fail: bool) -> bool:
    """Start the Check Quality transaction and activate monitoring."""
    if not n_clicks:
        raise PreventUpdate

    # Convert step and method names to the format expected by the mock server endpoint (hyphenated)
    step_name_hyphenated = STEP_NAME.replace("_", "-")
    check_quality_method_hyphenated = CHECK_QUALITY_METHOD.replace("_", "-")

    requests.post(
        f"{MOCK_API_URL}/steps/{step_name_hyphenated}:{check_quality_method_hyphenated}",
        json={"status": "running"},
    )

    def _finish() -> None:
        time.sleep(4)
        status = "failed" if should_fail else "completed"
        requests.post(
            f"{MOCK_API_URL}/steps/{step_name_hyphenated}:{check_quality_method_hyphenated}",
            json={"status": status},
        )

    threading.Thread(target=_finish, daemon=True).start()
    return True

Run the app#

if __name__ == "__main__":
    app.run()

Gallery generated by Sphinx-Gallery