This is an automated email from the ASF dual-hosted git repository.
pierrejeambrun pushed a commit to branch v3-1-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v3-1-test by this push:
new 4465006f731 [v3-1-test] Support Dynamic UI Alerts (#54677) (#56259)
4465006f731 is described below
commit 4465006f73170960c2fac87975fe8a1852a89037
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Wed Oct 1 12:05:59 2025 +0200
[v3-1-test] Support Dynamic UI Alerts (#54677) (#56259)
* feat: Dynamic UI Alerts
* docs: updated ui customization docs to include dynamic alerts
* docs: updated dynamic alerts documentation
* fix: corrected whitespace in customize-ui.rst
* fix: corrected whitespace in customize-ui.rst
---------
(cherry picked from commit 12a9d7b5c5d301849c513dd4fa458fef7ed2a369)
Co-authored-by: codecae <[email protected]>
Co-authored-by: Curtis Bangert <[email protected]>
---
airflow-core/docs/howto/customize-ui.rst | 115 ++++++++++++++++++---
.../api_fastapi/core_api/routes/ui/config.py | 4 +-
2 files changed, 101 insertions(+), 18 deletions(-)
diff --git a/airflow-core/docs/howto/customize-ui.rst
b/airflow-core/docs/howto/customize-ui.rst
index 1eb39309610..3681554f8ae 100644
--- a/airflow-core/docs/howto/customize-ui.rst
+++ b/airflow-core/docs/howto/customize-ui.rst
@@ -21,7 +21,7 @@ Customizing the UI
.. _customizing-the-ui:
Customizing Dag UI Header and Airflow Page Titles
-==================================================
+-------------------------------------------------
Airflow now allows you to customize the Dag home page header and page title.
This will help
distinguish between various installations of Airflow or simply amend the page
text.
@@ -61,17 +61,47 @@ After
.. image:: ../img/change-site-title/example_instance_name_configuration.png
+|
-Add custom alert messages on the dashboard
-------------------------------------------
+Adding Dashboard Alert Messages
+===============================
-Extra alert messages can be shown on the UI dashboard. This can be useful for
warning about setup issues
-or announcing changes to end users. The following example shows how to add
alert messages:
+Extra alert messages can be shown on the Airflow dashboard. This can be useful
for warning about setup issues, announcing changes
+to end users, or providing real-time status information. Dashboard alerts
support both static and dynamic content.
-1. Add the following contents to ``airflow_local_settings.py`` file under
``$AIRFLOW_HOME/config``.
- Each alert message should specify a severity level (``info``, ``warning``,
``error``) using ``category``.
+Basic Static Alerts
+-------------------
- .. code-block:: python
+To add static alert messages that remain constant until the webserver is
restarted:
+
+1. Create an ``airflow_local_settings.py`` file and place it in
``$PYTHONPATH`` or in the ``$AIRFLOW_HOME/config`` folder.
+ (Airflow adds ``$AIRFLOW_HOME/config`` to ``PYTHONPATH`` when Airflow is
initialized)
+
+2. Add the following contents to ``airflow_local_settings.py``:
+
+ .. note::
+ See :ref:`Configuring local settings
<set-config:configuring-local-settings>` for details on how to configure local
settings.
+
+ .. code-block:: python
+
+ from airflow.www.utils import UIAlert
+
+ DASHBOARD_UIALERTS = [
+ UIAlert("Welcome to Airflow"),
+ ]
+
+3. Restart the Airflow webserver, and you should now see the alert message
displayed on the dashboard.
+
+Alert Categories
+----------------
+
+You can control the category of the alert message. Available categories
include:
+
+- ``"info"`` (default) - Blue informational alerts
+- ``"warning"`` - Yellow warning alerts
+- ``"error"`` - Red error alerts
+
+.. code-block:: python
from airflow.api_fastapi.common.types import UIAlert
@@ -81,19 +111,70 @@ or announcing changes to end users. The following example
shows how to add alert
UIAlert(text="Critical error detected!", category="error"),
]
- See :ref:`Configuring local settings
<set-config:configuring-local-settings>` for details on how to
- configure local settings.
+.. image:: ../img/ui-alert-message.png
-2. Restart Airflow Webserver, and you should now see:
+Markdown Content in Alerts
+--------------------------
-.. image:: ../img/ui-alert-message.png
+Markdown can be included in alert messages for richer formatting. In the
following example, we show an alert
+message of heading 2 with a link included:
-Alert messages also support Markdown. In the following example, we show an
alert message of heading 2 with a link included.
+.. code-block:: python
- .. code-block:: python
+ from airflow.www.utils import UIAlert
- DASHBOARD_UIALERTS = [
- UIAlert(text="## Visit
[airflow.apache.org](https://airflow.apache.org)", category="info"),
- ]
+ DASHBOARD_UIALERTS = [
+ UIAlert(text="## Visit
[airflow.apache.org](https://airflow.apache.org)", category="info"),
+ ]
.. image:: ../img/ui-alert-message-markdown.png
+
+Dynamic Dashboard Alerts
+------------------------
+
+Dashboard alerts support dynamic content that updates each time the dashboard
page is refreshed. This allows for real-time
+status updates without requiring webserver restarts. Dynamic alerts must be
defined as an instance of an iterable object.
+The recommended approach is to create a class that subclasses ``list`` and
implements a custom ``__iter__`` method that
+yields fresh alerts each time Airflow iterates over the alerts.
+
+.. note::
+ When implementing dynamic alerts it is important to keep alert generation
logic lightweight to avoid
+ impacting dashboard load times. Consider caching results for expensive
operations and handle exceptions
+ gracefully to prevent alert generation from breaking the UI.
+
+Dynamic alerts are particularly useful for:
+
+- **Real-time notifications**: Display current status updates or announcements
+- **Deployment notifications**: Show current deployment status, build
progress, or GitOps state
+- **Temporary maintenance alerts**: Provide time-sensitive information about
ongoing maintenance or issues
+- **Environment-specific warnings**: Display different alerts based on current
environment conditions
+- **External service status**: Show the availability of dependent services or
APIs
+
+Creating Dynamic Alerts
+^^^^^^^^^^^^^^^^^^^^^^^
+
+To create dynamic alerts, define ``DASHBOARD_UIALERTS`` as an instance of a
class that subclasses ``list``
+and implements the ``__iter__`` method. The UI will iterate over any number
``UIAlert`` instances yielded by
+this method and expose them as alerts on the dashboard page.
+
+The example below demonstrates how logic can be applied to yield alerts
dynamically. More practical use
+cases might include alerts yielded from APIs, database queries or files.
+
+.. code-block:: python
+
+ import random
+ from airflow.www.utils import UIAlert
+
+
+ class DynamicAlerts(list):
+ def __iter__(self):
+ # This method is called each time Airflow iterates over
DASHBOARD_UIALERTS
+ # Example: Flip a coin
+ if random.choice([True, False]):
+ yield UIAlert("Heads!", category="info")
+ else:
+ yield UIAlert("Tails!", category="warning")
+
+
+ # Create an instance of the class
+ DASHBOARD_UIALERTS = DynamicAlerts()
diff --git a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/config.py
b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/config.py
index f4fe5d5c665..c0b7dd2e3b6 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/config.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/config.py
@@ -21,6 +21,7 @@ from typing import Any
from fastapi import Depends, status
from airflow.api_fastapi.common.router import AirflowRouter
+from airflow.api_fastapi.common.types import UIAlert
from airflow.api_fastapi.core_api.datamodels.ui.config import ConfigResponse
from airflow.api_fastapi.core_api.openapi.exceptions import
create_openapi_http_exception_doc
from airflow.api_fastapi.core_api.security import requires_authenticated
@@ -54,7 +55,8 @@ def get_configs() -> ConfigResponse:
additional_config: dict[str, Any] = {
"instance_name": conf.get("api", "instance_name", fallback="Airflow"),
"test_connection": conf.get("core", "test_connection",
fallback="Disabled"),
- "dashboard_alert": DASHBOARD_UIALERTS,
+ # Expose "dashboard_alert" using a list comprehension so UIAlert
instances can be expressed dynamically.
+ "dashboard_alert": [alert for alert in DASHBOARD_UIALERTS if
isinstance(alert, UIAlert)],
"show_external_log_redirect": task_log_reader.supports_external_link,
"external_log_name": getattr(task_log_reader.log_handler, "log_name",
None),
}