cyclid-ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +178 -0
- data/README.md +20 -0
- data/app/cyclid_ui.rb +124 -0
- data/app/cyclid_ui/config.rb +64 -0
- data/app/cyclid_ui/controllers/auth.rb +102 -0
- data/app/cyclid_ui/controllers/base.rb +41 -0
- data/app/cyclid_ui/controllers/health.rb +96 -0
- data/app/cyclid_ui/controllers/organization.rb +64 -0
- data/app/cyclid_ui/controllers/user.rb +40 -0
- data/app/cyclid_ui/helpers.rb +55 -0
- data/app/cyclid_ui/memcache.rb +45 -0
- data/app/cyclid_ui/models/user.rb +91 -0
- data/app/cyclid_ui/templates/footer.mustache +8 -0
- data/app/cyclid_ui/templates/job.mustache +21 -0
- data/app/cyclid_ui/templates/job_info.mustache +40 -0
- data/app/cyclid_ui/templates/layout.mustache +102 -0
- data/app/cyclid_ui/templates/login.mustache +78 -0
- data/app/cyclid_ui/templates/organization.mustache +150 -0
- data/app/cyclid_ui/templates/user.mustache +97 -0
- data/app/cyclid_ui/views/job.rb +25 -0
- data/app/cyclid_ui/views/layout.rb +52 -0
- data/app/cyclid_ui/views/login.rb +25 -0
- data/app/cyclid_ui/views/organization.rb +25 -0
- data/app/cyclid_ui/views/user.rb +25 -0
- data/bin/cyclid-ui-assets +17 -0
- data/lib/cyclid_ui/app.rb +4 -0
- data/public/images/LICENSE +3 -0
- data/public/images/cyclid-logo-large.png +0 -0
- data/public/images/favicon16.png +0 -0
- data/public/images/favicon32.png +0 -0
- data/public/images/favicon48.png +0 -0
- data/public/images/favicon64.png +0 -0
- data/public/images/favicon96.png +0 -0
- data/public/js/api.js +34 -0
- data/public/js/cyclid.js +32 -0
- data/public/js/job.js +215 -0
- data/public/js/organization.js +345 -0
- data/public/js/user.js +145 -0
- data/public/vendor/bootstrap/css/bootstrap-theme.css +587 -0
- data/public/vendor/bootstrap/css/bootstrap-theme.css.map +1 -0
- data/public/vendor/bootstrap/css/bootstrap-theme.min.css +6 -0
- data/public/vendor/bootstrap/css/bootstrap-theme.min.css.map +1 -0
- data/public/vendor/bootstrap/css/bootstrap.css +6760 -0
- data/public/vendor/bootstrap/css/bootstrap.css.map +1 -0
- data/public/vendor/bootstrap/css/bootstrap.min.css +6 -0
- data/public/vendor/bootstrap/css/bootstrap.min.css.map +1 -0
- data/public/vendor/bootstrap/css/custom.css +193 -0
- data/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
- data/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.svg +288 -0
- data/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
- data/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.woff2 +0 -0
- data/public/vendor/bootstrap/js/bootstrap.js +2363 -0
- data/public/vendor/bootstrap/js/bootstrap.min.js +7 -0
- data/public/vendor/bootstrap/js/npm.js +13 -0
- data/public/vendor/font-awesome/HELP-US-OUT.txt +7 -0
- data/public/vendor/font-awesome/css/font-awesome.css +2199 -0
- data/public/vendor/font-awesome/css/font-awesome.min.css +4 -0
- data/public/vendor/font-awesome/fonts/FontAwesome.otf +0 -0
- data/public/vendor/font-awesome/fonts/fontawesome-webfont.eot +0 -0
- data/public/vendor/font-awesome/fonts/fontawesome-webfont.svg +685 -0
- data/public/vendor/font-awesome/fonts/fontawesome-webfont.ttf +0 -0
- data/public/vendor/font-awesome/fonts/fontawesome-webfont.woff +0 -0
- data/public/vendor/font-awesome/fonts/fontawesome-webfont.woff2 +0 -0
- data/public/vendor/font-awesome/less/animated.less +34 -0
- data/public/vendor/font-awesome/less/bordered-pulled.less +25 -0
- data/public/vendor/font-awesome/less/core.less +12 -0
- data/public/vendor/font-awesome/less/fixed-width.less +6 -0
- data/public/vendor/font-awesome/less/font-awesome.less +18 -0
- data/public/vendor/font-awesome/less/icons.less +733 -0
- data/public/vendor/font-awesome/less/larger.less +13 -0
- data/public/vendor/font-awesome/less/list.less +19 -0
- data/public/vendor/font-awesome/less/mixins.less +60 -0
- data/public/vendor/font-awesome/less/path.less +15 -0
- data/public/vendor/font-awesome/less/rotated-flipped.less +20 -0
- data/public/vendor/font-awesome/less/screen-reader.less +5 -0
- data/public/vendor/font-awesome/less/stacked.less +20 -0
- data/public/vendor/font-awesome/less/variables.less +744 -0
- data/public/vendor/font-awesome/scss/_animated.scss +34 -0
- data/public/vendor/font-awesome/scss/_bordered-pulled.scss +25 -0
- data/public/vendor/font-awesome/scss/_core.scss +12 -0
- data/public/vendor/font-awesome/scss/_fixed-width.scss +6 -0
- data/public/vendor/font-awesome/scss/_icons.scss +733 -0
- data/public/vendor/font-awesome/scss/_larger.scss +13 -0
- data/public/vendor/font-awesome/scss/_list.scss +19 -0
- data/public/vendor/font-awesome/scss/_mixins.scss +60 -0
- data/public/vendor/font-awesome/scss/_path.scss +15 -0
- data/public/vendor/font-awesome/scss/_rotated-flipped.scss +20 -0
- data/public/vendor/font-awesome/scss/_screen-reader.scss +5 -0
- data/public/vendor/font-awesome/scss/_stacked.scss +20 -0
- data/public/vendor/font-awesome/scss/_variables.scss +744 -0
- data/public/vendor/font-awesome/scss/font-awesome.scss +18 -0
- data/public/vendor/jquery-2.2.4.min.js +4 -0
- data/public/vendor/jquery.md5.js +269 -0
- data/public/vendor/js.cookie.js +151 -0
- data/public/vendor/mustache.min.js +1 -0
- metadata +322 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
module Cyclid
|
17
|
+
module UI
|
18
|
+
module Views
|
19
|
+
# Job view
|
20
|
+
class Job < Layout
|
21
|
+
attr_reader :job_url, :job_id
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require 'digest/md5'
|
17
|
+
|
18
|
+
module Cyclid
|
19
|
+
module UI
|
20
|
+
module Views
|
21
|
+
# Main Layout view; everything common to the Views which use Layouts can
|
22
|
+
# be found here
|
23
|
+
class Layout < Mustache
|
24
|
+
attr_reader :organization, :api_url, :linkback_url
|
25
|
+
|
26
|
+
def username
|
27
|
+
@current_user.username || 'Nobody'
|
28
|
+
end
|
29
|
+
|
30
|
+
def organizations
|
31
|
+
@current_user.organizations
|
32
|
+
end
|
33
|
+
|
34
|
+
def title
|
35
|
+
@title || 'Cyclid'
|
36
|
+
end
|
37
|
+
|
38
|
+
# Return an array of elements to be inserted into the breadcrumb
|
39
|
+
def breadcrumbs
|
40
|
+
@crumbs.to_json
|
41
|
+
end
|
42
|
+
|
43
|
+
# Calculate the base Gravatar URL for the user
|
44
|
+
def gravatar_url
|
45
|
+
email = @current_user.email.downcase.strip
|
46
|
+
hash = Digest::MD5.hexdigest(email)
|
47
|
+
"https://www.gravatar.com/avatar/#{hash}?d=identicon&r=g"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
module Cyclid
|
17
|
+
module UI
|
18
|
+
module Views
|
19
|
+
# Login view. This is a non-Layout view.
|
20
|
+
class Login < Mustache
|
21
|
+
attr_reader :message
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
module Cyclid
|
17
|
+
module UI
|
18
|
+
module Views
|
19
|
+
# Organization view
|
20
|
+
class Organization < Layout
|
21
|
+
attr_reader :organization_url
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
module Cyclid
|
17
|
+
module UI
|
18
|
+
module Views
|
19
|
+
# User profile view
|
20
|
+
class User < Layout
|
21
|
+
attr_reader :user_url
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
# Copyright 2016 Liqwyd Ltd.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
puts File.expand_path('../../public', __FILE__)
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/public/js/api.js
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
// Perform an authenticated GET to the API server.
|
2
|
+
function api_get(url, username, success, error) {
|
3
|
+
$.ajax({
|
4
|
+
type: 'GET',
|
5
|
+
url: encodeURI(url),
|
6
|
+
dataType: 'json',
|
7
|
+
crossDomain: true,
|
8
|
+
beforeSend: function(xhr) {
|
9
|
+
var token = Cookies.get('cyclid.token');
|
10
|
+
var authorization = `Token ${username}:${token}`
|
11
|
+
xhr.setRequestHeader('Authorization', authorization);
|
12
|
+
},
|
13
|
+
success: success,
|
14
|
+
error: error
|
15
|
+
});
|
16
|
+
}
|
17
|
+
|
18
|
+
// Perform an authenticated PUT to the API server.
|
19
|
+
function api_put(url, data, username, success, error) {
|
20
|
+
$.ajax({
|
21
|
+
type: 'PUT',
|
22
|
+
url: encodeURI(url),
|
23
|
+
data: JSON.stringify(data),
|
24
|
+
contentType: 'application/json',
|
25
|
+
crossDomain: true,
|
26
|
+
beforeSend: function(xhr) {
|
27
|
+
var token = Cookies.get('cyclid.token');
|
28
|
+
var authorization = `Token ${username}:${token}`
|
29
|
+
xhr.setRequestHeader('Authorization', authorization);
|
30
|
+
},
|
31
|
+
success: success,
|
32
|
+
error: error
|
33
|
+
});
|
34
|
+
}
|
data/public/js/cyclid.js
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
// Create an interval and store the handle with a key
|
2
|
+
function addNamedInterval(name, func, interval) {
|
3
|
+
if( window.timers == undefined ){
|
4
|
+
console.log('initializing window.timers');
|
5
|
+
window.timers = {};
|
6
|
+
}
|
7
|
+
|
8
|
+
if( window.timers[name] == null ) {
|
9
|
+
var interval = setInterval(func, interval);
|
10
|
+
console.log(`setting interval ${interval} as ${name}`);
|
11
|
+
window.timers[name] = interval;
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
// Remove a named interval previously created with addNamedInterval
|
16
|
+
function removeNamedInterval(name) {
|
17
|
+
var interval = window.timers[name];
|
18
|
+
|
19
|
+
if( interval != undefined ) {
|
20
|
+
console.log(`clearing interval ${interval} for ${name}`);
|
21
|
+
clearInterval(interval);
|
22
|
+
}
|
23
|
+
window.timers[name] = null;
|
24
|
+
}
|
25
|
+
|
26
|
+
// Remove all named intervals previously created with addNamedInterval
|
27
|
+
function clearAllNamedIntervals() {
|
28
|
+
for(var timer in window.timers){
|
29
|
+
console.log(`removing ${timer}`);
|
30
|
+
removeNamedInterval(timer);
|
31
|
+
}
|
32
|
+
}
|
data/public/js/job.js
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
// Convert a Cyclid job status code to a human readable status
|
2
|
+
function ji_job_status_to_human(status_id) {
|
3
|
+
var statuses = {0: 'New',
|
4
|
+
1: 'Waiting',
|
5
|
+
2: 'Started',
|
6
|
+
3: 'Failing',
|
7
|
+
10: 'Succeeded',
|
8
|
+
11: 'Failed'};
|
9
|
+
var status = statuses[status_id];
|
10
|
+
|
11
|
+
var glyphs = {0: 'glyphicon-share-alt',
|
12
|
+
1: 'glyphicon-time',
|
13
|
+
2: 'glyphicon-refresh',
|
14
|
+
3: 'glyphicon-alert',
|
15
|
+
10: 'glyphicon-ok',
|
16
|
+
11: 'glyphicon-remove'};
|
17
|
+
var glyph = glyphs[status_id];
|
18
|
+
|
19
|
+
var labels = {0: 'label-primary',
|
20
|
+
1: 'label-primary',
|
21
|
+
2: 'label-info',
|
22
|
+
3: 'label-warning',
|
23
|
+
10: 'label-success',
|
24
|
+
11: 'label-danger'};
|
25
|
+
var label = labels[status_id];
|
26
|
+
|
27
|
+
return `<span class="label ${label}">
|
28
|
+
<span class="glyphicon ${glyph}" aria-hidden="true"></span> ${status}
|
29
|
+
</span>`
|
30
|
+
}
|
31
|
+
|
32
|
+
// Convert a Cyclid job status code to an indicator
|
33
|
+
function ji_job_status_to_indicator(status_id) {
|
34
|
+
var statuses = {0: 'New',
|
35
|
+
1: 'Waiting',
|
36
|
+
2: 'Started',
|
37
|
+
3: 'Failing',
|
38
|
+
10: 'Succeeded',
|
39
|
+
11: 'Failed'};
|
40
|
+
var status = statuses[status_id];
|
41
|
+
|
42
|
+
var glyphs = {0: 'glyphicon-share-alt',
|
43
|
+
1: 'glyphicon-time',
|
44
|
+
2: 'glyphicon-refresh',
|
45
|
+
3: 'glyphicon-alert',
|
46
|
+
10: 'glyphicon-ok',
|
47
|
+
11: 'glyphicon-remove'};
|
48
|
+
var glyph = glyphs[status_id];
|
49
|
+
|
50
|
+
var labels = {0: 'label-primary',
|
51
|
+
1: 'label-primary',
|
52
|
+
2: 'label-info',
|
53
|
+
3: 'label-warning',
|
54
|
+
10: 'label-success',
|
55
|
+
11: 'label-danger'};
|
56
|
+
var label = labels[status_id];
|
57
|
+
|
58
|
+
return `<span class="label ${label}">
|
59
|
+
<span class="glyphicon ${glyph}" aria-hidden="true" title="${status}"></span>
|
60
|
+
</span>`
|
61
|
+
}
|
62
|
+
|
63
|
+
function ji_calculate_duration(started, ended) {
|
64
|
+
var date_started = new Date(started);
|
65
|
+
var date_ended = new Date(ended);
|
66
|
+
|
67
|
+
var duration = '';
|
68
|
+
if( date_ended > 0 ){
|
69
|
+
duration = new Date(date_ended.getTime() - date_started.getTime()).toISOString().substr(11, 8);
|
70
|
+
}
|
71
|
+
|
72
|
+
return duration;
|
73
|
+
}
|
74
|
+
|
75
|
+
// Set & show the job log element
|
76
|
+
function ji_update_log(log_text) {
|
77
|
+
// Show the log
|
78
|
+
var outer = $('#ji_log_outer');
|
79
|
+
outer.removeClass('hidden');
|
80
|
+
|
81
|
+
// Find the current position of the scrollable element, before we update it
|
82
|
+
var inner = $('#ji_log_inner')
|
83
|
+
var diff = inner.prop('scrollHeight') - (inner.scrollTop() + inner.outerHeight());
|
84
|
+
|
85
|
+
// Update the log
|
86
|
+
inner.html(log_text);
|
87
|
+
|
88
|
+
// If the user hasn't scrolled up, scroll to the bottom to show the new log data
|
89
|
+
if( diff <= 0 )
|
90
|
+
inner.scrollTop(inner.prop('scrollHeight'));
|
91
|
+
}
|
92
|
+
|
93
|
+
// Is the job in a "Failed" or "Succeeded" state?
|
94
|
+
function ji_job_finished(job_status) {
|
95
|
+
if( job_status == 10 || job_status == 11 ) {
|
96
|
+
return true;
|
97
|
+
} else {
|
98
|
+
return false;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
// Is the job still active?
|
103
|
+
function ji_job_active(job_status) {
|
104
|
+
return !ji_job_finished(job_status);
|
105
|
+
}
|
106
|
+
|
107
|
+
function ji_update_status(job) {
|
108
|
+
var status = ji_job_status_to_human(job.status)
|
109
|
+
$('#ji_job_status').html(status);
|
110
|
+
$('#ji_job_status').data('status', job.status);
|
111
|
+
|
112
|
+
// Update the "Waiting" message appropriately
|
113
|
+
var waiting = '<h6>Unknown</h6>';
|
114
|
+
switch(job.status) {
|
115
|
+
case 1:
|
116
|
+
case 2:
|
117
|
+
waiting = '<h6><i class="fa fa-spinner fa-pulse"></i> Waiting for job to start...</h6>'
|
118
|
+
$('#ji_job_waiting').html(waiting);
|
119
|
+
$('#ji_job_waiting').removeClass('hidden');
|
120
|
+
break;
|
121
|
+
case 3:
|
122
|
+
case 4:
|
123
|
+
waiting = '<h6><i class="fa fa-cog fa-spin"></i> Waiting for job to complete...</h6>';
|
124
|
+
$('#ji_job_waiting').html(waiting);
|
125
|
+
$('#ji_job_waiting').removeClass('hidden');
|
126
|
+
break;
|
127
|
+
case 10:
|
128
|
+
case 11:
|
129
|
+
$('#ji_job_waiting').addClass('hidden');
|
130
|
+
break;
|
131
|
+
}
|
132
|
+
|
133
|
+
// Update the status indicator, if there is one
|
134
|
+
var indicator = ji_job_status_to_indicator(job.status);
|
135
|
+
$(`#row${job.job_id} > #status`).html(indicator);
|
136
|
+
}
|
137
|
+
|
138
|
+
// Set & show the job details
|
139
|
+
function ji_update_details(job) {
|
140
|
+
var title = `<a href="${gblLinkbackURL}/job/${job.id}">${job.job_name} <small>v${job.job_version}</small></a>`;
|
141
|
+
$('#ji_header').html(title);
|
142
|
+
|
143
|
+
$('#ji_job_id').text(job.id);
|
144
|
+
|
145
|
+
if (job.started) {
|
146
|
+
var started = new Date(job.started);
|
147
|
+
$('#ji_job_started').text(started.toUTCString());
|
148
|
+
}
|
149
|
+
|
150
|
+
if (job.ended) {
|
151
|
+
var ended = new Date(job.ended);
|
152
|
+
$('#ji_job_ended').text(ended.toUTCString());
|
153
|
+
}
|
154
|
+
|
155
|
+
var duration = ji_calculate_duration(job.started, job.ended);
|
156
|
+
$('#ji_job_duration').text(duration);
|
157
|
+
|
158
|
+
$('#ji_details').removeClass('hidden');
|
159
|
+
}
|
160
|
+
|
161
|
+
// Update everything: job details, status & log
|
162
|
+
function ji_update_all(job) {
|
163
|
+
ji_update_details(job);
|
164
|
+
ji_update_status(job);
|
165
|
+
ji_update_log(job.log);
|
166
|
+
}
|
167
|
+
|
168
|
+
function ji_get_failed(xhr) {
|
169
|
+
var failure_message = `<p>
|
170
|
+
<h2>Failed to retrieve job</h2><br>
|
171
|
+
<strong>${xhr.status}:</strong> ${xhr.responseText}
|
172
|
+
</p>`
|
173
|
+
$('#ji_failure > #error_message').html(failure_message);
|
174
|
+
|
175
|
+
$('#ji_failure').removeClass('hidden');
|
176
|
+
}
|
177
|
+
|
178
|
+
function ji_update_status_and_check_completion(url, job) {
|
179
|
+
var last_status = $('#ji_job_status').data('status');
|
180
|
+
if( job.status != last_status ) {
|
181
|
+
ji_update_status(job);
|
182
|
+
}
|
183
|
+
|
184
|
+
// Did the job end?
|
185
|
+
if( ji_job_finished(job.status) ){
|
186
|
+
console.log(`job #${job.job_id} ended`);
|
187
|
+
|
188
|
+
// Update the job details so that E.g. the "Ended" time is shown
|
189
|
+
api_get(url, gblUsername, ji_update_details, ji_get_failed);
|
190
|
+
|
191
|
+
// Find any timer associated with the job info & remove it
|
192
|
+
removeNamedInterval(`watcher${job.job_id}`);
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
function ji_watch_job(url) {
|
197
|
+
console.log(`ji_watch_job(${url})`);
|
198
|
+
|
199
|
+
// Check job status
|
200
|
+
var status_url = `${url}/status`;
|
201
|
+
console.log(`updating status from ${status_url}`);
|
202
|
+
api_get(status_url,
|
203
|
+
gblUsername,
|
204
|
+
function(job) {
|
205
|
+
ji_update_status_and_check_completion(url, job);
|
206
|
+
},
|
207
|
+
ji_get_failed);
|
208
|
+
|
209
|
+
// Update log
|
210
|
+
var log_url = `${url}/log`;
|
211
|
+
console.log(`updating log from ${log_url}`);
|
212
|
+
api_get(log_url, gblUsername, function(data) { ji_update_log(data.log); }, ji_get_failed);
|
213
|
+
|
214
|
+
console.log(`ji_watch_job(${url}) finished`);
|
215
|
+
}
|