|
72 | 72 | </tr> |
73 | 73 | <tr> |
74 | 74 | <td>Backup File</td> |
75 | | - <td> |
76 | | - Download: <span id="labelSqlFilename"></span> |
| 75 | + <td>Download: <span id="labelSqlFilename"></span> |
77 | 76 | <br /> |
78 | 77 | SHA 256: <span id="labelSha256"></span> |
79 | 78 | </td> |
|
108 | 107 |
|
109 | 108 | <script> |
110 | 109 |
|
| 110 | + let currentPercent = 0; |
| 111 | +
|
111 | 112 | let divThemes = document.querySelector("#divThemes"); |
112 | 113 |
|
113 | 114 | let linkThemeFile = document.getElementById("linkThemeFile"); |
|
160 | 161 | btnRestore.addEventListener('click', startRestore); |
161 | 162 | btnStop.addEventListener('click', stopTask); |
162 | 163 |
|
163 | | - // HTTP API Functions |
164 | | - async function fetchAPI(url, options = {}) { |
165 | | - try { |
166 | | - const response = await fetch(url, { |
167 | | - credentials: 'include', |
168 | | - ...options |
169 | | - }); |
170 | | -
|
171 | | - if (response.ok) { |
172 | | - const contentType = response.headers.get('content-type'); |
173 | | - if (contentType && contentType.includes('application/json')) { |
174 | | - return { ok: true, data: await response.json() }; |
175 | | - } else { |
176 | | - return { ok: true, text: await response.text() }; |
177 | | - } |
178 | | - } else { |
179 | | - const errorText = await response.text(); |
180 | | - return { ok: false, error: errorText, status: response.status }; |
181 | | - } |
182 | | - } catch (err) { |
183 | | - return { ok: false, error: err.message }; |
184 | | - } |
185 | | - } |
186 | | -
|
187 | 164 | async function startBackup() { |
188 | 165 | resetUIValues(); |
189 | 166 | disableButtons(); |
190 | 167 |
|
| 168 | + currentPercent = 0; |
| 169 | +
|
191 | 170 | try { |
192 | 171 | const formData = new FormData(); |
193 | 172 | formData.append('action', 'start_backup'); |
194 | 173 |
|
195 | | - const result = await fetchAPI(urlApiEndpoint, { |
| 174 | + const result = await fetch(urlApiEndpoint, { |
196 | 175 | method: 'POST', |
197 | | - body: formData |
| 176 | + body: formData, |
| 177 | + credentials: 'include' |
198 | 178 | }); |
199 | 179 |
|
200 | | - if (result.ok && result.data) { |
201 | | - currentTaskId = result.data.TaskId; |
202 | | - showGoodMessage("Success", result.data.Status); |
| 180 | + if (result.ok) { |
| 181 | + let jsonObject = await result.json(); |
| 182 | + currentTaskId = jsonObject.TaskId; |
| 183 | + showGoodMessage("Success", jsonObject.Status); |
203 | 184 | connectWebSocket(currentTaskId); |
204 | | - } else { |
205 | | - showErrorMessage("Error", result.error || "Failed to start backup"); |
| 185 | + } |
| 186 | + else { |
| 187 | + let errMsg = await result.text(); |
| 188 | + showErrorMessage("Error", errMsg); |
206 | 189 | enableButtons(); |
207 | 190 | } |
208 | 191 | } catch (err) { |
|
226 | 209 | formData.append('action', 'start_restore'); |
227 | 210 | formData.append('file', fileRestore.files[0]); |
228 | 211 |
|
229 | | - const result = await fetchAPI(urlApiEndpoint, { |
| 212 | + const result = await fetch(urlApiEndpoint, { |
230 | 213 | method: 'POST', |
231 | | - body: formData |
| 214 | + body: formData, |
| 215 | + credentials: 'include' |
232 | 216 | }); |
233 | 217 |
|
234 | | - if (result.ok && result.data) { |
235 | | - currentTaskId = result.data.TaskId; |
236 | | - showGoodMessage("Success", result.data.Status); |
| 218 | + if (result.ok) { |
| 219 | + let jsonObject = await result.json(); |
| 220 | + currentTaskId = jsonObject.TaskId; |
| 221 | + showGoodMessage("Success", jsonObject.Status); |
237 | 222 | connectWebSocket(currentTaskId); |
238 | | - } else { |
239 | | - showErrorMessage("Error", result.error || "Failed to start restore"); |
| 223 | + } |
| 224 | + else { |
| 225 | + let errMsg = result.text(); |
| 226 | + showErrorMessage("Error", errMsg); |
240 | 227 | enableButtons(); |
241 | 228 | } |
242 | 229 | } catch (err) { |
|
256 | 243 | formData.append('action', 'stop'); |
257 | 244 | formData.append('taskid', currentTaskId); |
258 | 245 |
|
259 | | - const result = await fetchAPI(urlApiEndpoint, { |
| 246 | + const result = await fetch(urlApiEndpoint, { |
260 | 247 | method: 'POST', |
261 | | - body: formData |
| 248 | + body: formData, |
| 249 | + credentials: 'include' |
262 | 250 | }); |
263 | 251 |
|
264 | 252 | if (result.ok) { |
265 | 253 | showGoodMessage("Success", "Stop request sent to server"); |
266 | 254 | } else { |
267 | | - showErrorMessage("Error", result.error || "Failed to stop task"); |
| 255 | + let errMsg = result.text(); |
| 256 | + showErrorMessage("Error", errMsg); |
268 | 257 | } |
269 | 258 | } catch (err) { |
270 | 259 | showErrorMessage("Error", err.message); |
|
382 | 371 | } |
383 | 372 |
|
384 | 373 | function updateUIValues(taskInfo) { |
| 374 | +
|
| 375 | + if (taskInfo.PercentCompleted < currentPercent) { |
| 376 | + // late echo, ignore |
| 377 | + return; |
| 378 | + } |
| 379 | + else { |
| 380 | + currentPercent = taskInfo.PercentCompleted; |
| 381 | + } |
| 382 | +
|
385 | 383 | // Basic task information |
386 | 384 | labelTaskId.textContent = taskInfo.TaskId || "--"; |
387 | 385 | lableTimeStart.textContent = taskInfo.TimeStartDisplay || "---"; |
|
0 commit comments