diff --git a/cvat-ui/src/components/projects-page/top-bar.tsx b/cvat-ui/src/components/projects-page/top-bar.tsx
index 57c9c02b..442fa3fa 100644
--- a/cvat-ui/src/components/projects-page/top-bar.tsx
+++ b/cvat-ui/src/components/projects-page/top-bar.tsx
@@ -1,4 +1,4 @@
-// Copyright (C) 2020-2021 Intel Corporation
+// Copyright (C) 2020-2022 Intel Corporation
//
// SPDX-License-Identifier: MIT
@@ -44,16 +44,17 @@ export default function TopBarComponent(): JSX.Element {
dispatch(restoreProjectAsync(file));
return false;
}}
+ className='cvat-import-project'
>
}
>
Create from backup
- {isImporting && }
+ {isImporting && }
diff --git a/tests/cypress/integration/actions_projects_models/case_114_backup_restore_project.js b/tests/cypress/integration/actions_projects_models/case_114_backup_restore_project.js
new file mode 100644
index 00000000..eda5b2b3
--- /dev/null
+++ b/tests/cypress/integration/actions_projects_models/case_114_backup_restore_project.js
@@ -0,0 +1,176 @@
+// Copyright (C) 2022 Intel Corporation
+//
+// SPDX-License-Identifier: MIT
+
+///
+
+const caseId = '114';
+let projectID = '';
+let projectBackupArchiveFullName;
+
+function getProjectID() {
+ cy.url().then((url) => {
+ projectID = Number(url.split('/').slice(-1)[0].split('?')[0]);
+ });
+}
+
+const project = {
+ name: `Case ${caseId}`,
+ label: 'Tree',
+ attrName: 'Kind',
+ attrVaue: 'Oak',
+};
+
+const task = {
+ name: `Case ${caseId}`,
+ multiAttrParams: false,
+ advancedConfigurationParams: false,
+ forProject: true,
+ attachToProject: false,
+};
+
+context('Backup, restore a project.', { browser: '!firefox' }, () => {
+ const imagesCount = 1;
+ const imageFileName = `image_${task.name.replace(' ', '_').toLowerCase()}`;
+ const width = 800;
+ const height = 800;
+ const posX = 10;
+ const posY = 10;
+ const color = 'gray';
+ const archiveName = `${imageFileName}.zip`;
+ const archivePath = `cypress/fixtures/${archiveName}`;
+ const imagesFolder = `cypress/fixtures/${imageFileName}`;
+ const directoryToArchive = imagesFolder;
+
+ const createRectangleShape2Points = {
+ points: 'By 2 Points',
+ type: 'Shape',
+ labelName: project.label,
+ firstX: 250,
+ firstY: 350,
+ secondX: 350,
+ secondY: 450,
+ };
+
+ before(() => {
+ cy.visit('/');
+ cy.login();
+ cy.imageGenerator(imagesFolder, imageFileName, width, height, color, posX, posY, project.label, imagesCount);
+ cy.createZipArchive(directoryToArchive, archivePath);
+ cy.goToProjectsList();
+ cy.createProjects(project.name, project.label, project.attrName, project.attrVaue);
+ cy.openProject(project.name);
+ getProjectID();
+ cy.createAnnotationTask(
+ task.name,
+ task.label,
+ task.attrName,
+ task.attrValue,
+ archiveName,
+ task.multiAttrParams,
+ task.advancedConfigurationParams,
+ task.forProject,
+ task.attachToProject,
+ project.name,
+ );
+ cy.openProject(project.name);
+ cy.openTaskJob(task.name);
+ cy.createRectangle(createRectangleShape2Points);
+ cy.saveJob();
+ cy.goToProjectsList();
+ });
+
+ after(() => {
+ cy.goToProjectsList();
+ cy.deleteProject(project.name, projectID);
+ });
+
+ describe(`Testing "${caseId}"`, () => {
+ it('Export the project.', () => {
+ cy.backupProject(project.name);
+ cy.getDownloadFileName().then((file) => {
+ projectBackupArchiveFullName = file;
+ cy.verifyDownload(projectBackupArchiveFullName);
+ });
+ });
+
+ it('Remove and restore the project from backup.', () => {
+ cy.deleteProject(project.name, projectID);
+ cy.restoreProject(projectBackupArchiveFullName);
+ });
+
+ it('Checking the availability of a project, task, shape.', () => {
+ cy.contains('.cvat-projects-project-item-title', project.name).should('exist');
+ cy.openProject(project.name);
+ getProjectID();
+ cy.contains('.cvat-constructor-viewer-item', project.label).should('exist');
+ cy.get('.cvat-tasks-list-item').should('have.length', 1);
+ cy.openTaskJob(task.name, 0, false);
+ cy.get('#cvat_canvas_shape_1').should('exist');
+ });
+ });
+});
+
+context('Backup, restore a project with a 3D task.', { browser: '!firefox' }, () => {
+ const archiveName3d = '../../cypress/integration/canvas3d_functionality/assets/test_canvas3d.zip';
+
+ const cuboidCreationParams = {
+ labelName: project.label,
+ x: 480,
+ y: 160,
+ };
+
+ before(() => {
+ cy.goToProjectsList();
+ cy.createProjects(project.name, project.label, project.attrName, project.attrVaue);
+ cy.openProject(project.name);
+ getProjectID();
+ cy.createAnnotationTask(
+ task.name,
+ task.label,
+ task.attrName,
+ task.attrValue,
+ archiveName3d,
+ task.multiAttrParams,
+ task.advancedConfigurationParams,
+ task.forProject,
+ task.attachToProject,
+ project.name,
+ );
+ cy.openProject(project.name);
+ cy.openTaskJob(task.name);
+ cy.create3DCuboid(cuboidCreationParams);
+ cy.saveJob();
+ cy.goToProjectsList();
+ });
+
+ after(() => {
+ cy.goToProjectsList();
+ cy.deleteProject(project.name, projectID);
+ });
+
+ describe(`Testing "${caseId}"`, () => {
+ it('Export the project.', () => {
+ cy.backupProject(project.name);
+ cy.getDownloadFileName().then((file) => {
+ projectBackupArchiveFullName = file;
+ cy.verifyDownload(projectBackupArchiveFullName);
+ });
+ });
+
+ it('Remove and restore the project from backup.', () => {
+ cy.deleteProject(project.name, projectID);
+ cy.restoreProject(projectBackupArchiveFullName);
+ });
+
+ it('Checking the availability of a project, task, shape.', () => {
+ cy.contains('.cvat-projects-project-item-title', project.name).should('exist');
+ cy.openProject(project.name);
+ getProjectID();
+ cy.contains('.cvat-constructor-viewer-item', project.label).should('exist');
+ cy.get('.cvat-tasks-list-item').should('have.length', 1);
+ cy.openTaskJob(task.name, 0, false);
+ cy.get('#cvat-objects-sidebar-state-item-1').should('exist');
+ });
+ });
+});
diff --git a/tests/cypress/support/commands_projects.js b/tests/cypress/support/commands_projects.js
index f1db0968..55bae092 100644
--- a/tests/cypress/support/commands_projects.js
+++ b/tests/cypress/support/commands_projects.js
@@ -1,4 +1,4 @@
-// Copyright (C) 2020-2021 Intel Corporation
+// Copyright (C) 2020-2022 Intel Corporation
//
// SPDX-License-Identifier: MIT
@@ -85,6 +85,22 @@ Cypress.Commands.add('exportProject', ({
cy.get('.cvat-notification-notice-export-project-start').should('be.visible');
});
+Cypress.Commands.add('backupProject', (projectName) => {
+ cy.projectActions(projectName);
+ cy.get('.cvat-project-actions-menu').contains('Backup Project').click();
+});
+
+Cypress.Commands.add('restoreProject', (archiveWithBackup) => {
+ cy.intercept('POST', '/api/v1/projects/backup?**').as('restoreProject');
+ cy.get('.cvat-import-project').click().find('input[type=file]').attachFile(archiveWithBackup);
+ cy.wait('@restoreProject', { timeout: 5000 }).its('response.statusCode').should('equal', 202);
+ cy.wait('@restoreProject').its('response.statusCode').should('equal', 201);
+ cy.contains('Project has been created succesfully')
+ .should('exist')
+ .and('be.visible');
+ cy.get('[data-icon="close"]').click(); // Close the notification
+});
+
Cypress.Commands.add('getDownloadFileName', () => {
cy.intercept('GET', '**=download').as('download');
cy.wait('@download').then((download) => {