mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 00:32:42 +01:00
Improve live Harbormaster log follow behaviors
Summary: Depends on D19166. Ref T13088. When the user scrolls away from a followed log, break the focus lock. Let users stop following a live log. Show when lines are added more clearly. Don't refresh quite as quickly give users a better shot at clicking the stop button. These behaviors can probably be refined but are at least more plausible and less actively user-hostile than the first version of this behavior was. Test Plan: Used `write-log --rate` to write a large log slowly. Clicked "Follow Log", followed for a bit. Scrolled away, still got live updates but no more scroll lock. Clicked stop, no more updates. Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam Maniphest Tasks: T13088 Differential Revision: https://secure.phabricator.com/D19167
This commit is contained in:
parent
4e91ad276d
commit
1f40e50f7e
4 changed files with 93 additions and 18 deletions
|
@ -78,7 +78,7 @@ return array(
|
||||||
'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
|
'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
|
||||||
'rsrc/css/application/files/global-drag-and-drop.css' => 'b556a948',
|
'rsrc/css/application/files/global-drag-and-drop.css' => 'b556a948',
|
||||||
'rsrc/css/application/flag/flag.css' => 'bba8f811',
|
'rsrc/css/application/flag/flag.css' => 'bba8f811',
|
||||||
'rsrc/css/application/harbormaster/harbormaster.css' => 'cd73d427',
|
'rsrc/css/application/harbormaster/harbormaster.css' => '730a4a3c',
|
||||||
'rsrc/css/application/herald/herald-test.css' => 'a52e323e',
|
'rsrc/css/application/herald/herald-test.css' => 'a52e323e',
|
||||||
'rsrc/css/application/herald/herald.css' => 'cd8d0134',
|
'rsrc/css/application/herald/herald.css' => 'cd8d0134',
|
||||||
'rsrc/css/application/maniphest/report.css' => '9b9580b7',
|
'rsrc/css/application/maniphest/report.css' => '9b9580b7',
|
||||||
|
@ -416,7 +416,7 @@ return array(
|
||||||
'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef',
|
'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef',
|
||||||
'rsrc/js/application/files/behavior-icon-composer.js' => '8499b6ab',
|
'rsrc/js/application/files/behavior-icon-composer.js' => '8499b6ab',
|
||||||
'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888',
|
'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888',
|
||||||
'rsrc/js/application/harbormaster/behavior-harbormaster-log.js' => 'ab1173d1',
|
'rsrc/js/application/harbormaster/behavior-harbormaster-log.js' => '191b4909',
|
||||||
'rsrc/js/application/herald/HeraldRuleEditor.js' => 'dca75c0e',
|
'rsrc/js/application/herald/HeraldRuleEditor.js' => 'dca75c0e',
|
||||||
'rsrc/js/application/herald/PathTypeahead.js' => 'f7fc67ec',
|
'rsrc/js/application/herald/PathTypeahead.js' => 'f7fc67ec',
|
||||||
'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3',
|
'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3',
|
||||||
|
@ -579,7 +579,7 @@ return array(
|
||||||
'font-fontawesome' => 'e838e088',
|
'font-fontawesome' => 'e838e088',
|
||||||
'font-lato' => 'c7ccd872',
|
'font-lato' => 'c7ccd872',
|
||||||
'global-drag-and-drop-css' => 'b556a948',
|
'global-drag-and-drop-css' => 'b556a948',
|
||||||
'harbormaster-css' => 'cd73d427',
|
'harbormaster-css' => '730a4a3c',
|
||||||
'herald-css' => 'cd8d0134',
|
'herald-css' => 'cd8d0134',
|
||||||
'herald-rule-editor' => 'dca75c0e',
|
'herald-rule-editor' => 'dca75c0e',
|
||||||
'herald-test-css' => 'a52e323e',
|
'herald-test-css' => 'a52e323e',
|
||||||
|
@ -636,7 +636,7 @@ return array(
|
||||||
'javelin-behavior-event-all-day' => 'b41537c9',
|
'javelin-behavior-event-all-day' => 'b41537c9',
|
||||||
'javelin-behavior-fancy-datepicker' => 'ecf4e799',
|
'javelin-behavior-fancy-datepicker' => 'ecf4e799',
|
||||||
'javelin-behavior-global-drag-and-drop' => '960f6a39',
|
'javelin-behavior-global-drag-and-drop' => '960f6a39',
|
||||||
'javelin-behavior-harbormaster-log' => 'ab1173d1',
|
'javelin-behavior-harbormaster-log' => '191b4909',
|
||||||
'javelin-behavior-herald-rule-editor' => '7ebaeed3',
|
'javelin-behavior-herald-rule-editor' => '7ebaeed3',
|
||||||
'javelin-behavior-high-security-warning' => 'a464fe03',
|
'javelin-behavior-high-security-warning' => 'a464fe03',
|
||||||
'javelin-behavior-history-install' => '7ee2b591',
|
'javelin-behavior-history-install' => '7ee2b591',
|
||||||
|
@ -1022,6 +1022,9 @@ return array(
|
||||||
'185bbd53' => array(
|
'185bbd53' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
),
|
),
|
||||||
|
'191b4909' => array(
|
||||||
|
'javelin-behavior',
|
||||||
|
),
|
||||||
'1ad0a787' => array(
|
'1ad0a787' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
'javelin-reactor',
|
'javelin-reactor',
|
||||||
|
@ -1765,9 +1768,6 @@ return array(
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
'phabricator-prefab',
|
'phabricator-prefab',
|
||||||
),
|
),
|
||||||
'ab1173d1' => array(
|
|
||||||
'javelin-behavior',
|
|
||||||
),
|
|
||||||
'ab2f381b' => array(
|
'ab2f381b' => array(
|
||||||
'javelin-request',
|
'javelin-request',
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
|
|
|
@ -720,12 +720,16 @@ final class HarbormasterBuildLogRenderController
|
||||||
|
|
||||||
private function renderLiveRow($log_size) {
|
private function renderLiveRow($log_size) {
|
||||||
$icon_down = id(new PHUIIconView())
|
$icon_down = id(new PHUIIconView())
|
||||||
->setIcon('fa-chevron-down');
|
->setIcon('fa-angle-double-down');
|
||||||
|
|
||||||
|
$icon_pause = id(new PHUIIconView())
|
||||||
|
->setIcon('fa-pause');
|
||||||
|
|
||||||
$follow = javelin_tag(
|
$follow = javelin_tag(
|
||||||
'a',
|
'a',
|
||||||
array(
|
array(
|
||||||
'sigil' => 'harbormaster-log-expand harbormaster-log-live',
|
'sigil' => 'harbormaster-log-expand harbormaster-log-live',
|
||||||
|
'class' => 'harbormaster-log-follow-start',
|
||||||
'meta' => array(
|
'meta' => array(
|
||||||
'headOffset' => $log_size,
|
'headOffset' => $log_size,
|
||||||
'head' => 0,
|
'head' => 0,
|
||||||
|
@ -737,8 +741,21 @@ final class HarbormasterBuildLogRenderController
|
||||||
$icon_down,
|
$icon_down,
|
||||||
' ',
|
' ',
|
||||||
pht('Follow Log'),
|
pht('Follow Log'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$stop_following = javelin_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'sigil' => 'harbormaster-log-expand',
|
||||||
|
'class' => 'harbormaster-log-follow-stop',
|
||||||
|
'meta' => array(
|
||||||
|
'stop' => true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
$icon_pause,
|
||||||
' ',
|
' ',
|
||||||
$icon_down,
|
pht('Stop Following Log'),
|
||||||
));
|
));
|
||||||
|
|
||||||
$expand_cells = array(
|
$expand_cells = array(
|
||||||
|
@ -747,7 +764,10 @@ final class HarbormasterBuildLogRenderController
|
||||||
array(
|
array(
|
||||||
'class' => 'harbormaster-log-follow',
|
'class' => 'harbormaster-log-follow',
|
||||||
),
|
),
|
||||||
$follow),
|
array(
|
||||||
|
$follow,
|
||||||
|
$stop_following,
|
||||||
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->renderActionTable($expand_cells);
|
return $this->renderActionTable($expand_cells);
|
||||||
|
|
|
@ -139,3 +139,31 @@
|
||||||
.harbormaster-log-expand-down .phui-icon-view {
|
.harbormaster-log-expand-down .phui-icon-view {
|
||||||
margin: 0 4px 0 0;
|
margin: 0 4px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.harbormaster-log-following .harbormaster-log-table
|
||||||
|
.harbormaster-log-follow-start {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.harbormaster-log-table .harbormaster-log-follow-stop {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.harbormaster-log-following .harbormaster-log-table
|
||||||
|
.harbormaster-log-follow-stop {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.harbormaster-log-appear > td {
|
||||||
|
animation: harbormaster-fade-in 1s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes harbormaster-fade-in {
|
||||||
|
0% {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
|
|
||||||
JX.behavior('harbormaster-log', function(config) {
|
JX.behavior('harbormaster-log', function(config) {
|
||||||
var contentNode = JX.$(config.contentNodeID);
|
var contentNode = JX.$(config.contentNodeID);
|
||||||
|
|
||||||
var following = false;
|
var following = false;
|
||||||
|
var autoscroll = false;
|
||||||
|
|
||||||
JX.DOM.listen(contentNode, 'click', 'harbormaster-log-expand', function(e) {
|
JX.DOM.listen(contentNode, 'click', 'harbormaster-log-expand', function(e) {
|
||||||
if (!e.isNormalClick()) {
|
if (!e.isNormalClick()) {
|
||||||
|
@ -14,20 +16,29 @@ JX.behavior('harbormaster-log', function(config) {
|
||||||
|
|
||||||
e.kill();
|
e.kill();
|
||||||
|
|
||||||
expand(e.getTarget());
|
expand(e.getTarget(), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
function expand(node) {
|
function expand(node, is_action) {
|
||||||
var row = JX.DOM.findAbove(node, 'tr');
|
var row = JX.DOM.findAbove(node, 'tr');
|
||||||
row = JX.DOM.findAbove(row, 'tr');
|
row = JX.DOM.findAbove(row, 'tr');
|
||||||
|
|
||||||
var data = JX.Stratcom.getData(node);
|
var data = JX.Stratcom.getData(node);
|
||||||
|
|
||||||
|
if (data.stop) {
|
||||||
|
following = false;
|
||||||
|
autoscroll = false;
|
||||||
|
JX.DOM.alterClass(contentNode, 'harbormaster-log-following', false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var uri = new JX.URI(config.renderURI)
|
var uri = new JX.URI(config.renderURI)
|
||||||
.addQueryParams(data);
|
.addQueryParams(data);
|
||||||
|
|
||||||
if (data.live) {
|
if (data.live && is_action) {
|
||||||
following = true;
|
following = true;
|
||||||
|
autoscroll = true;
|
||||||
|
JX.DOM.alterClass(contentNode, 'harbormaster-log-following', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
var request = new JX.Request(uri, function(r) {
|
var request = new JX.Request(uri, function(r) {
|
||||||
|
@ -46,18 +57,34 @@ JX.behavior('harbormaster-log', function(config) {
|
||||||
if (data.live) {
|
if (data.live) {
|
||||||
// If this was a live follow, scroll the new data into view. This is
|
// If this was a live follow, scroll the new data into view. This is
|
||||||
// probably intensely annoying in practice but seems cool for now.
|
// probably intensely annoying in practice but seems cool for now.
|
||||||
|
if (autoscroll) {
|
||||||
var last_row = rows[rows.length - 1];
|
var last_row = rows[rows.length - 1];
|
||||||
var tail_pos = JX.$V(last_row).y + JX.Vector.getDim(last_row).y;
|
var tail_pos = JX.$V(last_row).y + JX.Vector.getDim(last_row).y;
|
||||||
var view_y = JX.Vector.getViewport().y;
|
var view_y = JX.Vector.getViewport().y;
|
||||||
JX.DOM.scrollToPosition(null, (tail_pos - view_y) + 32);
|
JX.DOM.scrollToPosition(null, (tail_pos - view_y) + 32);
|
||||||
|
|
||||||
setTimeout(follow, 500);
|
// This will fire a scroll event, but we want to keep autoscroll
|
||||||
|
// enabled until we see an explicit scroll event by the user.
|
||||||
|
setTimeout(function() { autoscroll = true; }, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(follow, 2000);
|
||||||
|
|
||||||
|
for (var ii = 1; ii < (rows.length - 1); ii++) {
|
||||||
|
JX.DOM.alterClass(rows[ii], 'harbormaster-log-appear', true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
request.send();
|
request.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the user explicitly scrolls while following a log, keep live updating
|
||||||
|
// it but stop following it with the scrollbar.
|
||||||
|
JX.Stratcom.listen('scroll', null, function() {
|
||||||
|
autoscroll = false;
|
||||||
|
});
|
||||||
|
|
||||||
function follow() {
|
function follow() {
|
||||||
if (!following) {
|
if (!following) {
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue