- No workspace selected. Unable to open IDE
-
-
-
- Redirecting to the IDE for workspace {{ideCtrl.selectedWorkspace.name}}... Please Wait.
-

+
+
+
No workspace selected. Unable to open IDE
+
-
-
-
-
-
-
+
+
diff --git a/dashboard/src/app/ide/ide.service.js b/dashboard/src/app/ide/ide.service.js
index ebcaae3dc01..5e1120678e0 100644
--- a/dashboard/src/app/ide/ide.service.js
+++ b/dashboard/src/app/ide/ide.service.js
@@ -20,7 +20,7 @@ class IdeSvc {
* Default constructor that is using resource
* @ngInject for Dependency injection
*/
- constructor(cheAPI, $rootScope, lodash, $mdDialog, userDashboardConfig, $timeout, $websocket, $sce, proxySettings, ideLoaderSvc, $location, routeHistory, $q, $log, cheWorkspace) {
+ constructor(cheAPI, $rootScope, lodash, $mdDialog, userDashboardConfig, $timeout, $websocket, $sce, proxySettings, $location, routeHistory, $q, $log, cheWorkspace) {
this.cheAPI = cheAPI;
this.$rootScope = $rootScope;
this.lodash = lodash;
@@ -30,7 +30,6 @@ class IdeSvc {
this.userDashboardConfig = userDashboardConfig;
this.$sce = $sce;
this.proxySettings = proxySettings;
- this.ideLoaderSvc = ideLoaderSvc;
this.$location = $location;
this.routeHistory = routeHistory;
this.$q = $q;
@@ -39,39 +38,10 @@ class IdeSvc {
this.ideParams = new Map();
- this.currentStep = 0;
this.lastWorkspace = null;
+ this.openedWorkspace = null;
this.listeningChannels = [];
-
- this.steps = [
- {text: 'Initializing workspace', inProgressText: 'Provision workspace and associating it with the existing user', logs: '', hasError: false},
- {text: 'Starting workspace runtime', inProgressText: 'Retrieving the stack\'s image and launching it', logs: '', hasError: false},
- {text: 'Starting workspace agent', inProgressText: 'Agents provide RESTful services like intellisense and SSH', logs: '', hasError: false},
- {text: 'Open IDE', inProgressText: 'Opening IDE', logs: '', hasError: false}
- ];
-
- this.preventRedirection = false;
- }
-
- init() {
- this.steps.forEach((step) => {
- step.logs = '';
- step.hasError = false;
- });
-
- if (this.lastWorkspace) {
- this.cleanupChannels(this.lastWorkspace.id);
- }
- }
-
- getStepText(stepNumber) {
- let entry = this.steps[stepNumber];
- if (this.currentStep >= stepNumber) {
- return entry.inProgressText;
- } else {
- return entry.text;
- }
}
displayIDE() {
@@ -88,27 +58,25 @@ class IdeSvc {
}
handleError(error) {
- if (error.data.message) {
- this.steps[this.currentStep].logs += '\n' + error.data.message;
- }
- this.steps[this.currentStep].hasError = true;
this.$log.error(error);
}
- startIde(workspace, noIdeLoader) {
- this.lastWorkspace = workspace;
-
- let defer = this.$q.defer();
- if (!noIdeLoader) {
- this.ideLoaderSvc.addLoader();
+ startIde(workspace) {
+ if (this.lastWorkspace) {
+ this.cleanupChannels(this.lastWorkspace.id);
}
+ this.lastWorkspace = workspace;
- this.currentStep = 1;
+ this.updateRecentWorkspace(workspace.id);
let bus = this.cheAPI.getWebsocket().getBus(workspace.id);
let startWorkspaceDefer = this.$q.defer();
this.startWorkspace(bus, workspace).then(() => {
+ // update list of workspaces
+ // for new workspace to show in recent workspaces
+ this.cheAPI.cheWorkspace.fetchWorkspaces();
+
this.cheWorkspace.fetchStatusChange(workspace.id, 'RUNNING').then(() => {
return this.cheWorkspace.fetchWorkspaceDetails(workspace.id);
}).then(() => {
@@ -125,16 +93,18 @@ class IdeSvc {
});
return startWorkspaceDefer.promise.then(() => {
- if (workspace.id === this.lastWorkspace.id) {
+ if (this.lastWorkspace && workspace.id === this.lastWorkspace.id) {
// Now that the container is started, wait for the extension server. For this, needs to get runtime details
let websocketUrl = this.cheWorkspace.getWebsocketUrl(workspace.id);
// try to connect
this.websocketReconnect = 50;
this.connectToExtensionServer(websocketUrl, workspace.id);
+ } else {
+ this.cleanupChannels(workspace.id);
}
return this.$q.resolve();
}, (error) => {
- if (workspace.id === this.lastWorkspace.id) {
+ if (this.lastWorkspace && workspace.id === this.lastWorkspace.id) {
this.cleanupChannels(workspace.id);
}
return this.$q.reject(error);
@@ -157,21 +127,16 @@ class IdeSvc {
let findStatusLink = this.lodash.find(machineConfigsLinks, (machineConfigsLink) => {
return machineConfigsLink.rel === 'get machine status channel';
});
- let findOutputLink = this.lodash.find(machineConfigsLinks, (machineConfigsLink) => {
- return machineConfigsLink.rel === 'get machine logs channel';
- });
let workspaceId = data.id;
let agentChannel = 'workspace:' + data.id + ':ext-server:output';
let statusChannel = findStatusLink ? findStatusLink.parameters[0].defaultValue : null;
- let outputChannel = findOutputLink ? findOutputLink.parameters[0].defaultValue : null;
this.listeningChannels.push(statusChannel);
// for now, display log of status channel in case of errors
bus.subscribe(statusChannel, (message) => {
if (message.eventType === 'DESTROYED' && message.workspaceId === data.id && !this.$rootScope.showIDE) {
- this.steps[this.currentStep].hasError = true;
// need to show the error
this.$mdDialog.show(
this.$mdDialog.alert()
@@ -182,7 +147,6 @@ class IdeSvc {
);
}
if (message.eventType === 'ERROR' && message.workspaceId === data.id) {
- this.steps[this.currentStep].hasError = true;
// need to show the error
this.$mdDialog.show(
this.$mdDialog.alert()
@@ -197,14 +161,7 @@ class IdeSvc {
this.listeningChannels.push(agentChannel);
bus.subscribe(agentChannel, (message) => {
- if (this.currentStep < 2) {
- this.currentStep = 2;
- }
-
- let agentStep = 2;
-
if (message.eventType === 'ERROR' && message.workspaceId === data.id) {
- this.steps[agentStep].hasError = true;
// need to show the error
this.$mdDialog.show(
this.$mdDialog.alert()
@@ -214,38 +171,21 @@ class IdeSvc {
.ok('OK')
);
}
-
- if (this.steps[agentStep].logs.length > 0) {
- this.steps[agentStep].logs = this.steps[agentStep].logs + '\n' + message;
- } else {
- this.steps[agentStep].logs = message;
- }
- });
-
- this.listeningChannels.push(outputChannel);
- bus.subscribe(outputChannel, (message) => {
- if (this.steps[this.currentStep].logs.length > 0) {
- this.steps[this.currentStep].logs = this.steps[this.currentStep].logs + '\n' + message;
- } else {
- this.steps[this.currentStep].logs = message;
- }
});
-
}, (error) => {
this.handleError(error);
+ this.$q.reject(error);
});
return startWorkspacePromise;
}
connectToExtensionServer(websocketURL, workspaceId) {
- this.currentStep = 2;
// try to connect
let websocketStream = this.$websocket(websocketURL);
// on success, create project
websocketStream.onOpen(() => {
- this.openIde(workspaceId);
this.cleanupChannels(workspaceId, websocketStream);
});
@@ -258,7 +198,6 @@ class IdeSvc {
}, 1000);
} else {
this.cleanupChannels(workspaceId, websocketStream);
- this.steps[this.currentStep].hasError = true;
this.$log.error('error when starting remote extension', error);
// need to show the error
this.$mdDialog.show(
@@ -280,32 +219,23 @@ class IdeSvc {
this.ideAction = ideAction;
}
- openLastStartedIde(skipLoader) {
- this.openIde(this.lastWorkspace.id, skipLoader);
- }
+ openIde(workspaceId) {
+ this.$rootScope.hideNavbar = false;
- openIde(workspaceId, skipLoader) {
- this.$timeout(() => {
- this.currentStep = 3;
- }, 0);
+ this.updateRecentWorkspace(workspaceId);
- if (this.$rootScope.loadingIDE === false || this.preventRedirection) {
+ if (this.openedWorkspace && this.openedWorkspace.id === workspaceId) {
+ this.restoreIDE();
return;
}
- if (skipLoader) {
- this.ideLoaderSvc.addLoader();
- this.$rootScope.hideIdeLoader = true;
- }
-
let inDevMode = this.userDashboardConfig.developmentMode;
let randVal = Math.floor((Math.random() * 1000000) + 1);
let appendUrl = '?uid=' + randVal;
let workspace = this.cheWorkspace.getWorkspaceById(workspaceId);
- this.lastWorkspace = workspace;
+ this.openedWorkspace = workspace;
- let selfLink = this.getHrefLink(workspace, 'self link');
let ideUrlLink = this.getHrefLink(workspace, 'ide url');
if (this.ideAction != null) {
@@ -327,17 +257,22 @@ class IdeSvc {
} else {
this.$rootScope.ideIframeLink = ideUrlLink + appendUrl;
}
- if (!skipLoader) {
- this.$timeout(() => {
- this.$rootScope.hideIdeLoader = true;
- }, 4000);
- }
- this.$timeout(() => {
- this.$rootScope.showIDE = true;
- this.$rootScope.hideLoader = true;
- this.$rootScope.loadingIDE = false;
- }, 2000);
+ let defer = this.$q.defer();
+ if (workspace.status === 'RUNNING') {
+ defer.resolve();
+ } else {
+ this.cheWorkspace.fetchStatusChange(workspace.id, 'STARTING').then(() => {
+ defer.resolve();
+ }, (error) => {
+ defer.reject(error);
+ this.$log.error('Unable to start workspace: ', error);
+ })
+ }
+ defer.promise.then(() => {
+ // update list of recent workspaces
+ this.cheWorkspace.fetchWorkspaces();
+ });
}
/**
@@ -377,12 +312,14 @@ class IdeSvc {
return '';
}
- setPreventRedirection(preventRedirection) {
- this.preventRedirection = preventRedirection;
- }
-
- getPreventRedirection() {
- return this.preventRedirection;
+ /**
+ * Emit event to move workspace immediately
+ * to top of the recent workspaces list
+ *
+ * @param workspaceId
+ */
+ updateRecentWorkspace(workspaceId) {
+ this.$rootScope.$broadcast('recent-workspace:set', workspaceId);
}
}
diff --git a/dashboard/src/app/ide/ide.styl b/dashboard/src/app/ide/ide.styl
index b06d5f60dd1..45f30fe4f89 100644
--- a/dashboard/src/app/ide/ide.styl
+++ b/dashboard/src/app/ide/ide.styl
@@ -5,3 +5,19 @@
top 0
left 0
border none
+
+.open-ide-page
+ position relative
+ color $white-color
+
+.ide-page-loader
+ position absolute
+ top 0
+ bottom 0
+ left 0
+ right 0
+ margin auto
+
+.ide-page-loader-content
+ width 120px
+ height 120px
diff --git a/dashboard/src/app/index.styl b/dashboard/src/app/index.styl
index 3994ba810b5..2211c6d315a 100644
--- a/dashboard/src/app/index.styl
+++ b/dashboard/src/app/index.styl
@@ -12,10 +12,10 @@ che-roundimage()
border-radius 50%
che-developers-face()
- che-roundimage()
box-shadow-simple()
- height 20px
- width 20px
+ border-radius 1px
+ height 14px
+ width 14px
padding 0
@import '../../bower_components/bootstrap-stylus/bootstrap/index'
@@ -38,14 +38,19 @@ $che-logs-output-font = "Droid Sans Mono", monospace
background-color $menu-bg-color
md-sidenav.dark-menu-bg
- overflow auto
+ overflow hidden
img.pull-right
width 50px
md-sidenav
box-shadow none !important
- width 230px
+ width 200px
+ min-width 200px
+
+md-sidenav > *
+ width 200px
+ min-width 200px
html
@@ -53,7 +58,7 @@ body
font-size 13px
font-family 'Open Sans'
background-color $background-site-color
-
+ min-width 600px
button,
select,
@@ -73,10 +78,12 @@ label
font-weight normal !important
md-divider
- border-top-color #454F5F !important
+ border-top-color #353E5D !important
+ margin 0 10px
md-toolbar
font-size 1em
+ flex 1
md-option
padding 5px
@@ -85,13 +92,14 @@ md-option
md-option:hover
background-color $hover-on-list-color
-.sidebar-entry
- margin-left auto
+.md-open-menu-container
+ transition none !important
+
+ md-menu-item
+ transition none !important
.main-page
- max-width 1296px
min-width 320px
- margin-right auto
.main-page-loader
diff --git a/dashboard/src/app/navbar/navbar-config.js b/dashboard/src/app/navbar/navbar-config.js
index f5c5b61837e..cbbd10bd890 100644
--- a/dashboard/src/app/navbar/navbar-config.js
+++ b/dashboard/src/app/navbar/navbar-config.js
@@ -14,6 +14,11 @@ import {CheNavBarCtrl} from './navbar.controller';
import {CheNavBar} from './navbar.directive';
import {NavBarSelectedCtrl} from './navbar-selected.controller';
import {NavBarSelected} from './navbar-selected.directive';
+import {NavbarRecentWorkspacesController} from './recent-workspaces/recent-workspaces.controller';
+import {NavbarRecentWorkspaces} from './recent-workspaces/recent-workspaces.directive';
+
+import {NavbarDropdownMenuController} from './navbar-dropdown-menu/navbar-dropdown-menu.controller';
+import {NavbarDropdownMenu} from './navbar-dropdown-menu/navbar-dropdown-menu.directive';
export class NavbarConfig {
@@ -22,5 +27,11 @@ export class NavbarConfig {
register.controller('NavBarSelectedCtrl', NavBarSelectedCtrl);
register.directive('cheNavBar', CheNavBar);
register.directive('navBarSelected', NavBarSelected);
+
+ register.controller('NavbarRecentWorkspacesController', NavbarRecentWorkspacesController);
+ register.directive('navbarRecentWorkspaces', NavbarRecentWorkspaces);
+
+ register.controller('NavbarDropdownMenuController', NavbarDropdownMenuController);
+ register.directive('navbarDropdownMenu', NavbarDropdownMenu);
}
}
diff --git a/dashboard/src/app/navbar/navbar-dropdown-menu/navbar-dropdown-menu.controller.js b/dashboard/src/app/navbar/navbar-dropdown-menu/navbar-dropdown-menu.controller.js
new file mode 100644
index 00000000000..4fd2680331c
--- /dev/null
+++ b/dashboard/src/app/navbar/navbar-dropdown-menu/navbar-dropdown-menu.controller.js
@@ -0,0 +1,56 @@
+/*
+ * 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';
+
+
+/**
+ * This class is handling the controller for the dropdown menu on navbar
+ * @author Oleksii Kurinnyi
+ */
+export class NavbarDropdownMenuController {
+
+ /**
+ * Default constructor that is using resource
+ * @ngInject for Dependency injection
+ */
+ constructor($window) {
+ this.$window = $window;
+
+ this.offset = angular.isUndefined(this.offset) ? '0 0' : this.offset;
+ }
+
+ /**
+ * Method process click on dropdown-menu item. If item contains
+ * url property then application will follow this URL.
+ * Otherwise, onclick callback will be called.
+ *
+ * @param item {Object} the dropdown-menu item which was clicked on
+ */
+ process(item) {
+ if (item.url) {
+ this.redirect(item.url);
+ return;
+ }
+
+ if (item.onclick) {
+ item.onclick();
+ }
+ }
+
+ redirect(newPath) {
+ if (!newPath || this.isDisabled) {
+ return;
+ }
+ this.$window.location.href = newPath;
+ }
+}
+
+
diff --git a/dashboard/src/app/navbar/navbar-dropdown-menu/navbar-dropdown-menu.directive.js b/dashboard/src/app/navbar/navbar-dropdown-menu/navbar-dropdown-menu.directive.js
new file mode 100644
index 00000000000..7d01a3b36b3
--- /dev/null
+++ b/dashboard/src/app/navbar/navbar-dropdown-menu/navbar-dropdown-menu.directive.js
@@ -0,0 +1,155 @@
+/*
+ * 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 navbar.directive:NavbarDropdownMenu
+ * @description This class is handling the directive to show the dropdown menu in the navbar
+ * @author Oleksii Kurinnyi
+ */
+export class NavbarDropdownMenu {
+
+ /**
+ * Default constructor that is using resource
+ * @ngInject for Dependency injection
+ */
+ constructor($timeout, $document, $rootScope) {
+ this.$timeout = $timeout;
+ this.$document = $document;
+ this.$rootScope = $rootScope;
+
+
+ this.restrict = 'E';
+ this.bindToController = true;
+ this.templateUrl = 'app/navbar/navbar-dropdown-menu/navbar-dropdown-menu.html';
+ this.controller = 'NavbarDropdownMenuController';
+ this.controllerAs = 'navbarDropdownMenuController';
+
+ this.transclude = true;
+
+ // scope values
+ this.scope = {
+ dropdownItems: '=navbarDropdownItems',
+ isDisabled: '=?navbarDropdownDisabled',
+ externalCssClass: '@?navbarDropdownExternalClass',
+ offset: '@?navbarDropdownOffset'
+ };
+ }
+
+ compile($element, attrs) {
+ let jqButton = $element.find('[ng-transclude]');
+ if (angular.isDefined(attrs['navbarDropdownRightClick'])) {
+ jqButton.attr('ng-click', '');
+ jqButton.attr('che-on-right-click', '$mdOpenMenu($event)');
+ } else {
+ jqButton.attr('ng-click', '$mdOpenMenu($event)');
+ }
+ }
+
+ link($scope, $element) {
+ // store active menu element in rootScope
+ let menuContentEl = $element.find('.navbar-dropdown-menu'),
+ menuEl = $element.find('md-menu');
+ $scope.$watch(() => {
+ return menuContentEl.is(':visible');
+ }, (visible) => {
+ if (visible) {
+ this.$rootScope.navbarDropdownActiveMenu = menuEl[0];
+ }
+ });
+
+ let self = this;
+ this.$document.off().on('mousedown contextmenu', '.md-menu-backdrop', (e) => {
+ let eventType = e.type,
+ eventWhich = e.which,
+ backdropEl = angular.element(e.target);
+
+ if (eventType === 'mousedown') {
+ if (eventWhich === 3) {
+ // prevent event propagation for right mousedown
+ // and wait for contextmenu event
+ e.preventDefault();
+ e.stopPropagation();
+ return false;
+ } else {
+ eventType = 'click';
+ }
+ }
+
+ var x = e.clientX,
+ y = e.clientY,
+ stack = [];
+ let elementMouseIsOver = self.$document[0].elementFromPoint(x, y);
+ elementMouseIsOver.style.pointerEvents = 'none';
+ stack.push(elementMouseIsOver);
+
+ // iterate elements under cursor
+ let limit = 50,
+ nextTargetEl;
+ while (elementMouseIsOver.tagName !== 'MD-MENU' && limit > 0){
+ elementMouseIsOver = self.$document[0].elementFromPoint(x, y);
+
+ // break when top of tree is reached
+ if (stack[stack.length-1] === elementMouseIsOver) {
+ break;
+ }
+
+ let curEl = angular.element(elementMouseIsOver);
+
+ // element to trigger event
+ if (!nextTargetEl) {
+ nextTargetEl = curEl;
+ }
+
+ elementMouseIsOver.style.pointerEvents = 'none';
+ stack.push(elementMouseIsOver);
+
+ limit--;
+ }
+
+ // click on menu's backdrop to hide menu
+ backdropEl.triggerHandler('click');
+
+ if (elementMouseIsOver.tagName === 'MD-MENU') {
+ // if menu is found then
+ // check if click is caught over the same menu
+ if(elementMouseIsOver === this.$rootScope.navbarDropdownActiveMenu) {
+ // clear active menu
+ delete this.$rootScope.navbarDropdownActiveMenu;
+ } else {
+ // open new menu by triggering mouse event
+ angular.element(nextTargetEl).trigger({
+ type: eventType,
+ which: eventWhich
+ });
+ }
+ } else {
+ // if menu isn't found
+ // just trigger same mouse event on first found element
+ angular.element(nextTargetEl).trigger({
+ type: eventType,
+ which: eventWhich
+ });
+ }
+
+ // clean pointer events
+ for (let i=0; i
+
+
+
diff --git a/dashboard/src/app/navbar/navbar-dropdown-menu/navbar-dropdown-menu.styl b/dashboard/src/app/navbar/navbar-dropdown-menu/navbar-dropdown-menu.styl
new file mode 100644
index 00000000000..e32fd829b62
--- /dev/null
+++ b/dashboard/src/app/navbar/navbar-dropdown-menu/navbar-dropdown-menu.styl
@@ -0,0 +1,51 @@
+navbar-dropdown-menu
+ height inherit
+ min-height inherit
+
+ *
+ outline none
+
+ md-menu
+ outline none
+ height inherit
+ min-height inherit
+
+ a.md-button.che-navbar-selected
+ background-color $navbar-active-menu-background-color !important
+
+ div
+ height inherit
+ min-height inherit
+
+md-menu-content.navbar-dropdown-menu
+ che-border-radius(2px)
+ color $label-secondary-color
+ padding 3px 0
+
+ *
+ outline none
+
+ md-menu-item
+ height 21px
+ min-height 21px
+ font-size 11px
+
+ &:not([disabled]):hover
+ che-brightness(85%)
+ background-color $mouse-gray-color
+ cursor pointer
+
+ &[disabled] .navbar-click-area
+ color lighten($label-secondary-color, 50%)
+
+ .navbar-click-area
+ che-border-radius(2px)
+ display block
+ padding 2px 8px
+ color $label-secondary-color
+ cursor pointer
+ outline none
+
+ .navbar-dropdown-icon
+ padding-right 3px
+
diff --git a/dashboard/src/app/navbar/navbar-selected.directive.js b/dashboard/src/app/navbar/navbar-selected.directive.js
index bb5317d86b4..b168f62a8fe 100644
--- a/dashboard/src/app/navbar/navbar-selected.directive.js
+++ b/dashboard/src/app/navbar/navbar-selected.directive.js
@@ -33,19 +33,16 @@ export class NavBarSelected {
}
-
/**
* Monitor click
*/
- link($scope, element, attrs, controller) {
+ link($scope, element, attrs) {
let select = (elem) => {
// if there is a previous selected element, unselect it
if (this.$rootScope.selectedNavBarElement) {
this.$rootScope.selectedNavBarElement.removeClass('che-navbar-selected');
}
- controller.close();
-
// select the new element
this.$rootScope.selectedNavBarElement = elem;
// add the class
@@ -59,23 +56,32 @@ export class NavBarSelected {
}
// highlight item on click
- element.bind('click', () => {
+ element.bind('click', (event) => {
+ // prevent activating menu item if Ctrl key is pressed
+ if (event.ctrlKey) {
+ this.$rootScope.selectedNavBarElement.focus();
+ return;
+ }
select(element);
});
+ element.bind('mousedown', () => {
+ element.addClass('navbar-item-no-hover');
+ });
+ element.bind('mouseup', () => {
+ if (element !== this.$rootScope.selectedNavBarElement) {
+ element.blur();
+ }
+ });
+ element.bind('mouseover', () => {
+ element.removeClass('navbar-item-no-hover');
+ });
- $scope.$on('navbar-selected:clear', () => {
- // unselect item
- if (this.$rootScope.selectedNavBarElement) {
+ $scope.$on('navbar-selected:set', (event, path) => {
+ // unselect previously selected item
+ if (this.$rootScope.selectedNavBarElement === element) {
this.$rootScope.selectedNavBarElement.removeClass('che-navbar-selected');
delete this.$rootScope.selectedNavBarElement;
}
- });
- $scope.$on('navbar-selected:restore', (event, path) => {
- // check if item is selected already
- if (this.$rootScope.selectedNavBarElement) {
- return;
- }
-
// select item
if (attrs['ngHref'] === path) {
select(element);
diff --git a/dashboard/src/app/navbar/navbar-selected.styl b/dashboard/src/app/navbar/navbar-selected.styl
new file mode 100644
index 00000000000..728053f1d3b
--- /dev/null
+++ b/dashboard/src/app/navbar/navbar-selected.styl
@@ -0,0 +1,4 @@
+
+.admin-navbar-menu md-list-item a.md-button.navbar-item-no-hover:hover,
+.admin-navbar-menu md-menu a.md-button.navbar-item-no-hover:hover
+ background-color transparent !important
diff --git a/dashboard/src/app/navbar/navbar-theme.styl b/dashboard/src/app/navbar/navbar-theme.styl
new file mode 100644
index 00000000000..bba1d5e7720
--- /dev/null
+++ b/dashboard/src/app/navbar/navbar-theme.styl
@@ -0,0 +1,13 @@
+// navbar colors
+$navbar-backgroud-color = #282E44
+$navbar-active-menu-background-color = alpha($white-color, 20%)
+$navbar-border-right-color = $black-color
+$navbar-active-menu-mark-color = $che-logo-yellow-color
+$navbar-menu-icon-color = #808B9C
+$navbar-active-menu-icon-color = $light-gray-color
+$navbar-menu-text-color = $mouse-gray-color
+$navbar-menu-dark-text-color = $navbar-menu-icon-color
+$navbar-active-menu-text-color = $light-gray-color
+$navbar-section-title-color = #62687C
+$navbar-ide-iframe-button-background-color = lighten($navbar-backgroud-color, 31%)
+$navbar-ide-iframe-button-border-color = alpha($navbar-ide-iframe-button-background-color, 0.65)
diff --git a/dashboard/src/app/navbar/navbar.controller.js b/dashboard/src/app/navbar/navbar.controller.js
index 69a9559ca52..1acce89b879 100644
--- a/dashboard/src/app/navbar/navbar.controller.js
+++ b/dashboard/src/app/navbar/navbar.controller.js
@@ -16,12 +16,13 @@ export class CheNavBarCtrl {
* Default constructor
* @ngInject for Dependency injection
*/
- constructor($mdSidenav, $scope, $location, $route, userDashboardConfig, cheAPI) {
+ constructor($mdSidenav, $scope, $location, $route, userDashboardConfig, cheAPI, $rootScope, $window) {
this.mdSidenav = $mdSidenav;
this.$scope = $scope;
this.$location = $location;
this.$route = $route;
this.cheAPI = cheAPI;
+ this.$window = $window;
this.links = [{href: '#/create-workspace', name: 'New Workspace'}];
this.displayLoginItem = userDashboardConfig.developmentMode;
@@ -59,18 +60,10 @@ export class CheNavBarCtrl {
billing: '#/billing'
};
- // clear highlighting of menu item from navbar
- // if route is not part of navbar
- // or restore highlighting otherwise
+ // highlight navbar menu item
$scope.$on('$locationChangeStart', () => {
- let path = '#' + $location.path(),
- match = Object.keys(this.menuItemUrl).some(item => this.menuItemUrl[item] === path);
- if (match) {
- $scope.$broadcast('navbar-selected:restore', path);
- }
- else {
- $scope.$broadcast('navbar-selected:clear');
- }
+ let path = '#' + $location.path();
+ $scope.$broadcast('navbar-selected:set', path);
});
cheAPI.cheWorkspace.fetchWorkspaces();
@@ -94,4 +87,12 @@ export class CheNavBarCtrl {
getWorkspacesNumber() {
return this.cheAPI.cheWorkspace.getWorkspaces().length;
}
+
+ getProjectsNumber() {
+ return this.cheAPI.cheWorkspace.getAllProjects().length;
+ }
+
+ openLinkInNewTab(url) {
+ this.$window.open(url, '_blank');
+ }
}
diff --git a/dashboard/src/app/navbar/navbar.html b/dashboard/src/app/navbar/navbar.html
index 04c928efebe..d1f3cc543e4 100644
--- a/dashboard/src/app/navbar/navbar.html
+++ b/dashboard/src/app/navbar/navbar.html
@@ -14,77 +14,50 @@
-
+
+
diff --git a/dashboard/src/app/navbar/navbar.styl b/dashboard/src/app/navbar/navbar.styl
index 51d9f3042fc..cbbe0423761 100644
--- a/dashboard/src/app/navbar/navbar.styl
+++ b/dashboard/src/app/navbar/navbar.styl
@@ -9,17 +9,15 @@
* Codenvy, S.A. - initial API and implementation
*/
-$active-background-color = #3E4856
-$active-border-color = rgb(74, 144, 226)
-$navbar-menu-color = #C5D0DF
-$navbar-icon-color = #E2E2E3
$faces-shadow = rgba(255, 255, 255, 0.5)
$menu-font-size = 1em
-$submenu-font-size = 0.9em
+$submenu-font-size = 10px
+$circle-indicator-font-size = 0.7em
-.navbar-top-dropdown
- margin: 0 10px
- height 60px
+.navbar-top-logo
+ margin 5px 10px 0
+ height 54px
+ width 95px
/* restore non-allcaps */
.admin-navbar-menu section a.md-button
@@ -29,29 +27,40 @@ $submenu-font-size = 0.9em
.admin-navbar-menu md-list-item a.md-button
margin 0
+che-nav-bar
+ width 100%
+
.left-sidebar-container
- height 100vh
display flex
+ flex 1
flex-flow row wrap
justify-content space-around
+ width 100%
.left-sidebar-container md-toolbar
box-shadow none
+ background-color $navbar-backgroud-color
+ border-right 1px solid $navbar-border-right-color
.left-sidebar-menu
width 100%
-.left-sidebar-menu .navbar-subsection-item .navbar-item i,
-.left-sidebar-menu .navbar-submenu-item .navbar-item i,
-.navbar-submenu-content i
- width 40px
- font-size 19px
- line-height 12px
+.left-sidebar-menu .navbar-subsection-item .navbar-item .navbar-icon,
+.left-sidebar-menu .navbar-submenu-item .navbar-item .navbar-icon,
+.navbar-submenu-content .navbar-icon
+ width 20px
+ min-width 20px
+ font-size 14px
+ line-height 24px
text-align center
+ margin 0 4px 0 7px
.left-sidebar-menu .navbar-subsection-item.md-no-proxy
padding 0
+.left-sidebar-menu md-list
+ padding-top 5px
+
.admin-navbar-menu .navbar-subsection md-list
padding-top 4px
@@ -59,33 +68,48 @@ $submenu-font-size = 0.9em
min-height 0
margin-top -4px
-.admin-navbar-menu .navbar-identity span
- padding-left 3px
+.admin-navbar-menu
+ .navbar-section span.navbar-section-title
+ padding-top 10px
+ padding-left 10px
+ text-transform uppercase
+ font-size 0.9em
+ white-space nowrap
+ .navbar-section + md-list
+ padding-top 2px
/* text color */
.admin-navbar-menu .navbar-header,
.admin-navbar-menu .navbar-identity,
.admin-navbar-menu section a.md-button span,
.navbar-submenu-content a.md-button span
- color $navbar-menu-color
+ color $navbar-menu-text-color
+
+.admin-navbar-menu md-list-item a.md-button span.navbar-number
+ color $navbar-menu-dark-text-color
-.admin-navbar-menu section a.md-button i,
-.navbar-submenu-content a.md-button i
- color $navbar-icon-color
+.admin-navbar-menu .navbar-section span.navbar-section-title
+ color $navbar-section-title-color
+
+.admin-navbar-menu section a.md-button .navbar-icon,
+.navbar-submenu-content a.md-button .navbar-icon
+ color $navbar-menu-icon-color
.admin-navbar-menu section a.md-button,
.navbar-submenu-content a.md-button
height 36px
+.admin-navbar-menu md-list-item a.md-button.che-navbar-selected .navbar-icon
+ color $navbar-active-menu-icon-color
.admin-navbar-menu md-list-item a.md-button.che-navbar-selected span
- color $white-color
+ color $navbar-active-menu-text-color
/* background color */
.admin-navbar-menu md-list-item a.md-button.che-navbar-selected,
.admin-navbar-menu md-list-item a.md-button:hover,
.admin-navbar-menu md-menu a.md-button:hover
- background-color $active-background-color
+ background-color $navbar-active-menu-background-color
.admin-navbar-menu md-menu a.md-button.che-navbar-selected
background-color inherit
@@ -104,29 +128,58 @@ $submenu-font-size = 0.9em
.admin-navbar-menu md-list-item a.md-button
width fill-available
padding 0
+ height 26px
+ min-height 24px
+ border-radius 0
+
+.admin-navbar-menu .navbar-account-section md-list
+ padding 0
+
+.admin-navbar-menu .navbar-account-section md-list-item a.md-button
+ height inherit
+ min-height inherit
.admin-navbar-menu .left-sidebar-menu md-list-item > a.md-button .navbar-item,
.admin-navbar-menu .left-sidebar-menu md-menu > a.md-button .navbar-item,
.navbar-submenu-content md-menu-item > a.md-button .navbar-item
- padding-left 10px
+ padding-left 0
+ padding-right 5px
.admin-navbar-menu .left-sidebar-menu md-list-item > a.md-button .navbar-item.navbar-item-no-icon,
.admin-navbar-menu .left-sidebar-menu md-menu > a.md-button .navbar-item.navbar-item-no-icon,
.navbar-submenu-content md-menu-item > a.md-button .navbar-item.navbar-item-no-icon
- padding-left 51px
+ padding-left 36px
.admin-navbar-menu md-list-item a.md-button .navbar-item
- padding-left 87px
+ line-height 24px
+
+.admin-navbar-menu md-list-item a.md-button .navbar-item span
+ overflow: hidden
+ text-overflow ellipsis
+
+.admin-navbar-menu md-list-item a.md-button span.navbar-number
+ font-weight 600
.admin-navbar-menu section md-list,
.admin-navbar-menu .navbar-identity
width fill-available
-.admin-navbar-menu .navbar-subsection md-list-item a.md-button .navbar-item i
+.admin-navbar-menu .navbar-identity
+ height 100%
+
+.admin-navbar-menu .navbar-subsection md-list-item a.md-button .navbar-item .navbar-icon
line-height inherit
width 13px
margin-right 2px
+.left-sidebar-menu .navbar-subsection-item
+ height 26px
+ min-height 26px
+
+.left-sidebar-menu.navbar-account-section .navbar-subsection-item
+ height 31px
+ min-height 31px
+
/* hover, focus */
/* remove underline on focus */
.admin-navbar-menu section a.md-button:focus
@@ -136,7 +189,7 @@ $submenu-font-size = 0.9em
.admin-navbar-menu section.navbar-subsection md-list md-item.navbar-subsection-item md-list-item a.md-button.che-navbar-selected,
.admin-navbar-menu section.navbar-subsection md-list md-item.navbar-subsection-item md-list-item a.md-button:hover,
.navbar-submenu-content md-menu-item a.md-button:hover
- background-color $active-background-color
+ background-color $navbar-active-menu-background-color
.admin-navbar-menu a:hover, .admin-navbar-menu a.che-navbar-selected
color inherit
@@ -145,10 +198,10 @@ $submenu-font-size = 0.9em
.admin-navbar-menu .che-navbar-selected:before
content ""
left 0
- top 4px
- bottom 4px
+ top 0
+ bottom 0
position absolute
- border-left solid 3px $active-border-color
+ border-left solid 2px $navbar-active-menu-mark-color
/* animations */
.admin-navbar-menu .animation.ng-enter
@@ -183,9 +236,6 @@ $submenu-font-size = 0.9em
/* user avatar */
.admin-navbar-menu .navbar-identity .developers-face
che-developers-face()
- -webkit-box-shadow 0 0 0 1px $faces-shadow
- -moz-box-shadow 0 0 0 1px $faces-shadow
- box-shadow 0 0 0 1px $faces-shadow
/* fonts sizes */
.admin-navbar-menu .navbar-header,
@@ -196,11 +246,13 @@ $submenu-font-size = 0.9em
.navbar-identity
outline 0
- padding-left 7px
.admin-navbar-menu section a.md-button
font-size $submenu-font-size
+.admin-navbar-menu .workspace-status-indicator span
+ font-size $circle-indicator-font-size
+
/* remove focus effect on fold/unfold button */
.admin-navbar-menu .navbar-identity i.material-design:focus
outline none
@@ -229,3 +281,12 @@ $submenu-font-size = 0.9em
.admin-navbar-menu md-divider
margin-top 8px
margin-bottom 8px
+
+.navbar-iframe-button-left-border
+ position absolute
+ top 4px
+ right 0
+ width 0
+ height 16px
+ border-right 1px solid $navbar-ide-iframe-button-border-color
+ z-index 10
diff --git a/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.controller.js b/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.controller.js
new file mode 100644
index 00000000000..b12c5c16bdb
--- /dev/null
+++ b/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.controller.js
@@ -0,0 +1,206 @@
+/*
+ * 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 navbar.controller:NavbarRecentWorkspacesController
+ * @description This class is handling the controller of the recent workspaces to display in the navbar
+ * @author Oleksii Kurinnyi
+ */
+export class NavbarRecentWorkspacesController {
+
+ /**
+ * Default constructor
+ * @ngInject for Dependency injection
+ */
+ constructor(cheWorkspace, ideSvc, $window, $log, $rootScope) {
+ this.cheWorkspace = cheWorkspace;
+ this.ideSvc = ideSvc;
+ this.$window = $window;
+ this.$log = $log;
+ this.$rootScope = $rootScope;
+
+ // fetch workspaces when initializing
+ this.cheWorkspace.fetchWorkspaces();
+
+ this.dropdownItemTempl = [
+ // running
+ {
+ name: 'Stop',
+ scope: 'RUNNING',
+ icon: 'fa fa-stop',
+ _onclick: (workspaceId) => { this.stopRecentWorkspace(workspaceId) }
+ },
+ {
+ name: 'Snapshot',
+ scope: 'RUNNING',
+ icon: 'fa fa-clock-o',
+ _onclick: (workspaceId) => { this.createSnapshotRecentWorkspace(workspaceId) }
+ },
+ // stopped
+ {
+ name: 'Run',
+ scope: 'STOPPED',
+ icon: 'fa fa-play',
+ _onclick: (workspaceId) => { this.runRecentWorkspace(workspaceId) }
+ }
+ ];
+ this.dropdownItems = {};
+
+ this.veryRecentWorkspaceId = '';
+ let cleanup = $rootScope.$on('recent-workspace:set', (event, workspaceId) => {
+ this.veryRecentWorkspaceId = workspaceId;
+ });
+ $rootScope.$on('$destroy', () => {
+ cleanup();
+ });
+ }
+
+ /**
+ * Returns only workspaces which were opened at least once
+ * @returns {*}
+ */
+ getRecentWorkspaces() {
+ let workspaces = this.cheWorkspace.getWorkspaces();
+ workspaces.forEach((workspace) => {
+ if (!workspace.attributes) {
+ workspace.attributes = {
+ updated: 0,
+ created: 0
+ }
+ }
+ if (!workspace.attributes.updated) {
+ workspace.attributes.updated = workspace.attributes.created;
+ }
+ if (this.veryRecentWorkspaceId === workspace.id) {
+ workspace.attributes.opened = 1;
+ } else {
+ workspace.attributes.opened = 0;
+ }
+ });
+ return workspaces;
+ }
+
+ /**
+ * Returns status of workspace
+ * @returns {String}
+ */
+ getWorkspaceStatus(workspaceId) {
+ let workspace = this.cheWorkspace.getWorkspaceById(workspaceId);
+ return workspace ? workspace.status : 'unknown';
+ }
+
+ /**
+ * Returns name of workspace
+ * @returns {String}
+ */
+ getWorkspaceName(workspaceId) {
+ let workspace = this.cheWorkspace.getWorkspaceById(workspaceId);
+ return workspace ? workspace.config.name : 'unknown';
+ }
+
+ /**
+ * Returns true if workspace is opened in IDE
+ * @param workspaceId {String} workspace id
+ * @returns {*|null|boolean}
+ */
+ isOpen(workspaceId) {
+ return this.ideSvc.openedWorkspace && this.ideSvc.openedWorkspace.id === workspaceId;
+ }
+
+ /**
+ * Returns IDE link
+ * @param workspaceId {String} workspace id
+ * @returns {string}
+ */
+ getIdeLink(workspaceId) {
+ return '#/ide/' + this.getWorkspaceName(workspaceId);
+ }
+
+ /**
+ * Opens new tab/window with IDE
+ * @param workspaceId {String} workspace id
+ */
+ openLinkInNewTab(workspaceId) {
+ let url = this.getIdeLink(workspaceId);
+ this.$window.open(url, '_blank');
+ }
+
+ /**
+ * Builds and returns array of dropdown menu items for specified workspace
+ * @param workspaceId {String} workspace id
+ * @returns {*}
+ */
+ getDropdownItems(workspaceId) {
+ let workspace = this.cheWorkspace.getWorkspaceById(workspaceId),
+ disabled = workspace && (workspace.status === 'STARTING' || workspace.status === 'STOPPING'),
+ visibleScope = (workspace && (workspace.status === 'RUNNING' || workspace.status === 'STOPPING')) ? 'RUNNING' : 'STOPPED';
+
+ if (!this.dropdownItems[workspaceId]) {
+ this.dropdownItems[workspaceId] = [];
+ this.dropdownItems[workspaceId] = angular.copy(this.dropdownItemTempl);
+ }
+
+ this.dropdownItems[workspaceId].forEach((item) => {
+ item.disabled = disabled;
+ item.hidden = item.scope !== visibleScope;
+ item.onclick = () => {
+ item._onclick(workspace.id)
+ };
+ });
+
+ return this.dropdownItems[workspaceId];
+ }
+
+ /**
+ * Stops specified workspace
+ * @param workspaceId {String} workspace id
+ */
+ stopRecentWorkspace(workspaceId) {
+ this.cheWorkspace.stopWorkspace(workspaceId).then(() => {}, (error) => {
+ this.$log.error(error);
+ });
+ }
+
+ /**
+ * Starts specified workspace
+ * @param workspaceId {String} workspace id
+ */
+ runRecentWorkspace(workspaceId) {
+ let workspace = this.cheWorkspace.getWorkspaceById(workspaceId);
+
+ this.updateRecentWorkspace(workspaceId);
+ this.cheWorkspace.startWorkspace(workspace.id, workspace.config.defaultEnv).then(() => {}, (error) => {
+ this.$log.error(error);
+ });
+ }
+
+ /**
+ * Creates snapshot of specified workspace
+ * @param workspaceId {String} workspace id
+ */
+ createSnapshotRecentWorkspace(workspaceId) {
+ this.cheWorkspace.createSnapshot(workspaceId).then(() => {}, (error) => {
+ this.$log.error(error);
+ });
+ }
+
+ /**
+ * Emit event to move workspace immediately
+ * to top of the recent workspaces list
+ *
+ * @param workspaceId
+ */
+ updateRecentWorkspace(workspaceId) {
+ this.$rootScope.$broadcast('recent-workspace:set', workspaceId);
+ }
+}
diff --git a/dashboard/src/app/ide/ide-list-item-navbar/ide-list-item-navbar.directive.js b/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.directive.js
similarity index 52%
rename from dashboard/src/app/ide/ide-list-item-navbar/ide-list-item-navbar.directive.js
rename to dashboard/src/app/navbar/recent-workspaces/recent-workspaces.directive.js
index 40bb65a9ebc..d938b8ab976 100644
--- a/dashboard/src/app/ide/ide-list-item-navbar/ide-list-item-navbar.directive.js
+++ b/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.directive.js
@@ -11,26 +11,25 @@
'use strict';
/**
- * This class is handling the controller for the item in navbar allowing to redirect to the IDE
- * @author Florent Benoit
+ * @ngdoc directive
+ * @name navbar.directive:NavbarRecentWorkspaces
+ * @description This class is handling the directive of the listing recent opened workspaces in the navbar
+ * @author Oleksii Kurinnyi
*/
-class IdeListItemNavbar {
+export class NavbarRecentWorkspaces {
+
/**
* Default constructor that is using resource
* @ngInject for Dependency injection
*/
- constructor () {
- this.restrict='E';
- this.templateUrl = 'app/ide/ide-list-item-navbar/ide-list-item-navbar.html';
-
+ constructor() {
+ this.restrict = 'E';
+ this.templateUrl = 'app/navbar/recent-workspaces/recent-workspaces.html';
- this.controller = 'IdeListItemNavbarCtrl';
- this.controllerAs = 'ideListItemNavbarCtrl';
+ this.controller = 'NavbarRecentWorkspacesController';
+ this.controllerAs = 'navbarRecentWorkspacesController';
this.bindToController = true;
}
}
-
-export default IdeListItemNavbar;
-
diff --git a/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.html b/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.html
new file mode 100644
index 00000000000..3c9c6518d45
--- /dev/null
+++ b/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.html
@@ -0,0 +1,39 @@
+
diff --git a/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.styl b/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.styl
new file mode 100644
index 00000000000..2046c72e42a
--- /dev/null
+++ b/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.styl
@@ -0,0 +1,39 @@
+.recent-workspaces
+ $recent-workspaces-stopped-color = #9B9CA0
+ $recent-workspaces-notstopped-color = #C1C2C6
+
+ .navbar-subsection-item
+ height 19px
+ min-height 19px
+ line-height 19px
+
+ .md-button
+ height 19px !important
+ min-height 19px !important
+
+ .navbar-item
+ line-height 19px !important
+
+ .navbar-icon
+ font-size inherit !important
+ height 19px !important
+ line-height 19px !important
+
+ .spinner
+ height 19px
+
+ .workspace-status-indicator .workspace-status-stopped
+ color $recent-workspaces-stopped-color
+ text-shadow none
+
+ .md-button span.recent-workspaces-notstopped-workspace
+ color $recent-workspaces-notstopped-color
+
+ .md-button span.recent-workspaces-stopped-workspace
+ font-style italic
+ padding-right 2px
+ color $recent-workspaces-stopped-color
+
+.recent-workspaces-menu.navbar-dropdown-menu
+ width 140px
+ min-width 140px
diff --git a/dashboard/src/app/projects/create-project/create-project.controller.js b/dashboard/src/app/projects/create-project/create-project.controller.js
index 54b75cbe48e..2130faf7f2d 100755
--- a/dashboard/src/app/projects/create-project/create-project.controller.js
+++ b/dashboard/src/app/projects/create-project/create-project.controller.js
@@ -156,6 +156,8 @@ export class CreateProjectCtrl {
this.defaultWorkspaceName = null;
cheAPI.cheWorkspace.getWorkspaces();
+
+ $rootScope.showIDE = false;
}
/**
@@ -411,7 +413,11 @@ export class CreateProjectCtrl {
}
let startWorkspacePromise = this.cheAPI.getWorkspace().startWorkspace(workspace.id, workspace.config.defaultEnv);
- startWorkspacePromise.then(() => {}, (error) => {
+ startWorkspacePromise.then(() => {
+ // update list of workspaces
+ // for new workspace to show in recent workspaces
+ this.cheAPI.cheWorkspace.fetchWorkspaces();
+ }, (error) => {
let errorMessage;
if (!error || !error.data) {
@@ -438,6 +444,8 @@ export class CreateProjectCtrl {
}
createProjectInWorkspace(workspaceId, projectName, projectData, bus, websocketStream, workspaceBus) {
+ this.updateRecentWorkspace(workspaceId);
+
this.createProjectSvc.setCurrentProgressStep(3);
var promise;
@@ -952,6 +960,8 @@ export class CreateProjectCtrl {
//TODO: no account in che ? it's null when testing on localhost
let creationPromise = this.cheAPI.getWorkspace().createWorkspaceFromConfig(null, workspaceConfig, attributes);
creationPromise.then((workspace) => {
+ this.updateRecentWorkspace(workspace.id);
+
// init message bus if not there
if (this.workspaces.length === 0) {
this.messageBus = this.cheAPI.getWebsocket().getBus(workspace.id);
@@ -1232,4 +1242,14 @@ export class CreateProjectCtrl {
}
return [];
}
+
+ /**
+ * Emit event to move workspace immediately
+ * to top of the recent workspaces list
+ *
+ * @param workspaceId
+ */
+ updateRecentWorkspace(workspaceId) {
+ this.$rootScope.$broadcast('recent-workspace:set', workspaceId);
+ }
}
diff --git a/dashboard/src/app/projects/list-projects/list-projects.controller.js b/dashboard/src/app/projects/list-projects/list-projects.controller.js
index 10c5f030cdf..3d5932be4fb 100644
--- a/dashboard/src/app/projects/list-projects/list-projects.controller.js
+++ b/dashboard/src/app/projects/list-projects/list-projects.controller.js
@@ -22,7 +22,7 @@ export class ListProjectsCtrl {
* Default constructor that is using resource
* @ngInject for Dependency injection
*/
- constructor($mdDialog, cheAPI, cheNotification, lodash, $q) {
+ constructor($mdDialog, cheAPI, cheNotification, lodash, $q, $rootScope) {
this.$mdDialog = $mdDialog;
this.cheAPI = cheAPI;
this.cheNotification = cheNotification;
@@ -73,6 +73,8 @@ export class ListProjectsCtrl {
// projects on all workspaces
this.projects = [];
+
+ $rootScope.showIDE = false;
}
updateData() {
diff --git a/dashboard/src/app/workspaces/create-workspace/create-workspace.controller.js b/dashboard/src/app/workspaces/create-workspace/create-workspace.controller.js
index a526fa2095e..f9315562b7e 100644
--- a/dashboard/src/app/workspaces/create-workspace/create-workspace.controller.js
+++ b/dashboard/src/app/workspaces/create-workspace/create-workspace.controller.js
@@ -23,11 +23,12 @@ export class CreateWorkspaceCtrl {
* Default constructor that is using resource
* @ngInject for Dependency injection
*/
- constructor($location, cheAPI, cheNotification, lodash) {
+ constructor($location, cheAPI, cheNotification, lodash, $rootScope) {
this.$location = $location;
this.cheAPI = cheAPI;
this.cheNotification = cheNotification;
this.lodash = lodash;
+ this.$rootScope = $rootScope;
this.selectSourceOption = 'select-source-recipe';
@@ -56,6 +57,8 @@ export class CreateWorkspaceCtrl {
this.defaultWorkspaceName = null;
cheAPI.cheWorkspace.fetchWorkspaces();
+
+ $rootScope.showIDE = false;
}
/**
@@ -188,6 +191,11 @@ export class CreateWorkspaceCtrl {
*/
redirectAfterSubmitWorkspace(promise) {
promise.then((workspaceData) => {
+ // update list of workspaces
+ // for new workspace to show in recent workspaces
+ this.updateRecentWorkspace(workspaceData.id);
+ this.cheAPI.cheWorkspace.fetchWorkspaces();
+
let infoMessage = 'Workspace ' + workspaceData.config.name + ' successfully created.';
this.cheNotification.showInfo(infoMessage);
this.$location.path('/workspace/' + workspaceData.id);
@@ -197,4 +205,13 @@ export class CreateWorkspaceCtrl {
});
}
+ /**
+ * Emit event to move workspace immediately
+ * to top of the recent workspaces list
+ *
+ * @param workspaceId
+ */
+ updateRecentWorkspace(workspaceId) {
+ this.$rootScope.$broadcast('recent-workspace:set', workspaceId);
+ }
}
diff --git a/dashboard/src/app/workspaces/list-workspaces/list-workspaces.controller.js b/dashboard/src/app/workspaces/list-workspaces/list-workspaces.controller.js
index de92575985e..e8c0d03d2d2 100644
--- a/dashboard/src/app/workspaces/list-workspaces/list-workspaces.controller.js
+++ b/dashboard/src/app/workspaces/list-workspaces/list-workspaces.controller.js
@@ -22,7 +22,7 @@ export class ListWorkspacesCtrl {
* Default constructor that is using resource
* @ngInject for Dependency injection
*/
- constructor(cheAPI, $q, $log, $mdDialog, cheNotification, cheWorkspace) {
+ constructor(cheAPI, $q, $log, $mdDialog, cheNotification, cheWorkspace, $rootScope) {
this.cheAPI = cheAPI;
this.$q = $q;
this.$log = $log;
@@ -71,6 +71,8 @@ export class ListWorkspacesCtrl {
}
}
];
+
+ $rootScope.showIDE = false;
}
//Fetch current user's workspaces (where he is a member):
diff --git a/dashboard/src/app/workspaces/list-workspaces/workspace-item/workspace-item.html b/dashboard/src/app/workspaces/list-workspaces/workspace-item/workspace-item.html
index 7a9a3dbb64c..c6e66ea2225 100644
--- a/dashboard/src/app/workspaces/list-workspaces/workspace-item/workspace-item.html
+++ b/dashboard/src/app/workspaces/list-workspaces/workspace-item/workspace-item.html
@@ -39,7 +39,7 @@