You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by ka...@apache.org on 2020/10/30 12:43:40 UTC
[airflow] branch master updated: Fix: Responsive layout of DAGs
(Home) view (#11958)
This is an automated email from the ASF dual-hosted git repository.
kaxilnaik pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/master by this push:
new 1faf985 Fix: Responsive layout of DAGs (Home) view (#11958)
1faf985 is described below
commit 1faf985d83a15e0c2407e4d12a93437c299b44f2
Author: Ryan Hamilton <ry...@ryanahamilton.com>
AuthorDate: Fri Oct 30 08:42:58 2020 -0400
Fix: Responsive layout of DAGs (Home) view (#11958)
---
airflow/www/static/css/dags.css | 7 +-
airflow/www/static/css/main.css | 5 +
airflow/www/templates/airflow/dags.html | 280 ++++++++++++++++----------------
3 files changed, 152 insertions(+), 140 deletions(-)
diff --git a/airflow/www/static/css/dags.css b/airflow/www/static/css/dags.css
index 5a265a2..5affba0 100644
--- a/airflow/www/static/css/dags.css
+++ b/airflow/www/static/css/dags.css
@@ -24,7 +24,12 @@
.dags-table-header {
margin: 0;
- padding: 16px 0;
+ padding-top: 16px;
+}
+
+.dags-table-body {
+ margin: 0 1px;
+ overflow-x: scroll;
}
.dags-table-more {
diff --git a/airflow/www/static/css/main.css b/airflow/www/static/css/main.css
index f0500f9..e174ef0 100644
--- a/airflow/www/static/css/main.css
+++ b/airflow/www/static/css/main.css
@@ -422,3 +422,8 @@ label[for="timezone-other"],
top: 2px;
border: 0;
}
+
+/* Override default Bootstrap behavior to prevent wrapping */
+.btn-group {
+ display: inline-flex;
+}
diff --git a/airflow/www/templates/airflow/dags.html b/airflow/www/templates/airflow/dags.html
index 4078cfe..8b7b563 100644
--- a/airflow/www/templates/airflow/dags.html
+++ b/airflow/www/templates/airflow/dags.html
@@ -39,16 +39,16 @@
<div id="main_content">
<div class="dags-table-wrap">
<div class="row dags-table-header">
- <div class="col-sm-4">
- <div class="btn-group">
+ <div class="col-md-4">
+ <div class="form-group btn-group">
<a href="{{ url_for('Airflow.index', status='all', search=request.args.get('search', None), tags=request.args.get('tags', None)) }}" class="btn {{'btn-primary' if status_filter == 'all' else 'btn-default'}}" title="Show active and paused DAGS">All <span class="badge">{{ "{:,}".format(status_count_all) }}</span></a>
<a href="{{ url_for('Airflow.index', status='active', search=request.args.get('search', None), tags=request.args.get('tags', None)) }}" class="btn {{'btn-primary' if status_filter == 'active' else 'btn-default'}}" title="Show only active DAGS">Active <span class="badge">{{ "{:,}".format(status_count_active) }}</span></a>
<a href="{{ url_for('Airflow.index', status='paused', search=request.args.get('search', None), tags=request.args.get('tags', None)) }}" class="btn {{'btn-primary' if status_filter == 'paused' else 'btn-default'}}" title="Show only paused DAGS">Paused <span class="badge">{{ "{:,}".format(status_count_paused) }}</span></a>
</div>
</div>
- <div class="col-sm-4">
- <form id="tags_form" class="form-inline" style="width: 100%; text-align: left;">
- <div class="form-group search-input" style="width: 80%;">
+ <div class="col-sm-6 col-md-3">
+ <form id="tags_form" style="width: 100%; text-align: left;">
+ <div class="form-group search-input" style="width:100%;">
<select multiple name="tags" id="tags_filter" class="select2-drop-mask" style="width: 100%;">
{% for tag in tags %}
<option value="{{ tag.name }}" {% if tag.selected %}selected{% endif %}>{{ tag.name }}</option>
@@ -60,8 +60,8 @@
</div>
</form>
</div>
- <div class="col-sm-4">
- <form id="search_form" class="form-inline">
+ <div class="col-sm-6 col-md-3 col-md-offset-2">
+ <form id="search_form">
<div class="form-group search-input" style="width: 100%;">
<label for="dag_query" class="sr-only">Search DAGs</label>
<input type="search" id="dag_query" class="typeahead form-control search-input__input" data-provide="typeahead" style="width:100%;" value="{{search_query}}" autocomplete="off" placeholder="Search DAGs">
@@ -72,144 +72,146 @@
</form>
</div>
</div>
- <table class="table table-striped table-bordered table-hover">
- <thead>
- <tr>
- <th width="12">
- <span class="material-icons text-muted js-tooltip" title="Use this toggle to pause a DAG. The scheduler won't schedule new tasks instances for a paused DAG. Tasks already running at pause time won't be affected.">info</span>
- </th>
- <th>DAG</th>
- <th>Owner</th>
- <th>Runs
- <span class="material-icons text-muted js-tooltip" aria-hidden="true" title="Status of all previous DAG runs.">info</span>
- </th>
- <th>Schedule</th>
- <th style="width:180px;">Last Run
- <span class="material-icons text-muted js-tooltip" aria-hidden="true" title="Execution Date/Time of Highest Dag Run.">info</span>
- </th>
- <th>Recent Tasks
- <span class="material-icons text-muted js-tooltip" aria-hidden="true" title="Status of tasks from all active DAG runs or, if not currently active, from most recent run.">info</span>
- </th>
- <th class="text-center" style="width:110px;">Actions</th>
- <th style="width:52px;">Links</th>
- </tr>
- </thead>
- <tbody>
- {% if dags|length == 0 %}
- <tr><td colspan="9">No results</td></tr>
- {% endif %}
- {% for dag in dags %}
+ <div class="dags-table-body">
+ <table class="table table-striped table-bordered table-hover">
+ <thead>
<tr>
- {# Column 1: Turn dag on/off #}
- <td style="padding-right:0;">
- <label class="switch-label js-tooltip" title="Pause/Unpause DAG">
- <input class="switch-input" id="toggle-{{ dag.dag_id }}" dag_id="{{ dag.dag_id }}" type="checkbox" {{ "checked" if not dag.is_paused else "" }} method="post">
- <span class="switch" aria-hidden="true"></span>
- </label>
- </td>
- {# Column 2: Name #}
- <td>
- <a href="{{ url_for('Airflow.'+ dag.get_default_view(), dag_id=dag.dag_id) }}"
- title="{{ dag.description[0:80] + '…' if dag.description and dag.description|length > 80 else dag.description|default('', true) }}">
- <strong>{{ dag.dag_id }}</strong>
- </a>
- <div>
- {% for tag in dag.tags | sort(attribute='name') %}
- <a class="label label-info"
- href="?tags={{ tag.name }}"
- style="margin: 6px 6px 0 0;">
- {{ tag.name }}
- </a>
- {% endfor %}
- </div>
- </td>
- {# Column 3: Dag Owners #}
- <td>{{ dag.owners }}</td>
- {# Column 4: Dag Runs #}
- <td style="padding:0; width:120px;">
- {{ loading_dots(classes='js-loading-dag-stats text-muted') }}
- <svg height="10" width="10" id="dag-run-{{ dag.safe_dag_id }}" style="display: block;"></svg>
- </td>
- {# Column 5: Dag Schedule #}
- <td>
- <a class="label label-default schedule" href="{{ url_for('DagRunModelView.list') }}?_flt_3_dag_id={{ dag.dag_id }}">
- {{ dag.schedule_interval }}
- </a>
- </td>
- {# Column 6: Last Run #}
- <td id="last-run-{{ dag.safe_dag_id }}" class="text-nowrap latest_dag_run">
- {{ loading_dots(classes='js-loading-last-run text-muted') }}
- <a></a>
- <span aria-hidden="true" title=" " class="material-icons text-muted js-tooltip" style="display:none">info</span>
- </td>
- {# Column 7: Recent Tasks #}
- <td style="padding:0; width:323px; height:10px;">
- {{ loading_dots(classes='js-loading-task-stats text-muted') }}
- <svg height="10" width="10" id='task-run-{{ dag.safe_dag_id }}' style="display: block;"></svg>
- </td>
- {# Column 8: Actions #}
- <td class="text-center">
- <div class="btn-group">
- {% if dag %}
- <a href="{{ url_for('Airflow.trigger', dag_id=dag.dag_id) }}" title="Trigger DAG" aria-label="Trigger DAG" class="btn btn-sm btn-default btn-icon-only">
- <span class="material-icons" aria-hidden="true">play_arrow</span>
- </a>
- <a href="{{ url_for('Airflow.refresh', dag_id=dag.dag_id) }}" onclick="postAsForm(this.href); return false" title="Refresh DAG" aria-label="Refresh DAG" class="btn btn-sm btn-default btn-icon-only">
- <span class="material-icons" aria-hidden="true">refresh</span>
- </a>
- {% endif %}
- {# Use dag_id instead of dag.dag_id, because the DAG might not exist in the webserver's DagBag #}
- <a href="{{ url_for('Airflow.delete', dag_id=dag.dag_id) }}" onclick="return confirmDeleteDag(this, '{{ dag.dag_id }}')" title="Delete DAG" aria-label="Delete DAG" class="btn btn-sm btn-default btn-icon-only">
- <span class="material-icons text-danger" aria-hidden="true">delete_outline</span>
+ <th width="12">
+ <span class="material-icons text-muted js-tooltip" title="Use this toggle to pause a DAG. The scheduler won't schedule new tasks instances for a paused DAG. Tasks already running at pause time won't be affected.">info</span>
+ </th>
+ <th>DAG</th>
+ <th>Owner</th>
+ <th>Runs
+ <span class="material-icons text-muted js-tooltip" aria-hidden="true" title="Status of all previous DAG runs.">info</span>
+ </th>
+ <th>Schedule</th>
+ <th style="width:180px;">Last Run
+ <span class="material-icons text-muted js-tooltip" aria-hidden="true" title="Execution Date/Time of Highest Dag Run.">info</span>
+ </th>
+ <th>Recent Tasks
+ <span class="material-icons text-muted js-tooltip" aria-hidden="true" title="Status of tasks from all active DAG runs or, if not currently active, from most recent run.">info</span>
+ </th>
+ <th class="text-center" style="width:110px;">Actions</th>
+ <th style="width:52px;">Links</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% if dags|length == 0 %}
+ <tr><td colspan="9">No results</td></tr>
+ {% endif %}
+ {% for dag in dags %}
+ <tr>
+ {# Column 1: Turn dag on/off #}
+ <td style="padding-right:0;">
+ <label class="switch-label js-tooltip" title="Pause/Unpause DAG">
+ <input class="switch-input" id="toggle-{{ dag.dag_id }}" dag_id="{{ dag.dag_id }}" type="checkbox" {{ "checked" if not dag.is_paused else "" }} method="post">
+ <span class="switch" aria-hidden="true"></span>
+ </label>
+ </td>
+ {# Column 2: Name #}
+ <td>
+ <a href="{{ url_for('Airflow.'+ dag.get_default_view(), dag_id=dag.dag_id) }}"
+ title="{{ dag.description[0:80] + '…' if dag.description and dag.description|length > 80 else dag.description|default('', true) }}">
+ <strong>{{ dag.dag_id }}</strong>
</a>
- </div>
- </td>
- {# Column 9: Links #}
- <td class="dags-table-more">
- {% if dag %}
- <div class="dags-table-more__menu">
- <div class="dags-table-more__links">
- <a href="{{ url_for('Airflow.code', dag_id=dag.dag_id) }}" class="dags-table-more__link">
- <span class="material-icons" aria-hidden="true">code</span>
- Code
- </a>
- <a href="{{ url_for('Airflow.dag_details', dag_id=dag.dag_id) }}" class="dags-table-more__link">
- <span class="material-icons" aria-hidden="true">details</span>
- Details
- </a>
- <a href="{{ url_for('Airflow.gantt', dag_id=dag.dag_id) }}" class="dags-table-more__link">
- <span class="material-icons" aria-hidden="true">vertical_distribute</span>
- Gantt
- </a>
- <a href="{{ url_for('Airflow.landing_times', dag_id=dag.dag_id) }}" class="dags-table-more__link">
- <span class="material-icons" aria-hidden="true">flight_land</span>
- Landing
- </a>
- <a href="{{ url_for('Airflow.tries', dag_id=dag.dag_id) }}" class="dags-table-more__link">
- <span class="material-icons" aria-hidden="true">repeat</span>
- Tries
+ <div>
+ {% for tag in dag.tags | sort(attribute='name') %}
+ <a class="label label-info"
+ href="?tags={{ tag.name }}"
+ style="margin: 6px 6px 0 0;">
+ {{ tag.name }}
</a>
- <a href="{{ url_for('Airflow.duration', dag_id=dag.dag_id) }}" class="dags-table-more__link">
- <span class="material-icons" aria-hidden="true">hourglass_bottom</span>
- Duration
- </a>
- <a href="{{ url_for('Airflow.graph', dag_id=dag.dag_id) }}" class="dags-table-more__link">
- <span class="material-icons" aria-hidden="true">account_tree</span>
- Graph
+ {% endfor %}
+ </div>
+ </td>
+ {# Column 3: Dag Owners #}
+ <td>{{ dag.owners }}</td>
+ {# Column 4: Dag Runs #}
+ <td style="padding:0; width:120px;">
+ {{ loading_dots(classes='js-loading-dag-stats text-muted') }}
+ <svg height="10" width="10" id="dag-run-{{ dag.safe_dag_id }}" style="display: block;"></svg>
+ </td>
+ {# Column 5: Dag Schedule #}
+ <td>
+ <a class="label label-default schedule" href="{{ url_for('DagRunModelView.list') }}?_flt_3_dag_id={{ dag.dag_id }}">
+ {{ dag.schedule_interval }}
+ </a>
+ </td>
+ {# Column 6: Last Run #}
+ <td id="last-run-{{ dag.safe_dag_id }}" class="text-nowrap latest_dag_run">
+ {{ loading_dots(classes='js-loading-last-run text-muted') }}
+ <a></a>
+ <span aria-hidden="true" title=" " class="material-icons text-muted js-tooltip" style="display:none">info</span>
+ </td>
+ {# Column 7: Recent Tasks #}
+ <td style="padding:0; width:323px; height:10px;">
+ {{ loading_dots(classes='js-loading-task-stats text-muted') }}
+ <svg height="10" width="10" id='task-run-{{ dag.safe_dag_id }}' style="display: block;"></svg>
+ </td>
+ {# Column 8: Actions #}
+ <td class="text-center">
+ <div class="btn-group">
+ {% if dag %}
+ <a href="{{ url_for('Airflow.trigger', dag_id=dag.dag_id) }}" title="Trigger DAG" aria-label="Trigger DAG" class="btn btn-sm btn-default btn-icon-only">
+ <span class="material-icons" aria-hidden="true">play_arrow</span>
</a>
- <a href="{{ url_for('Airflow.tree', dag_id=dag.dag_id, num_runs=num_runs) }}" class="dags-table-more__link">
- <span class="material-icons" aria-hidden="true">nature</span>
- Tree
+ <a href="{{ url_for('Airflow.refresh', dag_id=dag.dag_id) }}" onclick="postAsForm(this.href); return false" title="Refresh DAG" aria-label="Refresh DAG" class="btn btn-sm btn-default btn-icon-only">
+ <span class="material-icons" aria-hidden="true">refresh</span>
</a>
- </div>
- <span class="dags-table-more__toggle"><span class="material-icons">more_horiz</span></span>
+ {% endif %}
+ {# Use dag_id instead of dag.dag_id, because the DAG might not exist in the webserver's DagBag #}
+ <a href="{{ url_for('Airflow.delete', dag_id=dag.dag_id) }}" onclick="return confirmDeleteDag(this, '{{ dag.dag_id }}')" title="Delete DAG" aria-label="Delete DAG" class="btn btn-sm btn-default btn-icon-only">
+ <span class="material-icons text-danger" aria-hidden="true">delete_outline</span>
+ </a>
</div>
- {% endif %}
- </td>
- </tr>
- {% endfor %}
- </tbody>
- </table>
+ </td>
+ {# Column 9: Links #}
+ <td class="dags-table-more">
+ {% if dag %}
+ <div class="dags-table-more__menu">
+ <div class="dags-table-more__links">
+ <a href="{{ url_for('Airflow.code', dag_id=dag.dag_id) }}" class="dags-table-more__link">
+ <span class="material-icons" aria-hidden="true">code</span>
+ Code
+ </a>
+ <a href="{{ url_for('Airflow.dag_details', dag_id=dag.dag_id) }}" class="dags-table-more__link">
+ <span class="material-icons" aria-hidden="true">details</span>
+ Details
+ </a>
+ <a href="{{ url_for('Airflow.gantt', dag_id=dag.dag_id) }}" class="dags-table-more__link">
+ <span class="material-icons" aria-hidden="true">vertical_distribute</span>
+ Gantt
+ </a>
+ <a href="{{ url_for('Airflow.landing_times', dag_id=dag.dag_id) }}" class="dags-table-more__link">
+ <span class="material-icons" aria-hidden="true">flight_land</span>
+ Landing
+ </a>
+ <a href="{{ url_for('Airflow.tries', dag_id=dag.dag_id) }}" class="dags-table-more__link">
+ <span class="material-icons" aria-hidden="true">repeat</span>
+ Tries
+ </a>
+ <a href="{{ url_for('Airflow.duration', dag_id=dag.dag_id) }}" class="dags-table-more__link">
+ <span class="material-icons" aria-hidden="true">hourglass_bottom</span>
+ Duration
+ </a>
+ <a href="{{ url_for('Airflow.graph', dag_id=dag.dag_id) }}" class="dags-table-more__link">
+ <span class="material-icons" aria-hidden="true">account_tree</span>
+ Graph
+ </a>
+ <a href="{{ url_for('Airflow.tree', dag_id=dag.dag_id, num_runs=num_runs) }}" class="dags-table-more__link">
+ <span class="material-icons" aria-hidden="true">nature</span>
+ Tree
+ </a>
+ </div>
+ <span class="dags-table-more__toggle"><span class="material-icons">more_horiz</span></span>
+ </div>
+ {% endif %}
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ </div>
</div>
<div class="row">
<div class="col-sm-6">