PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.6.3
MxChat – AI Chatbot & Content Generation for WordPress v2.6.3
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 / content-selector.js

content-selector.js in MxChat – AI Chatbot & Content Generation for WordPress 2.6.3, at js/content-selector.js

775 lines 30.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 jQuery(document).ready(function($) {
2 // Modal elements
3 const $modal = $('#mxchat-kb-content-selector-modal');
4 const $openButton = $('#mxchat-open-content-selector');
5 const $closeButtons = $('.mxchat-kb-modal-close');
6 const $contentList = $('.mxchat-kb-content-list');
7 const $loading = $('.mxchat-kb-loading');
8 const $pagination = $('.mxchat-kb-pagination');
9 const $processButton = $('#mxchat-kb-process-selected');
10 const $selectAll = $('#mxchat-kb-select-all');
11 const $selectionCount = $('.mxchat-kb-selection-count');
12
13 // Filter elements
14 const $searchInput = $('#mxchat-kb-content-search');1
15 const $typeFilter = $('#mxchat-kb-content-type-filter');
16 const $statusFilter = $('#mxchat-kb-content-status-filter');
17 const $processedFilter = $('#mxchat-kb-processed-filter');
18
19 // Current state - using let for variables that change
20 let currentPage = 1;
21 let totalPages = 1;
22 let selectedItems = new Set();
23 let allItems = [];
24
25 // Open modal when WordPress import button is clicked
26 $openButton.on('click', function() {
27 $modal.show();
28 // Reset to first page when opening the modal
29 currentPage = 1;
30 loadContent();
31 });
32
33 // Close modal
34 $closeButtons.on('click', function() {
35 $modal.hide();
36 });
37 // Handle import option box clicks (for non-WordPress options)
38 $('.mxchat-import-box').on('click', function() {
39 const $box = $(this);
40 const option = $box.data('option');
41
42 // Skip if this is the WordPress option (it has its own handler)
43 if (option === 'wordpress') {
44 return;
45 }
46
47 // Update active state
48 $('.mxchat-import-box').removeClass('active');
49 $box.addClass('active');
50
51 // Hide all input areas
52 $('#mxchat-url-input-area, #mxchat-content-input-area').hide();
53
54 // Handle different import options
55 switch (option) {
56 case 'pdf':
57 case 'sitemap':
58 case 'url':
59 // Show URL input area with appropriate placeholder
60 $('#mxchat-url-input-area').show();
61 $('#sitemap_url').attr('placeholder', $box.data('placeholder'));
62 $('#import_type').val(option);
63
64 // UPDATED: Add or update bot_id hidden field for URL forms
65 updateBotIdInForm('#mxchat-url-form');
66
67 // Update the description text based on the import type
68 let descriptionText = '';
69 if (option === 'pdf') {
70 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.';
71 } else if (option === 'sitemap') {
72 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.';
73 } else if (option === 'url') {
74 descriptionText = 'Import content from any webpage by entering its URL.';
75 }
76 $('#url-description-text').text(descriptionText);
77 break;
78
79 case 'content':
80 // Show content input area
81 $('#mxchat-content-input-area').show();
82
83 // UPDATED: Add or update bot_id hidden field for content forms
84 updateBotIdInForm('#mxchat-content-form');
85 break;
86 }
87 });
88
89 // Helper function to add/update bot_id hidden field in forms
90 function updateBotIdInForm(formSelector) {
91 const $form = $(formSelector);
92 if ($form.length === 0) return;
93
94 // Get current bot_id from the bot selector dropdown
95 const currentBotId = $('#mxchat-bot-selector').val();
96
97 // Only add bot_id field if multi-bot is active and bot is not 'default'
98 if (currentBotId && currentBotId !== 'default') {
99 // Remove existing bot_id field if it exists
100 $form.find('input[name="bot_id"]').remove();
101
102 // Add new bot_id field
103 $form.append('<input type="hidden" name="bot_id" value="' + currentBotId + '">');
104
105 console.log('Updated bot_id in form ' + formSelector + ' to: ' + currentBotId);
106 } else {
107 // Remove bot_id field if bot is default
108 $form.find('input[name="bot_id"]').remove();
109 }
110 }
111
112 // Load content via AJAX
113 function loadContent() {
114 $loading.show();
115 $contentList.find('.mxchat-kb-content-item').remove();
116
117 const data = {
118 action: 'mxchat_get_content_list',
119 nonce: mxchatSelector.nonce,
120 page: currentPage,
121 per_page: 50,
122 search: $searchInput.val(),
123 post_type: $typeFilter.val(),
124 post_status: $statusFilter.val(),
125 processed_filter: $processedFilter.val()
126 };
127
128 //console.log('Loading content for page', currentPage, 'with filters:', data);
129
130 $.ajax({
131 url: mxchatSelector.ajaxurl,
132 data: data,
133 method: 'GET',
134 dataType: 'json',
135 success: function(response) {
136 $loading.hide();
137
138 if (response.success && response.data.items && response.data.items.length > 0) {
139 // Store the items directly
140 let items = response.data.items;
141
142 if (items.length > 0) {
143 renderContentItems(items);
144 renderPagination(parseInt(response.data.current_page), parseInt(response.data.total_pages));
145
146 // Update state
147 allItems = items;
148 totalPages = parseInt(response.data.total_pages);
149 currentPage = parseInt(response.data.current_page);
150
151 // Update select all checkbox based on current selection
152 updateSelectAllState();
153 } else {
154 displayNoResults($processedFilter.val());
155 }
156 } else {
157 displayNoResults($processedFilter.val());
158 }
159 },
160 error: function(xhr, status, error) {
161 $loading.hide();
162 console.error('AJAX Error:', status, error);
163 $contentList.html('<div class="mxchat-kb-error">Error loading content. Please try again.</div>');
164 // Clear pagination on error
165 $pagination.empty();
166 }
167 });
168 }
169
170 // Helper function to display appropriate "no results" message
171 function displayNoResults(processedStatus) {
172 let message = 'No content found matching your criteria.';
173
174 if (processedStatus === 'processed') {
175 message = 'No content found in knowledge base.';
176 } else if (processedStatus === 'unprocessed') {
177 message = 'All content is already in knowledge base.';
178 }
179
180 $contentList.html('<div class="mxchat-kb-no-results">' + message + '</div>');
181 // Clear pagination when no results
182 $pagination.empty();
183 }
184
185 // Render content items
186 function renderContentItems(items) {
187 let html = '';
188
189 items.forEach(function(item) {
190 const isSelected = selectedItems.has(item.id);
191 const isProcessed = item.already_processed;
192 const chunkCount = item.chunk_count || 0;
193
194 // Updated badge text - include chunk count if > 1
195 let badgeText = 'Not In Knowledge Base';
196 if (isProcessed) {
197 badgeText = chunkCount > 1 ? `In Knowledge Base (${chunkCount} chunks)` : 'In Knowledge Base';
198 }
199 const badgeClass = isProcessed ? 'mxchat-kb-processed-badge' : 'mxchat-kb-unprocessed-badge';
200
201
202 html += `
203 <div class="mxchat-kb-content-item ${isProcessed ? 'processed' : ''}" data-id="${item.id}">
204 <div class="mxchat-kb-content-checkbox">
205 <input type="checkbox" id="content-${item.id}" ${isSelected ? 'checked' : ''}>
206 </div>
207 <div class="mxchat-kb-content-details">
208 <div class="mxchat-kb-content-title">
209 <a href="${item.permalink}" target="_blank">${item.title}</a>
210 <span class="${badgeClass}">${badgeText}</span>
211 ${isProcessed ? '<span class="mxchat-kb-last-updated">Last updated: ' + item.processed_date + '</span>' : ''}
212 </div>
213 <div class="mxchat-kb-content-meta">
214 <span class="mxchat-kb-content-type">${item.type}</span>
215 <span class="mxchat-kb-content-date">${item.date}</span>
216 <span class="mxchat-kb-content-words">${item.word_count} words</span>
217 </div>
218 <div class="mxchat-kb-content-excerpt">${item.excerpt}</div>
219 </div>
220 </div>
221 `;
222 });
223
224 $contentList.html(html);
225
226 // Add event listeners for checkboxes using delegation for better performance
227 $contentList.off('change', 'input[type="checkbox"]').on('change', 'input[type="checkbox"]', function() {
228 const $checkbox = $(this);
229 const itemId = parseInt($checkbox.closest('.mxchat-kb-content-item').data('id'));
230
231 if ($checkbox.is(':checked')) {
232 selectedItems.add(itemId);
233 } else {
234 selectedItems.delete(itemId);
235 }
236
237 updateSelection();
238 });
239 }
240
241 // Render pagination - FIXED VERSION
242 function renderPagination(currentPage, totalPages) {
243 // Clear existing pagination first
244 $pagination.empty();
245
246 // Don't render pagination if only one page
247 if (totalPages <= 1) {
248 return;
249 }
250
251 let html = '<div class="mxchat-kb-pagination-links">';
252
253 // Previous button
254 if (currentPage > 1) {
255 html += '<a href="#" class="mxchat-kb-page-link prev" data-page="' + (currentPage - 1) + '">&laquo; Previous</a>';
256 }
257
258 // Page numbers
259 const startPage = Math.max(1, currentPage - 2);
260 const endPage = Math.min(totalPages, startPage + 4);
261
262 for (let i = startPage; i <= endPage; i++) {
263 if (i === currentPage) {
264 html += '<span class="mxchat-kb-page-current">' + i + '</span>';
265 } else {
266 html += '<a href="#" class="mxchat-kb-page-link" data-page="' + i + '">' + i + '</a>';
267 }
268 }
269
270 // Next button
271 if (currentPage < totalPages) {
272 html += '<a href="#" class="mxchat-kb-page-link next" data-page="' + (currentPage + 1) + '">Next &raquo;</a>';
273 }
274
275 html += '</div>';
276
277 $pagination.html(html);
278 }
279
280 // Handle pagination clicks directly on the document
281 $(document).on('click', '.mxchat-kb-page-link', function(e) {
282 e.preventDefault();
283 const newPage = parseInt($(this).data('page'));
284 //console.log('Pagination clicked: changing from page', currentPage, 'to', newPage);
285
286 // Only reload if the page actually changed
287 if (currentPage !== newPage) {
288 currentPage = newPage;
289 loadContent();
290 }
291 });
292
293 // Update selection counts and button state
294 function updateSelection() {
295 const selectedCount = selectedItems.size;
296 $selectionCount.text(selectedCount + ' ' + (selectedCount === 1 ? 'selected' : 'selected'));
297 $('.mxchat-kb-selected-count').text('(' + selectedCount + ')');
298
299 // Determine if any selected items are already processed
300 const hasProcessedItems = Array.from(selectedItems).some(id => {
301 const item = allItems.find(item => item.id === id);
302 return item && item.already_processed;
303 });
304
305 if (selectedCount > 0) {
306 $processButton.prop('disabled', false);
307
308 // Update button text based on selection
309 if (hasProcessedItems && selectedCount === 1) {
310 $processButton.text('Update Selected Content (1)').addClass('update-mode');
311 } else if (hasProcessedItems && selectedCount > 1) {
312 $processButton.text('Process/Update Selected (' + selectedCount + ')').addClass('mixed-mode');
313 } else {
314 $processButton.text('Process Selected Content (' + selectedCount + ')').removeClass('update-mode mixed-mode');
315 }
316 } else {
317 $processButton.prop('disabled', true);
318 $processButton.text('Process Selected Content').removeClass('update-mode mixed-mode');
319 $('.mxchat-kb-selected-count').text('(0)');
320 }
321
322 updateSelectAllState();
323 }
324
325 // Update "Select All" checkbox state
326 function updateSelectAllState() {
327 const availableItems = allItems.length;
328 const selectedAvailableItems = allItems.filter(item => selectedItems.has(item.id)).length;
329
330 if (availableItems === 0) {
331 $selectAll.prop('checked', false);
332 $selectAll.prop('disabled', true);
333 } else if (selectedAvailableItems === availableItems) {
334 $selectAll.prop('checked', true);
335 } else {
336 $selectAll.prop('checked', false);
337 }
338 }
339
340 // Handle Select All checkbox
341 $selectAll.on('change', function() {
342 const isChecked = $(this).is(':checked');
343
344 $contentList.find('.mxchat-kb-content-item input[type="checkbox"]').each(function() {
345 const $checkbox = $(this);
346 const $item = $checkbox.closest('.mxchat-kb-content-item');
347 const itemId = parseInt($item.data('id'));
348
349 $checkbox.prop('checked', isChecked);
350
351 if (isChecked) {
352 selectedItems.add(itemId);
353 } else {
354 selectedItems.delete(itemId);
355 }
356 });
357
358 updateSelection();
359 });
360
361 // Handle search input
362 let searchTimer;
363 $searchInput.on('keyup', function() {
364 clearTimeout(searchTimer);
365 searchTimer = setTimeout(function() {
366 currentPage = 1; // Reset to first page on new search
367 loadContent();
368 }, 500);
369 });
370
371 // Handle filter changes
372 $typeFilter.add($statusFilter).add($processedFilter).on('change', function() {
373 currentPage = 1; // Reset to first page on filter change
374 selectedItems.clear(); // Clear selection when filter changes
375 loadContent();
376 });
377
378 // Process selected content
379 $processButton.on('click', function() {
380 if (selectedItems.size === 0) {
381 return;
382 }
383
384 const $button = $(this);
385 $button.prop('disabled', true);
386
387 // Update button text based on mode
388 if ($button.hasClass('update-mode')) {
389 $button.text('Updating...');
390 } else if ($button.hasClass('mixed-mode')) {
391 $button.text('Processing/Updating...');
392 } else {
393 $button.text('Processing...');
394 }
395
396 // Convert selected items to array
397 const selectedPostIds = Array.from(selectedItems);
398 const totalToProcess = selectedPostIds.length;
399 let processed = 0;
400 let updated = 0;
401 let failed = 0;
402 const results = {
403 success: [],
404 updated: [],
405 failed: []
406 };
407
408 // UPDATED: Get current bot_id for WordPress content processing
409 const currentBotId = $('#mxchat-bot-selector').val();
410
411 // Create a modal to show progress
412 const $progressModal = $('<div class="mxchat-kb-processing-overlay">' +
413 '<div class="mxchat-kb-processing-content">' +
414 '<h3>Processing Content</h3>' +
415 '<p class="mxchat-kb-processing-status">Processing 1 of ' + totalToProcess + '...</p>' +
416 '<div class="mxchat-kb-progress-bar"><div class="mxchat-kb-progress-fill" style="width: 0%"></div></div>' +
417 '<p class="mxchat-kb-current-item"></p>' +
418 '</div>' +
419 '</div>');
420
421 $('body').append($progressModal);
422
423 // Process posts one by one
424 function processNext(index) {
425 if (index >= selectedPostIds.length) {
426 // All done
427 finishProcessing();
428 return;
429 }
430
431 const postId = selectedPostIds[index];
432 const percent = Math.round((index / totalToProcess) * 100);
433 const item = allItems.find(item => item.id === postId);
434 const isUpdate = item && item.already_processed;
435
436 // Update progress UI
437 $progressModal.find('.mxchat-kb-processing-status')
438 .text((isUpdate ? 'Updating' : 'Processing') + ' ' + (index + 1) + ' of ' + totalToProcess + '...');
439 $progressModal.find('.mxchat-kb-progress-fill').css('width', percent + '%');
440
441 // UPDATED: Prepare AJAX data with bot_id
442 const ajaxData = {
443 action: 'mxchat_process_selected_content',
444 nonce: mxchatSelector.nonce,
445 post_ids: [postId],
446 is_update: isUpdate
447 };
448
449 // Add bot_id if multi-bot is active and not default
450 if (currentBotId && currentBotId !== 'default') {
451 ajaxData.bot_id = currentBotId;
452 }
453
454 // Make AJAX request for this post
455 $.ajax({
456 url: mxchatSelector.ajaxurl,
457 method: 'POST',
458 data: ajaxData,
459 dataType: 'json',
460 success: function(response) {
461 if (response.success) {
462 if (isUpdate) {
463 updated++;
464 results.updated.push({
465 id: postId,
466 title: response.data.title || ('ID: ' + postId)
467 });
468 } else {
469 processed++;
470 results.success.push({
471 id: postId,
472 title: response.data.title || ('ID: ' + postId)
473 });
474 }
475
476 $progressModal.find('.mxchat-kb-current-item')
477 .text('Successfully ' + (isUpdate ? 'updated' : 'processed') + ': ' + response.data.title);
478 } else {
479 failed++;
480 results.failed.push({
481 id: postId,
482 error: response.data || 'Unknown error'
483 });
484
485 $progressModal.find('.mxchat-kb-current-item')
486 .text('Failed to ' + (isUpdate ? 'update' : 'process') + ' ID: ' + postId);
487 }
488
489 // Process next post
490 setTimeout(function() {
491 processNext(index + 1);
492 }, 500); // Small delay between requests
493 },
494 error: function(xhr, status, error) {
495 failed++;
496 results.failed.push({
497 id: postId,
498 error: error || 'Server error'
499 });
500
501 $progressModal.find('.mxchat-kb-current-item')
502 .text('Error ' + (isUpdate ? 'updating' : 'processing') + ' ID: ' + postId);
503
504 // Process next post
505 setTimeout(function() {
506 processNext(index + 1);
507 }, 500);
508 }
509 });
510 }
511
512 // Function to finish processing and show results
513 function finishProcessing() {
514 // Remove progress modal
515 $progressModal.remove();
516
517 // Determine notification type based on results
518 let notificationClass = 'success';
519 if (failed > 0) {
520 notificationClass = processed > 0 || updated > 0 ? 'warning' : 'error';
521 }
522
523 // Create summary message
524 let resultHTML = '<div class="mxchat-kb-notification ' + notificationClass + '">' +
525 '<h4>';
526
527 if (processed > 0 && updated > 0) {
528 resultHTML += 'Processed ' + processed + ' new items and updated ' + updated + ' existing items';
529 } else if (processed > 0) {
530 resultHTML += 'Processed ' + processed + ' items successfully';
531 } else if (updated > 0) {
532 resultHTML += 'Updated ' + updated + ' items successfully';
533 } else {
534 resultHTML += 'No items were processed successfully';
535 }
536
537 if (failed > 0) {
538 resultHTML += ' with ' + failed + ' failures';
539 }
540
541 resultHTML += '</h4>';
542
543 // Add details if there were failures
544 if (failed > 0) {
545 resultHTML += '<div class="mxchat-kb-results-details">';
546 resultHTML += '<h5>Failed Items:</h5><ul>';
547
548 results.failed.forEach(function(item) {
549 resultHTML += '<li><strong>ID: ' + item.id + '</strong>: ' + item.error + '</li>';
550 });
551
552 resultHTML += '</ul></div>';
553 }
554
555 resultHTML += '</div>';
556
557 // Show results in modal
558 $modal.find('.mxchat-kb-modal-content').prepend($(resultHTML));
559
560 // Clear selection
561 selectedItems.clear();
562 updateSelection();
563
564 // Enable button
565 $button.prop('disabled', false)
566 .text('Process Selected Content')
567 .removeClass('update-mode mixed-mode');
568 $('.mxchat-kb-selected-count').text('(0)');
569
570 // Only reload if there were successful operations
571 if (processed > 0 || updated > 0) {
572 // Reload after delay
573 setTimeout(function() {
574 // Reload the knowledge base table - if this function exists
575 if (typeof reloadKnowledgeBaseTable === 'function') {
576 reloadKnowledgeBaseTable();
577 } else {
578 // Fallback: reload content list instead of full page reload
579 loadContent();
580 }
581 }, 3000);
582 }
583 }
584
585 // Start processing the first post
586 processNext(0);
587 });
588
589 // Initialize - Set WordPress as the active option by default
590 $('.mxchat-import-box[data-option="wordpress"]').addClass('active');
591 });
592
593 // Tab switching functionality - Keep this separate
594 jQuery(document).ready(function($) {
595
596 // Tab switching functionality
597 // Modified tab switching to check for Pinecone changes
598 $('.mxchat-kb-tab-button').on('click', function() {
599 var tabId = $(this).data('tab');
600 var $button = $(this);
601
602 // Switch tabs immediately for all tabs
603 $('.mxchat-kb-tab-button').removeClass('active');
604 $('.mxchat-kb-tab-content').removeClass('active');
605 $button.addClass('active');
606 $('#mxchat-kb-tab-' + tabId).addClass('active');
607
608 // Check if Pinecone was changed and we're going to import tab
609 if (tabId === 'import' && sessionStorage.getItem('mxchat_pinecone_changed') === 'true') {
610 sessionStorage.removeItem('mxchat_pinecone_changed');
611
612 // Show refresh notice
613 var $knowledgeCard = $('#mxchat-kb-tab-import .mxchat-card').eq(1);
614 if ($knowledgeCard.length > 0 && $knowledgeCard.find('.notice-warning').length === 0) {
615 var refreshNotice = $('<div class="notice notice-warning" style="margin: 15px 0; padding: 10px 15px;">' +
616 '<p style="margin: 0;">' +
617 '<span class="dashicons dashicons-info" style="color: #f0ad4e; margin-right: 5px;"></span>' +
618 'Database settings have changed. ' +
619 '<a href="#" onclick="location.reload(); return false;" style="font-weight: bold;">Click here to refresh</a> to see the updated knowledge base.' +
620 '</p></div>');
621
622 $knowledgeCard.prepend(refreshNotice);
623 }
624 }
625
626 // Initialize Pinecone functionality when Pinecone tab is activated
627 if (tabId === 'pinecone') {
628 setTimeout(function() {
629 initPineconeFeatures();
630 }, 100);
631 }
632 });
633
634
635 // Pinecone functionality
636 function initPineconeFeatures() {
637 //console.log('Initializing Pinecone features...');
638
639 if ($('#mxchat-kb-tab-pinecone').length === 0) {
640 return;
641 }
642
643 initPineconeToggle();
644 initPineconeConnectionTest();
645 checkPineconeCompatibility();
646 }
647
648 function initPineconeToggle() {
649 // Remove any existing handlers to prevent duplicates
650 $('input[name="mxchat_pinecone_addon_options[mxchat_use_pinecone]"]').off('change.pineconeToggle');
651
652 // Add the toggle handler for UI only (auto-save will handle the actual saving)
653 $('input[name="mxchat_pinecone_addon_options[mxchat_use_pinecone]"]').on('change.pineconeToggle', function() {
654 var $checkbox = $(this);
655 var isChecked = $checkbox.is(':checked');
656 var settingsDiv = $('.mxchat-pinecone-settings');
657
658 //console.log('Pinecone toggle changed to:', isChecked);
659
660 // Update the UI immediately
661 if (isChecked) {
662 settingsDiv.slideDown(300);
663 } else {
664 settingsDiv.slideUp(300);
665 }
666 });
667
668 // Set initial state based on current checkbox value
669 var currentToggle = $('input[name="mxchat_pinecone_addon_options[mxchat_use_pinecone]"]');
670 if (currentToggle.length > 0) {
671 var settingsDiv = $('.mxchat-pinecone-settings');
672 if (currentToggle.is(':checked')) {
673 settingsDiv.show();
674 } else {
675 settingsDiv.hide();
676 }
677 }
678 }
679
680 function initPineconeConnectionTest() {
681 $('#test-pinecone-connection').off('click.pinecone');
682
683 $('#test-pinecone-connection').on('click.pinecone', function() {
684 var button = $(this);
685 var resultDiv = $('#connection-test-result');
686
687 var apiKey = $('#mxchat_pinecone_api_key').val();
688 var host = $('#mxchat_pinecone_host').val();
689 var index = $('#mxchat_pinecone_index').val();
690
691 if (!apiKey || !host || !index) {
692 resultDiv.html('<div class="notice notice-error"><p>Please fill in all required fields first.</p></div>').show();
693 return;
694 }
695
696 button.prop('disabled', true).text('Testing...');
697 resultDiv.hide();
698
699 var ajaxUrl = (typeof mxchatPromptsAdmin !== 'undefined') ? mxchatPromptsAdmin.ajax_url : ajaxurl;
700 var nonce = (typeof mxchatPromptsAdmin !== 'undefined') ? mxchatPromptsAdmin.prompts_setting_nonce :
701 (typeof mxchatAdmin !== 'undefined') ? mxchatAdmin.setting_nonce : '';
702
703 $.ajax({
704 url: ajaxUrl,
705 type: 'POST',
706 data: {
707 action: 'mxchat_test_pinecone_connection',
708 _ajax_nonce: nonce,
709 api_key: apiKey,
710 host: host,
711 index_name: index
712 },
713 success: function(response) {
714 if (response.success) {
715 resultDiv.html('<div class="notice notice-success"><p><span class="dashicons dashicons-yes-alt"></span> ' + response.data.message + '</p></div>');
716 } else {
717 resultDiv.html('<div class="notice notice-error"><p><span class="dashicons dashicons-warning"></span> ' + response.data.message + '</p></div>');
718 }
719 resultDiv.show();
720 },
721 error: function() {
722 resultDiv.html('<div class="notice notice-error"><p>Connection test failed. Please check your settings.</p></div>').show();
723 },
724 complete: function() {
725 button.prop('disabled', false).text('Test Connection');
726 }
727 });
728 });
729 }
730
731 function checkPineconeCompatibility() {
732 if ($('.mxchat-pinecone-compatibility-notice').length > 0) {
733 return;
734 }
735
736 var hasOldAddon = $('body').hasClass('mxchat-pinecone-addon-active') ||
737 $('.pcm-card').length > 0;
738
739 if (hasOldAddon) {
740 var compatibilityNotice = $(`
741 <div class="notice notice-info mxchat-pinecone-compatibility-notice">
742 <p><strong>Pinecone Integration Notice:</strong> We've detected you have the Pinecone add-on installed.
743 Pinecone functionality is now built into the core plugin. You can safely deactivate the separate
744 Pinecone add-on after confirming your settings are migrated below.</p>
745 </div>
746 `);
747
748 $('#mxchat-kb-tab-pinecone .mxchat-card').prepend(compatibilityNotice);
749
750 migratePineconeSettings();
751 }
752 }
753
754 function migratePineconeSettings() {
755 if (typeof ajaxurl !== 'undefined') {
756 $.ajax({
757 url: ajaxurl,
758 type: 'POST',
759 data: {
760 action: 'mxchat_migrate_pinecone_settings',
761 _ajax_nonce: (typeof mxchatAdmin !== 'undefined') ? mxchatAdmin.setting_nonce : ''
762 },
763 success: function(response) {
764 if (response.success && response.data.migrated) {
765 location.reload();
766 }
767 },
768 error: function() {
769 //console.log('Pinecone settings migration not available');
770 }
771 });
772 }
773 }
774
775 });