PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.5.2
MxChat – AI Chatbot & Content Generation for WordPress v2.5.2
3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 2.0.3 2.0.4 2.0.5 2.0.6 All 152 releases
mxchat-basic / js / knowledge-processing.js

knowledge-processing.js in MxChat – AI Chatbot & Content Generation for WordPress 2.5.2, at js/knowledge-processing.js

1,031 lines 43.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 jQuery(document).ready(function($) {
2 // ========================================
3 // QUEUE PROCESSING SYSTEM
4 // ========================================
5
6 let isProcessingQueue = false;
7 let currentQueueId = null;
8 let currentQueueType = null;
9
10 // Check if we should start queue processing on page load
11 checkForActiveQueues();
12
13 // Form submission handler - triggers queue processing
14 $('#mxchat-url-form').on('submit', function(e) {
15 //console.log('MxChat: Form submitted, queue will be created');
16
17 // Don't prevent default - let form submit normally
18 // But schedule a check after redirect
19 localStorage.setItem('mxchat_check_queue_after_submit', Date.now().toString());
20 });
21
22 // Check if we just submitted a form and need to start processing
23 const justSubmitted = localStorage.getItem('mxchat_check_queue_after_submit');
24 if (justSubmitted) {
25 const submitTime = parseInt(justSubmitted);
26 const now = Date.now();
27
28 // If submitted within last 10 seconds, wait for queue to be created
29 if (now - submitTime < 10000) {
30 //console.log('MxChat: Form was just submitted, waiting for queue creation...');
31 localStorage.removeItem('mxchat_check_queue_after_submit');
32
33 // Show processing message
34 if ($('.mxchat-processing-message').length === 0) {
35 const message = $('<div class="mxchat-processing-message" style="text-align: center; padding: 15px; background: #f0f7ff; border-radius: 8px; margin-top: 15px;">⏳ Queue created! Processing will start in a moment...</div>');
36 $('.mxchat-import-section').after(message);
37 }
38
39 // Check for queue multiple times with increasing delays
40 setTimeout(function() { checkForActiveQueues(); }, 1000);
41 setTimeout(function() { checkForActiveQueues(); }, 2000);
42 setTimeout(function() { checkForActiveQueues(); }, 3000);
43 setTimeout(function() { checkForActiveQueues(); }, 5000);
44 }
45 }
46
47 function checkForActiveQueues() {
48 $.ajax({
49 url: ajaxurl,
50 type: 'POST',
51 data: {
52 action: 'mxchat_get_status_updates',
53 nonce: mxchatAdmin.status_nonce
54 },
55 success: function(response) {
56 //console.log('MxChat: Checking for active queues...', response);
57
58 if (response.sitemap_queue_id && response.sitemap_status) {
59 if (response.sitemap_status.status === 'processing') {
60 //console.log('MxChat: Found active sitemap queue:', response.sitemap_queue_id);
61 startQueueProcessing(response.sitemap_queue_id, 'sitemap');
62 } else if (response.sitemap_status.status === 'complete') {
63 //console.log('MxChat: Sitemap queue already complete');
64 // ADD THIS LINE:
65 $('.mxchat-processing-message').remove();
66 // Show completed status card (no auto-refresh)
67 updateSitemapStatus(response.sitemap_status);
68 }
69 }
70
71 if (response.pdf_queue_id && response.pdf_status) {
72 if (response.pdf_status.status === 'processing') {
73 //console.log('MxChat: Found active PDF queue:', response.pdf_queue_id);
74 startQueueProcessing(response.pdf_queue_id, 'pdf');
75 } else if (response.pdf_status.status === 'complete') {
76 //console.log('MxChat: PDF queue already complete');
77 // ADD THIS LINE:
78 $('.mxchat-processing-message').remove();
79 // Show completed status card (no auto-refresh)
80 updatePdfStatus(response.pdf_status);
81 }
82 }
83
84 // ADD THIS: If no queues found at all, remove the message
85 if (!response.sitemap_queue_id && !response.pdf_queue_id) {
86 $('.mxchat-processing-message').remove();
87 }
88 },
89 error: function(xhr, status, error) {
90 console.error('MxChat: Error checking for active queues:', error);
91 // ADD THIS: Remove message on error too
92 $('.mxchat-processing-message').remove();
93 }
94 });
95 }
96
97 /**
98 * Start processing a queue
99 */
100 function startQueueProcessing(queueId, queueType) {
101 if (isProcessingQueue) {
102 //console.log('MxChat: Already processing a queue, skipping');
103 return;
104 }
105
106 isProcessingQueue = true;
107 currentQueueId = queueId;
108 currentQueueType = queueType;
109
110 //console.log('MxChat: Starting queue processing:', queueId, queueType);
111
112 // Remove any "waiting" messages
113 $('.mxchat-processing-message').remove();
114
115 // Create or update status card
116 createOrUpdateStatusCard(queueType);
117
118 // Start the processing loop
119 processNextQueueItem();
120 }
121
122 /**
123 * Process the next item in the queue
124 */
125 function processNextQueueItem() {
126 if (!isProcessingQueue) {
127 //console.log('MxChat: Processing stopped');
128 return;
129 }
130
131 // Get next item from queue
132 $.ajax({
133 url: ajaxurl,
134 type: 'POST',
135 data: {
136 action: 'mxchat_get_next_queue_item',
137 nonce: mxchatAdmin.queue_nonce,
138 queue_id: currentQueueId
139 },
140 success: function(response) {
141 if (!response.success) {
142 console.error('MxChat: Error getting next queue item:', response.data);
143 // Check if queue is actually complete despite error
144 verifyQueueCompletion();
145 return;
146 }
147
148 if (response.data.complete) {
149 // Queue is complete!
150 //console.log('MxChat: Queue processing complete!');
151 handleQueueComplete();
152 return;
153 }
154
155 // Process this item
156 const item = response.data.item;
157 //console.log('MxChat: Processing item:', item.type, item.id);
158
159 processQueueItem(item);
160 },
161 error: function(xhr, status, error) {
162 console.error('MxChat: AJAX error getting next item:', error);
163 // Network error - verify queue status before retrying
164 setTimeout(function() {
165 verifyQueueCompletion();
166 }, 2000);
167 }
168 });
169 }
170
171 /**
172 * Verify if queue is actually complete
173 * Prevents infinite loops when last item fails
174 */
175 function verifyQueueCompletion() {
176 //console.log('MxChat: Verifying queue completion status...');
177
178 $.ajax({
179 url: ajaxurl,
180 type: 'POST',
181 data: {
182 action: 'mxchat_get_queue_status',
183 nonce: mxchatAdmin.queue_nonce,
184 queue_id: currentQueueId
185 },
186 success: function(response) {
187 if (response.success) {
188 const status = response.data;
189
190 // If no pending or processing items, queue is done
191 if (status.pending === 0 && status.processing === 0) {
192 //console.log('MxChat: Queue verified as complete');
193 handleQueueComplete();
194 } else {
195 // Still has items, try to continue
196 //console.log('MxChat: Queue still has pending items, continuing...');
197 processNextQueueItem();
198 }
199 } else {
200 // Can't verify, assume complete to prevent infinite loop
201 //console.log('MxChat: Could not verify queue status, assuming complete');
202 handleQueueComplete();
203 }
204 },
205 error: function() {
206 // Can't verify, assume complete to prevent infinite loop
207 //console.log('MxChat: Network error verifying queue, assuming complete');
208 handleQueueComplete();
209 }
210 });
211 }
212
213 /**
214 * Process a single queue item
215 * Never stops the queue - always continues regardless of success/failure
216 */
217 function processQueueItem(item) {
218 $.ajax({
219 url: ajaxurl,
220 type: 'POST',
221 data: {
222 action: 'mxchat_process_queue_item',
223 nonce: mxchatAdmin.queue_nonce,
224 item_id: item.id,
225 item_type: item.type,
226 item_data: item.data,
227 bot_id: item.bot_id
228 },
229 success: function(response) {
230 if (response.success) {
231 // Item processed successfully
232 //console.log('MxChat: Item processed successfully:', item.id);
233
234 // Update progress
235 updateQueueProgress();
236
237 // Small delay to prevent server overload, then process next
238 setTimeout(function() {
239 processNextQueueItem();
240 }, 500); // 500ms delay between items
241
242 } else {
243 // Item failed but we KEEP GOING
244 console.warn('MxChat: Item processing failed (will continue):', item.type, item.id);
245 console.warn('MxChat: Error details:', response.data);
246
247 // Update progress to reflect the attempt
248 updateQueueProgress();
249
250 // Continue to next item regardless
251 setTimeout(function() {
252 processNextQueueItem();
253 }, 500);
254 }
255 },
256 error: function(xhr, status, error) {
257 // Network error - log it but KEEP GOING
258 console.error('MxChat: AJAX/Network error processing item:', item.id, error);
259
260 // Update progress
261 updateQueueProgress();
262
263 // Wait a bit longer for network errors, then continue
264 setTimeout(function() {
265 processNextQueueItem();
266 }, 1000);
267 }
268 });
269 }
270
271 /**
272 * Update queue progress (fetches latest stats)
273 */
274 function updateQueueProgress() {
275 $.ajax({
276 url: ajaxurl,
277 type: 'POST',
278 data: {
279 action: 'mxchat_get_queue_status',
280 nonce: mxchatAdmin.queue_nonce,
281 queue_id: currentQueueId
282 },
283 success: function(response) {
284 if (response.success) {
285 const status = response.data;
286
287 // Update the appropriate status card
288 if (currentQueueType === 'pdf') {
289 updatePdfStatusFromQueue(status);
290 } else {
291 updateSitemapStatusFromQueue(status);
292 }
293 }
294 }
295 });
296 }
297
298 /**
299 * Handle queue completion
300 * NO AUTO-REFRESH - Show completed card with errors until dismissed
301 */
302 function handleQueueComplete() {
303 isProcessingQueue = false;
304
305 //console.log('MxChat: Queue processing completed - showing final results');
306
307 // Get final status with error details
308 $.ajax({
309 url: ajaxurl,
310 type: 'POST',
311 data: {
312 action: 'mxchat_get_queue_status',
313 nonce: mxchatAdmin.queue_nonce,
314 queue_id: currentQueueId
315 },
316 success: function(response) {
317 if (response.success) {
318 const status = response.data;
319
320 // Show completed status card (NO REFRESH)
321 if (currentQueueType === 'pdf') {
322 showCompletedPdfCard(status);
323 } else {
324 showCompletedSitemapCard(status);
325 }
326
327 // Mark the queue as complete on server
328 markQueueAsComplete(currentQueueId);
329
330 // Show notification based on results
331 if (status.failed > 0) {
332 showNotification('warning',
333 `Processing completed: ${status.completed} succeeded, ${status.failed} failed. ` +
334 `Review errors below and dismiss when ready.`
335 );
336 } else {
337 showNotification('success',
338 `Processing completed successfully! All ${status.completed} items processed. ` +
339 `Dismiss the status card when ready.`
340 );
341 }
342
343 // NO AUTO-REFRESH - User must manually dismiss
344 } else {
345 // Couldn't get final status, just show generic completion
346 showNotification('success', 'Processing completed! Refresh page to see final results.');
347 }
348 },
349 error: function() {
350 // Error getting final status
351 showNotification('success', 'Processing completed! Refresh page to see final results.');
352 }
353 });
354 }
355
356 /**
357 * Show completed PDF card with full error details (NO RETRY BUTTON)
358 */
359 function showCompletedPdfCard(status) {
360 let $card = $('.mxchat-status-card:contains("PDF Processing")');
361
362 if ($card.length === 0) {
363 return;
364 }
365
366 // Remove processing UI elements
367 $card.find('.mxchat-stop-form').remove();
368 $card.find('.mxchat-status-warning').remove();
369
370 // Update header with completion badge
371 $card.find('.mxchat-status-badge').remove();
372 if (status.failed > 0) {
373 $card.find('.mxchat-status-header h4').after(
374 '<span class="mxchat-status-badge mxchat-status-warning" style="margin-left: 10px; padding: 4px 12px; border-radius: 4px; font-size: 12px; font-weight: normal;">⚠️ Completed with ' +
375 status.failed + ' failures - Refresh to view entries</span>'
376 );
377 } else {
378 $card.find('.mxchat-status-header h4').after(
379 '<span class="mxchat-status-badge mxchat-status-success" style="margin-left: 10px; padding: 4px 12px; border-radius: 4px; font-size: 12px; font-weight: normal;">✓ Complete - Refresh to view entries</span>'
380 );
381 }
382
383 // Add dismiss button
384 addDismissButton($card);
385
386 // Update progress bar to 100%
387 $card.find('.mxchat-progress-fill').css('width', '100%');
388
389 // Update details with final stats
390 let detailsHtml = '<div style="background: #f0f7ff; padding: 15px; border-radius: 4px; margin-bottom: 15px;">';
391 detailsHtml += '<h4 style="margin: 0 0 10px 0;">📊 Final Results</h4>';
392 detailsHtml += '<p style="margin: 5px 0;"><strong>Total Pages:</strong> ' + status.total + '</p>';
393 detailsHtml += '<p style="margin: 5px 0; color: #2ea44f;"><strong>✓ Successfully Processed:</strong> ' + status.completed + '</p>';
394
395 if (status.failed > 0) {
396 detailsHtml += '<p style="margin: 5px 0; color: #cf222e;"><strong>✗ Failed:</strong> ' + status.failed + '</p>';
397 }
398
399 detailsHtml += '</div>';
400
401 // Add error details if there are failures (NO RETRY BUTTON)
402 if (status.failed > 0 && status.failed_items && status.failed_items.length > 0) {
403 detailsHtml += '<div class="mxchat-error-summary" style="background: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; margin-top: 15px;">';
404 detailsHtml += '<h4 style="margin: 0 0 10px 0; color: #856404;">⚠️ Failed Pages</h4>';
405
406 detailsHtml += '<details style="cursor: pointer;">';
407 detailsHtml += '<summary style="font-weight: bold; color: #856404; padding: 5px 0;">Click to view ' + status.failed_items.length + ' failed pages</summary>';
408
409 detailsHtml += '<div style="margin-top: 10px; max-height: 400px; overflow-y: auto;">';
410 detailsHtml += '<table style="width: 100%; border-collapse: collapse;">';
411 detailsHtml += '<thead><tr style="background: #f5f5f5;"><th style="padding: 8px; text-align: left;">Page</th><th style="padding: 8px; text-align: left;">Error</th><th style="padding: 8px; text-align: left;">Attempts</th></tr></thead>';
412 detailsHtml += '<tbody>';
413
414 status.failed_items.forEach(function(item) {
415 const data = JSON.parse(item.item_data);
416 const pageNum = data.page_number || 'Unknown';
417
418 detailsHtml += '<tr style="border-bottom: 1px solid #ddd;">';
419 detailsHtml += '<td style="padding: 8px;">Page ' + pageNum + '</td>';
420 detailsHtml += '<td style="padding: 8px; word-break: break-word;">' + (item.error_message || 'Unknown error') + '</td>';
421 detailsHtml += '<td style="padding: 8px;">' + item.attempts + '</td>';
422 detailsHtml += '</tr>';
423 });
424
425 detailsHtml += '</tbody></table>';
426 detailsHtml += '</div>';
427 detailsHtml += '</details>';
428
429 detailsHtml += '</div>';
430 }
431
432 $card.find('.mxchat-status-details').html(detailsHtml);
433 }
434
435 /**
436 * Show completed sitemap card with full error details (NO RETRY BUTTON)
437 */
438 function showCompletedSitemapCard(status) {
439 let $card = $('.mxchat-status-card:contains("Sitemap Processing")');
440
441 if ($card.length === 0) {
442 return;
443 }
444
445 // Remove processing UI elements
446 $card.find('.mxchat-stop-form').remove();
447 $card.find('.mxchat-status-warning').remove();
448
449 // Update header with completion badge
450 $card.find('.mxchat-status-badge').remove();
451 if (status.failed > 0) {
452 $card.find('.mxchat-status-header h4').after(
453 '<span class="mxchat-status-badge mxchat-status-warning" style="margin-left: 10px; padding: 4px 12px; border-radius: 4px; font-size: 12px; font-weight: normal;">⚠️ Completed with ' +
454 status.failed + ' failures - Refresh to view entries</span>'
455 );
456 } else {
457 $card.find('.mxchat-status-header h4').after(
458 '<span class="mxchat-status-badge mxchat-status-success" style="margin-left: 10px; padding: 4px 12px; border-radius: 4px; font-size: 12px; font-weight: normal;">✓ Complete - Refresh to view entries</span>'
459 );
460 }
461
462 // Add dismiss button
463 addDismissButton($card);
464
465 // Update progress bar to 100%
466 $card.find('.mxchat-progress-fill').css('width', '100%');
467
468 // Update details with final stats
469 let detailsHtml = '<div style="background: #f0f7ff; padding: 15px; border-radius: 4px; margin-bottom: 15px;">';
470 detailsHtml += '<h4 style="margin: 0 0 10px 0;">📊 Final Results</h4>';
471 detailsHtml += '<p style="margin: 5px 0;"><strong>Total URLs:</strong> ' + status.total + '</p>';
472 detailsHtml += '<p style="margin: 5px 0; color: #2ea44f;"><strong>✓ Successfully Processed:</strong> ' + status.completed + '</p>';
473
474 if (status.failed > 0) {
475 detailsHtml += '<p style="margin: 5px 0; color: #cf222e;"><strong>✗ Failed:</strong> ' + status.failed + '</p>';
476 }
477
478 detailsHtml += '</div>';
479
480 // Add error details if there are failures (NO RETRY BUTTON)
481 if (status.failed > 0 && status.failed_items && status.failed_items.length > 0) {
482 detailsHtml += '<div class="mxchat-error-summary" style="background: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; margin-top: 15px;">';
483 detailsHtml += '<h4 style="margin: 0 0 10px 0; color: #856404;">⚠️ Failed URLs</h4>';
484
485 detailsHtml += '<details style="cursor: pointer;">';
486 detailsHtml += '<summary style="font-weight: bold; color: #856404; padding: 5px 0;">Click to view ' + status.failed_items.length + ' failed URLs</summary>';
487
488 detailsHtml += '<div style="margin-top: 10px; max-height: 400px; overflow-y: auto;">';
489 detailsHtml += '<table style="width: 100%; border-collapse: collapse;">';
490 detailsHtml += '<thead><tr style="background: #f5f5f5;"><th style="padding: 8px; text-align: left;">URL</th><th style="padding: 8px; text-align: left;">Error</th><th style="padding: 8px; text-align: left;">Attempts</th></tr></thead>';
491 detailsHtml += '<tbody>';
492
493 status.failed_items.forEach(function(item) {
494 const data = JSON.parse(item.item_data);
495 const url = data.url || 'Unknown URL';
496 const displayUrl = url.length > 60 ? url.substring(0, 57) + '...' : url;
497
498 detailsHtml += '<tr style="border-bottom: 1px solid #ddd;">';
499 detailsHtml += '<td style="padding: 8px;"><a href="' + url + '" target="_blank" style="color: #0073aa; text-decoration: none;">' + displayUrl + '</a></td>';
500 detailsHtml += '<td style="padding: 8px; word-break: break-word;">' + (item.error_message || 'Unknown error') + '</td>';
501 detailsHtml += '<td style="padding: 8px;">' + item.attempts + '</td>';
502 detailsHtml += '</tr>';
503 });
504
505 detailsHtml += '</tbody></table>';
506 detailsHtml += '</div>';
507 detailsHtml += '</details>';
508
509 detailsHtml += '</div>';
510 }
511
512 $card.find('.mxchat-status-details').html(detailsHtml);
513 }
514
515 /**
516 * Mark queue as complete on server side
517 * This prevents it from auto-starting on page refresh
518 */
519 function markQueueAsComplete(queueId) {
520 // This is a fire-and-forget call to update queue status
521 $.ajax({
522 url: ajaxurl,
523 type: 'POST',
524 data: {
525 action: 'mxchat_mark_queue_complete',
526 nonce: mxchatAdmin.queue_nonce,
527 queue_id: queueId
528 },
529 success: function(response) {
530 //console.log('MxChat: Queue marked as complete on server');
531 },
532 error: function() {
533 //console.log('MxChat: Could not mark queue as complete, but continuing');
534 }
535 });
536 }
537
538 /**
539 * Stop processing button handler
540 */
541 $(document).on('submit', '.mxchat-stop-form', function() {
542 //console.log('MxChat: Stop processing requested');
543 isProcessingQueue = false;
544 currentQueueId = null;
545 currentQueueType = null;
546 });
547
548 /**
549 * Create or update status card
550 */
551 function createOrUpdateStatusCard(queueType) {
552 const cardTitle = queueType === 'pdf' ? 'PDF Processing Status' : 'Sitemap Processing Status';
553 let $card = $('.mxchat-status-card:contains("' + cardTitle + '")');
554
555 if ($card.length === 0) {
556 // Create new card
557 let html = '<div class="mxchat-status-card">';
558 html += '<div class="mxchat-status-header">';
559 html += '<h4>' + cardTitle + '</h4>';
560 html += '<div class="mxchat-status-warning" style="background: #fff3cd; color: #856404; padding: 8px 12px; border-radius: 4px; font-size: 13px; margin: 10px 0;">';
561 html += '⚠️ <strong>Keep this tab open</strong> - Processing runs in your browser';
562 html += '</div>';
563 html += '<form method="post" class="mxchat-stop-form" action="' +
564 mxchatAdmin.admin_url + 'admin-post.php?action=mxchat_stop_processing">';
565 html += '<input type="hidden" name="mxchat_stop_processing_nonce" value="' +
566 mxchatAdmin.stop_nonce + '">';
567 html += '<button type="submit" name="stop_processing" class="mxchat-button-secondary">';
568 html += 'Stop Processing</button></form>';
569 html += '</div>';
570 html += '<div class="mxchat-progress-bar">';
571 html += '<div class="mxchat-progress-fill" style="width: 0%"></div>';
572 html += '</div>';
573 html += '<div class="mxchat-status-details">';
574 html += '<p>Initializing...</p>';
575 html += '</div>';
576 html += '</div>';
577
578 // Insert card
579 let $importSection = $('.mxchat-import-section');
580 if ($importSection.length > 0) {
581 $importSection.after($(html));
582 }
583 }
584 }
585
586 /**
587 * Update PDF status from queue data (DURING PROCESSING)
588 */
589 function updatePdfStatusFromQueue(status) {
590 let $card = $('.mxchat-status-card:contains("PDF Processing")');
591
592 if ($card.length === 0) {
593 return;
594 }
595
596 // Update progress bar
597 $card.find('.mxchat-progress-fill').css('width', status.percentage + '%');
598
599 // Update details
600 let detailsHtml = '<p>Progress: ' + (status.completed + status.failed) + ' of ' +
601 status.total + ' pages (' + status.percentage + '%)</p>';
602
603 if (status.completed > 0) {
604 detailsHtml += '<p><strong>✓ Processed successfully:</strong> ' + status.completed + '</p>';
605 }
606
607 if (status.failed > 0) {
608 detailsHtml += '<p class="error-count"><strong>✗ Failed pages:</strong> ' + status.failed + '</p>';
609 }
610
611 detailsHtml += '<p><strong>Status:</strong> Processing</p>';
612
613 $card.find('.mxchat-status-details').html(detailsHtml);
614 }
615
616 /**
617 * Update sitemap status from queue data (DURING PROCESSING)
618 */
619 function updateSitemapStatusFromQueue(status) {
620 let $card = $('.mxchat-status-card:contains("Sitemap Processing")');
621
622 if ($card.length === 0) {
623 return;
624 }
625
626 // Update progress bar
627 $card.find('.mxchat-progress-fill').css('width', status.percentage + '%');
628
629 // Update details
630 let detailsHtml = '<p>Progress: ' + (status.completed + status.failed) + ' of ' +
631 status.total + ' URLs (' + status.percentage + '%)</p>';
632
633 if (status.completed > 0) {
634 detailsHtml += '<p><strong>✓ Processed successfully:</strong> ' + status.completed + '</p>';
635 }
636
637 if (status.failed > 0) {
638 detailsHtml += '<p class="error-count"><strong>✗ Failed URLs:</strong> ' + status.failed + '</p>';
639 }
640
641 detailsHtml += '<p><strong>Status:</strong> Processing</p>';
642
643 $card.find('.mxchat-status-details').html(detailsHtml);
644 }
645
646 // ========================================
647 // STATUS UPDATES FOR COMPLETED QUEUES (FROM SERVER)
648 // ========================================
649
650 /**
651 * Dismiss completed status button handler
652 */
653 $(document).on('click', '.mxchat-dismiss-button', function() {
654 const $button = $(this);
655 const $card = $button.closest('.mxchat-status-card');
656
657 let cardType = $card.data('card-type');
658 if (!cardType) {
659 cardType = $card.find('h4').text().includes('PDF') ? 'pdf' : 'sitemap';
660 }
661
662 $card.fadeOut(300, function() {
663 $(this).remove();
664 });
665
666 $.ajax({
667 url: ajaxurl,
668 type: 'POST',
669 data: {
670 action: 'mxchat_clear_queue',
671 nonce: mxchatAdmin.queue_nonce,
672 queue_id: $card.data('queue-id') || ''
673 },
674 success: function(response) {
675 //console.log('MxChat: Queue cleared');
676 }
677 });
678 });
679
680 /**
681 * Update PDF status card (for already completed queues on page load)
682 */
683 function updatePdfStatus(status) {
684 let $pdfCard = $('.mxchat-status-card:contains("PDF Processing")');
685
686 if ($pdfCard.length === 0 && status) {
687 createPdfStatusCard(status);
688 $pdfCard = $('.mxchat-status-card:contains("PDF Processing")');
689 }
690
691 if ($pdfCard.length > 0 && status.status === 'complete') {
692 // Show as completed (same as showCompletedPdfCard but from server data)
693 showCompletedPdfCard(status);
694 }
695 }
696
697 /**
698 * Update sitemap status card (for already completed queues on page load)
699 */
700 function updateSitemapStatus(status) {
701 let $sitemapCard = $('.mxchat-status-card:contains("Sitemap Processing")');
702
703 if ($sitemapCard.length === 0 && status) {
704 createSitemapStatusCard(status);
705 $sitemapCard = $('.mxchat-status-card:contains("Sitemap Processing")');
706 }
707
708 if ($sitemapCard.length > 0 && status.status === 'complete') {
709 // Show as completed (same as showCompletedSitemapCard but from server data)
710 showCompletedSitemapCard(status);
711 }
712 }
713
714 /**
715 * Create PDF status card
716 */
717 function createPdfStatusCard(status) {
718 let html = '<div class="mxchat-status-card" data-queue-id="' + (status.queue_id || '') + '">';
719 html += '<div class="mxchat-status-header">';
720 html += '<h4>PDF Processing Status</h4>';
721 html += '</div>';
722 html += '<div class="mxchat-progress-bar">';
723 html += '<div class="mxchat-progress-fill" style="width: ' + status.percentage + '%"></div>';
724 html += '</div>';
725 html += '<div class="mxchat-status-details">';
726 html += '<p>Progress: ' + status.processed_pages + ' of ' + status.total_pages + ' pages</p>';
727 html += '</div>';
728 html += '</div>';
729
730 $('.mxchat-import-section').after($(html));
731 }
732
733 /**
734 * Create sitemap status card
735 */
736 function createSitemapStatusCard(status) {
737 let html = '<div class="mxchat-status-card" data-queue-id="' + (status.queue_id || '') + '">';
738 html += '<div class="mxchat-status-header">';
739 html += '<h4>Sitemap Processing Status</h4>';
740 html += '</div>';
741 html += '<div class="mxchat-progress-bar">';
742 html += '<div class="mxchat-progress-fill" style="width: ' + status.percentage + '%"></div>';
743 html += '</div>';
744 html += '<div class="mxchat-status-details">';
745 html += '<p>Progress: ' + status.processed_urls + ' of ' + status.total_urls + ' URLs</p>';
746 html += '</div>';
747 html += '</div>';
748
749 $('.mxchat-import-section').after($(html));
750 }
751
752 /**
753 * Add dismiss button to completed cards
754 */
755 function addDismissButton($card) {
756 if ($card.find('.mxchat-dismiss-button').length === 0) {
757 const dismissButton = $('<button type="button" class="mxchat-dismiss-button" style="padding: 6px 12px; background: #666; color: white; border: none; border-radius: 3px; cursor: pointer; margin-left: 10px;">Dismiss</button>');
758 $card.find('.mxchat-status-header').append(dismissButton);
759 }
760 }
761
762 /**
763 * Show notification helper
764 */
765 function showNotification(type, message) {
766 const $notification = $('<div class="mxchat-kb-notification ' + type + '">' + message + '</div>');
767 $('.mxchat-content, body').first().prepend($notification);
768
769 setTimeout(function() {
770 $notification.fadeOut(300, function() {
771 $(this).remove();
772 });
773 }, 5000);
774 }
775
776 // ========================================
777 // ROLE-BASED CONTENT RESTRICTIONS (Keep existing code)
778 // ========================================
779
780 if ($('#mxchat-mappings-container').length > 0) {
781 loadTagRoleMappings();
782 }
783
784 $('#mxchat-add-tag-role').on('click', function() {
785 const tagSlug = $('#mxchat-tag-input').val().trim();
786 const roleRestriction = $('#mxchat-role-select').val();
787
788 if (!tagSlug) {
789 alert('Please enter a tag name');
790 return;
791 }
792
793 const $btn = $(this);
794 $btn.prop('disabled', true).html('<span class="dashicons dashicons-update-alt"></span> Adding...');
795
796 $.ajax({
797 url: ajaxurl,
798 type: 'POST',
799 data: {
800 action: 'mxchat_add_tag_role_mapping',
801 nonce: mxchatAdmin.settings_nonce,
802 tag_slug: tagSlug,
803 role_restriction: roleRestriction
804 },
805 success: function(response) {
806 if (response.success) {
807 $('#mxchat-tag-input').val('');
808 $('#mxchat-role-select').val('public');
809 loadTagRoleMappings();
810 showNotification('success', 'Tag-role mapping added successfully!');
811 } else {
812 alert('Error: ' + response.data);
813 }
814 $btn.prop('disabled', false).html('<span class="dashicons dashicons-plus-alt"></span> Add Mapping');
815 },
816 error: function() {
817 alert('Network error occurred');
818 $btn.prop('disabled', false).html('<span class="dashicons dashicons-plus-alt"></span> Add Mapping');
819 }
820 });
821 });
822
823 $(document).on('click', '.mxchat-delete-mapping', function() {
824 if (!confirm('Are you sure you want to delete this mapping?')) {
825 return;
826 }
827
828 const $btn = $(this);
829 const $row = $btn.closest('tr');
830 const tagSlug = $btn.data('tag-slug');
831
832 $btn.html('<span class="dashicons dashicons-update-alt"></span> Deleting...');
833 $row.addClass('mxchat-row-deleting');
834
835 $.ajax({
836 url: ajaxurl,
837 type: 'POST',
838 data: {
839 action: 'mxchat_delete_tag_role_mapping',
840 nonce: mxchatAdmin.settings_nonce,
841 tag_slug: tagSlug
842 },
843 success: function(response) {
844 if (response.success) {
845 $row.fadeOut(300, function() {
846 $(this).remove();
847 if ($('.mxchat-mappings-table tbody tr').length === 0) {
848 $('.mxchat-mappings-table').hide();
849 $('#mxchat-no-mappings').show();
850 }
851 });
852 showNotification('success', 'Mapping deleted successfully!');
853 } else {
854 alert('Error: ' + response.data);
855 $btn.html('<span class="dashicons dashicons-trash"></span> Delete');
856 $row.removeClass('mxchat-row-deleting');
857 }
858 },
859 error: function() {
860 alert('Network error occurred');
861 $btn.html('<span class="dashicons dashicons-trash"></span> Delete');
862 $row.removeClass('mxchat-row-deleting');
863 }
864 });
865 });
866
867 $('#mxchat-bulk-update-roles').on('click', function() {
868 if (!confirm('This will update role restrictions for all existing content with mapped tags. Continue?')) {
869 return;
870 }
871
872 const $btn = $(this);
873 const $progress = $('#mxchat-bulk-update-progress');
874 const $result = $('#mxchat-bulk-update-result');
875
876 $progress.show();
877 $result.hide();
878 $btn.prop('disabled', true);
879
880 $progress.find('.mxchat-progress-text').text('Starting bulk update...');
881 $progress.find('.mxchat-progress-fill').css('width', '0%');
882
883 $.ajax({
884 url: ajaxurl,
885 type: 'POST',
886 data: {
887 action: 'mxchat_bulk_update_tag_roles',
888 nonce: mxchatAdmin.settings_nonce
889 },
890 success: function(response) {
891 $progress.hide();
892 $btn.prop('disabled', false);
893
894 if (response.success) {
895 $result.removeClass('error').addClass('success');
896
897 let resultHtml = '<h5>Bulk Update Complete</h5>';
898 resultHtml += '<p><strong>Total Updated:</strong> ' + response.data.updated_count + '</p>';
899 resultHtml += '<p><strong>Tags Processed:</strong> ' + response.data.tags_processed + '</p>';
900
901 if (response.data.details && response.data.details.length > 0) {
902 resultHtml += '<ul>';
903 response.data.details.forEach(function(detail) {
904 resultHtml += '<li>' + detail + '</li>';
905 });
906 resultHtml += '</ul>';
907 }
908
909 $result.html(resultHtml).show();
910 showNotification('success', 'Bulk update completed successfully!');
911 } else {
912 $result.removeClass('success').addClass('error');
913 $result.html('<h5>Update Failed</h5><p>' + response.data + '</p>').show();
914 }
915 },
916 error: function() {
917 $progress.hide();
918 $btn.prop('disabled', false);
919 $result.removeClass('success').addClass('error');
920 $result.html('<h5>Network Error</h5><p>Please try again.</p>').show();
921 }
922 });
923 });
924
925 function loadTagRoleMappings() {
926 const $container = $('#mxchat-mappings-container');
927 $container.html('<div class="mxchat-loading-mappings"><span class="mxchat-role-spinner is-active"></span> Loading mappings...</div>');
928
929 $.ajax({
930 url: ajaxurl,
931 type: 'POST',
932 data: {
933 action: 'mxchat_get_tag_role_mappings',
934 nonce: mxchatAdmin.settings_nonce
935 },
936 success: function(response) {
937 if (response.success && response.data.mappings.length > 0) {
938 $('#mxchat-no-mappings').hide();
939
940 let html = '<table class="mxchat-mappings-table">';
941 html += '<thead><tr><th>Tag</th><th>Role Restriction</th><th>Posts with Tag</th><th>Actions</th></tr></thead><tbody>';
942
943 response.data.mappings.forEach(function(mapping) {
944 html += '<tr>';
945 html += '<td><span class="mxchat-tag-badge"><span class="dashicons dashicons-tag"></span>' + mapping.tag_slug + '</span></td>';
946 html += '<td><span class="mxchat-role-badge ' + mapping.role_restriction + '">' + mapping.role_label + '</span></td>';
947 html += '<td><span class="mxchat-post-count"><span class="dashicons dashicons-admin-post"></span>' + mapping.post_count + '</span></td>';
948 html += '<td><div class="mxchat-mapping-actions"><button class="mxchat-delete-mapping" data-tag-slug="' + mapping.tag_slug + '"><span class="dashicons dashicons-trash"></span> Delete</button></div></td>';
949 html += '</tr>';
950 });
951
952 html += '</tbody></table>';
953 $container.html(html);
954 } else {
955 $container.html('');
956 $('#mxchat-no-mappings').show();
957 }
958 },
959 error: function() {
960 $container.html('<div class="mxchat-error">Failed to load mappings. Please refresh the page.</div>');
961 }
962 });
963 }
964
965 // ========================================
966 // PINECONE DELETE HANDLER (Keep existing code)
967 // ========================================
968
969 $(document).on('click', '.delete-button-ajax', function(e) {
970 e.preventDefault();
971
972 if (!confirm('Are you sure you want to delete this entry?')) {
973 return;
974 }
975
976 var $button = $(this);
977 var $row = $button.closest('tr');
978 var vectorId = $button.data('vector-id');
979 var botId = $button.data('bot-id') || 'default';
980 var nonce = $button.data('nonce');
981
982 $button.prop('disabled', true);
983 $button.find('.dashicons').removeClass('dashicons-trash').addClass('dashicons-update-alt');
984 $row.addClass('mxchat-row-deleting');
985
986 $.ajax({
987 url: ajaxurl,
988 type: 'POST',
989 data: {
990 action: 'mxchat_delete_pinecone_prompt',
991 nonce: nonce,
992 vector_id: vectorId,
993 bot_id: botId
994 },
995 success: function(response) {
996 if (response.success) {
997 $row.fadeOut(500, function() {
998 $(this).remove();
999
1000 var $countSpan = $('.mxchat-record-count');
1001 if ($countSpan.length) {
1002 var currentText = $countSpan.text();
1003 var matches = currentText.match(/\((\d+)/);
1004 if (matches) {
1005 var currentCount = parseInt(matches[1]);
1006 var newCount = Math.max(0, currentCount - 1);
1007 $countSpan.text($countSpan.text().replace(/\(\d+/, '(' + newCount));
1008 }
1009 }
1010 });
1011
1012 $('<div class="notice notice-success is-dismissible"><p>Entry deleted successfully from Pinecone.</p></div>')
1013 .insertAfter('.mxchat-hero')
1014 .delay(3000)
1015 .fadeOut();
1016 } else {
1017 $button.prop('disabled', false);
1018 $button.find('.dashicons').removeClass('dashicons-update-alt').addClass('dashicons-trash');
1019 $row.removeClass('mxchat-row-deleting');
1020 alert('Error: ' + response.data);
1021 }
1022 },
1023 error: function() {
1024 $button.prop('disabled', false);
1025 $button.find('.dashicons').removeClass('dashicons-update-alt').addClass('dashicons-trash');
1026 $row.removeClass('mxchat-row-deleting');
1027 alert('Network error occurred');
1028 }
1029 });
1030 });
1031 });