diff --git a/cypress/integration/vault.spec.js b/cypress/integration/vault.spec.js --- a/cypress/integration/vault.spec.js +++ b/cypress/integration/vault.spec.js @@ -13,7 +13,7 @@ 'done': 'rgb(92, 184, 92)' }; -function createVaultCookingTask(objectType) { +function checkVaultCookingTask(objectType) { cy.contains('button', 'Actions') .click(); @@ -23,9 +23,7 @@ cy.contains('.dropdown-item', objectType) .click(); - cy.get('.modal-dialog') - .contains('button:visible', 'Ok') - .click(); + cy.wait('@checkVaultCookingTask'); } function updateVaultItemList(vaultUrl, vaultItems) { @@ -113,12 +111,21 @@ // Stub responses when requesting the vault API to simulate // a task has been created + + cy.route({ + method: 'GET', + url: this.vaultDirectoryUrl, + response: {'exception': 'NotFoundExc'} + }).as('checkVaultCookingTask'); + cy.route({ method: 'POST', url: this.vaultDirectoryUrl, response: this.genVaultDirCookingResponse('new') }).as('createVaultCookingTask'); + checkVaultCookingTask('as tarball'); + cy.route({ method: 'GET', url: this.vaultDirectoryUrl, @@ -126,7 +133,9 @@ }).as('checkVaultCookingTask'); // Create a vault cooking task through the GUI - createVaultCookingTask('Directory'); + cy.get('.modal-dialog') + .contains('button:visible', 'Ok') + .click(); cy.wait('@createVaultCookingTask'); @@ -185,12 +194,22 @@ // Stub responses when requesting the vault API to simulate // a task has been created + + cy.route({ + method: 'GET', + url: this.vaultRevisionUrl, + response: {'exception': 'NotFoundExc'} + }).as('checkVaultCookingTask'); + cy.route({ method: 'POST', url: this.vaultRevisionUrl, response: this.genVaultRevCookingResponse('new') }).as('createVaultCookingTask'); + // Create a vault cooking task through the GUI + checkVaultCookingTask('as git'); + cy.route({ method: 'GET', url: this.vaultRevisionUrl, @@ -198,7 +217,9 @@ }).as('checkVaultCookingTask'); // Create a vault cooking task through the GUI - createVaultCookingTask('Revision'); + cy.get('.modal-dialog') + .contains('button:visible', 'Ok') + .click(); cy.wait('@createVaultCookingTask'); @@ -311,4 +332,76 @@ cy.get(`#vault-task-${this.revision}`) .should('not.exist'); }); + + it('should offer to immediately download a directory tarball if already cooked', function() { + + // Browse a directory + cy.visit(this.directoryUrl); + + // Stub responses when requesting the vault API to simulate + // the directory tarball has already been cooked + cy.route({ + method: 'GET', + url: this.vaultDirectoryUrl, + response: this.genVaultDirCookingResponse('done') + }).as('checkVaultCookingTask'); + + // Stub response to the vault API to simulate archive download + cy.route({ + method: 'GET', + url: this.vaultFetchDirectoryUrl, + response: `fx:${this.directory}.tar.gz,binary`, + headers: { + 'Content-disposition': `attachment; filename=${this.directory}.tar.gz`, + 'Content-Type': 'application/gzip' + } + }).as('fetchCookedArchive'); + + // Create a vault cooking task through the GUI + checkVaultCookingTask('as tarball'); + + // Start archive download through the GUI + cy.get('.modal-dialog') + .contains('button:visible', 'Ok') + .click(); + + cy.wait('@fetchCookedArchive'); + + }); + + it('should offer to immediately download a revision gitfast archive if already cooked', function() { + + // Browse a directory + cy.visit(this.revisionUrl); + + // Stub responses when requesting the vault API to simulate + // the directory tarball has already been cooked + cy.route({ + method: 'GET', + url: this.vaultRevisionUrl, + response: this.genVaultRevCookingResponse('done') + }).as('checkVaultCookingTask'); + + // Stub response to the vault API to simulate archive download + cy.route({ + method: 'GET', + url: this.vaultFetchRevisionUrl, + response: `fx:${this.revision}.gitfast.gz,binary`, + headers: { + 'Content-disposition': `attachment; filename=${this.revision}.gitfast.gz`, + 'Content-Type': 'application/gzip' + } + }).as('fetchCookedArchive'); + + checkVaultCookingTask('as git'); + + // Start archive download through the GUI + cy.get('.modal-dialog') + .contains('button:visible', 'Ok') + .click(); + + cy.wait('@fetchCookedArchive'); + + }); + }); diff --git a/swh/web/assets/src/bundles/vault/vault-create-tasks.js b/swh/web/assets/src/bundles/vault/vault-create-tasks.js --- a/swh/web/assets/src/bundles/vault/vault-create-tasks.js +++ b/swh/web/assets/src/bundles/vault/vault-create-tasks.js @@ -7,6 +7,27 @@ import {handleFetchError, csrfPost} from 'utils/functions'; +export function vaultRequest(objectType, objectId) { + let vaultUrl; + if (objectType === 'directory') { + vaultUrl = Urls.api_1_vault_cook_directory(objectId); + } else { + vaultUrl = Urls.api_1_vault_cook_revision_gitfast(objectId); + } + // check if object has already been cooked + fetch(vaultUrl) + .then(response => response.json()) + .then(data => { + // object needs to be cooked + if (data.exception === 'NotFoundExc') { + $(`#vault-cook-${objectType}-modal`).modal('show'); + // object has been cooked and is in the vault cache + } else if (data.status === 'done') { + $(`#vault-fetch-${objectType}-modal`).modal('show'); + } + }); +} + function addVaultCookingTask(cookingTask) { let vaultCookingTasks = JSON.parse(localStorage.getItem('swh-vault-cooking-tasks')); if (!vaultCookingTasks) { @@ -64,6 +85,16 @@ } } +export function fetchDirectoryArchive(directoryId) { + $('#vault-fetch-directory-modal').modal('hide'); + const vaultUrl = Urls.api_1_vault_cook_directory(directoryId); + fetch(vaultUrl) + .then(response => response.json()) + .then(data => { + swh.vault.fetchCookedObject(data.fetch_url); + }); +} + export function cookRevisionArchive(revisionId) { let email = $('#swh-vault-revision-email').val().trim(); if (!email || validateEmail(email)) { @@ -78,3 +109,13 @@ $('#invalid-email-modal').modal('show'); } } + +export function fetchRevisionArchive(revisionId) { + $('#vault-fetch-directory-modal').modal('hide'); + const vaultUrl = Urls.api_1_vault_cook_revision_gitfast(revisionId); + fetch(vaultUrl) + .then(response => response.json()) + .then(data => { + swh.vault.fetchCookedObject(data.fetch_url); + }); +} diff --git a/swh/web/templates/browse/vault-ui.html b/swh/web/templates/browse/vault-ui.html --- a/swh/web/templates/browse/vault-ui.html +++ b/swh/web/templates/browse/vault-ui.html @@ -1,7 +1,7 @@ {% extends "./layout.html" %} {% comment %} -Copyright (C) 2017-2018 The Software Heritage developers +Copyright (C) 2017-2019 The Software Heritage developers See the AUTHORS file at the top-level directory of this distribution License: GNU Affero General Public License version 3, or any later version See top-level LICENSE file for more information @@ -37,31 +37,7 @@ - - +{% include "includes/vault-common.html" %} -{% endblock %} + \ No newline at end of file diff --git a/swh/web/templates/includes/vault-create-tasks.html b/swh/web/templates/includes/vault-create-tasks.html --- a/swh/web/templates/includes/vault-create-tasks.html +++ b/swh/web/templates/includes/vault-create-tasks.html @@ -16,13 +16,13 @@ @@ -42,8 +42,12 @@ + +