[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:
parent
5d4f5d36a2
commit
04f04e0ea7
|
@ -238,18 +238,6 @@ tr.corresponding-item-hover > td, tr.corresponding-item-hover > th {
|
|||
background-color: #D6FFE4 !important;
|
||||
}
|
||||
|
||||
#application-timeline.collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#job-timeline.collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#task-assignment-timeline.collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.control-panel {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ function drawApplicationTimeline(groupArray, eventObjArray, startTime, offset) {
|
|||
editable: false,
|
||||
align: 'left',
|
||||
showCurrentTime: false,
|
||||
min: startTime,
|
||||
start: startTime,
|
||||
zoomable: false,
|
||||
moment: function (date) {
|
||||
return vis.moment(date).utcOffset(offset);
|
||||
|
@ -50,7 +50,7 @@ function drawApplicationTimeline(groupArray, eventObjArray, startTime, offset) {
|
|||
};
|
||||
|
||||
$(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
|
||||
});
|
||||
|
||||
|
@ -75,6 +75,9 @@ function drawApplicationTimeline(groupArray, eventObjArray, startTime, offset) {
|
|||
|
||||
$("#application-timeline").toggleClass('collapsed');
|
||||
|
||||
var visibilityState = status ? "" : "none";
|
||||
$("#application-timeline").css("display", visibilityState);
|
||||
|
||||
// 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-closed');
|
||||
|
@ -89,6 +92,8 @@ $(function () {
|
|||
// Set it to false so that the click function can revert it
|
||||
window.localStorage.setItem("expand-application-timeline", "false");
|
||||
$("span.expand-application-timeline").trigger('click');
|
||||
} else {
|
||||
$("#application-timeline").css("display", "none");
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -103,7 +108,7 @@ function drawJobTimeline(groupArray, eventObjArray, startTime, offset) {
|
|||
editable: false,
|
||||
align: 'left',
|
||||
showCurrentTime: false,
|
||||
min: startTime,
|
||||
start: startTime,
|
||||
zoomable: false,
|
||||
moment: function (date) {
|
||||
return vis.moment(date).utcOffset(offset);
|
||||
|
@ -152,6 +157,9 @@ function drawJobTimeline(groupArray, eventObjArray, startTime, offset) {
|
|||
|
||||
$("#job-timeline").toggleClass('collapsed');
|
||||
|
||||
var visibilityState = status ? "" : "none";
|
||||
$("#job-timeline").css("display", visibilityState);
|
||||
|
||||
// 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-closed');
|
||||
|
@ -166,13 +174,15 @@ $(function () {
|
|||
// Set it to false so that the click function can revert it
|
||||
window.localStorage.setItem("expand-job-timeline", "false");
|
||||
$("span.expand-job-timeline").trigger('click');
|
||||
} else {
|
||||
$("#job-timeline").css("display", "none");
|
||||
}
|
||||
});
|
||||
|
||||
function drawTaskAssignmentTimeline(groupArray, eventObjArray, minLaunchTime, maxFinishTime, offset) {
|
||||
var groups = new vis.DataSet(groupArray);
|
||||
var items = new vis.DataSet(eventObjArray);
|
||||
var container = $("#task-assignment-timeline")[0]
|
||||
var container = $("#task-assignment-timeline")[0];
|
||||
var options = {
|
||||
groupOrder: function(a, b) {
|
||||
return a.value - b.value
|
||||
|
@ -181,15 +191,15 @@ function drawTaskAssignmentTimeline(groupArray, eventObjArray, minLaunchTime, ma
|
|||
align: 'left',
|
||||
selectable: false,
|
||||
showCurrentTime: false,
|
||||
min: minLaunchTime,
|
||||
max: maxFinishTime,
|
||||
start: minLaunchTime,
|
||||
end: maxFinishTime,
|
||||
zoomable: false,
|
||||
moment: function (date) {
|
||||
return vis.moment(date).utcOffset(offset);
|
||||
}
|
||||
};
|
||||
|
||||
var taskTimeline = new vis.Timeline(container)
|
||||
var taskTimeline = new vis.Timeline(container);
|
||||
taskTimeline.setOptions(options);
|
||||
taskTimeline.setGroups(groups);
|
||||
taskTimeline.setItems(items);
|
||||
|
@ -220,6 +230,9 @@ function drawTaskAssignmentTimeline(groupArray, eventObjArray, minLaunchTime, ma
|
|||
|
||||
$("#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.
|
||||
$(this).find(".expand-task-assignment-timeline-arrow").toggleClass("arrow-open");
|
||||
$(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
|
||||
window.localStorage.setItem("expand-task-assignment-timeline", "false");
|
||||
$("span.expand-task-assignment-timeline").trigger('click');
|
||||
} else {
|
||||
$("#task-assignment-timeline").css("display", "none");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
2
core/src/main/resources/org/apache/spark/ui/static/vis-timeline-graph2d.min.css
vendored
Normal file
2
core/src/main/resources/org/apache/spark/ui/static/vis-timeline-graph2d.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
60
core/src/main/resources/org/apache/spark/ui/static/vis-timeline-graph2d.min.js
vendored
Normal file
60
core/src/main/resources/org/apache/spark/ui/static/vis-timeline-graph2d.min.js
vendored
Normal file
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
|
@ -225,13 +225,14 @@ private[spark] object UIUtils extends Logging {
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="stylesheet"
|
||||
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/timeline-view.css")} type="text/css"/>
|
||||
<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/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/initialize-tooltips.js")}></script>
|
||||
<script src={prependBaseUri(request, "/static/table.js")}></script>
|
||||
|
|
|
@ -47,7 +47,7 @@ import org.apache.spark.status.api.v1.{JacksonMessageWriter, RDDDataDistribution
|
|||
|
||||
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)
|
||||
|
||||
|
|
|
@ -31,8 +31,10 @@ d3.min.js
|
|||
dagre-d3.min.js
|
||||
graphlib-dot.min.js
|
||||
sorttable.js
|
||||
vis.min.js
|
||||
vis.min.css
|
||||
vis-timeline-graph2d.min.js
|
||||
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.js
|
||||
dataTables.rowsGroup.js
|
||||
|
|
23
licenses-binary/LICENSE-vis-timeline.txt
Normal file
23
licenses-binary/LICENSE-vis-timeline.txt
Normal 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.
|
|
@ -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.
|
23
licenses/LICENSE-vis-timeline.txt
Normal file
23
licenses/LICENSE-vis-timeline.txt
Normal 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.
|
|
@ -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.
|
Loading…
Reference in a new issue