canvas_sync 0.17.17.beta1 → 0.17.18
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 +4 -4
- data/lib/canvas_sync/job_batches/batch.rb +9 -0
- data/lib/canvas_sync/job_batches/chain_builder.rb +8 -0
- data/lib/canvas_sync/job_batches/hier_batch_ids.lua +25 -0
- data/lib/canvas_sync/job_batches/sidekiq/web.rb +93 -0
- data/lib/canvas_sync/job_batches/sidekiq/web/batches_assets/css/styles.less +178 -0
- data/lib/canvas_sync/job_batches/sidekiq/web/batches_assets/js/batch_tree.js +106 -0
- data/lib/canvas_sync/job_batches/sidekiq/web/batches_assets/js/util.js +2 -0
- data/lib/canvas_sync/job_batches/sidekiq/web/views/_batch_tree.erb +6 -0
- data/lib/canvas_sync/job_batches/sidekiq/web/views/_common.erb +13 -0
- data/lib/canvas_sync/job_batches/sidekiq/web/views/batch.erb +15 -88
- data/lib/canvas_sync/version.rb +1 -1
- metadata +11 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 30e1a16308bbc8795dc671c19f35d29577665213261829d3180a9efeefab4adf
|
4
|
+
data.tar.gz: bade0d8907b22bf252b85ba4067798ebd3b6582deed06adfccf7a8951a6164b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a155b415154694a42c218bd5ef91f21ca7cdcc81967cc2f2c16a180eebfb32d1b279c72ea2eab58beaabb8e8a8905fe4ef4086ce758c9ee14b1583eccf06849
|
7
|
+
data.tar.gz: 3269c39188c086e7b3b03d6280414fbdc7a32c6780af5744da08f3f9432f4eb5ed993c3af4d22e2fe477d92ca8e4d705c62ba9e9005559a9e1145922f565aa4f
|
@@ -28,6 +28,7 @@ module CanvasSync
|
|
28
28
|
|
29
29
|
BID_EXPIRE_TTL = 2_592_000
|
30
30
|
SCHEDULE_CALLBACK = RedisScript.new(Pathname.new(__FILE__) + "../schedule_callback.lua")
|
31
|
+
BID_HIERARCHY = RedisScript.new(Pathname.new(__FILE__) + "../hier_batch_ids.lua")
|
31
32
|
|
32
33
|
attr_reader :bid
|
33
34
|
|
@@ -423,6 +424,14 @@ module CanvasSync
|
|
423
424
|
def push_callbacks(args, queue)
|
424
425
|
Batch::Callback::worker_class.enqueue_all(args, queue)
|
425
426
|
end
|
427
|
+
|
428
|
+
def bid_hierarchy(bid, depth: 4, per_depth: 5, slice: nil)
|
429
|
+
args = [bid, depth, per_depth]
|
430
|
+
args << slice if slice
|
431
|
+
redis do |r|
|
432
|
+
BID_HIERARCHY.call(r, [], args)
|
433
|
+
end
|
434
|
+
end
|
426
435
|
end
|
427
436
|
end
|
428
437
|
|
@@ -172,6 +172,14 @@ module CanvasSync
|
|
172
172
|
mapper[key] ||= []
|
173
173
|
end
|
174
174
|
|
175
|
+
# TODO: Add a Chain progress web View
|
176
|
+
# Augment Batch tree-view with Chain data
|
177
|
+
# > [DONE] Tree view w/o Chain will only show Parent/Current batches and Job Counts
|
178
|
+
# > If augmented with Chain data, the above will be annotated with Chain-related info and will be able to show Jobs defined in the Chain
|
179
|
+
# > Chain-jobs will be supplied chain_id and chain_step_id metadata
|
180
|
+
# > Using server-middleware, if a Chain-job (has chain_id and chain_step_id) creates a Batch, tag the Batch w/ the chain_id and chain_step_id
|
181
|
+
# > UI will map Batches to Chain-steps using the chain_step_id. UI will add entries for any Chain-steps that were not tied to a Batch
|
182
|
+
# > [DONE] Use a Lua script to find child batch IDs. Support max_depth, items_per_depth, top_depth_slice parameters
|
175
183
|
def enqueue_job(job_def)
|
176
184
|
job_class = job_def[:job].constantize
|
177
185
|
job_options = job_def[:parameters] || []
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
local function add_bids(root, depth)
|
3
|
+
local result_data = {}
|
4
|
+
|
5
|
+
if depth > 0 then
|
6
|
+
local sbids
|
7
|
+
if depth == tonumber(ARGV[2]) and ARGV[4] then
|
8
|
+
local min, max = ARGV[4]:match('(%d+):(%d+)')
|
9
|
+
sbids = redis.call('ZRANGE', 'BID-' .. root .. '-bids', min, max)
|
10
|
+
else
|
11
|
+
sbids = redis.call('ZRANGE', 'BID-' .. root .. '-bids', 0, tonumber(ARGV[3]) - 1)
|
12
|
+
end
|
13
|
+
|
14
|
+
local sub_data = {}
|
15
|
+
for _,v in ipairs(sbids) do
|
16
|
+
table.insert(sub_data, add_bids(v, depth - 1))
|
17
|
+
end
|
18
|
+
|
19
|
+
return { root, sub_data }
|
20
|
+
end
|
21
|
+
|
22
|
+
return { root, result_data}
|
23
|
+
end
|
24
|
+
|
25
|
+
return add_bids(ARGV[1], tonumber(ARGV[2]))
|
@@ -9,11 +9,19 @@ require_relative "web/helpers"
|
|
9
9
|
|
10
10
|
module CanvasSync::JobBatches::Sidekiq
|
11
11
|
module Web
|
12
|
+
DEV_MODE = (defined?(Rails) && !Rails.env.production?) || !!ENV["SIDEKIQ_WEB_TESTING"]
|
13
|
+
|
12
14
|
def self.registered(app) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
13
15
|
app.helpers do
|
14
16
|
include Web::Helpers
|
17
|
+
|
18
|
+
def dev_mode?
|
19
|
+
DEV_MODE
|
20
|
+
end
|
15
21
|
end
|
16
22
|
|
23
|
+
# =============== BATCHES =============== #
|
24
|
+
|
17
25
|
app.get "/batches" do
|
18
26
|
@count = (params['count'] || 25).to_i
|
19
27
|
@current_page, @total_size, @batches = page('batches', params['page'], @count)
|
@@ -26,6 +34,8 @@ module CanvasSync::JobBatches::Sidekiq
|
|
26
34
|
@bid = params[:bid]
|
27
35
|
@batch = CanvasSync::JobBatches::Batch.new(@bid)
|
28
36
|
|
37
|
+
@tree_data = tree_data(@bid)
|
38
|
+
|
29
39
|
@count = (params['count'] || 25).to_i
|
30
40
|
@current_batches_page, @total_batches_size, @sub_batches = page("BID-#{@batch.bid}-bids", params['batch_page'], @count)
|
31
41
|
@sub_batches = @sub_batches.map {|b, score| CanvasSync::JobBatches::Batch.new(b) }
|
@@ -36,6 +46,81 @@ module CanvasSync::JobBatches::Sidekiq
|
|
36
46
|
erb(get_template(:batch))
|
37
47
|
end
|
38
48
|
|
49
|
+
app.get "/batches/:bid/tree" do
|
50
|
+
@bid = params[:bid]
|
51
|
+
|
52
|
+
json(tree_data(@bid, slice: params[:slice]))
|
53
|
+
end
|
54
|
+
|
55
|
+
app.helpers do
|
56
|
+
def tree_data(root_bid, slice: nil)
|
57
|
+
tree_bids = CanvasSync::JobBatches::Batch.bid_hierarchy(root_bid, slice: slice)
|
58
|
+
|
59
|
+
CanvasSync::JobBatches::Batch.redis do |r|
|
60
|
+
layer_data = ->(layer, parent = nil) {
|
61
|
+
bid = layer[0]
|
62
|
+
batch = CanvasSync::JobBatches::Batch.new(bid)
|
63
|
+
|
64
|
+
jobs_total = r.hget("BID-#{bid}", "job_count").to_i
|
65
|
+
jobs_pending = r.hget("BID-#{bid}", 'pending').to_i
|
66
|
+
jobs_failed = r.scard("BID-#{bid}-failed").to_i
|
67
|
+
jobs_success = jobs_total - jobs_pending
|
68
|
+
|
69
|
+
batches_total = r.hget("BID-#{bid}", 'children').to_i
|
70
|
+
batches_success = r.scard("BID-#{bid}-batches-success").to_i
|
71
|
+
batches_pending = batches_total - batches_success
|
72
|
+
batches_failed = r.scard("BID-#{bid}-batches-failed").to_i
|
73
|
+
|
74
|
+
status = 'in_progress'
|
75
|
+
status = 'complete' if batches_pending == batches_failed && jobs_pending == jobs_failed
|
76
|
+
status = 'success' if batches_pending == 0 && jobs_pending == 0
|
77
|
+
status = 'deleted' if bid != root_bid && !batch.parent_bid
|
78
|
+
|
79
|
+
{
|
80
|
+
bid: bid,
|
81
|
+
created_at: r.hget("BID-#{bid}", 'created_at'),
|
82
|
+
status: status,
|
83
|
+
parent_bid: parent ? parent.bid : batch.parent_bid,
|
84
|
+
description: batch.description,
|
85
|
+
jobs: {
|
86
|
+
pending_count: jobs_pending,
|
87
|
+
successful_count: jobs_success,
|
88
|
+
failed_count: jobs_failed,
|
89
|
+
total_count: jobs_total,
|
90
|
+
# items: batches.map{|b| layer_data[b] },
|
91
|
+
},
|
92
|
+
batches: {
|
93
|
+
pending_count: batches_pending,
|
94
|
+
successful_count: batches_success,
|
95
|
+
failed_count: batches_failed,
|
96
|
+
total_count: batches_total,
|
97
|
+
items: layer[1].map{|b| layer_data[b, batch] },
|
98
|
+
},
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
data = layer_data[tree_bids]
|
103
|
+
data[:batches][:slice] = slice if slice
|
104
|
+
data
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def format_context(batch)
|
109
|
+
bits = []
|
110
|
+
own_keys = batch.context.own.keys
|
111
|
+
batch.context.flatten.each do |k,v|
|
112
|
+
added = own_keys.include? k
|
113
|
+
bits << " <span class=\"key #{added ? 'own' : 'inherited'}\">\"#{k}\": #{v.to_json},</span>"
|
114
|
+
end
|
115
|
+
bits = [
|
116
|
+
"{ // <span class=\"own\">Added</span> / <span class=\"inherited\">Inherited</span>",
|
117
|
+
*bits,
|
118
|
+
'}'
|
119
|
+
]
|
120
|
+
bits.join("\n")
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
39
124
|
app.post "/batches/all" do
|
40
125
|
if params['delete']
|
41
126
|
drain_zset('batches') do |batches|
|
@@ -107,6 +192,14 @@ module CanvasSync::JobBatches::Sidekiq
|
|
107
192
|
end
|
108
193
|
|
109
194
|
if defined?(::Sidekiq::Web)
|
195
|
+
rules = []
|
196
|
+
rules = [[:all, {"Cache-Control" => "public, max-age=86400"}]] unless CanvasSync::JobBatches::Sidekiq::Web::DEV_MODE
|
197
|
+
|
198
|
+
::Sidekiq::Web.use Rack::Static, urls: ["/batches_assets"],
|
199
|
+
root: File.expand_path("#{File.dirname(__FILE__)}/web"),
|
200
|
+
cascade: true,
|
201
|
+
header_rules: rules
|
202
|
+
|
110
203
|
::Sidekiq::Web.register CanvasSync::JobBatches::Sidekiq::Web
|
111
204
|
::Sidekiq::Web.tabs["Batches"] = "batches"
|
112
205
|
::Sidekiq::Web.tabs["Pools"] = "pools"
|
@@ -0,0 +1,178 @@
|
|
1
|
+
|
2
|
+
@color-green: #25c766;
|
3
|
+
@color-red: #c7254e;
|
4
|
+
@color-yellow: #c4c725;
|
5
|
+
|
6
|
+
.code-wrap.batch-context .args-extended {
|
7
|
+
white-space: pre;
|
8
|
+
|
9
|
+
.key {
|
10
|
+
white-space: pre-wrap;
|
11
|
+
margin-left: 2em;
|
12
|
+
text-indent: -2em;
|
13
|
+
display: inline-block;
|
14
|
+
}
|
15
|
+
|
16
|
+
.own {
|
17
|
+
color: @color-green;
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
|
22
|
+
.batch-tree {
|
23
|
+
.status-block {
|
24
|
+
.tree-stat {
|
25
|
+
margin: 0 4px;
|
26
|
+
|
27
|
+
&.pending {
|
28
|
+
color: @color-yellow;
|
29
|
+
}
|
30
|
+
&.failed {
|
31
|
+
color: @color-red;
|
32
|
+
}
|
33
|
+
&.success {
|
34
|
+
color: @color-green;
|
35
|
+
}
|
36
|
+
&.total {
|
37
|
+
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
.text-inactive {
|
43
|
+
color: darken(#fff, 35%);
|
44
|
+
font-size: 80%;
|
45
|
+
}
|
46
|
+
|
47
|
+
.tree-header {
|
48
|
+
position: relative;
|
49
|
+
|
50
|
+
.status-block {
|
51
|
+
position: absolute;
|
52
|
+
bottom: 0;
|
53
|
+
width: 100%;
|
54
|
+
|
55
|
+
margin-right: 8px;
|
56
|
+
font-size: 90%;
|
57
|
+
text-align: right;
|
58
|
+
|
59
|
+
.tree-stat {
|
60
|
+
font-style: italic;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
.tree-entry {
|
66
|
+
> .header {
|
67
|
+
display: flex;
|
68
|
+
align-items: center;
|
69
|
+
|
70
|
+
.header-inner {
|
71
|
+
padding: 4px 0;
|
72
|
+
border-bottom: 1px dashed white;
|
73
|
+
display: flex;
|
74
|
+
align-items: center;
|
75
|
+
flex: 1;
|
76
|
+
}
|
77
|
+
|
78
|
+
&:hover {
|
79
|
+
background-color: rgba(0,0,0,0.20);
|
80
|
+
border-radius: 3px;
|
81
|
+
}
|
82
|
+
|
83
|
+
.row-toggle {
|
84
|
+
width: 16px;
|
85
|
+
height: 16px;
|
86
|
+
text-align: center;
|
87
|
+
align-self: center;
|
88
|
+
border-radius: 50%;
|
89
|
+
border: 1px solid #999;
|
90
|
+
text-decoration: none;
|
91
|
+
margin: 0 4px;
|
92
|
+
font-size: 16px;
|
93
|
+
line-height: 15px;
|
94
|
+
|
95
|
+
&.not_applicable {
|
96
|
+
opacity: 0;
|
97
|
+
pointer-events: none;
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
.main {
|
102
|
+
flex: 1;
|
103
|
+
display: flex;
|
104
|
+
align-items: baseline;
|
105
|
+
|
106
|
+
.bid {
|
107
|
+
font-family: monospace;
|
108
|
+
padding: 3px 6px;
|
109
|
+
background: rgba(0,0,0,0.2);
|
110
|
+
border-radius: 3px;
|
111
|
+
font-size: 12px;
|
112
|
+
margin: 0 12px 0 0;
|
113
|
+
|
114
|
+
&:hover {
|
115
|
+
.bid-goto {
|
116
|
+
display: inline-block;
|
117
|
+
padding: 0 0 0 4px;
|
118
|
+
font-size: 200%;
|
119
|
+
line-height: 10px;
|
120
|
+
vertical-align: sub;
|
121
|
+
text-decoration: dotted;
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
.bid-goto {
|
126
|
+
display: none;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
.goto-link {
|
132
|
+
margin: 0 8px;
|
133
|
+
display: inline-block;
|
134
|
+
height: 16px;
|
135
|
+
font-size: 90%;
|
136
|
+
border-bottom: 1px dotted white;
|
137
|
+
}
|
138
|
+
|
139
|
+
.status-label {
|
140
|
+
font-family: monospace;
|
141
|
+
padding: 3px 6px;
|
142
|
+
background: rgba(0,0,0,0.2);
|
143
|
+
border-radius: 3px;
|
144
|
+
font-size: 12px;
|
145
|
+
margin: 0 12px 0 0;
|
146
|
+
|
147
|
+
&.deleted {
|
148
|
+
background: #99999933;
|
149
|
+
}
|
150
|
+
&.failed, &.complete {
|
151
|
+
background: #99000033;
|
152
|
+
}
|
153
|
+
&.success {
|
154
|
+
background: #00990033;
|
155
|
+
}
|
156
|
+
}
|
157
|
+
|
158
|
+
.status-block {
|
159
|
+
width: 10em;
|
160
|
+
text-align: center;
|
161
|
+
}
|
162
|
+
}
|
163
|
+
|
164
|
+
> .subitems {
|
165
|
+
padding-left: 16px;
|
166
|
+
|
167
|
+
>.load-more {
|
168
|
+
padding: 4px 0;
|
169
|
+
text-align: center;
|
170
|
+
border-bottom: 1px dashed white;
|
171
|
+
a {
|
172
|
+
border-bottom: 1px dotted white;
|
173
|
+
text-decoration: none;
|
174
|
+
}
|
175
|
+
}
|
176
|
+
}
|
177
|
+
}
|
178
|
+
}
|
@@ -0,0 +1,106 @@
|
|
1
|
+
import { h, Component, render } from 'https://unpkg.com/preact?module';
|
2
|
+
import htm from 'https://unpkg.com/htm?module';
|
3
|
+
import { root_url } from './util.js';
|
4
|
+
|
5
|
+
// Initialize htm with Preact
|
6
|
+
const html = htm.bind(h);
|
7
|
+
|
8
|
+
const StatusBlock = (props) => html`
|
9
|
+
<div class="status-block ${props.class || ''}">
|
10
|
+
${props.title && props.title + ':'}
|
11
|
+
<span class="tree-stat pending">${props.pending_count}</span>
|
12
|
+
|
|
13
|
+
<span class="tree-stat failed">${props.failed_count}</span>
|
14
|
+
|
|
15
|
+
<span class="tree-stat success">${props.successful_count}</span>
|
16
|
+
/
|
17
|
+
<span class="tree-stat total">${props.total_count}</span>
|
18
|
+
</div>
|
19
|
+
`
|
20
|
+
|
21
|
+
class TreeLevel extends Component {
|
22
|
+
get bid() {
|
23
|
+
return this.props.data.bid;
|
24
|
+
}
|
25
|
+
|
26
|
+
get batch() {
|
27
|
+
return this.props.data;
|
28
|
+
}
|
29
|
+
|
30
|
+
load_more = async (event) => {
|
31
|
+
event.preventDefault();
|
32
|
+
const l = this.batch.batches.items.length;
|
33
|
+
const resp = await fetch(`${root_url}batches/${this.bid}/tree?slice=${l}:${l + 5 - 1}`)
|
34
|
+
const result = await resp.json()
|
35
|
+
const newEntries = result.batches.items;
|
36
|
+
for (let ent of newEntries) {
|
37
|
+
this.batch.batches.items.push(ent)
|
38
|
+
}
|
39
|
+
this.forceUpdate()
|
40
|
+
}
|
41
|
+
|
42
|
+
toggle = (event) => {
|
43
|
+
event.preventDefault();
|
44
|
+
this.setState({ collapsed: !this.state.collapsed })
|
45
|
+
}
|
46
|
+
|
47
|
+
render() {
|
48
|
+
const { data: bd } = this.props;
|
49
|
+
|
50
|
+
let sub_entries = [];
|
51
|
+
let sub_batches = bd.batches.items;
|
52
|
+
for (let b of sub_batches) {
|
53
|
+
sub_entries.push(html`<${TreeLevel} data=${b} />`)
|
54
|
+
}
|
55
|
+
|
56
|
+
let fully_loaded = !(sub_batches.length < bd.batches.total_count);
|
57
|
+
|
58
|
+
const load_more_elem = html`<div class="load-more">
|
59
|
+
${sub_entries.length} / ${bd.batches.total_count} Items Loaded - <a href="#" onClick=${this.load_more}>Load More</a>
|
60
|
+
</div>`
|
61
|
+
|
62
|
+
return html`<div class="tree-entry tree-batch">
|
63
|
+
<div class="header">
|
64
|
+
<a class="row-toggle ${!bd.batches.total_count && 'not_applicable'}" onClick=${this.toggle} href="#">
|
65
|
+
${this.state.collapsed ? '+' : '-'}
|
66
|
+
</a>
|
67
|
+
|
68
|
+
<div class="header-inner">
|
69
|
+
<div class="main">
|
70
|
+
<span class="bid">
|
71
|
+
${bd.bid}
|
72
|
+
<a class="bid-goto" href="${root_url}batches/${bd.bid}">⇢</a>
|
73
|
+
</span>
|
74
|
+
${bd.description || (bd.status == 'deleted' && html`<i class="text-inactive">Deleted</i>`) || html`<i class="text-inactive">No Description</i>`}
|
75
|
+
</div>
|
76
|
+
|
77
|
+
<span class="status-label ${bd.status}">${bd.status}</span>
|
78
|
+
|
79
|
+
${bd.status != 'deleted' && html`
|
80
|
+
<${StatusBlock} class="job-status" title="Jobs" ...${bd.jobs} />
|
81
|
+
<${StatusBlock} class="batch-status" title="Batches" ...${bd.batches} />
|
82
|
+
`}
|
83
|
+
</div>
|
84
|
+
</div>
|
85
|
+
|
86
|
+
<div class="subitems ${this.state.collapsed ? 'hidden' : ''}">
|
87
|
+
${sub_entries}
|
88
|
+
${!fully_loaded && load_more_elem}
|
89
|
+
</div>
|
90
|
+
</div>`
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
class TreeRoot extends Component {
|
95
|
+
render() {
|
96
|
+
const tree_data = JSON.parse(document.querySelector('#batch-tree #initial-data').innerHTML);
|
97
|
+
return html`
|
98
|
+
<div class="tree-header">
|
99
|
+
<${StatusBlock} pending_count="pending" failed_count="failed" successful_count="successful" total_count="total" />
|
100
|
+
</div>
|
101
|
+
<${TreeLevel} data=${tree_data} />
|
102
|
+
`;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
render(html`<${TreeRoot} />`, document.querySelector('#batch-tree'));
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
<% add_to_head do %>
|
3
|
+
<meta name="sidekiq-baseurl" content="<%= root_path %>" />
|
4
|
+
<% if dev_mode? %>
|
5
|
+
<link href="<%= root_path %>batches_assets/css/styles.less" media="screen" rel="stylesheet/less" type="text/css" />
|
6
|
+
<script async type="text/javascript" src="https://unpkg.com/less@4.1.1/dist/less.js" data-async="true"></script>
|
7
|
+
<% else %>
|
8
|
+
<link href="<%= root_path %>batches_assets/css/styles.less" media="screen" rel="stylesheet/less" type="text/css" />
|
9
|
+
<script async type="text/javascript" src="https://unpkg.com/less@4.1.1/dist/less.js" data-async="true"></script>
|
10
|
+
<%# TODO: Pre-compile LESS %>
|
11
|
+
<!-- <link href="<%= root_path %>batches_assets/css/styles.css" media="screen" rel="stylesheet" type="text/css" /> -->
|
12
|
+
<% end %>
|
13
|
+
<% end %>
|
@@ -1,3 +1,5 @@
|
|
1
|
+
<%= erb get_template(:_common) %>
|
2
|
+
|
1
3
|
<h3><%= t('Batch') %></h3>
|
2
4
|
<% status = CanvasSync::JobBatches::Batch::Status.new(@batch) %>
|
3
5
|
|
@@ -17,70 +19,13 @@
|
|
17
19
|
<td><%= @batch.description %></td>
|
18
20
|
</tr>
|
19
21
|
<tr>
|
20
|
-
<th colspan="2" scope=row><%= t('
|
22
|
+
<th colspan="2" scope=row><%= t('Context') %></td>
|
21
23
|
<td>
|
22
|
-
<code class="code-wrap">
|
23
|
-
<div class="args-extended"><%= @batch
|
24
|
+
<code class="code-wrap batch-context">
|
25
|
+
<div class="args-extended"><%= format_context(@batch) %></div>
|
24
26
|
</code>
|
25
27
|
</td>
|
26
28
|
</tr>
|
27
|
-
<tr>
|
28
|
-
<th colspan="2" scope=row><%= t('Full Context') %></td>
|
29
|
-
<td>
|
30
|
-
<code class="code-wrap">
|
31
|
-
<div class="args-extended"><%= @batch.context.flatten.to_json %></div>
|
32
|
-
</code>
|
33
|
-
</td>
|
34
|
-
</tr>
|
35
|
-
|
36
|
-
<tr>
|
37
|
-
<th colspan="3">Jobs</th>
|
38
|
-
</tr>
|
39
|
-
<tr>
|
40
|
-
<th></th>
|
41
|
-
<th><%= t('Pending') %></th>
|
42
|
-
<td><%= status.pending %></th>
|
43
|
-
</tr>
|
44
|
-
<tr>
|
45
|
-
<th></th>
|
46
|
-
<th><%= t('Failed') %></th>
|
47
|
-
<td><%= status.failures %></th>
|
48
|
-
</tr>
|
49
|
-
<tr>
|
50
|
-
<th></th>
|
51
|
-
<th><%= t('Complete') %></th>
|
52
|
-
<td><%= status.completed_count %></th>
|
53
|
-
</tr>
|
54
|
-
<tr>
|
55
|
-
<th></th>
|
56
|
-
<th><%= t('Total') %></th>
|
57
|
-
<td><%= status.job_count %></th>
|
58
|
-
</tr>
|
59
|
-
|
60
|
-
<tr>
|
61
|
-
<th colspan="3">Batches</th>
|
62
|
-
</tr>
|
63
|
-
<tr>
|
64
|
-
<th></th>
|
65
|
-
<th><%= t('Pending') %></th>
|
66
|
-
<td><%= status.child_count - status.successful_children_count %></th>
|
67
|
-
</tr>
|
68
|
-
<tr>
|
69
|
-
<th></th>
|
70
|
-
<th><%= t('Failed') %></th>
|
71
|
-
<td><%= status.failed_children_count %></th>
|
72
|
-
</tr>
|
73
|
-
<tr>
|
74
|
-
<th></th>
|
75
|
-
<th><%= t('Success') %></th>
|
76
|
-
<td><%= status.successful_children_count %></th>
|
77
|
-
</tr>
|
78
|
-
<tr>
|
79
|
-
<th></th>
|
80
|
-
<th><%= t('Total') %></th>
|
81
|
-
<td><%= status.child_count %></th>
|
82
|
-
</tr>
|
83
|
-
|
84
29
|
</tbody>
|
85
30
|
</table>
|
86
31
|
</div>
|
@@ -88,51 +33,33 @@
|
|
88
33
|
<header class="row">
|
89
34
|
<div class="col-sm-5">
|
90
35
|
<h3>
|
91
|
-
<%= t('
|
36
|
+
<%= t('Child Batches') %>
|
92
37
|
</h3>
|
93
38
|
</div>
|
94
|
-
<%
|
95
|
-
@current_page = @current_jobs_page
|
96
|
-
@total_size = @total_jobs_size
|
97
|
-
%>
|
98
|
-
<% if @jobs.any? && @total_size > @count.to_i %>
|
99
|
-
<div class="col-sm-4">
|
100
|
-
<%= erb get_template(:_pagination), locals: { url: "#{root_path}batches/#{@batch.bid}", page_key: :job_page } %>
|
101
|
-
</div>
|
102
|
-
<% end %>
|
103
39
|
</header>
|
104
40
|
|
105
|
-
|
106
|
-
<div class="table_container">
|
107
|
-
<%= erb get_template(:_jobs_table), locals: { jobs: @jobs } %>
|
108
|
-
</div>
|
109
|
-
<% end %>
|
41
|
+
<%= erb get_template(:_batch_tree), locals: { } %>
|
110
42
|
|
111
43
|
<header class="row">
|
112
44
|
<div class="col-sm-5">
|
113
45
|
<h3>
|
114
|
-
<%= t('
|
46
|
+
<%= t('Jobs') %>
|
47
|
+
<i>(Queued and Current)</i>
|
115
48
|
</h3>
|
116
49
|
</div>
|
117
50
|
<%
|
118
|
-
@current_page = @
|
119
|
-
@total_size = @
|
51
|
+
@current_page = @current_jobs_page
|
52
|
+
@total_size = @total_jobs_size
|
120
53
|
%>
|
121
|
-
<% if @
|
54
|
+
<% if @jobs.any? && @total_size > @count.to_i %>
|
122
55
|
<div class="col-sm-4">
|
123
|
-
<%= erb get_template(:_pagination), locals: { url: "#{root_path}batches/#{@batch.bid}", page_key: :
|
56
|
+
<%= erb get_template(:_pagination), locals: { url: "#{root_path}batches/#{@batch.bid}", page_key: :job_page } %>
|
124
57
|
</div>
|
125
58
|
<% end %>
|
126
59
|
</header>
|
127
60
|
|
128
|
-
<% if @
|
61
|
+
<% if @jobs.any? %>
|
129
62
|
<div class="table_container">
|
130
|
-
<%= erb get_template(:
|
63
|
+
<%= erb get_template(:_jobs_table), locals: { jobs: @jobs } %>
|
131
64
|
</div>
|
132
65
|
<% end %>
|
133
|
-
|
134
|
-
<form class="form-horizontal" action="<%= root_path %>batches/<%= @batch.bid %>" method="post">
|
135
|
-
<%= csrf_tag %>
|
136
|
-
<a class="btn btn-default" href="<%= root_path %>batches"><%= t('GoBack') %></a>
|
137
|
-
<input class="btn btn-danger" type="submit" name="delete" value="<%= t('Delete') %>" data-confirm="<%= t('AreYouSure') %>" />
|
138
|
-
</form>
|
data/lib/canvas_sync/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: canvas_sync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.17.
|
4
|
+
version: 0.17.18
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nate Collings
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -442,6 +442,7 @@ files:
|
|
442
442
|
- lib/canvas_sync/job_batches/callback.rb
|
443
443
|
- lib/canvas_sync/job_batches/chain_builder.rb
|
444
444
|
- lib/canvas_sync/job_batches/context_hash.rb
|
445
|
+
- lib/canvas_sync/job_batches/hier_batch_ids.lua
|
445
446
|
- lib/canvas_sync/job_batches/hincr_max.lua
|
446
447
|
- lib/canvas_sync/job_batches/jobs/base_job.rb
|
447
448
|
- lib/canvas_sync/job_batches/jobs/concurrent_batch_job.rb
|
@@ -453,8 +454,13 @@ files:
|
|
453
454
|
- lib/canvas_sync/job_batches/schedule_callback.lua
|
454
455
|
- lib/canvas_sync/job_batches/sidekiq.rb
|
455
456
|
- lib/canvas_sync/job_batches/sidekiq/web.rb
|
457
|
+
- lib/canvas_sync/job_batches/sidekiq/web/batches_assets/css/styles.less
|
458
|
+
- lib/canvas_sync/job_batches/sidekiq/web/batches_assets/js/batch_tree.js
|
459
|
+
- lib/canvas_sync/job_batches/sidekiq/web/batches_assets/js/util.js
|
456
460
|
- lib/canvas_sync/job_batches/sidekiq/web/helpers.rb
|
461
|
+
- lib/canvas_sync/job_batches/sidekiq/web/views/_batch_tree.erb
|
457
462
|
- lib/canvas_sync/job_batches/sidekiq/web/views/_batches_table.erb
|
463
|
+
- lib/canvas_sync/job_batches/sidekiq/web/views/_common.erb
|
458
464
|
- lib/canvas_sync/job_batches/sidekiq/web/views/_jobs_table.erb
|
459
465
|
- lib/canvas_sync/job_batches/sidekiq/web/views/_pagination.erb
|
460
466
|
- lib/canvas_sync/job_batches/sidekiq/web/views/batch.erb
|
@@ -673,11 +679,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
673
679
|
version: '0'
|
674
680
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
675
681
|
requirements:
|
676
|
-
- - "
|
682
|
+
- - ">="
|
677
683
|
- !ruby/object:Gem::Version
|
678
|
-
version:
|
684
|
+
version: '0'
|
679
685
|
requirements: []
|
680
|
-
rubygems_version: 3.0.3
|
686
|
+
rubygems_version: 3.0.3
|
681
687
|
signing_key:
|
682
688
|
specification_version: 4
|
683
689
|
summary: Gem for generating Canvas models and migrations and syncing data from Canvas
|