diff --git a/airflow/www/templates/airflow/variable_list.html b/airflow/www/templates/airflow/variable_list.html
index a9d58b2885d41..fe2b4182fca3b 100644
--- a/airflow/www/templates/airflow/variable_list.html
+++ b/airflow/www/templates/airflow/variable_list.html
@@ -38,4 +38,8 @@
{% endif %}
{{ super() }}
+
{% endblock %}
diff --git a/airflow/www/templates/airflow/variable_show.html b/airflow/www/templates/airflow/variable_show.html
new file mode 100644
index 0000000000000..87fda206ceddb
--- /dev/null
+++ b/airflow/www/templates/airflow/variable_show.html
@@ -0,0 +1,28 @@
+{#
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+#}
+
+{% extends 'appbuilder/general/model/show.html' %}
+
+{% block tail %}
+ {{ super() }}
+
+{% endblock %}
diff --git a/airflow/www/templates/airflow/variable_show_widget.html b/airflow/www/templates/airflow/variable_show_widget.html
new file mode 100644
index 0000000000000..e459bfa930311
--- /dev/null
+++ b/airflow/www/templates/airflow/variable_show_widget.html
@@ -0,0 +1,70 @@
+{#
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+#}
+
+{% import 'appbuilder/general/lib.html' as lib %}
+{% include 'appbuilder/general/confirm.html' %}
+{% include 'appbuilder/general/alert.html' %}
+
+{% block columns %}
+
+{% if fieldsets %}
+
+ {% for fieldset_item in fieldsets %}
+ {% if fieldset_item[1].get('expanded') == None %}
+ {% set expanded = True %}
+ {% else %}
+ {% set expanded = fieldset_item[1].get('expanded') %}
+ {% endif %}
+ {% call lib.accordion_tag(loop.index,fieldset_item[0], expanded) %}
+
+
+ {% for item in fieldset_item[1].get('fields') %}
+
+ | {{label_columns.get(item)}} |
+ {{value_columns[include_columns.index(item)]}} |
+
+ {% endfor %}
+
+ {% endcall %}
+ {% endfor %}
+
+{% else %}
+
+
+
+ {% for item in include_columns %}
+
+ | {{label_columns.get(item)}} |
+
+ {{value_columns[loop.index-1]}}
+ |
+
+ {% endfor %}
+
+{% endif %}
+
+{% endblock columns %}
+
+
+{% block actions %}
+
+ {{ lib.render_action_links(actions, pk, modelview_name) }}
+ {{ lib.lnk_back() }}
+
+{% endblock actions %}
diff --git a/airflow/www/views.py b/airflow/www/views.py
index 4179b72b115a4..37b7fce791d01 100644
--- a/airflow/www/views.py
+++ b/airflow/www/views.py
@@ -74,6 +74,7 @@
UserStatsChartView,
ViewMenuModelView,
)
+from flask_appbuilder.urltools import get_order_args, get_page_args, get_page_size_args
from flask_appbuilder.widgets import FormWidget
from flask_babel import lazy_gettext
from jinja2.utils import htmlsafe_json_dumps, pformat # type: ignore
@@ -129,7 +130,7 @@
DateTimeWithNumRunsWithDagRunsForm,
TaskInstanceEditForm,
)
-from airflow.www.widgets import AirflowModelListWidget
+from airflow.www.widgets import AirflowModelListWidget, AirflowVariableShowWidget
PAGE_SIZE = conf.getint('webserver', 'page_size')
FILTER_TAGS_COOKIE = 'tags_filter'
@@ -4068,6 +4069,9 @@ class VariableModelView(AirflowModelView):
list_template = 'airflow/variable_list.html'
edit_template = 'airflow/variable_edit.html'
+ show_template = 'airflow/variable_show.html'
+
+ show_widget = AirflowVariableShowWidget
datamodel = AirflowModelView.CustomSQLAInterface(models.Variable) # type: ignore
@@ -4076,6 +4080,7 @@ class VariableModelView(AirflowModelView):
'add': 'create',
'list': 'read',
'edit': 'edit',
+ 'show': 'read',
'delete': 'delete',
'action_muldelete': 'delete',
'action_varexport': 'read',
@@ -4091,6 +4096,7 @@ class VariableModelView(AirflowModelView):
list_columns = ['key', 'val', 'description', 'is_encrypted']
add_columns = ['key', 'val', 'description']
edit_columns = ['key', 'val', 'description']
+ show_columns = ['key', 'val', 'description']
search_columns = ['key', 'val']
base_order = ('key', 'asc')
@@ -4116,6 +4122,26 @@ def prefill_form(self, form, request_id):
if secrets_masker.should_hide_value_for_key(form.key.data):
form.val.data = '*' * 8
+ def prefill_show(self, item):
+ if secrets_masker.should_hide_value_for_key(item.key):
+ item.val = '*' * 8
+
+ def _show(self, pk):
+ pages = get_page_args()
+ page_sizes = get_page_size_args()
+ orders = get_order_args()
+
+ item = self.datamodel.get(pk, self._base_filters)
+ if not item:
+ abort(404)
+ self.prefill_show(item)
+ widgets = self._get_show_widget(pk, item)
+ self.update_redirect()
+
+ return self._get_related_views_widgets(
+ item, orders=orders, pages=pages, page_sizes=page_sizes, widgets=widgets
+ )
+
extra_args = {"can_create_variable": _can_create_variable}
@action('muldelete', 'Delete', 'Are you sure you want to delete selected records?', single=False)
diff --git a/airflow/www/widgets.py b/airflow/www/widgets.py
index c99c5d4d8332c..c62628382a843 100644
--- a/airflow/www/widgets.py
+++ b/airflow/www/widgets.py
@@ -72,3 +72,9 @@ class BS3TextAreaROWidget(BS3TextAreaFieldWidget):
def __call__(self, field, **kwargs):
kwargs['readonly'] = 'true'
return super().__call__(field, **kwargs)
+
+
+class AirflowVariableShowWidget(RenderTemplateWidget):
+ """Airflow variable show widget"""
+
+ template = 'airflow/variable_show_widget.html'