This is an automated email from the ASF dual-hosted git repository.

eladkal pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new da6931561f Add support for arrays of different data types in the 
Trigger Form UI (#32734)
da6931561f is described below

commit da6931561f59a64f6489c56a5675c2cc6e6a2bca
Author: Matthieu Blais <[email protected]>
AuthorDate: Thu Aug 3 17:02:34 2023 +0800

    Add support for arrays of different data types in the Trigger Form UI 
(#32734)
    
    * Add JSON field for complex arrays with types other than string
    
    ---------
    
    Co-authored-by: Matthieu Blais <[email protected]>
    Co-authored-by: Jens Scheffler 
<[email protected]>
    Co-authored-by: eladkal <[email protected]>
---
 airflow/example_dags/example_params_ui_tutorial.py | 22 ++++++++++++++++++++++
 airflow/www/static/js/trigger.js                   | 11 ++++++++---
 airflow/www/templates/airflow/trigger.html         |  9 ++++++++-
 docs/apache-airflow/core-concepts/params.rst       |  5 ++++-
 4 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/airflow/example_dags/example_params_ui_tutorial.py 
b/airflow/example_dags/example_params_ui_tutorial.py
index c07f9fc7c2..cb25b1b408 100644
--- a/airflow/example_dags/example_params_ui_tutorial.py
+++ b/airflow/example_dags/example_params_ui_tutorial.py
@@ -127,6 +127,14 @@ with DAG(
                 # Note: Value display mapping does not need to be complete.s
             },
         ),
+        # An array of numbers
+        "array_of_numbers": Param(
+            [1, 2, 3],
+            "Only integers are accepted in this array",
+            type="array",
+            title="Array of numbers",
+            items={"type": "number"},
+        ),
         # Boolean as proper parameter with description
         "bool": Param(
             True,
@@ -208,6 +216,20 @@ with DAG(
             title="JSON entry field",
             section="Special advanced stuff with form fields",
         ),
+        "array_of_objects": Param(
+            [{"name": "account_name", "country": "country_name"}],
+            "Array with complex objects and validation rules. "
+            "See <a href='https://json-schema.org/understanding-json-schema";
+            "/reference/array.html#items'>JSON Schema validation options in 
specs.</a>",
+            type="array",
+            title="JSON array field",
+            items={
+                "type": "object",
+                "properties": {"name": {"type": "string"}, "country_name": 
{"type": "string"}},
+                "required": ["name"],
+            },
+            section="Special advanced stuff with form fields",
+        ),
         # If you want to have static parameters which are always passed and 
not editable by the user
         # then you can use the JSON schema option of passing constant values. 
These parameters
         # will not be displayed but passed to the DAG
diff --git a/airflow/www/static/js/trigger.js b/airflow/www/static/js/trigger.js
index 6ada3d615e..2ded629240 100644
--- a/airflow/www/static/js/trigger.js
+++ b/airflow/www/static/js/trigger.js
@@ -63,7 +63,8 @@ function updateJSONconf() {
         params[keyName] = null;
       } else if (
         elements[i].attributes.valuetype &&
-        elements[i].attributes.valuetype.value === "object"
+        (elements[i].attributes.valuetype.value === "object" ||
+          elements[i].attributes.valuetype.value === "advancedarray")
       ) {
         try {
           const textValue = objectFields.get(elements[i].name).getValue();
@@ -112,6 +113,7 @@ function initForm() {
     mode: { name: "javascript", json: true },
     gutters: ["CodeMirror-lint-markers"],
     lint: true,
+    indentUnit: 4,
   });
   jsonForm.setSize(null, height);
 
@@ -122,7 +124,8 @@ function initForm() {
       if (elements[i].name && elements[i].name.startsWith("element_")) {
         if (
           elements[i].attributes.valuetype &&
-          elements[i].attributes.valuetype.value === "object"
+          (elements[i].attributes.valuetype.value === "object" ||
+            elements[i].attributes.valuetype.value === "advancedarray")
         ) {
           // Apply JSON formatting and linting to all object fields in the form
           const field = CodeMirror.fromTextArea(elements[i], {
@@ -130,6 +133,7 @@ function initForm() {
             mode: { name: "javascript", json: true },
             gutters: ["CodeMirror-lint-markers"],
             lint: true,
+            indentUnit: 4,
           });
           field.on("blur", updateJSONconf);
           objectFields.set(elements[i].name, field);
@@ -230,7 +234,8 @@ function setRecentConfig(e) {
         element.value = newValue.join("\n");
       } else if (
         element.attributes.valuetype &&
-        element.attributes.valuetype.value === "object"
+        (element.attributes.valuetype.value === "object" ||
+          element.attributes.valuetype.value === "advancedarray")
       ) {
         objectFields
           .get(`element_${keys[i]}`)
diff --git a/airflow/www/templates/airflow/trigger.html 
b/airflow/www/templates/airflow/trigger.html
index e8965c3654..69f168db52 100644
--- a/airflow/www/templates/airflow/trigger.html
+++ b/airflow/www/templates/airflow/trigger.html
@@ -86,7 +86,14 @@
         {% endfor -%}
       </select>
     {% elif form_details.schema and "array" in form_details.schema.type %}
-      {% if "examples" in form_details.schema and form_details.schema.examples 
%}
+      {% if "items" in form_details.schema and form_details.schema.items %}
+      <textarea class="form-control" name="element_{{ form_key }}" 
id="element_{{ form_key }}" valuetype="advancedarray" rows="6"
+        {%- if not "null" in form_details.schema.type %} required=""{% endif 
-%}>
+        {%- if form_details.value is sequence %}
+          {{- form_details.value | tojson() -}}
+        {% endif -%}
+      </textarea>
+      {% elif "examples" in form_details.schema and 
form_details.schema.examples %}
       <select multiple name="element_{{ form_key }}" id="element_{{ form_key 
}}" class="select2-drop-mask" valuetype="multiselect"
         onchange="updateJSONconf();"{% if not "null" in 
form_details.schema.type %} required=""{% endif %}>
         {% for option in form_details.schema.examples -%}
diff --git a/docs/apache-airflow/core-concepts/params.rst 
b/docs/apache-airflow/core-concepts/params.rst
index 7619d56171..4159231505 100644
--- a/docs/apache-airflow/core-concepts/params.rst
+++ b/docs/apache-airflow/core-concepts/params.rst
@@ -190,7 +190,10 @@ The following features are supported in the Trigger UI 
Form:
     - ``boolean``: Generates a toggle button to be used as ``True`` or 
``False``.
     - ``date``, ``datetime`` and ``time``: Generate date and/or time picker
     - ``array``: Generates a HTML multi line text field, every line edited 
will be made into a string array as value.
-      if you add the attribute ``example`` with a list, a multi-value select 
option will be generated.
+      If you add the attribute ``example`` with a list, a multi-value select 
option will be generated.
+      If you add the attribute ``items``, a JSON entry field will be generated 
for more array types
+      and additional type validation as described in
+      `JSON Schema Array Items 
<https://json-schema.org/understanding-json-schema/reference/array.html#items>`_.
     - ``object``: Generates a JSON entry field
     - Note: Per default if you specify a type, a field will be made required 
with input - because of JSON validation.
       If you want to have a field value being added optional only, you must 
allow JSON schema validation allowing null values via:

Reply via email to