parent
d39ca3e80b
commit
3da13d54b5
|
|
@ -17,6 +17,8 @@ maven-eclipse.xml
|
|||
*.iws
|
||||
.idea/
|
||||
|
||||
.vscode/
|
||||
|
||||
# Compiled source #
|
||||
###################
|
||||
!*.com/
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@
|
|||
<artifactId>assembly-ide-war</artifactId>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che</groupId>
|
||||
<artifactId>assembly-workspace-loader-war</artifactId>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che</groupId>
|
||||
<artifactId>assembly-wsagent-server</artifactId>
|
||||
|
|
|
|||
|
|
@ -55,6 +55,15 @@
|
|||
<include>org.eclipse.che.dashboard:che-dashboard-war</include>
|
||||
</includes>
|
||||
</dependencySet>
|
||||
<dependencySet>
|
||||
<useProjectArtifact>false</useProjectArtifact>
|
||||
<unpack>false</unpack>
|
||||
<outputDirectory>tomcat/webapps</outputDirectory>
|
||||
<outputFileNameMapping>workspace-loader.war</outputFileNameMapping>
|
||||
<includes>
|
||||
<include>org.eclipse.che:assembly-workspace-loader-war</include>
|
||||
</includes>
|
||||
</dependencySet>
|
||||
<dependencySet>
|
||||
<useProjectArtifact>false</useProjectArtifact>
|
||||
<unpack>false</unpack>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
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:
|
||||
Red Hat, Inc. - initial API and implementation
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>che-assembly-parent</artifactId>
|
||||
<groupId>org.eclipse.che</groupId>
|
||||
<version>6.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>assembly-workspace-loader-war</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>Che Workspace Loader :: War Packaging</name>
|
||||
<description>Packages Che Workspace Loader application as a Java web app</description>
|
||||
<inceptionYear>2018</inceptionYear>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.workspace.loader</groupId>
|
||||
<artifactId>che-workspace-loader</artifactId>
|
||||
<type>zip</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<configuration>
|
||||
<overlays>
|
||||
<overlay>
|
||||
<groupId>org.eclipse.che.workspace.loader</groupId>
|
||||
<artifactId>che-workspace-loader</artifactId>
|
||||
<type>zip</type>
|
||||
</overlay>
|
||||
</overlays>
|
||||
<packagingExcludes>/webapp/</packagingExcludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>analyze</id>
|
||||
<configuration>
|
||||
<ignoredUnusedDeclaredDependencies>
|
||||
<!-- dependency is required just to overlay it's content -->
|
||||
<dep>org.eclipse.che.workspace.loader:che-workspace-loader</dep>
|
||||
</ignoredUnusedDeclaredDependencies>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Defines a controller that is serving the index.html page of a workspace loader.
|
||||
*
|
||||
* @author Florent Benoit
|
||||
*/
|
||||
public class WSLoaderController extends HttpServlet {
|
||||
|
||||
/** Use the default dispatcher to serve the resource. */
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
RequestDispatcher dispatcher = request.getRequestDispatcher("/loader/index.html");
|
||||
dispatcher.forward(request, response);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
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:
|
||||
Red Hat, Inc. - initial API and implementation
|
||||
|
||||
-->
|
||||
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||
version="3.0"
|
||||
metadata-complete="true">
|
||||
<absolute-ordering></absolute-ordering>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>WSLoader</servlet-name>
|
||||
<servlet-class>org.eclipse.che.WSLoaderController</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>WSLoader</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>default</servlet-name>
|
||||
<url-pattern>/loader/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
</web-app>
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
<module>assembly-wsagent-server</module>
|
||||
<module>assembly-ide-war</module>
|
||||
<module>assembly-wsmaster-war</module>
|
||||
<module>assembly-workspace-loader-war</module>
|
||||
<module>assembly-main</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ var serverOptions = {
|
|||
|
||||
var options = minimist(process.argv.slice(2), serverOptions);
|
||||
|
||||
var patterns = ['/api', '/ext', '/ws', '/datasource', '/java-ca', '/im', '/che', '/admin'];
|
||||
var patterns = ['/api', '/ext', '/ws', '/datasource', '/java-ca', '/im', '/che', '/admin', '/workspace-loader'];
|
||||
|
||||
var proxies = [];
|
||||
|
||||
|
|
@ -36,6 +36,8 @@ patterns.forEach(function(pattern) {
|
|||
proxyOptions.route = '/admin';
|
||||
} else if (pattern === '/ext') {
|
||||
proxyOptions.route = '/ext';
|
||||
} else if (pattern === '/workspace-loader') {
|
||||
proxyOptions.route = '/workspace-loader';
|
||||
} else {
|
||||
proxyOptions.route = '/api';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,11 +141,11 @@ class IdeSvc {
|
|||
let inDevMode = this.userDashboardConfig.developmentMode;
|
||||
let randVal = Math.floor((Math.random() * 1000000) + 1);
|
||||
let appendUrl = '?uid=' + randVal;
|
||||
|
||||
let workspace = this.cheWorkspace.getWorkspaceById(workspaceId);
|
||||
this.openedWorkspace = workspace;
|
||||
|
||||
let ideUrlLink = workspace.links.ide;
|
||||
let workspaceLoaderUrl = this.cheWorkspace.getWorkspaceLoaderUrl(workspace.namespace, workspace.config.name);
|
||||
let ideUrlLink = workspaceLoaderUrl || workspace.links.ide;
|
||||
|
||||
if (this.ideAction != null) {
|
||||
appendUrl = appendUrl + '&action=' + this.ideAction;
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ export class CheOrganization implements che.api.ICheOrganization {
|
|||
return this.cheResourcesDistribution.fetchAvailableOrganizationResources(organization.id).then(() => {
|
||||
let resource = this.cheResourcesDistribution.getOrganizationAvailableResourceByType(organization.id, this.resourceLimits.RAM);
|
||||
if (resource.amount === -1) {
|
||||
return 'RAM is not limited'
|
||||
return 'RAM is not limited';
|
||||
}
|
||||
|
||||
return resource ? 'Available RAM: ' + (resource.amount / 1024) + 'GB' : null;
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ export class CheHttpBackend {
|
|||
this.$httpBackend.when('GET', '/api/').respond(200, {rootResources: []});
|
||||
|
||||
this.$httpBackend.when('GET', '/api/keycloak/settings').respond(404);
|
||||
this.$httpBackend.when('GET', '/workspace-loader/').respond(404);
|
||||
|
||||
// add the remote call
|
||||
let workspaceReturn = [];
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ export class CheWorkspace {
|
|||
private statusDefers: Object;
|
||||
private workspaceSettings: any;
|
||||
private jsonRpcApiLocation: string;
|
||||
private workspaceLoaderUrl: string;
|
||||
/**
|
||||
* Map with instance of Observable by workspaceId.
|
||||
*/
|
||||
|
|
@ -164,6 +165,8 @@ export class CheWorkspace {
|
|||
cheBranding.unregisterCallback(CONTEXT_FETCHER_ID);
|
||||
};
|
||||
cheBranding.registerCallback(CONTEXT_FETCHER_ID, callback.bind(this));
|
||||
|
||||
this.checkWorkspaceLoader(userDashboardConfig.developmentMode, proxySettings);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -648,6 +651,10 @@ export class CheWorkspace {
|
|||
return '/ide/' + namespace + '/' + workspaceName;
|
||||
}
|
||||
|
||||
getWorkspaceLoaderUrl(namespace: string, workspaceName: string): string {
|
||||
return this.workspaceLoaderUrl ? this.workspaceLoaderUrl + namespace + '/' + workspaceName : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates deferred object which will be resolved
|
||||
* when workspace change it's status to given
|
||||
|
|
@ -797,4 +804,17 @@ export class CheWorkspace {
|
|||
}
|
||||
return wsUrl;
|
||||
}
|
||||
|
||||
private checkWorkspaceLoader(devmode: boolean, proxySettings: string): void {
|
||||
let url = '/workspace-loader/';
|
||||
|
||||
let promise = this.$http.get(url);
|
||||
promise.then((response: {data: any}) => {
|
||||
this.workspaceLoaderUrl = devmode ? proxySettings + url : url;
|
||||
}, (error: any) => {
|
||||
if (error.status !== 304) {
|
||||
this.workspaceLoaderUrl = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@
|
|||
|
||||
script.onerror = script.onabort = function() {
|
||||
console.error("Cannot load " + script.src);
|
||||
Loader.startLoading();
|
||||
};
|
||||
|
||||
document.head.appendChild(script);
|
||||
|
|
@ -135,10 +136,14 @@
|
|||
* Show loader and load compilation-mapping.txt file to determine which IDE JavaScript file will be loaded
|
||||
*/
|
||||
this.startLoading = function() {
|
||||
setTimeout(function() {
|
||||
setTimeout(() => {
|
||||
document.getElementById("ide-loader").style.opacity = 1;
|
||||
}, 1);
|
||||
|
||||
setTimeout(() => {
|
||||
window.parent.postMessage("show-ide", "*");
|
||||
}, 250);
|
||||
|
||||
var msg = "Cannot load compilation mappings";
|
||||
|
||||
try {
|
||||
|
|
@ -362,9 +367,8 @@
|
|||
};
|
||||
};
|
||||
|
||||
setTimeout(function() {
|
||||
setTimeout(() => {
|
||||
Loader.loadKeycloakSettings();
|
||||
window.parent.postMessage("show-ide", "*");
|
||||
}, 1);
|
||||
|
||||
</script>
|
||||
|
|
|
|||
13
pom.xml
13
pom.xml
|
|
@ -36,6 +36,7 @@
|
|||
<module>ide/che-ide-full</module>
|
||||
<module>ide/che-ide-gwt-app</module>
|
||||
<module>dashboard</module>
|
||||
<module>workspace-loader</module>
|
||||
<module>assembly</module>
|
||||
<module>selenium</module>
|
||||
</modules>
|
||||
|
|
@ -89,6 +90,12 @@
|
|||
<artifactId>assembly-main</artifactId>
|
||||
<version>${che.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che</groupId>
|
||||
<artifactId>assembly-workspace-loader-war</artifactId>
|
||||
<version>${che.version}</version>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che</groupId>
|
||||
<artifactId>assembly-wsagent-server</artifactId>
|
||||
|
|
@ -1876,6 +1883,12 @@
|
|||
<artifactId>che-selenium-test</artifactId>
|
||||
<version>${che.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.workspace.loader</groupId>
|
||||
<artifactId>che-workspace-loader</artifactId>
|
||||
<version>${che.version}</version>
|
||||
<type>zip</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-commons-test</artifactId>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
Dockerfile
|
||||
node_modules
|
||||
target
|
||||
dist
|
||||
package-lock.json
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
node_modules/
|
||||
dist/
|
||||
package-lock.json
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# Copyright (c) 2018-2018 Red Hat, Inc
|
||||
# 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
|
||||
|
||||
# This is a Dockerfile allowing to build workspace loader by using a docker container.
|
||||
# Build step: $ docker build -t eclipse-che-workspace-loader .
|
||||
# It builds an archive file that can be used by doing later
|
||||
# $ docker run --rm eclipse-che-workspace-loader | tar -C target/ -zxf -
|
||||
FROM node:6.11.2
|
||||
|
||||
COPY package.json /workspace-loader/
|
||||
RUN cd /workspace-loader && npm install
|
||||
|
||||
COPY . /workspace-loader/
|
||||
|
||||
RUN cd /workspace-loader && \
|
||||
npm run build && \
|
||||
npm run test && \
|
||||
cd target && \
|
||||
tar zcf /tmp/workspace-loader.tar.gz dist
|
||||
|
||||
CMD zcat /tmp/workspace-loader.tar.gz
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<!--
|
||||
Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
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:
|
||||
Red Hat, Inc. - initial API and implementation
|
||||
-->
|
||||
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
|
||||
<id>workspace-loader-zip</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/target/dist</directory>
|
||||
<outputDirectory>/loader</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"name": "che-workspace-loader",
|
||||
"version": "1.0.0",
|
||||
"description": "Eclipse Che Workspace Loader App",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"build": "webpack --config webpack.prod.js",
|
||||
"start": "webpack-dev-server --open --config webpack.dev.js"
|
||||
},
|
||||
"author": "",
|
||||
"license": "EPL-1.0",
|
||||
"devDependencies": {
|
||||
"@types/jest": "^22.1.3",
|
||||
"clean-webpack-plugin": "^0.1.18",
|
||||
"css-loader": "^0.28.9",
|
||||
"extract-text-webpack-plugin": "^3.0.2",
|
||||
"html-webpack-plugin": "^2.30.1",
|
||||
"jest": "^22.4.2",
|
||||
"style-loader": "^0.20.1",
|
||||
"ts-loader": "^3.4.0",
|
||||
"typescript": "^2.7.1",
|
||||
"uglifyjs-webpack-plugin": "^1.1.8",
|
||||
"webpack": "^3.10.0",
|
||||
"webpack-dev-server": "^2.11.1",
|
||||
"webpack-merge": "^4.1.1"
|
||||
},
|
||||
"dependencies": {},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
"js"
|
||||
],
|
||||
"transform": {
|
||||
"^.+\\.(ts)$": "<rootDir>/test/preprocessor.js"
|
||||
},
|
||||
"moduleNameMapper": {
|
||||
"\\.(css|less)$": "<rootDir>/test/mock.js"
|
||||
},
|
||||
"testMatch": [
|
||||
"**/test/*.(ts)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
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:
|
||||
Red Hat, Inc. - initial API and implementation
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>che-parent</artifactId>
|
||||
<groupId>org.eclipse.che</groupId>
|
||||
<version>6.2.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>org.eclipse.che.workspace.loader</groupId>
|
||||
<artifactId>che-workspace-loader</artifactId>
|
||||
<version>6.2.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Che Workspace Loader :: Web App</name>
|
||||
<inceptionYear>2018</inceptionYear>
|
||||
<build>
|
||||
<finalName>workspace-loader</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<tarLongFileMode>posix</tarLongFileMode>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<updateOnly>false</updateOnly>
|
||||
<descriptors>
|
||||
<descriptor>${project.basedir}/assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
<finalName>workspace-loader</finalName>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<configuration>
|
||||
<filesets>
|
||||
<fileset>
|
||||
<directory>${basedir}/node_modules</directory>
|
||||
<followSymlinks>false</followSymlinks>
|
||||
</fileset>
|
||||
<fileset>
|
||||
<directory>${basedir}/dist</directory>
|
||||
<followSymlinks>false</followSymlinks>
|
||||
</fileset>
|
||||
<fileset>
|
||||
<directory>${basedir}</directory>
|
||||
<includes>
|
||||
<include>**/package-lock.json</include>
|
||||
</includes>
|
||||
<followSymlinks>false</followSymlinks>
|
||||
</fileset>
|
||||
</filesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<!-- Docker build used by default. To use native build, use -Pnative -->
|
||||
<id>docker</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>build-image</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<target>
|
||||
<!-- build workspace loader with maven in docker -->
|
||||
<exec dir="${basedir}" executable="docker" failonerror="true">
|
||||
<arg value="build" />
|
||||
<arg value="-t" />
|
||||
<arg value="eclipse-che-workspace-loader" />
|
||||
<arg value="." />
|
||||
</exec>
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>unpack-docker-build</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<target>
|
||||
<!-- extract built workspace loader -->
|
||||
<exec executable="bash">
|
||||
<arg value="-c" />
|
||||
<arg value="docker run --rm eclipse-che-workspace-loader | tar -C target/ -xf -" />
|
||||
</exec>
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>native</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>build-workspace-loader</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<target>
|
||||
<!-- install node modules -->
|
||||
<exec dir="${basedir}" executable="npm" failonerror="true">
|
||||
<arg value="install" />
|
||||
</exec>
|
||||
<!-- build workspace loader -->
|
||||
<exec dir="${basedir}" executable="npm" failonerror="true">
|
||||
<arg value="run" />
|
||||
<arg value="build" />
|
||||
</exec>
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-workspace-loader</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<target>
|
||||
<!-- test workspace loader -->
|
||||
<exec dir="${basedir}" executable="npm" failonerror="true">
|
||||
<arg value="run" />
|
||||
<arg value="test" />
|
||||
</exec>
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
declare module 'che' {
|
||||
export = che;
|
||||
}
|
||||
|
||||
declare function require(string: string): any;
|
||||
|
||||
declare namespace che {
|
||||
export interface IWorkspace {
|
||||
id?: string;
|
||||
projects?: any;
|
||||
links?: {
|
||||
ide?: string
|
||||
[rel: string]: string;
|
||||
};
|
||||
temporary?: boolean;
|
||||
status?: string;
|
||||
namespace?: string;
|
||||
attributes?: IWorkspaceAttributes;
|
||||
config: IWorkspaceConfig;
|
||||
runtime?: IWorkspaceRuntime;
|
||||
isLocked?: boolean;
|
||||
usedResources?: string;
|
||||
}
|
||||
|
||||
export interface IWorkspaceConfig {
|
||||
name?: string;
|
||||
defaultEnv?: string;
|
||||
environments: {
|
||||
[envName: string]: IWorkspaceEnvironment
|
||||
};
|
||||
projects?: Array<any>;
|
||||
commands?: Array<any>;
|
||||
}
|
||||
|
||||
export interface IWorkspaceEnvironment {
|
||||
machines: {
|
||||
[machineName: string]: IEnvironmentMachine
|
||||
};
|
||||
recipe: IRecipe;
|
||||
}
|
||||
|
||||
export interface IRecipe {
|
||||
id?: string;
|
||||
content?: string;
|
||||
location?: string;
|
||||
contentType?: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface IEnvironmentMachine {
|
||||
installers?: string[];
|
||||
attributes?: {
|
||||
memoryLimitBytes?: string | number;
|
||||
[attrName: string]: string | number;
|
||||
};
|
||||
servers?: {
|
||||
[serverRef: string]: IEnvironmentMachineServer
|
||||
};
|
||||
volumes?: {
|
||||
[volumeRef: string]: IEnvironmentMachineVolume
|
||||
};
|
||||
env?: { [envName: string]: string };
|
||||
}
|
||||
|
||||
export interface IEnvironmentMachineServer {
|
||||
port: string | number;
|
||||
protocol: string;
|
||||
path?: string;
|
||||
properties?: any;
|
||||
attributes?: {
|
||||
[attrName: string]: string | number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IEnvironmentMachineVolume {
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface IWorkspaceAttributes {
|
||||
created: number;
|
||||
updated?: number;
|
||||
stackId?: string;
|
||||
errorMessage?: string;
|
||||
[propName: string]: string | number;
|
||||
}
|
||||
|
||||
export interface IWorkspaceRuntime {
|
||||
activeEnv: string;
|
||||
links: any[];
|
||||
machines: {
|
||||
[machineName: string]: IWorkspaceRuntimeMachine
|
||||
};
|
||||
owner: string;
|
||||
warnings: IWorkspaceWarning[];
|
||||
}
|
||||
|
||||
export interface IWorkspaceWarning {
|
||||
code?: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface IWorkspaceRuntimeMachine {
|
||||
attributes: { [propName: string]: string };
|
||||
servers: { [serverName: string]: IWorkspaceRuntimeMachineServer };
|
||||
}
|
||||
|
||||
export interface IWorkspaceRuntimeMachineServer {
|
||||
status: string;
|
||||
port: string;
|
||||
url: string;
|
||||
ref: string;
|
||||
protocol: string;
|
||||
path: string;
|
||||
attributes: { [propName: string]: string };
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<!--
|
||||
|
||||
Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
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:
|
||||
Red Hat, Inc. - initial API and implementation
|
||||
|
||||
-->
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<% if(htmlWebpackPlugin.options.cssName) { %>
|
||||
<link href="<%= htmlWebpackPlugin.options.urlPrefix %><%= htmlWebpackPlugin.options.cssName %>" rel="stylesheet">
|
||||
<% } %>
|
||||
<script src="<%= htmlWebpackPlugin.options.urlPrefix %><%= htmlWebpackPlugin.files.js %>" type="text/javascript" async="true"></script>
|
||||
</head>
|
||||
|
||||
<body style="background-color: #21252b; transition: background-color 0.5s ease;">
|
||||
<div id="workspace-loader">
|
||||
<div id="workspace-loader-label">Loading...</div>
|
||||
<div id="workspace-loader-progress">
|
||||
<div>
|
||||
<div id="workspace-loader-progress-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="workspace-console">
|
||||
<div id="workspace-console-container"></div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
require('./style.css');
|
||||
|
||||
import { WebsocketClient } from './json-rpc/websocket-client';
|
||||
import { CheJsonRpcMasterApi } from './json-rpc/che-json-rpc-master-api';
|
||||
import { Loader } from './loader/loader'
|
||||
|
||||
const WEBSOCKET_CONTEXT = '/api/websocket';
|
||||
|
||||
export class WorkspaceLoader {
|
||||
|
||||
loader: Loader;
|
||||
workspace: che.IWorkspace;
|
||||
startAfterStopping = false;
|
||||
|
||||
constructor(loader: Loader) {
|
||||
this.loader = loader;
|
||||
|
||||
/** Ask dashboard to show the IDE. */
|
||||
window.parent.postMessage("show-ide", "*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the workspace.
|
||||
*/
|
||||
load(): Promise<void> {
|
||||
let workspaceKey = this.getWorkspaceKey();
|
||||
|
||||
if (!workspaceKey || workspaceKey === "") {
|
||||
console.error("Workspace is not defined");
|
||||
return;
|
||||
}
|
||||
|
||||
return this.getWorkspace(workspaceKey)
|
||||
.then((workspace) => {
|
||||
this.workspace = workspace;
|
||||
|
||||
if (this.hasPreconfiguredIDE()) {
|
||||
return this.handleWorkspace();
|
||||
} else {
|
||||
return new Promise<void>((resolve) => {
|
||||
this.openURL(workspace.links.ide + this.getQueryString());
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the workspace has preconfigured IDE.
|
||||
*/
|
||||
hasPreconfiguredIDE() : boolean {
|
||||
if (this.workspace.config.defaultEnv && this.workspace.config.environments) {
|
||||
let defaultEnvironment = this.workspace.config.defaultEnv;
|
||||
let environment = this.workspace.config.environments[defaultEnvironment];
|
||||
|
||||
let machines = environment.machines;
|
||||
for (let machineName in machines) {
|
||||
let servers = machines[machineName].servers;
|
||||
for (let serverName in servers) {
|
||||
let attributes = servers[serverName].attributes;
|
||||
if (attributes['type'] === 'ide') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns workspace key from current address or empty string when it is undefined.
|
||||
*/
|
||||
getWorkspaceKey(): string {
|
||||
let result: string = window.location.pathname.substr(1);
|
||||
return result.substr(result.indexOf('/') + 1, result.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns base websocket URL.
|
||||
*/
|
||||
websocketBaseURL(): string {
|
||||
let wsProtocol = 'http:' === document.location.protocol ? 'ws' : 'wss';
|
||||
return wsProtocol + '://' + document.location.host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns query string.
|
||||
*/
|
||||
getQueryString(): string {
|
||||
return location.search;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get workspace by ID.
|
||||
*
|
||||
* @param workspaceId workspace id
|
||||
*/
|
||||
getWorkspace(workspaceId: string): Promise<che.IWorkspace> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let request = new XMLHttpRequest();
|
||||
request.open("GET", '/api/workspace/' + workspaceId);
|
||||
request.send();
|
||||
request.onreadystatechange = function () {
|
||||
if (this.readyState !== 4) { return; }
|
||||
if (this.status !== 200) {
|
||||
reject(this.status ? this.statusText : "Unknown error");
|
||||
return;
|
||||
}
|
||||
resolve(JSON.parse(this.responseText));
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Start current workspace.
|
||||
*/
|
||||
startWorkspace(): Promise<che.IWorkspace> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let request = new XMLHttpRequest();
|
||||
request.open("POST", `/api/workspace/${this.workspace.id}/runtime`);
|
||||
request.send();
|
||||
request.onreadystatechange = function () {
|
||||
if (this.readyState !== 4) { return; }
|
||||
if (this.status !== 200) {
|
||||
reject(this.status ? this.statusText : "Unknown error");
|
||||
return;
|
||||
}
|
||||
resolve(JSON.parse(this.responseText));
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles workspace status.
|
||||
*/
|
||||
handleWorkspace(): Promise<void> {
|
||||
if (this.workspace.status === 'RUNNING') {
|
||||
this.openIDE();
|
||||
return;
|
||||
}
|
||||
|
||||
return this.subscribeWorkspaceEvents().then(() => {
|
||||
if (this.workspace.status === 'STOPPED') {
|
||||
this.startWorkspace();
|
||||
} else if (this.workspace.status === 'STOPPING') {
|
||||
this.startAfterStopping = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows environment outputs.
|
||||
*
|
||||
* @param message output message
|
||||
*/
|
||||
onEnvironmentOutput(message) : void {
|
||||
this.loader.log(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changing of workspace status.
|
||||
*
|
||||
* @param status workspace status
|
||||
*/
|
||||
onWorkspaceStatusChanged(status) : void {
|
||||
if (status === 'RUNNING') {
|
||||
this.openIDE();
|
||||
} else if (status === 'STOPPED' && this.startAfterStopping) {
|
||||
this.startWorkspace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to the workspace events.
|
||||
*/
|
||||
subscribeWorkspaceEvents() : Promise<void> {
|
||||
let master = new CheJsonRpcMasterApi(new WebsocketClient());
|
||||
return new Promise((resolve) => {
|
||||
master.connect(this.websocketBaseURL() + WEBSOCKET_CONTEXT).then(() => {
|
||||
master.subscribeEnvironmentOutput(this.workspace.id,
|
||||
(message: any) => this.onEnvironmentOutput(message.text));
|
||||
|
||||
master.subscribeWorkspaceStatus(this.workspace.id,
|
||||
(message: any) => this.onWorkspaceStatusChanged(message.status));
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens IDE for the workspace.
|
||||
*/
|
||||
openIDE() : void {
|
||||
this.getWorkspace(this.workspace.id).then((workspace) => {
|
||||
let machines = workspace.runtime.machines;
|
||||
for (let machineName in machines) {
|
||||
let servers = machines[machineName].servers;
|
||||
for (let serverId in servers) {
|
||||
let attributes = servers[serverId].attributes;
|
||||
if (attributes['type'] === 'ide') {
|
||||
this.openURL(servers[serverId].url);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.openURL(workspace.links.ide);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule opening URL.
|
||||
* Scheduling prevents appearing an error net::ERR_CONNECTION_REFUSED instead opening the URL.
|
||||
*
|
||||
* @param url url to be opened
|
||||
*/
|
||||
openURL(url) : void {
|
||||
// Preconfigured IDE may use dedicated port. In this case Chrome browser fails
|
||||
// with error net::ERR_CONNECTION_REFUSED. Timer helps to open the URL without errors.
|
||||
setTimeout(() => {
|
||||
window.location.href = url;
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** Initialize */
|
||||
if (document.getElementById('workspace-console')) {
|
||||
new WorkspaceLoader(new Loader()).load();
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
'use strict';
|
||||
import {ICommunicationClient, JsonRpcClient} from './json-rpc-client';
|
||||
|
||||
export class IChannel {
|
||||
subscription: string;
|
||||
unsubscription: string;
|
||||
notification: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for basic CHE API communication methods.
|
||||
*
|
||||
* @author Ann Shumilova
|
||||
*/
|
||||
export class CheJsonRpcApiClient {
|
||||
/**
|
||||
* Client that implements JSON RPC protocol.
|
||||
*/
|
||||
private jsonRpcClient: JsonRpcClient;
|
||||
/**
|
||||
* Communication client (can be http, websocket).
|
||||
*/
|
||||
private client: ICommunicationClient;
|
||||
|
||||
constructor (client: ICommunicationClient) {
|
||||
this.client = client;
|
||||
this.jsonRpcClient = new JsonRpcClient(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe on the events from service.
|
||||
*
|
||||
* @param event event's name to subscribe
|
||||
* @param notification notification name to handle
|
||||
* @param handler event's handler
|
||||
* @param params params (optional)
|
||||
*/
|
||||
subscribe(event: string, notification: string, handler: Function, params?: any): void {
|
||||
this.jsonRpcClient.addNotificationHandler(notification, handler);
|
||||
this.jsonRpcClient.notify(event, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe concrete handler from events from service.
|
||||
*
|
||||
* @param event event's name to unsubscribe
|
||||
* @param notification notification name binded to the event
|
||||
* @param handler handler to be removed
|
||||
* @param params params (optional)
|
||||
*/
|
||||
unsubscribe(event: string, notification: string, handler: Function, params?: any): void {
|
||||
this.jsonRpcClient.removeNotificationHandler(notification, handler);
|
||||
this.jsonRpcClient.notify(event, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the pointed entrypoint
|
||||
*
|
||||
* @param entrypoint entrypoint to connect to
|
||||
* @returns {Promise<any>} promise
|
||||
*/
|
||||
connect(entrypoint: string): Promise<any> {
|
||||
return this.client.connect(entrypoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes request.
|
||||
*
|
||||
* @param method
|
||||
* @param params
|
||||
* @returns {ng.IPromise<any>}
|
||||
*/
|
||||
request(method: string, params?: any): Promise<any> {
|
||||
return this.jsonRpcClient.request(method, params);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
'use strict';
|
||||
import {CheJsonRpcApiClient} from './che-json-rpc-api-service';
|
||||
import {ICommunicationClient} from './json-rpc-client';
|
||||
|
||||
enum MasterChannels {
|
||||
ENVIRONMENT_OUTPUT = <any>'machine/log',
|
||||
ENVIRONMENT_STATUS = <any>'machine/statusChanged',
|
||||
WS_AGENT_OUTPUT = <any>'installer/log',
|
||||
WORKSPACE_STATUS = <any>'workspace/statusChanged'
|
||||
}
|
||||
const SUBSCRIBE: string = 'subscribe';
|
||||
const UNSUBSCRIBE: string = 'unsubscribe';
|
||||
|
||||
/**
|
||||
* Client API for workspace master interactions.
|
||||
*
|
||||
* @author Ann Shumilova
|
||||
*/
|
||||
export class CheJsonRpcMasterApi {
|
||||
private cheJsonRpcApi: CheJsonRpcApiClient;
|
||||
private clientId: string;
|
||||
|
||||
constructor (client: ICommunicationClient) {
|
||||
this.cheJsonRpcApi = new CheJsonRpcApiClient(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens connection to pointed entrypoint.
|
||||
*
|
||||
* @param entrypoint
|
||||
* @returns {IPromise<IHttpPromiseCallbackArg<any>>}
|
||||
*/
|
||||
connect(entrypoint: string): Promise<any> {
|
||||
return this.cheJsonRpcApi.connect(entrypoint).then(() => {
|
||||
return this.fetchClientId();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes the environment output.
|
||||
*
|
||||
* @param workspaceId workspace's id
|
||||
* @param machineName machine's name
|
||||
* @param callback callback to process event
|
||||
*/
|
||||
subscribeEnvironmentOutput(workspaceId: string, callback: Function): void {
|
||||
this.subscribe(MasterChannels.ENVIRONMENT_OUTPUT, workspaceId, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-subscribes the pointed callback from the environment output.
|
||||
*
|
||||
* @param workspaceId workspace's id
|
||||
* @param machineName machine's name
|
||||
* @param callback callback to process event
|
||||
*/
|
||||
unSubscribeEnvironmentOutput(workspaceId: string, callback: Function): void {
|
||||
this.unsubscribe(MasterChannels.ENVIRONMENT_OUTPUT, workspaceId, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes the environment status changed.
|
||||
*
|
||||
* @param workspaceId workspace's id
|
||||
* @param callback callback to process event
|
||||
*/
|
||||
subscribeEnvironmentStatus(workspaceId: string, callback: Function): void {
|
||||
this.subscribe(MasterChannels.ENVIRONMENT_STATUS, workspaceId, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-subscribes the pointed callback from environment status changed.
|
||||
*
|
||||
* @param workspaceId workspace's id
|
||||
* @param callback callback to process event
|
||||
*/
|
||||
unSubscribeEnvironmentStatus(workspaceId: string, callback: Function): void {
|
||||
this.unsubscribe(MasterChannels.ENVIRONMENT_STATUS, workspaceId, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes on workspace agent output.
|
||||
*
|
||||
* @param workspaceId workspace's id
|
||||
* @param callback callback to process event
|
||||
*/
|
||||
subscribeWsAgentOutput(workspaceId: string, callback: Function): void {
|
||||
this.subscribe(MasterChannels.WS_AGENT_OUTPUT, workspaceId, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-subscribes from workspace agent output.
|
||||
*
|
||||
* @param workspaceId workspace's id
|
||||
* @param callback callback to process event
|
||||
*/
|
||||
unSubscribeWsAgentOutput(workspaceId: string, callback: Function): void {
|
||||
this.unsubscribe(MasterChannels.WS_AGENT_OUTPUT, workspaceId, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to workspace's status.
|
||||
*
|
||||
* @param workspaceId workspace's id
|
||||
* @param callback callback to process event
|
||||
*/
|
||||
subscribeWorkspaceStatus(workspaceId: string, callback: Function): void {
|
||||
let statusHandler = (message: any) => {
|
||||
if (workspaceId === message.workspaceId) {
|
||||
callback(message);
|
||||
}
|
||||
};
|
||||
this.subscribe(MasterChannels.WORKSPACE_STATUS, workspaceId, statusHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-subscribes pointed callback from workspace's status.
|
||||
*
|
||||
* @param workspaceId
|
||||
* @param callback
|
||||
*/
|
||||
unSubscribeWorkspaceStatus(workspaceId: string, callback: Function): void {
|
||||
this.unsubscribe(MasterChannels.WORKSPACE_STATUS, workspaceId, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch client's id and strores it.
|
||||
*
|
||||
* @returns {IPromise<TResult>}
|
||||
*/
|
||||
fetchClientId(): Promise<any> {
|
||||
return this.cheJsonRpcApi.request('websocketIdService/getId').then((data: any) => {
|
||||
this.clientId = data[0];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns client's id.
|
||||
*
|
||||
* @returns {string} clinet connection identifier
|
||||
*/
|
||||
getClientId(): string {
|
||||
return this.clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs subscribe to the pointed channel for pointed workspace's ID and callback.
|
||||
*
|
||||
* @param channel channel to un-subscribe
|
||||
* @param workspaceId workspace's id
|
||||
* @param callback callback
|
||||
*/
|
||||
private subscribe(channel: MasterChannels, workspaceId: string, callback: Function): void {
|
||||
let method: string = channel.toString();
|
||||
let params = {method: method, scope: {workspaceId: workspaceId}};
|
||||
this.cheJsonRpcApi.subscribe(SUBSCRIBE, method, callback, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs un-subscribe of the pointed channel by pointed workspace's ID and callback.
|
||||
*
|
||||
* @param channel channel to un-subscribe
|
||||
* @param workspaceId workspace's id
|
||||
* @param callback callback
|
||||
*/
|
||||
private unsubscribe(channel: MasterChannels, workspaceId: string, callback: Function): void {
|
||||
let method: string = channel.toString();
|
||||
let params = {method: method, scope: {workspaceId: workspaceId}};
|
||||
this.cheJsonRpcApi.unsubscribe(UNSUBSCRIBE, method, callback, params);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
'use strict';
|
||||
import { IDeffered, Deffered } from './util';
|
||||
const JSON_RPC_VERSION: string = '2.0';
|
||||
|
||||
/**
|
||||
* Interface for communication between two entrypoints.
|
||||
* The implementation can be through websocket or http protocol.
|
||||
*/
|
||||
export interface ICommunicationClient {
|
||||
/**
|
||||
* Process responses.
|
||||
*/
|
||||
onResponse: Function;
|
||||
/**
|
||||
* Performs connections.
|
||||
*
|
||||
* @param entrypoint
|
||||
*/
|
||||
connect(entrypoint: string): Promise<any>;
|
||||
/**
|
||||
* Close the connection.
|
||||
*/
|
||||
disconnect(): void;
|
||||
/**
|
||||
* Send pointed data.
|
||||
*
|
||||
* @param data data to be sent
|
||||
*/
|
||||
send(data: any): void;
|
||||
}
|
||||
|
||||
interface IRequest {
|
||||
jsonrpc: string;
|
||||
id: string;
|
||||
method: string;
|
||||
params: any;
|
||||
}
|
||||
|
||||
interface INotification {
|
||||
jsonrpc: string;
|
||||
method: string;
|
||||
params: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* This client is handling the JSON RPC requests, responses and notifications.
|
||||
*
|
||||
* @author Ann Shumilova
|
||||
*/
|
||||
export class JsonRpcClient {
|
||||
/**
|
||||
* Client for performing communications.
|
||||
*/
|
||||
private client: ICommunicationClient;
|
||||
/**
|
||||
* The list of the pending requests by request id.
|
||||
*/
|
||||
private pendingRequests: Map<string, IDeffered<any>>;
|
||||
/**
|
||||
* The list of notification handlers by method name.
|
||||
*/
|
||||
private notificationHandlers: Map<string, Array<Function>>;
|
||||
private counter: number = 100;
|
||||
|
||||
constructor(client: ICommunicationClient) {
|
||||
this.client = client;
|
||||
this.pendingRequests = new Map<string, IDeffered<any>>();
|
||||
this.notificationHandlers = new Map<string, Array<Function>>();
|
||||
|
||||
this.client.onResponse = (message: any): void => {
|
||||
this.processResponse(message);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs JSON RPC request.
|
||||
*
|
||||
* @param method method's name
|
||||
* @param params params
|
||||
* @returns {IPromise<any>}
|
||||
*/
|
||||
request(method: string, params?: any): Promise<any> {
|
||||
let deferred = new Deffered();
|
||||
let id: string = (this.counter++).toString();
|
||||
this.pendingRequests.set(id, deferred);
|
||||
|
||||
let request: IRequest = {
|
||||
jsonrpc: JSON_RPC_VERSION,
|
||||
id: id,
|
||||
method: method,
|
||||
params: params
|
||||
};
|
||||
|
||||
this.client.send(request);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends JSON RPC notification.
|
||||
*
|
||||
* @param method method's name
|
||||
* @param params params (optional)
|
||||
*/
|
||||
notify(method: string, params?: any): void {
|
||||
let request: INotification = {
|
||||
jsonrpc: JSON_RPC_VERSION,
|
||||
method: method,
|
||||
params: params
|
||||
};
|
||||
|
||||
this.client.send(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds notification handler.
|
||||
*
|
||||
* @param method method's name
|
||||
* @param handler handler to process notification
|
||||
*/
|
||||
public addNotificationHandler(method: string, handler: Function): void {
|
||||
let handlers = this.notificationHandlers.get(method);
|
||||
|
||||
if (handlers) {
|
||||
handlers.push(handler);
|
||||
} else {
|
||||
handlers = [handler];
|
||||
this.notificationHandlers.set(method, handlers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes notification handler.
|
||||
*
|
||||
* @param method method's name
|
||||
* @param handler handler
|
||||
*/
|
||||
public removeNotificationHandler(method: string, handler: Function): void {
|
||||
let handlers = this.notificationHandlers.get(method);
|
||||
|
||||
if (handlers) {
|
||||
handlers.splice(handlers.indexOf(handler), 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes response - detects whether it is JSON RPC response or notification.
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
private processResponse(message: any): void {
|
||||
if (message.id && this.pendingRequests.has(message.id)) {
|
||||
this.processResponseMessage(message);
|
||||
} else {
|
||||
this.processNotification(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes JSON RPC notification.
|
||||
*
|
||||
* @param message message
|
||||
*/
|
||||
private processNotification(message: any): void {
|
||||
let method = message.method;
|
||||
let handlers = this.notificationHandlers.get(method);
|
||||
if (handlers && handlers.length > 0) {
|
||||
handlers.forEach((handler: Function) => {
|
||||
handler(message.params);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process JSON RPC response.
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
private processResponseMessage(message: any): void {
|
||||
let promise = this.pendingRequests.get(message.id);
|
||||
if (message.result) {
|
||||
promise.resolve(message.result);
|
||||
return;
|
||||
}
|
||||
if (message.error) {
|
||||
promise.reject(message.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
export interface IDeffered<T> {
|
||||
resolve(value?: T): void;
|
||||
reject(reason?: any): void;
|
||||
promise: Promise<T>;
|
||||
}
|
||||
|
||||
export class Deffered<T> implements IDeffered<T> {
|
||||
|
||||
promise: Promise<T>;
|
||||
private resolveF;
|
||||
private rejectF;
|
||||
constructor() {
|
||||
this.promise = new Promise((resolve, reject) => {
|
||||
this.resolve = resolve;
|
||||
this.reject = reject;
|
||||
});
|
||||
}
|
||||
resolve(value?: T): void {
|
||||
this.resolveF(value);
|
||||
}
|
||||
reject(reason?: any): void {
|
||||
this.rejectF(reason);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
'use strict';
|
||||
import { ICommunicationClient } from './json-rpc-client';
|
||||
|
||||
/**
|
||||
* The implementation for JSON RPC protocol communication through websocket.
|
||||
*
|
||||
* @author Ann Shumilova
|
||||
*/
|
||||
export class WebsocketClient implements ICommunicationClient {
|
||||
onResponse: Function;
|
||||
private websocketStream: WebSocket;
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs connection to the pointed entrypoint.
|
||||
*
|
||||
* @param entrypoint the entrypoint to connect to
|
||||
*/
|
||||
connect(entrypoint: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.websocketStream = new WebSocket(entrypoint);
|
||||
this.websocketStream.addEventListener("open", () => {
|
||||
resolve();
|
||||
});
|
||||
|
||||
this.websocketStream.addEventListener("error", () => {
|
||||
reject();
|
||||
});
|
||||
this.websocketStream.addEventListener("message", (message) => {
|
||||
let data = JSON.parse(message.data);
|
||||
this.onResponse(data);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs closing the connection.
|
||||
*/
|
||||
disconnect(): void {
|
||||
if (this.websocketStream) {
|
||||
this.websocketStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends pointed data.
|
||||
*
|
||||
* @param data to be sent
|
||||
*/
|
||||
send(data: any): void {
|
||||
this.websocketStream.send(JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
export class Loader {
|
||||
|
||||
/**
|
||||
* Initializes the Loader.
|
||||
*/
|
||||
constructor() {
|
||||
/** Show the loader */
|
||||
setTimeout(() => {
|
||||
document.getElementById('workspace-loader').style.display = "block";
|
||||
setTimeout(() => {
|
||||
document.getElementById('workspace-loader').style.opacity = "1";
|
||||
}, 1);
|
||||
}, 1);
|
||||
|
||||
/** Add click handler to maximize output */
|
||||
document.getElementById('workspace-console').onclick = () => this.onclick();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a message to output console.
|
||||
*
|
||||
* @param message message to log
|
||||
*/
|
||||
log(message: string): void {
|
||||
let element = document.createElement("pre");
|
||||
element.innerHTML = message;
|
||||
document.getElementById("workspace-console-container").appendChild(element);
|
||||
element.scrollIntoView();
|
||||
}
|
||||
|
||||
onclick(): void {
|
||||
if (document.getElementById('workspace-loader').hasAttribute("max")) {
|
||||
document.getElementById('workspace-loader').removeAttribute("max");
|
||||
document.getElementById('workspace-console').removeAttribute("max");
|
||||
} else {
|
||||
document.getElementById('workspace-loader').setAttribute("max", "");
|
||||
document.getElementById('workspace-console').setAttribute("max", "");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
/**
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
|
||||
#workspace-loader {
|
||||
position: fixed;
|
||||
width: 300px;
|
||||
height: 45px;
|
||||
left: 50%;
|
||||
top: 30%;
|
||||
margin-left: -150px;
|
||||
opacity: 0;
|
||||
display: none;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
#workspace-loader-label {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
width: 300px;
|
||||
height: 30px;
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
color: #a0a9b7;
|
||||
}
|
||||
|
||||
#workspace-loader-progress {
|
||||
position: absolute;
|
||||
width: 300px;
|
||||
height: 15px;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
background-color: #202325;
|
||||
border: 1px solid #456594;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#workspace-loader-progress>div {
|
||||
position: absolute;
|
||||
left: 1px;
|
||||
right: 1px;
|
||||
top: 1px;
|
||||
bottom: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#workspace-loader-progress-bar {
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
background-color: #498fe1;
|
||||
transition: all 0.2s linear;
|
||||
animation-name: dancing;
|
||||
animation-duration: 3s;
|
||||
animation-delay: 1s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
#workspace-console {
|
||||
position: fixed;
|
||||
left: 30px;
|
||||
right: 30px;
|
||||
bottom: 25px;
|
||||
height: 30%;
|
||||
background-color: transparent;
|
||||
overflow: auto;
|
||||
color: #e6e6e6;
|
||||
left: 2px;
|
||||
right: 2px;
|
||||
bottom: 2px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
#workspace-console>div {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#workspace-console pre {
|
||||
font-family: "Droid Sans Mono", monospace;
|
||||
font-size: 9pt;
|
||||
line-height: 13px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
cursor: text;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#workspace-loader[max] {
|
||||
top: 5%;
|
||||
}
|
||||
|
||||
#workspace-console[max] {
|
||||
height: calc(100% - 110px);
|
||||
}
|
||||
|
||||
@-webkit-keyframes dancing {
|
||||
0% {
|
||||
width: 0%;
|
||||
margin-left: 0%;
|
||||
}
|
||||
30% {
|
||||
width: 30%;
|
||||
margin-left: 0%;
|
||||
}
|
||||
70% {
|
||||
width: 30%;
|
||||
margin-left: 70%;
|
||||
}
|
||||
100% {
|
||||
width: 0%;
|
||||
margin-left: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dancing {
|
||||
0% {
|
||||
width: 0%;
|
||||
margin-left: 0%;
|
||||
}
|
||||
6% {
|
||||
width: 30%;
|
||||
margin-left: 0%;
|
||||
}
|
||||
14% {
|
||||
width: 30%;
|
||||
margin-left: 70%;
|
||||
}
|
||||
20% {
|
||||
width: 0%;
|
||||
margin-left: 100%;
|
||||
}
|
||||
100% {
|
||||
width: 0%;
|
||||
margin-left: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************
|
||||
*
|
||||
* Styled scroll bars
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-corner {
|
||||
background-color: transparent;
|
||||
display: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track, ::-webkit-scrollbar-track:hover, ::-webkit-scrollbar-track:active {
|
||||
background-color: transparent;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-clip: padding-box;
|
||||
background-color: rgba(215, 215, 215, 0.10);
|
||||
;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 0 2px rgba(235, 235, 235, 0.3);
|
||||
box-shadow: inset 0 0 2px rgba(235, 235, 235, 0.3);
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: rgba(215, 215, 215, 0.3);
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
module.exports = {};
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
|
||||
const compiler = require('typescript');
|
||||
|
||||
module.exports = {
|
||||
process(source, path) {
|
||||
return compiler.transpile(source, {}, path, []);
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
|
||||
/// <reference path="../src/custom.d.ts" />
|
||||
|
||||
'use strict';
|
||||
|
||||
import {WorkspaceLoader} from '../src/index';
|
||||
import { Loader } from '../src/loader/loader';
|
||||
|
||||
describe('Workspace Loader', () => {
|
||||
|
||||
let fakeWorkspaceConfig: che.IWorkspace;
|
||||
|
||||
beforeEach(function() {
|
||||
document.body.innerHTML = `<div id="workspace-loader">
|
||||
<div id="workspace-loader-label">Loading...</div>
|
||||
<div id="workspace-loader-progress">
|
||||
<div>
|
||||
<div id="workspace-loader-progress-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="workspace-console">
|
||||
<div id="workspace-console-container"></div>
|
||||
</div>`;
|
||||
|
||||
fakeWorkspaceConfig = {
|
||||
status: 'STOPPED',
|
||||
links: {
|
||||
ide: "test url"
|
||||
},
|
||||
config: {
|
||||
defaultEnv: "default",
|
||||
"environments": {
|
||||
"default": {
|
||||
machines: {
|
||||
machine: {
|
||||
servers: {
|
||||
server1: {
|
||||
attributes: {
|
||||
type: "ide"
|
||||
},
|
||||
port: 0,
|
||||
protocol: ""
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
recipe: {
|
||||
type: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} as che.IWorkspace;
|
||||
});
|
||||
|
||||
it('must have "workspace-loader" in DOM', () => {
|
||||
const loader = document.getElementById('workspace-loader');
|
||||
expect(loader).toBeTruthy();
|
||||
});
|
||||
|
||||
it('test when workspace key is not specified', () => {
|
||||
let loader = new Loader();
|
||||
let workspaceLoader = new WorkspaceLoader(loader);
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspaceKey');
|
||||
spyOn(workspaceLoader, 'getWorkspace');
|
||||
|
||||
workspaceLoader.load();
|
||||
|
||||
expect(workspaceLoader.getWorkspaceKey).toHaveBeenCalled();
|
||||
expect(workspaceLoader.getWorkspace).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('test getWorkspace with test value', () => {
|
||||
let loader = new Loader();
|
||||
let workspaceLoader = new WorkspaceLoader(loader);
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspaceKey').and.returnValue("foo/bar");
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspace').and.callFake(() => {
|
||||
return new Promise((resolve) => {
|
||||
resolve(fakeWorkspaceConfig);
|
||||
});
|
||||
});
|
||||
|
||||
workspaceLoader.load();
|
||||
|
||||
expect(workspaceLoader.getWorkspaceKey).toHaveBeenCalled();
|
||||
expect(workspaceLoader.getWorkspace).toHaveBeenCalledWith("foo/bar");
|
||||
});
|
||||
|
||||
describe('must open IDE directly when workspace does not have IDE server', () => {
|
||||
let workspaceLoader;
|
||||
|
||||
beforeEach((done) => {
|
||||
let loader = new Loader();
|
||||
workspaceLoader = new WorkspaceLoader(loader);
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspaceKey').and.returnValue("foo/bar");
|
||||
spyOn(workspaceLoader, 'getQueryString').and.returnValue("");
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspace').and.callFake(() => {
|
||||
return new Promise((resolve) => {
|
||||
fakeWorkspaceConfig.config.environments["default"].machines = {};
|
||||
resolve(fakeWorkspaceConfig);
|
||||
});
|
||||
});
|
||||
|
||||
spyOn(workspaceLoader, "handleWorkspace");
|
||||
|
||||
spyOn(workspaceLoader, "openURL").and.callFake(() => {
|
||||
done();
|
||||
});
|
||||
|
||||
workspaceLoader.load();
|
||||
});
|
||||
|
||||
it('basic workspace function must be called', () => {
|
||||
expect(workspaceLoader.getWorkspaceKey).toHaveBeenCalled();
|
||||
expect(workspaceLoader.getWorkspace).toHaveBeenCalledWith("foo/bar");
|
||||
});
|
||||
|
||||
it('handleWorkspace must not be called', () => {
|
||||
expect(workspaceLoader.handleWorkspace).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('must open IDE with `test url`', () => {
|
||||
expect(workspaceLoader.openURL).toHaveBeenCalledWith("test url");
|
||||
});
|
||||
});
|
||||
|
||||
describe('must open default IDE with query parameters when workspace does not have IDE server', () => {
|
||||
let workspaceLoader;
|
||||
|
||||
beforeEach((done) => {
|
||||
let loader = new Loader();
|
||||
workspaceLoader = new WorkspaceLoader(loader);
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspaceKey').and.returnValue("foo/bar");
|
||||
spyOn(workspaceLoader, 'getQueryString').and.returnValue("?param=value");
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspace').and.callFake(() => {
|
||||
return new Promise((resolve) => {
|
||||
fakeWorkspaceConfig.config.environments["default"].machines = {};
|
||||
resolve(fakeWorkspaceConfig);
|
||||
});
|
||||
});
|
||||
|
||||
spyOn(workspaceLoader, "handleWorkspace");
|
||||
|
||||
spyOn(workspaceLoader, "openURL").and.callFake(() => {
|
||||
done();
|
||||
});
|
||||
|
||||
workspaceLoader.load();
|
||||
});
|
||||
|
||||
it('must open IDE with `test url` and query param `param=value`', () => {
|
||||
expect(workspaceLoader.openURL).toHaveBeenCalledWith("test url?param=value");
|
||||
});
|
||||
});
|
||||
|
||||
describe('must handle workspace when it has IDE server', () => {
|
||||
let workspaceLoader;
|
||||
|
||||
beforeEach((done) => {
|
||||
let loader = new Loader();
|
||||
workspaceLoader = new WorkspaceLoader(loader);
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspaceKey').and.returnValue("foo/bar");
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspace').and.callFake(() => {
|
||||
return new Promise((resolve) => {
|
||||
resolve(fakeWorkspaceConfig);
|
||||
});
|
||||
});
|
||||
|
||||
spyOn(workspaceLoader, "handleWorkspace").and.callFake(() => {
|
||||
done();
|
||||
});
|
||||
|
||||
workspaceLoader.load();
|
||||
});
|
||||
|
||||
it('basic workspace function must be called', () => {
|
||||
expect(workspaceLoader.getWorkspaceKey).toHaveBeenCalled();
|
||||
expect(workspaceLoader.getWorkspace).toHaveBeenCalledWith("foo/bar");
|
||||
});
|
||||
|
||||
it('must be called', () => {
|
||||
expect(workspaceLoader.handleWorkspace).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('must open IDE for RUNNING workspace', () => {
|
||||
let workspaceLoader;
|
||||
|
||||
beforeEach((done) => {
|
||||
let loader = new Loader();
|
||||
workspaceLoader = new WorkspaceLoader(loader);
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspaceKey').and.returnValue("foo/bar");
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspace').and.callFake(() => {
|
||||
return new Promise((resolve) => {
|
||||
fakeWorkspaceConfig.status = 'RUNNING';
|
||||
resolve(fakeWorkspaceConfig);
|
||||
});
|
||||
});
|
||||
|
||||
spyOn(workspaceLoader, "subscribeWorkspaceEvents");
|
||||
|
||||
spyOn(workspaceLoader, "openIDE").and.callFake(() => {
|
||||
done();
|
||||
});
|
||||
|
||||
workspaceLoader.load();
|
||||
});
|
||||
|
||||
it('must not subscribe to events', () => {
|
||||
expect(workspaceLoader.subscribeWorkspaceEvents).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('must open IDE immediately', () => {
|
||||
expect(workspaceLoader.openIDE).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('> must start STOPPED workspace', () => {
|
||||
let workspaceLoader;
|
||||
|
||||
beforeEach((done) => {
|
||||
let loader = new Loader();
|
||||
workspaceLoader = new WorkspaceLoader(loader);
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspaceKey').and.returnValue("foo/bar");
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspace').and.callFake(() => {
|
||||
return new Promise((resolve) => {
|
||||
fakeWorkspaceConfig.status = 'STOPPED';
|
||||
resolve(fakeWorkspaceConfig);
|
||||
});
|
||||
});
|
||||
|
||||
spyOn(workspaceLoader, "subscribeWorkspaceEvents").and.callFake(() => {
|
||||
return new Promise((resolve) => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
spyOn(workspaceLoader, "startWorkspace").and.callFake(() => {
|
||||
done();
|
||||
});
|
||||
|
||||
spyOn(workspaceLoader, "openIDE");
|
||||
|
||||
workspaceLoader.load();
|
||||
});
|
||||
|
||||
it('openIDE must not be called if status is STOPPED', () => {
|
||||
expect(workspaceLoader.openIDE).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('must subscribe to events', () => {
|
||||
expect(workspaceLoader.subscribeWorkspaceEvents).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('must start the workspace', () => {
|
||||
expect(workspaceLoader.startWorkspace).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('openIDE must be called when workspace become RUNNING', () => {
|
||||
workspaceLoader.onWorkspaceStatusChanged("RUNNING");
|
||||
expect(workspaceLoader.openIDE).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('must restart STOPPING workspace', () => {
|
||||
let workspaceLoader;
|
||||
|
||||
beforeEach((done) => {
|
||||
let loader = new Loader();
|
||||
workspaceLoader = new WorkspaceLoader(loader);
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspaceKey').and.returnValue("foo/bar");
|
||||
|
||||
spyOn(workspaceLoader, 'getWorkspace').and.callFake(() => {
|
||||
return new Promise((resolve) => {
|
||||
fakeWorkspaceConfig.status = 'STOPPING';
|
||||
resolve(fakeWorkspaceConfig);
|
||||
});
|
||||
});
|
||||
|
||||
spyOn(workspaceLoader, "subscribeWorkspaceEvents").and.callFake(() => {
|
||||
return new Promise((resolve) => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
spyOn(workspaceLoader, "startWorkspace");
|
||||
spyOn(workspaceLoader, "openIDE");
|
||||
|
||||
workspaceLoader.load().then(() => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('must start the workspace after stopping', () => {
|
||||
expect(workspaceLoader.startAfterStopping).toEqual(true);
|
||||
});
|
||||
|
||||
|
||||
it('must start workspace when workspace status become STOPPED', () => {
|
||||
workspaceLoader.onWorkspaceStatusChanged("STOPPED");
|
||||
expect(workspaceLoader.startWorkspace).toHaveBeenCalled();
|
||||
expect(workspaceLoader.openIDE).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('must open IDE when workspace become RUNNING', () => {
|
||||
workspaceLoader.onWorkspaceStatusChanged("RUNNING");
|
||||
expect(workspaceLoader.openIDE).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"lib": ["dom","es6"],
|
||||
"sourceMap": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
{
|
||||
"defaultSeverity": "error",
|
||||
"rules": {
|
||||
"file-header": [
|
||||
true,
|
||||
"[\n\r]+ \\* Copyright \\(c\\) \\d{4}(-\\d{4})? .*[\n\r]+"
|
||||
],
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
true,
|
||||
"check-space"
|
||||
],
|
||||
"curly": true,
|
||||
"eofline": true,
|
||||
"forin": true,
|
||||
"indent": [
|
||||
true,
|
||||
"spaces"
|
||||
],
|
||||
"max-line-length": [
|
||||
true,
|
||||
180
|
||||
],
|
||||
"no-consecutive-blank-lines": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-var-keyword": true,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-whitespace"
|
||||
],
|
||||
"radix": true,
|
||||
"semicolon": [
|
||||
true,
|
||||
"always",
|
||||
"ignore-interfaces"
|
||||
],
|
||||
"trailing-comma": [
|
||||
false
|
||||
],
|
||||
"triple-equals": [
|
||||
true,
|
||||
"allow-null-check"
|
||||
],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"variable-name": false,
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
const path = require('path');
|
||||
const CleanWebpackPlugin = require('clean-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
entry: './src/index.ts',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/
|
||||
},
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.js']
|
||||
},
|
||||
output: {
|
||||
filename: 'bundle.js',
|
||||
path: path.resolve(__dirname, 'target/dist')
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
const merge = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
module.exports = merge(common, {
|
||||
devtool: 'inline-source-map',
|
||||
module:{
|
||||
rules:[
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [{
|
||||
loader: "style-loader" // creates style nodes from JS strings
|
||||
}, {
|
||||
loader: "css-loader" // translates CSS into CommonJS
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
devServer: {
|
||||
contentBase: './dist',
|
||||
port: 3000,
|
||||
index: 'index.html',
|
||||
historyApiFallback: true,
|
||||
proxy: {
|
||||
'/api/websocket': {
|
||||
target: 'http://localhost:8080',
|
||||
ws: true,
|
||||
},
|
||||
'/api/workspace': "http://localhost:8080",
|
||||
}
|
||||
},
|
||||
plugins:[
|
||||
new HtmlWebpackPlugin({
|
||||
inject: false,
|
||||
title: "Che Workspace Loader",
|
||||
template:"src/index.html",
|
||||
urlPrefix:"/"
|
||||
})
|
||||
]
|
||||
});
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2018-2018 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
const merge = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||
|
||||
module.exports = merge(common, {
|
||||
devtool: 'source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ExtractTextPlugin.extract({
|
||||
fallback: "style-loader",
|
||||
use: "css-loader"
|
||||
})
|
||||
}
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new UglifyJSPlugin({
|
||||
sourceMap: true
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: false,
|
||||
template: 'src/index.html',
|
||||
title: 'Che Workspace Loader',
|
||||
urlPrefix: '/workspace-loader/loader/',
|
||||
cssName: 'style.css'
|
||||
}),
|
||||
new ExtractTextPlugin('style.css')
|
||||
]
|
||||
});
|
||||
Loading…
Reference in New Issue