[SPARK-31420][WEBUI] Infinite timeline redraw in job details page

### What changes were proposed in this pull request?

Upgrade vis.js to fix an infinite re-drawing issue.

As reported here, old releases of vis.js have that issue.
Fortunately, the latest version seems to resolve the issue.

With the latest release of vis.js, there are some performance issues with the original `timeline-view.js` and `timeline-view.css` so I also changed them.

### Why are the changes needed?

For better UX.

### Does this PR introduce any user-facing change?

No. Appearance and functionalities are not changed.

### How was this patch tested?

I confirmed infinite redrawing doesn't happen with a JobPage which I had reproduced the issue.

With the original version of vis.js, I reproduced the issue with the following conditions.

* Use history server and load core/src/test/resources/spark-events.
* Visit the JobPage for job2 in application_1553914137147_0018.
* Zoom out to 80% on Safari / Chrome / Firefox.

Maybe, it depends on OS and the version of browsers.

Closes #28192 from sarutak/upgrade-visjs.

Authored-by: Kousuke Saruta <sarutak@oss.nttdata.com>
Signed-off-by: Gengliang Wang <gengliang.wang@databricks.com>
This commit is contained in:
Kousuke Saruta 2020-04-13 23:23:00 -07:00 committed by Gengliang Wang
parent 5d4f5d36a2
commit 04f04e0ea7
15 changed files with 140 additions and 114 deletions

View file

@ -238,18 +238,6 @@ tr.corresponding-item-hover > td, tr.corresponding-item-hover > th {
background-color: #D6FFE4 !important; background-color: #D6FFE4 !important;
} }
#application-timeline.collapsed {
display: none;
}
#job-timeline.collapsed {
display: none;
}
#task-assignment-timeline.collapsed {
display: none;
}
.control-panel { .control-panel {
margin-bottom: 5px; margin-bottom: 5px;
} }

View file

@ -26,7 +26,7 @@ function drawApplicationTimeline(groupArray, eventObjArray, startTime, offset) {
editable: false, editable: false,
align: 'left', align: 'left',
showCurrentTime: false, showCurrentTime: false,
min: startTime, start: startTime,
zoomable: false, zoomable: false,
moment: function (date) { moment: function (date) {
return vis.moment(date).utcOffset(offset); return vis.moment(date).utcOffset(offset);
@ -50,7 +50,7 @@ function drawApplicationTimeline(groupArray, eventObjArray, startTime, offset) {
}; };
$(this).click(function() { $(this).click(function() {
var jobPagePath = $(getSelectorForJobEntry(this)).find("a.name-link").attr("href") var jobPagePath = $(getSelectorForJobEntry(this)).find("a.name-link").attr("href");
window.location.href = jobPagePath window.location.href = jobPagePath
}); });
@ -75,6 +75,9 @@ function drawApplicationTimeline(groupArray, eventObjArray, startTime, offset) {
$("#application-timeline").toggleClass('collapsed'); $("#application-timeline").toggleClass('collapsed');
var visibilityState = status ? "" : "none";
$("#application-timeline").css("display", visibilityState);
// Switch the class of the arrow from open to closed. // Switch the class of the arrow from open to closed.
$(this).find('.expand-application-timeline-arrow').toggleClass('arrow-open'); $(this).find('.expand-application-timeline-arrow').toggleClass('arrow-open');
$(this).find('.expand-application-timeline-arrow').toggleClass('arrow-closed'); $(this).find('.expand-application-timeline-arrow').toggleClass('arrow-closed');
@ -89,6 +92,8 @@ $(function () {
// Set it to false so that the click function can revert it // Set it to false so that the click function can revert it
window.localStorage.setItem("expand-application-timeline", "false"); window.localStorage.setItem("expand-application-timeline", "false");
$("span.expand-application-timeline").trigger('click'); $("span.expand-application-timeline").trigger('click');
} else {
$("#application-timeline").css("display", "none");
} }
}); });
@ -103,7 +108,7 @@ function drawJobTimeline(groupArray, eventObjArray, startTime, offset) {
editable: false, editable: false,
align: 'left', align: 'left',
showCurrentTime: false, showCurrentTime: false,
min: startTime, start: startTime,
zoomable: false, zoomable: false,
moment: function (date) { moment: function (date) {
return vis.moment(date).utcOffset(offset); return vis.moment(date).utcOffset(offset);
@ -152,6 +157,9 @@ function drawJobTimeline(groupArray, eventObjArray, startTime, offset) {
$("#job-timeline").toggleClass('collapsed'); $("#job-timeline").toggleClass('collapsed');
var visibilityState = status ? "" : "none";
$("#job-timeline").css("display", visibilityState);
// Switch the class of the arrow from open to closed. // Switch the class of the arrow from open to closed.
$(this).find('.expand-job-timeline-arrow').toggleClass('arrow-open'); $(this).find('.expand-job-timeline-arrow').toggleClass('arrow-open');
$(this).find('.expand-job-timeline-arrow').toggleClass('arrow-closed'); $(this).find('.expand-job-timeline-arrow').toggleClass('arrow-closed');
@ -166,13 +174,15 @@ $(function () {
// Set it to false so that the click function can revert it // Set it to false so that the click function can revert it
window.localStorage.setItem("expand-job-timeline", "false"); window.localStorage.setItem("expand-job-timeline", "false");
$("span.expand-job-timeline").trigger('click'); $("span.expand-job-timeline").trigger('click');
} else {
$("#job-timeline").css("display", "none");
} }
}); });
function drawTaskAssignmentTimeline(groupArray, eventObjArray, minLaunchTime, maxFinishTime, offset) { function drawTaskAssignmentTimeline(groupArray, eventObjArray, minLaunchTime, maxFinishTime, offset) {
var groups = new vis.DataSet(groupArray); var groups = new vis.DataSet(groupArray);
var items = new vis.DataSet(eventObjArray); var items = new vis.DataSet(eventObjArray);
var container = $("#task-assignment-timeline")[0] var container = $("#task-assignment-timeline")[0];
var options = { var options = {
groupOrder: function(a, b) { groupOrder: function(a, b) {
return a.value - b.value return a.value - b.value
@ -181,15 +191,15 @@ function drawTaskAssignmentTimeline(groupArray, eventObjArray, minLaunchTime, ma
align: 'left', align: 'left',
selectable: false, selectable: false,
showCurrentTime: false, showCurrentTime: false,
min: minLaunchTime, start: minLaunchTime,
max: maxFinishTime, end: maxFinishTime,
zoomable: false, zoomable: false,
moment: function (date) { moment: function (date) {
return vis.moment(date).utcOffset(offset); return vis.moment(date).utcOffset(offset);
} }
}; };
var taskTimeline = new vis.Timeline(container) var taskTimeline = new vis.Timeline(container);
taskTimeline.setOptions(options); taskTimeline.setOptions(options);
taskTimeline.setGroups(groups); taskTimeline.setGroups(groups);
taskTimeline.setItems(items); taskTimeline.setItems(items);
@ -220,6 +230,9 @@ function drawTaskAssignmentTimeline(groupArray, eventObjArray, minLaunchTime, ma
$("#task-assignment-timeline").toggleClass("collapsed"); $("#task-assignment-timeline").toggleClass("collapsed");
var visibilityState = status ? "" : "none";
$("#task-assignment-timeline").css("display", visibilityState);
// Switch the class of the arrow from open to closed. // Switch the class of the arrow from open to closed.
$(this).find(".expand-task-assignment-timeline-arrow").toggleClass("arrow-open"); $(this).find(".expand-task-assignment-timeline-arrow").toggleClass("arrow-open");
$(this).find(".expand-task-assignment-timeline-arrow").toggleClass("arrow-closed"); $(this).find(".expand-task-assignment-timeline-arrow").toggleClass("arrow-closed");
@ -234,6 +247,8 @@ $(function () {
// Set it to false so that the click function can revert it // Set it to false so that the click function can revert it
window.localStorage.setItem("expand-task-assignment-timeline", "false"); window.localStorage.setItem("expand-task-assignment-timeline", "false");
$("span.expand-task-assignment-timeline").trigger('click'); $("span.expand-task-assignment-timeline").trigger('click');
} else {
$("#task-assignment-timeline").css("display", "none");
} }
}); });

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -225,13 +225,14 @@ private[spark] object UIUtils extends Logging {
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" <link rel="stylesheet"
href={prependBaseUri(request, "/static/bootstrap.min.css")} type="text/css"/> href={prependBaseUri(request, "/static/bootstrap.min.css")} type="text/css"/>
<link rel="stylesheet" href={prependBaseUri(request, "/static/vis.min.css")} type="text/css"/> <link rel="stylesheet"
href={prependBaseUri(request, "/static/vis-timeline-graph2d.min.css")} type="text/css"/>
<link rel="stylesheet" href={prependBaseUri(request, "/static/webui.css")} type="text/css"/> <link rel="stylesheet" href={prependBaseUri(request, "/static/webui.css")} type="text/css"/>
<link rel="stylesheet" <link rel="stylesheet"
href={prependBaseUri(request, "/static/timeline-view.css")} type="text/css"/> href={prependBaseUri(request, "/static/timeline-view.css")} type="text/css"/>
<script src={prependBaseUri(request, "/static/sorttable.js")} ></script> <script src={prependBaseUri(request, "/static/sorttable.js")} ></script>
<script src={prependBaseUri(request, "/static/jquery-3.4.1.min.js")}></script> <script src={prependBaseUri(request, "/static/jquery-3.4.1.min.js")}></script>
<script src={prependBaseUri(request, "/static/vis.min.js")}></script> <script src={prependBaseUri(request, "/static/vis-timeline-graph2d.min.js")}></script>
<script src={prependBaseUri(request, "/static/bootstrap.bundle.min.js")}></script> <script src={prependBaseUri(request, "/static/bootstrap.bundle.min.js")}></script>
<script src={prependBaseUri(request, "/static/initialize-tooltips.js")}></script> <script src={prependBaseUri(request, "/static/initialize-tooltips.js")}></script>
<script src={prependBaseUri(request, "/static/table.js")}></script> <script src={prependBaseUri(request, "/static/table.js")}></script>

View file

@ -47,7 +47,7 @@ import org.apache.spark.status.api.v1.{JacksonMessageWriter, RDDDataDistribution
private[spark] class SparkUICssErrorHandler extends DefaultCssErrorHandler { private[spark] class SparkUICssErrorHandler extends DefaultCssErrorHandler {
private val cssWhiteList = List("bootstrap.min.css", "vis.min.css") private val cssWhiteList = List("bootstrap.min.css", "vis-timeline-graph2d.min.css")
private def isInWhileList(uri: String): Boolean = cssWhiteList.exists(uri.endsWith) private def isInWhileList(uri: String): Boolean = cssWhiteList.exists(uri.endsWith)

View file

@ -31,8 +31,10 @@ d3.min.js
dagre-d3.min.js dagre-d3.min.js
graphlib-dot.min.js graphlib-dot.min.js
sorttable.js sorttable.js
vis.min.js vis-timeline-graph2d.min.js
vis.min.css vis-timeline-graph2d.min.js.map
vis-timeline-graph2d.min.css
vis-timeline-graph2d.min.css.map
dataTables.bootstrap4.1.10.20.min.css dataTables.bootstrap4.1.10.20.min.css
dataTables.bootstrap4.1.10.20.min.js dataTables.bootstrap4.1.10.20.min.js
dataTables.rowsGroup.js dataTables.rowsGroup.js

View file

@ -0,0 +1,23 @@
vis-timeline and vis-graph2d
https://visjs.github.io/vis-timeline/
Create a fully customizable, interactive timeline with items and ranges.
@version 7.3.4
@date 2020-03-18T17:03:58.105Z
@copyright (c) 2011-2017 Almende B.V, http://almende.com
@copyright (c) 2017-2019 visjs contributors, https://github.com/visjs
@license
vis.js is dual licensed under both
1. The Apache 2.0 License
http://www.apache.org/licenses/LICENSE-2.0
and
2. The MIT License
http://opensource.org/licenses/MIT
vis.js may be distributed under either license.

View file

@ -1,22 +0,0 @@
vis.js
https://github.com/almende/vis
A dynamic, browser-based visualization library.
@version 4.16.1
@date 2016-04-18
@license
Copyright (C) 2011-2016 Almende B.V, http://almende.com
Vis.js is dual licensed under both
* The Apache 2.0 License
http://www.apache.org/licenses/LICENSE-2.0
and
* The MIT License
http://opensource.org/licenses/MIT
Vis.js may be distributed under either license.

View file

@ -0,0 +1,23 @@
vis-timeline and vis-graph2d
https://visjs.github.io/vis-timeline/
Create a fully customizable, interactive timeline with items and ranges.
@version 7.3.4
@date 2020-03-18T17:03:58.105Z
@copyright (c) 2011-2017 Almende B.V, http://almende.com
@copyright (c) 2017-2019 visjs contributors, https://github.com/visjs
@license
vis.js is dual licensed under both
1. The Apache 2.0 License
http://www.apache.org/licenses/LICENSE-2.0
and
2. The MIT License
http://opensource.org/licenses/MIT
vis.js may be distributed under either license.

View file

@ -1,22 +0,0 @@
vis.js
https://github.com/almende/vis
A dynamic, browser-based visualization library.
@version 4.16.1
@date 2016-04-18
@license
Copyright (C) 2011-2016 Almende B.V, http://almende.com
Vis.js is dual licensed under both
* The Apache 2.0 License
http://www.apache.org/licenses/LICENSE-2.0
and
* The MIT License
http://opensource.org/licenses/MIT
Vis.js may be distributed under either license.