PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 3.2.25
MxChat – AI Chatbot & Content Generation for WordPress v3.2.25
3.2.25 3.2.24 3.2.23 3.2.22 3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 All 156 releases
mxchat-basic / js / knowledge-reimport.js

knowledge-reimport.js in MxChat – AI Chatbot & Content Generation for WordPress 3.2.25, at js/knowledge-reimport.js

288 lines 11.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Knowledge screen: "Re-import affected entries" (plan 89739b).
3 *
4 * Check first, rewrite on confirm. Both run as short server steps that save
5 * where they stopped, so this script only has to keep asking for the next
6 * step and draw what comes back. A closed tab loses nothing: the next page
7 * load picks the saved state up from the status call.
8 */
9 (function () {
10 'use strict';
11
12 var card = document.getElementById('mxchat-kb-reimport');
13 if (!card || typeof window.mxchatKbReimport === 'undefined') {
14 return;
15 }
16 var L = window.mxchatKbReimport;
17 var find = function (selector) { return card.querySelector(selector); };
18
19 var before = find('#mxchat-kb-reimport-before');
20 var edited = find('#mxchat-kb-reimport-edited');
21 var checkBtn = find('#mxchat-kb-reimport-check');
22 var applyBtn = find('#mxchat-kb-reimport-apply');
23 var clearBtn = find('#mxchat-kb-reimport-clear');
24 var progress = find('.mxch-kb-reimport-progress');
25 var bar = find('.mxch-progress-bar');
26 var fill = find('.mxch-progress-bar-fill');
27 var label = find('.mxch-progress-label');
28 var errorBox = find('.mxch-kb-reimport-error');
29 var errorText = find('.mxch-kb-reimport-error span');
30 var doneBox = find('.mxch-kb-reimport-done');
31 var doneText = find('.mxch-kb-reimport-done span');
32 var results = find('.mxch-kb-reimport-results');
33 var counts = find('.mxch-kb-reimport-counts');
34 var list = find('.mxch-kb-reimport-entries');
35 var more = find('.mxch-kb-reimport-more');
36 var others = find('.mxch-kb-reimport-others');
37 var othersText = find('.mxch-kb-reimport-others .mxch-disclosure-summary-text');
38 var othersList = find('.mxch-kb-reimport-notes');
39 var footer = find('.mxch-kb-reimport-footer');
40 var busy = false;
41 var last = null;
42
43 function fmt(template, a, b) {
44 return String(template).replace('%1$s', a).replace('%2$s', b).replace('%s', a);
45 }
46
47 function post(params) {
48 var body = new URLSearchParams();
49 body.append('action', 'mxchat_kb_reimport');
50 body.append('nonce', card.getAttribute('data-nonce'));
51 body.append('bot_id', card.getAttribute('data-bot') || 'default');
52 Object.keys(params).forEach(function (key) { body.append(key, params[key]); });
53 return fetch(L.ajaxUrl, { method: 'POST', credentials: 'same-origin', body: body }).then(function (response) {
54 return response.json();
55 });
56 }
57
58 /** One step, retried a few times: every step is resumable on the server. */
59 function step(params, attempt) {
60 attempt = attempt || 0;
61 return post(params).catch(function () {
62 if (attempt >= 3) {
63 throw new Error(L.requestFailed);
64 }
65 return new Promise(function (resolve) { setTimeout(resolve, 1500 * (attempt + 1)); }).then(function () {
66 var again = Object.assign({}, params);
67 delete again.restart;
68 return step(again, attempt + 1);
69 });
70 });
71 }
72
73 function badge(text, variant) {
74 var el = document.createElement('span');
75 el.className = 'mxch-badge' + (variant ? ' mxch-badge-' + variant : '');
76 el.textContent = text;
77 return el;
78 }
79
80 function row(labelText, noteText, badges) {
81 var li = document.createElement('li');
82 var source = document.createElement('span');
83 source.className = 'mxch-kb-reimport-source';
84 source.textContent = labelText;
85 if (noteText) {
86 var note = document.createElement('span');
87 note.className = 'mxch-kb-reimport-note';
88 note.textContent = noteText;
89 source.appendChild(note);
90 }
91 li.appendChild(source);
92 if (badges && badges.length) {
93 var wrap = document.createElement('span');
94 wrap.className = 'mxch-kb-reimport-reasons';
95 badges.forEach(function (b) { wrap.appendChild(b); });
96 li.appendChild(wrap);
97 }
98 return li;
99 }
100
101 function showError(message) {
102 errorText.textContent = message;
103 errorBox.hidden = false;
104 }
105
106 function setBusy(state) {
107 busy = state;
108 checkBtn.disabled = state;
109 applyBtn.disabled = state;
110 clearBtn.disabled = state;
111 before.disabled = state;
112 if (edited) {
113 edited.disabled = state;
114 }
115 }
116
117 function render(state) {
118 var phase = state.phase || 'idle';
119 last = state;
120 errorBox.hidden = true;
121 doneBox.hidden = true;
122
123 if (phase === 'idle') {
124 progress.hidden = true;
125 results.hidden = true;
126 footer.hidden = true;
127 return;
128 }
129 if (state.before && !busy) {
130 before.value = state.before;
131 }
132 if (edited && !busy && typeof state.with_edited !== 'undefined') {
133 edited.checked = !!state.with_edited;
134 }
135
136 // Progress: a check has no total to measure against, a rewrite has.
137 if (phase === 'scan') {
138 progress.hidden = false;
139 bar.hidden = true;
140 label.textContent = fmt(L.checking, state.scanned);
141 } else if (phase === 'apply') {
142 progress.hidden = false;
143 bar.hidden = false;
144 fill.style.width = (state.to_repair ? Math.round(state.pos / state.to_repair * 100) : 0) + '%';
145 label.textContent = fmt(L.rewriting, state.pos, state.to_repair);
146 } else {
147 progress.hidden = true;
148 }
149
150 if (phase === 'scan') {
151 results.hidden = true;
152 footer.hidden = true;
153 return;
154 }
155
156 results.hidden = false;
157 counts.textContent = '';
158 if (phase === 'done') {
159 counts.appendChild(badge(fmt(L.countRewritten, state.repaired), 'success'));
160 if (state.failed > 0) {
161 counts.appendChild(badge(fmt(L.countFailed, state.failed), 'error'));
162 }
163 } else {
164 counts.appendChild(badge(fmt(L.countRepair, state.to_repair), state.to_repair > 0 ? 'warning' : ''));
165 }
166 counts.appendChild(badge(fmt(L.countCorrect, state.unchanged), phase === 'done' ? '' : 'success'));
167 if (state.changed > 0) {
168 counts.appendChild(badge(fmt(L.countChanged, state.changed)));
169 }
170 if (state.edited > 0) {
171 counts.appendChild(badge(fmt(L.countEdited, state.edited), 'warning'));
172 }
173 if (state.skipped > 0) {
174 counts.appendChild(badge(fmt(L.countSkipped, state.skipped)));
175 }
176
177 list.textContent = '';
178 (state.list || []).forEach(function (entry) {
179 var badges = [];
180 if (entry.result === 'repaired') {
181 badges.push(badge(L.rewritten, 'success'));
182 } else if (entry.result === 'failed') {
183 badges.push(badge(L.notRewritten, 'error'));
184 } else if (entry.result) {
185 badges.push(badge(L.noLongerNeeded));
186 } else {
187 (entry.reasons || []).forEach(function (reason) { badges.push(badge(L.reasons[reason] || reason)); });
188 }
189 list.appendChild(row(entry.label, entry.result === 'failed' ? entry.note : '', badges));
190 });
191 list.hidden = !(state.list && state.list.length);
192 var extra = state.to_repair - (state.list ? state.list.length : 0);
193 more.hidden = extra <= 0;
194 more.textContent = extra > 0 ? fmt(L.andMore, extra) : '';
195
196 othersList.textContent = '';
197 (state.notes || []).forEach(function (note) {
198 var kind = note.kind === 'changed' ? L.leftAlone : (note.kind === 'edited' ? L.editedNotRewritten : L.skipped);
199 othersList.appendChild(row(note.label, note.note, [badge(kind, note.kind === 'edited' ? 'warning' : '')]));
200 });
201 others.hidden = !(state.notes && state.notes.length);
202 othersText.textContent = fmt(L.othersTitle, state.changed + state.skipped + (state.edited || 0));
203
204 if (state.error) {
205 showError(fmt(L.scanStopped, state.error));
206 }
207 if (phase === 'done') {
208 doneText.textContent = state.failed > 0 ? fmt(L.doneWithFailures, state.repaired, state.failed) : fmt(L.done, state.repaired);
209 doneBox.hidden = false;
210 } else if (phase === 'scanned' && state.to_repair === 0 && !state.error) {
211 doneText.textContent = L.nothingToDo;
212 doneBox.hidden = false;
213 }
214
215 footer.hidden = false;
216 var canApply = (phase === 'scanned' || phase === 'apply') && state.to_repair > 0 && !state.error;
217 applyBtn.hidden = !canApply;
218 find('.mxch-kb-reimport-cost').hidden = !canApply;
219 applyBtn.textContent = phase === 'apply' && state.pos > 0 ? fmt(L.resume, state.to_repair - state.pos) : fmt(L.apply, state.to_repair);
220 }
221
222 function loop(params, running) {
223 return step(params).then(function (res) {
224 if (!res || !res.success) {
225 throw new Error(res && res.data && res.data.message ? res.data.message : L.requestFailed);
226 }
227 render(res.data.state);
228 if (res.data.state.phase === running) {
229 return loop({ op: params.op }, running);
230 }
231 return res.data.state;
232 });
233 }
234
235 function run(params, running) {
236 if (busy) {
237 return;
238 }
239 setBusy(true);
240 errorBox.hidden = true;
241 loop(params, running).catch(function (error) {
242 progress.hidden = true;
243 showError(error.message);
244 }).then(function () {
245 setBusy(false);
246 });
247 }
248
249 checkBtn.addEventListener('click', function () {
250 results.hidden = true;
251 footer.hidden = true;
252 doneBox.hidden = true;
253 progress.hidden = false;
254 bar.hidden = true;
255 label.textContent = fmt(L.checking, 0);
256 run({ op: 'scan', restart: '1', before: before.value, edited: (edited && edited.checked) ? '1' : '0' }, 'scan');
257 });
258
259 applyBtn.addEventListener('click', function () {
260 if (last && last.to_repair) {
261 progress.hidden = false;
262 bar.hidden = false;
263 fill.style.width = Math.round(last.pos / last.to_repair * 100) + '%';
264 label.textContent = fmt(L.rewriting, last.pos, last.to_repair);
265 }
266 run({ op: 'apply' }, 'apply');
267 });
268
269 clearBtn.addEventListener('click', function () {
270 if (busy) {
271 return;
272 }
273 post({ op: 'cancel' }).then(function () { render({ phase: 'idle' }); }).catch(function () { showError(L.requestFailed); });
274 });
275
276 // A check or a rewrite left unfinished by a closed tab is shown as it stands.
277 post({ op: 'status' }).then(function (res) {
278 if (!res || !res.success || !res.data.state || res.data.state.phase === 'idle') {
279 return;
280 }
281 if (res.data.state.phase === 'scan') {
282 run({ op: 'scan' }, 'scan');
283 } else {
284 render(res.data.state);
285 }
286 }).catch(function () {});
287 })();
288