| @@ -822,8 +822,16 @@ | ||
| 822 | 822 | var stateEl = document.getElementById('mxchat-pinecone-docs-state'); |
| 823 | 823 | var state = {}; |
| 824 | 824 | try { state = stateEl ? JSON.parse(stateEl.textContent || '{}') : {}; } catch (e) { state = {}; } |
| 825 | 825 | var verifiedHost = String(state.verified_host || '').toLowerCase(); |
| 826 | + // 3e83e4: the LIVE chatbot's index type + host as saved, the migration | |
| 827 | + // state as last known, and the index name the page loaded with (so a | |
| 828 | + // suggested "-docs" name can be undone by switching back to Vector). | |
| 829 | + var liveType = state.index_type === 'document' ? 'document' : 'vector'; | |
| 830 | + var storedHost = String(state.stored_host || '').toLowerCase(); | |
| 831 | + var storedIndex = String(state.stored_index || ''); | |
| 832 | + var originalIndexName = $.trim($('#mxchat_pinecone_index').val() || ''); | |
| 833 | + var migrationState = (state.migration && state.migration.status) ? state.migration : null; | |
| 826 | 834 | var ajaxUrl = (typeof mxchatAdmin !== 'undefined' && mxchatAdmin.ajax_url) ? mxchatAdmin.ajax_url : ajaxurl; |
| 827 | 835 | var nonce = (typeof mxchatAdmin !== 'undefined' && mxchatAdmin.settings_nonce) ? mxchatAdmin.settings_nonce : |
| 828 | 836 | ((typeof mxchatPromptsAdmin !== 'undefined' && mxchatPromptsAdmin.prompts_setting_nonce) ? mxchatPromptsAdmin.prompts_setting_nonce : ''); |
| 829 | 837 | |
| @@ -838,23 +846,95 @@ | ||
| 838 | 846 | function currentType() { return $type.filter(':checked').val() || 'vector'; } |
| 839 | 847 | function hostValue() { |
| 840 | 848 | return $.trim($('#mxchat_pinecone_host').val() || '').replace(/^https?:\/\//i, '').replace(/\/+$/, '').toLowerCase(); |
| 841 | 849 | } |
| 850 | + function fmt(n) { n = parseInt(n, 10) || 0; return n.toLocaleString(); } | |
| 851 | + // Does saving Document right now point the chatbot at an index whose copy is unfinished? | |
| 852 | + function switchBlockedBy() { | |
| 853 | + if (currentType() !== 'document' || liveType === 'document' || !migrationState) { return null; } | |
| 854 | + if (migrationState.status !== 'running') { return null; } | |
| 855 | + if (String(migrationState.target_host || '').toLowerCase() !== hostValue()) { return null; } | |
| 856 | + return migrationState; | |
| 857 | + } | |
| 842 | 858 | function refreshGate() { |
| 843 | 859 | var isDoc = currentType() === 'document'; |
| 844 | 860 | $docs.toggle(isDoc); |
| 845 | 861 | var blocked = isDoc && (hostValue() === '' || hostValue() !== verifiedHost); |
| 862 | + $('#mxchat-pinecone-docs-gate').toggle(blocked); | |
| 863 | + var running = blocked ? null : switchBlockedBy(); | |
| 864 | + var $switchGate = $('#mxchat-pinecone-docs-switch-gate'); | |
| 865 | + if (running) { | |
| 866 | + $('#mxchat-pinecone-docs-switch-gate-text').text( | |
| 867 | + 'The copy into ' + (running.target_name || running.target_host) + ' is still running (' + fmt(running.copied) + ' of ' + fmt(running.total) + | |
| 868 | + ' records). Let it finish before switching the chatbot to the document index.' | |
| 869 | + ); | |
| 870 | + $switchGate.show(); | |
| 871 | + blocked = !$('#mxchat_pinecone_docs_switch_anyway').is(':checked'); | |
| 872 | + } else { | |
| 873 | + $switchGate.hide(); | |
| 874 | + $('#mxchat_pinecone_docs_switch_anyway').prop('checked', false); | |
| 875 | + } | |
| 846 | 876 | $submit.prop('disabled', blocked); |
| 847 | - $('#mxchat-pinecone-docs-gate').toggle(blocked); | |
| 848 | 877 | } |
| 849 | - $type.off('change.pineconeDocs').on('change.pineconeDocs', refreshGate); | |
| 850 | - $('#mxchat_pinecone_host').off('input.pineconeDocs change.pineconeDocs').on('input.pineconeDocs change.pineconeDocs', refreshGate); | |
| 851 | - refreshGate(); | |
| 878 | + // 47c61f: the status notice follows the host in the FIELD, the same | |
| 879 | + // comparison the Save gate makes. The server paints it from the saved | |
| 880 | + // host, which is the classic index for the whole length of a copy, so a | |
| 881 | + // checked document host typed here used to sit under "Not checked yet". | |
| 882 | + // Kept out of refreshGate(): a failed Check sets its own text first and | |
| 883 | + // then calls refreshGate(), and that text must survive until the host changes. | |
| 884 | + function refreshStatus() { | |
| 885 | + var typed = hostValue(); | |
| 886 | + if (typed !== '' && typed === verifiedHost) { | |
| 887 | + var dim = parseInt(state.expected_dimension, 10) || 0; | |
| 888 | + setStatus(true, String(state.status_checked || 'Document index checked: %1$s (%2$d dimensions).').replace('%1$s', typed).replace('%2$d', dim)); | |
| 889 | + } else { | |
| 890 | + setStatus(false, String(state.status_unchecked || 'Not checked yet. Create a document index below, or enter its host above and click Check index. The index type only saves once the host has been checked.')); | |
| 891 | + } | |
| 892 | + } | |
| 893 | + $('#mxchat_pinecone_docs_switch_anyway').off('change.pineconeDocs').on('change.pineconeDocs', refreshGate); | |
| 894 | + $('#mxchat_pinecone_host').off('input.pineconeDocs change.pineconeDocs').on('input.pineconeDocs change.pineconeDocs', function () { refreshStatus(); refreshGate(); }); | |
| 852 | 895 | |
| 853 | 896 | function post(data) { |
| 854 | 897 | data.nonce = nonce; |
| 855 | 898 | return $.post(ajaxUrl, data); |
| 856 | 899 | } |
| 900 | + | |
| 901 | + // ---- Index type change: a document index needs its own name, so when | |
| 902 | + // the field still holds the vector index's name (or is empty) suggest a | |
| 903 | + // free "<name>-docs" from the project; Vector restores the original. | |
| 904 | + var suggestedName = ''; | |
| 905 | + function nameIsOurs() { | |
| 906 | + var name = $.trim($('#mxchat_pinecone_index').val() || ''); | |
| 907 | + return name === '' || name === storedIndex || name === originalIndexName || name === suggestedName; | |
| 908 | + } | |
| 909 | + // When the host in the field is a checked document index, the name is | |
| 910 | + // that index's own; otherwise a free "<name>-docs" for the create button. | |
| 911 | + function suggestDocsName() { | |
| 912 | + var name = $.trim($('#mxchat_pinecone_index').val() || ''); | |
| 913 | + var apiKey = $('#mxchat_pinecone_api_key').val(); | |
| 914 | + if (liveType === 'document' || !apiKey || currentType() !== 'document') { return; } | |
| 915 | + if (!nameIsOurs()) { return; } // the owner typed their own | |
| 916 | + var host = (hostValue() !== '' && hostValue() === verifiedHost) ? hostValue() : ''; | |
| 917 | + post({ action: 'mxchat_pinecone_docs_suggest_name', base: name || storedIndex, host: host, api_key: apiKey }).done(function (response) { | |
| 918 | + if (response && response.success && response.data && response.data.name && currentType() === 'document' && nameIsOurs()) { | |
| 919 | + suggestedName = response.data.name; | |
| 920 | + $('#mxchat_pinecone_index').val(suggestedName); | |
| 921 | + } | |
| 922 | + }); | |
| 923 | + } | |
| 924 | + $type.off('change.pineconeDocs').on('change.pineconeDocs', function () { | |
| 925 | + if (currentType() === 'document') { | |
| 926 | + suggestDocsName(); | |
| 927 | + } else if (suggestedName !== '' && $.trim($('#mxchat_pinecone_index').val() || '') === suggestedName) { | |
| 928 | + $('#mxchat_pinecone_index').val(originalIndexName); | |
| 929 | + } | |
| 930 | + refreshGate(); | |
| 931 | + }); | |
| 932 | + // Pasting the checked document host resolves the name to that index's own. | |
| 933 | + $('#mxchat_pinecone_host').on('change.pineconeDocsName', function () { | |
| 934 | + if (currentType() === 'document' && hostValue() !== '' && hostValue() === verifiedHost) { suggestDocsName(); } | |
| 935 | + }); | |
| 936 | + refreshGate(); | |
| 857 | 937 | function failMessage(response, fallback) { |
| 858 | 938 | if (response && response.data) { |
| 859 | 939 | if (typeof response.data === 'string') { return response.data; } |
| 860 | 940 | if (response.data.message) { return response.data.message; } |
| @@ -890,8 +970,13 @@ | ||
| 890 | 970 | setStatus(true, 'Document index checked: ' + response.data.host + ' (' + response.data.dimension + ' dimensions).'); |
| 891 | 971 | notice(response.data.ready ? 'success' : 'info', response.data.message); |
| 892 | 972 | refreshGate(); |
| 893 | 973 | } else { |
| 974 | + // A taken name comes back with a free suggestion — fill it in so the next click works. | |
| 975 | + if (response && response.data && response.data.suggested) { | |
| 976 | + suggestedName = response.data.suggested; | |
| 977 | + $('#mxchat_pinecone_index').val(response.data.suggested); | |
| 978 | + } | |
| 894 | 979 | notice('error', failMessage(response, 'Could not create the index.')); |
| 895 | 980 | } |
| 896 | 981 | }).fail(function () { |
| 897 | 982 | notice('error', 'Could not reach the server to create the index.'); |
| @@ -934,45 +1019,173 @@ | ||
| 934 | 1019 | $btn.prop('disabled', false).text('Check index'); |
| 935 | 1020 | }); |
| 936 | 1021 | }); |
| 937 | 1022 | |
| 938 | - // ---- Migrate (copy, batch by batch, resumable) | |
| 1023 | + // ---- Migrate (copy, page by page, resumable). 3e83e4: the copy runs | |
| 1024 | + // against the document host in the form while the chatbot keeps | |
| 1025 | + // answering from the vector index; a dropped request is retried with | |
| 1026 | + // backoff, and a second click continues from the recorded position. | |
| 939 | 1027 | var $migrateBtn = $('#mxchat-pinecone-docs-migrate'); |
| 1028 | + // e50d2e: "Copy every namespace" — offered once the start response | |
| 1029 | + // reports records in other namespaces; the copy then walks every | |
| 1030 | + // namespace of the source in one run, each into its own namespace on | |
| 1031 | + // the document side. Disabled while a copy runs in this tab (the | |
| 1032 | + // server extends a running copy on the next Migrate click, never | |
| 1033 | + // underneath a step that is in flight). | |
| 1034 | + var $allNs = $('#mxchat_pinecone_docs_all_namespaces'); | |
| 1035 | + var $allNsRow = $('#mxchat-pinecone-docs-all-namespaces'); | |
| 1036 | + var stepRetries = 0; | |
| 1037 | + var STEP_RETRY_DELAYS = [1000, 2000, 4000, 8000, 16000]; | |
| 1038 | + function remainingOf(st) { | |
| 1039 | + var total = parseInt(st.total, 10) || 0, copied = parseInt(st.copied, 10) || 0; | |
| 1040 | + return Math.max(0, total - copied); | |
| 1041 | + } | |
| 1042 | + function otherNamespacesText(st) { | |
| 1043 | + var other = st.other_namespaces || {}; | |
| 1044 | + // 47c61f: default namespace first, then by name. The server writes them | |
| 1045 | + // in that order now; this covers states written before it did, and | |
| 1046 | + // namespaces named like numbers, which a JSON object reorders. | |
| 1047 | + var names = []; | |
| 1048 | + $.each(other, function (name) { names.push(String(name)); }); | |
| 1049 | + names.sort(function (a, b) { | |
| 1050 | + if (a === b) { return 0; } | |
| 1051 | + if (a === '__default__') { return -1; } | |
| 1052 | + if (b === '__default__') { return 1; } | |
| 1053 | + return a < b ? -1 : 1; | |
| 1054 | + }); | |
| 1055 | + var parts = []; | |
| 1056 | + $.each(names, function (i, name) { parts.push(name + ' (' + fmt(other[name]) + ')'); }); | |
| 1057 | + return parts.join(', '); | |
| 1058 | + } | |
| 1059 | + function otherNamespacesSummary(st) { | |
| 1060 | + var records = 0, n = 0; | |
| 1061 | + $.each(st.other_namespaces || {}, function (name, count) { records += parseInt(count, 10) || 0; n++; }); | |
| 1062 | + return n ? { records: records, count: n } : null; | |
| 1063 | + } | |
| 1064 | + function namespaceEntries(st) { | |
| 1065 | + var out = []; | |
| 1066 | + $.each(st.per_namespace || {}, function (key, e) { out.push($.extend({ key: key }, e)); }); | |
| 1067 | + return out; | |
| 1068 | + } | |
| 1069 | + function isMulti(st) { return !!st.all_namespaces || namespaceEntries(st).length > 1; } | |
| 1070 | + function namespaceLine(e, sep) { | |
| 1071 | + return e.key + ' ' + fmt(e.copied) + ' of ' + fmt(e.total) + (e.target_count ? (sep + 'the document index reports ' + fmt(e.target_count) + ')') : ''); | |
| 1072 | + } | |
| 940 | 1073 | function renderMigration(st) { |
| 1074 | + migrationState = (st && st.status) ? st : null; | |
| 941 | 1075 | var $progress = $('#mxchat-pinecone-docs-migrate-progress'); |
| 942 | 1076 | if (!st || !st.status) { |
| 943 | 1077 | $progress.hide(); |
| 944 | 1078 | $('#mxchat-pinecone-docs-migrate-counts').text(''); |
| 945 | 1079 | $('#mxchat-pinecone-docs-delete-old').hide(); |
| 1080 | + $allNsRow.hide(); | |
| 1081 | + refreshGate(); | |
| 946 | 1082 | return; |
| 947 | 1083 | } |
| 948 | 1084 | var total = parseInt(st.total, 10) || 0; |
| 949 | 1085 | var copied = parseInt(st.copied, 10) || 0; |
| 950 | 1086 | var pct = total > 0 ? Math.min(100, Math.round(copied * 100 / total)) : (st.status === 'done' ? 100 : 0); |
| 951 | - var suffix = st.status === 'done' ? ' — done' : (st.status === 'source_deleted' ? ' — old index deleted' : (st.status === 'running' ? ' — copying…' : '')); | |
| 1087 | + var multi = isMulti(st); | |
| 1088 | + var entries = namespaceEntries(st); | |
| 1089 | + var others = otherNamespacesSummary(st); | |
| 1090 | + var label, suffix; | |
| 1091 | + if (st.status === 'done') { | |
| 1092 | + suffix = ' — done' + (st.target_count ? ('; the document index reports ' + fmt(st.target_count) + ' records') : ''); | |
| 1093 | + } else if (st.status === 'source_deleted') { | |
| 1094 | + suffix = ' — old index deleted'; | |
| 1095 | + } else if (st.status === 'running') { | |
| 1096 | + suffix = st.error ? (' — stopped: ' + st.error) : (' — copying, ' + fmt(remainingOf(st)) + ' remaining…'); | |
| 1097 | + } else { | |
| 1098 | + suffix = ''; | |
| 1099 | + } | |
| 1100 | + if (multi && st.status === 'running') { | |
| 1101 | + var idx = 0, cur = null; | |
| 1102 | + $.each(entries, function (i, e) { if (e.key === (st.current === '' ? '__default__' : st.current)) { idx = i + 1; cur = e; } }); | |
| 1103 | + label = (cur ? ('Namespace ' + idx + ' of ' + entries.length + ' (' + cur.key + ') — ' + fmt(cur.copied) + ' of ' + fmt(cur.total) + ' records copied; ') : '') + | |
| 1104 | + fmt(copied) + ' of ' + fmt(total) + ' overall (' + pct + '%)' + (st.error ? (' — stopped: ' + st.error) : (', ' + fmt(remainingOf(st)) + ' remaining…')); | |
| 1105 | + } else if (multi) { | |
| 1106 | + label = fmt(copied) + ' of ' + fmt(total) + ' records copied across ' + entries.length + ' namespaces (' + pct + '%)' + suffix; | |
| 1107 | + } else { | |
| 1108 | + label = fmt(copied) + ' of ' + fmt(total) + ' records copied (' + pct + '%)' + suffix; | |
| 1109 | + } | |
| 952 | 1110 | $progress.show().find('.mxch-progress-bar-fill').css('width', pct + '%'); |
| 953 | - $progress.find('.mxch-progress-label').text(copied + ' of ' + total + ' records copied (' + pct + '%)' + suffix); | |
| 954 | - $('#mxchat-pinecone-docs-migrate-counts').text(st.source_name ? ('Source: ' + st.source_name + ' (' + total + ' records)') : ''); | |
| 955 | - $('#mxchat-pinecone-docs-delete-old').toggle(st.status === 'done' && total > 0 && copied >= total); | |
| 1111 | + $progress.find('.mxch-progress-label').text(label); | |
| 1112 | + var counts; | |
| 1113 | + if (multi) { | |
| 1114 | + var lines = $.map(entries, function (e) { return namespaceLine(e, ' ('); }); | |
| 1115 | + counts = (st.source_name ? ('Source: ' + st.source_name + ' (' + fmt(total) + ' records in ' + entries.length + ' namespaces). ') : '') + lines.join(' · ') + '.'; | |
| 1116 | + } else { | |
| 1117 | + counts = st.source_name ? ('Source: ' + st.source_name + ' (' + fmt(total) + ' records' + (st.namespace ? (' in namespace ' + st.namespace) : '') + ')') : ''; | |
| 1118 | + if (others) { | |
| 1119 | + counts += (counts ? '. ' : '') + 'Not copied — ' + fmt(others.records) + ' records in ' + others.count + ' other namespace' + (others.count === 1 ? '' : 's') + ': ' + otherNamespacesText(st) + '. Tick Copy every namespace and click Migrate to include them.'; | |
| 1120 | + } | |
| 1121 | + } | |
| 1122 | + $('#mxchat-pinecone-docs-migrate-counts').text(counts); | |
| 1123 | + // The toggle appears once the source is known to have other namespaces, and stays on for a copy of every namespace. | |
| 1124 | + $allNsRow.toggle(multi || !!others); | |
| 1125 | + if (st.all_namespaces) { $allNs.prop('checked', true); } | |
| 1126 | + $allNs.prop('disabled', $migrateBtn.prop('disabled')); | |
| 1127 | + // Delete old index is never offered while the copy is known to leave namespaces behind (the server refuses too). | |
| 1128 | + $('#mxchat-pinecone-docs-delete-old').toggle(st.status === 'done' && total > 0 && copied >= total && liveType === 'document' && !others); | |
| 1129 | + refreshGate(); | |
| 956 | 1130 | } |
| 1131 | + function migrateFinished(st) { | |
| 1132 | + $migrateBtn.prop('disabled', false).text('Migrate'); | |
| 1133 | + $allNs.prop('disabled', false); | |
| 1134 | + var total = parseInt(st.total, 10) || 0, copied = parseInt(st.copied, 10) || 0; | |
| 1135 | + var reported = st.target_count ? (' The document index reports ' + fmt(st.target_count) + ' records.') : ''; | |
| 1136 | + var stillVector = liveType === 'document' ? '' : ' Your chatbot is still on the vector index — save the Pinecone settings to switch it over.'; | |
| 1137 | + var entries = namespaceEntries(st); | |
| 1138 | + var others = otherNamespacesSummary(st); | |
| 1139 | + if (isMulti(st)) { | |
| 1140 | + var lines = $.map(entries, function (e) { return namespaceLine(e, ' ('); }); | |
| 1141 | + if (copied >= total) { | |
| 1142 | + notice('success', 'Copy finished: ' + fmt(copied) + ' of ' + fmt(total) + ' records across ' + entries.length + ' namespaces are in the document index — ' + lines.join(', ') + '.' + stillVector); | |
| 1143 | + } else { | |
| 1144 | + var short = $.map(entries, function (e) { return (parseInt(e.copied, 10) || 0) < (parseInt(e.total, 10) || 0) ? namespaceLine(e, ' (') : null; }); | |
| 1145 | + notice('warning', 'The copy reached the end of every namespace after ' + fmt(copied) + ' records, but ' + fmt(total) + ' were expected. Short: ' + short.join(', ') + '.' + reported + | |
| 1146 | + (parseInt(st.skipped, 10) ? (' ' + fmt(st.skipped) + ' records had no vector and were skipped.') : '')); | |
| 1147 | + } | |
| 1148 | + return; | |
| 1149 | + } | |
| 1150 | + if (copied >= total) { | |
| 1151 | + notice(others ? 'warning' : 'success', 'Copy finished: ' + fmt(copied) + ' of ' + fmt(total) + ' records are in the document index.' + reported + | |
| 1152 | + (others ? (' ' + fmt(others.records) + ' records in ' + others.count + ' other namespace' + (others.count === 1 ? ' were' : 's were') + ' not copied: ' + otherNamespacesText(st) + '. Tick Copy every namespace and click Migrate to include them.') : '') + stillVector); | |
| 1153 | + } else { | |
| 1154 | + notice('warning', 'The copy reached the end of the source namespace after ' + fmt(copied) + ' records, but ' + fmt(total) + ' were expected.' + reported + | |
| 1155 | + (others ? (' Records in other namespaces were not copied: ' + otherNamespacesText(st) + '.') : '') + | |
| 1156 | + (parseInt(st.skipped, 10) ? (' ' + fmt(st.skipped) + ' records had no vector and were skipped.') : '')); | |
| 1157 | + } | |
| 1158 | + } | |
| 957 | 1159 | function migrateStep() { |
| 958 | - post({ action: 'mxchat_pinecone_docs_migrate', mode: 'step' }).done(function (response) { | |
| 1160 | + post({ action: 'mxchat_pinecone_docs_migrate', mode: 'step', target_host: hostValue(), api_key: $('#mxchat_pinecone_api_key').val() }).done(function (response) { | |
| 1161 | + stepRetries = 0; | |
| 959 | 1162 | if (response && response.success) { |
| 960 | 1163 | renderMigration(response.data.state); |
| 961 | 1164 | if (response.data.state && response.data.state.status === 'running') { |
| 962 | - setTimeout(migrateStep, 150); | |
| 1165 | + setTimeout(migrateStep, 250); | |
| 963 | 1166 | } else { |
| 964 | - $migrateBtn.prop('disabled', false).text('Migrate'); | |
| 965 | - notice('success', 'Copy finished: ' + response.data.state.copied + ' of ' + response.data.state.total + ' records are in the document index.'); | |
| 1167 | + migrateFinished(response.data.state || {}); | |
| 966 | 1168 | } |
| 967 | 1169 | } else { |
| 968 | - if (response && response.data && response.data.state) { renderMigration(response.data.state); } | |
| 969 | - notice('error', failMessage(response, 'The copy stopped.') + ' Click Migrate to resume.'); | |
| 1170 | + var st = (response && response.data && response.data.state) ? response.data.state : null; | |
| 1171 | + if (st) { renderMigration(st); } | |
| 1172 | + notice('error', failMessage(response, 'The copy stopped.') + (st ? (' Click Migrate to continue from record ' + fmt(st.copied) + '.') : ' Click Migrate to resume.')); | |
| 970 | 1173 | $migrateBtn.prop('disabled', false).text('Migrate'); |
| 1174 | + $allNs.prop('disabled', false); | |
| 971 | 1175 | } |
| 972 | - }).fail(function () { | |
| 973 | - notice('error', 'Could not reach the server. Click Migrate to resume.'); | |
| 1176 | + }).fail(function (xhr) { | |
| 1177 | + // The server did not answer (timeout, 5xx, rate limit): wait and try the same step again. | |
| 1178 | + if (stepRetries < STEP_RETRY_DELAYS.length) { | |
| 1179 | + var delay = STEP_RETRY_DELAYS[stepRetries++]; | |
| 1180 | + notice('info', 'No answer from the server (HTTP ' + (xhr && xhr.status ? xhr.status : 0) + '). Retrying in ' + Math.round(delay / 1000) + ' s… the copy continues from where it stopped.'); | |
| 1181 | + setTimeout(migrateStep, delay); | |
| 1182 | + return; | |
| 1183 | + } | |
| 1184 | + stepRetries = 0; | |
| 1185 | + notice('error', 'The server stopped answering (HTTP ' + (xhr && xhr.status ? xhr.status : 0) + ') after several tries. Nothing is lost — click Migrate to continue from the last record copied.'); | |
| 974 | 1186 | $migrateBtn.prop('disabled', false).text('Migrate'); |
| 1187 | + $allNs.prop('disabled', false); | |
| 975 | 1188 | }); |
| 976 | 1189 | } |
| 977 | 1190 | $migrateBtn.off('click.pineconeDocs').on('click.pineconeDocs', function () { |
| 978 | 1191 | var source = $.trim($('#mxchat_pinecone_vector_host').val() || ''); |
| @@ -979,25 +1192,35 @@ | ||
| 979 | 1192 | if (!source) { |
| 980 | 1193 | notice('error', 'Enter the host of the vector index to copy from.'); |
| 981 | 1194 | return; |
| 982 | 1195 | } |
| 1196 | + if (!hostValue()) { | |
| 1197 | + notice('error', 'Enter the host of the document index to copy into, or create one with Create index for me.'); | |
| 1198 | + return; | |
| 1199 | + } | |
| 983 | 1200 | $migrateBtn.prop('disabled', true).text('Copying…'); |
| 1201 | + $allNs.prop('disabled', true); | |
| 984 | 1202 | $result.hide(); |
| 985 | - post({ action: 'mxchat_pinecone_docs_migrate', mode: 'start', source_host: source }).done(function (response) { | |
| 1203 | + stepRetries = 0; | |
| 1204 | + post({ action: 'mxchat_pinecone_docs_migrate', mode: 'start', source_host: source, target_host: hostValue(), api_key: $('#mxchat_pinecone_api_key').val(), all_namespaces: $allNs.is(':checked') ? 1 : 0 }).done(function (response) { | |
| 986 | 1205 | if (response && response.success) { |
| 987 | - renderMigration(response.data.state); | |
| 988 | - if (response.data.state && response.data.state.status === 'running') { | |
| 1206 | + var st = response.data.state || {}; | |
| 1207 | + if (st.target_host && !verifiedHost) { verifiedHost = String(st.target_host).toLowerCase(); setStatus(true, 'Document index checked: ' + st.target_host + '.'); } | |
| 1208 | + renderMigration(st); | |
| 1209 | + if (st.status === 'running') { | |
| 989 | 1210 | migrateStep(); |
| 990 | 1211 | } else { |
| 991 | - $migrateBtn.prop('disabled', false).text('Migrate'); | |
| 1212 | + migrateFinished(st); | |
| 992 | 1213 | } |
| 993 | 1214 | } else { |
| 994 | 1215 | notice('error', failMessage(response, 'The copy could not start.')); |
| 995 | 1216 | $migrateBtn.prop('disabled', false).text('Migrate'); |
| 1217 | + $allNs.prop('disabled', false); | |
| 996 | 1218 | } |
| 997 | 1219 | }).fail(function () { |
| 998 | 1220 | notice('error', 'Could not reach the server to start the copy.'); |
| 999 | 1221 | $migrateBtn.prop('disabled', false).text('Migrate'); |
| 1222 | + $allNs.prop('disabled', false); | |
| 1000 | 1223 | }); |
| 1001 | 1224 | }); |
| 1002 | 1225 | renderMigration(state.migration || null); |
| 1003 | 1226 | |