This is an automated email from the ASF dual-hosted git repository. jedcunningham 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 8cebfa7c82 Remove legacy dag details page and redirect to grid (#37232) 8cebfa7c82 is described below commit 8cebfa7c82f5af3f9d12370602cf640a1d06daff Author: Brent Bovenzi <br...@astronomer.io> AuthorDate: Wed Feb 7 19:41:49 2024 -0500 Remove legacy dag details page and redirect to grid (#37232) --- airflow/www/templates/airflow/dag_details.html | 144 ------------------------- airflow/www/views.py | 75 +------------ tests/www/views/test_views_acl.py | 13 --- tests/www/views/test_views_tasks.py | 31 ------ 4 files changed, 2 insertions(+), 261 deletions(-) diff --git a/airflow/www/templates/airflow/dag_details.html b/airflow/www/templates/airflow/dag_details.html deleted file mode 100644 index e6b7152d7c..0000000000 --- a/airflow/www/templates/airflow/dag_details.html +++ /dev/null @@ -1,144 +0,0 @@ -{# - 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 "airflow/dag.html" %} - -{% block page_title %}{{ dag.dag_id }} - DAG Details - {{ appbuilder.app_name }}{% endblock %} - -{% block content %} - {{ super() }} - <h3>{{ title }}</h3> - <div> - {% for state, count in states %} - <a - class="btn" - style="border: 0; background-color:{{ State.color(state)}}; color: {{ State.color_fg(state) }};" - href="{{ url_for('TaskInstanceModelView.list', _flt_3_dag_id=dag.dag_id, _flt_3_state=state) }}"> - {{ state }} <span class="badge">{{ count }}</span> - </a> - {% endfor %} - </div> - <br> - <table class="table table-striped table-bordered"> - {% if dag.parent_dag is defined and dag.parent_dag %} - <tr> - <th>Parent DAG</th> - <td> - <a href="{{ url_for('Airflow.' + dag.default_view, dag_id=dag.parent_dag.dag_id) }}">{{ dag.parent_dag.dag_id }}</a> - </td> - </tr> - {% endif %} - <tr> - <th>Schedule Interval</th> - <td>{{ dag.schedule_interval }}</td> - </tr> - <tr> - <th>Catchup</th> - <td>{{ dag.catchup }}</td> - </tr> - {% if dag.catchup %} - <tr> - <th>Start Date</th> - <td><time datetime="{{ dag.start_date }}">{{ dag.start_date }}</time></td> - </tr> - {% else %} - <tr> - <th>Started</th> - <td>{{ states|length > 0 }}</td> - </tr> - {% endif %} - <tr> - <th>End Date</th> - <td><time datetime="{{ dag.end_date }}">{{ dag.end_date }}</time></td> - </tr> - <tr> - <th>Max Active Runs</th> - <td>{{ active_runs | length }} / {{ dag.max_active_runs }}</td> - </tr> - <tr> - <th>Max Active Tasks</th> - <td>{{ dag.max_active_tasks }}</td> - </tr> - <tr> - <th>Default Args</th> - <td class="wrap">{{ dag.default_args | pprint }}</td> - </tr> - <tr> - <th>Tasks Count</th> - <td>{{ dag.tasks|length }}</td> - </tr> - <tr> - <th>Task IDs</th> - <td>{{ dag.task_ids }}</td> - </tr> - <tr> - <th>Relative file location</th> - <td>{{ dag.relative_fileloc }}</td> - </tr> - <tr> - <th>Owner</th> - <td>{{ dag.owner }}</td> - </tr> - <tr> - <th>Owner Links</th> - <td> - {% if dag.owner_links %} - {{ dag.owner_links }} - {% else %} - None - {% endif %} - </td> - </tr> - <tr> - <th>DAG Run Timeout</th> - <td>{{ dag.dagrun_timeout }}</td> - </tr> - <tr> - <th>Tags</th> - <td> - {% if tags is defined and tags %} - {% for tag in tags | sort(attribute='name') %} - <a class="label label-info" - href="{{ url_for('Airflow.index', tags=tag.name) }}" - style="margin: 3px 6px 3px 0;" - title="All DAGs tagged “{{ tag.name }}”" - > - {{ tag.name }} - </a> - {% endfor %} - {% else %} - None - {% endif %} - </td> - </tr> - </table> - <h5>DagModel debug information</h5> - <table class="table table-striped table-bordered"> - <tr> - <th>Attribute</th> - <th>Value</th> - </tr> - {% for attr, value in dag_model_attrs %} - <tr> - <td>{{ attr }}</td> - <td class="code wrap">{{ value }}</td> - </tr> - {% endfor %} - </table> -{% endblock %} diff --git a/airflow/www/views.py b/airflow/www/views.py index 0b7ede98dd..6e6caeba3c 100644 --- a/airflow/www/views.py +++ b/airflow/www/views.py @@ -1316,80 +1316,9 @@ class Airflow(AirflowBaseView): return redirect(url_for("Airflow.dag_details", **sanitize_args(request.args))) @expose("/dags/<string:dag_id>/details") - @auth.has_access_dag("GET", DagAccessEntity.RUN) - @provide_session - def dag_details(self, dag_id, session: Session = NEW_SESSION): + def dag_details(self, dag_id): """Get Dag details.""" - from airflow.models.dag import DagOwnerAttributes - - dag = get_airflow_app().dag_bag.get_dag(dag_id, session=session) - dag_model = DagModel.get_dagmodel(dag_id, session=session) - if not dag: - flash(f'DAG "{dag_id}" seems to be missing.', "error") - return redirect(url_for("Airflow.index")) - - wwwutils.check_import_errors(dag.fileloc, session) - wwwutils.check_dag_warnings(dag.dag_id, session) - - title = "DAG Details" - root = request.args.get("root", "") - - states = session.execute( - select(TaskInstance.state, sqla.func.count(TaskInstance.dag_id)) - .where(TaskInstance.dag_id == dag_id) - .group_by(TaskInstance.state) - ).all() - - active_runs = models.DagRun.find(dag_id=dag_id, state=DagRunState.RUNNING, external_trigger=False) - - tags = session.scalars(select(models.DagTag).where(models.DagTag.dag_id == dag_id)).all() - - # TODO: convert this to a relationship - owner_links = session.execute(select(DagOwnerAttributes).filter_by(dag_id=dag_id)).all() - - attrs_to_avoid = [ - "schedule_datasets", - "schedule_dataset_references", - "task_outlet_dataset_references", - "NUM_DAGS_PER_DAGRUN_QUERY", - "serialized_dag", - "tags", - "default_view", - "relative_fileloc", - "dag_id", - "description", - "max_active_runs", - "max_active_tasks", - "schedule_interval", - "owners", - "dag_owner_links", - "is_paused", - ] - attrs_to_avoid.extend(wwwutils.get_attr_renderer().keys()) - dag_model_attrs: list[tuple[str, Any]] = [ - (attr_name, attr) - for attr_name, attr in ( - (attr_name, getattr(dag_model, attr_name)) - for attr_name in dir(dag_model) - if not attr_name.startswith("_") and attr_name not in attrs_to_avoid - ) - if not callable(attr) - ] - - return self.render_template( - "airflow/dag_details.html", - dag=dag, - show_trigger_form_if_no_params=conf.getboolean("webserver", "show_trigger_form_if_no_params"), - dag_model=dag_model, - title=title, - root=root, - states=states, - State=State, - active_runs=active_runs, - tags=tags, - owner_links=owner_links, - dag_model_attrs=dag_model_attrs, - ) + return redirect(url_for("Airflow.grid", dag_id=dag_id)) @expose("/rendered-templates") @auth.has_access_dag("GET", DagAccessEntity.TASK_INSTANCE) diff --git a/tests/www/views/test_views_acl.py b/tests/www/views/test_views_acl.py index 83baf871e0..074483ed4a 100644 --- a/tests/www/views/test_views_acl.py +++ b/tests/www/views/test_views_acl.py @@ -459,19 +459,6 @@ def test_code_success_for_all_dag_user(client_all_dags_codes, dag_id): check_content_in_response(dag_id, resp) -def test_dag_details_success(client_all_dags_dagruns): - """User without RESOURCE_DAG_CODE can see the page, just not the ID.""" - url = "dag_details?dag_id=example_bash_operator" - resp = client_all_dags_dagruns.get(url, follow_redirects=True) - check_content_in_response("DAG Details", resp) - - -def test_dag_details_failure(dag_faker_client): - url = "dag_details?dag_id=example_bash_operator" - resp = dag_faker_client.get(url, follow_redirects=True) - check_content_not_in_response("DAG Details", resp) - - @pytest.mark.parametrize( "dag_id", ["example_bash_operator", "example_subdag_operator"], diff --git a/tests/www/views/test_views_tasks.py b/tests/www/views/test_views_tasks.py index 1e64cfeeeb..00803a3575 100644 --- a/tests/www/views/test_views_tasks.py +++ b/tests/www/views/test_views_tasks.py @@ -178,21 +178,6 @@ def client_ti_without_dag_edit(app): ["Rendered Template"], id="rendered-templates", ), - pytest.param( - "dag_details?dag_id=example_bash_operator", - ["DAG Details"], - id="dag-details-url-param", - ), - pytest.param( - "dag_details?dag_id=example_subdag_operator.section-1", - ["DAG Details"], - id="dag-details-subdag-url-param", - ), - pytest.param( - "dags/example_subdag_operator.section-1/details", - ["DAG Details"], - id="dag-details-subdag", - ), pytest.param( "object/graph_data?dag_id=example_bash_operator", ["runme_1"], @@ -450,22 +435,6 @@ def test_graph_view_without_dag_permission(app, one_dag_perm_user_client): check_content_in_response("Access is Denied", resp) -def test_dag_details_trigger_origin_dag_details_view(app, admin_client): - app.dag_bag.get_dag("test_graph_view").create_dagrun( - run_type=DagRunType.SCHEDULED, - execution_date=DEFAULT_DATE, - data_interval=(DEFAULT_DATE, DEFAULT_DATE), - start_date=timezone.utcnow(), - state=State.RUNNING, - ) - - url = "/dags/test_graph_view/details" - resp = admin_client.get(url, follow_redirects=True) - params = {"origin": "/dags/test_graph_view/details"} - href = f"/dags/test_graph_view/trigger?{html.escape(urllib.parse.urlencode(params))}" - check_content_in_response(href, resp) - - def test_last_dagruns(admin_client): resp = admin_client.post("last_dagruns", follow_redirects=True) check_content_in_response("example_bash_operator", resp)