/* global jQuery, prR2 */ /** * R2 Media Manager — admin JS. * * Drives batch loops for migrate-to-R2 and remove-local-files operations. * Each loop fires one AJAX request, waits for the response, updates the * progress bar, then fires the next request — until the server signals done=true * or the user clicks Pause. * * Also handles: Test R2 Connection button, Clear Log button. */ (function ($) { 'use strict'; // ── Batch runner ────────────────────────────────────────────────────────── /** * Run one batch of an AJAX operation and schedule the next. * * @param {string} action WP AJAX action name. * @param {string} nonce Nonce string from wp_localize_script. * @param {Object} state Mutable state: { processed, succeeded, failed, paused }. * @param {Object} ui jQuery element refs: $btn, $pauseBtn, $bar, $status. * @param {string} countKey 'succeeded' | 'removed' — key to read from response. * @param {string} failKey 'failed' | 'skipped'. */ function runBatch(action, nonce, state, ui, countKey, failKey) { if (state.paused) { ui.$status.text('Paused. Click the button again to resume.'); ui.$btn.prop('disabled', false).text(ui.$btn.data('resume-label')); ui.$pauseBtn.hide(); return; } $.post(prR2.ajaxUrl, { action: action, nonce: nonce, batch_size: prR2.batchSize, }) .done(function (res) { if (!res.success) { showNotice('error', 'Error: ' + (res.data ? res.data.message : 'Unknown error.')); ui.$btn.prop('disabled', false); ui.$pauseBtn.hide(); return; } var d = res.data; state.processed += d.processed; state.succeeded += (d[countKey] || 0); state.failed += (d[failKey] || 0); // remaining is the count left AFTER this batch. var total = state.processed + d.remaining; var pct = total > 0 ? Math.round((state.processed / total) * 100) : 100; ui.$bar.val(pct); ui.$status.text( 'Processed ' + state.processed + ' of ' + total + ' — success: ' + state.succeeded + (state.failed ? ', failed/skipped: ' + state.failed : '') ); if (d.done) { ui.$status.text( 'Done! ✓ Succeeded: ' + state.succeeded + (state.failed ? ' Failed/skipped: ' + state.failed : '') ); ui.$btn.prop('disabled', true); ui.$pauseBtn.hide(); // Reload after 1.5 s so the status table refreshes. setTimeout(function () { window.location.reload(); }, 1500); return; } runBatch(action, nonce, state, ui, countKey, failKey); }) .fail(function () { ui.$status.text('Network error — operation paused. Retry by clicking the button.'); ui.$btn.prop('disabled', false).text(ui.$btn.data('resume-label')); ui.$pauseBtn.hide(); }); } // ── Wire up Migrate button ──────────────────────────────────────────────── $('#pr-r2-btn-migrate').on('click', function () { var $btn = $(this); var state = { processed: 0, succeeded: 0, failed: 0, paused: false }; var ui = { $btn: $btn, $pauseBtn: $('#pr-r2-btn-migrate-pause'), $bar: $('#pr-r2-migrate-bar'), $status: $('#pr-r2-migrate-status'), }; $btn.data('resume-label', 'Resume migration').prop('disabled', true); ui.$pauseBtn.show(); $('#pr-r2-migrate-progress').show(); ui.$bar.val(0); ui.$status.text('Starting migration…'); runBatch('pr_r2_migrate_batch', prR2.nonceMigrate, state, ui, 'succeeded', 'failed'); }); $('#pr-r2-btn-migrate-pause').on('click', function () { // Signal the batch runner to stop after the current in-flight request. var state = $('#pr-r2-btn-migrate').data('batchState'); if (state) { state.paused = true; } }); // Re-wire so the button can resume (state persists in data). // Simpler: just reload the page — already-offloaded items are excluded by the query. // ── Wire up Remove Local button ─────────────────────────────────────────── $('#pr-r2-btn-remove').on('click', function () { var $btn = $(this); var state = { processed: 0, succeeded: 0, failed: 0, paused: false }; var ui = { $btn: $btn, $pauseBtn: $('#pr-r2-btn-remove-pause'), $bar: $('#pr-r2-remove-bar'), $status: $('#pr-r2-remove-status'), }; $btn.data('resume-label', 'Resume removal').prop('disabled', true); ui.$pauseBtn.show(); $('#pr-r2-remove-progress').show(); ui.$bar.val(0); ui.$status.text('Starting local-file removal…'); runBatch('pr_r2_remove_local_batch', prR2.nonceRemove, state, ui, 'removed', 'skipped'); }); $('#pr-r2-btn-remove-pause').on('click', function () { var state = $('#pr-r2-btn-remove').data('batchState'); if (state) { state.paused = true; } }); // ── Test Connection ─────────────────────────────────────────────────────── $('#pr-r2-btn-test').on('click', function () { var $btn = $(this); var $result = $('#pr-r2-test-result'); $btn.prop('disabled', true); $result.css('color', '#555').text('Testing…'); $.post(prR2.ajaxUrl, { action: 'pr_r2_test_connection', nonce: prR2.nonceTest }) .done(function (res) { if (res.success) { $result.css('color', '#090').text('✓ ' + res.data.message); } else { $result.css('color', '#c00').text('✗ ' + (res.data ? res.data.message : 'Failed.')); } }) .fail(function () { $result.css('color', '#c00').text('✗ Network error.'); }) .always(function () { $btn.prop('disabled', false); }); }); // ── Clear Log ───────────────────────────────────────────────────────────── $('#pr-r2-btn-clear-log').on('click', function () { if (!window.confirm('Clear all log entries?')) { return; } var $btn = $(this); $btn.prop('disabled', true); $.post(prR2.ajaxUrl, { action: 'pr_r2_clear_log', nonce: prR2.nonceClearLog }) .done(function (res) { if (res.success) { $('#pr-r2-log-tbody').closest('table').replaceWith('
Log cleared.
'); } else { showNotice('error', 'Could not clear log.'); } }) .always(function () { $btn.prop('disabled', false); }); }); // ── Utility ─────────────────────────────────────────────────────────────── function showNotice(type, msg) { var cls = type === 'error' ? 'notice-error' : 'notice-success'; $('#pr-r2-notice').html( '' + msg + '