PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.4.1
MxChat – AI Chatbot & Content Generation for WordPress v2.4.1
3.2.22 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 All 153 releases
← All changes | js/content-selector.js +250 -521 3.2.152.4.1 View file →
@@ -8,14 +8,8 @@
8 8 const $pagination = $('.mxchat-kb-pagination');
9 9 const $processButton = $('#mxchat-kb-process-selected');
10 10 const $selectAll = $('#mxchat-kb-select-all');
11 11 const $selectionCount = $('.mxchat-kb-selection-count');
12 - const $acfPdfExtractCheckbox = $('#mxchat-kb-acf-pdf-extract');
13 -
14 - // Restore last-used ACF→PDF extract preference from the server-localized default.
15 - if (typeof mxchatSelector !== 'undefined' && mxchatSelector.acfPdfExtractDefault) {
16 - $acfPdfExtractCheckbox.prop('checked', true);
17 - }
18 12
19 13 // Filter elements
20 14 const $searchInput = $('#mxchat-kb-content-search');1
21 15 const $typeFilter = $('#mxchat-kb-content-type-filter');
@@ -43,126 +37,51 @@
43 37 // Handle import option box clicks (for non-WordPress options)
44 38 $('.mxchat-import-box').on('click', function() {
45 39 const $box = $(this);
46 40 const option = $box.data('option');
47 -
41 +
48 42 // Skip if this is the WordPress option (it has its own handler)
49 43 if (option === 'wordpress') {
50 44 return;
51 45 }
52 -
46 +
53 47 // Update active state
54 48 $('.mxchat-import-box').removeClass('active');
55 49 $box.addClass('active');
56 -
50 +
57 51 // Hide all input areas
58 - $('#mxchat-url-input-area, #mxchat-content-input-area, #mxchat-pdf-upload-area, #mxchat-youtube-input-area').hide();
59 -
60 - // Hide sitemap-specific sections (but NOT for sitemap option - let detection logic handle it)
61 - if (option !== 'sitemap') {
62 - $('#mxchat-detected-sitemaps, #mxchat-no-sitemaps, #mxchat-sitemaps-loading').hide();
63 - }
64 -
52 + $('#mxchat-url-input-area, #mxchat-content-input-area').hide();
53 +
65 54 // Handle different import options
66 55 switch (option) {
67 - case 'pdf-url':
56 + case 'pdf':
68 57 case 'sitemap':
69 58 case 'url':
70 59 // Show URL input area with appropriate placeholder
71 60 $('#mxchat-url-input-area').show();
72 61 $('#sitemap_url').attr('placeholder', $box.data('placeholder'));
73 - $('#import_type').val(option === 'pdf-url' ? 'pdf' : option);
74 -
75 - // UPDATED: Add or update bot_id hidden field for URL forms
76 - updateBotIdInForm('#mxchat-url-form');
77 -
62 + $('#import_type').val(option);
63 +
78 64 // Update the description text based on the import type
79 65 let descriptionText = '';
80 - if (option === 'pdf-url') {
66 + if (option === 'pdf') {
81 67 descriptionText = 'Import a PDF document by entering its URL above. PDFs are processed via cron job. If processing does not start, you can manually process batch 5 pages at a time.';
82 68 } else if (option === 'sitemap') {
83 69 descriptionText = 'Enter a content-specific sub-sitemap URL, not the sitemap index. Sitemaps are processed via cron job. If processing does not start, you can manually process batch 5 pages at a time.';
84 - // Re-show sitemap sections if they were previously loaded
85 - const $sitemapsList = $('#mxchat-sitemaps-list');
86 - if ($sitemapsList.children().length > 0) {
87 - // Sitemaps were already loaded, just show the container
88 - $('#mxchat-detected-sitemaps').show();
89 - } else if ($('#mxchat-no-sitemaps').data('was-shown')) {
90 - // No sitemaps message was shown before
91 - $('#mxchat-no-sitemaps').show();
92 - }
93 - // Note: If neither condition is true, initSitemapDetection will show loading state
94 70 } else if (option === 'url') {
95 71 descriptionText = 'Import content from any webpage by entering its URL.';
96 72 }
97 73 $('#url-description-text').text(descriptionText);
98 74 break;
99 -
75 +
100 76 case 'content':
101 77 // Show content input area
102 78 $('#mxchat-content-input-area').show();
103 -
104 - // UPDATED: Add or update bot_id hidden field for content forms
105 - updateBotIdInForm('#mxchat-content-form');
106 79 break;
107 -
108 - case 'pdf-upload':
109 - // Show PDF file upload area
110 - $('#mxchat-pdf-upload-area').show();
111 -
112 - // Add or update bot_id hidden field for PDF upload form
113 - updateBotIdInForm('#mxchat-pdf-upload-form');
114 - break;
115 -
116 - case 'youtube':
117 - // Show YouTube import area
118 - $('#mxchat-youtube-input-area').show();
119 -
120 - // Add or update bot_id hidden field for YouTube form
121 - updateBotIdInForm('#mxchat-youtube-form');
122 - break;
123 80 }
124 81 });
125 82
126 -// YouTube import: toggle the manual-description box with the mode radios, and
127 -// only require the textarea when "Write my own" is selected.
128 -$(document).on('change', 'input[name="youtube_description_mode"]', function() {
129 - const manual = $('input[name="youtube_description_mode"]:checked').val() === 'manual';
130 - $('#mxchat-youtube-description-field').toggle(manual);
131 - $('#mxchat-youtube-description').prop('required', manual);
132 -});
133 83
134 -// If the server bounced back with prefill state (auto-import found no
135 -// transcript), reopen the YouTube form in manual mode ready to augment.
136 -if ($('#mxchat-youtube-form').data('yt-prefill')) {
137 - $('.mxchat-import-box[data-option="youtube"]').trigger('click');
138 - $('input[name="youtube_description_mode"]').trigger('change');
139 - $('#mxchat-youtube-description').trigger('focus');
140 -}
141 -
142 -// Helper function to add/update bot_id hidden field in forms
143 -function updateBotIdInForm(formSelector) {
144 - const $form = $(formSelector);
145 - if ($form.length === 0) return;
146 -
147 - // Get current bot_id from the bot selector dropdown
148 - const currentBotId = $('#mxchat-bot-selector').val();
149 -
150 - // Only add bot_id field if multi-bot is active and bot is not 'default'
151 - if (currentBotId && currentBotId !== 'default') {
152 - // Remove existing bot_id field if it exists
153 - $form.find('input[name="bot_id"]').remove();
154 -
155 - // Add new bot_id field
156 - $form.append('<input type="hidden" name="bot_id" value="' + currentBotId + '">');
157 -
158 - console.log('Updated bot_id in form ' + formSelector + ' to: ' + currentBotId);
159 - } else {
160 - // Remove bot_id field if bot is default
161 - $form.find('input[name="bot_id"]').remove();
162 - }
163 -}
164 -
165 84 // Load content via AJAX
166 85 function loadContent() {
167 86 $loading.show();
168 87 $contentList.find('.mxchat-kb-content-item').remove();
@@ -170,9 +89,9 @@
170 89 const data = {
171 90 action: 'mxchat_get_content_list',
172 91 nonce: mxchatSelector.nonce,
173 92 page: currentPage,
174 - per_page: 100,
93 + per_page: 50,
175 94 search: $searchInput.val(),
176 95 post_type: $typeFilter.val(),
177 96 post_status: $statusFilter.val(),
178 97 processed_filter: $processedFilter.val()
@@ -237,22 +156,18 @@
237 156
238 157 // Render content items
239 158 function renderContentItems(items) {
240 159 let html = '';
241 -
160 +
242 161 items.forEach(function(item) {
243 162 const isSelected = selectedItems.has(item.id);
244 163 const isProcessed = item.already_processed;
245 - const chunkCount = item.chunk_count || 0;
246 -
247 - // Updated badge text - include chunk count if > 1
248 - let badgeText = 'Not In Knowledge Base';
249 - if (isProcessed) {
250 - badgeText = chunkCount > 1 ? `In Knowledge Base (${chunkCount} chunks)` : 'In Knowledge Base';
251 - }
164 +
165 + // Updated badge text
166 + const badgeText = isProcessed ? 'In Knowledge Base' : 'Not In Knowledge Base';
252 167 const badgeClass = isProcessed ? 'mxchat-kb-processed-badge' : 'mxchat-kb-unprocessed-badge';
253 -
254 -
168 +
169 +
255 170 html += `
256 171 <div class="mxchat-kb-content-item ${isProcessed ? 'processed' : ''}" data-id="${item.id}">
257 172 <div class="mxchat-kb-content-checkbox">
258 173 <input type="checkbox" id="content-${item.id}" ${isSelected ? 'checked' : ''}>
@@ -272,9 +187,9 @@
272 187 </div>
273 188 </div>
274 189 `;
275 190 });
276 -
191 +
277 192 $contentList.html(html);
278 193
279 194 // Add event listeners for checkboxes using delegation for better performance
280 195 $contentList.off('change', 'input[type="checkbox"]').on('change', 'input[type="checkbox"]', function() {
@@ -347,36 +262,18 @@
347 262 function updateSelection() {
348 263 const selectedCount = selectedItems.size;
349 264 $selectionCount.text(selectedCount + ' ' + (selectedCount === 1 ? 'selected' : 'selected'));
350 265 $('.mxchat-kb-selected-count').text('(' + selectedCount + ')');
351 -
352 - // Show/hide clear all selections link
353 - let $clearAllLink = $('.mxchat-kb-clear-all-selections');
354 - if (selectedCount > 0) {
355 - if ($clearAllLink.length === 0) {
356 - $clearAllLink = $('<a href="#" class="mxchat-kb-clear-all-selections" style="margin-left: 10px; font-size: 12px; color: var(--mxch-error, #dc2626);">Clear all</a>');
357 - $selectionCount.after($clearAllLink);
358 - $clearAllLink.on('click', function(e) {
359 - e.preventDefault();
360 - selectedItems.clear();
361 - $('.mxchat-kb-content-item input[type="checkbox"]').prop('checked', false);
362 - updateSelection();
363 - });
364 - }
365 - $clearAllLink.show();
366 - } else {
367 - $clearAllLink.hide();
368 - }
369 -
266 +
370 267 // Determine if any selected items are already processed
371 268 const hasProcessedItems = Array.from(selectedItems).some(id => {
372 269 const item = allItems.find(item => item.id === id);
373 270 return item && item.already_processed;
374 271 });
375 -
272 +
376 273 if (selectedCount > 0) {
377 274 $processButton.prop('disabled', false);
378 -
275 +
379 276 // Update button text based on selection
380 277 if (hasProcessedItems && selectedCount === 1) {
381 278 $processButton.text('Update Selected Content (1)').addClass('update-mode');
382 279 } else if (hasProcessedItems && selectedCount > 1) {
@@ -388,9 +285,9 @@
388 285 $processButton.prop('disabled', true);
389 286 $processButton.text('Process Selected Content').removeClass('update-mode mixed-mode');
390 287 $('.mxchat-kb-selected-count').text('(0)');
391 288 }
392 -
289 +
393 290 updateSelectAllState();
394 291 }
395 292
396 293 // Update "Select All" checkbox state
@@ -445,401 +342,295 @@
445 342 selectedItems.clear(); // Clear selection when filter changes
446 343 loadContent();
447 344 });
448 345
449 -// Process selected content
450 -$processButton.on('click', function() {
451 - if (selectedItems.size === 0) {
452 - return;
453 - }
454 -
455 - const $button = $(this);
456 - $button.prop('disabled', true);
457 -
458 - // Update button text based on mode
459 - if ($button.hasClass('update-mode')) {
460 - $button.text('Updating...');
461 - } else if ($button.hasClass('mixed-mode')) {
462 - $button.text('Processing/Updating...');
463 - } else {
464 - $button.text('Processing...');
465 - }
466 -
467 - // Convert selected items to array
468 - const selectedPostIds = Array.from(selectedItems);
469 - const totalToProcess = selectedPostIds.length;
470 - let processed = 0;
471 - let updated = 0;
472 - let failed = 0;
473 - const results = {
474 - success: [],
475 - updated: [],
476 - failed: []
477 - };
478 -
479 - // UPDATED: Get current bot_id for WordPress content processing
480 - const currentBotId = $('#mxchat-bot-selector').val();
481 -
482 - // Flag to track if processing should be aborted
483 - let abortProcessing = false;
484 - let currentXHR = null;
485 -
486 - // Create a modal to show progress with stop button
487 - const $progressModal = $('<div class="mxchat-kb-processing-overlay">' +
488 - '<div class="mxchat-kb-processing-content">' +
489 - '<h3>Processing Content</h3>' +
490 - '<p class="mxchat-kb-processing-status">Processing 1 of ' + totalToProcess + '...</p>' +
491 - '<div class="mxchat-kb-progress-bar"><div class="mxchat-kb-progress-fill" style="width: 0%"></div></div>' +
492 - '<p class="mxchat-kb-current-item"></p>' +
493 - '<button type="button" class="mxchat-kb-stop-processing mxch-btn mxch-btn-secondary" style="margin-top: 15px;">' +
494 - '<span class="dashicons dashicons-controls-pause" style="margin-right: 5px;"></span>Stop Processing</button>' +
495 - '</div>' +
496 - '</div>');
497 -
498 - $('body').append($progressModal);
499 -
500 - // Handle stop button click
501 - $progressModal.find('.mxchat-kb-stop-processing').on('click', function() {
502 - abortProcessing = true;
503 - $(this).prop('disabled', true).html('<span class="dashicons dashicons-update spin" style="margin-right: 5px;"></span>Stopping...');
504 - if (currentXHR) {
505 - currentXHR.abort();
506 - }
507 - });
508 -
509 - // Process posts one by one
510 - function processNext(index) {
511 - // Check if processing was aborted
512 - if (abortProcessing) {
513 - finishProcessing(true); // Pass true to indicate abort
346 + // Process selected content
347 + $processButton.on('click', function() {
348 + if (selectedItems.size === 0) {
514 349 return;
515 350 }
516 -
517 - if (index >= selectedPostIds.length) {
518 - // All done
519 - finishProcessing();
520 - return;
351 +
352 + const $button = $(this);
353 + $button.prop('disabled', true);
354 +
355 + // Update button text based on mode
356 + if ($button.hasClass('update-mode')) {
357 + $button.text('Updating...');
358 + } else if ($button.hasClass('mixed-mode')) {
359 + $button.text('Processing/Updating...');
360 + } else {
361 + $button.text('Processing...');
521 362 }
522 -
523 - const postId = selectedPostIds[index];
524 - const percent = Math.round((index / totalToProcess) * 100);
525 - const item = allItems.find(item => item.id === postId);
526 - const isUpdate = item && item.already_processed;
527 -
528 - // Update progress UI
529 - $progressModal.find('.mxchat-kb-processing-status')
530 - .text((isUpdate ? 'Updating' : 'Processing') + ' ' + (index + 1) + ' of ' + totalToProcess + '...');
531 - $progressModal.find('.mxchat-kb-progress-fill').css('width', percent + '%');
532 -
533 - // UPDATED: Prepare AJAX data with bot_id
534 - const extractAcfPdfs = $acfPdfExtractCheckbox.prop('checked') ? 1 : 0;
535 - const ajaxData = {
536 - action: 'mxchat_process_selected_content',
537 - nonce: mxchatSelector.nonce,
538 - post_ids: [postId],
539 - is_update: isUpdate,
540 - extract_acf_pdfs: extractAcfPdfs
363 +
364 + // Convert selected items to array
365 + const selectedPostIds = Array.from(selectedItems);
366 + const totalToProcess = selectedPostIds.length;
367 + let processed = 0;
368 + let updated = 0;
369 + let failed = 0;
370 + const results = {
371 + success: [],
372 + updated: [],
373 + failed: []
541 374 };
542 -
543 - // Add bot_id if multi-bot is active and not default
544 - if (currentBotId && currentBotId !== 'default') {
545 - ajaxData.bot_id = currentBotId;
546 - }
547 -
548 - // Make AJAX request for this post (store reference for potential abort)
549 - currentXHR = $.ajax({
550 - url: mxchatSelector.ajaxurl,
551 - method: 'POST',
552 - data: ajaxData,
553 - dataType: 'json',
554 - success: function(response) {
555 - if (response.success) {
556 - if (isUpdate) {
557 - updated++;
558 - results.updated.push({
559 - id: postId,
560 - title: response.data.title || ('ID: ' + postId)
561 - });
375 +
376 + // Create a modal to show progress
377 + const $progressModal = $('<div class="mxchat-kb-processing-overlay">' +
378 + '<div class="mxchat-kb-processing-content">' +
379 + '<h3>Processing Content</h3>' +
380 + '<p class="mxchat-kb-processing-status">Processing 1 of ' + totalToProcess + '...</p>' +
381 + '<div class="mxchat-kb-progress-bar"><div class="mxchat-kb-progress-fill" style="width: 0%"></div></div>' +
382 + '<p class="mxchat-kb-current-item"></p>' +
383 + '</div>' +
384 + '</div>');
385 +
386 + $('body').append($progressModal);
387 +
388 + // Process posts one by one
389 + function processNext(index) {
390 + if (index >= selectedPostIds.length) {
391 + // All done
392 + finishProcessing();
393 + return;
394 + }
395 +
396 + const postId = selectedPostIds[index];
397 + const percent = Math.round((index / totalToProcess) * 100);
398 + const item = allItems.find(item => item.id === postId);
399 + const isUpdate = item && item.already_processed;
400 +
401 + // Update progress UI
402 + $progressModal.find('.mxchat-kb-processing-status')
403 + .text((isUpdate ? 'Updating' : 'Processing') + ' ' + (index + 1) + ' of ' + totalToProcess + '...');
404 + $progressModal.find('.mxchat-kb-progress-fill').css('width', percent + '%');
405 +
406 + // Make AJAX request for this post
407 + $.ajax({
408 + url: mxchatSelector.ajaxurl,
409 + method: 'POST',
410 + data: {
411 + action: 'mxchat_process_selected_content',
412 + nonce: mxchatSelector.nonce,
413 + post_ids: [postId],
414 + is_update: isUpdate
415 + },
416 + dataType: 'json',
417 + success: function(response) {
418 + if (response.success) {
419 + if (isUpdate) {
420 + updated++;
421 + results.updated.push({
422 + id: postId,
423 + title: response.data.title || ('ID: ' + postId)
424 + });
425 + } else {
426 + processed++;
427 + results.success.push({
428 + id: postId,
429 + title: response.data.title || ('ID: ' + postId)
430 + });
431 + }
432 +
433 + $progressModal.find('.mxchat-kb-current-item')
434 + .text('Successfully ' + (isUpdate ? 'updated' : 'processed') + ': ' + response.data.title);
562 435 } else {
563 - processed++;
564 - results.success.push({
436 + failed++;
437 + results.failed.push({
565 438 id: postId,
566 - title: response.data.title || ('ID: ' + postId)
439 + error: response.data || 'Unknown error'
567 440 });
441 +
442 + $progressModal.find('.mxchat-kb-current-item')
443 + .text('Failed to ' + (isUpdate ? 'update' : 'process') + ' ID: ' + postId);
568 444 }
569 445
570 - let successText = 'Successfully ' + (isUpdate ? 'updated' : 'processed') + ': ' + response.data.title;
571 - const pdfCount = parseInt(response.data.pdf_extracted_count, 10) || 0;
572 - if (pdfCount > 0) {
573 - const suffixTpl = (mxchatSelector.i18n && mxchatSelector.i18n.pdfExtractedSuffix) || ' (%d PDF(s) extracted)';
574 - successText += suffixTpl.replace('%d', pdfCount);
575 - }
576 - $progressModal.find('.mxchat-kb-current-item').text(successText);
577 - } else {
446 + // Process next post
447 + setTimeout(function() {
448 + processNext(index + 1);
449 + }, 500); // Small delay between requests
450 + },
451 + error: function(xhr, status, error) {
578 452 failed++;
579 453 results.failed.push({
580 454 id: postId,
581 - error: response.data || 'Unknown error'
455 + error: error || 'Server error'
582 456 });
583 457
584 458 $progressModal.find('.mxchat-kb-current-item')
585 - .text('Failed to ' + (isUpdate ? 'update' : 'process') + ' ID: ' + postId);
459 + .text('Error ' + (isUpdate ? 'updating' : 'processing') + ' ID: ' + postId);
460 +
461 + // Process next post
462 + setTimeout(function() {
463 + processNext(index + 1);
464 + }, 500);
586 465 }
466 + });
467 + }
468 +
469 + // Function to finish processing and show results
470 + function finishProcessing() {
471 + // Remove progress modal
472 + $progressModal.remove();
473 +
474 + // Determine notification type based on results
475 + let notificationClass = 'success';
476 + if (failed > 0) {
477 + notificationClass = processed > 0 || updated > 0 ? 'warning' : 'error';
478 + }
479 +
480 + // Create summary message
481 + let resultHTML = '<div class="mxchat-kb-notification ' + notificationClass + '">' +
482 + '<h4>';
483 +
484 + if (processed > 0 && updated > 0) {
485 + resultHTML += 'Processed ' + processed + ' new items and updated ' + updated + ' existing items';
486 + } else if (processed > 0) {
487 + resultHTML += 'Processed ' + processed + ' items successfully';
488 + } else if (updated > 0) {
489 + resultHTML += 'Updated ' + updated + ' items successfully';
490 + } else {
491 + resultHTML += 'No items were processed successfully';
492 + }
493 +
494 + if (failed > 0) {
495 + resultHTML += ' with ' + failed + ' failures';
496 + }
497 +
498 + resultHTML += '</h4>';
499 +
500 + // Add details if there were failures
501 + if (failed > 0) {
502 + resultHTML += '<div class="mxchat-kb-results-details">';
503 + resultHTML += '<h5>Failed Items:</h5><ul>';
587 504
588 - // Process next post
589 - setTimeout(function() {
590 - processNext(index + 1);
591 - }, 500); // Small delay between requests
592 - },
593 - error: function(xhr, status, error) {
594 - failed++;
595 - results.failed.push({
596 - id: postId,
597 - error: error || 'Server error'
505 + results.failed.forEach(function(item) {
506 + resultHTML += '<li><strong>ID: ' + item.id + '</strong>: ' + item.error + '</li>';
598 507 });
599 508
600 - $progressModal.find('.mxchat-kb-current-item')
601 - .text('Error ' + (isUpdate ? 'updating' : 'processing') + ' ID: ' + postId);
602 -
603 - // Process next post
604 - setTimeout(function() {
605 - processNext(index + 1);
606 - }, 500);
509 + resultHTML += '</ul></div>';
607 510 }
608 - });
609 - }
610 -
611 - // Function to finish processing and show results
612 - function finishProcessing(wasAborted) {
613 - // Remove progress modal
614 - $progressModal.remove();
615 -
616 - // Determine notification type based on results
617 - let notificationClass = 'success';
618 - if (wasAborted) {
619 - notificationClass = processed > 0 || updated > 0 ? 'warning' : 'info';
620 - } else if (failed > 0) {
621 - notificationClass = processed > 0 || updated > 0 ? 'warning' : 'error';
622 - }
623 -
624 - // Create summary message
625 - let resultHTML = '<div class="mxchat-kb-notification ' + notificationClass + '">' +
626 - '<h4>';
627 -
628 - if (wasAborted) {
629 - resultHTML += 'Processing stopped. ';
511 +
512 + resultHTML += '</div>';
513 +
514 + // Show results in modal
515 + $modal.find('.mxchat-kb-modal-content').prepend($(resultHTML));
516 +
517 + // Clear selection
518 + selectedItems.clear();
519 + updateSelection();
520 +
521 + // Enable button
522 + $button.prop('disabled', false)
523 + .text('Process Selected Content')
524 + .removeClass('update-mode mixed-mode');
525 + $('.mxchat-kb-selected-count').text('(0)');
526 +
527 + // Only reload if there were successful operations
630 528 if (processed > 0 || updated > 0) {
631 - resultHTML += 'Completed ' + (processed + updated) + ' of ' + totalToProcess + ' items before stopping';
632 - } else {
633 - resultHTML += 'No items were processed before stopping';
529 + // Reload after delay
530 + setTimeout(function() {
531 + // Reload the knowledge base table - if this function exists
532 + if (typeof reloadKnowledgeBaseTable === 'function') {
533 + reloadKnowledgeBaseTable();
534 + } else {
535 + // Fallback: reload content list instead of full page reload
536 + loadContent();
537 + }
538 + }, 3000);
634 539 }
635 - } else if (processed > 0 && updated > 0) {
636 - resultHTML += 'Processed ' + processed + ' new items and updated ' + updated + ' existing items';
637 - } else if (processed > 0) {
638 - resultHTML += 'Processed ' + processed + ' items successfully';
639 - } else if (updated > 0) {
640 - resultHTML += 'Updated ' + updated + ' items successfully';
641 - } else {
642 - resultHTML += 'No items were processed successfully';
643 540 }
644 -
645 - if (failed > 0 && !wasAborted) {
646 - resultHTML += ' with ' + failed + ' failures';
647 - }
648 541
649 - resultHTML += '</h4>';
650 -
651 - // Add details if there were failures
652 - if (failed > 0) {
653 - resultHTML += '<div class="mxchat-kb-results-details">';
654 - resultHTML += '<h5>Failed Items:</h5><ul>';
655 -
656 - results.failed.forEach(function(item) {
657 - resultHTML += '<li><strong>ID: ' + item.id + '</strong>: ' + item.error + '</li>';
658 - });
659 -
660 - resultHTML += '</ul></div>';
661 - }
662 -
663 - resultHTML += '</div>';
664 -
665 - // Show results in modal
666 - $modal.find('.mxchat-kb-modal-content').prepend($(resultHTML));
667 -
668 - // Clear selection
669 - selectedItems.clear();
670 - updateSelection();
671 -
672 - // Enable button
673 - $button.prop('disabled', false)
674 - .text('Process Selected Content')
675 - .removeClass('update-mode mixed-mode');
676 - $('.mxchat-kb-selected-count').text('(0)');
542 + // Start processing the first post
543 + processNext(0);
544 + });
677 545
678 - // Only reload if there were successful operations
679 - if (processed > 0 || updated > 0) {
680 - // Refresh the knowledge base table with properly grouped entries
681 - if (typeof window.refreshKnowledgeBaseTable === 'function') {
682 - window.refreshKnowledgeBaseTable();
683 - }
684 -
685 - // Reload content list to update "already processed" status
686 - setTimeout(function() {
687 - loadContent();
688 - }, 1000);
689 - }
690 - }
691 -
692 - // Start processing the first post
693 - processNext(0);
694 -});
695 -
696 546 // Initialize - Set WordPress as the active option by default
697 547 $('.mxchat-import-box[data-option="wordpress"]').addClass('active');
698 548 });
699 549
700 -// Navigation functionality for Knowledge Base page
550 +// Tab switching functionality - Keep this separate
701 551 jQuery(document).ready(function($) {
702 -
703 - // Hook into the new navigation system using .mxch-nav-link
704 - $(document).on('click', '.mxch-nav-link[data-target], .mxch-mobile-nav-link[data-target]', function() {
705 - var target = $(this).data('target');
706 -
707 - // Initialize Pinecone functionality when Pinecone section is activated
708 - if (target === 'pinecone') {
709 - setTimeout(function() {
710 - if (typeof initPineconeFeatures === 'function') {
711 - initPineconeFeatures();
712 - }
713 - }, 100);
552 +
553 +// Tab switching functionality
554 +// Modified tab switching to check for Pinecone changes
555 +$('.mxchat-kb-tab-button').on('click', function() {
556 + var tabId = $(this).data('tab');
557 + var $button = $(this);
558 +
559 + // Switch tabs immediately for all tabs
560 + $('.mxchat-kb-tab-button').removeClass('active');
561 + $('.mxchat-kb-tab-content').removeClass('active');
562 + $button.addClass('active');
563 + $('#mxchat-kb-tab-' + tabId).addClass('active');
564 +
565 + // Check if Pinecone was changed and we're going to import tab
566 + if (tabId === 'import' && sessionStorage.getItem('mxchat_pinecone_changed') === 'true') {
567 + sessionStorage.removeItem('mxchat_pinecone_changed');
568 +
569 + // Show refresh notice
570 + var $knowledgeCard = $('#mxchat-kb-tab-import .mxchat-card').eq(1);
571 + if ($knowledgeCard.length > 0 && $knowledgeCard.find('.notice-warning').length === 0) {
572 + var refreshNotice = $('<div class="notice notice-warning" style="margin: 15px 0; padding: 10px 15px;">' +
573 + '<p style="margin: 0;">' +
574 + '<span class="dashicons dashicons-info" style="color: #f0ad4e; margin-right: 5px;"></span>' +
575 + 'Database settings have changed. ' +
576 + '<a href="#" onclick="location.reload(); return false;" style="font-weight: bold;">Click here to refresh</a> to see the updated knowledge base.' +
577 + '</p></div>');
578 +
579 + $knowledgeCard.prepend(refreshNotice);
714 580 }
715 -
716 - // Initialize OpenAI Vector Store functionality when Vector Store section is activated
717 - if (target === 'openai-vectorstore') {
718 - setTimeout(function() {
719 - if (typeof initVectorStoreFeatures === 'function') {
720 - initVectorStoreFeatures();
721 - }
722 - }, 100);
723 - }
724 -
725 - // Check if Pinecone was changed and we're going to import section
726 - if (target === 'import' && sessionStorage.getItem('mxchat_pinecone_changed') === 'true') {
727 - sessionStorage.removeItem('mxchat_pinecone_changed');
728 -
729 - // Show refresh notice
730 - var $knowledgeCard = $('#import .mxch-card').eq(1);
731 - if ($knowledgeCard.length > 0 && $knowledgeCard.find('.notice-warning').length === 0) {
732 - var refreshNotice = $('<div class="notice notice-warning" style="margin: 15px 0; padding: 10px 15px;">' +
733 - '<p style="margin: 0;">' +
734 - '<span class="dashicons dashicons-info" style="color: #f0ad4e; margin-right: 5px;"></span>' +
735 - 'Database settings have changed. ' +
736 - '<a href="#" onclick="location.reload(); return false;" style="font-weight: bold;">Click here to refresh</a> to see the updated knowledge base.' +
737 - '</p></div>');
738 -
739 - $knowledgeCard.prepend(refreshNotice);
740 - }
741 - }
742 - });
743 -
744 - // Also check on page load if we're already on one of these sections
745 - setTimeout(function() {
746 - if ($('#pinecone').is(':visible') || $('#pinecone.active').length > 0) {
747 - if (typeof initPineconeFeatures === 'function') {
748 - initPineconeFeatures();
749 - }
750 - }
751 -
752 - if ($('#openai-vectorstore').is(':visible') || $('#openai-vectorstore.active').length > 0) {
753 - if (typeof initVectorStoreFeatures === 'function') {
754 - initVectorStoreFeatures();
755 - }
756 - }
757 - }, 200);
581 + }
582 +
583 + // Initialize Pinecone functionality when Pinecone tab is activated
584 + if (tabId === 'pinecone') {
585 + setTimeout(function() {
586 + initPineconeFeatures();
587 + }, 100);
588 + }
758 589 });
759 590
760 -// Pinecone and Vector Store functionality - global functions
761 -var initPineconeFeatures, initVectorStoreFeatures;
762 591
763 -(function($) {
764 -
765 - // Helper function to update sidebar badge when integration is toggled
766 - function updateSidebarBadge(section, isActive) {
767 - // Find the nav item for this section (both desktop and mobile)
768 - var $desktopNavItem = $('.mxch-nav-item[data-section="' + section + '"] .mxch-nav-link');
769 - var $mobileNavItem = $('.mxch-mobile-nav-link[data-target="' + section + '"]');
770 -
771 - // Remove existing badge if any
772 - $desktopNavItem.find('.mxch-active-badge').remove();
773 - $mobileNavItem.find('.mxch-active-badge').remove();
774 -
775 - // Add badge if active
776 - if (isActive) {
777 - var badgeHtml = '<span class="mxch-nav-link-badge mxch-active-badge">Active</span>';
778 - $desktopNavItem.append(badgeHtml);
779 - $mobileNavItem.append(badgeHtml);
780 - }
781 - }
782 -
783 592 // Pinecone functionality
784 - initPineconeFeatures = function() {
785 - // Check for either old or new section ID
786 - if ($('#pinecone').length === 0 && $('#mxchat-kb-tab-pinecone').length === 0) {
593 + function initPineconeFeatures() {
594 + //console.log('Initializing Pinecone features...');
595 +
596 + if ($('#mxchat-kb-tab-pinecone').length === 0) {
787 597 return;
788 598 }
789 -
599 +
790 600 initPineconeToggle();
791 601 initPineconeConnectionTest();
792 602 checkPineconeCompatibility();
793 - };
794 -
603 + }
604 +
795 605 function initPineconeToggle() {
796 606 // Remove any existing handlers to prevent duplicates
797 - var $toggleInput = $('input[name="mxchat_pinecone_addon_options[mxchat_use_pinecone]"]');
798 - $toggleInput.off('change.pineconeToggle');
799 -
800 - // Ensure the success notice exists in the settings div (add if not present)
801 - // Check for both the JS-added class and any existing PHP-rendered success notice
802 - var settingsDiv = $('.mxchat-pinecone-settings');
803 - if (settingsDiv.length > 0 && settingsDiv.find('.mxch-notice-success').length === 0) {
804 - var successNotice = $('<div class="mxch-notice mxch-notice-success mxchat-pinecone-enabled-notice" style="margin-bottom: 20px; display: none;">' +
805 - '<svg class="mxch-notice-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>' +
806 - '<span>Pinecone is enabled. All new knowledge base content will be stored in Pinecone.</span>' +
807 - '</div>');
808 - settingsDiv.prepend(successNotice);
809 - }
810 -
607 + $('input[name="mxchat_pinecone_addon_options[mxchat_use_pinecone]"]').off('change.pineconeToggle');
608 +
811 609 // Add the toggle handler for UI only (auto-save will handle the actual saving)
812 - $toggleInput.on('change.pineconeToggle', function() {
610 + $('input[name="mxchat_pinecone_addon_options[mxchat_use_pinecone]"]').on('change.pineconeToggle', function() {
813 611 var $checkbox = $(this);
814 612 var isChecked = $checkbox.is(':checked');
815 613 var settingsDiv = $('.mxchat-pinecone-settings');
816 - var enabledNotice = settingsDiv.find('.mxchat-pinecone-enabled-notice, .mxch-notice-success');
817 -
614 +
615 + //console.log('Pinecone toggle changed to:', isChecked);
616 +
818 617 // Update the UI immediately
819 618 if (isChecked) {
820 619 settingsDiv.slideDown(300);
821 - enabledNotice.slideDown(300);
822 620 } else {
823 - enabledNotice.slideUp(300);
824 621 settingsDiv.slideUp(300);
825 622 }
826 -
827 - // Update sidebar badge for Pinecone
828 - updateSidebarBadge('pinecone', isChecked);
829 623 });
830 -
624 +
831 625 // Set initial state based on current checkbox value
832 626 var currentToggle = $('input[name="mxchat_pinecone_addon_options[mxchat_use_pinecone]"]');
833 627 if (currentToggle.length > 0) {
834 628 var settingsDiv = $('.mxchat-pinecone-settings');
835 - var enabledNotice = settingsDiv.find('.mxchat-pinecone-enabled-notice, .mxch-notice-success');
836 629 if (currentToggle.is(':checked')) {
837 630 settingsDiv.show();
838 - enabledNotice.show();
839 631 } else {
840 632 settingsDiv.hide();
841 - enabledNotice.hide();
842 633 }
843 634 }
844 635 }
845 636
@@ -936,68 +727,6 @@
936 727 }
937 728 });
938 729 }
939 730 }
940 -
941 - // ============================================
942 - // OpenAI Vector Store functionality
943 - // ============================================
944 - initVectorStoreFeatures = function() {
945 - if ($('#openai-vectorstore').length === 0) {
946 - return;
947 - }
948 -
949 - initVectorStoreToggle();
950 - };
951 -
952 - function initVectorStoreToggle() {
953 - // Remove any existing handlers to prevent duplicates
954 - var $toggleInput = $('input[name="mxchat_openai_vectorstore_options[mxchat_use_openai_vectorstore]"]');
955 - $toggleInput.off('change.vectorstoreToggle');
956 -
957 - // Ensure the success notice exists in the settings div (add if not present)
958 - // Check for both the JS-added class and any existing PHP-rendered success notice
959 - var settingsDiv = $('.mxchat-vectorstore-settings');
960 - if (settingsDiv.length > 0 && settingsDiv.find('.mxch-notice-success').length === 0) {
961 - var successNotice = $('<div class="mxch-notice mxch-notice-success mxchat-vectorstore-enabled-notice" style="margin-bottom: 20px; display: none;">' +
962 - '<svg class="mxch-notice-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>' +
963 - '<span>OpenAI Vector Store is enabled. Queries will search your Vector Store for relevant content.</span>' +
964 - '</div>');
965 - settingsDiv.prepend(successNotice);
966 - }
967 -
968 - // Add the toggle handler for UI only (form submit will handle the actual saving)
969 - $toggleInput.on('change.vectorstoreToggle', function() {
970 - var $checkbox = $(this);
971 - var isChecked = $checkbox.is(':checked');
972 - var settingsDiv = $('.mxchat-vectorstore-settings');
973 - var enabledNotice = settingsDiv.find('.mxchat-vectorstore-enabled-notice, .mxch-notice-success');
974 -
975 - // Update the UI immediately
976 - if (isChecked) {
977 - settingsDiv.slideDown(300);
978 - enabledNotice.slideDown(300);
979 - } else {
980 - enabledNotice.slideUp(300);
981 - settingsDiv.slideUp(300);
982 - }
983 -
984 - // Update sidebar badge for OpenAI Vector Store
985 - updateSidebarBadge('openai-vectorstore', isChecked);
986 - });
987 -
988 - // Set initial state based on current checkbox value
989 - var currentToggle = $('input[name="mxchat_openai_vectorstore_options[mxchat_use_openai_vectorstore]"]');
990 - if (currentToggle.length > 0) {
991 - var settingsDiv = $('.mxchat-vectorstore-settings');
992 - var enabledNotice = settingsDiv.find('.mxchat-vectorstore-enabled-notice, .mxch-notice-success');
993 - if (currentToggle.is(':checked')) {
994 - settingsDiv.show();
995 - enabledNotice.show();
996 - } else {
997 - settingsDiv.hide();
998 - enabledNotice.hide();
999 - }
1000 - }
1001 - }
1002 -
1003 -})(jQuery);
731 +
732 +});