2019-06-27 19:10:34 +00:00
|
|
|
import Component from '@ember/component';
|
|
|
|
import { run } from '@ember/runloop';
|
|
|
|
import { task } from 'ember-concurrency';
|
2019-07-02 19:59:15 +00:00
|
|
|
import WindowResizable from 'nomad-ui/mixins/window-resizable';
|
2019-06-27 19:10:34 +00:00
|
|
|
|
2019-07-02 19:59:15 +00:00
|
|
|
export default Component.extend(WindowResizable, {
|
2019-06-27 19:10:34 +00:00
|
|
|
tagName: 'pre',
|
|
|
|
classNames: ['cli-window'],
|
|
|
|
'data-test-log-cli': true,
|
|
|
|
|
|
|
|
mode: 'streaming', // head, tail, streaming
|
|
|
|
isStreaming: true,
|
|
|
|
logger: null,
|
|
|
|
|
|
|
|
didReceiveAttrs() {
|
|
|
|
if (!this.logger) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
run.scheduleOnce('actions', () => {
|
|
|
|
switch (this.mode) {
|
|
|
|
case 'head':
|
|
|
|
this.head.perform();
|
|
|
|
break;
|
|
|
|
case 'tail':
|
|
|
|
this.tail.perform();
|
|
|
|
break;
|
|
|
|
case 'streaming':
|
|
|
|
if (this.isStreaming) {
|
|
|
|
this.stream.perform();
|
|
|
|
} else {
|
|
|
|
this.logger.stop();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
didInsertElement() {
|
|
|
|
this.fillAvailableHeight();
|
|
|
|
},
|
|
|
|
|
|
|
|
windowResizeHandler() {
|
|
|
|
run.once(this, this.fillAvailableHeight);
|
|
|
|
},
|
|
|
|
|
|
|
|
fillAvailableHeight() {
|
|
|
|
// This math is arbitrary and far from bulletproof, but the UX
|
|
|
|
// of having the log window fill available height is worth the hack.
|
|
|
|
const margins = 30; // Account for padding and margin on either side of the CLI
|
|
|
|
const cliWindow = this.element;
|
|
|
|
cliWindow.style.height = `${window.innerHeight - cliWindow.offsetTop - margins}px`;
|
|
|
|
},
|
|
|
|
|
|
|
|
head: task(function*() {
|
|
|
|
yield this.get('logger.gotoHead').perform();
|
|
|
|
run.scheduleOnce('afterRender', () => {
|
|
|
|
this.element.scrollTop = 0;
|
|
|
|
});
|
|
|
|
}),
|
|
|
|
|
|
|
|
tail: task(function*() {
|
|
|
|
yield this.get('logger.gotoTail').perform();
|
|
|
|
run.scheduleOnce('afterRender', () => {
|
|
|
|
const cliWindow = this.element;
|
|
|
|
cliWindow.scrollTop = cliWindow.scrollHeight;
|
|
|
|
});
|
|
|
|
}),
|
|
|
|
|
|
|
|
synchronizeScrollPosition(force = false) {
|
|
|
|
const cliWindow = this.element;
|
|
|
|
if (cliWindow.scrollHeight - cliWindow.scrollTop < 10 || force) {
|
|
|
|
// If the window is approximately scrolled to the bottom, follow the log
|
|
|
|
cliWindow.scrollTop = cliWindow.scrollHeight;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
stream: task(function*() {
|
|
|
|
// Force the scroll position to the bottom of the window when starting streaming
|
|
|
|
this.logger.one('tick', () => {
|
|
|
|
run.scheduleOnce('afterRender', () => this.synchronizeScrollPosition(true));
|
|
|
|
});
|
|
|
|
|
2019-08-07 22:11:32 +00:00
|
|
|
// Follow the log if the scroll position is near the bottom of the cli window
|
2019-10-08 18:44:19 +00:00
|
|
|
this.logger.on('tick', this, 'scheduleScrollSynchronization');
|
2019-08-07 22:11:32 +00:00
|
|
|
|
2019-06-27 19:10:34 +00:00
|
|
|
yield this.logger.startStreaming();
|
2019-10-08 18:44:19 +00:00
|
|
|
this.logger.off('tick', this, 'scheduleScrollSynchronization');
|
2019-06-27 19:10:34 +00:00
|
|
|
}),
|
|
|
|
|
2019-10-08 18:44:19 +00:00
|
|
|
scheduleScrollSynchronization() {
|
|
|
|
run.scheduleOnce('afterRender', () => this.synchronizeScrollPosition());
|
|
|
|
},
|
|
|
|
|
2019-06-27 19:10:34 +00:00
|
|
|
willDestroy() {
|
|
|
|
this.logger.stop();
|
|
|
|
},
|
|
|
|
});
|