diff --git a/swh/web/assets/src/bundles/vault/vault-ui.js b/swh/web/assets/src/bundles/vault/vault-ui.js index 8dc7203cb8746088c662c176f7fd671020f685c1..78540e41368136047c24c5fcdbe6f655f8bcf410 100644 --- a/swh/web/assets/src/bundles/vault/vault-ui.js +++ b/swh/web/assets/src/bundles/vault/vault-ui.js @@ -5,7 +5,7 @@ * See top-level LICENSE file for more information */ -import {handleFetchErrors} from 'utils/functions'; +import {handleFetchError, handleFetchErrors} from 'utils/functions'; let progress = `<div class="progress"> <div class="progress-bar progress-bar-success progress-bar-striped" @@ -36,6 +36,77 @@ function updateProgressBar(progressBar, cookingTask) { } } +let recookTask; + +// called when the user wants to download a cooked archive +export function fetchCookedObject(fetchUrl) { + recookTask = null; + // first, check if the link is still available from the vault + fetch(fetchUrl, {credentials: 'same-origin'}) + .then(response => { + // link is still alive, proceed to download + if (response.ok) { + $('#vault-fetch-iframe').attr('src', fetchUrl); + // link is dead + } else { + // get the associated cooking task + let vaultCookingTasks = JSON.parse(localStorage.getItem('swh-vault-cooking-tasks')); + for (let i = 0; i < vaultCookingTasks.length; ++i) { + if (vaultCookingTasks[i].fetch_url === fetchUrl) { + recookTask = vaultCookingTasks[i]; + break; + } + } + // display a modal asking the user if he wants to recook the archive + $('#vault-recook-object-modal').modal('show'); + } + }); +} + +// called when the user wants to recook an archive +// for which the download link is not available anymore +export function recookObject() { + if (recookTask) { + // stop cookink tasks status polling + clearTimeout(checkVaultId); + // build cook request url + let cookingUrl; + if (recookTask.object_type === 'directory') { + cookingUrl = Urls.vault_cook_directory(recookTask.object_id); + } else { + cookingUrl = Urls.vault_cook_revision_gitfast(recookTask.object_id); + } + if (recookTask.email) { + cookingUrl += '?email=' + recookTask.email; + } + // request archive cooking + fetch(cookingUrl, {credentials: 'same-origin', method: 'POST'}) + .then(handleFetchError) + .then(() => { + // update task status + recookTask.status = 'new'; + let vaultCookingTasks = JSON.parse(localStorage.getItem('swh-vault-cooking-tasks')); + for (let i = 0; i < vaultCookingTasks.length; ++i) { + if (vaultCookingTasks[i].object_id === recookTask.object_id) { + vaultCookingTasks[i] = recookTask; + break; + } + } + // save updated tasks to local storage + localStorage.setItem('swh-vault-cooking-tasks', JSON.stringify(vaultCookingTasks)); + // restart cooking tasks status polling + checkVaultCookingTasks(); + // hide recook archive modal + $('#vault-recook-object-modal').modal('hide'); + }) + // something went wrong + .catch(() => { + checkVaultCookingTasks(); + $('#vault-recook-object-modal').modal('hide'); + }); + } +} + function checkVaultCookingTasks() { let vaultCookingTasks = JSON.parse(localStorage.getItem('swh-vault-cooking-tasks')); if (!vaultCookingTasks || vaultCookingTasks.length === 0) { @@ -83,6 +154,7 @@ function checkVaultCookingTasks() { let rowTask = $('#vault-task-' + cookingTask.object_id); + let downloadLinkWait = 'Waiting for download link to be available'; if (!rowTask.length) { let browseUrl; @@ -111,10 +183,10 @@ function checkVaultCookingTasks() { } tableRow += `<td class="vault-object-id" data-object-id="${cookingTask.object_id}"><a href="${browseUrl}">${cookingTask.object_id}</a></td>`; tableRow += `<td style="width: 350px">${progressBar.outerHTML}</td>`; - let downloadLink = 'Waiting for download link to be available'; + let downloadLink = downloadLinkWait; if (cookingTask.status === 'done') { - downloadLink = `<a class="btn btn-default btn-sm" href="${cookingTask.fetch_url}` + - '"><i class="fa fa-download fa-fw" aria-hidden="true"></i>Download</a>'; + downloadLink = `<button class="btn btn-default btn-sm" onclick="swh.vault.fetchCookedObject('${cookingTask.fetch_url}')` + + '"><i class="fa fa-download fa-fw" aria-hidden="true"></i>Download</button>'; } else if (cookingTask.status === 'failed') { downloadLink = ''; } @@ -126,10 +198,12 @@ function checkVaultCookingTasks() { updateProgressBar(progressBar, cookingTask); let downloadLink = rowTask.find('.vault-dl-link'); if (cookingTask.status === 'done') { - downloadLink[0].innerHTML = `<a class="btn btn-default btn-sm" href="${cookingTask.fetch_url}` + - '"><i class="fa fa-download fa-fw" aria-hidden="true"></i>Download</a>'; + downloadLink[0].innerHTML = `<button class="btn btn-default btn-sm" onclick="swh.vault.fetchCookedObject('${cookingTask.fetch_url}')` + + '"><i class="fa fa-download fa-fw" aria-hidden="true"></i>Download</button>'; } else if (cookingTask.status === 'failed') { downloadLink[0].innerHTML = ''; + } else if (cookingTask.status === 'new') { + downloadLink[0].innerHTML = downloadLinkWait; } } } diff --git a/swh/web/templates/browse-vault-ui.html b/swh/web/templates/browse-vault-ui.html index d013821fa4f3488cbf17921de1a5e5d3dbd23585..8ec181223d0c58a932dfda5cf98bae2c0d83b753 100644 --- a/swh/web/templates/browse-vault-ui.html +++ b/swh/web/templates/browse-vault-ui.html @@ -37,7 +37,31 @@ See top-level LICENSE file for more information <tbody></tbody> </table> </div> - +<iframe id="vault-fetch-iframe" style="display:none;"></iframe> +<div class="modal fade" id="vault-recook-object-modal" tabindex="-1" role="dialog" aria-labelledby="vault-recook-object-modal-label" aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h6 class="modal-title" id="vault-recook-object-modal-label">Download link no more available</h6> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"> + <span aria-hidden="true">×</span> + </button> + </div> + <div class="modal-body"> + <p> + The requested archive is no more available to download from the Sofware Heritage Vault. + </p> + <p> + Do you want to cook it again ? + </p> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default btn-sm" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-default btn-sm" onclick="swh.vault.recookObject()">Ok</button> + </div> + </div> + </div> +</div> <script> swh.webapp.initPage('vault'); swh.vault.initUi();