Skip to content

Commit

Permalink
Fix some bug in web ui dags list page (auto-refresh & jump search nul…
Browse files Browse the repository at this point in the history
…l state) (#27141)

* Fix some bug in web ui dags list page

Signed-off-by: BobDu <[email protected]>

* use switch case & fix remove loading dot

Signed-off-by: BobDu <[email protected]>

* rename drawDagStats & selectors constants

Signed-off-by: BobDu <[email protected]>

* Further clean up of duplicate code

Signed-off-by: BobDu <[email protected]>

Signed-off-by: BobDu <[email protected]>
(cherry picked from commit ebd34cb)
  • Loading branch information
BobDu authored and ephraimbuddy committed Nov 9, 2022
1 parent 968704f commit 8b555ce
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 114 deletions.
145 changes: 34 additions & 111 deletions airflow/www/static/js/dags.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ const gridUrl = getMetaValue('grid_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;
Expand Down Expand Up @@ -188,10 +191,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()
Expand All @@ -203,103 +206,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);
}
Expand All @@ -310,7 +251,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')
Expand All @@ -322,10 +263,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);
});
}

Expand Down Expand Up @@ -355,14 +296,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();
}
}

Expand All @@ -381,7 +322,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)
Expand All @@ -391,19 +332,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)
Expand All @@ -415,13 +346,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) {
Expand All @@ -437,12 +361,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);
});
}

Expand All @@ -459,10 +382,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');
Expand Down
6 changes: 3 additions & 3 deletions airflow/www/templates/airflow/dags.html
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ <h2>{{ page_title }}</h2>
{% 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>
Expand Down Expand Up @@ -331,8 +331,8 @@ <h2>{{ page_title }}</h2>
{% 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">
Expand Down

0 comments on commit 8b555ce

Please sign in to comment.