Commit 44a26e8b authored by qhoangxuan's avatar qhoangxuan

wp4 - removed zoe_fe

parent c0841132
Deploying the Angular FrontEnd
==============================
Overview
--------
* The zoe angular frontend can be found in the ``zoe_fe`` folder.
Installation
------------
Installation can be done in two different ways. Both require installation of a few packages, which are listed in ``package.json``. All dependencies can be installed simply by running ``npm install`` from within the ``zoe_fe`` folder.
1. Development Server
* The first way to install the frontend is to install a local development server; this server will automatically reload when source files are changed. This can be done by the following two steps:
* Run ``ng serve``
* Navigate to ``http://localhost:4200/``
2. Proxy Server
* The second way to install zoe can be done using a proxy with zoe. Information for setting up a proxy for zoe can be found at ``docs/proxy.rst``. Once a proxy is created, installation is done by the following:
* Run ``ng build -prod --output-path=prod``
* This will create all the build files in the ``/prod`` directory. These files need to be copied to the frontend server setup in the proxy configuration.
* Note that in order to change the ``<base href="/">`` within the ``index.html`` file, it is possible to add the following to the ``ng build`` command: ``--base-href x`` where x is the new href value.
Read more
---------
More information for deploying the angular project can be found in its documentation at ``zoe_fe/README.md``.
The zoe angular frontend is an external of zoe and lives at can be found in the [zoe_fe](https://github.com/DistributedSystemsGroup/zoe-fe) repository folder.
.idea
node_modules
dist
build
coverage
\ No newline at end of file
# Zoe Front End
This project was generated with [angular-cli](https://github.com/angular/angular-cli) version 1.0.0-beta.16.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class`.
# Configuration
Edit file `/src/enviroments/environments.prod.ts` and configure the path of the zoe Front End application, and the url for the zoe APIs, you can use a relative path in case it is deployed on the same server.
# Installation
Run `npm install` to install all the application's dependencies.
Run `ng build --env=prod --output-path=build/prod/` to build the application in `build/prod` folder.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
### Change the BaseHref
In order to change the `<base href="/">` within the `index.html file`, is it possible to add the following parameter to the `ng build` command: `--base-href x`, where x is the value of the new href.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
Before running the tests make sure you are serving the app via `ng serve`.
## Deploying to Github Pages
Run `ng github-pages:deploy` to deploy to Github Pages.
## Further help
To get more help on the `angular-cli` use `ng --help` or go check out the [Angular-CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
{
"project": {
"version": "1.0.0-beta.16",
"name": "zoe-porting"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": "assets",
"index": "index.html",
"main": "main.ts",
"test": "test.ts",
"tsconfig": "tsconfig.json",
"prefix": "app",
"mobile": false,
"styles": [
"assets/css/style.css",
"../node_modules/bootstrap/dist/css/bootstrap.min.css",
"../node_modules/font-awesome/css/font-awesome.min.css"
],
"scripts": [
"../node_modules/core-js/client/shim.min.js",
"../node_modules/reflect-metadata/Reflect.js",
"../node_modules/systemjs/dist/system.src.js"
],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"addons": [],
"packages": [],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "css",
"prefixInterfaces": false
}
}
import { ZoePortingPage } from './app.po';
describe('zoe-porting App', function() {
let page: ZoePortingPage;
beforeEach(() => {
page = new ZoePortingPage();
});
it('should display message saying app works', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('app works!');
});
});
import { browser, element, by } from 'protractor';
export class ZoePortingPage {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}
{
"compileOnSave": false,
"compilerOptions": {
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "commonjs",
"moduleResolution": "node",
"outDir": "../dist/out-tsc-e2e",
"sourceMap": true,
"target": "es5",
"typeRoots": [
"../node_modules/@types"
]
}
}
// Karma configuration file, see link for more information
// https://karma-runner.github.io/0.13/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', 'angular-cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-remap-istanbul'),
require('angular-cli/plugins/karma')
],
files: [
{ pattern: './src/test.ts', watched: false }
],
preprocessors: {
'./src/test.ts': ['angular-cli']
},
remapIstanbulReporter: {
reports: {
html: 'coverage',
lcovonly: './coverage/coverage.lcov'
}
},
angularCli: {
config: './angular-cli.json',
environment: 'dev'
},
reporters: ['progress', 'karma-remap-istanbul'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};
{
"name": "zoe",
"description": "Zoe dashboard",
"version": "0.0.1",
"license": "MIT",
"angular-cli": {},
"scripts": {
"start": "ng serve",
"lint": "tslint \"src/**/*.ts\"",
"test": "ng test",
"pree2e": "webdriver-manager update",
"e2e": "protractor"
},
"private": true,
"dependencies": {
"@angular/common": "^2.4.10",
"@angular/compiler": "^2.4.10",
"@angular/core": "^2.4.10",
"@angular/forms": "^2.4.10",
"@angular/http": "^2.4.10",
"@angular/platform-browser": "^2.4.10",
"@angular/platform-browser-dynamic": "^2.4.10",
"@angular/router": "^3.4.10",
"angular2-moment": "*",
"bootstrap": "3.3.6",
"core-js": "^2.4.1",
"font-awesome": "*",
"rxjs": "^5.0.1",
"systemjs": "0.19.27",
"ts-helpers": "^1.1.1",
"zone.js": "^0.7.2"
},
"devDependencies": {
"@angular/cli": "^1.0.0",
"@angular/compiler-cli": "^2.4.10",
"@types/jasmine": "^2.2.30",
"codelyzer": "~0.0.26",
"jasmine-core": "2.4.1",
"jasmine-spec-reporter": "2.5.0",
"karma": "1.2.0",
"karma-chrome-launcher": "^2.0.0",
"karma-cli": "^1.0.1",
"karma-jasmine": "^1.0.2",
"karma-remap-istanbul": "^0.2.1",
"protractor": "4.0.9",
"ts-node": "1.2.1",
"tslint": "3.13.0",
"typescript": "^2.2.2"
}
}
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/docs/referenceConf.js
/*global jasmine */
var SpecReporter = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
useAllAngular2AppRoots: true,
beforeLaunch: function() {
require('ts-node').register({
project: 'e2e'
});
},
onPrepare: function() {
jasmine.getEnv().addReporter(new SpecReporter());
}
};
sonar.projectName=zoe_fe
sonar.projectVerion = 1.0
sonar.host.url=http://your-sonarqube-server-address
sonar.sources=src
sonar.exclusions=bower_components/**/*, node_modules/**/*
sonar.sourceEncoding=UTF-8
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './components/login/login.component';
import { ExecutionInfoComponent } from './components/execution-info/execution-info.component';
import { ExecutionNewComponent } from './components/execution-new/execution-new.component';
import { ExecutionListComponent } from './components/execution-list/execution-list.component';
import { ModuleWithProviders } from '@angular/core';
const appRoutes: Routes = [
{ path: '', component: LoginComponent, pathMatch: 'full' },
{ path: 'executions/list', component: ExecutionListComponent, pathMatch: 'full' },
{ path: 'executions/new', component: ExecutionNewComponent, pathMatch: 'full' },
{ path: 'executions/:id', component: ExecutionInfoComponent }
];
export const ZoeRoutingProviders: any[] = [
];
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);
/*
const routes: Routes = [
{ path: '', component: LoginComponent, pathMatch: 'full' },
{ path: 'executions/list', component: ExecutionListComponent, pathMatch: 'full' },
{ path: 'executions/new', component: ExecutionNewComponent, pathMatch: 'full' },
{ path: 'executions/:id', component: ExecutionInfoComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: []
})
export class ZoeRoutingModule { }
*/
/* tslint:disable:no-unused-variable */
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('App', () => {
beforeEach(function() {
this.app = new AppComponent();
});
it('should create the app', function() {
expect(this.app).toBeTruthy();
});
});
/*
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { FromUnixPipe, DateFormatPipe } from 'angular2-moment';
import { CapitalizePipe } from './pipes/capitalize.pipe';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { APP_BASE_HREF } from '@angular/common';
import { routing, ZoeRoutingProviders } from './app-routing.module';
import { NavbarComponent } from './components/navbar/navbar.component';
import { LoginComponent } from './components/login/login.component';
import { ExecutionInfoComponent } from './components/execution-info/execution-info.component';
import { ExecutionNewComponent } from './components/execution-new/execution-new.component';
import { ExecutionListComponent } from './components/execution-list/execution-list.component';
import { ApiService } from './services/api.service';
import { StorageService } from './services/storage.service';
import { ActivatedRoute } from '@angular/router';
let fixture;
describe('App: Zoe', () => {
let apiServiceStub = {
getAllExecutions: () => executions
};
let storageServiceStub = {
getUsername: () => "admin"
};
let activateRouteStub = {
params: [{"id":100}]
};
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent,
LoginComponent,
NavbarComponent,
ExecutionInfoComponent,
ExecutionNewComponent,
ExecutionListComponent,
CapitalizePipe,
FromUnixPipe,
DateFormatPipe
],
imports: [
FormsModule,
ReactiveFormsModule,
HttpModule,
routing
],
providers: [
{provide: ActivatedRoute, useValue: activateRouteStub },
{provide: ApiService, useValue: apiServiceStub },
{provide: StorageService, useValue: storageServiceStub },
ApiService,
StorageService,
ZoeRoutingProviders,
{provide: APP_BASE_HREF, useValue : '/' }
],
bootstrap: [
AppComponent
]
});
fixture = TestBed.createComponent(AppComponent);
});
it('should create the app', async(() => {
let app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as title 'Zoe - Dashboard'`, async(() => {
let app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('Zoe - Dashboard');
}));
it('should render the navbar', async(() => {
fixture.detectChanges();
let compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('nav a.navbar-brand').textContent).toContain('Zoe');
}));
it('should render the login form', async(() => {
let fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
let compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Login');
}));
});
*/
\ No newline at end of file
import { Component } from '@angular/core';
@Component({
selector: 'app-zoe',
template: `
<navbar></navbar>
<div class="container body">
<div class="main_container">
<router-outlet></router-outlet>
</div>
</div>
`
})
export class AppComponent {
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule, BaseRequestOptions, RequestOptions, Headers } from '@angular/http';
import { FromUnixPipe, DateFormatPipe } from 'angular2-moment';
import { routing, ZoeRoutingProviders } from './app-routing.module';
import { AppComponent } from './app.component';
import { CapitalizePipe } from './pipes/capitalize.pipe';
import { LoginComponent } from './components/login/login.component';
import { NavbarComponent } from './components/navbar/navbar.component';
import { ExecutionInfoComponent } from './components/execution-info/execution-info.component';
import { ExecutionNewComponent } from './components/execution-new/execution-new.component';
import { ExecutionListComponent } from './components/execution-list/execution-list.component';
import { ApiService } from './services/api.service';
import { StorageService } from './services/storage.service';
import { environment } from '../environments/environment'
/** When FE and BE are deployed on 2 different hostname we need to
* enable CORS on the BE. In order to let the browser support the
* cookies between each HTTP request, we need to set 2 different
* options by default in the whole application.
**/
class CORSRequestOptions extends BaseRequestOptions {
headers: Headers = new Headers({
'X-Requested-With': 'XMLHttpRequest'
});
withCredentials: boolean = true;
}
let providers: any[] = [
ApiService,
StorageService,
ZoeRoutingProviders
];
if (environment.cors) {
providers.push({ provide: RequestOptions, useClass: CORSRequestOptions })
}
@NgModule({
declarations: [
AppComponent,
CapitalizePipe,
FromUnixPipe,
DateFormatPipe,
LoginComponent,
NavbarComponent,
ExecutionInfoComponent,
ExecutionNewComponent,
ExecutionListComponent
],
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule,
HttpModule,
routing
],
providers: providers,
bootstrap: [
AppComponent
]
})
export class AppModule { }
/* tslint:disable:no-unused-variable */
import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { Execution } from '../../entities/execution'
import { Service } from '../../entities/service'
import { By } from '@angular/platform-browser';
import { ExecutionInfoComponent } from './execution-info.component';
import { ApiService } from '../../services/api.service';
import { FromUnixPipe, DateFormatPipe } from 'angular2-moment';
import { CapitalizePipe } from '../../pipes/capitalize.pipe';
import { ActivatedRoute } from '@angular/router';
let comp: ExecutionInfoComponent;
let fixture: ComponentFixture<ExecutionInfoComponent>;
let spyGetExecutionDetails;
let spyGetServiceDetails;
describe('Component: ExecutionInfo', () => {
let executionDetails = {
'id': '123',
'name': 'Execution Test',
'owner': 'owner1234',
'status': 'running',
'services': [456]
};
let execution = new Execution().deserialize(executionDetails);
let serviceDetails = {
'id': '456',
'name': 'Service Test'
};
let service = new Service().deserialize(serviceDetails);
let activateRouteStub = {
params: [{"id":100}]
};
let apiServiceStub = {
getExecutionDetails: (id: string) => execution,
getServiceDetails: (id: string) => service
};
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
ExecutionInfoComponent,
CapitalizePipe,
FromUnixPipe,
DateFormatPipe
], // declare the test component
providers: [
{provide: ActivatedRoute, useValue: activateRouteStub },
{provide: ApiService, useValue: apiServiceStub }
]
});
fixture = TestBed.createComponent(ExecutionInfoComponent);
comp = fixture.componentInstance; // BannerComponent test instance
let apiService = TestBed.get(ApiService);
spyGetExecutionDetails = spyOn(apiService, 'getExecutionDetails')
.and.returnValue(Promise.resolve(execution));
spyGetServiceDetails = spyOn(apiService, 'getServiceDetails')
.and.returnValue(Promise.resolve(service));
});
it('should create an instance', () => {
expect(fixture).toBeTruthy();
});
it('should not show "Details" before "getExecutionDetails" call', () => {
expect(fixture.debugElement.query(By.css('#execution-details'))).toBeNull();
expect(fixture.debugElement.query(By.css('#execution-service'))).toBeNull();
expect(spyGetExecutionDetails.calls.any()).toBe(false, 'getExecutionDetails not yet called');
expect(spyGetServiceDetails.calls.any()).toBe(false, 'getServiceDetails not yet called');
});
it('should still not show quote after component initialized', () => {
fixture.detectChanges();
expect(fixture.debugElement.query(By.css('.spinner-title')).nativeElement.textContent).toContain('Loading...');
expect(spyGetExecutionDetails.calls.any()).toBe(true, 'getExecutionDetails called');
expect(spyGetServiceDetails.calls.any()).toBe(false, 'getServiceDetails called');
});
it('should show execution details and service', async(() => {
fixture.detectChanges();
fixture.whenStable().then(() => { // wait for async getQuote
fixture.detectChanges(); // update view with quote
expect(fixture.debugElement.query(By.css('#execution-details')).nativeElement).toBeDefined();
expect(fixture.debugElement.query(By.css('#execution-service')).nativeElement).toBeDefined();
});
}));
});
\ No newline at end of file
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { Execution } from '../../entities/execution';
import { Service } from '../../entities/service';
import { ApiService } from '../../services/api.service';
@Component({
selector: 'execution-info',
template: `
<div *ngIf="errorMessage" class="alert alert-danger alert-dismissible fade in" role="alert">
{{errorMessage}}
</div>
<div *ngIf="warningMessage" class="alert alert-warning alert-dismissible fade in" role="alert">
{{warningMessage}}
</div>
<div *ngIf="loading" class="spinner-block">
<div class="spinner-title">Loading...</div> <i class="spinner-icon"></i>
</div>
<div *ngIf="!loading && execution" id="execution-details">
<h1>Execution <em>{{execution.id}}</em></h1>
<hr />
<h3>Details</h3>
<dl class="dl-horizontal">
<dt>Name</dt>
<dd>{{execution.name}}</dd>
<dt>Application name</dt>
<dd>{{execution.applicationName()}}</dd>
<dt>Owner</dt>
<dd>{{execution.owner}}</dd>
<dt>Status</dt>
<dd>{{execution.status}}</dd>
<dt>Submitted</dt>
<dd *ngIf="execution.submitted">{{execution.submitted | amFromUnix | amDateFormat:'MMM D, YYYY, h:mm:ss a'}}</dd>
<dd *ngIf="!execution.submitted">Not yet</dd>
<dt *ngIf="execution.scheduled">Scheduled</dt>
<dd *ngIf="execution.scheduled">{{execution.scheduled | amFromUnix | amDateFormat:'MMM D, YYYY, h:mm:ss a'}}</dd>
<dt>Started</dt>
<dd *ngIf="execution.started">{{execution.started | amFromUnix | amDateFormat:'MMM D, YYYY, h:mm:ss a'}}</dd>
<dd *ngIf="!execution.started">Not yet</dd>
<dt>Finished</dt>
<dd *ngIf="execution.finished">{{execution.finished | amFromUnix | amDateFormat:'MMM D, YYYY, h:mm:ss a'}}</dd>