diff --git a/dashboard/src/app/workspaces/workspace-details/export-workspace/dialog/export-tab-dialog.html b/dashboard/src/app/workspaces/workspace-details/export-workspace/dialog/export-tab-dialog.html new file mode 100644 index 0000000000..6f22f3f9b8 --- /dev/null +++ b/dashboard/src/app/workspaces/workspace-details/export-workspace/dialog/export-tab-dialog.html @@ -0,0 +1,86 @@ + + + + + + + + As a File + + + + + + + + + + + + + + + + To Private Cloud + + + + + An URL is required. + + + A name is required. + The name has to be less than 128 characters long. + The name has to be less than 128 characters long. + + + A password is required. + The name has to be less than 128 characters long. + The name has to be less than 128 characters long. + + + + + + + + + + + + + + + + + + HIDE + + diff --git a/dashboard/src/app/workspaces/workspace-details/export-workspace/dialog/export-workspace-dialog.controller.js b/dashboard/src/app/workspaces/workspace-details/export-workspace/dialog/export-workspace-dialog.controller.js new file mode 100644 index 0000000000..b202907f02 --- /dev/null +++ b/dashboard/src/app/workspaces/workspace-details/export-workspace/dialog/export-workspace-dialog.controller.js @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2015-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +'use strict'; + +/** + * @ngdoc controller + * @name workspace.export.controller:ExportWorkspaceDialogController + * @description This class is handling the controller for the dialog box about the export of workspace + * @author Florent Benoit + */ +export class ExportWorkspaceDialogController { + + /** + * Default constructor that is using resource + * @ngInject for Dependency injection + */ + constructor($q, $filter, lodash, cheRemote, cheNotification, $http, cheRecipeTemplate, $mdDialog, $log) { + this.$q = $q; + this.$filter = $filter; + this.$http = $http; + this.lodash = lodash; + this.cheRemote = cheRemote; + this.cheNotification = cheNotification; + this.cheRecipeTemplate = cheRecipeTemplate; + this.$mdDialog = $mdDialog; + this.$log = $log; + this.editorOptions = { + lineWrapping : true, + lineNumbers: false, + matchBrackets: true, + readOnly: 'nocursor', + mode: 'application/json' + }; + this.privateCloudUrl = ''; + this.privateCloudLogin = ''; + this.privateCloudPassword = ''; + this.retrieveWorkspace(); + this.importInProgress = false; + } + + /** + * It will hide the dialog box. + */ + hide() { + this.$mdDialog.hide(); + } + + /** + * Gets the workspace details and links to get download the JSON file + */ + retrieveWorkspace() { + let copyOfWorkspace = angular.copy(this.workspaceDetails); + this.downloadLink = '/api/workspace/' + this.workspaceId + '?downloadAsFile=' + this.workspaceDetails.name + '.json'; + + //remove links + delete copyOfWorkspace.links; + this.exportWorkspaceContent = this.$filter('json')(angular.fromJson(copyOfWorkspace), 2); + } + + /** + * Start the process to export to the private Cloud + */ + exportToPrivateCloud() { + this.exportInCloudSteps = ''; + this.importInProgress = true; + let login = this.cheRemote.newAuth(this.privateCloudUrl, this.privateCloudLogin, this.privateCloudPassword); + + login.then((authData) => { + let copyOfWorkspace = angular.copy(this.workspaceDetails); + copyOfWorkspace.name = 'import-' + copyOfWorkspace.name; + + // get content of the recipe + let environments = copyOfWorkspace.environments; + let defaultEnvName = copyOfWorkspace.defaultEnv; + let defaultEnvironment = this.lodash.find(environments, (environment) => { + return environment.name === defaultEnvName; + }); + + let recipeLocation = defaultEnvironment.machineConfigs[0].source.location; + + // get content of recipe + this.$http.get(recipeLocation).then((response) => { + + let recipeScriptContent = response.data; + // now upload the recipe to the remote service + let remoteRecipeAPI = this.cheRemote.newRecipe(authData); + + let recipeContent = this.cheRecipeTemplate.getDefaultRecipe(); + recipeContent.name = 'recipe-' + copyOfWorkspace.name; + recipeContent.script = recipeScriptContent; + + let createRecipePromise = remoteRecipeAPI.create(recipeContent); + createRecipePromise.then((recipe) => { + let findLink = this.lodash.find(recipe.links, (link) => { + return link.rel === 'get recipe script'; + }); + + // update copy of workspace with new recipe link + let recipeLink = findLink.href; + defaultEnvironment.machineConfigs[0].source.location = recipeLink; + + + let remoteWorkspaceAPI = this.cheRemote.newWorkspace(authData); + let remoteProjectAPI = this.cheRemote.newProject(authData); + this.exportInCloudSteps += 'Creating remote workspace...'; + let createWorkspacePromise = remoteWorkspaceAPI.createWorkspaceFromConfig(null, copyOfWorkspace); + createWorkspacePromise.then((remoteWorkspace) => { + this.exportInCloudSteps += 'ok !'; + // ok now we've to import each project with a location into the remote workspace + let importProjectsPromise = this.importProjectsIntoWorkspace(remoteWorkspaceAPI, remoteProjectAPI, remoteWorkspace, authData); + importProjectsPromise.then(() => { + this.exportInCloudSteps += 'Export of workspace ' + copyOfWorkspace.name + 'finished '; + this.cheNotification.showInfo('Successfully exported the workspace to ' + copyOfWorkspace.name + ' on ' + this.privateCloudUrl); + this.hide(); + }, (error) => { + this.handleError(error); + }) + + }, (error) => { + this.handleError(error); + }) + }); + }, (error) => { + this.handleError(error); + }); + + }, (error) => { + this.handleError(error); + }); + } + + + /** + * Import all projects with a given source location into the remote workspace + * @param workspace the remote workspace + */ + importProjectsIntoWorkspace(remoteWorkspaceAPI, remoteProjectAPI, workspace, authData) { + + var projectPromises = []; + + // ok so + workspace.projects.forEach((project) => { + if (project.source && project.source.location && project.source.location.length > 0) { + let deferred = this.$q.defer(); + let deferredPromise = deferred.promise; + projectPromises.push(deferredPromise); + this.exportInCloudSteps += 'Starting remote workspace...'; + + // compute WS url + let remoteURL = authData.url; + let remoteWsURL = remoteURL.replace('http', 'ws') + '/api/ws/'; + + let startWorkspacePromise = remoteWorkspaceAPI.startWorkspace(remoteWsURL, workspace.id, workspace.defaultEnv); + + startWorkspacePromise.then(() => { + this.exportInCloudSteps += 'ok !'; + let importProjectPromise = remoteProjectAPI.importProject(workspace.id, project.name, project.source); + + importProjectPromise.then(() => { + this.exportInCloudSteps += 'Importing project ' + project.name + '...'; + let updateProjectPromise = remoteProjectAPI.updateProject(workspace.id, project.name, project); + updateProjectPromise.then(() => { + deferred.resolve(workspace); + }, (error) => { + deferred.reject(error); + }); + }, (error) => { + deferred.reject(error); + }); + }, (error) => { + this.handleError(error); + }); + } + + }); + return this.$q.all(projectPromises); + } + + /** + * Notify user about the error. + * @param error the error message to display + */ + handleError(error) { + this.importInProgress = false; + var message; + if (error.data) { + if (error.data.message) { + message = error.data.message; + } else { + message = error.data; + } + } else { + message = 'unable to connect to ' + error.config.url; + } + this.cheNotification.showError('Exporting workspace failed: ' + message); + this.$log.error('error', message, error); + } + + +} diff --git a/dashboard/src/app/workspaces/workspace-details/export-workspace/dialog/export-workspace-dialog.styl b/dashboard/src/app/workspaces/workspace-details/export-workspace/dialog/export-workspace-dialog.styl new file mode 100644 index 0000000000..736a9a4575 --- /dev/null +++ b/dashboard/src/app/workspaces/workspace-details/export-workspace/dialog/export-workspace-dialog.styl @@ -0,0 +1,5 @@ +.export-workspace-progress-icon + width 52px + height 52px + fill $primary-color + margin-right 15px diff --git a/dashboard/src/app/workspaces/workspace-details/export-workspace/export-workspace.controller.js b/dashboard/src/app/workspaces/workspace-details/export-workspace/export-workspace.controller.js new file mode 100644 index 0000000000..ba105a6034 --- /dev/null +++ b/dashboard/src/app/workspaces/workspace-details/export-workspace/export-workspace.controller.js @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +'use strict'; + +/** + * @ngdoc controller + * @name workspace.export.controller:ExportWorkspaceController + * @description This class is handling the controller for the export of workspace + * @author Florent Benoit + */ +export class ExportWorkspaceController { + + /** + * Default constructor that is using resource + * @ngInject for Dependency injection + */ + constructor($mdDialog) { + this.$mdDialog = $mdDialog; + } + + showExport($event) { + this.$mdDialog.show({ + targetEvent: $event, + controller: 'ExportWorkspaceDialogController', + controllerAs: 'exportWorkspaceDialogController', + bindToController: true, + clickOutsideToClose: true, + locals: {workspaceId: this.workspaceId, + workspaceDetails: this.workspaceDetails, callbackController: this}, + templateUrl: 'app/workspaces/workspace-details/export-workspace/dialog/export-tab-dialog.html' + }); + } + + +} diff --git a/dashboard/src/app/workspaces/workspace-details/export-workspace/export-workspace.directive.js b/dashboard/src/app/workspaces/workspace-details/export-workspace/export-workspace.directive.js new file mode 100644 index 0000000000..e86836e213 --- /dev/null +++ b/dashboard/src/app/workspaces/workspace-details/export-workspace/export-workspace.directive.js @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +'use strict'; + +/** + * @ngdoc directive + * @name workspaces.details.directive:workspaceDetailsProjects + * @restrict E + * @element + * + * @description + * + * + * @usage + * + * + * @author Florent Benoit + */ +export class ExportWorkspace { + + /** + * Default constructor that is using resource + * @ngInject for Dependency injection + */ + constructor () { + this.restrict = 'E'; + this.templateUrl = 'app/workspaces/workspace-details/export-workspace/export-workspace.html'; + + this.controller = 'ExportWorkspaceController'; + this.controllerAs = 'exportWorkspaceCtrl'; + this.bindToController = true; + + // scope values + this.scope = { + workspaceId: '@workspaceId', + workspaceDetails: '=workspaceDetails' + }; + } + +} diff --git a/dashboard/src/app/workspaces/workspace-details/export-workspace/export-workspace.html b/dashboard/src/app/workspaces/workspace-details/export-workspace/export-workspace.html new file mode 100644 index 0000000000..a8473ae406 --- /dev/null +++ b/dashboard/src/app/workspaces/workspace-details/export-workspace/export-workspace.html @@ -0,0 +1,10 @@ + + + + Export your workspace. + + + + + + diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.js b/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.js index b339ff8fdf..9de768a345 100644 --- a/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.js +++ b/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.js @@ -20,24 +20,15 @@ export class WorkspaceDetailsCtrl { * Default constructor that is using resource injection * @ngInject for Dependency injection */ - constructor($route, $location, cheWorkspace, cheAPI, $mdDialog, cheNotification, $filter) { + constructor($route, $location, cheWorkspace, cheAPI, $mdDialog, cheNotification) { this.cheNotification = cheNotification; this.cheAPI = cheAPI; this.cheWorkspace = cheWorkspace; this.$mdDialog = $mdDialog; this.$location = $location; - this.$filter = $filter; this.workspaceId = $route.current.params.workspaceId; - this.editorOptions = { - lineWrapping : true, - lineNumbers: false, - matchBrackets: true, - readOnly: 'nocursor', - mode: 'application/json' - }; - this.loading = true; if (!this.cheWorkspace.getWorkspacesById().get(this.workspaceId)) { @@ -120,15 +111,6 @@ export class WorkspaceDetailsCtrl { }); } - exportWorkspace() { - let copyOfWorkspace = angular.copy(this.workspaceDetails); - this.downloadLink = '/api/workspace/' + this.workspaceId + '?downloadAsFile=' + this.workspaceDetails.name + '.json'; - - //remove links - delete copyOfWorkspace.links; - this.exportWorkspaceContent = this.$filter('json')(angular.fromJson(copyOfWorkspace), 2); - } - runWorkspace() { let promise = this.cheAPI.getWorkspace().startWorkspace(this.workspaceId, this.workspaceDetails.defaultEnv); diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-details.html b/dashboard/src/app/workspaces/workspace-details/workspace-details.html index dcd32556c8..a31628714a 100644 --- a/dashboard/src/app/workspaces/workspace-details/workspace-details.html +++ b/dashboard/src/app/workspaces/workspace-details/workspace-details.html @@ -55,35 +55,7 @@ - - - - Export your workspace to a JSON file. - - - - - - - - - - - - - - - - - - - - - + diff --git a/dashboard/src/app/workspaces/workspaces-config.js b/dashboard/src/app/workspaces/workspaces-config.js index bf3f8f79cc..1e4b4e3938 100644 --- a/dashboard/src/app/workspaces/workspaces-config.js +++ b/dashboard/src/app/workspaces/workspaces-config.js @@ -18,6 +18,9 @@ import {UsageChart} from './list-workspaces/workspace-item/usage-chart.directive import {WorkspaceItemCtrl} from './list-workspaces/workspace-item/workspace-item.controller'; import {WorkspaceDetailsCtrl} from './workspace-details/workspace-details.controller'; import {WorkspaceDetailsProjectsCtrl} from './workspace-details/workspace-projects/workspace-details-projects.controller'; +import {ExportWorkspaceController} from './workspace-details/export-workspace/export-workspace.controller'; +import {ExportWorkspace} from './workspace-details/export-workspace/export-workspace.directive'; +import {ExportWorkspaceDialogController} from './workspace-details/export-workspace/dialog/export-workspace-dialog.controller'; import {WorkspaceDetailsProjects} from './workspace-details/workspace-projects/workspace-details-projects.directive'; import {ReadyToGoStacksCtrl} from './create-workspace/select-stack/ready-to-go-stacks/ready-to-go-stacks.controller'; import {ReadyToGoStacks} from './create-workspace/select-stack/ready-to-go-stacks/ready-to-go-stacks.directive'; @@ -62,6 +65,10 @@ export class WorkspacesConfig { register.controller('WorkspaceDetailsProjectsCtrl', WorkspaceDetailsProjectsCtrl); register.directive('workspaceDetailsProjects', WorkspaceDetailsProjects); + register.controller('ExportWorkspaceDialogController', ExportWorkspaceDialogController); + register.controller('ExportWorkspaceController', ExportWorkspaceController); + register.directive('exportWorkspace', ExportWorkspace); + register.controller('WorkspaceRecipeCtrl', WorkspaceRecipeCtrl); register.directive('cheWorkspaceRecipe', WorkspaceRecipe);