You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by bb...@apache.org on 2022/10/21 14:40:14 UTC

[airflow] branch main updated: Fix some bug in web ui dags list page (auto-refresh & jump search null state) (#27141)

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

bbovenzi 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 ebd34cbd9f Fix some bug in web ui dags list page (auto-refresh & jump search null state) (#27141)
ebd34cbd9f is described below

commit ebd34cbd9f62d086bb39727d85fd58a0758edba3
Author: Bob Du <i...@bobdu.cc>
AuthorDate: Fri Oct 21 22:39:59 2022 +0800

    Fix some bug in web ui dags list page (auto-refresh & jump search null state) (#27141)
    
    * Fix some bug in web ui dags list page
    
    Signed-off-by: BobDu <i...@bobdu.cc>
    
    * use switch case & fix remove loading dot
    
    Signed-off-by: BobDu <i...@bobdu.cc>
    
    * rename drawDagStats & selectors constants
    
    Signed-off-by: BobDu <i...@bobdu.cc>
    
    * Further clean up of duplicate code
    
    Signed-off-by: BobDu <i...@bobdu.cc>
    
    Signed-off-by: BobDu <i...@bobdu.cc>
---
 airflow/www/static/js/dags.js           | 145 ++++++++------------------------
 airflow/www/templates/airflow/dags.html |   6 +-
 2 files changed, 37 insertions(+), 114 deletions(-)

diff --git a/airflow/www/static/js/dags.js b/airflow/www/static/js/dags.js
index 3acd8a4742..5872f8f27f 100644
--- a/airflow/www/static/js/dags.js
+++ b/airflow/www/static/js/dags.js
@@ -44,6 +44,9 @@ const datasetsUrl = getMetaValue('datasets_url');
 const nextDatasets = {};
 let nextDatasetsError;
 
+const DAG_RUN = 'dag-run';
+const TASK_INSTANCE = 'task-instance';
+
 // auto refresh interval in milliseconds
 // (x2 the interval in tree/graph view since this page can take longer to refresh )
 const refreshIntervalMs = 2000;
@@ -189,10 +192,10 @@ d3.selectAll('.js-last-run-tooltip')
     d3.select(this).attr('data-original-title', tiTooltip(lastRunData));
   });
 
-function drawDagStatsForDag(dagId, states) {
-  const g = d3.select(`svg#dag-run-${dagId.replace(/\./g, '__dot__')}`)
+function drawDagStats(selector, dagId, states) {
+  const g = d3.select(`svg#${selector}-${dagId.replace(/\./g, '__dot__')}`)
     .attr('height', diameter + (strokeWidthHover * 2))
-    .attr('width', '120px')
+    .attr('width', (states.length * (diameter + circleMargin)) + circleMargin)
     .selectAll('g')
     .data(states)
     .enter()
@@ -204,103 +207,41 @@ function drawDagStatsForDag(dagId, states) {
     });
 
   g.append('svg:a')
-    .attr('href', (d) => `${dagRunUrl}?_flt_3_dag_id=${dagId}&_flt_3_state=${d.state}`)
-    .append('circle')
-    .attr('id', (d) => `run-${dagId.replace(/\./g, '_')}${d.state || 'none'}`)
-    .attr('class', 'has-svg-tooltip')
-    .attr('stroke-width', (d) => {
-      if (d.count > 0) return strokeWidth;
-
-      return 1;
-    })
-    .attr('stroke', (d) => {
-      if (d.count > 0) return STATE_COLOR[d.state];
-
-      return 'gainsboro';
-    })
-    .attr('fill', '#fff')
-    .attr('r', diameter / 2)
-    .attr('title', (d) => d.state)
-    .on('mouseover', (d) => {
-      if (d.count > 0) {
-        d3.select(this).transition().duration(400)
-          .attr('fill', '#e2e2e2')
-          .style('stroke-width', strokeWidthHover);
+    .attr('href', (d) => {
+      const params = new URLSearchParams();
+      params.append('_flt_3_dag_id', dagId);
+      /* eslint no-unused-expressions: ["error", { "allowTernary": true }] */
+      d.state ? params.append('_flt_3_state', d.state) : params.append('_flt_8_state', '');
+      switch (selector) {
+        case DAG_RUN: return `${dagRunUrl}?${params.toString()}`;
+        case TASK_INSTANCE: return `${taskInstanceUrl}?${params.toString()}`;
+        default: return '';
       }
     })
-    .on('mouseout', (d) => {
-      if (d.count > 0) {
-        d3.select(this).transition().duration(400)
-          .attr('fill', '#fff')
-          .style('stroke-width', strokeWidth);
-      }
-    })
-    .style('opacity', 0)
-    .transition()
-    .duration(300)
-    .delay((d, i) => i * 50)
-    .style('opacity', 1);
-  d3.select('.js-loading-dag-stats').remove();
-
-  g.append('text')
-    .attr('fill', '#51504f')
-    .attr('text-anchor', 'middle')
-    .attr('vertical-align', 'middle')
-    .attr('font-size', 9)
-    .attr('y', 3)
-    .style('pointer-events', 'none')
-    .text((d) => (d.count > 0 ? d.count : ''));
-}
-
-function dagStatsHandler(error, json) {
-  Object.keys(json).forEach((dagId) => {
-    const states = json[dagId];
-    drawDagStatsForDag(dagId, states);
-  });
-}
-
-function drawTaskStatsForDag(dagId, states) {
-  const g = d3.select(`svg#task-run-${dagId.replace(/\./g, '__dot__')}`)
-    .attr('height', diameter + (strokeWidthHover * 2))
-    .attr('width', (states.length * (diameter + circleMargin)) + circleMargin)
-    .selectAll('g')
-    .data(states)
-    .enter()
-    .append('g')
-    .attr('transform', (d, i) => {
-      const x = (i * (diameter + circleMargin)) + (diameter / 2 + circleMargin);
-      const y = (diameter / 2) + strokeWidthHover;
-      return `translate(${x},${y})`;
-    });
-
-  g.append('svg:a')
-    .attr('href', (d) => `${taskInstanceUrl}?_flt_3_dag_id=${dagId}&_flt_3_state=${d.state}`)
     .append('circle')
-    .attr('id', (d) => `task-${dagId.replace(/\./g, '_')}${d.state || 'none'}`)
+    .attr('id', (d) => `${selector}-${dagId.replace(/\./g, '_')}-${d.state || 'none'}`)
     .attr('class', 'has-svg-tooltip')
     .attr('stroke-width', (d) => {
       if (d.count > 0) return strokeWidth;
-
       return 1;
     })
     .attr('stroke', (d) => {
       if (d.count > 0) return STATE_COLOR[d.state];
-
       return 'gainsboro';
     })
     .attr('fill', '#fff')
     .attr('r', diameter / 2)
     .attr('title', (d) => d.state || 'none')
-    .on('mouseover', function mouseOver(d) {
+    .on('mouseover', (d) => {
       if (d.count > 0) {
-        d3.select(this).transition().duration(400)
+        d3.select(d3.event.currentTarget).transition().duration(400)
           .attr('fill', '#e2e2e2')
           .style('stroke-width', strokeWidthHover);
       }
     })
-    .on('mouseout', function mouseOut(d) {
+    .on('mouseout', (d) => {
       if (d.count > 0) {
-        d3.select(this).transition().duration(400)
+        d3.select(d3.event.currentTarget).transition().duration(400)
           .attr('fill', '#fff')
           .style('stroke-width', strokeWidth);
       }
@@ -311,7 +252,7 @@ function drawTaskStatsForDag(dagId, states) {
     .delay((d, i) => i * 50)
     .style('opacity', 1);
 
-  d3.select('.js-loading-task-stats').remove();
+  d3.select(`.js-loading-${selector}-stats`).remove();
 
   g.append('text')
     .attr('fill', '#51504f')
@@ -323,10 +264,10 @@ function drawTaskStatsForDag(dagId, states) {
     .text((d) => (d.count > 0 ? d.count : ''));
 }
 
-function taskStatsHandler(error, json) {
+function dagStatsHandler(selector, json) {
   Object.keys(json).forEach((dagId) => {
     const states = json[dagId];
-    drawTaskStatsForDag(dagId, states);
+    drawDagStats(selector, dagId, states);
   });
 }
 
@@ -356,14 +297,14 @@ function getDagStats() {
       .post(params, lastDagRunsHandler);
     d3.json(dagStatsUrl)
       .header('X-CSRFToken', csrfToken)
-      .post(params, dagStatsHandler);
+      .post(params, (error, json) => dagStatsHandler(DAG_RUN, json));
     d3.json(taskStatsUrl)
       .header('X-CSRFToken', csrfToken)
-      .post(params, taskStatsHandler);
+      .post(params, (error, json) => dagStatsHandler(TASK_INSTANCE, json));
   } else {
     // no dags, hide the loading dots
-    $('.js-loading-task-stats').remove();
-    $('.js-loading-dag-stats').remove();
+    $(`.js-loading-${DAG_RUN}-stats`).remove();
+    $(`.js-loading-${TASK_INSTANCE}-stats`).remove();
   }
 }
 
@@ -382,7 +323,7 @@ function hideSvgTooltip() {
   $('#svg-tooltip').css('display', 'none');
 }
 
-function refreshDagRunsAndTasks(selector, dagId, states) {
+function refreshDagStats(selector, dagId, states) {
   d3.select(`svg#${selector}-${dagId.replace(/\./g, '__dot__')}`)
     .selectAll('circle')
     .data(states)
@@ -392,19 +333,9 @@ function refreshDagRunsAndTasks(selector, dagId, states) {
     })
     .attr('stroke', (d) => {
       if (d.count > 0) return STATE_COLOR[d.state];
-
       return 'gainsboro';
-    })
-    .attr('fill', '#fff')
-    .attr('r', diameter / 2)
-    .attr('title', (d) => d.state)
-    .on('mouseover', (d) => {
-      if (d.count > 0) {
-        d3.select(this).transition().duration(400)
-          .attr('fill', '#e2e2e2')
-          .style('stroke-width', strokeWidthHover);
-      }
     });
+
   d3.select(`svg#${selector}-${dagId.replace(/\./g, '__dot__')}`)
     .selectAll('text')
     .data(states)
@@ -416,13 +347,6 @@ function refreshDagRunsAndTasks(selector, dagId, states) {
     });
 }
 
-function refreshTaskStateHandler(error, ts) {
-  Object.keys(ts).forEach((dagId) => {
-    const states = ts[dagId];
-    refreshDagRunsAndTasks('task-run', dagId, states);
-  });
-}
-
 let refreshInterval;
 
 function checkActiveRuns(json) {
@@ -438,12 +362,11 @@ function checkActiveRuns(json) {
   }
 }
 
-function refreshDagRuns(error, json) {
-  checkActiveRuns(json);
+function refreshDagStatsHandler(selector, json) {
+  if (selector === DAG_RUN) checkActiveRuns(json);
   Object.keys(json).forEach((dagId) => {
     const states = json[dagId];
-    drawDagStatsForDag(dagId, states);
-    refreshDagRunsAndTasks('dag-run', dagId, states);
+    refreshDagStats(selector, dagId, states);
   });
 }
 
@@ -460,10 +383,10 @@ function handleRefresh({ activeDagsOnly = false } = {}) {
       .post(params, lastDagRunsHandler);
     d3.json(dagStatsUrl)
       .header('X-CSRFToken', csrfToken)
-      .post(params, refreshDagRuns);
+      .post(params, (error, json) => refreshDagStatsHandler(DAG_RUN, json));
     d3.json(taskStatsUrl)
       .header('X-CSRFToken', csrfToken)
-      .post(params, refreshTaskStateHandler);
+      .post(params, (error, json) => refreshDagStatsHandler(TASK_INSTANCE, json));
   }
   setTimeout(() => {
     $('#loading-dots').css('display', 'none');
diff --git a/airflow/www/templates/airflow/dags.html b/airflow/www/templates/airflow/dags.html
index 4639c17ace..72c875330e 100644
--- a/airflow/www/templates/airflow/dags.html
+++ b/airflow/www/templates/airflow/dags.html
@@ -268,7 +268,7 @@
               {% endfor %}
             </td>
             <td style="padding:0; width:130px;">
-              {{ loading_dots(classes='js-loading-dag-stats text-muted') }}
+              {{ loading_dots(classes='js-loading-dag-run-stats text-muted') }}
               <svg height="10" width="10" id="dag-run-{{ dag.safe_dag_id }}" style="display: block;"></svg>
             </td>
             <td>
@@ -342,8 +342,8 @@
               {% endif %}
             </td>
             <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>
+              {{ loading_dots(classes='js-loading-task-instance-stats text-muted') }}
+              <svg height="10" width="10" id='task-instance-{{ dag.safe_dag_id }}' style="display: block;"></svg>
             </td>
             <td class="text-center">
               <div class="btn-group">