fix(import): guard realtime progress bar against late progress events

A 'progress' event arriving after 'complete' recreated an unmanaged
progress modal that nothing closed. Add an importFinished flag so the
progress handler no-ops after completion, and force-close the modal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ali 2026-06-12 16:19:28 +00:00
parent bdf32afa2d
commit 14383c0e15
2 changed files with 14 additions and 0 deletions

View File

@ -594,6 +594,10 @@ KBImport.import = {
loadSelectedTransactions: function(selectedTxns) { loadSelectedTransactions: function(selectedTxns) {
KBImport.loadingErrors = []; KBImport.loadingErrors = [];
const total = selectedTxns.length; const total = selectedTxns.length;
// Защита от гонки realtime: 'complete' закрывает прогресс. Опоздавший 'progress'
// иначе пересоздаёт модал, который уже никто не закрывает. Флаг делает
// обработчик прогресса no-op после завершения.
let importFinished = false;
frappe.show_progress( frappe.show_progress(
__('Importing Transactions'), 0, total, __('Importing Transactions'), 0, total,
@ -603,6 +607,7 @@ KBImport.import = {
// Listen for realtime progress from background job // Listen for realtime progress from background job
frappe.realtime.off('kb_import_progress'); frappe.realtime.off('kb_import_progress');
frappe.realtime.on('kb_import_progress', function(data) { frappe.realtime.on('kb_import_progress', function(data) {
if (importFinished) return;
frappe.show_progress( frappe.show_progress(
__('Importing Transactions'), data.current, data.total, __('Importing Transactions'), data.current, data.total,
__('Importing transaction {0} of {1}', [data.current, data.total]) __('Importing transaction {0} of {1}', [data.current, data.total])
@ -612,9 +617,11 @@ KBImport.import = {
// Listen for completion from background job // Listen for completion from background job
frappe.realtime.off('kb_import_complete'); frappe.realtime.off('kb_import_complete');
frappe.realtime.on('kb_import_complete', function(data) { frappe.realtime.on('kb_import_complete', function(data) {
importFinished = true;
frappe.realtime.off('kb_import_progress'); frappe.realtime.off('kb_import_progress');
frappe.realtime.off('kb_import_complete'); frappe.realtime.off('kb_import_complete');
KBImport.import._onBulkComplete(data); KBImport.import._onBulkComplete(data);
setTimeout(KBImport.import._closeProgress, 150);
}); });
frappe.call({ frappe.call({

View File

@ -636,6 +636,10 @@ KBBTImport.import = {
loadSelectedTransactions: function(selectedTxns) { loadSelectedTransactions: function(selectedTxns) {
KBBTImport.loadingErrors = []; KBBTImport.loadingErrors = [];
const total = selectedTxns.length; const total = selectedTxns.length;
// Защита от гонки realtime: 'complete' закрывает прогресс. Опоздавший 'progress'
// иначе пересоздаёт модал, который уже никто не закрывает. Флаг делает
// обработчик прогресса no-op после завершения.
let importFinished = false;
frappe.show_progress( frappe.show_progress(
__('Importing Transactions'), 0, total, __('Importing Transactions'), 0, total,
@ -645,6 +649,7 @@ KBBTImport.import = {
// Listen for realtime progress from background job // Listen for realtime progress from background job
frappe.realtime.off('kb_bt_import_progress'); frappe.realtime.off('kb_bt_import_progress');
frappe.realtime.on('kb_bt_import_progress', function(data) { frappe.realtime.on('kb_bt_import_progress', function(data) {
if (importFinished) return;
frappe.show_progress( frappe.show_progress(
__('Importing Transactions'), data.current, data.total, __('Importing Transactions'), data.current, data.total,
__('Importing transaction {0} of {1}', [data.current, data.total]) __('Importing transaction {0} of {1}', [data.current, data.total])
@ -654,9 +659,11 @@ KBBTImport.import = {
// Listen for completion from background job // Listen for completion from background job
frappe.realtime.off('kb_bt_import_complete'); frappe.realtime.off('kb_bt_import_complete');
frappe.realtime.on('kb_bt_import_complete', function(data) { frappe.realtime.on('kb_bt_import_complete', function(data) {
importFinished = true;
frappe.realtime.off('kb_bt_import_progress'); frappe.realtime.off('kb_bt_import_progress');
frappe.realtime.off('kb_bt_import_complete'); frappe.realtime.off('kb_bt_import_complete');
KBBTImport.import._onBulkComplete(data); KBBTImport.import._onBulkComplete(data);
setTimeout(KBBTImport.import._closeProgress, 150);
}); });
frappe.call({ frappe.call({