Fix workflow forward task immediate disconnection issue
Fixed critical bug where forward tasks in workflows would immediately disconnect calls instead of forwarding them properly. Changes: - Fixed append_twiml_element function to properly handle Dial elements with child Number elements - Enhanced create_forward_twiml to extract numbers from nested data structures - Added comprehensive error handling for missing forward numbers - Added detailed logging throughout workflow execution for debugging - Set default timeout of 30 seconds for forward operations The issue was caused by the Dial element being converted to string which lost all child Number elements, resulting in an empty dial that would immediately disconnect. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -413,6 +413,7 @@ jQuery(document).ready(function($) {
|
||||
html += '</select>';
|
||||
html += '<input type="hidden" name="voice_name" value="' + (data.voice_name || '') + '">';
|
||||
html += '<button type="button" class="button button-small" onclick="loadWorkflowVoices(this)">Load Voices</button>';
|
||||
html += '<button type="button" class="button button-small" onclick="refreshWorkflowVoices(this)" title="Refresh voices">🔄</button>';
|
||||
html += '</div>';
|
||||
|
||||
// Audio File Options
|
||||
@@ -454,6 +455,7 @@ jQuery(document).ready(function($) {
|
||||
html += '</select>';
|
||||
html += '<input type="hidden" name="voice_name" value="' + (data.voice_name || '') + '">';
|
||||
html += '<button type="button" class="button button-small" onclick="loadWorkflowVoices(this)">Load Voices</button>';
|
||||
html += '<button type="button" class="button button-small" onclick="refreshWorkflowVoices(this)" title="Refresh voices">🔄</button>';
|
||||
html += '</div>';
|
||||
|
||||
// Audio File Options
|
||||
@@ -520,6 +522,7 @@ jQuery(document).ready(function($) {
|
||||
html += '</select>';
|
||||
html += '<input type="hidden" name="voice_name" value="' + (data.voice_name || '') + '">';
|
||||
html += '<button type="button" class="button button-small" onclick="loadWorkflowVoices(this)">Load Voices</button>';
|
||||
html += '<button type="button" class="button button-small" onclick="refreshWorkflowVoices(this)" title="Refresh voices">🔄</button>';
|
||||
html += '</div>';
|
||||
|
||||
// Audio File Options
|
||||
@@ -559,6 +562,7 @@ jQuery(document).ready(function($) {
|
||||
html += '</select>';
|
||||
html += '<input type="hidden" name="voice_name" value="' + (data.voice_name || '') + '">';
|
||||
html += '<button type="button" class="button button-small" onclick="loadWorkflowVoices(this)">Load Voices</button>';
|
||||
html += '<button type="button" class="button button-small" onclick="refreshWorkflowVoices(this)" title="Refresh voices">🔄</button>';
|
||||
html += '</div>';
|
||||
|
||||
// Audio File Options
|
||||
@@ -1774,6 +1778,97 @@ jQuery(document).ready(function($) {
|
||||
});
|
||||
};
|
||||
|
||||
// Refresh voices function for workflow
|
||||
window.refreshWorkflowVoices = function(buttonOrSelect) {
|
||||
var $button, $select;
|
||||
|
||||
// Check if we were passed a button or a select element
|
||||
if ($(buttonOrSelect).is('button')) {
|
||||
$button = $(buttonOrSelect);
|
||||
$select = $button.prev('select.voice-select');
|
||||
} else if ($(buttonOrSelect).is('select')) {
|
||||
$select = $(buttonOrSelect);
|
||||
$button = $select.next('button');
|
||||
} else {
|
||||
// Fallback - assume it's a button
|
||||
$button = $(buttonOrSelect);
|
||||
$select = $button.prev('select.voice-select');
|
||||
}
|
||||
|
||||
// Read the current value
|
||||
var currentValue = '';
|
||||
var selectedOption = $select.find('option:selected');
|
||||
if (selectedOption.length && selectedOption.val()) {
|
||||
currentValue = selectedOption.val();
|
||||
} else {
|
||||
currentValue = $select.attr('data-current') || '';
|
||||
}
|
||||
|
||||
if ($button.length) {
|
||||
$button.text('Refreshing...').prop('disabled', true);
|
||||
}
|
||||
|
||||
$.post(twp_ajax.ajax_url, {
|
||||
action: 'twp_refresh_elevenlabs_voices',
|
||||
nonce: twp_ajax.nonce
|
||||
}, function(response) {
|
||||
if ($button.length) {
|
||||
$button.text('🔄').prop('disabled', false);
|
||||
}
|
||||
|
||||
if (response.success) {
|
||||
var options = '<option value="">Default voice</option>';
|
||||
|
||||
response.data.forEach(function(voice) {
|
||||
var selected = (voice.voice_id === currentValue) ? ' selected' : '';
|
||||
var description = voice.labels ? Object.values(voice.labels).join(', ') : '';
|
||||
var optionText = voice.name + (description ? ' (' + description + ')' : '');
|
||||
options += '<option value="' + voice.voice_id + '" data-voice-name="' + voice.name + '"' + selected + '>' + optionText + '</option>';
|
||||
});
|
||||
|
||||
$select.html(options);
|
||||
|
||||
// If we had a current value, make sure it's selected
|
||||
if (currentValue) {
|
||||
$select.val(currentValue);
|
||||
// Update the voice name field with the selected voice's name
|
||||
var $voiceNameInput = $select.siblings('input[name="voice_name"]');
|
||||
if ($voiceNameInput.length) {
|
||||
var selectedVoice = $select.find('option:selected');
|
||||
var voiceName = selectedVoice.data('voice-name') || selectedVoice.text() || '';
|
||||
if (selectedVoice.val() === '') {
|
||||
voiceName = '';
|
||||
}
|
||||
$voiceNameInput.val(voiceName);
|
||||
}
|
||||
}
|
||||
|
||||
// Show success message
|
||||
var $statusMsg = $('<span style="color: green; font-size: 12px; margin-left: 5px;">Refreshed!</span>');
|
||||
$button.after($statusMsg);
|
||||
setTimeout(function() {
|
||||
$statusMsg.remove();
|
||||
}, 3000);
|
||||
|
||||
} else {
|
||||
var errorMessage = 'Error refreshing voices: ';
|
||||
if (typeof response.data === 'string') {
|
||||
errorMessage += response.data;
|
||||
} else if (response.data && response.data.message) {
|
||||
errorMessage += response.data.message;
|
||||
} else {
|
||||
errorMessage += 'Unknown error';
|
||||
}
|
||||
alert(errorMessage);
|
||||
}
|
||||
}).fail(function() {
|
||||
if ($button.length) {
|
||||
$button.text('🔄').prop('disabled', false);
|
||||
}
|
||||
alert('Failed to refresh voices. Please check your API key.');
|
||||
});
|
||||
};
|
||||
|
||||
// Toggle audio type options visibility
|
||||
$(document).on('change', 'input[name="audio_type"]', function() {
|
||||
var $container = $(this).closest('.step-config-section');
|
||||
|
Reference in New Issue
Block a user