@@ -7,11 +7,9 @@ django.jQuery(function ($) {
77 if ( ! batchUpgradeId ) {
88 return ;
99 }
10-
11- // Initialize existing upgrade operations with progress bars
1210 initializeExistingBatchUpgradeOperations ( $ ) ;
11+ initializeMainProgressBar ( $ ) ;
1312
14- // Use the controller API host (always defined in change_form.html)
1513 const wsHost = owControllerApiHost . host ;
1614 const wsUrl = `${ getWebSocketProtocol ( ) } ${ wsHost } /ws/firmware-upgrader/batch-upgrade-operation/${ batchUpgradeId } /` ;
1715
@@ -47,35 +45,35 @@ function initializeExistingBatchUpgradeOperations($, isRetry = false) {
4745 if ( batchUpgradeOperationsInitialized && isRetry ) {
4846 return ;
4947 }
50-
5148 let statusCells = $ ( "#result_list tbody td.status-cell" ) ;
5249 let processedCount = 0 ;
53-
5450 statusCells . each ( function ( ) {
5551 let statusCell = $ ( this ) ;
56- let statusText =
57- statusCell . find ( ".status-content" ) . text ( ) . trim ( ) ||
58- statusCell . text ( ) . trim ( ) ;
59-
6052 if ( statusCell . find ( ".upgrade-status-container" ) . length > 0 ) {
6153 return ;
6254 }
63-
55+ let statusText = statusCell . find ( ".status-content" ) . text ( ) . trim ( ) ;
56+ if ( ! statusText ) {
57+ let cellText = statusCell . text ( ) . trim ( ) ;
58+ statusText = cellText . replace ( / \d + % .* $ / , "" ) . trim ( ) ;
59+ }
6460 if (
6561 statusText &&
6662 ( statusText . includes ( "progress" ) ||
6763 statusText === "success" ||
6864 statusText === "completed successfully" ||
65+ statusText === "completed with some failures" ||
6966 statusText === "failed" ||
70- statusText === "aborted" )
67+ statusText === "aborted" ||
68+ statusText === "cancelled" )
7169 ) {
7270 let operationId = statusCell . attr ( "data-operation-id" ) || "unknown" ;
71+
7372 let operation = {
7473 status : statusText ,
7574 id : operationId ,
7675 progress : null ,
7776 } ;
78-
7977 updateBatchStatusWithProgressBar ( statusCell , operation ) ;
8078 processedCount ++ ;
8179 }
@@ -92,14 +90,21 @@ function initializeExistingBatchUpgradeOperations($, isRetry = false) {
9290
9391function initBatchUpgradeProgressWebSockets ( $ , batchUpgradeProgressWebSocket ) {
9492 batchUpgradeProgressWebSocket . addEventListener ( "open" , function ( e ) {
95- batchUpgradeOperationsInitialized = false ;
96- requestCurrentBatchState ( batchUpgradeProgressWebSocket ) ;
97- initializeExistingBatchUpgradeOperations ( $ , false ) ;
93+ let existingContainers = $ (
94+ "#result_list tbody td.status-cell .upgrade-status-container" ,
95+ ) ;
96+ if ( existingContainers . length === 0 ) {
97+ batchUpgradeOperationsInitialized = false ;
98+ requestCurrentBatchState ( batchUpgradeProgressWebSocket ) ;
99+ initializeExistingBatchUpgradeOperations ( $ , false ) ;
100+ } else {
101+ // Just request current state without reinitializing
102+ requestCurrentBatchState ( batchUpgradeProgressWebSocket ) ;
103+ }
98104 } ) ;
99105
100106 batchUpgradeProgressWebSocket . addEventListener ( "close" , function ( e ) {
101107 batchUpgradeOperationsInitialized = false ;
102-
103108 if ( e . code === 1006 ) {
104109 console . error ( "WebSocket closed" ) ;
105110 }
@@ -112,7 +117,6 @@ function initBatchUpgradeProgressWebSockets($, batchUpgradeProgressWebSocket) {
112117 batchUpgradeProgressWebSocket . addEventListener ( "message" , function ( e ) {
113118 try {
114119 let data = JSON . parse ( e . data ) ;
115-
116120 if ( data . type === "batch_status" ) {
117121 updateBatchProgress ( data ) ;
118122 } else if ( data . type === "operation_progress" ) {
@@ -134,33 +138,74 @@ function initBatchUpgradeProgressWebSockets($, batchUpgradeProgressWebSocket) {
134138
135139function updateBatchProgress ( data ) {
136140 let $ = django . jQuery ;
137-
138- // Update the main progress bar
139141 let mainProgressElement = $ ( ".batch-main-progress" ) ;
140142 if ( mainProgressElement . length > 0 ) {
141143 let progressPercentage =
142144 data . total > 0 ? Math . round ( ( data . completed / data . total ) * 100 ) : 0 ;
143145 let statusClass = ( data . status || "" ) . replace ( / \s + / g, "-" ) ;
146+ let showPercentageText = true ;
144147
145148 if ( data . status === "success" ) {
146149 progressPercentage = 100 ;
147150 statusClass = "completed-successfully" ;
151+ showPercentageText = true ;
152+ } else if ( data . status === "failed" ) {
153+ let successfulOpsCount = $ ( "#result_list tbody tr" ) . filter ( function ( ) {
154+ let statusText = $ ( this ) . find ( ".status-cell .status-content" ) . text ( ) . trim ( ) ;
155+ return statusText === "success" || statusText === "completed successfully" ;
156+ } ) . length ;
157+
158+ // Also check individual operation containers for success
159+ if ( successfulOpsCount === 0 ) {
160+ $ ( "#result_list tbody tr" ) . each ( function ( ) {
161+ let statusContainer = $ ( this ) . find ( ".upgrade-status-container" ) ;
162+ if (
163+ statusContainer . length &&
164+ statusContainer . find ( ".upgrade-progress-fill.success" ) . length
165+ ) {
166+ successfulOpsCount ++ ;
167+ }
168+ } ) ;
169+ }
170+ if ( successfulOpsCount > 0 ) {
171+ // Some operations succeeded - partial success (orange)
172+ progressPercentage = 100 ;
173+ statusClass = "partial-success" ;
174+ showPercentageText = false ;
175+ } else {
176+ // All operations failed - total failure (red)
177+ progressPercentage = 100 ;
178+ statusClass = "failed" ;
179+ showPercentageText = false ;
180+ }
148181 }
149182
150183 let progressHtml = `
151184 <div class="upgrade-progress-bar">
152185 <div class="upgrade-progress-fill ${ statusClass } " style="width: ${ progressPercentage } %"></div>
153186 </div>
154- <span class="upgrade-progress-text">${ progressPercentage } %</span>
155187 ` ;
188+ if ( showPercentageText ) {
189+ progressHtml += `<span class="upgrade-progress-text">${ progressPercentage } %</span>` ;
190+ }
191+
156192 mainProgressElement . html ( progressHtml ) ;
157193 }
158194
195+ // Update completion information in the admin form if available
196+ if ( data . total && data . completed ) {
197+ let completedInfo = $ ( ".field-completed .readonly" ) ;
198+ if ( completedInfo . length > 0 ) {
199+ completedInfo . text ( `${ data . completed } out of ${ data . total } ` ) ;
200+ }
201+ }
159202 let statusField = $ ( ".field-status .readonly" ) ;
160203 if ( statusField . length > 0 && data . status ) {
161204 let displayStatus = data . status ;
162205 if ( data . status === "success" ) {
163206 displayStatus = "completed successfully" ;
207+ } else if ( data . status === "failed" ) {
208+ displayStatus = "completed with some failures" ;
164209 } else if ( data . status === "in-progress" ) {
165210 displayStatus = "in progress" ;
166211 }
@@ -194,15 +239,13 @@ function updateBatchOperationProgress(data) {
194239
195240 if ( operationId === data . operation_id ) {
196241 found = true ;
197-
198242 let operation = {
199243 status : data . status ,
200244 id : data . operation_id ,
201245 progress : data . progress ,
202246 } ;
203247
204248 updateBatchStatusWithProgressBar ( statusCell , operation ) ;
205-
206249 if ( data . modified ) {
207250 let modifiedCell = row . find ( "td:nth-child(4)" ) ;
208251 modifiedCell . html ( getFormattedDateTimeString ( data . modified ) ) ;
@@ -221,13 +264,10 @@ function addNewOperationRow(data) {
221264 if ( ! data . device_name || ! data . device_id ) {
222265 return ;
223266 }
224-
225267 let tbody = $ ( "#result_list tbody" ) ;
226268 let existingRows = tbody . find ( "tr" ) . length ;
227269 let rowClass = existingRows % 2 === 0 ? "row1" : "row2" ;
228-
229270 tbody . find ( "tr td[colspan]" ) . parent ( ) . remove ( ) ;
230-
231271 let deviceUrl = `/admin/firmware_upgrader/upgradeoperation/${ data . operation_id } /change/` ;
232272 let imageDisplay = data . image_name || "None" ;
233273 let modifiedTime = data . modified
@@ -250,40 +290,22 @@ function addNewOperationRow(data) {
250290 ` ;
251291
252292 tbody . append ( newRowHtml ) ;
253-
254- // Update the new row with progress bar
255293 let newRow = tbody . find ( `tr:last` ) ;
256294 let statusCell = newRow . find ( ".status-cell" ) ;
257295 let operation = {
258296 status : data . status ,
259297 id : data . operation_id ,
260298 progress : data . progress ,
261299 } ;
262-
263300 updateBatchStatusWithProgressBar ( statusCell , operation ) ;
264301}
265302
266303function updateBatchStatusWithProgressBar ( statusCell , operation ) {
267304 let $ = django . jQuery ;
268305 let status = operation . status ;
269- let progressPercentage = getBatchProgressPercentage (
270- status ,
271- operation . progress ,
272- ) ;
273- let progressClass = status . replace ( / \s + / g, "-" ) ;
274-
275- if ( ! statusCell . find ( ".upgrade-status-container" ) . length ) {
276- statusCell . find ( ".status-content" ) . empty ( ) ;
277- statusCell
278- . find ( ".status-content" )
279- . append ( '<div class="upgrade-status-container"></div>' ) ;
280-
281- if ( ! statusCell . find ( ".status-content" ) . length ) {
282- statusCell . empty ( ) ;
283- statusCell . append ( '<div class="upgrade-status-container"></div>' ) ;
284- }
285- }
286-
306+ let progressPercentage = getBatchProgressPercentage ( status , operation . progress ) ;
307+ statusCell . empty ( ) ;
308+ statusCell . append ( '<div class="upgrade-status-container"></div>' ) ;
287309 let statusContainer = statusCell . find ( ".upgrade-status-container" ) ;
288310 let statusHtml = "" ;
289311
@@ -303,30 +325,37 @@ function updateBatchStatusWithProgressBar(statusCell, operation) {
303325 statusHtml = `<div class="upgrade-progress-bar">
304326 <div class="upgrade-progress-fill aborted" style="width: 100%"></div>
305327 </div>` ;
328+ } else if ( status === "cancelled" ) {
329+ statusHtml = `<div class="upgrade-progress-bar">
330+ <div class="upgrade-progress-fill cancelled" style="width: 100%"></div>
331+ </div>` ;
306332 } else {
307333 statusHtml = `<div class="upgrade-progress-bar">
308334 <div class="upgrade-progress-fill" style="width: ${ progressPercentage } %"></div>
309335 </div>` ;
310336 }
311-
312337 statusContainer . html ( statusHtml ) ;
313338}
314339
315340function getBatchProgressPercentage ( status , operationProgress = null ) {
316341 if ( operationProgress !== null && operationProgress !== undefined ) {
317342 return Math . min ( 100 , Math . max ( 5 , operationProgress ) ) ;
318343 }
319- if ( status === "completed successfully" ) {
344+ if (
345+ status === "completed successfully" ||
346+ status === "success" ||
347+ status === "failed" ||
348+ status === "aborted" ||
349+ status === "cancelled"
350+ ) {
320351 return 100 ;
321352 }
322353 return 5 ;
323354}
324355
325356function getBatchUpgradeIdFromUrl ( ) {
326357 try {
327- let matches = window . location . pathname . match (
328- / \/ b a t c h u p g r a d e o p e r a t i o n \/ ( [ ^ \/ ] + ) \/ / ,
329- ) ;
358+ let matches = window . location . pathname . match ( / \/ b a t c h u p g r a d e o p e r a t i o n \/ ( [ ^ \/ ] + ) \/ / ) ;
330359 return matches && matches [ 1 ] ? matches [ 1 ] : null ;
331360 } catch ( error ) {
332361 console . error ( "Error extracting batch ID from URL:" , error ) ;
@@ -342,6 +371,52 @@ function getWebSocketProtocol() {
342371 return protocol ;
343372}
344373
374+ function initializeMainProgressBar ( $ ) {
375+ let statusField = $ ( ".field-status .readonly" ) ;
376+ if ( statusField . length > 0 ) {
377+ let currentStatusText = statusField
378+ . contents ( )
379+ . filter ( function ( ) {
380+ return this . nodeType === 3 && this . textContent . trim ( ) ;
381+ } )
382+ . first ( )
383+ . text ( )
384+ . trim ( ) ;
385+
386+ let mainProgressElement = $ ( ".batch-main-progress" ) ;
387+ if ( mainProgressElement . length > 0 && currentStatusText ) {
388+ let progressPercentage = 100 ;
389+ let statusClass = "" ;
390+ let showPercentageText = true ;
391+
392+ if ( currentStatusText === "completed successfully" ) {
393+ statusClass = "completed-successfully" ;
394+ showPercentageText = true ;
395+ } else if ( currentStatusText === "completed with some failures" ) {
396+ statusClass = "partial-success" ;
397+ showPercentageText = false ;
398+ } else if ( currentStatusText === "in progress" ) {
399+ statusClass = "in-progress" ;
400+ showPercentageText = true ;
401+ progressPercentage = 0 ;
402+ } else {
403+ statusClass = "failed" ;
404+ showPercentageText = false ;
405+ }
406+
407+ let progressHtml = `
408+ <div class="upgrade-progress-bar">
409+ <div class="upgrade-progress-fill ${ statusClass } " style="width: ${ progressPercentage } %"></div>
410+ </div>
411+ ` ;
412+ if ( showPercentageText ) {
413+ progressHtml += `<span class="upgrade-progress-text">${ progressPercentage } %</span>` ;
414+ }
415+ mainProgressElement . html ( progressHtml ) ;
416+ }
417+ }
418+ }
419+
345420function getFormattedDateTimeString ( dateTimeString ) {
346421 let dateTime = new Date ( dateTimeString ) ;
347422 return dateTime . toLocaleString ( ) ;
0 commit comments