@@ -140,61 +140,125 @@ function updateBatchProgress(data) {
140140 let $ = django . jQuery ;
141141 let mainProgressElement = $ ( ".batch-main-progress" ) ;
142142 if ( mainProgressElement . length > 0 ) {
143- let progressPercentage =
144- data . total > 0 ? Math . round ( ( data . completed / data . total ) * 100 ) : 0 ;
143+ let total = data . total || 0 ;
144+ let completed = data . completed || 0 ;
145+ let progressPercentage = total > 0 ? Math . round ( ( completed / total ) * 100 ) : 0 ;
145146 let showPercentageText = true ;
146- let statusClass = FW_UPGRADE_CSS_CLASSES . IN_PROGRESS ; // Safe default
147+ let progressHtml = "" ;
148+ let legendHtml = "" ;
147149
148- if ( data . status === FW_UPGRADE_STATUS . SUCCESS ) {
149- progressPercentage = 100 ;
150- statusClass = FW_UPGRADE_CSS_CLASSES . COMPLETED_SUCCESSFULLY ;
151- showPercentageText = true ;
152- } else if ( data . status === FW_UPGRADE_STATUS . CANCELLED ) {
153- progressPercentage = 100 ;
154- statusClass = FW_UPGRADE_CSS_CLASSES . CANCELLED ;
155- showPercentageText = false ;
156- } else if ( data . status === FW_UPGRADE_STATUS . FAILED ) {
157- let successfulOpsCount = $ ( "#result_list tbody tr" ) . filter ( function ( ) {
158- let statusText = $ ( this ) . find ( ".status-cell .status-content" ) . text ( ) . trim ( ) ;
159- return FW_STATUS_GROUPS . SUCCESS . has ( statusText ) ;
160- } ) . length ;
161- // Also check individual operation containers for success
162- if ( successfulOpsCount === 0 ) {
163- $ ( "#result_list tbody tr" ) . each ( function ( ) {
164- let statusContainer = $ ( this ) . find ( ".upgrade-status-container" ) ;
165- if (
166- statusContainer . length &&
167- statusContainer . find ( ".upgrade-progress-fill.success" ) . length
168- ) {
169- successfulOpsCount ++ ;
170- }
150+ let statusCountSum =
151+ ( data . successful || 0 ) +
152+ ( data . failed || 0 ) +
153+ ( data . aborted || 0 ) +
154+ ( data . cancelled || 0 ) ;
155+ if ( data . successful !== undefined && total > 0 && statusCountSum > 0 ) {
156+ // Multicolor status which shows proportional segments per status
157+ let successful = data . successful || 0 ;
158+ let failed = data . failed || 0 ;
159+ let aborted = data . aborted || 0 ;
160+ let cancelled = data . cancelled || 0 ;
161+ let segments = [ ] ;
162+ if ( successful > 0 ) {
163+ segments . push ( {
164+ cssClass : FW_UPGRADE_CSS_CLASSES . SUCCESS ,
165+ count : successful ,
166+ label : FW_UPGRADE_DISPLAY_STATUS . SUCCESS ,
167+ } ) ;
168+ }
169+ if ( failed > 0 ) {
170+ segments . push ( {
171+ cssClass : FW_UPGRADE_CSS_CLASSES . FAILED ,
172+ count : failed ,
173+ label : FW_UPGRADE_DISPLAY_STATUS . FAILED ,
171174 } ) ;
172175 }
173- if ( successfulOpsCount > 0 ) {
174- // Some operations succeeded - partial success (orange)
176+ if ( aborted > 0 ) {
177+ segments . push ( {
178+ cssClass : FW_UPGRADE_CSS_CLASSES . ABORTED ,
179+ count : aborted ,
180+ label : FW_UPGRADE_DISPLAY_STATUS . ABORTED ,
181+ } ) ;
182+ }
183+ if ( cancelled > 0 ) {
184+ segments . push ( {
185+ cssClass : FW_UPGRADE_CSS_CLASSES . CANCELLED ,
186+ count : cancelled ,
187+ label : FW_UPGRADE_DISPLAY_STATUS . CANCELLED ,
188+ } ) ;
189+ }
190+ let usedWidth = 0 ;
191+ let segmentsHtml = segments
192+ . map ( function ( seg , index ) {
193+ let segmentWidth =
194+ index === segments . length - 1
195+ ? progressPercentage - usedWidth
196+ : Math . round ( ( seg . count / total ) * 100 ) ;
197+ usedWidth += segmentWidth ;
198+ return (
199+ '<div class="upgrade-progress-fill ' +
200+ escapeHtml ( seg . cssClass ) +
201+ '" style="width: ' +
202+ escapeHtml ( String ( segmentWidth ) ) +
203+ '%"></div>'
204+ ) ;
205+ } )
206+ . join ( "" ) ;
207+ progressHtml = '<div class="upgrade-progress-bar">' + segmentsHtml + "</div>" ;
208+ // legend builing function
209+ if ( segments . length > 0 ) {
210+ let legendItems = segments
211+ . map ( function ( seg ) {
212+ return (
213+ '<span class="legend-item">' +
214+ '<span class="legend-dot ' +
215+ escapeHtml ( seg . cssClass ) +
216+ '"></span>' +
217+ escapeHtml ( String ( seg . count ) ) +
218+ " " +
219+ escapeHtml ( seg . label ) +
220+ "</span>"
221+ ) ;
222+ } )
223+ . join ( "" ) ;
224+ legendHtml = '<div class="batch-progress-legend">' + legendItems + "</div>" ;
225+ }
226+ if (
227+ data . status === FW_UPGRADE_STATUS . FAILED ||
228+ data . status === FW_UPGRADE_STATUS . CANCELLED
229+ ) {
230+ showPercentageText = false ;
231+ }
232+ } else {
233+ // Fallback: single-color will be rendered when per-status counts are not available
234+ let statusClass = FW_UPGRADE_CSS_CLASSES . IN_PROGRESS ;
235+ if ( data . status === FW_UPGRADE_STATUS . SUCCESS ) {
175236 progressPercentage = 100 ;
176- statusClass = FW_UPGRADE_CSS_CLASSES . PARTIAL_SUCCESS ;
237+ statusClass = FW_UPGRADE_CSS_CLASSES . COMPLETED_SUCCESSFULLY ;
238+ } else if ( data . status === FW_UPGRADE_STATUS . CANCELLED ) {
239+ progressPercentage = 100 ;
240+ statusClass = FW_UPGRADE_CSS_CLASSES . CANCELLED ;
177241 showPercentageText = false ;
178- } else {
179- // All operations failed - total failure (red)
242+ } else if ( data . status === FW_UPGRADE_STATUS . FAILED ) {
180243 progressPercentage = 100 ;
181244 statusClass = FW_UPGRADE_CSS_CLASSES . FAILED ;
182245 showPercentageText = false ;
183246 }
247+ progressHtml =
248+ '<div class="upgrade-progress-bar">' +
249+ '<div class="upgrade-progress-fill ' +
250+ escapeHtml ( statusClass ) +
251+ '" style="width: ' +
252+ escapeHtml ( String ( progressPercentage ) ) +
253+ '%"></div></div>' ;
184254 }
185- let progressHtml = `
186- <div class="upgrade-progress-bar">
187- <div class="upgrade-progress-fill ${ escapeHtml ( statusClass ) } "
188- style="width: ${ escapeHtml ( String ( progressPercentage ) ) } %">
189- </div>
190- </div>
191- ` ;
192255 if ( showPercentageText ) {
193- progressHtml += `<span class="upgrade-progress-text">
194- ${ escapeHtml ( String ( progressPercentage ) ) } %
195- </span>` ;
256+ progressHtml +=
257+ '<span class="upgrade-progress-text">' +
258+ escapeHtml ( String ( progressPercentage ) ) +
259+ "%</span>" ;
196260 }
197- mainProgressElement . html ( progressHtml ) ;
261+ mainProgressElement . html ( progressHtml + legendHtml ) ;
198262 }
199263 // Update completion information in the admin form if available
200264 if ( data . total !== undefined && data . completed !== undefined ) {
0 commit comments