| @@ -59,427 +59,13 @@ | ||
| 59 | 59 | $('.mxch-mobile-menu').removeClass('open'); |
| 60 | 60 | $('.mxch-mobile-overlay').removeClass('open'); |
| 61 | 61 | }); |
| 62 | 62 | |
| 63 | - // ========================================================================== | |
| 64 | - // AI Tools: autosave the function-calling toggle + per-tool checklist | |
| 65 | - // (matches MxChat's autosave UX — no Save button). plan a41dee. | |
| 66 | - // ========================================================================== | |
| 67 | - var $fc = $('#mxch-fc-settings'); | |
| 68 | - if ($fc.length) { | |
| 69 | - var fcNonce = $fc.data('fc-nonce'); | |
| 70 | - var $fcStatus = $('#mxch-fc-save-status'); | |
| 71 | - var fcTimer = null; | |
| 72 | - | |
| 73 | - function fcCollectAndSave() { | |
| 74 | - // Presence = active (plan d450a7): the global on/off toggle is gone, so | |
| 75 | - // the gate is derived from whether any tool is enabled. The server | |
| 76 | - // derives this too; we send it for an immediate, correct nav badge. | |
| 77 | - var enabled = $fc.find('input[name="mxchat_fc_tools[]"]:checked').length > 0 ? '1' : '0'; | |
| 78 | - var allTools = $fc.find('input[name="mxchat_fc_all_tools[]"]').map(function () { return $(this).val(); }).get(); | |
| 79 | - var checked = $fc.find('input[name="mxchat_fc_tools[]"]:checked').map(function () { return $(this).val(); }).get(); | |
| 80 | - // Per-tool "when to use" hints, keyed by callback. | |
| 81 | - var hints = {}; | |
| 82 | - $fc.find('.mxch-fc-hint-input').each(function () { | |
| 83 | - var cb = $(this).data('fc-callback'); | |
| 84 | - if (cb) { hints[cb] = $(this).val(); } | |
| 85 | - }); | |
| 86 | - | |
| 87 | - if ($fcStatus.length) { $fcStatus.text('Saving…').removeClass('is-saved is-error'); } | |
| 88 | - | |
| 89 | - $.post(mxchActionsData.ajaxUrl, { | |
| 90 | - action: 'mxchat_fc_autosave', | |
| 91 | - nonce: fcNonce, | |
| 92 | - enabled: enabled, | |
| 93 | - all_tools: allTools, | |
| 94 | - tools: checked, | |
| 95 | - hints: hints | |
| 96 | - }).done(function () { | |
| 97 | - if ($fcStatus.length) { | |
| 98 | - $fcStatus.text('Saved').addClass('is-saved'); | |
| 99 | - setTimeout(function () { $fcStatus.text('').removeClass('is-saved'); }, 2000); | |
| 100 | - } | |
| 101 | - }).fail(function () { | |
| 102 | - if ($fcStatus.length) { $fcStatus.text('Save failed — try again').addClass('is-error'); } | |
| 103 | - }); | |
| 104 | - } | |
| 105 | - | |
| 106 | - // The hidden store's checkboxes are toggled programmatically by the | |
| 107 | - // list/detail/modal flow (which calls fcCollectAndSave() directly). Keep | |
| 108 | - // a change-bound autosave as a safety net for any direct mutation. | |
| 109 | - $fc.on('change', 'input[name="mxchat_fc_tools[]"]', function () { | |
| 110 | - clearTimeout(fcTimer); | |
| 111 | - fcTimer = setTimeout(fcCollectAndSave, 200); | |
| 112 | - }); | |
| 113 | - | |
| 114 | - // ====================================================================== | |
| 115 | - // AI Tools MASTER-DETAIL list + detail panel (plan d450a7). | |
| 116 | - // Clones the Trigger Phrases list/detail UX: the left list shows the | |
| 117 | - // ACTIVE tools (a tool in the list = active — no global toggle, no | |
| 118 | - // per-tool enable checkbox); selecting one shows its detail on the right | |
| 119 | - // with Edit (usage note) + Remove. "Add" opens the same two-step | |
| 120 | - // capability picker. Pure view layer over the hidden #mxch-fc-tool-store | |
| 121 | - // inputs — the unchanged mxchat_fc_autosave contract (mxchat_fc_tools[] / | |
| 122 | - // mxchat_fc_all_tools[] + hints) stays the source of truth. FC-specific | |
| 123 | - // IDs/classes keep the Trigger Phrases JS off these elements. | |
| 124 | - // ====================================================================== | |
| 125 | - var $fcStore = $('#mxch-fc-tool-store'); | |
| 126 | - if ($fcStore.length) { | |
| 127 | - var $fcPanel = $('#mxch-fc-panel'); | |
| 128 | - var $fcList = $('#mxch-fc-list'); | |
| 129 | - var $fcCount = $('#mxch-fc-count'); | |
| 130 | - var $fcEmpty = $('#mxch-fc-empty'); | |
| 131 | - var $fcView = $('#mxch-fc-view'); | |
| 132 | - var $fcDetail = $('#mxch-fc-detail-panel'); | |
| 133 | - var $fcSearch = $('#mxch-fc-search'); | |
| 134 | - var $fcModal = $('#mxch-fc-tool-modal'); | |
| 135 | - var fcCurrentCb = null; // tool being added/edited in the modal | |
| 136 | - var fcViewCb = null; // tool currently shown in the detail panel | |
| 137 | - var fcGuardedClose = null; // dirty-checked close, re-armed on each open | |
| 138 | - var fcSelected = new Set(); // callbacks ticked for bulk remove (plan 5f7409) | |
| 139 | - | |
| 140 | - var fcI18n = { | |
| 141 | - tools: $fcPanel.data('i18n-tools') || 'tools', | |
| 142 | - tool: $fcPanel.data('i18n-tool') || 'tool', | |
| 143 | - active: $fcPanel.data('i18n-active') || 'Active', | |
| 144 | - addon: $fcPanel.data('i18n-addon') || 'Add-on', | |
| 145 | - sensitive: $fcPanel.data('i18n-sensitive') || 'Sensitive', | |
| 146 | - noHint: $fcPanel.data('i18n-nohint') || 'No usage note — the AI decides on its own when to use this.' | |
| 147 | - }; | |
| 148 | - // Localized Add/Edit titles + button labels read from the modal DOM. | |
| 149 | - var $fcStep2Title = $('#mxch-fc-modal-step2-title'); | |
| 150 | - var $fcSaveBtn = $('#mxch-fc-modal-save'); | |
| 151 | - var FC_TITLE_ADD = $fcStep2Title.data('add-title') || 'Add Tool'; | |
| 152 | - var FC_TITLE_EDIT = $fcStep2Title.data('edit-title') || 'Edit Tool'; | |
| 153 | - var FC_BTN_ADD = $fcSaveBtn.data('add-label') || 'Add Tool'; | |
| 154 | - var FC_BTN_SAVE = $fcSaveBtn.data('save-label') || 'Save Changes'; | |
| 155 | - | |
| 156 | - function fcEsc(s) { return $('<div>').text(s == null ? '' : String(s)).html(); } | |
| 157 | - function fcEntry(cb) { | |
| 158 | - return $fcStore.find('.mxch-fc-tool').filter(function () { | |
| 159 | - return String($(this).data('fc-callback')) === String(cb); | |
| 160 | - }); | |
| 161 | - } | |
| 162 | - function fcIsOn($t) { return $t.find('input[name="mxchat_fc_tools[]"]').is(':checked'); } | |
| 163 | - function fcIsMobile() { return window.innerWidth <= 782; } | |
| 164 | - | |
| 165 | - // Show the empty "Select a tool" state in the detail panel. | |
| 166 | - function fcShowEmpty() { | |
| 167 | - fcViewCb = null; | |
| 168 | - if ($fcView.length) $fcView.hide(); | |
| 169 | - if ($fcEmpty.length) $fcEmpty.show(); | |
| 170 | - $fcList.find('.mxch-fc-list-item').removeClass('active'); | |
| 171 | - if (fcIsMobile()) { $fcDetail.removeClass('mobile-active'); $('body').removeClass('mxch-mobile-panel-open'); } | |
| 172 | - } | |
| 173 | - | |
| 174 | - // Build the left list from the store (active tools only), applying the | |
| 175 | - // current search filter. Updates the count + resets the view if the | |
| 176 | - // shown tool was just removed. | |
| 177 | - function fcRenderList() { | |
| 178 | - if (!$fcList.length) return; | |
| 179 | - var q = $.trim(($fcSearch.val() || '')).toLowerCase(); | |
| 180 | - $fcList.empty(); | |
| 181 | - var total = 0; | |
| 182 | - $fcStore.find('.mxch-fc-tool').each(function () { | |
| 183 | - var $t = $(this); | |
| 184 | - if (!fcIsOn($t)) return; | |
| 185 | - total++; | |
| 186 | - var cb = $t.data('fc-callback'); | |
| 187 | - var label = $t.data('fc-label') || cb; | |
| 188 | - var desc = $t.data('fc-desc') || ''; | |
| 189 | - var icon = $t.data('fc-icon') || 'admin-generic'; | |
| 190 | - var isAddon = String($t.data('fc-addon')) === '1'; | |
| 191 | - var isCautious = String($t.data('fc-cautious')) === '1'; | |
| 192 | - if (q && String(label).toLowerCase().indexOf(q) === -1 && String(desc).toLowerCase().indexOf(q) === -1) return; | |
| 193 | - var typeBits = []; | |
| 194 | - if (isAddon) typeBits.push(fcI18n.addon); | |
| 195 | - if (isCautious) typeBits.push(fcI18n.sensitive); | |
| 196 | - var typeLabel = typeBits.length ? typeBits.join(' · ') : fcI18n.active; | |
| 197 | - var activeCls = (String(cb) === String(fcViewCb)) ? ' active' : ''; | |
| 198 | - var isSel = fcSelected.has(String(cb)); | |
| 199 | - var selCls = isSel ? ' selected' : ''; | |
| 200 | - $fcList.append( | |
| 201 | - '<div class="mxch-fc-list-item' + activeCls + selCls + '" data-fc-callback="' + fcEsc(cb) + '">' + | |
| 202 | - '<input type="checkbox" class="mxch-fc-checkbox"' + (isSel ? ' checked' : '') + '>' + | |
| 203 | - '<div class="mxch-action-icon"><span class="dashicons dashicons-' + fcEsc(icon) + '"></span></div>' + | |
| 204 | - '<div class="mxch-action-info">' + | |
| 205 | - '<div class="mxch-action-name">' + fcEsc(label) + '</div>' + | |
| 206 | - '<div class="mxch-action-type-label">' + fcEsc(typeLabel) + '</div>' + | |
| 207 | - '</div>' + | |
| 208 | - '<div class="mxch-action-meta">' + | |
| 209 | - '<span class="mxch-action-status enabled">' + fcEsc(fcI18n.active) + '</span>' + | |
| 210 | - '</div>' + | |
| 211 | - '</div>' | |
| 212 | - ); | |
| 213 | - }); | |
| 214 | - if ($fcCount.length) { | |
| 215 | - $fcCount.text(total + ' ' + (total === 1 ? fcI18n.tool : fcI18n.tools)); | |
| 216 | - } | |
| 217 | - // Drop any selected callbacks that are no longer in the list (e.g. | |
| 218 | - // filtered out or removed) so the bulk count stays truthful. | |
| 219 | - var fcPresent = {}; | |
| 220 | - $fcList.find('.mxch-fc-list-item').each(function () { | |
| 221 | - fcPresent[String($(this).data('fc-callback'))] = true; | |
| 222 | - }); | |
| 223 | - fcSelected.forEach(function (selCb) { | |
| 224 | - if (!fcPresent[String(selCb)]) { fcSelected.delete(selCb); } | |
| 225 | - }); | |
| 226 | - fcUpdateSelectionUI(); | |
| 227 | - // If the tool currently in the detail panel is no longer active, reset. | |
| 228 | - if (fcViewCb && !fcIsOn(fcEntry(fcViewCb))) { fcShowEmpty(); } | |
| 229 | - } | |
| 230 | - | |
| 231 | - // Populate + show the detail view for one tool. | |
| 232 | - function fcSelectTool(cb) { | |
| 233 | - var $t = fcEntry(cb); | |
| 234 | - if (!$t.length || !fcIsOn($t)) { fcShowEmpty(); return; } | |
| 235 | - fcViewCb = String(cb); | |
| 236 | - var label = $t.data('fc-label') || cb; | |
| 237 | - var desc = $t.data('fc-desc') || ''; | |
| 238 | - var icon = $t.data('fc-icon') || 'admin-generic'; | |
| 239 | - var isAddon = String($t.data('fc-addon')) === '1'; | |
| 240 | - var isCautious = String($t.data('fc-cautious')) === '1'; | |
| 241 | - var hint = $.trim($t.find('.mxch-fc-hint-input').val() || ''); | |
| 242 | - var typeBits = []; | |
| 243 | - if (isAddon) typeBits.push(fcI18n.addon); | |
| 244 | - if (isCautious) typeBits.push(fcI18n.sensitive); | |
| 245 | - $('#mxch-fc-view-icon').html('<span class="dashicons dashicons-' + fcEsc(icon) + '"></span>'); | |
| 246 | - $('#mxch-fc-view-label').text(label); | |
| 247 | - $('#mxch-fc-view-type').text(typeBits.join(' · ')); | |
| 248 | - $('#mxch-fc-view-desc').text(desc); | |
| 249 | - var $hint = $('#mxch-fc-view-hint'); | |
| 250 | - if (hint) { $hint.text(hint).removeClass('is-muted'); } | |
| 251 | - else { $hint.text(fcI18n.noHint).addClass('is-muted'); } | |
| 252 | - // Setup requirement (plan 183856): show the tool's setup note (e.g. the | |
| 253 | - // Brave-key requirement on Web/Image Search) when present, else hide it. | |
| 254 | - var setup = $.trim(String($t.data('fc-setup') || '')); | |
| 255 | - var $setupWrap = $('#mxch-fc-view-setup-wrap'); | |
| 256 | - if (setup) { $('#mxch-fc-view-setup').text(setup); $setupWrap.show(); } | |
| 257 | - else { $setupWrap.hide(); } | |
| 258 | - $fcEmpty.hide(); | |
| 259 | - $fcView.show(); | |
| 260 | - $fcList.find('.mxch-fc-list-item').removeClass('active') | |
| 261 | - .filter(function () { return String($(this).data('fc-callback')) === String(cb); }).addClass('active'); | |
| 262 | - if (fcIsMobile()) { $fcDetail.addClass('mobile-active'); $('body').addClass('mxch-mobile-panel-open'); } | |
| 263 | - } | |
| 264 | - | |
| 265 | - // ---- Add/Edit modal (two-step capability picker) ---- | |
| 266 | - function fcShowStep(n) { | |
| 267 | - $fcModal.find('.mxch-fc-modal-step').hide(); | |
| 268 | - $fcModal.find('.mxch-fc-modal-step[data-step="' + n + '"]').show(); | |
| 269 | - } | |
| 270 | - function fcCloseModal() { $fcModal.hide(); fcCurrentCb = null; fcGuardedClose = null; } | |
| 271 | - | |
| 272 | - // The modal holds an editable "when to use" hint, so it never closes on the | |
| 273 | - // backdrop and confirms before discarding. fcArmGuard must run AFTER a step | |
| 274 | - // populates its fields: mxchatGuardedClose snapshots at call time, so arming | |
| 275 | - // it earlier would measure "dirty" against empty and confirm on every close. | |
| 276 | - function fcArmGuard() { | |
| 277 | - if (typeof mxchatGuardedClose !== 'function' || !$fcModal.length) return; | |
| 278 | - fcGuardedClose = mxchatGuardedClose($fcModal[0], fcCloseModal); | |
| 279 | - } | |
| 280 | - function fcRequestClose(e) { (fcGuardedClose || fcCloseModal)(e); } | |
| 281 | - | |
| 282 | - // Step 1: grid of tools not yet added. | |
| 283 | - function fcOpenAddModal() { | |
| 284 | - // Back-to-step-1 keeps the step-2 baseline: re-arming here would treat a | |
| 285 | - // hint typed before Back as clean and discard it silently on close. | |
| 286 | - var fcWasOpen = $fcModal.is(':visible'); | |
| 287 | - var $grid = $('#mxch-fc-modal-grid').empty(); | |
| 288 | - var addable = 0; | |
| 289 | - $fcStore.find('.mxch-fc-tool').each(function () { | |
| 290 | - var $t = $(this); | |
| 291 | - if (fcIsOn($t)) return; // already active | |
| 292 | - addable++; | |
| 293 | - var cb = $t.data('fc-callback'); | |
| 294 | - var label = $t.data('fc-label') || cb; | |
| 295 | - var desc = $t.data('fc-desc') || ''; | |
| 296 | - var icon = $t.data('fc-icon') || 'admin-generic'; | |
| 297 | - var isAddon = String($t.data('fc-addon')) === '1'; | |
| 298 | - var isCautious = String($t.data('fc-cautious')) === '1'; | |
| 299 | - var badges = ''; | |
| 300 | - if (isAddon) { badges += ' <span class="mxch-fc-badge mxch-fc-badge-addon">' + fcEsc(fcI18n.addon) + '</span>'; } | |
| 301 | - if (isCautious) { badges += ' <span class="mxch-fc-badge mxch-fc-badge-sensitive">' + fcEsc(fcI18n.sensitive) + '</span>'; } | |
| 302 | - $grid.append( | |
| 303 | - '<div class="mxch-type-card mxch-fc-type-card" data-fc-callback="' + fcEsc(cb) + '">' + | |
| 304 | - '<div class="mxch-type-icon"><span class="dashicons dashicons-' + fcEsc(icon) + '"></span></div>' + | |
| 305 | - '<div class="mxch-type-info">' + | |
| 306 | - '<h4>' + fcEsc(label) + badges + '</h4>' + | |
| 307 | - '<p>' + fcEsc(desc) + '</p>' + | |
| 308 | - '</div>' + | |
| 309 | - '</div>' | |
| 310 | - ); | |
| 311 | - }); | |
| 312 | - $('#mxch-fc-modal-allset').toggle(addable === 0); | |
| 313 | - $grid.toggle(addable > 0); | |
| 314 | - fcShowStep(1); | |
| 315 | - $fcModal.css('display', 'flex'); | |
| 316 | - if (!fcWasOpen) fcArmGuard(); | |
| 317 | - } | |
| 318 | - | |
| 319 | - // Step 2: confirm + when-to-use (shared by Add and Edit). | |
| 320 | - function fcOpenConfigStep(cb) { | |
| 321 | - var $t = fcEntry(cb); | |
| 322 | - if (!$t.length) return; | |
| 323 | - fcCurrentCb = cb; | |
| 324 | - var editing = fcIsOn($t); | |
| 325 | - $('#mxch-fc-modal-selected-icon').html('<span class="dashicons dashicons-' + fcEsc($t.data('fc-icon') || 'admin-generic') + '"></span>'); | |
| 326 | - $('#mxch-fc-modal-selected-label').text($t.data('fc-label') || cb); | |
| 327 | - $('#mxch-fc-modal-selected-desc').text($t.data('fc-desc') || ''); | |
| 328 | - $('#mxch-fc-modal-hint').val($t.find('.mxch-fc-hint-input').val() || ''); | |
| 329 | - $('#mxch-fc-modal-sensitive').toggle(String($t.data('fc-cautious')) === '1'); | |
| 330 | - $fcStep2Title.text(editing ? FC_TITLE_EDIT : FC_TITLE_ADD); | |
| 331 | - $fcSaveBtn.text(editing ? FC_BTN_SAVE : FC_BTN_ADD); | |
| 332 | - fcShowStep(2); | |
| 333 | - $fcModal.css('display', 'flex'); | |
| 334 | - fcArmGuard(); // after the hint is loaded: that value is the clean baseline | |
| 335 | - } | |
| 336 | - | |
| 337 | - // ---- wiring ---- | |
| 338 | - // "Add" buttons (panel header + empty state) — delegated on $fc. | |
| 339 | - $fc.on('click', '.js-mxch-fc-add', fcOpenAddModal); | |
| 340 | - $fcModal.on('click', '.mxch-fc-type-card', function () { fcOpenConfigStep($(this).data('fc-callback')); }); | |
| 341 | - $('#mxch-fc-modal-back').on('click', fcOpenAddModal); | |
| 342 | - $fcModal.on('click', '[data-fc-modal-close]', fcRequestClose); // X + Cancel | |
| 343 | - // No backdrop close: a click dispatches on the common ancestor of its mousedown | |
| 344 | - // and mouseup, so releasing a selection past the dialog edge targets the backdrop | |
| 345 | - // and would discard the hint — and a plain backdrop click discarded it outright. | |
| 346 | - $(document).on('keydown', function (e) { if (e.key === 'Escape' && $fcModal.is(':visible')) fcRequestClose(e); }); | |
| 347 | - | |
| 348 | - // Modal Save (Add or Edit): write the store inputs, autosave, refresh | |
| 349 | - // the list, and show the tool's detail on the right. | |
| 350 | - $fcSaveBtn.on('click', function () { | |
| 351 | - if (!fcCurrentCb) return; | |
| 352 | - var $t = fcEntry(fcCurrentCb); | |
| 353 | - if (!$t.length) return; | |
| 354 | - var cb = fcCurrentCb; | |
| 355 | - $t.find('.mxch-fc-hint-input').val($('#mxch-fc-modal-hint').val() || ''); | |
| 356 | - $t.find('input[name="mxchat_fc_tools[]"]').prop('checked', true); | |
| 357 | - fcCloseModal(); | |
| 358 | - fcRenderList(); | |
| 359 | - fcSelectTool(cb); | |
| 360 | - fcCollectAndSave(); | |
| 361 | - }); | |
| 362 | - | |
| 363 | - // List item click → show that tool's detail. | |
| 364 | - $fcList.on('click', '.mxch-fc-list-item', function () { | |
| 365 | - fcSelectTool($(this).data('fc-callback')); | |
| 366 | - }); | |
| 367 | - | |
| 368 | - // Detail Edit → reopen the config step for the viewed tool. | |
| 369 | - $('#mxch-fc-edit-btn').on('click', function () { | |
| 370 | - if (fcViewCb) fcOpenConfigStep(fcViewCb); | |
| 371 | - }); | |
| 372 | - // Detail Remove → disable the tool (keep its hint for a later re-add), | |
| 373 | - // refresh the list, and return to the empty state. | |
| 374 | - $('#mxch-fc-remove-btn').on('click', function () { | |
| 375 | - if (!fcViewCb) return; | |
| 376 | - var $t = fcEntry(fcViewCb); | |
| 377 | - if (!$t.length) return; | |
| 378 | - $t.find('input[name="mxchat_fc_tools[]"]').prop('checked', false); | |
| 379 | - fcShowEmpty(); | |
| 380 | - fcRenderList(); | |
| 381 | - fcCollectAndSave(); | |
| 382 | - }); | |
| 383 | - | |
| 384 | - // ---- Bulk selection + bulk remove ---- | |
| 385 | - // Clones the Trigger Phrases #all-actions bulk toolbar behavior, but | |
| 386 | - // wires removal to the SAME path the single Remove button uses (uncheck | |
| 387 | - // each tool's store checkbox, then one autosave). FC-specific IDs keep | |
| 388 | - // this isolated from the Trigger Phrases bulk JS (plan 5f7409). | |
| 389 | - var $fcSelectAll = $('#mxch-fc-select-all'); | |
| 390 | - var $fcBulkDelete = $('#mxch-fc-delete-selected'); | |
| 391 | - var $fcSelCount = $('#mxch-fc-selected-count'); | |
| 392 | - | |
| 393 | - function fcUpdateSelectionUI() { | |
| 394 | - var count = fcSelected.size; | |
| 395 | - if (count > 0) { | |
| 396 | - $fcSelCount.text(count + ' selected').addClass('has-selection'); | |
| 397 | - $fcBulkDelete.prop('disabled', false); | |
| 398 | - $fcList.addClass('selection-mode'); | |
| 399 | - } else { | |
| 400 | - $fcSelCount.removeClass('has-selection'); | |
| 401 | - $fcBulkDelete.prop('disabled', true); | |
| 402 | - $fcList.removeClass('selection-mode'); | |
| 403 | - } | |
| 404 | - var totalItems = $fcList.find('.mxch-fc-checkbox').length; | |
| 405 | - var checkedItems = $fcList.find('.mxch-fc-checkbox:checked').length; | |
| 406 | - $fcSelectAll.prop('checked', totalItems > 0 && checkedItems === totalItems); | |
| 407 | - $fcSelectAll.prop('indeterminate', checkedItems > 0 && checkedItems < totalItems); | |
| 408 | - } | |
| 409 | - | |
| 410 | - // Select-all toggles every visible tool row. | |
| 411 | - $fcSelectAll.on('change', function () { | |
| 412 | - var on = $(this).is(':checked'); | |
| 413 | - fcSelected.clear(); | |
| 414 | - $fcList.find('.mxch-fc-list-item').each(function () { | |
| 415 | - var $row = $(this); | |
| 416 | - var cb = String($row.data('fc-callback')); | |
| 417 | - $row.find('.mxch-fc-checkbox').prop('checked', on); | |
| 418 | - if (on) { fcSelected.add(cb); $row.addClass('selected'); } | |
| 419 | - else { $row.removeClass('selected'); } | |
| 420 | - }); | |
| 421 | - fcUpdateSelectionUI(); | |
| 422 | - }); | |
| 423 | - | |
| 424 | - // Per-row checkbox: toggle selection without opening the detail view. | |
| 425 | - $fcList.on('click', '.mxch-fc-checkbox', function (e) { | |
| 426 | - e.stopPropagation(); | |
| 427 | - var $row = $(this).closest('.mxch-fc-list-item'); | |
| 428 | - var cb = String($row.data('fc-callback')); | |
| 429 | - if ($(this).is(':checked')) { fcSelected.add(cb); $row.addClass('selected'); } | |
| 430 | - else { fcSelected.delete(cb); $row.removeClass('selected'); } | |
| 431 | - fcUpdateSelectionUI(); | |
| 432 | - }); | |
| 433 | - | |
| 434 | - // Bulk remove: same removal path as single Remove — uncheck each tool's | |
| 435 | - // store checkbox (presence = active), then refresh + autosave once. | |
| 436 | - $fcBulkDelete.on('click', function () { | |
| 437 | - if (!fcSelected.size) return; | |
| 438 | - var msg = (window.mxchActionsData && mxchActionsData.i18n && mxchActionsData.i18n.confirmBulkDelete) | |
| 439 | - || 'Remove the selected tools? They stay available to add back later.'; | |
| 440 | - if (!window.confirm(msg)) return; | |
| 441 | - var removingViewed = false; | |
| 442 | - fcSelected.forEach(function (cb) { | |
| 443 | - var $t = fcEntry(cb); | |
| 444 | - if ($t.length) { $t.find('input[name="mxchat_fc_tools[]"]').prop('checked', false); } | |
| 445 | - if (String(cb) === String(fcViewCb)) { removingViewed = true; } | |
| 446 | - }); | |
| 447 | - fcSelected.clear(); | |
| 448 | - if (removingViewed) { fcShowEmpty(); } | |
| 449 | - fcRenderList(); | |
| 450 | - fcCollectAndSave(); | |
| 451 | - }); | |
| 452 | - | |
| 453 | - // Search filter. | |
| 454 | - $fcSearch.on('input', function () { fcRenderList(); }); | |
| 455 | - | |
| 456 | - // Refresh — re-render the list from the store (parity with the Trigger | |
| 457 | - // Phrases refresh affordance; the list is client-built so this re-syncs | |
| 458 | - // the view rather than re-fetching). | |
| 459 | - $('#mxch-fc-refresh').on('click', function () { | |
| 460 | - var $btn = $(this); | |
| 461 | - $btn.addClass('spinning'); | |
| 462 | - fcRenderList(); | |
| 463 | - setTimeout(function () { $btn.removeClass('spinning'); }, 500); | |
| 464 | - }); | |
| 465 | - | |
| 466 | - fcRenderList(); | |
| 467 | - } | |
| 468 | - } | |
| 469 | - | |
| 470 | 63 | // Quick action buttons |
| 471 | 64 | $('.mxch-quick-action-btn[data-action="view-actions"]').on('click', function() { |
| 472 | 65 | $('.mxch-nav-link[data-target="all-actions"]').trigger('click'); |
| 473 | 66 | }); |
| 474 | 67 | |
| 475 | - // Dashboard explainer cards — generic "jump to this section" (e.g. Set up AI Tools). | |
| 476 | - $('.mxch-approach-btn[data-approach-target]').on('click', function() { | |
| 477 | - var target = $(this).data('approach-target'); | |
| 478 | - $('.mxch-nav-link[data-target="' + target + '"]').trigger('click'); | |
| 479 | - }); | |
| 480 | - | |
| 481 | - // "Add Trigger Phrase" on the dashboard → jump to Trigger Phrases + open the editor. | |
| 482 | 68 | $('#mxch-add-action-dashboard-btn').on('click', function() { |
| 483 | 69 | $('.mxch-nav-link[data-target="all-actions"]').trigger('click'); |
| 484 | 70 | setTimeout(function() { |
| 485 | 71 | openActionEditor(); |
| @@ -527,171 +113,8 @@ | ||
| 527 | 113 | let selectedActions = new Set(); |
| 528 | 114 | let currentSortOrder = 'desc'; |
| 529 | 115 | let currentFilter = ''; |
| 530 | 116 | |
| 531 | - // ========================================================================== | |
| 532 | - // Phrase Tag Management | |
| 533 | - // ========================================================================== | |
| 534 | - | |
| 535 | - let currentPhrases = []; // Array of {id, text, isLegacy} | |
| 536 | - | |
| 537 | - function renderPhraseTags() { | |
| 538 | - const $container = $('#mxch-phrase-tags'); | |
| 539 | - let html = ''; | |
| 540 | - currentPhrases.forEach(function(phrase, index) { | |
| 541 | - const legacyClass = phrase.isLegacy ? ' mxch-phrase-legacy' : ''; | |
| 542 | - const badge = phrase.isLegacy ? ' <span class="mxch-legacy-badge">legacy</span>' : ''; | |
| 543 | - html += '<span class="mxch-phrase-pill' + legacyClass + '" data-index="' + index + '" data-phrase-id="' + (phrase.id || '') + '">' | |
| 544 | - + escapeHtml(phrase.text) + badge | |
| 545 | - + ' <button type="button" class="mxch-phrase-remove" title="Remove">×</button>' | |
| 546 | - + '</span>'; | |
| 547 | - }); | |
| 548 | - $container.html(html); | |
| 549 | - } | |
| 550 | - | |
| 551 | - function addPhraseFromInput() { | |
| 552 | - const $input = $('#mxch-phrase-input'); | |
| 553 | - const text = $input.val().trim(); | |
| 554 | - if (!text) return; | |
| 555 | - | |
| 556 | - const formMode = $('#mxch-form-mode').val(); | |
| 557 | - const intentId = $('#mxch-action-id').val(); | |
| 558 | - | |
| 559 | - if (formMode === 'edit' && intentId) { | |
| 560 | - // Edit mode: AJAX add immediately | |
| 561 | - const $btn = $('#mxch-add-phrase-btn'); | |
| 562 | - $btn.prop('disabled', true).text('Adding...'); | |
| 563 | - | |
| 564 | - $.ajax({ | |
| 565 | - url: mxchActionsData.ajaxUrl, | |
| 566 | - type: 'POST', | |
| 567 | - data: { | |
| 568 | - action: 'mxchat_add_phrase', | |
| 569 | - intent_id: intentId, | |
| 570 | - phrase: text, | |
| 571 | - security: mxchActionsData.addPhraseNonce | |
| 572 | - }, | |
| 573 | - success: function(response) { | |
| 574 | - $btn.prop('disabled', false).text('Add'); | |
| 575 | - if (response.success) { | |
| 576 | - currentPhrases.push({id: response.data.id, text: text, isLegacy: false}); | |
| 577 | - renderPhraseTags(); | |
| 578 | - $input.val('').focus(); | |
| 579 | - } else { | |
| 580 | - alert(response.data || 'Failed to add phrase.'); | |
| 581 | - } | |
| 582 | - }, | |
| 583 | - error: function() { | |
| 584 | - $btn.prop('disabled', false).text('Add'); | |
| 585 | - alert('Failed to add phrase. Please try again.'); | |
| 586 | - } | |
| 587 | - }); | |
| 588 | - } else { | |
| 589 | - // Add mode: just push locally | |
| 590 | - currentPhrases.push({id: null, text: text, isLegacy: false}); | |
| 591 | - renderPhraseTags(); | |
| 592 | - $input.val('').focus(); | |
| 593 | - } | |
| 594 | - } | |
| 595 | - | |
| 596 | - // Add phrase on Enter key | |
| 597 | - $(document).on('keydown', '#mxch-phrase-input', function(e) { | |
| 598 | - if (e.key === 'Enter') { | |
| 599 | - e.preventDefault(); | |
| 600 | - addPhraseFromInput(); | |
| 601 | - } | |
| 602 | - }); | |
| 603 | - | |
| 604 | - // Add phrase on button click | |
| 605 | - $(document).on('click', '#mxch-add-phrase-btn', function() { | |
| 606 | - addPhraseFromInput(); | |
| 607 | - }); | |
| 608 | - | |
| 609 | - // Remove phrase on X click | |
| 610 | - $(document).on('click', '.mxch-phrase-remove', function(e) { | |
| 611 | - e.stopPropagation(); | |
| 612 | - const $pill = $(this).closest('.mxch-phrase-pill'); | |
| 613 | - const index = parseInt($pill.data('index')); | |
| 614 | - const phrase = currentPhrases[index]; | |
| 615 | - | |
| 616 | - if (!phrase) return; | |
| 617 | - | |
| 618 | - if (phrase.isLegacy) { | |
| 619 | - // Delete legacy phrases from main table | |
| 620 | - const intentId = $('#mxch-action-id').val(); | |
| 621 | - if (!intentId) { | |
| 622 | - currentPhrases.splice(index, 1); | |
| 623 | - renderPhraseTags(); | |
| 624 | - return; | |
| 625 | - } | |
| 626 | - | |
| 627 | - if (!confirm('Remove all legacy grouped phrases? You can re-add them individually for better matching.')) return; | |
| 628 | - | |
| 629 | - $.ajax({ | |
| 630 | - url: mxchActionsData.ajaxUrl, | |
| 631 | - type: 'POST', | |
| 632 | - data: { | |
| 633 | - action: 'mxchat_delete_legacy_phrases', | |
| 634 | - intent_id: intentId, | |
| 635 | - security: mxchActionsData.deleteLegacyNonce | |
| 636 | - }, | |
| 637 | - success: function(response) { | |
| 638 | - if (response.success) { | |
| 639 | - currentPhrases.splice(index, 1); | |
| 640 | - renderPhraseTags(); | |
| 641 | - } else { | |
| 642 | - alert(response.data || 'Failed to remove legacy phrases.'); | |
| 643 | - } | |
| 644 | - } | |
| 645 | - }); | |
| 646 | - } else if (phrase.id) { | |
| 647 | - // Delete individual phrase via AJAX | |
| 648 | - $.ajax({ | |
| 649 | - url: mxchActionsData.ajaxUrl, | |
| 650 | - type: 'POST', | |
| 651 | - data: { | |
| 652 | - action: 'mxchat_delete_phrase', | |
| 653 | - phrase_id: phrase.id, | |
| 654 | - security: mxchActionsData.deletePhraseNonce | |
| 655 | - }, | |
| 656 | - success: function(response) { | |
| 657 | - if (response.success) { | |
| 658 | - currentPhrases.splice(index, 1); | |
| 659 | - renderPhraseTags(); | |
| 660 | - } else { | |
| 661 | - alert(response.data || 'Failed to delete phrase.'); | |
| 662 | - } | |
| 663 | - } | |
| 664 | - }); | |
| 665 | - } else { | |
| 666 | - // Local-only phrase (add mode, not yet saved) | |
| 667 | - currentPhrases.splice(index, 1); | |
| 668 | - renderPhraseTags(); | |
| 669 | - } | |
| 670 | - }); | |
| 671 | - | |
| 672 | - function fetchIndividualPhrases(intentId, callback) { | |
| 673 | - $.ajax({ | |
| 674 | - url: mxchActionsData.ajaxUrl, | |
| 675 | - type: 'POST', | |
| 676 | - data: { | |
| 677 | - action: 'mxchat_get_phrases', | |
| 678 | - intent_id: intentId, | |
| 679 | - security: mxchActionsData.getPhrasesNonce | |
| 680 | - }, | |
| 681 | - success: function(response) { | |
| 682 | - if (response.success) { | |
| 683 | - callback(response.data.phrases || []); | |
| 684 | - } else { | |
| 685 | - callback([]); | |
| 686 | - } | |
| 687 | - }, | |
| 688 | - error: function() { | |
| 689 | - callback([]); | |
| 690 | - } | |
| 691 | - }); | |
| 692 | - } | |
| 693 | - | |
| 694 | 117 | // Load action list on page load |
| 695 | 118 | loadActionList(1, '', ''); |
| 696 | 119 | |
| 697 | 120 | // Search functionality with debounce |
| @@ -846,15 +269,15 @@ | ||
| 846 | 269 | totalPages = response.data.total_pages; |
| 847 | 270 | updateActionCount(response.data.showing_start, response.data.showing_end, response.data.total_actions); |
| 848 | 271 | renderPagination(response.data.page, response.data.total_pages, searchTerm, filter); |
| 849 | 272 | } else { |
| 850 | - $container.html('<div class="mxch-list-empty"><p>No trigger phrases found</p></div>'); | |
| 273 | + $container.html('<div class="mxch-list-empty"><p>No actions found</p></div>'); | |
| 851 | 274 | updateActionCount(0, 0, 0); |
| 852 | 275 | $('#mxch-actions-pagination').html(''); |
| 853 | 276 | } |
| 854 | 277 | }, |
| 855 | 278 | error: function() { |
| 856 | - $container.html('<div class="mxch-list-empty"><p>Error loading trigger phrases</p></div>'); | |
| 279 | + $container.html('<div class="mxch-list-empty"><p>Error loading actions</p></div>'); | |
| 857 | 280 | } |
| 858 | 281 | }); |
| 859 | 282 | } |
| 860 | 283 | |
| @@ -878,11 +301,9 @@ | ||
| 878 | 301 | data-phrases="${escapeHtml(action.phrases)}" |
| 879 | 302 | data-threshold="${action.threshold}" |
| 880 | 303 | data-callback="${escapeHtml(action.callback_function)}" |
| 881 | 304 | data-enabled="${action.enabled ? '1' : '0'}" |
| 882 | - data-enabled-bots='${escapeHtml(JSON.stringify(action.enabled_bots))}' | |
| 883 | - data-has-legacy="${action.has_legacy_vector ? '1' : '0'}" | |
| 884 | - data-individual-count="${action.individual_phrase_count || 0}"> | |
| 305 | + data-enabled-bots='${escapeHtml(JSON.stringify(action.enabled_bots))}'> | |
| 885 | 306 | <input type="checkbox" class="mxch-action-checkbox"${isChecked}> |
| 886 | 307 | <div class="mxch-action-icon"> |
| 887 | 308 | <span class="dashicons dashicons-${escapeHtml(action.icon || 'admin-generic')}"></span> |
| 888 | 309 | </div> |
| @@ -934,11 +355,11 @@ | ||
| 934 | 355 | |
| 935 | 356 | // Update action count display |
| 936 | 357 | function updateActionCount(start, end, total) { |
| 937 | 358 | if (total === 0) { |
| 938 | - $('#mxch-action-count').text('0 trigger phrases'); | |
| 359 | + $('#mxch-action-count').text('0 actions'); | |
| 939 | 360 | } else { |
| 940 | - $('#mxch-action-count').text(`${start}-${end} / ${total} trigger phrases`); | |
| 361 | + $('#mxch-action-count').text(`${start}-${end} / ${total} actions`); | |
| 941 | 362 | } |
| 942 | 363 | } |
| 943 | 364 | |
| 944 | 365 | // Render pagination |
| @@ -987,18 +408,12 @@ | ||
| 987 | 408 | phrases: $item.data('phrases'), |
| 988 | 409 | threshold: $item.data('threshold'), |
| 989 | 410 | callback_function: $item.data('callback'), |
| 990 | 411 | enabled: $item.data('enabled') == '1', |
| 991 | - enabled_bots: $item.data('enabled-bots') || ['default'], | |
| 992 | - has_legacy: $item.data('has-legacy') == '1', | |
| 993 | - individualPhrases: [] | |
| 412 | + enabled_bots: $item.data('enabled-bots') || ['default'] | |
| 994 | 413 | }; |
| 995 | 414 | |
| 996 | - // Fetch individual phrases then show view | |
| 997 | - fetchIndividualPhrases(actionId, function(phrases) { | |
| 998 | - data.individualPhrases = phrases; | |
| 999 | - showActionView(data); | |
| 1000 | - }); | |
| 415 | + showActionView(data); | |
| 1001 | 416 | } |
| 1002 | 417 | |
| 1003 | 418 | // Show action view (details) |
| 1004 | 419 | function showActionView(action) { |
| @@ -1025,22 +440,14 @@ | ||
| 1025 | 440 | const iconClass = $typeCard.find('.dashicons').attr('class') || 'dashicons dashicons-admin-generic'; |
| 1026 | 441 | $('#mxch-view-icon').html('<span class="' + iconClass + '"></span>'); |
| 1027 | 442 | $('#mxch-detail-icon').html('<span class="' + iconClass + '"></span>'); |
| 1028 | 443 | |
| 1029 | - // Phrases - show legacy grouped phrases and individual phrases | |
| 444 | + // Phrases | |
| 445 | + const phrases = action.phrases.split(',').map(p => p.trim()).filter(p => p); | |
| 1030 | 446 | let phrasesHtml = ''; |
| 1031 | - const legacyPhrases = action.phrases ? String(action.phrases).trim() : ''; | |
| 1032 | - if (legacyPhrases) { | |
| 1033 | - phrasesHtml += '<span class="mxch-phrase-tag mxch-phrase-legacy">' + escapeHtml(legacyPhrases) + ' <span class="mxch-legacy-badge">legacy</span></span>'; | |
| 1034 | - } | |
| 1035 | - if (action.individualPhrases && action.individualPhrases.length) { | |
| 1036 | - action.individualPhrases.forEach(function(p) { | |
| 1037 | - phrasesHtml += '<span class="mxch-phrase-tag">' + escapeHtml(p.phrase) + '</span>'; | |
| 1038 | - }); | |
| 1039 | - } | |
| 1040 | - if (!phrasesHtml) { | |
| 1041 | - phrasesHtml = '<span class="mxch-no-phrases">No trigger phrases configured</span>'; | |
| 1042 | - } | |
| 447 | + phrases.forEach(function(phrase) { | |
| 448 | + phrasesHtml += '<span class="mxch-phrase-tag">' + escapeHtml(phrase) + '</span>'; | |
| 449 | + }); | |
| 1043 | 450 | $('#mxch-view-phrases').html(phrasesHtml); |
| 1044 | 451 | |
| 1045 | 452 | // Settings |
| 1046 | 453 | $('#mxch-view-threshold').text(action.threshold + '%'); |
| @@ -1098,24 +505,12 @@ | ||
| 1098 | 505 | $('#mxch-action-id').val(action.id); |
| 1099 | 506 | $('#mxch-callback-function').val(action.callback_function); |
| 1100 | 507 | $('#mxch-form-mode').val('edit'); |
| 1101 | 508 | $('#mxch-action-label').val(action.label); |
| 509 | + $('#mxch-action-phrases').val(action.phrases); | |
| 1102 | 510 | $('#mxch-action-threshold').val(action.threshold); |
| 1103 | 511 | $('#mxch-threshold-value').text(action.threshold + '%'); |
| 1104 | 512 | |
| 1105 | - // Populate phrase tags | |
| 1106 | - currentPhrases = []; | |
| 1107 | - const legacyPhrases = action.phrases ? String(action.phrases).trim() : ''; | |
| 1108 | - if (legacyPhrases) { | |
| 1109 | - currentPhrases.push({id: 'legacy', text: legacyPhrases, isLegacy: true}); | |
| 1110 | - } | |
| 1111 | - if (action.individualPhrases && action.individualPhrases.length) { | |
| 1112 | - action.individualPhrases.forEach(function(p) { | |
| 1113 | - currentPhrases.push({id: p.id, text: p.phrase, isLegacy: false}); | |
| 1114 | - }); | |
| 1115 | - } | |
| 1116 | - renderPhraseTags(); | |
| 1117 | - | |
| 1118 | 513 | // Set selected type display |
| 1119 | 514 | const $typeCard = $('.mxch-type-card[data-value="' + action.callback_function + '"]'); |
| 1120 | 515 | const iconHtml = $typeCard.find('.mxch-type-icon').html(); |
| 1121 | 516 | const typeLabel = $typeCard.data('label'); |
| @@ -1123,9 +518,9 @@ | ||
| 1123 | 518 | |
| 1124 | 519 | $('#mxch-selected-type-icon').html(iconHtml); |
| 1125 | 520 | $('#mxch-selected-type-label').text(typeLabel); |
| 1126 | 521 | $('#mxch-selected-type-desc').text(typeDesc); |
| 1127 | - $('#mxch-config-title').text('Edit Trigger Phrase'); | |
| 522 | + $('#mxch-config-title').text('Edit Action'); | |
| 1128 | 523 | |
| 1129 | 524 | // Set enabled bots |
| 1130 | 525 | const enabledBots = Array.isArray(action.enabled_bots) ? action.enabled_bots : ['default']; |
| 1131 | 526 | $('#mxch-bot-selector input[type="checkbox"]').each(function() { |
| @@ -1132,9 +527,9 @@ | ||
| 1132 | 527 | $(this).prop('checked', enabledBots.includes($(this).val())); |
| 1133 | 528 | }); |
| 1134 | 529 | |
| 1135 | 530 | // Update save button text |
| 1136 | - $('#mxch-save-action').text('Update Trigger Phrase'); | |
| 531 | + $('#mxch-save-action').text('Update Action'); | |
| 1137 | 532 | } |
| 1138 | 533 | |
| 1139 | 534 | // Reset form |
| 1140 | 535 | function resetForm() { |
| @@ -1141,16 +536,13 @@ | ||
| 1141 | 536 | $('#mxch-action-id').val(''); |
| 1142 | 537 | $('#mxch-callback-function').val(''); |
| 1143 | 538 | $('#mxch-form-mode').val('add'); |
| 1144 | 539 | $('#mxch-action-label').val(''); |
| 540 | + $('#mxch-action-phrases').val(''); | |
| 1145 | 541 | $('#mxch-action-threshold').val(85); |
| 1146 | - | |
| 1147 | - // Clear phrase tags | |
| 1148 | - currentPhrases = []; | |
| 1149 | - renderPhraseTags(); | |
| 1150 | 542 | $('#mxch-threshold-value').text('85%'); |
| 1151 | - $('#mxch-config-title').text('Configure Trigger Phrase'); | |
| 1152 | - $('#mxch-save-action').text('Save Trigger Phrase'); | |
| 543 | + $('#mxch-config-title').text('Configure Action'); | |
| 544 | + $('#mxch-save-action').text('Save Action'); | |
| 1153 | 545 | |
| 1154 | 546 | // Reset bot selection |
| 1155 | 547 | $('#mxch-bot-selector input[type="checkbox"]').prop('checked', false); |
| 1156 | 548 | $('#mxch-bot-selector input[value="default"]').prop('checked', true); |
| @@ -1327,8 +719,9 @@ | ||
| 1327 | 719 | const formMode = $('#mxch-form-mode').val(); |
| 1328 | 720 | const actionId = $('#mxch-action-id').val(); |
| 1329 | 721 | const callbackFunction = $('#mxch-callback-function').val(); |
| 1330 | 722 | const label = $('#mxch-action-label').val().trim(); |
| 723 | + const phrases = $('#mxch-action-phrases').val().trim(); | |
| 1331 | 724 | const threshold = $('#mxch-action-threshold').val(); |
| 1332 | 725 | |
| 1333 | 726 | // Validation |
| 1334 | 727 | if (!callbackFunction) { |
| @@ -1341,12 +734,11 @@ | ||
| 1341 | 734 | $('#mxch-action-label').focus(); |
| 1342 | 735 | return; |
| 1343 | 736 | } |
| 1344 | 737 | |
| 1345 | - // Check phrases exist (from tag input) | |
| 1346 | - if (currentPhrases.length === 0) { | |
| 1347 | - alert('Please add at least one trigger phrase.'); | |
| 1348 | - $('#mxch-phrase-input').focus(); | |
| 738 | + if (!phrases) { | |
| 739 | + alert('Please enter at least one trigger phrase.'); | |
| 740 | + $('#mxch-action-phrases').focus(); | |
| 1349 | 741 | return; |
| 1350 | 742 | } |
| 1351 | 743 | |
| 1352 | 744 | // Get enabled bots |
| @@ -1363,8 +755,9 @@ | ||
| 1363 | 755 | |
| 1364 | 756 | const data = { |
| 1365 | 757 | action: formMode === 'edit' ? 'mxchat_edit_intent_ajax' : 'mxchat_add_intent_ajax', |
| 1366 | 758 | intent_label: label, |
| 759 | + phrases: phrases, | |
| 1367 | 760 | similarity_threshold: threshold, |
| 1368 | 761 | callback_function: callbackFunction, |
| 1369 | 762 | enabled_bots: enabledBots, |
| 1370 | 763 | security: formMode === 'edit' ? mxchActionsData.editNonce : mxchActionsData.addNonce |
| @@ -1371,20 +764,8 @@ | ||
| 1371 | 764 | }; |
| 1372 | 765 | |
| 1373 | 766 | if (formMode === 'edit') { |
| 1374 | 767 | data.intent_id = actionId; |
| 1375 | - // In edit mode, phrases are managed via individual AJAX calls already | |
| 1376 | - // Send empty phrases to skip legacy re-embedding | |
| 1377 | - data.phrases = ''; | |
| 1378 | - } else { | |
| 1379 | - // Add mode: send individual phrases for per-phrase embedding | |
| 1380 | - const nonLegacyPhrases = currentPhrases.filter(p => !p.isLegacy).map(p => p.text); | |
| 1381 | - if (nonLegacyPhrases.length > 0) { | |
| 1382 | - data.individual_phrases = nonLegacyPhrases; | |
| 1383 | - data.phrases = ''; | |
| 1384 | - } else { | |
| 1385 | - data.phrases = ''; | |
| 1386 | - } | |
| 1387 | 768 | } |
| 1388 | 769 | |
| 1389 | 770 | $.ajax({ |
| 1390 | 771 | url: mxchActionsData.ajaxUrl, |