Refactored and image support of the task-file component
This commit is contained in:
parent
29dacd0c2a
commit
f2d31fdf1a
|
@ -13,6 +13,7 @@ export default Component.extend({
|
||||||
allocation: null,
|
allocation: null,
|
||||||
task: null,
|
task: null,
|
||||||
file: null,
|
file: null,
|
||||||
|
stat: null, // { Name, IsDir, Size, FileMode, ModTime, ContentType }
|
||||||
|
|
||||||
// When true, request logs from the server agent
|
// When true, request logs from the server agent
|
||||||
useServer: false,
|
useServer: false,
|
||||||
|
@ -23,49 +24,78 @@ export default Component.extend({
|
||||||
clientTimeout: 1000,
|
clientTimeout: 1000,
|
||||||
serverTimeout: 5000,
|
serverTimeout: 5000,
|
||||||
|
|
||||||
didReceiveAttrs() {
|
mode: 'head',
|
||||||
if (this.allocation && this.task) {
|
|
||||||
// this.send('toggleStream');
|
fileComponent: computed('stat', function() {
|
||||||
|
// TODO: Switch to this.stat.ContentType
|
||||||
|
// TODO: Determine binary/unsupported non-text files to set to "cannot view" component
|
||||||
|
const matches = this.stat.Name.match(/^.+?\.(.+)$/);
|
||||||
|
const ext = matches ? matches[1] : '';
|
||||||
|
|
||||||
|
switch (ext) {
|
||||||
|
case 'jpg':
|
||||||
|
case 'jpeg':
|
||||||
|
case 'gif':
|
||||||
|
case 'png':
|
||||||
|
return 'image';
|
||||||
|
default:
|
||||||
|
return 'stream';
|
||||||
}
|
}
|
||||||
},
|
}),
|
||||||
|
|
||||||
didInsertElement() {
|
isLarge: computed('stat', function() {
|
||||||
this.fillAvailableHeight();
|
return this.stat.Size > 50000;
|
||||||
},
|
}),
|
||||||
|
|
||||||
windowResizeHandler() {
|
isStreamable: computed('stat', function() {
|
||||||
run.once(this, this.fillAvailableHeight);
|
return false;
|
||||||
},
|
return this.stat.ContentType.startsWith('text/');
|
||||||
|
}),
|
||||||
|
|
||||||
fillAvailableHeight() {
|
isStreaming: false,
|
||||||
// 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 + 30; // Account for padding and margin on either side of the CLI
|
|
||||||
const cliWindow = this.$('.cli-window');
|
|
||||||
cliWindow.height(window.innerHeight - cliWindow.offset().top - margins);
|
|
||||||
},
|
|
||||||
|
|
||||||
fileUrl: computed('task.name', 'allocation.id', 'file', function() {
|
catUrl: computed('allocation.id', 'task.name', 'file', function() {
|
||||||
return `/v1/client/fs/cat/${this.allocation.id}?path=${this.task.name}/${this.file}`;
|
return `/v1/client/fs/cat/${this.allocation.id}?path=${this.task.name}/${this.file}`;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
logUrl: computed('allocation.id', 'allocation.node.httpAddr', 'useServer', function() {
|
fetchMode: computed('isLarge', 'mode', function() {
|
||||||
const address = this.get('allocation.node.httpAddr');
|
if (!this.isLarge) {
|
||||||
const allocation = this.get('allocation.id');
|
return 'cat';
|
||||||
|
} else if (this.mode === 'head') {
|
||||||
|
return 'readat';
|
||||||
|
}
|
||||||
|
|
||||||
const url = `/v1/client/fs/logs/${allocation}`;
|
return 'stream';
|
||||||
return this.useServer ? url : `//${address}${url}`;
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
logParams: computed('task', 'mode', function() {
|
fileUrl: computed(
|
||||||
return {
|
'allocation.id',
|
||||||
task: this.task,
|
'allocation.node.httpAddr',
|
||||||
type: this.mode,
|
'fetchMode',
|
||||||
};
|
'useServer',
|
||||||
|
function() {
|
||||||
|
const address = this.get('allocation.node.httpAddr');
|
||||||
|
const url = `/v1/client/fs/${this.fetchMode}/${this.allocation.id}`;
|
||||||
|
return this.useServer ? url : `//${address}${url}`;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
|
||||||
|
fileParams: computed('task.name', 'file', 'mode', function() {
|
||||||
|
const path = `${this.task.name}/${this.file}`;
|
||||||
|
|
||||||
|
switch (this.mode) {
|
||||||
|
case 'head':
|
||||||
|
return { path, offset: 0, limit: 50000 };
|
||||||
|
case 'tail':
|
||||||
|
case 'stream':
|
||||||
|
return { path, offset: 50000, origin: 'end' };
|
||||||
|
default:
|
||||||
|
return { path };
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
logger: logger('logUrl', 'logParams', function logFetch() {
|
logger: logger('fileUrl', 'fileParams', function logFetch() {
|
||||||
// If the log request can't settle in one second, the client
|
// If the file request can't settle in one second, the client
|
||||||
// must be unavailable and the server should be used instead
|
// must be unavailable and the server should be used instead
|
||||||
const timing = this.useServer ? this.serverTimeout : this.clientTimeout;
|
const timing = this.useServer ? this.serverTimeout : this.clientTimeout;
|
||||||
return url =>
|
return url =>
|
||||||
|
@ -83,49 +113,17 @@ export default Component.extend({
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
head: task(function*() {
|
|
||||||
yield this.get('logger.gotoHead').perform();
|
|
||||||
run.scheduleOnce('afterRender', () => {
|
|
||||||
this.$('.cli-window').scrollTop(0);
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
|
|
||||||
tail: task(function*() {
|
|
||||||
yield this.get('logger.gotoTail').perform();
|
|
||||||
run.scheduleOnce('afterRender', () => {
|
|
||||||
const cliWindow = this.$('.cli-window');
|
|
||||||
cliWindow.scrollTop(cliWindow[0].scrollHeight);
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
|
|
||||||
stream: task(function*() {
|
|
||||||
this.logger.on('tick', () => {
|
|
||||||
run.scheduleOnce('afterRender', () => {
|
|
||||||
const cliWindow = this.$('.cli-window');
|
|
||||||
cliWindow.scrollTop(cliWindow[0].scrollHeight);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
yield this.logger.startStreaming();
|
|
||||||
this.logger.off('tick');
|
|
||||||
}),
|
|
||||||
|
|
||||||
willDestroy() {
|
|
||||||
this.logger.stop();
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
setMode(mode) {
|
|
||||||
this.logger.stop();
|
|
||||||
this.set('mode', mode);
|
|
||||||
this.stream.perform();
|
|
||||||
},
|
|
||||||
toggleStream() {
|
toggleStream() {
|
||||||
if (this.get('logger.isStreaming')) {
|
this.toggleProperty('isStreaming');
|
||||||
this.logger.stop();
|
},
|
||||||
} else {
|
gotoHead() {
|
||||||
this.stream.perform();
|
this.set('mode', 'head');
|
||||||
}
|
this.set('isStreaming', false);
|
||||||
|
},
|
||||||
|
gotoTail() {
|
||||||
|
this.set('mode', 'tail');
|
||||||
|
this.set('isStreaming', false);
|
||||||
},
|
},
|
||||||
failoverToServer() {
|
failoverToServer() {
|
||||||
this.set('useServer', true);
|
this.set('useServer', true);
|
||||||
|
|
|
@ -6,19 +6,24 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div class="boxed-section-head">
|
<div class="boxed-section-head">
|
||||||
<span class="pull-right">
|
<span class="pull-right">
|
||||||
<a data-test-log-action="raw" class="button is-white" href="{{fileUrl}}" target="_blank" rel="noopener noreferrer">View Raw File</a>
|
<a data-test-log-action="raw" class="button is-white" href="{{catUrl}}" target="_blank" rel="noopener noreferrer">View Raw File</a>
|
||||||
{{#if isLarge}}
|
{{#if (and isLarge isStreamable)}}
|
||||||
<button data-test-log-action="head" class="button is-white" onclick={{perform head}}>Head</button>
|
<button data-test-log-action="head" class="button is-white" onclick={{action "gotoHead"}}>Head</button>
|
||||||
<button data-test-log-action="tail" class="button is-white" onclick={{perform tail}}>Tail</button>
|
<button data-test-log-action="tail" class="button is-white" onclick={{action "gotoTail"}}>Tail</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if isStreaming}}
|
{{#if isStreamable}}
|
||||||
<button data-test-log-action="toggle-stream" class="button is-white" onclick={{action "toggleStream"}}>
|
<button data-test-log-action="toggle-stream" class="button is-white" onclick={{action "toggleStream"}}>
|
||||||
{{x-icon (if logger.isStreaming "media-pause" "media-play") class="is-text"}}
|
{{x-icon (if logger.isStreaming "media-pause" "media-play") class="is-text"}}
|
||||||
</button>
|
</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div data-test-log-box class="boxed-section-body is-dark is-full-bleed">
|
<div data-test-file-box class="boxed-section-body {{if (eq fileComponent "stream") "is-dark is-full-bleed"}}">
|
||||||
{{!-- switch file component here --}}
|
{{#if (eq fileComponent "stream")}}
|
||||||
<pre data-test-log-cli class="cli-window"><code>{{logger.output}}</code></pre>
|
{{streaming-file logger=logger mode=mode isStreaming=isStreaming}}
|
||||||
|
{{else if (eq fileComponent "image")}}
|
||||||
|
{{image-file src=catUrl alt=stat.Name size=stat.Size}}
|
||||||
|
{{else}}
|
||||||
|
<h1>No component</h1>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue