Commit aa4150d7 authored by Olivier PODEVIN's avatar Olivier PODEVIN
Browse files

Merge branch 'dev'

parents 29bdd0a2 1d2a9d0e
Pipeline #17 failed with stages
.git
.gitignore
.vscode
jsatorb-frontend-ws.code-workspace
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch index.html",
"type": "firefox",
"request": "launch",
"reAttach": true,
"file": "${workspaceFolder}/index.html"
},
{
"name": "Launch JSatOrb front",
"type": "firefox",
"request": "launch",
"reAttach": true,
"url": "http://localhost:4200",
"webRoot": "${workspaceFolder}"
},
{
"name": "Attach",
"type": "firefox",
"request": "attach"
},
{
"name": "Launch WebExtension",
"type": "firefox",
"request": "launch",
"reAttach": true,
"addonPath": "${workspaceFolder}"
}
]
}
\ No newline at end of file
FROM node:11.6.0-alpine AS builder
# -----------------------------------------------------------------------------
# JSatOrb project: Dockerization of the JSatOrb GUI Angular server
# -----------------------------------------------------------------------------
# NodeJS v11.15.0
# Angular CLI v8.3.20
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Multi-stage build: first image - Build the Angular application.
# -----------------------------------------------------------------------------
# Use NodeJS 11.15 base image
FROM node:11.15.0 AS builder
# Set working dir
WORKDIR /app
# Copy the application
COPY . .
# Install dependencies and build the application
RUN npm install && \
npm run ng build
# -----------------------------------------------------------------------------
# Multi-stage build: second image - Deploy the JSatOrb server into nginx.
# -----------------------------------------------------------------------------
# Use the latest nginx image
FROM nginx:alpine
COPY --from=builder /app/dist/jsatorb-cesium-front/ /usr/share/nginx/html/
# Copy the built JSatOrb server to the nginx server content folder
COPY --from=builder /app/dist/jsatorb-frontend/ /usr/share/nginx/html/
# Copy the JSatOrb specific nginx configuration
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Expose Web port 80
EXPOSE 80
# Set the nginx server entry point
ENTRYPOINT [ "nginx", "-g", "daemon off;" ]
# Useful links
# https://mherman.org/blog/dockerizing-an-angular-app/
# CesiumJS Angular App (front-end)
# JSatOrb project: Angular JSatOrb GUI (front-end)
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.0.3.
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.1.3.
It contains the JSatOrb GUI which relies on the JSatOrb REST API to provide a simulator to ISAE/Supaero students.
## Prérequis
- Avoir nodejs et npm d'installé
- Avoir Angular Cli installé en général ``` npm install -g @angular/cli ```
## Prerequisites
```
cd jsatorb-cesium-front
npm install
```
___Note: the following pre-requisites are satisfied when installing the JSatOrb development environment detailed in the [JSatOrb developer installation documentation](../jsatorb/doc/dev/dev-install.md).___
- NodeJS and NPM are installed
- Angular CLI installed ``` npm install -g @angular/cli ```
- Angular Material DateTimePicker v2.0.4 installed ``` npm install --save @angular-material-components/datetime-picker@2.0.4 ```
https://www.npmjs.com/package/@angular-material-components/datetime-picker
- Image cropper v3.1.8 for Angular installed ``` npm install ngx-image-cropper@3.1.8 --save ```
https://www.npmjs.com/package/ngx-image-cropper
- Angular Material Moment Adapter v2.0.2 installed ``` npm install --save @angular-material-components/moment-adapter@2.0.2 ```
## 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.
If currently working with an outdated datetime-picker version (initial version is 2.0.1), run the following commands:
- ``` npm uninstall @angular-material-components/datetime-picker@2.0.1 ```,
- ``` npm install @angular-material-components/datetime-picker@2.0.4 ```,
- ``` npm ls @angular-material-components/datetime-picker ``` to check installation's effectiveness.
## Todo
Todo :
- Sur la partie backend du calcules des eclipses indiquer l'angle d'inclinaison du soleil
- TLE via celestrack
- Formulaire : bloqué les champs des noms lorqu'on modifie les satellites
- Produire de la doc notament sur les messages envoyé et reçu
# Module installation
## Bug solving
git co -b master remotes/origin/origin/master
git push origin master
```
cd jsatorb-frontend
npm install
```
## Run the development server
To run an Angular server in the development environment:
- Run `ng serve` to run the Angular/JSatOrb GUI server.
- Navigate to `http://localhost:4200/`.
- The application will be automatically re-compiled if you change any of the source files.
___Note: in a JSatOrb user environment, the JSatOrb GUI server is ran from a Docker container located in the user installation folder.___
\ No newline at end of file
......@@ -3,7 +3,7 @@
"version": 1,
"newProjectRoot": "projects",
"projects": {
"cesium-server": {
"jsatorb-frontend": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
......@@ -17,7 +17,7 @@
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/cesium-server",
"outputPath": "dist/jsatorb-frontend",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
......@@ -68,18 +68,18 @@
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "cesium-server:build"
"browserTarget": "jsatorb-frontend:build"
},
"configurations": {
"production": {
"browserTarget": "cesium-server:build:production"
"browserTarget": "jsatorb-frontend:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "cesium-server:build"
"browserTarget": "jsatorb-frontend:build"
}
},
"test": {
......@@ -119,7 +119,7 @@
}
}
},
"cesium-server-e2e": {
"jsatorb-frontend-e2e": {
"root": "e2e/",
"projectType": "application",
"prefix": "",
......@@ -128,11 +128,11 @@
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "cesium-server:serve"
"devServerTarget": "jsatorb-frontend:serve"
},
"configurations": {
"production": {
"devServerTarget": "cesium-server:serve:production"
"devServerTarget": "jsatorb-frontend:serve:production"
}
}
},
......@@ -148,5 +148,5 @@
}
}
},
"defaultProject": "cesium-server"
"defaultProject": "jsatorb-frontend"
}
{
"folders": [
{
"path": "."
},
{
"path": "/home/jsatorb/JSatOrb/mission-data"
}
],
"settings": {}
}
\ No newline at end of file
{
"name": "cesium-server",
"name": "jsatorb-frontend",
"version": "0.0.0",
"lockfileVersion": 1,
"requires": true,
......@@ -212,6 +212,22 @@
}
}
},
"@angular-material-components/datetime-picker": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@angular-material-components/datetime-picker/-/datetime-picker-2.0.4.tgz",
"integrity": "sha512-3nXGFz7GXbFYeBI2/72rcmPFTWtcC1ERlgdkaY+65dFHXPIc8hKGv6o+JbtCoYPg7xmVCCy4xhmOgfd/CFGyOw==",
"requires": {
"tslib": "^1.9.0"
}
},
"@angular-material-components/moment-adapter": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@angular-material-components/moment-adapter/-/moment-adapter-2.0.2.tgz",
"integrity": "sha512-QO8ftUkUzFIK8QhG9Z/f00Y5Z1BYBdOmIiEHOd6hwcKQK2PS87tAIETPLOjHnUONSAQjTVWcw8/WpQTBqCNxyA==",
"requires": {
"tslib": "^1.9.0"
}
},
"@angular/animations": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-8.2.3.tgz",
......@@ -6641,6 +6657,15 @@
"integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
"dev": true
},
"ngx-image-cropper": {
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/ngx-image-cropper/-/ngx-image-cropper-3.1.8.tgz",
"integrity": "sha512-4XaHNdPdhSh37zChDvW7fZ61z5SuzRP87bj624GtVacfvBk4EpZ6V6YkiD99XxzB0IkEt6DIfmGT+TAxAdQNAw==",
"requires": {
"hammerjs": "^2.0.8",
"tslib": "^1.9.0"
}
},
"ngx-nanospace-client-lib": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/ngx-nanospace-client-lib/-/ngx-nanospace-client-lib-0.4.2.tgz",
......
{
"name": "cesium-server",
"version": "0.0.0",
"name": "jsatorb-frontend",
"version": "1.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
......@@ -11,6 +11,8 @@
},
"private": true,
"dependencies": {
"@angular-material-components/datetime-picker": "^2.0.4",
"@angular-material-components/moment-adapter": "^2.0.2",
"@angular/animations": "^8.1.1",
"@angular/cdk": "~8.1.1",
"@angular/common": "~8.1.1",
......@@ -30,6 +32,7 @@
"chart.js": "^2.7.3",
"core-js": "^2.5.4",
"hammerjs": "^2.0.8",
"ngx-image-cropper": "^3.1.8",
"ngx-nanospace-client-lib": "^0.4.2",
"ngx-socket-io": "^2.1.1",
"rxjs": "~6.5.2",
......
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BaseDisplayMessageComponent } from './base-display-message.component';
describe('BaseDisplayMessageComponent', () => {
let component: BaseDisplayMessageComponent;
let fixture: ComponentFixture<BaseDisplayMessageComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BaseDisplayMessageComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BaseDisplayMessageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-base-display-message',
templateUrl: './base-display-message.component.html',
styleUrls: ['./base-display-message.component.scss']
})
/**
* Component used to centralize the message display functions (see below).
* Each component using this one declares two divs in its HTML part and uses centralized styles which are in the 'styles.scss' file.
*/
export class BaseDisplayMessageComponent implements OnInit {
constructor() { }
ngOnInit() {
}
public lastErrorMessage: string; // Variable used to show error messages, if any, when sending a request to the REST API.
public lastInfoMessage: string; // Variable used to show informative messages, if any, when sending a request to the REST API.
/**
* Setter.
* @param msg The informative message to set.
*/
setInfoMessage(msg: string) {
this.lastErrorMessage = '';
this.lastInfoMessage = msg;
console.log(msg);
}
/**
* Setter.
* @param msg The error message to set.
*/
setErrorMessage(msg: string) {
this.lastErrorMessage = msg;
this.lastInfoMessage = '';
console.error(msg);
}
/**
* Update the GUI operation message according to a returned status.
* @param status The status to react to.
*/
updateMessages(status: Map<string, string>) {
if (status.has('status')) {
if (status.get('status') == 'SUCCESS') {
if (status.has('message')) { // If a message exists in the status to display...
this.setInfoMessage(status.get('message'));
}
// If no message associated with the SUCCESS status, no worry
} else { // FAILURE
if (status.has('message')) { // If a message exists in the status to display...
this.setErrorMessage(status.get('message'));
} else {
this.setErrorMessage('Unknown status received (status=FAIL but no message). Debug to check invalid status source !');
}
}
} else { // If not SUCCESS/FAIL status => Error message, by default, with a warning on the missing status value.
if (status.has('message')) { // If a message exists in the status to display...
this.setErrorMessage(status.get('message') + ' (warning: no status (SUCCESS/FAIL) detected in the status to display)');
} else { // Else, warn that an invalid status has been received.
this.setErrorMessage('Unknown status received (no status, no message). Debug to check invalid status source !')
}
}
}
}
<div mat-dialog-content>
{{ message }}
</div>
<div mat-dialog-actions>
<button mat-button (click)="onNoClick()">No</button>
<button mat-button [mat-dialog-close]="true" cdkFocusInitial>Yes</button>
</div>
\ No newline at end of file
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ConfirmationDialogComponent } from './confirmation-dialog.component';
describe('ConfirmationDialogComponent', () => {
let component: ConfirmationDialogComponent;
let fixture: ComponentFixture<ConfirmationDialogComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ConfirmationDialogComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ConfirmationDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
@Component({
selector: 'app-confirmation-dialog',
templateUrl: './confirmation-dialog.component.html',
styleUrls: ['./confirmation-dialog.component.scss']
})
/**
* This component represents a reusable modal confirmation dialog.
* Code widely inspired by the one on this link:
* https://firstclassjs.com/create-a-reusable-confirmation-dialog-in-angular-7-using-angular-material/#confirmation-dialog-component
*/
export class ConfirmationDialogComponent {
constructor(public dialogRef: MatDialogRef<ConfirmationDialogComponent>,
@Inject(MAT_DIALOG_DATA) public message: string) { }
onNoClick(): void {
this.dialogRef.close();
}
}
<div class="form-header">
<h2>Constellation Form</h2>
<a routerLink="">
<mat-icon color="accent">arrow_back_ios</mat-icon>
</a>
</div>
<div class="example-container">
<div class="constellationInput">
<mat-form-field>
<mat-label for="consName"> Constellation Name</mat-label>
<input matInput [(ngModel)]="consName" id="consName"/>
</mat-form-field>
<mat-form-field class="jso-field-full-width">
<mat-select [(ngModel)]="selectedSat" placeholder="Select a satellite to add to the constellation">
<mat-option *ngFor="let avSat of getAvailableSatellites()" [value]="avSat"> {{ avSat }}</mat-option>
</mat-select>
<button mat-icon-button class="jso-button-full-width" (click)="addSat()" [disabled]="!isSelectedSat()"><mat-icon color="warn">add</mat-icon>Add satellite</button>
<div class="jso-button-spacer"></div>
<button mat-icon-button class="jso-button-full-width" (click)="addAllSats()" [disabled]="!isThereSatellitesToAdd()"><mat-icon color="warn">add</mat-icon>Add all satellites</button>
</mat-form-field>
<mat-list>
<mat-list-item *ngFor="let sat of getSatellitesInConstellation()"> {{ sat }}
<div class="btn-item">
<button mat-icon-button (click)="removeSat(sat)"><mat-icon color="warn">close</mat-icon></button>
</div>
</mat-list-item>
</mat-list>
<!-- Disable the 'Save' button if the constellation name is empty -->
<button mat-stroked-button [disabled]="!consName" (click)="onSaveConstellation()" color="accent">Save</button>
<div class="jso-button-spacer"></div>
<!-- Constellation Wizard -->
<button mat-stroked-button (click)="onCreateConstellation()" color="accent">Constellation generator</button>
</div>
</div>
<!-- Message display area -->
<div *ngIf="lastErrorMessage" class="jso-error-message-display">
<p class="jso-text-style">{{ lastErrorMessage }}</p>
</div>
<div *ngIf="lastInfoMessage" class="jso-info-message-display">
<p class="jso-text-style">{{ lastInfoMessage }}</p>
</div>
.example-container {
display: flex;
flex-direction: column;
max-width: 100%;
}
.example-container {
margin-left: 50px;
margin-right: 50px;
}
.example-container form {
margin-bottom: 20px;
}
.example-container form > * {
margin: 5px 0;
}
.example-container .mat-radio-button {
margin: 0 5px;
}
.constellationInput{
display: flex;
flex-direction: column;
width: 100%;
}
$icon-size: 75px;
.form-header {
display: flex;
justify-content: space-between;
margin: 50px;
a {
mat-icon {
margin-left: 12px;
font-size: $icon-size;
}
}
}
\ No newline at end of file
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ConstellationFormComponent } from './constellation-form.component';
describe('ConstellationFormComponent', () => {
let component: ConstellationFormComponent;
let fixture: ComponentFixture<ConstellationFormComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ConstellationFormComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ConstellationFormComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import {Component, OnInit, OnDestroy, SystemJsNgModuleLoader} from '@angular/core';
import {ConstellationModel} from '../../Models/Constellation.model';
import {MissionService} from '../../Services/mission/mission.service';
import {ActivatedRoute, Router} from '@angular/router';
import { Subscription } from 'rxjs';
import { BaseDisplayMessageComponent } from '../base-display-message/base-display-message.component';
import { SatelliteModel } from 'src/app/Models/Satellite.model';
@Component({
selector: 'app-constellation-form',
templateUrl: './constellation-form.component.html',
styleUrls: ['./constellation-form.component.scss']
})
export class ConstellationFormComponent extends BaseDisplayMessageComponent implements OnInit, OnDes