Factory migration (#4413)
parent
2fcb0fbc1f
commit
62d32687c2
|
|
@ -155,6 +155,10 @@
|
|||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-github-oauth2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-github-pullrequest</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-github-shared</artifactId>
|
||||
|
|
@ -243,6 +247,14 @@
|
|||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-product-info</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-pullrequest-ide</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-pullrequest-shared</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-python-lang-ide</artifactId>
|
||||
|
|
|
|||
|
|
@ -1,2 +1,6 @@
|
|||
|
||||
RewriteRule ^/api/(.*)$ /wsmaster/api/$1 [L]
|
||||
RewriteRule ^/factory\\?(.*)$ /dashboard/#/load-factory/$1 [R,NE]
|
||||
RewriteRule ^/factory/(.*)$ /dashboard/#/load-factory/$1 [R,NE]
|
||||
RewriteRule ^/f/?(.*)$ /dashboard/#/load-factory/$1 [R,NE]
|
||||
RewriteRule ^/f\\?(.*)$ /dashboard/#/load-factory/$1 [R,NE]
|
||||
|
|
|
|||
|
|
@ -106,6 +106,10 @@
|
|||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-factory</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-machine</artifactId>
|
||||
|
|
@ -178,6 +182,10 @@
|
|||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-docker-machine</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-github-factory-resolver</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-github-oauth2</artifactId>
|
||||
|
|
@ -198,10 +206,18 @@
|
|||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-openshift-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-pullrequest-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-ssh-machine</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-url-factory</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.persistence</groupId>
|
||||
<artifactId>eclipselink</artifactId>
|
||||
|
|
@ -237,11 +253,6 @@
|
|||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-factory</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-commons-test</artifactId>
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ import org.eclipse.che.api.agent.shared.model.Agent;
|
|||
import org.eclipse.che.api.core.rest.CheJsonProvider;
|
||||
import org.eclipse.che.api.core.rest.MessageBodyAdapter;
|
||||
import org.eclipse.che.api.core.rest.MessageBodyAdapterInterceptor;
|
||||
import org.eclipse.che.api.factory.server.FactoryAcceptValidator;
|
||||
import org.eclipse.che.api.factory.server.FactoryCreateValidator;
|
||||
import org.eclipse.che.api.factory.server.FactoryEditValidator;
|
||||
import org.eclipse.che.api.factory.server.FactoryParametersResolver;
|
||||
import org.eclipse.che.api.machine.shared.Constants;
|
||||
import org.eclipse.che.api.user.server.TokenValidator;
|
||||
import org.eclipse.che.api.workspace.server.WorkspaceConfigMessageBodyAdapter;
|
||||
|
|
@ -36,6 +40,7 @@ import org.eclipse.che.api.workspace.server.WorkspaceMessageBodyAdapter;
|
|||
import org.eclipse.che.api.workspace.server.stack.StackMessageBodyAdapter;
|
||||
import org.eclipse.che.core.db.schema.SchemaInitializer;
|
||||
import org.eclipse.che.inject.DynaModule;
|
||||
import org.eclipse.che.plugin.github.factory.resolver.GithubFactoryParametersResolver;
|
||||
import org.flywaydb.core.internal.util.PlaceholderReplacer;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
|
@ -62,6 +67,18 @@ public class WsMasterModule extends AbstractModule {
|
|||
bind(org.eclipse.che.core.db.DBInitializer.class).asEagerSingleton();
|
||||
bind(PlaceholderReplacer.class).toProvider(org.eclipse.che.core.db.schema.impl.flyway.PlaceholderReplacerProvider.class);
|
||||
|
||||
//factory
|
||||
bind(FactoryAcceptValidator.class).to(org.eclipse.che.api.factory.server.impl.FactoryAcceptValidatorImpl.class);
|
||||
bind(FactoryCreateValidator.class).to(org.eclipse.che.api.factory.server.impl.FactoryCreateValidatorImpl.class);
|
||||
bind(FactoryEditValidator.class).to(org.eclipse.che.api.factory.server.impl.FactoryEditValidatorImpl.class);
|
||||
bind(org.eclipse.che.api.factory.server.FactoryService.class);
|
||||
install(new org.eclipse.che.api.factory.server.jpa.FactoryJpaModule());
|
||||
|
||||
Multibinder<FactoryParametersResolver> factoryParametersResolverMultibinder =
|
||||
Multibinder.newSetBinder(binder(), FactoryParametersResolver.class);
|
||||
factoryParametersResolverMultibinder.addBinding()
|
||||
.to(GithubFactoryParametersResolver.class);
|
||||
|
||||
install(new org.eclipse.che.plugin.docker.compose.ComposeModule());
|
||||
|
||||
bind(org.eclipse.che.api.user.server.CheUserCreator.class);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,18 @@
|
|||
<class>org.eclipse.che.api.machine.server.model.impl.SnapshotImpl</class>
|
||||
<class>org.eclipse.che.api.machine.server.recipe.RecipeImpl</class>
|
||||
|
||||
<class>org.eclipse.che.api.factory.server.model.impl.FactoryImpl</class>
|
||||
<class>org.eclipse.che.api.factory.server.model.impl.OnAppClosedImpl</class>
|
||||
<class>org.eclipse.che.api.factory.server.model.impl.OnProjectsLoadedImpl</class>
|
||||
<class>org.eclipse.che.api.factory.server.model.impl.OnAppLoadedImpl</class>
|
||||
<class>org.eclipse.che.api.factory.server.model.impl.PoliciesImpl</class>
|
||||
<class>org.eclipse.che.api.factory.server.model.impl.ActionImpl</class>
|
||||
<class>org.eclipse.che.api.factory.server.model.impl.AuthorImpl</class>
|
||||
<class>org.eclipse.che.api.factory.server.model.impl.ButtonAttributesImpl</class>
|
||||
<class>org.eclipse.che.api.factory.server.model.impl.ButtonImpl</class>
|
||||
<class>org.eclipse.che.api.factory.server.model.impl.IdeImpl</class>
|
||||
<class>org.eclipse.che.api.factory.server.FactoryImage</class>
|
||||
|
||||
<class>org.eclipse.che.api.ssh.server.model.impl.SshPairImpl</class>
|
||||
|
||||
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||
|
|
|
|||
|
|
@ -32,11 +32,6 @@ public interface Policies {
|
|||
*/
|
||||
Long getUntil();
|
||||
|
||||
/**
|
||||
* Re-open projects on factory 2-nd click
|
||||
*/
|
||||
String getMatch();
|
||||
|
||||
/**
|
||||
* Workspace creation strategy
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ public class CheCacheDisablingFilter extends CacheDisablingFilter {
|
|||
|
||||
private Set<Pattern> actionPatterns = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
Enumeration<String> names = filterConfig.getInitParameterNames();
|
||||
while (names.hasMoreElements()) {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ public class CheCacheForcingFilter extends CacheForcingFilter {
|
|||
|
||||
private Set<Pattern> actionPatterns = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
Enumeration<String> names = filterConfig.getInitParameterNames();
|
||||
while (names.hasMoreElements()) {
|
||||
|
|
|
|||
|
|
@ -107,23 +107,27 @@ public class CheCacheDisablingFilterTest {
|
|||
private class MockFilterConfig implements FilterConfig {
|
||||
private final Map<String, String> filterParams = new HashMap<>();
|
||||
|
||||
public MockFilterConfig() {
|
||||
MockFilterConfig() {
|
||||
this.filterParams.put("pattern1", "^.*\\.nocache\\..*$");
|
||||
this.filterParams.put("pattern2", "^.*/_app/.*$");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilterName() {
|
||||
return this.getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletContext getServletContext() {
|
||||
throw new UnsupportedOperationException("The method does not supported in " + this.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInitParameter(String key) {
|
||||
return this.filterParams.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getInitParameterNames() {
|
||||
return Collections.enumeration(filterParams.keySet());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,23 +108,27 @@ public class CheCacheForcingFilterTest {
|
|||
private class MockFilterConfig implements FilterConfig {
|
||||
private final Map<String, String> filterParams = new HashMap<>();
|
||||
|
||||
public MockFilterConfig() {
|
||||
MockFilterConfig() {
|
||||
this.filterParams.put("pattern1", "^.*\\.cache\\..*$");
|
||||
this.filterParams.put("pattern2", "^.*/_app/.*$");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilterName() {
|
||||
return this.getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletContext getServletContext() {
|
||||
throw new UnsupportedOperationException("The method does not supported in " + this.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInitParameter(String key) {
|
||||
return this.filterParams.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getInitParameterNames() {
|
||||
return Collections.enumeration(filterParams.keySet());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 controller of directive for displaying action box.
|
||||
* @ngdoc controller
|
||||
* @name factory.directive:FactoryActionBoxController
|
||||
* @author Florent Benoit
|
||||
*/
|
||||
export class FactoryActionBoxController {
|
||||
private $mdDialog: ng.material.IDialogService;
|
||||
private actions: Array<any>;
|
||||
private selectedAction: string;
|
||||
private factoryObject: any;
|
||||
private lifecycle: any;
|
||||
private onChange: Function;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource injection
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($mdDialog: ng.material.IDialogService) {
|
||||
this.$mdDialog = $mdDialog;
|
||||
|
||||
this.actions = [];
|
||||
this.actions.push({name : 'RunCommand', id: 'runcommand'});
|
||||
this.actions.push({name : 'openFile', id: 'openfile'});
|
||||
this.selectedAction = this.actions[0].id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit the action based on the provided index
|
||||
* @param $event the mouse event
|
||||
* @param index the index in the array of factory actions
|
||||
*/
|
||||
editAction($event: any, index: number): void {
|
||||
let action = this.factoryObject.ide[this.lifecycle].actions[index];
|
||||
this.$mdDialog.show({
|
||||
targetEvent: $event,
|
||||
controller: 'FactoryActionDialogEditController',
|
||||
controllerAs: 'factoryActionDialogEditCtrl',
|
||||
bindToController: true,
|
||||
clickOutsideToClose: true,
|
||||
locals: {
|
||||
callbackController: this,
|
||||
index: index,
|
||||
// selectedAction: action
|
||||
selectedValue: action.properties
|
||||
},
|
||||
templateUrl: 'app/factories/create-factory/action/factory-action-edit.html'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit action callback.
|
||||
*
|
||||
* @param index the index in the array of factory actions
|
||||
* @param newValue new value
|
||||
*/
|
||||
callbackEditAction(index: number, newValue: any): void {
|
||||
this.factoryObject.ide[this.lifecycle].actions[index].properties = newValue;
|
||||
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
addAction(): void {
|
||||
if (!this.factoryObject.ide) {
|
||||
this.factoryObject.ide = {};
|
||||
}
|
||||
if (!this.factoryObject.ide[this.lifecycle]) {
|
||||
this.factoryObject.ide[this.lifecycle] = {};
|
||||
this.factoryObject.ide[this.lifecycle].actions = [];
|
||||
}
|
||||
|
||||
let actionToAdd;
|
||||
if ('openfile' === this.selectedAction) {
|
||||
actionToAdd = {
|
||||
"properties": {
|
||||
"file": this.selectedParam
|
||||
},
|
||||
"id": "openFile"
|
||||
};
|
||||
} else if ('runcommand' === this.selectedAction) {
|
||||
actionToAdd = {
|
||||
"properties": {
|
||||
"name": this.selectedParam
|
||||
},
|
||||
"id": "runCommand"
|
||||
};
|
||||
}
|
||||
if (actionToAdd) {
|
||||
this.factoryObject.ide[this.lifecycle].actions.push(actionToAdd);
|
||||
}
|
||||
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove action based on the provided index
|
||||
* @param index the index in the array of factory actions
|
||||
*/
|
||||
removeAction(index: number): void {
|
||||
this.factoryObject.ide[this.lifecycle].actions.splice(index, 1);
|
||||
|
||||
this.onChange();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 action box.
|
||||
* @author Florent Benoit
|
||||
*/
|
||||
export class FactoryActionBox {
|
||||
private restrict: string;
|
||||
private templateUrl: string;
|
||||
private replace: boolean;
|
||||
private controller: string;
|
||||
private controllerAs: string;
|
||||
private bindToController: boolean;
|
||||
|
||||
private scope: {
|
||||
[propName: string]: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor() {
|
||||
this.restrict = 'E';
|
||||
|
||||
this.templateUrl = 'app/factories/create-factory/action/factory-action-box.html';
|
||||
this.replace = false;
|
||||
|
||||
this.controller = 'FactoryActionBoxController';
|
||||
this.controllerAs = 'factoryActionBoxCtrl';
|
||||
|
||||
this.bindToController = true;
|
||||
|
||||
// scope values
|
||||
this.scope = {
|
||||
lifecycle: '@cdvyLifecycle',
|
||||
actionTitle: '@?cdvyActionTitle',
|
||||
callbackController: '=cdvyCallbackController',
|
||||
factoryObject: '=cdvyFactoryObject',
|
||||
onChange: '&cdvyOnChange'
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<form name="actionsForm">
|
||||
<div class="factory-actions-panel" layout="column">
|
||||
<div layout="column" layout-align="start start">
|
||||
<div layout="row" layout-align="start start"
|
||||
class="factory-actions-input">
|
||||
<che-select che-option-values="factoryActionBoxCtrl.actions"
|
||||
che-place-holder="Select action"
|
||||
aria-label="Select action"
|
||||
che-size="3"
|
||||
che-value="factoryActionBoxCtrl.selectedAction">
|
||||
</che-select>
|
||||
<che-input che-name="value"
|
||||
che-form="actionsForm"
|
||||
che-place-holder="Enter value"
|
||||
aria-label="Enter value"
|
||||
required
|
||||
ng-model="factoryActionBoxCtrl.selectedParam">
|
||||
<div ng-message="required">Param is required.</div>
|
||||
</che-input>
|
||||
</div>
|
||||
<che-button-primary che-button-title="Add"
|
||||
ng-click="factoryActionBoxCtrl.addAction()"
|
||||
ng-disabled="actionsForm.$invalid"></che-button-primary>
|
||||
</div>
|
||||
|
||||
<div ng-if="factoryActionBoxCtrl.factoryObject.ide.onProjectsLoaded.actions.length > 0"
|
||||
class="factory-actions-list">
|
||||
<che-list>
|
||||
<che-list-item ng-repeat="action in factoryActionBoxCtrl.factoryObject.ide.onProjectsLoaded.actions"
|
||||
flex-gt-sm="100" flex-sm="33">
|
||||
<div layout="row" flex>
|
||||
<div layout="column"
|
||||
layout-align="start start"
|
||||
class="factory-actions-row-action-name">
|
||||
<span>{{action.id}}</span>
|
||||
</div>
|
||||
<div flex layout-align="start start"
|
||||
class="factory-actions-row-action-param"
|
||||
ng-click="factoryActionBoxCtrl.editAction($event, $index)">
|
||||
{{action.properties.name ? action.properties.name : action.properties.file}}
|
||||
</div>
|
||||
<div flex="10" layout="row" layout-align="center start"
|
||||
class="che-list-actions">
|
||||
<div ng-click="factoryActionBoxCtrl.removeAction($index)" class="factory-commands-widget-actions">
|
||||
<span class="fa fa-times-circle"></span>
|
||||
</div>
|
||||
<div ng-click="factoryActionBoxCtrl.editAction($event, $index)" class="factory-commands-widget-actions">
|
||||
<span class="fa fa-edit"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</che-list-item>
|
||||
</che-list>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
.factory-actions-panel
|
||||
margin-top -6px
|
||||
|
||||
& > div
|
||||
margin-bottom 10px
|
||||
|
||||
.factory-actions-input
|
||||
min-height 50px
|
||||
height 50px
|
||||
|
||||
.che-select
|
||||
margin-top 4px
|
||||
margin-right 20px
|
||||
|
||||
.factory-actions-list
|
||||
max-width 600px
|
||||
|
||||
md-list
|
||||
margin 0
|
||||
|
||||
div
|
||||
outline none
|
||||
|
||||
md-icon
|
||||
font-size 18px
|
||||
height auto
|
||||
width auto
|
||||
color $clear-foggy-sky-color
|
||||
line-height 18px
|
||||
|
||||
.factory-commands-widget-actions
|
||||
display inline-block
|
||||
line-height inherit
|
||||
min-height 100%
|
||||
cursor pointer
|
||||
outline none
|
||||
|
||||
span
|
||||
line-height inherit
|
||||
|
||||
.fa-times-circle::before,
|
||||
.fa-edit::before
|
||||
position relative
|
||||
top 3px
|
||||
|
||||
.factory-actions-row-action-name
|
||||
min-width 220px
|
||||
width 220px
|
||||
|
||||
span
|
||||
padding 2px
|
||||
|
||||
.factory-actions-row-action-param
|
||||
cursor pointer
|
||||
|
||||
.factory-edit-action-input
|
||||
margin-top -6px
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
import {FactoryActionBoxController} from './factory-action-box.controller';
|
||||
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name factory.directive:FactoryActionDialogEditController
|
||||
* @description This class is handling the controller for editing action of a factory
|
||||
* @author Florent Benoit
|
||||
*/
|
||||
export class FactoryActionDialogEditController {
|
||||
isName: boolean;
|
||||
isFile: boolean;
|
||||
selectedValue: { name: string; file: string };
|
||||
|
||||
private $mdDialog: ng.material.IDialogService;
|
||||
private index: number;
|
||||
private callbackController: FactoryActionBoxController;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($mdDialog: ng.material.IDialogService) {
|
||||
this.$mdDialog = $mdDialog;
|
||||
|
||||
this.isName = angular.isDefined(this.selectedValue.name);
|
||||
this.isFile = angular.isDefined(this.selectedValue.file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback of the edit button of the dialog.
|
||||
*/
|
||||
edit() {
|
||||
this.$mdDialog.hide();
|
||||
this.callbackController.callbackEditAction(this.index, this.selectedValue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback of the cancel button of the dialog.
|
||||
*/
|
||||
abort() {
|
||||
this.$mdDialog.hide();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<che-popup title="Edit action" on-close="factoryActionDialogEditCtrl.abort()">
|
||||
<form name="editActionForm" flex>
|
||||
<div ng-if="factoryActionDialogEditCtrl.isName">
|
||||
<che-input focusable
|
||||
che-name="Editing"
|
||||
che-form="editActionForm"
|
||||
che-label-name="Param"
|
||||
required
|
||||
ng-model="factoryActionDialogEditCtrl.selectedValue.name">
|
||||
<div ng-message="required">Param is required</div>
|
||||
</che-input>
|
||||
</div>
|
||||
<div ng-if="factoryActionDialogEditCtrl.isFile">
|
||||
<che-input focusable
|
||||
che-name="Editing"
|
||||
che-form="editActionForm"
|
||||
che-label-name="Param"
|
||||
required
|
||||
ng-model="factoryActionDialogEditCtrl.selectedValue.file">
|
||||
<div ng-message="required">Param is required</div>
|
||||
</che-input>
|
||||
</div>
|
||||
<che-button-notice che-button-title="Close"
|
||||
ng-click="factoryActionDialogEditCtrl.abort()">
|
||||
</che-button-notice>
|
||||
<che-button-primary
|
||||
che-button-title="Edit" ng-disabled="editActionForm.$invalid"
|
||||
ng-click="factoryActionDialogEditCtrl.edit()"></che-button-primary>
|
||||
</form>
|
||||
</che-popup>
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 factory.directive:FactoryCommandDialogEditController
|
||||
* @description This class is handling the controller for editing command of a factory
|
||||
* @author Florent Benoit
|
||||
*/
|
||||
export class FactoryCommandDialogEditController {
|
||||
private $mdDialog: ng.material.IDialogService;
|
||||
private callbackController: any;
|
||||
private index: number;
|
||||
private selectedValue: any;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($mdDialog: ng.material.IDialogService) {
|
||||
this.$mdDialog = $mdDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback of the edit button of the dialog.
|
||||
*/
|
||||
edit(): void {
|
||||
this.$mdDialog.hide();
|
||||
this.callbackController.callbackEditAction(this.index, this.selectedValue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback of the cancel button of the dialog.
|
||||
*/
|
||||
abort(): void {
|
||||
this.$mdDialog.hide();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<che-popup title="Edit command" on-close="factoryCommandDialogEditCtrl.abort()">
|
||||
<form name="editActionForm" flex>
|
||||
<che-input focusable
|
||||
che-name="Editing"
|
||||
che-form="editActionForm"
|
||||
che-label-name="Param"
|
||||
required
|
||||
ng-model="factoryCommandDialogEditCtrl.selectedValue">
|
||||
<div ng-message="required">Param is required</div>
|
||||
</che-input>
|
||||
<che-button-notice che-button-title="Close"
|
||||
ng-click="factoryCommandDialogEditCtrl.abort()">
|
||||
</che-button-notice>
|
||||
<che-button-primary
|
||||
che-button-title="Edit" ng-disabled="editActionForm.$invalid"
|
||||
ng-click="factoryCommandDialogEditCtrl.edit()"></che-button-primary>
|
||||
</form>
|
||||
</che-popup>
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 controller of directive for displaying factory command.
|
||||
* @ngdoc controller
|
||||
* @name factory.directive:FactoryCommandController
|
||||
* @author Florent Benoit
|
||||
*/
|
||||
export class FactoryCommandController {
|
||||
private $mdDialog: ng.material.IDialogService;
|
||||
private factoryObject: any;
|
||||
private onChange: Function;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource injection
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($mdDialog: ng.material.IDialogService) {
|
||||
this.$mdDialog = $mdDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* User clicked on the add button to add a new command
|
||||
* @param $event
|
||||
*/
|
||||
addCommand(): void {
|
||||
if (!this.factoryObject) {
|
||||
this.factoryObject = {};
|
||||
}
|
||||
|
||||
if (!this.factoryObject.workspace) {
|
||||
this.factoryObject.workspace = {};
|
||||
}
|
||||
|
||||
if (!this.factoryObject.workspace.commands) {
|
||||
this.factoryObject.workspace.commands = [];
|
||||
}
|
||||
let command = {
|
||||
"commandLine": this.commandLine,
|
||||
"name": this.commandLineName,
|
||||
"attributes": {
|
||||
"previewUrl": ""
|
||||
},
|
||||
"type": "custom"
|
||||
};
|
||||
|
||||
this.factoryObject.workspace.commands.push(command);
|
||||
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove command based on the provided index
|
||||
* @param index the index in the array of workspace commands
|
||||
*/
|
||||
removeCommand(index: number): void {
|
||||
this.factoryObject.workspace.commands.splice(index, 1);
|
||||
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit the command based on the provided index
|
||||
* @param $event the mouse event
|
||||
* @param index the index in the array of workspace commands
|
||||
*/
|
||||
editCommand($event: any, index: number): void {
|
||||
this.$mdDialog.show({
|
||||
targetEvent: $event,
|
||||
controller: 'FactoryCommandDialogEditController',
|
||||
controllerAs: 'factoryCommandDialogEditCtrl',
|
||||
bindToController: true,
|
||||
clickOutsideToClose: true,
|
||||
locals: {
|
||||
callbackController: this,
|
||||
index: index,
|
||||
selectedValue: this.factoryObject.workspace.commands[index].commandLine
|
||||
},
|
||||
templateUrl: 'app/factories/create-factory/command/factory-command-edit.html'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback on edit action.
|
||||
*
|
||||
* @param index commands index
|
||||
* @param newValue value to update with
|
||||
*/
|
||||
callbackEditAction(index: number, newValue: string) {
|
||||
this.factoryObject.workspace.commands[index].commandLine = newValue;
|
||||
|
||||
this.onChange();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 factory commands.
|
||||
* @author Florent Benoit
|
||||
*/
|
||||
export class FactoryCommand {
|
||||
private restrict: string;
|
||||
private templateUrl: string;
|
||||
private replace: boolean;
|
||||
private controller: string;
|
||||
private controllerAs: string;
|
||||
private bindToController: boolean;
|
||||
|
||||
private scope: {
|
||||
[propName: string]: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor() {
|
||||
this.restrict = 'E';
|
||||
|
||||
this.templateUrl = 'app/factories/create-factory/command/factory-command.html';
|
||||
this.replace = false;
|
||||
|
||||
this.controller = 'FactoryCommandController';
|
||||
this.controllerAs = 'factoryCommandCtrl';
|
||||
|
||||
this.bindToController = true;
|
||||
|
||||
// scope values
|
||||
this.scope = {
|
||||
factoryObject: '=cdvyFactoryObject',
|
||||
onChange: '&cdvyOnChange'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<form name="commandsForm">
|
||||
<div class="factory-commands-panel" layout="column">
|
||||
<div layout="column" layout-align="start start">
|
||||
<div layout="row" layout-align="start start"
|
||||
class="factory-commands-input">
|
||||
<che-input che-form="commandsForm"
|
||||
che-name="name"
|
||||
che-place-holder="Name of the command"
|
||||
aria-label="Name of the command"
|
||||
ng-model="factoryCommandCtrl.commandLineName"
|
||||
required
|
||||
ng-minlength="1"
|
||||
ng-maxlength="20"
|
||||
ng-pattern="/^[A-Za-z0-9_\-\.]+$/">
|
||||
<div ng-message="required">A name is required.</div>
|
||||
<div ng-message="pattern">Workspace name may contain digits, latin letters, _ , . , - and should start only
|
||||
with digits, latin
|
||||
letters or underscores
|
||||
</div>
|
||||
<div ng-message="minlength">The name has to be more than 1 character long.</div>
|
||||
<div ng-message="maxlength">The name has to be less than 20 characters long.</div>
|
||||
</che-input>
|
||||
<che-input che-form="commandsForm"
|
||||
che-name="commandLine"
|
||||
aria-label="Command"
|
||||
che-place-holder="Command Line: example: mvn clean install -f ${current.project.path}"
|
||||
che-width="auto"
|
||||
ng-model="factoryCommandCtrl.commandLine"
|
||||
required
|
||||
ng-minlength="1"
|
||||
ng-maxlength="500">
|
||||
<div ng-message="required">A name is required.</div>
|
||||
<div ng-message="minlength">The name has to be more than 1 character long.</div>
|
||||
<div ng-message="maxlength">The name has to be less than 500 characters long.</div>
|
||||
</che-input>
|
||||
</div>
|
||||
<che-button-primary che-button-title="Add"
|
||||
ng-click="factoryCommandCtrl.addCommand()"
|
||||
ng-disabled="commandsForm.$invalid"></che-button-primary>
|
||||
</div>
|
||||
|
||||
<div ng-if="factoryCommandCtrl.factoryObject.workspace.commands.length > 0"
|
||||
class="factory-commands-list">
|
||||
<che-list>
|
||||
<che-list-item ng-repeat="command in factoryCommandCtrl.factoryObject.workspace.commands"
|
||||
flex="100">
|
||||
<div layout="row" flex>
|
||||
<div layout="column"
|
||||
layout-align="start start"
|
||||
class="factory-commands-row-command-name">
|
||||
<span>{{command.name}}</span>
|
||||
</div>
|
||||
<div flex
|
||||
layout="column"
|
||||
layout-align="start start"
|
||||
ng-click="factoryCommandCtrl.editCommand($event, $index)"
|
||||
class="factory-commands-row-command">
|
||||
{{command.commandLine}}
|
||||
</div>
|
||||
<div flex="10" layout="row" layout-align="center start"
|
||||
class="che-list-actions">
|
||||
<div ng-click="factoryCommandCtrl.removeCommand($index)" class="factory-commands-widget-actions">
|
||||
<span class="fa fa-times-circle"></span>
|
||||
</div>
|
||||
<div ng-click="factoryCommandCtrl.editCommand($event, $index)" class="factory-commands-widget-actions">
|
||||
<span class="fa fa-edit"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</che-list-item>
|
||||
</che-list>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
.factory-commands-panel
|
||||
margin-top -6px
|
||||
|
||||
& > div
|
||||
margin-bottom 10px
|
||||
|
||||
.factory-commands-input
|
||||
min-height 50px
|
||||
height 50px
|
||||
|
||||
.che-input
|
||||
margin-right 20px
|
||||
|
||||
.factory-commands-list
|
||||
max-width 600px
|
||||
|
||||
md-list
|
||||
margin 0
|
||||
|
||||
div
|
||||
outline none
|
||||
|
||||
md-icon
|
||||
font-size 18px
|
||||
height auto
|
||||
width auto
|
||||
color $clear-foggy-sky-color
|
||||
line-height 18px
|
||||
|
||||
.factory-commands-widget-actions
|
||||
display inline-block
|
||||
line-height inherit
|
||||
min-height 100%
|
||||
cursor pointer
|
||||
outline none
|
||||
|
||||
span
|
||||
line-height inherit
|
||||
|
||||
.fa-times-circle::before,
|
||||
.fa-edit::before
|
||||
position relative
|
||||
top 3px
|
||||
|
||||
.factory-commands-row-command-name
|
||||
min-width 220px
|
||||
width 220px
|
||||
|
||||
span
|
||||
padding 2px
|
||||
|
||||
.factory-commands-row-command
|
||||
cursor pointer
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
import {CheNotification} from '../../../../components/notification/che-notification.factory';
|
||||
import {CheAPI} from '../../../../components/api/che-api.factory';
|
||||
|
||||
/* global FileReader */
|
||||
|
||||
/**
|
||||
* Controller for upload factory from the file.
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class FactoryFromFileCtrl {
|
||||
private cheAPI: CheAPI;
|
||||
private cheNotification: CheNotification;
|
||||
private uploader: any;
|
||||
private isImporting: boolean;
|
||||
private factoryContent: any;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource injection
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($filter: ng.IFilterService, cheAPI: CheAPI, cheNotification: CheNotification, FileUploader: any) {
|
||||
'ngInject';
|
||||
|
||||
this.cheAPI = cheAPI;
|
||||
this.cheNotification = cheNotification;
|
||||
|
||||
// if you want select just one file, you won't need to clear the input
|
||||
FileUploader.FileSelect.prototype.isEmptyAfterSelection = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
this.uploader = new FileUploader();
|
||||
|
||||
// settings
|
||||
this.uploader.queueLimit = 1; // maximum count of files
|
||||
this.uploader.autoUpload = true; // automatically upload files after adding them to the queue
|
||||
this.uploader.removeAfterUpload = true; // automatically remove files from the queue after uploading
|
||||
|
||||
this.isImporting = this.uploader.isUploading;
|
||||
|
||||
var ctrl = this;
|
||||
|
||||
// filters
|
||||
this.uploader.filters.push({
|
||||
name: 'sizeFilter',
|
||||
fn: (item: any) => {
|
||||
// file must not be smaller then some size
|
||||
let isValidSize = item.size > 0 && item.size < 500000;
|
||||
|
||||
if (!isValidSize) {
|
||||
ctrl.cheNotification.showError('File size error.');
|
||||
}
|
||||
return isValidSize;
|
||||
}
|
||||
});
|
||||
|
||||
this.uploader.filters.push({
|
||||
name: 'typeFilter',
|
||||
fn: (item: any) => {
|
||||
// file must be json
|
||||
let isValidItem = item.type === 'application/json' || item.type === '';
|
||||
|
||||
if (!isValidItem) {
|
||||
ctrl.cheNotification.showError('File type error.');
|
||||
}
|
||||
return isValidItem;
|
||||
}
|
||||
});
|
||||
|
||||
// callback
|
||||
this.uploader.onAfterAddingFile = function (fileItem) {
|
||||
let uploadedFileName = fileItem._file.name;
|
||||
let reader = new FileReader();
|
||||
|
||||
reader.readAsText(fileItem._file);
|
||||
reader.onload = function () {
|
||||
try {
|
||||
ctrl.factoryContent = $filter('json')(angular.fromJson(reader.result), 2);
|
||||
ctrl.cheNotification.showInfo('Successfully loaded file\'s configuration ' + uploadedFileName + '.');
|
||||
} catch (e) {
|
||||
// invalid JSON
|
||||
ctrl.factoryContent = null;
|
||||
ctrl.cheNotification.showError('Invalid JSON.');
|
||||
}
|
||||
};
|
||||
reader.onerror = function (error: any) {
|
||||
ctrl.cheNotification.showError(error.data.message ? error.data.message : 'Error reading file.');
|
||||
console.log('Error reading file');
|
||||
};
|
||||
};
|
||||
|
||||
this.factoryContent = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 configuring factory from file.
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class FactoryFromFile {
|
||||
private restrict: string;
|
||||
private templateUrl: string;
|
||||
private replace: boolean;
|
||||
private controller: string;
|
||||
private controllerAs: string;
|
||||
private bindToController: boolean;
|
||||
|
||||
private scope: {
|
||||
[propName: string]: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor() {
|
||||
this.restrict = 'E';
|
||||
|
||||
this.templateUrl = 'app/factories/create-factory/config-file-tab/factory-from-file.html';
|
||||
this.replace = false;
|
||||
|
||||
this.controller = 'FactoryFromFileCtrl';
|
||||
this.controllerAs = 'factoryFromFileCtrl';
|
||||
|
||||
this.bindToController = true;
|
||||
|
||||
// scope values
|
||||
this.scope = {
|
||||
isImporting: '=cdvyIsImporting',
|
||||
factoryContent: '=cdvyFactoryContent'
|
||||
};
|
||||
}
|
||||
|
||||
link($scope: ng.IScope, element: ng.IAugmentedJQuery) {
|
||||
$scope.clickUpload = () => {
|
||||
// search the input fields
|
||||
let inputElements = element.find('input');
|
||||
inputElements.eq(0).click();
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<!--
|
||||
|
||||
CODENVY CONFIDENTIAL
|
||||
__________________
|
||||
|
||||
[2015] - [2016] Codenvy, S.A.
|
||||
All Rights Reserved.
|
||||
|
||||
NOTICE: All information contained herein is, and remains
|
||||
the property of Codenvy S.A. and its suppliers,
|
||||
if any. The intellectual and technical concepts contained
|
||||
herein are proprietary to Codenvy S.A.
|
||||
and its suppliers and may be covered by U.S. and Foreign Patents,
|
||||
patents in process, and are protected by trade secret or copyright law.
|
||||
Dissemination of this information or reproduction of this material
|
||||
is strictly forbidden unless prior written permission is obtained
|
||||
from Codenvy S.A..
|
||||
|
||||
-->
|
||||
<div class="factory-from-file" layout="row" flex layout-align="start center">
|
||||
<che-label-container che-label-name="File">
|
||||
<div layout="row">
|
||||
<button ng-disabled="factoryFromFileCtrl.uploader.queue.length > 0 || factoryFromFileCtrl.uploader.isUploading" tabindex="0"
|
||||
md-theme="default" ng-click="clickUpload()"
|
||||
class="md-accent md-raised md-hue-2 md-button md-default-theme">
|
||||
<span class="ng-scope">Upload file</span>
|
||||
</button>
|
||||
<input type="file" accept="application/json" uploader="factoryFromFileCtrl.uploader" nv-file-select/>
|
||||
</div>
|
||||
</che-label-container>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
.factory-from-file
|
||||
min-height 80px
|
||||
|
||||
.factory-from-file label
|
||||
font-size inherit
|
||||
|
||||
.factory-from-file input
|
||||
display none
|
||||
|
||||
.factory-from-file button
|
||||
box-shadow 0 2px 5px 0 $disabled-color
|
||||
border-radius 2px !important
|
||||
padding-right 20px
|
||||
padding-left 20px
|
||||
font-size 1.5em
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
|
||||
|
||||
import {CreateFactoryCtrl} from '../create-factory/create-factory.controller';
|
||||
|
||||
import {FactoryFromWorkspaceCtrl} from '../create-factory/workspaces-tab/factory-from-workpsace.controller';
|
||||
import {FactoryFromWorkspace} from '../create-factory/workspaces-tab/factory-from-workspace.directive';
|
||||
import {FactoryFromFileCtrl} from '../create-factory/config-file-tab/factory-from-file.controller';
|
||||
import {FactoryFromFile} from '../create-factory/config-file-tab/factory-from-file.directive';
|
||||
import {FactoryFromTemplateCtrl} from '../create-factory/template-tab/factory-from-template.controller';
|
||||
import {FactoryFromTemplate} from '../create-factory/template-tab/factory-from-template.directive';
|
||||
import {FactoryActionBoxController} from './action/factory-action-box.controller';
|
||||
import {FactoryActionBox} from './action/factory-action-box.directive';
|
||||
import {FactoryActionDialogEditController} from './action/factory-action-edit.controller';
|
||||
import {FactoryCommandController} from './command/factory-command.controller';
|
||||
import {FactoryCommand} from './command/factory-command.directive';
|
||||
import {FactoryCommandDialogEditController} from './command/factory-command-edit.controller';
|
||||
import {CreateFactoryGitController} from './git/create-factory-git.controller';
|
||||
import {CreateFactoryGit} from './git/create-factory-git.directive';
|
||||
|
||||
export class CreateFactoryConfig {
|
||||
|
||||
constructor(register: che.IRegisterService) {
|
||||
|
||||
register.controller('CreateFactoryCtrl', CreateFactoryCtrl);
|
||||
|
||||
register.controller('FactoryFromWorkspaceCtrl', FactoryFromWorkspaceCtrl);
|
||||
register.directive('cdvyFactoryFromWorkspace', FactoryFromWorkspace);
|
||||
|
||||
register.controller('FactoryFromFileCtrl', FactoryFromFileCtrl);
|
||||
register.directive('cdvyFactoryFromFile', FactoryFromFile);
|
||||
|
||||
register.controller('FactoryFromTemplateCtrl', FactoryFromTemplateCtrl);
|
||||
register.directive('cdvyFactoryFromTemplate', FactoryFromTemplate);
|
||||
|
||||
register.controller('FactoryActionBoxController', FactoryActionBoxController);
|
||||
register.directive('cdvyFactoryActionBox', FactoryActionBox);
|
||||
|
||||
register.controller('FactoryCommandController', FactoryCommandController);
|
||||
register.directive('cdvyFactoryCommand', FactoryCommand);
|
||||
|
||||
register.controller('CreateFactoryGitController', CreateFactoryGitController);
|
||||
register.directive('cdvyCreateFactoryGit', CreateFactoryGit);
|
||||
|
||||
register.controller('FactoryActionDialogEditController', FactoryActionDialogEditController);
|
||||
register.controller('FactoryCommandDialogEditController', FactoryCommandDialogEditController);
|
||||
|
||||
|
||||
|
||||
// config routes
|
||||
register.app.config(($routeProvider: any) => {
|
||||
$routeProvider.accessWhen('/factories/create-factory', {
|
||||
title: 'New Factory',
|
||||
templateUrl: 'app/factories/create-factory/create-factory.html',
|
||||
controller: 'CreateFactoryCtrl',
|
||||
controllerAs: 'createFactoryCtrl'
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
import {CheAPI} from '../../../components/api/che-api.factory';
|
||||
import {CheNotification} from '../../../components/notification/che-notification.factory';
|
||||
|
||||
/**
|
||||
* Controller for a create factory.
|
||||
* @author Oleksii Orel
|
||||
* @author Florent Benoit
|
||||
*/
|
||||
export class CreateFactoryCtrl {
|
||||
private $location: ng.ILocationService;
|
||||
private $log: ng.ILogService;
|
||||
private cheAPI: CheAPI;
|
||||
private cheNotification: CheNotification;
|
||||
private lodash: _.LoDashStatic;
|
||||
private $filter: ng.IFilterService;
|
||||
private $document: ng.IDocumentService;
|
||||
private isLoading: boolean;
|
||||
private isImporting: boolean;
|
||||
private stackRecipeMode: string;
|
||||
private factoryContent: any;
|
||||
private factoryObject: any;
|
||||
private form: any;
|
||||
private name: string;
|
||||
private factoryId: string;
|
||||
private factoryLink: string;
|
||||
private factoryBadgeUrl: string;
|
||||
private markdown: string;
|
||||
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource injection
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($location: ng.ILocationService, cheAPI: CheAPI, $log: ng.ILogService, cheNotification: CheNotification, $scope: ng.IScope,
|
||||
$filter: ng.IFilterService, lodash: _.LoDashStatic, $document: ng.IDocumentService) {
|
||||
this.$location = $location;
|
||||
this.cheAPI = cheAPI;
|
||||
this.$log = $log;
|
||||
this.cheNotification = cheNotification;
|
||||
this.$filter = $filter;
|
||||
this.lodash = lodash;
|
||||
this.$document = $document;
|
||||
|
||||
this.isLoading = false;
|
||||
this.isImporting = false;
|
||||
|
||||
this.stackRecipeMode = 'current-recipe';
|
||||
|
||||
this.factoryContent = null;
|
||||
|
||||
$scope.$watch('createFactoryCtrl.factoryObject', () => {
|
||||
this.factoryContent = this.$filter('json')(angular.fromJson(this.factoryObject));
|
||||
}, true);
|
||||
|
||||
$scope.$watch('createFactoryCtrl.gitLocation', (newValue: string) => {
|
||||
// update underlying model
|
||||
// updating first project item
|
||||
if (!this.factoryObject) {
|
||||
let templateName = 'git';
|
||||
let promise = this.cheAPI.getFactoryTemplate().fetchFactoryTemplate(templateName);
|
||||
|
||||
promise.then(() => {
|
||||
let factoryContent = this.cheAPI.getFactoryTemplate().getFactoryTemplate(templateName);
|
||||
this.factoryObject = angular.fromJson(factoryContent);
|
||||
this.updateGitProjectLocation(newValue);
|
||||
});
|
||||
} else {
|
||||
this.updateGitProjectLocation(newValue);
|
||||
}
|
||||
|
||||
}, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear factory content
|
||||
*/
|
||||
clearFactoryContent(): void {
|
||||
this.factoryContent = null;
|
||||
}
|
||||
|
||||
setForm(form: any): void {
|
||||
this.form = form;
|
||||
}
|
||||
|
||||
isFormInvalid(): boolean {
|
||||
return this.form ? this.form.$invalid: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the source project location for git
|
||||
* @param location the new location
|
||||
*/
|
||||
updateGitProjectLocation(location: string): void {
|
||||
let project = this.factoryObject.workspace.projects[0];
|
||||
project.source.type = 'git';
|
||||
project.source.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory by factory content
|
||||
* @param factoryContent
|
||||
*/
|
||||
createFactoryByContent(factoryContent: any): void {
|
||||
if (!factoryContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// try to set factory name
|
||||
try {
|
||||
let factoryObject = angular.fromJson(factoryContent);
|
||||
factoryObject.name = this.name;
|
||||
factoryContent = angular.toJson(factoryObject);
|
||||
} catch (e) {
|
||||
this.$log.error(e);
|
||||
}
|
||||
|
||||
this.isImporting = true;
|
||||
|
||||
let promise = this.cheAPI.getFactory().createFactoryByContent(factoryContent);
|
||||
|
||||
promise.then((factory: che.IFactory) => {
|
||||
this.isImporting = false;
|
||||
|
||||
this.lodash.find(factory.links, (link: any) => {
|
||||
if (link.rel === 'accept' || link.rel === 'accept-named') {
|
||||
this.factoryLink = link.href;
|
||||
}
|
||||
});
|
||||
|
||||
var parser = this.$document[0].createElement('a');
|
||||
parser.href = this.factoryLink;
|
||||
this.factoryId = factory.id;
|
||||
this.factoryBadgeUrl = parser.protocol + '//' + parser.hostname + '/factory/resources/codenvy-contribute.svg';
|
||||
|
||||
this.markdown = '[](' + this.factoryLink + ')';
|
||||
}, (error: any) => {
|
||||
this.isImporting = false;
|
||||
this.cheNotification.showError(error.data.message ? error.data.message : 'Create factory failed.');
|
||||
this.$log.error(error);
|
||||
}).then(() => {
|
||||
this.finishFlow();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Flow of creating a factory is finished, we can redirect to details of factory
|
||||
*/
|
||||
finishFlow(): void {
|
||||
this.clearFactoryContent();
|
||||
this.$location.path('/factory/' + this.factoryId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
<!--
|
||||
|
||||
CODENVY CONFIDENTIAL
|
||||
__________________
|
||||
|
||||
[2015] - [2016] Codenvy, S.A.
|
||||
All Rights Reserved.
|
||||
|
||||
NOTICE: All information contained herein is, and remains
|
||||
the property of Codenvy S.A. and its suppliers,
|
||||
if any. The intellectual and technical concepts contained
|
||||
herein are proprietary to Codenvy S.A.
|
||||
and its suppliers and may be covered by U.S. and Foreign Patents,
|
||||
patents in process, and are protected by trade secret or copyright law.
|
||||
Dissemination of this information or reproduction of this material
|
||||
is strictly forbidden unless prior written permission is obtained
|
||||
from Codenvy S.A..
|
||||
|
||||
-->
|
||||
<che-toolbar che-title="New Factory From"></che-toolbar>
|
||||
|
||||
<md-content md-scroll-y flex md-theme="default">
|
||||
<md-progress-linear md-mode="indeterminate" class="create-factory-progress"
|
||||
ng-show="createFactoryCtrl.isLoading"></md-progress-linear>
|
||||
<div class="create-factory" ng-hide="createFactoryCtrl.isLoading">
|
||||
|
||||
<!-- Name -->
|
||||
<che-label-container che-label-name="Name">
|
||||
<ng-form name="createFactoryForm">
|
||||
<div layout="column" class="create-factory-input"
|
||||
ng-init="createFactoryCtrl.setForm(createFactoryForm)">
|
||||
<che-input-box che-form="createFactoryForm"
|
||||
che-name="name"
|
||||
che-place-holder="Name of the factory"
|
||||
aria-label="Name of the factory"
|
||||
ng-model="createFactoryCtrl.name"
|
||||
ng-trim
|
||||
ng-minlength="3"
|
||||
ng-maxlength="20"
|
||||
ng-pattern="/^[ A-Za-z0-9_\-\.]+$/">
|
||||
<div ng-message="required">A name is required.</div>
|
||||
<div ng-message="pattern">Factory name may contain digits, latin letters, spaces, _ , . , - and should start
|
||||
only
|
||||
with digits, latin letters or underscores
|
||||
</div>
|
||||
<div ng-message="minlength">The name has to be more than 3 characters long.</div>
|
||||
<div ng-message="maxlength">The name has to be less than 20 characters long.</div>
|
||||
</che-input-box>
|
||||
</div>
|
||||
</ng-form>
|
||||
</che-label-container>
|
||||
|
||||
<!--Factory source-->
|
||||
<che-label-container che-label-name="Source"
|
||||
class="che-label-container-last">
|
||||
<md-tabs md-dynamic-height="true" md-stretch-tabs="auto" md-center-tabs="false" md-selected="selectedIndex"
|
||||
md-border-bottom="true"
|
||||
class="factory-select-source-details">
|
||||
<md-tab md-on-select="createFactoryCtrl.clearFactoryContent()">
|
||||
<md-tab-label>
|
||||
<md-icon md-font-icon="fa fa-server" class="che-tab-label-icon"></md-icon>
|
||||
<span class="che-tab-label-title">Workspace</span>
|
||||
</md-tab-label>
|
||||
<md-tab-body>
|
||||
<cdvy-factory-from-workspace cdvy-factory-content="createFactoryCtrl.factoryContent"
|
||||
cdvy-is-loading="createFactoryCtrl.isLoading"
|
||||
cdvy-is-importing="createFactoryCtrl.isImporting"></cdvy-factory-from-workspace>
|
||||
</md-tab-body>
|
||||
</md-tab>
|
||||
<md-tab md-on-select="createFactoryCtrl.clearFactoryContent()">
|
||||
<md-tab-label>
|
||||
<md-icon md-font-icon="fa-git" class="fa che-tab-label-icon"></md-icon>
|
||||
<span class="che-tab-label-title">Git</span>
|
||||
</md-tab-label>
|
||||
<md-tab-body>
|
||||
<div layout="row" layout-align="start center" class="create-factory-git-content">
|
||||
<cdvy-create-factory-git cdvy-git-location="createFactoryCtrl.gitLocation" layout-fill
|
||||
layout-align="start start"></cdvy-create-factory-git>
|
||||
</div>
|
||||
</md-tab-body>
|
||||
</md-tab>
|
||||
<md-tab md-on-select="createFactoryCtrl.clearFactoryContent()">
|
||||
<md-tab-label>
|
||||
<md-icon md-font-icon="fa fa-download" class="che-tab-label-icon"></md-icon>
|
||||
<span class="che-tab-label-title">Config</span>
|
||||
</md-tab-label>
|
||||
<md-tab-body>
|
||||
<div layout-fill layout="row" layout-align="start center">
|
||||
<cdvy-factory-from-file cdvy-factory-content="createFactoryCtrl.factoryContent"
|
||||
cdvy-is-importing="createFactoryCtrl.isImporting" layout="column"
|
||||
flex></cdvy-factory-from-file>
|
||||
</div>
|
||||
</md-tab-body>
|
||||
</md-tab>
|
||||
<md-tab md-on-select="createFactoryCtrl.clearFactoryContent(); templateSelected = true;" md-on-deselect="templateSelected = false;">
|
||||
<md-tab-label>
|
||||
<md-icon md-font-icon="fa fa-magic" class="che-tab-label-icon"></md-icon>
|
||||
<span class="che-tab-label-title">Template</span>
|
||||
</md-tab-label>
|
||||
<md-tab-body>
|
||||
<div layout-fill layout="row" layout-align="start center" ng-if="templateSelected">
|
||||
<cdvy-factory-from-template cdvy-factory-content="createFactoryCtrl.factoryContent"
|
||||
cdvy-is-importing="createFactoryCtrl.isImporting" layout="column"
|
||||
flex></cdvy-factory-from-template>
|
||||
</div>
|
||||
</md-tab-body>
|
||||
</md-tab>
|
||||
</md-tabs>
|
||||
</che-label-container>
|
||||
|
||||
<!--button 'Create'-->
|
||||
<che-button-primary id="create-factory-next-button"
|
||||
che-button-title="Create"
|
||||
ng-click="createFactoryCtrl.createFactoryByContent(createFactoryCtrl.factoryContent)"
|
||||
ng-disabled="createFactoryCtrl.isFormInvalid() || !createFactoryCtrl.factoryContent || createFactoryCtrl.isImporting || createFactoryCtrl.isLoading"></che-button-primary>
|
||||
</div>
|
||||
</md-content>
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
md-content .create-factory
|
||||
overflow auto
|
||||
min-height calc(100vh - 152px)
|
||||
background-color $white-color !important
|
||||
padding 0 14px
|
||||
|
||||
button
|
||||
margin-left 0
|
||||
margin-right 0
|
||||
margin-bottom 16px
|
||||
|
||||
.che-label-container-content .create-factory-input
|
||||
margin -6px 0
|
||||
|
||||
md-progress-linear.create-factory-progress
|
||||
z-index 1
|
||||
height 10px
|
||||
position absolute
|
||||
|
||||
.create-factory .factory-configuration-panel p
|
||||
font-weight bold
|
||||
margin-bottom 20px
|
||||
color $red-lipstick-color
|
||||
|
||||
.create-factory md-tabs-content-wrapper
|
||||
display inline
|
||||
|
||||
che-button-primary#create-factory-next-button button
|
||||
margin 10px 0 100px
|
||||
font-size 1.2em
|
||||
width 100% !important
|
||||
|
||||
.create-factory-share-header-widget
|
||||
border-top 1px solid $primary-color
|
||||
box-shadow-simple()
|
||||
padding-left 24px
|
||||
padding-right 24px
|
||||
padding-bottom 0px
|
||||
min-height 80px !important
|
||||
max-height 80px !important
|
||||
background-color $background-color
|
||||
z-index 4
|
||||
|
||||
.create-factory-share-header-widget-badge
|
||||
margin-left 20px
|
||||
margin-right 20px
|
||||
|
||||
.create-factory-share-header-widget-markdown
|
||||
text-align center
|
||||
height 18px
|
||||
font-size 0.9em
|
||||
margin-right 15px
|
||||
padding-left 10px
|
||||
padding-right 10px
|
||||
border 1px solid $label-info-color
|
||||
border-radius 2px
|
||||
|
||||
.create-factory-share-header-widget-clipboard
|
||||
font-size 1.3em
|
||||
|
||||
.create-factory-share-header-widget-icon
|
||||
font-size 3em
|
||||
color $default-dark-color
|
||||
margin-right 20px
|
||||
|
||||
md-card.create-factory-factory-information-card
|
||||
margin 24px
|
||||
background-color $white-color
|
||||
font-size 1.1em
|
||||
font-family sans-serif
|
||||
|
||||
md-tabs.factory-select-source-details
|
||||
margin -15px 0
|
||||
|
||||
md-tabs.factory-select-source-details:not(.md-no-tab-content):not(.md-dynamic-height)
|
||||
min-height 448px
|
||||
|
||||
md-tabs.factory-select-source-details md-tab-content > div:first-child
|
||||
height 100% !important
|
||||
|
||||
|
||||
.create-factory-share-header-small-button
|
||||
margin-right 15px
|
||||
padding 0 15px
|
||||
font-size 9pt
|
||||
cursor pointer
|
||||
height 18px
|
||||
background-color $primary-color
|
||||
color $white-color
|
||||
border-radius 2px
|
||||
|
||||
.create-factory-share-header-small-button:hover
|
||||
color $white-color
|
||||
text-decoration none
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 git part of Factory
|
||||
* @ngdoc controller
|
||||
* @name factory.directive:CreateFactoryGitController
|
||||
* @author Florent Benoit
|
||||
*/
|
||||
export class CreateFactoryGitController {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 creating factory from git.
|
||||
* @author Florent Benoit
|
||||
*/
|
||||
export class CreateFactoryGit {
|
||||
private restrict: string;
|
||||
private templateUrl: string;
|
||||
private controller: string;
|
||||
private controllerAs: string;
|
||||
private bindToController: boolean;
|
||||
|
||||
private scope: {
|
||||
[propName: string]: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor() {
|
||||
this.controller = 'CreateFactoryGitController';
|
||||
this.controllerAs = 'createFactoryGitCtrl';
|
||||
this.bindToController = true;
|
||||
|
||||
this.restrict = 'E';
|
||||
this.templateUrl = 'app/factories/create-factory/git/create-factory-git.html';
|
||||
|
||||
|
||||
// scope values
|
||||
this.scope = {
|
||||
location: '=cdvyGitLocation'
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<!--
|
||||
|
||||
Copyright (c) 2015 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
|
||||
|
||||
-->
|
||||
<che-label-container che-label-name="Git URL">
|
||||
<form name="createFactoryGitForm">
|
||||
<div class="create-factory-git-input">
|
||||
<che-input-box che-form="createFactoryGitForm"
|
||||
che-name="remoteGitURL"
|
||||
che-place-holder="Repository URL"
|
||||
che-width="auto"
|
||||
ng-model="createFactoryGitCtrl.location"
|
||||
git-url
|
||||
required>
|
||||
<div ng-message="gitUrl">Invalid Git URL</div>
|
||||
<div ng-message="required">A repository URL is required.</div>
|
||||
</che-input-box>
|
||||
</div>
|
||||
</form>
|
||||
</che-label-container>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
.create-factory-git-input
|
||||
margin -6px 0
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
import {CheAPI} from '../../../../components/api/che-api.factory';
|
||||
import {CheNotification} from '../../../../components/notification/che-notification.factory';
|
||||
|
||||
/**
|
||||
* Controller for creating factory from a template.
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class FactoryFromTemplateCtrl {
|
||||
private $filter: ng.IFilterService;
|
||||
private cheAPI: CheAPI;
|
||||
private cheNotification: CheNotification;
|
||||
private isImporting: boolean;
|
||||
private factoryContent: any;
|
||||
private editorOptions: any;
|
||||
private templateName: string;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource injection
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($filter: ng.IFilterService, cheAPI: CheAPI, cheNotification: CheNotification, $timeout: ng.ITimeoutService) {
|
||||
this.$filter = $filter;
|
||||
this.cheAPI = cheAPI;
|
||||
this.cheNotification = cheNotification;
|
||||
|
||||
this.isImporting = false;
|
||||
this.factoryContent = null;
|
||||
this.templateName = 'minimal';
|
||||
this.getFactoryTemplate(this.templateName);
|
||||
|
||||
this.editorOptions = {
|
||||
mode: 'application/json',
|
||||
onLoad: (editor: any) => {
|
||||
$timeout(() => {
|
||||
editor.refresh();
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// gets factory template.
|
||||
getFactoryTemplate(templateName: string) {
|
||||
let factoryContent = this.cheAPI.getFactoryTemplate().getFactoryTemplate(templateName);
|
||||
|
||||
if (factoryContent) {
|
||||
this.factoryContent = this.$filter('json')(factoryContent, 2);
|
||||
return;
|
||||
}
|
||||
|
||||
this.isImporting = true;
|
||||
|
||||
// fetch it:
|
||||
let promise = this.cheAPI.getFactoryTemplate().fetchFactoryTemplate(templateName);
|
||||
|
||||
promise.then((factoryContent: any) => {
|
||||
this.isImporting = false;
|
||||
this.factoryContent = this.$filter('json')(factoryContent, 2);
|
||||
}, (error: any) => {
|
||||
this.isImporting = false;
|
||||
this.cheNotification.showError(error.data.message ? error.data.message : 'Fail to get factory template.');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 factory from template widget.
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class FactoryFromTemplate {
|
||||
private restrict: string;
|
||||
private templateUrl: string;
|
||||
private controller: string;
|
||||
private controllerAs: string;
|
||||
private bindToController: boolean;
|
||||
private replace: boolean;
|
||||
|
||||
private scope: {
|
||||
[propName: string]: string;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor() {
|
||||
this.restrict = 'E';
|
||||
|
||||
this.templateUrl = 'app/factories/create-factory/template-tab/factory-from-template.html';
|
||||
this.replace = false;
|
||||
|
||||
this.controller = 'FactoryFromTemplateCtrl';
|
||||
this.controllerAs = 'factoryFromTemplateCtrl';
|
||||
|
||||
this.bindToController = true;
|
||||
|
||||
// scope values
|
||||
this.scope = {
|
||||
factoryContent: '=cdvyFactoryContent',
|
||||
isImporting: '=cdvyIsImporting'
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<!--
|
||||
|
||||
CODENVY CONFIDENTIAL
|
||||
__________________
|
||||
|
||||
[2015] - [2016] Codenvy, S.A.
|
||||
All Rights Reserved.
|
||||
|
||||
NOTICE: All information contained herein is, and remains
|
||||
the property of Codenvy S.A. and its suppliers,
|
||||
if any. The intellectual and technical concepts contained
|
||||
herein are proprietary to Codenvy S.A.
|
||||
and its suppliers and may be covered by U.S. and Foreign Patents,
|
||||
patents in process, and are protected by trade secret or copyright law.
|
||||
Dissemination of this information or reproduction of this material
|
||||
is strictly forbidden unless prior written permission is obtained
|
||||
from Codenvy S.A..
|
||||
|
||||
-->
|
||||
<div class="factory-from-template" layout="row" flex layout-align="start center">
|
||||
<che-label-container che-label-name="Select Template">
|
||||
<div layout="column">
|
||||
<che-toggle ng-model="factoryFromTemplateCtrl.templateName">
|
||||
<che-toggle-button ng-click="factoryFromTemplateCtrl.getFactoryTemplate(factoryFromTemplateCtrl.templateName)"
|
||||
che-font-icon="material-design icon-ic_unfold_less_24px"
|
||||
che-title="minimal"></che-toggle-button>
|
||||
<che-toggle-button ng-click="factoryFromTemplateCtrl.getFactoryTemplate(factoryFromTemplateCtrl.templateName)"
|
||||
che-font-icon="material-design icon-ic_unfold_more_24px"
|
||||
che-title="complete"></che-toggle-button>
|
||||
</che-toggle>
|
||||
|
||||
<textarea ui-codemirror="factoryFromTemplateCtrl.editorOptions"
|
||||
ng-model="factoryFromTemplateCtrl.factoryContent"
|
||||
aria-label="Factory configuration editor">
|
||||
</textarea>
|
||||
</div>
|
||||
</che-label-container>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
.factory-from-template
|
||||
min-height 80px
|
||||
|
||||
.factory-from-template .CodeMirror
|
||||
border 1px solid $list-separator-color
|
||||
min-height 500px
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
import {CheAPI} from '../../../../components/api/che-api.factory';
|
||||
import {CheNotification} from '../../../../components/notification/che-notification.factory';
|
||||
|
||||
/**
|
||||
* Controller for creating factory from a workspace.
|
||||
* @author Oleksii Orel
|
||||
* @author Michail Kuznyetsov
|
||||
*/
|
||||
export class FactoryFromWorkspaceCtrl {
|
||||
private $filter: ng.IFilterService;
|
||||
private cheAPI: CheAPI;
|
||||
private cheNotification: CheNotification;
|
||||
private workspaces: Array<che.IWorkspace>;
|
||||
private workspacesById: Map<string, che.IWorkspace>;
|
||||
private filtersWorkspaceSelected: any;
|
||||
private workspaceFilter: any;
|
||||
private isLoading: boolean;
|
||||
private isImporting: boolean;
|
||||
private factoryContent: any;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource injection
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($filter: ng.IFilterService, cheAPI: CheAPI, cheNotification: CheNotification) {
|
||||
this.$filter = $filter;
|
||||
this.cheAPI = cheAPI;
|
||||
this.cheNotification = cheNotification;
|
||||
|
||||
this.workspaces = cheAPI.getWorkspace().getWorkspaces();
|
||||
this.workspacesById = cheAPI.getWorkspace().getWorkspacesById();
|
||||
|
||||
this.filtersWorkspaceSelected = {};
|
||||
|
||||
this.workspaceFilter = {config: {name: ''}};
|
||||
|
||||
this.isLoading = true;
|
||||
|
||||
// fetch workspaces when initializing
|
||||
let promise = cheAPI.getWorkspace().fetchWorkspaces();
|
||||
|
||||
promise.then(() => {
|
||||
this.isLoading = false;
|
||||
this.updateData();
|
||||
}, (error: any) => {
|
||||
this.isLoading = false;
|
||||
if (error.status === 304) {
|
||||
this.updateData();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
updateData(): void {
|
||||
this.setAllFiltersWorkspaces(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get factory content from workspace
|
||||
* @param workspace is selected workspace
|
||||
*/
|
||||
getFactoryContentFromWorkspace(workspace: che.IWorkspace) {
|
||||
let factoryContent = this.cheAPI.getFactory().getFactoryContentFromWorkspace(workspace);
|
||||
if (factoryContent) {
|
||||
this.factoryContent = this.$filter('json')(factoryContent, 2);
|
||||
return;
|
||||
}
|
||||
|
||||
this.isImporting = true;
|
||||
|
||||
let promise = this.cheAPI.getFactory().fetchFactoryContentFromWorkspace(workspace);
|
||||
|
||||
promise.then((factoryContent: any) => {
|
||||
this.isImporting = false;
|
||||
this.factoryContent = this.$filter('json')(factoryContent, 2);
|
||||
}, (error: any) => {
|
||||
let message = (error.data && error.data.message) ? error.data.message : 'Get factory configuration failed.'
|
||||
if (error.status === 400) {
|
||||
message = 'Factory can\'t be created. The selected workspace has no projects defined. Project sources must be available from an external storage.';
|
||||
}
|
||||
|
||||
this.isImporting = false;
|
||||
this.factoryContent = null;
|
||||
this.cheNotification.showError(message);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all workspaces in the filters of workspaces
|
||||
* @param isChecked is setting value
|
||||
*/
|
||||
setAllFiltersWorkspaces(isChecked: boolean) {
|
||||
this.workspaces.forEach((workspace: che.IWorkspace) => {
|
||||
this.filtersWorkspaceSelected[workspace.id] = isChecked;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the workspace name by ID
|
||||
* @param workspaceId
|
||||
* @returns {String} workspace name
|
||||
*/
|
||||
getWorkspaceName(workspaceId: string) {
|
||||
let workspace = this.workspacesById.get(workspaceId);
|
||||
if (workspace && workspace.config.name) {
|
||||
return workspace.config.name;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 configuring factory form workspace.
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class FactoryFromWorkspace {
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor() {
|
||||
this.restrict = 'E';
|
||||
|
||||
this.templateUrl = 'app/factories/create-factory/workspaces-tab/factory-from-workspace.html';
|
||||
this.replace = false;
|
||||
|
||||
this.controller = 'FactoryFromWorkspaceCtrl';
|
||||
this.controllerAs = 'factoryFromWorkspaceCtrl';
|
||||
|
||||
this.bindToController = true;
|
||||
|
||||
// scope values
|
||||
this.scope = {
|
||||
isLoading: '=cdvyIsLoading',
|
||||
isImporting: '=cdvyIsImporting',
|
||||
factoryContent: '=cdvyFactoryContent'
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<!--
|
||||
|
||||
CODENVY CONFIDENTIAL
|
||||
__________________
|
||||
|
||||
[2015] - [2016] Codenvy, S.A.
|
||||
All Rights Reserved.
|
||||
|
||||
NOTICE: All information contained herein is, and remains
|
||||
the property of Codenvy S.A. and its suppliers,
|
||||
if any. The intellectual and technical concepts contained
|
||||
herein are proprietary to Codenvy S.A.
|
||||
and its suppliers and may be covered by U.S. and Foreign Patents,
|
||||
patents in process, and are protected by trade secret or copyright law.
|
||||
Dissemination of this information or reproduction of this material
|
||||
is strictly forbidden unless prior written permission is obtained
|
||||
from Codenvy S.A..
|
||||
|
||||
-->
|
||||
<md-content class="factory-from-workspace" flex>
|
||||
<div class="factory-from-workspace-search">
|
||||
<che-search che-placeholder="Search for workspaces"
|
||||
ng-model="factoryFromWorkspaceCtrl.workspaceFilter.config.name"></che-search>
|
||||
</div>
|
||||
<span class="projects-list-workspace-name">{{factoryFromWorkspaceCtrl.getWorkspaceName(workspaceId)}}</span>
|
||||
<span ng-show="(workspaces | filter:factoryFromWorkspaceCtrl.workspaceFilter).length == 0 && workspaces.length > 0"
|
||||
class="workspace-list-empty">No workspaces found</span>
|
||||
</che-list-title>
|
||||
<che-list>
|
||||
<che-list-item ng-show="(factoryFromWorkspaceCtrl.workspaces | filter:factoryFromWorkspaceCtrl.workspaceFilter).length > 0"
|
||||
ng-repeat="workspace in factoryFromWorkspaceCtrl.workspaces | filter:factoryFromWorkspaceCtrl.workspaceFilter"
|
||||
flex-gt-sm="100" flex="33" ng-mouseover="hover=true" ng-mouseout="hover=false">
|
||||
<div layout-gt-sm="row" flex="100" layout-align="start center" class="project-list-row"
|
||||
ng-click="factoryFromWorkspaceCtrl.getFactoryContentFromWorkspace(workspace)">
|
||||
<div class="workspace-list-static-icon" layout-align="center center">
|
||||
<div class="workspace-icon">
|
||||
<md-icon md-font-icon="fa fa-server"></md-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div flex layout="column"
|
||||
layout-align-gt="start center"
|
||||
layout-align-sm="center center">
|
||||
<div class="project-name">
|
||||
<a class="codenvy-hover">{{workspace.config.name}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</che-list-item>
|
||||
</che-list>
|
||||
</md-content>
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
.factory-from-workspace-search
|
||||
margin-top 20px
|
||||
|
||||
.factory-from-workspace che-search
|
||||
color $label-primary-color
|
||||
|
||||
.factory-from-workspace che-search .search-component
|
||||
border-bottom 1px solid $disabled-color
|
||||
|
||||
.factory-from-workspace che-search .search-input
|
||||
color $label-primary-color
|
||||
|
||||
.factory-from-workspace che-search md-icon
|
||||
font-size 14px
|
||||
|
||||
.factory-from-workspace che-search .search-input::-webkit-input-placeholder
|
||||
color $label-primary-color
|
||||
font-style italic
|
||||
font-size 14px
|
||||
opacity 0.5
|
||||
|
||||
.factory-from-workspace che-search .search-input:-moz-placeholder
|
||||
/* Mozilla Firefox 4 to 18 */
|
||||
color $label-primary-color
|
||||
font-style italic
|
||||
font-size 14px
|
||||
opacity 0.5
|
||||
|
||||
.factory-from-workspace che-search .search-input::-moz-placeholder
|
||||
/* Mozilla Firefox 19+ */
|
||||
color $label-primary-color
|
||||
font-style italic
|
||||
font-size 14px
|
||||
opacity 0.5
|
||||
|
||||
.factory-from-project-workspace-filter .workspace-selector md-checkbox:after
|
||||
che-separator()
|
||||
margin-top 17px
|
||||
margin-left 10px
|
||||
position relative
|
||||
|
||||
.factory-from-project-workspace-filter .workspace-selector:last-child md-checkbox:after
|
||||
display none
|
||||
|
||||
.factory-from-project-workspace-filter .greyed .md-icon
|
||||
background-color $disabled-color !important
|
||||
|
||||
.factory-from-workspace .workspace-list-static-icon
|
||||
flex 0 0 86px
|
||||
text-align center
|
||||
|
||||
.factory-from-workspace .workspace-list-static-icon project-type-icon
|
||||
margin 0 24px
|
||||
padding 10px 0
|
||||
width 36px
|
||||
height 36px
|
||||
line-height 36px
|
||||
font-size 36px
|
||||
color $label-secondary-color
|
||||
|
||||
.factory-from-workspace md-icon
|
||||
width auto
|
||||
height auto
|
||||
font-size 24px
|
||||
line-height 24px
|
||||
color $label-info-color
|
||||
|
||||
.factory-from-workspace .workspace-icon,
|
||||
.factory-from-workspace .workspace-icon:hover,
|
||||
.factory-from-workspace .workspace-icon md-icon,
|
||||
.factory-from-workspace .workspace-icon md-icon:hover
|
||||
color $label-secondary-color
|
||||
|
||||
.factory-from-workspace .project-list-row
|
||||
outline none
|
||||
margin-left 0
|
||||
margin-right 0
|
||||
cursor pointer
|
||||
min-height 56px
|
||||
|
||||
.factory-from-workspace .project-name
|
||||
font-size 16px
|
||||
line-height 19px
|
||||
margin-bottom 3px
|
||||
color $label-primary-color
|
||||
|
||||
.factory-from-workspace .project-list-row:focus
|
||||
background-color $focus-on-list-color
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
|
||||
|
||||
import {FactoryDetailsConfig} from './factory-details/factory-details-config';
|
||||
import {CreateFactoryConfig} from './create-factory/create-factory-config';
|
||||
import {LastFactoriesConfig} from './last-factories/last-factories-config';
|
||||
import {ListFactoriesController} from './list-factories/list-factories.controller';
|
||||
import {FactoryItemController} from './list-factories/factory-item/factory-item.controller';
|
||||
import {CheFactoryItem} from './list-factories/factory-item/factory-item.directive';
|
||||
import {LoadFactoryController} from './load-factory/load-factory.controller';
|
||||
import {LoadFactoryService} from './load-factory/load-factory.service';
|
||||
|
||||
export class FactoryConfig {
|
||||
|
||||
constructor(register: che.IRegisterService) {
|
||||
register.controller('ListFactoriesController', ListFactoriesController);
|
||||
|
||||
register.controller('FactoryItemController', FactoryItemController);
|
||||
register.directive('cdvyFactoryItem', CheFactoryItem);
|
||||
|
||||
register.controller('LoadFactoryController', LoadFactoryController);
|
||||
register.service('loadFactoryService', LoadFactoryService);
|
||||
|
||||
// config routes
|
||||
register.app.config(function ($routeProvider) {
|
||||
$routeProvider.accessWhen('/factories', {
|
||||
title: 'Factories',
|
||||
templateUrl: 'app/factories/list-factories/list-factories.html',
|
||||
controller: 'ListFactoriesController',
|
||||
controllerAs: 'listFactoriesCtrl'
|
||||
})
|
||||
.accessWhen('/load-factory', {
|
||||
title: 'Load Factory',
|
||||
templateUrl: 'app/factories/load-factory/load-factory.html',
|
||||
controller: 'LoadFactoryController',
|
||||
controllerAs: 'loadFactoryController'
|
||||
})
|
||||
.accessWhen('/load-factory/:id', {
|
||||
title: 'Load Factory',
|
||||
templateUrl: 'app/factories/load-factory/load-factory.html',
|
||||
controller: 'LoadFactoryController',
|
||||
controllerAs: 'loadFactoryController'
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// config files
|
||||
new FactoryDetailsConfig(register);
|
||||
new CreateFactoryConfig(register);
|
||||
new LastFactoriesConfig(register);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
|
||||
import {FactoryDetailsController} from '../factory-details/factory-details.controller';
|
||||
import {InformationTabConfig} from './information-tab/information-tab-config';
|
||||
|
||||
|
||||
export class FactoryDetailsConfig {
|
||||
|
||||
constructor(register: che.IRegisterService) {
|
||||
register.controller('FactoryDetailsController', FactoryDetailsController);
|
||||
|
||||
// config routes
|
||||
register.app.config(($routeProvider: any) => {
|
||||
let locationProvider = {
|
||||
title: 'Factory',
|
||||
templateUrl: 'app/factories/factory-details/factory-details.html',
|
||||
controller: 'FactoryDetailsController',
|
||||
controllerAs: 'factoryDetailsController'
|
||||
};
|
||||
|
||||
$routeProvider.accessWhen('/factory/:id', locationProvider)
|
||||
.accessWhen('/factory/:id/:tabName', locationProvider);
|
||||
|
||||
});
|
||||
|
||||
// config files
|
||||
new InformationTabConfig(register);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
import {CheNotification} from '../../../components/notification/che-notification.factory';
|
||||
import {CheFactory} from '../../../components/api/che-factory.factory';
|
||||
|
||||
/**
|
||||
* Controller for a factory details.
|
||||
* @author Florent Benoit
|
||||
*/
|
||||
export class FactoryDetailsController {
|
||||
private cheFactory: CheFactory;
|
||||
private factory: che.IFactory;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource injection
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($route: ng.route.IRouteService, cheFactory: CheFactory, cheNotification: CheNotification) {
|
||||
'ngInject';
|
||||
|
||||
this.cheFactory = cheFactory;
|
||||
let factoryId = $route.current.params.id;
|
||||
this.factory = this.cheFactory.getFactoryById(factoryId);
|
||||
|
||||
cheFactory.fetchFactoryById(factoryId).then((factory: che.IFactory) => {
|
||||
this.factory = factory;
|
||||
}, (error: any) => {
|
||||
cheNotification.showError(error.data.message ? error.data.message : 'Get factory failed.');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the factory url based on id.
|
||||
* @returns {link.href|*} link value
|
||||
*/
|
||||
getFactoryIdUrl(): string {
|
||||
if (!this.factory) {
|
||||
return null;
|
||||
}
|
||||
return this.cheFactory.getFactoryIdUrl(this.factory);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<!--
|
||||
|
||||
CODENVY CONFIDENTIAL
|
||||
__________________
|
||||
|
||||
[2015] - [2016] Codenvy, S.A.
|
||||
All Rights Reserved.
|
||||
|
||||
NOTICE: All information contained herein is, and remains
|
||||
the property of Codenvy S.A. and its suppliers,
|
||||
if any. The intellectual and technical concepts contained
|
||||
herein are proprietary to Codenvy S.A.
|
||||
and its suppliers and may be covered by U.S. and Foreign Patents,
|
||||
patents in process, and are protected by trade secret or copyright law.
|
||||
Dissemination of this information or reproduction of this material
|
||||
is strictly forbidden unless prior written permission is obtained
|
||||
from Codenvy S.A..
|
||||
|
||||
-->
|
||||
<che-toolbar
|
||||
che-title="{{factoryDetailsController.factory.name ? factoryDetailsController.factory.name : factoryDetailsController.factory.id}}"
|
||||
che-title-icons-controller="factoryDetailsController"
|
||||
che-button-name="Open"
|
||||
che-button-href="{{factoryDetailsController.getFactoryIdUrl()}}"
|
||||
che-button-href-target="_blank"
|
||||
che-breadcrumb-title="All factories"
|
||||
che-breadcrumb-href="#/factories">
|
||||
</che-toolbar>
|
||||
<md-content md-scroll-y flex class="factory-details factory-details-content">
|
||||
<cdvy-factory-information cdvy-factory="factoryDetailsController.factory"></cdvy-factory-information>
|
||||
</md-content>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
md-content.factory-details
|
||||
overflow auto
|
||||
min-height calc(100vh - 152px)
|
||||
|
||||
md-progress-linear.factory-details-progress
|
||||
z-index 1
|
||||
height 10px
|
||||
position absolute
|
||||
|
||||
.factory-details-content
|
||||
background-color $white-color !important
|
||||
padding 0 14px
|
||||
|
||||
button
|
||||
margin-left 0
|
||||
margin-right 0
|
||||
margin-bottom 16px
|
||||
|
||||
.factory-delete-label label
|
||||
color $che-delete-label-color
|
||||
|
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
import {CheAPI} from '../../../../../components/api/che-api.factory';
|
||||
import {CheNotification} from '../../../../../components/notification/che-notification.factory';
|
||||
|
||||
/**
|
||||
* Controller for a factory information.
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class FactoryInformationController {
|
||||
|
||||
private confirmDialogService: any;
|
||||
private cheAPI: CheAPI;
|
||||
private cheNotification: CheNotification;
|
||||
private $location: ng.ILocationService;
|
||||
private $log: ng.ILogService;
|
||||
private $timeout: ng.ITimeoutService;
|
||||
private lodash: _.LoDashStatic;
|
||||
private $filter: ng.IFilterService;
|
||||
|
||||
private timeoutPromise: ng.IPromise<any>;
|
||||
private editorLoadedPromise: ng.IPromise<any>;
|
||||
private editorOptions: any;
|
||||
private factoryInformationForm: any;
|
||||
private stackRecipeMode: string;
|
||||
private factory: che.IFactory;
|
||||
private copyOriginFactory: che.IFactory;
|
||||
private factoryContent: any;
|
||||
private workspaceImportedRecipe: any;
|
||||
private environmentName: string;
|
||||
private workspaceName: string;
|
||||
private stackId: string;
|
||||
private workspaceConfig: any;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource injection
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($scope: ng.IScope, cheAPI: CheAPI, cheNotification: CheNotification, $location: ng.ILocationService, $log: ng.ILogService,
|
||||
$timeout: ng.ITimeoutService, lodash: _.LoDashStatic, $filter: ng.IFilterService, $q: ng.IQService, confirmDialogService: any) {
|
||||
this.cheAPI = cheAPI;
|
||||
this.cheNotification = cheNotification;
|
||||
this.$location = $location;
|
||||
this.$log = $log;
|
||||
this.$timeout = $timeout;
|
||||
this.lodash = lodash;
|
||||
this.$filter = $filter;
|
||||
this.confirmDialogService = confirmDialogService;
|
||||
|
||||
this.timeoutPromise = null;
|
||||
$scope.$on('$destroy', () => {
|
||||
if (this.timeoutPromise) {
|
||||
$timeout.cancel(this.timeoutPromise);
|
||||
}
|
||||
});
|
||||
|
||||
let editorLoadedDefer = $q.defer();
|
||||
this.editorLoadedPromise = editorLoadedDefer.promise;
|
||||
this.editorOptions = {
|
||||
onLoad: ((instance: any) => {
|
||||
editorLoadedDefer.resolve(instance);
|
||||
})
|
||||
};
|
||||
|
||||
this.stackRecipeMode = 'current-recipe';
|
||||
|
||||
this.updateData();
|
||||
$scope.$watch(() => {
|
||||
return this.factory;
|
||||
}, () => {
|
||||
this.updateData();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update factory content data for editor
|
||||
*/
|
||||
updateData(): void {
|
||||
if (!this.factory) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.workspaceName = this.factory.workspace.name;
|
||||
this.environmentName = this.factory.workspace.defaultEnv;
|
||||
|
||||
this.copyOriginFactory = angular.copy(this.factory);
|
||||
if (this.copyOriginFactory.links) {
|
||||
delete this.copyOriginFactory.links;
|
||||
}
|
||||
|
||||
let factoryContent = this.$filter('json')(this.copyOriginFactory);
|
||||
if (factoryContent !== this.factoryContent) {
|
||||
if (!this.factoryContent) {
|
||||
this.editorLoadedPromise.then((instance) => {
|
||||
this.$timeout(() => {
|
||||
instance.refresh();
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
this.factoryContent = factoryContent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns object's attributes.
|
||||
*
|
||||
* @param targetObject object to process
|
||||
* @returns {string[]}
|
||||
*/
|
||||
getObjectKeys(targetObject: any): Array<string> {
|
||||
return Object.keys(targetObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the factory's data changed state.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isFactoryChanged(): boolean {
|
||||
if (!this.copyOriginFactory) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let testFactory = angular.copy(this.factory);
|
||||
if (testFactory.links) {
|
||||
delete testFactory.links;
|
||||
}
|
||||
|
||||
return angular.equals(this.copyOriginFactory, testFactory) !== true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update factory data.
|
||||
*/
|
||||
updateFactory(): void {
|
||||
this.factoryContent = this.$filter('json')(this.copyOriginFactory);
|
||||
|
||||
if (this.factoryInformationForm.$invalid || !this.isFactoryChanged()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$timeout.cancel(this.timeoutPromise);
|
||||
this.timeoutPromise = this.$timeout(() => {
|
||||
this.doUpdateFactory(this.copyOriginFactory);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the factory url based on id.
|
||||
*
|
||||
* @returns {link.href|*} link value
|
||||
*/
|
||||
getFactoryIdUrl(): string {
|
||||
return this.cheAPI.getFactory().getFactoryIdUrl(this.factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the factory url based on name.
|
||||
*
|
||||
* @returns {link.href|*} link value
|
||||
*/
|
||||
getFactoryNamedUrl(): string {
|
||||
return this.cheAPI.getFactory().getFactoryNamedUrl(this.factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to update factory
|
||||
*/
|
||||
doUpdateFactory(factory: che.IFactory): void {
|
||||
let promise = this.cheAPI.getFactory().setFactory(factory);
|
||||
|
||||
promise.then((factory: che.IFactory) => {
|
||||
this.factory = factory;
|
||||
this.cheNotification.showInfo('Factory information successfully updated.');
|
||||
}, (error: any) => {
|
||||
this.cheNotification.showError(error.data.message ? error.data.message : 'Update factory failed.');
|
||||
this.$log.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for factory editor focus event.
|
||||
*/
|
||||
factoryEditorOnFocus(): void {
|
||||
if (this.timeoutPromise) {
|
||||
this.$timeout.cancel(this.timeoutPromise);
|
||||
this.doUpdateFactory(this.copyOriginFactory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets factory editor.
|
||||
*/
|
||||
factoryEditorReset(): void {
|
||||
this.factoryContent = this.$filter('json')(this.copyOriginFactory, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates factory's content.
|
||||
*/
|
||||
updateFactoryContent(): void {
|
||||
let promise = this.cheAPI.getFactory().setFactoryContent(this.factory.id, this.factoryContent);
|
||||
|
||||
promise.then((factory: che.IFactory) => {
|
||||
this.factory = factory;
|
||||
this.cheNotification.showInfo('Factory information successfully updated.');
|
||||
}, (error: any) => {
|
||||
this.factoryContent = this.$filter('json')(this.copyOriginFactory, 2);
|
||||
this.cheNotification.showError(error.data.message ? error.data.message : 'Update factory failed.');
|
||||
this.$log.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes factory with confirmation.
|
||||
*/
|
||||
deleteFactory(): void {
|
||||
let content = 'Please confirm removal for the factory \'' + (this.factory.name ? this.factory.name : this.factory.id) + '\'.';
|
||||
let promise = this.confirmDialogService.showConfirmDialog('Remove the factory', content, 'Delete');
|
||||
|
||||
promise.then(() => {
|
||||
// remove it !
|
||||
let promise = this.cheAPI.getFactory().deleteFactoryById(this.factory.id);
|
||||
promise.then(() => {
|
||||
this.$location.path('/factories');
|
||||
}, (error: any) => {
|
||||
this.cheNotification.showError(error.data.message ? error.data.message : 'Delete failed.');
|
||||
this.$log.log(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recipe value of the environment.
|
||||
*
|
||||
* @returns {any}
|
||||
*/
|
||||
getRecipe(): string {
|
||||
if (this.copyOriginFactory && this.copyOriginFactory.workspace) {
|
||||
let environement = this.copyOriginFactory.workspace.environments[this.copyOriginFactory.workspace.defaultEnv];
|
||||
return environement.recipe.location || environement.recipe.content;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles stack and workspace config changes.
|
||||
*
|
||||
* @param config workspace config
|
||||
* @param stackId stack id
|
||||
*/
|
||||
onWorkspaceStackChanged(config: any, stackId: string): void {
|
||||
this.stackId = stackId;
|
||||
this.workspaceConfig = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves stacks changes in workspace config inside factory.
|
||||
*/
|
||||
saveStack(): void {
|
||||
if (!this.copyOriginFactory) {
|
||||
return;
|
||||
}
|
||||
this.copyOriginFactory.workspace.environments[this.factory.workspace.defaultEnv] = this.workspaceConfig.environments[this.workspaceConfig.defaultEnv];
|
||||
|
||||
this.updateFactory();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 factory-information widget.
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class FactoryInformation {
|
||||
private restrict: string;
|
||||
private templateUrl: string;
|
||||
private replace: boolean;
|
||||
private controller: string;
|
||||
private controllerAs: string;
|
||||
private bindToController: boolean;
|
||||
|
||||
private scope: {
|
||||
[propName: string]: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor() {
|
||||
this.restrict = 'E';
|
||||
|
||||
this.templateUrl = 'app/factories/factory-details/information-tab/factory-information/factory-information.html';
|
||||
this.replace = false;
|
||||
|
||||
this.controller = 'FactoryInformationController';
|
||||
this.controllerAs = 'factoryInformationController';
|
||||
|
||||
this.bindToController = true;
|
||||
|
||||
// scope values
|
||||
this.scope = {
|
||||
factory: '=cdvyFactory'
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
<!--
|
||||
|
||||
CODENVY CONFIDENTIAL
|
||||
__________________
|
||||
|
||||
[2015] - [2016] Codenvy, S.A.
|
||||
All Rights Reserved.
|
||||
|
||||
NOTICE: All information contained herein is, and remains
|
||||
the property of Codenvy S.A. and its suppliers,
|
||||
if any. The intellectual and technical concepts contained
|
||||
herein are proprietary to Codenvy S.A.
|
||||
and its suppliers and may be covered by U.S. and Foreign Patents,
|
||||
patents in process, and are protected by trade secret or copyright law.
|
||||
Dissemination of this information or reproduction of this material
|
||||
is strictly forbidden unless prior written permission is obtained
|
||||
from Codenvy S.A..
|
||||
|
||||
-->
|
||||
<div class="factory-information" ng-if="factoryInformationController.copyOriginFactory">
|
||||
<!-- Name -->
|
||||
<che-label-container che-label-name="Name">
|
||||
<div layout="column" class="factory-information-input">
|
||||
<ng-form name="factoryInformationForm">
|
||||
<che-input che-form="factoryInformationForm"
|
||||
ng-init="factoryInformationController.factoryInformationForm = factoryInformationForm"
|
||||
che-name="name"
|
||||
che-place-holder="Name of the factory"
|
||||
aria-label="Name of the factory"
|
||||
ng-model="factoryInformationController.copyOriginFactory.name"
|
||||
ng-change="factoryInformationController.updateFactory()"
|
||||
ng-trim
|
||||
ng-minlength="3"
|
||||
ng-maxlength="20"
|
||||
ng-pattern="/^[ A-Za-z0-9_\-\.]+$/">
|
||||
<div ng-message="required">A name is required.</div>
|
||||
<div ng-message="pattern">Factory name may contain digits, latin letters, spaces, _ , . , - and should start
|
||||
only
|
||||
with digits, latin letters or underscores
|
||||
</div>
|
||||
<div ng-message="minlength">The name has to be more than 3 characters long.</div>
|
||||
<div ng-message="maxlength">The name has to be less than 20 characters long.</div>
|
||||
</che-input>
|
||||
</ng-form>
|
||||
</div>
|
||||
</che-label-container>
|
||||
|
||||
<!-- URL -->
|
||||
<che-label-container che-label-name="URL">
|
||||
<che-text-info ng-show="factoryInformationController.getFactoryNamedUrl()"
|
||||
che-text="factoryInformationController.getFactoryNamedUrl()"
|
||||
che-href="factoryInformationController.getFactoryNamedUrl()"
|
||||
che-copy-clipboard="true"
|
||||
class="factory-information-panel-item"></che-text-info>
|
||||
<che-text-info che-text="factoryInformationController.getFactoryIdUrl()"
|
||||
che-href="factoryInformationController.getFactoryIdUrl()"
|
||||
che-copy-clipboard="true"
|
||||
class="factory-information-panel-item"></che-text-info>
|
||||
</che-label-container>
|
||||
|
||||
<!-- Creation Date -->
|
||||
<che-label-container che-label-name="Creation Date">
|
||||
<che-text-info
|
||||
che-text="factoryInformationController.factory.creator.created | amDateFormat:'Do MMMM YYYY'">
|
||||
</che-text-info>
|
||||
</che-label-container>
|
||||
|
||||
<!--Stack-->
|
||||
<che-label-container che-label-name="Configure Stack"
|
||||
che-label-description="Stacks are recipes or images used to define your environment runtime. Workspace environments are used to build and run your project.">
|
||||
<md-radio-group ng-model="factoryInformationController.stackRecipeMode">
|
||||
<md-radio-button value="current-recipe">Use current recipe</md-radio-button>
|
||||
<div ng-if="factoryInformationController.stackRecipeMode === 'current-recipe'">
|
||||
<div ng-if="factoryInformationController.getRecipe()">
|
||||
{{factoryInformationController.getRecipe()}}
|
||||
</div>
|
||||
<div ng-if="!factoryInformationController.getRecipe()">
|
||||
none
|
||||
</div>
|
||||
</div>
|
||||
<md-radio-button value="from-stack">Configure recipe from a stack</md-radio-button>
|
||||
</md-radio-group>
|
||||
<div ng-if="factoryInformationController.stackRecipeMode === 'from-stack'">
|
||||
<workspace-select-stack workspace-stack-on-change="factoryInformationController.onWorkspaceStackChanged(config, stackId)"
|
||||
workspace-name="factoryInformationController.workspaceName"
|
||||
environment-name="factoryInformationController.environmentName"
|
||||
workspace-imported-recipe="factoryInformationController.workspaceImportedRecipe"></workspace-select-stack>
|
||||
<che-button-primary che-button-title="Save" class="save-stack-button"
|
||||
ng-click="factoryInformationController.saveStack()"></che-button-primary>
|
||||
</div>
|
||||
</che-label-container>
|
||||
|
||||
<che-label-container che-label-name="Workspace"
|
||||
che-label-description="A workspace contains projects and runtime environments.">
|
||||
<!--Workspace name-->
|
||||
<che-label-container che-label-name="Name">
|
||||
<ng-form name="factoryInformationForm">
|
||||
<div class="factory-information-input">
|
||||
<che-input che-form="factoryInformationForm"
|
||||
che-name="name"
|
||||
che-place-holder="Name of the workspace"
|
||||
aria-label="Name of the workspace"
|
||||
ng-model="factoryInformationController.copyOriginFactory.workspace.name"
|
||||
ng-change="factoryInformationController.updateFactory()"
|
||||
required
|
||||
ng-minlength="3"
|
||||
ng-maxlength="20"
|
||||
ng-pattern="/^[A-Za-z0-9_\-\.]+$/">
|
||||
<div ng-message="required">A name is required.</div>
|
||||
<div ng-message="pattern">Workspace name may contain digits, latin letters, _ , . , - and should start
|
||||
only with digits, latin
|
||||
letters or underscores
|
||||
</div>
|
||||
<div ng-message="minlength">The name has to be more than 3 characters long.</div>
|
||||
<div ng-message="maxlength">The name has to be less than 20 characters long.</div>
|
||||
</che-input>
|
||||
</div>
|
||||
</ng-form>
|
||||
</che-label-container>
|
||||
<!--Workspace RAM-->
|
||||
<che-label-container che-label-name="RAM">
|
||||
<ng-form name="factoryInformationForm">
|
||||
<div data-ng-repeat="(environmentKey, environmentValue) in factoryInformationController.copyOriginFactory.workspace.environments">
|
||||
<span ng-if="factoryInformationController.getObjectKeys(factoryInformationController.copyOriginFactory.workspace.environments).length > 1"
|
||||
class="workspace-environment-name">ENVIRONMENT: {{environmentKey}}</span>
|
||||
|
||||
<div>
|
||||
<div data-ng-repeat="(machineKey, machineValue) in environmentValue.machines">
|
||||
<div class="workspace-machine" ng-if="machineValue.attributes && machineValue.attributes.memoryLimitBytes">
|
||||
<span ng-if="factoryInformationController.getObjectKeys(environmentValue.machines).length > 1">MACHINE: {{machineKey}}</span>
|
||||
<che-workspace-ram-allocation-slider
|
||||
ng-model="machineValue.attributes.memoryLimitBytes"
|
||||
che-on-change="factoryInformationController.updateFactory()"></che-workspace-ram-allocation-slider>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-form>
|
||||
</che-label-container>
|
||||
</che-label-container>
|
||||
|
||||
<!-- Configure commands -->
|
||||
<che-label-container che-label-name="Configure Commands"
|
||||
che-label-description="Commands are processes that are invoked by users from a dropdown in the IDE.">
|
||||
<cdvy-factory-command cdvy-factory-object="factoryInformationController.copyOriginFactory"
|
||||
cdvy-on-change="factoryInformationController.updateFactory()"></cdvy-factory-command>
|
||||
</che-label-container>
|
||||
|
||||
<!-- Configure actions -->
|
||||
<che-label-container che-label-name="Configure Actions"
|
||||
che-label-description="Tell the IDE to perform additional actions after the workspace is loaded.">
|
||||
<!-- almost no action is possible at this lifecycle
|
||||
<cdvy-factory-action-box cdvy-lifecycle="onAppLoaded"
|
||||
cdvy-action-title="Actions executed after IDE is loaded"
|
||||
cdvy-callback-controller="factoryInformationController"
|
||||
cdvy-factory-object="factoryInformationController.factoryObject"></cdvy-factory-action-box>
|
||||
-->
|
||||
<cdvy-factory-action-box cdvy-lifecycle="onProjectsLoaded"
|
||||
cdvy-callback-controller="factoryInformationController"
|
||||
cdvy-factory-object="factoryInformationController.copyOriginFactory"
|
||||
cdvy-on-change="factoryInformationController.updateFactory()"></cdvy-factory-action-box>
|
||||
</che-label-container>
|
||||
|
||||
<!-- Configuration -->
|
||||
<che-label-container che-label-name="Configuration"
|
||||
che-label-description="JSON definition of the factory."
|
||||
ng-class="{ 'disabled-state': !factoryInformationController.factoryContent }">
|
||||
<div class="factory-configuration-panel">
|
||||
<md-content layout="column" layout-fill>
|
||||
<div class="json-editor" ng-if="factoryInformationController.factoryContent !== null">
|
||||
<textarea ui-codemirror="factoryInformationController.editorOptions"
|
||||
ng-model="factoryInformationController.factoryContent"
|
||||
aria-label="Factory configuration editor"
|
||||
ng-focus="factoryInformationController.factoryEditorOnFocus()"></textarea>
|
||||
</div>
|
||||
</md-content>
|
||||
<div layout="row" flex>
|
||||
<div>
|
||||
<a href="/docs/integration-guide/workspace-automation/index.html" target="_blank">Factory configuration docs</a>
|
||||
</div>
|
||||
<div layout="row" layout-align="end start" flex>
|
||||
<div>
|
||||
<che-button-default che-button-title="Reload"
|
||||
ng-click="factoryInformationController.factoryEditorReset()"></che-button-default>
|
||||
</div>
|
||||
<div class="factory-information-update-button">
|
||||
<che-button-primary che-button-title="Update"
|
||||
ng-disabled="factoryInformationController.factoryContent === factoryInformationController.$filter('json')(factoryInformationController.copyOriginFactory, 2);"
|
||||
ng-click="factoryInformationController.updateFactoryContent()"></che-button-primary>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</che-label-container>
|
||||
|
||||
<!-- Delete button -->
|
||||
<che-label-container class="factory-delete-label"
|
||||
che-label-name="Delete Factory"
|
||||
che-label-description="This is irreversible.">
|
||||
<che-button-danger che-button-title="Delete"
|
||||
ng-click="factoryInformationController.deleteFactory()"></che-button-danger>
|
||||
</che-label-container>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
.factory-information-panel-item:not(:last-child)
|
||||
margin-bottom 10px
|
||||
|
||||
.factory-information .che-label-container-content .factory-information-input
|
||||
margin-top -6px
|
||||
|
||||
.factory-information .disabled-state
|
||||
cursor not-allowed
|
||||
background-color transparent
|
||||
|
||||
.factory-information
|
||||
overflow auto
|
||||
min-height calc(100vh - 152px)
|
||||
background-color $white-color !important
|
||||
padding 0 14px
|
||||
|
||||
button
|
||||
margin 0 30px 0 0
|
||||
|
||||
.che-label-container-content .factory-information-input
|
||||
margin-top -6px
|
||||
|
||||
.factory-information-update-button button
|
||||
margin-right 0
|
||||
|
||||
.json-editor
|
||||
font-size 12px
|
||||
margin-bottom 20px
|
||||
|
||||
.workspace-environment-name + div
|
||||
margin-top 8px
|
||||
|
||||
.workspace-machine
|
||||
margin-left 45px
|
||||
|
||||
.che-ram-allocation-slider .slider-wrapper
|
||||
margin-bottom -15px
|
||||
|
||||
.save-stack-button button
|
||||
margin-top 20px
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
|
||||
import {FactoryInformationController} from '../information-tab/factory-information/factory-information.controller';
|
||||
import {FactoryInformation} from '../information-tab/factory-information/factory-information.directive';
|
||||
|
||||
|
||||
export class InformationTabConfig {
|
||||
|
||||
constructor(register: che.IRegisterService) {
|
||||
register.controller('FactoryInformationController', FactoryInformationController);
|
||||
register.directive('cdvyFactoryInformation', FactoryInformation);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
|
||||
import {LastFactoriesController} from './last-factories.controller';
|
||||
import {LastFactories} from './last-factories.directive';
|
||||
|
||||
export class LastFactoriesConfig {
|
||||
|
||||
constructor(register: che.IRegisterService) {
|
||||
register.controller('LastFactoriesController', LastFactoriesController);
|
||||
register.directive('cdvyLastFactories', LastFactories);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
import {CheFactory} from '../../../components/api/che-factory.factory';
|
||||
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name factories.controller:LastFactoriesController
|
||||
* @description This class is handling the controller of the last factories to display in the dashboard
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class LastFactoriesController {
|
||||
|
||||
private cheFactory: CheFactory;
|
||||
private factories: Array<che.IFactory>;
|
||||
private factoriesOrderBy: string;
|
||||
private maxItems: number;
|
||||
private isLoading: boolean;
|
||||
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor(cheFactory: CheFactory) {
|
||||
this.cheFactory = cheFactory;
|
||||
|
||||
this.factories = this.cheFactory.getPageFactories();
|
||||
|
||||
// todo we should change to modificationDate after model's change
|
||||
this.factoriesOrderBy = '-creator.created';
|
||||
this.maxItems = 5;
|
||||
|
||||
// todo add OrderBy to condition in fetch API
|
||||
let promise = this.cheFactory.fetchFactories(this.maxItems, 0);
|
||||
|
||||
this.isLoading = true;
|
||||
promise.finally(() => {
|
||||
this.isLoading = false;
|
||||
this.updateFactories();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update factories array
|
||||
*/
|
||||
updateFactories(): void {
|
||||
this.factories = this.cheFactory.getPageFactories();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of factories.
|
||||
*
|
||||
* @returns {Array<che.IFactory>}
|
||||
*/
|
||||
getFactories(): Array<che.IFactory> {
|
||||
return this.factories;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 factories.directive:LastFactories
|
||||
* @description This class is handling the directive of the listing last opened factories
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class LastFactories {
|
||||
private restrict: string;
|
||||
private templateUrl: string;
|
||||
private replace: boolean;
|
||||
private controller: string;
|
||||
private controllerAs: string;
|
||||
private bindToController: boolean;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor() {
|
||||
this.restrict = 'E';
|
||||
this.templateUrl = 'app/factories/last-factories/last-factories.html';
|
||||
this.replace = false;
|
||||
this.controller = 'LastFactoriesController';
|
||||
this.controllerAs = 'lastFactoriesController';
|
||||
this.bindToController = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<!--
|
||||
|
||||
CODENVY CONFIDENTIAL
|
||||
__________________
|
||||
|
||||
[2015] - [2016] Codenvy, S.A.
|
||||
All Rights Reserved.
|
||||
|
||||
NOTICE: All information contained herein is, and remains
|
||||
the property of Codenvy S.A. and its suppliers,
|
||||
if any. The intellectual and technical concepts contained
|
||||
herein are proprietary to Codenvy S.A.
|
||||
and its suppliers and may be covered by U.S. and Foreign Patents,
|
||||
patents in process, and are protected by trade secret or copyright law.
|
||||
Dissemination of this information or reproduction of this material
|
||||
is strictly forbidden unless prior written permission is obtained
|
||||
from Codenvy S.A..
|
||||
|
||||
-->
|
||||
<dashboard-panel panel-title="Recent Factories">
|
||||
|
||||
<md-progress-linear md-mode="indeterminate"
|
||||
ng-show="lastFactoriesController.isLoading"></md-progress-linear>
|
||||
|
||||
<div class="dashboard-last-factories" ng-show="!lastFactoriesController.isLoading">
|
||||
<div class="dashboard-add-button">
|
||||
<che-button-primary che-button-title="Create Factory"
|
||||
ng-href="#/factories/create-factory"></che-button-primary>
|
||||
</div>
|
||||
|
||||
<span ng-show="lastFactoriesController.getFactories().length === 0" class="last-factories-empty-label">No factories found</span>
|
||||
|
||||
<che-list ng-show="lastFactoriesController.getFactories().length > 0">
|
||||
<cdvy-factory-item layout="row"
|
||||
ng-repeat="factory in lastFactoriesController.getFactories() | orderBy:lastFactoriesController.factoriesOrderBy | limitTo:lastFactoriesController.maxItems"
|
||||
cdvy-factory="factory"
|
||||
cdvy-is-selectable="false"/>
|
||||
</che-list>
|
||||
</div>
|
||||
</dashboard-panel>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
.last-factories-empty-label
|
||||
margin-left 20px
|
||||
color $label-info-color
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
import {CheFactory} from '../../../../components/api/che-factory.factory';
|
||||
import {CheEnvironmentRegistry} from '../../../../components/api/environment/che-environment-registry.factory';
|
||||
|
||||
/**
|
||||
* Controller for a factory item.
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class FactoryItemController {
|
||||
private $location: ng.ILocationService;
|
||||
private cheFactory: CheFactory;
|
||||
private cheEnvironmentRegistry: CheEnvironmentRegistry;
|
||||
private lodash: _.LoDashStatic;
|
||||
private factory: che.IFactory;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource injection
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($location: ng.ILocationService, cheFactory: CheFactory, cheEnvironmentRegistry: CheEnvironmentRegistry, lodash: _.LoDashStatic) {
|
||||
this.$location = $location;
|
||||
this.cheFactory = cheFactory;
|
||||
this.cheEnvironmentRegistry = cheEnvironmentRegistry;
|
||||
this.lodash = lodash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of factory links.
|
||||
*
|
||||
* @returns {Array<any>}
|
||||
*/
|
||||
getFactoryLinks(): Array<any> {
|
||||
return this.cheFactory.detectLinks(this.factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to factory details.
|
||||
*/
|
||||
redirectToFactoryDetails(): void {
|
||||
this.$location.path('/factory/' + this.factory.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns display value of memory limit.
|
||||
*
|
||||
* @returns {string} display value of memory limit
|
||||
*/
|
||||
getMemoryLimit(): string {
|
||||
if (!this.factory.workspace) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
let defaultEnvName = this.factory.workspace.defaultEnv;
|
||||
let environment = this.factory.workspace.environments[defaultEnvName];
|
||||
|
||||
let recipeType = environment.recipe.type;
|
||||
let environmentManager = this.cheEnvironmentRegistry.getEnvironmentManager(recipeType);
|
||||
let machines = environmentManager.getMachines(environment);
|
||||
|
||||
let limits = this.lodash.pluck(machines, 'attributes.memoryLimitBytes');
|
||||
let total = 0;
|
||||
limits.forEach((limit: number) => {
|
||||
if (limit) {
|
||||
total += limit / (1024 * 1024);
|
||||
}
|
||||
});
|
||||
|
||||
return (total > 0) ? total + ' MB' : '-';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 factory item in list.
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class CheFactoryItem {
|
||||
restrict: string = 'E';
|
||||
|
||||
templateUrl: string = 'app/factories/list-factories/factory-item/factory-item.html';
|
||||
replace = false;
|
||||
|
||||
controller: string = 'FactoryItemController';
|
||||
controllerAs: string = 'factoryItemController';
|
||||
|
||||
bindToController: boolean = true;
|
||||
|
||||
// we require ngModel as we want to use it inside our directive
|
||||
require: Array<string> = ['ngModel'];
|
||||
scope: {
|
||||
[propName: string]: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
constructor() {
|
||||
this.scope = {
|
||||
factory: '=cdvyFactory',
|
||||
isChecked: '=cdvyChecked',
|
||||
isSelectable: '=cdvyIsSelectable',
|
||||
isSelect: '=?ngModel',
|
||||
onCheckboxClick: '&?cdvyOnCheckboxClick'
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<!--
|
||||
|
||||
CODENVY CONFIDENTIAL
|
||||
__________________
|
||||
|
||||
[2015] - [2016] Codenvy, S.A.
|
||||
All Rights Reserved.
|
||||
|
||||
NOTICE: All information contained herein is, and remains
|
||||
the property of Codenvy S.A. and its suppliers,
|
||||
if any. The intellectual and technical concepts contained
|
||||
herein are proprietary to Codenvy S.A.
|
||||
and its suppliers and may be covered by U.S. and Foreign Patents,
|
||||
patents in process, and are protected by trade secret or copyright law.
|
||||
Dissemination of this information or reproduction of this material
|
||||
is strictly forbidden unless prior written permission is obtained
|
||||
from Codenvy S.A..
|
||||
|
||||
-->
|
||||
<che-list-item flex ng-mouseover="hover=true" ng-mouseout="hover=false">
|
||||
<div flex="100"
|
||||
layout="row"
|
||||
layout-align="start stretch"
|
||||
class="che-list-item-row">
|
||||
<div layout="row"
|
||||
layout-align="start center"
|
||||
class="che-checkbox-area"
|
||||
ng-if="factoryItemController.isSelectable === true">
|
||||
<che-list-item-checked ng-model="factoryItemController.isSelect"
|
||||
che-aria-label-checkbox="Factory {{factoryItemController.factory.name}}"
|
||||
ng-click="factoryItemController.onCheckboxClick()"></che-list-item-checked>
|
||||
</div>
|
||||
<div flex
|
||||
layout-xs="column" layout-gt-xs="row"
|
||||
layout-align-gt-xs="start center"
|
||||
layout-align-xs="start start"
|
||||
class="che-list-item-details">
|
||||
<div flex-gt-xs="25"
|
||||
class="che-list-item-name"
|
||||
ng-click="factoryItemController.redirectToFactoryDetails();">
|
||||
<span class="che-xs-header noselect" hide-gt-xs>Factory</span>
|
||||
<span tooltip="Created: {{factoryItemController.factory.creator.created | amDateFormat:'dddd, MMMM Do, YYYY'}}"
|
||||
class="che-hover">{{factoryItemController.factory.name ? factoryItemController.factory.name : factoryItemController.getFactoryLinks()[0]}}</span>
|
||||
</div>
|
||||
<div flex-gt-xs="60" ng-click="factoryItemController.redirectToFactoryDetails();">
|
||||
<span class="che-xs-header noselect" hide-gt-xs>RAM</span>
|
||||
<span class="factory-consumed-value">{{factoryItemController.getMemoryLimit()}}</span>
|
||||
</div>
|
||||
<div flex-gt-xs="15">
|
||||
<span class="che-xs-header noselect" hide-gt-xs>Actions</span>
|
||||
<span class="che-list-actions">
|
||||
<a tooltip="Open in IDE" ng-href="#/load-factory/{{factoryItemController.factory.id}}">
|
||||
<span class="fa fa-chevron-circle-right factory-action"></span>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</che-list-item>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
.che-list-item-row .factory-consumed-value
|
||||
line-height initial
|
||||
font-size 12px
|
||||
font-weight bold
|
||||
color $che-medium-blue-color
|
||||
|
||||
.che-list-actions .factory-action
|
||||
min-width 16px
|
||||
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
import {ConfirmDialogService} from '../../../components/service/confirm-dialog/confirm-dialog.service';
|
||||
import {CheAPI} from "../../../components/api/che-api.factory";
|
||||
import {CheNotification} from "../../../components/notification/che-notification.factory";
|
||||
|
||||
/**
|
||||
* Controller for the factories.
|
||||
* @author Florent Benoit
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class ListFactoriesController {
|
||||
|
||||
private confirmDialogService: ConfirmDialogService;
|
||||
private cheAPI: CheAPI;
|
||||
private cheNotification: CheNotification;
|
||||
private $q: ng.IQService;
|
||||
private $log: ng.ILogService;
|
||||
|
||||
private maxItems: number;
|
||||
private skipCount: number;
|
||||
|
||||
private factoriesOrderBy: string;
|
||||
private factoriesFilter: any;
|
||||
private factoriesSelectedStatus: any;
|
||||
private isNoSelected: boolean;
|
||||
private isAllSelected: boolean;
|
||||
private isBulkChecked: boolean;
|
||||
|
||||
private isLoading: boolean;
|
||||
private factories: any;
|
||||
private pagesInfo: any;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource injection
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($q: ng.IQService, $log: ng.ILogService, cheAPI: CheAPI, cheNotification: CheNotification, $rootScope: che.IRootScopeService,
|
||||
confirmDialogService: ConfirmDialogService) {
|
||||
this.$q = $q;
|
||||
this.$log = $log;
|
||||
this.cheAPI = cheAPI;
|
||||
this.cheNotification = cheNotification;
|
||||
this.confirmDialogService = confirmDialogService;
|
||||
|
||||
this.maxItems = 15;
|
||||
this.skipCount = 0;
|
||||
|
||||
this.factoriesOrderBy = '';
|
||||
this.factoriesFilter = {name: ''};
|
||||
this.factoriesSelectedStatus = {};
|
||||
this.isNoSelected = true;
|
||||
this.isAllSelected = false;
|
||||
this.isBulkChecked = false;
|
||||
|
||||
this.isLoading = true;
|
||||
this.factories = cheAPI.getFactory().getPageFactories();
|
||||
|
||||
let promise = cheAPI.getFactory().fetchFactories(this.maxItems, this.skipCount);
|
||||
promise.then(() => {
|
||||
this.isLoading = false;
|
||||
}, (error: any) => {
|
||||
this.isLoading = false;
|
||||
if (error.status !== 304) {
|
||||
this.cheNotification.showError(error.data && error.data.message ? error.data.message : 'Failed to retrieve the list of factories.');
|
||||
}
|
||||
});
|
||||
|
||||
this.pagesInfo = cheAPI.getFactory().getPagesInfo();
|
||||
|
||||
$rootScope.showIDE = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make all factories in list checked.
|
||||
*/
|
||||
selectAllFactories(): void {
|
||||
this.factories.forEach((factory: che.IFactory) => {
|
||||
this.factoriesSelectedStatus[factory.id] = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Make all factories in list unchecked.
|
||||
*/
|
||||
deselectAllFactories(): any {
|
||||
this.factories.forEach((factory: che.IFactory) => {
|
||||
this.factoriesSelectedStatus[factory.id] = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Change bulk selection value.
|
||||
*/
|
||||
changeBulkSelection(): void {
|
||||
if (this.isBulkChecked) {
|
||||
this.deselectAllFactories();
|
||||
this.isBulkChecked = false;
|
||||
} else {
|
||||
this.selectAllFactories();
|
||||
this.isBulkChecked = true;
|
||||
}
|
||||
this.updateSelectedStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update factories selected status.
|
||||
*/
|
||||
updateSelectedStatus(): void {
|
||||
this.isNoSelected = true;
|
||||
this.isAllSelected = true;
|
||||
|
||||
this.factories.forEach((factory: che.IFactory) => {
|
||||
if (this.factoriesSelectedStatus[factory.id]) {
|
||||
this.isNoSelected = false;
|
||||
} else {
|
||||
this.isAllSelected = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (this.isNoSelected) {
|
||||
this.isBulkChecked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isAllSelected) {
|
||||
this.isBulkChecked = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all selected factories
|
||||
*/
|
||||
deleteSelectedFactories(): void {
|
||||
let factoriesSelectedStatusKeys = Object.keys(this.factoriesSelectedStatus);
|
||||
let checkedFactoriesKeys = [];
|
||||
|
||||
if (!factoriesSelectedStatusKeys.length) {
|
||||
this.cheNotification.showError('No such factories.');
|
||||
return;
|
||||
}
|
||||
|
||||
factoriesSelectedStatusKeys.forEach((key: string) => {
|
||||
if (this.factoriesSelectedStatus[key] === true) {
|
||||
checkedFactoriesKeys.push(key);
|
||||
}
|
||||
});
|
||||
|
||||
let numberToDelete = checkedFactoriesKeys.length;
|
||||
if (!numberToDelete) {
|
||||
this.cheNotification.showError('No such factory.');
|
||||
return;
|
||||
}
|
||||
|
||||
let confirmationPromise = this.showDeleteFactoriesConfirmation(numberToDelete);
|
||||
|
||||
confirmationPromise.then(() => {
|
||||
let isError = false;
|
||||
let deleteFactoryPromises = [];
|
||||
|
||||
checkedFactoriesKeys.forEach((factoryId: string) => {
|
||||
this.factoriesSelectedStatus[factoryId] = false;
|
||||
|
||||
let promise = this.cheAPI.getFactory().deleteFactoryById(factoryId);
|
||||
|
||||
promise.then(() => {
|
||||
}, (error: any) => {
|
||||
isError = true;
|
||||
this.$log.error('Cannot delete factory: ', error);
|
||||
});
|
||||
deleteFactoryPromises.push(promise);
|
||||
});
|
||||
|
||||
this.$q.all(deleteFactoryPromises).finally(() => {
|
||||
this.isLoading = true;
|
||||
|
||||
let promise = this.cheAPI.getFactory().fetchFactories(this.maxItems, this.skipCount);
|
||||
|
||||
promise.then(() => {
|
||||
this.isLoading = false;
|
||||
}, (error) => {
|
||||
this.isLoading = false;
|
||||
if (error.status !== 304) {
|
||||
this.cheNotification.showError(error.data.message ? error.data.message : 'Update information failed.');
|
||||
}
|
||||
});
|
||||
|
||||
if (isError) {
|
||||
this.cheNotification.showError('Delete failed.');
|
||||
} else {
|
||||
this.cheNotification.showInfo('Selected ' + (numberToDelete === 1 ? 'factory' : 'factories') + ' has been removed.');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask for loading the users page in asynchronous way
|
||||
* @param pageKey - the key of page
|
||||
*/
|
||||
fetchFactoriesPage(pageKey: string): void {
|
||||
this.isLoading = true;
|
||||
let promise = this.cheAPI.getFactory().fetchFactoryPage(pageKey);
|
||||
|
||||
promise.then(() => {
|
||||
this.isLoading = false;
|
||||
}, (error) => {
|
||||
this.isLoading = false;
|
||||
if (error.status !== 304) {
|
||||
this.cheNotification.showError(error.data && error.data.message ? error.data.message : 'Update information failed.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the next page is exist.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
hasNextPage(): boolean {
|
||||
if (this.pagesInfo.countOfPages) {
|
||||
return this.pagesInfo.currentPageNumber < this.pagesInfo.countOfPages;
|
||||
}
|
||||
return this.factories.length === this.maxItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the last page is exist.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
hasLastPage(): boolean {
|
||||
if (this.pagesInfo.countOfPages) {
|
||||
return this.pagesInfo.currentPageNumber < this.pagesInfo.countOfPages;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the previous page is exist.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
hasPreviousPage(): boolean {
|
||||
return this.pagesInfo.currentPageNumber > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if we have more then one page.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isPagination(): boolean {
|
||||
if (this.pagesInfo.countOfPages) {
|
||||
return this.pagesInfo.countOfPages > 1;
|
||||
}
|
||||
return this.factories.length === this.maxItems || this.pagesInfo.currentPageNumber > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show confirmation popup before delete
|
||||
* @param numberToDelete {number}
|
||||
* @returns {ng.IPromise<any>}
|
||||
*/
|
||||
showDeleteFactoriesConfirmation(numberToDelete: number): ng.IPromise<any> {
|
||||
let content = 'Would you like to delete ';
|
||||
if (numberToDelete > 1) {
|
||||
content += 'these ' + numberToDelete + ' factories?';
|
||||
} else {
|
||||
content += 'this selected factory?';
|
||||
}
|
||||
return this.confirmDialogService.showConfirmDialog('Remove factories', content, 'Delete');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
<!--
|
||||
|
||||
CODENVY CONFIDENTIAL
|
||||
__________________
|
||||
|
||||
[2015] - [2016] Codenvy, S.A.
|
||||
All Rights Reserved.
|
||||
|
||||
NOTICE: All information contained herein is, and remains
|
||||
the property of Codenvy S.A. and its suppliers,
|
||||
if any. The intellectual and technical concepts contained
|
||||
herein are proprietary to Codenvy S.A.
|
||||
and its suppliers and may be covered by U.S. and Foreign Patents,
|
||||
patents in process, and are protected by trade secret or copyright law.
|
||||
Dissemination of this information or reproduction of this material
|
||||
is strictly forbidden unless prior written permission is obtained
|
||||
from Codenvy S.A..
|
||||
|
||||
-->
|
||||
<che-toolbar che-title="All factories" border-none></che-toolbar>
|
||||
<che-description che-link-title="Learn more." che-link="/docs/integration-guide/workspace-automation/index.html">
|
||||
Factories enable workspace automation and are packaged as a consumer-friendly URL. Create new Factories to onboard your team, or integrate
|
||||
with your toolchain.
|
||||
</che-description>
|
||||
<md-content md-scroll-y flex layout="column" md-theme="maincontent-theme" class="factories-list-factories">
|
||||
<md-progress-linear md-mode="indeterminate" class="factories-list-factories-progress"
|
||||
ng-if="listFactoriesCtrl.isLoading"></md-progress-linear>
|
||||
<md-content flex class="md-maincontent-theme-theme" ng-show="!listFactoriesCtrl.isLoading">
|
||||
<che-list-header che-input-placeholder="Search"
|
||||
che-search-model="listFactoriesCtrl.factoriesFilter.name"
|
||||
che-hide-search="listFactoriesCtrl.factories.length === 0"
|
||||
che-add-button-title="Create Factory"
|
||||
che-add-button-href="#/factories/create-factory"
|
||||
che-delete-button-title="Delete"
|
||||
che-on-delete="listFactoriesCtrl.deleteSelectedFactories()"
|
||||
che-hide-delete="listFactoriesCtrl.isNoSelected"
|
||||
che-hide-header="(listFactoriesCtrl.factories | filter:listFactoriesCtrl.factoriesFilter).length === 0">
|
||||
<div flex="100"
|
||||
layout="row"
|
||||
layout-align="start stretch"
|
||||
class="che-list-item-row">
|
||||
<div layout="column" layout-gt-xs="row"
|
||||
layout-align="start center"
|
||||
class="che-checkbox-area">
|
||||
<div layout="row" layout-align="center center" class="che-list-item-checkbox-main">
|
||||
<md-checkbox class="che-list-item-checkbox"
|
||||
aria-label="Factory list"
|
||||
ng-checked="listFactoriesCtrl.isBulkChecked"
|
||||
ng-click="listFactoriesCtrl.changeBulkSelection()"></md-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
<div flex hide-xs layout-gt-xs="row"
|
||||
layout-align="start center"
|
||||
class="che-list-item-details">
|
||||
<che-list-header-column flex-gt-xs="25"
|
||||
che-sort-value='listFactoriesCtrl.factoriesOrderBy'
|
||||
che-sort-item='[name, id]'
|
||||
che-column-title='Factory'></che-list-header-column>
|
||||
<che-list-header-column flex-gt-xs="60"
|
||||
che-sort-value='listFactoriesCtrl.factoriesOrderBy'
|
||||
che-sort-item='workspace.environments[0].machines[0].limits.ram'
|
||||
che-column-title='RAM'></che-list-header-column>
|
||||
<che-list-header-column flex-gt-xs="15"
|
||||
che-column-title='Actions'></che-list-header-column>
|
||||
</div>
|
||||
</div>
|
||||
</che-list-header>
|
||||
<che-list ng-show="(listFactoriesCtrl.factories | filter:listFactoriesCtrl.factoriesFilter).length > 0">
|
||||
<cdvy-factory-item
|
||||
ng-repeat="factory in listFactoriesCtrl.factories | filter:listFactoriesCtrl.factoriesFilter | orderBy:listFactoriesCtrl.factoriesOrderBy"
|
||||
cdvy-factory="factory"
|
||||
cdvy-is-selectable="true"
|
||||
ng-model="listFactoriesCtrl.factoriesSelectedStatus[factory.id]"
|
||||
cdvy-on-checkbox-click="listFactoriesCtrl.updateSelectedStatus()"/>
|
||||
</che-list>
|
||||
<div class="paging-buttons-area" ng-if="listFactoriesCtrl.isPagination()">
|
||||
<md-button
|
||||
ng-disabled="!listFactoriesCtrl.hasPreviousPage()"
|
||||
ng-click="listFactoriesCtrl.fetchFactoriesPage('first');">
|
||||
<span><<</span>
|
||||
</md-button>
|
||||
<md-button
|
||||
ng-disabled="!listFactoriesCtrl.hasPreviousPage()"
|
||||
ng-click="listFactoriesCtrl.fetchFactoriesPage('prev');">
|
||||
<span><</span>
|
||||
</md-button>
|
||||
<md-button disabled>
|
||||
<span>{{listFactoriesCtrl.pagesInfo.currentPageNumber}}</span>
|
||||
</md-button>
|
||||
<md-button
|
||||
ng-disabled="!listFactoriesCtrl.hasNextPage()"
|
||||
ng-click="listFactoriesCtrl.fetchFactoriesPage('next');">
|
||||
<span>></span>
|
||||
</md-button>
|
||||
<md-button
|
||||
ng-disabled="!listFactoriesCtrl.hasLastPage()"
|
||||
ng-click="listFactoriesCtrl.fetchFactoriesPage('last');">
|
||||
<span>>></span>
|
||||
</md-button>
|
||||
</div>
|
||||
<div class="che-list-empty">
|
||||
<span ng-show="listFactoriesCtrl.factories.length > 0 && (listFactoriesCtrl.factories | filter:listFactoriesCtrl.factoriesFilter).length === 0">
|
||||
No factories found.
|
||||
</span>
|
||||
<span ng-show="listFactoriesCtrl.factories.length === 0">There are no factories.</span>
|
||||
</div>
|
||||
</md-content>
|
||||
</md-content>
|
||||
|
|
@ -0,0 +1,689 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
import {CheAPI} from '../../../components/api/che-api.factory';
|
||||
import {LoadFactoryService} from './load-factory.service';
|
||||
import {CheNotification} from '../../../components/notification/che-notification.factory';
|
||||
import {RouteHistory} from '../../../components/routing/route-history.service';
|
||||
|
||||
/**
|
||||
* This class is handling the controller for the factory loading.
|
||||
* @author Ann Shumilova
|
||||
*/
|
||||
export class LoadFactoryController {
|
||||
private cheAPI: CheAPI;
|
||||
private $websocket: ng.websocket.IWebSocketProvider;
|
||||
private $timeout: ng.ITimeoutService;
|
||||
private $mdDialog: ng.material.IDialogService;
|
||||
private loadFactoryService: LoadFactoryService;
|
||||
private lodash: _.LoDashStatic;
|
||||
private cheNotification: CheNotification;
|
||||
private $location: ng.ILocationService;
|
||||
private routeHistory: RouteHistory;
|
||||
private $window: ng.IWindowService;
|
||||
private routeParams: any;
|
||||
|
||||
private workspaces: Array<che.IWorkspace>;
|
||||
private workspace: che.IWorkspace;
|
||||
private projectsToImport: number;
|
||||
|
||||
private websocketReconnect: number;
|
||||
|
||||
private factory: che.IFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor(cheAPI: CheAPI, $websocket: ng.websocket.IWebSocketProvider, $route: ng.route.IRouteService, $timeout: ng.ITimeoutService,
|
||||
$mdDialog: ng.material.IDialogService, loadFactoryService: LoadFactoryService, lodash: _.LoDashStatic, cheNotification: CheNotification,
|
||||
$location: ng.ILocationService, routeHistory: RouteHistory, $window: ng.IWindowService) {
|
||||
this.cheAPI = cheAPI;
|
||||
this.$websocket = $websocket;
|
||||
this.$timeout = $timeout;
|
||||
this.$mdDialog = $mdDialog;
|
||||
this.loadFactoryService = loadFactoryService;
|
||||
this.lodash = lodash;
|
||||
this.cheNotification = cheNotification;
|
||||
this.$location = $location;
|
||||
this.routeHistory = routeHistory;
|
||||
this.$window = $window;
|
||||
|
||||
this.workspaces = [];
|
||||
this.workspace = {};
|
||||
|
||||
this.websocketReconnect = 50;
|
||||
|
||||
this.hideMenuAndFooter();
|
||||
|
||||
this.loadFactoryService.resetLoadProgress();
|
||||
this.loadFactoryService.setLoadFactoryInProgress(true);
|
||||
|
||||
this.routeParams = $route.current.params;
|
||||
this.getFactoryData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides menu and footer to maximize view.
|
||||
*/
|
||||
hideMenuAndFooter(): void {
|
||||
angular.element(document.querySelectorAll('[id*=navmenu]')).hide();
|
||||
angular.element(document.querySelectorAll('.che-footer')).hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the menu and footer.
|
||||
*/
|
||||
restoreMenuAndFooter(): void {
|
||||
angular.element(document.querySelectorAll('[id*=navmenu]')).show();
|
||||
angular.element(document.querySelectorAll('.che-footer')).show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves factory data.
|
||||
*/
|
||||
getFactoryData(): void {
|
||||
let promise;
|
||||
if (this.routeParams.id) {
|
||||
this.factory = this.cheAPI.getFactory().getFactoryById(this.routeParams.id);
|
||||
promise = this.cheAPI.getFactory().fetchFactoryById(this.routeParams.id);
|
||||
} else if (this.routeParams) {
|
||||
promise = this.processFactoryParameters(this.routeParams);
|
||||
} else {
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].hasError = true;
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].logs = 'Required parameters for loading factory are not there.';
|
||||
}
|
||||
if (promise) {
|
||||
promise.then((factory: che.IFactory) => {
|
||||
this.factory = factory;
|
||||
|
||||
// check factory polices:
|
||||
if (!this.checkPolicies(this.factory)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check factory contains workspace config:
|
||||
if (!this.factory.workspace) {
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].hasError = true;
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].logs = 'Factory has no workspace config.';
|
||||
} else {
|
||||
this.fetchWorkspaces();
|
||||
}
|
||||
}, (error: any) => {
|
||||
this.handleError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes factory parameters.
|
||||
*
|
||||
* @param parameters
|
||||
* @returns {any}
|
||||
*/
|
||||
processFactoryParameters(parameters: any): ng.IPromise<any> {
|
||||
// user name and factory name should be handled differently:
|
||||
if (parameters.name || parameters.user) {
|
||||
if (Object.keys(parameters).length === 2) {
|
||||
return this.processUser(parameters.user, parameters.name);
|
||||
} else {
|
||||
let paramName = parameters.name ? 'Factory name' : 'User name';
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].logs = 'Invalid factory URL. ' + paramName + ' is missed or misspelled.';
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].hasError = true;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return this.cheAPI.getFactory().fetchParameterFactory(parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes factory's user. Checks user with such name exists.
|
||||
*
|
||||
* @param name user name
|
||||
* @param factoryName
|
||||
* @returns {IPromise<IHttpPromiseCallbackArg<any>>}
|
||||
*/
|
||||
processUser(name: string, factoryName: string): ng.IPromise<any> {
|
||||
return this.cheAPI.getUser().fetchUserByName(name).then((user: che.IUser) => {
|
||||
return this.cheAPI.getFactory().fetchFactoryByName(factoryName, user.id);
|
||||
}, (error: any) => {
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].logs = 'Invalid factory URL. User with name ' + name + ' does not exist.';
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].hasError = true;
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks factory's policies.
|
||||
*
|
||||
* @param factory factory to be checked
|
||||
* @returns {boolean} <code>true</code> if factory policies validation has passed
|
||||
*/
|
||||
checkPolicies(factory: che.IFactory): boolean {
|
||||
if (!factory.policies || !factory.policies.referer) {
|
||||
return true;
|
||||
}
|
||||
// process referrer:
|
||||
let factoryReferrer = factory.policies.referer;
|
||||
let referrer = document.referrer;
|
||||
if (referrer && (referrer.indexOf(factoryReferrer) >= 0)) {
|
||||
return true;
|
||||
} else {
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].logs = 'Factory referrer policy does not match the current one.';
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].hasError = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles pointed error - prints it on the proper screen.
|
||||
*
|
||||
* @param error error to be handled
|
||||
*/
|
||||
handleError(error: any): void {
|
||||
if (error.data.message) {
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].logs = error.data.message;
|
||||
this.cheNotification.showError(error.data.message);
|
||||
}
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].hasError = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect workspace to start: create new one or get created one.
|
||||
*/
|
||||
getWorkspaceToStart(): void {
|
||||
let createPolicy = (this.factory.policies) ? this.factory.policies.create : 'perClick';
|
||||
var workspace = null;
|
||||
switch (createPolicy) {
|
||||
case 'perUser' :
|
||||
workspace = this.lodash.find(this.workspaces, (w: che.IWorkspace) => {
|
||||
return this.factory.id === w.attributes.factoryId;
|
||||
});
|
||||
break;
|
||||
case 'perAccount' :
|
||||
// todo when account is ready
|
||||
workspace = this.lodash.find(this.workspaces, (w: che.IWorkspace) => {
|
||||
return this.factory.workspace.name === w.config.name;
|
||||
});
|
||||
break;
|
||||
case 'perClick' :
|
||||
break;
|
||||
}
|
||||
|
||||
if (workspace) {
|
||||
this.startWorkspace(workspace);
|
||||
} else {
|
||||
this.createWorkspace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches workspaces.
|
||||
*/
|
||||
fetchWorkspaces(): any {
|
||||
this.loadFactoryService.goToNextStep();
|
||||
|
||||
let promise = this.cheAPI.getWorkspace().fetchWorkspaces();
|
||||
promise.then(() => {
|
||||
this.workspaces = this.cheAPI.getWorkspace().getWorkspaces();
|
||||
this.getWorkspaceToStart();
|
||||
}, () => {
|
||||
this.workspaces = this.cheAPI.getWorkspace().getWorkspaces();
|
||||
this.getWorkspaceToStart();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create workspace from factory config.
|
||||
*/
|
||||
createWorkspace(): any {
|
||||
let config = this.factory.workspace;
|
||||
// set factory attribute:
|
||||
let attrs = {factoryId: this.factory.id};
|
||||
config.name = this.getWorkspaceName(config.name);
|
||||
|
||||
// todo: fix account when ready:
|
||||
let creationPromise = this.cheAPI.getWorkspace().createWorkspaceFromConfig(null, config, attrs);
|
||||
creationPromise.then((data: any) => {
|
||||
this.$timeout(() => {
|
||||
this.startWorkspace(data);
|
||||
}, 1000);
|
||||
}, (error: any) => {
|
||||
this.handleError(error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get workspace name by detecting the existing names
|
||||
* and generate new name if necessary.
|
||||
*
|
||||
* @param name workspace name
|
||||
* @returns {string} generated name
|
||||
*/
|
||||
getWorkspaceName(name: string): string {
|
||||
if (this.workspaces.length === 0) {
|
||||
return name;
|
||||
}
|
||||
let existingNames = this.lodash.pluck(this.workspaces, 'config.name');
|
||||
|
||||
if (existingNames.indexOf(name) < 0) {
|
||||
return name;
|
||||
}
|
||||
|
||||
let generatedName = name;
|
||||
let counter = 1;
|
||||
while (existingNames.indexOf(generatedName) >= 0) {
|
||||
generatedName = name + '_' + counter++;
|
||||
}
|
||||
return generatedName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks workspace status and starts it if necessary,
|
||||
*
|
||||
* @param workspace workspace to process
|
||||
*/
|
||||
startWorkspace(workspace: che.IWorkspace): void {
|
||||
this.workspace = workspace;
|
||||
var bus = this.cheAPI.getWebsocket().getBus();
|
||||
|
||||
if (workspace.status === 'RUNNING') {
|
||||
this.loadFactoryService.setCurrentProgressStep(4);
|
||||
this.importProjects(bus);
|
||||
return;
|
||||
}
|
||||
|
||||
this.subscribeOnEvents(workspace, bus);
|
||||
|
||||
this.$timeout(() => {
|
||||
this.doStartWorkspace(workspace);
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs workspace start.
|
||||
*
|
||||
* @param workspace
|
||||
*/
|
||||
doStartWorkspace(workspace: che.IWorkspace): void {
|
||||
let startWorkspacePromise = this.cheAPI.getWorkspace().startWorkspace(workspace.id, workspace.config.defaultEnv);
|
||||
this.loadFactoryService.goToNextStep();
|
||||
|
||||
startWorkspacePromise.then((data: any) => {
|
||||
console.log('Workspace started', data);
|
||||
}, (error) => {
|
||||
let errorMessage;
|
||||
|
||||
if (!error || !error.data) {
|
||||
errorMessage = 'This factory is unable to start a new workspace.';
|
||||
} else if (error.data.errorCode === 10000 && error.data.attributes) {
|
||||
let attributes = error.data.attributes;
|
||||
|
||||
errorMessage = 'This factory is unable to start a new workspace.' +
|
||||
' Your running workspaces are consuming ' +
|
||||
attributes.used_ram + attributes.ram_unit + ' RAM.' +
|
||||
' Your current RAM limit is ' + attributes.limit_ram + attributes.ram_unit +
|
||||
'. This factory requested an additional ' +
|
||||
attributes.required_ram + attributes.ram_unit + '.' +
|
||||
' You can stop other workspaces to free resources.';
|
||||
} else {
|
||||
errorMessage = error.data.message;
|
||||
}
|
||||
|
||||
this.handleError({data: {message: errorMessage}});
|
||||
});
|
||||
}
|
||||
|
||||
subscribeOnEvents(data: any, bus: any): void {
|
||||
// get channels
|
||||
let statusLink = this.lodash.find(data.links, (link: any) => {
|
||||
return link.rel === 'environment.status_channel';
|
||||
});
|
||||
|
||||
let outputLink = this.lodash.find(data.links, (link: any) => {
|
||||
return link.rel === 'environment.output_channel';
|
||||
});
|
||||
|
||||
let workspaceId = data.id;
|
||||
|
||||
let agentChannel = 'workspace:' + data.id + ':ext-server:output';
|
||||
let statusChannel = statusLink ? statusLink.parameters[0].defaultValue : null;
|
||||
let outputChannel = outputLink ? outputLink.parameters[0].defaultValue : null;
|
||||
|
||||
bus.subscribe(outputChannel, (message: any) => {
|
||||
message = this.getDisplayMachineLog(message);
|
||||
if (this.getLoadingSteps()[this.getCurrentProgressStep()].logs.length > 0) {
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].logs = this.getLoadingSteps()[this.getCurrentProgressStep()].logs + '\n' + message;
|
||||
} else {
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].logs = message;
|
||||
}
|
||||
});
|
||||
|
||||
// for now, display log of status channel in case of errors
|
||||
bus.subscribe(statusChannel, (message: any) => {
|
||||
if (message.eventType === 'DESTROYED' && message.workspaceId === data.id) {
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].hasError = true;
|
||||
|
||||
// need to show the error
|
||||
this.$mdDialog.show(
|
||||
this.$mdDialog.alert()
|
||||
.title('Unable to start workspace')
|
||||
.content('Unable to start workspace. It may be linked to OutOfMemory or the container has been destroyed')
|
||||
.ariaLabel('Workspace start')
|
||||
.ok('OK')
|
||||
);
|
||||
}
|
||||
if (message.eventType === 'ERROR' && message.workspaceId === data.id) {
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].hasError = true;
|
||||
// need to show the error
|
||||
this.$mdDialog.show(
|
||||
this.$mdDialog.alert()
|
||||
.title('Error when starting workspace')
|
||||
.content('Unable to start workspace. Error when trying to start the workspace: ' + message.error)
|
||||
.ariaLabel('Workspace start')
|
||||
.ok('OK')
|
||||
);
|
||||
}
|
||||
console.log('Status channel of workspaceID', workspaceId, message);
|
||||
});
|
||||
|
||||
// subscribe to workspace events
|
||||
bus.subscribe('workspace:' + workspaceId, (message: any) => {
|
||||
|
||||
if (message.eventType === 'ERROR' && message.workspaceId === workspaceId) {
|
||||
// need to show the error
|
||||
this.$mdDialog.show(
|
||||
this.$mdDialog.alert()
|
||||
.title('Error when starting agent')
|
||||
.content('Unable to start workspace agent. Error when trying to start the workspace agent: ' + message.error)
|
||||
.ariaLabel('Workspace agent start')
|
||||
.ok('OK')
|
||||
);
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].hasError = true;
|
||||
}
|
||||
|
||||
if (message.eventType === 'RUNNING' && message.workspaceId === workspaceId) {
|
||||
this.finish();
|
||||
}
|
||||
});
|
||||
|
||||
bus.subscribe(agentChannel, (message: any) => {
|
||||
let agentStep = 3;
|
||||
if (this.loadFactoryService.getCurrentProgressStep() < agentStep) {
|
||||
this.loadFactoryService.setCurrentProgressStep(agentStep);
|
||||
}
|
||||
|
||||
if (this.getLoadingSteps()[agentStep].logs.length > 0) {
|
||||
this.getLoadingSteps()[agentStep].logs = this.getLoadingSteps()[agentStep].logs + '\n' + message;
|
||||
} else {
|
||||
this.getLoadingSteps()[agentStep].logs = message;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the log to be displayed per machine.
|
||||
*
|
||||
* @param log origin log content
|
||||
* @returns {*} parsed log
|
||||
*/
|
||||
getDisplayMachineLog(log: any): string {
|
||||
log = angular.fromJson(log);
|
||||
if (angular.isObject(log)) {
|
||||
return '[' + log.machineName + '] ' + log.content;
|
||||
} else {
|
||||
return log;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs importing projects.
|
||||
*
|
||||
* @param bus
|
||||
*/
|
||||
importProjects(bus: any): void {
|
||||
let promise = this.cheAPI.getWorkspace().fetchWorkspaceDetails(this.workspace.id);
|
||||
promise.then(() => {
|
||||
let projects = this.cheAPI.getWorkspace().getWorkspacesById().get(this.workspace.id).config.projects;
|
||||
this.detectProjectsToImport(projects, bus);
|
||||
}, (error: any) => {
|
||||
if (error.status !== 304) {
|
||||
let projects = this.cheAPI.getWorkspace().getWorkspacesById().get(this.workspace.id).config.projects;
|
||||
this.detectProjectsToImport(projects, bus);
|
||||
} else {
|
||||
this.handleError(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the projects to be imported.
|
||||
*
|
||||
* @param projects projects list
|
||||
* @param bus
|
||||
*/
|
||||
detectProjectsToImport(projects: Array<che.IProject>, bus: any): void {
|
||||
this.projectsToImport = 0;
|
||||
|
||||
projects.forEach((project: che.IProject) => {
|
||||
if (!this.isProjectOnFileSystem(project)) {
|
||||
this.projectsToImport++;
|
||||
this.importProject(this.workspace.id, project, bus);
|
||||
}
|
||||
});
|
||||
|
||||
if (this.projectsToImport === 0) {
|
||||
this.finish();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Project is on file system if there is no errors except code=9.
|
||||
*/
|
||||
isProjectOnFileSystem(project: che.IProject): boolean {
|
||||
let problems = project.problems;
|
||||
if (!problems || problems.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (var i = 0; i < problems.length; i++) {
|
||||
if (problems[i].code === 9) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs project import to pointed workspace.
|
||||
*
|
||||
* @param workspaceId workspace id, where project should be imported to
|
||||
* @param project project to be imported
|
||||
* @param bus
|
||||
*/
|
||||
importProject(workspaceId: string, project: che.IProject, bus: any): void {
|
||||
var promise;
|
||||
// websocket channel
|
||||
var channel = 'importProject:output';
|
||||
|
||||
// on import
|
||||
bus.subscribe(channel, (message: any) => {
|
||||
this.getLoadingSteps()[this.getCurrentProgressStep()].logs = message.line;
|
||||
});
|
||||
|
||||
let projectService = this.cheAPI.getWorkspace().getWorkspaceAgent(workspaceId).getProject();
|
||||
promise = projectService.importProject(project.name, project.source);
|
||||
|
||||
// needs to update configuration of the project
|
||||
let updatePromise = promise.then(() => {
|
||||
projectService.updateProject(project.name, project);
|
||||
}, (error) => {
|
||||
this.handleError(error);
|
||||
});
|
||||
|
||||
updatePromise.then(() => {
|
||||
this.projectsToImport--;
|
||||
if (this.projectsToImport === 0) {
|
||||
this.finish();
|
||||
}
|
||||
bus.unsubscribe(channel);
|
||||
}, (error: any) => {
|
||||
bus.unsubscribe(channel);
|
||||
this.handleError(error);
|
||||
|
||||
// need to show the error
|
||||
this.$mdDialog.show(
|
||||
this.$mdDialog.alert()
|
||||
.title('Error while importing project')
|
||||
.content(error.statusText + ': ' + error.data.message)
|
||||
.ariaLabel('Import project')
|
||||
.ok('OK')
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs operations at the end of accepting factory.
|
||||
*/
|
||||
finish(): void {
|
||||
this.loadFactoryService.setCurrentProgressStep(4);
|
||||
|
||||
// people should go back to the dashboard after factory is initialized
|
||||
this.routeHistory.pushPath('/');
|
||||
|
||||
var ideParams = [];
|
||||
if (this.routeParams) {
|
||||
if (this.routeParams.id || (this.routeParams.name && this.routeParams.user)) {
|
||||
ideParams.push('factory-id:' + this.factory.id);
|
||||
} else {
|
||||
// add every factory parameter by prefix
|
||||
Object.keys(this.routeParams).forEach((key: string) => {
|
||||
ideParams.push('factory-' + key + ':' + this.$window.encodeURIComponent(this.routeParams[key]));
|
||||
});
|
||||
}
|
||||
|
||||
// add factory mode
|
||||
ideParams.push('factory:' + 'true');
|
||||
}
|
||||
// add workspace Id
|
||||
ideParams.push('workspaceId:' + this.workspace.id);
|
||||
|
||||
this.$location.path(this.getIDELink()).search('ideParams', ideParams);
|
||||
|
||||
// restore elements
|
||||
this.restoreMenuAndFooter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns workspace name.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
getWorkspace(): string {
|
||||
return this.workspace.config.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text(logs) of pointed step.
|
||||
*
|
||||
* @param stepNumber number of step
|
||||
* @returns {string} step's text
|
||||
*/
|
||||
getStepText(stepNumber: number): string {
|
||||
return this.loadFactoryService.getStepText(stepNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns loading steps of the factory.
|
||||
*
|
||||
* @returns {any}
|
||||
*/
|
||||
getLoadingSteps(): any {
|
||||
return this.loadFactoryService.getFactoryLoadingSteps();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current step, which is in progress.
|
||||
*
|
||||
* @returns {any} the info of current step, which is in progress
|
||||
*/
|
||||
getCurrentProgressStep(): any {
|
||||
return this.loadFactoryService.getCurrentProgressStep();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the loading factory in progress state.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isLoadFactoryInProgress(): boolean {
|
||||
return this.loadFactoryService.isLoadFactoryInProgress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the loading factory process in progress.
|
||||
*/
|
||||
setLoadFactoryInProgress(): void {
|
||||
this.loadFactoryService.setLoadFactoryInProgress(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the loading factory process.
|
||||
*/
|
||||
resetLoadFactoryInProgress(): void {
|
||||
this.restoreMenuAndFooter();
|
||||
let newLocation = this.isResourceProblem() ? '/workspaces' : '/factories';
|
||||
this.$location.path(newLocation);
|
||||
this.loadFactoryService.resetLoadProgress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns IDE link.
|
||||
*
|
||||
* @returns {string} IDE application link
|
||||
*/
|
||||
getIDELink() {
|
||||
return '/ide/' + this.workspace.namespace + '/' + this.workspace.config.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs navigation back to dashboard.
|
||||
*/
|
||||
backToDashboard(): void {
|
||||
this.restoreMenuAndFooter();
|
||||
this.$location.path('/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs downloading of the logs.
|
||||
*/
|
||||
downloadLogs(): void {
|
||||
let logs = '';
|
||||
this.getLoadingSteps().forEach((step) => {
|
||||
logs += step.logs + '\n';
|
||||
});
|
||||
window.open('data:text/csv,' + encodeURIComponent(logs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether there was problem with resources.
|
||||
*
|
||||
* @returns {any|boolean}
|
||||
*/
|
||||
isResourceProblem(): boolean {
|
||||
let currentCreationStep = this.getLoadingSteps()[this.getCurrentProgressStep()];
|
||||
return currentCreationStep.hasError && currentCreationStep.logs.includes('You can stop other workspaces');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<!--
|
||||
|
||||
CODENVY CONFIDENTIAL
|
||||
__________________
|
||||
|
||||
[2015] - [2016] Codenvy, S.A.
|
||||
All Rights Reserved.
|
||||
|
||||
NOTICE: All information contained herein is, and remains
|
||||
the property of Codenvy S.A. and its suppliers,
|
||||
if any. The intellectual and technical concepts contained
|
||||
herein are proprietary to Codenvy S.A.
|
||||
and its suppliers and may be covered by U.S. and Foreign Patents,
|
||||
patents in process, and are protected by trade secret or copyright law.
|
||||
Dissemination of this information or reproduction of this material
|
||||
is strictly forbidden unless prior written permission is obtained
|
||||
from Codenvy S.A..
|
||||
|
||||
-->
|
||||
<div class="load-factory-main-container">
|
||||
<div flex class="ide-loader" layout-align="center center" layout="column">
|
||||
<div class="load-factory-content">
|
||||
<che-loader layout="column" layout-aling="center center">
|
||||
<!--crane and terminals-->
|
||||
<div layout="row" class="che-loader-animation-panel main-page" flex>
|
||||
<div layout="column"
|
||||
hide-xs hide-sm
|
||||
layout-align="end-start">
|
||||
<che-loader-crane che-all-steps="loadFactoryController.getLoadingSteps()"
|
||||
che-exclude-steps="[loadFactoryController.getLoadingSteps().length-1]"
|
||||
che-step="{{loadFactoryController.getCurrentProgressStep()}}"
|
||||
che-switch-on-iteration="true">
|
||||
</che-loader-crane>
|
||||
</div>
|
||||
<div layout="column"
|
||||
layout-align="center center"
|
||||
flex="auto">
|
||||
<che-steps-container class="load-factory-working-log"
|
||||
che-all-steps="loadFactoryController.getLoadingSteps()"
|
||||
che-current-step="loadFactoryController.getCurrentProgressStep()"></che-steps-container>
|
||||
</div>
|
||||
</div>
|
||||
<!--bottom bar-->
|
||||
<div class="che-loader-bottom-bar" flex="none">
|
||||
<div layout="row" layout-align="center stretch" class="main-page load-factory-bottom-bar">
|
||||
<div flex="50" layout="column" layout-align="end start" class="load-factory-bottom-bar-left">
|
||||
<che-link ng-click="loadFactoryController.backToDashboard()" che-link-text="← Back to Dashboard"
|
||||
class="load-factory-back-link"></che-link>
|
||||
</div>
|
||||
<div flex="50" layout="column" layout-align="end end" class="load-factory-bottom-bar-right">
|
||||
<div class="load-factory-retry-block"
|
||||
layout="column" layout-align="start end">
|
||||
<che-button-danger che-button-title="{{loadFactoryController.isResourceProblem() ? 'Stop running workspaces' : 'Retry'}}"
|
||||
ng-click="loadFactoryController.resetLoadFactoryInProgress()"
|
||||
ng-show="loadFactoryController.getLoadingSteps()[loadFactoryController.getCurrentProgressStep()].hasError"></che-button-danger>
|
||||
<che-link class="load-factory-download-link"
|
||||
ng-click="loadFactoryController.downloadLogs()"
|
||||
che-link-text="Problem? download logs"></che-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</che-loader>
|
||||
</div>
|
||||
|
||||
<div class="load-factory-logo logo-color-white" ng-include="branding.logoURL"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 service for the factory loading.
|
||||
* @author Ann Shumilova
|
||||
*/
|
||||
export class LoadFactoryService {
|
||||
private loadFactoryInProgress: boolean;
|
||||
private currentProgressStep: number;
|
||||
private loadingSteps: Array<any>;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor () {
|
||||
this.loadFactoryInProgress = false;
|
||||
this.currentProgressStep = 0;
|
||||
|
||||
|
||||
this.loadingSteps = [
|
||||
{text: 'Loading factory', inProgressText: '', logs: '', hasError: false},
|
||||
{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: '', logs: '', hasError: false}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text of the pointed step depending on it's state.
|
||||
*
|
||||
* @param stepNumber number of the step.
|
||||
* @returns {string} steps's text
|
||||
*/
|
||||
getStepText(stepNumber: number): string {
|
||||
let entry = this.loadingSteps[stepNumber];
|
||||
if (this.currentProgressStep >= stepNumber) {
|
||||
return entry.inProgressText;
|
||||
} else {
|
||||
return entry.text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the information of the factory's loading steps.
|
||||
*
|
||||
* @returns {Array<any>} loading steps of the factory
|
||||
*/
|
||||
getFactoryLoadingSteps(): Array<any> {
|
||||
return this.loadingSteps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of the step, which has to be in progress.
|
||||
*
|
||||
* @param currentProgressStep step number
|
||||
*/
|
||||
setCurrentProgressStep(currentProgressStep: number): void {
|
||||
this.currentProgressStep = currentProgressStep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proceeds the flow to the next step.
|
||||
*/
|
||||
goToNextStep(): void {
|
||||
this.currentProgressStep++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of the current step.
|
||||
*
|
||||
* @returns {number} current step's number
|
||||
*/
|
||||
getCurrentProgressStep(): number {
|
||||
return this.currentProgressStep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the loading progress.
|
||||
*/
|
||||
resetLoadProgress(): void {
|
||||
this.loadingSteps.forEach((step) => {
|
||||
step.logs = '';
|
||||
step.hasError = false;
|
||||
});
|
||||
this.currentProgressStep = 0;
|
||||
|
||||
this.loadFactoryInProgress = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the in-progress state of the whole factory loading flow.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isLoadFactoryInProgress(): boolean {
|
||||
return this.loadFactoryInProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the in-progress state of the whole factory loading flow.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
setLoadFactoryInProgress(value: boolean): void {
|
||||
this.loadFactoryInProgress = value;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
.load-factory-main-container
|
||||
position absolute
|
||||
width 100%
|
||||
height 100%
|
||||
|
||||
.ide-loader
|
||||
height 100%
|
||||
width 100%
|
||||
background-color #1c253f
|
||||
|
||||
.load-factory-content
|
||||
width 100%
|
||||
|
||||
.load-factory-working-log
|
||||
margin 35px 0
|
||||
|
||||
.load-factory-bottom-bar
|
||||
height 90px
|
||||
|
||||
.load-factory-bottom-bar-left
|
||||
margin-left 100px
|
||||
|
||||
.load-factory-bottom-bar-right
|
||||
margin-right 35px
|
||||
|
||||
.load-factory-back-link
|
||||
margin-top 20px
|
||||
|
||||
.load-factory-download-link
|
||||
margin-top 20px
|
||||
margin-right 8px
|
||||
|
||||
@media (max-width:959px)
|
||||
.load-factory-bottom-bar
|
||||
.load-factory-bottom-bar-left
|
||||
margin-left 8px
|
||||
.load-factory-bottom-bar-right
|
||||
margin-right 8px
|
||||
|
||||
.load-factory-logo
|
||||
height 35px
|
||||
position fixed
|
||||
left 0
|
||||
right 0
|
||||
bottom 15px
|
||||
margin auto
|
||||
z-index 100
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
'use strict';
|
||||
|
||||
import {Register} from '../components/utils/register';
|
||||
import {FactoryConfig} from './factories/factories-config';
|
||||
|
||||
import {ComponentsConfig} from '../components/components-config';
|
||||
|
||||
|
|
@ -383,3 +384,4 @@ new WorkspacesConfig(instanceRegister);
|
|||
new DashboardConfig(instanceRegister);
|
||||
new StacksConfig(instanceRegister);
|
||||
new DocsConfig(instanceRegister);
|
||||
new FactoryConfig(instanceRegister);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export class CheNavBarController {
|
|||
administration: '#/administration',
|
||||
// subsections
|
||||
plugins: '#/admin/plugins',
|
||||
factories: '#/factories',
|
||||
account: '#/account',
|
||||
stacks: '#/stacks'
|
||||
};
|
||||
|
|
@ -81,6 +82,11 @@ export class CheNavBarController {
|
|||
getWorkspacesNumber(): number {
|
||||
return this.cheAPI.getWorkspace().getWorkspaces().length;
|
||||
}
|
||||
|
||||
getFactoriesNumber(): number {
|
||||
let pagesInfo = this.cheAPI.getFactory().getPagesInfo();
|
||||
return pagesInfo && pagesInfo.count ? pagesInfo.count : this.cheAPI.getFactory().factoriesById.size;
|
||||
}
|
||||
|
||||
openLinkInNewTab(url: string): void {
|
||||
this.$window.open(url, '_blank');
|
||||
|
|
|
|||
|
|
@ -49,6 +49,16 @@
|
|||
</div>
|
||||
</md-button>
|
||||
</md-list-item>
|
||||
<md-list-item flex class="navbar-subsection-item">
|
||||
<md-button nav-bar-selected flex che-reload-href
|
||||
href="{{navbarCtrl.menuItemUrl.factories}}" layout-align="left">
|
||||
<div class="navbar-item" layout="row" layout-align="start center">
|
||||
<md-icon md-font-icon="navbar-icon chefont cheico-factory"></md-icon>
|
||||
<span>Factories</span>
|
||||
<span class="navbar-number" ng-show="navbarCtrl.getFactoriesNumber()"> ({{navbarCtrl.getFactoriesNumber()}})</span>
|
||||
</div>
|
||||
</md-button>
|
||||
</md-list-item>
|
||||
<md-list-item flex class="navbar-subsection-item">
|
||||
<md-button nav-bar-selected flex che-reload-href
|
||||
href="{{navbarCtrl.menuItemUrl.administration}}" layout-align="left">
|
||||
|
|
|
|||
|
|
@ -12,12 +12,14 @@
|
|||
|
||||
import {CheWorkspaceBuilder} from './che-workspace-builder';
|
||||
import {CheProjectReferenceBuilder} from './che-projectreference-builder';
|
||||
import {CheFactoryBuilder} from './che-factory-builder';
|
||||
import {CheProjectDetailsBuilder} from './che-projectdetails-builder';
|
||||
import {CheProjectTypeBuilder} from './che-projecttype-builder';
|
||||
import {CheProjectTemplateBuilder} from './che-projecttemplate-builder';
|
||||
import {CheProjectTypeAttributeDescriptorBuilder} from './che-projecttype-attribute-descriptor-builder';
|
||||
import {CheProfileBuilder} from './che-profile-builder';
|
||||
import {CheStackBuilder} from './che-stack-builder';
|
||||
import {CheUserBuilder} from './che-user-builder';
|
||||
|
||||
/**
|
||||
* This class is providing the entry point for accessing the builders
|
||||
|
|
@ -96,4 +98,20 @@ export class CheAPIBuilder {
|
|||
getStackBuilder() {
|
||||
return new CheStackBuilder();
|
||||
}
|
||||
|
||||
/***
|
||||
* The Che Factory builder
|
||||
* @returns {CheFactoryBuilder}
|
||||
*/
|
||||
getFactoryBuilder() {
|
||||
return new CheFactoryBuilder();
|
||||
}
|
||||
|
||||
/***
|
||||
* The Che User builder
|
||||
* @returns {CheUserBuilder}
|
||||
*/
|
||||
getUserBuilder() {
|
||||
return new CheUserBuilder();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 providing a builder for factory
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class CheFactoryBuilder {
|
||||
|
||||
private factory: che.IFactory;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
constructor() {
|
||||
this.factory = {};
|
||||
this.factory.creator = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the creator email
|
||||
* @param email
|
||||
* @returns {CheFactoryBuilder}
|
||||
*/
|
||||
withCreatorEmail(email) {
|
||||
this.factory.creator.email = email;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the creator name
|
||||
* @param name
|
||||
* @returns {CheFactoryBuilder}
|
||||
*/
|
||||
withCreatorName(name) {
|
||||
this.factory.creator.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id of the factory
|
||||
* @param id
|
||||
* @returns {CheFactoryBuilder}
|
||||
*/
|
||||
withId(id) {
|
||||
this.factory.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the factory
|
||||
* @param name
|
||||
* @returns {CheFactoryBuilder}
|
||||
*/
|
||||
withName(name) {
|
||||
this.factory.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the workspace of the factory
|
||||
* @param workspace
|
||||
* @returns {CheFactoryBuilder}
|
||||
*/
|
||||
withWorkspace(workspace) {
|
||||
this.factory.workspace = workspace;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the factory
|
||||
* @returns {CheFactoryBuilder|*}
|
||||
*/
|
||||
build() {
|
||||
return this.factory;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 providing a builder for User
|
||||
* @author Florent Benoit
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class CheUserBuilder {
|
||||
private user: che.IUser;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
constructor() {
|
||||
this.user = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the email of the user
|
||||
* @param email the email to use
|
||||
* @returns {CodenvyUserBuilder}
|
||||
*/
|
||||
withEmail(email) {
|
||||
this.user.email = email;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id of the user
|
||||
* @param id the id to use
|
||||
* @returns {CodenvyUserBuilder}
|
||||
*/
|
||||
withId(id) {
|
||||
this.user.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aliases of the user
|
||||
* @param aliases the aliases to use
|
||||
* @returns {CodenvyUserBuilder}
|
||||
*/
|
||||
withAliases(aliases) {
|
||||
this.user.aliases = aliases;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the user
|
||||
* @returns {CodenvyUserBuilder.user|*}
|
||||
*/
|
||||
build() {
|
||||
return this.user;
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ import {CheWorkspace} from './che-workspace.factory';
|
|||
import {CheProjectTemplate} from './che-project-template.factory';
|
||||
import {CheRecipe} from './che-recipe.factory';
|
||||
import {CheRecipeTemplate} from './che-recipe-template.factory';
|
||||
import {CheFactory} from './che-factory.factory';
|
||||
import {CheStack} from './che-stack.factory';
|
||||
import {CheWebsocket} from './che-websocket.factory';
|
||||
import {CheProfile} from './che-profile.factory';
|
||||
|
|
@ -22,6 +23,7 @@ import {ChePreferences} from './che-preferences.factory';
|
|||
import {CheService} from './che-service.factory';
|
||||
import {CheHttpBackend} from './test/che-http-backend';
|
||||
import {CheHttpBackendProviderFactory} from './test/che-http-backend-provider.factory'
|
||||
import {CheFactoryTemplate} from './che-factory-template.factory';
|
||||
import {CheHttpBackendFactory} from './test/che-http-backend.factory';
|
||||
import {CheAPIBuilder} from './builder/che-api-builder.factory';
|
||||
import {CheAdminPlugins} from './che-admin-plugins.factory';
|
||||
|
|
@ -32,12 +34,14 @@ import {CheEnvironmentRegistry} from './environment/che-environment-registry.fac
|
|||
import {CheAgent} from './che-agent.factory';
|
||||
import {CheSsh} from './che-ssh.factory';
|
||||
import {CheNamespaceRegistry} from './namespace/che-namespace-registry.factory';
|
||||
import {CheUser} from './che-user.factory';
|
||||
|
||||
export class ApiConfig {
|
||||
|
||||
constructor(register) {
|
||||
register.factory('cheWorkspace', CheWorkspace);
|
||||
register.factory('cheProjectTemplate', CheProjectTemplate);
|
||||
register.factory('cheFactory', CheFactory);
|
||||
register.factory('cheProfile', CheProfile);
|
||||
register.factory('chePreferences', ChePreferences);
|
||||
register.factory('cheWebsocket', CheWebsocket);
|
||||
|
|
@ -49,6 +53,7 @@ export class ApiConfig {
|
|||
register.factory('cheAPIBuilder', CheAPIBuilder);
|
||||
register.factory('cheAdminPlugins', CheAdminPlugins);
|
||||
register.factory('cheAdminService', CheAdminService);
|
||||
register.factory('cheFactoryTemplate', CheFactoryTemplate);
|
||||
register.factory('cheService', CheService);
|
||||
register.factory('cheAPI', CheAPI);
|
||||
register.factory('cheRemote', CheRemote);
|
||||
|
|
@ -57,5 +62,6 @@ export class ApiConfig {
|
|||
register.factory('cheAgent', CheAgent);
|
||||
register.factory('cheSsh', CheSsh);
|
||||
register.factory('cheNamespaceRegistry', CheNamespaceRegistry);
|
||||
register.factory('cheUser', CheUser);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import {CheSsh} from './che-ssh.factory';
|
|||
'use strict';
|
||||
import {CheWorkspace} from './che-workspace.factory';
|
||||
import {CheProfile} from './che-profile.factory';
|
||||
import {CheFactory} from './che-factory.factory';
|
||||
import {CheFactoryTemplate} from './che-factory-template.factory';
|
||||
import {ChePreferences} from './che-preferences.factory';
|
||||
import {CheProjectTemplate} from './che-project-template.factory';
|
||||
import {CheWebsocket} from './che-websocket.factory';
|
||||
|
|
@ -23,6 +25,7 @@ import {CheRecipeTemplate} from './che-recipe-template.factory';
|
|||
import {CheStack} from './che-stack.factory';
|
||||
import {CheOAuthProvider} from './che-o-auth-provider.factory';
|
||||
import {CheAgent} from './che-agent.factory';
|
||||
import {CheUser} from './che-user.factory';
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -37,6 +40,8 @@ export class CheAPI {
|
|||
private chePreferences: ChePreferences;
|
||||
private cheProjectTemplate: CheProjectTemplate;
|
||||
private cheWebsocket: CheWebsocket;
|
||||
private cheFactory: CheFactory;
|
||||
private cheFactoryTemplate: CheFactoryTemplate;
|
||||
private cheService: CheService;
|
||||
private cheAdminPlugins: CheAdminPlugins;
|
||||
private cheAdminService: CheAdminService;
|
||||
|
|
@ -46,14 +51,20 @@ export class CheAPI {
|
|||
private cheOAuthProvider: CheOAuthProvider;
|
||||
private cheAgent: CheAgent;
|
||||
private cheSsh: CheSsh;
|
||||
private cheUser: CheUser;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor(cheWorkspace: CheWorkspace, cheProfile: CheProfile, chePreferences: ChePreferences, cheProjectTemplate: CheProjectTemplate, cheWebsocket: CheWebsocket, cheService: CheService, cheAdminPlugins: CheAdminPlugins, cheAdminService: CheAdminService, cheRecipe: CheRecipe, cheRecipeTemplate: CheRecipeTemplate, cheStack: CheStack, cheOAuthProvider: CheOAuthProvider, cheAgent: CheAgent, cheSsh: CheSsh) {
|
||||
constructor(cheWorkspace: CheWorkspace, cheFactory: CheFactory, cheFactoryTemplate: CheFactoryTemplate, cheProfile: CheProfile,
|
||||
chePreferences: ChePreferences, cheProjectTemplate: CheProjectTemplate, cheWebsocket: CheWebsocket, cheService: CheService,
|
||||
cheAdminPlugins: CheAdminPlugins, cheAdminService: CheAdminService, cheRecipe: CheRecipe, cheRecipeTemplate: CheRecipeTemplate,
|
||||
cheStack: CheStack, cheOAuthProvider: CheOAuthProvider, cheAgent: CheAgent, cheSsh: CheSsh, cheUser: CheUser) {
|
||||
this.cheWorkspace = cheWorkspace;
|
||||
this.cheProfile = cheProfile;
|
||||
this.cheFactory = cheFactory;
|
||||
this.cheFactoryTemplate = cheFactoryTemplate;
|
||||
this.chePreferences = chePreferences;
|
||||
this.cheProjectTemplate = cheProjectTemplate;
|
||||
this.cheWebsocket = cheWebsocket;
|
||||
|
|
@ -66,6 +77,7 @@ export class CheAPI {
|
|||
this.cheOAuthProvider = cheOAuthProvider;
|
||||
this.cheAgent = cheAgent;
|
||||
this.cheSsh = cheSsh;
|
||||
this.cheUser = cheUser;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -129,7 +141,7 @@ export class CheAPI {
|
|||
* The Che Admin Services API
|
||||
* @returns {CheAdminService}
|
||||
*/
|
||||
getAdminService() {
|
||||
getAdminService(): CheAdminService {
|
||||
return this.cheAdminService;
|
||||
}
|
||||
|
||||
|
|
@ -182,4 +194,28 @@ export class CheAPI {
|
|||
return this.cheSsh;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Che Factory API
|
||||
* @returns {CheFactory|*}
|
||||
*/
|
||||
getFactory(): CheFactory {
|
||||
return this.cheFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Che Factory Template API
|
||||
* @returns {CheFactoryTemplate|*}
|
||||
*/
|
||||
getFactoryTemplate(): CheFactoryTemplate {
|
||||
return this.cheFactoryTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Che use API.
|
||||
*
|
||||
* @returns {CheUser}
|
||||
*/
|
||||
getUser(): CheUser {
|
||||
return this.cheUser;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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 factory template retrieval
|
||||
* It sets to the Map factory templates
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class CheFactoryTemplate {
|
||||
|
||||
private $resource: ng.resource.IResourceService;
|
||||
private $q: ng.IQService;
|
||||
private factoryTemplatesByName: Map<string, any>;
|
||||
private remoteFactoryTemplateAPI: ng.resource.IResourceClass<any>;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($resource: ng.resource.IResourceService, $q: ng.IQService) {
|
||||
// keep resource
|
||||
this.$resource = $resource;
|
||||
this.$q = $q;
|
||||
|
||||
// factory templates map
|
||||
this.factoryTemplatesByName = new Map();
|
||||
|
||||
// remote call
|
||||
this.remoteFactoryTemplateAPI = this.$resource('https://dockerfiles.codenvycorp.com/templates-4.8/factory/:fileName');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask for loading the factory template in asynchronous way
|
||||
* If there are no changes, it's not updated
|
||||
* @param templateName the template name
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
fetchFactoryTemplate(templateName: string): ng.IPromise<any> {
|
||||
var deferred = this.$q.defer();
|
||||
|
||||
let templateFileName = templateName + '.json';
|
||||
|
||||
let promise = this.remoteFactoryTemplateAPI.get({fileName: templateFileName}).$promise;
|
||||
|
||||
promise.then((factoryTemplateContent) => {
|
||||
//update factory template map
|
||||
this.factoryTemplatesByName.set(templateName, factoryTemplateContent);
|
||||
deferred.resolve(factoryTemplateContent);
|
||||
}, (error) => {
|
||||
if (error.status === 304) {
|
||||
let findFactoryTemplateContent = this.factoryTemplatesByName.get(templateName);
|
||||
deferred.resolve(findFactoryTemplateContent);
|
||||
} else {
|
||||
deferred.reject(error);
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets factory template by template name
|
||||
* @param templateName the template name
|
||||
* @returns factory template content
|
||||
*/
|
||||
getFactoryTemplate(templateName: string): any {
|
||||
return this.factoryTemplatesByName.get(templateName);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,645 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
import {CheUser} from './che-user.factory';
|
||||
|
||||
/* global FormData */
|
||||
|
||||
interface IFactoriesResource<T> extends ng.resource.IResourceClass<T> {
|
||||
updateFactory: any;
|
||||
getFactoryContentFromWorkspace: any;
|
||||
getFactoryParameters: any;
|
||||
createFactoryByContent: any;
|
||||
getFactories: any;
|
||||
getFactoryByName: any;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This class is handling the factory retrieval
|
||||
* @author Florent Benoit
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class CheFactory {
|
||||
private $resource: ng.resource.IResourceService;
|
||||
private $q: ng.IQService;
|
||||
private lodash: _.LoDashStatic;
|
||||
private cheUser: CheUser;
|
||||
|
||||
private remoteFactoryAPI: IFactoriesResource<any>;
|
||||
|
||||
private factoriesById: Map<string, che.IFactory>;
|
||||
private factoriesByName: Map<string, che.IFactory>;
|
||||
private parametersFactories: Map<string, che.IFactory>;
|
||||
private factoryContentsByWorkspaceId: Map<string, any>;
|
||||
private pageFactories: Array<che.IFactory>;
|
||||
private factoryPagesMap: Map<number, any>;
|
||||
private pageInfo: any;
|
||||
private itemsPerPage: number;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($resource: ng.resource.IResourceService, $q: ng.IQService, lodash: _.LoDashStatic, cheUser: CheUser) {
|
||||
// keep resource
|
||||
this.$resource = $resource;
|
||||
this.$q = $q;
|
||||
this.cheUser = cheUser;
|
||||
|
||||
this.lodash = lodash;
|
||||
|
||||
// factories details by id
|
||||
this.factoriesById = new Map();
|
||||
// factories details by key: userID:factoryName
|
||||
this.factoriesByName = new Map();
|
||||
this.parametersFactories = new Map();
|
||||
this.factoryContentsByWorkspaceId = new Map();
|
||||
|
||||
//paging
|
||||
this.pageFactories = [];// all current page factories
|
||||
this.factoryPagesMap = new Map();// page factories by relative link
|
||||
this.pageInfo = {};//pages info
|
||||
|
||||
this.remoteFactoryAPI = <IFactoriesResource<any>>this.$resource('/api/factory/:factoryId', {factoryId: '@id'}, {
|
||||
updateFactory: {method: 'PUT', url: '/api/factory/:factoryId'},
|
||||
getFactoryContentFromWorkspace: {method: 'GET', url: '/api/factory/workspace/:workspaceId'},
|
||||
getFactoryParameters: {method: 'POST', url: '/api/factory/resolver/'},
|
||||
createFactoryByContent: {
|
||||
method: 'POST',
|
||||
url: '/api/factory',
|
||||
isArray: false,
|
||||
headers: {'Content-Type': undefined},
|
||||
transformRequest: angular.identity
|
||||
},
|
||||
getFactories: {
|
||||
method: 'GET',
|
||||
url: '/api/factory/find?creator.userId=:userId&maxItems=:maxItems&skipCount=:skipCount',
|
||||
isArray: false,
|
||||
responseType: 'json',
|
||||
transformResponse: (data, headersGetter) => {
|
||||
return this._getPageFromResponse(data, headersGetter('link'));
|
||||
}
|
||||
},
|
||||
getFactoryByName: {
|
||||
method: 'GET',
|
||||
url: '/api/factory/find?creator.userId=:userId&name=:factoryName',
|
||||
isArray: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_getPageFromResponse(data: any, headersLink: any): any {
|
||||
let links = new Map();
|
||||
if (!headersLink) {
|
||||
//TODO remove it after adding headers paging links on server side
|
||||
let user = this.cheUser.getUser().id;
|
||||
if (!this.itemsPerPage || !user) {
|
||||
return {factories: data};
|
||||
}
|
||||
this.pageInfo.currentPageNumber = this.pageInfo.currentPageNumber ? this.pageInfo.currentPageNumber : 1;
|
||||
let link = '/api/factory/find?creator.userId=' + user + '&maxItems=' + this.itemsPerPage;
|
||||
links.set('first', link + '&skipCount=0');
|
||||
if (data && data.length > 0) {
|
||||
links.set('next', link + '&skipCount=' + this.pageInfo.currentPageNumber * this.itemsPerPage);
|
||||
}
|
||||
if (this.pageInfo.currentPageNumber > 1) {
|
||||
links.set('prev', link + '&skipCount=' + (this.pageInfo.currentPageNumber - 2) * this.itemsPerPage);
|
||||
}
|
||||
return {
|
||||
factories: data,
|
||||
links: links
|
||||
};
|
||||
}
|
||||
let pattern = new RegExp('<([^>]+?)>.+?rel="([^"]+?)"', 'g');
|
||||
let result;
|
||||
while (result = pattern.exec(headersLink)) { //look for pattern
|
||||
links.set(result[2], result[1]);//add link
|
||||
}
|
||||
return {
|
||||
factories: data,
|
||||
links: links
|
||||
};
|
||||
}
|
||||
|
||||
_getPageParamByLink(pageLink: string): any {
|
||||
let pageParamMap = new Map();
|
||||
let pattern = new RegExp('([_\\w]+)=([\\w]+)', 'g');
|
||||
let result;
|
||||
while (result = pattern.exec(pageLink)) {
|
||||
pageParamMap.set(result[1], result[2]);
|
||||
}
|
||||
|
||||
let skipCount = pageParamMap.get('skipCount');
|
||||
let maxItems = pageParamMap.get('maxItems');
|
||||
if (!maxItems || maxItems === 0) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
maxItems: maxItems,
|
||||
skipCount: skipCount ? skipCount : 0
|
||||
};
|
||||
}
|
||||
|
||||
_updateCurrentPage(): void {
|
||||
let pageData = this.factoryPagesMap.get(this.pageInfo.currentPageNumber);
|
||||
if (!pageData) {
|
||||
return;
|
||||
}
|
||||
this.pageFactories.length = 0;
|
||||
if (!pageData.factories) {
|
||||
return;
|
||||
}
|
||||
pageData.factories.forEach((factory: che.IFactory) => {
|
||||
factory.name = factory.name ? factory.name : '';
|
||||
this.pageFactories.push(factory);
|
||||
});
|
||||
}
|
||||
|
||||
_updateCurrentPageFactories(factories: Array<any>): void {
|
||||
this.pageFactories.length = 0;
|
||||
if (!factories) {
|
||||
return;
|
||||
}
|
||||
factories.forEach((factory: any) => {
|
||||
factory.name = factory.name ? factory.name : '';
|
||||
this.pageFactories.push(factory);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update factory page links by relative direction ('first', 'prev', 'next', 'last')
|
||||
*/
|
||||
_updatePagesData(data: any): void {
|
||||
if (!data.links) {
|
||||
return;
|
||||
}
|
||||
|
||||
let firstPageLink = data.links.get('first');
|
||||
if (firstPageLink) {
|
||||
let firstPageData = {link: firstPageLink, factories: null};
|
||||
if (this.pageInfo.currentPageNumber === 1) {
|
||||
firstPageData.factories = data.factories;
|
||||
}
|
||||
if (!this.factoryPagesMap.get(1) || firstPageData.factories) {
|
||||
this.factoryPagesMap.set(1, firstPageData);
|
||||
}
|
||||
}
|
||||
let lastPageLink = data.links.get('last');
|
||||
if (lastPageLink) {
|
||||
let pageParam = this._getPageParamByLink(lastPageLink);
|
||||
this.pageInfo.countOfPages = pageParam.skipCount / pageParam.maxItems + 1;
|
||||
this.pageInfo.count = pageParam.skipCount;
|
||||
let lastPageData = {link: lastPageLink, factories: null};
|
||||
if (this.pageInfo.currentPageNumber === this.pageInfo.countOfPages) {
|
||||
lastPageData.factories = data.factories;
|
||||
}
|
||||
if (!this.factoryPagesMap.get(this.pageInfo.countOfPages) || lastPageData.factories) {
|
||||
this.factoryPagesMap.set(this.pageInfo.countOfPages, lastPageData);
|
||||
}
|
||||
}
|
||||
let prevPageLink = data.links.get('prev');
|
||||
let prevPageNumber = this.pageInfo.currentPageNumber - 1;
|
||||
if (prevPageNumber > 0 && prevPageLink) {
|
||||
let prevPageData = {link: prevPageLink};
|
||||
if (!this.factoryPagesMap.get(prevPageNumber)) {
|
||||
this.factoryPagesMap.set(prevPageNumber, prevPageData);
|
||||
}
|
||||
}
|
||||
let nextPageLink = data.links.get('next');
|
||||
let nextPageNumber = this.pageInfo.currentPageNumber + 1;
|
||||
if (nextPageNumber) {
|
||||
let nextPageData = {link: nextPageLink};
|
||||
if (!this.factoryPagesMap.get(nextPageNumber)) {
|
||||
this.factoryPagesMap.set(nextPageNumber, nextPageData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the page information.
|
||||
* @returns {Object}
|
||||
*/
|
||||
getPagesInfo(): any {
|
||||
return this.pageInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask for loading the factories in asynchronous way
|
||||
* If there are no changes, it's not updated
|
||||
* @param maxItems - the max number of items to return
|
||||
* @param skipCount - the number of items to skip
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
fetchFactories(maxItems, skipCount): ng.IPromise<any> {
|
||||
this.itemsPerPage = maxItems;
|
||||
let promise = this._getFactories({maxItems: maxItems, skipCount: skipCount});
|
||||
|
||||
return promise.then((data: any) => {
|
||||
this.pageInfo.currentPageNumber = skipCount / maxItems + 1;
|
||||
this._updateCurrentPageFactories(data.factories);
|
||||
this._updatePagesData(data);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask for loading the factories page in asynchronous way
|
||||
* If there are no changes, it's not updated
|
||||
* @param pageKey - the key of page ('first', 'prev', 'next', 'last' or '1', '2', '3' ...)
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
fetchFactoryPage(pageKey: string) {
|
||||
let deferred = this.$q.defer();
|
||||
let pageNumber;
|
||||
if ('first' === pageKey) {
|
||||
pageNumber = 1;
|
||||
} else if ('prev' === pageKey) {
|
||||
pageNumber = this.pageInfo.currentPageNumber - 1;
|
||||
} else if ('next' === pageKey) {
|
||||
pageNumber = this.pageInfo.currentPageNumber + 1;
|
||||
} else if ('last' === pageKey) {
|
||||
pageNumber = this.pageInfo.countOfPages;
|
||||
} else {
|
||||
pageNumber = parseInt(pageKey, 10);
|
||||
}
|
||||
if (pageNumber < 1) {
|
||||
pageNumber = 1;
|
||||
} else if (pageNumber > this.pageInfo.countOfPages) {
|
||||
pageNumber = this.pageInfo.countOfPages;
|
||||
}
|
||||
let pageData = this.factoryPagesMap.get(pageNumber);
|
||||
if (pageData.link) {
|
||||
this.pageInfo.currentPageNumber = pageNumber;
|
||||
let queryData = this._getPageParamByLink(pageData.link);
|
||||
if (!queryData) {
|
||||
deferred.reject({data: {message: 'Error. No necessary link.'}});
|
||||
return deferred.promise;
|
||||
}
|
||||
let promise = this._getFactories(queryData);
|
||||
promise.then((data: any) => {
|
||||
this._updatePagesData(data);
|
||||
pageData.factories = data.factories;
|
||||
this._updateCurrentPage();
|
||||
deferred.resolve(data);
|
||||
}, (error: any) => {
|
||||
if (error && error.status === 304) {
|
||||
this._updateCurrentPage();
|
||||
}
|
||||
deferred.reject(error);
|
||||
});
|
||||
} else {
|
||||
deferred.reject({data: {message: 'Error. No necessary link.'}});
|
||||
}
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
_getFactories(queryData): ng.IPromise<any> {
|
||||
let deferred = this.$q.defer();
|
||||
let user = this.cheUser.getUser();
|
||||
|
||||
if (user) {
|
||||
queryData.userId = user.id;
|
||||
this.remoteFactoryAPI.getFactories(queryData).$promise.then((data) => {
|
||||
this._updateFactoriesDetails(data.factories).then((factoriesDetails) => {
|
||||
data.factories = factoriesDetails;//update factories
|
||||
deferred.resolve(data);
|
||||
}, (error) => {
|
||||
deferred.reject(error);
|
||||
});
|
||||
}, (error) => {
|
||||
deferred.reject(error);
|
||||
});
|
||||
} else {
|
||||
this.cheUser.fetchUser().then((user) => {
|
||||
queryData.userId = user.id;
|
||||
this.remoteFactoryAPI.getFactories(queryData).$promise.then((data) => {
|
||||
this._updateFactoriesDetails(data.factories).then((factoriesDetails) => {
|
||||
data.factories = factoriesDetails;//update factories
|
||||
deferred.resolve(data);
|
||||
}, (error) => {
|
||||
deferred.reject(error);
|
||||
});
|
||||
}, (error) => {
|
||||
deferred.reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
_updateFactoriesDetails(factories: Array<any>): ng.IPromise<any> {
|
||||
let deferred = this.$q.defer();
|
||||
let factoriesDetails = [];
|
||||
|
||||
if (!factories || factories.length === 0) {
|
||||
deferred.resolve(factoriesDetails);
|
||||
}
|
||||
|
||||
let promises = [];
|
||||
factories.forEach((factory: any) => {
|
||||
let factoryPromise = this.fetchFactoryById(factory.id);//ask the factory details
|
||||
factoryPromise.then((factoryDetails: any) => {
|
||||
factoriesDetails.push(factoryDetails);
|
||||
});
|
||||
promises.push(factoryPromise);
|
||||
});
|
||||
this.$q.all(promises).then(() => {
|
||||
deferred.resolve(factoriesDetails);
|
||||
}, (error) => {
|
||||
deferred.reject(error);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the factory service path.
|
||||
* @returns {string}
|
||||
*/
|
||||
getFactoryServicePath(): string {
|
||||
return 'factory';
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask for loading the factory content in asynchronous way
|
||||
* If there are no changes, it's not updated
|
||||
* @param workspace workspace
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
fetchFactoryContentFromWorkspace(workspace: che.IWorkspace): ng.IPromise<any> {
|
||||
let deferred = this.$q.defer();
|
||||
|
||||
let factoryContent = this.factoryContentsByWorkspaceId.get(workspace.id);
|
||||
if (factoryContent) {
|
||||
deferred.resolve(factoryContent);
|
||||
}
|
||||
|
||||
let promise = this.remoteFactoryAPI.getFactoryContentFromWorkspace({
|
||||
workspaceId: workspace.id
|
||||
}).$promise;
|
||||
|
||||
promise.then((factoryContent: any) => {
|
||||
//update factoryContents map
|
||||
this.factoryContentsByWorkspaceId.set(workspace.id, factoryContent);
|
||||
deferred.resolve(factoryContent);
|
||||
}, (error: any) => {
|
||||
if (error.status === 304) {
|
||||
let findFactoryContent = this.factoryContentsByWorkspaceId.get(workspace.id);
|
||||
deferred.resolve(findFactoryContent);
|
||||
} else {
|
||||
deferred.reject(error);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get factory from workspace
|
||||
* @param workspace
|
||||
* @return the factory content
|
||||
*/
|
||||
getFactoryContentFromWorkspace(workspace: che.IWorkspace): any {
|
||||
return this.factoryContentsByWorkspaceId.get(workspace.workspaceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create factory by content
|
||||
* @param factoryContent the factory content
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
createFactoryByContent(factoryContent: any): ng.IPromise<any> {
|
||||
let formDataObject = new FormData();
|
||||
formDataObject.append('factory', factoryContent);
|
||||
|
||||
return this.remoteFactoryAPI.createFactoryByContent({}, formDataObject).$promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current page factories
|
||||
* @returns {Array}
|
||||
*/
|
||||
getPageFactories(): Array<che.IFactory> {
|
||||
return this.pageFactories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask for loading the factory in asynchronous way
|
||||
* If there are no changes, it's not updated
|
||||
* @param factoryId the factory ID
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
fetchFactoryById(factoryId: string): ng.IPromise<any> {
|
||||
let deferred = this.$q.defer();
|
||||
|
||||
let promise = this.remoteFactoryAPI.get({factoryId: factoryId}).$promise;
|
||||
promise.then((factory: any) => {
|
||||
factory.name = factory.name ? factory.name : '';
|
||||
this.factoriesById.set(factoryId, factory);
|
||||
deferred.resolve(factory);
|
||||
}, (error: any) => {
|
||||
if (error.status === 304) {
|
||||
deferred.resolve(this.factoriesById.get(factoryId));
|
||||
} else {
|
||||
deferred.reject(error);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches factory by the user's id and factory's name.
|
||||
*
|
||||
* @param factoryName name of the factory to be fetched.
|
||||
* @param userId user id
|
||||
* @returns {IPromise<T>}
|
||||
*/
|
||||
fetchFactoryByName(factoryName: string, userId: string): ng.IPromise<any> {
|
||||
let deferred = this.$q.defer();
|
||||
let key = userId + ':' + factoryName;
|
||||
let promise = this.remoteFactoryAPI.getFactoryByName({factoryName: factoryName, userId: userId}).$promise;
|
||||
promise.then((factories: Array<che.IFactory>) => {
|
||||
let factory = factories.length ? factories[0] : null;
|
||||
this.factoriesByName.set(key, factory);
|
||||
deferred.resolve(factory);
|
||||
}, (error: any) => {
|
||||
if (error.status === 304) {
|
||||
deferred.resolve(this.factoriesByName.get(key));
|
||||
} else {
|
||||
deferred.reject(error);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask for getting parameter the factory in asynchronous way
|
||||
* If there are no changes, it's not updated
|
||||
* @param parameters the factory parameters
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
fetchParameterFactory(parameters: any): ng.IPromise<any> {
|
||||
let deferred = this.$q.defer();
|
||||
|
||||
let promise = this.remoteFactoryAPI.getFactoryParameters({}, parameters).$promise;
|
||||
promise.then((factory: any) => {
|
||||
factory.name = factory.name ? factory.name : '';
|
||||
this.parametersFactories.set(parameters, factory);
|
||||
deferred.resolve(factory);
|
||||
}, (error: any) => {
|
||||
if (error.status === 304) {
|
||||
deferred.resolve(this.parametersFactories.get(parameters));
|
||||
} else {
|
||||
deferred.reject(error);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects links for factory acceptance (with id and named one)
|
||||
* @param factory factory to detect links
|
||||
* @returns [*] links acceptance links
|
||||
*/
|
||||
detectLinks(factory: che.IFactory): Array<any> {
|
||||
let links = [];
|
||||
|
||||
if (!factory || !factory.links) {
|
||||
return links;
|
||||
}
|
||||
|
||||
this.lodash.find(factory.links, (link: any) => {
|
||||
if (link.rel === 'accept' || link.rel === 'accept-named') {
|
||||
links.push(link.href);
|
||||
}
|
||||
});
|
||||
|
||||
return links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the factory from factoryMap by factoryId
|
||||
* @param factoryId the factory ID
|
||||
* @returns factory
|
||||
*/
|
||||
getFactoryById(factoryId: string): any {
|
||||
return this.factoriesById.get(factoryId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the factory
|
||||
* @param factory
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
setFactory(factory: che.IFactory): ng.IPromise<any> {
|
||||
let deferred = this.$q.defer();
|
||||
// check factory
|
||||
if (!factory || !factory.id) {
|
||||
deferred.reject({data: {message: 'Read factory error.'}});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
let promise = this.remoteFactoryAPI.updateFactory({factoryId: factory.id}, factory).$promise;
|
||||
// check if was OK or not
|
||||
promise.then((factory: any) => {
|
||||
factory.name = factory.name ? factory.name : '';
|
||||
this.fetchFactoryPage(this.pageInfo.currentPageNumber);
|
||||
deferred.resolve(factory);
|
||||
}, (error: any) => {
|
||||
deferred.reject(error);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the factory content by factoryId
|
||||
* @param factoryId the factory ID
|
||||
* @param factoryContent the factory content
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
setFactoryContent(factoryId: string, factoryContent: any): ng.IPromise<any> {
|
||||
let deferred = this.$q.defer();
|
||||
|
||||
let promise = this.remoteFactoryAPI.updateFactory({factoryId: factoryId}, factoryContent).$promise;
|
||||
// check if was OK or not
|
||||
promise.then(() => {
|
||||
let fetchFactoryPromise = this.fetchFactoryById(factoryId);
|
||||
//check if was OK or not
|
||||
fetchFactoryPromise.then((factory: any) => {
|
||||
this.fetchFactoryPage(this.pageInfo.currentPageNumber);
|
||||
deferred.resolve(factory);
|
||||
}, (error: any) => {
|
||||
deferred.reject(error);
|
||||
});
|
||||
}, (error) => {
|
||||
deferred.reject(error);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs factory deleting by the given factoryId.
|
||||
* @param factoryId the factory ID
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
deleteFactoryById(factoryId: string): ng.IPromise<any> {
|
||||
let promise = this.remoteFactoryAPI.delete({factoryId: factoryId}).$promise;
|
||||
//check if was OK or not
|
||||
return promise.then(() => {
|
||||
this.factoriesById.delete(factoryId);//update factories map
|
||||
if (this.pageInfo && this.pageInfo.currentPageNumber) {
|
||||
this.fetchFactoryPage(this.pageInfo.currentPageNumber);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that extract the factory ID from a factory URL
|
||||
* @param factoryURL the factory URL to analyze
|
||||
* @returns the stringified ID of a factory
|
||||
*/
|
||||
getIDFromFactoryAPIURL(factoryURL: string): string {
|
||||
let index = factoryURL.lastIndexOf('/factory/');
|
||||
if (index > 0) {
|
||||
return factoryURL.slice(index + '/factory/'.length, factoryURL.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the factory url based on id.
|
||||
* @returns {link.href|*} link value
|
||||
*/
|
||||
getFactoryIdUrl(factory: any): string {
|
||||
let link = this.lodash.find(factory.links, (link: any) => {
|
||||
return 'accept' === link.rel;
|
||||
});
|
||||
return link ? link.href : 'No value';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the factory url based on name.
|
||||
*
|
||||
* @returns {link.href|*} link value
|
||||
*/
|
||||
getFactoryNamedUrl(factory: any): string {
|
||||
let link = this.lodash.find(factory.links, (link: any) => {
|
||||
return 'accept-named' === link.rel;
|
||||
});
|
||||
|
||||
return link ? link.href : null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
|
||||
/**
|
||||
* Test of the Codenvy Factory API
|
||||
*/
|
||||
describe('CheFactory', () => {
|
||||
|
||||
|
||||
/**
|
||||
* User Factory for the test
|
||||
*/
|
||||
let factory;
|
||||
|
||||
/**
|
||||
* API builder.
|
||||
*/
|
||||
let apiBuilder;
|
||||
|
||||
/**
|
||||
* Backend for handling http operations
|
||||
*/
|
||||
let httpBackend;
|
||||
|
||||
/**
|
||||
* Che backend
|
||||
*/
|
||||
let cheBackend;
|
||||
|
||||
/**
|
||||
* setup module
|
||||
*/
|
||||
beforeEach(angular.mock.module('userDashboard'));
|
||||
|
||||
/**
|
||||
* Inject factory and http backend
|
||||
*/
|
||||
beforeEach(inject((cheFactory, cheAPIBuilder, cheHttpBackend) => {
|
||||
|
||||
factory = cheFactory;
|
||||
apiBuilder = cheAPIBuilder;
|
||||
cheBackend = cheHttpBackend;
|
||||
httpBackend = cheHttpBackend.getHttpBackend();
|
||||
}));
|
||||
|
||||
/**
|
||||
* Check assertion after the test
|
||||
*/
|
||||
afterEach(() => {
|
||||
httpBackend.verifyNoOutstandingExpectation();
|
||||
httpBackend.verifyNoOutstandingRequest();
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Check that we're able to fetch factory data
|
||||
*/
|
||||
it('Fetch factories', () => {
|
||||
// setup tests objects
|
||||
let maxItem = 3;
|
||||
let skipCount = 0;
|
||||
let testUser = apiBuilder.getUserBuilder().withId('testUserId').build();
|
||||
let testFactory1 = apiBuilder.getFactoryBuilder().withId('testId1').withName('testName1').withCreatorEmail('testEmail1').build();
|
||||
let testFactory2 = apiBuilder.getFactoryBuilder().withId('testId2').withName('testName2').withCreatorEmail('testEmail2').build();
|
||||
let testFactory3 = apiBuilder.getFactoryBuilder().withId('testId3').withName('testName3').withCreatorEmail('testEmail3').build();
|
||||
let testFactory4 = apiBuilder.getFactoryBuilder().withId('testId4').withName('testName4').withCreatorEmail('testEmail4').build();
|
||||
|
||||
// providing requests
|
||||
// add test objects on Http backend
|
||||
cheBackend.setDefaultUser(testUser);
|
||||
cheBackend.addUserFactory(testFactory1);
|
||||
cheBackend.addUserFactory(testFactory2);
|
||||
cheBackend.addUserFactory(testFactory3);
|
||||
cheBackend.addUserFactory(testFactory4);
|
||||
cheBackend.setPageMaxItem(maxItem);
|
||||
cheBackend.setPageSkipCount(skipCount);
|
||||
|
||||
// setup backend for factories
|
||||
cheBackend.factoriesBackendSetup();
|
||||
|
||||
// fetch factory
|
||||
factory.fetchFactories(maxItem, skipCount);
|
||||
|
||||
// expecting GETs
|
||||
httpBackend.expectGET('/api/user');
|
||||
|
||||
httpBackend.expectGET('/api/factory/find?creator.userId=' + testUser.id + '&maxItems=' + maxItem + '&skipCount=' + skipCount);
|
||||
httpBackend.expectGET('/api/factory/' + testFactory1.id);
|
||||
httpBackend.expectGET('/api/factory/' + testFactory2.id);
|
||||
httpBackend.expectGET('/api/factory/' + testFactory3.id);
|
||||
|
||||
// flush command
|
||||
httpBackend.flush();
|
||||
|
||||
// now, check factories
|
||||
let pageFactories = factory.getPageFactories();
|
||||
let factory1 = factory.getFactoryById(testFactory1.id);
|
||||
|
||||
let factory2 = factory.getFactoryById(testFactory2.id);
|
||||
let factory3 = factory.getFactoryById(testFactory3.id);
|
||||
|
||||
// check id, name and email of pge factories
|
||||
expect(pageFactories.length).toEqual(maxItem);
|
||||
expect(factory1.id).toEqual(testFactory1.id);
|
||||
expect(factory1.name).toEqual(testFactory1.name);
|
||||
expect(factory1.creator.email).toEqual(testFactory1.creator.email);
|
||||
expect(factory2.id).toEqual(testFactory2.id);
|
||||
expect(factory2.name).toEqual(testFactory2.name);
|
||||
expect(factory2.creator.email).toEqual(testFactory2.creator.email);
|
||||
expect(factory3.id).toEqual(testFactory3.id);
|
||||
expect(factory3.name).toEqual(testFactory3.name);
|
||||
expect(factory3.creator.email).toEqual(testFactory3.creator.email);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Check that we're able to fetch factory data by id
|
||||
*/
|
||||
it('Fetch factor by id', () => {
|
||||
// setup tests objects
|
||||
let testFactory = apiBuilder.getFactoryBuilder().withId('testId').withName('testName').withCreatorEmail('testEmail').build();
|
||||
|
||||
// providing request
|
||||
// add test factory on Http backend
|
||||
cheBackend.addUserFactory(testFactory);
|
||||
|
||||
// setup backend
|
||||
cheBackend.factoriesBackendSetup();
|
||||
|
||||
// fetch factory
|
||||
factory.fetchFactoryById(testFactory.id);
|
||||
|
||||
// expecting GETs
|
||||
httpBackend.expectGET('/api/factory/' + testFactory.id);
|
||||
|
||||
// flush command
|
||||
httpBackend.flush();
|
||||
|
||||
// now, check factory
|
||||
let targetFactory = factory.getFactoryById(testFactory.id);
|
||||
|
||||
// check id, name and email of factory
|
||||
expect(targetFactory.id).toEqual(testFactory.id);
|
||||
expect(targetFactory.name).toEqual(testFactory.name);
|
||||
expect(targetFactory.creator.email).toEqual(testFactory.creator.email);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Check that we're able to delete factor by id
|
||||
*/
|
||||
it('Delete factor by id', () => {
|
||||
// setup tests objects
|
||||
let testFactory = apiBuilder.getFactoryBuilder().withId('testId').withName('testName').withCreatorEmail('testEmail').build();
|
||||
|
||||
// providing request
|
||||
// add test factory on Http backend
|
||||
cheBackend.addUserFactory(testFactory);
|
||||
|
||||
// setup backend
|
||||
cheBackend.factoriesBackendSetup();
|
||||
|
||||
// delete factory
|
||||
factory.deleteFactoryById(testFactory.id);
|
||||
|
||||
// expecting GETs
|
||||
httpBackend.expectDELETE('/api/factory/' + testFactory.id);
|
||||
|
||||
// flush command
|
||||
httpBackend.flush();
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets factory page object from response
|
||||
*/
|
||||
it('Gets factory page object from response', () => {
|
||||
let testFactory1 = apiBuilder.getFactoryBuilder().withId('testId1').withName('testName1').withCreatorEmail('testEmail1').build();
|
||||
let testFactory2 = apiBuilder.getFactoryBuilder().withId('testId2').withName('testName2').withCreatorEmail('testEmail2').build();
|
||||
let factories = [testFactory1, testFactory2];
|
||||
|
||||
let test_link_1 = '/api/factory/find?creator.userId=testUserId&skipCount=0&maxItems=5';
|
||||
let test_rel_1 = 'first';
|
||||
let test_link_2 = '/api/factory/find?creator.userId=testUserId&skipCount=20&maxItems=5';
|
||||
let test_rel_2 = 'last';
|
||||
let test_link_3 = '/api/factory/find?creator.userId=testUserId&skipCount=5&maxItems=5';
|
||||
let test_rel_3 = 'next';
|
||||
|
||||
let headersLink = '\<' + test_link_1 + '\>' + '; rel="' + test_rel_1 + '",' +
|
||||
'\<' + test_link_2 + '\>' + '; rel="' + test_rel_2 + '",' +
|
||||
'\<' + test_link_3 + '\>' + '; rel="' + test_rel_3 + '"';
|
||||
|
||||
cheBackend.factoriesBackendSetup();
|
||||
|
||||
// gets page
|
||||
let pageObject = factory._getPageFromResponse(factories, headersLink);
|
||||
|
||||
httpBackend.flush();
|
||||
|
||||
// check page factories and links
|
||||
expect(pageObject.factories).toEqual(factories);
|
||||
expect(pageObject.links.get(test_rel_1)).toEqual(test_link_1);
|
||||
expect(pageObject.links.get(test_rel_2)).toEqual(test_link_2);
|
||||
expect(pageObject.links.get(test_rel_3)).toEqual(test_link_3);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets maxItems and skipCount from link params
|
||||
*/
|
||||
it('Gets maxItems and skipCount from link params', () => {
|
||||
let skipCount = 20;
|
||||
let maxItems = 5;
|
||||
let test_link = '/api/factory/find?creator.userId=testUserId&skipCount=' + skipCount + '&maxItems=' + maxItems;
|
||||
|
||||
cheBackend.factoriesBackendSetup();
|
||||
|
||||
// gets page
|
||||
let pageParams = factory._getPageParamByLink(test_link);
|
||||
|
||||
httpBackend.flush();
|
||||
|
||||
// check page factories and links
|
||||
expect(parseInt(pageParams.maxItems, 10)).toEqual(maxItems);
|
||||
expect(parseInt(pageParams.skipCount, 10)).toEqual(skipCount);
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,432 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
|
||||
interface IUsersResource<T> extends ng.resource.IResourceClass<T> {
|
||||
findByID: any,
|
||||
findByAlias: any,
|
||||
findByName: any,
|
||||
setPassword: any,
|
||||
createUser: any,
|
||||
getUsers: any,
|
||||
removeUserById: any
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is handling the user API retrieval
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class CheUser {
|
||||
private $resource: ng.resource.IResourceService;
|
||||
private $q: ng.IQService;
|
||||
private $cookies: ng.cookies.ICookiesService;
|
||||
private remoteUserAPI: IUsersResource<any>;
|
||||
private logoutAPI: ng.resource.IResourceClass<any>;
|
||||
|
||||
private useridMap: Map<string, che.IUser>;
|
||||
private userAliasMap: Map<string, che.IUser>;
|
||||
private userNameMap: Map<string, che.IUser>;
|
||||
private usersMap: Map<string, che.IUser>;
|
||||
private userPagesMap: Map<number, any>;
|
||||
private pageInfo: any;
|
||||
/**
|
||||
* Current user.
|
||||
*/
|
||||
private user: che.IUser;
|
||||
|
||||
/**
|
||||
* Default constructor that is using resource
|
||||
* @ngInject for Dependency injection
|
||||
*/
|
||||
constructor($resource: ng.resource.IResourceService, $q: ng.IQService, $cookies: ng.cookies.ICookiesService) {
|
||||
this.$q = $q;
|
||||
this.$resource = $resource;
|
||||
this.$cookies = $cookies;
|
||||
|
||||
// remote call
|
||||
this.remoteUserAPI = <IUsersResource<any>> this.$resource('/api/user', {}, {
|
||||
findByID: {method: 'GET', url: '/api/user/:userId'},
|
||||
findByAlias: {method: 'GET', url: '/api/user/find?email=:alias'},
|
||||
findByName: {method: 'GET', url: '/api/user/find?name=:name'},
|
||||
setPassword: {
|
||||
method: 'POST', url: '/api/user/password', isArray: false,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
|
||||
}
|
||||
},
|
||||
createUser: {method: 'POST', url: '/api/user'},
|
||||
getUsers: {
|
||||
method: 'GET',
|
||||
url: '/api/admin/user?maxItems=:maxItems&skipCount=:skipCount',
|
||||
isArray: false,
|
||||
responseType: 'json',
|
||||
transformResponse: (data: any, headersGetter: any) => {
|
||||
return this._getPageFromResponse(data, headersGetter('link'));
|
||||
}
|
||||
},
|
||||
removeUserById: {method: 'DELETE', url: '/api/user/:userId'}
|
||||
});
|
||||
|
||||
this.logoutAPI = this.$resource('/api/auth/logout', {});
|
||||
|
||||
// users by ID
|
||||
this.useridMap = new Map();
|
||||
|
||||
// users by alias
|
||||
this.userAliasMap = new Map();
|
||||
|
||||
// users by name
|
||||
this.userNameMap = new Map();
|
||||
|
||||
// all users by ID
|
||||
this.usersMap = new Map();
|
||||
|
||||
// page users by relative link
|
||||
this.userPagesMap = new Map();
|
||||
|
||||
//pages info
|
||||
this.pageInfo = {};
|
||||
|
||||
//Current user has to be for sure fetched:
|
||||
this.fetchUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new user
|
||||
* @param name - new user name
|
||||
* @param email - new user e-mail
|
||||
* @param password - new user password
|
||||
* @returns {*}
|
||||
*/
|
||||
createUser(name: string, email: string, password: string): ng.IPromise<any> {
|
||||
let data: {
|
||||
password: string;
|
||||
name: string;
|
||||
email?: string;
|
||||
};
|
||||
|
||||
data = {
|
||||
password: password,
|
||||
name: name
|
||||
};
|
||||
|
||||
if (email) {
|
||||
data.email = email;
|
||||
}
|
||||
|
||||
let promise = this.remoteUserAPI.createUser(data).$promise;
|
||||
|
||||
// check if was OK or not
|
||||
promise.then((user: che.IUser) => {
|
||||
//update users map
|
||||
this.usersMap.set(user.id, user);//add user
|
||||
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
_getPageFromResponse(data: any, headersLink: string): any {
|
||||
let links = new Map();
|
||||
if (!headersLink) {
|
||||
return {users: data};
|
||||
}
|
||||
let pattern = new RegExp('<([^>]+?)>.+?rel="([^"]+?)"', 'g');
|
||||
let result;
|
||||
while (result = pattern.exec(headersLink)) { //look for pattern
|
||||
links.set(result[2], result[1]);//add link
|
||||
}
|
||||
return {
|
||||
users: data,
|
||||
links: links
|
||||
};
|
||||
}
|
||||
|
||||
_getPageParamByLink(pageLink: string): any {
|
||||
let lastPageParamMap = new Map();
|
||||
let pattern = new RegExp('([_\\w]+)=([\\w]+)', 'g');
|
||||
let result;
|
||||
while (result = pattern.exec(pageLink)) {
|
||||
lastPageParamMap.set(result[1], result[2]);
|
||||
}
|
||||
|
||||
let skipCount = lastPageParamMap.get('skipCount');
|
||||
let maxItems = lastPageParamMap.get('maxItems');
|
||||
if (!maxItems || maxItems === 0) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
maxItems: maxItems,
|
||||
skipCount: skipCount ? skipCount : 0
|
||||
};
|
||||
}
|
||||
|
||||
_updateCurrentPage(): void {
|
||||
let pageData = this.userPagesMap.get(this.pageInfo.currentPageNumber);
|
||||
if (!pageData) {
|
||||
return;
|
||||
}
|
||||
this.usersMap.clear();
|
||||
if (!pageData.users) {
|
||||
return;
|
||||
}
|
||||
pageData.users.forEach((user: che.IUser) => {
|
||||
this.usersMap.set(user.id, user);//add user
|
||||
});
|
||||
}
|
||||
|
||||
_updateCurrentPageUsers(users: Array<any>): void {
|
||||
this.usersMap.clear();
|
||||
if (!users) {
|
||||
return;
|
||||
}
|
||||
users.forEach((user: che.IUser) => {
|
||||
this.usersMap.set(user.id, user);//add user
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user page links by relative direction ('first', 'prev', 'next', 'last')
|
||||
*/
|
||||
_updatePagesData(data: any): any {
|
||||
if (!data.links) {
|
||||
return;
|
||||
}
|
||||
let firstPageLink = data.links.get('first');
|
||||
if (firstPageLink) {
|
||||
let firstPageData: { users?: Array<any>; link?: string; } = {link: firstPageLink};
|
||||
if (this.pageInfo.currentPageNumber === 1) {
|
||||
firstPageData.users = data.users;
|
||||
}
|
||||
if (!this.userPagesMap.get(1) || firstPageData.users) {
|
||||
this.userPagesMap.set(1, firstPageData);
|
||||
}
|
||||
}
|
||||
let lastPageLink = data.links.get('last');
|
||||
if (lastPageLink) {
|
||||
let pageParam = this._getPageParamByLink(lastPageLink);
|
||||
this.pageInfo.countOfPages = pageParam.skipCount / pageParam.maxItems + 1;
|
||||
this.pageInfo.count = pageParam.skipCount;
|
||||
let lastPageData: { users?: Array<any>; link?: string; } = {link: lastPageLink};
|
||||
if (this.pageInfo.currentPageNumber === this.pageInfo.countOfPages) {
|
||||
lastPageData.users = data.users;
|
||||
}
|
||||
if (!this.userPagesMap.get(this.pageInfo.countOfPages) || lastPageData.users) {
|
||||
this.userPagesMap.set(this.pageInfo.countOfPages, lastPageData);
|
||||
}
|
||||
}
|
||||
let prevPageLink = data.links.get('prev');
|
||||
let prevPageNumber = this.pageInfo.currentPageNumber - 1;
|
||||
if (prevPageNumber > 0 && prevPageLink) {
|
||||
let prevPageData = {link: prevPageLink};
|
||||
if (!this.userPagesMap.get(prevPageNumber)) {
|
||||
this.userPagesMap.set(prevPageNumber, prevPageData);
|
||||
}
|
||||
}
|
||||
let nextPageLink = data.links.get('next');
|
||||
let nextPageNumber = this.pageInfo.currentPageNumber + 1;
|
||||
if (nextPageNumber) {
|
||||
let lastPageData = {link: nextPageLink};
|
||||
if (!this.userPagesMap.get(nextPageNumber)) {
|
||||
this.userPagesMap.set(nextPageNumber, lastPageData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pageInfo
|
||||
* @returns {Object}
|
||||
*/
|
||||
getPagesInfo(): any {
|
||||
return this.pageInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask for loading the users in asynchronous way
|
||||
* If there are no changes, it's not updated
|
||||
* @param maxItems - the max number of items to return
|
||||
* @param skipCount - the number of items to skip
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
fetchUsers(maxItems: number, skipCount: number): ng.IPromise<any> {
|
||||
let promise = this.remoteUserAPI.getUsers({maxItems: maxItems, skipCount: skipCount}).$promise;
|
||||
|
||||
promise.then((data) => {
|
||||
this.pageInfo.currentPageNumber = skipCount / maxItems + 1;
|
||||
this._updateCurrentPageUsers(data.users);
|
||||
this._updatePagesData(data);
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask for loading the users page in asynchronous way
|
||||
* If there are no changes, it's not updated
|
||||
* @param pageKey - the key of page ('first', 'prev', 'next', 'last' or '1', '2', '3' ...)
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
fetchUsersPage(pageKey): ng.IPromise<any> {
|
||||
let deferred = this.$q.defer();
|
||||
let pageNumber;
|
||||
if ('first' === pageKey) {
|
||||
pageNumber = 1;
|
||||
} else if ('prev' === pageKey) {
|
||||
pageNumber = this.pageInfo.currentPageNumber - 1;
|
||||
} else if ('next' === pageKey) {
|
||||
pageNumber = this.pageInfo.currentPageNumber + 1;
|
||||
} else if ('last' === pageKey) {
|
||||
pageNumber = this.pageInfo.countOfPages;
|
||||
} else {
|
||||
pageNumber = parseInt(pageKey, 10);
|
||||
}
|
||||
if (pageNumber < 1) {
|
||||
pageNumber = 1;
|
||||
} else if (pageNumber > this.pageInfo.countOfPages) {
|
||||
pageNumber = this.pageInfo.countOfPages;
|
||||
}
|
||||
let pageData = this.userPagesMap.get(pageNumber);
|
||||
if (pageData.link) {
|
||||
this.pageInfo.currentPageNumber = pageNumber;
|
||||
let promise = this.remoteUserAPI.getUsers(this._getPageParamByLink(pageData.link)).$promise;
|
||||
promise.then((data) => {
|
||||
this._updatePagesData(data);
|
||||
pageData.users = data.users;
|
||||
this._updateCurrentPage();
|
||||
deferred.resolve(data);
|
||||
}, (error) => {
|
||||
if (error && error.status === 304) {
|
||||
this._updateCurrentPage();
|
||||
}
|
||||
deferred.reject(error);
|
||||
});
|
||||
} else {
|
||||
deferred.reject({data: {message: 'Error. No necessary link.'}});
|
||||
}
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the users
|
||||
* @returns {Map}
|
||||
*/
|
||||
getUsersMap(): Map<string, any> {
|
||||
return this.usersMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs user deleting by the given user ID.
|
||||
* @param userId the user id
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
deleteUserById(userId: string): ng.IPromise<any> {
|
||||
let promise = this.remoteUserAPI.removeUserById({userId: userId}).$promise;
|
||||
|
||||
// check if was OK or not
|
||||
promise.then(() => {
|
||||
//update users map
|
||||
this.usersMap.delete(userId);//remove user
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs current user deletion.
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
deleteCurrentUser(): ng.IPromise<any> {
|
||||
let userId = this.user.id;
|
||||
let promise = this.remoteUserAPI.removeUserById({userId: userId}).$promise;
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs logout of current user.
|
||||
* @returns {y.ResourceClass.prototype.$promise|*|$promise|T.$promise|S.$promise}
|
||||
*/
|
||||
logout(): ng.IPromise<any> {
|
||||
let data = {token: this.$cookies['session-access-key']};
|
||||
let promise = this.logoutAPI.save(data).$promise;
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user
|
||||
* @return user
|
||||
*/
|
||||
getUser(): any {
|
||||
return this.user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the user
|
||||
*/
|
||||
fetchUser(): ng.IPromise<any> {
|
||||
let promise = this.remoteUserAPI.get().$promise;
|
||||
// check if if was OK or not
|
||||
promise.then((user: che.IUser) => {
|
||||
this.user = user;
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
fetchUserId(userId: string): ng.IPromise<any> {
|
||||
let promise = this.remoteUserAPI.findByID({userId: userId}).$promise;
|
||||
let parsedResultPromise = promise.then((user: che.IUser) => {
|
||||
this.useridMap.set(userId, user);
|
||||
});
|
||||
|
||||
return parsedResultPromise;
|
||||
}
|
||||
|
||||
getUserFromId(userId: string): any {
|
||||
return this.useridMap.get(userId);
|
||||
}
|
||||
|
||||
fetchUserByAlias(alias: string): ng.IPromise<any> {
|
||||
let promise = this.remoteUserAPI.findByAlias({alias: alias}).$promise;
|
||||
let parsedResultPromise = promise.then((user: che.IUser) => {
|
||||
this.useridMap.set(user.id, user);
|
||||
this.userAliasMap.set(alias, user);
|
||||
});
|
||||
|
||||
return parsedResultPromise;
|
||||
}
|
||||
|
||||
getUserByAlias(userAlias: string): any {
|
||||
return this.userAliasMap.get(userAlias);
|
||||
}
|
||||
|
||||
fetchUserByName(name: string): ng.IPromise<any> {
|
||||
let promise = this.remoteUserAPI.findByName({name: name}).$promise;
|
||||
let resultPromise = promise.then((user: che.IUser) => {
|
||||
this.userNameMap.set(name, user);
|
||||
return user;
|
||||
}, (error: any) => {
|
||||
if (error.status === 304) {
|
||||
return this.userNameMap.get(name);
|
||||
}
|
||||
return this.$q.reject(error);
|
||||
});
|
||||
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
getUserByName(name: string): any {
|
||||
return this.userNameMap.get(name);
|
||||
}
|
||||
|
||||
setPassword(password: any): ng.IPromise<any> {
|
||||
return this.remoteUserAPI.setPassword('password=' + password).$promise;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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';
|
||||
import {CheUser} from './che-user.factory';
|
||||
import {CheAPIBuilder} from './builder/che-api-builder.factory';
|
||||
import {CheHttpBackend} from './test/che-http-backend';
|
||||
|
||||
/**
|
||||
* Test of the Codenvy User API
|
||||
*/
|
||||
describe('CheUser', () => {
|
||||
|
||||
/**
|
||||
* User Factory for the test
|
||||
*/
|
||||
let factory;
|
||||
|
||||
/**
|
||||
* API builder.
|
||||
*/
|
||||
let apiBuilder;
|
||||
|
||||
/**
|
||||
* Backend for handling http operations
|
||||
*/
|
||||
let httpBackend;
|
||||
|
||||
/**
|
||||
* Che backend
|
||||
*/
|
||||
let cheBackend;
|
||||
|
||||
/**
|
||||
* setup module
|
||||
*/
|
||||
beforeEach(angular.mock.module('userDashboard'));
|
||||
|
||||
/**
|
||||
* Inject factory and http backend
|
||||
*/
|
||||
beforeEach(inject((cheUser: CheUser, cheAPIBuilder: CheAPIBuilder, cheHttpBackend: CheHttpBackend) => {
|
||||
|
||||
factory = cheUser;
|
||||
apiBuilder = cheAPIBuilder;
|
||||
cheBackend = cheHttpBackend;
|
||||
httpBackend = cheHttpBackend.getHttpBackend();
|
||||
}));
|
||||
|
||||
/**
|
||||
* Check assertion after the test
|
||||
*/
|
||||
afterEach(() => {
|
||||
httpBackend.verifyNoOutstandingExpectation();
|
||||
httpBackend.verifyNoOutstandingRequest();
|
||||
});
|
||||
|
||||
/**
|
||||
* Check that we're able to fetch user data
|
||||
*/
|
||||
it('Fetch user', () => {
|
||||
// setup tests objects
|
||||
let userId = 'idTestUser';
|
||||
let email = 'eclipseCodenvy@eclipse.org';
|
||||
|
||||
let testUser = apiBuilder.getUserBuilder().withId(userId).withEmail(email).build();
|
||||
|
||||
// providing request
|
||||
// add test user on Http backend
|
||||
cheBackend.setDefaultUser(testUser);
|
||||
|
||||
// setup backend for users
|
||||
cheBackend.setup();
|
||||
|
||||
// fetch user
|
||||
factory.fetchUser(true);
|
||||
|
||||
// expecting GETs
|
||||
httpBackend.expectGET('/api/user');
|
||||
|
||||
// flush command
|
||||
httpBackend.flush();
|
||||
|
||||
// now, check user
|
||||
let user = factory.getUser();
|
||||
|
||||
// check id and email
|
||||
expect(user.id).toEqual(userId);
|
||||
expect(user.email).toEqual(email);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Check that we're able to fetch user data by id
|
||||
*/
|
||||
it('Fetch user by id', () => {
|
||||
// setup tests objects
|
||||
let userId = 'newIdTestUser';
|
||||
let email = 'eclipseCodenvy@eclipse.org';
|
||||
|
||||
let testUser = apiBuilder.getUserBuilder().withId(userId).withEmail(email).build();
|
||||
|
||||
// providing request
|
||||
// add test user on Http backend
|
||||
cheBackend.addUserById(testUser);
|
||||
|
||||
// setup backend
|
||||
cheBackend.setup();
|
||||
|
||||
// fetch user
|
||||
factory.fetchUserId(userId);
|
||||
|
||||
// expecting GETs
|
||||
httpBackend.expectGET('/api/user/' + userId);
|
||||
|
||||
// flush command
|
||||
httpBackend.flush();
|
||||
|
||||
// now, check user
|
||||
let user = factory.getUserFromId(userId);
|
||||
|
||||
// check id and email
|
||||
expect(user.id).toEqual(userId);
|
||||
expect(user.email).toEqual(email);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Check that we're able to fetch user data by email
|
||||
*/
|
||||
it('Fetch user by alias', () => {
|
||||
// setup tests objects
|
||||
let userId = 'testUser';
|
||||
let email = 'eclipseCodenvy@eclipse.org';
|
||||
|
||||
let testUser = apiBuilder.getUserBuilder().withId(userId).withEmail(email).build();
|
||||
|
||||
// providing request
|
||||
// add test user on Http backend
|
||||
cheBackend.addUserEmail(testUser);
|
||||
|
||||
// setup backend
|
||||
cheBackend.setup();
|
||||
|
||||
// fetch user
|
||||
factory.fetchUserByAlias(email);
|
||||
|
||||
// expecting GETs
|
||||
httpBackend.expectGET('/api/user/find?email=' + email);
|
||||
|
||||
// flush command
|
||||
httpBackend.flush();
|
||||
|
||||
// now, check user
|
||||
let user = factory.getUserByAlias(email);
|
||||
|
||||
// check id and email
|
||||
expect(user.id).toEqual(userId);
|
||||
expect(user.email).toEqual(email);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Check that we're able to set attributes into profile
|
||||
*/
|
||||
it('Set password', () => {
|
||||
// setup
|
||||
let testPassword = 'newTestPassword';
|
||||
|
||||
// setup backend
|
||||
cheBackend.setup();
|
||||
|
||||
// fetch profile
|
||||
factory.setPassword(testPassword);
|
||||
|
||||
// expecting a POST
|
||||
httpBackend.expectPOST('/api/user/password', 'password=' + testPassword);
|
||||
|
||||
// flush command
|
||||
httpBackend.flush();
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Check that we're able to create user
|
||||
*/
|
||||
it('Create user', () => {
|
||||
let user = {
|
||||
password: 'password12345',
|
||||
email: 'eclipseCodenvy@eclipse.org',
|
||||
name: 'testName'
|
||||
};
|
||||
|
||||
// setup backend
|
||||
cheBackend.setup();
|
||||
|
||||
// create user
|
||||
factory.createUser(user.name, user.email, user.password);
|
||||
|
||||
// expecting a POST
|
||||
httpBackend.expectPOST('/api/user', user);
|
||||
|
||||
// flush command
|
||||
httpBackend.flush();
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Gets user page object from response
|
||||
*/
|
||||
it('Gets user page object from response', () => {
|
||||
let testUser_1 = apiBuilder.getUserBuilder().withId('testUser1Id').withEmail('testUser1@eclipse.org').build();
|
||||
let testUser_2 = apiBuilder.getUserBuilder().withId('testUser2Id').withEmail('testUser2@eclipse.org').build();
|
||||
let users = [testUser_1, testUser_2];
|
||||
|
||||
let test_link_1 = 'https://aio.codenvy-dev.com/api/admin/user?skipCount=0&maxItems=5';
|
||||
let test_rel_1 = 'first';
|
||||
let test_link_2 = 'https://aio.codenvy-dev.com/api/admin/user?skipCount=20&maxItems=5';
|
||||
let test_rel_2 = 'last';
|
||||
let test_link_3 = 'https://aio.codenvy-dev.com/api/admin/user?skipCount=5&maxItems=5';
|
||||
let test_rel_3 = 'next';
|
||||
|
||||
let headersLink = '\<' + test_link_1 + '\>' + '; rel="' + test_rel_1 + '",' +
|
||||
'\<' + test_link_2 + '\>' + '; rel="' + test_rel_2 + '",' +
|
||||
'\<' + test_link_3 + '\>' + '; rel="' + test_rel_3 + '"';
|
||||
|
||||
// setup backend
|
||||
cheBackend.setup();
|
||||
|
||||
// gets page
|
||||
let pageObject = factory._getPageFromResponse(users, headersLink);
|
||||
|
||||
// flush command
|
||||
httpBackend.flush();
|
||||
|
||||
// check page users and links
|
||||
expect(pageObject.users).toEqual(users);
|
||||
expect(pageObject.links.get(test_rel_1)).toEqual(test_link_1);
|
||||
expect(pageObject.links.get(test_rel_2)).toEqual(test_link_2);
|
||||
expect(pageObject.links.get(test_rel_3)).toEqual(test_link_3);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets maxItems and skipCount from link params
|
||||
*/
|
||||
it('Gets maxItems and skipCount from link params', () => {
|
||||
let skipCount = 20;
|
||||
let maxItems = 5;
|
||||
let test_link = 'https://aio.codenvy-dev.com/api/admin/user?skipCount=' + skipCount + '&maxItems=' + maxItems;
|
||||
|
||||
// setup backend
|
||||
cheBackend.setup();
|
||||
|
||||
// gets page
|
||||
let pageParams = factory._getPageParamByLink(test_link);
|
||||
|
||||
// flush command
|
||||
httpBackend.flush();
|
||||
|
||||
// check page users and links
|
||||
expect(parseInt(pageParams.maxItems, 10)).toEqual(maxItems);
|
||||
expect(parseInt(pageParams.skipCount, 10)).toEqual(skipCount);
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 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
|
||||
*/
|
||||
declare namespace che.namespace {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -31,6 +31,14 @@ export class CheHttpBackend {
|
|||
private defaultProfilePrefs: any;
|
||||
private defaultBranding: any;
|
||||
private defaultPreferences: any;
|
||||
private defaultUser: che.IUser;
|
||||
private userIdMap: Map<string, che.IUser>;
|
||||
private userEmailMap: Map<string, che.IUser>;
|
||||
private factoriesMap: Map<string, che.IFactory>;
|
||||
private pageMaxItem: number;
|
||||
private pageSkipCount: number;
|
||||
|
||||
|
||||
|
||||
private isAutoSnapshot: boolean = false;
|
||||
private isAutoRestore: boolean = false;
|
||||
|
|
@ -51,6 +59,13 @@ export class CheHttpBackend {
|
|||
this.workspaceAgentMap = new Map();
|
||||
this.stacks = [];
|
||||
|
||||
this.defaultUser = {};
|
||||
this.userIdMap = new Map();
|
||||
this.userEmailMap = new Map();
|
||||
this.factoriesMap = new Map();
|
||||
this.pageMaxItem = 5;
|
||||
this.pageSkipCount = 0;
|
||||
|
||||
this.defaultProfile = cheAPIBuilder.getProfileBuilder().withId('idDefaultUser').withEmail('eclipseChe@eclipse.org').withFirstName('FirstName').withLastName('LastName').build();
|
||||
this.defaultProfilePrefs = {};
|
||||
this.defaultBranding = {};
|
||||
|
|
@ -113,6 +128,27 @@ export class CheHttpBackend {
|
|||
|
||||
this.httpBackend.when('POST', '/api/analytics/log/session-usage').respond(200, {});
|
||||
|
||||
// change password
|
||||
this.httpBackend.when('POST', '/api/user/password').respond(() => {
|
||||
return [200, {success: true, errors: []}];
|
||||
});
|
||||
|
||||
// create new user
|
||||
this.httpBackend.when('POST', '/api/user').respond(() => {
|
||||
return [200, {success: true, errors: []}];
|
||||
});
|
||||
|
||||
this.httpBackend.when('GET', '/api/user').respond(this.defaultUser);
|
||||
|
||||
let userIdKeys = this.userIdMap.keys();
|
||||
for (let key of userIdKeys) {
|
||||
this.httpBackend.when('GET', '/api/user/' + key).respond(this.userIdMap.get(key));
|
||||
}
|
||||
|
||||
let userEmailKeys = this.userEmailMap.keys();
|
||||
for (let key of userEmailKeys) {
|
||||
this.httpBackend.when('GET', '/api/user/find?email=' + key).respond(this.userEmailMap.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -387,4 +423,84 @@ export class CheHttpBackend {
|
|||
this.httpBackend.when('POST', this.workspaceAgentMap.get(workspaceId) + '/svn/info?workspaceId=' + workspaceId).respond(svnInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup Backend for factories
|
||||
*/
|
||||
factoriesBackendSetup() {
|
||||
this.setup();
|
||||
|
||||
let allFactories = [];
|
||||
let pageFactories = [];
|
||||
|
||||
let factoriesKeys = this.factoriesMap.keys();
|
||||
for (let key of factoriesKeys) {
|
||||
let factory = this.factoriesMap.get(key);
|
||||
this.httpBackend.when('GET', '/api/factory/' + factory.id).respond(factory);
|
||||
this.httpBackend.when('DELETE', '/api/factory/' + factory.id).respond(() => {
|
||||
return [200, {success: true, errors: []}];
|
||||
});
|
||||
allFactories.push(factory);
|
||||
}
|
||||
|
||||
if (this.defaultUser) {
|
||||
this.httpBackend.when('GET', '/api/user').respond(this.defaultUser);
|
||||
|
||||
if (allFactories.length > this.pageSkipCount) {
|
||||
if(allFactories.length > this.pageSkipCount + this.pageMaxItem) {
|
||||
pageFactories = allFactories.slice(this.pageSkipCount, this.pageSkipCount + this.pageMaxItem);
|
||||
} else {
|
||||
pageFactories = allFactories.slice(this.pageSkipCount);
|
||||
}
|
||||
}
|
||||
this.httpBackend.when('GET', '/api/factory/find?creator.userId=' + this.defaultUser.id + '&maxItems=' + this.pageMaxItem + '&skipCount=' + this.pageSkipCount).respond(pageFactories);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given factory
|
||||
* @param factory
|
||||
*/
|
||||
addUserFactory(factory) {
|
||||
this.factoriesMap.set(factory.id, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets max objects on response
|
||||
* @param pageMaxItem
|
||||
*/
|
||||
setPageMaxItem(pageMaxItem) {
|
||||
this.pageMaxItem = pageMaxItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets skip count of values
|
||||
* @param pageSkipCount
|
||||
*/
|
||||
setPageSkipCount(pageSkipCount) {
|
||||
this.pageSkipCount = pageSkipCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given user
|
||||
* @param user
|
||||
*/
|
||||
setDefaultUser(user) {
|
||||
this.defaultUser = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given user to userIdMap
|
||||
* @param user
|
||||
*/
|
||||
addUserById(user) {
|
||||
this.userIdMap.set(user.id, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given user to userEmailMap
|
||||
* @param user
|
||||
*/
|
||||
addUserEmail(user) {
|
||||
this.userEmailMap.set(user.email, user);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -227,4 +227,22 @@ declare namespace _che {
|
|||
label: string;
|
||||
location: string;
|
||||
}
|
||||
|
||||
export interface IUser {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
aliases: Array<string>;
|
||||
}
|
||||
|
||||
export interface IFactory {
|
||||
id: string;
|
||||
name?: string;
|
||||
v: string;
|
||||
workspace: IWorkspaceConfig;
|
||||
creator: any;
|
||||
ide?: any;
|
||||
button?: any;
|
||||
policies?: any;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,6 +69,10 @@
|
|||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-factory-shared</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-git-shared</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-machine-shared</artifactId>
|
||||
|
|
|
|||
|
|
@ -943,4 +943,109 @@ public interface CoreLocalizationConstant extends Messages {
|
|||
@Key("authentication.dialog.rejected.by.user")
|
||||
String authenticationDialogRejectedByUser();
|
||||
|
||||
|
||||
/* Factories */
|
||||
@Key("projects.import.configuring.cloning")
|
||||
String cloningSource();
|
||||
|
||||
@Key("create.factory.action.title")
|
||||
String createFactoryActionTitle();
|
||||
|
||||
@Key("create.factory.already.exist")
|
||||
String createFactoryAlreadyExist();
|
||||
|
||||
@Key("create.factory.unable.create.from.current.workspace")
|
||||
String createFactoryFromCurrentWorkspaceFailed();
|
||||
|
||||
@Key("create.factory.form.title")
|
||||
String createFactoryTitle();
|
||||
|
||||
@Key("create.factory.label.name")
|
||||
String createFactoryName();
|
||||
|
||||
@Key("create.factory.label.link")
|
||||
String createFactoryLink();
|
||||
|
||||
@Key("create.factory.button.create")
|
||||
String createFactoryButton();
|
||||
|
||||
@Key("create.factory.button.close")
|
||||
String createFactoryButtonClose();
|
||||
|
||||
@Key("create.factory.configure.button.tooltip")
|
||||
String createFactoryConfigureTooltip();
|
||||
|
||||
@Key("create.factory.launch.button.tooltip")
|
||||
String createFactoryLaunchTooltip();
|
||||
|
||||
|
||||
@Key("import.config.view.name")
|
||||
String importFromConfigurationName();
|
||||
|
||||
@Key("import.config.view.description")
|
||||
String importFromConfigurationDescription();
|
||||
|
||||
@Key("project.import.configured.cloned")
|
||||
String clonedSource(String projectName);
|
||||
|
||||
@Key("import.config.form.button.import")
|
||||
String importButton();
|
||||
|
||||
@Key("import.config.view.title")
|
||||
String importFromConfigurationTitle();
|
||||
|
||||
@Key("import.config.form.prompt")
|
||||
String configFileTitle();
|
||||
|
||||
@Key("project.already.imported")
|
||||
String projectAlreadyImported(String projectName);
|
||||
|
||||
@Key("project.import.cloned.with.checkout")
|
||||
String clonedSourceWithCheckout(String projectName, String repoName, String ref, String branch);
|
||||
|
||||
@Key("project.import.cloned.with.checkout.start.point")
|
||||
String clonedWithCheckoutOnStartPoint(String projectName, String repoName, String startPoint, String branch);
|
||||
|
||||
@Key("project.import.configuring.cloning")
|
||||
String cloningSource(String projectName);
|
||||
|
||||
@Key("project.import.ssh.key.upload.failed.title")
|
||||
String cloningSourceSshKeyUploadFailedTitle();
|
||||
|
||||
@Key("project.import.ssh.key.upload.failed.text")
|
||||
String cloningSourcesSshKeyUploadFailedText();
|
||||
|
||||
@Key("message.ssh.key.not.found.text")
|
||||
String acceptSshNotFoundText();
|
||||
|
||||
@Key("project.import.cloning.failed.without.start.point")
|
||||
String cloningSourceWithCheckoutFailed(String branch, String repoName);
|
||||
|
||||
@Key("project.import.cloning.failed.with.start.point")
|
||||
String cloningSourceCheckoutFailed(String project, String branch);
|
||||
|
||||
@Key("project.import.cloning.failed.title")
|
||||
String cloningSourceFailedTitle(String projectName);
|
||||
|
||||
@Key("project.import.configuring.failed")
|
||||
String configuringSourceFailed(String projectName);
|
||||
|
||||
@Key("welcome.preferences.title")
|
||||
String welcomePreferencesTitle();
|
||||
|
||||
@Key("export.config.view.name")
|
||||
String exportConfigName();
|
||||
|
||||
@Key("export.config.view.description")
|
||||
String exportConfigDescription();
|
||||
|
||||
@Key("export.config.error.message")
|
||||
String exportConfigErrorMessage();
|
||||
|
||||
@Key("export.config.dialog.not.under.vcs.title")
|
||||
String exportConfigDialogNotUnderVcsTitle();
|
||||
|
||||
@Key("export.config.dialog.not.under.vcs.text")
|
||||
String exportConfigDialogNotUnderVcsText();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ import org.eclipse.che.ide.context.AppContextImpl;
|
|||
import org.eclipse.che.ide.debug.DebugApiModule;
|
||||
import org.eclipse.che.ide.editor.EditorApiModule;
|
||||
import org.eclipse.che.ide.editor.preferences.EditorPreferencesModule;
|
||||
import org.eclipse.che.ide.factory.FactoryApiModule;
|
||||
import org.eclipse.che.ide.factory.inject.FactoryGinModule;
|
||||
import org.eclipse.che.ide.filetypes.FileTypeApiModule;
|
||||
import org.eclipse.che.ide.keybinding.KeyBindingManager;
|
||||
import org.eclipse.che.ide.machine.MachineApiModule;
|
||||
|
|
@ -110,7 +110,7 @@ public class CoreGinModule extends AbstractGinModule {
|
|||
install(new ProjectApiModule());
|
||||
install(new ProjectImportModule());
|
||||
install(new OAuthApiModule());
|
||||
install(new FactoryApiModule());
|
||||
install(new FactoryGinModule());
|
||||
|
||||
// configure miscellaneous core components
|
||||
bind(StandardComponentInitializer.class).in(Singleton.class);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.factory;
|
||||
|
||||
import com.google.gwt.core.client.Callback;
|
||||
import com.google.gwt.core.client.ScriptInjector;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.eclipse.che.ide.api.action.ActionManager;
|
||||
import org.eclipse.che.ide.api.action.DefaultActionGroup;
|
||||
import org.eclipse.che.ide.api.extension.Extension;
|
||||
import org.eclipse.che.ide.factory.accept.AcceptFactoryHandler;
|
||||
import org.eclipse.che.ide.factory.action.CreateFactoryAction;
|
||||
import org.eclipse.che.ide.factory.json.ImportFromConfigAction;
|
||||
import org.eclipse.che.ide.factory.welcome.OpenWelcomePageAction;
|
||||
|
||||
import static com.google.gwt.core.client.ScriptInjector.TOP_WINDOW;
|
||||
import static org.eclipse.che.ide.api.action.IdeActions.GROUP_PROJECT;
|
||||
import static org.eclipse.che.ide.api.action.IdeActions.GROUP_WORKSPACE;
|
||||
|
||||
/**
|
||||
* @author Vladyslav Zhukovskii
|
||||
*/
|
||||
@Singleton
|
||||
@Extension(title = "Factory", version = "3.0.0")
|
||||
public class FactoryExtension {
|
||||
|
||||
@Inject
|
||||
public FactoryExtension(AcceptFactoryHandler acceptFactoryHandler,
|
||||
ActionManager actionManager,
|
||||
FactoryResources resources,
|
||||
CreateFactoryAction configureFactoryAction,
|
||||
ImportFromConfigAction importFromConfigAction,
|
||||
OpenWelcomePageAction openWelcomePageAction) {
|
||||
acceptFactoryHandler.process();
|
||||
|
||||
/*
|
||||
* Inject resources and js
|
||||
*/
|
||||
ScriptInjector.fromUrl("https://apis.google.com/js/client:plusone.js?parsetags=explicit")
|
||||
.setWindow(TOP_WINDOW)
|
||||
.inject();
|
||||
|
||||
ScriptInjector.fromUrl("https://connect.facebook.net/en_US/sdk.js")
|
||||
.setWindow(TOP_WINDOW)
|
||||
.setCallback(new Callback<Void, Exception>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception reason) {
|
||||
}
|
||||
|
||||
private native void init() /*-{
|
||||
$wnd.FB.init({
|
||||
appId: "318167898391385",
|
||||
xfbml: true,
|
||||
version: "v2.1"
|
||||
});
|
||||
}-*/;
|
||||
}).inject();
|
||||
|
||||
resources.factoryCSS().ensureInjected();
|
||||
|
||||
DefaultActionGroup projectGroup = (DefaultActionGroup)actionManager.getAction(GROUP_PROJECT);
|
||||
DefaultActionGroup workspaceGroup = (DefaultActionGroup)actionManager.getAction(GROUP_WORKSPACE);
|
||||
|
||||
actionManager.registerAction("openWelcomePage", openWelcomePageAction);
|
||||
actionManager.registerAction("importProjectFromCodenvyConfigAction", importFromConfigAction);
|
||||
actionManager.registerAction("configureFactoryAction", configureFactoryAction);
|
||||
|
||||
projectGroup.add(importFromConfigAction);
|
||||
workspaceGroup.add(configureFactoryAction);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.factory;
|
||||
|
||||
import com.google.gwt.resources.client.ClientBundle;
|
||||
import com.google.gwt.resources.client.CssResource;
|
||||
|
||||
import org.eclipse.che.ide.ui.Styles;
|
||||
import org.vectomatic.dom.svg.ui.SVGResource;
|
||||
|
||||
/**
|
||||
* Factory extension resources (css styles, images).
|
||||
*
|
||||
* @author Ann Shumilova
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
public interface FactoryResources extends ClientBundle {
|
||||
interface FactoryCSS extends CssResource, Styles {
|
||||
String label();
|
||||
|
||||
String createFactoryButton();
|
||||
|
||||
String labelErrorPosition();
|
||||
}
|
||||
|
||||
interface Style extends CssResource {
|
||||
String launchIcon();
|
||||
|
||||
String configureIcon();
|
||||
}
|
||||
|
||||
@Source({"Factory.css", "org/eclipse/che/ide/api/ui/style.css", "org/eclipse/che/ide/ui/Styles.css"})
|
||||
FactoryCSS factoryCSS();
|
||||
|
||||
@Source("export-config.svg")
|
||||
SVGResource exportConfig();
|
||||
|
||||
@Source("import-config.svg")
|
||||
SVGResource importConfig();
|
||||
|
||||
@Source("execute.svg")
|
||||
SVGResource execute();
|
||||
|
||||
@Source("cog-icon.svg")
|
||||
SVGResource configure();
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.factory.accept;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.web.bindery.event.shared.EventBus;
|
||||
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
|
||||
import org.eclipse.che.api.factory.shared.dto.IdeActionDto;
|
||||
import org.eclipse.che.api.factory.shared.dto.IdeDto;
|
||||
import org.eclipse.che.ide.CoreLocalizationConstant;
|
||||
import org.eclipse.che.ide.api.action.ActionManager;
|
||||
import org.eclipse.che.ide.api.app.AppContext;
|
||||
import org.eclipse.che.ide.api.factory.FactoryAcceptedEvent;
|
||||
import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent;
|
||||
import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler;
|
||||
import org.eclipse.che.ide.api.notification.NotificationManager;
|
||||
import org.eclipse.che.ide.api.notification.StatusNotification;
|
||||
import org.eclipse.che.ide.factory.utils.FactoryProjectImporter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.NOT_EMERGE_MODE;
|
||||
|
||||
/**
|
||||
* @author Sergii Leschenko
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
@Singleton
|
||||
public class AcceptFactoryHandler {
|
||||
private final CoreLocalizationConstant localizationConstant;
|
||||
private final FactoryProjectImporter factoryProjectImporter;
|
||||
private final EventBus eventBus;
|
||||
private final AppContext appContext;
|
||||
private final ActionManager actionManager;
|
||||
private final NotificationManager notificationManager;
|
||||
|
||||
private StatusNotification notification;
|
||||
private boolean isImportingStarted;
|
||||
|
||||
@Inject
|
||||
public AcceptFactoryHandler(CoreLocalizationConstant localizationConstant,
|
||||
FactoryProjectImporter factoryProjectImporter,
|
||||
EventBus eventBus,
|
||||
AppContext appContext,
|
||||
ActionManager actionManager,
|
||||
NotificationManager notificationManager) {
|
||||
this.factoryProjectImporter = factoryProjectImporter;
|
||||
this.localizationConstant = localizationConstant;
|
||||
this.eventBus = eventBus;
|
||||
this.appContext = appContext;
|
||||
this.actionManager = actionManager;
|
||||
this.notificationManager = notificationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts factory if it is present in context of application
|
||||
*/
|
||||
public void process() {
|
||||
final FactoryDto factory;
|
||||
if ((factory = appContext.getFactory()) == null) {
|
||||
return;
|
||||
}
|
||||
eventBus.addHandler(WsAgentStateEvent.TYPE, new WsAgentStateHandler() {
|
||||
@Override
|
||||
public void onWsAgentStarted(final WsAgentStateEvent event) {
|
||||
if (isImportingStarted) {
|
||||
return;
|
||||
}
|
||||
|
||||
isImportingStarted = true;
|
||||
|
||||
notification = notificationManager
|
||||
.notify(localizationConstant.cloningSource(), StatusNotification.Status.PROGRESS, NOT_EMERGE_MODE);
|
||||
performOnAppLoadedActions(factory);
|
||||
startImporting(factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWsAgentStopped(WsAgentStateEvent event) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void startImporting(final FactoryDto factory) {
|
||||
factoryProjectImporter.startImporting(factory,
|
||||
new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
notification.setStatus(StatusNotification.Status.SUCCESS);
|
||||
notification.setContent(localizationConstant.cloningSource());
|
||||
performOnProjectsLoadedActions(factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable throwable) {
|
||||
notification.setStatus(StatusNotification.Status.FAIL);
|
||||
notification.setContent(throwable.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void performOnAppLoadedActions(final FactoryDto factory) {
|
||||
final IdeDto ide = factory.getIde();
|
||||
if (ide == null || ide.getOnAppLoaded() == null) {
|
||||
return;
|
||||
}
|
||||
for (IdeActionDto action : ide.getOnAppLoaded().getActions()) {
|
||||
actionManager.performAction(action.getId(), action.getProperties());
|
||||
}
|
||||
}
|
||||
|
||||
private void performOnProjectsLoadedActions(final FactoryDto factory) {
|
||||
final IdeDto ide = factory.getIde();
|
||||
if (ide == null || ide.getOnProjectsLoaded() == null) {
|
||||
eventBus.fireEvent(new FactoryAcceptedEvent(factory));
|
||||
return;
|
||||
}
|
||||
for (IdeActionDto action : ide.getOnProjectsLoaded().getActions()) {
|
||||
actionManager.performAction(action.getId(), action.getProperties());
|
||||
}
|
||||
eventBus.fireEvent(new FactoryAcceptedEvent(factory));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.factory.action;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.eclipse.che.ide.CoreLocalizationConstant;
|
||||
import org.eclipse.che.ide.api.action.AbstractPerspectiveAction;
|
||||
import org.eclipse.che.ide.api.action.ActionEvent;
|
||||
import org.eclipse.che.ide.factory.configure.CreateFactoryPresenter;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
@Singleton
|
||||
public class CreateFactoryAction extends AbstractPerspectiveAction {
|
||||
|
||||
private final CreateFactoryPresenter presenter;
|
||||
|
||||
@Inject
|
||||
public CreateFactoryAction(CreateFactoryPresenter presenter,
|
||||
CoreLocalizationConstant localizationConstant) {
|
||||
super(Collections.singletonList("Project Perspective"), localizationConstant.createFactoryActionTitle(), null, null, null);
|
||||
this.presenter = presenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
presenter.showDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInPerspective(@NotNull ActionEvent event) {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.factory.configure;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.eclipse.che.api.core.rest.shared.dto.Link;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
|
||||
import org.eclipse.che.api.promises.client.Operation;
|
||||
import org.eclipse.che.api.promises.client.OperationException;
|
||||
import org.eclipse.che.api.promises.client.PromiseError;
|
||||
import org.eclipse.che.ide.CoreLocalizationConstant;
|
||||
import org.eclipse.che.ide.api.app.AppContext;
|
||||
import org.eclipse.che.ide.api.factory.FactoryServiceClient;
|
||||
import org.eclipse.che.ide.util.Pair;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
@Singleton
|
||||
public class CreateFactoryPresenter implements CreateFactoryView.ActionDelegate {
|
||||
public static final String CONFIGURE_LINK = "/dashboard/#/factory/";
|
||||
|
||||
private final CreateFactoryView view;
|
||||
private final AppContext appContext;
|
||||
private final FactoryServiceClient factoryService;
|
||||
private final CoreLocalizationConstant localizationConstant;
|
||||
|
||||
@Inject
|
||||
public CreateFactoryPresenter(CreateFactoryView view,
|
||||
AppContext appContext,
|
||||
FactoryServiceClient factoryService,
|
||||
CoreLocalizationConstant localizationConstant) {
|
||||
this.view = view;
|
||||
this.appContext = appContext;
|
||||
this.factoryService = factoryService;
|
||||
this.localizationConstant = localizationConstant;
|
||||
view.setDelegate(this);
|
||||
}
|
||||
|
||||
public void showDialog() {
|
||||
view.showDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateClicked() {
|
||||
final String factoryName = view.getFactoryName();
|
||||
factoryService.getFactoryJson(appContext.getWorkspace().getId(), null)
|
||||
.then(new Operation<FactoryDto>() {
|
||||
@Override
|
||||
public void apply(final FactoryDto factory) throws OperationException {
|
||||
factoryService.findFactory(null, null, Collections.singletonList(Pair.of("name", factoryName)))
|
||||
.then(saveFactory(factory, factoryName))
|
||||
.catchError(logError());
|
||||
}
|
||||
})
|
||||
.catchError(logError());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFactoryNameChanged(String factoryName) {
|
||||
view.enableCreateFactoryButton(isValidFactoryName(factoryName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelClicked() {
|
||||
view.close();
|
||||
}
|
||||
|
||||
private Operation<List<FactoryDto>> saveFactory(final FactoryDto factory, final String factoryName) {
|
||||
return new Operation<List<FactoryDto>>() {
|
||||
@Override
|
||||
public void apply(List<FactoryDto> factories) throws OperationException {
|
||||
if (!factories.isEmpty()) {
|
||||
view.showFactoryNameError(localizationConstant.createFactoryAlreadyExist(), null);
|
||||
} else {
|
||||
factoryService.saveFactory(factory.withName(factoryName))
|
||||
.then(new Operation<FactoryDto>() {
|
||||
@Override
|
||||
public void apply(FactoryDto factory) throws OperationException {
|
||||
final Link link = factory.getLink("accept-named");
|
||||
if (link != null) {
|
||||
view.setAcceptFactoryLink(link.getHref());
|
||||
}
|
||||
view.setConfigureFactoryLink(CONFIGURE_LINK + factory.getId() + "/configure");
|
||||
}
|
||||
})
|
||||
.catchError(logError());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Operation<PromiseError> logError() {
|
||||
return err -> view.showFactoryNameError(localizationConstant.createFactoryFromCurrentWorkspaceFailed(), err.getMessage());
|
||||
}
|
||||
|
||||
private boolean isValidFactoryName(String name) {
|
||||
if (name.length() == 0 || name.length() >= 125) {
|
||||
return false;
|
||||
}
|
||||
view.hideFactoryNameError();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.factory.configure;
|
||||
|
||||
import com.google.inject.ImplementedBy;
|
||||
|
||||
import org.eclipse.che.commons.annotation.Nullable;
|
||||
import org.eclipse.che.ide.api.mvp.View;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Representation of create factory popup.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
@ImplementedBy(CreateFactoryViewImpl.class)
|
||||
public interface CreateFactoryView extends View<CreateFactoryView.ActionDelegate> {
|
||||
|
||||
interface ActionDelegate {
|
||||
|
||||
/** Performs any actions appropriate in response to the user having pressed the Create button */
|
||||
void onCreateClicked();
|
||||
|
||||
/** Performs any actions appropriate in response to the user having type into Factory name input */
|
||||
void onFactoryNameChanged(String factoryName);
|
||||
|
||||
/** Performs any actions appropriate in response to the user having pressed the Cancel button. */
|
||||
void onCancelClicked();
|
||||
}
|
||||
|
||||
/** Preforms closing create factory popup */
|
||||
void close();
|
||||
|
||||
/** Preforms showing create factory popup */
|
||||
void showDialog();
|
||||
|
||||
/** Gets factory name from input */
|
||||
String getFactoryName();
|
||||
|
||||
/** Set accept factory link */
|
||||
void setAcceptFactoryLink(@NotNull String acceptLink);
|
||||
|
||||
/** Set accept factory link */
|
||||
void setConfigureFactoryLink(@NotNull String configureLink);
|
||||
|
||||
/** Set enable create factory button */
|
||||
void enableCreateFactoryButton(boolean enabled);
|
||||
|
||||
/** Shows error if factory name invalid */
|
||||
void showFactoryNameError(@NotNull String labelMessage, @Nullable String tooltipMessage);
|
||||
|
||||
/** Hide error of factory name is valid */
|
||||
void hideFactoryNameError();
|
||||
}
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.factory.configure;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.gwt.event.dom.client.KeyCodes;
|
||||
import com.google.gwt.event.dom.client.KeyUpEvent;
|
||||
import com.google.gwt.regexp.shared.RegExp;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.uibinder.client.UiHandler;
|
||||
import com.google.gwt.user.client.ui.Anchor;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.eclipse.che.commons.annotation.Nullable;
|
||||
import org.eclipse.che.ide.CoreLocalizationConstant;
|
||||
import org.eclipse.che.ide.factory.FactoryResources;
|
||||
import org.eclipse.che.ide.ui.Tooltip;
|
||||
import org.eclipse.che.ide.ui.menu.PositionController;
|
||||
import org.eclipse.che.ide.ui.window.Window;
|
||||
import org.eclipse.che.ide.ui.zeroclipboard.ClipboardButtonBuilder;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import static com.google.gwt.dom.client.Style.Unit;
|
||||
|
||||
/**
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
@Singleton
|
||||
public class CreateFactoryViewImpl extends Window implements CreateFactoryView {
|
||||
private static final RegExp FACTORY_NAME_PATTERN = RegExp.compile("[^A-Za-z0-9_-]");
|
||||
|
||||
|
||||
interface FactoryViewImplUiBinder extends UiBinder<Widget, CreateFactoryViewImpl> {
|
||||
}
|
||||
|
||||
private final FactoryResources factoryResources;
|
||||
|
||||
private ActionDelegate delegate;
|
||||
|
||||
@UiField
|
||||
FactoryResources.Style style;
|
||||
@UiField
|
||||
TextBox factoryName;
|
||||
@UiField
|
||||
TextBox factoryLink;
|
||||
@UiField
|
||||
Label factoryNameLabel;
|
||||
@UiField
|
||||
Label factoryLinkLabel;
|
||||
@UiField
|
||||
Label factoryNameErrorLabel;
|
||||
@UiField
|
||||
Button createFactoryButton;
|
||||
@UiField
|
||||
FlowPanel upperPanel;
|
||||
@UiField
|
||||
FlowPanel lowerPanel;
|
||||
@UiField
|
||||
FlowPanel createFactoryPanel;
|
||||
@UiField
|
||||
Anchor launch;
|
||||
@UiField
|
||||
Anchor configure;
|
||||
|
||||
private Tooltip labelsErrorTooltip;
|
||||
|
||||
@Inject
|
||||
protected CreateFactoryViewImpl(FactoryViewImplUiBinder uiBinder,
|
||||
CoreLocalizationConstant locale,
|
||||
FactoryResources factoryResources,
|
||||
ClipboardButtonBuilder buttonBuilder) {
|
||||
this.factoryResources = factoryResources;
|
||||
setTitle(locale.createFactoryTitle());
|
||||
setWidget(uiBinder.createAndBindUi(this));
|
||||
factoryNameLabel.setText(locale.createFactoryName());
|
||||
factoryLinkLabel.setText(locale.createFactoryLink());
|
||||
configure.getElement().insertFirst(factoryResources.configure().getSvg().getElement());
|
||||
launch.getElement().insertFirst(factoryResources.execute().getSvg().getElement());
|
||||
launch.addStyleName(style.launchIcon());
|
||||
configure.addStyleName(style.configureIcon());
|
||||
createFactoryButton.setEnabled(false);
|
||||
Button cancelButton =
|
||||
createButton(locale.createFactoryButtonClose(), "git-remotes-pull-cancel", event -> delegate.onCancelClicked());
|
||||
createFactoryButton.addClickHandler(clickEvent -> delegate.onCreateClicked());
|
||||
cancelButton.ensureDebugId("projectReadOnlyGitUrl-btnClose");
|
||||
addButtonToFooter(cancelButton);
|
||||
getWidget().getElement().getStyle().setPadding(0, Unit.PX);
|
||||
buttonBuilder.withResourceWidget(factoryLink).build();
|
||||
factoryLink.setReadOnly(true);
|
||||
final Tooltip launchFactoryTooltip = Tooltip.create((elemental.dom.Element)launch.getElement(),
|
||||
PositionController.VerticalAlign.TOP,
|
||||
PositionController.HorizontalAlign.MIDDLE,
|
||||
locale.createFactoryLaunchTooltip());
|
||||
launchFactoryTooltip.setShowDelayDisabled(false);
|
||||
|
||||
final Tooltip configureFactoryTooltip = Tooltip.create((elemental.dom.Element)configure.getElement(),
|
||||
PositionController.VerticalAlign.TOP,
|
||||
PositionController.HorizontalAlign.MIDDLE,
|
||||
locale.createFactoryConfigureTooltip());
|
||||
configureFactoryTooltip.setShowDelayDisabled(false);
|
||||
factoryName.getElement().setAttribute("placeholder", "new-factory-name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDelegate(ActionDelegate delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showDialog() {
|
||||
clear();
|
||||
this.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFactoryName() {
|
||||
return factoryName.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptFactoryLink(String acceptLink) {
|
||||
factoryLink.setText(acceptLink);
|
||||
launch.getElement().setAttribute("target", "_blank");
|
||||
launch.setHref(acceptLink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConfigureFactoryLink(String configureLink) {
|
||||
configure.getElement().setAttribute("target", "_blank");
|
||||
configure.setHref(configureLink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableCreateFactoryButton(boolean enabled) {
|
||||
createFactoryButton.setEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showFactoryNameError(@NotNull String labelMessage, @Nullable String tooltipMessage) {
|
||||
factoryName.addStyleName(factoryResources.factoryCSS().inputError());
|
||||
factoryNameErrorLabel.setText(labelMessage);
|
||||
if (labelsErrorTooltip != null) {
|
||||
labelsErrorTooltip.destroy();
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(tooltipMessage)) {
|
||||
labelsErrorTooltip = Tooltip.create((elemental.dom.Element)factoryNameErrorLabel.getElement(),
|
||||
PositionController.VerticalAlign.TOP,
|
||||
PositionController.HorizontalAlign.MIDDLE,
|
||||
tooltipMessage);
|
||||
labelsErrorTooltip.setShowDelayDisabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideFactoryNameError() {
|
||||
factoryName.removeStyleName(factoryResources.factoryCSS().inputError());
|
||||
factoryNameErrorLabel.setText("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.hide();
|
||||
}
|
||||
|
||||
@UiHandler({"factoryName"})
|
||||
public void onProjectNameChanged(KeyUpEvent event) {
|
||||
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER
|
||||
&& createFactoryButton.isEnabled()) {
|
||||
delegate.onCreateClicked();
|
||||
} else {
|
||||
String name = factoryName.getValue();
|
||||
if (!Strings.isNullOrEmpty(name) && FACTORY_NAME_PATTERN.test(name)) {
|
||||
name = name.replaceAll("[^A-Za-z0-9_]", "-");
|
||||
factoryName.setValue(name);
|
||||
}
|
||||
delegate.onFactoryNameChanged(name);
|
||||
}
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
launch.getElement().removeAttribute("href");
|
||||
configure.getElement().removeAttribute("href");
|
||||
createFactoryButton.setEnabled(false);
|
||||
factoryName.removeStyleName(factoryResources.factoryCSS().inputError());
|
||||
factoryNameErrorLabel.setText("");
|
||||
factoryName.setText("");
|
||||
factoryLink.setText("");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
<!--
|
||||
|
||||
Copyright (c) 2012-2017 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
|
||||
|
||||
-->
|
||||
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
||||
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
||||
<ui:with field='res' type='org.eclipse.che.ide.factory.FactoryResources'/>
|
||||
<ui:with field='locale' type='org.eclipse.che.ide.CoreLocalizationConstant'/>
|
||||
<ui:style type='org.eclipse.che.ide.factory.FactoryResources.Style'>
|
||||
@eval tabBorderColor org.eclipse.che.ide.api.theme.Style.theme.tabBorderColor();
|
||||
|
||||
.border {
|
||||
border-bottom: 1px solid tabBorderColor;
|
||||
}
|
||||
|
||||
.topPanel {
|
||||
padding: 16px 16px 22px 16px;
|
||||
}
|
||||
|
||||
.lowerPanel {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.centerAlign {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.iconContainer {
|
||||
padding-left: 15px;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.launchIcon svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
fill: #9B9B9B;
|
||||
}
|
||||
|
||||
.launchIcon:hover svg {
|
||||
fill: rgba(0, 182, 142, 0.91);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.configureIcon svg {
|
||||
margin-top: 1px;
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
fill: #9B9B9B;
|
||||
}
|
||||
|
||||
.configureIcon:hover svg {
|
||||
fill: #E0E0E0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: literal("calc(100% - 95px)");
|
||||
}
|
||||
|
||||
.inputContainer {
|
||||
width: literal("calc(100% - 80px)");
|
||||
}
|
||||
.inputReadOnly {
|
||||
float: left;
|
||||
width: literal("calc(100% - 32px)");
|
||||
}
|
||||
.inputReadOnly + div {
|
||||
margin: 0;
|
||||
}
|
||||
</ui:style>
|
||||
|
||||
<g:FlowPanel width="340px" ui:field="createFactoryPanel">
|
||||
<g:FlowPanel ui:field="upperPanel" addStyleNames="{style.topPanel} {style.border}">
|
||||
<g:Label ui:field="factoryNameLabel" addStyleNames="{res.factoryCSS.label}"/>
|
||||
<g:TextBox ui:field="factoryName" addStyleNames="{style.input}"/>
|
||||
<g:Button ui:field="createFactoryButton" text="{locale.createFactoryButton}"
|
||||
addStyleNames="{style.border} {res.factoryCSS.createFactoryButton}"/>
|
||||
<g:Label ui:field="factoryNameErrorLabel" wordWrap="true" addStyleNames="{res.factoryCSS.labelErrorPosition} {style.input}"/>
|
||||
</g:FlowPanel>
|
||||
<g:FlowPanel ui:field="lowerPanel" addStyleNames="{style.lowerPanel}">
|
||||
<g:Label ui:field="factoryLinkLabel" addStyleNames="{res.factoryCSS.label}"/>
|
||||
<g:FlowPanel addStyleNames="{style.centerAlign}">
|
||||
<g:FlowPanel addStyleNames="{style.inputContainer}">
|
||||
<g:TextBox ui:field="factoryLink" addStyleNames="{style.inputReadOnly}"/>
|
||||
</g:FlowPanel>
|
||||
<g:FlowPanel addStyleNames="{style.iconContainer}">
|
||||
<g:Anchor ui:field="configure"/>
|
||||
<g:Anchor ui:field="launch"/>
|
||||
</g:FlowPanel>
|
||||
</g:FlowPanel>
|
||||
</g:FlowPanel>
|
||||
</g:FlowPanel>
|
||||
</ui:UiBinder>
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.factory.inject;
|
||||
|
||||
import com.google.gwt.inject.client.AbstractGinModule;
|
||||
import com.google.gwt.inject.client.multibindings.GinMultibinder;
|
||||
|
||||
import org.eclipse.che.ide.api.factory.FactoryServiceClient;
|
||||
import org.eclipse.che.ide.api.preferences.PreferencePagePresenter;
|
||||
import org.eclipse.che.ide.factory.FactoryServiceClientImpl;
|
||||
import org.eclipse.che.ide.factory.json.ImportFromConfigView;
|
||||
import org.eclipse.che.ide.factory.json.ImportFromConfigViewImpl;
|
||||
import org.eclipse.che.ide.factory.welcome.GreetingPartView;
|
||||
import org.eclipse.che.ide.factory.welcome.GreetingPartViewImpl;
|
||||
import org.eclipse.che.ide.factory.welcome.preferences.ShowWelcomePreferencePagePresenter;
|
||||
import org.eclipse.che.ide.factory.welcome.preferences.ShowWelcomePreferencePageView;
|
||||
import org.eclipse.che.ide.factory.welcome.preferences.ShowWelcomePreferencePageViewImpl;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* @author Vladyslav Zhukovskii
|
||||
*/
|
||||
public class FactoryGinModule extends AbstractGinModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(GreetingPartView.class).to(GreetingPartViewImpl.class).in(Singleton.class);
|
||||
bind(ImportFromConfigView.class).to(ImportFromConfigViewImpl.class).in(Singleton.class);
|
||||
bind(ShowWelcomePreferencePageView.class).to(ShowWelcomePreferencePageViewImpl.class).in(Singleton.class);
|
||||
bind(FactoryServiceClient.class).to(FactoryServiceClientImpl.class).in(Singleton.class);
|
||||
|
||||
final GinMultibinder<PreferencePagePresenter> prefBinder = GinMultibinder.newSetBinder(binder(), PreferencePagePresenter.class);
|
||||
prefBinder.addBinding().to(ShowWelcomePreferencePagePresenter.class);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.factory.json;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.eclipse.che.ide.CoreLocalizationConstant;
|
||||
import org.eclipse.che.ide.api.action.Action;
|
||||
import org.eclipse.che.ide.api.action.ActionEvent;
|
||||
import org.eclipse.che.ide.factory.FactoryResources;
|
||||
|
||||
/**
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Singleton
|
||||
public class ImportFromConfigAction extends Action {
|
||||
|
||||
private final ImportFromConfigPresenter presenter;
|
||||
|
||||
@Inject
|
||||
public ImportFromConfigAction(final ImportFromConfigPresenter presenter,
|
||||
CoreLocalizationConstant locale,
|
||||
FactoryResources resources) {
|
||||
super(locale.importFromConfigurationName(), locale.importFromConfigurationDescription(), null, resources.importConfig());
|
||||
this.presenter = presenter;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
presenter.showDialog();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void update(ActionEvent event) {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.factory.json;
|
||||
|
||||
import com.google.gwt.json.client.JSONException;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
|
||||
import org.eclipse.che.ide.CoreLocalizationConstant;
|
||||
import org.eclipse.che.ide.api.notification.NotificationManager;
|
||||
import org.eclipse.che.ide.api.notification.StatusNotification;
|
||||
import org.eclipse.che.ide.dto.DtoFactory;
|
||||
import org.eclipse.che.ide.factory.utils.FactoryProjectImporter;
|
||||
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.NOT_EMERGE_MODE;
|
||||
|
||||
/**
|
||||
* Imports project from factory.json file
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public class ImportFromConfigPresenter implements ImportFromConfigView.ActionDelegate {
|
||||
private final CoreLocalizationConstant localizationConstant;
|
||||
private final ImportFromConfigView view;
|
||||
private final NotificationManager notificationManager;
|
||||
private final DtoFactory dtoFactory;
|
||||
private final FactoryProjectImporter projectImporter;
|
||||
private final AsyncCallback<Void> importerCallback;
|
||||
|
||||
private StatusNotification notification;
|
||||
|
||||
@Inject
|
||||
public ImportFromConfigPresenter(final CoreLocalizationConstant localizationConstant,
|
||||
FactoryProjectImporter projectImporter,
|
||||
ImportFromConfigView view,
|
||||
NotificationManager notificationManager,
|
||||
DtoFactory dtoFactory) {
|
||||
this.localizationConstant = localizationConstant;
|
||||
this.notificationManager = notificationManager;
|
||||
this.view = view;
|
||||
this.dtoFactory = dtoFactory;
|
||||
this.view.setDelegate(this);
|
||||
this.projectImporter = projectImporter;
|
||||
|
||||
importerCallback = new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
notification.setContent(localizationConstant.clonedSource(null));
|
||||
notification.setStatus(StatusNotification.Status.SUCCESS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable throwable) {
|
||||
notification.setContent(throwable.getMessage());
|
||||
notification.setStatus(StatusNotification.Status.FAIL);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Show dialog. */
|
||||
public void showDialog() {
|
||||
view.setEnabledImportButton(false);
|
||||
view.showDialog();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void onCancelClicked() {
|
||||
view.closeDialog();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void onImportClicked() {
|
||||
view.closeDialog();
|
||||
FactoryDto factoryJson;
|
||||
try {
|
||||
factoryJson = dtoFactory.createDtoFromJson(view.getFileContent(), FactoryDto.class);
|
||||
} catch (JSONException jsonException) {
|
||||
notification.setStatus(StatusNotification.Status.FAIL);
|
||||
notification.setContent("Error parsing factory object.");
|
||||
return;
|
||||
}
|
||||
|
||||
notification = notificationManager.notify(localizationConstant.cloningSource(), null, StatusNotification.Status.PROGRESS, NOT_EMERGE_MODE);
|
||||
projectImporter.startImporting(factoryJson, importerCallback);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onErrorReadingFile(String errorMessage) {
|
||||
view.setEnabledImportButton(false);
|
||||
notification.setStatus(StatusNotification.Status.FAIL);
|
||||
notification.setContent(errorMessage);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.factory.json;
|
||||
|
||||
import com.google.gwt.user.client.ui.IsWidget;
|
||||
|
||||
/**
|
||||
* The view of {@link ImportFromConfigPresenter}.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public interface ImportFromConfigView extends IsWidget {
|
||||
|
||||
public interface ActionDelegate {
|
||||
/** Performs any actions appropriate in response to the user having pressed the Cancel button. */
|
||||
void onCancelClicked();
|
||||
|
||||
/** Performs any actions appropriate in response to the user having pressed the Import button. */
|
||||
void onImportClicked();
|
||||
|
||||
/** Performs any actions appropriate in response to error reading file */
|
||||
void onErrorReadingFile(String errorMessage);
|
||||
}
|
||||
|
||||
/** Show dialog. */
|
||||
void showDialog();
|
||||
|
||||
/** Close dialog */
|
||||
void closeDialog();
|
||||
|
||||
/** Sets the delegate to receive events from this view. */
|
||||
void setDelegate(ActionDelegate delegate);
|
||||
|
||||
/** Enables or disables import button */
|
||||
void setEnabledImportButton(boolean enabled);
|
||||
|
||||
/** Get content of selected file */
|
||||
String getFileContent();
|
||||
}
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.factory.json;
|
||||
|
||||
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.FileUpload;
|
||||
import com.google.gwt.user.client.ui.FormPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.che.ide.CoreLocalizationConstant;
|
||||
import org.eclipse.che.ide.ui.window.Window;
|
||||
|
||||
/**
|
||||
* The implementation of {@link ImportFromConfigView}.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public class ImportFromConfigViewImpl extends Window implements ImportFromConfigView {
|
||||
|
||||
@SuppressWarnings("unused") // used in native js
|
||||
private static final int MAX_FILE_SIZE_MB = 3;
|
||||
|
||||
public interface ImportFromConfigViewBinder extends UiBinder<Widget, ImportFromConfigViewImpl> {
|
||||
|
||||
}
|
||||
|
||||
@UiField
|
||||
FormPanel uploadForm;
|
||||
@UiField
|
||||
Label errorMessage;
|
||||
FileUpload fileUpload;
|
||||
|
||||
private ActionDelegate delegate;
|
||||
|
||||
private String fileContent;
|
||||
|
||||
private final Button buttonImport;
|
||||
|
||||
@Inject
|
||||
public ImportFromConfigViewImpl(ImportFromConfigViewBinder importFromConfigViewBinder,
|
||||
CoreLocalizationConstant locale) {
|
||||
this.setTitle(locale.importFromConfigurationTitle());
|
||||
setWidget(importFromConfigViewBinder.createAndBindUi(this));
|
||||
|
||||
Button btnCancel = createButton(locale.cancelButton(), "import-from-config-btn-cancel", event -> delegate.onCancelClicked());
|
||||
addButtonToFooter(btnCancel);
|
||||
|
||||
buttonImport = createButton(locale.importButton(), "import-from-config-btn-import", event -> delegate.onImportClicked());
|
||||
addButtonToFooter(buttonImport);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void showDialog() {
|
||||
errorMessage.setText("");
|
||||
fileContent = null;
|
||||
fileUpload = new FileUpload();
|
||||
fileUpload.setHeight("22px");
|
||||
fileUpload.setWidth("100%");
|
||||
fileUpload.setName("file");
|
||||
fileUpload.ensureDebugId("import-from-config-ChooseFile");
|
||||
addHandler(fileUpload.getElement());
|
||||
|
||||
fileUpload.addChangeHandler(event -> buttonImport.setEnabled(fileUpload.getFilename() != null));
|
||||
|
||||
uploadForm.add(fileUpload);
|
||||
|
||||
this.show();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void closeDialog() {
|
||||
hide();
|
||||
onClose();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void setDelegate(ActionDelegate delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabledImportButton(boolean enabled) {
|
||||
buttonImport.setEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileContent() {
|
||||
return fileContent;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected void onClose() {
|
||||
uploadForm.remove(fileUpload);
|
||||
fileUpload = null;
|
||||
}
|
||||
|
||||
private native void addHandler(Element element) /*-{
|
||||
var instance = this;
|
||||
|
||||
function readFileContent(evt) {
|
||||
// Check for the various File API support.
|
||||
if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
|
||||
instance.@org.eclipse.che.ide.factory.json.ImportFromConfigViewImpl::onError(Ljava/lang/String;)
|
||||
('The File APIs are not fully supported in this browser.');
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedFile = evt.target.files[0];
|
||||
|
||||
var max_size = @org.eclipse.che.ide.factory.json.ImportFromConfigViewImpl::MAX_FILE_SIZE_MB;
|
||||
|
||||
if (selectedFile.size > max_size * 100000) {
|
||||
instance.@org.eclipse.che.ide.factory.json.ImportFromConfigViewImpl::resetUploadFileField()();
|
||||
instance.@org.eclipse.che.ide.factory.json.ImportFromConfigViewImpl::setErrorMessageOnForm(Ljava/lang/String;)
|
||||
('File size exceeds the limit ' + max_size + 'mb');
|
||||
return;
|
||||
}
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
//reseting error message
|
||||
instance.@org.eclipse.che.ide.factory.json.ImportFromConfigViewImpl::setErrorMessageOnForm(Ljava/lang/String;)('');
|
||||
//getting file's content
|
||||
instance.@org.eclipse.che.ide.factory.json.ImportFromConfigViewImpl::fileContent = reader.result;
|
||||
};
|
||||
|
||||
reader.onerror = function (event) {
|
||||
instance.@org.eclipse.che.ide.factory.json.ImportFromConfigViewImpl::onError(Ljava/lang/String;)
|
||||
('Error reading config file ' + event.target.error.code);
|
||||
};
|
||||
|
||||
reader.readAsText(selectedFile);
|
||||
}
|
||||
|
||||
element.addEventListener('change', readFileContent, false);
|
||||
}-*/;
|
||||
|
||||
private void resetUploadFileField() {
|
||||
uploadForm.remove(fileUpload);
|
||||
fileUpload = new FileUpload();
|
||||
fileUpload.setHeight("22px");
|
||||
fileUpload.setWidth("100%");
|
||||
fileUpload.setName("file");
|
||||
fileUpload.ensureDebugId("import-from-config-ChooseFile");
|
||||
addHandler(fileUpload.getElement());
|
||||
|
||||
fileUpload.addChangeHandler(event -> buttonImport.setEnabled(fileUpload.getFilename() != null));
|
||||
uploadForm.add(fileUpload);
|
||||
}
|
||||
|
||||
private void setErrorMessageOnForm(String msg) {
|
||||
errorMessage.setText(msg);
|
||||
}
|
||||
|
||||
private void onError(String message) {
|
||||
delegate.onErrorReadingFile(message);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<!--
|
||||
|
||||
Copyright (c) 2012-2017 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
|
||||
|
||||
-->
|
||||
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
||||
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
||||
<ui:with field='locale' type='org.eclipse.che.ide.CoreLocalizationConstant'/>
|
||||
<ui:style>
|
||||
.emptyBorder {
|
||||
margin: 6px;
|
||||
}
|
||||
|
||||
.spacing {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.errorMsg {
|
||||
color: red;
|
||||
}
|
||||
</ui:style>
|
||||
<g:DockLayoutPanel unit="PX" width="350px" height="75px" addStyleNames="{style.emptyBorder}">
|
||||
<g:north size="65.0">
|
||||
<g:DockLayoutPanel unit="PX" width="100%" height="100%" styleName="{style.spacing}">
|
||||
<g:north size="20.0">
|
||||
<g:Label text="{locale.configFileTitle}"/>
|
||||
</g:north>
|
||||
<g:center size="25.0">
|
||||
<g:FormPanel ui:field="uploadForm" debugId="import-from-config-uploadForm"/>
|
||||
</g:center>
|
||||
<g:south size="20.0">
|
||||
<g:Label ui:field="errorMessage" text="" styleName="{style.errorMsg}"/>
|
||||
</g:south>
|
||||
|
||||
</g:DockLayoutPanel>
|
||||
</g:north>
|
||||
</g:DockLayoutPanel>
|
||||
</ui:UiBinder>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue