+
+ The recipe is required.
+
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/recipe/workspace-recipe.styl b/dashboard/src/app/workspaces/workspace-details/select-stack/recipe/workspace-recipe.styl
similarity index 93%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/recipe/workspace-recipe.styl
rename to dashboard/src/app/workspaces/workspace-details/select-stack/recipe/workspace-recipe.styl
index ca2c0bafa53..c75e38c3b66 100644
--- a/dashboard/src/app/workspaces/create-workspace/select-stack/recipe/workspace-recipe.styl
+++ b/dashboard/src/app/workspaces/workspace-details/select-stack/recipe/workspace-recipe.styl
@@ -11,7 +11,8 @@
.recipe-editor .CodeMirror
border 1px solid $list-separator-color
- min-height 500px
+ height 300px
+ min-height 300px
.recipe-docs-link
margin-top 5px
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/create-project-stack-library-selected-stack.filter.ts b/dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/create-project-stack-library-selected-stack.filter.ts
similarity index 100%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/create-project-stack-library-selected-stack.filter.ts
rename to dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/create-project-stack-library-selected-stack.filter.ts
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/create-project-stack-library.controller.ts b/dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/create-project-stack-library.controller.ts
similarity index 100%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/create-project-stack-library.controller.ts
rename to dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/create-project-stack-library.controller.ts
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/create-project-stack-library.directive.ts b/dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/create-project-stack-library.directive.ts
similarity index 90%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/create-project-stack-library.directive.ts
rename to dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/create-project-stack-library.directive.ts
index 88e0999b5b3..99501abba2b 100644
--- a/dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/create-project-stack-library.directive.ts
+++ b/dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/create-project-stack-library.directive.ts
@@ -29,7 +29,7 @@ export class CreateProjectStackLibrary {
*/
constructor() {
this.restrict = 'E';
- this.templateUrl = 'app/workspaces/create-workspace/select-stack/stack-library/create-project-stack-library.html';
+ this.templateUrl = 'app/workspaces/workspace-details/select-stack/stack-library/create-project-stack-library.html';
this.controller = 'CreateProjectStackLibraryController';
this.controllerAs = 'createProjectStackLibraryCtrl';
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/create-project-stack-library.html b/dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/create-project-stack-library.html
similarity index 100%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/create-project-stack-library.html
rename to dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/create-project-stack-library.html
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-filter/che-stack-library-filter.controller.ts b/dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-filter/che-stack-library-filter.controller.ts
similarity index 100%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-filter/che-stack-library-filter.controller.ts
rename to dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-filter/che-stack-library-filter.controller.ts
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-filter/che-stack-library-filter.directive.ts b/dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-filter/che-stack-library-filter.directive.ts
similarity index 94%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-filter/che-stack-library-filter.directive.ts
rename to dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-filter/che-stack-library-filter.directive.ts
index 58aaba4999c..9d9d400e097 100644
--- a/dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-filter/che-stack-library-filter.directive.ts
+++ b/dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-filter/che-stack-library-filter.directive.ts
@@ -29,7 +29,7 @@ export class CheStackLibraryFilter {
*/
constructor () {
this.restrict = 'E';
- this.templateUrl = 'app/workspaces/create-workspace/select-stack/stack-library/stack-library-filter/che-stack-library-filter.html';
+ this.templateUrl = 'app/workspaces/workspace-details/select-stack/stack-library/stack-library-filter/che-stack-library-filter.html';
this.controller = 'CheStackLibraryFilterController';
this.controllerAs = 'cheStackLibraryFilterCtrl';
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-filter/che-stack-library-filter.html b/dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-filter/che-stack-library-filter.html
similarity index 100%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-filter/che-stack-library-filter.html
rename to dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-filter/che-stack-library-filter.html
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-filter/che-stack-library-filter.styl b/dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-filter/che-stack-library-filter.styl
similarity index 100%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-filter/che-stack-library-filter.styl
rename to dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-filter/che-stack-library-filter.styl
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.directive.ts b/dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.directive.ts
similarity index 87%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.directive.ts
rename to dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.directive.ts
index 9d572c42df3..58b3c291fad 100644
--- a/dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.directive.ts
+++ b/dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.directive.ts
@@ -23,7 +23,7 @@ export class CheStackLibrarySelecter {
*/
constructor () {
this.restrict='E';
- this.templateUrl = 'app/workspaces/create-workspace/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.html';
+ this.templateUrl = 'app/workspaces/workspace-details/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.html';
// scope values
this.scope = {
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.html b/dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.html
similarity index 100%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.html
rename to dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.html
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.styl b/dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.styl
similarity index 100%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.styl
rename to dashboard/src/app/workspaces/workspace-details/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.styl
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/workspace-select-stack.controller.ts b/dashboard/src/app/workspaces/workspace-details/select-stack/workspace-select-stack.controller.ts
similarity index 100%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/workspace-select-stack.controller.ts
rename to dashboard/src/app/workspaces/workspace-details/select-stack/workspace-select-stack.controller.ts
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/workspace-select-stack.directive.ts b/dashboard/src/app/workspaces/workspace-details/select-stack/workspace-select-stack.directive.ts
similarity index 91%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/workspace-select-stack.directive.ts
rename to dashboard/src/app/workspaces/workspace-details/select-stack/workspace-select-stack.directive.ts
index 4429cc01888..d3ab9a30cc4 100644
--- a/dashboard/src/app/workspaces/create-workspace/select-stack/workspace-select-stack.directive.ts
+++ b/dashboard/src/app/workspaces/workspace-details/select-stack/workspace-select-stack.directive.ts
@@ -22,7 +22,7 @@ export class WorkspaceSelectStack {
*/
constructor() {
this.restrict = 'E';
- this.templateUrl = 'app/workspaces/create-workspace/select-stack/workspace-select-stack.html';
+ this.templateUrl = 'app/workspaces/workspace-details/select-stack/workspace-select-stack.html';
this.replace = true;
this.bindToController = true;
this.controller = 'WorkspaceSelectStackController';
diff --git a/dashboard/src/app/workspaces/create-workspace/select-stack/workspace-select-stack.html b/dashboard/src/app/workspaces/workspace-details/select-stack/workspace-select-stack.html
similarity index 90%
rename from dashboard/src/app/workspaces/create-workspace/select-stack/workspace-select-stack.html
rename to dashboard/src/app/workspaces/workspace-details/select-stack/workspace-select-stack.html
index dc7b44cf997..5b61ec95c7c 100644
--- a/dashboard/src/app/workspaces/create-workspace/select-stack/workspace-select-stack.html
+++ b/dashboard/src/app/workspaces/workspace-details/select-stack/workspace-select-stack.html
@@ -24,7 +24,8 @@
Custom stack
-
diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.ts b/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.ts
index 64b93784560..18aab4950e5 100644
--- a/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.ts
+++ b/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.ts
@@ -9,127 +9,168 @@
* Codenvy, S.A. - initial API and implementation
*/
'use strict';
+import {CheEnvironmentRegistry} from '../../../components/api/environment/che-environment-registry.factory';
+import {CheNotification} from '../../../components/notification/che-notification.factory';
+import {CheWorkspace} from '../../../components/api/che-workspace.factory';
+import IdeSvc from '../../ide/ide.service';
+import {WorkspaceDetailsService} from './workspace-details.service';
/**
- * Controller for a workspace details.
+ * @ngdoc controller
+ * @name workspaces.workspace.details.controller:WorkspaceDetailsController
+ * @description This class is handling the controller for workspace to create and edit.
* @author Ann Shumilova
+ * @author Oleksii Kurinnyi
*/
+
+enum Tab {Settings, Runtime}
+
export class WorkspaceDetailsController {
- $location;
- $log;
- $mdDialog;
- $q;
- $rootScope: angular.IRootScopeService;
- $route;
- $scope: angular.IScope;
- $timeout;
- cheNotification;
- cheWorkspace;
- ideSvc;
- lodash;
- workspaceDetailsService;
-
- workspaceDetails;
- copyWorkspaceDetails;
- machinesViewStatus;
+ $location: ng.ILocationService;
+ $log: ng.ILogService;
+ $mdDialog: ng.material.IDialogService;
+ $q: ng.IQService;
+ $route: ng.route.IRouteService;
+ $rootScope: ng.IRootScopeService;
+ $scope: ng.IScope;
+ $timeout: ng.ITimeoutService;
+ cheEnvironmentRegistry: CheEnvironmentRegistry;
+ cheNotification: CheNotification;
+ cheWorkspace: CheWorkspace;
+ ideSvc: IdeSvc;
+ workspaceDetailsService: WorkspaceDetailsService;
+
+ loading: boolean = false;
+ isCreationFlow: boolean = true;
+ selectedTabIndex: number;
+
namespace: string;
workspaceId: string;
workspaceName: string;
newName: string;
- workspaceKey: string;
- editMode: boolean;
- showApplyMessage: boolean;
- loading: boolean;
- timeoutPromise: Promise
;
- invalidWorkspace: string;
- selectedTabIndex;
+ stack: any;
+ workspaceDetails: any = {};
+ copyWorkspaceDetails: any = {};
+ machinesViewStatus: any = {};
errorMessage: string;
+ invalidWorkspace: string;
+ editMode: boolean = false;
+ showApplyMessage: boolean = false;
+
+ usedNamesList: any = [];
+
+ forms: Map = new Map();
+ tab: Object;
/**
* Default constructor that is using resource injection
* @ngInject for Dependency injection
*/
- constructor($scope, $rootScope, $route, $location, cheWorkspace, $mdDialog, cheNotification, ideSvc, $log, workspaceDetailsService, lodash, $q, $timeout) {
+ constructor($location: ng.ILocationService, $log: ng.ILogService, $mdDialog: ng.material.IDialogService, $q: ng.IQService, $route: ng.route.IRouteService, $rootScope: ng.IRootScopeService, $scope: ng.IScope, $timeout: ng.ITimeoutService, cheEnvironmentRegistry: CheEnvironmentRegistry, cheNotification: CheNotification, cheWorkspace: CheWorkspace, ideSvc: IdeSvc, workspaceDetailsService: WorkspaceDetailsService) {
+ this.$log = $log;
+ this.$location = $location;
+ this.$mdDialog = $mdDialog;
+ this.$q = $q;
+ this.$route = $route;
this.$rootScope = $rootScope;
+ this.$scope = $scope;
+ this.$timeout = $timeout;
+ this.cheEnvironmentRegistry = cheEnvironmentRegistry;
this.cheNotification = cheNotification;
this.cheWorkspace = cheWorkspace;
- this.$mdDialog = $mdDialog;
- this.$location = $location;
this.ideSvc = ideSvc;
- this.$log = $log;
this.workspaceDetailsService = workspaceDetailsService;
- this.lodash = lodash;
- this.$q = $q;
- this.$timeout = $timeout;
- this.workspaceDetails = {};
- this.copyWorkspaceDetails = {};
- this.machinesViewStatus = {};
- this.namespace = $route.current.params.namespace;
- this.workspaceName = $route.current.params.workspaceName;
- this.workspaceKey = this.namespace + ":" + this.workspaceName;
- this.editMode = false;
- this.showApplyMessage = false;
+ this.tab = Tab;
- this.loading = true;
- this.timeoutPromise;
- $scope.$on('$destroy', () => {
- if (this.timeoutPromise) {
- $timeout.cancel(this.timeoutPromise);
- }
+ cheWorkspace.fetchWorkspaces().then(() => {
+ let workspaces: any[] = cheWorkspace.getWorkspaces();
+ workspaces.forEach((workspace: any) => {
+ this.usedNamesList.push(workspace.config.name);
+ });
});
- if (!this.cheWorkspace.getWorkspaceByName(this.namespace, this.workspaceName)) {
- let promise = this.cheWorkspace.fetchWorkspaceDetails(this.workspaceKey);
- promise.then(() => {
+ (this.$rootScope as any).showIDE = false;
+
+ this.init();
+ }
+
+ init(): void {
+ let routeParams = this.$route.current.params;
+ if (routeParams && routeParams.namespace && routeParams.workspaceName) {
+ this.isCreationFlow = false;
+ this.namespace = routeParams.namespace;
+ this.workspaceName = routeParams.workspaceName;
+
+ this.fetchWorkspaceDetails().then(() => {
+ this.workspaceDetails = this.cheWorkspace.getWorkspaceByName(this.namespace, this.workspaceName);
this.updateWorkspaceData();
- }, (error) => {
- if (error.status === 304) {
- this.updateWorkspaceData();
- } else {
- this.loading = false;
- this.invalidWorkspace = error.statusText;
- }
+ }).finally(() => {
+ this.loading = false;
});
+
+ // search the selected page
+ let page = this.$route.current.params.page;
+ if (!page) {
+ this.$location.path('/workspace/' + this.namespace + '/' + this.workspaceName);
+ } else {
+ let selectedTabIndex = Tab.Settings;
+ switch (page) {
+ case 'info':
+ selectedTabIndex = Tab.Settings;
+ break;
+ case 'projects':
+ selectedTabIndex = 2;
+ break;
+ case 'share':
+ selectedTabIndex = 3;
+ break;
+ default:
+ this.$location.path('/workspace/' + this.namespace + '/' + this.workspaceName);
+ break;
+ }
+ this.$timeout(() => {
+ this.selectedTabIndex = selectedTabIndex;
+ });
+ }
} else {
- this.updateWorkspaceData();
+ this.isCreationFlow = true;
+ this.namespace = '';
+ this.workspaceName = this.generateWorkspaceName();
+ this.copyWorkspaceDetails = {config: {}};
}
+ this.newName = this.workspaceName;
+ }
- this.cheWorkspace.fetchWorkspaces();
+ /**
+ * Fetches the workspace details.
+ *
+ * @returns {Promise}
+ */
+ fetchWorkspaceDetails(): ng.IPromise {
+ let defer = this.$q.defer();
- //search the selected page
- let page = $route.current.params.page;
- if (!page) {
- $location.path('/workspace/' + this.namespace + '/' + this.workspaceName);
+ if (this.cheWorkspace.getWorkspaceByName(this.namespace, this.workspaceName)) {
+ defer.resolve();
} else {
- switch (page) {
- case 'info':
- this.selectedTabIndex = 0;
- break;
- case 'projects':
- this.selectedTabIndex = 2;
- break;
- case 'share':
- this.selectedTabIndex = 3;
- break;
- default:
- $location.path('/workspace/' + this.namespace + '/' + this.workspaceName);
- break;
- }
+ this.cheWorkspace.fetchWorkspaceDetails(this.namespace + ':' + this.workspaceName).then(() => {
+ defer.resolve();
+ }, (error: any) => {
+ if (error.status === 304) {
+ defer.resolve();
+ } else {
+ this.invalidWorkspace = error.statusText;
+ defer.reject(error);
+ }
+ });
}
+ return defer.promise;
}
/**
- * Returns workspace details sections (tabs, example - projects)
- * @returns {*}
+ * Creates copy of workspace config.
*/
- getSections() {
- return this.workspaceDetailsService.getSections();
- }
-
- //Update the workspace data to be displayed.
- updateWorkspaceData() {
- this.workspaceDetails = this.cheWorkspace.getWorkspaceByName(this.namespace, this.workspaceName);
+ updateWorkspaceData(): void {
if (this.loading) {
this.loading = false;
}
@@ -142,72 +183,83 @@ export class WorkspaceDetailsController {
/**
* Returns true if name of workspace is changed.
+ *
* @returns {boolean}
*/
- isNameChanged() {
- if (this.workspaceDetails) {
+ isNameChanged(): boolean {
+ if (this.workspaceDetails && this.workspaceDetails.config) {
return this.workspaceDetails.config.name !== this.newName;
}
return false;
}
/**
- * Updates name of workspace
- * @param isFormValid {boolean} true if workspaceNameForm is valid
+ * Updates name of workspace in config.
+ *
+ * @param isFormValid {boolean}
*/
- updateName(isFormValid) {
+ updateName(isFormValid: boolean): void {
if (isFormValid === false || !this.isNameChanged()) {
return;
}
this.copyWorkspaceDetails.config.name = this.newName;
- this.doUpdateWorkspace();
+
+ if (!this.isCreationFlow) {
+ this.doUpdateWorkspace();
+ }
}
/**
- * Callback which is called after workspace config was changed
- * @returns {Promise}
+ * Returns current status of workspace.
+ *
+ * @returns {String}
*/
- updateWorkspaceConfig() {
- this.editMode = !angular.equals(this.copyWorkspaceDetails.config, this.workspaceDetails.config);
-
- let status = this.getWorkspaceStatus();
- if (status === 'STOPPED' || status === 'STOPPING') {
- this.showApplyMessage = false;
- } else {
- this.showApplyMessage = true;
+ getWorkspaceStatus(): string {
+ if (this.isCreationFlow) {
+ return 'CREATING';
}
- let defer = this.$q.defer();
- defer.resolve();
- return defer.promise;
+ let unknownStatus = 'unknown';
+ let workspace = this.cheWorkspace.getWorkspaceById(this.workspaceId);
+ return workspace ? workspace.status : unknownStatus;
}
/**
- * Updates workspace info.
+ * Returns workspace details sections (tabs, example - projects)
+ *
+ * @returns {*}
*/
- doUpdateWorkspace() {
- delete this.copyWorkspaceDetails.links;
+ getSections(): any {
+ return this.workspaceDetailsService.getSections();
+ }
- let promise = this.cheWorkspace.updateWorkspace(this.workspaceId, this.copyWorkspaceDetails);
- promise.then((data) => {
- this.workspaceName = data.config.name;
- this.updateWorkspaceData();
- this.cheNotification.showInfo('Workspace updated.');
- return this.$location.path('/workspace/' + this.namespace + '/' + this.workspaceName);
- }, (error) => {
- this.loading = false;
- this.cheNotification.showError(error.data.message !== null ? error.data.message : 'Update workspace failed.');
- this.$log.error(error);
- });
+ /**
+ * Callback when environment has been changed.
+ *
+ * @returns {ng.IPromise}
+ */
+ updateWorkspaceConfig(): ng.IPromise {
+ if (!this.isCreationFlow) {
+ this.editMode = !angular.equals(this.copyWorkspaceDetails.config, this.workspaceDetails.config);
+
+ let status = this.getWorkspaceStatus();
+ if (status === 'STOPPED' || status === 'STOPPING') {
+ this.showApplyMessage = false;
+ } else {
+ this.showApplyMessage = true;
+ }
+ }
- return promise;
+ let defer = this.$q.defer();
+ defer.resolve();
+ return defer.promise;
}
/**
* Updates workspace config and restarts workspace if it's necessary
*/
- applyConfigChanges() {
+ applyConfigChanges(): void {
this.editMode = false;
this.showApplyMessage = false;
@@ -248,13 +300,117 @@ export class WorkspaceDetailsController {
/**
* Cancels workspace config changes that weren't stored
*/
- cancelConfigChanges() {
+ cancelConfigChanges(): void {
this.editMode = false;
this.updateWorkspaceData();
}
- //Perform workspace deletion.
- deleteWorkspace(event) {
+ /**
+ * Updates workspace info.
+ *
+ * @returns {ng.IPromise}
+ */
+ doUpdateWorkspace(): ng.IPromise {
+ delete this.copyWorkspaceDetails.links;
+
+ let promise = this.cheWorkspace.updateWorkspace(this.workspaceId, this.copyWorkspaceDetails);
+ promise.then((data: any) => {
+ this.workspaceName = data.config.name;
+ this.workspaceDetails = this.cheWorkspace.getWorkspaceByName(this.namespace, this.workspaceName);
+ this.updateWorkspaceData();
+ this.cheNotification.showInfo('Workspace updated.');
+ return this.$location.path('/workspace/' + this.namespace + '/' + this.workspaceName);
+ }, (error: any) => {
+ this.loading = false;
+ this.cheNotification.showError(error.data.message !== null ? error.data.message : 'Update workspace failed.');
+ this.$log.error(error);
+ });
+
+ return promise;
+ }
+
+ /**
+ * Generates a default workspace name
+ *
+ * @returns {String} name of workspace
+ */
+ generateWorkspaceName(): string {
+ let name,
+ iterations = 100;
+ while (iterations--) {
+ name = 'wksp-' + (('0000' + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4)); // jshint ignore:line
+ if (!this.usedNamesList.includes(name)) {
+ break;
+ }
+ }
+ return name;
+ }
+
+ /**
+ * Submit a new workspace
+ */
+ createWorkspace(): void {
+ let attributes = this.stack ? {stackId: this.stack.id} : {};
+ let creationPromise = this.cheWorkspace.createWorkspaceFromConfig(null, this.copyWorkspaceDetails.config, attributes);
+ this.redirectAfterSubmitWorkspace(creationPromise);
+ }
+
+
+ /**
+ * Handle the redirect for the given promise after workspace has been created
+ *
+ * @param promise {ng.IPromise} used to gather workspace data
+ */
+ redirectAfterSubmitWorkspace(promise: ng.IPromise): void {
+ promise.then((workspaceData: any) => {
+ // update list of workspaces
+ // for new workspace to show in recent workspaces
+ this.updateRecentWorkspace(workspaceData.id);
+
+ let infoMessage = 'Workspace ' + workspaceData.config.name + ' successfully created.';
+ this.cheNotification.showInfo(infoMessage);
+ this.cheWorkspace.fetchWorkspaces().then(() => {
+ this.$location.path('/workspace/' + workspaceData.namespace + '/' + workspaceData.config.name);
+ });
+ }, (error: any) => {
+ let errorMessage = error.data.message ? error.data.message : 'Error during workspace creation.';
+ this.cheNotification.showError(errorMessage);
+ });
+ }
+
+ /**
+ * Emit event to move workspace immediately
+ * to top of the recent workspaces list in left navbar
+ *
+ * @param workspaceId {string}
+ */
+ updateRecentWorkspace(workspaceId: string): void {
+ this.$rootScope.$broadcast('recent-workspace:set', workspaceId);
+ }
+
+ /**
+ * Updates the workspace's environment with data entered by user.
+ *
+ * @param workspace workspace to update
+ */
+ setEnvironment(workspace: any): void {
+ if (!workspace.defaultEnv || !workspace.environments || workspace.environments.length === 0) {
+ return;
+ }
+
+ let environment = workspace.environments[workspace.defaultEnv];
+ if (!environment) {
+ return;
+ }
+
+ let recipeType = environment.recipe.type;
+ let environmentManager = this.cheEnvironmentRegistry.getEnvironmentManager(recipeType);
+ let machinesList = environmentManager.getMachines(environment);
+ workspace.environments[workspace.defaultEnv] = environmentManager.getEnvironment(environment, machinesList);
+ }
+
+ // perform workspace deletion.
+ deleteWorkspace(event: MouseEvent): void {
let confirm = this.$mdDialog.confirm()
.title('Would you like to delete workspace \'' + this.workspaceDetails.config.name + '\'?')
.ariaLabel('Delete workspace')
@@ -274,12 +430,12 @@ export class WorkspaceDetailsController {
});
}
- removeWorkspace() {
+ removeWorkspace(): ng.IPromise {
let promise = this.cheWorkspace.deleteWorkspaceConfig(this.workspaceId);
promise.then(() => {
this.$location.path('/workspaces');
- }, (error) => {
+ }, (error: any) => {
this.cheNotification.showError(error.data.message !== null ? error.data.message : 'Delete workspace failed.');
this.$log.error(error);
});
@@ -287,30 +443,30 @@ export class WorkspaceDetailsController {
return promise;
}
- runWorkspace() {
+ runWorkspace(): void {
delete this.errorMessage;
let promise = this.ideSvc.startIde(this.workspaceDetails);
- promise.then(() => {}, (error) => {
- let errorMessage;
-
- if (!error || !(error.data || error.error)) {
- errorMessage = 'Unable to start this workspace.';
- } else if (error.error) {
- errorMessage = error.error;
- } else if (error.data.errorCode === 10000 && error.data.attributes) {
- let attributes = error.data.attributes;
-
- errorMessage = 'Unable to start this workspace.' +
- ' There are ' + attributes.workspaces_count + ' running workspaces consuming ' +
- attributes.used_ram + attributes.ram_unit + ' RAM.' +
- ' Your current RAM limit is ' + attributes.limit_ram + attributes.ram_unit +
- '. This workspace requires an additional ' +
- attributes.required_ram + attributes.ram_unit + '.' +
- ' You can stop other workspaces to free resources.';
- } else {
- errorMessage = error.data.message;
- }
+ promise.then(() => {}, (error: any) => {
+ let errorMessage;
+
+ if (!error || !(error.data || error.error)) {
+ errorMessage = 'Unable to start this workspace.';
+ } else if (error.error) {
+ errorMessage = error.error;
+ } else if (error.data.errorCode === 10000 && error.data.attributes) {
+ let attributes = error.data.attributes;
+
+ errorMessage = 'Unable to start this workspace.' +
+ ' There are ' + attributes.workspaces_count + ' running workspaces consuming ' +
+ attributes.used_ram + attributes.ram_unit + ' RAM.' +
+ ' Your current RAM limit is ' + attributes.limit_ram + attributes.ram_unit +
+ '. This workspace requires an additional ' +
+ attributes.required_ram + attributes.ram_unit + '.' +
+ ' You can stop other workspaces to free resources.';
+ } else {
+ errorMessage = error.data.message;
+ }
this.cheNotification.showError(errorMessage);
this.$log.error(error);
@@ -319,10 +475,10 @@ export class WorkspaceDetailsController {
});
}
- stopWorkspace() {
+ stopWorkspace(): void {
let promise = this.cheWorkspace.stopWorkspace(this.workspaceId);
- promise.then(() => {}, (error) => {
+ promise.then(() => {}, (error: any) => {
this.cheNotification.showError(error.data.message !== null ? error.data.message : 'Stop workspace failed.');
this.$log.error(error);
});
@@ -331,19 +487,54 @@ export class WorkspaceDetailsController {
/**
* Creates snapshot of workspace
*/
- createSnapshotWorkspace() {
- this.cheWorkspace.createSnapshot(this.workspaceId).then(() => {}, (error) => {
+ createSnapshotWorkspace(): void {
+ this.cheWorkspace.createSnapshot(this.workspaceId).then(() => {}, (error: any) => {
this.cheNotification.showError(error.data.message !== null ? error.data.message : 'Creating snapshot failed.');
this.$log.error(error);
});
}
/**
- * Returns current status of workspace
- * @returns {String}
+ * Register forms
+ *
+ * @param tab {number} tab number
+ * @param form
*/
- getWorkspaceStatus() {
- let workspace = this.cheWorkspace.getWorkspaceById(this.workspaceId);
- return workspace ? workspace.status : 'unknown';
+ setForm(tab: number, form: ng.IFormController): void {
+ this.forms.set(tab, form);
+ }
+
+ /**
+ * Returns false if all forms from specified tabs are valid
+ *
+ * @param tabs {Array} list of tab IDs
+ * @returns {boolean}
+ */
+ checkFormsNotValid(tabs: number[]): boolean {
+ return tabs.some((tab: number) => {
+ let form = this.forms.get(tab);
+ return form && form.$invalid;
+ });
+ }
+
+ /**
+ * Returns true when 'Create' button should be disabled
+ *
+ * @returns {boolean}
+ */
+ isCreateButtonDisabled(): boolean {
+ let tabs = [Tab.Settings, Tab.Runtime];
+
+ return this.checkFormsNotValid(tabs);
+ }
+
+ /**
+ * Returns true when 'Runtime' tab should be disabled
+ *
+ * @returns {boolean}
+ */
+ isRuntimeTabDisabled(): boolean {
+ return this.checkFormsNotValid([Tab.Settings]);
}
}
+
diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-details.html b/dashboard/src/app/workspaces/workspace-details/workspace-details.html
index 43cafa45149..4bddddb3da7 100644
--- a/dashboard/src/app/workspaces/workspace-details/workspace-details.html
+++ b/dashboard/src/app/workspaces/workspace-details/workspace-details.html
@@ -1,54 +1,61 @@
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+ md-selected="workspaceDetailsController.selectedTabIndex"
+ md-center-tabs="">
+
+
Settings
-
+
-
-
+
+
+
Runtime
-
+
+
+
-
+
{{section.title}}
@@ -129,14 +144,12 @@
-
+ workspace-edit-mode-show-message="workspaceDetailsController.showApplyMessage"
+ workspace-edit-mode-on-save="workspaceDetailsController.applyConfigChanges()"
+ workspace-edit-mode-on-cancel="workspaceDetailsController.cancelConfigChanges()">
-
- {{workspaceDetailsCtrl.invalidWorkspace}}
+
+ {{workspaceDetailsController.invalidWorkspace}}
-
-
diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-details.styl b/dashboard/src/app/workspaces/workspace-details/workspace-details.styl
index 55073eb93da..a1e8acde0b8 100644
--- a/dashboard/src/app/workspaces/workspace-details/workspace-details.styl
+++ b/dashboard/src/app/workspaces/workspace-details/workspace-details.styl
@@ -1,29 +1,34 @@
-.workspace-details-description
- color $disabled-color
-
.workspace-details-content
- padding 0 14px
+ md-tab-content
+ padding 0 14px
+
+ .workspace-details-tab-content
+
+ .workspace-details-description
+ color $disabled-color
+
+ button
+ margin 0 30px 0 0
+
+ .workspace-status-indicator .fa-circle
+ font-size 19px
- button
- margin 0 30px 0 0
+ span.workspace-status-text
+ color lighten($che-ide-background-color, 40%) !important
+ margin-bottom 4px
+ margin-left 10px
- .workspace-status-indicator .fa-circle
- font-size 19px
+ .workspace-restart-message
+ color $disabled-color
+ margin-top 15px
- span.workspace-status-text
- color lighten($che-ide-background-color, 40%) !important
- margin-bottom 4px
- margin-left 10px
+ .workspace-details-delete-label label
+ color $che-delete-label-color
- .workspace-delete-label label
- color $che-delete-label-color
+ .che-label-container-content
- .che-label-container-content
- .workspace-details-input
- margin -6px 0
- .workspace-details-action-buttons
- margin-top 20px
+ .workspace-details-input
+ margin -6px 0
- .workspace-details-restart-message
- color $disabled-color
- margin-top 15px
+ .workspace-details-action-buttons
+ margin-top 20px
diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-projects/workspace-details-projects.controller.ts b/dashboard/src/app/workspaces/workspace-details/workspace-projects/workspace-details-projects.controller.ts
index f35f9746525..6bfea1bb7e3 100644
--- a/dashboard/src/app/workspaces/workspace-details/workspace-projects/workspace-details-projects.controller.ts
+++ b/dashboard/src/app/workspaces/workspace-details/workspace-projects/workspace-details-projects.controller.ts
@@ -60,6 +60,7 @@ export class WorkspaceDetailsProjectsCtrl {
updateProjectsData() {
this.workspace = this.cheWorkspace.getWorkspaceByName(this.namespace, this.workspaceName);
this.projects = this.workspace.config.projects;
+ this.workspaceId = this.workspace.id;
}
/**
diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-projects/workspace-details-projects.html b/dashboard/src/app/workspaces/workspace-details/workspace-projects/workspace-details-projects.html
index 494cdccb775..0b57d87ef6a 100644
--- a/dashboard/src/app/workspaces/workspace-details/workspace-projects/workspace-details-projects.html
+++ b/dashboard/src/app/workspaces/workspace-details/workspace-projects/workspace-details-projects.html
@@ -15,7 +15,7 @@
{ return this.recipeScript; }, () => {
+ if (this.isCustomStack) {
+ this.cheStackLibrarySelecter(null);
+ }
+ });
+ $scope.$watch(() => { return this.recipeUrl; }, () => {
+ if (this.isCustomStack) {
+ this.cheStackLibrarySelecter(null);
+ }
+ });
+ $scope.$watch(() => { return this.recipeFormat; }, () => {
+ if (this.isCustomStack) {
+ this.cheStackLibrarySelecter(null);
+ }
+ });
+ }
+
+ /**
+ * Callback when tab has been change.
+ *
+ * @param tabName {string} the select tab name
+ */
+ setStackTab(tabName: string): void {
+ if (tabName === 'custom-stack') {
+ this.cheStackLibrarySelecter(null);
+ this.isCustomStack = true;
+ }
+ }
+
+ /**
+ * Callback when stack has been set.
+ *
+ * @param stack {object} the selected stack
+ */
+ cheStackLibrarySelecter(stack: any): void {
+ if (stack) {
+ this.isCustomStack = false;
+ this.recipeUrl = null;
+ }
+ this.stack = stack;
+
+ let source = this.getSource();
+ let config = this.buildWorkspaceConfig(source);
+
+ if (!config.defaultEnv || (!this.stack && !this.recipeFormat)) {
+ return;
+ }
+
+ this.workspaceStackOnChange({config: config});
+ }
+
+ /**
+ * Builds workspace config.
+ *
+ * @param source
+ * @returns {config}
+ */
+ buildWorkspaceConfig(source: any): any {
+ let stackWorkspaceConfig;
+ if (this.stack) {
+ stackWorkspaceConfig = this.stack.workspaceConfig;
+ } else if (!this.stack && source && source.format === 'compose' && source.content) {
+ let machines = this.composeEnvironmentManager.getMachines({recipe: source}),
+ environment = this.composeEnvironmentManager.getEnvironment({recipe: source}, machines);
+ stackWorkspaceConfig = {
+ defaultEnv: this.workspaceName,
+ environments: {
+ [this.workspaceName]: environment
+ }
+ };
+ }
+
+
+ return this.cheWorkspace.formWorkspaceConfig(stackWorkspaceConfig, this.workspaceName, source, DEFAULT_WORKSPACE_RAM);
+ }
+
+ /**
+ * Returns stack source.
+ *
+ * @returns {object}
+ */
+ getSource(): any {
+ let source: any = {};
+ source.type = 'dockerfile';
+ // user provides recipe URL or recipe's content:
+ if (this.isCustomStack) {
+ this.stack = null;
+ source.type = 'environment';
+ source.format = this.recipeFormat;
+ if (this.recipeUrl && this.recipeUrl.length > 0) {
+ source.location = this.recipeUrl;
+ } else {
+ source.content = this.recipeScript;
+ }
+ } else if (this.stack) {
+ // check predefined recipe location
+ if (this.stack && this.stack.source && this.stack.source.type === 'location') {
+ this.recipeUrl = this.stack.source.origin;
+ source.location = this.recipeUrl;
+ } else {
+ source = this.getSourceFromStack(this.stack);
+ }
+ }
+ return source;
+ }
+
+ /**
+ * Detects machine source from pointed stack.
+ *
+ * @param stack {object} to retrieve described source
+ * @returns {source} machine source config
+ */
+ getSourceFromStack(stack: any): any {
+ let source: any = {};
+ source.type = 'dockerfile';
+
+ switch (stack.source.type.toLowerCase()) {
+ case 'image':
+ source.content = 'FROM ' + stack.source.origin;
+ break;
+ case 'dockerfile':
+ source.content = stack.source.origin;
+ break;
+ default:
+ throw 'Not implemented';
+ }
+
+ return source;
+ }
+}
diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-stacks/workspace-stacks.directive.ts b/dashboard/src/app/workspaces/workspace-details/workspace-stacks/workspace-stacks.directive.ts
new file mode 100644
index 00000000000..373d8c86358
--- /dev/null
+++ b/dashboard/src/app/workspaces/workspace-details/workspace-stacks/workspace-stacks.directive.ts
@@ -0,0 +1,44 @@
+/*
+ * 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';
+
+/**
+ * Defines a directive for displaying stacks tab.
+ * @author Oleksii Kurinnyi
+ */
+export class WorkspaceStacks {
+ restrict: string = 'E';
+ templateUrl: string = 'app/workspaces/workspace-details/workspace-stacks/workspace-stacks.html';
+ replace: boolean = false;
+
+ controller: string = 'WorkspaceStacksController';
+ controllerAs: string = 'workspaceStacksController';
+
+ bindToController: boolean = true;
+
+ scope: {
+ [propName: string]: string
+ };
+
+ /**
+ * Default constructor that is using resource
+ * @ngInject for Dependency injection
+ */
+ constructor() {
+ // scope values
+ this.scope = {
+ workspaceName: '=',
+ workspaceStackOnChange: '&'
+ };
+ }
+
+}
+
diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-stacks/workspace-stacks.html b/dashboard/src/app/workspaces/workspace-details/workspace-stacks/workspace-stacks.html
new file mode 100644
index 00000000000..b4b66292255
--- /dev/null
+++ b/dashboard/src/app/workspaces/workspace-details/workspace-stacks/workspace-stacks.html
@@ -0,0 +1,6 @@
+
diff --git a/dashboard/src/app/workspaces/workspaces-config.ts b/dashboard/src/app/workspaces/workspaces-config.ts
index 57725f404b2..a15989122da 100644
--- a/dashboard/src/app/workspaces/workspaces-config.ts
+++ b/dashboard/src/app/workspaces/workspaces-config.ts
@@ -14,36 +14,37 @@ import {ListWorkspacesCtrl} from './list-workspaces/list-workspaces.controller';
import {CheWorkspaceItem} from './list-workspaces/workspace-item/workspace-item.directive';
import {CheWorkspaceStatus} from './list-workspaces/workspace-status-action/workspace-status.directive';
import {WorkspaceStatusController} from './list-workspaces/workspace-status-action/workspace-status.controller';
-import {CreateWorkspaceController} from './create-workspace/create-workspace.controller';
+import {WorkspaceDetailsController} from './workspace-details/workspace-details.controller';
+import {WorkspaceStacksController} from './workspace-details/workspace-stacks/workspace-stacks.controller';
+import {WorkspaceStacks} from './workspace-details/workspace-stacks/workspace-stacks.directive';
import {UsageChart} from './list-workspaces/workspace-item/usage-chart.directive';
import {WorkspaceItemCtrl} from './list-workspaces/workspace-item/workspace-item.controller';
import {WorkspaceEditModeOverlay} from './workspace-edit-mode/workspace-edit-mode-overlay.directive';
import {WorkspaceEditModeToolbarButton} from './workspace-edit-mode/workspace-edit-mode-toolbar-button.directive';
-import {WorkspaceDetailsController} from './workspace-details/workspace-details.controller';
import {WorkspaceDetailsProjectsCtrl} from './workspace-details/workspace-projects/workspace-details-projects.controller';
import {WorkspaceDetailsService} from './workspace-details/workspace-details.service';
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 {ReadyToGoStacksController} 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';
-import {WorkspaceRecipeController} from './create-workspace/select-stack/recipe/workspace-recipe.controller';
-import {WorkspaceRecipe} from './create-workspace/select-stack/recipe/workspace-recipe.directive';
-import {CheStackLibrarySelecter} from './create-workspace/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.directive';
-import {CreateProjectStackLibraryController} from './create-workspace/select-stack/stack-library/create-project-stack-library.controller';
-import {CreateProjectStackLibrary} from './create-workspace/select-stack/stack-library/create-project-stack-library.directive';
-import {WorkspaceSelectStackController} from './create-workspace/select-stack/workspace-select-stack.controller';
-import {WorkspaceSelectStack} from './create-workspace/select-stack/workspace-select-stack.directive';
+import {ReadyToGoStacksController} from './workspace-details/select-stack/ready-to-go-stacks/ready-to-go-stacks.controller';
+import {ReadyToGoStacks} from './workspace-details/select-stack/ready-to-go-stacks/ready-to-go-stacks.directive';
+import {WorkspaceRecipeController} from './workspace-details/select-stack/recipe/workspace-recipe.controller';
+import {WorkspaceRecipe} from './workspace-details/select-stack/recipe/workspace-recipe.directive';
+import {CheStackLibrarySelecter} from './workspace-details/select-stack/stack-library/stack-library-selecter/che-stack-library-selecter.directive';
+import {CreateProjectStackLibraryController} from './workspace-details/select-stack/stack-library/create-project-stack-library.controller';
+import {CreateProjectStackLibrary} from './workspace-details/select-stack/stack-library/create-project-stack-library.directive';
+import {WorkspaceSelectStackController} from './workspace-details/select-stack/workspace-select-stack.controller';
+import {WorkspaceSelectStack} from './workspace-details/select-stack/workspace-select-stack.directive';
import {CheWorkspaceRamAllocationSliderController} from './workspace-ram-slider/che-workspace-ram-allocation-slider.controller';
import {CheWorkspaceRamAllocationSlider} from './workspace-ram-slider/che-workspace-ram-allocation-slider.directive';
import {WorkspaceStatus} from './workspace-status/workspace-status.directive';
import {WorkspaceStatusIndicator} from './workspace-status/workspace-status-indicator.directive';
-import {CheStackLibraryFilterController} from './create-workspace/select-stack/stack-library/stack-library-filter/che-stack-library-filter.controller';
-import {CheStackLibraryFilter} from './create-workspace/select-stack/stack-library/stack-library-filter/che-stack-library-filter.directive';
-import {CreateProjectStackLibrarySelectedStackFilter} from './create-workspace/select-stack/stack-library/create-project-stack-library-selected-stack.filter';
+import {CheStackLibraryFilterController} from './workspace-details/select-stack/stack-library/stack-library-filter/che-stack-library-filter.controller';
+import {CheStackLibraryFilter} from './workspace-details/select-stack/stack-library/stack-library-filter/che-stack-library-filter.directive';
+import {CreateProjectStackLibrarySelectedStackFilter} from './workspace-details/select-stack/stack-library/create-project-stack-library-selected-stack.filter';
import {WorkspaceEnvironmentsController} from './workspace-details/environments/environments.controller';
import {WorkspaceEnvironments} from './workspace-details/environments/environments.directive';
@@ -78,7 +79,9 @@ export class WorkspacesConfig {
new CreateProjectStackLibrarySelectedStackFilter(register);
register.controller('ListWorkspacesCtrl', ListWorkspacesCtrl);
- register.controller('CreateWorkspaceController', CreateWorkspaceController);
+ register.controller('WorkspaceDetailsController', WorkspaceDetailsController);
+ register.controller('WorkspaceStacksController', WorkspaceStacksController);
+ register.directive('workspaceStacks', WorkspaceStacks);
register.directive('cheWorkspaceItem', CheWorkspaceItem);
register.controller('WorkspaceItemCtrl', WorkspaceItemCtrl);
@@ -90,8 +93,6 @@ export class WorkspacesConfig {
register.directive('workspaceEditModeOverlay', WorkspaceEditModeOverlay);
register.directive('workspaceEditModeToolbarButton', WorkspaceEditModeToolbarButton);
- register.controller('WorkspaceDetailsController', WorkspaceDetailsController);
-
register.controller('WorkspaceDetailsProjectsCtrl', WorkspaceDetailsProjectsCtrl);
register.directive('workspaceDetailsProjects', WorkspaceDetailsProjects);
register.service('workspaceDetailsService', WorkspaceDetailsService);
@@ -146,7 +147,7 @@ export class WorkspacesConfig {
title: (params) => { return params.workspaceName;},
templateUrl: 'app/workspaces/workspace-details/workspace-details.html',
controller: 'WorkspaceDetailsController',
- controllerAs: 'workspaceDetailsCtrl'
+ controllerAs: 'workspaceDetailsController'
};
// config routes
@@ -160,11 +161,11 @@ export class WorkspacesConfig {
.accessWhen('/workspace/:namespace/:workspaceName', locationProvider)
.accessWhen('/workspace/:namespace/:workspaceName/:page', locationProvider)
.accessWhen('/create-workspace', {
- title: 'New Workspace',
- templateUrl: 'app/workspaces/create-workspace/create-workspace.html',
- controller: 'CreateWorkspaceController',
- controllerAs: 'createWorkspaceCtrl'
- });
+ title: 'New Workspace',
+ templateUrl: 'app/workspaces/workspace-details/workspace-details.html',
+ controller: 'WorkspaceDetailsController',
+ controllerAs: 'workspaceDetailsController'
+ });
});
}
}
diff --git a/dashboard/src/components/api/environment/compose-environment-manager.ts b/dashboard/src/components/api/environment/compose-environment-manager.ts
index 76f3fa808f4..008228d9618 100644
--- a/dashboard/src/components/api/environment/compose-environment-manager.ts
+++ b/dashboard/src/components/api/environment/compose-environment-manager.ts
@@ -17,28 +17,28 @@ import {EnvironmentManager} from './environment-manager';
*
* Format sample and specific description:
*
- *services:
- * devmachine:
- * image: codenvy/ubuntu_jdk8
- * depends_on:
- * - anotherMachine
- * mem_limit: 2147483648
- * anotherMachine:
- * image: codenvy/ubuntu_jdk8
- * depends_on:
- * - thirdMachine
- * mem_limit: 1073741824
- * thirdMachine:
- * image: codenvy/ubuntu_jdk8
- * mem_limit: 512741824
- * labels:
- * com.example.description: "Accounting webapp"
- * com.example.department: "Finance"
- * com.example.label-with-empty-value: ""
- * environment:
- * SOME_ENV: development
- * SHOW: 'true'
- * SESSION_SECRET:
+ * services:
+ * devmachine:
+ * image: codenvy/ubuntu_jdk8
+ * depends_on:
+ * - anotherMachine
+ * mem_limit: 2147483648
+ * anotherMachine:
+ * image: codenvy/ubuntu_jdk8
+ * depends_on:
+ * - thirdMachine
+ * mem_limit: 1073741824
+ * thirdMachine:
+ * image: codenvy/ubuntu_jdk8
+ * mem_limit: 512741824
+ * labels:
+ * com.example.description: "Accounting webapp"
+ * com.example.department: "Finance"
+ * com.example.label-with-empty-value: ""
+ * environment:
+ * SOME_ENV: development
+ * SHOW: 'true'
+ * SESSION_SECRET:
*
*
*
@@ -50,16 +50,22 @@ import {EnvironmentManager} from './environment-manager';
* @author Ann Shumilova
*/
+interface IComposeRecipe {
+ services: {
+ [machineName: string]: any
+ };
+}
export class ComposeEnvironmentManager extends EnvironmentManager {
+ $log: ng.ILogService;
- constructor($log) {
+ constructor($log: ng.ILogService) {
super();
this.$log = $log;
}
- get editorMode() {
+ get editorMode(): string {
return 'text/x-yaml';
}
@@ -67,18 +73,41 @@ export class ComposeEnvironmentManager extends EnvironmentManager {
* Parses recipe content
*
* @param content {string} recipe content
- * @returns {object} recipe object
+ * @returns {IComposeRecipe} recipe object
*/
- _parseRecipe(content) {
- let recipe = {};
+ _parseRecipe(content: string): IComposeRecipe {
+ let recipe = null;
try {
- recipe = jsyaml.load(content);
+ recipe = this._validate(jsyaml.load(content));
} catch (e) {
this.$log.error(e);
}
return recipe;
}
+ /**
+ * Validate given recipe
+ *
+ * @param {IComposeRecipe} recipe
+ * @returns {IComposeRecipe | *}
+ * @private
+ */
+ _validate(recipe: IComposeRecipe): IComposeRecipe | void {
+ if (!recipe.services) {
+ throw new Error('Recipe should contain services section.');
+ }
+
+ let services: any = Object.keys(recipe.services);
+ services.forEach((serviceName: string) => {
+ let serviceFields: any = Object.keys(recipe.services[serviceName] || {});
+ if (!serviceFields || (serviceFields.includes('build') === false && serviceFields.includes('image') === false)) {
+ throw new Error('Service \'' + serviceName + '\' should contain \'build\' or \'image\' section.');
+ }
+ });
+
+ return recipe;
+ }
+
/**
* Dumps recipe object
*
@@ -86,7 +115,7 @@ export class ComposeEnvironmentManager extends EnvironmentManager {
* @returns {string} recipe content
*/
- _stringifyRecipe(recipe) {
+ _stringifyRecipe(recipe: IComposeRecipe): string {
let content = '';
try {
content = jsyaml.dump(recipe);
@@ -103,20 +132,27 @@ export class ComposeEnvironmentManager extends EnvironmentManager {
* @param environment environment's configuration
* @returns {Array} list of machines defined in environment
*/
- getMachines(environment) {
- let recipe = null,
- machines = [],
- machineNames;
+ getMachines(environment: any): any[] {
+ let recipe: any = null,
+ machines: any[] = [],
+ machineNames: string[] = [];
if (environment.recipe.content) {
recipe = this._parseRecipe(environment.recipe.content);
- machineNames = Object.keys(recipe.services);
- } else {
+ if (recipe) {
+ machineNames = Object.keys(recipe.services);
+ } else if (environment.machines) {
+ machineNames = Object.keys(environment.machines);
+ }
+ } else if (environment.recipe.location) {
machineNames = Object.keys(environment.machines);
}
- machineNames.forEach((machineName) => {
- let machine = angular.copy(environment.machines[machineName]) || {};
+ machineNames.forEach((machineName: string) => {
+ let machine: any = {};
+ if (environment.machines && environment.machines[machineName]) {
+ machine = angular.copy(environment.machines[machineName]);
+ }
machine.name = machineName;
machine.recipe = recipe ? recipe.services[machineName] : recipe;
@@ -138,24 +174,30 @@ export class ComposeEnvironmentManager extends EnvironmentManager {
* @param machines the list of machines
* @returns environment's configuration
*/
- getEnvironment(environment, machines) {
+ getEnvironment(environment: any, machines: any[]): any {
let newEnvironment = super.getEnvironment(environment, machines);
if (newEnvironment.recipe.content) {
- let recipe = this._parseRecipe(newEnvironment.recipe.content);
-
- machines.forEach((machine) => {
- let machineName = machine.name;
- if (machine.recipe.environment && Object.keys(machine.recipe.environment).length) {
- recipe.services[machineName].environment = angular.copy(machine.recipe.environment);
- } else {
- delete recipe.services[machineName].environment;
+ let recipe: IComposeRecipe = this._parseRecipe(newEnvironment.recipe.content);
+
+ if (recipe) {
+ machines.forEach((machine: any) => {
+ let machineName = machine.name;
+ if (!recipe.services[machineName]) {
+ return;
+ }
+ if (machine.recipe.environment && Object.keys(machine.recipe.environment).length) {
+ recipe.services[machineName].environment = angular.copy(machine.recipe.environment);
+ } else {
+ delete recipe.services[machineName].environment;
+ }
+ });
+
+ try {
+ newEnvironment.recipe.content = this._stringifyRecipe(recipe);
+ } catch (e) {
+ this.$log.error('Cannot retrieve environment\'s recipe, error: ', e);
}
- });
- try {
- newEnvironment.recipe.content = this._stringifyRecipe(recipe);
- } catch (e) {
- this.$log.error('Cannot retrieve environment\'s recipe, error: ', e);
}
}
@@ -168,7 +210,7 @@ export class ComposeEnvironmentManager extends EnvironmentManager {
* @param machine {object}
* @returns {*}
*/
- getSource(machine) {
+ getSource(machine: any): any {
if (!machine.recipe) {
return null;
}
@@ -186,7 +228,7 @@ export class ComposeEnvironmentManager extends EnvironmentManager {
* @param machine {object}
* @returns {boolean}
*/
- canEditEnvVariables(machine) {
+ canEditEnvVariables(machine: any): boolean {
return !!machine.recipe;
}
@@ -196,7 +238,7 @@ export class ComposeEnvironmentManager extends EnvironmentManager {
* @param machine {object}
* @returns {*}
*/
- getEnvVariables(machine) {
+ getEnvVariables(machine: any): any {
if (!machine.recipe) {
return null;
}
@@ -210,7 +252,7 @@ export class ComposeEnvironmentManager extends EnvironmentManager {
* @param machine {object}
* @param envVariables {object}
*/
- setEnvVariables(machine, envVariables) {
+ setEnvVariables(machine: any, envVariables: any): void {
if (!machine.recipe) {
return;
}
@@ -228,7 +270,7 @@ export class ComposeEnvironmentManager extends EnvironmentManager {
* @param machine {object}
* @returns {boolean}
*/
- canRenameMachine(machine) {
+ canRenameMachine(machine: any): boolean {
return !!machine.recipe;
}
@@ -240,12 +282,12 @@ export class ComposeEnvironmentManager extends EnvironmentManager {
* @param newName {string}
* @returns {*} new environment
*/
- renameMachine(environment, oldName, newName) {
+ renameMachine(environment: any, oldName: string, newName: string): any {
try {
- let recipe = this._parseRecipe(environment.recipe.content);
+ let recipe: IComposeRecipe = this._parseRecipe(environment.recipe.content);
// fix relations to other machines in recipe
- Object.keys(recipe.services).forEach((serviceName) => {
+ Object.keys(recipe.services).forEach((serviceName: any) => {
if (serviceName === oldName) {
return;
}
@@ -297,7 +339,7 @@ export class ComposeEnvironmentManager extends EnvironmentManager {
* @param machine {object}
* @returns {boolean}
*/
- canDeleteMachine(machine) {
+ canDeleteMachine(machine: any): boolean {
return !!machine.recipe;
}
@@ -308,12 +350,12 @@ export class ComposeEnvironmentManager extends EnvironmentManager {
* @param name {string} name of machine
* @returns {*} new environment
*/
- deleteMachine(environment, name) {
+ deleteMachine(environment: any, name: string): any {
try {
- let recipe = this._parseRecipe(environment.recipe.content);
+ let recipe: IComposeRecipe = this._parseRecipe(environment.recipe.content);
// fix relations to other machines in recipe
- Object.keys(recipe.services).forEach((serviceName) => {
+ Object.keys(recipe.services).forEach((serviceName: any) => {
if (serviceName === name) {
return;
}
diff --git a/dashboard/src/components/api/environment/docker-file-environment-manager.ts b/dashboard/src/components/api/environment/docker-file-environment-manager.ts
index 8b1ee7ed704..6720529cd45 100644
--- a/dashboard/src/components/api/environment/docker-file-environment-manager.ts
+++ b/dashboard/src/components/api/environment/docker-file-environment-manager.ts
@@ -31,19 +31,22 @@ import {DockerfileParser} from './docker-file-parser';
*
* @author Ann Shumilova
*/
+
+const ENV_INSTRUCTION: string = 'ENV';
+
export class DockerFileEnvironmentManager extends EnvironmentManager {
+ $log: ng.ILogService;
+ parser: DockerfileParser;
- constructor($log) {
+ constructor($log: ng.ILogService) {
super();
this.$log = $log;
- this.ENV_INSTRUCTION = 'ENV';
-
this.parser = new DockerfileParser();
}
- get editorMode() {
+ get editorMode(): string {
return 'text/x-dockerfile';
}
@@ -54,8 +57,8 @@ export class DockerFileEnvironmentManager extends EnvironmentManager {
* @returns {Array} a list of instructions and arguments
* @private
*/
- _parseRecipe(content) {
- let recipe = [];
+ _parseRecipe(content: string): any[] {
+ let recipe: any[] = null;
try {
recipe = this.parser.parse(content);
} catch (e) {
@@ -67,11 +70,11 @@ export class DockerFileEnvironmentManager extends EnvironmentManager {
/**
* Dumps a list of instructions and arguments into dockerfile
*
- * @param instructions {array} array of objects
+ * @param instructions {Array} array of objects
* @returns {string} dockerfile
* @private
*/
- _stringifyRecipe(instructions) {
+ _stringifyRecipe(instructions: any[]): string {
let content = '';
try {
@@ -90,7 +93,7 @@ export class DockerFileEnvironmentManager extends EnvironmentManager {
* @param machines the list of machines
* @returns environment's configuration
*/
- getEnvironment(environment, machines) {
+ getEnvironment(environment: any, machines: any): any {
let newEnvironment = super.getEnvironment(environment, machines);
// machines should contain one machine only
@@ -111,7 +114,7 @@ export class DockerFileEnvironmentManager extends EnvironmentManager {
* @param environment environment's configuration
* @returns {Array} list of machines defined in environment
*/
- getMachines(environment) {
+ getMachines(environment: any): any[] {
let recipe = null,
machines = [];
@@ -119,7 +122,7 @@ export class DockerFileEnvironmentManager extends EnvironmentManager {
recipe = this._parseRecipe(environment.recipe.content);
}
- Object.keys(environment.machines).forEach((machineName) => {
+ Object.keys(environment.machines).forEach((machineName: string) => {
let machine = angular.copy(environment.machines[machineName]);
machine.name = machineName;
machine.recipe = recipe;
@@ -136,12 +139,12 @@ export class DockerFileEnvironmentManager extends EnvironmentManager {
* @param machine
* @returns {*}
*/
- getSource(machine) {
+ getSource(machine: any): any {
if (!machine.recipe) {
return null;
}
- let from = machine.recipe.find((line) => {
+ let from = machine.recipe.find((line: any) => {
return line.instruction === 'FROM';
});
@@ -154,7 +157,7 @@ export class DockerFileEnvironmentManager extends EnvironmentManager {
* @param machine {object}
* @returns {boolean}
*/
- canEditEnvVariables(machine) {
+ canEditEnvVariables(machine: any): boolean {
return !!machine.recipe;
}
@@ -164,18 +167,18 @@ export class DockerFileEnvironmentManager extends EnvironmentManager {
* @param machine {object}
* @returns {*}
*/
- getEnvVariables(machine) {
+ getEnvVariables(machine: any): any {
if (!machine.recipe) {
return null;
}
let envVariables = {};
- let envList = machine.recipe.filter((line) => {
- return line.instruction === this.ENV_INSTRUCTION;
+ let envList = machine.recipe.filter((line: any) => {
+ return line.instruction === ENV_INSTRUCTION;
}) || [];
- envList.forEach((line) => {
+ envList.forEach((line: any) => {
envVariables[line.argument[0]] = line.argument[1];
});
@@ -188,7 +191,7 @@ export class DockerFileEnvironmentManager extends EnvironmentManager {
* @param machine {object}
* @param envVariables {object}
*/
- setEnvVariables(machine, envVariables) {
+ setEnvVariables(machine: any, envVariables: any): void {
if (!machine.recipe) {
return;
}
@@ -196,19 +199,19 @@ export class DockerFileEnvironmentManager extends EnvironmentManager {
let newRecipe = [];
// new recipe without any 'ENV' instruction
- newRecipe = machine.recipe.filter((line) => {
- return line.instruction !== this.ENV_INSTRUCTION;
+ newRecipe = machine.recipe.filter((line: any) => {
+ return line.instruction !== ENV_INSTRUCTION;
});
// add environments if any
if (Object.keys(envVariables).length) {
- Object.keys(envVariables).forEach((name) => {
+ Object.keys(envVariables).forEach((name: string) => {
let line = {
- instruction: this.ENV_INSTRUCTION,
+ instruction: ENV_INSTRUCTION,
argument: [name, envVariables[name]]
};
- newRecipe.splice(1,0,line);
- })
+ newRecipe.splice(1, 0, line);
+ });
}
machine.recipe = newRecipe;
diff --git a/dashboard/src/components/api/environment/docker-file-parser.spec.ts b/dashboard/src/components/api/environment/docker-file-parser.spec.ts
index 164dd75b63c..68fb6b16359 100644
--- a/dashboard/src/components/api/environment/docker-file-parser.spec.ts
+++ b/dashboard/src/components/api/environment/docker-file-parser.spec.ts
@@ -32,7 +32,7 @@ describe('Simper dockerfile parser', () => {
let result = parser._parseArgument(instruction, argument);
let expectedResult = [{
- instruction:'ENV',
+ instruction: 'ENV',
argument: ['name', 'environment variable value']
}];
expect(result).toEqual(expectedResult);
@@ -45,13 +45,13 @@ describe('Simper dockerfile parser', () => {
let result = parser._parseArgument(instruction, argument);
let expectedResult = [{
- instruction:'ENV',
+ instruction: 'ENV',
argument: ['myName', 'John Doe']
- },{
- instruction:'ENV',
+ }, {
+ instruction: 'ENV',
argument: ['myDog', 'Rex The Dog']
}, {
- instruction:'ENV',
+ instruction: 'ENV',
argument: ['myCat', 'fluffy']
}];
expect(result).toEqual(expectedResult);
@@ -60,23 +60,22 @@ describe('Simper dockerfile parser', () => {
it('should parse a dockerfile', () => {
let dockerfile = 'FROM codenvy/ubuntu_jdk8ENV'
- +'\nENV myCat fluffy'
- +'\nENV myDog Rex The Dog'
- +'\nENV myName John Doe';
+ + '\n#ENV myCat fluffy'
+ + '\nENV myDog Rex The Dog'
+ + '\nENV myName John Doe';
let result = parser.parse(dockerfile);
let expectedResult = [{
- instruction:'FROM',
+ instruction: 'FROM',
argument: 'codenvy/ubuntu_jdk8ENV'
- },{
- instruction:'ENV',
- argument: ['myCat', 'fluffy']
- },{
- instruction:'ENV',
+ }, {
+ comment: '#ENV myCat fluffy'
+ }, {
+ instruction: 'ENV',
argument: ['myDog', 'Rex The Dog']
- },{
- instruction:'ENV',
+ }, {
+ instruction: 'ENV',
argument: ['myName', 'John Doe']
}];
expect(result).toEqual(expectedResult);
@@ -84,25 +83,24 @@ describe('Simper dockerfile parser', () => {
it('should stringify an object into a dockerfile', () => {
let instructions = [{
- instruction:'FROM',
+ instruction: 'FROM',
argument: 'codenvy/ubuntu_jdk8ENV'
- },{
- instruction:'ENV',
- argument: ['myCat', 'fluffy']
- },{
- instruction:'ENV',
+ }, {
+ comment: '#ENV myCat fluffy'
+ }, {
+ instruction: 'ENV',
argument: ['myDog', 'Rex The Dog']
- },{
- instruction:'ENV',
+ }, {
+ instruction: 'ENV',
argument: ['myName', 'John Doe']
}];
let result = parser.dump(instructions);
let expectedResult = 'FROM codenvy/ubuntu_jdk8ENV'
- +'\nENV myCat fluffy'
- +'\nENV myDog Rex The Dog'
- +'\nENV myName John Doe';
+ + '\n#ENV myCat fluffy'
+ + '\nENV myDog Rex The Dog'
+ + '\nENV myName John Doe';
expect(result.trim()).toEqual(expectedResult);
});
diff --git a/dashboard/src/components/api/environment/docker-file-parser.ts b/dashboard/src/components/api/environment/docker-file-parser.ts
index 73fb0db933e..7f237dc4ac8 100644
--- a/dashboard/src/components/api/environment/docker-file-parser.ts
+++ b/dashboard/src/components/api/environment/docker-file-parser.ts
@@ -14,11 +14,28 @@
* Simple parser and simple dumper of dockerfiles.
* @author Oleksii Kurinnyi
*/
+
+interface IRecipeLine {
+ instruction?: string;
+ argument?: string | string[];
+ comment?: string;
+}
+
export class DockerfileParser {
+ fromRE: RegExp;
+ backslashLineBreakRE: RegExp;
+ lineBreakRE: RegExp;
+ commentLineRE: RegExp;
+ instructionRE: RegExp;
+ envVariablesRE: RegExp;
+ quotesRE: RegExp;
+ backslashSpaceRE: RegExp;
constructor() {
+ this.fromRE = /^FROM\s+\w+/m;
this.backslashLineBreakRE = /\\\r?\n(\s+)?/;
this.lineBreakRE = /\r?\n/;
+ this.commentLineRE = /^#/;
this.instructionRE = /(\w+)\s+?(.+)/;
this.envVariablesRE = /(?:^|(?:\s+))([^\s=]+?)=([^=]+?)(?:(?=\s+\w+=)|$)/g;
// | | | |
@@ -33,28 +50,40 @@ export class DockerfileParser {
/**
* Parses a dockerfile into array of pairs of instructions and arguments
*
- * @param content
- * @returns {Array}
+ * @param {string} content recipe content
+ * @returns {IRecipeLine[]}
*/
- parse(content) {
+ parse(content: string): IRecipeLine[] {
+ if (!this.fromRE.test(content)) {
+ throw new TypeError('Dockerfile should start with \'FROM\' instruction. Cannot parse this recipe.');
+ }
+
// join multiline instructions
content = this._joinMultilineInstructions(content);
// split dockerfile into separate instruction lines
- let instructionLines = content.split(this.lineBreakRE);
+ let instructionLines: string[] = content.split(this.lineBreakRE);
// split instruction line into instruction and argument
- let instructions = [];
- instructionLines.forEach((line) => {
+ let instructions: IRecipeLine[] = [];
+ instructionLines.forEach((line: string) => {
+ line = line.trim();
+
+ // check for comment line
+ if (this.commentLineRE.test(line)) {
+ instructions.push({comment: line});
+ return;
+ }
+
let m = line.match(this.instructionRE);
if (m) {
let instruction = m[1],
argument = m[2];
// parse argument
- let results = this._parseArgument(instruction, argument);
+ let results: IRecipeLine[] = this._parseArgument(instruction, argument);
- results.forEach((result) => {
+ results.forEach((result: IRecipeLine) => {
instructions.push(result);
});
}
@@ -67,10 +96,10 @@ export class DockerfileParser {
* Remove line breaks from lines which end with backslash
*
* @param content {string}
- * @returns {*}
+ * @returns {string}
* @private
*/
- _joinMultilineInstructions(content) {
+ _joinMultilineInstructions(content: string): string {
return content.replace(this.backslashLineBreakRE, '');
}
@@ -79,20 +108,20 @@ export class DockerfileParser {
*
* @param instruction {string}
* @param argumentStr {string}
- * @returns {Array}
+ * @returns {IRecipeLine[]}
* @private
*/
- _parseArgument(instruction, argumentStr) {
- let results = [];
+ _parseArgument(instruction: string, argumentStr: string): IRecipeLine[] {
+ let results: IRecipeLine[] = [];
switch (instruction) {
case 'ENV':
if (argumentStr.includes('=')) {
// this argument string contains one or more environment variables
let match;
- while(match = this.envVariablesRE.exec(argumentStr)) {
- let name = match[1],
- value = match[2];
+ while (match = this.envVariablesRE.exec(argumentStr)) {
+ let name: string = match[1],
+ value: string = match[2];
if (this.quotesRE.test(value)) {
value = value.replace(this.quotesRE, '');
}
@@ -110,7 +139,7 @@ export class DockerfileParser {
let firstSpaceIndex = argumentStr.indexOf(' ');
results.push({
instruction: instruction,
- argument: [argumentStr.slice(0, firstSpaceIndex), argumentStr.slice(firstSpaceIndex+1)]
+ argument: [argumentStr.slice(0, firstSpaceIndex), argumentStr.slice(firstSpaceIndex + 1)]
});
}
break;
@@ -125,16 +154,20 @@ export class DockerfileParser {
}
/**
- * Dumps an array into a dockerfile
+ * Dumps an array of instructions into a dockerfile
*
- * @param instructions {array}
+ * @param instructions {IRecipeLine[]}
* @returns {string}
*/
- dump(instructions) {
+ dump(instructions: IRecipeLine[]): string {
let content = '';
- instructions.forEach((line) => {
- content += line.instruction + ' ' + this._stringifyArgument(line.instruction, line.argument) + '\n';
+ instructions.forEach((line: IRecipeLine) => {
+ if (line.comment) {
+ content += line.comment + '\n';
+ } else {
+ content += line.instruction + ' ' + this._stringifyArgument(line) + '\n';
+ }
});
return content;
@@ -143,17 +176,16 @@ export class DockerfileParser {
/**
* Dumps argument object depending on instruction.
*
- * @param instruction {string}
- * @param argument {*|string}
+ * @param line {IRecipeLine}
* @returns {string}
* @private
*/
- _stringifyArgument(instruction, argument) {
- switch (instruction) {
+ _stringifyArgument(line: IRecipeLine): string {
+ switch (line.instruction) {
case 'ENV':
- return argument.join(' ');
+ return (line.argument as string[]).join(' ');
default:
- return argument;
+ return line.argument as string;
}
}
}
diff --git a/dashboard/src/components/api/environment/docker-image-environment-manager.ts b/dashboard/src/components/api/environment/docker-image-environment-manager.ts
index fbfab0fdee2..0241bae4230 100644
--- a/dashboard/src/components/api/environment/docker-image-environment-manager.ts
+++ b/dashboard/src/components/api/environment/docker-image-environment-manager.ts
@@ -39,10 +39,10 @@ export class DockerImageEnvironmentManager extends EnvironmentManager {
* @param environment environment's configuration
* @returns {Array} list of machines defined in environment
*/
- getMachines(environment) {
+ getMachines(environment: any): any {
let machines = [];
- Object.keys(environment.machines).forEach((machineName) => {
+ Object.keys(environment.machines).forEach((machineName: string) => {
let machine = angular.copy(environment.machines[machineName]);
machine.name = machineName;
machine.recipe = environment.recipe;
@@ -60,7 +60,7 @@ export class DockerImageEnvironmentManager extends EnvironmentManager {
* @param machines the list of machines
* @returns environment's configuration
*/
- getEnvironment(environment, machines) {
+ getEnvironment(environment: any, machines: any): any {
return super.getEnvironment(environment, machines);
}
@@ -70,6 +70,6 @@ export class DockerImageEnvironmentManager extends EnvironmentManager {
* @param machine {object}
* @returns {{image: string}}
*/
- getSource(machine) {
+ getSource(machine: any): any {
return {image: machine.recipe.location};
}}
diff --git a/dashboard/src/components/api/environment/environment-manager.ts b/dashboard/src/components/api/environment/environment-manager.ts
index 464e07ab0ee..3a9930e84ea 100644
--- a/dashboard/src/components/api/environment/environment-manager.ts
+++ b/dashboard/src/components/api/environment/environment-manager.ts
@@ -14,33 +14,62 @@
* This is base class, which describes the environment manager.
* It's aim is to handle machines retrieval and editing, based on the type of environment.
*/
+
+const WS_AGENT_NAME: string = 'org.eclipse.che.ws-agent';
+const TERMINAL_AGENT_NAME: string = 'org.eclipse.che.terminal';
+const SSH_AGENT_NAME: string = 'org.eclipse.che.ssh';
+
export class EnvironmentManager {
- constructor() {
- this.WS_AGENT_NAME = 'org.eclipse.che.ws-agent';
+ constructor() { }
+
+ get editorMode(): string {
+ return '';
}
- canRenameMachine() {
+ canRenameMachine(machine: any): boolean {
return false;
}
- canDeleteMachine() {
+ canDeleteMachine(machine: any): boolean {
return false;
}
- canEditEnvVariables() {
+ canEditEnvVariables(machine: any): boolean {
return false;
}
/**
* Retrieves the list of machines.
*
+ * @param {*} environment
* @returns {Array} list of machines defined in environment
*/
- getMachines() {
+ getMachines(environment: any): any[] {
return [];
}
+ /**
+ * Renames machine.
+ *
+ * @param environment {object}
+ * @param oldName {string}
+ * @param newName {string}
+ */
+ renameMachine(environment: any, oldName: string, newName: string): void {
+ throw new TypeError('EnvironmentManager: cannot rename machine.');
+ }
+
+ /**
+ * Removes machine.
+ *
+ * @param environment {object}
+ * @param name {string} name of machine
+ */
+ deleteMachine(environment: any, name: string): void {
+ throw new TypeError('EnvironmentManager: cannot delete machine.');
+ }
+
/**
* Provides the environment configuration based on machines format.
*
@@ -48,12 +77,15 @@ export class EnvironmentManager {
* @param machines the list of machines
* @returns environment's configuration
*/
- getEnvironment(environment, machines) {
+ getEnvironment(environment: any, machines: any): any {
let newEnvironment = angular.copy(environment);
machines.forEach((machine) => {
let machineName = machine.name;
+ if (angular.isUndefined(newEnvironment.machines)) {
+ newEnvironment.machines = {};
+ }
if (angular.isUndefined(newEnvironment.machines[machineName])) {
newEnvironment.machines[machineName] = {'attributes': {}};
}
@@ -71,8 +103,8 @@ export class EnvironmentManager {
* @param machine
* @returns {boolean}
*/
- isDev(machine) {
- return machine.agents && machine.agents.includes(this.WS_AGENT_NAME);
+ isDev(machine: any): boolean {
+ return machine.agents && machine.agents.includes(WS_AGENT_NAME);
}
/**
@@ -81,32 +113,40 @@ export class EnvironmentManager {
* @param machine machine to edit
* @param isDev defined whether machine is developer or not
*/
- setDev(machine, isDev) {
+ setDev(machine: any, isDev: boolean): void {
let hasWsAgent = this.isDev(machine);
- if (isDev && !hasWsAgent) {
+ if (isDev) {
machine.agents = machine.agents ? machine.agents : [];
- machine.agents.push(this.WS_AGENT_NAME);
+ if (!hasWsAgent) {
+ machine.agents.push(WS_AGENT_NAME);
+ }
+ if (!machine.agents.includes(SSH_AGENT_NAME)) {
+ machine.agents.push(SSH_AGENT_NAME);
+ }
+ if (!machine.agents.includes(TERMINAL_AGENT_NAME)) {
+ machine.agents.push(TERMINAL_AGENT_NAME);
+ }
return;
}
if (!isDev && hasWsAgent) {
- machine.agents.splice(machine.agents.indexOf(this.WS_AGENT_NAME), 1);
+ machine.agents.splice(machine.agents.indexOf(WS_AGENT_NAME), 1);
}
}
- getServers(machine) {
+ getServers(machine: any): any {
return machine.servers || {};
}
- setServers(machine, servers) {
+ setServers(machine: any, servers: any): void {
machine.servers = angular.copy(servers);
}
- getAgents(machine) {
- return machine.agents || {};
+ getAgents(machine: any): any[] {
+ return machine.agents || [];
}
- setAgents(machine, agents) {
+ setAgents(machine: any, agents: any[]): void {
machine.agents = angular.copy(agents);
}
@@ -114,9 +154,9 @@ export class EnvironmentManager {
* Returns memory limit from machine's attributes
*
* @param machine
- * @returns {*} memory limit in bytes
+ * @returns {number|string} memory limit in bytes
*/
- getMemoryLimit(machine) {
+ getMemoryLimit(machine: any): number|string {
if (machine && machine.attributes && machine.attributes.memoryLimitBytes) {
return machine.attributes.memoryLimitBytes;
}
@@ -131,12 +171,12 @@ export class EnvironmentManager {
* @param machine machine to change memory limit
* @param limit memory limit
*/
- setMemoryLimit(machine, limit) {
+ setMemoryLimit(machine: any, limit: number): void {
machine.attributes = machine.attributes ? machine.attributes : {};
machine.attributes.memoryLimitBytes = limit;
}
- getEnvVariables() {
+ getEnvVariables(machine: any): any {
return null;
}
}
diff --git a/dashboard/src/components/widget/button/che-button.directive.ts b/dashboard/src/components/widget/button/che-button.directive.ts
index c3c011d0b76..5116275628a 100644
--- a/dashboard/src/components/widget/button/che-button.directive.ts
+++ b/dashboard/src/components/widget/button/che-button.directive.ts
@@ -51,6 +51,10 @@ export class CheButton {
template = template + ` ng-href="${attrs.ngHref}"`;
}
+ if (attrs.ngDisabled) {
+ template = template + ` disabled="${attrs.ngHref}"`;
+ }
+
template = template + '>';
if (attrs.cheButtonIcon) {
diff --git a/dashboard/src/components/widget/input/che-input.styl b/dashboard/src/components/widget/input/che-input.styl
index 58a044989dd..d5c1f09ddc4 100644
--- a/dashboard/src/components/widget/input/che-input.styl
+++ b/dashboard/src/components/widget/input/che-input.styl
@@ -78,5 +78,5 @@ label.che-input-desktop-label
box-shadow none
background-color inherit
- input[readonly] + .che-input-icon
+ input[readonly] + .che-input-icon, input[type="hidden"] + .che-input-icon
display none
diff --git a/dashboard/src/components/widget/toolbar/che-toolbar.styl b/dashboard/src/components/widget/toolbar/che-toolbar.styl
index 65be03f214c..b2469e74a75 100644
--- a/dashboard/src/components/widget/toolbar/che-toolbar.styl
+++ b/dashboard/src/components/widget/toolbar/che-toolbar.styl
@@ -71,7 +71,7 @@ $toolbar-height = 60px
.che-toolbar-control-button md-icon
vertical-align inherit
-.che-toolbar-open-button .che-button.md-button
+.che-toolbar .che-button.md-button
color $white-color !important
font-size 13px !important
font-weight bold !important