Plugin Directory

Changeset 3414458


Ignore:
Timestamp:
12/08/2025 02:56:22 PM (2 months ago)
Author:
2wstechnologies
Message:

fix retry background button + add tracking system for failed queries

Location:
askeet/trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • askeet/trunk/askeet.php

    r3414259 r3414458  
    217217            'ai_fixing_query' => __('The assistant is trying to fix the query...', 'askeet'),
    218218            'ai_failed_3_times' => __('Unable to process the request, please reformulate your question.', 'askeet'),
    219             'ai_failed_5_times' => __('Unable to process the request after 5 attempts, please reformulate your question.', 'askeet'),
     219            'ai_failed_5_times' => __('Unable to process the request, please reformulate your question.', 'askeet'),
    220220            'ai_retrying' => __('Retrying...', 'askeet'),
    221221            'ai_warning' => __('Askeet is an AI and may make mistakes. Please verify the responses.', 'askeet'),
     
    418418            $sql_error = isset($data['sql_error']) ? sanitize_textarea_field(wp_unslash($data['sql_error'])) : '';
    419419            $retry_attempt = isset($data['retry_attempt']) ? intval($data['retry_attempt']) : 0;
     420            $query_id = isset($data['query_id']) ? intval($data['query_id']) : null;
    420421        } else {
    421422            $query_request = isset($_POST['query_request']) ? sanitize_textarea_field(wp_unslash($_POST['query_request'])) : '';
     
    426427            $sql_error = isset($_POST['sql_error']) ? sanitize_textarea_field(wp_unslash($_POST['sql_error'])) : '';
    427428            $retry_attempt = isset($_POST['retry_attempt']) ? intval($_POST['retry_attempt']) : 0;
     429            $query_id = isset($_POST['query_id']) ? intval($_POST['query_id']) : null;
    428430        }
    429431        $db_structure = $this->askeet_get_full_db_structure();
     
    439441            'sql_error' => $sql_error,
    440442            'retry_attempt' => $retry_attempt,
     443            'query_id' => $query_id,
    441444        );
     445        // Debug logging - can be removed in production
     446        error_log('[ASKEET PHP DEBUG] Sending to API: retry_attempt=' . $retry_attempt . ', query_id=' . ($query_id !== null ? $query_id : 'null'));
    442447        $response = wp_remote_post($full_url, array(
    443448            'timeout' => 60,
     
    486491            // PATCH: Detect daily limit and add current_plan from backend
    487492            if (isset($data['error']) && (stripos($data['error'], 'daily limit') !== false)) {
    488                 wp_send_json_error(array('message' => $data['error'], 'current_plan' => isset($data['current_plan']) ? $data['current_plan'] : ''));
     493                wp_send_json_error(array(
     494                    'message' => $data['error'],
     495                    'current_plan' => isset($data['current_plan']) ? $data['current_plan'] : '',
     496                    'sql_query' => isset($data['sql_query']) ? $data['sql_query'] : '',
     497                    'query_id' => isset($data['query_id']) ? $data['query_id'] : null // Include query_id for retry tracking
     498                ));
    489499                exit;
    490500            }
    491             wp_send_json_error(array('message' => isset($data['error']) ? $data['error'] : __('Erreur de traitement de la réponse IA.', 'askeet')));
     501            wp_send_json_error(array(
     502                'message' => isset($data['error']) ? $data['error'] : __('Erreur de traitement de la réponse IA.', 'askeet'),
     503                'sql_query' => isset($data['sql_query']) ? $data['sql_query'] : '', // Include sql_query for retry context
     504                'query_id' => isset($data['query_id']) ? $data['query_id'] : null // Include query_id for retry tracking
     505            ));
    492506            exit;
    493507        }
     
    495509        $sql_query = preg_replace('/\s+/', ' ', $sql_query);
    496510        if (empty($sql_query)) {
    497             wp_send_json_error(['message' => __('Impossible de traiter la demande, veuillez reformuler votre question.', 'askeet')]);
     511            wp_send_json_error([
     512                'message' => __('Impossible de traiter la demande, veuillez reformuler votre question.', 'askeet'),
     513                'sql_query' => '', // Include empty sql_query for retry context
     514                'query_id' => isset($data['query_id']) ? $data['query_id'] : null // Include query_id for retry tracking
     515            ]);
    498516            exit;
    499517        }
    500518        // Vérification de sécurité : seules les requêtes SELECT sont autorisées
    501519        if (!$this->askeet_is_safe_query($sql_query)) {
    502             wp_send_json_error(['message' => 'Seules les requêtes SELECT sont autorisées.']);
     520            wp_send_json_error([
     521                'message' => 'Seules les requêtes SELECT sont autorisées.',
     522                'sql_query' => $sql_query, // Include sql_query for retry context
     523                'query_id' => isset($data['query_id']) ? $data['query_id'] : null // Include query_id for retry tracking
     524            ]);
    503525            exit;
    504526        }
     
    517539        }
    518540        if ($error) {
    519             wp_send_json_error(array('message' => __('Erreur SQL: ', 'askeet') . $error));
     541            wp_send_json_error(array(
     542                'message' => __('Erreur SQL: ', 'askeet') . $error,
     543                'sql_query' => $sql_query,
     544                'query_id' => isset($data['query_id']) ? $data['query_id'] : null
     545            ));
    520546            exit;
    521547        }
     
    523549        if (empty($results)) {
    524550        }
    525         wp_send_json_success(array('results' => $results, 'sql_query' => $sql_query));
     551        wp_send_json_success(array(
     552            'results' => $results,
     553            'sql_query' => $sql_query,
     554            'query_id' => isset($data['query_id']) ? $data['query_id'] : null
     555        ));
    526556        exit;
    527557    }
  • askeet/trunk/assets/css/style.css

    r3414259 r3414458  
    8484}
    8585
     86/* Specific button overrides for WordPress admin compatibility */
    8687#btn-discord,
    8788#btn-slack,
    88 #btn-support {
     89#btn-support,
     90.askeet-guide-wrapper #btn-discord,
     91.askeet-guide-wrapper #btn-slack,
     92.askeet-guide-wrapper #btn-support,
     93.askeet-guide-wrapper .button-group a.btn,
     94.askeet-guide-wrapper .button-group .btn,
     95.wrap.askeet .button-group a.btn,
     96.wrap.askeet .button-group .btn,
     97body.wp-admin #btn-discord,
     98body.wp-admin #btn-slack,
     99body.wp-admin #btn-support {
    89100  color: #ffffff !important;
    90101  background: linear-gradient(135deg, #005a9e 0%, #0077cc 100%) !important;
     102  -webkit-text-fill-color: #ffffff !important;
     103  text-shadow: none !important;
     104}
     105
     106#btn-discord:visited,
     107#btn-slack:visited,
     108#btn-support:visited,
     109.askeet-guide-wrapper a.btn:visited,
     110.button-group a.btn:visited {
     111  color: #ffffff !important;
     112  -webkit-text-fill-color: #ffffff !important;
    91113}
    92114
     
    15721594
    15731595.wcqa-retry-query.button {
    1574     background: linear-gradient(135deg, #ff6b6b 0%, #ee5a5a 100%) !important;
     1596    background: linear-gradient(135deg, #6c757d 0%, #5a6268 100%) !important;
    15751597    color: #fff !important;
    15761598    border: none !important;
     
    15811603    cursor: pointer !important;
    15821604    transition: all 0.3s ease !important;
    1583     box-shadow: 0 2px 8px rgba(255, 107, 107, 0.3) !important;
     1605    box-shadow: 0 2px 8px rgba(108, 117, 125, 0.3) !important;
    15841606}
    15851607
    15861608.wcqa-retry-query.button:hover {
    1587     background: linear-gradient(135deg, #ff5252 0%, #e53935 100%) !important;
     1609    background: linear-gradient(135deg, #5a6268 0%, #495057 100%) !important;
    15881610    transform: translateY(-1px) !important;
    1589     box-shadow: 0 4px 12px rgba(255, 107, 107, 0.4) !important;
     1611    box-shadow: 0 4px 12px rgba(108, 117, 125, 0.4) !important;
    15901612}
    15911613
  • askeet/trunk/assets/js/script.js

    r3414259 r3414458  
    1414    let lastQueryLastSql = '';
    1515    let lastQueryLastColumns = [];
     16    let executionRetryCount = 0; // Track retries for execution logging
     17    let currentQueryId = null; // Track query_id for database updates on retries
    1618
    1719    // Helper: scroll chat to bottom
     
    218220        lastQueryRequest = queryRequest;
    219221        lastQueryChatHistory = JSON.parse(JSON.stringify(chatHistory));
     222        currentQueryId = null; // Reset query_id for new query
     223        executionRetryCount = 0; // Reset execution retry count
    220224        renderMessage(null, 'user', queryRequest);
    221225        $('#query-request').val('');
     
    239243            };
    240244
    241             // If this is a retry, include the failed query and error for AI context
    242             if (attempt > 1 && lastFailedSqlQuery) {
    243                 requestData.failed_sql_query = lastFailedSqlQuery;
    244                 requestData.sql_error = lastErrorMessage;
     245            // If this is a retry, include the failed query, error and query_id for AI context
     246            if (attempt > 1 && (lastFailedSqlQuery || lastErrorMessage)) {
     247                requestData.failed_sql_query = lastFailedSqlQuery || '';
     248                requestData.sql_error = lastErrorMessage || '';
    245249                requestData.retry_attempt = attempt;
     250                if (currentQueryId) {
     251                    requestData.query_id = currentQueryId;
     252                }
     253                console.log('[RETRY DEBUG] Sending retry - attempt:', attempt, 'currentQueryId:', currentQueryId, 'lastFailedSqlQuery:', !!lastFailedSqlQuery, 'lastErrorMessage:', !!lastErrorMessage);
     254            } else {
     255                console.log('[QUERY DEBUG] First attempt - attempt:', attempt, 'currentQueryId:', currentQueryId);
    246256            }
    247257
     
    260270                    let sql_query = (response.data && response.data.sql_query) ? response.data.sql_query : (response.sql_query ? response.sql_query : '');
    261271                    currentSqlQuery = sql_query || '';
     272
     273                    // Store query_id for tracking (from first response)
     274                    let responseQueryId = (response.data && response.data.query_id) ? response.data.query_id : null;
     275                    console.log('[RESPONSE DEBUG] response.success:', response.success, 'responseQueryId:', responseQueryId, 'currentQueryId before:', currentQueryId);
     276                    if (responseQueryId && !currentQueryId) {
     277                        currentQueryId = responseQueryId;
     278                        console.log('[QUERY] Got query_id:', currentQueryId);
     279                    }
     280
    262281                    // Only execute the paginated query, do NOT render SQL or button
    263282                    if (response.success && currentSqlQuery) {
     
    273292                    } else {
    274293                        // Store failed query info for next retry
    275                         if (sql_query) {
    276                             lastFailedSqlQuery = sql_query;
     294                        // Capture SQL query even on failure if available
     295                        let failedQuery = sql_query ||
     296                            (response.data && response.data.sql_query) ||
     297                            (response.sql_query) || '';
     298                        if (failedQuery) {
     299                            lastFailedSqlQuery = failedQuery;
    277300                        }
    278                         lastErrorMessage = (response.data && response.data.message) ? response.data.message : 'Query failed';
     301
     302                        // Capture query_id from error response for retry tracking
     303                        let errorQueryId = (response.data && response.data.query_id) ? response.data.query_id : null;
     304                        if (errorQueryId && !currentQueryId) {
     305                            currentQueryId = errorQueryId;
     306                            console.log('[RETRY] Got query_id from error response:', currentQueryId);
     307                        }
     308
     309                        // Get error message from response
     310                        lastErrorMessage = (response.data && response.data.message) ? response.data.message :
     311                            (response.message) ? response.message : 'Query failed - AI could not generate valid SQL';
     312
     313                        console.log('[RETRY] Attempt', attempt, 'failed. SQL:', lastFailedSqlQuery, 'Error:', lastErrorMessage, 'query_id:', currentQueryId);
    279314
    280315                        // Check if it's a non-retryable error (like security restriction)
     
    283318
    284319                        if (isNonRetryableError || attempt >= maxAttempts) {
    285                             // Max attempts reached or non-retryable error, show final error
     320                            // Max attempts reached or non-retryable error - log final failure
     321                            logExecutionResult(false, lastFailedSqlQuery, lastErrorMessage, attempt);
     322                            executionRetryCount = 0; // Reset
     323
    286324                            removeLoading();
    287325                            $('#process-query').prop('disabled', false);
     
    315353                            lastErrorMessage = resp.data.message;
    316354                        }
     355                        // Capture SQL query from error response if available
     356                        if (resp && resp.data && resp.data.sql_query) {
     357                            lastFailedSqlQuery = resp.data.sql_query;
     358                        }
    317359                    } catch(e){}
    318360
     361                    console.log('[RETRY] Attempt', attempt, 'error. Error:', lastErrorMessage);
     362
    319363                    if (attempt >= maxAttempts) {
    320                         // Max attempts reached, show final error
     364                        // Max attempts reached - log final failure
     365                        logExecutionResult(false, lastFailedSqlQuery, 'Network error: ' + lastErrorMessage, attempt);
     366                        executionRetryCount = 0; // Reset
     367
    321368                        removeLoading();
    322369                        $('#process-query').prop('disabled', false);
     
    362409
    363410            // If this is a retry, include the failed query and error for AI context
    364             if (attempt > 1 && lastFailedSqlQuery) {
    365                 requestData.failed_sql_query = lastFailedSqlQuery;
    366                 requestData.sql_error = lastErrorMessage;
     411            if (attempt > 1 && (lastFailedSqlQuery || lastErrorMessage)) {
     412                requestData.failed_sql_query = lastFailedSqlQuery || '';
     413                requestData.sql_error = lastErrorMessage || '';
    367414                requestData.retry_attempt = attempt;
    368415            }
     
    392439                    } else {
    393440                        // Store failed query info for next retry
    394                         if (sql_query) {
    395                             lastFailedSqlQuery = sql_query;
     441                        // Capture SQL query even on failure if available
     442                        let failedQuery = sql_query ||
     443                            (response.data && response.data.sql_query) ||
     444                            (response.sql_query) || '';
     445                        if (failedQuery) {
     446                            lastFailedSqlQuery = failedQuery;
    396447                        }
    397                         lastErrorMessage = (response.data && response.data.message) ? response.data.message : 'Query failed';
     448
     449                        // Get error message from response
     450                        lastErrorMessage = (response.data && response.data.message) ? response.data.message :
     451                            (response.message) ? response.message : 'Query failed - AI could not generate valid SQL';
     452
     453                        console.log('[RETRY-LAST] Attempt', attempt, 'failed. SQL:', lastFailedSqlQuery, 'Error:', lastErrorMessage);
    398454
    399455                        // Check if it's a non-retryable error (like security restriction)
     
    402458
    403459                        if (isNonRetryableError || attempt >= maxAttempts) {
    404                             // Max attempts reached or non-retryable error, show final error
     460                            // Max attempts reached or non-retryable error - log final failure
     461                            logExecutionResult(false, lastFailedSqlQuery, lastErrorMessage, attempt);
     462                            executionRetryCount = 0; // Reset
     463
    405464                            removeLoading();
    406465                            $('#process-query').prop('disabled', false);
     
    434493                            lastErrorMessage = resp.data.message;
    435494                        }
     495                        // Capture SQL query from error response if available
     496                        if (resp && resp.data && resp.data.sql_query) {
     497                            lastFailedSqlQuery = resp.data.sql_query;
     498                        }
    436499                    } catch(e){}
    437500
     501                    console.log('[RETRY-LAST] Attempt', attempt, 'error. Error:', lastErrorMessage);
     502
    438503                    if (attempt >= maxAttempts) {
    439                         // Max attempts reached, show final error
     504                        // Max attempts reached - log final failure
     505                        logExecutionResult(false, lastFailedSqlQuery, 'Network error: ' + lastErrorMessage, attempt);
     506                        executionRetryCount = 0; // Reset
     507
    440508                        removeLoading();
    441509                        $('#process-query').prop('disabled', false);
     
    450518        }
    451519        tryProcessQuery();
     520    }
     521
     522    // Retry with execution error context - called when SQL execution fails
     523    function retryWithExecutionError(originalQuery, failedSql, executionError) {
     524        console.log('[RETRY EXEC] Starting retry with execution error context');
     525        console.log('[RETRY EXEC] Original query:', originalQuery);
     526        console.log('[RETRY EXEC] Failed SQL:', failedSql);
     527        console.log('[RETRY EXEC] Execution error:', executionError);
     528
     529        // Show loading
     530        renderLoading();
     531        $('#process-query').prop('disabled', true);
     532
     533        let attempt = 0;
     534        const maxAttempts = 5;
     535        let lastFailedSqlQuery = failedSql;
     536        let lastErrorMessage = executionError;
     537
     538        function tryProcessQueryWithContext() {
     539            attempt++;
     540            console.log('[RETRY EXEC] Attempt', attempt, 'of', maxAttempts);
     541
     542            // Always include error context since we're retrying due to execution error
     543            let requestData = {
     544                action: 'askeet_process_query_request',
     545                query_request: originalQuery,
     546                failed_sql_query: lastFailedSqlQuery,
     547                sql_error: lastErrorMessage,
     548                retry_attempt: attempt,
     549                nonce: askeet_query_assistant.nonce,
     550                install_id: askeet_query_assistant.install_id
     551            };
     552
     553            // Include query_id for database tracking
     554            if (currentQueryId) {
     555                requestData.query_id = currentQueryId;
     556            }
     557
     558            console.log('[RETRY EXEC DEBUG] query_id being sent:', currentQueryId, 'retry_attempt:', attempt);
     559
     560            $.ajax({
     561                url: askeet_query_assistant.ajax_url,
     562                type: 'POST',
     563                data: requestData,
     564                success: function(response) {
     565                    if (handleLimitModals(response)) {
     566                        removeLoading();
     567                        $('#process-query').prop('disabled', false);
     568                        return;
     569                    }
     570
     571                    let sql_query = (response.data && response.data.sql_query) ? response.data.sql_query : (response.sql_query ? response.sql_query : '');
     572                    currentSqlQuery = sql_query || '';
     573
     574                    if (response.success && currentSqlQuery) {
     575                        console.log('[RETRY EXEC] Got new SQL, executing:', currentSqlQuery);
     576                        // Try to execute the new query
     577                        executeQueryPage(1, true);
     578                    } else if (response.success) {
     579                        removeLoading();
     580                        $('#process-query').prop('disabled', false);
     581                        renderMessage('<div class="query-success">'+askeet_query_assistant_i18n.query_executed_successfully+' 0 '+askeet_query_assistant_i18n.results_found+'.</div>', 'ai');
     582                    } else {
     583                        // AI returned error - capture and retry if attempts left
     584                        let newFailedQuery = sql_query ||
     585                            (response.data && response.data.sql_query) ||
     586                            (response.sql_query) || lastFailedSqlQuery;
     587                        if (newFailedQuery) {
     588                            lastFailedSqlQuery = newFailedQuery;
     589                        }
     590                        lastErrorMessage = (response.data && response.data.message) ? response.data.message :
     591                            (response.message) ? response.message : 'Query generation failed';
     592
     593                        console.log('[RETRY EXEC] Attempt', attempt, 'failed. New error:', lastErrorMessage);
     594
     595                        if (attempt >= maxAttempts) {
     596                            // Log final failure after all retries exhausted
     597                            logExecutionResult(false, lastFailedSqlQuery, lastErrorMessage, attempt);
     598                            executionRetryCount = 0; // Reset
     599
     600                            removeLoading();
     601                            $('#process-query').prop('disabled', false);
     602                            clearErrorMessages();
     603                            renderMessage('<div class="query-error">'+(askeet_query_assistant_i18n.ai_failed_5_times || askeet_query_assistant_i18n.ai_failed_3_times)+'</div>', 'ai', null, true);
     604                        } else {
     605                            setTimeout(tryProcessQueryWithContext, 1000);
     606                        }
     607                    }
     608                },
     609                error: function(xhr, status, error) {
     610                    lastErrorMessage = error || 'Network error';
     611                    console.log('[RETRY EXEC] Network error on attempt', attempt, ':', lastErrorMessage);
     612
     613                    if (attempt >= maxAttempts) {
     614                        // Log final failure after all retries exhausted (network error)
     615                        logExecutionResult(false, lastFailedSqlQuery, 'Network error: ' + lastErrorMessage, attempt);
     616                        executionRetryCount = 0; // Reset
     617
     618                        removeLoading();
     619                        $('#process-query').prop('disabled', false);
     620                        clearErrorMessages();
     621                        renderMessage('<div class="query-error">'+askeet_query_assistant_i18n.error_communication+'</div>', 'ai', null, true);
     622                    } else {
     623                        setTimeout(tryProcessQueryWithContext, 1000);
     624                    }
     625                }
     626            });
     627        }
     628
     629        tryProcessQueryWithContext();
    452630    }
    453631
     
    525703
    526704                if (response.success) {
     705                    // Log successful execution
     706                    logExecutionResult(true, currentSqlQuery, '', executionRetryCount);
     707                    executionRetryCount = 0; // Reset retry count after success
     708
    527709                    lastResults = response.data.results;
    528710                    lastResultsHtml = response.data.html_results;
     
    627809                }
    628810                else {
    629                     clearErrorMessages();
    630                     let errorMsg = '';
    631                     if (response.data && response.data.message && response.data.message.indexOf('Seules les requêtes SELECT sont autorisées') !== -1) {
    632                         errorMsg = response.data.message;
     811                    // SQL execution error - capture for potential retry
     812                    let executionError = (response.data && response.data.message) ? response.data.message : 'SQL execution failed';
     813                    let failedSql = currentSqlQuery || '';
     814
     815                    console.log('[EXEC ERROR] SQL:', failedSql, 'Error:', executionError);
     816
     817                    // Check if it's a non-retryable error (like security restriction)
     818                    let isNonRetryableError = response.data && response.data.message &&
     819                        response.data.message.indexOf('Seules les requêtes SELECT sont autorisées') !== -1;
     820
     821                    if (isNonRetryableError) {
     822                        // Security error - don't retry, just show error and log failure
     823                        logExecutionResult(false, failedSql, executionError, 0);
     824                        clearErrorMessages();
     825                        renderMessage('<div class="query-error">'+response.data.message+'</div>', 'ai', null, true);
     826                    } else if (isNewQuery && lastQueryRequest) {
     827                        // This was a new query that failed on execution - trigger auto-retry with context
     828                        console.log('[EXEC ERROR] Triggering auto-retry with execution error context');
     829                        executionRetryCount++; // Increment retry count
     830                        retryWithExecutionError(lastQueryRequest, failedSql, executionError);
    633831                    } else {
    634                         errorMsg = askeet_query_assistant_i18n.ai_failed_3_times;
    635                     }
    636                     renderMessage('<div class="query-error">'+errorMsg+'</div>', 'ai', null, true);
     832                        // Not a new query or no original query - just show error with retry button and log failure
     833                        logExecutionResult(false, failedSql, executionError, executionRetryCount);
     834                        executionRetryCount = 0; // Reset
     835                        clearErrorMessages();
     836                        renderMessage('<div class="query-error">'+executionError+'</div>', 'ai', null, true);
     837                    }
    637838                }
    638839            },
     
    640841                removeLoading();
    641842                clearErrorMessages();
     843                // Log network/AJAX error
     844                logExecutionResult(false, currentSqlQuery, 'Network error: ' + (error || status), executionRetryCount);
     845                executionRetryCount = 0; // Reset
     846
    642847                try {
    643848                    var resp = xhr.responseJSON || JSON.parse(xhr.responseText);
     
    14411646    });
    14421647
     1648    // ========================================
     1649    // EXECUTION RESULT LOGGING
     1650    // ========================================
     1651
     1652    /**
     1653     * Log the actual SQL execution result to the API for tracking.
     1654     * Updates the existing query record with WordPress execution results.
     1655     *
     1656     * @param {boolean} success - Whether the SQL executed successfully
     1657     * @param {string} sqlQuery - The SQL that was executed
     1658     * @param {string} error - Error message if execution failed
     1659     * @param {number} retryCount - Number of retries that were needed
     1660     */
     1661    function logExecutionResult(success, sqlQuery, error, retryCount) {
     1662        // Don't block execution, fire and forget
     1663        let requestData = {
     1664            install_id: installId,
     1665            sql_query: sqlQuery || '',
     1666            execution_success: success,
     1667            execution_error: error || '',
     1668            retry_count: retryCount || 0
     1669        };
     1670
     1671        // Include query_id if available for more reliable matching
     1672        if (currentQueryId) {
     1673            requestData.query_id = currentQueryId;
     1674        }
     1675
     1676        $.ajax({
     1677            url: apiUrl + '/log-execution-result',
     1678            type: 'POST',
     1679            contentType: 'application/json',
     1680            data: JSON.stringify(requestData),
     1681            success: function(response) {
     1682                console.log('[EXEC LOG] Execution result logged:', success ? 'SUCCESS' : 'FAILED', 'query_id:', currentQueryId);
     1683            },
     1684            error: function(xhr, status, err) {
     1685                console.log('[EXEC LOG] Failed to log execution result:', err);
     1686            }
     1687        });
     1688    }
     1689
    14431690    // Star click - submit rating
    14441691    $(document).on('click', '.wcqa-star', function() {
Note: See TracChangeset for help on using the changeset viewer.